diff -u --recursive --new-file v2.4.0-test8/linux/CREDITS linux/CREDITS --- v2.4.0-test8/linux/CREDITS Fri Sep 8 12:38:00 2000 +++ linux/CREDITS Tue Sep 19 17:47:06 2000 @@ -485,7 +485,7 @@ S: USA N: Juan Jose Ciarlante -W: http://juanjox.linuxhq.com/ +W: http://juanjox.kernelnotes.org/ E: jjciarla@raiz.uncu.edu.ar E: jjo@mendoza.gov.ar D: Network driver alias support @@ -734,6 +734,7 @@ N: Johannes Erdfelt E: jerdfelt@valinux.com +E: johannes@erdfelt.com D: Linux/IA-64 bootloader and kernel goop, USB S: 6350 Stoneridge Mall Road S: Pleasanton, CA 94588 @@ -1728,7 +1729,7 @@ S: Germany N: Mark W. McClelland -E: mmcclelland@delphi.com +E: mwm@i.am E: mark@alpha.dyndns.org W: http://alpha.dyndns.org/ov511/ D: OV511 driver diff -u --recursive --new-file v2.4.0-test8/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.4.0-test8/linux/Documentation/Configure.help Tue Sep 5 12:57:51 2000 +++ linux/Documentation/Configure.help Fri Sep 22 17:11:37 2000 @@ -1088,22 +1088,25 @@ Support for PowerMac IDE devices (must also enable IDE) CONFIG_BLK_DEV_IDE_PMAC - No help for CONFIG_BLK_DEV_IDE_PMAC + This driver provides support for the built-in IDE controller on most + of the recent Apple Power Macintoshes and PowerBooks. + If unsure, say Y. PowerMac IDE DMA support CONFIG_BLK_DEV_IDEDMA_PMAC - No help for CONFIG_BLK_DEV_IDEDMA_PMAC + This option allows the driver for the built-in IDE controller on + Power Macintoshes and PowerBooks to use DMA (direct memory access) + to transfer data to and from memory. Saying Y is safe and improves + performance. Use DMA by default -CONFIG_IDEDMA_PMAC_AUTO - Prior to kernel version 2.1.112, Linux used to automatically use - DMA for IDE drives and chipsets which support it. Due to concerns - about a couple of cases where buggy hardware may have caused damage, - the default is now to NOT use DMA automatically. To revert to the - previous behaviour, say Y to this question. - - If you suspect your hardware is at all flakey, say N here. - Do NOT email the IDE kernel people regarding this issue! +CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO + This option allows the driver for the built-in IDE controller on + Power Macintoshes and PowerBooks to use DMA automatically, without + it having to be explicitly enabled. This option is provided because + of concerns about a couple of cases where using DMA on buggy PC + hardware may have caused damage. Saying Y should be safe on all + Apple machines. Macintosh Quadra/Powerbook IDE interface support CONFIG_BLK_DEV_MAC_IDE @@ -4910,6 +4913,14 @@ it as a module, say M here and read Documentation/modules.txt. The module will be called phonedev.o. +Compaq Smart Array support +CONFIG_BLK_CPQ_CISS_DA + This is the driver for Compaq Smart Array controllers. + Everyone using these boards should say Y here. + See "linux/Documentation/cciss.txt" for the current list of + boards supported by this driver, and for further information + on the use of this driver. + QuickNet Internet LineJack/PhoneJack support CONFIG_PHONE_IXJ Say M if you have a telephony card manufactured by Quicknet @@ -5358,9 +5369,10 @@ IBM ServeRAID Support CONFIG_SCSI_IPS This is support for the IBM ServeRAID hardware RAID controllers. - - Please consult the SCSI-HOWTO, available from - http://www.linuxdoc.org/docs.html#howto . + See http://www.developer.ibm.com/welcome/netfinity/serveraid.html + for more information. If this driver does not work correctly + without modification please contact the author by email at + ipslinux@us.ibm.com. You can build this driver as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -7864,6 +7876,9 @@ and using COMX interfaces. Further info on these cards can be found at http://www.itc.hu or . + You must say Y to "/proc file system support" (CONFIG_PROC_FS) to + use this driver. + If you want to compile this as a module, say M and read Documentation/modules.txt. The module will be called comx.o. @@ -8152,8 +8167,10 @@ module, say M here and read Documentation/modules.txt as well as Documentation/networking/net-modules.txt. -RealTek 8129 (not 8019/8029!) support (EXPERIMENTAL) +RealTek 8129 (not 8019/8029/8139!) support (EXPERIMENTAL) CONFIG_RTL8129 + This is NOT for RTL-8139 cards. Instead, select the 8139too driver + (CONFIG_8139TOO). This is a driver for the Fast Ethernet PCI network cards based on the RTL8129 chip. If you have one of those, say Y and read the Ethernet-HOWTO, available from @@ -8276,6 +8293,11 @@ - SK-9844 (dual link 1000Base-SX) - SK-9821 (single link 1000Base-T) - SK-9822 (dual link 1000Base-T) + - SK-9861 (single link Volition connector) + - SK-9862 (dual link Volition connector) + The driver also supports the following adapters from Allied Telesyn: + - AT2970... + The dual link adapters support a link-failover feature. Read Documentation/networking/sk98lin.txt for information about optional driver parameters. @@ -8682,6 +8704,18 @@ Documentation/networking/net-modules.txt. The module will be called eexpress.o. +Packet Engines Hamachi GNIC-II support +CONFIG_HAMACHI + If you have a Gigabit Ethernet card of this type, say Y and read + the Ethernet-HOWTO, available from + http://www.linuxdoc.org/docs.html#howto . + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. The module will be called + hamachi.o. + HP PCLAN+ (27247B and 27252A) support CONFIG_HPLAN_PLUS If you have a network (Ethernet) card of this type, say Y and read @@ -9005,23 +9039,31 @@ module, say M here and read Documentation/modules.txt as well as Documentation/networking/net-modules.txt. -SMC EtherPower II (EXPERIMENTAL) +SMC EtherPower II CONFIG_EPIC100 - If you have an SMC EtherPower II 9432 PCI Ethernet network card - which is based on the SMC83c170, say Y and read the Ethernet-HOWTO, - available from http://www.linuxdoc.org/docs.html#howto . - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called epic100.o. If you want to compile it as a - module, say M here and read Documentation/modules.txt as well as - Documentation/networking/net-modules.txt. + This driver is for the SMC EtherPower II 9432 PCI Ethernet NIC, + which is based on the SMC83c17x (EPIC/100). + More specific information and updates are available from + http://www.scyld.com/network/epic100.html SGI Seeq ethernet controller support CONFIG_SGISEEQ Say Y here if you have an Seeq based Ethernet network card. This is used in many Silicon Graphics machines. +Sundance "Alta" PCI Ethernet support +CONFIG_SUNDANCE + This driver is for the Sundance "Alta" chip. + More specific information and updates are available from + http://www.scyld.com/network/sundance.html + +Winbond W89c840 PCI Ethernet support +CONFIG_WINBOND_840 + This driver is for the Winbond W89c840 chip. It also works with + the TX9882 chip on the Compex RL100-ATX board. + More specific information and updates are available from + http://www.scyld.com/network/drivers.html + Zenith Z-Note support (EXPERIMENTAL) CONFIG_ZNET The Zenith Z-Note notebook computer has a built-in network @@ -9979,10 +10021,24 @@ The module will be called wmforce.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. +Use input layer for ADB devices +CONFIG_INPUT_ADBHID + Say Y here if you want to have ADB (Apple Desktop Bus) HID devices + such as keyboards, mice, joysticks, or graphic tablets handled by the + input layer. If you say Y here, make sure to say Y to the + corresponding drivers "Keyboard support" (CONFIG_INPUT_KEYBDEV), + "Mouse Support" (CONFIG_INPUT_MOUSEDEV) and "Event interface support" + (CONFIG_INPUT_EVDEV) as well. + + If you say N here, you still have the option of using the old ADB + keyboard and mouse drivers. + + If unsure, say Y. + Keyboard support CONFIG_INPUT_KEYBDEV - Say Y here if you want your USB HID keyboard to be able to serve as - a system keyboard. + Say Y here if you want your USB HID keyboard (or an ADB keyboard + handled by the input layer) to be able to serve as a system keyboard. This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -9991,10 +10047,11 @@ Mouse support CONFIG_INPUT_MOUSEDEV - Say Y here if you want your USB HID mouse to be accessible as - char devices 13:32+ - /dev/input/mouseX and 13:63 - /dev/input/mice - as an emulated PS/2 mouse. That way, all user space programs will - be able to use your mouse. + Say Y here if you want your USB HID mouse (or ADB mouse handled by + the input layer) to be accessible as char devices 13:32+ - + /dev/input/mouseX and 13:63 - /dev/input/mice as an emulated ImPS/2 + mouse. That way, all user space programs will be able to use your + mouse. If unsure, say Y. @@ -10029,8 +10086,8 @@ Event interface support CONFIG_INPUT_EVDEV - Say Y here if you want your USB HID device events be accessible - under char device 13:64+ - /dev/inputX in a generic way. + Say Y here if you want your USB or ADB HID device events be accessible + under char device 13:64+ - /dev/input/eventX in a generic way. This is the future ... USB Scanner support @@ -10245,7 +10302,8 @@ CONFIG_USB_PEGASUS Say Y if you want to use your USB ethernet device. Supported cards until now are: - ADMtek AN986 (eval. board) + ADMtek AN986 Pegasus (eval. board) + ADMtek ADM8511 Pegasus II (eval. board) Accton 10/100 Billington USB-100 Corega FEter USB-TX @@ -10255,6 +10313,8 @@ LANEED Ethernet LD-USB/TX SMC 202 SOHOware NUB Ethernet + + Any Pegasus II based board also are supported. If you have devices with vendor IDs other than noted above you should add them in the driver code and send a message to me (petkan@dce.bg) for update. @@ -11309,6 +11369,21 @@ want), say M here and read Documentation/modules.txt. The module will be called smbfs.o. Most people say N, however. +use nls by default +CONFIG_SMB_NLS_DEFAULT + Enabling this will make smbfs use nls translations by default. You + need to specify the local charset (CONFIG_NLS_DEFAULT) in the nls + settings and you need to give the default nls for the SMB server as + CONFIG_SMB_NLS_REMOTE. + + The nls settings can be changed at mount time, if your smbmount + supports that, using the codepage and iocharset parameters. + + Currently no smbmount distributed with samba supports this, it is + assumed future versions will. In the meantime you can get an + unofficial patch for samba 2.0.7 from: + http://www.hojdpunkten.ac.se/054/samba/index.html + nls support setting CONFIG_SMB_NLS_REMOTE This setting allows you to specify a default value for which @@ -15425,6 +15500,42 @@ have it autoloaded. The act of removing the module shuts down the sound hardware for more power savings. +Mac-on-Linux support +CONFIG_MOL + This option enables low-level support for Mac-on-Linux. + MOL lets you run MacOS and Linux simultaneously. Please + visit for more information. + If unsure, say Y. + +ADB raw keycode support +CONFIG_MAC_ADBKEYCODES + This provides support for sending raw ADB keycodes to console + devices. This is the default up to 2.4.0, but in future this may be + phased out in favor of generic Linux keycodes. If you say Y here, you + can dynamically switch via the + /proc/sys/dev/mac_hid/keyboard_sends_linux_keycodes + sysctl and with the "keyboard_sends_linux_keycodes=" kernel argument. + + If unsure, say Y here. + +Mouse button 2+3 emulation support +CONFIG_MAC_EMUMOUSEBTN + This provides generic support for emulating the 2nd and 3rd mouse + button with keypresses. If you say Y here, the emulation is still + disabled by default. The emulation is controlled by these sysctl entries: + /proc/sys/dev/mac_hid/mouse_button_emulation + /proc/sys/dev/mac_hid/mouse_button2_keycode + /proc/sys/dev/mac_hid/mouse_button3_keycode + +Enhanced Real Time Clock Support +CONFIG_PPC_RTC + If you say Y here and create a character special file /dev/rtc with + major number 10 and minor number 135 using mknod ("man mknod"), you + will get access to the real time clock (or hardware clock) built + into your computer. + + If unsure, say Y here. + Support for Open Firmware device tree in /proc CONFIG_PROC_DEVICETREE This option adds a device-tree directory under /proc which contains @@ -15915,12 +16026,18 @@ # ARM options # ARM System type -CONFIG_ARCH_ARC +CONFIG_ARCH_ARCA5K This selects what ARM system you wish to build the kernel for. It also selects to some extent the CPU type. If you are unsure what to set this option to, please consult any information supplied with your system. +2MB physical memory +CONFIG_PAGESIZE_16 + Say Y here if your Archimedes or A5000 system has only 2MB of + memory, otherwise say N. The resulting kernel will not run on a + machine with 4MB of memory. + Include support for the CATS CONFIG_ARCH_CATS Say Y here if you intend to run this kernel on the CATS. @@ -16020,6 +16137,27 @@ http://www.visuaide.com/pagevictor.en.html for information on this system. +Support ARM610 processor +CONFIG_CPU_ARM6 + Say Y here if you wish to include support for the ARM610 processor. + +Support ARM710 processor +CONFIG_CPU_ARM7 + Say Y here if you wish to include support for the ARM710 processor. + +Support StrongARM(R) SA-110 processor +CONFIG_CPU_SA110 + Say Y here if you wish to include support for the Intel(R) + StrongARM(R) SA-110 processor. + +Support ARM720 processor +CONFIG_CPU_ARM720 + Say Y here if you wish to include support for the ARM720 processor. + +Support ARM920 +CONFIG_CPU_ARM920 + Say Y here if you wish to include support for the ARM920 processor. + Math emulation CONFIG_NWFPE Say Y to include the NWFPE floating point emulator in the kernel. @@ -16134,8 +16272,8 @@ 21285 serial port support CONFIG_SERIAL_21285 - If you have a machine based on a 21285 (Footbridge) StrongARM/PCI - bridge you can enable its onboard serial port by enabling this + If you have a machine based on a 21285 (Footbridge) StrongARM(R)/ + PCI bridge you can enable its onboard serial port by enabling this option. The device has major ID 4, minor 64. Console on 21285 serial port diff -u --recursive --new-file v2.4.0-test8/linux/Documentation/DocBook/Makefile linux/Documentation/DocBook/Makefile --- v2.4.0-test8/linux/Documentation/DocBook/Makefile Sat Aug 12 14:25:54 2000 +++ linux/Documentation/DocBook/Makefile Sun Oct 1 20:18:54 2000 @@ -55,11 +55,11 @@ $(TOPDIR)/scripts/docgen $(TOPDIR)/arch/i386/kernel/mca.c \ mcabook.sgml -videobook.sgml: videobook.tmpl $(TOPDIR)/drivers/char/videodev.c - $(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/char/videodev.c \ +videobook.sgml: videobook.tmpl $(TOPDIR)/drivers/media/video/videodev.c + $(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/media/video/videodev.c \ videobook.sgml -APISOURCES := $(TOPDIR)/drivers/char/videodev.c \ +APISOURCES := $(TOPDIR)/drivers/media/video/videodev.c \ $(TOPDIR)/arch/i386/kernel/mca.c \ $(TOPDIR)/arch/i386/kernel/mtrr.c \ $(TOPDIR)/drivers/char/misc.c \ @@ -72,6 +72,7 @@ $(TOPDIR)/drivers/sound/sound_firmware.c \ $(TOPDIR)/drivers/net/wan/syncppp.c \ $(TOPDIR)/drivers/net/wan/z85230.c \ + $(TOPDIR)/fs/locks.c \ $(TOPDIR)/fs/devfs/base.c \ $(TOPDIR)/kernel/pm.c \ $(TOPDIR)/kernel/ksyms.c \ diff -u --recursive --new-file v2.4.0-test8/linux/Documentation/DocBook/kernel-api.tmpl linux/Documentation/DocBook/kernel-api.tmpl --- v2.4.0-test8/linux/Documentation/DocBook/kernel-api.tmpl Wed Jul 26 19:47:48 2000 +++ linux/Documentation/DocBook/kernel-api.tmpl Sun Oct 1 20:18:54 2000 @@ -61,6 +61,10 @@ Registration and Superblocks !Efs/super.c + File Locks +!Efs/locks.c +!Ifs/locks.c + @@ -137,7 +141,7 @@ Video4Linux -!Edrivers/char/videodev.c +!Edrivers/media/video/videodev.c diff -u --recursive --new-file v2.4.0-test8/linux/Documentation/DocBook/videobook.tmpl linux/Documentation/DocBook/videobook.tmpl --- v2.4.0-test8/linux/Documentation/DocBook/videobook.tmpl Wed Mar 15 10:28:32 2000 +++ linux/Documentation/DocBook/videobook.tmpl Sun Oct 1 20:18:54 2000 @@ -1657,7 +1657,7 @@ Public Functions Provided -!Edrivers/char/videodev.c +!Edrivers/media/video/videodev.c diff -u --recursive --new-file v2.4.0-test8/linux/Documentation/SubmittingDrivers linux/Documentation/SubmittingDrivers --- v2.4.0-test8/linux/Documentation/SubmittingDrivers Wed Dec 31 16:00:00 1969 +++ linux/Documentation/SubmittingDrivers Tue Sep 19 08:01:34 2000 @@ -0,0 +1,112 @@ +Submitting Drivers For The Linux Kernel +--------------------------------------- + +This document is intended to explain how to submit device drivers to the +Linux 2.2 and 2.4test kernel trees. Note that if you are interested in video +card drivers you should probably talk to XFree86 (http://wwww.xfree86.org) +instead. + +Allocating Device Numbers +------------------------- + +Major and minor numbers for devices are allocated by the Linux assigned name +and number authority (currently better known as H Peter Anvin). The +site is http://www.lanana.org/. This also deals with allocating numbers for +devices that are not going to be submitted to the mainstream kernel. + +If you don't use assigned numbers then when you device is submitted it will +get given an assigned number even if that is different from values you may +have shipped to customers before. + +Who To Submit Drivers To +------------------------ + +Linux 2.0: + No new drivers are accepted for this kernel tree + +Linux 2.2: + If the code area has a general maintainer then please submit it to + the maintainer listed in MAINTAINERS in the kernel file. If the + maintainer does not respond or you cannot find the appropriate + maintainer then please contact Alan Cox + +Linux 2.4test: + This kernel tree is under active development. The same rules apply + as 2.2 but you may wish to submit your driver via linux-kernel (see + resources) and follow that list to track changes in API's. These + should no longer be occuring as we are now in a code freeze. + The final contact point for Linux 2.4 submissions is + . + +What Criteria Determine Acceptance +---------------------------------- + +Licensing: The code must be released to us under the GNU 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 + licenses. + +Interfaces: If your driver uses existing interfaces and behaves like + other drivers in the same class it will be much more likely + to be accepted than if it invents gratuitous new ones. + If you need to implement a common API over Linux and NT + drivers do it in userspace. + +Code: Please use the Linux style of code formatting as documented + in Documentation/CodingStyle. If you have sections of code + that need to be in other formats, for example because they + are shared with a windows driver kit and you want to + maintain them just once seperate them out nicely and note + this fact. + +Portability: Pointers are not always 32bits, people do not all have + floating point and you shouldn't use inline x86 assembler in + your driver without careful thought. Pure x86 drivers + generally are not popular. If you only have x86 hardware it + is hard to test portability but it is easy to make sure the + code can easily be made portable. + +Clarity: It helps if anyone can see how to fix the driver. It helps + you because you get patches not bug reports. If you submit a + driver that intentionally obfuscates how the hardware works + it will go in the bitbucket. + +Control: In general if there is active maintainance of a driver by + the author then patches will be redirected to them unless + they are totally obvious and without need of checking. + If you want to be the contact and update point for the + driver it is a good idea to state this in the comments. + +What Criteria Do Not Determine Acceptance +----------------------------------------- + +Vendor: Being the hardware vendor and maintaining the driver is + often a good thing. If there is a stable working driver from + other people already in the tree don't expect 'we are the + vendor' to get your driver chosen. Ideally work with the + existing driver author to build a single perfect driver. + +Author: It doesn't matter if a large Linux company wrote the driver, + or you did. Nobody has any special access to the kernel + tree. Anyone who tells you otherwise isn't telling the + whole story. + + +Resources +--------- + +Linux kernel master tree: + ftp.kernel.org:/pub/linux/kernel/... + +Linux kernel mailing list: + linux-kernel@vger.kernel.org + [mail majordomo@vger.kernel.org to subscribe] + +Kernel traffic: + Weekly summary of kernel list activity (much easier to read) + [http://kt.linuxcare.com/kernel-traffic] + +Linux USB project: + http://sourceforge.net/projects/linux-usb/ + diff -u --recursive --new-file v2.4.0-test8/linux/Documentation/arm/README linux/Documentation/arm/README --- v2.4.0-test8/linux/Documentation/arm/README Mon Jun 19 17:59:33 2000 +++ linux/Documentation/arm/README Mon Sep 18 15:15:24 2000 @@ -52,6 +52,36 @@ the problem, what you were doing, etc. +Include files +------------- + + Several new include directories have been created under include/asm-arm, + which are there to reduce the clutter in the top-level directory. These + directories, and their purpose is listed below: + + arch-* machine/platform specific header files + hardware driver-internal ARM specific data structures/definitions + mach descriptions of generic ARM to specific machine interfaces + proc-* processor dependent header files (currently only two + categories) + + +Machine/Platform support +------------------------ + + The ARM tree contains support for a lot of different machine types. To + continue supporting these differences, it has become necessary to split + machine-specific parts by directory. For this, the machine category is + used to select which directories and files get included (we will use + $(MACHINE) to refer to the category) + + To this end, we now have arch/arm/mach-$(MACHINE) directories which are + designed to house the non-driver files for a particular machine (eg, PCI, + memory management, architecture definitions etc). For all future + machines, there should be a corresponding include/asm-arm/arch-$(MACHINE) + directory. + + Modules ------- diff -u --recursive --new-file v2.4.0-test8/linux/Documentation/cciss.txt linux/Documentation/cciss.txt --- v2.4.0-test8/linux/Documentation/cciss.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/cciss.txt Fri Sep 22 17:11:37 2000 @@ -0,0 +1,47 @@ +This driver is for Compaq's SMART Array Controllers. + +Supported Cards: +---------------- + +This driver is known to work with the following cards: + + * SA 5300 + +If notes are not already created in the /dev/cciss directory + +# mkdev.cciss [ctlrs] + +Where ctlrs is the number of controllers you have (defaults to 1 if not +specified). + +Device Naming: +-------------- + +You need some entries in /dev for the cciss device. The mkdev.cciss script +can make device nodes for you automatically. Currently the device setup +is as follows: + +Major numbers: + 104 cciss0 + 105 cciss1 + 106 cciss2 + etc... + +Minor numbers: + b7 b6 b5 b4 b3 b2 b1 b0 + |----+----| |----+----| + | | + | +-------- Partition ID (0=wholedev, 1-15 partition) + | + +-------------------- Logical Volume number + +The suggested device naming scheme is: +/dev/cciss/c0d0 Controller 0, disk 0, whole device +/dev/cciss/c0d0p1 Controller 0, disk 0, partition 1 +/dev/cciss/c0d0p2 Controller 0, disk 0, partition 2 +/dev/cciss/c0d0p3 Controller 0, disk 0, partition 3 + +/dev/cciss/c1d1 Controller 1, disk 1, whole device +/dev/cciss/c1d1p1 Controller 1, disk 1, partition 1 +/dev/cciss/c1d1p2 Controller 1, disk 1, partition 2 +/dev/cciss/c1d1p3 Controller 1, disk 1, partition 3 diff -u --recursive --new-file v2.4.0-test8/linux/Documentation/cpqarray.txt linux/Documentation/cpqarray.txt --- v2.4.0-test8/linux/Documentation/cpqarray.txt Fri Jul 28 12:50:51 2000 +++ linux/Documentation/cpqarray.txt Mon Sep 18 14:57:01 2000 @@ -17,6 +17,7 @@ * SA 4200 * SA 4250ES * SA 431 + * RAID LC2 Controller It should also work with some really old Disk array adapters, but I am unable to test against these cards: diff -u --recursive --new-file v2.4.0-test8/linux/Documentation/fb/sa1100fb.txt linux/Documentation/fb/sa1100fb.txt --- v2.4.0-test8/linux/Documentation/fb/sa1100fb.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/fb/sa1100fb.txt Mon Sep 18 15:15:24 2000 @@ -0,0 +1,39 @@ +[This file is cloned from VesaFB/matroxfb] + +What is sa1100fb? +================= + +This is a driver for a graphic framebuffer for the SA-1100 LCD +controller. + +Configuration +============== + +For most common passive displays, giving the option + +video=sa1100:bpp:,lccr0:,lccr1:,lccr2:,lccr3: + +on the kernel command line should be enough to configure the +controller. The bits per pixel (bpp) value should be 4, 8, 12, or +16. LCCR values are display-specific and should be computed as +documented in the SA-1100 Developer's Manual, Section 11.7. Dual-panel +displays are supported as long as the SDS bit is set in LCCR0; GPIO<9:2> +are used for the lower panel. + +For active displays or displays requiring additional configuration +(controlling backlights, powering on the LCD, etc.), the command line +options may not be enough to configure the display. Adding sections to +sa1100fb_init_fbinfo(), sa1100fb_activate_var(), +sa1100fb_disable_lcd_controller(), and sa1100fb_enable_lcd_controller() +will probably be necessary. + +Accepted options: + +bpp: Configure for bits per pixel +lccr0: Configure LCD control register 0 (11.7.3) +lccr1: Configure LCD control register 1 (11.7.4) +lccr2: Configure LCD control register 2 (11.7.5) +lccr3: Configure LCD control register 3 (11.7.6) + +-- +Mark Huang diff -u --recursive --new-file v2.4.0-test8/linux/Documentation/filesystems/ext2.txt linux/Documentation/filesystems/ext2.txt --- v2.4.0-test8/linux/Documentation/filesystems/ext2.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/filesystems/ext2.txt Sun Oct 1 20:21:20 2000 @@ -0,0 +1,224 @@ + +The Second Extended Filesystem +============================== + +ext2 was originally released in January 1993. Written by R\'emy Card, +Theodore Ts'o and Stephen Tweedie, it was a major rewrite of the +Extended Filesystem. It is currently (February 1999) the predominant +filesystem in use by Linux. There are also implementations available +for NetBSD, FreeBSD, the GNU HURD, Windows 95/98/NT, OS/2 and RISC OS. + +Options +======= + +When mounting an ext2 filesystem, the following options are accepted. +Defaults are marked with (*). + +bsddf (*) Makes `df' act like BSD. +minixdf Makes `df' act like Minix. + +check=none, nocheck Perform no checks upon the filesystem. +check=normal (*) Perform normal checks on the filesystem. +check=strict Perform extra checks on the filesystem. + +debug For developers only. + +errors=continue (*) Keep going on a filesystem error. +errors=remount-ro Remount the filesystem read-only on an error. +errors=panic Panic and halt the machine if an error occurs. + +grpid, bsdgroups Give objects the same group ID as their parent. +nogrpid, sysvgroups (*) New objects have the group ID of their creator. + +resuid=n The user which may use the reserved blocks. +resgid=n The group which may use the reserved blocks. + +sb=n Use alternate superblock at this location. + +grpquota,noquota,quota,usrquota Quota options are silently ignored by ext2. + + +Specification +============= + +ext2 shares many properties with traditional Unix filesystems. It has +the concepts of blocks, inodes and directories. It has space in the +specification for Access Control Lists (ACLs), fragments, undeletion and +compression though these are not yet implemented (some are available as +separate patches). There is also a versioning mechanism to allow new +features (such as journalling) to be added in a maximally compatible +manner. + +Blocks +------ + +The space in the device or file is split up into blocks. These are +a fixed size, of 1024, 2048 or 4096 bytes, which is decided when the +filesystem is created. Smaller blocks mean less wasted space per file, +but require slightly more accounting overhead. + +Blocks are clustered into block groups in order to reduce fragmentation +and minimise the amount of head seeking when reading a large amount of +consecutive data. Each block group has a descriptor and the array of +descriptors is stored immediately after the superblock. Two blocks at +the start of each group are reserved for the block usage bitmap and +the inode usage bitmap which show which blocks and inodes are used. +Since each bitmap fits in a block, this means that the maximum size of +a block group is 8 times the size of a block. + +The first (non-reserved) blocks in the block group are designated as +the inode table for the block and the remainder are the data blocks. +The block allocation algorithm attempts to allocate data blocks in the +same block group as the inode which contains them. + +The Superblock +-------------- + +The superblock contains all the information about the configuration of +the filing system. It is stored in block 1 of the filesystem (numbering +from 0) and it is essential to mounting it. Since it is so important, +backup copies of the superblock are stored in block groups throughout +the filesystem. The first revision of ext2 stores a copy at the start +of every block group. Later revisions can store a copy in only some +block groups to reduce the amount of redundancy on large filesystems. +The groups chosen are 0, 1 and powers of 3, 5 and 7. + +The information in the superblock contains fields such as how many +inodes and blocks are in the filesystem and how many are unused, how +many inodes and blocks are in a block group, when the filesystem was +mounted, when it was modified, what version of the filesystem it is +(see the Revisions section below) and which OS created it. + +If the revision of the filesystem is recent enough then there are extra +fields, such as a volume name, a unique identifier, the inode size, +support for compression, block preallocation and creating fewer backup +superblocks. + +All fields in the superblock (as in all other ext2 structures) are stored +on the disc in little endian format, so a filesystem is portable between +machines without having to know what machine it was created on. + +Inodes +------ + +The inode (index node) is the fundamental concept in the ext2 filesystem. +Each object in the filesystem is represented by an inode. The inode +structure contains pointers to the filesystem blocks which contain the +data held in the object and all of the metadata about an object except +its name. The metadata about an object includes the permissions, owner, +group, flags, size, number of blocks used, access time, change time, +modification time, deletion time, number of links, fragments, version +(for NFS) and ACLs. + +There are several reserved fields which are currently unused in the inode +structure and several which are overloaded. One field is used for the +directory ACL if the inode is a directory and for the top 32 bits of +the file size if the inode is a regular file. The translator field is +unused under Linux, but is used by the HURD to reference the inode of +a program which will be used to interpret this object. The HURD also +has larger permissions, owner and group fields, so it uses some of the +other unused by Linux fields to store the extra bits. + +There are pointers to the first 12 blocks which contain the file's data +in the inode. There is a pointer to an indirect block (which contains +pointers to the next set of blocks), a pointer to a doubly-indirect +block (which contains pointers to indirect blocks) and a pointer to a +trebly-indirect block (which contains pointers to doubly-indirect blocks). + +The flags field contains some ext2-specific flags which aren't catered +for by the standard chmod flags. These flags can be listed with +lsattr and changed with the chattr command. There are flags for secure +deletion, undeletable, compression, synchronous updates, immutability, +append-only, dumpable, no-atime, and btree directories. Not all of +these are supported yet. + +Directories +----------- + +A directory is a filesystem object and has an inode just like a file. +It is a specially formatted file containing records which associate +each name with an inode number. Later revisions of the filesystem also +encode the type of the object (file, directory, symlink, device, fifo, +socket) in the directory entry for speed. The current implementation +of ext2 uses a linked list in directories; a planned enhancement will +use btrees instead. The current implementation also never shrinks +directories once they have grown to accommodate more files. + +Special files +------------- + +Symbolic links are also filesystem objects with inodes. They deserve +special mention because the data for them is stored within the inode +itself if the symlink is less than 60 bytes long. It uses the fields +which would normally be used to store the pointers to blocks to store +the data. This is a worthwhile optimisation to make as it does not then +take up a block, and most symlinks are less than 60 characters long. + +Character and block special devices never have data blocks assigned to +them. Instead, their device number is stored in the inode, again reusing +the fields which would be used to point to the blocks. + +Revisions +--------- + +The revisioning mechanism used in ext2 is sophisticated. The revisioning +mechanism is not supported by version 0 (EXT2_GOOD_OLD_REV) of ext2 but +was introduced in version 1. There are three 32-bit fields, one for +compatible features, one for read-only compatible features and one for +incompatible features. + +Reserved Space +-------------- + +In ext2, there is a mechanism for reserving a certain number of blocks +for a particular user (normally the super-user). This is intended to +allow for the system to continue functioning even if a user fills up +all the available space. It also keeps the filesystem from filling up +entirely which helps combat fragmentation. + +Filesystem check +---------------- + +At boot time, most systems run a consistency check (e2fsck) on their +filesystems. The superblock of the ext2 filesystem contains several +fields which indicate whether fsck should actually run (since checking +the filesystem at boot can take a long time if it is large). fsck will +run if the filesystem was not unmounted without errors, if the maximum +mount count has been exceeded or if the maximum time between checks has +been exceeded. + +Metadata +-------- + +It is frequently claimed that the ext2 implementation of writing +asynchronous metadata is faster than the ffs synchronous metadata +scheme but less reliable. Both methods are equally resolvable by their +respective fsck programs. + +If you're exceptionally paranoid, there are 3 ways of making metadata +writes synchronous: + +per-file if you have the source: use the O_SYNC argument to open() +per-file if you don't have the source: use chattr +S +per-filesystem: mount -o sync + +the first and last are not ext2 specific but do force the metadata to +be written synchronously. + +References +========== + +The kernel source file:/usr/src/linux/fs/ext2/ +Design & Implementation http://khg.redhat.com/HyperNews/get/fs/ext2intro.html +Compression http://debs.fuller.edu/e2compr/ +ACL support ftp://tsx-11.mit.edu/pub/linux/ALPHA/ext2fs +updated ACL work http://aerobee.informatik.uni-bremen.de/acl_eng.html +e2fsprogs ftp://tsx-11.mit.edu/pub/linux/packages/ext2fs + +Implementations for: +OS/2 http://perso.wanadoo.fr/matthieu.willm/ext2-os2/ +Windows 95 http://www.yipton.demon.co.uk/ +Windows NT http://www.cyco.nl/~andreys/ext2fsnt/ + http://uranus.it.swin.edu.au/~jn/linux/Explore2fs.htm +DOS client ftp://metalab.unc.edu/pub/Linux/system/filesystems/ext2/ +RISC OS client ftp://ftp.barnet.ac.uk/pub/acorn/armlinux/iscafs/ diff -u --recursive --new-file v2.4.0-test8/linux/Documentation/filesystems/proc.txt linux/Documentation/filesystems/proc.txt --- v2.4.0-test8/linux/Documentation/filesystems/proc.txt Fri Jul 28 12:50:51 2000 +++ linux/Documentation/filesystems/proc.txt Mon Sep 18 14:57:02 2000 @@ -619,11 +619,6 @@ used ones is far behind, you've encountered a peak in your usage of file handles and you don't need to increase the maximum. -However, there is still a per process limit of open files, which unfortunately -can't be changed that easily. It is set to 1024 by default. To change this you -have to edit the files limits.h and fs.h in the kernel source tree. Finally, -change the definition of NR_OPEN and recompile the kernel. - inode-state, inode-nr and inode-max ----------------------------------- diff -u --recursive --new-file v2.4.0-test8/linux/Documentation/kbuild/00-INDEX linux/Documentation/kbuild/00-INDEX --- v2.4.0-test8/linux/Documentation/kbuild/00-INDEX Mon Feb 1 12:03:20 1999 +++ linux/Documentation/kbuild/00-INDEX Sun Sep 17 09:45:06 2000 @@ -6,3 +6,5 @@ - overview of kbuild commands config-language.txt - specification of Config Language, the language in Config.in files +makefiles.txt + - developer information for linux kernel makefiles diff -u --recursive --new-file v2.4.0-test8/linux/Documentation/kbuild/makefiles.txt linux/Documentation/kbuild/makefiles.txt --- v2.4.0-test8/linux/Documentation/kbuild/makefiles.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/kbuild/makefiles.txt Wed Sep 27 16:40:56 2000 @@ -0,0 +1,1226 @@ +Linux Kernel Makefiles +2000-September-14 +Michael Elizabeth Chastain, + + + +=== Table of Contents + +This document describes the Linux kernel Makefiles. + + 1 Overview + 2 Who does what + 3 Makefile language + 4 Variables passed down from the top + 5 The structure of an arch Makefile + 5.1 Architecture-specific variables + 5.2 Vmlinux build variables + 5.3 Post-vmlinux goals + 5.4 Mandatory arch-specific goals + 6 The structure of a subdirectory Makefile + 6.1 Comments + 6.2 Goal definitions + 6.3 Adapter section + 6.4 Rules.make section + 6.5 Special rules + 7 Rules.make variables + 7.1 Subdirectories + 7.2 Object file goals + 7.3 Library file goals + 7.4 Loadable module goals + 7.5 Multi-part modules + 7.6 Compilation flags + 7.7 Miscellaneous variables + 8 New-style variables + 9 Compatibility with Linux Kernel 2.2 + 10 Credits + + +=== 1 Overview + +The Makefiles have five parts: + + Makefile: the top Makefile. + .config: the kernel configuration file. + arch/*/Makefile: the arch Makefiles. + Subdirectory Makefiles: there are about 300 of these. + Rules.make: the common rules for all subdirectory Makefiles. + +The top Makefile reads the .config file, which comes from the +kernel configuration process. + +The top Makefile is responsible for building two major products: vmlinux +(the resident kernel image) and modules (any module files). It builds +these goals by recursively descending into the subdirectories of the +kernel source tree. The list of subdirectories which are visited depends +upon the kernel configuration. + +The top Makefile textually includes an arch Makefile with the name +arch/$(ARCH)/Makefile. The arch Makefile supplies architecture-specific +information to the top Makefile. + +Each subdirectory has a Makefile which carries out the commands passed +down from above. The subdirectory Makefile uses information from the +.config file to construct various file lists, and then it textually +includes the common rules in Rules.make. + +Rules.make defines rules which are common to all the subdirectory +Makefiles. It has a public interface in the form of certain variable +lists. It then declares rules based on those lists. + + + +=== 2 Who does what + +People have four different relationships with the kernel Makefiles. + +*Users* are people who build kernels. These people type commands such as +"make menuconfig" or "make bzImage". They usually do not read or edit +any kernel Makefiles (or any other source files). + +*Normal developers* are people who work on features such as device +drivers, file systems, and network protocols. These people need to +maintain the subdirectory Makefiles for the subsystem that they are +working on. In order to do this effectively, they need some overall +knowledge about the kernel Makefiles, plus detailed knowledge about the +public interface for Rules.make. + +*Arch developers* are people who work on an entire architecture, such +as sparc or ia64. Arch developers need to know about the arch Makefiles +as well as subdirectory Makefiles. + +*Kbuild developers* are people who work on the kernel build system itself. +These people need to know about all aspects of the kernel Makefiles. + +This document is aimed towards normal developers and arch developers. + + + +=== 3 Makefile language + +The kernel Makefiles are designed to run with Gnu Make. The Makefiles +use only the documented features of Gnu Make, but they do use many +Gnu extensions. + +Gnu Make supports elementary list-processing functions. The kernel +Makefiles use a novel style of list building and manipulation with few +"if" statements. + +Gnu Make has two assignment operators, ":=" and "=". ":=" performs +immediate evaluation of the right-hand side and stores an actual string +into the left-hand side. "=" is like a formula definition; it stores the +right-hand side in an unevaluated form and then evaluates this form each +time the left-hand side is used. + +There are some cases where "=" is appropriate. Usually, though, ":=" +is the right choice. + +All of the examples in this document were drawn from actual kernel +sources. The examples have been reformatted (white space changed, lines +split), but are otherwise exactly the same. + + + +=== 4 Variables passed down from the top + +The top Makefile exports the following variables: + + VERSION, PATCHLEVEL, SUBLEVEL, EXTRAVERSION + + These variables define the current kernel version. A few arch + Makefiles actually use these values directly; they should use + $(KERNELRELEASE) instead. + + $(VERSION), $(PATCHLEVEL), and $(SUBLEVEL) define the basic + three-part version number, such as "2", "4", and "0". These three + values are always numeric. + + $(EXTRAVERSION) defines an even tinier sublevel for pre-patches + or additional patches. It is usually some non-numeric string + such as "-pre4", and is often blank. + + KERNELRELEASE + + $(KERNELRELEASE) is a single string such as "2.4.0-pre4", suitable + for constructing installation directory names or showing in + version strings. Some arch Makefiles use it for this purpose. + + ARCH + + This variable defines the target architecture, such as "i386", + "arm", or "sparc". Many subdirectory Makefiles test $(ARCH) + to determine which files to compile. + + By default, the top Makefile sets $(ARCH) to be the same as the + host system system architecture. For a cross build, a user may + override the value of $(ARCH) on the command line: + + make ARCH=m68k ... + + TOPDIR, HPATH + + $(TOPDIR) is the path to the top of the kernel source tree. + Subdirectory Makefiles need this so that they can include + $(TOPDIR)/Rules.make. + + $(HPATH) is equal to $(TOPDIR)/include. A few arch Makefiles + need to use this to do special things using include files. + + SUBDIRS + + $(SUBDIRS) is a list of directories which the top Makefile + enters in order to build either vmlinux or modules. The actual + directories in $(SUBDIRS) depend on the kernel configuration. + The top Makefile defines this variable, and the arch Makefile + extends it. + + HEAD, CORE_FILES, NETWORKS, DRIVERS, LIBS + LINKFLAGS + + $(HEAD), $(CORE_FILES), $(NETWORKS), $(DRIVERS), and $(LIBS) + specify lists of object files and libraries to be linked into + vmlinux. + + The files in $(HEAD) are linked first in vmlinux. + + $(LINKFLAGS) specifies the flags to build vmlinux. + + The top Makefile and the arch Makefile jointly define these + variables. The top Makefile defines $(CORE_FILES), $(NETWORKS), + $(DRIVERS), and $(LIBS). The arch Makefile defines $(HEAD) + and $(LINKFLAGS), and extends $(CORE_FILES) and $(LIBS). + + Note: there are more names here than necessary. $(NETWORKS), + $(DRIVERS), and even $(LIBS) could be subsumed into $(CORE_FILES). + + CPP, CC, AS, LD, AR, NM, STRIP, OBJCOPY, OBJDUMP + CPPFLAGS, CFLAGS, CFLAGS_KERNEL, MODFLAGS, AFLAGS, LDFLAGS + PERL + GENKSYMS + + These variables specify the commands and flags that Rules.make + uses to build goal files from source files. + + $(CFLAGS_KERNEL) contains extra C compiler flags used to compile + resident kernel code. + + $(MODFLAGS) contains extra C compiler flags used to compile code + for loadable kernel modules. In the future, this flag may be + renamed to the more regular name $(CFLAGS_MODULE). + + $(AFLAGS) contains assembler flags. + + $(GENKSYMS) contains the command used to generate kernel symbol + signatures when CONFIG_MODVERSIONS is enabled. The genksyms + command comes from the modutils package. + + CROSS_COMPILE + + This variable is a prefix path for other variables such as $(CC), + $(AS), and $(LD). The arch Makefiles sometimes use and set this + variable explicitly. Subdirectory Makefiles don't need to worry + about it. + + The user may override $(CROSS_COMPILE) on the command line if + desired. + + HOSTCC, HOSTCFLAGS + + These variables define the C compiler and C compiler flags to + be used for compiling host side programs. These are separate + variables because the target architecture can be different from + the host architecture. + + If your Makefile compiles and runs a program that is executed + during the course of building the kernel, then it should use + $(HOSTCC) and $(HOSTCFLAGS). + + For example, the subdirectory drivers/pci has a helper program + named gen-devlist.c. This program reads a list of PCI ID's and + generates C code in the output files classlist.h and devlist.h. + + Suppose that a user has an i386 computer and wants to build a + kernel for an ia64 machine. Then the user would use an ia64 + cross-compiler for most of the compilation, but would use a + native i386 host compiler to compile drivers/pci/gen-devlist.c. + + For another example, kbuild helper programs such as + scripts/mkdep.c and scripts/lxdialog/*.c are compiled with + $(HOSTCC) rather than $(CC). + + ROOT_DEV, SVGA_MODE, RAMDISK + + End users edit these variables to specify certain information + about the configuration of their kernel. These variables + are ancient! They are also specific to the i386 architecture. + They really should be replaced with CONFIG_* options. + + MAKEBOOT + + This variable is defined and used only inside the main arch + Makefiles. The top Makefile should not export it. + + INSTALL_PATH + + This variable defines a place for the arch Makefiles to install + the resident kernel image and System.map file. + + INSTALL_MOD_PATH, MODLIB + + $(INSTALL_MOD_PATH) specifies a prefix to $(MODLIB) for module + installation. This variable is not defined in the Makefile but + may be passed in by the user if desired. + + $(MODLIB) specifies the directory for module installation. + The top Makefile defines $(MODLIB) to + $(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE). The user may + override this value on the command line if desired. + + CONFIG_SHELL + + This variable is private between Makefile and Rules.make. + Arch makefiles and subdirectory Makefiles should never use this. + + MODVERFILE + + An internal variable. This doesn't need to be exported, as it + is never used outside of the top Makefile. + + MAKE, MAKEFILES + + Some variables internal to Gnu Make. + + $(MAKEFILES) in particular is used to force the arch Makefiles + and subdirectory Makefiles to read $(TOPDIR)/.config without + including it explicitly. (This was an implementation hack and + could be fixed). + + + +=== 5 The structure of an arch Makefile + + + +--- 5.1 Architecture-specific variables + +The top Makefile includes one arch Makefile file, arch/$(ARCH)/Makefile. +This section describes the functions of the arch Makefile. + +An arch Makefile extends some of the top Makefile's variables with +architecture-specific values. + + SUBDIRS + + The top Makefile defines $(SUBDIRS). The arch Makefile extends + $(SUBDIRS) with a list of architecture-specific directories. + + Example: + + # arch/alpha/Makefile + + SUBDIRS := $(SUBDIRS) arch/alpha/kernel arch/alpha/mm \ + arch/alpha/lib arch/alpha/math-emu + + This list may depend on the configuration: + + # arch/arm/Makefile + + ifeq ($(CONFIG_ARCH_ACORN),y) + SUBDIRS += drivers/acorn + ... + endif + + CPP, CC, AS, LD, AR, NM, STRIP, OBJCOPY, OBJDUMP + CPPFLAGS, CFLAGS, CFLAGS_KERNEL, MODFLAGS, AFLAGS, LDFLAGS + + The top Makefile defines these variables, and the arch Makefile + extends them. + + Many arch Makefiles dynamically run the target C compiler to + probe what options it supports: + + # arch/i386/Makefile + + # only work around strength reduction bug(s) on older gcc versions + CFLAGS += $(shell if ! $(CC) -march=i486 -S -o /dev/null \ + -xc /dev/null >/dev/null 2>&1; \ + then echo "-fno-strength-reduce"; fi) + + # prevent gcc from keeping the stack 16 byte aligned + CFLAGS += $(shell if $(CC) -mpreferred-stack-boundary=2 \ + -S -o /dev/null -xc /dev/null >/dev/null 2>&1; \ + then echo "-mpreferred-stack-boundary=2"; fi) + + And, of course, $(CFLAGS) can depend on the configuration: + + # arch/i386/Makefile + + ifdef CONFIG_M386 + CFLAGS += $(shell if $(CC) -march=i386 -S -o /dev/null \ + -xc /dev/null >/dev/null 2>&1; \ + then echo "-march=i386"; else echo "-m386"; fi) + endif + + ifdef CONFIG_M486 + CFLAGS += $(shell if $(CC) -march=i486 -S -o /dev/null \ + -xc /dev/null >/dev/null 2>&1; \ + then echo "-march=i486"; else echo "-m486"; fi) + endif + + ifdef CONFIG_M586 + CFLAGS += $(shell if $(CC) -march=i586 -S -o /dev/null \ + -xc /dev/null >/dev/null 2>&1; \ + then echo "-march=i586"; fi) + endif + + Some arch Makefiles redefine the compilation commands in order + to add architecture-specific flags: + + # arch/s390/Makefile + + LD=$(CROSS_COMPILE)ld -m elf_s390 + OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S + + + +--- 5.2 Vmlinux build variables + +An arch Makefile co-operates with the top Makefile to define variables +which specify how to build the vmlinux file. Note that there is no +corresponding arch-specific section for modules; the module-building +machinery is all architecture-independent. + + HEAD, CORE_FILES, LIBS + LINKFLAGS + + The top Makefile defines the architecture-independent core of + thse variables, and the arch Makefile extends them. Note that the + arch Makefile defines (not just extends) $(HEAD) and $(LINKFLAGS). + + Example: + + # arch/m68k/Makefile + + ifndef CONFIG_SUN3 + LINKFLAGS = -T $(TOPDIR)/arch/m68k/vmlinux.lds + else + LINKFLAGS = -T $(TOPDIR)/arch/m68k/vmlinux-sun3.lds -N + endif + + ... + + ifndef CONFIG_SUN3 + HEAD := arch/m68k/kernel/head.o + else + HEAD := arch/m68k/kernel/sun3-head.o + endif + + SUBDIRS += arch/m68k/kernel arch/m68k/mm arch/m68k/lib + CORE_FILES := arch/m68k/kernel/kernel.o arch/m68k/mm/mm.o $(CORE_FILES) + LIBS += arch/m68k/lib/lib.a + + + +--- 5.3 Post-vmlinux goals + +An arch Makefile specifies goals that take the vmlinux file, compress +it, wrap it in bootstrapping code, and copy the resulting files somewhere. +This includes various kinds of installation commands. + +These post-vmlinux goals are not standardized across different +architectures. Here is a list of these goals and the architectures +that support each of them (as of kernel version 2.4.0-test6-pre5): + + balo mips + bootimage alpha + bootpfile alpha, ia64 + bzImage i386, m68k + bzdisk i386 + bzlilo i386 + compressed i386, m68k, mips, mips64, sh + dasdfmt s390 + Image arm + image s390 + install arm, i386 + lilo m68k + msb alpha, ia64 + my-special-boot alpha, ia64 + orionboot mips + rawboot alpha + silo s390 + srmboot alpha + tftpboot.img sparc, sparc64 + vmlinux.64 mips64 + vmlinux.aout sparc64 + zImage arm, i386, m68k, mips, mips64, ppc, sh + zImage.initrd ppc + zdisk i386, mips, mips64, sh + zinstall arm + zlilo i386 + znetboot.initrd ppc + + + +--- 5.4 Mandatory arch-specific goals + +An arch Makefile must define the following arch-specific goals. +These goals provide arch-specific actions for the corresponding goals +in the top Makefile: + + archclean clean + archdep dep + archmrproper mrproper + + + +=== 6 The structure of a subdirectory Makefile + +A subdirectory Makefile has five sections. + + + +--- 6.1 Comments + +The first section is a comment header. Just write what you would +write if you were editing a C source file, but use "# ..." instead of +"/* ... */". Historically, many anonymous people have edited kernel +Makefiles without leaving any change histories in the header; comments +from them would have been valuable. + + + +--- 6.2 Goal definitions + +The second section is a bunch of definitions that are the heart of the +subdirectory Makefile. These lines define the files to be built, any +special compilation options, and any subdirectories to be recursively +entered. The declarations in these lines depend heavily on the kernel +configuration variables (CONFIG_* symbols). + +In some Makefiles ("old-style Makefiles"), the second section looks +like this: + + # drivers/parport/Makefile + ifeq ($(CONFIG_PARPORT_PC),y) + LX_OBJS += parport_pc.o + else + ifeq ($(CONFIG_PARPORT_PC),m) + MX_OBJS += parport_pc.o + endif + endif + +In most Makefiles ("new-style Makefiles"), the second section looks +like this: + + # drivers/block/Makefile + obj-$(CONFIG_MAC_FLOPPY) += swim3.o + obj-$(CONFIG_BLK_DEV_FD) += floppy.o + obj-$(CONFIG_AMIGA_FLOPPY) += amiflop.o + obj-$(CONFIG_ATARI_FLOPPY) += ataflop.o + +The new-style Makefiles are more compact and easier to get correct +for certain features (such as CONFIG_* options that enable more than +one file). If you have a choice, please write a new-style Makefile. + + + +--- 6.3 Adapter section + +The third section is an adapter section. In old-style Makefiles, this +third section is not present. In new-style Makefiles, the third section +contains boilerplate code which converts from new-style variables to +old-style variables. This is because Rules.make processes only the +old-style variables. + + + +--- 6.4 Rules.make section + +The fourth section is the single line: + + include $(TOPDIR)/Rules.make + + + +--- 6.5 Special rules + +The fifth section contains any special Makefile rules needed that are +not available through the common rules in Rules.make. + + + +=== 7 Rules.make variables + +The public interface of Rules.make consists of the following variables: + + + +--- 7.1 Subdirectories + + ALL_SUB_DIRS, SUB_DIRS, MOD_IN_SUB_DIRS, MOD_SUB_DIRS + + $(ALL_SUB_DIRS) is an unconditional list of *all* the + subdirectories in a given directory. This list should not depend + on the kernel configuration. + + $(SUB_DIRS) is a list of subdirectories which may contribute code + to vmlinux. This list may depend on the kernel configuration. + + $(MOD_SUB_DIRS) and $(MOD_IN_SUB_DIRS) are lists of subdirectories + which may build kernel modules. Both names have exactly the + same meaning. (In version 2.2 and earlier kernels, these + variables had different meanings -- hence the different names). + + For new code, $(MOD_SUB_DIRS) is recommended and $(MOD_IN_SUB_DIRS) + is deprecated. + + Example: + + # fs/Makefile + ALL_SUB_DIRS = coda minix ext2 fat msdos vfat proc isofs nfs \ + umsdos ntfs hpfs sysv smbfs ncpfs ufs efs affs \ + romfs autofs hfs lockd nfsd nls devpts devfs \ + adfs partitions qnx4 udf bfs cramfs openpromfs \ + autofs4 ramfs jffs + SUB_DIRS := + + ... + + ifeq ($(CONFIG_EXT2_FS),y) + SUB_DIRS += ext2 + else + ifeq ($(CONFIG_EXT2_FS),m) + MOD_SUB_DIRS += ext2 + endif + endif + + ifeq ($(CONFIG_CRAMFS),y) + SUB_DIRS += cramfs + else + ifeq ($(CONFIG_CRAMFS),m) + MOD_SUB_DIRS += cramfs + endif + endif + + Example: + + # drivers/net/Makefile + SUB_DIRS := + MOD_SUB_DIRS := + MOD_IN_SUB_DIRS := + ALL_SUB_DIRS := $(SUB_DIRS) fc hamradio irda pcmcia tokenring \ + wan sk98lin arcnet skfp tulip appletalk + + ... + + ifeq ($(CONFIG_IRDA),y) + SUB_DIRS += irda + MOD_IN_SUB_DIRS += irda + else + ifeq ($(CONFIG_IRDA),m) + MOD_IN_SUB_DIRS += irda + endif + endif + + ifeq ($(CONFIG_TR),y) + SUB_DIRS += tokenring + MOD_IN_SUB_DIRS += tokenring + else + ifeq ($(CONFIG_TR),m) + MOD_IN_SUB_DIRS += tokenring + endif + endif + + + +--- 7.2 Object file goals + + O_TARGET, O_OBJS, OX_OBJS + + The subdirectory Makefile specifies object files for vmlinux in + the lists $(O_OBJS) and $(OX_OBJS). These lists depend on the + kernel configuration. + + The "X" in "OX_OBJS" stands for "eXport". Files in $(OX_OBJS) + may use the EXPORT_SYMBOL macro to define public symbols which + loadable kernel modules can see. Files in $(O_OBJS) may not use + EXPORT_SYMBOL (and you will get a funky error message if you try). + + [Yes, it's kludgy to do this by hand. Yes, you can define all + your objects as $(OX_OBJS) whether they define symbols or not; + but then you will notice a lot of extra compiles when you edit + any source file. Blame CONFIG_MODVERSIONS for this.] + + Rules.make compiles all the $(O_OBJS) and $(OX_OBJS) files. + It then calls "$(LD) -r" to merge these files into one .o file + with the name $(O_TARGET). This $(O_TARGET) name also appears + in the top Makefile. + + The order of files in $(O_OBJS) and $(OX_OBJS) is significant. + All $(OX_OBJS) files come first, in the order listed, followed by + all $(O_OBJS) files, in the order listed. Duplicates in the lists + are allowed: the first instance will be linked into $(O_TARGET) + and succeeding instances will be ignored. (Note: Rules.make may + emit warning messages for duplicates, but this is harmless). + + Example: + + # arch/alpha/kernel/Makefile + O_TARGET := kernel.o + O_OBJS := entry.o traps.o process.o osf_sys.o irq.o \ + irq_alpha.o signal.o setup.o ptrace.o time.o \ + semaphore.o + OX_OBJS := alpha_ksyms.o + + ifdef CONFIG_SMP + O_OBJS += smp.o irq_smp.o + endif + + ifdef CONFIG_PCI + O_OBJS += pci.o pci_iommu.o + endif + + Even if a subdirectory Makefile has an $(O_TARGET), the .config + options still control whether or not its $(O_TARGET) goes into + vmlinux. See the $(M_OBJS) example below. + + + +--- 7.3 Library file goals + + L_TARGET, L_OBJS, LX_OBJS + + These names are similar to the O_* names. Once again, $(L_OBJS) + and $(LX_OBJS) specify object files for the resident kernel; + once again, the lists depend on the current configuration; and + once again, the files that call EXPORT_SYMBOL go on the "X" list. + + The difference is that "L" stands for "Library". After making + $(L_OBJS) and $(LX_OBJS), Rules.make uses the "$(AR) rcs" command + to put these files into an archive file (a library) with the + name $(L_TARGET). This name also appears in the top Makefile. + + Example: + + # arch/i386/lib/Makefile + L_TARGET = lib.a + L_OBJS = checksum.o old-checksum.o delay.o \ + usercopy.o getuser.o putuser.o iodebug.o + + ifdef CONFIG_X86_USE_3DNOW + L_OBJS += mmx.o + endif + + ifdef CONFIG_HAVE_DEC_LOCK + L_OBJS += dec_and_lock.o + endif + + The order of files in $(L_OBJS) and $(LX_OBJS) is not significant. + Duplicates in the lists are allowed. (Note: Rules.make may emit + warning messages for duplicates, but this is harmless). + + A subdirectory Makefile can specify either an $(O_TARGET), + an $(L_TARGET), or both. Here is a discussion of the differences. + + All of the files in an $(O_TARGET) are guaranteed to appear in + the resident vmlinux image. In an $(L_TARGET), only the files + that satisfy undefined symbol references from other files will + appear in vmlinux. + + In a conventional link process, the linker processes some + object files and creates a list of unresolved external symbols. + The linker then looks in a set of libraries to resolve these + symbols. Indeed, the Linux kernel used to be linked this way, + with the bulk of the code stored in libraries. + + But vmlinux contains two types of object files that cannot be + fetched out of libraries this way: + + (1) object files that are purely EXPORT_SYMBOL definitions + (2) object files that use module_init or __initcall initializers + (instead of an initialization routine called externally) + + These files contain autonomous initializer sections which provide + code and data without being explicitly called. If these files + were stored in $(L_TARGET) libraries, the linker would fail + to include them in vmlinux. Thus, most subdirectory Makefiles + specify an $(O_TARGET) and do not use $(L_TARGET). + + Other considerations: $(O_TARGET) leads to faster re-link times + during development activity, but $(L_TARGET) gives better error + messages for unresolved symbols. + + + +--- 7.4 Loadable module goals + + M_OBJS, MX_OBJS + + $(M_OBJS) and $(MX_OBJS) specify object files which are built + as loadable kernel modules. As usual, the "X" in $(MX_OBJS) + stands for "eXport"; source files that use EXPORT_SYMBOL must + appear on an $(MX_OBJS) list. + + A module may be built from one source file or several source + files. In the case of one source file, the subdirectory + Makefile simply adds the file to either $(M_OBJS) or $(MX_OBJS), + as appropriate. + + Example: + + # drivers/net/irda/Makefile + ifeq ($(CONFIG_IRTTY_SIR),y) + L_OBJS += irtty.o + else + ifeq ($(CONFIG_IRTTY_SIR),m) + M_OBJS += irtty.o + endif + endif + + ifeq ($(CONFIG_IRPORT_SIR),y) + LX_OBJS += irport.o + else + ifeq ($(CONFIG_IRPORT_SIR),m) + MX_OBJS += irport.o + endif + endif + + If a kernel module is built from several source files, there + are two ways to specify the set of source files. One way is to + build a single module for the entire subdirectory. This way is + popular in the file system and network protocol stacks. + + Example: + + # fs/ext2/Makefile + O_TARGET := ext2.o + O_OBJS := acl.o balloc.o bitmap.o dir.o file.o fsync.o \ + ialloc.o inode.o ioctl.o namei.o super.o symlink.o \ + truncate.o + M_OBJS := $(O_TARGET) + + In this example, the module name will be ext2.o. Because this + file has the same name has $(O_TARGET), Rules.make will use + the $(O_TARGET) rule to build ext2.o: it will run "$(LD) -r" + on the list of $(O_OBJS) files. + + Note that this subdirectory Makefile defines both an $(O_TARGET) + and an $(M_OBJS). The control code, up in fs/Makefile, will + select between these two. If CONFIG_EXT2_FS=y, then fs/Makefile + will build $(O_TARGET); and if CONFIG_EXT_FS=m, then fs/Makefile + will build $(M_OBJS) instead. (Yes, this is a little delicate + and a little confusing). + + + +--- 7.5 Multi-part modules + + MI_OBJS, MIX_OBJS + + Some kernel modules are composed of several object files + linked together, but do not include every object file in their + subdirectory. $(MI_OBJS) and $(MIX_OBJS) are for this case. + + "M" stands for Module. + "I" stands for Intermediate. + "X", as usual, stands for "eXport symbol". + + Example: + + # drivers/sound/Makefile + gus-objs := gus_card.o gus_midi.o gus_vol.o gus_wave.o ics2101.o + pas2-objs := pas2_card.o pas2_midi.o pas2_mixer.o pas2_pcm.o + sb-objs := sb_card.o + + gus.o: $(gus-objs) + $(LD) -r -o $@ $(gus-objs) + + pas2.o: $(pas2-objs) + $(LD) -r -o $@ $(pas2-objs) + + sb.o: $(sb-objs) + $(LD) -r -o $@ $(sb-objs) + + The kernel modules gus.o, pas2.o, and sb.o are the *composite + files*. The object files gus_card.o, gus_midi.o, gus_vol.o, + gus_wave.o, ics2101.o, pas2_card.o, pas2_midi.o, pas2_mixer.o, + pas2_pcm.o, and sb_card.o are *component files*. The component + files are also called *intermediate files*. + + In another part of drivers/sound/Makefile (not shown), all of + the component files are split out. For the resident drivers: + the component object files go onto $(O_OBJS) and $(OX_OBJS) + lists, depending on whether they export symbols or not; and the + composite files are never built. For the kernel modules: the + component object files go onto $(MI_OBJS) and $(MIX_OBJS); + the composite files go onto $(M_OBJS). + + The subdirectory Makefile must also specify the linking rule + for a multi-object-file module: + + # drivers/sound/Makefile + + gus.o: $(gus-objs) + $(LD) -r -o $@ $(gus-objs) + + pas2.o: $(pas2-objs) + $(LD) -r -o $@ $(pas2-objs) + + sb.o: $(sb-objs) + $(LD) -r -o $@ $(sb-objs) + + + +--- 7.6 Compilation flags + + EXTRA_CFLAGS, EXTRA_AFLAGS, EXTRA_LDFLAGS, EXTRA_ARFLAGS + + $(EXTRA_CFLAGS) specifies options for compiling C files with + $(CC). The options in this variable apply to all $(CC) commands + for files in the current directory. + + Example: + + # drivers/sound/emu10k1/Makefile + EXTRA_CFLAGS += -I. + ifdef DEBUG + EXTRA_CFLAGS += -DEMU10K1_DEBUG + endif + + $(EXTRA_CFLAGS) does not apply to subdirectories of the current + directory. Also, it does not apply to files compiled with + $(HOSTCC). + + This variable is necessary because the top Makefile owns the + variable $(CFLAGS) and uses it for compilation flags for the + entire tree. + + $(EXTRA_AFLAGS) is a similar string for per-directory options + when compiling assembly language source. + + Example: at the time of writing, there were no examples of + $(EXTRA_AFLAGS) in the kernel corpus. + + $(EXTRA_LDFLAGS) and $(EXTRA_ARFLAGS) are similar strings for + per-directory options to $(LD) and $(AR). + + Example: at the time of writing, there were no examples of + $(EXTRA_LDFLAGS) or $(EXTRA_ARFLAGS) in the kernel corpus. + + CFLAGS_$@, AFLAGS_$@ + + $(CFLAGS_$@) specifies per-file options for $(CC). The $@ + part has a literal value which specifies the file that it's for. + + Example: + + # drivers/scsi/Makefile + CFLAGS_aha152x.o = -DAHA152X_STAT -DAUTOCONF + CFLAGS_gdth.o = # -DDEBUG_GDTH=2 -D__SERIAL__ -D__COM2__ \ + -DGDTH_STATISTICS + CFLAGS_seagate.o = -DARBITRATE -DPARITY -DSEAGATE_USE_ASM + + These three lines specify compilation flags for aha152x.o, + gdth.o, and seagate.o + + $(AFLAGS_$@) is a similar feature for source files in assembly + languages. + + Example: + + # arch/arm/kernel/Makefile + AFLAGS_head-armv.o := -DTEXTADDR=$(TEXTADDR) -traditional + AFLAGS_head-armo.o := -DTEXTADDR=$(TEXTADDR) -traditional + + Rules.make has a feature where an object file depends on the + value of $(CFLAGS_$@) that was used to compile it. (It also + depends on the values of $(CFLAGS) and $(EXTRA_CFLAGS)). Thus, + if you change the value of $(CFLAGS_$@) for a file, either by + editing the Makefile or overriding the value some other way, + Rules.make will do the right thing and re-compile your source + file with the new options. + + Note: because of a deficiency in Rules.make, assembly language + files do not have flag dependencies. If you edit $(AFLAGS_$@) + for such a file, you will have to remove the object file in order + to re-build from source. + + LD_RFLAG + + This variable is used, but never defined. It appears to be a + vestige of some abandoned experiment. + + + +--- 7.7 Miscellaneous variables + + IGNORE_FLAGS_OBJS + + $(IGNORE_FLAGS_OBJS) is a list of object files which will not have + their flag dependencies automatically tracked. This is a hackish + feature, used to kludge around a problem in the implementation + of flag dependencies. (The problem is that flag dependencies + assume that a %.o file is built from a matching %.S or %.c file. + This is sometimes not true). + + USE_STANDARD_AS_RULE + + This is a transition variable. If $(USE_STANDARD_AS_RULE) + is defined, then Rules.make will provide standard rules for + assembling %.S files into %.o files or %.s files (%.s files + are useful only to developers). + + If $(USE_STANDARD_AS_RULE) is not defined, then Rules.make + will not provide these standard rules. In this case, the + subdirectory Makefile must provide its own private rules for + assembling %.S files. + + In the past, all Makefiles provided private %.S rules. Newer + Makefiles should define USE_STANDARD_AS_RULE and use the standard + Rules.make rules. As soon as all the Makefiles across all + architectures have been converted to USE_STANDARD_AS_RULE, then + Rules.make can drop the conditional test on USE_STANDARD_AS_RULE. + After that, all the other Makefiles can drop the definition of + USE_STANDARD_AS_RULE. + + + +=== 8 New-style variables + +The "new-style variables" are simpler and more powerful than the +"old-style variables". As a result, many subdirectory Makefiles shrank +more than 60%. This author hopes that, in time, all arch Makefiles and +subdirectory Makefiles will convert to the new style. + +Rules.make does not understand new-style variables. Thus, each new-style +Makefile has a section of boilerplate code that converts the new-style +variables into old-style variables. There is also some mixing, where +people define most variables using "new style" but then fall back to +"old style" for a few lines. + + obj-y obj-m obj-n obj- + + These variables replace $(O_OBJS), $(OX_OBJS), $(M_OBJS), + and $(MX_OBJS). + + Example: + + # drivers/block/Makefile + obj-$(CONFIG_MAC_FLOPPY) += swim3.o + obj-$(CONFIG_BLK_DEV_FD) += floppy.o + obj-$(CONFIG_AMIGA_FLOPPY) += amiflop.o + obj-$(CONFIG_ATARI_FLOPPY) += ataflop.o + + Notice the use of $(CONFIG_...) substitutions on the left hand + side of an assignment operator. This gives Gnu Make the power + of associative indexing! Each of these assignments replaces + eight lines of code in an old-style Makefile. + + After executing all of the assignments, the subdirectory + Makefile has built up four lists: $(obj-y), $(obj-m), $(obj-n), + and $(obj-). + + $(obj-y) is a list of files to include in vmlinux. + $(obj-m) is a list of files to build as single-file modules. + $(obj-n) and $(obj-) are ignored. + + Each list may contain duplicates items; duplicates are + automatically removed later. Also, if a file appears in both + $(obj-y) and $(obj-m), it will automatically be removed from + the $(obj-m) list. + + Example: + + # drivers/net/Makefile + + ... + obj-$(CONFIG_OAKNET) += oaknet.o 8390.o + ... + obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o + ... + obj-$(CONFIG_STNIC) += stnic.o 8390.o + ... + obj-$(CONFIG_MAC8390) += daynaport.o 8390.o + ... + + In this example, four different drivers require the code in + 8390.o. If one or more of these four drivers are built into + vmlinux, then 8390.o will also be built into vmlinux, and will + *not* be built as a module -- even if another driver which needs + 8390.o is built as a module. (The modular driver is able to + use services of the 8390.o code in the resident vmlinux image). + + export-objs + + $(export-objs) is a list of all the files in the subdirectory + which potentially export symbols. The canonical way to construct + this list is: + + grep -l EXPORT_SYMBOL *.c + + (but watch out for sneaky files that call EXPORT_SYMBOL from an + included header file!) + + This is a potential list, independent of the kernel configuration. + All files that export symbols go into $(export-objs). The + boilerplate code then uses the $(export-objs) list to separate + the real file lists into $(*_OBJS) and $(*X_OBJS). + + Experience has shown that maintaining the proper X's in an + old-style Makefile is difficult and error-prone. Maintaining the + $(export-objs) list in a new-style Makefile is simpler and easier + to audit. + + list-multi + $(foo)-objs + + Some kernel modules are composed of multiple object files linked + together. $(list-multi) is a list of such kernel modules. + This is a static list; it does not depend on the configuration. + + For each kernel module in $(list-multi) there is another list + of all the object files which make up that module. For a kernel + module named foo.o, its object file list is foo-objs. + + Example: + + # drivers/scsi/Makefile + list-multi := scsi_mod.o sr_mod.o initio.o a100u2w.o + + ... + + scsi_mod-objs := hosts.o scsi.o scsi_ioctl.o constants.o \ + scsicam.o scsi_proc.o scsi_error.o \ + scsi_obsolete.o scsi_queue.o scsi_lib.o \ + scsi_merge.o scsi_dma.o scsi_scan.o \ + scsi_syms.o + sr_mod-objs := sr.o sr_ioctl.o sr_vendor.o + initio-objs := ini9100u.o i91uscsi.o + a100u2w-objs := inia100.o i60uscsi.o + + The subdirectory Makefile puts the modules onto obj-* lists in + the usual configuration-dependent way: + + obj-$(CONFIG_SCSI) += scsi_mod.o + obj-$(CONFIG_BLK_DEV_SR) += sr_mod.o + obj-$(CONFIG_SCSI_INITIO) += initio.o + obj-$(CONFIG_SCSI_INIA100) += a100u2w.o + + Suppose that CONFIG_SCSI=y. Then vmlinux needs to link in all + 14 components of scsi_mod.o, so these components will go onto + $(O_OBJS) and $(OX_OBJS). The composite file scsi_mod.o will + never be created. The boilerplate conversion code produces this + result with a few lines of list processing commands. + + Suppose that CONFIG_BLK_DEV_SR=m. Then the 3 components + of sr_mod.o will linked together with "$(LD) -r" to make the + kernel module sr_mod.o, so these 3 components need to go onto + the $(MI_OBJS) and $(MIX_OBJS) lists; the composite file sr_mod.o + goes onto $(M_OBJS). The boilerplate conversion code takes care + of this, too. + + And suppose CONFIG_SCSI_INITIO=n. Then initio.o goes onto the + $(obj-n) list and that's the end of it. Its component files + are not compiled, and the composite file is not created. + + Finally, the subdirectory Makefile needs to define rules to + build each multi-object kernel module from its component list. + Example: + + # drivers/scsi/Makefile + + scsi_mod.o: $(scsi_mod-objs) + $(LD) -r -o $@ $(scsi_mod-objs) + + sr_mod.o: $(sr_mod-objs) + $(LD) -r -o $@ $(sr_mod-objs) + + initio.o: $(initio-objs) + $(LD) -r -o $@ $(initio-objs) + + a100u2w.o: $(a100u2w-objs) + $(LD) -r -o $@ $(a100u2w-objs) + + These rules are very regular; it would be nice for the boilerplate + code or Rules.make to synthesize these rules automatically. + But until that happens, the subdirectory Makefile needs to define + these rules explicitly. + + subdir-y subdir-m subdir-n subdir- + + These variables replace $(ALL_SUB_DIRS), $(SUB_DIRS) and + $(MOD_SUB_DIRS). + + Example: + + # drivers/Makefile + subdir-$(CONFIG_PCI) += pci + subdir-$(CONFIG_PCMCIA) += pcmcia + subdir-$(CONFIG_MTD) += mtd + subdir-$(CONFIG_SBUS) += sbus + + These variables work similar to obj-*, but are used for + subdirectories instead of object files. + + After executing all of the assignments, the subdirectory + Makefile has built up four lists: $(subdir-y), $(subdir-m), + $(subdir-n), and $(subdir-). + + $(subdir-y) is a list of directories that should be entered + for making vmlinux. + $(subdir-m) is a list of directories that should be entered + for making modules. + $(subdir-n) and $(subdir-) are only used for collecting a list + of all subdirectories of this directory. + + Each list besides subdir-y may contain duplicates items; duplicates + are automatically removed later. + + mod-subdirs + + $(mod-subdirs) is a list of all the the subdirectories that should + be added to $(subdir-m), too if they appear in $(subdir-y) + + Example: + + # fs/Makefile + mod-subdirs := nls + + This means nls should be added to (subdir-y) and $(subdir-m) if + CONFIG_NFS = y. + + +=== 9 Compatibility with Linux Kernel 2.2 + +Most of the information in this document also applies to 2.2, although +there is no indication of which things have changed when. Here are some +hints for writing subdirectory Makefiles that are compatible with Linux +kernel 2.2. + +You can write either an old-style Makefile or a new-style Makefile +with a boilerplate adapter section. See the 2.2 version of +drivers/sound/Makefile for a copy of the boilerplate code. + +In 2.2, Rules.make makes a distinction between $(MOD_SUB_DIRS) +and $(MOD_IN_SUB_DIRS). If you have a single directory with no +subdirectories, this will not matter to you. If you have a whole +tree, then you need to know the difference between $(MOD_SUB_DIRS) +and $(MOD_IN_SUB_DIRS). For example code: $(MOD_SUB_DIRS) is used +extensively in fs/Makefile; $(MOD_IN_SUB_DIRS) is used extensively in +drivers/net/Makefile. + +If you are already using MOD_LIST_NAME, go ahead and keep using it. +If you don't already have a MOD_LIST_NAME, go ahead and keep not using +one; your module will be a 'misc' module in 2.2. + +Assembly language rules were a mess in 2.2. If you have assembly language +files, this author recommends that you write your own explicit rules +for each file by name. + + + +=== 10 Credits + +Thanks to the members of the linux-kbuild mailing list for reviewing +drafts of this document, with particular thanks to Peter Samuelson +and Thomas Molina. diff -u --recursive --new-file v2.4.0-test8/linux/Documentation/mkdev.cciss linux/Documentation/mkdev.cciss --- v2.4.0-test8/linux/Documentation/mkdev.cciss Wed Dec 31 16:00:00 1969 +++ linux/Documentation/mkdev.cciss Fri Sep 22 17:11:37 2000 @@ -0,0 +1,40 @@ +#!/bin/sh +# Script to create device nodes for SMART array controllers +# Usage: +# mkdev.cciss [num controllers] [num log volumes] [num partitions] +# +# With no arguments, the script assumes 1 controller, 16 logical volumes, +# and 16 partitions/volume, which is adequate for most configurations. +# +# If you had 5 controllers and were planning on no more than 4 logical volumes +# each, using a maximum of 8 partitions per volume, you could say: +# +# mkdev.cciss 5 4 8 +# +# Of course, this has no real benefit over "mkdev.cciss 5" except that it +# doesn't create so many device nodes in /dev/cciss. + +NR_CTLR=${1-1} +NR_VOL=${2-16} +NR_PART=${3-16} + +if [ ! -d /dev/cciss ]; then + mkdir -p /dev/cciss +fi + +C=0; while [ $C -lt $NR_CTLR ]; do + MAJ=`expr $C + 104` + D=0; while [ $D -lt $NR_VOL ]; do + P=0; while [ $P -lt $NR_PART ]; do + MIN=`expr $D \* 16 + $P` + if [ $P -eq 0 ]; then + mknod /dev/cciss/c${C}d${D} b $MAJ $MIN + else + mknod /dev/cciss/c${C}d${D}p${P} b $MAJ $MIN + fi + P=`expr $P + 1` + done + D=`expr $D + 1` + done + C=`expr $C + 1` +done diff -u --recursive --new-file v2.4.0-test8/linux/Documentation/networking/8139too.txt linux/Documentation/networking/8139too.txt --- v2.4.0-test8/linux/Documentation/networking/8139too.txt Fri Sep 8 12:37:34 2000 +++ linux/Documentation/networking/8139too.txt Sun Sep 17 09:41:28 2000 @@ -1,6 +1,6 @@ "8139too" Fast Ethernet driver for Linux - Improved support for RTL-8139 Fast Ethernet adapters + Improved support for RTL-8139 10/100 Fast Ethernet adapters Copyright 2000 Jeff Garzik @@ -8,6 +8,7 @@ Architectures supported (all PCI platforms): x86, Alpha AXP, PowerPC, Sparc64 + Kernel versions supported: 2.4.x @@ -130,6 +131,8 @@ And thanks to every supporter free software. +(see top of 8139too.c for further credits and kudos) + Submitting Bug Reports @@ -156,38 +159,50 @@ 1) Work with Donald to merge fixes and updates into his driver. -2) 2.2.x COMPATIBILITY SUPPORT IS BROKEN. DO NOT USE IT. -It is included only for enterprising hackers willing to help fix it. +2) ethtool support -3) PPC platform has stability problems. +3) PPC platform has stability problems. (XXX: verify this is still true) 4) Sparc64 platform not tested at all. -5) Identify and fix "rx wedge" when ping flooded. (WIP) - -7) N-Way auto-negotiation is known to fail in some cases. This problem -also occurs in the rtl8139 driver in kernels 2.2.x/2.3.x. Solution: -Following technique in sunhme and sunbmac, use a kernel timer to -manually perform autonegotiation in case the network or card cannot do -it automatically. (patches welcome) - 8) Much improved command line / module parameter setup. (patches and suggestions welcome) (WIP) 9) Better documentation. (patches welcome) -10) (rtl8139-diag modified from Becker version, DONE) -User-mode (or maybe optional /proc) diagnostics program. - 11) RTL8139C support untested. -12) 10base-T support flaky or slow +12) 10base-T support flaky or slow (todo: verify this is still true) Change History -------------- + +Version 0.9.10 - September 12, 2000 + +* Never wrap an Rx packet (faster Rx interrupt handling) +* Clear all TxAborted conditions (bug fix) +* Correct copyright +* More credits +* Update NWay doc URL +* Clean up commonly used ifdef switches +* Reorg info displayed at bootup/modprobe time +* Remove some unneeded spinlocks +* Misc cosmetic code cleanup +* Always print interrupt status for abnormal interrupts +* Use RealTek-recommended FIFO and DMA burst settings (1024 bytes) + + +Version 0.9.9 - September 9, 2000 + +* Fix oops-able bug in Rx ring wrap calculation (David Ford) +* Use PIO instead of MMIO when USE_IO_OPS is defined +* Move Rx error handling out of Rx interrupt handler, resulting in + tighter Rx interrupt processing + + Version 0.9.8 - September 7, 2000 * Propagate request_irq error value (andrew morton) diff -u --recursive --new-file v2.4.0-test8/linux/Documentation/networking/cs89x0.txt linux/Documentation/networking/cs89x0.txt --- v2.4.0-test8/linux/Documentation/networking/cs89x0.txt Fri Jul 28 12:50:51 2000 +++ linux/Documentation/networking/cs89x0.txt Mon Sep 18 14:58:17 2000 @@ -1,666 +1,688 @@ - -NOTE ----- - -This document was contributed by Cirrus Logic for kernel 2.2.5. This version -has been updated for 2.3.48 by Andrew Morton - -Cirrus make a copy of this driver available at their website, as -described below. In general, you should use the driver version which -comes with your Linux distribution. - - - -CIRRUS LOGIC LAN CS8900/CS8920 ETHERNET ADAPTERS -Linux Network Interface Driver ver. 2.00 -=============================================================================== - - -TABLE OF CONTENTS - -1.0 CIRRUS LOGIC LAN CS8900/CS8920 ETHERNET ADAPTERS - 1.1 Product Overview - 1.2 Driver Description - 1.2.1 Driver Name - 1.2.2 File in the Driver Package - 1.3 System Requirements - 1.4 Licensing Information - -2.0 ADAPTER INSTALLATION and CONFIGURATION - 2.1 CS8900-based Adapter Configuration - 2.2 CS8920-based Adapter Configuration - -3.0 LOADING THE DRIVER AS A MODULE - -4.0 COMPILING THE DRIVER - 4.1 Compiling the Driver as a Loadable Module - 4.2 Compiling the driver to support memory mode - 4.3 Compiling the driver to support Rx DMA - 4.4 Compiling the Driver into the Kernel - -5.0 TESTING AND TROUBLESHOOTING - 5.1 Known Defects and Limitations - 5.2 Testing the Adapter - 5.2.1 Diagnostic Self-Test - 5.2.2 Diagnostic Network Test - 5.3 Using the Adapter's LEDs - 5.4 Resolving I/O Conflicts - -6.0 TECHNICAL SUPPORT - 6.1 Contacting Cirrus Logic's Technical Support - 6.2 Information Required Before Contacting Technical Support - 6.3 Obtaining the Latest Driver Version - 6.4 Current maintainer - - - -1.0 CIRRUS LOGIC LAN CS8900/CS8920 ETHERNET ADAPTERS -=============================================================================== - - -1.1 PRODUCT OVERVIEW - -The CS8900-based ISA Ethernet Adapters from Cirrus Logic follow -IEEE 802.3 standards and support half or full-duplex operation in ISA bus -computers on 10 Mbps Ethernet networks. The adapters are designed for operation -in 16-bit ISA or EISA bus expansion slots and are available in -10BaseT-only or 3-media configurations (10BaseT, 10Base2, and AUI for 10Base-5 -or fiber networks). - -CS8920-based adapters are similar to the CS8900-based adapter with additional -features for Plug and Play (PnP) support and Wakeup Frame recognition. As -such, the configuration procedures differ somewhat between the two types of -adapters. Refer to the "Adapter Configuration" section for details on -configuring both types of adapters. - - -1.2 DRIVER DESCRIPTION - -The CS8900/CS8920 Ethernet Adapter driver for Linux supports the Linux -v2.3.48 or greater kernel. It can be compiled directly into the kernel -or loaded at run-time as a device driver module. - -1.2.1 Driver Name: cs89x0 - -1.2.2 Files in the Driver Archive: - -The files in the driver at Cirrus' website include: - - readme.txt - this file - build - batch file to compile cs89x0.c. - cs89x0.c - driver C code - cs89x0.h - driver header file - cs89x0.o - pre-compiled module (for v2.2.5 kernel) - config/Config.in - sample file to include cs89x0 driver in the kernel. - config/Makefile - sample file to include cs89x0 driver in the kernel. - config/Space.c - sample file to include cs89x0 driver in the kernel. - - - -1.3 SYSTEM REQUIREMENTS - -The following hardware is required: - - * Cirrus Logic LAN (CS8900/20-based) Ethernet ISA Adapter - - * IBM or IBM-compatible PC with: - * An 80386 or higher processor - * 16 bytes of contiguous IO space available between 210h - 370h - * One available IRQ (5,10,11,or 12 for the CS8900, 3-7,9-15 for CS8920). - - * Appropriate cable (and connector for AUI, 10BASE-2) for your network - topology. - -The following software is required: - -* LINUX kernel version 2.3.48 or higher - - * CS8900/20 Setup Utility (DOS-based) - - * LINUX kernel sources for your kernel (if compiling into kernel) - - * GNU Toolkit (gcc and make) v2.6 or above (if compiling into kernel - or a module) - - - -1.4 LICENSING INFORMATION - -This program is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free Software -Foundation, version 1. - -This program is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -more details. - -For a full copy of the GNU General Public License, write to the Free Software -Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - - -2.0 ADAPTER INSTALLATION and CONFIGURATION -=============================================================================== - -Both the CS8900 and CS8920-based adapters can be configured using parameters -stored in an on-board EEPROM. You must use the DOS-based CS8900/20 Setup -Utility if you want to change the adapter's configuration in EEPROM. - -When loading the driver as a module, you can specify many of the adapter's -configuration parameters on the command-line to override the EEPROM's settings -or for interface configuration when an EEPROM is not used. (CS8920-based -adapters must use an EEPROM.) See Section 3.0 LOADING THE DRIVER AS A MODULE. - -Since the CS8900/20 Setup Utility is a DOS-based application, you must install -and configure the adapter in a DOS-based system using the CS8900/20 Setup -Utility before installation in the target LINUX system. (Not required if -installing a CS8900-based adapter and the default configuration is acceptable.) - - -2.1 CS8900-BASED ADAPTER CONFIGURATION - -CS8900-based adapters shipped from Cirrus Logic have been configured -with the following "default" settings: - - Operation Mode: Memory Mode - IRQ: 10 - Base I/O Address: 300 - Memory Base Address: D0000 - Optimization: DOS Client - Transmission Mode: Half-duplex - BootProm: None - Media Type: Autodetect (3-media cards) or - 10BASE-T (10BASE-T only adapter) - -You should only change the default configuration settings if conflicts with -another adapter exists. To change the adapter's configuration, run the -CS8900/20 Setup Utility. - - -2.2 CS8920-BASED ADAPTER CONFIGURATION - -CS8920-based adapters are shipped from Cirrus Logic configured as Plug -and Play (PnP) enabled. However, since the cs89x0 driver does NOT -support PnP, you must install the CS8920 adapter in a DOS-based PC and -run the CS8900/20 Setup Utility to disable PnP and configure the -adapter before installation in the target Linux system. Failure to do -this will leave the adapter inactive and the driver will be unable to -communicate with the adapter. - - - **************************************************************** - * CS8920-BASED ADAPTERS: * - * * - * CS8920-BASED ADAPTERS ARE PLUG and PLAY ENABLED BY DEFAULT. * - * THE CS89X0 DRIVER DOES NOT SUPPORT PnP. THEREFORE, YOU MUST * - * RUN THE CS8900/20 SETUP UTILITY TO DISABLE PnP SUPPORT AND * - * TO ACTIVATE THE ADAPTER. * - **************************************************************** - - - - -3.0 LOADING THE DRIVER AS A MODULE -=============================================================================== - -If the driver is compiled as a loadable module, you can load the driver module -with the 'modprobe' command. Many of the adapter's configuration parameters can -be specified as command-line arguments to the load command. This facility -provides a means to override the EEPROM's settings or for interface -configuration when an EEPROM is not used. - -Example: - - insmod cs89x0.o io=0x200 irq=0xA media=aui - -This example loads the module and configures the adapter to use an IO port base -address of 200h, interrupt 10, and use the AUI media connection. The following -configuration options are available on the command line: - -* io=### - specify IO address (200h-360h) -* irq=## - specify interrupt level -* use_dma=1 - Enable DMA -* dma=# - specify dma channel (Driver is compiled to support - Rx DMA only) -* dmasize=# (16 or 64) - DMA size 16K or 64K. Default value is set to 16. -* media=rj45 - specify media type - or media=bnc - or media=aui - or medai=auto -* duplex=full - specify forced half/full/autonegotiate duplex - or duplex=half - or duplex=auto -* debug=# - debug level (only available if the driver was compiled - for debugging) - -NOTES: - -a) If an EEPROM is present, any specified command-line parameter - will override the corresponding configuration value stored in - EEPROM. - -b) The "io" parameter must be specified on the command-line. - -c) In case you can not re-load the driver because Linux system - returns the "device or resource busy" message, try to re-load it by - increment the IO port address by one. The driver will write - commands to the IO base addresses to reset the data port pointer. - You can specify an I/O address with an address value one greater - than the configured address. Example, to scan for an adapter - located at IO base 0x300, specify an IO address of 0x301. - -d) The "duplex=auto" parameter is only supported for the CS8920. - -e) The minimum command-line configuration required if an EEPROM is - not present is: - - io - irq - media type (no autodetect) - -f) The following additional parameters are CS89XX defaults (values - used with no EEPROM or command-line argument). - - * DMA Burst = enabled - * IOCHRDY Enabled = enabled - * UseSA = enabled - * CS8900 defaults to half-duplex if not specified on command-line - * CS8920 defaults to autoneg if not specified on command-line - * Use reset defaults for other config parameters - * dma_mode = 0 - -g) You can use ifconfig to set the adapter's Ethernet address. - -h) Many Linux distributions use the 'modprobe' command to load - modules. This program uses the '/etc/conf.modules' file to - determine configuration information which is passed to a driver - module when it is loaded. All the configuration options which are - described above may be placed within /etc/conf.modules. - - For example: - - > cat /etc/conf.modules - ... - alias eth0 cs89x0 - options cs89x0 io=0x0200 dma=5 use_dma=1 - ... - - In this example we are telling the module system that the - ethernet driver for this machine should use the cs89x0 driver. We - are asking 'modprobe' to pass the 'io', 'dma' and 'use_dma' - arguments to the driver when it is loaded. - -i) Cirrus recommend that the cs89x0 use the ISA DMA channels 5, 6 or - 7. You will probably find that other DMA channels will not work. - -j) The cs89x0 supports DMA for receiving only. DMA mode is - significantly more efficient. Flooding a 400 MHz Celeron machine - with large ping packets consumes 82% of its CPU capacity in non-DMA - mode. With DMA this is reduced to 45%. - -k) If your Linux kernel was compiled with inbuilt plug-and-play - support you will be able to find information about the cs89x0 card - with the command - - cat /proc/isapnp - -l) If during DMA operation you find erratic behavior or network data - corruption you should use your PC's BIOS to slow the EISA bus clock. - - -4.0 COMPILING THE DRIVER -=============================================================================== - -The cs89x0 driver can be compiled directly into the kernel or compiled into -a loadable device driver module. - - -4.1 COMPILING THE DRIVER AS A LOADABLE MODULE - -To compile the driver into a loadable module, use the following command -(single command line, without quotes): - -"gcc -D__KERNEL__ -I/usr/src/linux/include -I/usr/src/linux/net/inet -Wall --Wstrict-prototypes -O2 -fomit-frame-pointer -DMODULE -DCONFIG_MODVERSIONS --c cs89x0.c" - -4.2 COMPILING THE DRIVER TO SUPPORT MEMORY MODE - -Support for memory mode was not carried over into the 2.3 series kernels. - -4.3 COMPILING THE DRIVER TO SUPPORT Rx DMA - -The compile-time optionality for DMA was removed in the 2.3 kernel -series. DMA support is now unconditionally part of the driver. It is -enabled by the 'use_dma=1' module option. - -4.4 COMPILING THE DRIVER INTO THE KERNEL - -If your Linux distribution already has support for the cs89x0 driver -then simply copy the source file to the /usr/src/linux/drivers/net -directory to replace the original ones and run the make utility to -rebuild the kernel. See Step 3 for rebuilding the kernel. - -If your Linux does not include the cs89x0 driver, you need to edit three -configuration files, copy the source file to the /usr/src/linux/drivers/net -directory, and then run the make utility to rebuild the kernel. - -1. Edit the following configuration files by adding the statements as -indicated. (When possible, try to locate the added text to the section of the -file containing similar statements). - - -a.) In /usr/src/linux/drivers/net/Config.in, add: - -tristate 'CS89x0 support' CONFIG_CS89x0 - -Example: - - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate 'ICL EtherTeam 16i/32 support' CONFIG_ETH16I - fi - - tristate 'CS89x0 support' CONFIG_CS89x0 - - tristate 'NE2000/NE1000 support' CONFIG_NE2000 - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate 'NI5210 support' CONFIG_NI52 - - -b.) In /usr/src/linux/drivers/net/Makefile, add the following lines: - -ifeq ($(CONFIG_CS89x0),y) -L_OBJS += cs89x0.o -else - ifeq ($(CONFIG_CS89x0),m) - M_OBJS += cs89x0.o - endif -endif - - -c.) In /linux/drivers/net/Space.c file, add the line: - -extern int cs89x0_probe(struct device *dev); - - -Example: - - extern int ultra_probe(struct device *dev); - extern int wd_probe(struct device *dev); - extern int el2_probe(struct device *dev); - - extern int cs89x0_probe(struct device *dev); - - extern int ne_probe(struct device *dev); - extern int hp_probe(struct device *dev); - extern int hp_plus_probe(struct device *dev); - - -Also add: - - #ifdef CONFIG_CS89x0 - { cs89x0_probe,0 }, - #endif - - -2.) Copy the driver source files (cs89x0.c and cs89x0.h) -into the /usr/src/linux/drivers/net directory. - - -3.) Go to /usr/src/linux directory and run 'make config' followed by 'make dep' -and finally 'make' (or make bzImage) to rebuild the kernel. - -4.) Use the DOS 'setup' utility to disable plug and play on the NIC. - - -5.0 TESTING AND TROUBLESHOOTING -=============================================================================== - -5.1 KNOWN DEFECTS and LIMITATIONS - -Refer to the RELEASE.TXT file distributed as part of this archive for a list of -known defects, driver limitations, and work arounds. - - -5.2 TESTING THE ADAPTER - -Once the adapter has been installed and configured, the diagnostic option of -the CS8900/20 Setup Utility can be used to test the functionality of the -adapter and its network connection. Use the diagnostics 'Self Test' option to -test the functionality of the adapter with the hardware configuration you have -assigned. You can use the diagnostics 'Network Test' to test the ability of the -adapter to communicate across the Ethernet with another PC equipped with a -CS8900/20-based adapter card (it must also be running the CS8900/20 Setup -Utility). - - NOTE: The Setup Utility's diagnostics are designed to run in a - DOS-only operating system environment. DO NOT run the diagnostics - from a DOS or command prompt session under Windows 95, Windows NT, - OS/2, or other operating system. - -To run the diagnostics tests on the CS8900/20 adapter: - - 1.) Boot DOS on the PC and start the CS8900/20 Setup Utility. - - 2.) The adapter's current configuration is displayed. Hit the ENTER key to - get to the main menu. - - 4.) Select 'Diagnostics' (ALT-G) from the main menu. - * Select 'Self-Test' to test the adapter's basic functionality. - * Select 'Network Test' to test the network connection and cabling. - - -5.2.1 DIAGNOSTIC SELF-TEST - -The diagnostic self-test checks the adapter's basic functionality as well as -its ability to communicate across the ISA bus based on the system resources -assigned during hardware configuration. The following tests are performed: - - * IO Register Read/Write Test - The IO Register Read/Write test insures that the CS8900/20 can be - accessed in IO mode, and that the IO base address is correct. - - * Shared Memory Test - The Shared Memory test insures the CS8900/20 can be accessed in memory - mode and that the range of memory addresses assigned does not conflict - with other devices in the system. - - * Interrupt Test - The Interrupt test insures there are no conflicts with the assigned IRQ - signal. - - * EEPROM Test - The EEPROM test insures the EEPROM can be read. - - * Chip RAM Test - The Chip RAM test insures the 4K of memory internal to the CS8900/20 is - working properly. - - * Internal Loop-back Test - The Internal Loop Back test insures the adapter's transmitter and - receiver are operating properly. If this test fails, make sure the - adapter's cable is connected to the network (check for LED activity for - example). - - * Boot PROM Test - The Boot PROM test insures the Boot PROM is present, and can be read. - Failure indicates the Boot PROM was not successfully read due to a - hardware problem or due to a conflicts on the Boot PROM address - assignment. (Test only applies if the adapter is configured to use the - Boot PROM option.) - -Failure of a test item indicates a possible system resource conflict with -another device on the ISA bus. In this case, you should use the Manual Setup -option to reconfigure the adapter by selecting a different value for the system -resource that failed. - - -5.2.2 DIAGNOSTIC NETWORK TEST - -The Diagnostic Network Test verifies a working network connection by -transferring data between two CS8900/20 adapters installed in different PCs -on the same network. (Note: the diagnostic network test should not be run -between two nodes across a router.) - -This test requires that each of the two PCs have a CS8900/20-based adapter -installed and have the CS8900/20 Setup Utility running. The first PC is -configured as a Responder and the other PC is configured as an Initiator. -Once the Initiator is started, it sends data frames to the Responder which -returns the frames to the Initiator. - -The total number of frames received and transmitted are displayed on the -Initiator's display, along with a count of the number of frames received and -transmitted OK or in error. The test can be terminated anytime by the user at -either PC. - -To setup the Diagnostic Network Test: - - 1.) Select a PC with a CS8900/20-based adapter and a known working network - connection to act as the Responder. Run the CS8900/20 Setup Utility - and select 'Diagnostics -> Network Test -> Responder' from the main - menu. Hit ENTER to start the Responder. - - 2.) Return to the PC with the CS8900/20-based adapter you want to test and - start the CS8900/20 Setup Utility. - - 3.) From the main menu, Select 'Diagnostic -> Network Test -> Initiator'. - Hit ENTER to start the test. - -You may stop the test on the Initiator at any time while allowing the Responder -to continue running. In this manner, you can move to additional PCs and test -them by starting the Initiator on another PC without having to stop/start the -Responder. - - - -5.3 USING THE ADAPTER'S LEDs - -The 2 and 3-media adapters have two LEDs visible on the back end of the board -located near the 10Base-T connector. - -Link Integrity LED: A "steady" ON of the green LED indicates a valid 10Base-T -connection. (Only applies to 10Base-T. The green LED has no significance for -a 10Base-2 or AUI connection.) - -TX/RX LED: The yellow LED lights briefly each time the adapter transmits or -receives data. (The yellow LED will appear to "flicker" on a typical network.) - - -5.4 RESOLVING I/O CONFLICTS - -An IO conflict occurs when two or more adapter use the same ISA resource (IO -address, memory address or IRQ). You can usually detect an IO conflict in one -of four ways after installing and or configuring the CS8900/20-based adapter: - - 1.) The system does not boot properly (or at all). - - 2.) The driver can not communicate with the adapter, reporting an "Adapter - not found" error message. - - 3.) You cannot connect to the network or the driver will not load. - - 4.) If you have configured the adapter to run in memory mode but the driver - reports it is using IO mode when loading, this is an indication of a - memory address conflict. - -If an IO conflict occurs, run the CS8900/20 Setup Utility and perform a -diagnostic self-test. Normally, the ISA resource in conflict will fail the -self-test. If so, reconfigure the adapter selecting another choice for the -resource in conflict. Run the diagnostics again to check for further IO -conflicts. - -In some cases, such as when the PC will not boot, it may be necessary to remove -the adapter and reconfigure it by installing it in another PC to run the -CS8900/20 Setup Utility. Once reinstalled in the target system, run the -diagnostics self-test to ensure the new configuration is free of conflicts -before loading the driver again. - -When manually configuring the adapter, keep in mind the typical ISA system -resource usage as indicated in the tables below. - -I/O Address Device IRQ Device ------------ -------- --- -------- - 200-20F Game I/O adapter 3 COM2, Bus Mouse - 230-23F Bus Mouse 4 COM1 - 270-27F LPT3: third parallel port 5 LPT2 - 2F0-2FF COM2: second serial port 6 Floppy Disk controller - 320-32F Fixed disk controller 7 LPT1 - 8 Real-time Clock - 9 EGA/VGA display adapter - 12 Mouse (PS/2) -Memory Address Device 13 Math Coprocessor --------------- --------------------- 14 Hard Disk controller -A000-BFFF EGA Graphics Adpater -A000-C7FF VGA Graphics Adpater -B000-BFFF Mono Graphics Adapter -B800-BFFF Color Graphics Adapter -E000-FFFF AT BIOS - - - - -6.0 TECHNICAL SUPPORT -=============================================================================== - -6.1 CONTACTING CIRRUS LOGIC'S TECHNICAL SUPPORT - -Cirrus Logic's CS89XX Technical Application Support can be reached at: - -Telephone :(800) 888-5016 (from inside U.S. and Canada) - :(512) 442-7555 (from outside the U.S. and Canada) -Fax :(512) 912-3871 -Email :ethernet@crystal.cirrus.com -WWW :http://www.cirrus.com - - -6.2 INFORMATION REQUIRED BEFORE CONTACTING TECHNICAL SUPPORT - -Before contacting Cirrus Logic for technical support, be prepared to provide as -Much of the following information as possible. - -1.) Adapter type (CRD8900, CDB8900, CDB8920, etc.) - -2.) Adapter configuration - - * IO Base, Memory Base, IO or memory mode enabled, IRQ, DMA channel - * Plug and Play enabled/disabled (CS8920-based adapters only) - * Configured for media auto-detect or specific media type (which type). - -3.) PC System's Configuration - - * Plug and Play system (yes/no) - * BIOS (make and version) - * System make and model - * CPU (type and speed) - * System RAM - * SCSI Adapter - -4.) Software - - * CS89XX driver and version - * Your network operating system and version - * Your system's OS version - * Version of all protocol support files - -5.) Any Error Message displayed. - - - -6.3 OBTAINING THE LATEST DRIVER VERSION - -You can obtain the latest CS89XX drivers and support software from Cirrus Logic's -Web site. You can also contact Cirrus Logic's Technical Support (email: -ethernet@crystal.cirrus.com) and request that you be registered for automatic -software-update notification. - -Cirrus Logic maintains a web page at http://www.cirrus.com with the -the latest drivers and technical publications. - - -6.4 Current maintainer - -In February 2000 the maintenance of this driver was assumed by Andrew -Morton - - + +NOTE +---- + +This document was contributed by Cirrus Logic for kernel 2.2.5. This version +has been updated for 2.3.48 by Andrew Morton + +Cirrus make a copy of this driver available at their website, as +described below. In general, you should use the driver version which +comes with your Linux distribution. + + + +CIRRUS LOGIC LAN CS8900/CS8920 ETHERNET ADAPTERS +Linux Network Interface Driver ver. 2.00 +=============================================================================== + + +TABLE OF CONTENTS + +1.0 CIRRUS LOGIC LAN CS8900/CS8920 ETHERNET ADAPTERS + 1.1 Product Overview + 1.2 Driver Description + 1.2.1 Driver Name + 1.2.2 File in the Driver Package + 1.3 System Requirements + 1.4 Licensing Information + +2.0 ADAPTER INSTALLATION and CONFIGURATION + 2.1 CS8900-based Adapter Configuration + 2.2 CS8920-based Adapter Configuration + +3.0 LOADING THE DRIVER AS A MODULE + +4.0 COMPILING THE DRIVER + 4.1 Compiling the Driver as a Loadable Module + 4.2 Compiling the driver to support memory mode + 4.3 Compiling the driver to support Rx DMA + 4.4 Compiling the Driver into the Kernel + +5.0 TESTING AND TROUBLESHOOTING + 5.1 Known Defects and Limitations + 5.2 Testing the Adapter + 5.2.1 Diagnostic Self-Test + 5.2.2 Diagnostic Network Test + 5.3 Using the Adapter's LEDs + 5.4 Resolving I/O Conflicts + +6.0 TECHNICAL SUPPORT + 6.1 Contacting Cirrus Logic's Technical Support + 6.2 Information Required Before Contacting Technical Support + 6.3 Obtaining the Latest Driver Version + 6.4 Current maintainer + + + +1.0 CIRRUS LOGIC LAN CS8900/CS8920 ETHERNET ADAPTERS +=============================================================================== + + +1.1 PRODUCT OVERVIEW + +The CS8900-based ISA Ethernet Adapters from Cirrus Logic follow +IEEE 802.3 standards and support half or full-duplex operation in ISA bus +computers on 10 Mbps Ethernet networks. The adapters are designed for operation +in 16-bit ISA or EISA bus expansion slots and are available in +10BaseT-only or 3-media configurations (10BaseT, 10Base2, and AUI for 10Base-5 +or fiber networks). + +CS8920-based adapters are similar to the CS8900-based adapter with additional +features for Plug and Play (PnP) support and Wakeup Frame recognition. As +such, the configuration procedures differ somewhat between the two types of +adapters. Refer to the "Adapter Configuration" section for details on +configuring both types of adapters. + + +1.2 DRIVER DESCRIPTION + +The CS8900/CS8920 Ethernet Adapter driver for Linux supports the Linux +v2.3.48 or greater kernel. It can be compiled directly into the kernel +or loaded at run-time as a device driver module. + +1.2.1 Driver Name: cs89x0 + +1.2.2 Files in the Driver Archive: + +The files in the driver at Cirrus' website include: + + readme.txt - this file + build - batch file to compile cs89x0.c. + cs89x0.c - driver C code + cs89x0.h - driver header file + cs89x0.o - pre-compiled module (for v2.2.5 kernel) + config/Config.in - sample file to include cs89x0 driver in the kernel. + config/Makefile - sample file to include cs89x0 driver in the kernel. + config/Space.c - sample file to include cs89x0 driver in the kernel. + + + +1.3 SYSTEM REQUIREMENTS + +The following hardware is required: + + * Cirrus Logic LAN (CS8900/20-based) Ethernet ISA Adapter + + * IBM or IBM-compatible PC with: + * An 80386 or higher processor + * 16 bytes of contiguous IO space available between 210h - 370h + * One available IRQ (5,10,11,or 12 for the CS8900, 3-7,9-15 for CS8920). + + * Appropriate cable (and connector for AUI, 10BASE-2) for your network + topology. + +The following software is required: + +* LINUX kernel version 2.3.48 or higher + + * CS8900/20 Setup Utility (DOS-based) + + * LINUX kernel sources for your kernel (if compiling into kernel) + + * GNU Toolkit (gcc and make) v2.6 or above (if compiling into kernel + or a module) + + + +1.4 LICENSING INFORMATION + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation, version 1. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +more details. + +For a full copy of the GNU General Public License, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + + +2.0 ADAPTER INSTALLATION and CONFIGURATION +=============================================================================== + +Both the CS8900 and CS8920-based adapters can be configured using parameters +stored in an on-board EEPROM. You must use the DOS-based CS8900/20 Setup +Utility if you want to change the adapter's configuration in EEPROM. + +When loading the driver as a module, you can specify many of the adapter's +configuration parameters on the command-line to override the EEPROM's settings +or for interface configuration when an EEPROM is not used. (CS8920-based +adapters must use an EEPROM.) See Section 3.0 LOADING THE DRIVER AS A MODULE. + +Since the CS8900/20 Setup Utility is a DOS-based application, you must install +and configure the adapter in a DOS-based system using the CS8900/20 Setup +Utility before installation in the target LINUX system. (Not required if +installing a CS8900-based adapter and the default configuration is acceptable.) + + +2.1 CS8900-BASED ADAPTER CONFIGURATION + +CS8900-based adapters shipped from Cirrus Logic have been configured +with the following "default" settings: + + Operation Mode: Memory Mode + IRQ: 10 + Base I/O Address: 300 + Memory Base Address: D0000 + Optimization: DOS Client + Transmission Mode: Half-duplex + BootProm: None + Media Type: Autodetect (3-media cards) or + 10BASE-T (10BASE-T only adapter) + +You should only change the default configuration settings if conflicts with +another adapter exists. To change the adapter's configuration, run the +CS8900/20 Setup Utility. + + +2.2 CS8920-BASED ADAPTER CONFIGURATION + +CS8920-based adapters are shipped from Cirrus Logic configured as Plug +and Play (PnP) enabled. However, since the cs89x0 driver does NOT +support PnP, you must install the CS8920 adapter in a DOS-based PC and +run the CS8900/20 Setup Utility to disable PnP and configure the +adapter before installation in the target Linux system. Failure to do +this will leave the adapter inactive and the driver will be unable to +communicate with the adapter. + + + **************************************************************** + * CS8920-BASED ADAPTERS: * + * * + * CS8920-BASED ADAPTERS ARE PLUG and PLAY ENABLED BY DEFAULT. * + * THE CS89X0 DRIVER DOES NOT SUPPORT PnP. THEREFORE, YOU MUST * + * RUN THE CS8900/20 SETUP UTILITY TO DISABLE PnP SUPPORT AND * + * TO ACTIVATE THE ADAPTER. * + **************************************************************** + + + + +3.0 LOADING THE DRIVER AS A MODULE +=============================================================================== + +If the driver is compiled as a loadable module, you can load the driver module +with the 'modprobe' command. Many of the adapter's configuration parameters can +be specified as command-line arguments to the load command. This facility +provides a means to override the EEPROM's settings or for interface +configuration when an EEPROM is not used. + +Example: + + insmod cs89x0.o io=0x200 irq=0xA media=aui + +This example loads the module and configures the adapter to use an IO port base +address of 200h, interrupt 10, and use the AUI media connection. The following +configuration options are available on the command line: + +* io=### - specify IO address (200h-360h) +* irq=## - specify interrupt level +* use_dma=1 - Enable DMA +* dma=# - specify dma channel (Driver is compiled to support + Rx DMA only) +* dmasize=# (16 or 64) - DMA size 16K or 64K. Default value is set to 16. +* media=rj45 - specify media type + or media=bnc + or media=aui + or medai=auto +* duplex=full - specify forced half/full/autonegotiate duplex + or duplex=half + or duplex=auto +* debug=# - debug level (only available if the driver was compiled + for debugging) + +NOTES: + +a) If an EEPROM is present, any specified command-line parameter + will override the corresponding configuration value stored in + EEPROM. + +b) The "io" parameter must be specified on the command-line. + +c) In case you can not re-load the driver because Linux system + returns the "device or resource busy" message, try to re-load it by + increment the IO port address by one. The driver will write + commands to the IO base addresses to reset the data port pointer. + You can specify an I/O address with an address value one greater + than the configured address. Example, to scan for an adapter + located at IO base 0x300, specify an IO address of 0x301. + +d) The "duplex=auto" parameter is only supported for the CS8920. + +e) The minimum command-line configuration required if an EEPROM is + not present is: + + io + irq + media type (no autodetect) + +f) The following additional parameters are CS89XX defaults (values + used with no EEPROM or command-line argument). + + * DMA Burst = enabled + * IOCHRDY Enabled = enabled + * UseSA = enabled + * CS8900 defaults to half-duplex if not specified on command-line + * CS8920 defaults to autoneg if not specified on command-line + * Use reset defaults for other config parameters + * dma_mode = 0 + +g) You can use ifconfig to set the adapter's Ethernet address. + +h) Many Linux distributions use the 'modprobe' command to load + modules. This program uses the '/etc/conf.modules' file to + determine configuration information which is passed to a driver + module when it is loaded. All the configuration options which are + described above may be placed within /etc/conf.modules. + + For example: + + > cat /etc/conf.modules + ... + alias eth0 cs89x0 + options cs89x0 io=0x0200 dma=5 use_dma=1 + ... + + In this example we are telling the module system that the + ethernet driver for this machine should use the cs89x0 driver. We + are asking 'modprobe' to pass the 'io', 'dma' and 'use_dma' + arguments to the driver when it is loaded. + +i) Cirrus recommend that the cs89x0 use the ISA DMA channels 5, 6 or + 7. You will probably find that other DMA channels will not work. + +j) The cs89x0 supports DMA for receiving only. DMA mode is + significantly more efficient. Flooding a 400 MHz Celeron machine + with large ping packets consumes 82% of its CPU capacity in non-DMA + mode. With DMA this is reduced to 45%. + +k) If your Linux kernel was compiled with inbuilt plug-and-play + support you will be able to find information about the cs89x0 card + with the command + + cat /proc/isapnp + +l) If during DMA operation you find erratic behavior or network data + corruption you should use your PC's BIOS to slow the EISA bus clock. + +m) If the cs89x0 driver is compiled directly into the kernel + (non-modular) then its I/O address is automatically determined by + ISA bus probing. The IRQ number, media options, etc are determined + from the card's EEPROM. + +n) If the cs89x0 driver is compiled directly into the kernel, DMA + mode may be selected by providing the kernel with a boot option + 'cs89x0_dma=N' where 'N' is the desired DMA channel number (5, 6 or 7). + + Kernel boot options may be provided on the LILO command line: + + LILO boot: linux cs89x0_dma=5 + + or they may be placed in /etc/lilo.conf: + + image=/boot/bzImage-2.3.48 + append="cs89x0_dma=5" + label=linux + root=/dev/hda5 + read-only + + The DMA Rx buffer size is hardwired to 16 kbytes in this mode. + (64k mode is not available). + + +4.0 COMPILING THE DRIVER +=============================================================================== + +The cs89x0 driver can be compiled directly into the kernel or compiled into +a loadable device driver module. + + +4.1 COMPILING THE DRIVER AS A LOADABLE MODULE + +To compile the driver into a loadable module, use the following command +(single command line, without quotes): + +"gcc -D__KERNEL__ -I/usr/src/linux/include -I/usr/src/linux/net/inet -Wall +-Wstrict-prototypes -O2 -fomit-frame-pointer -DMODULE -DCONFIG_MODVERSIONS +-c cs89x0.c" + +4.2 COMPILING THE DRIVER TO SUPPORT MEMORY MODE + +Support for memory mode was not carried over into the 2.3 series kernels. + +4.3 COMPILING THE DRIVER TO SUPPORT Rx DMA + +The compile-time optionality for DMA was removed in the 2.3 kernel +series. DMA support is now unconditionally part of the driver. It is +enabled by the 'use_dma=1' module option. + +4.4 COMPILING THE DRIVER INTO THE KERNEL + +If your Linux distribution already has support for the cs89x0 driver +then simply copy the source file to the /usr/src/linux/drivers/net +directory to replace the original ones and run the make utility to +rebuild the kernel. See Step 3 for rebuilding the kernel. + +If your Linux does not include the cs89x0 driver, you need to edit three +configuration files, copy the source file to the /usr/src/linux/drivers/net +directory, and then run the make utility to rebuild the kernel. + +1. Edit the following configuration files by adding the statements as +indicated. (When possible, try to locate the added text to the section of the +file containing similar statements). + + +a.) In /usr/src/linux/drivers/net/Config.in, add: + +tristate 'CS89x0 support' CONFIG_CS89x0 + +Example: + + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'ICL EtherTeam 16i/32 support' CONFIG_ETH16I + fi + + tristate 'CS89x0 support' CONFIG_CS89x0 + + tristate 'NE2000/NE1000 support' CONFIG_NE2000 + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'NI5210 support' CONFIG_NI52 + + +b.) In /usr/src/linux/drivers/net/Makefile, add the following lines: + +ifeq ($(CONFIG_CS89x0),y) +L_OBJS += cs89x0.o +else + ifeq ($(CONFIG_CS89x0),m) + M_OBJS += cs89x0.o + endif +endif + + +c.) In /linux/drivers/net/Space.c file, add the line: + +extern int cs89x0_probe(struct device *dev); + + +Example: + + extern int ultra_probe(struct device *dev); + extern int wd_probe(struct device *dev); + extern int el2_probe(struct device *dev); + + extern int cs89x0_probe(struct device *dev); + + extern int ne_probe(struct device *dev); + extern int hp_probe(struct device *dev); + extern int hp_plus_probe(struct device *dev); + + +Also add: + + #ifdef CONFIG_CS89x0 + { cs89x0_probe,0 }, + #endif + + +2.) Copy the driver source files (cs89x0.c and cs89x0.h) +into the /usr/src/linux/drivers/net directory. + + +3.) Go to /usr/src/linux directory and run 'make config' followed by 'make dep' +and finally 'make' (or make bzImage) to rebuild the kernel. + +4.) Use the DOS 'setup' utility to disable plug and play on the NIC. + + +5.0 TESTING AND TROUBLESHOOTING +=============================================================================== + +5.1 KNOWN DEFECTS and LIMITATIONS + +Refer to the RELEASE.TXT file distributed as part of this archive for a list of +known defects, driver limitations, and work arounds. + + +5.2 TESTING THE ADAPTER + +Once the adapter has been installed and configured, the diagnostic option of +the CS8900/20 Setup Utility can be used to test the functionality of the +adapter and its network connection. Use the diagnostics 'Self Test' option to +test the functionality of the adapter with the hardware configuration you have +assigned. You can use the diagnostics 'Network Test' to test the ability of the +adapter to communicate across the Ethernet with another PC equipped with a +CS8900/20-based adapter card (it must also be running the CS8900/20 Setup +Utility). + + NOTE: The Setup Utility's diagnostics are designed to run in a + DOS-only operating system environment. DO NOT run the diagnostics + from a DOS or command prompt session under Windows 95, Windows NT, + OS/2, or other operating system. + +To run the diagnostics tests on the CS8900/20 adapter: + + 1.) Boot DOS on the PC and start the CS8900/20 Setup Utility. + + 2.) The adapter's current configuration is displayed. Hit the ENTER key to + get to the main menu. + + 4.) Select 'Diagnostics' (ALT-G) from the main menu. + * Select 'Self-Test' to test the adapter's basic functionality. + * Select 'Network Test' to test the network connection and cabling. + + +5.2.1 DIAGNOSTIC SELF-TEST + +The diagnostic self-test checks the adapter's basic functionality as well as +its ability to communicate across the ISA bus based on the system resources +assigned during hardware configuration. The following tests are performed: + + * IO Register Read/Write Test + The IO Register Read/Write test insures that the CS8900/20 can be + accessed in IO mode, and that the IO base address is correct. + + * Shared Memory Test + The Shared Memory test insures the CS8900/20 can be accessed in memory + mode and that the range of memory addresses assigned does not conflict + with other devices in the system. + + * Interrupt Test + The Interrupt test insures there are no conflicts with the assigned IRQ + signal. + + * EEPROM Test + The EEPROM test insures the EEPROM can be read. + + * Chip RAM Test + The Chip RAM test insures the 4K of memory internal to the CS8900/20 is + working properly. + + * Internal Loop-back Test + The Internal Loop Back test insures the adapter's transmitter and + receiver are operating properly. If this test fails, make sure the + adapter's cable is connected to the network (check for LED activity for + example). + + * Boot PROM Test + The Boot PROM test insures the Boot PROM is present, and can be read. + Failure indicates the Boot PROM was not successfully read due to a + hardware problem or due to a conflicts on the Boot PROM address + assignment. (Test only applies if the adapter is configured to use the + Boot PROM option.) + +Failure of a test item indicates a possible system resource conflict with +another device on the ISA bus. In this case, you should use the Manual Setup +option to reconfigure the adapter by selecting a different value for the system +resource that failed. + + +5.2.2 DIAGNOSTIC NETWORK TEST + +The Diagnostic Network Test verifies a working network connection by +transferring data between two CS8900/20 adapters installed in different PCs +on the same network. (Note: the diagnostic network test should not be run +between two nodes across a router.) + +This test requires that each of the two PCs have a CS8900/20-based adapter +installed and have the CS8900/20 Setup Utility running. The first PC is +configured as a Responder and the other PC is configured as an Initiator. +Once the Initiator is started, it sends data frames to the Responder which +returns the frames to the Initiator. + +The total number of frames received and transmitted are displayed on the +Initiator's display, along with a count of the number of frames received and +transmitted OK or in error. The test can be terminated anytime by the user at +either PC. + +To setup the Diagnostic Network Test: + + 1.) Select a PC with a CS8900/20-based adapter and a known working network + connection to act as the Responder. Run the CS8900/20 Setup Utility + and select 'Diagnostics -> Network Test -> Responder' from the main + menu. Hit ENTER to start the Responder. + + 2.) Return to the PC with the CS8900/20-based adapter you want to test and + start the CS8900/20 Setup Utility. + + 3.) From the main menu, Select 'Diagnostic -> Network Test -> Initiator'. + Hit ENTER to start the test. + +You may stop the test on the Initiator at any time while allowing the Responder +to continue running. In this manner, you can move to additional PCs and test +them by starting the Initiator on another PC without having to stop/start the +Responder. + + + +5.3 USING THE ADAPTER'S LEDs + +The 2 and 3-media adapters have two LEDs visible on the back end of the board +located near the 10Base-T connector. + +Link Integrity LED: A "steady" ON of the green LED indicates a valid 10Base-T +connection. (Only applies to 10Base-T. The green LED has no significance for +a 10Base-2 or AUI connection.) + +TX/RX LED: The yellow LED lights briefly each time the adapter transmits or +receives data. (The yellow LED will appear to "flicker" on a typical network.) + + +5.4 RESOLVING I/O CONFLICTS + +An IO conflict occurs when two or more adapter use the same ISA resource (IO +address, memory address or IRQ). You can usually detect an IO conflict in one +of four ways after installing and or configuring the CS8900/20-based adapter: + + 1.) The system does not boot properly (or at all). + + 2.) The driver can not communicate with the adapter, reporting an "Adapter + not found" error message. + + 3.) You cannot connect to the network or the driver will not load. + + 4.) If you have configured the adapter to run in memory mode but the driver + reports it is using IO mode when loading, this is an indication of a + memory address conflict. + +If an IO conflict occurs, run the CS8900/20 Setup Utility and perform a +diagnostic self-test. Normally, the ISA resource in conflict will fail the +self-test. If so, reconfigure the adapter selecting another choice for the +resource in conflict. Run the diagnostics again to check for further IO +conflicts. + +In some cases, such as when the PC will not boot, it may be necessary to remove +the adapter and reconfigure it by installing it in another PC to run the +CS8900/20 Setup Utility. Once reinstalled in the target system, run the +diagnostics self-test to ensure the new configuration is free of conflicts +before loading the driver again. + +When manually configuring the adapter, keep in mind the typical ISA system +resource usage as indicated in the tables below. + +I/O Address Device IRQ Device +----------- -------- --- -------- + 200-20F Game I/O adapter 3 COM2, Bus Mouse + 230-23F Bus Mouse 4 COM1 + 270-27F LPT3: third parallel port 5 LPT2 + 2F0-2FF COM2: second serial port 6 Floppy Disk controller + 320-32F Fixed disk controller 7 LPT1 + 8 Real-time Clock + 9 EGA/VGA display adapter + 12 Mouse (PS/2) +Memory Address Device 13 Math Coprocessor +-------------- --------------------- 14 Hard Disk controller +A000-BFFF EGA Graphics Adpater +A000-C7FF VGA Graphics Adpater +B000-BFFF Mono Graphics Adapter +B800-BFFF Color Graphics Adapter +E000-FFFF AT BIOS + + + + +6.0 TECHNICAL SUPPORT +=============================================================================== + +6.1 CONTACTING CIRRUS LOGIC'S TECHNICAL SUPPORT + +Cirrus Logic's CS89XX Technical Application Support can be reached at: + +Telephone :(800) 888-5016 (from inside U.S. and Canada) + :(512) 442-7555 (from outside the U.S. and Canada) +Fax :(512) 912-3871 +Email :ethernet@crystal.cirrus.com +WWW :http://www.cirrus.com + + +6.2 INFORMATION REQUIRED BEFORE CONTACTING TECHNICAL SUPPORT + +Before contacting Cirrus Logic for technical support, be prepared to provide as +Much of the following information as possible. + +1.) Adapter type (CRD8900, CDB8900, CDB8920, etc.) + +2.) Adapter configuration + + * IO Base, Memory Base, IO or memory mode enabled, IRQ, DMA channel + * Plug and Play enabled/disabled (CS8920-based adapters only) + * Configured for media auto-detect or specific media type (which type). + +3.) PC System's Configuration + + * Plug and Play system (yes/no) + * BIOS (make and version) + * System make and model + * CPU (type and speed) + * System RAM + * SCSI Adapter + +4.) Software + + * CS89XX driver and version + * Your network operating system and version + * Your system's OS version + * Version of all protocol support files + +5.) Any Error Message displayed. + + + +6.3 OBTAINING THE LATEST DRIVER VERSION + +You can obtain the latest CS89XX drivers and support software from Cirrus Logic's +Web site. You can also contact Cirrus Logic's Technical Support (email: +ethernet@crystal.cirrus.com) and request that you be registered for automatic +software-update notification. + +Cirrus Logic maintains a web page at http://www.cirrus.com with the +the latest drivers and technical publications. + + +6.4 Current maintainer + +In February 2000 the maintenance of this driver was assumed by Andrew +Morton diff -u --recursive --new-file v2.4.0-test8/linux/Documentation/networking/sk98lin.txt linux/Documentation/networking/sk98lin.txt --- v2.4.0-test8/linux/Documentation/networking/sk98lin.txt Fri Jul 28 12:50:52 2000 +++ linux/Documentation/networking/sk98lin.txt Fri Sep 15 14:34:19 2000 @@ -1,9 +1,9 @@ -(C)Copyright 1999 SysKonnect. +(C)Copyright 1999-2000 SysKonnect. =========================================================================== -sk98lin.txt created 11-Nov-1999 +sk98lin.txt created 12-Sept-2000 -Readme File for sk98lin.o v3.04 +Readme File for sk98lin.o v3.05 SK-NET Gigabit Ethernet Adapter SK-98xx Driver for Linux This file contains @@ -372,6 +372,12 @@ (8) HISTORY =========== + +VERSION 3.05 (In-Kernel version) +Problems fixed: +- Failed for multiple adapters in kernel 2.4.0 +New features: +- New versions of several common modules VERSION 3.04 (In-Kernel version) Problems fixed: diff -u --recursive --new-file v2.4.0-test8/linux/Documentation/networking/tuntap.txt linux/Documentation/networking/tuntap.txt --- v2.4.0-test8/linux/Documentation/networking/tuntap.txt Wed Aug 23 09:30:13 2000 +++ linux/Documentation/networking/tuntap.txt Fri Sep 22 15:19:30 2000 @@ -25,29 +25,24 @@ br_sigio.c - bridge based on async io and SIGIO signal. However the best example is VTun http://vtun.sourceforge.net :)) -2. Installation - Run './configure' to configure the driver. - - Run 'make install' to compile and install driver module and to create - /dev/net/tun device node. - -3. Loading driver module - Linux - To load TUN/TAP driver module run: - modprobe tun - To configure automatic loading of the 'tun' module you have to add: - alias char-major-195 tun - to the /etc/conf.modules, and run: +2. Configuration + Create device node: + mknod /dev/net/tun c 10 200 + + Driver module autoloading + Make sure that "Kernel module loader" - module auto-loading support is enabled + in your kernel. + + Add following line to the /etc/modules.conf: + alias char-major-10-200 tun + + Run: modprobe -a - TUN/TAP driver will be automatically loaded when application access - /dev/net/tun. - If "Kernel module loader" - module auto-loading support is not enabled - in your kernel then you can add - modprobe tun - to one of the startup rc files. -4. Program interface - 4.1 Network device allocation: + Driver will be automatically loaded when application access /dev/net/tun. + +3. Program interface + 3.1 Network device allocation: int tun_alloc(char *dev) { @@ -76,7 +71,7 @@ return fd; } - 4.2 Frame format: + 3.2 Frame format: If flag IFF_NO_PI is not set each frame format is: Flags [2 bytes] Proto [2 bytes] @@ -120,7 +115,7 @@ 4. What is TUN/TAP driver used for? As mentioned above, main purpose of TUN/TAP driver is tunneling. -It used by VTun (http://vtun.netpedia.net). +It is used by VTun (http://vtun.sourceforge.net). 5. How does Virtual network device actually work ? Virtual network device can be viewed as a simple Point-to-Point or @@ -146,5 +141,3 @@ 8. Does TAP driver support kernel Ethernet bridging? Yes. Linux and FreeBSD drivers support Ethernet bridging. - - diff -u --recursive --new-file v2.4.0-test8/linux/Documentation/networking/vortex.txt linux/Documentation/networking/vortex.txt --- v2.4.0-test8/linux/Documentation/networking/vortex.txt Mon Aug 21 08:57:35 2000 +++ linux/Documentation/networking/vortex.txt Fri Sep 15 16:28:25 2000 @@ -166,8 +166,9 @@ Sets the time duration (in milliseconds) after which the kernel decides that the transmitter has become stuck and needs to be reset. - This is mainly for debugging purposes. The default value is 400 (0.4 - seconds). + This is mainly for debugging purposes, although it may be advantageous + to increase this value on LANs which have very high collision rates. + The default value is 400 (0.4 seconds). Additional resources -------------------- diff -u --recursive --new-file v2.4.0-test8/linux/Documentation/oops-tracing.txt linux/Documentation/oops-tracing.txt --- v2.4.0-test8/linux/Documentation/oops-tracing.txt Mon Aug 21 08:57:35 2000 +++ linux/Documentation/oops-tracing.txt Tue Oct 3 09:24:41 2000 @@ -1,7 +1,8 @@ Quick Summary ------------- -Install ksymoops from ftp://ftp.ocs.com.au/pub/ksymoops +Install ksymoops from +ftp://ftp..kernel.org/pub/linux/utils/kernel/ksymoops Read the ksymoops man page. ksymoops < the_oops.txt diff -u --recursive --new-file v2.4.0-test8/linux/Documentation/pci.txt linux/Documentation/pci.txt --- v2.4.0-test8/linux/Documentation/pci.txt Mon May 15 12:13:10 2000 +++ linux/Documentation/pci.txt Sun Sep 17 09:45:06 2000 @@ -188,6 +188,11 @@ list. pci_module_init() Inline helper function for ensuring correct pci_driver initialization and error handling. +pci_resource_start() Returns bus start address for a given PCI region +pci_resource_end() Returns bus end address for a given PCI region +pci_resource_len() Returns the byte length of a PCI region +pci_set_drvdata() Set private driver data pointer for a pci_dev +pci_get_drvdata() Return private driver data pointer for a pci_dev 7. Miscellaneous hints diff -u --recursive --new-file v2.4.0-test8/linux/Documentation/sound/AD1816 linux/Documentation/sound/AD1816 --- v2.4.0-test8/linux/Documentation/sound/AD1816 Mon May 10 13:00:10 1999 +++ linux/Documentation/sound/AD1816 Wed Sep 27 13:53:52 2000 @@ -1,52 +1,15 @@ Documentation for the AD1816(A) sound driver ============================================ -NOTE: This driver is still EXPERIMENTAL, so don't use it on production -systems! - - Installation: ------------- -To get your AD1816(A) based sound card work, you'll have to enable -module support ("Enable loadable module support") and support for -experimental code ("Prompt for development and/or incomplete -code/drivers") during kernel configuration. Enable "Sound card -support", "OSS modules support" and "Support for AD1816(A) based cards -(EXPERIMENTAL)" in the sound configuration menu, too. Be sure, that -you build "Support for AD1816(A) based cards (EXPERIMENTAL)" as a MODULE, -otherwise you may run into problems later. -Now build, install and reboot the new kernel as usual. - -Since the AD1816(A) is a P'n'P sound chip you'll usually have to -configure it using the isapnptools. See isapnptools documentation for -details on configuring P'n'P cards. - -After you have successfully configured the card using isapnp, you may -load the AD1816 driver using modprobe. A typical modprobe call should -look like this: - - modprobe ad1816 io=0x530 irq=5 dma=1 dma2=3 ad1816_clockfreq=33000 - -if your isapnp.conf file looks like this (relevant lines only): - - (INT 0 (IRQ 5 (MODE +E))) - (DMA 0 (CHANNEL 1)) - (DMA 1 (CHANNEL 3)) - (IO 0 (BASE 0x0220)) - (IO 1 (BASE 0x0388)) - (IO 2 (BASE 0x0530)) - -NOTE: Be sure, that you use the address IO 2 (in our example 0x530) when -loading the module! - -If your setup was correct, you should see the following messages in -/var/log/messages (numbers may be different): - -Nov 6 17:07:26 tek01 kernel: ad1816_detect(530) -Nov 6 17:07:26 tek01 kernel: ad1816_detect() - Detected OK -Nov 6 17:07:26 tek01 kernel: AD1816 Version: 3 - +To get your AD1816(A) based sound card work, you'll have to enable support for +experimental code ("Prompt for development and/or incomplete code/drivers") +and isapnp ("Plug and Play support", "ISA Plug and Play support"). Enable +"Sound card support", "OSS modules support" and "Support for AD1816(A) based +cards (EXPERIMENTAL)" in the sound configuration menu, too. Now build, install +and reboot the new kernel as usual. Features: --------- @@ -86,13 +49,7 @@ ---------------- First of all you should check, if the driver has been loaded -properly. If you get the following message in your /var/log/messages: - -Nov 6 17:06:31 tek01 kernel: ad1816_detect(530) -Nov 6 17:06:31 tek01 kernel: Chip is not an AD1816 or chip is not active - -you either used the wrong address for loading the driver, your chip is -not an AD1816 or you forgot to initialize the card with isapnp. +properly. If loading of the driver succeeds, but playback/capture fails, check if you used the correct values for irq, dma and dma2 when loading the module. @@ -122,6 +79,6 @@ Bugreports, bugfixes and related questions should be sent via E-Mail to: tek@rbg.informatik.tu-darmstadt.de - Thorsten Knabe - Last modified: 1999/05/02 +Christoph Hellwig + Last modified: 2000/09/20 diff -u --recursive --new-file v2.4.0-test8/linux/Documentation/sound/ESS linux/Documentation/sound/ESS --- v2.4.0-test8/linux/Documentation/sound/ESS Fri Jul 28 12:50:52 2000 +++ linux/Documentation/sound/ESS Wed Sep 27 13:53:52 2000 @@ -1,9 +1,10 @@ Documentation for the ESS AudioDrive chips -In 2.2 kernels the SoundBlaster driver not only tries to detect an ESS chip, it +In 2.4 kernels the SoundBlaster driver not only tries to detect an ESS chip, it tries to detect the type of ESS chip too. The correct detection of the chip -doesn't always succeed however, so the default behaviour is 2.0 behaviour -which means: only detect ES688 and ES1688. +doesn't always succeed however, so unless you use the kernel isapnp facilities +(and you chip is pnp capable) the default behaviour is 2.0 behaviour which +means: only detect ES688 and ES1688. All ESS chips now have a recording level setting. This is a need-to-have for people who want to use their ESS for recording sound. diff -u --recursive --new-file v2.4.0-test8/linux/Documentation/sound/ESS1868 linux/Documentation/sound/ESS1868 --- v2.4.0-test8/linux/Documentation/sound/ESS1868 Wed Dec 16 12:52:00 1998 +++ linux/Documentation/sound/ESS1868 Wed Sep 27 13:53:52 2000 @@ -2,17 +2,21 @@ The ESS1868 sound card is a PnP ESS1688-compatible 16-bit sound card. -Notes about configuring the sound card: +It should be automatically detected by the Linux Kernel isapnp support when you +load the sb.o module. Otherwise you should take care of: * The ESS1868 does not allow use of a 16-bit DMA, thus DMA 0, 1, 2, and 3 may only be used. * isapnptools version 1.14 does work with ESS1868. Earlier versions might not. - + * Sound support MUST be compiled as MODULES, not statically linked into the kernel. - + + +NOTE: this is only needed when not using the kernel isapnp support! + For configuring the sound card's I/O addresses, IRQ and DMA, here is a sample copy of the isapnp.conf directives regarding the ESS1868: @@ -47,38 +51,5 @@ /sbin/insmod opl3 io=0x388 /sbin/insmod v_midi -opl3 is the FM synthesizer--I have not tried the SoftOSS wavetable -synthesizer yet, but I assume it would work as well. Also, doing: -/sbin/insmod opl3 -/sbin/insmod adlib_card io=0x388 -works, but I believe the sound quality is a bit distorted when playing MIDI -files. - -When using the above setup, my /proc/sound gives the following: - -OSS/Free:3.8s2++-971130 -Load type: Driver loaded as a module -Kernel: Linux scitus.dyn.ml.org 2.1.104 #1 SMP Sun May 24 11:04:27 EDT 1998 i486 -Config options: 0 - -Installed drivers: - -Card config: - -Audio devices: -0: ESS ES1688 AudioDrive (rev 11) (3.1) - -Synth devices: -0: Yamaha OPL-3 - -Midi devices: -0: Loopback MIDI Port 1 -1: Loopback MIDI Port 2 - -Timers: -0: System clock - -Mixers: -0: Sound Blaster - - +opl3 is the FM synthesizer +/sbin/insmod opl3 io=0x388 diff -u --recursive --new-file v2.4.0-test8/linux/Documentation/sound/INSTALL.awe linux/Documentation/sound/INSTALL.awe --- v2.4.0-test8/linux/Documentation/sound/INSTALL.awe Thu Apr 29 11:53:41 1999 +++ linux/Documentation/sound/INSTALL.awe Wed Sep 27 13:53:52 2000 @@ -9,12 +9,9 @@ If you're using PnP cards, the initialization of PnP is required before loading this driver. You have now three options: 1. Use isapnptools. - 2. Install PnP kernel driver patch. + 2. Use in-kernel isapnp support. 3. Initialize PnP on DOS/Windows, then boot linux by loadlin. In this document, only the case 1 case is treated. -For the case 2, please refer to the instruction in PnP driver project. -The home page of PnP driver project is the following URL: - http://www-jcr.lmh.ox.ac.uk/~pnp/ ---------------------------------------------------------------- * Installation on Red Hat 5.0 Sound Driver diff -u --recursive --new-file v2.4.0-test8/linux/Documentation/sound/Introduction linux/Documentation/sound/Introduction --- v2.4.0-test8/linux/Documentation/sound/Introduction Fri Jul 28 12:50:52 2000 +++ linux/Documentation/sound/Introduction Wed Sep 27 13:53:52 2000 @@ -27,6 +27,8 @@ added info on OSS and ALSA. 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) + Modular Sound Drivers: ====================== @@ -46,17 +48,13 @@ forums for bug reporting. The modular sound drivers may be loaded via insmod or modprobe. -To support all the various sound modules, there are three general +To support all the various sound modules, there are two general support modules that must be loaded first: soundcore.o: Top level handler for the sound system, provides a set of functions for registration of devices by type. - soundlow.o: Low-level sound drivers which are not part of - OSS/Lite (Open Sound System), including SB32/AWE - synthesizer, etc. - sound.o: Common sound functions required by all modules. For the specific sound modules (e.g., sb.o for the Soundblaster), @@ -255,6 +253,9 @@ Since this was originally release, I have received a couple of mails from people who have accomplished this! +NOTE: In Linux 2.4 the Sound Blaster driver (and only this one yet) +supports multiple cards with one module by default. +Read the file 'Soundblaster' in this directory for details. Sound Problems: =============== @@ -277,8 +278,7 @@ and /proc/dma. Are you trying to use an address, IRQ or DMA port that another device is using? - C) Check (cat) /proc/sys/pnp (if this exists, you - may need a kernel patch to get this device). + C) Check (cat) /proc/isapnp D) Inspect your /var/log/messages file. Often that will indicate what IRQ or IO port could not be obtained. @@ -332,8 +332,9 @@ There are several ways of configuring your sound: -1) Hardcoded in the kernel at compile time (not applicable when - using sound modules). This was the OLD way! +1) On the kernel command line (when using the sound driver(s) + compiled in the kernel). Check the driver source and + documentation for details. 2) On the command line when using insmod or in a bash script using command line calls to load sound. @@ -344,6 +345,10 @@ 5) Via the OSS soundconf program (with the commercial version of the OSS driver. + +6) By just loading the module and let isapnp do everything relevant + for you. This works only with a few drivers yet and - of course - + only with isapnp hardware. And I am sure, several other ways. diff -u --recursive --new-file v2.4.0-test8/linux/Documentation/sound/NEWS linux/Documentation/sound/NEWS --- v2.4.0-test8/linux/Documentation/sound/NEWS Wed Dec 31 16:00:00 1969 +++ linux/Documentation/sound/NEWS Wed Sep 27 13:53:52 2000 @@ -0,0 +1,42 @@ +Linux 2.4 Sound Changes +2000-September-25 +Christoph Hellwig, + + + +=== isapnp support + +The Linux 2.4 Kernel does have reliable in-kernel isapnp support. +Some drivers (sb.o, ad1816.o awe_wave.o) do now support automatically +detecting and configuring isapnp devices. +If you have a not yet supported isapnp soundcard, mail me the content +of '/proc/isapnp' on your system and some information about your card +and its driver(s) so I can try to get isapnp working for it. + + + +=== soundcard resources on kernel commandline + +Before Linux 2.4 you had to specify the resources for sounddrivers +statically linked into the kernel at compile time +(in make config/menuconfig/xconfig). In Linux 2.4 the ressources are +now specified at the boot-time kernel commandline (e.g. the lilo +'append=' line or everything that's after the kernel name in grub). +Read the Configure.help entry for your card for the parameters. + + +=== softoss is gone + +In Linux 2.4 the softoss in-kernel software synthesizer is no more aviable. +Use a user space software synthesizer like timidity instead. + + + +=== /dev/sndstat and /proc/sound are gone + +In older Linux versions those files exported some information about the +OSS/Free configuration to userspace. In Linux 2.3 they were removed because +they did not support the growing number of pci soundcards and there were +some general problems with this interface. + + diff -u --recursive --new-file v2.4.0-test8/linux/Documentation/sound/PSS-updates linux/Documentation/sound/PSS-updates --- v2.4.0-test8/linux/Documentation/sound/PSS-updates Wed Dec 31 16:00:00 1969 +++ linux/Documentation/sound/PSS-updates Mon Sep 18 15:02:02 2000 @@ -0,0 +1,88 @@ + This file contains notes for users of PSS sound cards who wish to use the +newly added features of the newest version of this driver. + + The major enhancements present in this new revision of this driver is the +addition of two new module parameters that allow you to take full advantage of +all the features present on your PSS sound card. These features include the +ability to enable both the builtin CDROM and joystick ports. + +pss_enable_joystick + + This parameter is basically a flag. A 0 will leave the joystick port +disabled, while a non-zero value would enable the joystick port. The default +setting is pss_enable_joystick=0 as this keeps this driver fully compatable +with systems that were using previous versions of this driver. If you wish to +enable the joystick port you will have to add pss_enable_joystick=1 as an +argument to the driver. To actually use the joystick port you will then have +to load the joystick driver itself. Just remember to load the joystick driver +AFTER the pss sound driver. + +pss_cdrom_port + + This parameter takes a port address as its parameter. Any available port +address can be specified to enable the CDROM port, except for 0x0 and -1 as +these values would leave the port disabled. Like the joystick port, the cdrom +port will require that an appropiate CDROM driver be loaded before you can make +use of the newly enabled CDROM port. Like the joystick port option above, +remember to load the CDROM driver AFTER the pss sound driver. While it may +differ on some PSS sound cards, all the PSS sound cards that I have seen have a +builtin Wearnes CDROM port. If this is the case with your PSS sound card you +should load aztcd with the appropiate port option that matches the port you +assigned to the CDROM port when you loaded your pss sound driver. (ex. +modprobe pss pss_cdrom_port=0x340 && modprobe aztcd aztcd=0x340) The default +setting of this parameter leaves the CDROM port disabled to maintain full +compatability with systems using previous versions of this driver. + + Other options have also been added for the added convenience and utility +of the user. These options are only available if this driver is loaded as a +module. + +pss_no_sound + + This module parameter is a flag that can be used to tell the driver to +just configure non-sound components. 0 configures all components, a non-0 +value will only attept to configure the CDROM and joystick ports. This +parameter can be used by a user who only wished to use the builtin joystick +and/or CDROM port(s) of his PSS sound card. If this driver is loaded with this +parameter and with the paramter below set to true then a user can safely unload +this driver with the following command "rmmod pss && rmmod ad1848 && rmmod +mpu401 && rmmod sound && rmmod soundcore" and retain the full functionality of +his CDROM and/or joystick port(s) while gaining back the memory previously used +by the sound drivers. This default setting of this parameter is 0 to retain +full behavioral compatability with previous versions of this driver. + +pss_keep_settings + + This parameter can be used to specify whether you want the driver to reset +all emulations whenever its unloaded. This can be useful for those who are +sharing resources (io ports, IRQ's, DMA's) between different ISA cards. This +flag can also be useful in that future versions of this driver may reset all +emulations by default on the driver's unloading (as it probably should), so +specifying it now will ensure that all future versions of this driver will +continue to work as expected. The default value of this parameter is 1 to +retain full behavioral compatability with previous versions of this driver. + +pss_firmware + + This parameter can be used to specify the file containing the firmware +code so that a user could tell the driver where that file is located instead +of having to put it in a predefined location with a predefined name. The +default setting of this parameter is "/etc/sound/pss_synth" as this was the +path and filename the hardcoded value in the previous versions of this driver. + +Examples: + +# Normal PSS sound card system, loading of drivers. +# Should be specified in an rc file (ex. Slackware uses /etc/rc.d/rc.modules). + +/sbin/modprobe pss pss_io=0x220 mpu_io=0x338 mpu_irq=9 mss_io=0x530 mss_irq=10 mss_dma=1 pss_cdrom_port=0x340 pss_enable_joystick=1 +/sbin/modprobe aztcd aztcd=0x340 +/sbin/modprobe joystick + +# System using the PSS sound card just for its CDROM and joystick ports. +# Should be specified in an rc file (ex. Slackware uses /etc/rc.d/rc.modules). + +/sbin/modprobe pss pss_io=0x220 pss_cdrom_port=0x340 pss_enable_joystick=1 pss_no_sound=1 +/sbin/rmmod pss && /sbin/rmmod ad1848 && /sbin/rmmod mpu401 && /sbin/rmmod sound && /sbin/rmmod soundcore # This line not needed, but saves memory. +/sbin/modprobe aztcd aztcd=0x340 +/sbin/modprobe joystick diff -u --recursive --new-file v2.4.0-test8/linux/Documentation/usb/CREDITS linux/Documentation/usb/CREDITS --- v2.4.0-test8/linux/Documentation/usb/CREDITS Fri Jul 28 12:50:52 2000 +++ linux/Documentation/usb/CREDITS Mon Oct 2 12:02:16 2000 @@ -5,6 +5,7 @@ difficult to maintain, add yourself with a patch if desired. Georg Acher + David Brownell Alan Cox Randy Dunlap Johannes Erdfelt @@ -14,6 +15,7 @@ Greg Kroah-Hartman Pavel Machek Paul Mackerras + Petko Manlolov David E. Nelson Vojtech Pavlik Bill Ryder @@ -112,6 +114,10 @@ serial converter, and the documentation for the device to allow a driver to be written. + - Thanks to ADMtek for providing Pegasus and Pegasus II + evaluation boards, specs and valuable advices during + the driver development. + And thanks go to (hey! in no particular order :) - Oren Tirosh , for standing so patiently diff -u --recursive --new-file v2.4.0-test8/linux/Documentation/usb/URB.txt linux/Documentation/usb/URB.txt --- v2.4.0-test8/linux/Documentation/usb/URB.txt Fri Jul 28 12:50:52 2000 +++ linux/Documentation/usb/URB.txt Tue Oct 3 09:24:40 2000 @@ -26,6 +26,7 @@ handler, the continuous streaming itself is transparently done by the URB-machinery. + 1.2. The URB structure typedef struct urb @@ -43,7 +44,7 @@ // status after each completion int status; // returned status - unsigned int transfer_flags; // ASAP, SP_OK, EARLY_COMPLETE + unsigned int transfer_flags; // ASAP, SP_OK, etc. // for data stage (CTRL), BULK, INT and ISO void *transfer_buffer; // associated data buffer @@ -68,6 +69,7 @@ iso_packet_descriptor_t iso_frame_desc[0]; } urb_t, *purb_t; + 1.3. How to get an URB? URBs are allocated with the following call @@ -85,6 +87,7 @@ This call also may free internal (host controller specific) memory in the future. + 1.4. What has to be filled in? Depending on the type of transaction, there are some macros @@ -102,10 +105,10 @@ If short packets should NOT be tolerated, set USB_DISABLE_SPD in transfer_flags. -Usually, (to reduce restart time) the completion handler is called -AFTER the URB re-submission. You can get the other way by setting -USB_URB_EARLY_COMPLETE in transfer_flags. This is implicit for -INT transfers. +Usually, to reduce restart time, the completion handler is called +AFTER the URB re-submission. However, it is called BEFORE URB +re-submission for INT transfers that are being continued. + 1.5. How to submit an URB? @@ -133,9 +136,12 @@ The same applies to INT transfers, but here the seamless continuation is independent of the transfer flags (implicitly ASAP). + 1.6. How to cancel an already running URB? -Call +For an URB which you've submitted, but which hasn't been returned to +your driver by the host controller, call + int unlink_urb(purb_t purb) It removes the urb from the internal list and frees all allocated @@ -143,6 +149,13 @@ unlink_urb() returns, you can safely free the URB with free_urb(urb) and all other possibly associated data (urb->context etc.) +There is also an asynchronous unlink mode. To use this, set the +the USB_ASYNC_UNLINK flag in urb->transfer flags before calling +usb_unlink_urb(). When using async unlinking, the URB will not +normally be unlinked when unlink_urb() returns. Instead, wait for +the completion handler to be called. + + 1.7. What about the completion handler? The completion handler is optional, but useful for fast data processing @@ -158,6 +171,18 @@ detect any USB errors. Since the context parameter is included in the URB, you can pass information to the completion handler. +NOTE: ***** WARNING ***** +AVOID using the urb->dev field in your completion handler; it's cleared +as part of URB unlinking. Instead, use urb->context to hold all the +data your driver needs. + +NOTE: ***** WARNING ***** +Also, NEVER SLEEP IN A COMPLETION HANDLER. These are normally called +during hardware interrupt processing. If you can, defer substantial +work to a tasklet (bottom half) to keep system latencies low. You'll +probably need to use spinlocks to protect data structures you manipulate +in completion handlers. + 1.8. How to do isochronous (ISO) transfers? @@ -184,11 +209,13 @@ in seamless ISO streaming. For continuous streaming you have to use URB linking. + 1.9. How to start interrupt (INT) transfers? -INT transfers are currently implemented with 8 different queues for intervals -for 1, 2, 4,... 128ms. Only one TD is allocated for each interrupt. After -calling the completion handler, the TD is recycled. +INT transfers are currently implemented with different queues for intervals +for 1, 2, 4,... 128ms. Only one URB is allocated for each interrupt. After +calling the completion handler, that URB is recycled by the host controller +driver (HCD). With the submission of one URB, the interrupt is scheduled until it is canceled by unlink_urb. diff -u --recursive --new-file v2.4.0-test8/linux/Documentation/usb/error-codes.txt linux/Documentation/usb/error-codes.txt --- v2.4.0-test8/linux/Documentation/usb/error-codes.txt Tue Jan 4 16:12:59 2000 +++ linux/Documentation/usb/error-codes.txt Mon Oct 2 12:02:16 2000 @@ -42,6 +42,13 @@ -EMSGSIZE endpoint message size is zero, do interface/alternate setting +USB_ST_BANDWIDTH_ERROR +-ENOSPC The host controller's bandwidth is already consumed and + this request would push it past its allowed limit. + +-ESHUTDOWN The host controller has been disabled due to some + problem that could not be worked around. + ************************************************************************** * Error codes returned by in urb->status * @@ -88,6 +95,8 @@ USB_ST_URB_INVALID_ERROR -EINVAL ISO madness, if this happens: Log off and go home + +-ECONNRESET the URB is being unlinked asynchronously ************************************************************************** * Error codes returned by usbcore-functions * diff -u --recursive --new-file v2.4.0-test8/linux/Documentation/usb/ov511.txt linux/Documentation/usb/ov511.txt --- v2.4.0-test8/linux/Documentation/usb/ov511.txt Fri Jul 28 12:50:52 2000 +++ linux/Documentation/usb/ov511.txt Tue Sep 19 11:37:59 2000 @@ -6,14 +6,16 @@ Homepage: http://alpha.dyndns.org/ov511 NEW IN THIS VERSION: - o Sensor detection fixes - o More efficient/reliable buffer allocation - o Many minor fixes + o Stability improvements + o Support for hue control + o 160x120 mostly working + o OV6620 color problems fixed + o More WebCam 3 detection improvements INTRODUCTION: This is a driver for the OV511, a USB-only chip used in many "webcam" devices. -Any camera using the OV511/OV511+ and the OV7610/20/20AE CCD should work.It +Any camera using the OV511/OV511+ and the OV7610/20/20AE CCD should work. It supports streaming and capture of color or monochrome video via the Video4Linux API. Most V4L apps are compatible with it, but a few videoconferencing programs do not work yet. The following resolutions are supported: 640x480, 448x336, @@ -195,20 +197,28 @@ both OV511 and OV511+ cameras, trial-and-error may be necessary for finding the optimum setting. - + NAME: retry_sync + TYPE: boolean + DEFAULT: 0 + DESC: Prevent apps from timing out if frame is not done in time. This is + useful if you are having problems with Xawtv getting "stuck" on a frame + when your system is under heavy load. + WORKING FEATURES: - o Color streaming/capture at 640x480, 448x336, 384x288, 352x288, and 320x240 - o YUV420 and YUV422P color + o Color streaming/capture at 640x480, 448x336, 384x288, 352x288, 320x240, and + 160x120 + o RGB24, YUV420, YUV422, YUYV, and YUV422P color o Monochrome - o Setting/getting of saturation, contrast and brightness (no hue yet; only - works with OV7610, not the OV7620 or OV7620AE) + o Setting/getting of saturation, contrast, brightness, and hue (only some of + them work the OV7620 and OV7620AE) o proc status reporting EXPERIMENTAL FEATURES: o fix_rgb_offset: Sometimes works, but other times causes errors with xawtv and corrupted frames. If you have a very fast CPU, you can try it. o Snapshot mode (only works with some read() based apps; see below for more) - o read() support + o OV6620 sensor support + o GBR422 parsing TODO: o Fix the noise / grainy image problem. @@ -216,25 +226,23 @@ frame rate quite a bit. OmniVision wouldn't tell me how the algorithm works, so we can't really work on that yet. Please kindly inform OmniVision that you would like them to release their specifications to the Linux community. - o Get 160x120 working - o YUV422 (and other color modes) + o YUV422 o Get snapshot mode working with mmap(). o Fix fixFrameRGBoffset(). It is not stable yet with streaming video. - o Get hue (red/blue channel balance) adjustment working (in ov511_get_picture() - and ov511_set_picture()) o Get autoadjust disable working o V4L2 support (Probably not until it goes into the kernel) - o Fix I2C initialization. Some people are reporting problems with reading the - 7610 registers. This could be due to timing differences, an excessive I2C - clock rate, or a problem with ov511_i2c_read(). + o Creative WebCam III has problems initializing its sensor. This should be + fixed now, but if you still have problems let me know. o Get rid of the memory management functions (put them in videodev.c??) - o Setting of contrast and brightness not working with 7620 + o Setting of contrast and brightness not working with 7620/7620AE o Driver/camera state save/restore for when USB supports suspend/resume o Unstable on SMP systems + o OV7620/OV6620 experience frame corruption with moving objects + o OV6620 is too dark HOW TO CONTACT ME: -You can email me at mmcclelland@delphi.com . Please prefix the subject line +You can email me at mwm@i.am . Please prefix the subject line with "OV511: " so that I am certain to notice your message. CREDITS: diff -u --recursive --new-file v2.4.0-test8/linux/MAINTAINERS linux/MAINTAINERS --- v2.4.0-test8/linux/MAINTAINERS Tue Sep 5 13:46:15 2000 +++ linux/MAINTAINERS Sun Oct 1 19:46:22 2000 @@ -210,6 +210,13 @@ L: linux-fbdev@vuser.vu.union.edu S: Maintained +COMPAQ FIBRE CHANNEL 64-bit/66MHz PCI non-intelligent HBA +P: Amy Vanzant-Hodge +M: Amy Vanzant-Hodge (fibrechannel@compaq.com) +L: compaqandlinux@cpqlin.van-dijk.net +W: ftp.compaq.com/pub/products/drivers/linux +S: Supported + COMPAQ SMART2 RAID DRIVER P: Charles White M: Charles White @@ -217,6 +224,13 @@ W: ftp.compaq.com/pub/products/drivers/linux S: Supported +COMPAQ SMART CISS RAID DRIVER +P: Charles White +M: Charles White +L: compaqandlinux@cpqlin.van-dijk.net +W: ftp.compaq.com/pub/products/drivers/linux +S: Supported + COMPUTONE INTELLIPORT MULTIPORT CARD P: Doug McNash P: Michael H. Warfield @@ -236,6 +250,7 @@ P: Michael Elizabeth Chastain M: mec@shout.net L: linux-kbuild@torque.net +W: http://www.kernel.org/pub/linux/kernel/projects/kbuild/ S: Maintained CONFIGURE.HELP @@ -471,6 +486,15 @@ W: http://www.nt.tuwien.ac.at/~kkudielk/Linux/ S: Maintained +KERNEL BUILD (Makefile, Rules.make, scripts/*) +P: Keith Owens +M: kaos@ocs.com.au +P: Michael Elizabeth Chastain +M: mec@shout.net +L: linux-kbuild@torque.net +W: http://www.kernel.org/pub/linux/kernel/projects/kbuild/ +S: Maintained + LOGICAL VOLUME MANAGER P: Heinz Mauelshagen M: linux-LVM@EZ-Darmstadt.Telekom.de @@ -1096,6 +1120,13 @@ W: http://mosquitonet.Stanford.EDU/strip.html S: Unsupported ? +STRADIS MPEG-2 DECODER DRIVER +P: Nathan Laredo +M: laredo@gnu.org +W: http://mpeg.openprojects.net/ +W: http://www.stradis.com/ +S: Maintained + SUPERH P: Niibe Yutaka M: gniibe@chroot.org @@ -1152,6 +1183,13 @@ L: linux-tulip@cesdis.gsfc.nasa.gov S: Maintained +TUN/TAP driver +P: Maxim Krasnyansky +M: maxk@qualcomm.com, max_mk@yahoo.com +L: vtun@office.satix.net +W: http://vtun.sourceforge.net/tun +S: Maintained + U14-34F SCSI DRIVER P: Dario Ballabio M: dario@milano.europe.dg.com @@ -1214,7 +1252,8 @@ USB HUB P: Johannes Erdfelt -M: jerdfelt@sventech.com +M: jerdfelt@valinux.com +M: johannes@erdfelt.com L: linux-usb-users@lists.sourceforge.net L: linux-usb-devel@lists.sourceforge.net S: Maintained @@ -1228,7 +1267,7 @@ USB OV511 DRIVER P: Mark McClelland -M: mmcclelland@delphi.com +M: mwm@i.am L: linux-usb-users@lists.sourceforge.net L: linux-usb-devel@lists.sourceforge.net W: http://alpha.dyndns.org/ov511/ diff -u --recursive --new-file v2.4.0-test8/linux/Makefile linux/Makefile --- v2.4.0-test8/linux/Makefile Wed Aug 23 18:36:46 2000 +++ linux/Makefile Mon Oct 2 14:22:59 2000 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 0 -EXTRAVERSION = -test8 +EXTRAVERSION = -test9 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) @@ -138,7 +138,7 @@ DRIVERS-$(CONFIG_NUBUS) += drivers/nubus/nubus.a DRIVERS-$(CONFIG_ISDN) += drivers/isdn/isdn.a DRIVERS-$(CONFIG_NET_FC) += drivers/net/fc/fc.o -DRIVERS-$(CONFIG_APPLETALK) += drivers/net/appletalk/appletalk.a +DRIVERS-$(CONFIG_APPLETALK) += drivers/net/appletalk/appletalk.o DRIVERS-$(CONFIG_TR) += drivers/net/tokenring/tr.a DRIVERS-$(CONFIG_WAN) += drivers/net/wan/wan.o DRIVERS-$(CONFIG_ARCNET) += drivers/net/arcnet/arcnet.a @@ -161,7 +161,7 @@ DRIVERS-$(CONFIG_SBUS) += drivers/sbus/sbus.a DRIVERS-$(CONFIG_ZORRO) += drivers/zorro/zorro.a DRIVERS-$(CONFIG_FC4) += drivers/fc4/fc4.a -DRIVERS-$(CONFIG_PPC) += drivers/macintosh/macintosh.o +DRIVERS-$(CONFIG_ALL_PPC) += drivers/macintosh/macintosh.o DRIVERS-$(CONFIG_MAC) += drivers/macintosh/macintosh.o DRIVERS-$(CONFIG_ISAPNP) += drivers/pnp/pnp.o DRIVERS-$(CONFIG_SGI_IP22) += drivers/sgi/sgi.a @@ -174,8 +174,9 @@ DRIVERS-$(CONFIG_I2O) += drivers/i2o/i2o.o DRIVERS-$(CONFIG_IRDA) += drivers/net/irda/irda.o DRIVERS-$(CONFIG_I2C) += drivers/i2c/i2c.o -DRIVERS-$(CONFIG_PHONE) += drivers/telephony/telephony.a +DRIVERS-$(CONFIG_PHONE) += drivers/telephony/telephony.o DRIVERS-$(CONFIG_ACPI_INTERPRETER) += drivers/acpi/acpi.o +DRIVERS-$(CONFIG_MD) += drivers/md/mddev.o DRIVERS += $(DRIVERS-y) diff -u --recursive --new-file v2.4.0-test8/linux/README linux/README --- v2.4.0-test8/linux/README Mon Aug 21 08:57:35 2000 +++ linux/README Tue Oct 3 09:24:41 2000 @@ -270,7 +270,8 @@ on making sense of the dump is in Documentation/oops-tracing.txt - You can use the "ksymoops" program to make sense of the dump. This - utility can be downloaded from ftp://ftp.ocs.com.au/pub/ksymoops . + utility can be downloaded from + ftp://ftp..kernel.org/pub/linux/utils/kernel/ksymoops. Alternately you can do the dump lookup by hand: - In debugging dumps like the above, it helps enormously if you can diff -u --recursive --new-file v2.4.0-test8/linux/Rules.make linux/Rules.make --- v2.4.0-test8/linux/Rules.make Sun Aug 13 09:55:51 2000 +++ linux/Rules.make Mon Sep 18 14:59:23 2000 @@ -73,6 +73,9 @@ endif +%.lst: %.c + $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -g -c -o $*.o $< + $(TOPDIR)/scripts/makelst $* $(TOPDIR) $(OBJDUMP) # # # diff -u --recursive --new-file v2.4.0-test8/linux/arch/alpha/Makefile linux/arch/alpha/Makefile --- v2.4.0-test8/linux/arch/alpha/Makefile Mon Aug 28 21:21:57 2000 +++ linux/arch/alpha/Makefile Mon Sep 25 12:36:09 2000 @@ -8,7 +8,7 @@ # Copyright (C) 1994 by Linus Torvalds # -NM := nm -B +NM := $(NM) -B LINKFLAGS = -static -T arch/alpha/vmlinux.lds -N #-relax CFLAGS := $(CFLAGS) -pipe -mno-fp-regs -ffixed-8 @@ -119,6 +119,10 @@ archdep: @$(MAKEBOOT) dep + +vmlinux: arch/alpha/vmlinux.lds + +arch/alpha/vmlinux.lds: arch/alpha/vmlinux.lds.in $(CPP) $(CPPFLAGS) -xc -P arch/alpha/vmlinux.lds.in -o arch/alpha/vmlinux.lds bootpfile: diff -u --recursive --new-file v2.4.0-test8/linux/arch/alpha/boot/Makefile linux/arch/alpha/boot/Makefile --- v2.4.0-test8/linux/arch/alpha/boot/Makefile Tue Jul 18 22:58:27 2000 +++ linux/arch/alpha/boot/Makefile Mon Sep 25 12:36:09 2000 @@ -68,7 +68,7 @@ $(OBJSTRIP) -v $(VMLINUX) vmlinux.nh vmlinux: $(TOPDIR)/vmlinux - strip -o vmlinux $(VMLINUX) + $(STRIP) -o vmlinux $(VMLINUX) tools/lxboot: $(OBJSTRIP) bootloader $(OBJSTRIP) -p bootloader tools/lxboot diff -u --recursive --new-file v2.4.0-test8/linux/arch/alpha/config.in linux/arch/alpha/config.in --- v2.4.0-test8/linux/arch/alpha/config.in Tue Aug 22 11:41:14 2000 +++ linux/arch/alpha/config.in Tue Sep 19 10:57:30 2000 @@ -239,6 +239,8 @@ source drivers/block/Config.in +source drivers/md/Config.in + if [ "$CONFIG_NET" = "y" ]; then source net/Config.in fi diff -u --recursive --new-file v2.4.0-test8/linux/arch/alpha/kernel/pci_iommu.c linux/arch/alpha/kernel/pci_iommu.c --- v2.4.0-test8/linux/arch/alpha/kernel/pci_iommu.c Wed Jun 21 22:30:59 2000 +++ linux/arch/alpha/kernel/pci_iommu.c Fri Sep 22 14:07:43 2000 @@ -416,7 +416,9 @@ ptes = &arena->ptes[dma_ofs]; sg = leader; do { +#if DEBUG_ALLOC > 0 struct scatterlist *last_sg = sg; +#endif size = sg->length; paddr = virt_to_phys(sg->address); diff -u --recursive --new-file v2.4.0-test8/linux/arch/alpha/kernel/smp.c linux/arch/alpha/kernel/smp.c --- v2.4.0-test8/linux/arch/alpha/kernel/smp.c Tue Sep 5 13:50:02 2000 +++ linux/arch/alpha/kernel/smp.c Fri Sep 22 14:07:43 2000 @@ -1046,8 +1046,8 @@ " blbs %0,2b\n" " br 1b\n" ".previous" - : "=r" (tmp), "=m" (__dummy_lock(lock)), "=r" (stuck) - : "1" (__dummy_lock(lock)), "2" (stuck)); + : "=r" (tmp), "=m" (lock->lock), "=r" (stuck) + : "1" (lock->lock), "2" (stuck) : "memory"); if (stuck < 0) { printk(KERN_WARNING @@ -1124,9 +1124,9 @@ " blt %1,8b\n" " br 1b\n" ".previous" - : "=m" (__dummy_lock(lock)), "=&r" (regx), "=&r" (regy), + : "=m" (*(volatile int *)lock), "=&r" (regx), "=&r" (regy), "=&r" (stuck_lock), "=&r" (stuck_reader) - : "0" (__dummy_lock(lock)), "3" (stuck_lock), "4" (stuck_reader)); + : "0" (*(volatile int *)lock), "3" (stuck_lock), "4" (stuck_reader) : "memory"); if (stuck_lock < 0) { printk(KERN_WARNING "write_lock stuck at %p\n", inline_pc); @@ -1163,8 +1163,8 @@ " blbs %1,6b;" " br 1b\n" ".previous" - : "=m" (__dummy_lock(lock)), "=&r" (regx), "=&r" (stuck_lock) - : "0" (__dummy_lock(lock)), "2" (stuck_lock)); + : "=m" (*(volatile int *)lock), "=&r" (regx), "=&r" (stuck_lock) + : "0" (*(volatile int *)lock), "2" (stuck_lock) : "memory"); if (stuck_lock < 0) { printk(KERN_WARNING "read_lock stuck at %p\n", inline_pc); diff -u --recursive --new-file v2.4.0-test8/linux/arch/alpha/kernel/time.c linux/arch/alpha/kernel/time.c --- v2.4.0-test8/linux/arch/alpha/kernel/time.c Mon Aug 21 07:52:34 2000 +++ linux/arch/alpha/kernel/time.c Fri Sep 22 14:09:00 2000 @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -135,38 +136,6 @@ write_unlock(&xtime_lock); } -/* - * Converts Gregorian date to seconds since 1970-01-01 00:00:00. - * Assumes input in normal date format, i.e. 1980-12-31 23:59:59 - * => year=1980, mon=12, day=31, hour=23, min=59, sec=59. - * - * [For the Julian calendar (which was used in Russia before 1917, - * Britain & colonies before 1752, anywhere else before 1582, - * and is still in use by some communities) leave out the - * -year/100+year/400 terms, and add 10.] - * - * This algorithm was first published by Gauss (I think). - * - * WARNING: this function will overflow on 2106-02-07 06:28:16 on - * machines were long is 32-bit! (However, as time_t is signed, we - * will already get problems at other places on 2038-01-19 03:14:08) - */ -static inline unsigned long mktime(unsigned int year, unsigned int mon, - unsigned int day, unsigned int hour, - unsigned int min, unsigned int sec) -{ - if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */ - mon += 12; /* Puts Feb last since it has leap day */ - year -= 1; - } - return ((( - (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) + - year*365 - 719499 - )*24 + hour /* now have hours */ - )*60 + min /* now have minutes */ - )*60 + sec; /* finally seconds */ -} - void common_init_rtc(void) { @@ -200,7 +169,7 @@ init_rtc_irq(); } -void +void __init time_init(void) { unsigned int year, mon, day, hour, min, sec, cc1, cc2, epoch; @@ -267,17 +236,14 @@ BCD_TO_BIN(year); } - /* PC-like is standard; used for year <= 20 || year >= 100 */ + /* PC-like is standard; used for year < 20 || year >= 70 */ epoch = 1900; - if (year > 20 && year < 48) - /* ARC console, used on some not so old boards */ + if (year >= 20 && year < 48) + /* NT epoch */ epoch = 1980; else if (year >= 48 && year < 70) - /* Digital UNIX, used on older boards (eg. AXPpxi33) */ + /* Digital UNIX epoch */ epoch = 1952; - else if (year >= 70 && year < 100) - /* Digital DECstations, very old... */ - epoch = 1928; printk(KERN_INFO "Using epoch = %d\n", epoch); diff -u --recursive --new-file v2.4.0-test8/linux/arch/alpha/math-emu/Makefile linux/arch/alpha/math-emu/Makefile --- v2.4.0-test8/linux/arch/alpha/math-emu/Makefile Thu Dec 2 15:28:54 1999 +++ linux/arch/alpha/math-emu/Makefile Fri Sep 22 13:54:09 2000 @@ -8,7 +8,7 @@ # Note 2! The CFLAGS definition is now in the main makefile... O_TARGET := math-emu.o -O_OBJS := math.o +O_OBJS := math.o qrnnd.o CFLAGS += -I. -I$(TOPDIR)/include/math-emu -w ifeq ($(CONFIG_MATHEMU),m) diff -u --recursive --new-file v2.4.0-test8/linux/arch/alpha/math-emu/math.c linux/arch/alpha/math-emu/math.c --- v2.4.0-test8/linux/arch/alpha/math-emu/math.c Tue Mar 21 10:47:06 2000 +++ linux/arch/alpha/math-emu/math.c Fri Sep 22 13:54:09 2000 @@ -84,66 +84,6 @@ #endif /* MODULE */ -/* For 128-bit division. */ - -void -udiv128(unsigned long divisor_f0, unsigned long divisor_f1, - unsigned long dividend_f0, unsigned long dividend_f1, - unsigned long *quot, unsigned long *remd) -{ - _FP_FRAC_DECL_2(quo); - _FP_FRAC_DECL_2(rem); - _FP_FRAC_DECL_2(tmp); - unsigned long i, num_bits, bit; - - _FP_FRAC_SET_2(rem, _FP_ZEROFRAC_2); - _FP_FRAC_SET_2(quo, _FP_ZEROFRAC_2); - - if (_FP_FRAC_ZEROP_2(divisor)) - goto out; - - if (_FP_FRAC_GT_2(divisor, dividend)) { - _FP_FRAC_COPY_2(rem, dividend); - goto out; - } - - if (_FP_FRAC_EQ_2(divisor, dividend)) { - __FP_FRAC_SET_2(quo, 0, 1); - goto out; - } - - num_bits = 128; - while (1) { - bit = _FP_FRAC_NEGP_2(dividend); - _FP_FRAC_COPY_2(tmp, rem); - _FP_FRAC_SLL_2(tmp, 1); - _FP_FRAC_LOW_2(tmp) |= bit; - if (! _FP_FRAC_GE_2(tmp, divisor)) - break; - _FP_FRAC_COPY_2(rem, tmp); - _FP_FRAC_SLL_2(dividend, 1); - num_bits--; - } - - for (i = 0; i < num_bits; i++) { - bit = _FP_FRAC_NEGP_2(dividend); - _FP_FRAC_SLL_2(rem, 1); - _FP_FRAC_LOW_2(rem) |= bit; - _FP_FRAC_SUB_2(tmp, rem, divisor); - bit = _FP_FRAC_NEGP_2(tmp); - _FP_FRAC_SLL_2(dividend, 1); - _FP_FRAC_SLL_2(quo, 1); - if (!bit) { - _FP_FRAC_LOW_2(quo) |= 1; - _FP_FRAC_COPY_2(rem, tmp); - } - } - -out: - *quot = quo_f1; - *remd = rem_f1; - return; -} /* * Emulate the floating point instruction at address PC. Returns 0 if diff -u --recursive --new-file v2.4.0-test8/linux/arch/alpha/math-emu/qrnnd.S linux/arch/alpha/math-emu/qrnnd.S --- v2.4.0-test8/linux/arch/alpha/math-emu/qrnnd.S Wed Dec 31 16:00:00 1969 +++ linux/arch/alpha/math-emu/qrnnd.S Fri Sep 22 13:54:09 2000 @@ -0,0 +1,163 @@ + # Alpha 21064 __udiv_qrnnd + # Copyright (C) 1992, 1994, 1995, 2000 Free Software Foundation, Inc. + + # This file is part of GCC. + + # The GNU MP Library is free software; you can redistribute it and/or modify + # it under the terms of the GNU General Public License as published by + # the Free Software Foundation; either version 2 of the License, or (at your + # option) any later version. + + # In addition to the permissions in the GNU General Public License, the + # Free Software Foundation gives you unlimited permission to link the + # compiled version of this file with other programs, and to distribute + # those programs without any restriction coming from the use of this + # file. (The General Public License restrictions do apply in other + # respects; for example, they cover modification of the file, and + # distribution when not linked into another program.) + + # This file is distributed in the hope that it will be useful, but + # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public + # License for more details. + + # You should have received a copy of the GNU General Public License + # along with GCC; see the file COPYING. If not, write to the + # Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + # MA 02111-1307, USA. + + .set noreorder + .set noat + + .text + + .globl __udiv_qrnnd + .ent __udiv_qrnnd +__udiv_qrnnd: + .frame $30,0,$26,0 + .prologue 0 + +#define cnt $2 +#define tmp $3 +#define rem_ptr $16 +#define n1 $17 +#define n0 $18 +#define d $19 +#define qb $20 +#define AT $at + + ldiq cnt,16 + blt d,$largedivisor + +$loop1: cmplt n0,0,tmp + addq n1,n1,n1 + bis n1,tmp,n1 + addq n0,n0,n0 + cmpule d,n1,qb + subq n1,d,tmp + cmovne qb,tmp,n1 + bis n0,qb,n0 + cmplt n0,0,tmp + addq n1,n1,n1 + bis n1,tmp,n1 + addq n0,n0,n0 + cmpule d,n1,qb + subq n1,d,tmp + cmovne qb,tmp,n1 + bis n0,qb,n0 + cmplt n0,0,tmp + addq n1,n1,n1 + bis n1,tmp,n1 + addq n0,n0,n0 + cmpule d,n1,qb + subq n1,d,tmp + cmovne qb,tmp,n1 + bis n0,qb,n0 + cmplt n0,0,tmp + addq n1,n1,n1 + bis n1,tmp,n1 + addq n0,n0,n0 + cmpule d,n1,qb + subq n1,d,tmp + cmovne qb,tmp,n1 + bis n0,qb,n0 + subq cnt,1,cnt + bgt cnt,$loop1 + stq n1,0(rem_ptr) + bis $31,n0,$0 + ret $31,($26),1 + +$largedivisor: + and n0,1,$4 + + srl n0,1,n0 + sll n1,63,tmp + or tmp,n0,n0 + srl n1,1,n1 + + and d,1,$6 + srl d,1,$5 + addq $5,$6,$5 + +$loop2: cmplt n0,0,tmp + addq n1,n1,n1 + bis n1,tmp,n1 + addq n0,n0,n0 + cmpule $5,n1,qb + subq n1,$5,tmp + cmovne qb,tmp,n1 + bis n0,qb,n0 + cmplt n0,0,tmp + addq n1,n1,n1 + bis n1,tmp,n1 + addq n0,n0,n0 + cmpule $5,n1,qb + subq n1,$5,tmp + cmovne qb,tmp,n1 + bis n0,qb,n0 + cmplt n0,0,tmp + addq n1,n1,n1 + bis n1,tmp,n1 + addq n0,n0,n0 + cmpule $5,n1,qb + subq n1,$5,tmp + cmovne qb,tmp,n1 + bis n0,qb,n0 + cmplt n0,0,tmp + addq n1,n1,n1 + bis n1,tmp,n1 + addq n0,n0,n0 + cmpule $5,n1,qb + subq n1,$5,tmp + cmovne qb,tmp,n1 + bis n0,qb,n0 + subq cnt,1,cnt + bgt cnt,$loop2 + + addq n1,n1,n1 + addq $4,n1,n1 + bne $6,$Odd + stq n1,0(rem_ptr) + bis $31,n0,$0 + ret $31,($26),1 + +$Odd: + /* q' in n0. r' in n1 */ + addq n1,n0,n1 + + cmpult n1,n0,tmp # tmp := carry from addq + subq n1,d,AT + addq n0,tmp,n0 + cmovne tmp,AT,n1 + + cmpult n1,d,tmp + addq n0,1,AT + cmoveq tmp,AT,n0 + subq n1,d,AT + cmoveq tmp,AT,n1 + + stq n1,0(rem_ptr) + bis $31,n0,$0 + ret $31,($26),1 + + .end __udiv_qrnnd diff -u --recursive --new-file v2.4.0-test8/linux/arch/alpha/math-emu/sfp-util.h linux/arch/alpha/math-emu/sfp-util.h --- v2.4.0-test8/linux/arch/alpha/math-emu/sfp-util.h Thu Dec 2 15:28:54 1999 +++ linux/arch/alpha/math-emu/sfp-util.h Fri Sep 22 13:54:09 2000 @@ -17,18 +17,13 @@ : "r" ((UDItype)(u)), \ "r" ((UDItype)(v))) -extern void udiv128(unsigned long, unsigned long, - unsigned long, unsigned long, - unsigned long *, - unsigned long *); - -#define udiv_qrnnd(q, r, n1, n0, d) \ - do { \ - unsigned long xr, xi; \ - udiv128((n0), (n1), 0, (d), &xr, &xi); \ - (q) = xr; \ - (r) = xi; \ +#define udiv_qrnnd(q, r, n1, n0, d) \ + do { unsigned long __r; \ + (q) = __udiv_qrnnd (&__r, (n1), (n0), (d)); \ + (r) = __r; \ } while (0) +extern unsigned long __udiv_qrnnd (unsigned long *, unsigned long, + unsigned long , unsigned long); #define UDIV_NEEDS_NORMALIZATION 1 diff -u --recursive --new-file v2.4.0-test8/linux/arch/alpha/mm/extable.c linux/arch/alpha/mm/extable.c --- v2.4.0-test8/linux/arch/alpha/mm/extable.c Mon Jun 19 17:59:33 2000 +++ linux/arch/alpha/mm/extable.c Fri Sep 22 14:07:43 2000 @@ -88,7 +88,7 @@ */ ret = search_exception_table_without_gp(addr); if (ret) { - printk(KERN_ALERT, "%s: [%lx] EX_TABLE search fail with" + printk(KERN_ALERT "%s: [%lx] EX_TABLE search fail with" "exc frame GP, success with raw GP\n", current->comm, addr); return ret; diff -u --recursive --new-file v2.4.0-test8/linux/arch/alpha/mm/fault.c linux/arch/alpha/mm/fault.c --- v2.4.0-test8/linux/arch/alpha/mm/fault.c Mon Jun 19 17:59:33 2000 +++ linux/arch/alpha/mm/fault.c Mon Sep 18 14:57:02 2000 @@ -167,7 +167,7 @@ if ((fixup = search_exception_table(regs->pc, regs->gp)) != 0) { unsigned long newpc; newpc = fixup_exception(dpf_reg, fixup, regs->pc); -#if 1 +#if 0 printk("%s: Exception at [<%lx>] (%lx) handled successfully\n", current->comm, regs->pc, newpc); #endif diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/Makefile linux/arch/arm/Makefile --- v2.4.0-test8/linux/arch/arm/Makefile Sun Sep 3 11:19:11 2000 +++ linux/arch/arm/Makefile Mon Sep 18 15:15:24 2000 @@ -10,7 +10,7 @@ # License. See the file "COPYING" in the main directory of this archive # for more details. # -# Copyright (C) 1995-1999 by Russell King +# Copyright (C) 1995-2000 by Russell King OBJCOPY := $(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S CPP := $(CC) -E @@ -51,21 +51,11 @@ CFLAGS_PROC_CPU_26 := -mcpu=arm3 -mapcs-26 -Os CFLAGS_PROC_CPU_32v3 := -march=armv3 CFLAGS_PROC_CPU_32v4 := -march=armv4 -CFLAGS_ARM6 := -mtune=arm6 -CFLAGS_ARM7 := -mtune=arm7 -CFLAGS_ARM720 := -mtune=arm7tdmi -CFLAGS_ARM920 := -mtune=arm9tdmi -CFLAGS_SA110 := -mtune=strongarm110 else CFLAGS += -DNO_TEXT_SECTIONS CFLAGS_PROC_CPU_26 := -m3 -CFLAGS_PROC_CPU_32v3 := -CFLAGS_PROC_CPU_32v4 := -CFLAGS_ARM6 := -m6 -CFLAGS_ARM7 := -m6 -CFLAGS_ARM720 := -m6 -CFLAGS_ARM920 := -m6 -CFLAGS_SA110 := -m6 +CFLAGS_PROC_CPU_32v3 := -m6 +CFLAGS_PROC_CPU_32v4 := -m6 endif # @@ -88,31 +78,16 @@ CFLAGS += $(CFLAGS_PROC_CPU_32v3) AFLAGS += -mapcs-32 -marmv3m endif - # - # Exactly one of the following must be selected - # - ifeq ($(CONFIG_CPU_ARM6),y) - CFLAGS += $(CFLAGS_ARM6) - else - ifeq ($(CONFIG_CPU_ARM7),y) - CFLAGS += $(CFLAGS_ARM7) - else - ifeq ($(CONFIG_CPU_ARM720),y) - CFLAGS += $(CFLAGS_ARM720) - else - ifeq ($(CONFIG_CPU_ARM920),y) - CFLAGS += $(CFLAGS_ARM920) - else - ifeq ($(CONFIG_CPU_SA110),y) - CFLAGS += $(CFLAGS_SA110) - else - ifeq ($(CONFIG_CPU_SA1100),y) - CFLAGS += $(CFLAGS_SA110) - endif - endif - endif - endif - 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 endif @@ -169,7 +144,10 @@ endif # Only set INCDIR if its not already defined above -INCDIR ?= $(MACHINE) +# Grr, ?= doesn't work as all the other assignment operators do. Make bug? +ifeq ($(origin INCDIR), undefined) +INCDIR := $(MACHINE) +endif # If we have a machine-specific directory, then include it in the build. MACHDIR := arch/arm/mach-$(MACHINE) diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/boot/Makefile linux/arch/arm/boot/Makefile --- v2.4.0-test8/linux/arch/arm/boot/Makefile Sun Sep 3 11:19:11 2000 +++ linux/arch/arm/boot/Makefile Mon Sep 18 15:15:24 2000 @@ -42,6 +42,13 @@ INITRD_VIRT = 0xc0800000 endif +ifeq ($(CONFIG_ARCH_INTEGRATOR),y) +ZTEXTADDR = 0x00008000 +PARAMS = 0x00000100 +INITRD_PHYS = 0x00800000 +INITRD_VIRT = 0xc0800000 +endif + ifeq ($(CONFIG_ARCH_NEXUSPCI),y) ZTEXTADDR = 0x40200000 ZRELADDR = 0x40008000 diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/boot/bootp/bootp.lds linux/arch/arm/boot/bootp/bootp.lds --- v2.4.0-test8/linux/arch/arm/boot/bootp/bootp.lds Sun Sep 3 11:19:11 2000 +++ linux/arch/arm/boot/bootp/bootp.lds Mon Sep 18 15:15:24 2000 @@ -1,3 +1,12 @@ +/* + * linux/arch/arm/boot/bootp/bootp.lds + * + * Copyright (C) 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. + */ OUTPUT_ARCH(arm) ENTRY(_start) SECTIONS diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/boot/bootp/init.S linux/arch/arm/boot/bootp/init.S --- v2.4.0-test8/linux/arch/arm/boot/bootp/init.S Sun Aug 13 09:54:15 2000 +++ linux/arch/arm/boot/bootp/init.S Mon Sep 18 15:15:24 2000 @@ -1,6 +1,14 @@ /* - * Header file for splitting kernel + initrd. Note that we pass - * r0 through to r3 straight through. + * linux/arch/arm/boot/bootp/init.S + * + * Copyright (C) 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. + * + * Header file for splitting kernel + initrd. Note that we pass + * r0 through to r3 straight through. */ .section .start,#alloc,#execinstr .type _entry, #function diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/boot/compressed/Makefile linux/arch/arm/boot/compressed/Makefile --- v2.4.0-test8/linux/arch/arm/boot/compressed/Makefile Sun Aug 13 09:54:15 2000 +++ linux/arch/arm/boot/compressed/Makefile Mon Sep 18 15:15:24 2000 @@ -24,6 +24,10 @@ OBJS += head-netwinder.o endif +ifeq ($(CONFIG_ARCH_INTEGRATOR),y) +OBJS += head-netwinder.o +endif + ifeq ($(CONFIG_ARCH_NEXUSPCI),y) HEAD = head-nexuspci.o endif diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/boot/compressed/head-netwinder.S linux/arch/arm/boot/compressed/head-netwinder.S --- v2.4.0-test8/linux/arch/arm/boot/compressed/head-netwinder.S Sun Aug 13 09:54:15 2000 +++ linux/arch/arm/boot/compressed/head-netwinder.S Mon Sep 18 15:15:24 2000 @@ -1,3 +1,12 @@ +/* + * linux/arch/arm/boot/compressed/head-netwinder.S + * + * Copyright (C) 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. + */ #define K(a,b,c) ((a) << 24 | (b) << 12 | (c)) .section ".start", #alloc, #execinstr diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/boot/compressed/head.S linux/arch/arm/boot/compressed/head.S --- v2.4.0-test8/linux/arch/arm/boot/compressed/head.S Sun Sep 3 11:19:11 2000 +++ linux/arch/arm/boot/compressed/head.S Mon Sep 18 15:15:24 2000 @@ -1,7 +1,11 @@ /* - * linux/arch/arm/boot/compressed/head.S + * linux/arch/arm/boot/compressed/head.S * - * Copyright (C) 1996-1999 Russell King + * Copyright (C) 1996-1999 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 diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/boot/compressed/ll_char_wr.S linux/arch/arm/boot/compressed/ll_char_wr.S --- v2.4.0-test8/linux/arch/arm/boot/compressed/ll_char_wr.S Thu Jun 17 01:11:35 1999 +++ linux/arch/arm/boot/compressed/ll_char_wr.S Mon Sep 18 15:15:24 2000 @@ -1,12 +1,16 @@ /* - * linux/arch/arm/lib/ll_char_wr.S + * linux/arch/arm/lib/ll_char_wr.S * - * Copyright (C) 1995, 1996 Russell King. + * Copyright (C) 1995, 1996 Russell King. * - * Speedups & 1bpp code (C) 1996 Philip Blundell & 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. * - * 10-04-96 RMK Various cleanups & reduced register usage. - * 08-04-98 RMK Shifts re-ordered + * Speedups & 1bpp code (C) 1996 Philip Blundell & Russell King. + * + * 10-04-96 RMK Various cleanups & reduced register usage. + * 08-04-98 RMK Shifts re-ordered */ @ Regs: [] = corruptible diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/boot/compressed/setup-sa1100.S linux/arch/arm/boot/compressed/setup-sa1100.S --- v2.4.0-test8/linux/arch/arm/boot/compressed/setup-sa1100.S Sun Sep 3 11:19:11 2000 +++ linux/arch/arm/boot/compressed/setup-sa1100.S Mon Sep 18 15:15:24 2000 @@ -51,12 +51,6 @@ * This is called from decompress_kernel() with the arch_decomp_setup() macro. */ -/* - * void sa1100_setup( int arch_id ); - * - * This is called from decompress_kernel() with the arch_decomp_setup() macro. - */ - ENTRY(sa1100_setup) mov r3, r0 @ keep machine type in r3 diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/boot/compressed/vmlinux.lds.in linux/arch/arm/boot/compressed/vmlinux.lds.in --- v2.4.0-test8/linux/arch/arm/boot/compressed/vmlinux.lds.in Wed Oct 20 16:29:08 1999 +++ linux/arch/arm/boot/compressed/vmlinux.lds.in Mon Sep 18 15:15:24 2000 @@ -1,3 +1,12 @@ +/* + * linux/arch/arm/boot/compressed/vmlinux.lds.in + * + * Copyright (C) 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. + */ OUTPUT_ARCH(arm) ENTRY(_start) SECTIONS diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/config.in linux/arch/arm/config.in --- v2.4.0-test8/linux/arch/arm/config.in Tue Aug 22 11:41:14 2000 +++ linux/arch/arm/config.in Tue Sep 19 10:57:30 2000 @@ -15,6 +15,7 @@ bool 'Prompt for obsolete code/drivers' CONFIG_OBSOLETE endmenu + mainmenu_option next_comment comment 'Loadable module support' bool 'Enable loadable module support' CONFIG_MODULES @@ -24,6 +25,7 @@ fi endmenu + mainmenu_option next_comment comment 'System Type' @@ -33,49 +35,60 @@ Co-EBSA285 CONFIG_ARCH_CO285 \ EBSA-110 CONFIG_ARCH_EBSA110 \ FootBridge CONFIG_ARCH_FOOTBRIDGE \ + Integrator CONFIG_ARCH_INTEGRATOR \ RiscPC CONFIG_ARCH_RPC \ SA1100-based CONFIG_ARCH_SA1100" RiscPC # the following are placeholders for when they are fully integrated -# Cirrus CL-PS7500FE CONFIG_ARCH_CLPS7500 \ # LinkUp-L7200 CONFIG_ARCH_L7200 +mainmenu_option next_comment +comment 'Archimedes/A5000 Implementations' if [ "$CONFIG_ARCH_ARCA5K" = "y" ]; then # These architectures will be combined. However, until this # is complete... Note that the ARC will take precidence over # A5K comment 'Archimedes/A5000 Implementations (select only ONE)' - bool ' Archimedes support' CONFIG_ARCH_ARC - bool ' A5000 support' CONFIG_ARCH_A5K + + bool ' Archimedes' CONFIG_ARCH_ARC + bool ' A5000' CONFIG_ARCH_A5K fi +endmenu + +mainmenu_option next_comment +comment 'Footbridge Implementations' if [ "$CONFIG_ARCH_FOOTBRIDGE" = "y" ]; then - comment 'Footbridge Implementations' - bool ' CATS support' CONFIG_ARCH_CATS - bool ' Compaq Personal Server support' CONFIG_ARCH_PERSONAL_SERVER - bool ' EBSA285 (addin mode) support' CONFIG_ARCH_EBSA285_ADDIN - bool ' EBSA285 (host mode) support' CONFIG_ARCH_EBSA285_HOST - bool ' NetWinder support' CONFIG_ARCH_NETWINDER + bool ' CATS' CONFIG_ARCH_CATS + bool ' Compaq Personal Server' CONFIG_ARCH_PERSONAL_SERVER + bool ' EBSA285 (addin mode)' CONFIG_ARCH_EBSA285_ADDIN + bool ' EBSA285 (host mode)' CONFIG_ARCH_EBSA285_HOST + bool ' NetWinder' CONFIG_ARCH_NETWINDER fi +endmenu + +mainmenu_option next_comment +comment 'SA11x0 Implementations' if [ "$CONFIG_ARCH_SA1100" = "y" ]; then - comment 'SA11x0 Implementations' - bool ' Include support for Assabet' CONFIG_SA1100_ASSABET + + bool ' Assabet' CONFIG_SA1100_ASSABET if [ "$CONFIG_SA1100_ASSABET" = "y" ]; then - bool ' Include support for Neponset' CONFIG_ASSABET_NEPONSET + bool ' Include support for Neponset' CONFIG_ASSABET_NEPONSET fi - bool ' Include support for Brutus' CONFIG_SA1100_BRUTUS - bool ' Include support for CerfBoard' CONFIG_SA1100_CERF - bool ' Include support for Compaq iPAQ H3600 (Bitsy)' CONFIG_SA1100_BITSY -# bool ' Include support for Empeg' CONFIG_SA1100_EMPEG -# bool ' Include support for Itsy' CONFIG_SA1100_ITSY - bool ' Include support for LART' CONFIG_SA1100_LART -# bool ' Include support for PLEB' CONFIG_SA1100_PLEB - bool ' Include support for ThinClient' CONFIG_SA1100_THINCLIENT - bool ' Include support for GraphicsClient' CONFIG_SA1100_GRAPHICSCLIENT - bool ' Include support for nanoEngine' CONFIG_SA1100_NANOENGINE - bool ' Include support for Victor' CONFIG_SA1100_VICTOR -# bool ' Include support for Tifon' CONFIG_SA1100_TIFON - bool ' Include support for XP860' CONFIG_SA1100_XP860 + bool ' Brutus' CONFIG_SA1100_BRUTUS + bool ' CerfBoard' CONFIG_SA1100_CERF + bool ' Compaq iPAQ H3600 (Bitsy)' CONFIG_SA1100_BITSY +# bool ' Empeg' CONFIG_SA1100_EMPEG +# bool ' Itsy' CONFIG_SA1100_ITSY + bool ' LART' CONFIG_SA1100_LART +# bool ' PLEB' CONFIG_SA1100_PLEB + bool ' ThinClient' CONFIG_SA1100_THINCLIENT + bool ' GraphicsClient' CONFIG_SA1100_GRAPHICSCLIENT + bool ' nanoEngine' CONFIG_SA1100_NANOENGINE + bool ' Victor' CONFIG_SA1100_VICTOR +# bool ' Tifon' CONFIG_SA1100_TIFON + bool ' XP860' CONFIG_SA1100_XP860 + # Someday, we'll support this as a general option. bool ' Load kernel using Angel Debug Monitor' CONFIG_ANGELBOOT # Determine if SA1111 support is required @@ -84,6 +97,7 @@ define_bool CONFIG_SA1111 y fi fi +endmenu # Definitions to make life easier if [ "$CONFIG_ARCH_ARCA5K" = "y" -o \ @@ -129,12 +143,14 @@ define_bool CONFIG_CPU_26 n fi +comment 'Processor Type' + # Select CPU and optimisation dependent on architecture if [ "$CONFIG_ARCH_RPC" = "y" ]; then define_bool CONFIG_CPU_32v3 y - bool 'Support ARM610' CONFIG_CPU_ARM6 - bool 'Support ARM710' CONFIG_CPU_ARM7 - bool 'Support StrongARM110' CONFIG_CPU_SA110 + bool 'Support ARM610 processor' CONFIG_CPU_ARM6 + bool 'Support ARM710 processor' CONFIG_CPU_ARM7 + bool 'Support StrongARM(R) SA-110 processor' CONFIG_CPU_SA110 fi if [ "$CONFIG_ARCH_EBSA110" = "y" -o \ "$CONFIG_FOOTBRIDGE" = "y" -o \ @@ -152,11 +168,33 @@ define_bool CONFIG_CPU_32v4 y define_bool CONFIG_CPU_ARM720 y fi +if [ "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then + define_bool CONFIG_CPU_32v4 y + bool 'Support ARM720 processor' CONFIG_CPU_ARM720 + bool 'Support ARM920 processor' CONFIG_CPU_ARM920 +# bool 'Support ARM10 processor' CONFIG_CPU_ARM10 +fi if [ "$CONFIG_ARCH_SA1100" = "y" ]; then define_bool CONFIG_CPU_32v4 y define_bool CONFIG_CPU_SA1100 y fi +if [ "$CONFIG_CPU_ARM920" = "y" ]; then + bool ' ARM920 CPU idle' CONFIG_CPU_ARM920_CPU_IDLE + bool ' ARM920 I-Cache on' CONFIG_CPU_ARM920_I_CACHE_ON + bool ' ARM920 D-Cache on' CONFIG_CPU_ARM920_D_CACHE_ON + if [ "$CONFIG_CPU_ARM920_D_CACHE_ON" = "y" ] ; then + bool ' Force write through caches on ARM920' CONFIG_CPU_ARM920_WRITETHROUGH + fi +fi +#if [ "$CONFIG_CPU_ARM10" = "y" ]; then +# bool ' ARM10 I-Cache on' CONFIG_CPU_ARM10_I_CACHE_ON +# bool ' ARM10 D-Cache on' CONFIG_CPU_ARM10_D_CACHE_ON +# if [ "$CONFIG_CPU_ARM10_D_CACHE_ON" = "y" ] ; then +# bool ' Force write through caches on ARM10' CONFIG_CPU_ARM10_FORCE_WRITE_THROUGH +# fi +#fi + # Select various configuration options depending on the machine type if [ "$CONFIG_ARCH_SA1100" = "y" ]; then define_bool CONFIG_DISCONTIGMEM y @@ -164,12 +202,21 @@ define_bool CONFIG_DISCONTIGMEM n fi +endmenu + +mainmenu_option next_comment +comment 'General setup' + # Now handle the bus types if [ "$CONFIG_ARCH_NEXUSPCI" = "y" -o \ "$CONFIG_FOOTBRIDGE_HOST" = "y" ]; then define_bool CONFIG_PCI y else - define_bool CONFIG_PCI n + if [ "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then + bool 'PCI support' CONFIG_PCI + else + define_bool CONFIG_PCI n + fi fi if [ "$CONFIG_FOOTBRIDGE_HOST" = "y" -o \ @@ -189,10 +236,7 @@ if [ "$CONFIG_SA1100_ASSABET" = "y" ]; then define_bool CONFIG_PC_KEYMAP y fi -endmenu -mainmenu_option next_comment -comment 'General setup' source drivers/pci/Config.in bool 'Support hot-pluggable devices' CONFIG_HOTPLUG if [ "$CONFIG_HOTPLUG" = "y" ]; then @@ -223,20 +267,23 @@ "$CONFIG_ARCH_SA1100" = "y" -o \ "$CONFIG_ARCH_CLPS7500" = "y" -o \ "$CONFIG_ARCH_PERSONAL_SERVER" = "y" -o \ - "$CONFIG_ARCH_CATS" = "y" ]; then + "$CONFIG_ARCH_CATS" = "y" -o \ + "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then string 'Default kernel command string' CONFIG_CMDLINE "" fi if [ "$CONFIG_ARCH_NETWINDER" = "y" -o \ "$CONFIG_ARCH_EBSA110" = "y" -o \ "$CONFIG_ARCH_EBSA285" = "y" -o \ "$CONFIG_ARCH_CO285" = "y" -o \ - "$CONFIG_ARCH_SA1100" = "y" ]; then + "$CONFIG_ARCH_SA1100" = "y" -o \ + "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then bool 'Timer and CPU usage LEDs' CONFIG_LEDS if [ "$CONFIG_LEDS" = "y" ]; then if [ "$CONFIG_ARCH_NETWINDER" = "y" -o \ "$CONFIG_ARCH_EBSA285" = "y" -o \ "$CONFIG_ARCH_CO285" = "y" -o \ - "$CONFIG_ARCH_SA1100" = "y" ]; then + "$CONFIG_ARCH_SA1100" = "y" -o \ + "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then bool ' Timer LED' CONFIG_LEDS_TIMER bool ' CPU usage LED' CONFIG_LEDS_CPU fi @@ -254,6 +301,7 @@ source drivers/mtd/Config.in source drivers/pnp/Config.in source drivers/block/Config.in +source drivers/md/Config.in if [ "$CONFIG_ARCH_ACORN" = "y" ]; then source drivers/acorn/block/Config.in @@ -322,10 +370,6 @@ fi fi -#source drivers/misc/Config.in - -source drivers/media/Config.in - source fs/Config.in if [ "$CONFIG_VT" = "y" ]; then @@ -354,7 +398,6 @@ fi source drivers/usb/Config.in -source drivers/input/Config.in mainmenu_option next_comment diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/def-configs/assabet linux/arch/arm/def-configs/assabet --- v2.4.0-test8/linux/arch/arm/def-configs/assabet Mon Jun 19 17:59:33 2000 +++ linux/arch/arm/def-configs/assabet Mon Sep 18 15:15:24 2000 @@ -2,20 +2,23 @@ # Automatically generated make config: don't edit # CONFIG_ARM=y +# CONFIG_SBUS is not set CONFIG_UID16=y # # Code maturity level options # CONFIG_EXPERIMENTAL=y +# CONFIG_OBSOLETE is not set # -# System and Processor Type +# System Type # # CONFIG_ARCH_ARC is not set # CONFIG_ARCH_A5K is not set +# CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_FOOTBRIDGE is not set +# CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_RPC is not set CONFIG_ARCH_SA1100=y @@ -24,25 +27,27 @@ # CONFIG_SA1100_ASSABET=y # CONFIG_ASSABET_NEPONSET is not set -# CONFIG_SA1100_BITSY is not set # CONFIG_SA1100_BRUTUS is not set +# CONFIG_SA1100_BITSY is not set # CONFIG_SA1100_LART is not set # CONFIG_SA1100_THINCLIENT is not set # CONFIG_SA1100_GRAPHICSCLIENT is not set # CONFIG_SA1100_VICTOR is not set -CONFIG_DISCONTIGMEM=y -CONFIG_SA1100_FREQUENCY_SCALE=y +CONFIG_ANGELBOOT=y +# CONFIG_SA1100_FREQUENCY_SCALE is not set # CONFIG_SA1100_VOLTAGE_SCALE is not set -# CONFIG_ARCH_ACORN is not set CONFIG_CPU_32=y # CONFIG_CPU_26 is not set CONFIG_CPU_32v4=y CONFIG_CPU_SA1100=y +# CONFIG_ARCH_ACORN is not set +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set +CONFIG_DISCONTIGMEM=y # CONFIG_PCI is not set # CONFIG_ISA is not set # CONFIG_ISA_DMA is not set -# CONFIG_SBUS is not set -CONFIG_ALIGNMENT_TRAP=y # # Loadable module support @@ -54,6 +59,15 @@ # # General setup # +CONFIG_HOTPLUG=y + +# +# PC Card support +# +CONFIG_PCMCIA=y +# CONFIG_PCMCIA_DEBUG is not set +CONFIG_SA1100_PCMCIA=y +CONFIG_VIRTUAL_BUS=y CONFIG_NET=y CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set @@ -64,34 +78,23 @@ # CONFIG_BINFMT_AOUT is not set CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set +# CONFIG_PM is not set # CONFIG_ARTHUR is not set - -# -# Parallel port support -# -# CONFIG_PARPORT is not set -CONFIG_CMDLINE="" +CONFIG_CMDLINE="keepinitrd" CONFIG_LEDS=y CONFIG_LEDS_TIMER=y CONFIG_LEDS_CPU=y -CONFIG_HOTPLUG=y +CONFIG_ALIGNMENT_TRAP=y # -# PC Card support +# Parallel port support # -CONFIG_PCMCIA=y -# CONFIG_PCMCIA_DEBUG is not set -CONFIG_SA1100_PCMCIA=y -CONFIG_VIRTUAL_BUS=y +# CONFIG_PARPORT is not set # -# I2O device support +# Memory Technology Devices (MTD) # -# CONFIG_I2O is not set -# CONFIG_I2O_BLOCK is not set -# CONFIG_I2O_LAN is not set -# CONFIG_I2O_SCSI is not set -# CONFIG_I2O_PROC is not set +# CONFIG_MTD is not set # # Plug and Play configuration @@ -113,92 +116,14 @@ # CONFIG_BLK_DEV_MD is not set # CONFIG_MD_LINEAR is not set # CONFIG_MD_RAID0 is not set -# CONFIG_RAID15_DANGEROUS is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y # CONFIG_BLK_DEV_FLASH is not set # -# Character devices -# -CONFIG_VT=y -# CONFIG_VT_CONSOLE is not set -CONFIG_SERIAL_SA1100=y -CONFIG_SERIAL_SA1100_CONSOLE=y -# CONFIG_SERIAL is not set -# CONFIG_SERIAL_EXTENDED is not set -# CONFIG_SERIAL_NONSTANDARD is not set -CONFIG_UNIX98_PTYS=y -CONFIG_UNIX98_PTY_COUNT=32 - -# -# I2C support -# -# CONFIG_I2C is not set - -# -# Mice -# -# CONFIG_BUSMOUSE is not set -# CONFIG_MOUSE is not set - -# -# Joysticks -# -# CONFIG_JOYSTICK is not set -# CONFIG_QIC02_TAPE is not set - -# -# Watchdog Cards -# -# CONFIG_WATCHDOG is not set -# CONFIG_NVRAM is not set -# CONFIG_RTC is not set - -# -# Video For Linux -# -# CONFIG_VIDEO_DEV is not set -# CONFIG_DTLK is not set -# CONFIG_R3964 is not set -# CONFIG_APPLICOM is not set - -# -# Ftape, the floppy tape device driver -# -# CONFIG_FTAPE is not set -# CONFIG_DRM is not set -# CONFIG_DRM_TDFX is not set -# CONFIG_PCMCIA_SERIAL is not set -# CONFIG_AGP is not set - -# -# Console drivers -# -# CONFIG_VGA_CONSOLE is not set -CONFIG_FB=y - -# -# Frame-buffer support -# -CONFIG_FB=y -CONFIG_DUMMY_CONSOLE=y -CONFIG_FB_SA1100=y -# CONFIG_FB_VIRTUAL is not set -# CONFIG_FBCON_ADVANCED is not set -CONFIG_FBCON_CFB2=y -CONFIG_FBCON_CFB4=y -CONFIG_FBCON_CFB8=y -CONFIG_FBCON_CFB16=y -CONFIG_FBCON_FONTWIDTH8_ONLY=y -CONFIG_FBCON_FONTS=y -CONFIG_FONT_8x8=y -# CONFIG_FONT_8x16 is not set -# CONFIG_FONT_SUN8x16 is not set -# CONFIG_FONT_PEARL_8x8 is not set -# CONFIG_FONT_ACORN_8x8 is not set - -# # Networking options # # CONFIG_PACKET is not set @@ -230,9 +155,9 @@ # 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_ECONET is not set # CONFIG_WAN_ROUTER is not set @@ -245,16 +170,6 @@ # CONFIG_NET_SCHED is not set # -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set - -# -# IrDA (infrared) support -# -# CONFIG_IRDA is not set - -# # Network device support # CONFIG_NETDEVICES=y @@ -329,6 +244,16 @@ CONFIG_PCMCIA_NETCARD=y # +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# # ATA/IDE/MFM/RLL support # CONFIG_IDE=y @@ -368,6 +293,7 @@ # CONFIG_BLK_DEV_ISAPNP is not set # CONFIG_IDE_CHIPSETS is not set # CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set # CONFIG_BLK_DEV_IDE_MODES is not set # @@ -376,22 +302,75 @@ # CONFIG_SCSI is not set # -# Sound +# I2O device support # -CONFIG_SOUND=y -CONFIG_SOUND_UDA1341=y -# CONFIG_SOUND_CMPCI is not set -# CONFIG_SOUND_EMU10K1 is not set -# CONFIG_SOUND_ES1370 is not set -# CONFIG_SOUND_ES1371 is not set -# CONFIG_SOUND_ESSSOLO1 is not set -# CONFIG_SOUND_MAESTRO is not set -# CONFIG_SOUND_SONICVIBES is not set -# CONFIG_SOUND_TRIDENT is not set -# CONFIG_SOUND_MSNDCLAS is not set -# CONFIG_SOUND_MSNDPIN is not set -# CONFIG_SOUND_VIA82CXXX is not set -# CONFIG_SOUND_OSS is not set +# CONFIG_I2O is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Character devices +# +CONFIG_VT=y +# CONFIG_VT_CONSOLE is not set +CONFIG_SERIAL_SA1100=y +CONFIG_SERIAL_SA1100_CONSOLE=y +# CONFIG_TOUCHSCREEN_SA1100 is not set +# CONFIG_TOUCHSCREEN_BITSY is not set +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=32 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_JOYSTICK is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set + +# +# Video For Linux +# +# CONFIG_VIDEO_DEV is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_DRM is not set +# CONFIG_DRM_TDFX is not set +# CONFIG_PCMCIA_SERIAL is not set +# CONFIG_AGP is not set # # File systems @@ -409,6 +388,7 @@ # 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 @@ -507,6 +487,51 @@ # CONFIG_NLS_KOI8_R is not set # +# Console drivers +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_FB=y + +# +# Frame-buffer support +# +CONFIG_FB=y +CONFIG_DUMMY_CONSOLE=y +CONFIG_FB_SA1100=y +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FBCON_ADVANCED is not set +CONFIG_FBCON_CFB2=y +CONFIG_FBCON_CFB4=y +CONFIG_FBCON_CFB8=y +CONFIG_FBCON_CFB16=y +CONFIG_FBCON_FONTWIDTH8_ONLY=y +CONFIG_FBCON_FONTS=y +CONFIG_FONT_8x8=y +# CONFIG_FONT_8x16 is not set +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set + +# +# Sound +# +CONFIG_SOUND=y +CONFIG_SOUND_UDA1341=y +# CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_EMU10K1 is not set +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_MAESTRO is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_TRIDENT is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set +# CONFIG_SOUND_OSS is not set +# CONFIG_SOUND_TVMIXER is not set + +# # USB support # # CONFIG_USB is not set @@ -517,6 +542,6 @@ CONFIG_FRAME_POINTER=y CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_USER=y -CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_INFO is not set # CONFIG_MAGIC_SYSRQ is not set # CONFIG_DEBUG_LL is not set diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/def-configs/brutus linux/arch/arm/def-configs/brutus --- v2.4.0-test8/linux/arch/arm/def-configs/brutus Mon Jun 19 17:59:33 2000 +++ linux/arch/arm/def-configs/brutus Mon Sep 18 15:15:24 2000 @@ -2,45 +2,51 @@ # Automatically generated make config: don't edit # CONFIG_ARM=y +# CONFIG_SBUS is not set CONFIG_UID16=y # # Code maturity level options # CONFIG_EXPERIMENTAL=y +# CONFIG_OBSOLETE is not set # -# System and processor type +# System Type # # CONFIG_ARCH_ARC is not set # CONFIG_ARCH_A5K is not set -# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_FOOTBRIDGE is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_RPC is not set CONFIG_ARCH_SA1100=y + +# +# SA11x0 Implementations +# # CONFIG_SA1100_ASSABET is not set CONFIG_SA1100_BRUTUS=y -# CONFIG_SA1100_EMPEG is not set -# CONFIG_SA1100_ITSY is not set # CONFIG_SA1100_BITSY is not set # CONFIG_SA1100_LART is not set -# CONFIG_SA1100_PLEB is not set # CONFIG_SA1100_THINCLIENT is not set # CONFIG_SA1100_GRAPHICSCLIENT is not set # CONFIG_SA1100_VICTOR is not set -# CONFIG_SA1100_TIFON is not set -CONFIG_DISCONTIGMEM=y -# CONFIG_ARCH_ACORN is not set +CONFIG_ANGELBOOT=y +# CONFIG_SA1100_FREQUENCY_SCALE is not set +# CONFIG_SA1100_VOLTAGE_SCALE is not set CONFIG_CPU_32=y # CONFIG_CPU_26 is not set CONFIG_CPU_32v4=y CONFIG_CPU_SA1100=y +# CONFIG_ARCH_ACORN is not set +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set +CONFIG_DISCONTIGMEM=y # CONFIG_PCI is not set # CONFIG_ISA is not set # CONFIG_ISA_DMA is not set -# CONFIG_SBUS is not set -# CONFIG_PCMCIA is not set -# CONFIG_ALIGNMENT_TRAP is not set # # Loadable module support @@ -52,34 +58,35 @@ # # General setup # +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set # CONFIG_NET is not set CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set -# CONFIG_SYSCTL is not set +CONFIG_SYSCTL=y CONFIG_NWFPE=y CONFIG_KCORE_ELF=y # CONFIG_KCORE_AOUT is not set CONFIG_BINFMT_AOUT=y CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set +# CONFIG_PM is not set # CONFIG_ARTHUR is not set +CONFIG_CMDLINE="keepinitrd" +CONFIG_LEDS=y +CONFIG_LEDS_TIMER=y +CONFIG_LEDS_CPU=y +# CONFIG_ALIGNMENT_TRAP is not set # # Parallel port support # # CONFIG_PARPORT is not set -CONFIG_CMDLINE="" -CONFIG_LEDS=y -CONFIG_LEDS_TIMER=y -CONFIG_LEDS_CPU=y # -# I2O device support +# Memory Technology Devices (MTD) # -# CONFIG_I2O is not set -# CONFIG_I2O_BLOCK is not set -# CONFIG_I2O_SCSI is not set -# CONFIG_I2O_PROC is not set +# CONFIG_MTD is not set # # Plug and Play configuration @@ -100,18 +107,48 @@ # CONFIG_BLK_DEV_LVM is not set # CONFIG_BLK_DEV_MD is not set # CONFIG_MD_LINEAR is not set -# CONFIG_MD_STRIPED is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y # CONFIG_BLK_DEV_FLASH is not set # +# ATA/IDE/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# # Character devices # CONFIG_VT=y # CONFIG_VT_CONSOLE is not set CONFIG_SERIAL_SA1100=y CONFIG_SERIAL_SA1100_CONSOLE=y +# CONFIG_TOUCHSCREEN_SA1100 is not set +# CONFIG_TOUCHSCREEN_BITSY is not set # CONFIG_SERIAL is not set # CONFIG_SERIAL_EXTENDED is not set # CONFIG_SERIAL_NONSTANDARD is not set @@ -139,6 +176,7 @@ # Watchdog Cards # # CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set # CONFIG_NVRAM is not set # CONFIG_RTC is not set @@ -159,43 +197,6 @@ # CONFIG_AGP is not set # -# Console drivers -# -# CONFIG_VGA_CONSOLE is not set -CONFIG_FB=y - -# -# Frame-buffer support -# -CONFIG_FB=y -CONFIG_DUMMY_CONSOLE=y -CONFIG_FB_SA1100=y -# CONFIG_FB_VIRTUAL is not set -# CONFIG_FBCON_ADVANCED is not set -CONFIG_FBCON_CFB2=y -CONFIG_FBCON_CFB4=y -CONFIG_FBCON_CFB8=y -CONFIG_FBCON_FONTWIDTH8_ONLY=y -CONFIG_FBCON_FONTS=y -CONFIG_FONT_8x8=y -# CONFIG_FONT_8x16 is not set -# CONFIG_FONT_SUN8x16 is not set -# CONFIG_FONT_PEARL_8x8 is not set -# CONFIG_FONT_ACORN_8x8 is not set - -# -# ATA/IDE/MFM/RLL support -# -# CONFIG_IDE is not set -# CONFIG_BLK_DEV_IDE_MODES is not set -# CONFIG_BLK_DEV_HD is not set - -# -# SCSI support -# -# CONFIG_SCSI is not set - -# # File systems # # CONFIG_QUOTA is not set @@ -211,6 +212,7 @@ # 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 @@ -242,6 +244,37 @@ # CONFIG_PARTITION_ADVANCED is not set CONFIG_MSDOS_PARTITION=y # CONFIG_NLS is not set + +# +# Console drivers +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_FB=y + +# +# Frame-buffer support +# +CONFIG_FB=y +CONFIG_DUMMY_CONSOLE=y +CONFIG_FB_SA1100=y +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FBCON_ADVANCED is not set +CONFIG_FBCON_CFB2=y +CONFIG_FBCON_CFB4=y +CONFIG_FBCON_CFB8=y +CONFIG_FBCON_CFB16=y +CONFIG_FBCON_FONTWIDTH8_ONLY=y +CONFIG_FBCON_FONTS=y +CONFIG_FONT_8x8=y +# CONFIG_FONT_8x16 is not set +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set + +# +# Sound +# +# CONFIG_SOUND is not set # # USB support diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/def-configs/cerf linux/arch/arm/def-configs/cerf --- v2.4.0-test8/linux/arch/arm/def-configs/cerf Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/def-configs/cerf Mon Sep 18 15:15:24 2000 @@ -0,0 +1,423 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_ARM=y +# CONFIG_SBUS is not set +CONFIG_UID16=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_OBSOLETE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +# CONFIG_KMOD is not set + +# +# System Type +# +# CONFIG_ARCH_ARC is not set +# CONFIG_ARCH_A5K is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_RPC is not set +CONFIG_ARCH_SA1100=y + +# +# SA11x0 Implementations +# +# CONFIG_SA1100_ASSABET is not set +# CONFIG_SA1100_BRUTUS is not set +CONFIG_SA1100_CERF=y +# CONFIG_SA1100_BITSY is not set +# CONFIG_SA1100_LART is not set +# CONFIG_SA1100_THINCLIENT is not set +# CONFIG_SA1100_GRAPHICSCLIENT is not set +# CONFIG_SA1100_VICTOR is not set +# CONFIG_ANGELBOOT is not set +# CONFIG_SA1100_FREQUENCY_SCALE is not set +# CONFIG_SA1100_VOLTAGE_SCALE is not set +CONFIG_CPU_32=y +# CONFIG_CPU_26 is not set +CONFIG_CPU_32v4=y +CONFIG_CPU_SA1100=y +# CONFIG_ARCH_ACORN is not set +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set +CONFIG_DISCONTIGMEM=y +# CONFIG_PCI is not set +# CONFIG_ISA is not set +# CONFIG_ISA_DMA is not set + +# +# General setup +# +CONFIG_HOTPLUG=y + +# +# PC Card support +# +CONFIG_PCMCIA=y +# CONFIG_PCMCIA_DEBUG is not set +CONFIG_SA1100_PCMCIA=y +CONFIG_VIRTUAL_BUS=y +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +CONFIG_NWFPE=y +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_PM is not set +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="keepinitrd" +CONFIG_LEDS=y +CONFIG_LEDS_TIMER=y +CONFIG_LEDS_CPU=y +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_LVM is not set +# CONFIG_BLK_DEV_MD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_INITRD=y +CONFIG_BLK_DEV_FLASH=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP 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_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 + +# +# 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_NET_SB1000 is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_CERF_CS8900A=y +# CONFIG_ARM_AM79C961A is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_PCI is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_YELLOWFIN is not set +# CONFIG_ACENIC is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# PCMCIA network device support +# +# CONFIG_NET_PCMCIA is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +CONFIG_BLK_DEV_IDECS=y +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set +# CONFIG_BLK_DEV_IDE_MODES is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# I2O device support +# +# CONFIG_I2O is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_SERIAL_SA1100=y +CONFIG_SERIAL_SA1100_CONSOLE=y +# CONFIG_TOUCHSCREEN_UCB1200 is not set +# CONFIG_TOUCHSCREEN_BITSY is not set +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=32 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_JOYSTICK is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set + +# +# Video For Linux +# +# CONFIG_VIDEO_DEV is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_DRM is not set +# CONFIG_PCMCIA_SERIAL is not set +# CONFIG_AGP is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_FAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_RAMFS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +# CONFIG_NFSD is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL 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 + +# +# Sound +# +CONFIG_SOUND=y +# CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_EMU10K1 is not set +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_MAESTRO is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_TRIDENT is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_OSS is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# Kernel hacking +# +CONFIG_FRAME_POINTER=y +CONFIG_DEBUG_ERRORS=y +CONFIG_DEBUG_USER=y +# CONFIG_DEBUG_INFO is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_DEBUG_LL is not set diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/def-configs/clps7500 linux/arch/arm/def-configs/clps7500 --- v2.4.0-test8/linux/arch/arm/def-configs/clps7500 Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/def-configs/clps7500 Mon Sep 18 15:15:24 2000 @@ -0,0 +1,490 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_ARM=y +# CONFIG_SBUS is not set +CONFIG_UID16=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +CONFIG_OBSOLETE=y + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# System Type +# +# CONFIG_ARCH_ARCA5K is not set +CONFIG_ARCH_CLPS7500=y +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_FTVPCI is not set +# CONFIG_ARCH_TBOX is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_ACORN is not set +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set +CONFIG_CPU_32=y +# CONFIG_CPU_26 is not set +CONFIG_CPU_32v3=y +CONFIG_CPU_ARM7=y +# CONFIG_DISCONTIGMEM is not set +# CONFIG_PCI is not set +# CONFIG_ISA is not set +# CONFIG_ISA_DMA is not set + +# +# General setup +# +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_SYSCTL is not set +CONFIG_NWFPE=y +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_PM is not set +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="root=/dev/nfs rw" +# CONFIG_ALIGNMENT_TRAP is not set + +# +# Parallel port support +# +CONFIG_PARPORT=y +CONFIG_PARPORT_PC=y +CONFIG_PARPORT_PC_FIFO=y +# CONFIG_PARPORT_PC_SUPERIO is not set +# CONFIG_PARPORT_AMIGA is not set +# CONFIG_PARPORT_MFC3 is not set +# CONFIG_PARPORT_ATARI is not set +# CONFIG_PARPORT_SUNBPP is not set +# CONFIG_PARPORT_OTHER is not set +CONFIG_PARPORT_1284=y + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DOC1000 is not set +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOCPROBE is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_MTDRAM is not set + +# +# MTD drivers for mapped chips +# +# CONFIG_MTD_CFI is not set +# CONFIG_MTD_CFI_INTELEXT is not set +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_JEDEC is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_PHYSMAP is not set + +# +# Drivers for chip mappings +# +# CONFIG_MTD_MIXMEM is not set +# CONFIG_MTD_NORA is not set +# CONFIG_MTD_OCTAGON is not set +# CONFIG_MTD_PNC2000 is not set +# CONFIG_MTD_RPXLITE is not set +# CONFIG_MTD_VMAX is not set + +# +# User modules and translation layers for MTD devices +# +# CONFIG_MTD_CHAR is not set +# CONFIG_MTD_BLOCK is not set +# CONFIG_FTL is not set +# CONFIG_NFTL is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_LVM is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +# CONFIG_BLK_DEV_INITRD is not set +CONFIG_BLK_DEV_FLD7500=y + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_IP_ROUTER is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_ALIAS is not set +# CONFIG_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 + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +CONFIG_DUMMY=y +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_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_YELLOWFIN is not set +# CONFIG_ACENIC is not set +# CONFIG_SK98LIN is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +CONFIG_PPP=y +# CONFIG_PPP_MULTILINK is not set +# CONFIG_PPP_ASYNC is not set +# CONFIG_PPP_SYNC_TTY is not set +# CONFIG_PPP_DEFLATE is not set +# CONFIG_PPP_BSDCOMP is not set +# CONFIG_PPPOE is not set +CONFIG_SLIP=y +CONFIG_SLIP_COMPRESSED=y +# CONFIG_SLIP_SMART is not set +# CONFIG_SLIP_MODE_SLIP6 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 +# CONFIG_ASH is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ATA/IDE/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_SERIAL=y +# CONFIG_SERIAL_CONSOLE is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 +CONFIG_PRINTER=y +CONFIG_LP_CONSOLE=y +# CONFIG_PPDEV is not set + +# +# I2C support +# +CONFIG_I2C=y +CONFIG_I2C_ALGOBIT=y +# CONFIG_I2C_PHILIPSPAR is not set +# CONFIG_I2C_ELV is not set +# CONFIG_I2C_VELLEMAN is not set +# CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_CHARDEV is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +CONFIG_MOUSE=y +CONFIG_PSMOUSE=y +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set + +# +# Joysticks +# +# CONFIG_JOYSTICK is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +CONFIG_CLPS7500_FLASH=y +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set + +# +# Video For Linux +# +# CONFIG_VIDEO_DEV is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set +# CONFIG_AGP is not set +# CONFIG_DRM 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 is not set +# CONFIG_RAMFS is not set +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +CONFIG_MINIX_FS=y +# 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=y +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_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=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_MSDOS_PARTITION 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 + +# +# Console drivers +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_FB=y + +# +# Frame-buffer support +# +CONFIG_FB=y +CONFIG_DUMMY_CONSOLE=y +CONFIG_FB_ACORN=y +# CONFIG_CHRONTEL_7003 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_VIRTUAL is not set +CONFIG_FBCON_ADVANCED=y +# CONFIG_FBCON_MFB is not set +# CONFIG_FBCON_CFB2 is not set +# CONFIG_FBCON_CFB4 is not set +CONFIG_FBCON_CFB8=y +# CONFIG_FBCON_CFB16 is not set +# CONFIG_FBCON_CFB24 is not set +# CONFIG_FBCON_CFB32 is not set +# CONFIG_FBCON_AFB is not set +# CONFIG_FBCON_ILBM is not set +# CONFIG_FBCON_IPLAN2P2 is not set +# CONFIG_FBCON_IPLAN2P4 is not set +# CONFIG_FBCON_IPLAN2P8 is not set +# CONFIG_FBCON_MAC is not set +# CONFIG_FBCON_VGA_PLANES is not set +# CONFIG_FBCON_VGA is not set +# CONFIG_FBCON_HGA is not set +# CONFIG_FBCON_FONTWIDTH8_ONLY is not set +# CONFIG_FBCON_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# Kernel hacking +# +# CONFIG_FRAME_POINTER is not set +# CONFIG_DEBUG_ERRORS is not set +# CONFIG_DEBUG_USER is not set +# CONFIG_DEBUG_INFO is not set +CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_LL is not set diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/def-configs/lart linux/arch/arm/def-configs/lart --- v2.4.0-test8/linux/arch/arm/def-configs/lart Mon Jun 19 17:59:33 2000 +++ linux/arch/arm/def-configs/lart Mon Sep 18 15:15:24 2000 @@ -2,53 +2,62 @@ # Automatically generated by make menuconfig: don't edit # CONFIG_ARM=y +# CONFIG_SBUS is not set CONFIG_UID16=y # # Code maturity level options # CONFIG_EXPERIMENTAL=y +# CONFIG_OBSOLETE is not set # -# System and Processor Type +# Loadable module support # -# CONFIG_ARCH_ARC is not set -# CONFIG_ARCH_A5K is not set +CONFIG_MODULES=y +CONFIG_MODVERSIONS=y +# CONFIG_KMOD is not set + +# +# System Type +# +# CONFIG_ARCH_ARCA5K is not set +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CO285 is not set # CONFIG_ARCH_EBSA110 is not set -# CONFIG_FOOTBRIDGE is not set +# CONFIG_ARCH_FOOTBRIDGE is not set # CONFIG_ARCH_RPC is not set CONFIG_ARCH_SA1100=y # CONFIG_SA1100_ASSABET is not set -# CONFIG_SA1100_BITSY is not set # CONFIG_SA1100_BRUTUS is not set +# CONFIG_SA1100_CERF is not set +# CONFIG_SA1100_BITSY is not set CONFIG_SA1100_LART=y # CONFIG_SA1100_THINCLIENT is not set # CONFIG_SA1100_GRAPHICSCLIENT is not set +# CONFIG_SA1100_NANOENGINE is not set # CONFIG_SA1100_VICTOR is not set -CONFIG_DISCONTIGMEM=y +# CONFIG_ANGELBOOT is not set CONFIG_SA1100_FREQUENCY_SCALE=m CONFIG_SA1100_VOLTAGE_SCALE=y # CONFIG_ARCH_ACORN is not set +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set CONFIG_CPU_32=y # CONFIG_CPU_26 is not set CONFIG_CPU_32v4=y CONFIG_CPU_SA1100=y +CONFIG_DISCONTIGMEM=y # CONFIG_PCI is not set # CONFIG_ISA is not set # CONFIG_ISA_DMA is not set -# CONFIG_SBUS is not set -CONFIG_ALIGNMENT_TRAP=y - -# -# Loadable module support -# -CONFIG_MODULES=y -CONFIG_MODVERSIONS=y -# CONFIG_KMOD is not set # # General setup # +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set CONFIG_NET=y CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set @@ -59,26 +68,23 @@ CONFIG_BINFMT_AOUT=y CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set +CONFIG_PM=y # CONFIG_ARTHUR is not set +CONFIG_CMDLINE="console=ttyS0,9600" +CONFIG_LEDS=y +# CONFIG_LEDS_TIMER is not set +CONFIG_LEDS_CPU=y +CONFIG_ALIGNMENT_TRAP=y # # Parallel port support # # CONFIG_PARPORT is not set -CONFIG_CMDLINE="console=ttyS0,9600" -CONFIG_LEDS=y -# CONFIG_LEDS_TIMER is not set -CONFIG_LEDS_CPU=y -# CONFIG_HOTPLUG is not set # -# I2O device support +# Memory Technology Devices (MTD) # -# CONFIG_I2O is not set -# CONFIG_I2O_BLOCK is not set -# CONFIG_I2O_LAN is not set -# CONFIG_I2O_SCSI is not set -# CONFIG_I2O_PROC is not set +# CONFIG_MTD is not set # # Plug and Play configuration @@ -100,66 +106,18 @@ # CONFIG_BLK_DEV_MD is not set # CONFIG_MD_LINEAR is not set # CONFIG_MD_RAID0 is not set -# CONFIG_RAID15_DANGEROUS is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y -# CONFIG_BLK_DEV_FLASH is not set - -# -# Character devices -# -# CONFIG_VT is not set -CONFIG_SERIAL_SA1100=y -CONFIG_SERIAL_SA1100_CONSOLE=y -# CONFIG_SERIAL is not set -# CONFIG_SERIAL_EXTENDED is not set -# CONFIG_SERIAL_NONSTANDARD is not set -# CONFIG_UNIX98_PTYS is not set - -# -# I2C support -# -# CONFIG_I2C is not set - -# -# Mice -# -# CONFIG_BUSMOUSE is not set -# CONFIG_MOUSE is not set - -# -# Joysticks -# -# CONFIG_JOYSTICK is not set -# CONFIG_QIC02_TAPE is not set - -# -# Watchdog Cards -# -# CONFIG_WATCHDOG is not set -# CONFIG_NVRAM is not set -# CONFIG_RTC is not set - -# -# Video For Linux -# -# CONFIG_VIDEO_DEV is not set -# CONFIG_DTLK is not set -# CONFIG_R3964 is not set -# CONFIG_APPLICOM is not set - -# -# Ftape, the floppy tape device driver -# -# CONFIG_FTAPE is not set -# CONFIG_DRM is not set -# CONFIG_DRM_TDFX is not set -# CONFIG_AGP is not set +CONFIG_BLK_DEV_FLASH=m # # Networking options # -# CONFIG_PACKET is not set +CONFIG_PACKET=m +# CONFIG_PACKET_MMAP is not set # CONFIG_NETLINK is not set # CONFIG_NETFILTER is not set # CONFIG_FILTER is not set @@ -172,17 +130,17 @@ # 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 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_BRIDGE is not set # CONFIG_LLC is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set @@ -195,16 +153,6 @@ # CONFIG_NET_SCHED is not set # -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set - -# -# IrDA (infrared) support -# -# CONFIG_IRDA is not set - -# # Network device support # CONFIG_NETDEVICES=y @@ -221,7 +169,37 @@ # # Ethernet (10 or 100Mbit) # -# CONFIG_NET_ETHERNET is not set +CONFIG_NET_ETHERNET=y +# CONFIG_ARM_AM79C961A is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_AC3200 is not set +# CONFIG_APRICOT is not set +CONFIG_CS89x0=m +# CONFIG_DE4X5 is not set +# CONFIG_TULIP is not set +# CONFIG_DGRS is not set +# CONFIG_DM9102 is not set +# CONFIG_EEPRO100 is not set +# CONFIG_LNE390 is not set +# CONFIG_NE3210 is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_RTL8129 is not set +# CONFIG_8139TOO is not set +# CONFIG_SIS900 is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_ES3210 is not set +# CONFIG_EPIC100 is not set +# CONFIG_NET_POCKET is not set # # Ethernet (1000 Mbit) @@ -262,11 +240,49 @@ # CONFIG_WAN is not set # +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# # ATA/IDE/MFM/RLL support # -# CONFIG_IDE is not set -# CONFIG_BLK_DEV_IDE_MODES is not set +CONFIG_IDE=m + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=m +# CONFIG_BLK_DEV_HD_IDE is not set # CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=m +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set +# CONFIG_BLK_DEV_IDECS is not set +CONFIG_BLK_DEV_IDECD=m +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set +# CONFIG_BLK_DEV_IDE_MODES is not set # # SCSI support @@ -274,54 +290,71 @@ # CONFIG_SCSI is not set # -# Sound +# I2O device support # -CONFIG_SOUND=m -# CONFIG_SOUND_CMPCI is not set -# CONFIG_SOUND_EMU10K1 is not set -# CONFIG_SOUND_ES1370 is not set -# CONFIG_SOUND_ES1371 is not set -# CONFIG_SOUND_ESSSOLO1 is not set -# CONFIG_SOUND_MAESTRO is not set -# CONFIG_SOUND_SONICVIBES is not set -# CONFIG_SOUND_TRIDENT is not set -# CONFIG_SOUND_MSNDCLAS is not set -# CONFIG_SOUND_MSNDPIN is not set -# CONFIG_SOUND_VIA82CXXX is not set -CONFIG_SOUND_OSS=m -CONFIG_SOUND_TRACEINIT=y -# CONFIG_SOUND_DMAP is not set -# CONFIG_SOUND_AD1816 is not set -# CONFIG_SOUND_SGALAXY is not set -# CONFIG_SOUND_ADLIB is not set -# CONFIG_SOUND_ACI_MIXER is not set -# CONFIG_SOUND_CS4232 is not set -# CONFIG_SOUND_SSCAPE is not set -# CONFIG_SOUND_GUS is not set -# CONFIG_SOUND_ICH is not set -# CONFIG_SOUND_VMIDI is not set -# CONFIG_SOUND_TRIX is not set -# CONFIG_SOUND_MSS is not set -# CONFIG_SOUND_MPU401 is not set -# CONFIG_SOUND_NM256 is not set -# CONFIG_SOUND_MAD16 is not set -# CONFIG_SOUND_PAS is not set -# CONFIG_PAS_JOYSTICK is not set -# CONFIG_SOUND_PSS is not set -# CONFIG_SOUND_SOFTOSS is not set -# CONFIG_SOUND_SB is not set -# CONFIG_SOUND_AWE32_SYNTH is not set -# CONFIG_SOUND_WAVEFRONT is not set -# CONFIG_SOUND_MAUI is not set -# CONFIG_SOUND_YM3812 is not set -# CONFIG_SOUND_OPL3SA1 is not set -# CONFIG_SOUND_OPL3SA2 is not set -# CONFIG_SOUND_YMPCI is not set -# CONFIG_SOUND_UART6850 is not set -# CONFIG_SOUND_AEDSP16 is not set -# CONFIG_SOUND_VIDC is not set -# CONFIG_SOUND_WAVEARTIST is not set -CONFIG_SOUND_SA1100_SSP=m +# CONFIG_I2O is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_SERIAL_SA1100=y +CONFIG_SERIAL_SA1100_CONSOLE=y +CONFIG_TOUCHSCREEN_UCB1200=m +# CONFIG_TOUCHSCREEN_BITSY 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 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_JOYSTICK is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set + +# +# Video For Linux +# +# CONFIG_VIDEO_DEV is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set # # File systems @@ -339,6 +372,7 @@ # 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 @@ -367,13 +401,13 @@ # Network File Systems # # CONFIG_CODA_FS is not set -# CONFIG_NFS_FS is not set +CONFIG_NFS_FS=m # 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_SUNRPC=m +CONFIG_LOCKD=m # CONFIG_SMB_FS is not set # CONFIG_NCP_FS is not set # CONFIG_NCPFS_PACKET_SIGNING is not set @@ -395,6 +429,57 @@ # CONFIG_NLS is not set # +# Sound +# +CONFIG_SOUND=m +# CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_EMU10K1 is not set +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_MAESTRO is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_TRIDENT is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set +CONFIG_SOUND_OSS=m +CONFIG_SOUND_TRACEINIT=y +# CONFIG_SOUND_DMAP is not set +# CONFIG_SOUND_AD1816 is not set +# CONFIG_SOUND_SGALAXY is not set +# CONFIG_SOUND_ADLIB is not set +# CONFIG_SOUND_ACI_MIXER is not set +# CONFIG_SOUND_CS4232 is not set +# CONFIG_SOUND_SSCAPE is not set +# CONFIG_SOUND_GUS is not set +# CONFIG_SOUND_ICH is not set +# CONFIG_SOUND_VMIDI is not set +# CONFIG_SOUND_TRIX is not set +# CONFIG_SOUND_MSS is not set +# CONFIG_SOUND_MPU401 is not set +# CONFIG_SOUND_NM256 is not set +# CONFIG_SOUND_MAD16 is not set +# CONFIG_SOUND_PAS is not set +# CONFIG_PAS_JOYSTICK is not set +# CONFIG_SOUND_PSS is not set +# CONFIG_SOUND_SOFTOSS is not set +# CONFIG_SOUND_SB is not set +# CONFIG_SOUND_AWE32_SYNTH is not set +# CONFIG_SOUND_WAVEFRONT is not set +# CONFIG_SOUND_MAUI is not set +# CONFIG_SOUND_YM3812 is not set +# CONFIG_SOUND_OPL3SA1 is not set +# CONFIG_SOUND_OPL3SA2 is not set +# CONFIG_SOUND_YMPCI is not set +# CONFIG_SOUND_UART6850 is not set +# CONFIG_SOUND_AEDSP16 is not set +# CONFIG_SOUND_VIDC is not set +# CONFIG_SOUND_WAVEARTIST is not set +CONFIG_SOUND_SA1100_SSP=m +# CONFIG_SOUND_TVMIXER is not set + +# # USB support # # CONFIG_USB is not set @@ -406,5 +491,5 @@ CONFIG_DEBUG_ERRORS=y CONFIG_DEBUG_USER=y # CONFIG_DEBUG_INFO is not set -# CONFIG_MAGIC_SYSRQ is not set +CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_LL=y diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/def-configs/shark linux/arch/arm/def-configs/shark --- v2.4.0-test8/linux/arch/arm/def-configs/shark Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/def-configs/shark Mon Sep 18 15:15:24 2000 @@ -0,0 +1,655 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_ARM=y +# CONFIG_SBUS is not set +CONFIG_UID16=y + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_OBSOLETE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# System Type +# +# CONFIG_ARCH_ARCA5K is not set +# CONFIG_ARCH_CLPS7500 is not set +# CONFIG_ARCH_CO285 is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_FTVPCI is not set +# CONFIG_ARCH_TBOX is not set +CONFIG_ARCH_SHARK=y +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_ACORN is not set +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set +CONFIG_CPU_32=y +# CONFIG_CPU_26 is not set +CONFIG_CPU_32v4=y +CONFIG_CPU_SA110=y +# CONFIG_DISCONTIGMEM is not set +CONFIG_PCI=y +CONFIG_ISA=y +CONFIG_ISA_DMA=y +CONFIG_PC_KEYB=y +CONFIG_PC_KEYMAP=y + +# +# General setup +# +# CONFIG_PCI_NAMES is not set +# CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +CONFIG_NWFPE=y +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_PM is not set +# CONFIG_ARTHUR is not set +CONFIG_LEDS=y +CONFIG_LEDS_TIMER=y +# CONFIG_LEDS_CPU is not set +# CONFIG_ALIGNMENT_TRAP is not set + +# +# Parallel port support +# +CONFIG_PARPORT=y +CONFIG_PARPORT_PC=y +# CONFIG_PARPORT_PC_FIFO is not set +# CONFIG_PARPORT_PC_SUPERIO is not set +# CONFIG_PARPORT_AMIGA is not set +# CONFIG_PARPORT_MFC3 is not set +# CONFIG_PARPORT_ATARI is not set +# CONFIG_PARPORT_SUNBPP is not set +# CONFIG_PARPORT_OTHER is not set +# CONFIG_PARPORT_1284 is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_LVM is not set +# CONFIG_BLK_DEV_MD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +# 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_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_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 + +# +# 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_NET_SB1000 is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_ARM_AM79C961A is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_AC3200 is not set +# CONFIG_APRICOT is not set +CONFIG_CS89x0=y +# CONFIG_DE4X5 is not set +# CONFIG_TULIP is not set +# CONFIG_DGRS is not set +# CONFIG_DM9102 is not set +# CONFIG_EEPRO100 is not set +# CONFIG_LNE390 is not set +# CONFIG_NE3210 is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_RTL8129 is not set +# CONFIG_8139TOO is not set +# CONFIG_SIS900 is not set +# CONFIG_TLAN is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_ES3210 is not set +# CONFIG_EPIC100 is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_YELLOWFIN is not set +# CONFIG_ACENIC 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 +# CONFIG_ASH is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ATA/IDE/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +CONFIG_BLK_DEV_IDECD=y +# CONFIG_BLK_DEV_IDETAPE is not set +CONFIG_BLK_DEV_IDEFLOPPY=y +# CONFIG_BLK_DEV_IDESCSI is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_RZ1000 is not set +# CONFIG_BLK_DEV_IDEPCI is not set +# CONFIG_BLK_DEV_SL82C105 is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set +# CONFIG_BLK_DEV_IDE_MODES is not set + +# +# SCSI support +# +CONFIG_SCSI=m + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=m +CONFIG_SD_EXTRA_DEVS=40 +CONFIG_CHR_DEV_ST=m +CONFIG_BLK_DEV_SR=m +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_SR_EXTRA_DEVS=2 +CONFIG_CHR_DEV_SG=m + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_DEBUG_QUEUES is not set +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI low-level drivers +# +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_AM53C974 is not set +# CONFIG_SCSI_MEGARAID is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_DMA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_PPA is not set +# CONFIG_SCSI_IMM is not set +# CONFIG_SCSI_NCR53C406A is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_SIM710 is not set +# CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_NCR53C8XX is not set +# CONFIG_SCSI_SYM53C8XX is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_QLOGIC_ISP is not set +# CONFIG_SCSI_QLOGIC_FC is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_DEBUG is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_UNIX98_PTYS is not set +CONFIG_PRINTER=m +# CONFIG_LP_CONSOLE is not set +# CONFIG_PPDEV is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +CONFIG_MOUSE=y +CONFIG_PSMOUSE=y +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set + +# +# Joysticks +# +CONFIG_JOYSTICK=y +CONFIG_INPUT_JOYDEV=y + +# +# Game port support +# +# CONFIG_INPUT_NS558 is not set +# CONFIG_INPUT_LIGHTNING is not set +# CONFIG_INPUT_PCIGAME is not set + +# +# Gameport joysticks +# +# CONFIG_INPUT_ANALOG is not set +# CONFIG_INPUT_A3D is not set +# CONFIG_INPUT_ADI is not set +# CONFIG_INPUT_COBRA is not set +# CONFIG_INPUT_GF2K is not set +# CONFIG_INPUT_GRIP is not set +# CONFIG_INPUT_INTERACT is not set +# CONFIG_INPUT_TMDC is not set +# CONFIG_INPUT_SIDEWINDER is not set + +# +# Serial port support +# +# CONFIG_INPUT_SERPORT is not set + +# +# Serial port joysticks +# +# CONFIG_INPUT_WARRIOR is not set +# CONFIG_INPUT_MAGELLAN is not set +# CONFIG_INPUT_SPACEORB is not set +# CONFIG_INPUT_SPACEBALL is not set +# CONFIG_INPUT_IFORCE_232 is not set + +# +# Parallel port joysticks +# +# CONFIG_INPUT_DB9 is not set +# CONFIG_INPUT_GAMECON is not set +# CONFIG_INPUT_TURBOGRAFX is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +CONFIG_RTC=y + +# +# Video For Linux +# +# CONFIG_VIDEO_DEV is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BFS_FS is not set +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +# CONFIG_UMSDOS_FS is not set +CONFIG_VFAT_FS=y +# CONFIG_EFS_FS is not set +CONFIG_JFFS_FS_VERBOSE=0 +# CONFIG_CRAMFS is not set +# CONFIG_RAMFS is not set +CONFIG_ISO9660_FS=y +CONFIG_JOLIET=y +# CONFIG_MINIX_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_ROMFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +# CONFIG_NFSD is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +CONFIG_NLS_CODEPAGE_850=y +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_UTF8 is not set + +# +# Console drivers +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_FB=y + +# +# Frame-buffer support +# +CONFIG_FB=y +CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_RIVA is not set +# CONFIG_FB_CLGEN is not set +# CONFIG_FB_PM2 is not set +CONFIG_FB_CYBER2000=y +# CONFIG_FB_MATROX is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FBCON_ADVANCED is not set +CONFIG_FBCON_CFB8=y +CONFIG_FBCON_CFB16=y +CONFIG_FBCON_CFB24=y +# CONFIG_FBCON_FONTWIDTH8_ONLY is not set +# CONFIG_FBCON_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y + +# +# Sound +# +CONFIG_SOUND=m +# CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_EMU10K1 is not set +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_MAESTRO is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_TRIDENT is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set +CONFIG_SOUND_OSS=m +# CONFIG_SOUND_TRACEINIT is not set +# CONFIG_SOUND_DMAP is not set +# CONFIG_SOUND_AD1816 is not set +# CONFIG_SOUND_SGALAXY is not set +# CONFIG_SOUND_ADLIB is not set +# CONFIG_SOUND_ACI_MIXER is not set +# CONFIG_SOUND_CS4232 is not set +# CONFIG_SOUND_SSCAPE is not set +# CONFIG_SOUND_GUS is not set +# CONFIG_SOUND_ICH is not set +# CONFIG_SOUND_VMIDI is not set +# CONFIG_SOUND_TRIX is not set +# CONFIG_SOUND_MSS is not set +# CONFIG_SOUND_MPU401 is not set +# CONFIG_SOUND_NM256 is not set +# CONFIG_SOUND_MAD16 is not set +# CONFIG_SOUND_PAS is not set +# CONFIG_SOUND_PSS is not set +# CONFIG_SOUND_SOFTOSS is not set +CONFIG_SOUND_SB=m +# CONFIG_SOUND_AWE32_SYNTH is not set +# CONFIG_SOUND_WAVEFRONT is not set +# CONFIG_SOUND_MAUI is not set +# CONFIG_SOUND_YM3812 is not set +# CONFIG_SOUND_OPL3SA1 is not set +# CONFIG_SOUND_OPL3SA2 is not set +# CONFIG_SOUND_YMPCI is not set +# CONFIG_SOUND_UART6850 is not set +# CONFIG_SOUND_AEDSP16 is not set +# CONFIG_SOUND_VIDC is not set +# CONFIG_SOUND_WAVEARTIST is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# Kernel hacking +# +# CONFIG_FRAME_POINTER is not set +CONFIG_DEBUG_ERRORS=y +CONFIG_DEBUG_USER=y +# CONFIG_DEBUG_INFO is not set +# CONFIG_MAGIC_SYSRQ is not set +CONFIG_DEBUG_LL=y diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/kernel/Makefile linux/arch/arm/kernel/Makefile --- v2.4.0-test8/linux/arch/arm/kernel/Makefile Sun Aug 13 09:54:15 2000 +++ linux/arch/arm/kernel/Makefile Mon Sep 18 15:15:24 2000 @@ -15,10 +15,18 @@ O_OBJS_arc = dma-arc.o oldlatches.o O_OBJS_rpc = dma-rpc.o -O_OBJS_footbridge = dma-footbridge.o hw-footbridge.o isa.o -O_OBJS_sa1100 = hw-sa1100.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 + +pci-$(CONFIG_ARCH_NEXUSPCI) += ftv-pci.o + + O_TARGET := kernel.o # Object file lists. @@ -30,21 +38,18 @@ obj-n := obj- := -export-objs := armksyms.o dma.o ecard.o hw-footbridge.o \ - hw-sa1100.o leds-$(MACHINE).o oldlatches.o +export-objs := armksyms.o dma.o ecard.o \ + $(leds-$(MACHINE)) oldlatches.o \ + time.o 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).o +obj-$(CONFIG_LEDS) += $(leds-$(MACHINE)) obj-$(CONFIG_ARTHUR) += arthur.o obj-$(CONFIG_ISA_DMA) += dma-isa.o -ifeq ($(MACHINE),nexuspci) - obj-$(CONFIG_PCI) += plx9080.o -else - obj-$(CONFIG_PCI) += bios32.o dec21285.o -endif +obj-$(CONFIG_PCI) += bios32.o $(pci-$(MACHINE)) $(pci-y) # Files that are both resident and modular; remove from modular. diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/kernel/arch.c linux/arch/arm/kernel/arch.c --- v2.4.0-test8/linux/arch/arm/kernel/arch.c Sun Aug 13 09:54:15 2000 +++ linux/arch/arm/kernel/arch.c Mon Sep 18 15:15:24 2000 @@ -1,10 +1,10 @@ /* - * linux/arch/arm/kernel/arch.c + * linux/arch/arm/kernel/arch.c * - * Architecture specific fixups. This is where any - * parameters in the params struct are fixed up, or - * any additional architecture specific information - * is pulled from the params struct. + * Architecture specific fixups. This is where any + * parameters in the params struct are fixed up, or + * any additional architecture specific information + * is pulled from the params struct. */ #include #include @@ -12,12 +12,12 @@ #include #include -#include #include #include #include -#include "arch.h" +#include +#include unsigned int vram_size; @@ -69,6 +69,8 @@ } #ifdef CONFIG_ARCH_RPC +extern void __init rpc_map_io(void); + MACHINE_START(RISCPC, "Acorn-RiscPC") MAINTAINER("Russell King") BOOT_MEM(0x10000000, 0x03000000, 0xe0000000) @@ -76,6 +78,7 @@ DISABLE_PARPORT(0) DISABLE_PARPORT(1) FIXUP(fixup_acorn) + MAPIO(rpc_map_io) MACHINE_END #endif #ifdef CONFIG_ARCH_ARC @@ -94,379 +97,6 @@ #endif #endif -#ifdef CONFIG_ARCH_EBSA285 - -static void __init -fixup_ebsa285(struct machine_desc *desc, struct param_struct *params, - char **cmdline, struct meminfo *mi) -{ - ORIG_X = params->u1.s.video_x; - ORIG_Y = params->u1.s.video_y; - ORIG_VIDEO_COLS = params->u1.s.video_num_cols; - ORIG_VIDEO_LINES = params->u1.s.video_num_rows; -} - -MACHINE_START(EBSA285, "EBSA285") - MAINTAINER("Russell King") - BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0xfe000000) - BOOT_PARAMS(0x00000100) - VIDEO(0x000a0000, 0x000bffff) - FIXUP(fixup_ebsa285) -MACHINE_END -#endif - -#ifdef CONFIG_ARCH_NETWINDER -/* - * Older NeTTroms either do not provide a parameters - * page, or they don't supply correct information in - * the parameter page. - */ -static void __init -fixup_netwinder(struct machine_desc *desc, struct param_struct *params, - char **cmdline, struct meminfo *mi) -{ -#ifdef CONFIG_ISAPNP - extern int isapnp_disable; - - /* - * We must not use the kernels ISAPnP code - * on the NetWinder - it will reset the settings - * for the WaveArtist chip and render it inoperable. - */ - isapnp_disable = 1; -#endif - - if (params->u1.s.nr_pages != 0x02000 && - params->u1.s.nr_pages != 0x04000 && - params->u1.s.nr_pages != 0x08000 && - params->u1.s.nr_pages != 0x10000) { - printk(KERN_WARNING "Warning: bad NeTTrom parameters " - "detected, using defaults\n"); - - params->u1.s.nr_pages = 0x2000; /* 32MB */ - params->u1.s.ramdisk_size = 0; - params->u1.s.flags = FLAG_READONLY; - params->u1.s.initrd_start = 0; - params->u1.s.initrd_size = 0; - params->u1.s.rd_start = 0; - } -} - -MACHINE_START(NETWINDER, "Rebel-NetWinder") - MAINTAINER("Russell King/Rebel.com") - BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0xfe000000) - BOOT_PARAMS(0x00000100) - VIDEO(0x000a0000, 0x000bffff) - DISABLE_PARPORT(0) - DISABLE_PARPORT(2) - FIXUP(fixup_netwinder) -MACHINE_END -#endif - -#ifdef CONFIG_ARCH_CATS -/* - * CATS uses soft-reboot by default, since - * hard reboots fail on early boards. - */ -static void __init -fixup_cats(struct machine_desc *desc, struct param_struct *params, - char **cmdline, struct meminfo *mi) -{ - ORIG_VIDEO_LINES = 25; - ORIG_VIDEO_POINTS = 16; - ORIG_Y = 24; -} - -MACHINE_START(CATS, "Chalice-CATS") - MAINTAINER("Philip Blundell") - BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0xfe000000) - SOFT_REBOOT - FIXUP(fixup_cats) -MACHINE_END -#endif - -#ifdef CONFIG_ARCH_CO285 - -static void __init -fixup_coebsa285(struct machine_desc *desc, struct param_struct *params, - char **cmdline, struct meminfo *mi) -{ - extern unsigned long boot_memory_end; - extern char boot_command_line[]; - - mi->nr_banks = 1; - mi->bank[0].start = PHYS_OFFSET; - mi->bank[0].size = boot_memory_end; - mi->bank[0].node = 0; - - *cmdline = boot_command_line; -} - -MACHINE_START(CO285, "co-EBSA285") - MAINTAINER("Mark van Doesburg") - BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0x7cf00000) - FIXUP(fixup_coebsa285) -MACHINE_END -#endif - -#ifdef CONFIG_ARCH_SA1100 - -static void victor_power_off(void) -{ - /* switch off power supply */ - mdelay(2000); - GPCR = GPIO_GPIO23; - while (1); -} - - -static void xp860_power_off(void) -{ - GPDR |= GPIO_GPIO20; - GPSR = GPIO_GPIO20; - mdelay(1000); - GPCR = GPIO_GPIO20; - while(1); -} - - -extern void select_sa1100_io_desc(void); -#define SET_BANK(__nr,__start,__size) \ - mi->bank[__nr].start = (__start), \ - mi->bank[__nr].size = (__size), \ - mi->bank[__nr].node = (((unsigned)(__start) - PHYS_OFFSET) >> 27) -static void __init -fixup_sa1100(struct machine_desc *desc, struct param_struct *params, - char **cmdline, struct meminfo *mi) -{ - select_sa1100_io_desc(); - - if (machine_is_assabet()) { - /* - * On Assabet, we must probe for the Neponset board *before* - * paging_init() has occured to actually determine the amount - * of RAM available. - */ - extern void map_sa1100_gpio_regs(void); - extern void get_assabet_scr(void); - map_sa1100_gpio_regs(); - get_assabet_scr(); - - SET_BANK( 0, 0xc0000000, 32*1024*1024 ); - mi->nr_banks = 1; - - if (machine_has_neponset()) { - printk("Neponset expansion board detected\n"); - /* - * Note that Neponset RAM is slower... - * and still untested. - * This would be a candidate for - * _real_ NUMA support. - */ - //SET_BANK( 1, 0xd0000000, 32*1024*1024 ); - //mi->nr_banks = 2; - } - - ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); - setup_ramdisk( 1, 0, 0, 8192 ); - setup_initrd( 0xc0800000, 3*1024*1024 ); - } - - else if (machine_is_brutus()) { - SET_BANK( 0, 0xc0000000, 4*1024*1024 ); - SET_BANK( 1, 0xc8000000, 4*1024*1024 ); - SET_BANK( 2, 0xd0000000, 4*1024*1024 ); - SET_BANK( 3, 0xd8000000, 4*1024*1024 ); - mi->nr_banks = 4; - - ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); - setup_ramdisk( 1, 0, 0, 8192 ); - setup_initrd( __phys_to_virt(0xd8000000), 3*1024*1024 ); - } - - else if (machine_is_cerf()) { - // 16Meg Ram. - SET_BANK( 0, 0xc0000000, 8*1024*1024 ); - SET_BANK( 1, 0xc8000000, 8*1024*1024 ); // comment this out for 8MB Cerfs - mi->nr_banks = 2; - - ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); - setup_ramdisk(1, 0, 0, 8192); - // Save 2Meg for RAMDisk - setup_initrd(0xc0500000, 3*1024*1024); - } - - else if (machine_is_empeg()) { - SET_BANK( 0, 0xc0000000, 4*1024*1024 ); - SET_BANK( 1, 0xc8000000, 4*1024*1024 ); - mi->nr_banks = 2; - - ROOT_DEV = MKDEV( 3, 1 ); /* /dev/hda1 */ - setup_ramdisk( 1, 0, 0, 4096 ); - setup_initrd( 0xd0000000+((1024-320)*1024), (320*1024) ); - } - - else if (machine_is_lart()) { - /* - * Note that LART is a special case - it doesn't use physical - * address line A23 on the DRAM, so we effectively have 4 * 8MB - * in two SA1100 banks. - */ - SET_BANK( 0, 0xc0000000, 8*1024*1024 ); - SET_BANK( 1, 0xc1000000, 8*1024*1024 ); - SET_BANK( 2, 0xc8000000, 8*1024*1024 ); - SET_BANK( 3, 0xc9000000, 8*1024*1024 ); - mi->nr_banks = 4; - - ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); - setup_ramdisk(1, 0, 0, 8192); - setup_initrd(0xc0400000, 4*1024*1024); - } - - else if (machine_is_thinclient() || machine_is_graphicsclient()) { - SET_BANK( 0, 0xc0000000, 16*1024*1024 ); - mi->nr_banks = 1; - - ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); - setup_ramdisk( 1, 0, 0, 8192 ); - setup_initrd( __phys_to_virt(0xc0800000), 4*1024*1024 ); - } - - else if (machine_is_nanoengine()) { - SET_BANK( 0, 0xc0000000, 32*1024*1024 ); - mi->nr_banks = 1; - - ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); - setup_ramdisk( 1, 0, 0, 8192 ); - setup_initrd( __phys_to_virt(0xc0800000), 4*1024*1024 ); - - /* Get command line parameters passed from the loader (if any) */ - if( *((char*)0xc0000100) ) - *cmdline = ((char *)0xc0000100); - } - else if (machine_is_tifon()) { - SET_BANK( 0, 0xc0000000, 16*1024*1024 ); - SET_BANK( 1, 0xc8000000, 16*1024*1024 ); - mi->nr_banks = 2; - - ROOT_DEV = MKDEV(UNNAMED_MAJOR, 0); - setup_ramdisk(1, 0, 0, 4096); - setup_initrd( 0xd0000000 + 0x1100004, 0x140000 ); - } - - else if (machine_is_victor()) { - SET_BANK( 0, 0xc0000000, 4*1024*1024 ); - mi->nr_banks = 1; - - ROOT_DEV = MKDEV( 60, 2 ); - - /* Get command line parameters passed from the loader (if any) */ - if( *((char*)0xc0000000) ) - strcpy( *cmdline, ((char *)0xc0000000) ); - - /* power off if any problem */ - strcat( *cmdline, " panic=1" ); - - pm_power_off = victor_power_off; - } - - else if (machine_is_xp860()) { - SET_BANK( 0, 0xc0000000, 32*1024*1024 ); - mi->nr_banks = 1; - - pm_power_off = xp860_power_off; - } -} - -#ifdef CONFIG_SA1100_ASSABET -MACHINE_START(ASSABET, "Intel-Assabet") - BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) - FIXUP(fixup_sa1100) -MACHINE_END -#endif -#ifdef CONFIG_SA1100_BITSY -MACHINE_START(BITSY, "Compaq Bitsy") - BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) - BOOT_PARAMS(0xc0000100) - FIXUP(fixup_sa1100) -MACHINE_END -#endif -#ifdef CONFIG_SA1100_BRUTUS -MACHINE_START(BRUTUS, "Intel Brutus (SA1100 eval board)") - BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) - FIXUP(fixup_sa1100) -MACHINE_END -#endif -#ifdef CONFIG_SA1100_CERF -MACHINE_START(CERF, "Intrinsyc CerfBoard") - MAINTAINER("Pieter Truter") - BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) - FIXUP(fixup_sa1100) -MACHINE_END -#endif -#ifdef CONFIG_SA1100_EMPEG -MACHINE_START(EMPEG, "empeg MP3 Car Audio Player") - BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) - FIXUP(fixup_sa1100) -MACHINE_END -#endif -#ifdef CONFIG_SA1100_GRAPHICSCLIENT -MACHINE_START(GRAPHICSCLIENT, "ADS GraphicsClient") - BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) - FIXUP(fixup_sa1100) -MACHINE_END -#endif -#ifdef CONFIG_SA1100_ITSY -MACHINE_START(ITSY, "Compaq Itsy") - BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) - BOOT_PARAMS(0xc0000100 - FIXUP(fixup_sa1100) -MACHINE_END -#endif -#ifdef CONFIG_SA1100_LART -MACHINE_START(LART, "LART") - BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) - FIXUP(fixup_sa1100) -MACHINE_END -#endif -#ifdef CONFIG_SA1100_NANOENGINE -MACHINE_START(NANOENGINE, "BSE nanoEngine") - BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) - FIXUP(fixup_sa1100) -MACHINE_END -#endif -#ifdef CONFIG_SA1100_PLEB -MACHINE_START(PLEB, "PLEB") - BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) - FIXUP(fixup_sa1100) -MACHINE_END -#endif -#ifdef CONFIG_SA1100_THINCLIENT -MACHINE_START(THINCLIENT, "ADS ThinClient") - BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) - FIXUP(fixup_sa1100) -MACHINE_END -#endif -#ifdef CONFIG_SA1100_TIFON -MACHINE_START(TIFON, "Tifon") - BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) - FIXUP(fixup_sa1100) -MACHINE_END -#endif -#ifdef CONFIG_SA1100_VICTOR -MACHINE_START(VICTOR, "VisuAide Victor") - BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) - FIXUP(fixup_sa1100) -MACHINE_END -#endif -#ifdef CONFIG_SA1100_XP860 -MACHINE_START(XP860, "XP860") - BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) - FIXUP(fixup_sa1100) -MACHINE_END -#endif -#endif - #ifdef CONFIG_ARCH_L7200 static void __init @@ -483,14 +113,20 @@ setup_initrd( __phys_to_virt(0xf1000000), 0x00162b0d); } +extern void __init l7200_map_io(void); + MACHINE_START(L7200, "LinkUp Systems L7200SDB") MAINTAINER("Steve Hill") BOOT_MEM(0xf0000000, 0x80040000, 0xd0000000) FIXUP(fixup_l7200) + MAPIO(l7200_map_io) MACHINE_END #endif #ifdef CONFIG_ARCH_EBSA110 + +extern void __init ebsa110_map_io(void); + MACHINE_START(EBSA110, "EBSA110") MAINTAINER("Russell King") BOOT_MEM(0x00000000, 0xe0000000, 0xe0000000) @@ -498,18 +134,27 @@ DISABLE_PARPORT(0) DISABLE_PARPORT(2) SOFT_REBOOT + MAPIO(ebsa110_map_io) MACHINE_END #endif #ifdef CONFIG_ARCH_NEXUSPCI + +extern void __init nexuspci_map_io(void); + MACHINE_START(NEXUSPCI, "FTV/PCI") MAINTAINER("Philip Blundell") BOOT_MEM(0x40000000, 0x10000000, 0xe0000000) + MAPIO(nexuspci_map_io) MACHINE_END #endif #ifdef CONFIG_ARCH_TBOX + +extern void __init tbox_map_io(void); + MACHINE_START(TBOX, "unknown-TBOX") MAINTAINER("Philip Blundell") BOOT_MEM(0x80000000, 0x00400000, 0xe0000000) + MAPIO(tbox_map_io) MACHINE_END #endif #ifdef CONFIG_ARCH_CLPS7110 @@ -528,22 +173,12 @@ MACHINE_END #endif #ifdef CONFIG_ARCH_CLPS7500 + +extern void __init clps7500_map_io(void); + MACHINE_START(CLPS7500, "CL-PS7500") MAINTAINER("Philip Blundell") BOOT_MEM(0x10000000, 0x03000000, 0xe0000000) -MACHINE_END -#endif -#ifdef CONFIG_ARCH_SHARK -MACHINE_START(SHARK, "Shark") - MAINTAINER("Alexander Schulz") - BOOT_MEM(0x08000000, 0x40000000, 0xe0000000) - VIDEO(0x06000000, 0x061fffff) -MACHINE_END -#endif -#ifdef CONFIG_ARCH_PERSONAL_SERVER -MACHINE_START(PERSONAL_SERVER, "Compaq Personal Server") - MAINTAINER("Jamey Hicks / George France") - BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0xfe000000) - BOOT_PARAMS(0x00000100) + MAPIO(clps7500_map_io) MACHINE_END #endif diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/kernel/arch.h linux/arch/arm/kernel/arch.h --- v2.4.0-test8/linux/arch/arm/kernel/arch.h Fri May 12 11:21:20 2000 +++ linux/arch/arm/kernel/arch.h Wed Dec 31 16:00:00 1969 @@ -1,74 +0,0 @@ -/* - * The size of struct machine_desc - * (for assembler code) - */ -#define SIZEOF_MACHINE_DESC 40 - -#ifndef __ASSEMBLY__ - -struct machine_desc { - /* - * Note! The first four elements are used - * by assembler code in head-armv.S - */ - unsigned int nr; /* architecture number */ - unsigned int phys_ram; /* start of physical ram */ - unsigned int phys_io; /* start of physical io */ - unsigned int virt_io; /* start of virtual io */ - - const char *name; /* architecture name */ - unsigned int param_offset; /* parameter page */ - - unsigned int video_start; /* start of video RAM */ - unsigned int video_end; /* end of video RAM */ - - unsigned int reserve_lp0 :1; /* never has lp0 */ - unsigned int reserve_lp1 :1; /* never has lp1 */ - unsigned int reserve_lp2 :1; /* never has lp2 */ - unsigned int broken_hlt :1; /* hlt is broken */ - unsigned int soft_reboot :1; /* soft reboot */ - void (*fixup)(struct machine_desc *, - struct param_struct *, char **, - struct meminfo *); -}; - -/* - * Set of macros to define architecture features. This is built into - * a table by the linker. - */ -#define MACHINE_START(_type,_name) \ -const struct machine_desc __mach_desc_##_type \ - __attribute__((__section__(".arch.info"))) = { \ - nr: MACH_TYPE_##_type##, \ - name: _name, - -#define MAINTAINER(n) - -#define BOOT_MEM(_pram,_pio,_vio) \ - phys_ram: _pram, \ - phys_io: _pio, \ - virt_io: _vio, - -#define BOOT_PARAMS(_params) \ - param_offset: _params, - -#define VIDEO(_start,_end) \ - video_start: _start, \ - video_end: _end, - -#define DISABLE_PARPORT(_n) \ - reserve_lp##_n##: 1, - -#define BROKEN_HLT \ - broken_hlt: 1, - -#define SOFT_REBOOT \ - soft_reboot: 1, - -#define FIXUP(_func) \ - fixup: _func, - -#define MACHINE_END \ -}; - -#endif diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/kernel/armksyms.c linux/arch/arm/kernel/armksyms.c --- v2.4.0-test8/linux/arch/arm/kernel/armksyms.c Sun Aug 13 09:54:15 2000 +++ linux/arch/arm/kernel/armksyms.c Mon Sep 18 15:15:24 2000 @@ -1,3 +1,12 @@ +/* + * linux/arch/arm/kernel/armksyms.c + * + * Copyright (C) 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 @@ -110,23 +119,6 @@ EXPORT_SYMBOL(pm_power_off); /* processor dependencies */ -#ifdef MULTI_CPU -EXPORT_SYMBOL(processor); -#else -EXPORT_SYMBOL(cpu_flush_cache_all); -EXPORT_SYMBOL(cpu_flush_cache_area); -EXPORT_SYMBOL(cpu_flush_cache_entry); -EXPORT_SYMBOL(cpu_clean_cache_area); -EXPORT_SYMBOL(cpu_flush_ram_page); -EXPORT_SYMBOL(cpu_flush_tlb_all); -EXPORT_SYMBOL(cpu_flush_tlb_area); -EXPORT_SYMBOL(cpu_set_pgd); -EXPORT_SYMBOL(cpu_set_pmd); -EXPORT_SYMBOL(cpu_set_pte); -EXPORT_SYMBOL(cpu_flush_icache_area); -EXPORT_SYMBOL(cpu_cache_wback_area); -EXPORT_SYMBOL(cpu_cache_purge_area); -#endif EXPORT_SYMBOL(__machine_arch_type); /* networking */ diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/kernel/arthur.c linux/arch/arm/kernel/arthur.c --- v2.4.0-test8/linux/arch/arm/kernel/arthur.c Mon Jun 26 12:04:00 2000 +++ linux/arch/arm/kernel/arthur.c Mon Sep 18 15:15:24 2000 @@ -1,6 +1,14 @@ /* * Arthur personality - * Copyright (C) 1998-1999 Philip Blundell + * + * Copyright (C) 1998, 1999, 2000 Philip Blundell + */ + +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the 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 diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/kernel/bios32.c linux/arch/arm/kernel/bios32.c --- v2.4.0-test8/linux/arch/arm/kernel/bios32.c Sun Sep 3 11:19:11 2000 +++ linux/arch/arm/kernel/bios32.c Mon Sep 18 15:15:24 2000 @@ -1,9 +1,9 @@ /* - * arch/arm/kernel/bios32.c + * linux/arch/arm/kernel/bios32.c * - * PCI bios-type initialisation for PCI machines + * PCI bios-type initialisation for PCI machines * - * Bits taken from various places. + * Bits taken from various places. */ #include #include diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/kernel/calls.S linux/arch/arm/kernel/calls.S --- v2.4.0-test8/linux/arch/arm/kernel/calls.S Fri Aug 11 14:29:05 2000 +++ linux/arch/arm/kernel/calls.S Mon Sep 18 15:15:24 2000 @@ -1,9 +1,13 @@ /* - * linux/arch/arm/lib/calls.h + * linux/arch/arm/lib/calls.h * - * Copyright (C) 1995-1998 Russell King + * Copyright (C) 1995-1998 Russell King * - * This file is included twice in entry-common.S + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This file is included twice in entry-common.S */ #ifndef NR_syscalls #define NR_syscalls 256 diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/kernel/debug-armo.S linux/arch/arm/kernel/debug-armo.S --- v2.4.0-test8/linux/arch/arm/kernel/debug-armo.S Wed Oct 20 16:29:08 1999 +++ linux/arch/arm/kernel/debug-armo.S Mon Sep 18 15:15:24 2000 @@ -1,9 +1,13 @@ /* - * linux/arch/arm/kernel/debug-armo.S + * linux/arch/arm/kernel/debug-armo.S * - * Copyright (C) 1999 Russell King + * Copyright (C) 1999 Russell King * - * 26-bit debugging code + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 26-bit debugging code */ #include diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/kernel/debug-armv.S linux/arch/arm/kernel/debug-armv.S --- v2.4.0-test8/linux/arch/arm/kernel/debug-armv.S Sun Aug 13 09:54:15 2000 +++ linux/arch/arm/kernel/debug-armv.S Mon Sep 18 15:15:24 2000 @@ -1,14 +1,18 @@ /* - * linux/arch/arm/kernel/debug-armv.S + * linux/arch/arm/kernel/debug-armv.S * - * Copyright (C) 1994-1999 Russell King + * Copyright (C) 1994-1999 Russell King * - * 32-bit debugging code + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 32-bit debugging code */ #include #include #include -#include +#include .text @@ -29,10 +33,10 @@ .endm .macro busyuart,rd,rx -1002: ldrb \rd, [\rx, #0x14] +1001: ldrb \rd, [\rx, #0x14] and \rd, \rd, #0x60 teq \rd, #0x60 - bne 1002b + bne 1001b .endm .macro waituart,rd,rx @@ -189,6 +193,38 @@ tst \rd, #1 << 3 @ UARTFLGUBUSY - 1 when busy bne 1001b .endm + +#elif defined(CONFIG_ARCH_INTEGRATOR) + +#include + + .equ io_virt, 0xf0000000 + (0x16000000 >> 4) + .equ io_phys, 0x16000000 + + .macro addruart,rx + mrc p15, 0, \rx, c1, c0 + tst \rx, #1 @ MMU enabled? + moveq \rx, #0x16000000 @ physical base address + movne \rx, #0xf0000000 @ virtual base + addne \rx, \rx, #0x16000000 >> 4 + .endm + + .macro senduart,rd,rx + strb \rd, [\rx, #AMBA_UARTDR] + .endm + + .macro waituart,rd,rx +1001: ldr \rd, [\rx, #0x18] @ UARTFLG + tst \rd, #1 << 5 @ UARTFLGUTXFF - 1 when full + bne 1001b + .endm + + .macro busyuart,rd,rx +1001: ldr \rd, [\rx, #0x18] @ UARTFLG + tst \rd, #1 << 3 @ UARTFLGUBUSY - 1 when busy + bne 1001b + .endm + #else #error Unknown architecture #endif diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/kernel/dec21285.c linux/arch/arm/kernel/dec21285.c --- v2.4.0-test8/linux/arch/arm/kernel/dec21285.c Sun Sep 3 11:19:11 2000 +++ linux/arch/arm/kernel/dec21285.c Mon Sep 18 15:15:24 2000 @@ -1,7 +1,11 @@ /* - * arch/arm/kernel/dec21285.c: PCI functions for DC21285 + * linux/arch/arm/kernel/dec21285.c: PCI functions for DC21285 * - * Copyright (C) 1998-2000 Russell King, Phil Blundell + * Copyright (C) 1998-2000 Russell King, Phil Blundell + * + * 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 @@ -12,12 +16,11 @@ #include #include -#include #include #include #include - #include +#include #define MAX_SLOTS 21 diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/kernel/dma-arc.c linux/arch/arm/kernel/dma-arc.c --- v2.4.0-test8/linux/arch/arm/kernel/dma-arc.c Sun Aug 13 09:54:15 2000 +++ linux/arch/arm/kernel/dma-arc.c Mon Sep 18 15:15:24 2000 @@ -1,9 +1,13 @@ /* - * arch/arm/kernel/dma-arc.c + * linux/arch/arm/kernel/dma-arc.c * - * Copyright (C) 1998-1999 Dave Gilbert / Russell King + * Copyright (C) 1998-1999 Dave Gilbert / Russell King * - * DMA functions specific to Archimedes and A5000 architecture + * 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. + * + * DMA functions specific to Archimedes and A5000 architecture */ #include #include @@ -11,11 +15,12 @@ #include #include +#include #include #include #include -#include "dma.h" +#include #define DPRINTK(x...) printk(KERN_DEBUG x) @@ -30,11 +35,11 @@ unsigned long flags; DPRINTK("enable_dma fdc1772 data read\n"); save_flags(flags); - cliIF(); + clf(); memcpy ((void *)0x1c, (void *)&fdc1772_dma_read, &fdc1772_dma_read_end - &fdc1772_dma_read); - fdc1772_setupdma(dma->buf.length, __bus_to_virt(dma->buf.address)); /* Sets data pointer up */ + fdc1772_setupdma(dma->buf.length, dma->buf.address); /* Sets data pointer up */ enable_irq (64); restore_flags(flags); } @@ -46,10 +51,10 @@ unsigned long flags; DPRINTK("enable_dma fdc1772 data write\n"); save_flags(flags); - cliIF(); + clf(); memcpy ((void *)0x1c, (void *)&fdc1772_dma_write, &fdc1772_dma_write_end - &fdc1772_dma_write); - fdc1772_setupdma(dma->buf.length, __bus_to_virt(dma->buf.address)); /* Sets data pointer up */ + fdc1772_setupdma(dma->buf.length, dma->buf.address); /* Sets data pointer up */ enable_irq (64); restore_flags(flags); @@ -77,7 +82,7 @@ DPRINTK("arc_floppy_cmdend_enable_dma\n"); /*printk("enable_dma fdc1772 command end FIQ\n");*/ save_flags(flags); - cliIF(); + clf(); /* B fdc1772_comendhandler */ *((unsigned int *)0x1c)=0xea000000 | @@ -150,7 +155,7 @@ } memcpy((void *)0x1c, fiqhandler_start, fiqhandler_length); regs.ARM_r9 = dma->buf.length; - regs.ARM_r10 = __bus_to_virt(dma->buf.address); + regs.ARM_r10 = dma->buf.address; regs.ARM_fp = (int)PCIO_FLOPPYDMABASE; set_fiq_regs(®s); enable_irq(dma->dma_irq); @@ -173,7 +178,7 @@ /* * This is virtual DMA - we don't need anything here */ -static int sound_enable_disable_dma(dmach_t channel, dma_t *dma) +static void sound_enable_disable_dma(dmach_t channel, dma_t *dma) { } @@ -195,8 +200,8 @@ #endif #ifdef CONFIG_ARCH_A5K if (machine_is_a5k()) { - dma[DMA_VIRTUAL_FLOPPY].dma_irq = 64; - dma[DMA_VIRTUAL_FLOPPY].d_ops = &a5k_floppy_dma_ops; + dma[DMA_VIRTUAL_FLOPPY0].dma_irq = 64; + dma[DMA_VIRTUAL_FLOPPY0].d_ops = &a5k_floppy_dma_ops; } #endif dma[DMA_VIRTUAL_SOUND].d_ops = &sound_dma_ops; diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/kernel/dma-footbridge.c linux/arch/arm/kernel/dma-footbridge.c --- v2.4.0-test8/linux/arch/arm/kernel/dma-footbridge.c Tue Jul 18 22:43:24 2000 +++ linux/arch/arm/kernel/dma-footbridge.c Mon Sep 18 15:15:24 2000 @@ -1,27 +1,24 @@ /* - * arch/arm/kernel/dma-ebsa285.c + * linux/arch/arm/kernel/dma-ebsa285.c * - * Copyright (C) 1998 Phil Blundell + * Copyright (C) 1998 Phil Blundell * * DMA functions specific to EBSA-285/CATS architectures * - * Changelog: - * 09-Nov-1998 RMK Split out ISA DMA functions to dma-isa.c - * 17-Mar-1999 RMK Allow any EBSA285-like architecture to have + * Changelog: + * 09-Nov-1998 RMK Split out ISA DMA functions to dma-isa.c + * 17-Mar-1999 RMK Allow any EBSA285-like architecture to have * ISA DMA controllers. */ - #include #include #include -#include #include #include -#include "dma.h" - -extern void isa_init_dma(dma_t *dma); +#include +#include #if 0 static int fb_dma_request(dmach_t channel, dma_t *dma) diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/kernel/dma-isa.c linux/arch/arm/kernel/dma-isa.c --- v2.4.0-test8/linux/arch/arm/kernel/dma-isa.c Tue Jul 18 22:43:24 2000 +++ linux/arch/arm/kernel/dma-isa.c Mon Sep 18 15:15:24 2000 @@ -1,24 +1,30 @@ /* - * arch/arm/kernel/dma-isa.c: ISA DMA primitives + * linux/arch/arm/kernel/dma-isa.c * - * Copyright (C) 1999-2000 Russell King + * Copyright (C) 1999-2000 Russell King * - * Taken from various sources, including: - * linux/include/asm/dma.h: Defines for using and allocating dma channels. - * Written by Hennus Bergman, 1992. - * High DMA channel support & info by Hannu Savolainen and John Boyd, - * Nov. 1992. - * arch/arm/kernel/dma-ebsa285.c - * Copyright (C) 1998 Phil Blundell + * 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. + * + * ISA DMA primitives + * Taken from various sources, including: + * linux/include/asm/dma.h: Defines for using and allocating dma channels. + * Written by Hennus Bergman, 1992. + * High DMA channel support & info by Hannu Savolainen and John Boyd, + * Nov. 1992. + * arch/arm/kernel/dma-ebsa285.c + * Copyright (C) 1998 Phil Blundell */ #include #include #include +#include #include #include -#include "dma.h" +#include #define ISA_DMA_MODE_READ 0x44 #define ISA_DMA_MODE_WRITE 0x48 @@ -60,47 +66,57 @@ { if (dma->invalid) { unsigned long address, length; - unsigned int mode; - - address = dma->buf.address; - length = dma->buf.length - 1; - - outb(address >> 16, isa_dma_port[channel][ISA_DMA_PGLO]); - outb(address >> 24, isa_dma_port[channel][ISA_DMA_PGHI]); - - if (channel >= 4) { - address >>= 1; - length >>= 1; - } - - outb(0, isa_dma_port[channel][ISA_DMA_CLRFF]); - - outb(address, isa_dma_port[channel][ISA_DMA_ADDR]); - outb(address >> 8, isa_dma_port[channel][ISA_DMA_ADDR]); - - outb(length, isa_dma_port[channel][ISA_DMA_COUNT]); - outb(length >> 8, isa_dma_port[channel][ISA_DMA_COUNT]); + unsigned int mode, direction; mode = channel & 3; - switch (dma->dma_mode & DMA_MODE_MASK) { case DMA_MODE_READ: mode |= ISA_DMA_MODE_READ; - dma_cache_inv(__bus_to_virt(dma->buf.address), dma->buf.length); + direction = PCI_DMA_FROMDEVICE; break; case DMA_MODE_WRITE: mode |= ISA_DMA_MODE_WRITE; - dma_cache_wback(__bus_to_virt(dma->buf.address), dma->buf.length); + direction = PCI_DMA_TODEVICE; break; case DMA_MODE_CASCADE: mode |= ISA_DMA_MODE_CASCADE; + direction = PCI_DMA_BIDIRECTIONAL; break; default: break; } + + if (!dma->using_sg) { + /* + * Cope with ISA-style drivers which expect cache + * coherence. + */ + dma->buf.dma_address = pci_map_single(NULL, + dma->buf.address, dma->buf.length, + direction); + } + + address = dma->buf.dma_address; + length = dma->buf.length - 1; + + outb(address >> 16, isa_dma_port[channel][ISA_DMA_PGLO]); + outb(address >> 24, isa_dma_port[channel][ISA_DMA_PGHI]); + + if (channel >= 4) { + address >>= 1; + length >>= 1; + } + + outb(0, isa_dma_port[channel][ISA_DMA_CLRFF]); + + outb(address, isa_dma_port[channel][ISA_DMA_ADDR]); + outb(address >> 8, isa_dma_port[channel][ISA_DMA_ADDR]); + + outb(length, isa_dma_port[channel][ISA_DMA_COUNT]); + outb(length >> 8, isa_dma_port[channel][ISA_DMA_COUNT]); if (dma->dma_mode & DMA_AUTOINIT) mode |= ISA_DMA_AUTOINIT; diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/kernel/dma-rpc.c linux/arch/arm/kernel/dma-rpc.c --- v2.4.0-test8/linux/arch/arm/kernel/dma-rpc.c Sun Aug 13 09:54:15 2000 +++ linux/arch/arm/kernel/dma-rpc.c Mon Sep 18 15:15:24 2000 @@ -1,25 +1,30 @@ /* - * arch/arm/kernel/dma-rpc.c + * linux/arch/arm/kernel/dma-rpc.c * - * Copyright (C) 1998 Russell King + * Copyright (C) 1998 Russell King * - * DMA functions specific to RiscPC architecture + * 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. + * + * DMA functions specific to RiscPC architecture */ #include #include #include #include +#include #include #include #include #include -#include #include #include #include -#include "dma.h" +#include +#include #if 0 typedef enum { @@ -47,13 +52,13 @@ #define state_wait_a 1 #define state_wait_b 2 -static void iomd_get_next_sg(dmasg_t *sg, dma_t *dma) +static void iomd_get_next_sg(struct scatterlist *sg, dma_t *dma) { unsigned long end, offset, flags = 0; if (dma->sg) { - sg->address = dma->sg->address; - offset = sg->address & ~PAGE_MASK; + sg->dma_address = dma->sg->dma_address; + offset = sg->dma_address & ~PAGE_MASK; end = offset + dma->sg->length; @@ -66,7 +71,7 @@ sg->length = end - TRANSFER_SIZE; dma->sg->length -= end - offset; - dma->sg->address += end - offset; + dma->sg->dma_address += end - offset; if (dma->sg->length == 0) { if (dma->sgcount > 1) { @@ -79,22 +84,22 @@ } } else { flags = DMA_END_S | DMA_END_L; - sg->address = 0; + sg->dma_address = 0; sg->length = 0; } sg->length |= flags; } -static inline void iomd_setup_dma_a(dmasg_t *sg, dma_t *dma) +static inline void iomd_setup_dma_a(struct scatterlist *sg, dma_t *dma) { - outl_t(sg->address, dma->dma_base + CURA); + outl_t(sg->dma_address, dma->dma_base + CURA); outl_t(sg->length, dma->dma_base + ENDA); } -static inline void iomd_setup_dma_b(dmasg_t *sg, dma_t *dma) +static inline void iomd_setup_dma_b(struct scatterlist *sg, dma_t *dma) { - outl_t(sg->address, dma->dma_base + CURB); + outl_t(sg->dma_address, dma->dma_base + CURB); outl_t(sg->length, dma->dma_base + ENDB); } @@ -160,17 +165,8 @@ static int iomd_request_dma(dmach_t channel, dma_t *dma) { - unsigned long flags; - int ret; - - save_flags_cli(flags); - ret = request_irq(dma->dma_irq, iomd_dma_handle, - SA_INTERRUPT, dma->device_id, dma); - if (!ret) - disable_irq(dma->dma_irq); - restore_flags(flags); - - return ret; + return request_irq(dma->dma_irq, iomd_dma_handle, + SA_INTERRUPT, dma->device_id, dma); } static void iomd_free_dma(dmach_t channel, dma_t *dma) @@ -186,6 +182,17 @@ if (dma->invalid) { dma->invalid = 0; + /* + * Cope with ISA-style drivers which expect cache + * coherence. + */ + if (!dma->using_sg) { + dma->buf.dma_address = pci_map_single(NULL, + dma->buf.address, dma->buf.length, + dma->dma_mode == DMA_MODE_READ ? + PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE); + } + outb_t(DMA_CR_C, dma_base + CR); dma->state = state_prog_a; } @@ -279,8 +286,8 @@ } regs.ARM_r9 = dma->buf.length; - regs.ARM_r10 = __bus_to_virt(dma->buf.address); - regs.ARM_fp = (int)PCIO_FLOPPYDMABASE; + regs.ARM_r10 = (unsigned long)dma->buf.address; + regs.ARM_fp = (unsigned long)PCIO_FLOPPYDMABASE; if (claim_fiq(&fh)) { printk("floppydma: couldn't claim FIQ.\n"); diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/kernel/dma.c linux/arch/arm/kernel/dma.c --- v2.4.0-test8/linux/arch/arm/kernel/dma.c Sun Aug 13 09:54:15 2000 +++ linux/arch/arm/kernel/dma.c Mon Sep 18 15:15:24 2000 @@ -1,11 +1,15 @@ /* - * linux/arch/arm/kernel/dma.c + * linux/arch/arm/kernel/dma.c * - * Copyright (C) 1995-2000 Russell King + * Copyright (C) 1995-2000 Russell King * - * Front-end to the DMA handling. This handles the allocation/freeing - * of DMA channels, and provides a unified interface to the machines - * DMA facilities. + * 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. + * + * Front-end to the DMA handling. This handles the allocation/freeing + * of DMA channels, and provides a unified interface to the machines + * DMA facilities. */ #include #include @@ -16,7 +20,7 @@ #include -#include "dma.h" +#include spinlock_t dma_spin_lock = SPIN_LOCK_UNLOCKED; @@ -111,12 +115,13 @@ /* Set DMA Scatter-Gather list */ -void set_dma_sg (dmach_t channel, dmasg_t *sg, int nr_sg) +void set_dma_sg (dmach_t channel, struct scatterlist *sg, int nr_sg) { dma_t *dma = dma_chan + channel; dma->sg = sg; dma->sgcount = nr_sg; + dma->using_sg = 1; dma->invalid = 1; } @@ -134,7 +139,8 @@ dma->sg = &dma->buf; dma->sgcount = 1; - dma->buf.address = physaddr; + dma->buf.address = bus_to_virt(physaddr); + dma->using_sg = 0; dma->invalid = 1; } @@ -153,6 +159,7 @@ dma->sg = &dma->buf; dma->sgcount = 1; dma->buf.length = count; + dma->using_sg = 0; dma->invalid = 1; } diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/kernel/dma.h linux/arch/arm/kernel/dma.h --- v2.4.0-test8/linux/arch/arm/kernel/dma.h Tue Jul 18 22:43:24 2000 +++ linux/arch/arm/kernel/dma.h Wed Dec 31 16:00:00 1969 @@ -1,48 +0,0 @@ -/* - * linux/arch/arm/kernel/dma.h - * - * Copyright (C) 1998-2000 Russell King - * - * This header file describes the interface between the generic DMA handler - * (dma.c) and the architecture-specific DMA backends (dma-*.c) - */ - -struct dma_struct; -typedef struct dma_struct dma_t; - -struct dma_ops { - int (*request)(dmach_t, dma_t *); /* optional */ - void (*free)(dmach_t, dma_t *); /* optional */ - void (*enable)(dmach_t, dma_t *); /* mandatory */ - void (*disable)(dmach_t, dma_t *); /* mandatory */ - int (*residue)(dmach_t, dma_t *); /* optional */ - int (*setspeed)(dmach_t, dma_t *, int); /* optional */ - char *type; -}; - -struct dma_struct { - dmasg_t buf; /* single DMA */ - int sgcount; /* number of DMA SG */ - dmasg_t *sg; /* DMA Scatter-Gather List */ - - unsigned int active:1; /* Transfer active */ - unsigned int invalid:1; /* Address/Count changed */ - dmamode_t dma_mode; /* DMA mode */ - int speed; /* DMA speed */ - - unsigned int lock; /* Device is allocated */ - const char *device_id; /* Device name */ - - unsigned int dma_base; /* Controller base address */ - int dma_irq; /* Controller IRQ */ - int state; /* Controller state */ - dmasg_t cur_sg; /* Current controller buffer */ - - struct dma_ops *d_ops; -}; - -/* Prototype: void arch_dma_init(dma) - * Purpose : Initialise architecture specific DMA - * Params : dma - pointer to array of DMA structures - */ -void arch_dma_init(dma_t *dma); diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/kernel/ecard.c linux/arch/arm/kernel/ecard.c --- v2.4.0-test8/linux/arch/arm/kernel/ecard.c Sun Sep 3 11:52:27 2000 +++ linux/arch/arm/kernel/ecard.c Mon Sep 18 15:15:24 2000 @@ -1,27 +1,30 @@ /* - * linux/arch/arm/kernel/ecard.c + * linux/arch/arm/kernel/ecard.c * - * Find all installed expansion cards, and handle interrupts from them. + * Copyright 1995-1998 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. * - * Copyright 1995-1998 Russell King + * Find all installed expansion cards, and handle interrupts from them. * - * Created from information from Acorns RiscOS3 PRMs + * Created from information from Acorns RiscOS3 PRMs * - * 08-Dec-1996 RMK Added code for the 9'th expansion card - the ether + * 08-Dec-1996 RMK Added code for the 9'th expansion card - the ether * podule slot. - * 06-May-1997 RMK Added blacklist for cards whose loader doesn't work. - * 12-Sep-1997 RMK Created new handling of interrupt enables/disables + * 06-May-1997 RMK Added blacklist for cards whose loader doesn't work. + * 12-Sep-1997 RMK Created new handling of interrupt enables/disables * - cards can now register their own routine to control * interrupts (recommended). - * 29-Sep-1997 RMK Expansion card interrupt hardware not being re-enabled + * 29-Sep-1997 RMK Expansion card interrupt hardware not being re-enabled * on reset from Linux. (Caused cards not to respond * under RiscOS without hard reset). - * 15-Feb-1998 RMK Added DMA support - * 12-Sep-1998 RMK Added EASI support - * 10-Jan-1999 RMK Run loaders in a simulated RISC OS environment. - * 17-Apr-1999 RMK Support for EASI Type C cycles. + * 15-Feb-1998 RMK Added DMA support + * 12-Sep-1998 RMK Added EASI support + * 10-Jan-1999 RMK Run loaders in a simulated RISC OS environment. + * 17-Apr-1999 RMK Support for EASI Type C cycles. */ - #define ECARD_C #define __KERNEL_SYSCALLS__ @@ -137,15 +140,10 @@ if (req->ec == NULL) { ecard_t *ec; - for (ec = cards; ec; ec = ec->next) { - printk(KERN_DEBUG "Resetting card %d\n", - ec->slot_no); - + for (ec = cards; ec; ec = ec->next) if (ec->loader) ecard_loader_reset(POD_INT_ADDR(ec->podaddr), ec->loader); - } - printk(KERN_DEBUG "All cards reset\n"); } else if (req->ec->loader) ecard_loader_reset(POD_INT_ADDR(req->ec->podaddr), req->ec->loader); diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/kernel/entry-armo.S linux/arch/arm/kernel/entry-armo.S --- v2.4.0-test8/linux/arch/arm/kernel/entry-armo.S Sun Aug 13 09:54:15 2000 +++ linux/arch/arm/kernel/entry-armo.S Mon Sep 18 15:15:24 2000 @@ -1,25 +1,29 @@ /* - * linux/arch/arm/kernel/entry-armo.S + * linux/arch/arm/kernel/entry-armo.S * - * Copyright (C) 1995,1996,1997,1998 Russell King. + * Copyright (C) 1995,1996,1997,1998 Russell King. * - * Low-level vector interface routines + * 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. * - * Design issues: - * - We have several modes that each vector can be called from, - * each with its own set of registers. On entry to any vector, - * we *must* save the registers used in *that* mode. + * Low-level vector interface routines * - * - This code must be as fast as possible. + * Design issues: + * - We have several modes that each vector can be called from, + * each with its own set of registers. On entry to any vector, + * we *must* save the registers used in *that* mode. * - * There are a few restrictions on the vectors: - * - the SWI vector cannot be called from *any* non-user mode + * - This code must be as fast as possible. * - * - the FP emulator is *never* called from *any* non-user mode undefined - * instruction. + * There are a few restrictions on the vectors: + * - the SWI vector cannot be called from *any* non-user mode * - * Ok, so this file may be a mess, but its as efficient as possible while - * adhering to the above criteria. + * - the FP emulator is *never* called from *any* non-user mode undefined + * instruction. + * + * Ok, so this file may be a mess, but its as efficient as possible while + * adhering to the above criteria. */ #include #include diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/kernel/entry-armv.S linux/arch/arm/kernel/entry-armv.S --- v2.4.0-test8/linux/arch/arm/kernel/entry-armv.S Sun Aug 13 09:54:15 2000 +++ linux/arch/arm/kernel/entry-armv.S Mon Sep 18 15:15:25 2000 @@ -1,13 +1,17 @@ /* - * linux/arch/arm/kernel/entry-armv.S + * linux/arch/arm/kernel/entry-armv.S * - * Copyright (C) 1996,1997,1998 Russell King. - * ARM700 fix by Matthew Godbolt (linux-user@willothewisp.demon.co.uk) + * Copyright (C) 1996,1997,1998 Russell King. + * ARM700 fix by Matthew Godbolt (linux-user@willothewisp.demon.co.uk) * - * Low-level vector interface routines + * 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. * - * Note: there is a StrongARM bug in the STMIA rn, {regs}^ instruction that causes - * it to save wrong values... Be aware! + * Low-level vector interface routines + * + * Note: there is a StrongARM bug in the STMIA rn, {regs}^ instruction that causes + * it to save wrong values... Be aware! */ #include /* for CONFIG_ARCH_xxxx */ #include @@ -68,7 +72,7 @@ #ifdef IOC_BASE /* IOC / IOMD based hardware */ -#include +#include .equ ioc_base_high, IOC_BASE & 0xff000000 .equ ioc_base_low, IOC_BASE & 0x00ff0000 @@ -226,7 +230,7 @@ .endm #elif defined(CONFIG_FOOTBRIDGE) -#include +#include .macro disable_fiq .endm @@ -425,9 +429,9 @@ .endm .macro get_irqnr_and_base, irqnr, irqstat, base - mov r4, #irq_base_addr @ Virt addr IRQ regs - add r4, r4, #0x00001000 @ Status reg - ldr \irqstat, [r4] @ get interrupts + mov \irqstat, #irq_base_addr @ Virt addr IRQ regs + add \irqstat, \irqstat, #0x00001000 @ Status reg + ldr \irqstat, [\irqstat, #0] @ get interrupts mov \irqnr, #0 1001: tst \irqstat, #1 addeq \irqnr, \irqnr, #1 @@ -438,6 +442,32 @@ .endm .macro irq_prio_table + .endm + +#elif defined(CONFIG_ARCH_INTEGRATOR) + + .macro disable_fiq + .endm + + .macro get_irqnr_and_base, irqnr, irqstat, base +/* FIXME: should not be using soo many LDRs here */ + ldr \irqnr, =IO_ADDRESS(INTEGRATOR_IC_BASE) + ldr \irqstat, [\irqnr, #IRQ_STATUS] @ get masked status + ldr \irqnr, =IO_ADDRESS(INTEGRATOR_HDR_BASE) + ldr \irqnr, [\irqnr, #(INTEGRATOR_HDR_IC_OFFSET+IRQ_STATUS)] + orr \irqstat, \irqstat, \irqnr, lsl #INTEGRATOR_CM_INT0 + + mov \irqnr, #0 +1001: tst \irqstat, #1 + bne 1002f + add \irqnr, \irqnr, #1 + mov \irqstat, \irqstat, lsr #1 + cmp \irqnr, #22 + bcc 1001b +1002: /* EQ will be set if we reach 22 */ + .endm + + .macro irq_prio_table .endm #else diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/kernel/entry-common.S linux/arch/arm/kernel/entry-common.S --- v2.4.0-test8/linux/arch/arm/kernel/entry-common.S Sun Aug 13 09:54:15 2000 +++ linux/arch/arm/kernel/entry-common.S Mon Sep 18 15:15:25 2000 @@ -1,3 +1,12 @@ +/* + * linux/arch/arm/kernel/entry-common.S + * + * Copyright (C) 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 #define PT_TRACESYS 0x00000002 diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/kernel/ftv-pci.c linux/arch/arm/kernel/ftv-pci.c --- v2.4.0-test8/linux/arch/arm/kernel/ftv-pci.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/kernel/ftv-pci.c Mon Sep 18 15:15:25 2000 @@ -0,0 +1,51 @@ +/* + * linux/arch/arm/kernel/ftv-pci.c + * + * PCI bios-type initialisation for PCI machines + * + * Bits taken from various places. + */ +#include +#include +#include + +#include +#include + +/* + * Owing to a PCB cockup, issue A backplanes are wired thus: + * + * Slot 1 2 3 4 5 Bridge S1 S2 S3 S4 + * IRQ D C B A A C B A D + * A D C B B D C B A + * B A D C C A D C B + * C B A D D B A D C + * + * ID A31 A30 A29 A28 A27 A26 DEV4 DEV5 DEV6 DEV7 + * + * Actually, this isn't too bad, because with the processor card + * in slot 5 on the primary bus, the IRQs rotate on both sides + * as you'd expect. + */ + +static int irqmap_ftv[] __initdata = { IRQ_PCI_D, IRQ_PCI_C, IRQ_PCI_B, IRQ_PCI_A }; + +static int __init ftv_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + if (slot > 0x10) + slot--; + return irqmap_ftv[(slot - pin) & 3]; +} + +static u8 __init ftv_swizzle(struct pci_dev *dev, u8 *pin) +{ + return PCI_SLOT(dev->devfn); +} + +/* ftv host-specific stuff */ +struct hw_pci ftv_pci __initdata = { + init: plx90x0_init, + swizzle: ftv_swizzle, + map_irq: ftv_map_irq, +}; + diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/kernel/head-armo.S linux/arch/arm/kernel/head-armo.S --- v2.4.0-test8/linux/arch/arm/kernel/head-armo.S Sun Sep 3 11:19:11 2000 +++ linux/arch/arm/kernel/head-armo.S Mon Sep 18 15:15:25 2000 @@ -1,9 +1,13 @@ /* - * linux/arch/arm/kernel/head-armo.S + * linux/arch/arm/kernel/head-armo.S * - * Copyright (C) 1994-2000 Russell King + * Copyright (C) 1994-2000 Russell King * - * 26-bit kernel startup code + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 26-bit kernel startup code */ #include #include diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/kernel/head-armv.S linux/arch/arm/kernel/head-armv.S --- v2.4.0-test8/linux/arch/arm/kernel/head-armv.S Sun Aug 13 09:54:15 2000 +++ linux/arch/arm/kernel/head-armv.S Mon Sep 18 15:15:25 2000 @@ -1,26 +1,36 @@ /* - * linux/arch/arm/kernel/head-armv.S + * linux/arch/arm/kernel/head-armv.S * - * Copyright (C) 1994-1999 Russell King + * Copyright (C) 1994-1999 Russell King * - * 32-bit kernel startup code for all architectures + * 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. + * + * 32-bit kernel startup code for all architectures */ #include #include #include -#include -#include - -#include "arch.h" +#include +#include #if (TEXTADDR & 0xffff) != 0x8000 #error TEXTADDR must start at 0xXXXX8000 #endif -#define SWAPPER_PGDIR_OFFSET 0x4000 #define K(a,b,c) ((a) << 24 | (b) << 12 | (c)) +/* + * swapper_pg_dir is the virtual address of the "init_task" page tables. + * SWAPPER_PGDIR_OFFSET is the offset from the start of memory of the + * page tables. + * + * Note that at the moment, we assume TEXTADDR is the virtual equivalent + * of start of memory + 0x8000 + */ +#define SWAPPER_PGDIR_OFFSET 0x4000 .globl SYMBOL_NAME(swapper_pg_dir) .equ SYMBOL_NAME(swapper_pg_dir), TEXTADDR - 0x8000 + SWAPPER_PGDIR_OFFSET @@ -50,7 +60,7 @@ * ideal, but in this case, it should ONLY set r0 and r1 to the * appropriate value. */ -#ifdef CONFIG_ARCH_NETWINDER +#if defined(CONFIG_ARCH_NETWINDER) || defined(CONFIG_ARCH_INTEGRATOR) /* * Compatability cruft for old NetWinder NeTTroms. This * code is currently scheduled for destruction in 2.5.xx @@ -85,18 +95,23 @@ mov r5, #0 movne pc, r0 - mov r1, #5 @ (will go in 2.5) - mov r12, #2 << 24 @ scheduled for removal in 2.5.xx + mov r1, #MACH_TYPE_NETWINDER @ (will go in 2.5) + mov r12, #2 << 24 @ scheduled for removal in 2.5.xx orr r12, r12, #5 << 12 +__entry: #endif -#ifdef CONFIG_ARCH_L7200 +#if defined(CONFIG_ARCH_L7200) /* * FIXME - No bootloader, so manually set 'r1' with our architecture number. */ - mov r1, #19 + mov r1, #MACH_TYPE_L7200 +#elif defined(CONFIG_ARCH_INTEGRATOR) + mov r1, #MACH_TYPE_INTEGRATOR #endif -__entry: bl __lookup_processor_type + mov r0, #F_BIT | I_BIT | MODE_SVC @ make sure svc mode + msr cpsr_c, r0 @ and all irqs diabled + bl __lookup_processor_type teq r10, #0 @ invalid processor? moveq r0, #'p' @ yes, error 'p' beq __error @@ -140,7 +155,7 @@ @ sp = stack pointer str r12, [r2] - mov fp, #0 @ Clear BSS + mov fp, #0 @ Clear BSS (and zero fp) 1: cmp r4, r5 strcc fp, [r4],#4 bcc 1b @@ -182,17 +197,19 @@ bne 1b /* * Create identity mapping for first MB of kernel. - * map in four sections (4MB) for kernel. - * these are marked cacheable and bufferable. + * This is marked cacheable and bufferable. * * The identity mapping will be removed by paging_init() */ - mov r3, #0x0c @ cacheable, bufferable - orr r3, r3, r8 @ | pagetable flags - add r3, r3, r5 @ + start of RAM + add r3, r8, r5 @ mmuflags + start of RAM add r0, r4, r5, lsr #18 str r3, [r0] @ identity mapping - add r0, r4, #(TEXTADDR - 0x8000) >> 18 @ start of kernel + /* + * Now setup the pagetables for our kernel direct + * mapped region. We round TEXTADDR down to the + * nearest megabyte boundary. + */ + add r0, r4, #(TEXTADDR & 0xfff00000) >> 18 @ start of kernel str r3, [r0], #4 @ PAGE_OFFSET + 0MB add r3, r3, #1 << 20 str r3, [r0], #4 @ PAGE_OFFSET + 1MB @@ -200,6 +217,9 @@ str r3, [r0], #4 @ PAGE_OFFSET + 2MB add r3, r3, #1 << 20 str r3, [r0], #4 @ PAGE_OFFSET + 3MB + + bic r8, r8, #0x0c @ turn off cacheable + @ and bufferable bits #ifdef CONFIG_DEBUG_LL /* * Map in IO space for serial debugging. diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/kernel/hw-footbridge.c linux/arch/arm/kernel/hw-footbridge.c --- v2.4.0-test8/linux/arch/arm/kernel/hw-footbridge.c Sun Aug 13 09:54:15 2000 +++ linux/arch/arm/kernel/hw-footbridge.c Wed Dec 31 16:00:00 1969 @@ -1,692 +0,0 @@ -/* - * arch/arm/kernel/hw-footbridge.c - * - * Footbridge-dependent machine fixup - * - * Copyright (C) 1998, 1999 Russell King, Phil Blundell - */ -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#define IRDA_IO_BASE 0x180 -#define GP1_IO_BASE 0x338 -#define GP2_IO_BASE 0x33a - - -#ifdef CONFIG_LEDS -#define DEFAULT_LEDS 0 -#else -#define DEFAULT_LEDS GPIO_GREEN_LED -#endif - -/* - * Netwinder stuff - */ -#ifdef CONFIG_ARCH_NETWINDER - -/* - * Winbond WB83977F accessibility stuff - */ -static inline void wb977_open(void) -{ - outb(0x87, 0x370); - outb(0x87, 0x370); -} - -static inline void wb977_close(void) -{ - outb(0xaa, 0x370); -} - -static inline void wb977_wb(int reg, int val) -{ - outb(reg, 0x370); - outb(val, 0x371); -} - -static inline void wb977_ww(int reg, int val) -{ - outb(reg, 0x370); - outb(val >> 8, 0x371); - outb(reg + 1, 0x370); - outb(val, 0x371); -} - -#define wb977_device_select(dev) wb977_wb(0x07, dev) -#define wb977_device_disable() wb977_wb(0x30, 0x00) -#define wb977_device_enable() wb977_wb(0x30, 0x01) - -/* - * This is a lock for accessing ports GP1_IO_BASE and GP2_IO_BASE - */ -spinlock_t gpio_lock = SPIN_LOCK_UNLOCKED; - -static unsigned int current_gpio_op = 0; -static unsigned int current_gpio_io = 0; -static unsigned int current_cpld = 0; - -void gpio_modify_op(int mask, int set) -{ - unsigned int new_gpio, changed; - - new_gpio = (current_gpio_op & ~mask) | set; - changed = new_gpio ^ current_gpio_op; - current_gpio_op = new_gpio; - - if (changed & 0xff) - outb(new_gpio, GP1_IO_BASE); - if (changed & 0xff00) - outb(new_gpio >> 8, GP2_IO_BASE); -} - -static inline void __gpio_modify_io(int mask, int in) -{ - unsigned int new_gpio, changed; - int port; - - new_gpio = (current_gpio_io & ~mask) | in; - changed = new_gpio ^ current_gpio_io; - current_gpio_io = new_gpio; - - changed >>= 1; - new_gpio >>= 1; - - wb977_device_select(7); - - for (port = 0xe1; changed && port < 0xe8; changed >>= 1) { - wb977_wb(port, new_gpio & 1); - - port += 1; - new_gpio >>= 1; - } - - wb977_device_select(8); - - for (port = 0xe8; changed && port < 0xec; changed >>= 1) { - wb977_wb(port, new_gpio & 1); - - port += 1; - new_gpio >>= 1; - } -} - -void gpio_modify_io(int mask, int in) -{ - /* Open up the SuperIO chip */ - wb977_open(); - - __gpio_modify_io(mask, in); - - /* Close up the EFER gate */ - wb977_close(); -} - -int gpio_read(void) -{ - return inb(GP1_IO_BASE) | inb(GP2_IO_BASE) << 8; -} - -/* - * Initialise the Winbond W83977F global registers - */ -static inline void wb977_init_global(void) -{ - /* - * Enable R/W config registers - */ - wb977_wb(0x26, 0x40); - - /* - * Power down FDC (not used) - */ - wb977_wb(0x22, 0xfe); - - /* - * GP12, GP11, CIRRX, IRRXH, GP10 - */ - wb977_wb(0x2a, 0xc1); - - /* - * GP23, GP22, GP21, GP20, GP13 - */ - wb977_wb(0x2b, 0x6b); - - /* - * GP17, GP16, GP15, GP14 - */ - wb977_wb(0x2c, 0x55); -} - -/* - * Initialise the Winbond W83977F printer port - */ -static inline void wb977_init_printer(void) -{ - wb977_device_select(1); - - /* - * mode 1 == EPP - */ - wb977_wb(0xf0, 0x01); -} - -/* - * Initialise the Winbond W83977F keyboard controller - */ -static inline void wb977_init_keyboard(void) -{ - wb977_device_select(5); - - /* - * Keyboard controller address - */ - wb977_ww(0x60, 0x0060); - wb977_ww(0x62, 0x0064); - - /* - * Keyboard IRQ 1, active high, edge trigger - */ - wb977_wb(0x70, 1); - wb977_wb(0x71, 0x02); - - /* - * Mouse IRQ 5, active high, edge trigger - */ - wb977_wb(0x72, 5); - wb977_wb(0x73, 0x02); - - /* - * KBC 8MHz - */ - wb977_wb(0xf0, 0x40); - - /* - * Enable device - */ - wb977_device_enable(); -} - -/* - * Initialise the Winbond W83977F Infra-Red device - */ -static inline void wb977_init_irda(void) -{ - wb977_device_select(6); - - /* - * IR base address - */ - wb977_ww(0x60, IRDA_IO_BASE); - - /* - * IRDA IRQ 6, active high, edge trigger - */ - wb977_wb(0x70, 6); - wb977_wb(0x71, 0x02); - - /* - * RX DMA - ISA DMA 0 - */ - wb977_wb(0x74, 0x00); - - /* - * TX DMA - Disable Tx DMA - */ - wb977_wb(0x75, 0x04); - - /* - * Append CRC, Enable bank selection - */ - wb977_wb(0xf0, 0x03); - - /* - * Enable device - */ - wb977_device_enable(); -} - -/* - * Initialise Winbond W83977F general purpose IO - */ -static inline void wb977_init_gpio(void) -{ - unsigned long flags; - - /* - * Set up initial I/O definitions - */ - current_gpio_io = -1; - __gpio_modify_io(-1, GPIO_DONE | GPIO_WDTIMER); - - wb977_device_select(7); - - /* - * Group1 base address - */ - wb977_ww(0x60, GP1_IO_BASE); - wb977_ww(0x62, 0); - wb977_ww(0x64, 0); - - /* - * GP10 (Orage button) IRQ 10, active high, edge trigger - */ - wb977_wb(0x70, 10); - wb977_wb(0x71, 0x02); - - /* - * GP10: Debounce filter enabled, IRQ, input - */ - wb977_wb(0xe0, 0x19); - - /* - * Enable Group1 - */ - wb977_device_enable(); - - wb977_device_select(8); - - /* - * Group2 base address - */ - wb977_ww(0x60, GP2_IO_BASE); - - /* - * Clear watchdog timer regs - * - timer disable - */ - wb977_wb(0xf2, 0x00); - - /* - * - disable LED, no mouse nor keyboard IRQ - */ - wb977_wb(0xf3, 0x00); - - /* - * - timer counting, disable power LED, disable timeouot - */ - wb977_wb(0xf4, 0x00); - - /* - * Enable group2 - */ - wb977_device_enable(); - - /* - * Set Group1/Group2 outputs - */ - spin_lock_irqsave(&gpio_lock, flags); - gpio_modify_op(-1, GPIO_RED_LED | GPIO_FAN); - spin_unlock_irqrestore(&gpio_loc, flags); -} - -/* - * Initialise the Winbond W83977F chip. - */ -static void __init wb977_init(void) -{ - request_region(0x370, 2, "W83977AF configuration"); - - /* - * Open up the SuperIO chip - */ - wb977_open(); - - /* - * Initialise the global registers - */ - wb977_init_global(); - - /* - * Initialise the various devices in - * the multi-IO chip. - */ - wb977_init_printer(); - wb977_init_keyboard(); - wb977_init_irda(); - wb977_init_gpio(); - - /* - * Close up the EFER gate - */ - wb977_close(); -} - -void cpld_modify(int mask, int set) -{ - int msk; - - current_cpld = (current_cpld & ~mask) | set; - - gpio_modify_io(GPIO_DATA | GPIO_IOCLK | GPIO_IOLOAD, 0); - gpio_modify_op(GPIO_IOLOAD, 0); - - for (msk = 8; msk; msk >>= 1) { - int bit = current_cpld & msk; - - gpio_modify_op(GPIO_DATA | GPIO_IOCLK, bit ? GPIO_DATA : 0); - gpio_modify_op(GPIO_IOCLK, GPIO_IOCLK); - } - - gpio_modify_op(GPIO_IOCLK|GPIO_DATA, 0); - gpio_modify_op(GPIO_IOLOAD|GPIO_DSCLK, GPIO_IOLOAD|GPIO_DSCLK); - gpio_modify_op(GPIO_IOLOAD, 0); -} - -static void __init cpld_init(void) -{ - unsigned long flags; - - spin_lock_irqsave(&gpio_lock, flags); - cpld_modify(-1, CPLD_UNMUTE | CPLD_7111_DISABLE); - spin_unlock_irqrestore(&gpio_lock, flags); -} - -static unsigned char rwa_unlock[] __initdata = -{ 0x00, 0x00, 0x6a, 0xb5, 0xda, 0xed, 0xf6, 0xfb, 0x7d, 0xbe, 0xdf, 0x6f, 0x37, 0x1b, - 0x0d, 0x86, 0xc3, 0x61, 0xb0, 0x58, 0x2c, 0x16, 0x8b, 0x45, 0xa2, 0xd1, 0xe8, 0x74, - 0x3a, 0x9d, 0xce, 0xe7, 0x73, 0x39 }; - -#ifndef DEBUG -#define dprintk(x...) -#else -#define dprintk(x...) printk(x) -#endif - -#define WRITE_RWA(r,v) do { outb((r), 0x279); udelay(10); outb((v), 0xa79); } while (0) - -static inline void rwa010_unlock(void) -{ - int i; - - WRITE_RWA(2, 2); - mdelay(10); - - for (i = 0; i < sizeof(rwa_unlock); i++) { - outb(rwa_unlock[i], 0x279); - udelay(10); - } -} - -static inline void rwa010_read_ident(void) -{ - unsigned char si[9]; - int i, j; - - WRITE_RWA(3, 0); - WRITE_RWA(0, 128); - - outb(1, 0x279); - - mdelay(1); - - dprintk("Identifier: "); - for (i = 0; i < 9; i++) { - si[i] = 0; - for (j = 0; j < 8; j++) { - int bit; - udelay(250); - inb(0x203); - udelay(250); - bit = inb(0x203); - dprintk("%02X ", bit); - bit = (bit == 0xaa) ? 1 : 0; - si[i] |= bit << j; - } - dprintk("(%02X) ", si[i]); - } - dprintk("\n"); -} - -static inline void rwa010_global_init(void) -{ - WRITE_RWA(6, 2); // Assign a card no = 2 - - dprintk("Card no = %d\n", inb(0x203)); - - /* disable the modem section of the chip */ - WRITE_RWA(7, 3); - WRITE_RWA(0x30, 0); - - /* disable the cdrom section of the chip */ - WRITE_RWA(7, 4); - WRITE_RWA(0x30, 0); - - /* disable the MPU-401 section of the chip */ - WRITE_RWA(7, 2); - WRITE_RWA(0x30, 0); -} - -static inline void rwa010_game_port_init(void) -{ - int i; - - WRITE_RWA(7, 5); - - dprintk("Slider base: "); - WRITE_RWA(0x61, 1); - i = inb(0x203); - - WRITE_RWA(0x60, 2); - dprintk("%02X%02X (201)\n", inb(0x203), i); - - WRITE_RWA(0x30, 1); -} - -static inline void rwa010_waveartist_init(int base, int irq, int dma) -{ - int i; - - WRITE_RWA(7, 0); - - dprintk("WaveArtist base: "); - WRITE_RWA(0x61, base); - i = inb(0x203); - - WRITE_RWA(0x60, base >> 8); - dprintk("%02X%02X (%X),", inb(0x203), i, base); - - WRITE_RWA(0x70, irq); - dprintk(" irq: %d (%d),", inb(0x203), irq); - - WRITE_RWA(0x74, dma); - dprintk(" dma: %d (%d)\n", inb(0x203), dma); - - WRITE_RWA(0x30, 1); -} - -static inline void rwa010_soundblaster_init(int sb_base, int al_base, int irq, int dma) -{ - int i; - - WRITE_RWA(7, 1); - - dprintk("SoundBlaster base: "); - WRITE_RWA(0x61, sb_base); - i = inb(0x203); - - WRITE_RWA(0x60, sb_base >> 8); - dprintk("%02X%02X (%X),", inb(0x203), i, sb_base); - - dprintk(" irq: "); - WRITE_RWA(0x70, irq); - dprintk("%d (%d),", inb(0x203), irq); - - dprintk(" 8-bit DMA: "); - WRITE_RWA(0x74, dma); - dprintk("%d (%d)\n", inb(0x203), dma); - - dprintk("AdLib base: "); - WRITE_RWA(0x63, al_base); - i = inb(0x203); - - WRITE_RWA(0x62, al_base >> 8); - dprintk("%02X%02X (%X)\n", inb(0x203), i, al_base); - - WRITE_RWA(0x30, 1); -} - -static void rwa010_soundblaster_reset(void) -{ - int i; - - outb(1, 0x226); - udelay(3); - outb(0, 0x226); - - for (i = 0; i < 5; i++) { - if (inb(0x22e) & 0x80) - break; - mdelay(1); - } - if (i == 5) - printk("SoundBlaster: DSP reset failed\n"); - - dprintk("SoundBlaster DSP reset: %02X (AA)\n", inb(0x22a)); - - for (i = 0; i < 5; i++) { - if ((inb(0x22c) & 0x80) == 0) - break; - mdelay(1); - } - - if (i == 5) - printk("SoundBlaster: DSP not ready\n"); - else { - outb(0xe1, 0x22c); - - dprintk("SoundBlaster DSP id: "); - i = inb(0x22a); - udelay(1); - i |= inb(0x22a) << 8; - dprintk("%04X\n", i); - - for (i = 0; i < 5; i++) { - if ((inb(0x22c) & 0x80) == 0) - break; - mdelay(1); - } - - if (i == 5) - printk("SoundBlaster: could not turn speaker off\n"); - - outb(0xd3, 0x22c); - } - - /* turn on OPL3 */ - outb(5, 0x38a); - outb(1, 0x38b); -} - -static void __init rwa010_init(void) -{ - rwa010_unlock(); - rwa010_read_ident(); - rwa010_global_init(); - rwa010_game_port_init(); - rwa010_waveartist_init(0x250, 3, 7); - rwa010_soundblaster_init(0x220, 0x388, 3, 1); - rwa010_soundblaster_reset(); -} - -EXPORT_SYMBOL(gpio_lock); -EXPORT_SYMBOL(gpio_modify_op); -EXPORT_SYMBOL(gpio_modify_io); -EXPORT_SYMBOL(cpld_modify); - -/* - * Initialise any other hardware after we've got the PCI bus - * initialised. We may need the PCI bus to talk to this other - * hardware. - */ -static int __init nw_hw_init(void) -{ - /* - * this ought to have a better home... - * Since this calls the above routines, which are - * compiled only if CONFIG_ARCH_NETWINDER is set, - * these should only be parsed by the compiler - * in the same circumstance. - */ - if (machine_is_netwinder()) { - unsigned long flags; - - wb977_init(); - cpld_init(); - rwa010_init(); - - spin_lock_irqsave(&gpio_lock, flags); - gpio_modify_op(GPIO_RED_LED|GPIO_GREEN_LED, DEFAULT_LEDS); - spin_unlock_irqrestore(&gpio_lock, flags); - } - return 0; -} - -__initcall(nw_hw_init); -#endif - -/* - * CATS stuff - */ -#ifdef CONFIG_ARCH_CATS - -#define CONFIG_PORT 0x370 -#define INDEX_PORT (CONFIG_PORT) -#define DATA_PORT (CONFIG_PORT + 1) - -static int __init cats_hw_init(void) -{ - if (machine_is_cats()) { - /* Set Aladdin to CONFIGURE mode */ - outb(0x51, CONFIG_PORT); - outb(0x23, CONFIG_PORT); - - /* Select logical device 3 */ - outb(0x07, INDEX_PORT); - outb(0x03, DATA_PORT); - - /* Set parallel port to DMA channel 3, ECP+EPP1.9, - enable EPP timeout */ - outb(0x74, INDEX_PORT); - outb(0x03, DATA_PORT); - - outb(0xf0, INDEX_PORT); - outb(0x0f, DATA_PORT); - - outb(0xf1, INDEX_PORT); - outb(0x07, DATA_PORT); - - /* Select logical device 4 */ - outb(0x07, INDEX_PORT); - outb(0x04, DATA_PORT); - - /* UART1 high speed mode */ - outb(0xf0, INDEX_PORT); - outb(0x02, DATA_PORT); - - /* Select logical device 5 */ - outb(0x07, INDEX_PORT); - outb(0x05, DATA_PORT); - - /* UART2 high speed mode */ - outb(0xf0, INDEX_PORT); - outb(0x02, DATA_PORT); - - /* Set Aladdin to RUN mode */ - outb(0xbb, CONFIG_PORT); - } - - return 0; -} - -__initcall(cats_hw_init); -#endif - diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/kernel/hw-sa1100.c linux/arch/arm/kernel/hw-sa1100.c --- v2.4.0-test8/linux/arch/arm/kernel/hw-sa1100.c Sun Aug 13 09:54:15 2000 +++ linux/arch/arm/kernel/hw-sa1100.c Wed Dec 31 16:00:00 1969 @@ -1,184 +0,0 @@ -/* - * arch/arm/kernel/hw-sa1100.c - * - * SA1100-dependent machine specifics - * - * Copyright (C) 2000 Nicolas Pitre - * - * This will certainly contain more stuff with time... like power management, - * special hardware autodetection, etc. - * - */ -#include -#include -#include -#include -#include - -#include -#include -#include - -/* - * SA1100 GPIO edge detection for IRQs: - * IRQs are generated on Falling-Edge, Rising-Edge, or both. - * This must be called *before* the appropriate IRQ is registered. - * Use this instead of directly setting GRER/GFER. - */ - -int GPIO_IRQ_rising_edge; -int GPIO_IRQ_falling_edge; - -void set_GPIO_IRQ_edge( int gpio_mask, int edge ) -{ - if( edge & GPIO_FALLING_EDGE ) - GPIO_IRQ_falling_edge |= gpio_mask; - else - GPIO_IRQ_falling_edge &= ~gpio_mask; - if( edge & GPIO_RISING_EDGE ) - GPIO_IRQ_rising_edge |= gpio_mask; - else - GPIO_IRQ_rising_edge &= ~gpio_mask; -} - -EXPORT_SYMBOL(set_GPIO_IRQ_edge); - - -#ifdef CONFIG_SA1100_ASSABET - -unsigned long BCR_value = BCR_DB1110; -unsigned long SCR_value = SCR_INIT; -EXPORT_SYMBOL(BCR_value); -EXPORT_SYMBOL(SCR_value); - -/* - * Read System Configuration "Register" - * (taken from "Intel StrongARM SA-1110 Microprocessor Development Board - * User's Guide", section 4.4.1) - * - * This same scan is performed in arch/arm/boot/compressed/head-sa1100.S - * to set up the serial port for decompression status messages. We - * repeat it here because the kernel may not be loaded as a zImage, and - * also because it's a hassle to communicate the SCR value to the kernel - * from the decompressor. - */ - -void __init get_assabet_scr(void) -{ - unsigned long flags, scr, i; - - save_flags_cli(flags); - GPDR |= 0x3fc; /* Configure GPIO 9:2 as outputs */ - GPSR = 0x3fc; /* Write 0xFF to GPIO 9:2 */ - GPDR &= ~(0x3fc); /* Configure GPIO 9:2 as inputs */ - for(i = 100; i--; scr = GPLR); /* Read GPIO 9:2 */ - GPDR |= 0x3fc; /* restore correct pin direction */ - restore_flags(flags); - scr &= 0x3fc; /* save as system configuration byte. */ - - SCR_value = scr; -} - -#endif /* CONFIG_SA1100_ASSABET */ - -/* - * Bitsy has extended, write-only memory-mapped GPIO's - */ -#if defined(CONFIG_SA1100_BITSY) -static int bitsy_egpio = EGPIO_BITSY_RS232_ON; -void clr_bitsy_egpio(unsigned long x) -{ - bitsy_egpio &= ~x; - *(volatile int *)0xdc000000 = bitsy_egpio; -} -void set_bitsy_egpio(unsigned long x) -{ - bitsy_egpio |= x; - *(volatile int *)0xdc000000 = bitsy_egpio; -} -EXPORT_SYMBOL(clr_bitsy_egpio); -EXPORT_SYMBOL(set_bitsy_egpio); -#endif - -#ifdef CONFIG_SA1111 - -void __init sa1111_init(void){ - unsigned long id=SKID; - - if((id & SKID_ID_MASK) == SKID_SA1111_ID) - printk(KERN_INFO "SA-1111 Microprocessor Companion Chip: " - "silicon revision %x, metal revision %x\n", - (id & SKID_SIREV_MASK)>>4, (id & SKID_MTREV_MASK)); - else { - printk(KERN_ERR "Could not detect SA-1111!\n"); - return; - } - - /* 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; - TUCR = TUCR_3_6864MHz; - - /* Now, set up the PLL and RCLK in the SA-1111: */ - SKCR = SKCR_PLL_BYPASS | SKCR_RDYEN | SKCR_OE_EN; - udelay(100); - SKCR = SKCR_PLL_BYPASS | SKCR_RCLKEN | SKCR_RDYEN | SKCR_OE_EN; - - /* SA-1111 Register Access Bus should now be available. Clocks for - * any other SA-1111 functional blocks must be enabled separately - * using the SKPCR. - */ - - { - /* - * SA1111 DMA bus master setup - */ - int cas; - - /* 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) ); - - TUCR |= (1<<10); - } -} - -#endif - - -static int __init hw_sa1100_init(void) -{ - if( machine_is_assabet() ){ - if(machine_has_neponset()){ -#ifdef CONFIG_ASSABET_NEPONSET - LEDS = WHOAMI; - sa1111_init(); -#else - printk( "Warning: Neponset detected but full support " - "hasn't been configured in the kernel\n" ); -#endif - } - } else if (machine_is_xp860()) { - sa1111_init(); - } - return 0; -} - -module_init(hw_sa1100_init); diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/kernel/init_task.c linux/arch/arm/kernel/init_task.c --- v2.4.0-test8/linux/arch/arm/kernel/init_task.c Wed Oct 20 16:29:08 1999 +++ linux/arch/arm/kernel/init_task.c Mon Sep 18 15:15:25 2000 @@ -1,6 +1,10 @@ +/* + * linux/arch/arm/kernel/init_task.c + */ #include #include #include +#include #include #include diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/kernel/irq.c linux/arch/arm/kernel/irq.c --- v2.4.0-test8/linux/arch/arm/kernel/irq.c Sun Aug 13 09:54:15 2000 +++ linux/arch/arm/kernel/irq.c Mon Sep 18 15:15:25 2000 @@ -4,16 +4,18 @@ * Copyright (C) 1992 Linus Torvalds * Modifications for ARM processor Copyright (C) 1995-1998 Russell King. * - * 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. - */ - -/* - * 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. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This 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. + * + * 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 diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/kernel/isa.c linux/arch/arm/kernel/isa.c --- v2.4.0-test8/linux/arch/arm/kernel/isa.c Mon Jun 26 12:04:01 2000 +++ linux/arch/arm/kernel/isa.c Mon Sep 18 15:15:25 2000 @@ -1,9 +1,16 @@ /* - * arch/arm/kernel/isa.c + * linux/arch/arm/kernel/isa.c * - * ISA shared memory and I/O port support + * Copyright (C) 1999 Phil Blundell * - * Copyright (C) 1999 Phil Blundell + * ISA shared memory and I/O port support + */ + +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. */ /* diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/kernel/leds-ebsa110.c linux/arch/arm/kernel/leds-ebsa110.c --- v2.4.0-test8/linux/arch/arm/kernel/leds-ebsa110.c Mon Jun 19 17:59:34 2000 +++ linux/arch/arm/kernel/leds-ebsa110.c Mon Sep 18 15:15:25 2000 @@ -1,23 +1,32 @@ /* - * arch/arm/kernel/leds-ebsa110.c + * linux/arch/arm/kernel/leds-ebsa110.c * - * Copyright (C) 1998 Russell King + * Copyright (C) 1998 Russell King * - * EBSA-110 LED control routines. We use the led as follows: + * 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. * - * - Red - toggles state every 50 timer interrupts + * EBSA-110 LED control routines. We use the led as follows: + * + * - Red - toggles state every 50 timer interrupts */ #include +#include +#include #include #include #include +#include + +static spinlock_t leds_lock; static void ebsa110_leds_event(led_event_t ledevt) { unsigned long flags; - save_flags_cli(flags); + spin_lock_irqsave(&leds_lock, flags); switch(ledevt) { case led_timer: @@ -28,9 +37,15 @@ break; } - restore_flags(flags); + spin_unlock_irqrestore(&leds_lock, flags); } -void (*leds_event)(led_event_t) = ebsa110_leds_event; +static int __init leds_init(void) +{ + if (machine_is_ebsa110()) + leds_event = ebsa110_leds_event; + + return 0; +} -EXPORT_SYMBOL(leds_event); +__initcall(leds_init); diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/kernel/leds-footbridge.c linux/arch/arm/kernel/leds-footbridge.c --- v2.4.0-test8/linux/arch/arm/kernel/leds-footbridge.c Sun Aug 13 09:54:15 2000 +++ linux/arch/arm/kernel/leds-footbridge.c Wed Dec 31 16:00:00 1969 @@ -1,257 +0,0 @@ -/* - * arch/arm/kernel/leds-footbridge.c - * - * Copyright (C) 1998-1999 Russell King - * - * EBSA-285 and NetWinder LED control routines. - * - * The EBSA-285 uses the leds as follows: - * - Green - toggles state every 50 timer interrupts - * - Amber - On if system is not idle - * - Red - currently unused - * - * The Netwinder uses the leds as follows: - * - Green - toggles state every 50 timer interrupts - * - Red - On if the system is not idle - * - * Changelog: - * 02-05-1999 RMK Various cleanups - */ -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#define LED_STATE_ENABLED 1 -#define LED_STATE_CLAIMED 2 -static char led_state; -static char hw_led_state; - -static spinlock_t leds_lock = SPIN_LOCK_UNLOCKED; -extern spinlock_t gpio_lock; - -#if defined(CONFIG_ARCH_EBSA285) || defined(CONFIG_ARCH_CO285) - -static void ebsa285_leds_event(led_event_t evt) -{ - unsigned long flags; - - spin_lock_irqsave(&leds_lock, flags); - - switch (evt) { - case led_start: - hw_led_state = XBUS_LED_RED | XBUS_LED_GREEN; -#ifndef CONFIG_LEDS_CPU - hw_led_state |= XBUS_LED_AMBER; -#endif - led_state |= LED_STATE_ENABLED; - break; - - case led_stop: - led_state &= ~LED_STATE_ENABLED; - break; - - case led_claim: - led_state |= LED_STATE_CLAIMED; - hw_led_state = XBUS_LED_RED | XBUS_LED_GREEN | XBUS_LED_AMBER; - break; - - case led_release: - led_state &= ~LED_STATE_CLAIMED; - hw_led_state = XBUS_LED_RED | XBUS_LED_GREEN | XBUS_LED_AMBER; - break; - -#ifdef CONFIG_LEDS_TIMER - case led_timer: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state ^= XBUS_LED_GREEN; - break; -#endif - -#ifdef CONFIG_LEDS_CPU - case led_idle_start: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state |= XBUS_LED_AMBER; - break; - - case led_idle_end: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state &= ~XBUS_LED_AMBER; - break; -#endif - - case led_halted: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state &= ~XBUS_LED_RED; - break; - - case led_green_on: - if (led_state & LED_STATE_CLAIMED) - hw_led_state &= ~XBUS_LED_GREEN; - break; - - case led_green_off: - if (led_state & LED_STATE_CLAIMED) - hw_led_state |= XBUS_LED_GREEN; - break; - - case led_amber_on: - if (led_state & LED_STATE_CLAIMED) - hw_led_state &= ~XBUS_LED_AMBER; - break; - - case led_amber_off: - if (led_state & LED_STATE_CLAIMED) - hw_led_state |= XBUS_LED_AMBER; - break; - - case led_red_on: - if (led_state & LED_STATE_CLAIMED) - hw_led_state &= ~XBUS_LED_RED; - break; - - case led_red_off: - if (led_state & LED_STATE_CLAIMED) - hw_led_state |= XBUS_LED_RED; - break; - - default: - break; - } - - if (led_state & LED_STATE_ENABLED) - *XBUS_LEDS = hw_led_state; - - spin_unlock_irqrestore(&leds_lock, flags); -} - -#endif - -#ifdef CONFIG_ARCH_NETWINDER - -static void netwinder_leds_event(led_event_t evt) -{ - unsigned long flags; - - spin_lock_irqsave(&leds_lock, flags); - - switch (evt) { - case led_start: - led_state |= LED_STATE_ENABLED; - hw_led_state = GPIO_GREEN_LED; - break; - - case led_stop: - led_state &= ~LED_STATE_ENABLED; - break; - - case led_claim: - led_state |= LED_STATE_CLAIMED; - hw_led_state = 0; - break; - - case led_release: - led_state &= ~LED_STATE_CLAIMED; - hw_led_state = 0; - break; - -#ifdef CONFIG_LEDS_TIMER - case led_timer: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state ^= GPIO_GREEN_LED; - break; -#endif - -#ifdef CONFIG_LEDS_CPU - case led_idle_start: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state &= ~GPIO_RED_LED; - break; - - case led_idle_end: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state |= GPIO_RED_LED; - break; -#endif - - case led_halted: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state |= GPIO_RED_LED; - break; - - case led_green_on: - if (led_state & LED_STATE_CLAIMED) - hw_led_state |= GPIO_GREEN_LED; - break; - - case led_green_off: - if (led_state & LED_STATE_CLAIMED) - hw_led_state &= ~GPIO_GREEN_LED; - break; - - case led_amber_on: - if (led_state & LED_STATE_CLAIMED) - hw_led_state |= GPIO_GREEN_LED | GPIO_RED_LED; - break; - - case led_amber_off: - if (led_state & LED_STATE_CLAIMED) - hw_led_state &= ~(GPIO_GREEN_LED | GPIO_RED_LED); - break; - - case led_red_on: - if (led_state & LED_STATE_CLAIMED) - hw_led_state |= GPIO_RED_LED; - break; - - case led_red_off: - if (led_state & LED_STATE_CLAIMED) - hw_led_state &= ~GPIO_RED_LED; - break; - - default: - break; - } - - spin_unlock_irqrestore(&leds_lock, flags); - - if (led_state & LED_STATE_ENABLED) { - spin_lock_irqsave(&gpio_lock, flags); - gpio_modify_op(GPIO_RED_LED | GPIO_GREEN_LED, hw_led_state); - spin_unlock_irqrestore(&gpio_lock, flags); - } -} - -#endif - -static void dummy_leds_event(led_event_t evt) -{ -} - -void (*leds_event)(led_event_t) = dummy_leds_event; - -EXPORT_SYMBOL(leds_event); - -static int __init leds_init(void) -{ -#if defined(CONFIG_ARCH_EBSA285) || defined(CONFIG_ARCH_CO285) - if (machine_is_ebsa285() || machine_is_co285()) - leds_event = ebsa285_leds_event; -#endif -#ifdef CONFIG_ARCH_NETWINDER - if (machine_is_netwinder()) - leds_event = netwinder_leds_event; -#endif - - leds_event(led_start); - - return 0; -} - -__initcall(leds_init); diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/kernel/leds-ftvpci.c linux/arch/arm/kernel/leds-ftvpci.c --- v2.4.0-test8/linux/arch/arm/kernel/leds-ftvpci.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/kernel/leds-ftvpci.c Mon Sep 18 15:15:25 2000 @@ -0,0 +1,31 @@ +/* + * linux/arch/arm/kernel/leds-ftvpci.c + * + * Copyright (C) 1999 FutureTV Labs Ltd + */ + +#include + +#include +#include +#include +#include + +static void ftvpci_leds_event(led_event_t ledevt) +{ + static int led_state = 0; + + switch(ledevt) { + case led_timer: + led_state ^= 1; + raw_writeb(0x1a | led_state, INTCONT_BASE); + break; + + default: + break; + } +} + +void (*leds_event)(led_event_t) = ftvpci_leds_event; + +EXPORT_SYMBOL(leds_event); diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/kernel/leds-sa1100.c linux/arch/arm/kernel/leds-sa1100.c --- v2.4.0-test8/linux/arch/arm/kernel/leds-sa1100.c Sun Aug 13 09:54:15 2000 +++ linux/arch/arm/kernel/leds-sa1100.c Wed Dec 31 16:00:00 1969 @@ -1,437 +0,0 @@ -/* - * linux/arch/arm/kernel/leds-sa1100.c - * - * Copyright (C) 2000 John Dorsey - * - * Original (leds-footbridge.c) by Russell King - * - * Added Brutus LEDs support - * Nicolas Pitre, Mar 19, 2000 - * - * Added LART LED support - * Erik Mouw (J.A.K.Mouw@its.tudelft.nl), April 21, 2000 - * - * - * Assabet uses the LEDs as follows: - * - Green - toggles state every 50 timer interrupts - * - Red - on if system is not idle - * - * Brutus uses the LEDs as follows: - * - D3 (Green, GPIO9) - toggles state every 50 timer interrupts - * - D17 (Red, GPIO20) - on if system is not idle - * - D4 (Green, GPIO8) - misc function - * - * LART uses the LED as follows: - * - GPIO23 is the LED, on if system is not idle - * You can use both CONFIG_LEDS_CPU and CONFIG_LEDS_TIMER at the same - * time, but in that case the timer events will still dictate the - * pace of the LED. - * - */ -#include -#include -#include -#include -#include - -#include -#include -#include -#include - - -#define LED_STATE_ENABLED 1 -#define LED_STATE_CLAIMED 2 - -static unsigned int led_state; -static unsigned int hw_led_state; - - -#ifdef CONFIG_SA1100_ASSABET - -#define BCR_LED_MASK (BCR_LED_GREEN | BCR_LED_RED) - -static void assabet_leds_event(led_event_t evt) -{ - unsigned long flags; - - save_flags_cli(flags); - - switch (evt) { - case led_start: - hw_led_state = BCR_LED_RED | BCR_LED_GREEN; - led_state = LED_STATE_ENABLED; - break; - - case led_stop: - led_state &= ~LED_STATE_ENABLED; - break; - - case led_claim: - led_state |= LED_STATE_CLAIMED; - hw_led_state = BCR_LED_RED | BCR_LED_GREEN; - break; - - case led_release: - led_state &= ~LED_STATE_CLAIMED; - hw_led_state = BCR_LED_RED | BCR_LED_GREEN; - break; - -#ifdef CONFIG_LEDS_TIMER - case led_timer: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state ^= BCR_LED_GREEN; - break; -#endif - -#ifdef CONFIG_LEDS_CPU - case led_idle_start: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state |= BCR_LED_RED; - break; - - case led_idle_end: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state &= ~BCR_LED_RED; - break; -#endif - - case led_halted: - break; - - case led_green_on: - if (led_state & LED_STATE_CLAIMED) - hw_led_state &= ~BCR_LED_GREEN; - break; - - case led_green_off: - if (led_state & LED_STATE_CLAIMED) - hw_led_state |= BCR_LED_GREEN; - break; - - case led_amber_on: - break; - - case led_amber_off: - break; - - case led_red_on: - if (led_state & LED_STATE_CLAIMED) - hw_led_state &= ~BCR_LED_RED; - break; - - case led_red_off: - if (led_state & LED_STATE_CLAIMED) - hw_led_state |= BCR_LED_RED; - break; - - default: - break; - } - - if (led_state & LED_STATE_ENABLED) - BCR = BCR_value = (BCR_value & ~BCR_LED_MASK) | hw_led_state; - - restore_flags(flags); -} - -#endif /* CONFIG_SA1100_ASSABET */ - -#ifdef CONFIG_SA1100_BRUTUS - -#define LED_D3 GPIO_GPIO(9) -#define LED_D4 GPIO_GPIO(8) -#define LED_D17 GPIO_GPIO(20) -#define LED_MASK (LED_D3|LED_D4|LED_D17) - -static void brutus_leds_event(led_event_t evt) -{ - unsigned long flags; - - save_flags_cli(flags); - - switch (evt) { - case led_start: - hw_led_state = LED_MASK; - led_state = LED_STATE_ENABLED; - break; - - case led_stop: - led_state &= ~LED_STATE_ENABLED; - break; - - case led_claim: - led_state |= LED_STATE_CLAIMED; - hw_led_state = LED_MASK; - break; - - case led_release: - led_state &= ~LED_STATE_CLAIMED; - hw_led_state = LED_MASK; - break; - -#ifdef CONFIG_LEDS_TIMER - case led_timer: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state ^= LED_D3; - break; -#endif - -#ifdef CONFIG_LEDS_CPU - case led_idle_start: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state |= LED_D17; - break; - - case led_idle_end: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state &= ~LED_D17; - break; -#endif - - case led_green_on: - hw_led_state &= ~LED_D4; - break; - - case led_green_off: - hw_led_state |= LED_D4; - break; - - case led_amber_on: - break; - - case led_amber_off: - break; - - case led_red_on: - if (led_state & LED_STATE_CLAIMED) - hw_led_state &= ~LED_D17; - break; - - case led_red_off: - if (led_state & LED_STATE_CLAIMED) - hw_led_state |= LED_D17; - break; - - default: - break; - } - - if (led_state & LED_STATE_ENABLED) { - GPSR = hw_led_state; - GPCR = hw_led_state ^ LED_MASK; - } - - restore_flags(flags); -} - -#endif /* CONFIG_SA1100_BRUTUS */ - -#ifdef CONFIG_SA1100_LART - -#define LED_23 GPIO_GPIO23 -#define LED_MASK (LED_23) - - -static void lart_leds_event(led_event_t evt) -{ - unsigned long flags; - - save_flags_cli(flags); - - switch(evt) { - case led_start: - hw_led_state = LED_MASK; - led_state = LED_STATE_ENABLED; - break; - - case led_stop: - led_state &= ~LED_STATE_ENABLED; - break; - - case led_claim: - led_state |= LED_STATE_CLAIMED; - hw_led_state = LED_MASK; - break; - - case led_release: - led_state &= ~LED_STATE_CLAIMED; - hw_led_state = LED_MASK; - break; - -#ifdef CONFIG_LEDS_TIMER - case led_timer: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state ^= LED_23; - break; -#endif - -#ifdef CONFIG_LEDS_CPU - case led_idle_start: - /* The LART people like the LED to be off when the - system is idle... */ - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state &= ~LED_23; - break; - - case led_idle_end: - /* ... and on if the system is not idle */ - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state |= LED_23; - break; -#endif - - case led_red_on: - if (led_state & LED_STATE_CLAIMED) - hw_led_state &= ~LED_23; - break; - - case led_red_off: - if (led_state & LED_STATE_CLAIMED) - hw_led_state |= LED_23; - break; - - default: - break; - } - - /* Now set the GPIO state, or nothing will happen at all */ - if (led_state & LED_STATE_ENABLED) { - GPSR = hw_led_state; - GPCR = hw_led_state ^ LED_MASK; - } - - restore_flags(flags); -} - -#endif /* CONFIG_SA1100_LART */ - -#ifdef CONFIG_SA1100_CERF -#define LED_D0 GPIO_GPIO(0) -#define LED_D1 GPIO_GPIO(1) -#define LED_D2 GPIO_GPIO(2) -#define LED_D3 GPIO_GPIO(3) -#define LED_MASK (LED_D0|LED_D1|LED_D2|LED_D3) - -static void cerf_leds_event(led_event_t evt) -{ - unsigned long flags; - - save_flags_cli(flags); - - switch (evt) { - case led_start: - hw_led_state = LED_MASK; - led_state = LED_STATE_ENABLED; - break; - - case led_stop: - led_state &= ~LED_STATE_ENABLED; - break; - - case led_claim: - led_state |= LED_STATE_CLAIMED; - hw_led_state = LED_MASK; - break; - case led_release: - led_state &= ~LED_STATE_CLAIMED; - hw_led_state = LED_MASK; - break; - -#ifdef CONFIG_LEDS_TIMER - case led_timer: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state ^= LED_D0; - break; -#endif - -#ifdef CONFIG_LEDS_CPU - case led_idle_start: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state &= ~LED_D1; - break; - - case led_idle_end: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state |= LED_D1; - break; -#endif - case led_green_on: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state &= ~LED_D2; - break; - - case led_green_off: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state |= LED_D2; - break; - - case led_amber_on: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state &= ~LED_D3; - break; - - case led_amber_off: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state |= LED_D3; - break; - - case led_red_on: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state &= ~LED_D1; - break; - - case led_red_off: - if (!(led_state & LED_STATE_CLAIMED)) - hw_led_state |= LED_D1; - break; - - default: - break; - } - - if (led_state & LED_STATE_ENABLED) { - GPSR = hw_led_state; - GPCR = hw_led_state ^ LED_MASK; - } - - restore_flags(flags); -} - -#endif /* CONFIG_SA1100_CERF */ - -static void dummy_leds_event(led_event_t evt) -{ -} - -void (*leds_event)(led_event_t) = dummy_leds_event; - -EXPORT_SYMBOL(leds_event); - -static int __init -sa1100_leds_init(void) -{ -#ifdef CONFIG_SA1100_ASSABET - if (machine_is_assabet()) - leds_event = assabet_leds_event; -#endif -#ifdef CONFIG_SA1100_BRUTUS - if (machine_is_brutus()) - leds_event = brutus_leds_event; -#endif -#ifdef CONFIG_SA1100_LART - if (machine_is_lart()) - leds_event = lart_leds_event; -#endif -#ifdef CONFIG_SA1100_CERF - if (machine_is_cerf()) - { - //GPDR |= 0x0000000F; - leds_event = cerf_leds_event; - } -#endif - leds_event(led_start); - return 0; -} - -__initcall(sa1100_leds_init); diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/kernel/oldlatches.c linux/arch/arm/kernel/oldlatches.c --- v2.4.0-test8/linux/arch/arm/kernel/oldlatches.c Sun Aug 13 09:54:15 2000 +++ linux/arch/arm/kernel/oldlatches.c Mon Sep 18 15:15:25 2000 @@ -1,7 +1,14 @@ -/* Support for the latches on the old Archimedes which control the floppy, - * hard disc and printer +/* + * linux/arch/arm/kernel/oldlatches.c * - * (c) David Alan Gilbert 1995/1996,2000 + * Copyright (C) David Alan Gilbert 1995/1996,2000 + * + * 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. + * + * Support for the latches on the old Archimedes which control the floppy, + * hard disc and printer */ #include #include diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/kernel/plx90x0.c linux/arch/arm/kernel/plx90x0.c --- v2.4.0-test8/linux/arch/arm/kernel/plx90x0.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/kernel/plx90x0.c Mon Sep 18 15:15:25 2000 @@ -0,0 +1,198 @@ +/* + * Driver for PLX Technology PCI9000-series host bridge. + * + * Copyright (C) 1997, 1998, 1999, 2000 FutureTV Labs Ltd + */ + +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* + * Since the following functions are all very similar, the common parts + * are pulled out into these macros. + */ + +#define PLX_CLEAR_CONFIG \ + __raw_writel(0, PLX_BASE + 0xac); \ + local_irq_restore(flags); } + +#define PLX_SET_CONFIG \ + { unsigned long flags; \ + local_irq_save(flags); \ + __raw_writel((1<<31 | (dev->bus->number << 16) \ + | (dev->devfn << 8) | (where & ~3) \ + | ((dev->bus->number == 0)?0:1)), PLX_BASE + 0xac); \ + +#define PLX_CONFIG_WRITE(size) \ + PLX_SET_CONFIG \ + __raw_write##size(value, PCIO_BASE + (where & 3)); \ + if (__raw_readw(PLX_BASE + 0x6) & 0x2000) \ + __raw_writew(0x2000, PLX_BASE + 0x6); \ + PLX_CLEAR_CONFIG \ + return PCIBIOS_SUCCESSFUL; + +#define PLX_CONFIG_READ(size) \ + PLX_SET_CONFIG \ + *value = __raw_read##size(PCIO_BASE + (where & 3)); \ + if (__raw_readw(PLX_BASE + 0x6) & 0x2000) { \ + __raw_writew(0x2000, PLX_BASE + 0x6); \ + *value = 0xffffffffUL; \ + } \ + PLX_CLEAR_CONFIG \ + return PCIBIOS_SUCCESSFUL; + +/* Configuration space access routines */ + +static int +plx90x0_read_config_byte (struct pci_dev *dev, + int where, u8 *value) +{ + PLX_CONFIG_READ(b) +} + +static int +plx90x0_read_config_word (struct pci_dev *dev, + int where, u16 *value) +{ + PLX_CONFIG_READ(w) +} + +static int +plx90x0_read_config_dword (struct pci_dev *dev, + int where, u32 *value) +{ + PLX_CONFIG_READ(l) +} + +static int +plx90x0_write_config_byte (struct pci_dev *dev, + int where, u8 value) +{ + PLX_CONFIG_WRITE(b) +} + +static int +plx90x0_write_config_word (struct pci_dev *dev, + int where, u16 value) +{ + PLX_CONFIG_WRITE(w) +} + +static int +plx90x0_write_config_dword (struct pci_dev *dev, + int where, u32 value) +{ + PLX_CONFIG_WRITE(l) +} + +static void +plx_syserr_handler(int irq, void *handle, struct pt_regs *regs) +{ + printk("PLX90x0: machine check %04x (pc=%08lx)\n", + readw(PLX_BASE + 6), regs->ARM_pc); + __raw_writew(0xf000, PLX_BASE + 6); +} + +static struct pci_ops +plx90x0_ops = +{ + plx90x0_read_config_byte, + plx90x0_read_config_word, + plx90x0_read_config_dword, + plx90x0_write_config_byte, + plx90x0_write_config_word, + plx90x0_write_config_dword, +}; + +/* + * Initialise the PCI system. + */ + +void __init +plx90x0_init(struct arm_sysdata *sysdata) +{ + static const unsigned long int base = PLX_BASE; + char *what; + unsigned long bar = (unsigned long)virt_to_bus((void *)PAGE_OFFSET); + unsigned int pci_cmd = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE; + + /* Have a sniff around and see which PLX device is present. */ + unsigned long id = __raw_readl(base + 0xf0); + +#if 0 + /* This check was a good idea, but can fail. The PLX9060 puts no + default value in these registers unless NB# is asserted (which it + isn't on these cards). */ + if ((id & 0xffff) != PCI_VENDOR_ID_PLX) + return; /* Nothing found */ +#endif + + /* Found one - now work out what it is. */ + switch (id >> 16) { + case 0: /* PCI_DEVICE_ID_PLX_9060 */ + what = "PCI9060"; + break; + case PCI_DEVICE_ID_PLX_9060ES: + what = "PCI9060ES"; + break; + case PCI_DEVICE_ID_PLX_9060SD: + what = "PCI9060SD"; /* uhuhh.. */ + break; + case PCI_DEVICE_ID_PLX_9080: + what = "PCI9080"; + break; + default: + printk("PCI: Unknown PLX device %04lx found -- ignored.\n", + id >> 16); + return; + } + + printk("PCI: PLX Technology %s host bridge found.\n", what); + + /* Now set it up for both master and slave accesses. */ + __raw_writel(0xffff0147, base + 0x4); + __raw_writeb(32, base + 0xd); + __raw_writel(0x8 | bar, base + 0x18); + __raw_writel(0xf8000008, base + 0x80); + __raw_writel(0x40000001, base + 0x84); + __raw_writel(0, base + 0x88); + __raw_writel(0, base + 0x8c); + __raw_writel(0x11, base + 0x94); + __raw_writel(0xC3 + (4 << 28) + + (8 << 11) + (1 << 10) + + (1 << 24), base + 0x98); + __raw_writel(0xC0000000, base + 0x9c); + __raw_writel(PLX_MEM_START, base + 0xa0); + __raw_writel(PLX_IO_START, base + 0xa4); + __raw_writel(0x3, base + 0xa8); + __raw_writel(0, base + 0xac); + __raw_writel(0x10001, base + 0xe8); + __raw_writel(0x8000767e, base + 0xec); + + request_irq(IRQ_SYSERR, plx_syserr_handler, 0, + "system error", NULL); + + pci_scan_bus(0, &plx90x0_ops, sysdata); + + pci_cmd |= sysdata->bus[0].features; + + printk("PCI: Fast back to back transfers %sabled\n", + (sysdata->bus[0].features & PCI_COMMAND_FAST_BACK) ? + "en" : "dis"); +} diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/kernel/process.c linux/arch/arm/kernel/process.c --- v2.4.0-test8/linux/arch/arm/kernel/process.c Tue Sep 5 13:50:01 2000 +++ linux/arch/arm/kernel/process.c Mon Sep 18 15:15:25 2000 @@ -3,8 +3,11 @@ * * Copyright (C) 1996-2000 Russell King - Converted to ARM. * Origional Copyright (C) 1995 Linus Torvalds + * + * 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 @@ -173,10 +176,11 @@ flags & CC_Z_BIT ? 'Z' : 'z', flags & CC_C_BIT ? 'C' : 'c', flags & CC_V_BIT ? 'V' : 'v'); - printk(" IRQs %s FIQs %s Mode %s Segment %s\n", + printk(" IRQs %s FIQs %s Mode %s%s Segment %s\n", interrupts_enabled(regs) ? "on" : "off", fast_interrupts_enabled(regs) ? "on" : "off", processor_modes[processor_mode(regs)], + thumb_mode(regs) ? " (T)" : "", get_fs() == get_ds() ? "kernel" : "user"); #if defined(CONFIG_CPU_32) { diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/kernel/ptrace.c linux/arch/arm/kernel/ptrace.c --- v2.4.0-test8/linux/arch/arm/kernel/ptrace.c Sun Sep 3 11:19:11 2000 +++ linux/arch/arm/kernel/ptrace.c Mon Sep 18 15:15:25 2000 @@ -1,8 +1,14 @@ -/* ptrace.c */ -/* By Ross Biro 1/23/92 */ -/* edited by Linus Torvalds */ -/* edited for ARM by Russell King */ - +/* + * linux/arch/arm/kernel/ptrace.c + * + * By Ross Biro 1/23/92 + * edited by Linus Torvalds + * ARM modifications Copyright (C) 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 diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/kernel/ptrace.h linux/arch/arm/kernel/ptrace.h --- v2.4.0-test8/linux/arch/arm/kernel/ptrace.h Mon Jun 26 12:04:01 2000 +++ linux/arch/arm/kernel/ptrace.h Mon Sep 18 15:15:25 2000 @@ -1,3 +1,12 @@ +/* + * linux/arch/arm/kernel/ptrace.h + * + * Copyright (C) 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. + */ extern void __ptrace_cancel_bpt(struct task_struct *); extern int ptrace_set_bpt(struct task_struct *); diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/kernel/semaphore.c linux/arch/arm/kernel/semaphore.c --- v2.4.0-test8/linux/arch/arm/kernel/semaphore.c Mon Aug 14 13:09:07 2000 +++ linux/arch/arm/kernel/semaphore.c Mon Sep 18 15:15:25 2000 @@ -1,11 +1,15 @@ /* - * ARM semaphore implementation, taken from + * ARM semaphore implementation, taken from * - * i386 semaphore implementation. + * i386 semaphore implementation. * - * (C) Copyright 1999 Linus Torvalds + * (C) Copyright 1999 Linus Torvalds * - * Modified for ARM by Russell King + * Modified for ARM by 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 diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/kernel/setup.c linux/arch/arm/kernel/setup.c --- v2.4.0-test8/linux/arch/arm/kernel/setup.c Sun Aug 13 09:54:15 2000 +++ linux/arch/arm/kernel/setup.c Mon Sep 18 15:15:25 2000 @@ -2,6 +2,10 @@ * linux/arch/arm/kernel/setup.c * * 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 @@ -21,7 +25,7 @@ #include #include -#include "arch.h" +#include #ifndef MEM_SIZE #define MEM_SIZE (16*1024*1024) @@ -31,7 +35,7 @@ #define CONFIG_CMDLINE "" #endif -extern void paging_init(struct meminfo *); +extern void paging_init(struct meminfo *, struct machine_desc *desc); extern void bootmem_init(struct meminfo *); extern void reboot_setup(char *str); extern void disable_hlt(void); @@ -163,7 +167,7 @@ printk("Architecture: %s\n", list->name); if (compat) - printk(KERN_WARNING "Using compatability code " + printk(KERN_WARNING "Using compatibility code " "scheduled for removal in v%d.%d.%d\n", compat >> 24, (compat >> 12) & 0x3ff, compat & 0x3ff); @@ -378,7 +382,7 @@ saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; parse_cmdline(&meminfo, cmdline_p, from); bootmem_init(&meminfo); - paging_init(&meminfo); + paging_init(&meminfo, mdesc); request_standard_resources(&meminfo, mdesc); #ifdef CONFIG_VT diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/kernel/signal.c linux/arch/arm/kernel/signal.c --- v2.4.0-test8/linux/arch/arm/kernel/signal.c Sun Sep 3 11:53:42 2000 +++ linux/arch/arm/kernel/signal.c Mon Sep 18 15:15:25 2000 @@ -2,8 +2,11 @@ * linux/arch/arm/kernel/signal.c * * Copyright (C) 1995, 1996 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 diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/kernel/sys_arm.c linux/arch/arm/kernel/sys_arm.c --- v2.4.0-test8/linux/arch/arm/kernel/sys_arm.c Tue Sep 5 13:50:01 2000 +++ linux/arch/arm/kernel/sys_arm.c Mon Sep 18 15:15:25 2000 @@ -1,14 +1,17 @@ /* - * linux/arch/arm/kernel/sys_arm.c + * linux/arch/arm/kernel/sys_arm.c * - * Copyright (C) People who wrote linux/arch/i386/kernel/sys_i386.c - * Copyright (C) 1995, 1996 Russell King. - * - * This file contains various random system calls that - * have a non-standard calling sequence on the Linux/arm - * platform. + * Copyright (C) People who wrote linux/arch/i386/kernel/sys_i386.c + * Copyright (C) 1995, 1996 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. + * + * This file contains various random system calls that + * have a non-standard calling sequence on the Linux/arm + * platform. */ - #include #include #include diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/kernel/time-acorn.c linux/arch/arm/kernel/time-acorn.c --- v2.4.0-test8/linux/arch/arm/kernel/time-acorn.c Sun Feb 6 17:45:25 2000 +++ linux/arch/arm/kernel/time-acorn.c Mon Sep 18 15:15:25 2000 @@ -1,12 +1,16 @@ /* - * linux/arch/arm/kernel/time-acorn.c + * linux/arch/arm/kernel/time-acorn.c * - * Copyright (c) 1996-2000 Russell King. + * Copyright (c) 1996-2000 Russell King. * - * Changelog: - * 24-Sep-1996 RMK Created - * 10-Oct-1996 RMK Brought up to date with arch-sa110eval - * 04-Dec-1997 RMK Updated for new arch/arm/time.c + * 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. + * + * Changelog: + * 24-Sep-1996 RMK Created + * 10-Oct-1996 RMK Brought up to date with arch-sa110eval + * 04-Dec-1997 RMK Updated for new arch/arm/time.c */ #include #include @@ -14,8 +18,8 @@ #include #include -#include #include +#include extern unsigned long (*gettimeoffset)(void); diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/kernel/time.c linux/arch/arm/kernel/time.c --- v2.4.0-test8/linux/arch/arm/kernel/time.c Tue Jul 18 22:43:24 2000 +++ linux/arch/arm/kernel/time.c Mon Sep 18 15:15:25 2000 @@ -4,15 +4,20 @@ * Copyright (C) 1991, 1992, 1995 Linus Torvalds * Modifications for ARM (C) 1994, 1995, 1996,1997 Russell King * - * This file contains the ARM-specific time handling details: - * reading the RTC at bootup, etc... + * 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. * - * 1994-07-02 Alan Modra - * fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime - * 1998-12-20 Updated NTP code according to technical memorandum Jan '96 - * "A Kernel Model for Precision Timekeeping" by Dave Mills + * This file contains the ARM-specific time handling details: + * reading the RTC at bootup, etc... + * + * 1994-07-02 Alan Modra + * fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime + * 1998-12-20 Updated NTP code according to technical memorandum Jan '96 + * "A Kernel Model for Precision Timekeeping" by Dave Mills */ #include +#include #include #include #include @@ -64,37 +69,6 @@ */ unsigned long (*gettimeoffset)(void) = dummy_gettimeoffset; -/* Converts Gregorian date to seconds since 1970-01-01 00:00:00. - * Assumes input in normal date format, i.e. 1980-12-31 23:59:59 - * => year=1980, mon=12, day=31, hour=23, min=59, sec=59. - * - * [For the Julian calendar (which was used in Russia before 1917, - * Britain & colonies before 1752, anywhere else before 1582, - * and is still in use by some communities) leave out the - * -year/100+year/400 terms, and add 10.] - * - * This algorithm was first published by Gauss (I think). - * - * WARNING: this function will overflow on 2106-02-07 06:28:16 on - * machines were long is 32-bit! (However, as time_t is signed, we - * will already get problems at other places on 2038-01-19 03:14:08) - */ -unsigned long -mktime(unsigned int year, unsigned int mon, unsigned int day, - unsigned int hour, unsigned int min, unsigned int sec) -{ - if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */ - mon += 12; /* Puts Feb last since it has leap day */ - year -= 1; - } - return ((( - (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) + - year*365 - 719499 - )*24 + hour /* now have hours */ - )*60 + min /* now have minutes */ - )*60 + sec; /* finally seconds */ -} - /* * Handle kernel profile stuff... */ @@ -151,6 +125,16 @@ #include +static void dummy_leds_event(led_event_t evt) +{ +} + +void (*leds_event)(led_event_t) = dummy_leds_event; + +#ifdef CONFIG_MODULES +EXPORT_SYMBOL(leds_event); +#endif + static void do_leds(void) { #ifdef CONFIG_LEDS_CPU @@ -234,7 +218,7 @@ } static struct irqaction timer_irq = { - NULL, 0, 0, "timer", NULL, NULL + name: "timer", }; /* diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/kernel/traps.c linux/arch/arm/kernel/traps.c --- v2.4.0-test8/linux/arch/arm/kernel/traps.c Sun Aug 13 09:54:15 2000 +++ linux/arch/arm/kernel/traps.c Mon Sep 18 15:15:25 2000 @@ -3,12 +3,14 @@ * * Copyright (C) 1995, 1996 Russell King * Fragments that appear the same as linux/arch/i386/kernel/traps.c (C) Linus Torvalds - */ - -/* - * 'traps.c' handles hardware exceptions after we have saved some state in - * 'linux/arch/arm/lib/traps.S'. Mostly a debugging aid, but will probably - * kill the offending process. + * + * 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. + * + * 'traps.c' handles hardware exceptions after we have saved some state in + * 'linux/arch/arm/lib/traps.S'. Mostly a debugging aid, but will probably + * kill the offending process. */ #include #include @@ -314,7 +316,7 @@ case 2: /* sys_cacheflush */ #ifdef CONFIG_CPU_32 /* r0 = start, r1 = end, r2 = flags */ - cpu_flush_cache_area(regs->ARM_r0, regs->ARM_r1, 1); + cpu_cache_clean_invalidate_range(regs->ARM_r0, regs->ARM_r1, 1); #endif break; diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/kernel/via82c505.c linux/arch/arm/kernel/via82c505.c --- v2.4.0-test8/linux/arch/arm/kernel/via82c505.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/kernel/via82c505.c Tue Sep 19 08:31:53 2000 @@ -0,0 +1,186 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#define MAX_SLOTS 7 + +#define CONFIG_CMD(dev, where) (0x80000000 | (dev->bus->number << 16) | (dev->devfn << 8) | (where & ~3)) + +static int +via82c505_read_config_byte(struct pci_dev *dev, int where, u8 *value) +{ + outl(CONFIG_CMD(dev,where),0xCF8); + *value=inb(0xCFC + (where&3)); + return PCIBIOS_SUCCESSFUL; +} + +static int +via82c505_read_config_word(struct pci_dev *dev, int where, u16 *value) +{ + outl(CONFIG_CMD(dev,where),0xCF8); + *value=inw(0xCFC + (where&2)); + return PCIBIOS_SUCCESSFUL; +} + +static int +via82c505_read_config_dword(struct pci_dev *dev, int where, u32 *value) +{ + outl(CONFIG_CMD(dev,where),0xCF8); + *value=inl(0xCFC); + return PCIBIOS_SUCCESSFUL; +} + +static int +via82c505_write_config_byte(struct pci_dev *dev, int where, u8 value) +{ + outl(CONFIG_CMD(dev,where),0xCF8); + outb(value, 0xCFC + (where&3)); + return PCIBIOS_SUCCESSFUL; +} + +static int +via82c505_write_config_word(struct pci_dev *dev, int where, u16 value) +{ + outl(CONFIG_CMD(dev,where),0xCF8); + outw(value, 0xCFC + (where&2)); + return PCIBIOS_SUCCESSFUL; +} + +static int +via82c505_write_config_dword(struct pci_dev *dev, int where, u32 value) +{ + outl(CONFIG_CMD(dev,where),0xCF8); + outl(value, 0xCFC); + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops via82c505_ops = { + via82c505_read_config_byte, + via82c505_read_config_word, + via82c505_read_config_dword, + via82c505_write_config_byte, + via82c505_write_config_word, + via82c505_write_config_dword, +}; + +#ifdef CONFIG_ARCH_SHARK + +static char size_wanted = 0; + +static int +dummy_read_config_byte(struct pci_dev *dev, int where, u8 *value) +{ + *value=0; + return PCIBIOS_SUCCESSFUL; +} + +static int +dummy_read_config_word(struct pci_dev *dev, int where, u16 *value) +{ + *value=0; + return PCIBIOS_SUCCESSFUL; +} + +static int +dummy_read_config_dword(struct pci_dev *dev, int where, u32 *value) +{ + if (dev->devfn != 0) *value = 0; + else + switch(where) { + case PCI_VENDOR_ID: + *value = PCI_VENDOR_ID_INTERG | PCI_DEVICE_ID_INTERG_2010 << 16; + break; + case PCI_CLASS_REVISION: + *value = PCI_CLASS_DISPLAY_VGA << 16; + break; + case PCI_BASE_ADDRESS_0: + if (size_wanted) { + /* 0x00900000 bytes long */ + *value = 0xff700000; + size_wanted = 0; + } else { + *value = FB_START; + } + break; + case PCI_INTERRUPT_LINE: + *value = 6; + break; + default: + *value=0; + } + return PCIBIOS_SUCCESSFUL; +} + +static int +dummy_write_config_byte(struct pci_dev *dev, int where, u8 value) +{ + return PCIBIOS_SUCCESSFUL; +} + +static int +dummy_write_config_word(struct pci_dev *dev, int where, u16 value) +{ + return PCIBIOS_SUCCESSFUL; +} + +static int +dummy_write_config_dword(struct pci_dev *dev, int where, u32 value) +{ + if ((dev->devfn == 0) && (where == PCI_BASE_ADDRESS_0) && (value == 0xffffffff)) + size_wanted = 1; + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops dummy_ops = { + dummy_read_config_byte, + dummy_read_config_word, + dummy_read_config_dword, + dummy_write_config_byte, + dummy_write_config_word, + dummy_write_config_dword, +}; +#endif + +void __init via82c505_init(struct arm_pci_sysdata *sysdata) +{ + unsigned int pci_cmd = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | + PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE; + struct pci_dev *dev; + struct pci_bus *bus; + + printk(KERN_DEBUG "PCI: VIA 82c505\n"); + request_region(0xA8,2,"via config"); + request_region(0xCF8,8,"pci config"); + + /* Enable compatible Mode */ + outb(0x96,0xA8); + outb(0x18,0xA9); + outb(0x93,0xA8); + outb(0xd0,0xA9); + + pci_scan_bus(0, &via82c505_ops, sysdata); + + pci_cmd |= sysdata->bus[0].features; + + printk("PCI: Fast back to back transfers %sabled\n", + (sysdata->bus[0].features & PCI_COMMAND_FAST_BACK) ? "en" : "dis"); + +#ifdef CONFIG_ARCH_SHARK + /* + * Initialize a fake pci-bus number 1 for the CyberPro + * on the vlbus + */ + bus = pci_scan_bus(1, &dummy_ops, sysdata); +#endif +} diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/lib/Makefile linux/arch/arm/lib/Makefile --- v2.4.0-test8/linux/arch/arm/lib/Makefile Sun Sep 3 11:19:11 2000 +++ linux/arch/arm/lib/Makefile Mon Sep 18 15:15:25 2000 @@ -25,6 +25,7 @@ L_OBJS_nexuspci := io-footbridge.o L_OBJS_sa1100 := io-footbridge.o L_OBJS_shark := io-shark.o +L_OBJS_integrator := io-shark.o ifeq ($(PROCESSOR),armo) L_OBJS += uaccess-armo.o diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/lib/backtrace.S linux/arch/arm/lib/backtrace.S --- v2.4.0-test8/linux/arch/arm/lib/backtrace.S Tue Nov 23 22:23:11 1999 +++ linux/arch/arm/lib/backtrace.S Mon Sep 18 15:15:25 2000 @@ -1,7 +1,11 @@ /* - * linux/arch/arm/lib/backtrace.S + * linux/arch/arm/lib/backtrace.S * - * Copyright (C) 1995, 1996 Russell King + * Copyright (C) 1995, 1996 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 diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/lib/changebit.S linux/arch/arm/lib/changebit.S --- v2.4.0-test8/linux/arch/arm/lib/changebit.S Mon Jun 19 17:59:34 2000 +++ linux/arch/arm/lib/changebit.S Mon Sep 18 15:15:25 2000 @@ -1,9 +1,12 @@ /* - * linux/arch/arm/lib/changebit.S + * linux/arch/arm/lib/changebit.S * - * Copyright (C) 1995-1996 Russell King + * Copyright (C) 1995-1996 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 .text diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/lib/clearbit.S linux/arch/arm/lib/clearbit.S --- v2.4.0-test8/linux/arch/arm/lib/clearbit.S Mon Jun 19 17:59:34 2000 +++ linux/arch/arm/lib/clearbit.S Mon Sep 18 15:15:25 2000 @@ -1,9 +1,12 @@ /* - * linux/arch/arm/lib/clearbit.S + * linux/arch/arm/lib/clearbit.S * - * Copyright (C) 1995-1996 Russell King + * Copyright (C) 1995-1996 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 .text diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/lib/copy_page.S linux/arch/arm/lib/copy_page.S --- v2.4.0-test8/linux/arch/arm/lib/copy_page.S Sun Sep 3 11:19:11 2000 +++ linux/arch/arm/lib/copy_page.S Mon Sep 18 15:15:25 2000 @@ -1,10 +1,13 @@ /* - * linux/arch/arm/lib/copypage.S + * linux/arch/arm/lib/copypage.S * - * Copyright (C) 1995-1999 Russell King + * Copyright (C) 1995-1999 Russell King * - * ASM optimised string functions + * 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. * + * ASM optimised string functions */ #include #include diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/lib/csumipv6.S linux/arch/arm/lib/csumipv6.S --- v2.4.0-test8/linux/arch/arm/lib/csumipv6.S Thu Jan 13 13:30:31 2000 +++ linux/arch/arm/lib/csumipv6.S Mon Sep 18 15:15:25 2000 @@ -1,7 +1,11 @@ /* - * linux/arch/arm/lib/csumipv6.S + * linux/arch/arm/lib/csumipv6.S * - * Copyright (C) 1995-1998 Russell King + * Copyright (C) 1995-1998 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 diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/lib/csumpartial.S linux/arch/arm/lib/csumpartial.S --- v2.4.0-test8/linux/arch/arm/lib/csumpartial.S Thu Jan 13 13:30:31 2000 +++ linux/arch/arm/lib/csumpartial.S Mon Sep 18 15:15:25 2000 @@ -1,7 +1,11 @@ /* - * linux/arch/arm/lib/csumpartial.S + * linux/arch/arm/lib/csumpartial.S * - * Copyright (C) 1995-1998 Russell King + * Copyright (C) 1995-1998 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 diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/lib/csumpartialcopy.S linux/arch/arm/lib/csumpartialcopy.S --- v2.4.0-test8/linux/arch/arm/lib/csumpartialcopy.S Tue Apr 25 16:54:39 2000 +++ linux/arch/arm/lib/csumpartialcopy.S Mon Sep 18 15:15:25 2000 @@ -1,7 +1,11 @@ /* - * linux/arch/arm/lib/csumpartialcopy.S + * linux/arch/arm/lib/csumpartialcopy.S * - * Copyright (C) 1995-1998 Russell King + * Copyright (C) 1995-1998 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 diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/lib/csumpartialcopyuser.S linux/arch/arm/lib/csumpartialcopyuser.S --- v2.4.0-test8/linux/arch/arm/lib/csumpartialcopyuser.S Tue Apr 25 16:54:39 2000 +++ linux/arch/arm/lib/csumpartialcopyuser.S Mon Sep 18 15:15:25 2000 @@ -1,7 +1,11 @@ /* - * linux/arch/arm/lib/csumpartialcopyuser.S + * linux/arch/arm/lib/csumpartialcopyuser.S * - * Copyright (C) 1995-1998 Russell King + * Copyright (C) 1995-1998 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 @@ -396,6 +400,12 @@ mov r4, r4, lsr #8 b .exit +/* + * FIXME: minor buglet here + * We don't return the checksum for the data present in the buffer. To do + * so properly, we would have to add in whatever registers were loaded before + * the fault, which, with the current asm above is not predictable. + */ #if defined(CONFIG_CPU_32) .section .fixup,"ax" #endif diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/lib/delay.S linux/arch/arm/lib/delay.S --- v2.4.0-test8/linux/arch/arm/lib/delay.S Sun Sep 3 11:19:11 2000 +++ linux/arch/arm/lib/delay.S Mon Sep 18 15:15:25 2000 @@ -1,7 +1,11 @@ /* - * linux/arch/arm/lib/delay.S + * linux/arch/arm/lib/delay.S * - * Copyright (C) 1995, 1996 Russell King + * Copyright (C) 1995, 1996 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 diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/lib/findbit.S linux/arch/arm/lib/findbit.S --- v2.4.0-test8/linux/arch/arm/lib/findbit.S Mon Jun 19 17:59:34 2000 +++ linux/arch/arm/lib/findbit.S Mon Sep 18 15:15:25 2000 @@ -1,9 +1,12 @@ /* - * linux/arch/arm/lib/findbit.S + * linux/arch/arm/lib/findbit.S * - * Copyright (C) 1995-2000 Russell King + * 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 .text diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/lib/floppydma.S linux/arch/arm/lib/floppydma.S --- v2.4.0-test8/linux/arch/arm/lib/floppydma.S Thu Jun 17 01:11:35 1999 +++ linux/arch/arm/lib/floppydma.S Mon Sep 18 15:15:25 2000 @@ -1,7 +1,11 @@ /* - * linux/arch/arm/lib/floppydma.S + * linux/arch/arm/lib/floppydma.S * - * Copyright (C) 1995, 1996 Russell King + * Copyright (C) 1995, 1996 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 diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/lib/getconsdata.c linux/arch/arm/lib/getconsdata.c --- v2.4.0-test8/linux/arch/arm/lib/getconsdata.c Mon Jun 19 17:59:34 2000 +++ linux/arch/arm/lib/getconsdata.c Mon Sep 18 15:15:25 2000 @@ -1,7 +1,11 @@ /* - * linux/arch/arm/lib/getconsdata.c + * linux/arch/arm/lib/getconsdata.c * - * Copyright (C) 1995-2000 Russell King + * 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 diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/lib/io-acorn.S linux/arch/arm/lib/io-acorn.S --- v2.4.0-test8/linux/arch/arm/lib/io-acorn.S Thu Jun 17 01:11:35 1999 +++ linux/arch/arm/lib/io-acorn.S Mon Sep 18 15:15:25 2000 @@ -1,7 +1,11 @@ /* - * linux/arch/arm/lib/io.S + * linux/arch/arm/lib/io-acorn.S * - * Copyright (C) 1995, 1996 Russell King + * Copyright (C) 1995, 1996 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 /* for CONFIG_CPU_nn */ #include diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/lib/io-ebsa110.S linux/arch/arm/lib/io-ebsa110.S --- v2.4.0-test8/linux/arch/arm/lib/io-ebsa110.S Thu Jun 17 01:11:35 1999 +++ linux/arch/arm/lib/io-ebsa110.S Mon Sep 18 15:15:25 2000 @@ -1,7 +1,11 @@ /* - * linux/arch/arm/lib/io-ebsa.S + * linux/arch/arm/lib/io-ebsa.S * - * Copyright (C) 1995, 1996 Russell King + * Copyright (C) 1995, 1996 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 diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/lib/io-shark.c linux/arch/arm/lib/io-shark.c --- v2.4.0-test8/linux/arch/arm/lib/io-shark.c Sun Mar 12 19:39:39 2000 +++ linux/arch/arm/lib/io-shark.c Mon Sep 18 15:15:25 2000 @@ -1,11 +1,15 @@ /* - * linux/arch/arm/lib/io-shark.c + * linux/arch/arm/lib/io-shark.c * - * by Alexander.Schulz@stud.uni-karlsruhe.de + * by Alexander.Schulz@stud.uni-karlsruhe.de * * derived from: * linux/arch/arm/lib/io-ebsa.S * Copyright (C) 1995, 1996 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 diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/lib/memchr.S linux/arch/arm/lib/memchr.S --- v2.4.0-test8/linux/arch/arm/lib/memchr.S Sun Sep 3 11:19:11 2000 +++ linux/arch/arm/lib/memchr.S Mon Sep 18 15:15:25 2000 @@ -1,9 +1,13 @@ /* - * linux/arch/arm/lib/memchr.S + * linux/arch/arm/lib/memchr.S * - * Copyright (C) 1995-2000 Russell King + * Copyright (C) 1995-2000 Russell King * - * ASM optimised string functions + * 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. + * + * ASM optimised string functions */ #include #include diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/lib/memcpy.S linux/arch/arm/lib/memcpy.S --- v2.4.0-test8/linux/arch/arm/lib/memcpy.S Sun Sep 3 11:19:11 2000 +++ linux/arch/arm/lib/memcpy.S Mon Sep 18 15:15:25 2000 @@ -1,9 +1,13 @@ /* - * linux/arch/arm/lib/memcpy.S + * linux/arch/arm/lib/memcpy.S * - * Copyright (C) 1995-1999 Russell King + * Copyright (C) 1995-1999 Russell King * - * ASM optimised string functions + * 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. + * + * ASM optimised string functions */ #include #include diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/lib/memset.S linux/arch/arm/lib/memset.S --- v2.4.0-test8/linux/arch/arm/lib/memset.S Sun Sep 3 11:19:11 2000 +++ linux/arch/arm/lib/memset.S Mon Sep 18 15:15:25 2000 @@ -1,9 +1,13 @@ /* - * linux/arch/arm/lib/memset.S + * linux/arch/arm/lib/memset.S * - * Copyright (C) 1995-2000 Russell King + * Copyright (C) 1995-2000 Russell King * - * ASM optimised string functions + * 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. + * + * ASM optimised string functions */ #include #include diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/lib/memzero.S linux/arch/arm/lib/memzero.S --- v2.4.0-test8/linux/arch/arm/lib/memzero.S Sun Sep 3 11:19:11 2000 +++ linux/arch/arm/lib/memzero.S Mon Sep 18 15:15:25 2000 @@ -1,7 +1,11 @@ /* - * linux/arch/arm/lib/memzero.S + * linux/arch/arm/lib/memzero.S * - * Copyright (C) 1995-2000 Russell King + * 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 diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/lib/setbit.S linux/arch/arm/lib/setbit.S --- v2.4.0-test8/linux/arch/arm/lib/setbit.S Mon Jun 19 17:59:34 2000 +++ linux/arch/arm/lib/setbit.S Mon Sep 18 15:15:25 2000 @@ -1,9 +1,12 @@ /* - * linux/arch/arm/lib/setbit.S + * linux/arch/arm/lib/setbit.S * - * Copyright (C) 1995-1996 Russell King + * Copyright (C) 1995-1996 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 .text diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/lib/strchr.S linux/arch/arm/lib/strchr.S --- v2.4.0-test8/linux/arch/arm/lib/strchr.S Sun Sep 3 11:19:11 2000 +++ linux/arch/arm/lib/strchr.S Mon Sep 18 15:15:25 2000 @@ -1,9 +1,13 @@ /* - * linux/arch/arm/lib/strchr.S + * linux/arch/arm/lib/strchr.S * - * Copyright (C) 1995-2000 Russell King + * Copyright (C) 1995-2000 Russell King * - * ASM optimised string functions + * 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. + * + * ASM optimised string functions */ #include #include diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/lib/strncpy_from_user.S linux/arch/arm/lib/strncpy_from_user.S --- v2.4.0-test8/linux/arch/arm/lib/strncpy_from_user.S Sun Sep 3 11:19:11 2000 +++ linux/arch/arm/lib/strncpy_from_user.S Mon Sep 18 15:15:25 2000 @@ -1,7 +1,11 @@ /* - * linux/arch/arm/lib/strncpy_from_user.S + * linux/arch/arm/lib/strncpy_from_user.S * - * Copyright (C) 1995-2000 Russell King + * 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 diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/lib/strnlen_user.S linux/arch/arm/lib/strnlen_user.S --- v2.4.0-test8/linux/arch/arm/lib/strnlen_user.S Sun Sep 3 11:19:11 2000 +++ linux/arch/arm/lib/strnlen_user.S Mon Sep 18 15:15:25 2000 @@ -1,7 +1,11 @@ /* - * linux/arch/arm/lib/strnlen_user.S + * linux/arch/arm/lib/strnlen_user.S * - * Copyright (C) 1995-2000 Russell King + * 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 diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/lib/strrchr.S linux/arch/arm/lib/strrchr.S --- v2.4.0-test8/linux/arch/arm/lib/strrchr.S Sun Sep 3 11:19:11 2000 +++ linux/arch/arm/lib/strrchr.S Mon Sep 18 15:15:25 2000 @@ -1,9 +1,13 @@ /* - * linux/arch/arm/lib/strrchr.S + * linux/arch/arm/lib/strrchr.S * - * Copyright (C) 1995-2000 Russell King + * Copyright (C) 1995-2000 Russell King * - * ASM optimised string functions + * 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. + * + * ASM optimised string functions */ #include #include diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/lib/testchangebit.S linux/arch/arm/lib/testchangebit.S --- v2.4.0-test8/linux/arch/arm/lib/testchangebit.S Mon Jun 19 17:59:34 2000 +++ linux/arch/arm/lib/testchangebit.S Mon Sep 18 15:15:25 2000 @@ -1,9 +1,12 @@ /* - * linux/arch/arm/lib/testchangebit.S + * linux/arch/arm/lib/testchangebit.S * - * Copyright (C) 1995-1996 Russell King + * Copyright (C) 1995-1996 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 .text diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/lib/testclearbit.S linux/arch/arm/lib/testclearbit.S --- v2.4.0-test8/linux/arch/arm/lib/testclearbit.S Mon Jun 19 17:59:34 2000 +++ linux/arch/arm/lib/testclearbit.S Mon Sep 18 15:15:25 2000 @@ -1,9 +1,12 @@ /* - * linux/arch/arm/lib/testclearbit.S + * linux/arch/arm/lib/testclearbit.S * - * Copyright (C) 1995-1996 Russell King + * Copyright (C) 1995-1996 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 .text diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/lib/testsetbit.S linux/arch/arm/lib/testsetbit.S --- v2.4.0-test8/linux/arch/arm/lib/testsetbit.S Mon Jun 19 17:59:34 2000 +++ linux/arch/arm/lib/testsetbit.S Mon Sep 18 15:15:25 2000 @@ -1,9 +1,12 @@ /* - * linux/arch/arm/lib/testsetbit.S + * linux/arch/arm/lib/testsetbit.S * - * Copyright (C) 1995-1996 Russell King + * Copyright (C) 1995-1996 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 .text diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/lib/uaccess-armo.S linux/arch/arm/lib/uaccess-armo.S --- v2.4.0-test8/linux/arch/arm/lib/uaccess-armo.S Sun Sep 3 11:19:11 2000 +++ linux/arch/arm/lib/uaccess-armo.S Mon Sep 18 15:15:25 2000 @@ -1,10 +1,14 @@ /* - * arch/arm/lib/uaccess-armo.S + * linux/arch/arm/lib/uaccess-armo.S * - * Copyright (C) 1998 Russell King + * Copyright (C) 1998 Russell King * - * Note! Some code fragments found in here have a special calling - * convention - they are not APCS compliant! + * Note! Some code fragments found in here have a special calling + * convention - they are not APCS compliant! + * + * 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 diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/lib/uaccess.S linux/arch/arm/lib/uaccess.S --- v2.4.0-test8/linux/arch/arm/lib/uaccess.S Sun Sep 3 11:19:11 2000 +++ linux/arch/arm/lib/uaccess.S Mon Sep 18 15:15:25 2000 @@ -1,11 +1,15 @@ /* - * linux/arch/arm/lib/uaccess.S + * linux/arch/arm/lib/uaccess.S * - * Copyright (C) 1995, 1996,1997,1998 Russell King + * Copyright (C) 1995, 1996,1997,1998 Russell King * - * Routines to block copy data to/from user memory - * These are highly optimised both for the 4k page size - * and for various alignments. + * 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. + * + * Routines to block copy data to/from user memory + * These are highly optimised both for the 4k page size + * and for various alignments. */ #include #include diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/mach-footbridge/Makefile linux/arch/arm/mach-footbridge/Makefile --- v2.4.0-test8/linux/arch/arm/mach-footbridge/Makefile Sun Sep 3 11:19:11 2000 +++ linux/arch/arm/mach-footbridge/Makefile Mon Sep 18 15:15:25 2000 @@ -9,7 +9,7 @@ # Object file lists. -obj-y := #arch.o dma.o mm.o +obj-y := arch.o #dma.o mm.o obj-m := obj-n := obj- := @@ -24,13 +24,13 @@ endif ifeq ($(CONFIG_LEDS),y) -#obj-$(CONFIG_ARCH_CO285) += ebsa285-leds.o -#obj-$(CONFIG_ARCH_EBSA285) += ebsa285-leds.o -#obj-$(CONFIG_ARCH_NETWINDER) += netwinder-leds.o +obj-$(CONFIG_ARCH_CO285) += ebsa285-leds.o +obj-$(CONFIG_ARCH_EBSA285) += ebsa285-leds.o +obj-$(CONFIG_ARCH_NETWINDER) += netwinder-leds.o endif -#obj-$(CONFIG_ARCH_CATS) += cats-hw.o -#obj-$(CONFIG_ARCH_NETWINDER) += netwinder-hw.o +obj-$(CONFIG_ARCH_CATS) += cats-hw.o +obj-$(CONFIG_ARCH_NETWINDER) += netwinder-hw.o # Files that are both resident and modular; remove from modular. diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/mach-footbridge/arch.c linux/arch/arm/mach-footbridge/arch.c --- v2.4.0-test8/linux/arch/arm/mach-footbridge/arch.c Sun Sep 3 11:19:11 2000 +++ linux/arch/arm/mach-footbridge/arch.c Mon Sep 18 15:15:25 2000 @@ -12,7 +12,7 @@ #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/mach-footbridge/ebsa285-leds.c linux/arch/arm/mach-footbridge/ebsa285-leds.c --- v2.4.0-test8/linux/arch/arm/mach-footbridge/ebsa285-leds.c Tue Sep 5 12:56:51 2000 +++ linux/arch/arm/mach-footbridge/ebsa285-leds.c Mon Sep 18 15:15:25 2000 @@ -1,8 +1,11 @@ /* - * linux/arch/arm/mach-footbridge/ebsa285-leds.c + * linux/arch/arm/mach-footbridge/ebsa285-leds.c * - * Copyright (C) 1998-1999 Russell King + * Copyright (C) 1998-1999 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. * EBSA-285 control routines. * * The EBSA-285 uses the leds as follows: diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/mach-footbridge/netwinder-leds.c linux/arch/arm/mach-footbridge/netwinder-leds.c --- v2.4.0-test8/linux/arch/arm/mach-footbridge/netwinder-leds.c Tue Sep 5 12:56:51 2000 +++ linux/arch/arm/mach-footbridge/netwinder-leds.c Mon Sep 18 15:15:25 2000 @@ -1,7 +1,11 @@ /* - * linux/arch/arm/mach-footbridge/netwinder-leds.c + * linux/arch/arm/mach-footbridge/netwinder-leds.c * - * Copyright (C) 1998-1999 Russell King + * Copyright (C) 1998-1999 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. * * NetWinder LED control routines. * diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/mach-sa1100/Makefile linux/arch/arm/mach-sa1100/Makefile --- v2.4.0-test8/linux/arch/arm/mach-sa1100/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mach-sa1100/Makefile Mon Sep 18 15:15:25 2000 @@ -0,0 +1,34 @@ +# +# Makefile for the linux kernel. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). + +USE_STANDARD_AS_RULE := true + +O_TARGET := sa1100.o + +# Object file lists. + +obj-y := arch.o hw.o #dma.o mm.o +obj-m := +obj-n := +obj- := + +export-objs := hw.o leds.o + +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.0-test8/linux/arch/arm/mach-sa1100/arch.c linux/arch/arm/mach-sa1100/arch.c --- v2.4.0-test8/linux/arch/arm/mach-sa1100/arch.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mach-sa1100/arch.c Mon Sep 18 15:15:25 2000 @@ -0,0 +1,291 @@ +/* + * linux/arch/arm/mach-sa1100/arch.c + * + * Architecture specific fixups. This is where any + * parameters in the params struct are fixed up, or + * any additional architecture specific information + * is pulled from the params struct. + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +extern void setup_initrd(unsigned int start, unsigned int size); +extern void setup_ramdisk(int doload, int prompt, int start, unsigned int rd_sz); + +static void victor_power_off(void) +{ + /* switch off power supply */ + mdelay(2000); + GPCR = GPIO_GPIO23; + while (1); +} + + +static void xp860_power_off(void) +{ + GPDR |= GPIO_GPIO20; + GPSR = GPIO_GPIO20; + mdelay(1000); + GPCR = GPIO_GPIO20; + while(1); +} + + +extern void __init sa1100_map_io(void); + +#define SET_BANK(__nr,__start,__size) \ + mi->bank[__nr].start = (__start), \ + mi->bank[__nr].size = (__size), \ + mi->bank[__nr].node = (((unsigned)(__start) - PHYS_OFFSET) >> 27) +static void __init +fixup_sa1100(struct machine_desc *desc, struct param_struct *params, + char **cmdline, struct meminfo *mi) +{ + if (machine_is_assabet()) { + /* + * On Assabet, we must probe for the Neponset board *before* + * paging_init() has occured to actually determine the amount + * of RAM available. + */ + extern void map_sa1100_gpio_regs(void); + extern void get_assabet_scr(void); + map_sa1100_gpio_regs(); + get_assabet_scr(); + + SET_BANK( 0, 0xc0000000, 32*1024*1024 ); + mi->nr_banks = 1; + + if (machine_has_neponset()) { + printk("Neponset expansion board detected\n"); + /* + * Note that Neponset RAM is slower... + * and still untested. + * This would be a candidate for + * _real_ NUMA support. + */ + //SET_BANK( 1, 0xd0000000, 32*1024*1024 ); + //mi->nr_banks = 2; + } + + ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + setup_ramdisk( 1, 0, 0, 8192 ); + setup_initrd( 0xc0800000, 3*1024*1024 ); + } + + else if (machine_is_brutus()) { + SET_BANK( 0, 0xc0000000, 4*1024*1024 ); + SET_BANK( 1, 0xc8000000, 4*1024*1024 ); + SET_BANK( 2, 0xd0000000, 4*1024*1024 ); + SET_BANK( 3, 0xd8000000, 4*1024*1024 ); + mi->nr_banks = 4; + + ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + setup_ramdisk( 1, 0, 0, 8192 ); + setup_initrd( __phys_to_virt(0xd8000000), 3*1024*1024 ); + } + + else if (machine_is_cerf()) { + // 16Meg Ram. + SET_BANK( 0, 0xc0000000, 8*1024*1024 ); + SET_BANK( 1, 0xc8000000, 8*1024*1024 ); // comment this out for 8MB Cerfs + mi->nr_banks = 2; + + ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + setup_ramdisk(1, 0, 0, 8192); + // Save 2Meg for RAMDisk + setup_initrd(0xc0500000, 3*1024*1024); + } + + else if (machine_is_empeg()) { + SET_BANK( 0, 0xc0000000, 4*1024*1024 ); + SET_BANK( 1, 0xc8000000, 4*1024*1024 ); + mi->nr_banks = 2; + + ROOT_DEV = MKDEV( 3, 1 ); /* /dev/hda1 */ + setup_ramdisk( 1, 0, 0, 4096 ); + setup_initrd( 0xd0000000+((1024-320)*1024), (320*1024) ); + } + + else if (machine_is_lart()) { + /* + * Note that LART is a special case - it doesn't use physical + * address line A23 on the DRAM, so we effectively have 4 * 8MB + * in two SA1100 banks. + */ + SET_BANK( 0, 0xc0000000, 8*1024*1024 ); + SET_BANK( 1, 0xc1000000, 8*1024*1024 ); + SET_BANK( 2, 0xc8000000, 8*1024*1024 ); + SET_BANK( 3, 0xc9000000, 8*1024*1024 ); + mi->nr_banks = 4; + + ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + setup_ramdisk(1, 0, 0, 8192); + setup_initrd(0xc0400000, 4*1024*1024); + } + + else if (machine_is_thinclient() || machine_is_graphicsclient()) { + SET_BANK( 0, 0xc0000000, 16*1024*1024 ); + mi->nr_banks = 1; + + ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + setup_ramdisk( 1, 0, 0, 8192 ); + setup_initrd( __phys_to_virt(0xc0800000), 4*1024*1024 ); + } + + else if (machine_is_nanoengine()) { + SET_BANK( 0, 0xc0000000, 32*1024*1024 ); + mi->nr_banks = 1; + + ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + setup_ramdisk( 1, 0, 0, 8192 ); + setup_initrd( __phys_to_virt(0xc0800000), 4*1024*1024 ); + + /* Get command line parameters passed from the loader (if any) */ + if( *((char*)0xc0000100) ) + *cmdline = ((char *)0xc0000100); + } + else if (machine_is_tifon()) { + SET_BANK( 0, 0xc0000000, 16*1024*1024 ); + SET_BANK( 1, 0xc8000000, 16*1024*1024 ); + mi->nr_banks = 2; + + ROOT_DEV = MKDEV(UNNAMED_MAJOR, 0); + setup_ramdisk(1, 0, 0, 4096); + setup_initrd( 0xd0000000 + 0x1100004, 0x140000 ); + } + + else if (machine_is_victor()) { + SET_BANK( 0, 0xc0000000, 4*1024*1024 ); + mi->nr_banks = 1; + + ROOT_DEV = MKDEV( 60, 2 ); + + /* Get command line parameters passed from the loader (if any) */ + if( *((char*)0xc0000000) ) + strcpy( *cmdline, ((char *)0xc0000000) ); + + /* power off if any problem */ + strcat( *cmdline, " panic=1" ); + + pm_power_off = victor_power_off; + } + + else if (machine_is_xp860()) { + SET_BANK( 0, 0xc0000000, 32*1024*1024 ); + mi->nr_banks = 1; + + pm_power_off = xp860_power_off; + } +} + +#ifdef CONFIG_SA1100_ASSABET +MACHINE_START(ASSABET, "Intel-Assabet") + BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) + FIXUP(fixup_sa1100) + MAPIO(sa1100_map_io) +MACHINE_END +#endif +#ifdef CONFIG_SA1100_BITSY +MACHINE_START(BITSY, "Compaq Bitsy") + BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) + BOOT_PARAMS(0xc0000100) + FIXUP(fixup_sa1100) + MAPIO(sa1100_map_io) +MACHINE_END +#endif +#ifdef CONFIG_SA1100_BRUTUS +MACHINE_START(BRUTUS, "Intel Brutus (SA1100 eval board)") + BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) + FIXUP(fixup_sa1100) + MAPIO(sa1100_map_io) +MACHINE_END +#endif +#ifdef CONFIG_SA1100_CERF +MACHINE_START(CERF, "Intrinsyc CerfBoard") + MAINTAINER("Pieter Truter") + BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) + FIXUP(fixup_sa1100) + MAPIO(sa1100_map_io) +MACHINE_END +#endif +#ifdef CONFIG_SA1100_EMPEG +MACHINE_START(EMPEG, "empeg MP3 Car Audio Player") + BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) + FIXUP(fixup_sa1100) + MAPIO(sa1100_map_io) +MACHINE_END +#endif +#ifdef CONFIG_SA1100_GRAPHICSCLIENT +MACHINE_START(GRAPHICSCLIENT, "ADS GraphicsClient") + BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) + FIXUP(fixup_sa1100) + MAPIO(sa1100_map_io) +MACHINE_END +#endif +#ifdef CONFIG_SA1100_ITSY +MACHINE_START(ITSY, "Compaq Itsy") + BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) + BOOT_PARAMS(0xc0000100 + FIXUP(fixup_sa1100) + MAPIO(sa1100_map_io) +MACHINE_END +#endif +#ifdef CONFIG_SA1100_LART +MACHINE_START(LART, "LART") + BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) + FIXUP(fixup_sa1100) + MAPIO(sa1100_map_io) +MACHINE_END +#endif +#ifdef CONFIG_SA1100_NANOENGINE +MACHINE_START(NANOENGINE, "BSE nanoEngine") + BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) + FIXUP(fixup_sa1100) + MAPIO(sa1100_map_io) +MACHINE_END +#endif +#ifdef CONFIG_SA1100_PLEB +MACHINE_START(PLEB, "PLEB") + BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) + FIXUP(fixup_sa1100) + MAPIO(sa1100_map_io) +MACHINE_END +#endif +#ifdef CONFIG_SA1100_THINCLIENT +MACHINE_START(THINCLIENT, "ADS ThinClient") + BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) + FIXUP(fixup_sa1100) + MAPIO(sa1100_map_io) +MACHINE_END +#endif +#ifdef CONFIG_SA1100_TIFON +MACHINE_START(TIFON, "Tifon") + BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) + FIXUP(fixup_sa1100) + MAPIO(sa1100_map_io) +MACHINE_END +#endif +#ifdef CONFIG_SA1100_VICTOR +MACHINE_START(VICTOR, "VisuAide Victor") + BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) + FIXUP(fixup_sa1100) + MAPIO(sa1100_map_io) +MACHINE_END +#endif +#ifdef CONFIG_SA1100_XP860 +MACHINE_START(XP860, "XP860") + BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000) + FIXUP(fixup_sa1100) + MAPIO(sa1100_map_io) +MACHINE_END +#endif diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/mach-sa1100/hw.c linux/arch/arm/mach-sa1100/hw.c --- v2.4.0-test8/linux/arch/arm/mach-sa1100/hw.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mach-sa1100/hw.c Mon Sep 18 15:15:25 2000 @@ -0,0 +1,188 @@ +/* + * arch/arm/kernel/hw-sa1100.c + * + * SA1100-dependent machine specifics + * + * Copyright (C) 2000 Nicolas Pitre + * + * This will certainly contain more stuff with time... like power management, + * special hardware autodetection, etc. + * + */ +#include +#include +#include +#include +#include + +#include +#include +#include + +/* + * SA1100 GPIO edge detection for IRQs: + * IRQs are generated on Falling-Edge, Rising-Edge, or both. + * This must be called *before* the appropriate IRQ is registered. + * Use this instead of directly setting GRER/GFER. + */ + +int GPIO_IRQ_rising_edge; +int GPIO_IRQ_falling_edge; + +void set_GPIO_IRQ_edge( int gpio_mask, int edge ) +{ + if( edge & GPIO_FALLING_EDGE ) + GPIO_IRQ_falling_edge |= gpio_mask; + else + GPIO_IRQ_falling_edge &= ~gpio_mask; + if( edge & GPIO_RISING_EDGE ) + GPIO_IRQ_rising_edge |= gpio_mask; + else + GPIO_IRQ_rising_edge &= ~gpio_mask; +} + +EXPORT_SYMBOL(set_GPIO_IRQ_edge); + + +#ifdef CONFIG_SA1100_ASSABET + +unsigned long BCR_value = BCR_DB1110; +unsigned long SCR_value = SCR_INIT; +EXPORT_SYMBOL(BCR_value); +EXPORT_SYMBOL(SCR_value); + +/* + * Read System Configuration "Register" + * (taken from "Intel StrongARM SA-1110 Microprocessor Development Board + * User's Guide", section 4.4.1) + * + * This same scan is performed in arch/arm/boot/compressed/head-sa1100.S + * to set up the serial port for decompression status messages. We + * repeat it here because the kernel may not be loaded as a zImage, and + * also because it's a hassle to communicate the SCR value to the kernel + * from the decompressor. + */ + +void __init get_assabet_scr(void) +{ + unsigned long flags, scr, i; + + local_irq_save(flags); + GPDR |= 0x3fc; /* Configure GPIO 9:2 as outputs */ + GPSR = 0x3fc; /* Write 0xFF to GPIO 9:2 */ + GPDR &= ~(0x3fc); /* Configure GPIO 9:2 as inputs */ + for(i = 100; i--; scr = GPLR); /* Read GPIO 9:2 */ + GPDR |= 0x3fc; /* restore correct pin direction */ + local_irq_restore(flags); + scr &= 0x3fc; /* save as system configuration byte. */ + + SCR_value = scr; +} + +#endif /* CONFIG_SA1100_ASSABET */ + + +#if defined(CONFIG_SA1100_BITSY) +/* + * Bitsy has extended, write-only memory-mapped GPIO's + */ +static int bitsy_egpio = EGPIO_BITSY_RS232_ON; +void clr_bitsy_egpio(unsigned long x) +{ + bitsy_egpio &= ~x; + *(volatile int *)0xdc000000 = bitsy_egpio; +} +void set_bitsy_egpio(unsigned long x) +{ + bitsy_egpio |= x; + *(volatile int *)0xdc000000 = bitsy_egpio; +} +EXPORT_SYMBOL(clr_bitsy_egpio); +EXPORT_SYMBOL(set_bitsy_egpio); +#endif + + +#ifdef CONFIG_SA1111 + +static void __init sa1111_init(void){ + unsigned long id=SKID; + + if((id & SKID_ID_MASK) == SKID_SA1111_ID) + printk(KERN_INFO "SA-1111 Microprocessor Companion Chip: " + "silicon revision %x, metal revision %x\n", + (id & SKID_SIREV_MASK)>>4, (id & SKID_MTREV_MASK)); + else { + printk(KERN_ERR "Could not detect SA-1111!\n"); + return; + } + + /* 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; + TUCR = TUCR_3_6864MHz; + + /* Now, set up the PLL and RCLK in the SA-1111: */ + SKCR = SKCR_PLL_BYPASS | SKCR_RDYEN | SKCR_OE_EN; + udelay(100); + SKCR = SKCR_PLL_BYPASS | SKCR_RCLKEN | SKCR_RDYEN | SKCR_OE_EN; + + /* SA-1111 Register Access Bus should now be available. Clocks for + * any other SA-1111 functional blocks must be enabled separately + * using the SKPCR. + */ + + { + /* + * SA1111 DMA bus master setup + */ + int cas; + + /* 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) ); + + TUCR |= (1<<10); + } +} + +#else +#define sa1111_init() printk( "Warning: missing SA1111 support\n" ) +#endif + + +static int __init hw_sa1100_init(void) +{ + if( machine_is_assabet() ){ + if(machine_has_neponset()){ +#ifdef CONFIG_ASSABET_NEPONSET + LEDS = WHOAMI; + sa1111_init(); +#else + printk( "Warning: Neponset detected but full support " + "hasn't been configured in the kernel\n" ); +#endif + } + } else if (machine_is_xp860()) { + sa1111_init(); + } + return 0; +} + +module_init(hw_sa1100_init); diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/mach-sa1100/leds.c linux/arch/arm/mach-sa1100/leds.c --- v2.4.0-test8/linux/arch/arm/mach-sa1100/leds.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mach-sa1100/leds.c Mon Sep 18 15:15:25 2000 @@ -0,0 +1,429 @@ +/* + * linux/arch/arm/kernel/leds-sa1100.c + * + * Copyright (C) 2000 John Dorsey + * + * Original (leds-footbridge.c) by Russell King + * + * Added Brutus LEDs support + * Nicolas Pitre, Mar 19, 2000 + * + * Added LART LED support + * Erik Mouw (J.A.K.Mouw@its.tudelft.nl), April 21, 2000 + * + * + * Assabet uses the LEDs as follows: + * - Green - toggles state every 50 timer interrupts + * - Red - on if system is not idle + * + * Brutus uses the LEDs as follows: + * - D3 (Green, GPIO9) - toggles state every 50 timer interrupts + * - D17 (Red, GPIO20) - on if system is not idle + * - D4 (Green, GPIO8) - misc function + * + * LART uses the LED as follows: + * - GPIO23 is the LED, on if system is not idle + * You can use both CONFIG_LEDS_CPU and CONFIG_LEDS_TIMER at the same + * time, but in that case the timer events will still dictate the + * pace of the LED. + * + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +#define LED_STATE_ENABLED 1 +#define LED_STATE_CLAIMED 2 + +static unsigned int led_state; +static unsigned int hw_led_state; + + +#ifdef CONFIG_SA1100_ASSABET + +#define BCR_LED_MASK (BCR_LED_GREEN | BCR_LED_RED) + +static void assabet_leds_event(led_event_t evt) +{ + unsigned long flags; + + local_irq_save(flags); + + switch (evt) { + case led_start: + hw_led_state = BCR_LED_RED | BCR_LED_GREEN; + led_state = LED_STATE_ENABLED; + break; + + case led_stop: + led_state &= ~LED_STATE_ENABLED; + break; + + case led_claim: + led_state |= LED_STATE_CLAIMED; + hw_led_state = BCR_LED_RED | BCR_LED_GREEN; + break; + + case led_release: + led_state &= ~LED_STATE_CLAIMED; + hw_led_state = BCR_LED_RED | BCR_LED_GREEN; + break; + +#ifdef CONFIG_LEDS_TIMER + case led_timer: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state ^= BCR_LED_GREEN; + break; +#endif + +#ifdef CONFIG_LEDS_CPU + case led_idle_start: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state |= BCR_LED_RED; + break; + + case led_idle_end: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state &= ~BCR_LED_RED; + break; +#endif + + case led_halted: + break; + + case led_green_on: + if (led_state & LED_STATE_CLAIMED) + hw_led_state &= ~BCR_LED_GREEN; + break; + + case led_green_off: + if (led_state & LED_STATE_CLAIMED) + hw_led_state |= BCR_LED_GREEN; + break; + + case led_amber_on: + break; + + case led_amber_off: + break; + + case led_red_on: + if (led_state & LED_STATE_CLAIMED) + hw_led_state &= ~BCR_LED_RED; + break; + + case led_red_off: + if (led_state & LED_STATE_CLAIMED) + hw_led_state |= BCR_LED_RED; + break; + + default: + break; + } + + if (led_state & LED_STATE_ENABLED) + BCR = BCR_value = (BCR_value & ~BCR_LED_MASK) | hw_led_state; + + local_irq_restore(flags); +} + +#endif /* CONFIG_SA1100_ASSABET */ + +#ifdef CONFIG_SA1100_BRUTUS + +#define LED_D3 GPIO_GPIO(9) +#define LED_D4 GPIO_GPIO(8) +#define LED_D17 GPIO_GPIO(20) +#define LED_MASK (LED_D3|LED_D4|LED_D17) + +static void brutus_leds_event(led_event_t evt) +{ + unsigned long flags; + + local_irq_save(flags); + + switch (evt) { + case led_start: + hw_led_state = LED_MASK; + led_state = LED_STATE_ENABLED; + break; + + case led_stop: + led_state &= ~LED_STATE_ENABLED; + break; + + case led_claim: + led_state |= LED_STATE_CLAIMED; + hw_led_state = LED_MASK; + break; + + case led_release: + led_state &= ~LED_STATE_CLAIMED; + hw_led_state = LED_MASK; + break; + +#ifdef CONFIG_LEDS_TIMER + case led_timer: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state ^= LED_D3; + break; +#endif + +#ifdef CONFIG_LEDS_CPU + case led_idle_start: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state |= LED_D17; + break; + + case led_idle_end: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state &= ~LED_D17; + break; +#endif + + case led_green_on: + hw_led_state &= ~LED_D4; + break; + + case led_green_off: + hw_led_state |= LED_D4; + break; + + case led_amber_on: + break; + + case led_amber_off: + break; + + case led_red_on: + if (led_state & LED_STATE_CLAIMED) + hw_led_state &= ~LED_D17; + break; + + case led_red_off: + if (led_state & LED_STATE_CLAIMED) + hw_led_state |= LED_D17; + break; + + default: + break; + } + + if (led_state & LED_STATE_ENABLED) { + GPSR = hw_led_state; + GPCR = hw_led_state ^ LED_MASK; + } + + local_irq_restore(flags); +} + +#endif /* CONFIG_SA1100_BRUTUS */ + +#ifdef CONFIG_SA1100_LART + +#define LED_23 GPIO_GPIO23 +#define LED_MASK (LED_23) + + +static void lart_leds_event(led_event_t evt) +{ + unsigned long flags; + + local_irq_save(flags); + + switch(evt) { + case led_start: + hw_led_state = LED_MASK; + led_state = LED_STATE_ENABLED; + break; + + case led_stop: + led_state &= ~LED_STATE_ENABLED; + break; + + case led_claim: + led_state |= LED_STATE_CLAIMED; + hw_led_state = LED_MASK; + break; + + case led_release: + led_state &= ~LED_STATE_CLAIMED; + hw_led_state = LED_MASK; + break; + +#ifdef CONFIG_LEDS_TIMER + case led_timer: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state ^= LED_23; + break; +#endif + +#ifdef CONFIG_LEDS_CPU + case led_idle_start: + /* The LART people like the LED to be off when the + system is idle... */ + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state &= ~LED_23; + break; + + case led_idle_end: + /* ... and on if the system is not idle */ + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state |= LED_23; + break; +#endif + + case led_red_on: + if (led_state & LED_STATE_CLAIMED) + hw_led_state &= ~LED_23; + break; + + case led_red_off: + if (led_state & LED_STATE_CLAIMED) + hw_led_state |= LED_23; + break; + + default: + break; + } + + /* Now set the GPIO state, or nothing will happen at all */ + if (led_state & LED_STATE_ENABLED) { + GPSR = hw_led_state; + GPCR = hw_led_state ^ LED_MASK; + } + + local_irq_restore(flags); +} + +#endif /* CONFIG_SA1100_LART */ + +#ifdef CONFIG_SA1100_CERF +#define LED_D0 GPIO_GPIO(0) +#define LED_D1 GPIO_GPIO(1) +#define LED_D2 GPIO_GPIO(2) +#define LED_D3 GPIO_GPIO(3) +#define LED_MASK (LED_D0|LED_D1|LED_D2|LED_D3) + +static void cerf_leds_event(led_event_t evt) +{ + unsigned long flags; + + local_irq_save(flags); + + switch (evt) { + case led_start: + hw_led_state = LED_MASK; + led_state = LED_STATE_ENABLED; + break; + + case led_stop: + led_state &= ~LED_STATE_ENABLED; + break; + + case led_claim: + led_state |= LED_STATE_CLAIMED; + hw_led_state = LED_MASK; + break; + case led_release: + led_state &= ~LED_STATE_CLAIMED; + hw_led_state = LED_MASK; + break; + +#ifdef CONFIG_LEDS_TIMER + case led_timer: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state ^= LED_D0; + break; +#endif + +#ifdef CONFIG_LEDS_CPU + case led_idle_start: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state &= ~LED_D1; + break; + + case led_idle_end: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state |= LED_D1; + break; +#endif + case led_green_on: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state &= ~LED_D2; + break; + + case led_green_off: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state |= LED_D2; + break; + + case led_amber_on: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state &= ~LED_D3; + break; + + case led_amber_off: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state |= LED_D3; + break; + + case led_red_on: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state &= ~LED_D1; + break; + + case led_red_off: + if (!(led_state & LED_STATE_CLAIMED)) + hw_led_state |= LED_D1; + break; + + default: + break; + } + + if (led_state & LED_STATE_ENABLED) { + GPSR = hw_led_state; + GPCR = hw_led_state ^ LED_MASK; + } + + local_irq_restore(flags); +} + +#endif /* CONFIG_SA1100_CERF */ + +static int __init +sa1100_leds_init(void) +{ +#ifdef CONFIG_SA1100_ASSABET + if (machine_is_assabet()) + leds_event = assabet_leds_event; +#endif +#ifdef CONFIG_SA1100_BRUTUS + if (machine_is_brutus()) + leds_event = brutus_leds_event; +#endif +#ifdef CONFIG_SA1100_LART + if (machine_is_lart()) + leds_event = lart_leds_event; +#endif +#ifdef CONFIG_SA1100_CERF + if (machine_is_cerf()) + { + //GPDR |= 0x0000000F; + leds_event = cerf_leds_event; + } +#endif + leds_event(led_start); + return 0; +} + +__initcall(sa1100_leds_init); diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/mach-shark/Makefile linux/arch/arm/mach-shark/Makefile --- v2.4.0-test8/linux/arch/arm/mach-shark/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mach-shark/Makefile Mon Sep 18 15:15:25 2000 @@ -0,0 +1,32 @@ +# +# 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). + +O_TARGET := shark.o + +# Object file lists. + +obj-y := arch.o dma.o mm.o pci.o +obj-m := +obj-n := +obj- := + +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.0-test8/linux/arch/arm/mach-shark/arch.c linux/arch/arm/mach-shark/arch.c --- v2.4.0-test8/linux/arch/arm/mach-shark/arch.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mach-shark/arch.c Tue Sep 19 08:31:53 2000 @@ -0,0 +1,31 @@ +/* + * linux/arch/arm/mach-shark/arch.c + * + * Architecture specific fixups. This is where any + * parameters in the params struct are fixed up, or + * any additional architecture specific information + * is pulled from the params struct. + */ +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +extern void setup_initrd(unsigned int start, unsigned int size); +extern void setup_ramdisk(int doload, int prompt, int start, unsigned int rd_sz); +extern void __init footbridge_map_io(void); +extern void __init shark_map_io(void); + +MACHINE_START(SHARK, "Shark") + MAINTAINER("Alexander Schulz") + BOOT_MEM(0x08000000, 0x40000000, 0xe0000000) + VIDEO(0x06000000, 0x061fffff) + MAPIO(shark_map_io) +MACHINE_END diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/mach-shark/dma.c linux/arch/arm/mach-shark/dma.c --- v2.4.0-test8/linux/arch/arm/mach-shark/dma.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mach-shark/dma.c Mon Sep 18 15:15:25 2000 @@ -0,0 +1,25 @@ +/* + * linux/arch/arm/mach-shark/dma.c + * + * by Alexander.Schulz@stud.uni-karlsruhe.de + * + * derived from: + * arch/arm/kernel/dma-ebsa285.c + * Copyright (C) 1998 Phil Blundell + */ + +#include +#include +#include + +#include +#include + +#include + +void __init arch_dma_init(dma_t *dma) +{ +#ifdef CONFIG_ISA_DMA + isa_init_dma(dma); +#endif +} diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/mach-shark/mm.c linux/arch/arm/mach-shark/mm.c --- v2.4.0-test8/linux/arch/arm/mach-shark/mm.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mach-shark/mm.c Mon Sep 18 15:15:25 2000 @@ -0,0 +1,30 @@ +/* + * linux/arch/arm/mach-shark/mm.c + * + * by Alexander.Schulz@stud.uni-karlsruhe.de + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include + +#include +#include +#include + +#include + +static struct map_desc shark_io_desc[] __initdata = { + { IO_BASE , IO_START , IO_SIZE , DOMAIN_IO, 0, 1, 0, 0 }, + { FB_BASE , FB_START , FB_SIZE , DOMAIN_IO, 0, 1, 0, 0 }, + { FBREG_BASE , FBREG_START , FBREG_SIZE , DOMAIN_IO, 0, 1, 0, 0 }, + LAST_DESC +}; + +void __init shark_map_io(void) +{ + iotable_init(shark_io_desc); +} diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/mach-shark/pci.c linux/arch/arm/mach-shark/pci.c --- v2.4.0-test8/linux/arch/arm/mach-shark/pci.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mach-shark/pci.c Tue Sep 19 08:31:53 2000 @@ -0,0 +1,27 @@ +/* + * linux/arch/arm/mach-shark/pci.c + * + * PCI bios-type initialisation for PCI machines + * + * Bits taken from various places. + */ +#include +#include +#include + +#include +#include + +static int __init shark_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + if (dev->bus->number == 0) + if (dev->devfn == 0) return 255; + else return 11; + else return 6; +} + +struct hw_pci shark_pci __initdata = { + init: via82c505_init, + swizzle: no_swizzle, + map_irq: shark_map_irq +}; diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/mm/Makefile linux/arch/arm/mm/Makefile --- v2.4.0-test8/linux/arch/arm/mm/Makefile Sun Aug 13 09:54:15 2000 +++ linux/arch/arm/mm/Makefile Mon Sep 18 15:15:25 2000 @@ -9,40 +9,61 @@ USE_STANDARD_AS_RULE := true +EXTRA_AFLAGS := -traditional O_TARGET := mm.o -O_OBJS := extable.o fault-$(PROCESSOR).o init.o \ + +# Object file lists. + +obj-y := extable.o fault-$(PROCESSOR).o init.o \ mm-$(PROCESSOR).o small_page.o +obj-m := +obj-n := +obj- := +export-objs := proc-syms.o -ifeq ($(CONFIG_CPU_26),y) - O_OBJS += proc-arm2,3.o -endif +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_ARM10) += proc-arm10.o +p-$(CONFIG_CPU_SA110) += proc-sa110.o +p-$(CONFIG_CPU_SA1100) += proc-sa110.o +obj-$(CONFIG_CPU_32) += consistent.o ioremap.o ifeq ($(CONFIG_CPU_32),y) - ifeq ($(CONFIG_CPU_ARM6),y) - P_OBJS += proc-arm6,7.o - endif - ifeq ($(CONFIG_CPU_ARM7),y) - P_OBJS += proc-arm6,7.o - endif - ifeq ($(CONFIG_CPU_ARM720),y) - P_OBJS += proc-arm720.o - endif - ifeq ($(CONFIG_CPU_SA110),y) - P_OBJS += proc-sa110.o - endif - ifeq ($(CONFIG_CPU_SA1100),y) - P_OBJS += proc-sa110.o - endif - O_OBJS += mm-$(MACHINE).o consistent.o ioremap.o $(sort $(P_OBJS)) +obj-$(CONFIG_MODULES) += proc-syms.o +endif + +# Integrator follows "new style" +# Soon, others will do too, and we can get rid of this +MMMACH := mm-$(MACHINE).o +ifeq ($(MMMACH),$(wildcard $(MMMACH))) +obj-$(CONFIG_CPU_32) += $(MMMACH) 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 +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 +proc-arm920.o: ../lib/constants.h +proc-arm10.o: ../lib/constants.h proc-sa110.o: ../lib/constants.h diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/mm/consistent.c linux/arch/arm/mm/consistent.c --- v2.4.0-test8/linux/arch/arm/mm/consistent.c Mon Jun 19 17:59:34 2000 +++ linux/arch/arm/mm/consistent.c Mon Sep 18 15:15:25 2000 @@ -1,5 +1,13 @@ /* - * Dynamic DMA mapping support. + * linux/arch/arm/mm/consistent.c + * + * Copyright (C) 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. + * + * Dynamic DMA mapping support. */ #include #include @@ -43,18 +51,19 @@ ret = __ioremap(virt_to_phys((void *)page), size, 0); if (ret) { /* free wasted pages */ - unsigned long end = page + (PAGE_SIZE << order); + unsigned long end; /* * we need to ensure that there are no * cachelines in use, or worse dirty in * this area. */ - dma_cache_inv(page, size); - dma_cache_inv(ret, size); + invalidate_dcache_range(page, page + size); + invalidate_dcache_range((unsigned long)ret, (unsigned long)ret + size); - *dma_handle = virt_to_bus((void *)page); + *dma_handle = __virt_to_bus(page); + end = page + (PAGE_SIZE << order); page += size; while (page < end) { free_page(page); @@ -102,17 +111,20 @@ */ void consistent_sync(void *vaddr, size_t size, int direction) { + unsigned long start = (unsigned long)vaddr; + unsigned long end = start + size; + switch (direction) { case PCI_DMA_NONE: BUG(); case PCI_DMA_FROMDEVICE: /* invalidate only */ - dma_cache_inv(vaddr, size); + invalidate_dcache_range(start, end); break; case PCI_DMA_TODEVICE: /* writeback only */ - dma_cache_wback(vaddr, size); + clean_dcache_range(start, end); break; case PCI_DMA_BIDIRECTIONAL: /* writeback and invalidate */ - dma_cache_wback_inv(vaddr, size); + flush_dcache_range(start, end); break; } } diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/mm/extable.c linux/arch/arm/mm/extable.c --- v2.4.0-test8/linux/arch/arm/mm/extable.c Wed Nov 10 08:31:37 1999 +++ linux/arch/arm/mm/extable.c Mon Sep 18 15:15:25 2000 @@ -1,5 +1,5 @@ /* - * linux/arch/arm/mm/extable.c + * linux/arch/arm/mm/extable.c */ #include diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/mm/fault-armo.c linux/arch/arm/mm/fault-armo.c --- v2.4.0-test8/linux/arch/arm/mm/fault-armo.c Wed Oct 20 16:29:08 1999 +++ linux/arch/arm/mm/fault-armo.c Mon Sep 18 15:15:25 2000 @@ -3,8 +3,11 @@ * * Copyright (C) 1995 Linus Torvalds * Modifications for ARM processor (c) 1995-1999 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 diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/mm/fault-armv.c linux/arch/arm/mm/fault-armv.c --- v2.4.0-test8/linux/arch/arm/mm/fault-armv.c Mon Jun 19 17:59:34 2000 +++ linux/arch/arm/mm/fault-armv.c Mon Sep 18 15:15:25 2000 @@ -3,8 +3,11 @@ * * Copyright (C) 1995 Linus Torvalds * Modifications for ARM processor (c) 1995-1999 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 @@ -399,7 +402,11 @@ return; bad: force_sig(inf->sig, current); - die_if_kernel(inf->name, regs, fsr); + + printk(KERN_ALERT "Unhandled fault: %s (%X) at 0x%08lx\n", + inf->name, fsr, addr); + show_pte(current->mm, addr); + die_if_kernel("Oops", regs, 0); return; weirdness: diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/mm/fault-common.c linux/arch/arm/mm/fault-common.c --- v2.4.0-test8/linux/arch/arm/mm/fault-common.c Mon Jun 26 12:04:01 2000 +++ linux/arch/arm/mm/fault-common.c Mon Sep 18 15:15:25 2000 @@ -3,6 +3,10 @@ * * Copyright (C) 1995 Linus Torvalds * Modifications for ARM processor (c) 1995-1999 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 @@ -12,7 +16,7 @@ * This is useful to dump out the page tables associated with * 'addr' in mm 'mm'. */ -static void show_pte(struct mm_struct *mm, unsigned long addr) +void show_pte(struct mm_struct *mm, unsigned long addr) { pgd_t *pgd; @@ -31,7 +35,7 @@ break; if (pgd_bad(*pgd)) { - printk("(bad)\n"); + printk("(bad)"); break; } @@ -42,7 +46,7 @@ break; if (pmd_bad(*pmd)) { - printk("(bad)\n"); + printk("(bad)"); break; } diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/mm/init.c linux/arch/arm/mm/init.c --- v2.4.0-test8/linux/arch/arm/mm/init.c Thu Sep 7 08:44:50 2000 +++ linux/arch/arm/mm/init.c Mon Sep 18 15:15:25 2000 @@ -2,6 +2,10 @@ * linux/arch/arm/mm/init.c * * 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 @@ -27,7 +31,8 @@ #include #include -#include "map.h" +#include +#include #ifndef CONFIG_DISCONTIGMEM #define NR_NODES 1 @@ -387,6 +392,12 @@ */ reserve_bootmem_node(0, __pa(swapper_pg_dir), PTRS_PER_PGD * sizeof(void *)); +#else + /* + * Stop this memory from being grabbed - its special DMA + * memory that is required for the screen. + */ + reserve_bootmem_node(0, 0x02000000, 0x00080000); #endif /* * And don't forget to reserve the allocator bitmap, @@ -466,7 +477,7 @@ * paging_init() sets up the page tables, initialises the zone memory * maps, and sets up the zero page, bad page and bad page tables. */ -void __init paging_init(struct meminfo *mi) +void __init paging_init(struct meminfo *mi, struct machine_desc *mdesc) { void *zero_page, *bad_page, *bad_table; int node; @@ -474,16 +485,19 @@ memcpy(&meminfo, mi, sizeof(meminfo)); /* - * allocate what we need for the bad pages + * allocate what we need for the bad pages. + * note that we count on this going ok. */ zero_page = alloc_bootmem_low_pages(PAGE_SIZE); bad_page = alloc_bootmem_low_pages(PAGE_SIZE); bad_table = alloc_bootmem_low_pages(TABLE_SIZE); /* - * initialise the page tables + * initialise the page tables. */ - pagetable_init(mi); + memtable_init(mi); + if (mdesc->map_io) + mdesc->map_io(); flush_tlb_all(); /* diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/mm/ioremap.c linux/arch/arm/mm/ioremap.c --- v2.4.0-test8/linux/arch/arm/mm/ioremap.c Sun Feb 6 17:45:25 2000 +++ linux/arch/arm/mm/ioremap.c Mon Sep 18 15:15:25 2000 @@ -1,5 +1,5 @@ /* - * arch/arm/mm/ioremap.c + * linux/arch/arm/mm/ioremap.c * * Re-map IO memory to kernel address space so that we can access it. * diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/mm/map.h linux/arch/arm/mm/map.h --- v2.4.0-test8/linux/arch/arm/mm/map.h Tue Apr 25 16:54:39 2000 +++ linux/arch/arm/mm/map.h Wed Dec 31 16:00:00 1969 @@ -1,25 +0,0 @@ -/* - * linux/arch/arm/mm/map.h - * - * Copyright (C) 1999 Russell King - * - * Page table mapping constructs and function prototypes - */ -struct map_desc { - unsigned long virtual; - unsigned long physical; - unsigned long length; - int domain:4, - prot_read:1, - prot_write:1, - cacheable:1, - bufferable:1; -}; - -extern struct map_desc io_desc[]; -extern unsigned int io_desc_size; - -struct meminfo; - -extern void create_memmap_holes(struct meminfo *); -extern void pagetable_init(struct meminfo *); diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/mm/mm-armo.c linux/arch/arm/mm/mm-armo.c --- v2.4.0-test8/linux/arch/arm/mm/mm-armo.c Tue Apr 25 16:54:39 2000 +++ linux/arch/arm/mm/mm-armo.c Mon Sep 18 15:15:25 2000 @@ -1,9 +1,13 @@ /* - * arch/arm/mm/mm-armo.c + * linux/arch/arm/mm/mm-armo.c * - * Page table sludge for older ARM processor architectures. + * Copyright (C) 1998-2000 Russell King * - * Copyright (C) 1998-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. + * + * Page table sludge for older ARM processor architectures. */ #include #include @@ -15,7 +19,7 @@ #include #include -#include "map.h" +#include #define MEMC_TABLE_SIZE (256*sizeof(unsigned long)) #define PGD_TABLE_SIZE (PTRS_PER_PGD * BYTES_PER_PTR) @@ -147,7 +151,7 @@ * some more work to get it to fit into our separate processor and * architecture structure. */ -void __init pagetable_init(struct meminfo *mi) +void __init memtable_init(struct meminfo *mi) { pte_t *pte; int i; @@ -160,6 +164,11 @@ for (i = 1; i < PTRS_PER_PGD; i++) pgd_val(swapper_pg_dir[i]) = 0; +} + +void __init iotable_init(struct map_desc *io_desc) +{ + /* nothing to do */ } /* diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/mm/mm-armv.c linux/arch/arm/mm/mm-armv.c --- v2.4.0-test8/linux/arch/arm/mm/mm-armv.c Mon Aug 7 21:02:27 2000 +++ linux/arch/arm/mm/mm-armv.c Mon Sep 18 15:15:25 2000 @@ -1,9 +1,13 @@ /* * linux/arch/arm/mm/mm-armv.c * - * Page table sludge for ARM v3 and v4 processor architectures. - * * Copyright (C) 1998-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. + * + * Page table sludge for ARM v3 and v4 processor architectures. */ #include #include @@ -16,7 +20,7 @@ #include #include -#include "map.h" +#include unsigned long *valid_addr_bitmap; @@ -62,6 +66,10 @@ #define FIRST_KERNEL_PGD_NR (FIRST_USER_PGD_NR + USER_PTRS_PER_PGD) +#define clean_cache_area(start,size) \ + cpu_cache_clean_invalidate_range((unsigned long)start, ((unsigned long)start) + size, 0); + + /* * need to get a 16k page for level 1 */ @@ -72,10 +80,13 @@ if (pgd) { pgd_t *init = pgd_offset_k(0); - + memzero(pgd, FIRST_KERNEL_PGD_NR * sizeof(pgd_t)); memcpy(pgd + FIRST_KERNEL_PGD_NR, init + FIRST_KERNEL_PGD_NR, (PTRS_PER_PGD - FIRST_KERNEL_PGD_NR) * sizeof(pgd_t)); + /* + * FIXME: this should not be necessary + */ clean_cache_area(pgd, PTRS_PER_PGD * sizeof(pgd_t)); /* @@ -310,18 +321,17 @@ } } -void __init pagetable_init(struct meminfo *mi) +/* + * Setup initial mappings. We use the page we allocated for zero page to hold + * the mappings, which will get overwritten by the vectors in traps_init(). + * The mappings must be in virtual address order. + */ +void __init memtable_init(struct meminfo *mi) { struct map_desc *init_maps, *p, *q; unsigned long address = 0; int i; - /* - * Setup initial mappings. We use the page we allocated - * for zero page to hold the mappings, which will get - * overwritten by the vectors in traps_init(). The - * mappings must be in virtual address order. - */ init_maps = p = alloc_bootmem_low_pages(PAGE_SIZE); p->physical = virt_to_phys(init_maps); @@ -401,16 +411,21 @@ } } while (address != 0); - /* - * Create the architecture specific mappings - */ - for (i = 0; i < io_desc_size; i++) - create_mapping(io_desc + i); - flush_cache_all(); } -static inline void free_memmap(unsigned long start, unsigned long end) +/* + * Create the architecture specific mappings + */ +void __init iotable_init(struct map_desc *io_desc) +{ + int i; + + for (i = 0; io_desc[i].last == 0; i++) + create_mapping(io_desc + i); +} + +static inline void free_memmap(int node, unsigned long start, unsigned long end) { unsigned long pg, pgend; @@ -422,10 +437,8 @@ start = __virt_to_phys(pg); end = __virt_to_phys(pgend); - /* - * The mem_map is always stored in node 0 - */ - free_bootmem_node(0, start, end - start); + + free_bootmem_node(node, start, end - start); } static inline void free_unused_memmap_node(int node, struct meminfo *mi) @@ -449,7 +462,7 @@ * between the current bank and the previous, free it. */ if (prev_bank_end && prev_bank_end != bank_start) - free_memmap(prev_bank_end, bank_start); + free_memmap(node, prev_bank_end, bank_start); prev_bank_end = PAGE_ALIGN(mi->bank[i].start + mi->bank[i].size); diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/mm/mm-clps7500.c linux/arch/arm/mm/mm-clps7500.c --- v2.4.0-test8/linux/arch/arm/mm/mm-clps7500.c Mon Feb 28 14:16:37 2000 +++ linux/arch/arm/mm/mm-clps7500.c Mon Sep 18 15:15:25 2000 @@ -1,12 +1,11 @@ /* - * arch/arm/mm/mm-cl7500.c + * linux/arch/arm/mm/mm-cl7500.c * - * Extra MM routines for CL7500 architecture + * Copyright (C) 1998 Russell King + * Copyright (C) 1999 Nexus Electronics Ltd * - * Copyright (C) 1998 Russell King - * Copyright (C) 1999 Nexus Electronics Ltd + * Extra MM routines for CL7500 architecture */ - #include #include @@ -14,15 +13,17 @@ #include #include -#include "map.h" - -#define SIZE(x) (sizeof(x) / sizeof(x[0])) +#include -struct map_desc io_desc[] __initdata = { +static struct map_desc cl7500_io_desc[] __initdata = { { IO_BASE, IO_START, IO_SIZE , DOMAIN_IO, 0, 1 }, /* IO space */ { ISA_BASE, ISA_START, ISA_SIZE , DOMAIN_IO, 0, 1 }, /* ISA space */ { FLASH_BASE, FLASH_START, FLASH_SIZE, DOMAIN_IO, 0, 1 }, /* Flash */ - { LED_BASE, LED_START, LED_SIZE , DOMAIN_IO, 0, 1 } /* LED */ + { LED_BASE, LED_START, LED_SIZE , DOMAIN_IO, 0, 1 }, /* LED */ + LAST_DESC }; -unsigned int __initdata io_desc_size = SIZE(io_desc); +void __init clps7500_map_io(void) +{ + iotable_init(cl7500_io_desc); +} diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/mm/mm-ebsa110.c linux/arch/arm/mm/mm-ebsa110.c --- v2.4.0-test8/linux/arch/arm/mm/mm-ebsa110.c Tue Apr 25 16:54:39 2000 +++ linux/arch/arm/mm/mm-ebsa110.c Mon Sep 18 15:15:25 2000 @@ -1,9 +1,13 @@ /* - * arch/arm/mm/mm-ebsa110.c + * linux/arch/arm/mm/mm-ebsa110.c * - * Extra MM routines for the EBSA-110 architecture + * Copyright (C) 1998-1999 Russell King * - * Copyright (C) 1998-1999 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. + * + * Extra MM routines for the EBSA-110 architecture */ #include #include @@ -12,13 +16,15 @@ #include #include -#include "map.h" +#include -#define SIZE(x) (sizeof(x) / sizeof(x[0])) - -struct map_desc io_desc[] __initdata = { +static struct map_desc ebsa110_io_desc[] __initdata = { { IO_BASE - PGDIR_SIZE, 0xc0000000, PGDIR_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, - { IO_BASE , IO_START , IO_SIZE , DOMAIN_IO, 0, 1, 0, 0 } + { IO_BASE , IO_START , IO_SIZE , DOMAIN_IO, 0, 1, 0, 0 }, + LAST_DESC }; -unsigned int __initdata io_desc_size = SIZE(io_desc); +void __init ebsa110_map_io(void) +{ + iotable_init(ebsa110_io_desc); +} diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/mm/mm-footbridge.c linux/arch/arm/mm/mm-footbridge.c --- v2.4.0-test8/linux/arch/arm/mm/mm-footbridge.c Sun Aug 13 09:54:15 2000 +++ linux/arch/arm/mm/mm-footbridge.c Mon Sep 18 15:15:25 2000 @@ -1,9 +1,13 @@ /* - * arch/arm/mm/mm-footbridge.c + * linux/arch/arm/mm/mm-footbridge.c * - * Extra MM routines for the EBSA285 architecture + * Copyright (C) 1998-2000 Russell King, Dave Gilbert. * - * Copyright (C) 1998-1999 Russell King, Dave Gilbert. + * 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. + * + * Extra MM routines for the EBSA285 architecture */ #include #include @@ -13,73 +17,83 @@ #include #include #include -#include - -#include "map.h" +#include +#include -#define SIZE(x) (sizeof(x) / sizeof(x[0])) +#include /* - * The first entry allows us to fiddle with the EEPROM from user-space. - * This entry will go away in time, once the fmu32 can mmap() the - * flash. It can't at the moment. - * - * If you want to fiddle with PCI VGA cards from user space, then - * change the '0, 1 }' for the PCI MEM and PCI IO to '1, 1 }' - * You can then access the PCI bus at 0xe0000000 and 0xffe00000. + * Common mapping for all systems. Note that the outbound write flush is + * commented out since there is a "No Fix" problem with it. Not mapping + * it means that we have extra bullet protection on our feet. */ - -#ifdef CONFIG_FOOTBRIDGE_HOST +static struct map_desc fb_common_io_desc[] __initdata = { + { ARMCSR_BASE, DC21285_ARMCSR_BASE, ARMCSR_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, + { XBUS_BASE, 0x40000000, XBUS_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, + LAST_DESC +}; /* - * The mapping when the footbridge is in host mode. + * The mapping when the footbridge is in host mode. We don't map any of + * this when we are in add-in mode. */ -#define MAPPING \ - { FLASH_BASE, DC21285_FLASH, FLASH_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, \ - { PCIMEM_BASE, DC21285_PCI_MEM, PCIMEM_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, \ - { PCICFG0_BASE, DC21285_PCI_TYPE_0_CONFIG, PCICFG0_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, \ - { PCICFG1_BASE, DC21285_PCI_TYPE_1_CONFIG, PCICFG1_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, \ - { PCIIACK_BASE, DC21285_PCI_IACK, PCIIACK_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, \ - { WFLUSH_BASE, DC21285_OUTBOUND_WRITE_FLUSH, WFLUSH_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, \ - { ARMCSR_BASE, DC21285_ARMCSR_BASE, ARMCSR_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, \ - { PCIO_BASE, DC21285_PCI_IO, PCIO_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, \ - { XBUS_BASE, 0x40000000, XBUS_SIZE, DOMAIN_IO, 0, 1, 0, 0 } - -#else +static struct map_desc ebsa285_host_io_desc[] __initdata = { +#if defined(CONFIG_ARCH_FOOTBRIDGE) && defined(CONFIG_FOOTBRIDGE_HOST) + { PCIMEM_BASE, DC21285_PCI_MEM, PCIMEM_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, + { PCICFG0_BASE, DC21285_PCI_TYPE_0_CONFIG, PCICFG0_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, + { PCICFG1_BASE, DC21285_PCI_TYPE_1_CONFIG, PCICFG1_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, + { PCIIACK_BASE, DC21285_PCI_IACK, PCIIACK_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, + { PCIO_BASE, DC21285_PCI_IO, PCIO_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, +#endif + LAST_DESC +}; /* - * The mapping when the footbridge is in add-in mode. + * The CO-ebsa285 mapping. */ -#define MAPPING \ - { PCIO_BASE, DC21285_PCI_IO, PCIO_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, \ - { XBUS_BASE, 0x40000000, XBUS_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, \ - { ARMCSR_BASE, DC21285_ARMCSR_BASE, ARMCSR_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, \ - { WFLUSH_BASE, DC21285_OUTBOUND_WRITE_FLUSH, WFLUSH_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, \ - { FLASH_BASE, DC21285_FLASH, FLASH_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, \ - { PCIMEM_BASE, DC21285_PCI_MEM, PCIMEM_SIZE, DOMAIN_IO, 0, 1, 0, 0 } - +static struct map_desc co285_io_desc[] __initdata = { +#ifdef CONFIG_ARCH_CO285 + { PCIO_BASE, DC21285_PCI_IO, PCIO_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, + { PCIMEM_BASE, DC21285_PCI_MEM, PCIMEM_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, #endif - -struct map_desc io_desc[] __initdata = { - MAPPING + LAST_DESC }; -unsigned int __initdata io_desc_size = SIZE(io_desc); +void __init footbridge_map_io(void) +{ + struct map_desc *desc = NULL; + + /* + * Set up the common mapping first; we need this to + * determine whether we're in host mode or not. + */ + iotable_init(fb_common_io_desc); + + /* + * Now, work out what we've got to map in addition on this + * platform. + */ + if (machine_is_co285()) + desc = co285_io_desc; + else if (footbridge_cfn_mode()) + desc = ebsa285_host_io_desc; + if (desc) + iotable_init(desc); +} #ifdef CONFIG_FOOTBRIDGE_ADDIN /* - * These two functions convert virtual addresses to PCI addresses - * and PCI addresses to virtual addresses. Note that it is only - * legal to use these on memory obtained via get_free_page or - * kmalloc. + * These two functions convert virtual addresses to PCI addresses and PCI + * addresses to virtual addresses. Note that it is only legal to use these + * on memory obtained via get_free_page or kmalloc. */ unsigned long __virt_to_bus(unsigned long res) { #ifdef CONFIG_DEBUG_ERRORS if (res < PAGE_OFFSET || res >= (unsigned long)high_memory) { - printk("__virt_to_phys: invalid virtual address 0x%08lx\n", res); + printk("__virt_to_bus: invalid virtual address 0x%08lx\n", res); __backtrace(); } #endif @@ -93,7 +107,7 @@ #ifdef CONFIG_DEBUG_ERRORS if (res < PAGE_OFFSET || res >= (unsigned long)high_memory) { - printk("__phys_to_virt: invalid virtual address 0x%08lx\n", res); + printk("__bus_to_virt: invalid virtual address 0x%08lx\n", res); __backtrace(); } #endif diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/mm/mm-l7200.c linux/arch/arm/mm/mm-l7200.c --- v2.4.0-test8/linux/arch/arm/mm/mm-l7200.c Sun Aug 13 09:54:15 2000 +++ linux/arch/arm/mm/mm-l7200.c Mon Sep 18 15:15:25 2000 @@ -1,11 +1,10 @@ /* - * arch/arm/mm/mm-lusl7200.c + * linux/arch/arm/mm/mm-lusl7200.c * - * Extra MM routines for L7200 architecture + * Copyright (C) 2000 Steve Hill (sjhill@cotw.com) * - * Copyright (C) 2000 Steve Hill (sjhill@cotw.com) + * Extra MM routines for L7200 architecture */ - #include #include @@ -13,13 +12,15 @@ #include #include -#include "map.h" - -#define SIZE(x) (sizeof(x) / sizeof(x[0])) +#include -struct map_desc io_desc[] __initdata = { +static struct map_desc l7200_io_desc[] __initdata = { { IO_BASE, IO_START, IO_SIZE, DOMAIN_IO, 0, 1 ,0 ,0}, { IO_BASE_2, IO_START_2, IO_SIZE_2, DOMAIN_IO, 0, 1 ,0 ,0}, + LAST_DESC }; -unsigned int __initdata io_desc_size = SIZE(io_desc); +void __init l7200_map_io(void) +{ + iotable_init(l7200_io_desc); +} diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/mm/mm-nexuspci.c linux/arch/arm/mm/mm-nexuspci.c --- v2.4.0-test8/linux/arch/arm/mm/mm-nexuspci.c Mon Feb 28 14:16:37 2000 +++ linux/arch/arm/mm/mm-nexuspci.c Mon Sep 18 15:15:25 2000 @@ -1,13 +1,12 @@ /* - * arch/arm/mm/mm-nexuspci.c - * from arch/arm/mm/mm-ebsa110.c + * linux/arch/arm/mm/mm-nexuspci.c + * from linux/arch/arm/mm/mm-ebsa110.c * - * Extra MM routines for the FTV/PCI architecture + * Copyright (C) 1998-1999 Phil Blundell + * Copyright (C) 1998-1999 Russell King * - * Copyright (C) 1998-1999 Phil Blundell - * Copyright (C) 1998-1999 Russell King + * Extra MM routines for the FTV/PCI architecture */ - #include #include #include @@ -16,16 +15,18 @@ #include #include -#include "map.h" - -struct map_desc io_desc[] __initdata = { +#include + +static struct map_desc nexuspci_io_desc[] __initdata = { { INTCONT_BASE, INTCONT_START, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, { PLX_BASE, PLX_START, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, { PCIO_BASE, PLX_IO_START, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, { DUART_BASE, DUART_START, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, - { STATUS_BASE, STATUS_START, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 } + { STATUS_BASE, STATUS_START, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, + LAST_DESC }; -#define SIZE(x) (sizeof(x) / sizeof(x[0])) - -unsigned int __initdata io_desc_size = SIZE(io_desc); +void __init nexuspci_map_io(void) +{ + iotable_init(nexuspci_io_desc); +} diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/mm/mm-rpc.c linux/arch/arm/mm/mm-rpc.c --- v2.4.0-test8/linux/arch/arm/mm/mm-rpc.c Tue Apr 25 16:54:39 2000 +++ linux/arch/arm/mm/mm-rpc.c Mon Sep 18 15:15:25 2000 @@ -1,9 +1,13 @@ /* - * arch/arm/mm/mm-rpc.c + * linux/arch/arm/mm/mm-rpc.c * - * Extra MM routines for RiscPC architecture + * Copyright (C) 1998-1999 Russell King * - * Copyright (C) 1998-1999 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. + * + * Extra MM routines for RiscPC architecture */ #include @@ -12,17 +16,16 @@ #include #include -#include "map.h" - -#define SIZE(x) (sizeof(x) / sizeof(x[0])) +#include -struct map_desc io_desc[] __initdata = { - /* VRAM */ - { SCREEN_BASE, SCREEN_START, 2*1048576, DOMAIN_IO, 0, 1, 0, 0 }, - /* IO space */ - { IO_BASE, IO_START, IO_SIZE , DOMAIN_IO, 0, 1, 0, 0 }, - /* EASI space */ - { EASI_BASE, EASI_START, EASI_SIZE, DOMAIN_IO, 0, 1, 0, 0 } +static struct map_desc rpc_io_desc[] __initdata = { + { SCREEN_BASE, SCREEN_START, 2*1048576, DOMAIN_IO, 0, 1, 0, 0 }, /* VRAM */ + { IO_BASE, IO_START, IO_SIZE , DOMAIN_IO, 0, 1, 0, 0 }, /* IO space */ + { EASI_BASE, EASI_START, EASI_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, /* EASI space */ + LAST_DESC }; -unsigned int __initdata io_desc_size = SIZE(io_desc); +void __init rpc_map_io(void) +{ + iotable_init(rpc_io_desc); +} diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/mm/mm-sa1100.c linux/arch/arm/mm/mm-sa1100.c --- v2.4.0-test8/linux/arch/arm/mm/mm-sa1100.c Sun Aug 13 09:54:15 2000 +++ linux/arch/arm/mm/mm-sa1100.c Mon Sep 18 15:15:25 2000 @@ -1,20 +1,19 @@ /* - * arch/arm/mm/mm-sa1100.c + * linux/arch/arm/mm/mm-sa1100.c * - * Extra MM routines for the SA1100 architecture + * Copyright (C) 1998-1999 Russell King + * Copyright (C) 1999 Hugo Fiennes * - * Copyright (C) 1998-1999 Russell King - * Copyright (C) 1999 Hugo Fiennes + * Extra MM routines for the SA1100 architecture * - * 1999/12/04 Nicolas Pitre + * 1999/12/04 Nicolas Pitre * Converted memory definition for struct meminfo initialisations. * Memory is listed physically now. * - * 2000/04/07 Nicolas Pitre + * 2000/04/07 Nicolas Pitre * Reworked for run-time selection of memory definitions * */ - #include #include #include @@ -25,171 +24,158 @@ #include #include -#include "map.h" +#include -#define SIZE(x) (sizeof(x) / sizeof(x[0])) - - -#define SA1100_STD_IO_MAPPING \ +static struct map_desc standard_io_desc[] __initdata = { /* virtual physical length domain r w c b */ \ - { 0xe0000000, 0x20000000, 0x04000000, DOMAIN_IO, 1, 1, 0, 0 }, /* PCMCIA0 IO */ \ - { 0xe4000000, 0x30000000, 0x04000000, DOMAIN_IO, 1, 1, 0, 0 }, /* PCMCIA1 IO */ \ - { 0xe8000000, 0x28000000, 0x04000000, DOMAIN_IO, 1, 1, 0, 0 }, /* PCMCIA0 attr */ \ - { 0xec000000, 0x38000000, 0x04000000, DOMAIN_IO, 1, 1, 0, 0 }, /* PCMCIA1 attr */ \ - { 0xf0000000, 0x2c000000, 0x04000000, DOMAIN_IO, 1, 1, 0, 0 }, /* PCMCIA0 mem */ \ - { 0xf4000000, 0x3c000000, 0x04000000, DOMAIN_IO, 1, 1, 0, 0 }, /* PCMCIA1 mem */ \ - { 0xf8000000, 0x80000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCM */ \ - { 0xfa000000, 0x90000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* SCM */ \ - { 0xfc000000, 0xa0000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* MER */ \ - { 0xfe000000, 0xb0000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 } /* LCD + DMA */ + { 0xf6000000, 0x20000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* PCMCIA0 IO */ + { 0xf7000000, 0x30000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* PCMCIA1 IO */ + { 0xf8000000, 0x80000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCM */ + { 0xfa000000, 0x90000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* SCM */ + { 0xfc000000, 0xa0000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* MER */ + { 0xfe000000, 0xb0000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* LCD + DMA */ + LAST_DESC +}; +/* + * Typically, static virtual address mappings are as follow: + * + * 0xe8000000-0xefffffff: flash memory (especially when multiple flash + * banks need to be mapped contigously) + * 0xf0000000-0xf3ffffff: miscellaneous stuff (CPLDs, etc.) + * 0xf4000000-0xf4ffffff: SA-1111 + * 0xf5000000-0xf5ffffff: reserved (used by cache flushing area) + * 0xf6000000-0xffffffff: reserved (internal SA1100 IO defined above) + * + * Below 0xe8000000 is reserved for vm allocation. + */ static struct map_desc assabet_io_desc[] __initdata = { #ifdef CONFIG_SA1100_ASSABET - { 0xd0000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */ - { 0xd4000000, 0x10000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* System Registers */ - { 0xdc000000, 0x12000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* Board Control Register */ - { 0xd8000000, 0x40000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA-1111 */ - SA1100_STD_IO_MAPPING -#endif -}; - -static struct map_desc nanoengine_io_desc[] __initdata = { -#ifdef CONFIG_SA1100_NANOENGINE - { 0xd0000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */ - { 0xd4000000, 0x10000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* System Registers */ - { 0xdc000000, 0x18A00000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* Internal PCI Config Space */ - SA1100_STD_IO_MAPPING + { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */ + { 0xf0000000, 0x10000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* System Registers */ + { 0xf1000000, 0x12000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* Board Control Register */ + { 0xf2800000, 0x4b800000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* MQ200 */ + { 0xf4000000, 0x40000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA-1111 */ #endif + LAST_DESC }; static struct map_desc bitsy_io_desc[] __initdata = { #ifdef CONFIG_SA1100_BITSY - { 0xd0000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */ - { 0xdc000000, 0x49000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* EGPIO 0 */ - SA1100_STD_IO_MAPPING + { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */ + { 0xf0000000, 0x49000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* EGPIO 0 */ #endif + LAST_DESC }; static struct map_desc cerf_io_desc[] __initdata = { #ifdef CONFIG_SA1100_CERF - { 0xd8000000, 0x08000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* Crystal Chip */ - { 0xd0000000, 0x00000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */ - SA1100_STD_IO_MAPPING + { 0xe8000000, 0x00000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */ + { 0xf0000000, 0x08000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* Crystal Chip */ #endif + LAST_DESC }; static struct map_desc empeg_io_desc[] __initdata = { #ifdef CONFIG_SA1100_EMPEG { EMPEG_FLASHBASE, 0x00000000, 0x00200000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash */ - SA1100_STD_IO_MAPPING #endif + LAST_DESC }; static struct map_desc graphicsclient_io_desc[] __initdata = { #ifdef CONFIG_SA1100_GRAPHICSCLIENT - { 0xd0000000, 0x08000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 */ - { 0xd0800000, 0x18000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 3 */ - { 0xdc000000, 0x10000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* CPLD */ - SA1100_STD_IO_MAPPING + { 0xe8000000, 0x08000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 */ + { 0xf0000000, 0x10000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* CPLD */ #endif + LAST_DESC }; static struct map_desc lart_io_desc[] __initdata = { #ifdef CONFIG_SA1100_LART - { 0xd0000000, 0x00000000, 0x00400000, DOMAIN_IO, 1, 1, 0, 0 }, /* main flash memory */ - { 0xd8000000, 0x08000000, 0x00400000, DOMAIN_IO, 1, 1, 0, 0 }, /* main flash, alternative location */ - SA1100_STD_IO_MAPPING + { 0xe8000000, 0x00000000, 0x00400000, DOMAIN_IO, 1, 1, 0, 0 }, /* main flash memory */ + { 0xec000000, 0x08000000, 0x00400000, DOMAIN_IO, 1, 1, 0, 0 }, /* main flash, alternative location */ #endif + LAST_DESC +}; + +static struct map_desc nanoengine_io_desc[] __initdata = { +#ifdef CONFIG_SA1100_NANOENGINE + { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */ + { 0xf0000000, 0x10000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* System Registers */ + { 0xf1000000, 0x18A00000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* Internal PCI Config Space */ +#endif + LAST_DESC }; static struct map_desc thinclient_io_desc[] __initdata = { #ifdef CONFIG_SA1100_THINCLIENT #if 0 - { 0xd0000000, 0x00000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 when JP1 2-4 */ + { 0xe8000000, 0x00000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 when JP1 2-4 */ #else - { 0xd0000000, 0x08000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 when JP1 3-4 */ + { 0xe8000000, 0x08000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 when JP1 3-4 */ #endif - { 0xdc000000, 0x10000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* CPLD */ - SA1100_STD_IO_MAPPING + { 0xf0000000, 0x10000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* CPLD */ #endif + LAST_DESC }; static struct map_desc tifon_io_desc[] __initdata = { #ifdef CONFIG_SA1100_TIFON - { 0xd0000000, 0x00000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 */ - { 0xd0800000, 0x08000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 2 */ - SA1100_STD_IO_MAPPING + { 0xe8000000, 0x00000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 1 */ + { 0xe8800000, 0x08000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 2 */ #endif + LAST_DESC }; static struct map_desc victor_io_desc[] __initdata = { #ifdef CONFIG_SA1100_VICTOR - { 0xd0000000, 0x00000000, 0x00200000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash */ - SA1100_STD_IO_MAPPING + { 0xe8000000, 0x00000000, 0x00200000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash */ #endif + LAST_DESC }; static struct map_desc xp860_io_desc[] __initdata = { #ifdef CONFIG_SA1100_XP860 - { 0xd8000000, 0x40000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA-1111 */ - { 0xda000000, 0x10000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* SCSI */ - { 0xdc000000, 0x18000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* LAN */ - SA1100_STD_IO_MAPPING + { 0xf4000000, 0x40000000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA-1111 */ + { 0xf0000000, 0x10000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* SCSI */ + { 0xf1000000, 0x18000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* LAN */ #endif + LAST_DESC }; -static struct map_desc default_io_desc[] __initdata = { - SA1100_STD_IO_MAPPING -}; +void __init sa1100_map_io(void) +{ + struct map_desc *desc = NULL; + iotable_init(standard_io_desc); -/* - * Here it would be wiser to simply assign a pointer to the appropriate - * list, but io_desc is already declared as an array in "map.h". - */ -struct map_desc io_desc[20] __initdata = {}; -unsigned int io_desc_size; + if (machine_is_assabet()) + desc = assabet_io_desc; + else if (machine_is_nanoengine()) + desc = nanoengine_io_desc; + else if (machine_is_bitsy()) + desc = bitsy_io_desc; + else if (machine_is_cerf()) + desc = cerf_io_desc; + else if (machine_is_empeg()) + desc = empeg_io_desc; + else if (machine_is_graphicsclient()) + desc = graphicsclient_io_desc; + else if (machine_is_lart()) + desc = lart_io_desc; + else if (machine_is_thinclient()) + desc = thinclient_io_desc; + else if (machine_is_tifon()) + desc = tifon_io_desc; + else if (machine_is_victor()) + desc = victor_io_desc; + else if (machine_is_xp860()) + desc = xp860_io_desc; -void __init select_sa1100_io_desc(void) -{ - if( machine_is_assabet() ) { - memcpy( io_desc, assabet_io_desc, sizeof(assabet_io_desc) ); - io_desc_size = SIZE(assabet_io_desc); - } else if( machine_is_nanoengine() ) { - memcpy( io_desc, nanoengine_io_desc, sizeof(nanoengine_io_desc) ); - io_desc_size = SIZE(nanoengine_io_desc); - } else if( machine_is_bitsy() ) { - memcpy( io_desc, bitsy_io_desc, sizeof(bitsy_io_desc) ); - io_desc_size = SIZE(bitsy_io_desc); - } else if( machine_is_cerf() ) { - memcpy( io_desc, cerf_io_desc, sizeof(cerf_io_desc) ); - io_desc_size = SIZE(cerf_io_desc); - } else if( machine_is_empeg() ) { - memcpy( io_desc, empeg_io_desc, sizeof(empeg_io_desc) ); - io_desc_size = SIZE(empeg_io_desc); - } else if( machine_is_graphicsclient() ) { - memcpy( io_desc, graphicsclient_io_desc, sizeof(graphicsclient_io_desc) ); - io_desc_size = SIZE(graphicsclient_io_desc); - } else if( machine_is_lart() ) { - memcpy( io_desc, lart_io_desc, sizeof(lart_io_desc) ); - io_desc_size = SIZE(lart_io_desc); - } else if( machine_is_thinclient() ) { - memcpy( io_desc, thinclient_io_desc, sizeof(thinclient_io_desc) ); - io_desc_size = SIZE(thinclient_io_desc); - } else if( machine_is_tifon() ) { - memcpy( io_desc, tifon_io_desc, sizeof(tifon_io_desc) ); - io_desc_size = SIZE(tifon_io_desc); - } else if( machine_is_victor() ) { - memcpy( io_desc, victor_io_desc, sizeof(victor_io_desc) ); - io_desc_size = SIZE(victor_io_desc); - } else if( machine_is_xp860() ) { - memcpy( io_desc, xp860_io_desc, sizeof(xp860_io_desc) ); - io_desc_size = SIZE(xp860_io_desc); - } else { - memcpy( io_desc, default_io_desc, sizeof(default_io_desc) ); - io_desc_size = SIZE(default_io_desc); - } + if (desc) + iotable_init(desc); } diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/mm/mm-shark.c linux/arch/arm/mm/mm-shark.c --- v2.4.0-test8/linux/arch/arm/mm/mm-shark.c Mon Mar 27 10:46:29 2000 +++ linux/arch/arm/mm/mm-shark.c Wed Dec 31 16:00:00 1969 @@ -1,25 +0,0 @@ -/* - * arch/arm/mm/mm-shark.c - * - * by Alexander.Schulz@stud.uni-karlsruhe.de - */ -#include -#include -#include - -#include -#include -#include - -#include "map.h" - -struct map_desc io_desc[] __initdata = { - { IO_BASE , IO_START , IO_SIZE , DOMAIN_IO, 0, 1, 0, 0 }, - { FB_BASE , FB_START , FB_SIZE , DOMAIN_IO, 0, 1, 0, 0 }, - { FBREG_BASE , FBREG_START , FBREG_SIZE , DOMAIN_IO, 0, 1, 0, 0 } -}; - - -#define SIZEOFMAP (sizeof(io_desc) / sizeof(io_desc[0])) - -unsigned int __initdata io_desc_size = SIZEOFMAP; diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/mm/mm-tbox.c linux/arch/arm/mm/mm-tbox.c --- v2.4.0-test8/linux/arch/arm/mm/mm-tbox.c Fri Oct 29 11:42:57 1999 +++ linux/arch/arm/mm/mm-tbox.c Mon Sep 18 15:15:25 2000 @@ -1,13 +1,11 @@ /* - * arch/arm/mm/mm-tbox.c - * from arch/arm/mm/mm-ebsa110.c + * linux/arch/arm/mm/mm-tbox.c * - * Extra MM routines for the Tbox architecture + * Copyright (C) 1998, 1999, 2000 Phil Blundell + * Copyright (C) 1998-1999 Russell King * - * Copyright (C) 1998 Phil Blundell - * Copyright (C) 1998-1999 Russell King + * Extra MM routines for the Tbox architecture */ - #include #include #include @@ -16,44 +14,15 @@ #include #include -#include "map.h" +#include -#define SIZE(x) (sizeof(x) / sizeof(x[0])) - -/* Logical Physical - * 0xffff1000 0x00100000 DMA registers - * 0xffff2000 0x00200000 MPEG - * 0xffff3000 0x00300000 FPGA1 local control - * 0xffff4000 0x00400000 External serial - * 0xffff5000 0x00500000 Internal serial - * 0xffff6000 0x00600000 Parallel - * 0xffff7000 0x00700000 Interrupt control - * 0xffff8000 0x00800000 Computer video - * 0xffff9000 0x00900000 Control register 0 - * 0xffffs000 0x00a00000 Control register 1 - * 0xffffb000 0x00b00000 Control register 2 - * 0xffffc000 0x00c00000 FPGA2 local control - * 0xffffd000 0x00d00000 Interrupt reset - * 0xffffe000 0x00e00000 MPEG DMA throttle - */ - -const struct map_desc io_desc[] __initdata = { - { 0xffff0000, 0x01000000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, - { 0xffff1000, 0x00100000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, - { 0xffff2000, 0x00200000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, - { 0xffff3000, 0x00300000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, - { 0xffff4000, 0x00400000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, - { 0xfe000000, 0x00400000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, - { 0xffff5000, 0x00500000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, - { 0xffff6000, 0x00600000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, - { 0xffff7000, 0x00700000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, - { 0xffff8000, 0x00800000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, - { 0xffff9000, 0x00900000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, - { 0xffffa000, 0x00a00000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, - { 0xffffb000, 0x00b00000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, - { 0xffffc000, 0x00c00000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, - { 0xffffd000, 0x00d00000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, - { 0xffffe000, 0x00e00000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 } +static struct map_desc tbox_io_desc[] __initdata = { + /* See hardware.h for details */ + { IO_BASE, IO_START, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, + LAST_DESC }; -unsigned int __initdata io_desc_size = SIZE(io_desc); +void __init tbox_map_io(void) +{ + iotable_init(tbox_io_desc); +} diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/mm/proc-arm2,3.S linux/arch/arm/mm/proc-arm2,3.S --- v2.4.0-test8/linux/arch/arm/mm/proc-arm2,3.S Mon Jun 26 12:04:01 2000 +++ linux/arch/arm/mm/proc-arm2,3.S Mon Sep 18 15:15:25 2000 @@ -1,10 +1,16 @@ /* - * linux/arch/arm/mm/proc-arm2,3.S: MMU functions for ARM2,3 + * linux/arch/arm/mm/proc-arm2,3.S * - * (C) 1997-1999 Russell King + * Copyright (C) 1997-1999 Russell King * - * These are the low level assembler for performing cache - * and memory functions on ARM2, ARM250 and ARM3 processors. + * 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. + * + * MMU functions for ARM2,3 + * + * These are the low level assembler for performing cache + * and memory functions on ARM2, ARM250 and ARM3 processors. */ #include #include diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/mm/proc-arm6,7.S linux/arch/arm/mm/proc-arm6,7.S --- v2.4.0-test8/linux/arch/arm/mm/proc-arm6,7.S Mon Jun 26 12:04:01 2000 +++ linux/arch/arm/mm/proc-arm6,7.S Mon Sep 18 15:15:25 2000 @@ -1,20 +1,25 @@ /* - * linux/arch/arm/mm/proc-arm6,7.S: MMU functions for ARM6 + * linux/arch/arm/mm/proc-arm6,7.S * - * (C) 1997-2000 Russell King + * Copyright (C) 1997-2000 Russell King * - * These are the low level assembler for performing cache and TLB - * functions on the ARM6 & ARM7. + * 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. + * + * MMU functions for ARM6 + * + * These are the low level assembler for performing cache and TLB + * functions on the ARM6 & ARM7. */ #include #include #include -#include #include "../lib/constants.h" /* - * Function: arm6_7_flush_cache_all (void) - * : arm6_7_flush_cache_page (unsigned long address, int size, int flags) + * Function: arm6_7_cache_clean_invalidate_all (void) + * : arm6_7_cache_clean_invalidate_page (unsigned long address, int size, int flags) * * Params : address Area start address * : size size of area @@ -22,41 +27,41 @@ * * Purpose : Flush all cache lines */ -ENTRY(cpu_arm6_flush_cache_all) -ENTRY(cpu_arm7_flush_cache_all) -ENTRY(cpu_arm6_flush_cache_area) -ENTRY(cpu_arm7_flush_cache_area) -ENTRY(cpu_arm6_flush_cache_entry) -ENTRY(cpu_arm7_flush_cache_entry) -ENTRY(cpu_arm6_flush_icache_area) -ENTRY(cpu_arm7_flush_icache_area) -ENTRY(cpu_arm6_flush_icache_page) -ENTRY(cpu_arm7_flush_icache_page) -ENTRY(cpu_arm6_cache_wback_area) -ENTRY(cpu_arm7_cache_wback_area) -ENTRY(cpu_arm6_cache_purge_area) -ENTRY(cpu_arm7_cache_purge_area) +ENTRY(cpu_arm6_cache_clean_invalidate_all) +ENTRY(cpu_arm7_cache_clean_invalidate_all) +ENTRY(cpu_arm6_cache_clean_invalidate_range) +ENTRY(cpu_arm7_cache_clean_invalidate_range) +ENTRY(cpu_arm6_invalidate_icache_range) +ENTRY(cpu_arm7_invalidate_icache_range) +ENTRY(cpu_arm6_invalidate_icache_page) +ENTRY(cpu_arm7_invalidate_icache_page) +ENTRY(cpu_arm6_dcache_clean_range) +ENTRY(cpu_arm7_dcache_clean_range) +ENTRY(cpu_arm6_dcache_invalidate_range) +ENTRY(cpu_arm7_dcache_invalidate_range) mov r0, #0 mcr p15, 0, r0, c7, c0, 0 @ flush cache -ENTRY(cpu_arm6_clean_cache_area) -ENTRY(cpu_arm7_clean_cache_area) +ENTRY(cpu_arm6_dcache_clean_page) +ENTRY(cpu_arm7_dcache_clean_page) +ENTRY(cpu_arm6_dcache_clean_entry) +ENTRY(cpu_arm7_dcache_clean_entry) ENTRY(cpu_arm6_flush_ram_page) ENTRY(cpu_arm7_flush_ram_page) mov pc, lr /* - * Function: arm6_7_flush_tlb_all (void) + * Function: arm6_7_tlb_invalidate_all (void) * * Purpose : flush all TLB entries in all caches */ -ENTRY(cpu_arm6_flush_tlb_all) -ENTRY(cpu_arm7_flush_tlb_all) +ENTRY(cpu_arm6_tlb_invalidate_all) +ENTRY(cpu_arm7_tlb_invalidate_all) mov r0, #0 mcr p15, 0, r0, c5, c0, 0 @ flush TLB mov pc, lr /* - * Function: arm6_7_flush_tlb_page (unsigned long address, int end, int flags) + * Function: arm6_7_tlb_invalidate_page (unsigned long address, int end, int flags) * * Params : address Area start address * : end Area end address @@ -64,8 +69,8 @@ * * Purpose : flush a TLB entry */ -ENTRY(cpu_arm6_flush_tlb_area) -ENTRY(cpu_arm7_flush_tlb_area) +ENTRY(cpu_arm6_tlb_invalidate_range) +ENTRY(cpu_arm7_tlb_invalidate_range) 1: mcr p15, 0, r0, c6, c0, 0 @ flush TLB add r0, r0, #4096 cmp r0, r1 @@ -73,15 +78,15 @@ mov pc, lr /* - * Function: arm6_7_flush_tlb_page (unsigned long address, int flags) + * Function: arm6_7_tlb_invalidate_page (unsigned long address, int flags) * * Params : address Address * : flags b0 = I-TLB as well * * Purpose : flush a TLB entry */ -ENTRY(cpu_arm6_flush_tlb_page) -ENTRY(cpu_arm7_flush_tlb_page) +ENTRY(cpu_arm6_tlb_invalidate_page) +ENTRY(cpu_arm7_tlb_invalidate_page) mcr p15, 0, r0, c6, c0, 0 @ flush TLB mov pc, lr @@ -392,23 +397,33 @@ .word cpu_arm6_check_bugs .word cpu_arm6_proc_init .word cpu_arm6_proc_fin - .word cpu_arm6_flush_cache_all - .word cpu_arm6_flush_cache_area - .word cpu_arm6_flush_cache_entry - .word cpu_arm6_clean_cache_area + .word cpu_arm6_reset + .word cpu_arm6_do_idle + + /* cache */ + .word cpu_arm6_cache_clean_invalidate_all + .word cpu_arm6_cache_clean_invalidate_range .word cpu_arm6_flush_ram_page - .word cpu_arm6_flush_tlb_all - .word cpu_arm6_flush_tlb_area + + /* dcache */ + .word cpu_arm6_dcache_invalidate_range + .word cpu_arm6_dcache_clean_range + .word cpu_arm6_dcache_clean_page + .word cpu_arm6_dcache_clean_entry + + /* icache */ + .word cpu_arm6_invalidate_icache_range + .word cpu_arm6_invalidate_icache_page + + /* tlb */ + .word cpu_arm6_tlb_invalidate_all + .word cpu_arm6_tlb_invalidate_range + .word cpu_arm6_tlb_invalidate_page + + /* pgtable */ .word cpu_arm6_set_pgd .word cpu_arm6_set_pmd .word cpu_arm6_set_pte - .word cpu_arm6_reset - .word cpu_arm6_flush_icache_area - .word cpu_arm6_cache_wback_area - .word cpu_arm6_cache_purge_area - .word cpu_arm6_flush_tlb_page - .word cpu_arm6_do_idle - .word cpu_arm6_flush_icache_page .size arm6_processor_functions, . - arm6_processor_functions /* @@ -421,23 +436,33 @@ .word cpu_arm7_check_bugs .word cpu_arm7_proc_init .word cpu_arm7_proc_fin - .word cpu_arm7_flush_cache_all - .word cpu_arm7_flush_cache_area - .word cpu_arm7_flush_cache_entry - .word cpu_arm7_clean_cache_area + .word cpu_arm7_reset + .word cpu_arm7_do_idle + + /* cache */ + .word cpu_arm7_cache_clean_invalidate_all + .word cpu_arm7_cache_clean_invalidate_range .word cpu_arm7_flush_ram_page - .word cpu_arm7_flush_tlb_all - .word cpu_arm7_flush_tlb_area + + /* dcache */ + .word cpu_arm7_dcache_invalidate_range + .word cpu_arm7_dcache_clean_range + .word cpu_arm7_dcache_clean_page + .word cpu_arm7_dcache_clean_entry + + /* icache */ + .word cpu_arm7_invalidate_icache_range + .word cpu_arm7_invalidate_icache_page + + /* tlb */ + .word cpu_arm7_tlb_invalidate_all + .word cpu_arm7_tlb_invalidate_range + .word cpu_arm7_tlb_invalidate_page + + /* pgtable */ .word cpu_arm7_set_pgd .word cpu_arm7_set_pmd .word cpu_arm7_set_pte - .word cpu_arm7_reset - .word cpu_arm7_flush_icache_area - .word cpu_arm7_cache_wback_area - .word cpu_arm7_cache_purge_area - .word cpu_arm7_flush_tlb_page - .word cpu_arm7_do_idle - .word cpu_arm7_flush_icache_page .size arm7_processor_functions, . - arm7_processor_functions .type cpu_arm6_info, #object @@ -479,7 +504,7 @@ __arm6_proc_info: .long 0x41560600 .long 0xfffffff0 - .long 0x00000c12 + .long 0x00000c1e b __arm6_setup .long cpu_arch_name .long cpu_elf_name @@ -492,7 +517,7 @@ __arm610_proc_info: .long 0x41560610 .long 0xfffffff0 - .long 0x00000c12 + .long 0x00000c1e b __arm6_setup .long cpu_arch_name .long cpu_elf_name @@ -505,7 +530,7 @@ __arm7_proc_info: .long 0x41007000 .long 0xffffff00 - .long 0x00000c12 + .long 0x00000c1e b __arm7_setup .long cpu_arch_name .long cpu_elf_name @@ -518,7 +543,7 @@ __arm710_proc_info: .long 0x41007100 .long 0xfff8ff00 - .long 0x00000c12 + .long 0x00000c1e b __arm7_setup .long cpu_arch_name .long cpu_elf_name diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/mm/proc-arm720.S linux/arch/arm/mm/proc-arm720.S --- v2.4.0-test8/linux/arch/arm/mm/proc-arm720.S Sun Aug 13 09:54:15 2000 +++ linux/arch/arm/mm/proc-arm720.S Mon Sep 18 15:15:25 2000 @@ -1,27 +1,44 @@ /* - * linux/arch/arm/mm/proc-arm720.S: MMU functions for ARM720 + * linux/arch/arm/mm/proc-arm720.S: MMU functions for ARM720 + * + * Copyright (C) 2000 Steve Hill (sjhill@cotw.com) + * Rob Scott (rscott@mtrob.fdns.net) + * Copyright (C) 2000 ARM Limited, Deep Blue Solutions Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * Copyright (C) 2000 Steve Hill (sjhill@cotw.com) - * Rob Scott (rscott@mtrob.fdns.net) * * These are the low level assembler for performing cache and TLB - * functions on the ARM720T. + * functions on the ARM720T. The ARM720T has a writethrough IDC + * cache, so we don't need to clean it. * - * Changelog: - * 05-09-2000 SJH Created by moving 720 specific functions - * out of 'proc-arm6,7.S' per RSK discussion - * 07-25-2000 SJH Added idle function. + * Changelog: + * 05-09-2000 SJH Created by moving 720 specific functions + * out of 'proc-arm6,7.S' per RMK discussion + * 07-25-2000 SJH Added idle function. + * 08-25-2000 DBS Updated for integration of ARM Ltd version. */ #include #include #include -#include #include #include "../lib/constants.h" /* - * Function: arm720_flush_cache_all (void) - * : arm720_flush_cache_page (unsigned long address, int size, + * Function: arm720_cache_clean_invalidate_all (void) + * : arm720_cache_clean_invalidate_page (unsigned long address, int size, * int flags) * * Params : address Area start address @@ -30,33 +47,37 @@ * * Purpose : Flush all cache lines */ -ENTRY(cpu_arm720_flush_cache_all) -ENTRY(cpu_arm720_flush_cache_area) -ENTRY(cpu_arm720_flush_cache_entry) -ENTRY(cpu_arm720_flush_icache_area) -ENTRY(cpu_arm720_flush_icache_page) -ENTRY(cpu_arm720_cache_wback_area) -ENTRY(cpu_arm720_cache_purge_area) +ENTRY(cpu_arm720_cache_clean_invalidate_all) +ENTRY(cpu_arm720_cache_clean_invalidate_range) +ENTRY(cpu_arm720_icache_invalidate_range) +ENTRY(cpu_arm720_icache_invalidate_page) +ENTRY(cpu_arm720_dcache_invalidate_range) mov r0, #0 mcr p15, 0, r0, c7, c7, 0 @ flush cache mov pc, lr -ENTRY(cpu_arm720_clean_cache_area) +/* + * These just expect cache lines to be cleaned. Since we have a writethrough + * cache, we never have any dirty cachelines to worry about. + */ +ENTRY(cpu_arm720_dcache_clean_range) +ENTRY(cpu_arm720_dcache_clean_page) +ENTRY(cpu_arm720_dcache_clean_entry) ENTRY(cpu_arm720_flush_ram_page) mov pc, lr /* - * Function: arm720_flush_tlb_all (void) + * Function: arm720_tlb_invalidate_all (void) * * Purpose : flush all TLB entries in all caches */ -ENTRY(cpu_arm720_flush_tlb_all) +ENTRY(cpu_arm720_tlb_invalidate_all) mov r0, #0 mcr p15, 0, r0, c8, c7, 0 @ flush TLB (v4) mov pc, lr /* - * Function: arm720_flush_tlb_page (unsigned long address, int end, int flags) + * Function: arm720_tlb_invalidate_page (unsigned long address, int end, int flags) * * Params : address Area start address * : end Area end address @@ -64,7 +85,7 @@ * * Purpose : flush a TLB entry */ -ENTRY(cpu_arm720_flush_tlb_area) +ENTRY(cpu_arm720_tlb_invalidate_range) 1: mcr p15, 0, r0, c8, c7, 1 @ flush TLB (v4) add r0, r0, #4096 cmp r0, r1 @@ -72,14 +93,14 @@ mov pc, lr /* - * Function: arm720_flush_tlb_page (unsigned long address, int flags) + * Function: arm720_tlb_invalidate_page (unsigned long address, int flags) * * Params : address Address * : flags b0 = I-TLB as well * * Purpose : flush a TLB entry */ -ENTRY(cpu_arm720_flush_tlb_page) +ENTRY(cpu_arm720_tlb_invalidate_page) mcr p15, 0, r0, c8, c7, 1 @ flush TLB (v4) mov pc, lr @@ -262,12 +283,15 @@ mov pc, lr ENTRY(cpu_arm720_proc_fin) - mrs r0, cpsr - orr r0, r0, #F_BIT | I_BIT - msr cpsr, r0 - mov r0, #0x31 @ ....S..DP...M + stmfd sp!, {lr} + mov ip, #F_BIT | I_BIT | SVC_MODE + msr cpsr_c, ip + mrc p15, 0, r0, c1, c0, 0 + bic r0, r0, #0x1000 @ ...i............ + bic r0, r0, #0x000e @ ............wca. mcr p15, 0, r0, c1, c0, 0 @ disable caches - mov pc, lr + mcr p15, 0, r1, c7, c7, 0 @ invalidate cache + ldmfd sp!, {pc} /* * Function: arm720_proc_do_idle (void) @@ -281,10 +305,12 @@ * 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] + str r1, [r2, #4] +#endif mov pc, lr /* @@ -295,7 +321,7 @@ */ ENTRY(cpu_arm720_set_pgd) mov r1, #0 - mcr p15, 0, r1, c7, c7, 0 @ flush cache + mcr p15, 0, r1, c7, c7, 0 @ invalidate cache mcr p15, 0, r0, c2, c0, 0 @ update page table ptr mcr p15, 0, r1, c8, c7, 0 @ flush TLB (v4) mov pc, lr @@ -340,9 +366,6 @@ movne r2, #0 str r2, [r0] @ hardware version - - mcr p15, 0, r0, c7, c7, 0 @ flush cache - mcr p15, 0, r0, c8, c7, 0 @ flush TLB (v4) mov pc, lr /* @@ -351,30 +374,37 @@ * Notes : This sets up everything for a reset */ ENTRY(cpu_arm720_reset) - mov r0, #0 - mcr p15, 0, r0, c7, c7, 0 @ flush cache - mcr p15, 0, r0, c8, c7, 0 @ flush TLB (v4) - mov pc, lr + mov ip, #0 + mcr p15, 0, ip, c7, c7, 0 @ invalidate cache + mcr p15, 0, ip, c8, c7, 0 @ flush TLB (v4) + mrc p15, 0, ip, c1, c0, 0 @ get ctrl register + bic ip, ip, #0x000f @ ............wcam + bic ip, ip, #0x2100 @ ..v....s........ + mcr p15, 0, ip, c1, c0, 0 @ ctrl register + mov pc, r0 cpu_armvlsi_name: .asciz "ARM/VLSI" cpu_arm720_name: - .asciz "ARM 720" + .asciz "ARM720T" .align .section ".text.init", #alloc, #execinstr __arm720_setup: mov r0, #0 - mcr p15, 0, r0, c7, c7, 0 @ flush caches on v4 + mcr p15, 0, r0, c7, c7, 0 @ invalidate caches mcr p15, 0, r0, c8, c7, 0 @ flush TLB (v4) mcr p15, 0, r4, c2, c0 @ load page table pointer mov r0, #0x1f @ Domains 0, 1 = client mcr p15, 0, r0, c3, c0 @ load domain access register - - /* Set CP15 Control reg bits (RSBLDPWCAM) */ - mov r0, #0x7d @ ...LDPWC.M - orr r0, r0, #0x100 @ .S.LDPWC.M + + mrc p15, 0, r0, c1, c0 @ get control register + bic r0, r0, #0x2e00 + bic r0, r0, #0x000e + orr r0, r0, #0x0031 @ ..V...RSBLDPWCAM + orr r0, r0, #0x0100 @ .........111.... (old) + orr r0, r0, #0x000c @ ..0...01..111101 (new) mov pc, lr @ __ret (head-armv.S) /* @@ -387,23 +417,33 @@ .word cpu_arm720_check_bugs .word cpu_arm720_proc_init .word cpu_arm720_proc_fin - .word cpu_arm720_flush_cache_all - .word cpu_arm720_flush_cache_area - .word cpu_arm720_flush_cache_entry - .word cpu_arm720_clean_cache_area + .word cpu_arm720_reset + .word cpu_arm720_do_idle + + /* cache */ + .word cpu_arm720_cache_clean_invalidate_all + .word cpu_arm720_cache_clean_invalidate_range .word cpu_arm720_flush_ram_page - .word cpu_arm720_flush_tlb_all - .word cpu_arm720_flush_tlb_area + + /* dcache */ + .word cpu_arm720_dcache_invalidate_range + .word cpu_arm720_dcache_clean_range + .word cpu_arm720_dcache_clean_page + .word cpu_arm720_dcache_clean_entry + + /* icache */ + .word cpu_arm720_icache_invalidate_range + .word cpu_arm720_icache_invalidate_page + + /* tlb */ + .word cpu_arm720_tlb_invalidate_all + .word cpu_arm720_tlb_invalidate_range + .word cpu_arm720_tlb_invalidate_page + + /* pgtable */ .word cpu_arm720_set_pgd .word cpu_arm720_set_pmd .word cpu_arm720_set_pte - .word cpu_arm720_reset - .word cpu_arm720_flush_icache_area - .word cpu_arm720_cache_wback_area - .word cpu_arm720_cache_purge_area - .word cpu_arm720_flush_tlb_page - .word cpu_arm720_do_idle - .word cpu_arm720_flush_icache_page .size arm720_processor_functions, . - arm720_processor_functions .type cpu_arm720_info, #object @@ -431,11 +471,11 @@ __arm720_proc_info: .long 0x41807200 @ cpu_val .long 0xffffff00 @ cpu_mask - .long 0x00000c12 @ __cpu_mmu_flags + .long 0x00000c0e @ __cpu_mmu_flags b __arm720_setup @ --cpu_flush .long cpu_arch_name @ arch_name .long cpu_elf_name @ elf_name - .long HWCAP_SWP | HWCAP_26BIT @ elf_hwcap + .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT @ elf_hwcap .long cpu_arm720_info @ info .long arm720_processor_functions .size __arm720_proc_info, . - __arm720_proc_info diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/mm/proc-arm920.S linux/arch/arm/mm/proc-arm920.S --- v2.4.0-test8/linux/arch/arm/mm/proc-arm920.S Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mm/proc-arm920.S Mon Sep 18 15:15:25 2000 @@ -0,0 +1,602 @@ +/* + * linux/arch/arm/mm/arm920.S: MMU functions for ARM920 + * + * Copyright (C) 1999,2000 ARM Limited + * Copyright (C) 2000 Deep Blue Solutions Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * These are the low level assembler for performing cache and TLB + * functions on the arm920. + */ +#include +#include +#include +#include +#include +#include "../lib/constants.h" + +/* + * This is the maximum size of an area which will be invalidated + * using the single invalidate entry instructions. Anything larger + * than this, and we go for the whole cache. + * + * This value should be chosen such that we choose the cheapest + * alternative. + */ +#define MAX_AREA_SIZE 16384 + +/* + * the cache line size of the I and D cache + */ +#define DCACHELINESIZE 32 +#define ICACHELINESIZE 32 + +/* + * and the page size + */ +#define PAGESIZE 4096 + + .text + +/* + * cpu_arm920_data_abort() + * + * obtain information about current aborted instruction + * + * r0 = address of aborted instruction + * + * Returns: + * r0 = address of abort + * r1 != 0 if writing + * r3 = FSR + */ + .align 5 +ENTRY(cpu_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 + mrc p15, 0, r3, c5, c0, 0 @ get FSR + and r1, r1, #2 + and r3, r3, #255 + mov pc, lr + +/* + * cpu_arm920_check_bugs() + */ +ENTRY(cpu_arm920_check_bugs) + mrs ip, cpsr + bic ip, ip, #F_BIT + msr cpsr, ip + mov pc, lr + +/* + * cpu_arm920_proc_init() + */ +ENTRY(cpu_arm920_proc_init) + mov pc, lr + +/* + * cpu_arm920_proc_fin() + */ +ENTRY(cpu_arm920_proc_fin) + stmfd sp!, {lr} + mov ip, #F_BIT | I_BIT | SVC_MODE + msr cpsr_c, ip + bl cpu_arm920_cache_clean_invalidate_all + mrc p15, 0, r0, c1, c0, 0 @ ctrl register + bic r0, r0, #0x1000 @ ...i............ + bic r0, r0, #0x000e @ ............wca. + mcr p15, 0, r0, c1, c0, 0 @ disable caches + ldmfd sp!, {pc} + +/* + * cpu_arm920_reset(loc) + * + * Perform a soft reset of the system. Put the CPU into the + * same state as it would be if it had been reset, and branch + * to what would be the reset vector. + * + * loc: location to jump to for soft reset + */ + .align 5 +ENTRY(cpu_arm920_reset) + mov ip, #0 + mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches + mcr p15, 0, ip, c7, c10, 4 @ drain WB + mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs + mrc p15, 0, ip, c1, c0, 0 @ ctrl register + bic ip, ip, #0x000f @ ............wcam + bic ip, ip, #0x1100 @ ...i...s........ + mcr p15, 0, ip, c1, c0, 0 @ ctrl register + mov pc, r0 + +/* + * cpu_arm920_do_idle() + */ + .align 5 +ENTRY(cpu_arm920_do_idle) +#if defined(CONFIG_CPU_ARM920_CPU_IDLE) + mcr p15, 0, r0, c7, c0, 4 @ Wait for interrupt +#endif + mov pc, lr + +/* ================================= CACHE ================================ */ + + +/* + * cpu_arm920_cache_clean_invalidate_all() + * + * clean and invalidate all cache lines + * + * Note: + * 1. we should preserve r0 at all times + */ + .align 5 +ENTRY(cpu_arm920_cache_clean_invalidate_all) + mov r2, #1 +cpu_arm920_cache_clean_invalidate_all_r2: + mov ip, #0 +#ifdef CONFIG_CPU_ARM920_FORCE_WRITE_THROUGH + mcr p15, 0, ip, c7, c6, 0 @ invalidate D cache +#else +/* + * 'Clean & Invalidate whole DCache' + * Re-written to use Index Ops. + * Uses registers r1, r3 and ip + */ + mov r1, #7 << 5 @ 8 segments +1: orr r3, r1, #63 << 26 @ 64 entries +2: mcr p15, 0, r3, c7, c14, 2 @ clean & invalidate D index + subs r3, r3, #1 << 26 + bcs 2b @ entries 63 to 0 + subs r1, r1, #1 << 5 + bcs 1b @ segments 7 to 0 +#endif + teq r2, #0 + mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache + mcr p15, 0, ip, c7, c10, 4 @ drain WB + mov pc, lr + +/* + * cpu_arm920_cache_clean_invalidate_range(start, end, flags) + * + * clean and invalidate all cache lines associated with this area of memory + * + * start: Area start address + * end: Area end address + * flags: nonzero for I cache as well + */ + .align 5 +ENTRY(cpu_arm920_cache_clean_invalidate_range) + bic r0, r0, #DCACHELINESIZE - 1 @ && added by PGM + sub r3, r1, r0 + cmp r3, #MAX_AREA_SIZE + bgt cpu_arm920_cache_clean_invalidate_all_r2 +1: mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry + add r0, r0, #DCACHELINESIZE + mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry + add r0, r0, #DCACHELINESIZE + cmp r0, r1 + blt 1b + teq r2, #0 + movne r0, #0 + mcrne p15, 0, r0, c7, c5, 0 @ invalidate I cache + mov pc, lr + +/* + * cpu_arm920_flush_ram_page(page) + * + * clean and invalidate all cache lines associated with this area of memory + * + * page: page to clean and invalidate + */ + .align 5 +ENTRY(cpu_arm920_flush_ram_page) + mov r1, #PAGESIZE +1: mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry + add r0, r0, #DCACHELINESIZE + mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry + add r0, r0, #DCACHELINESIZE + subs r1, r1, #2 * DCACHELINESIZE + bne 1b + mcr p15, 0, r1, c7, c10, 4 @ drain WB + mov pc, lr + +/* ================================ D-CACHE =============================== */ + +/* + * cpu_arm920_dcache_invalidate_range(start, end) + * + * throw away all D-cached data in specified region without an obligation + * to write them back. Note however that we must clean the D-cached entries + * around the boundaries if the start and/or end address are not cache + * aligned. + * + * start: virtual start address + * end: virtual end address + */ + .align 5 +ENTRY(cpu_arm920_dcache_invalidate_range) + tst r0, #DCACHELINESIZE - 1 + bic r0, r0, #DCACHELINESIZE - 1 + mcrne p15, 0, r0, c7, c10, 1 @ clean D entry + tst r1, #DCACHELINESIZE - 1 + mcrne p15, 0, r1, c7, c10, 1 @ clean D entry +1: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry + add r0, r0, #DCACHELINESIZE + cmp r0, r1 + blt 1b + mov pc, lr + +/* + * cpu_arm920_dcache_clean_range(start, end) + * + * For the specified virtual address range, ensure that all caches contain + * clean data, such that peripheral accesses to the physical RAM fetch + * correct data. + * + * start: virtual start address + * end: virtual end address + */ + .align 5 +ENTRY(cpu_arm920_dcache_clean_range) + bic r0, r0, #DCACHELINESIZE - 1 + sub r1, r1, r0 + cmp r1, #MAX_AREA_SIZE + mov r2, #0 + bgt cpu_arm920_cache_clean_invalidate_all_r2 + +1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry + add r0, r0, #DCACHELINESIZE + mcr p15, 0, r0, c7, c10, 1 @ clean D entry + add r0, r0, #DCACHELINESIZE + subs r1, r1, #2 * DCACHELINESIZE + bpl 1b + mcr p15, 0, r2, c7, c10, 4 @ drain WB + mov pc, lr + +/* + * cpu_arm920_dcache_clean_page(page) + * + * Cleans a single page of dcache so that if we have any future aliased + * mappings, they will be consistent at the time that they are created. + * + * page: virtual address of page to clean from dcache + * + * Note: + * 1. we don't need to flush the write buffer in this case. + * 2. we don't invalidate the entries since when we write the page + * out to disk, the entries may get reloaded into the cache. + */ + .align 5 +ENTRY(cpu_arm920_dcache_clean_page) +#ifndef CONFIG_CPU_ARM920_FORCE_WRITE_THROUGH + mov r1, #PAGESIZE +1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry + add r0, r0, #DCACHELINESIZE + mcr p15, 0, r0, c7, c10, 1 @ clean D entry + add r0, r0, #DCACHELINESIZE + subs r1, r1, #2 * DCACHELINESIZE + bne 1b +#endif + mov pc, lr + +/* + * cpu_arm920_dcache_clean_entry(addr) + * + * Clean the specified entry of any caches such that the MMU + * translation fetches will obtain correct data. + * + * addr: cache-unaligned virtual address + */ + .align 5 +ENTRY(cpu_arm920_dcache_clean_entry) +#ifndef CONFIG_CPU_ARM920_FORCE_WRITE_THROUGH + mcr p15, 0, r0, c7, c10, 1 @ clean D entry +#endif + mcr p15, 0, r0, c7, c10, 4 @ drain WB + mov pc, lr + +/* ================================ I-CACHE =============================== */ + +/* + * cpu_arm920_icache_invalidate_range(start, end) + * + * invalidate a range of virtual addresses from the Icache + * + * start: virtual start address + * end: virtual end address + */ + .align 5 +ENTRY(cpu_arm920_icache_invalidate_range) +1: mcr p15, 0, r0, c7, c10, 1 @ Clean D entry + add r0, r0, #DCACHELINESIZE + cmp r0, r1 + blo 1b + mov r0, #0 + mcr p15, 0, r0, c7, c10, 4 @ drain WB +ENTRY(cpu_arm920_icache_invalidate_page) + /* why no invalidate I cache --rmk */ + mov pc, lr + + +/* ================================== TLB ================================= */ + +/* + * cpu_arm920_tlb_invalidate_all() + * + * Invalidate all TLB entries + */ + .align 5 +ENTRY(cpu_arm920_tlb_invalidate_all) + mov r0, #0 + mcr p15, 0, r0, c7, c10, 4 @ drain WB + mcr p15, 0, r0, c8, c7, 0 @ invalidate I & D TLBs + mov pc, lr + +/* + * cpu_arm920_tlb_invalidate_range(start, end) + * + * invalidate TLB entries covering the specified range + * + * start: range start address + * end: range end address + */ + .align 5 +ENTRY(cpu_arm920_tlb_invalidate_range) + mov r3, #0 + mcr p15, 0, r3, c7, c10, 4 @ drain WB +1: mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry + mcr p15, 0, r0, c8, c5, 1 @ invalidate I TLB entry + add r0, r0, #PAGESIZE + cmp r0, r1 + blt 1b + mov pc, lr + +/* + * cpu_arm920_tlb_invalidate_page(page, flags) + * + * invalidate the TLB entries for the specified page. + * + * page: page to invalidate + * flags: non-zero if we include the I TLB + */ + .align 5 +ENTRY(cpu_arm920_tlb_invalidate_page) + mov r3, #0 + mcr p15, 0, r3, c7, c10, 4 @ drain WB + teq r1, #0 + mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry + mcrne p15, 0, r0, c8, c5, 1 @ invalidate I TLB entry + mov pc, lr + +/* =============================== PageTable ============================== */ + +/* + * cpu_arm920_set_pgd(pgd) + * + * Set the translation base pointer to be as described by pgd. + * + * pgd: new page tables + */ + .align 5 +ENTRY(cpu_arm920_set_pgd) + mov ip, #0 +#ifdef CONFIG_CPU_ARM920_FORCE_WRITE_THROUGH + /* Any reason why we don't use mcr p15, 0, r0, c7, c7, 0 here? --rmk */ + mcr p15, 0, ip, c7, c6, 0 @ invalidate D cache +#else +@ && 'Clean & Invalidate whole DCache' +@ && Re-written to use Index Ops. +@ && Uses registers r1, r3 and ip + + mov r1, #7 << 5 @ 8 segments +1: orr r3, r1, #63 << 26 @ 64 entries +2: mcr p15, 0, r3, c7, c14, 2 @ clean & invalidate D index + subs r3, r3, #1 << 26 + bcs 2b @ entries 63 to 0 + subs r1, r1, #1 << 5 + bcs 1b @ segments 7 to 0 +#endif + mcr p15, 0, ip, c7, c5, 0 @ invalidate I cache + mcr p15, 0, ip, c7, c10, 4 @ drain WB + mcr p15, 0, r0, c2, c0, 0 @ load page table pointer + mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs + mov pc, lr + +/* + * cpu_arm920_set_pmd(pmdp, pmd) + * + * Set a level 1 translation table entry, and clean it out of + * any caches such that the MMUs can load it correctly. + * + * pmdp: pointer to PMD entry + * pmd: PMD value to store + */ + .align 5 +ENTRY(cpu_arm920_set_pmd) +#ifdef CONFIG_CPU_ARM920_FORCE_WRITE_THROUGH + eor r2, r1, #0x0a @ C & Section + tst r2, #0x0b + biceq r1, r1, #4 @ clear bufferable bit +#endif + str r1, [r0] + mcr p15, 0, r0, c7, c10, 1 @ clean D entry + mcr p15, 0, r0, c7, c10, 4 @ drain WB + mov pc, lr + +/* + * cpu_arm920_set_pte(ptep, pte) + * + * Set a PTE and flush it out + */ + .align 5 +ENTRY(cpu_arm920_set_pte) + str r1, [r0], #-1024 @ linux version + + eor r1, r1, #LPTE_PRESENT | LPTE_YOUNG | LPTE_WRITE | LPTE_DIRTY + + bic r2, r1, #0xff0 + bic r2, r2, #3 + orr r2, r2, #HPTE_TYPE_SMALL + + tst r1, #LPTE_USER | LPTE_EXEC @ User or Exec? + orrne r2, r2, #HPTE_AP_READ + + tst r1, #LPTE_WRITE | LPTE_DIRTY @ Write and Dirty? + orreq r2, r2, #HPTE_AP_WRITE + + tst r1, #LPTE_PRESENT | LPTE_YOUNG @ Present and Young? + movne r2, #0 + +#ifdef CONFIG_CPU_ARM920_FORCE_WRITE_THROUGH + eor r3, r1, #0x0a @ C & small page? + tst r3, #0x0b + biceq r2, r2, #4 +#endif + str r2, [r0] @ hardware version + mov r0, r0 + mcr p15, 0, r0, c7, c10, 1 @ clean D entry + mcr p15, 0, r0, c7, c10, 4 @ drain WB + mov pc, lr + + +cpu_manu_name: + .asciz "ARM/VLSI" +ENTRY(cpu_arm920_name) + .ascii "Arm920" +#if defined(CONFIG_CPU_ARM920_CPU_IDLE) + .ascii "s" +#endif +#if defined(CONFIG_CPU_ARM920_I_CACHE_ON) + .ascii "i" +#endif +#if defined(CONFIG_CPU_ARM920_D_CACHE_ON) + .ascii "d" +#if defined(CONFIG_CPU_ARM920_FORCE_WRITE_THROUGH) + .ascii "(wt)" +#else + .ascii "(wb)" +#endif +#endif + .ascii "\0" + .align + + .section ".text.init", #alloc, #execinstr + +__arm920_setup: + mov r0, #0 + mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4 + mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4 + mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4 + mcr p15, 0, r4, c2, c0 @ load page table pointer + mov r0, #0x1f @ Domains 0, 1 = client + mcr p15, 0, r0, c3, c0 @ load domain access register + mrc p15, 0, r0, c1, c0 @ get control register v4 +/* + * Clear out 'unwanted' bits (then put them in if we need them) + */ + bic r0, r0, #0x0e00 @ ....??r......... + bic r0, r0, #0x0002 @ ..............a. + bic r0, r0, #0x000c @ W,D + bic r0, r0, #0x1000 @ I +/* + * Turn on what we want + */ + orr r0, r0, #0x0031 @ ..........DP...M + orr r0, r0, #0x0100 @ .......S........ + +#ifdef CONFIG_CPU_ARM920_D_CACHE_ON + orr r0, r0, #0x0004 @ Enable D cache +#endif +#ifdef CONFIG_CPU_ARM920_I_CACHE_ON + orr r0, r0, #0x1000 @ I Cache on +#endif + mov pc, lr + + .text + +/* + * Purpose : Function pointers used to access above functions - all calls + * come through these + */ + .type arm920_processor_functions, #object +arm920_processor_functions: + .word cpu_arm920_data_abort + .word cpu_arm920_check_bugs + .word cpu_arm920_proc_init + .word cpu_arm920_proc_fin + .word cpu_arm920_reset + .word cpu_arm920_do_idle + + /* cache */ + .word cpu_arm920_cache_clean_invalidate_all + .word cpu_arm920_cache_clean_invalidate_range + .word cpu_arm920_flush_ram_page + + /* dcache */ + .word cpu_arm920_dcache_invalidate_range + .word cpu_arm920_dcache_clean_range + .word cpu_arm920_dcache_clean_page + .word cpu_arm920_dcache_clean_entry + + /* icache */ + .word cpu_arm920_icache_invalidate_range + .word cpu_arm920_icache_invalidate_page + + /* tlb */ + .word cpu_arm920_tlb_invalidate_all + .word cpu_arm920_tlb_invalidate_range + .word cpu_arm920_tlb_invalidate_page + + /* pgtable */ + .word cpu_arm920_set_pgd + .word cpu_arm920_set_pmd + .word cpu_arm920_set_pte + .size arm920_processor_functions, . - arm920_processor_functions + + .type cpu_arm920_info, #object +cpu_arm920_info: + .long cpu_manu_name + .long cpu_arm920_name + .size cpu_arm920_info, . - cpu_arm920_info + + .type cpu_arch_name, #object +cpu_arch_name: + .asciz "armv4" + .size cpu_arch_name, . - cpu_arch_name + + .type cpu_elf_name, #object +cpu_elf_name: + .asciz "v4" + .size cpu_elf_name, . - cpu_elf_name + .align + + .section ".proc.info", #alloc, #execinstr + + .type __arm920_proc_info,#object +__arm920_proc_info: + .long 0x41009200 + .long 0xff00fff0 + .long 0x00000c1e @ mmuflags + b __arm920_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT + .long cpu_arm920_info + .long arm920_processor_functions + .size __arm920_proc_info, . - __arm920_proc_info diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/mm/proc-sa110.S linux/arch/arm/mm/proc-sa110.S --- v2.4.0-test8/linux/arch/arm/mm/proc-sa110.S Sun Aug 13 09:54:15 2000 +++ linux/arch/arm/mm/proc-sa110.S Mon Sep 18 15:15:25 2000 @@ -1,15 +1,21 @@ /* - * linux/arch/arm/mm/proc-sa110.S: MMU functions for SA110 + * linux/arch/arm/mm/proc-sa110.S * - * (C) 1997-2000 Russell King + * Copyright (C) 1997-2000 Russell King * - * These are the low level assembler for performing cache and TLB - * functions on the StrongARM-110, StrongARM-1100 and StrongARM-1110. + * 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. + * + * MMU functions for SA110 + * + * These are the low level assembler for performing cache and TLB + * functions on the StrongARM-110, StrongARM-1100 and StrongARM-1110. * - * Note that SA1100 and SA1110 share everything but their name and CPU ID. + * Note that SA1100 and SA1110 share everything but their name and CPU ID. * - * 12-jun-2000, Erik Mouw (J.A.K.Mouw@its.tudelft.nl): - * Flush the read buffer at context switches + * 12-jun-2000, Erik Mouw (J.A.K.Mouw@its.tudelft.nl): + * Flush the read buffer at context switches */ #include #include @@ -21,24 +27,35 @@ * is larger than this, then we flush the whole cache */ #define MAX_AREA_SIZE 32768 + +/* + * the cache line size of the I and D cache + */ +#define DCACHELINESIZE 32 + +/* + * and the page size + */ +#define PAGESIZE 4096 + #define FLUSH_OFFSET 32768 .macro flush_110_dcache rd, ra, re add \re, \ra, #16384 @ only necessary for 16k -1001: ldr \rd, [\ra], #32 +1001: ldr \rd, [\ra], #DCACHELINESIZE teq \re, \ra bne 1001b .endm .macro flush_1100_dcache rd, ra, re add \re, \ra, #8192 @ only necessary for 8k -1001: ldr \rd, [\ra], #32 +1001: ldr \rd, [\ra], #DCACHELINESIZE teq \re, \ra bne 1001b #ifdef FLUSH_BASE_MINICACHE add \ra, \ra, #FLUSH_BASE_MINICACHE - FLUSH_BASE add \re, \ra, #512 @ only 512 bytes -1002: ldr \rd, [\ra], #32 +1002: ldr \rd, [\ra], #DCACHELINESIZE teq \re, \ra bne 1002b #endif @@ -48,610 +65,705 @@ Lclean_switch: .long 0 .text + /* - * Function: sa110_flush_cache_all (void) - * Purpose : Flush all cache lines - */ - .align 5 -ENTRY(cpu_sa110_flush_cache_all) @ preserves r0 - mov r2, #1 -cpu_sa110_flush_cache_all_r2: - ldr r3, =Lclean_switch - ldr ip, =FLUSH_BASE - ldr r1, [r3] - ands r1, r1, #1 - eor r1, r1, #1 - str r1, [r3] - addne ip, ip, #FLUSH_OFFSET - flush_110_dcache r3, ip, r1 - mov ip, #0 - teq r2, #0 - mcrne p15, 0, ip, c7, c5, 0 @ flush I cache - mcr p15, 0, ip, c7, c10, 4 @ drain WB - mov pc, lr - - .align 5 -ENTRY(cpu_sa1100_flush_cache_all) @ preserves r0 - mov r2, #1 -cpu_sa1100_flush_cache_all_r2: - ldr r3, =Lclean_switch - ldr ip, =FLUSH_BASE - ldr r1, [r3] - ands r1, r1, #1 - eor r1, r1, #1 - str r1, [r3] - addne ip, ip, #FLUSH_OFFSET - flush_1100_dcache r3, ip, r1 - mov ip, #0 - teq r2, #0 - mcrne p15, 0, ip, c7, c5, 0 @ flush I cache - mcr p15, 0, r1, c9, c0, 0 @ flush RB - mcr p15, 0, ip, c7, c10, 4 @ drain WB - mov pc, lr - -/* - * Function: sa110_flush_cache_area (unsigned long address, int end, int flags) - * Params : address Area start address - * : end Area end address - * : flags b0 = I cache as well - * Purpose : clean & flush all cache lines associated with this area of memory - */ - .align 5 -ENTRY(cpu_sa110_flush_cache_area) - sub r3, r1, r0 - cmp r3, #MAX_AREA_SIZE - bgt cpu_sa110_flush_cache_all_r2 -1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry - mcr p15, 0, r0, c7, c6, 1 @ flush D entry - add r0, r0, #32 - mcr p15, 0, r0, c7, c10, 1 @ clean D entry - mcr p15, 0, r0, c7, c6, 1 @ flush D entry - add r0, r0, #32 - cmp r0, r1 - blt 1b - teq r2, #0 - movne r0, #0 - mcrne p15, 0, r0, c7, c5, 0 @ flush I cache - mov pc, lr - -ENTRY(cpu_sa1100_flush_cache_area) - sub r3, r1, r0 - cmp r3, #MAX_AREA_SIZE - bgt cpu_sa1100_flush_cache_all_r2 - b 1b - -/* - * Function: sa110_cache_wback_area(unsigned long address, unsigned long end) - * Params : address Area start address - * : end Area end address - * Purpose : ensure all dirty cachelines in the specified area have been - * written out to memory (for DMA) - */ - .align 5 -ENTRY(cpu_sa110_cache_wback_area) - sub r3, r1, r0 - cmp r3, #MAX_AREA_SIZE - mov r2, #0 - bgt cpu_sa110_flush_cache_all_r2 - bic r0, r0, #31 -1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry - add r0, r0, #32 - mcr p15, 0, r0, c7, c10, 1 @ clean D entry - add r0, r0, #32 - cmp r0, r1 - blt 1b - mcr p15, 0, r2, c7, c10, 4 @ drain WB - mov pc, lr - -ENTRY(cpu_sa1100_cache_wback_area) - sub r3, r1, r0 - cmp r3, #MAX_AREA_SIZE - mov r2, #0 - bgt cpu_sa1100_flush_cache_all_r2 - bic r0, r0, #31 - b 1b -/* - * Function: sa110_cache_purge_area(unsigned long address, unsigned long end) - * Params : address Area start address - * : end Area end address - * Purpose : throw away all D-cached data in specified region without - * an obligation to write it back. - * Note : Must clean the D-cached entries around the boundaries if the - * start and/or end address are not cache aligned. - */ - .align 5 -ENTRY(cpu_sa110_cache_purge_area) -ENTRY(cpu_sa1100_cache_purge_area) - tst r0, #31 - bic r0, r0, #31 - mcrne p15, 0, r0, c7, c10, 1 @ clean D entry - tst r1, #31 - mcrne p15, 0, r1, c7, c10, 1 @ clean D entry -1: mcr p15, 0, r0, c7, c6, 1 @ flush D entry - add r0, r0, #32 - cmp r0, r1 - blt 1b - mov pc, lr - -/* - * Function: sa110_flush_cache_entry (unsigned long address) - * Params : address Address of cache line to flush - * Purpose : clean & flush an entry - */ - .align 5 -ENTRY(cpu_sa110_flush_cache_entry) -ENTRY(cpu_sa1100_flush_cache_entry) - mov r1, #0 - mcr p15, 0, r0, c7, c10, 1 @ clean D entry - mcr p15, 0, r1, c7, c10, 4 @ drain WB - mcr p15, 0, r1, c7, c5, 0 @ flush I cache - mov pc, lr - -/* - * Function: sa110_clean_cache_area(unsigned long start, unsigned long size) - * Params : address Address of cache line to clean - * Purpose : Ensure that physical memory reflects cache at this location - * for page table purposes. - */ -ENTRY(cpu_sa110_clean_cache_area) -ENTRY(cpu_sa1100_clean_cache_area) -1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry (drain is done by TLB fns) - add r0, r0, #32 - subs r1, r1, #32 - bhi 1b - mov pc, lr - -/* - * Function: sa110_flush_ram_page (unsigned long page) - * Params : page Area start address - * Purpose : clean all cache lines associated with this area of memory - */ - .align 5 -ENTRY(cpu_sa110_flush_ram_page) -ENTRY(cpu_sa1100_flush_ram_page) - mov r1, #4096 -1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry - add r0, r0, #32 - mcr p15, 0, r0, c7, c10, 1 @ clean D entry - add r0, r0, #32 - mcr p15, 0, r0, c7, c10, 1 @ clean D entry - add r0, r0, #32 - mcr p15, 0, r0, c7, c10, 1 @ clean D entry - add r0, r0, #32 - subs r1, r1, #128 - bne 1b - mov r0, #0 - mcr p15, 0, r0, c7, c10, 4 @ drain WB - mov pc, lr - -/* - * Function: sa110_flush_tlb_all (void) - * Purpose : flush all TLB entries in all caches - */ - .align 5 -ENTRY(cpu_sa110_flush_tlb_all) -ENTRY(cpu_sa1100_flush_tlb_all) - mov ip, #0 - mcr p15, 0, ip, c7, c10, 4 @ drain WB - mcr p15, 0, ip, c8, c7, 0 @ flush I & D tlbs - mov pc, lr - -/* - * Function: sa110_flush_tlb_area (unsigned long address, unsigned long end, int flags) - * Params : address Area start address - * : end Area end address - * : flags b0 = I-TLB as well - * Purpose : flush a TLB entry - */ - .align 5 -ENTRY(cpu_sa110_flush_tlb_area) -ENTRY(cpu_sa1100_flush_tlb_area) - mov r3, #0 - mcr p15, 0, r3, c7, c10, 4 @ drain WB -1: cmp r0, r1 - mcrlt p15, 0, r0, c8, c6, 1 @ flush D TLB entry - addlt r0, r0, #4096 - cmp r0, r1 - mcrlt p15, 0, r0, c8, c6, 1 @ flush D TLB entry - addlt r0, r0, #4096 - blt 1b - teq r2, #0 - mcrne p15, 0, r3, c8, c5, 0 @ flush I TLB - mov pc, lr - -/* - * Function: sa110_flush_tlb_page (unsigned long address, int flags) - * Params : address Address to flush - * : flags b0 = I-TLB as well - * Purpose : flush a TLB entry - */ - .align 5 -ENTRY(cpu_sa110_flush_tlb_page) -ENTRY(cpu_sa1100_flush_tlb_page) - mov r3, #0 - mcr p15, 0, r3, c7, c10, 4 @ drain WB - mcr p15, 0, r0, c8, c6, 1 @ flush D TLB entry - teq r1, #0 - mcrne p15, 0, r3, c8, c5, 0 @ flush I TLB - mov pc, lr - -/* - * Function: sa110_flush_icache_area (unsigned long address, unsigned long size) - * Params : address Address of area to flush - * : size Size of area to flush - * Purpose : flush an area from the Icache - */ - .align 5 -ENTRY(cpu_sa110_flush_icache_area) -ENTRY(cpu_sa1100_flush_icache_area) -1: mcr p15, 0, r0, c7, c10, 1 @ Clean D entry - add r0, r0, #32 - subs r1, r1, #32 - bhi 1b - mov r0, #0 - mcr p15, 0, r0, c7, c10, 4 @ drain WB - mcr p15, 0, r0, c7, c5, 0 @ flush I cache - mov pc, lr - - .align 5 -ENTRY(cpu_sa110_flush_icache_page) -ENTRY(cpu_sa1100_flush_icache_page) - mcr p15, 0, r0, c7, c5, 0 @ flush I cache - mov pc, lr - -/* - * Function: sa110_data_abort () - * Params : r0 = address of aborted instruction - * Purpose : obtain information about current aborted instruction - * Returns : r0 = address of abort - * : r1 != 0 if writing - * : r3 = FSR + * cpu_sa110_data_abort() + * + * obtain information about current aborted instruction + * + * r0 = address of aborted instruction + * + * Returns: + * r0 = address of abort + * r1 != 0 if writing + * r3 = FSR */ - .align 5 + .align 5 ENTRY(cpu_sa110_data_abort) ENTRY(cpu_sa1100_data_abort) - ldr r1, [r0] @ read instruction causing problem - mrc p15, 0, r0, c6, c0, 0 @ get FAR - mov r1, r1, lsr #19 @ b1 = L - mrc p15, 0, r3, c5, c0, 0 @ get FSR - and r1, r1, #2 - and r3, r3, #255 - mov pc, lr - - .align 5 -/* - * Function: sa110_set_pgd(unsigned long pgd_phys) - * Params : pgd_phys Physical address of page table - * Purpose : Perform a task switch, saving the old processes state, and restoring - * the new. + ldr r1, [r0] @ read aborted instruction + mrc p15, 0, r0, c6, c0, 0 @ get FAR + mov r1, r1, lsr #19 @ b1 = L + mrc p15, 0, r3, c5, c0, 0 @ get FSR + and r1, r1, #2 + and r3, r3, #255 + mov pc, lr + +/* + * cpu_sa110_check_bugs() */ - .align 5 -ENTRY(cpu_sa110_set_pgd) - ldr r3, =Lclean_switch - ldr ip, =FLUSH_BASE - ldr r2, [r3] - ands r2, r2, #1 - eor r2, r2, #1 - str r2, [r3] - addne ip, ip, #FLUSH_OFFSET - flush_110_dcache r3, ip, r1 - mov r1, #0 - mcr p15, 0, r1, c7, c5, 0 @ flush I cache - mcr p15, 0, r1, c7, c10, 4 @ drain WB - mcr p15, 0, r0, c2, c0, 0 @ load page table pointer - mcr p15, 0, r1, c8, c7, 0 @ flush TLBs - mov pc, lr +ENTRY(cpu_sa110_check_bugs) +ENTRY(cpu_sa1100_check_bugs) + mrs ip, cpsr + bic ip, ip, #F_BIT + msr cpsr, ip + mov pc, lr - .align 5 -ENTRY(cpu_sa1100_set_pgd) - ldr r3, =Lclean_switch - ldr ip, =FLUSH_BASE - ldr r2, [r3] - ands r2, r2, #1 - eor r2, r2, #1 - str r2, [r3] - addne ip, ip, #FLUSH_OFFSET - flush_1100_dcache r3, ip, r1 - mov r1, #0 - mcr p15, 0, r1, c7, c5, 0 @ flush I cache - mcr p15, 0, r1, c9, c0, 0 @ flush RB - mcr p15, 0, r1, c7, c10, 4 @ drain WB - mcr p15, 0, r0, c2, c0, 0 @ load page table pointer - mcr p15, 0, r1, c8, c7, 0 @ flush TLBs - mov pc, lr - -/* - * Function: sa110_set_pmd(pmd_t *pmdp, pmd_t pmd) - * Params : r0 = Address to set - * : r1 = value to set - * Purpose : Set a PMD and flush it out +/* + * cpu_sa110_proc_init() */ - .align 5 -ENTRY(cpu_sa110_set_pmd) -ENTRY(cpu_sa1100_set_pmd) - str r1, [r0] - mcr p15, 0, r0, c7, c10, 1 @ clean D entry - mcr p15, 0, r0, c7, c10, 4 @ drain WB - mov pc, lr +ENTRY(cpu_sa110_proc_init) +ENTRY(cpu_sa1100_proc_init) + mov r0, #0 + mcr p15, 0, r0, c15, c1, 2 @ Enable clock switching + mov pc, lr /* - * Function: sa110_set_pte(pte_t *ptep, pte_t pte) - * Params : r0 = Address to set - * : r1 = value to set - * Purpose : Set a PTE and flush it out + * cpu_sa110_proc_fin() */ - .align 5 -ENTRY(cpu_sa110_set_pte) -ENTRY(cpu_sa1100_set_pte) - str r1, [r0], #-1024 @ linux version +ENTRY(cpu_sa110_proc_fin) + stmfd sp!, {lr} + mov ip, #F_BIT | I_BIT | SVC_MODE + msr cpsr_c, ip + bl cpu_sa110_cache_clean_invalidate_all @ clean caches +1: mov r0, #0 + mcr p15, 0, r0, c15, c2, 2 @ Disable clock switching + mrc p15, 0, r0, c1, c0, 0 @ ctrl register + bic r0, r0, #0x1000 @ ...i............ + bic r0, r0, #0x000e @ ............wca. + mcr p15, 0, r0, c1, c0, 0 @ disable caches + ldmfd sp!, {pc} - eor r1, r1, #LPTE_PRESENT | LPTE_YOUNG | LPTE_WRITE | LPTE_DIRTY +ENTRY(cpu_sa1100_proc_fin) + stmfd sp!, {lr} + mov ip, #F_BIT | I_BIT | SVC_MODE + msr cpsr_c, ip + bl cpu_sa1100_cache_clean_invalidate_all @ clean caches + b 1b - bic r2, r1, #0xff0 - bic r2, r2, #3 - orr r2, r2, #HPTE_TYPE_SMALL +/* + * cpu_sa110_reset(loc) + * + * Perform a soft reset of the system. Put the CPU into the + * same state as it would be if it had been reset, and branch + * to what would be the reset vector. + * + * loc: location to jump to for soft reset + */ + .align 5 +ENTRY(cpu_sa110_reset) +ENTRY(cpu_sa1100_reset) + mov ip, #0 + mcr p15, 0, ip, c7, c7, 0 @ invalidate I,D caches + mcr p15, 0, ip, c7, c10, 4 @ drain WB + mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs + mrc p15, 0, ip, c1, c0, 0 @ ctrl register + bic ip, ip, #0x000f @ ............wcam + bic ip, ip, #0x1100 @ ...i...s........ + mcr p15, 0, ip, c1, c0, 0 @ ctrl register + mov pc, r0 - tst r1, #LPTE_USER | LPTE_EXEC @ User or Exec? - orrne r2, r2, #HPTE_AP_READ +/* + * cpu_sa110_do_idle(type) + * + * Cause the processor to idle + * + * type: call type: + * 0 = slow idle + * 1 = fast idle + * 2 = switch to slow processor clock + * 3 = switch to fast processor clock + */ + .align 5 +idle: mcr p15, 0, r0, c15, c8, 2 @ Wait for interrupt, cache aligned + mov r0, r0 @ safety + mov pc, lr - tst r1, #LPTE_WRITE | LPTE_DIRTY @ Write and Dirty? - orreq r2, r2, #HPTE_AP_WRITE +ENTRY(cpu_sa110_do_idle) + mov ip, #0 + cmp r0, #4 + addcc pc, pc, r0, lsl #2 + mov pc, lr + + b idle + b idle + b slow_clock + b fast_clock + +fast_clock: + mcr p15, 0, ip, c15, c1, 2 @ enable clock switching + mov pc, lr + +slow_clock: + mcr p15, 0, ip, c15, c2, 2 @ disable clock switching + ldr r1, =UNCACHEABLE_ADDR @ load from uncacheable loc + ldr r1, [r1, #0] @ force switch to MCLK + mov pc, lr + + .align 5 +ENTRY(cpu_sa1100_do_idle) + mov r0, r0 @ 4 nop padding + mov r0, r0 + mov r0, r0 + mov r0, #0 + ldr r1, =UNCACHEABLE_ADDR @ ptr to uncacheable address + mrs r2, cpsr + orr r3, r2, #192 @ disallow interrupts + msr cpsr_c, r3 + @ --- aligned to a cache line + mcr p15, 0, r0, c15, c2, 2 @ disable clock switching + ldr r1, [r1, #0] @ force switch to MCLK + mcr p15, 0, r0, c15, c8, 2 @ wait for interrupt + mov r0, r0 @ safety + mcr p15, 0, r0, c15, c1, 2 @ enable clock switching + msr cpsr_c, r2 @ allow interrupts + mov pc, lr - tst r1, #LPTE_PRESENT | LPTE_YOUNG @ Present and Young? - movne r2, #0 +/* ================================= CACHE ================================ */ - str r2, [r0] @ hardware version - mov r0, r0 - mcr p15, 0, r0, c7, c10, 1 @ clean D entry - mcr p15, 0, r0, c7, c10, 4 @ drain WB - mov pc, lr /* - * Function: sa110_check_bugs (void) - * : sa110_proc_init (void) - * : sa110_proc_fin (void) - * Notes : This processor does not require these + * cpu_sa110_cache_clean_invalidate_all (void) + * + * clean and invalidate all cache lines + * + * Note: + * 1. we should preserve r0 at all times */ -ENTRY(cpu_sa110_check_bugs) -ENTRY(cpu_sa1100_check_bugs) - mrs ip, cpsr - bic ip, ip, #F_BIT - msr cpsr, ip - mov pc, lr + .align 5 +ENTRY(cpu_sa110_cache_clean_invalidate_all) + mov r2, #1 +cpu_sa110_cache_clean_invalidate_all_r2: + ldr r3, =Lclean_switch + ldr ip, =FLUSH_BASE + ldr r1, [r3] + ands r1, r1, #1 + eor r1, r1, #1 + str r1, [r3] + addne ip, ip, #FLUSH_OFFSET + flush_110_dcache r3, ip, r1 + mov ip, #0 + teq r2, #0 + mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache + mcr p15, 0, ip, c7, c10, 4 @ drain WB + mov pc, lr + + .align 5 +ENTRY(cpu_sa1100_cache_clean_invalidate_all) + mov r2, #1 +cpu_sa1100_cache_clean_invalidate_all_r2: + ldr r3, =Lclean_switch + ldr ip, =FLUSH_BASE + ldr r1, [r3] + ands r1, r1, #1 + eor r1, r1, #1 + str r1, [r3] + addne ip, ip, #FLUSH_OFFSET + flush_1100_dcache r3, ip, r1 + mov ip, #0 + teq r2, #0 + mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache + mcr p15, 0, r1, c9, c0, 0 @ invalidate RB + mcr p15, 0, ip, c7, c10, 4 @ drain WB + mov pc, lr -ENTRY(cpu_sa110_proc_init) -ENTRY(cpu_sa1100_proc_init) - mov r0, #0 - mcr p15, 0, r0, c15, c1, 2 @ Enable clock switching - mov pc, lr +/* + * cpu_sa110_cache_clean_invalidate_range(start, end, flags) + * + * clean and invalidate all cache lines associated with this area of memory + * + * start: Area start address + * end: Area end address + * flags: nonzero for I cache as well + */ + .align 5 +ENTRY(cpu_sa110_cache_clean_invalidate_range) + bic r0, r0, #DCACHELINESIZE - 1 + sub r3, r1, r0 + cmp r3, #MAX_AREA_SIZE + bgt cpu_sa110_cache_clean_invalidate_all_r2 +1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry + mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry + add r0, r0, #DCACHELINESIZE + mcr p15, 0, r0, c7, c10, 1 @ clean D entry + mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry + add r0, r0, #DCACHELINESIZE + cmp r0, r1 + blt 1b + teq r2, #0 + movne r0, #0 + mcrne p15, 0, r0, c7, c5, 0 @ invalidate I cache + mov pc, lr + +ENTRY(cpu_sa1100_cache_clean_invalidate_range) + sub r3, r1, r0 + cmp r3, #MAX_AREA_SIZE + bgt cpu_sa1100_cache_clean_invalidate_all_r2 + b 1b -ENTRY(cpu_sa110_proc_fin) - stmfd sp!, {r1, lr} - mov ip, #F_BIT | I_BIT | SVC_MODE - msr cpsr_c, ip - bl cpu_sa110_flush_cache_all @ clean caches -1: mov r0, #0 - mcr p15, 0, r0, c15, c2, 2 @ Disable clock switching - mrc p15, 0, r0, c1, c0, 0 - bic r0, r0, #0x1000 @ ...i............ - bic r0, r0, #0x000e @ ............wca. - mcr p15, 0, r0, c1, c0, 0 @ disable caches - ldmfd sp!, {r1, pc} +/* + * cpu_sa110_flush_ram_page(page) + * + * clean and invalidate all cache lines associated with this area of memory + * + * page: page to clean and invalidate + */ + .align 5 +ENTRY(cpu_sa110_flush_ram_page) +ENTRY(cpu_sa1100_flush_ram_page) + mov r1, #PAGESIZE +1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry + add r0, r0, #DCACHELINESIZE + mcr p15, 0, r0, c7, c10, 1 @ clean D entry + add r0, r0, #DCACHELINESIZE + subs r1, r1, #2 * DCACHELINESIZE + bne 1b + mcr p15, 0, r1, c7, c10, 4 @ drain WB + mov pc, lr -ENTRY(cpu_sa1100_proc_fin) - stmfd sp!, {r1, lr} - mov ip, #F_BIT | I_BIT | SVC_MODE - msr cpsr_c, ip - bl cpu_sa1100_flush_cache_all @ clean caches - b 1b - - - .align 5 -idle: mcr p15, 0, r0, c15, c8, 2 @ Wait for interrupt, cache aligned - mov r0, r0 @ safety - mov pc, lr -/* - * Function: *_do_idle - * Params : r0 = call type: - * 0 = slow idle - * 1 = fast idle - * 2 = switch to slow processor clock - * 3 = switch to fast processor clock +/* ================================ D-CACHE =============================== */ + +/* + * cpu_sa110_dcache_invalidate_range(start, end) + * + * throw away all D-cached data in specified region without an obligation + * to write them back. Note however that we must clean the D-cached entries + * around the boundaries if the start and/or end address are not cache + * aligned. + * + * start: virtual start address + * end: virtual end address */ -ENTRY(cpu_sa110_do_idle) -ENTRY(cpu_sa1100_do_idle) - mov ip, #0 - cmp r0, #4 - addcc pc, pc, r0, lsl #2 - mov pc, lr - - b idle - b idle - b slow_clock - b fast_clock - -fast_clock: mcr p15, 0, ip, c15, c1, 2 @ enable clock switching - mov pc, lr - -slow_clock: mcr p15, 0, ip, c15, c2, 2 @ disable clock switching - ldr r1, =UNCACHEABLE_ADDR @ load from uncacheable loc - ldr r1, [r1, #0] @ force switch to MCLK - mov pc, lr - -/* - * Function: sa110_reset - * Params : r0 = address to jump to - * Notes : This sets up everything for a reset + .align 5 +ENTRY(cpu_sa110_dcache_invalidate_range) +ENTRY(cpu_sa1100_dcache_invalidate_range) + tst r0, #DCACHELINESIZE - 1 + bic r0, r0, #DCACHELINESIZE - 1 + mcrne p15, 0, r0, c7, c10, 1 @ clean D entry + tst r1, #DCACHELINESIZE - 1 + mcrne p15, 0, r1, c7, c10, 1 @ clean D entry +1: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry + add r0, r0, #DCACHELINESIZE + cmp r0, r1 + blt 1b + mov pc, lr + +/* + * cpu_sa110_dcache_clean_range(start, end) + * + * For the specified virtual address range, ensure that all caches contain + * clean data, such that peripheral accesses to the physical RAM fetch + * correct data. + * + * start: virtual start address + * end: virtual end address */ - .align 5 -ENTRY(cpu_sa110_reset) -ENTRY(cpu_sa1100_reset) - mov ip, #0 - mcr p15, 0, ip, c7, c7, 0 @ flush I,D caches - mcr p15, 0, ip, c7, c10, 4 @ drain WB - mcr p15, 0, ip, c8, c7, 0 @ flush I & D tlbs - mrc p15, 0, ip, c1, c0, 0 @ ctrl register - bic ip, ip, #0x000f @ ............wcam - bic ip, ip, #0x1100 @ ...i...s........ - mcr p15, 0, ip, c1, c0, 0 @ ctrl register - mov pc, r0 + .align 5 +ENTRY(cpu_sa110_dcache_clean_range) + bic r0, r0, #DCACHELINESIZE - 1 + sub r1, r1, r0 + cmp r1, #MAX_AREA_SIZE + mov r2, #0 + bgt cpu_sa110_cache_clean_invalidate_all_r2 +1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry + add r0, r0, #DCACHELINESIZE + mcr p15, 0, r0, c7, c10, 1 @ clean D entry + add r0, r0, #DCACHELINESIZE + subs r1, r1, #2 * DCACHELINESIZE + bpl 1b + mcr p15, 0, r2, c7, c10, 4 @ drain WB + mov pc, lr + +ENTRY(cpu_sa1100_dcache_clean_range) + bic r0, r0, #DCACHELINESIZE - 1 + sub r1, r1, r0 + cmp r1, #MAX_AREA_SIZE + mov r2, #0 + bgt cpu_sa1100_cache_clean_invalidate_all_r2 + b 1b + +/* + * cpu_sa110_clean_dcache_page(page) + * + * Cleans a single page of dcache so that if we have any future aliased + * mappings, they will be consistent at the time that they are created. + * + * Note: + * 1. we don't need to flush the write buffer in this case. + * 2. we don't invalidate the entries since when we write the page + * out to disk, the entries may get reloaded into the cache. + */ + .align 5 +ENTRY(cpu_sa110_dcache_clean_page) +ENTRY(cpu_sa1100_dcache_clean_page) + mov r1, #PAGESIZE +1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry + add r0, r0, #DCACHELINESIZE + mcr p15, 0, r0, c7, c10, 1 @ clean D entry + add r0, r0, #DCACHELINESIZE + subs r1, r1, #2 * DCACHELINESIZE + bne 1b + mov pc, lr + +/* + * cpu_sa110_dcache_clean_entry(addr) + * + * Clean the specified entry of any caches such that the MMU + * translation fetches will obtain correct data. + * + * addr: cache-unaligned virtual address + */ + .align 5 +ENTRY(cpu_sa110_dcache_clean_entry) +ENTRY(cpu_sa1100_dcache_clean_entry) + mcr p15, 0, r0, c7, c10, 1 @ clean D entry + mcr p15, 0, r0, c7, c10, 4 @ drain WB + mov pc, lr + +/* ================================ I-CACHE =============================== */ + +/* + * cpu_sa110_icache_invalidate_range(start, end) + * + * invalidate a range of virtual addresses from the Icache + * + * start: virtual start address + * end: virtual end address + */ + .align 5 +ENTRY(cpu_sa110_icache_invalidate_range) +ENTRY(cpu_sa1100_icache_invalidate_range) +1: mcr p15, 0, r0, c7, c10, 1 @ Clean D entry + add r0, r0, #DCACHELINESIZE + cmp r0, r1 + blo 1b + mov r0, #0 + mcr p15, 0, r0, c7, c10, 4 @ drain WB +ENTRY(cpu_sa110_icache_invalidate_page) +ENTRY(cpu_sa1100_icache_invalidate_page) + mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache + mov pc, lr + +/* ================================== TLB ================================= */ + +/* + * cpu_sa110_tlb_invalidate_all() + * + * Invalidate all TLB entries + */ + .align 5 +ENTRY(cpu_sa110_tlb_invalidate_all) +ENTRY(cpu_sa1100_tlb_invalidate_all) + mov r0, #0 + mcr p15, 0, r0, c7, c10, 4 @ drain WB + mcr p15, 0, r0, c8, c7, 0 @ invalidate I & D TLBs + mov pc, lr + +/* + * cpu_sa110_tlb_invalidate_range(start, end) + * + * invalidate TLB entries covering the specified range + * + * start: range start address + * end: range end address + */ + .align 5 +ENTRY(cpu_sa110_tlb_invalidate_range) +ENTRY(cpu_sa1100_tlb_invalidate_range) + mov r3, #0 + mcr p15, 0, r3, c7, c10, 4 @ drain WB +1: mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry + add r0, r0, #PAGESIZE + cmp r0, r1 + blt 1b + mcr p15, 0, r3, c8, c5, 0 @ invalidate I TLB + mov pc, lr + +/* + * cpu_sa110_tlb_invalidate_page(page, flags) + * + * invalidate the TLB entries for the specified page. + * + * page: page to invalidate + * flags: non-zero if we include the I TLB + */ + .align 5 +ENTRY(cpu_sa110_tlb_invalidate_page) +ENTRY(cpu_sa1100_tlb_invalidate_page) + mov r3, #0 + mcr p15, 0, r3, c7, c10, 4 @ drain WB + teq r1, #0 + mcr p15, 0, r0, c8, c6, 1 @ invalidate D TLB entry + mcrne p15, 0, r3, c8, c5, 0 @ invalidate I TLB + mov pc, lr + +/* =============================== PageTable ============================== */ + +/* + * cpu_sa110_set_pgd(pgd) + * + * Set the translation base pointer to be as described by pgd. + * + * pgd: new page tables + */ + .align 5 +ENTRY(cpu_sa110_set_pgd) + ldr r3, =Lclean_switch + ldr ip, =FLUSH_BASE + ldr r2, [r3] + ands r2, r2, #1 + eor r2, r2, #1 + str r2, [r3] + addne ip, ip, #FLUSH_OFFSET + flush_110_dcache r3, ip, r1 + mov r1, #0 + mcr p15, 0, r1, c7, c5, 0 @ invalidate I cache + mcr p15, 0, r1, c7, c10, 4 @ drain WB + mcr p15, 0, r0, c2, c0, 0 @ load page table pointer + mcr p15, 0, r1, c8, c7, 0 @ invalidate I & D TLBs + mov pc, lr + +/* + * cpu_sa1100_set_pgd(pgd) + * + * Set the translation base pointer to be as described by pgd. + * + * pgd: new page tables + */ + .align 5 +ENTRY(cpu_sa1100_set_pgd) + ldr r3, =Lclean_switch + ldr ip, =FLUSH_BASE + ldr r2, [r3] + ands r2, r2, #1 + eor r2, r2, #1 + str r2, [r3] + addne ip, ip, #FLUSH_OFFSET + flush_1100_dcache r3, ip, r1 + mov ip, #0 + mcr p15, 0, ip, c7, c5, 0 @ invalidate I cache + mcr p15, 0, ip, c9, c0, 0 @ invalidate RB + mcr p15, 0, ip, c7, c10, 4 @ drain WB + mcr p15, 0, r0, c2, c0, 0 @ load page table pointer + mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs + mov pc, lr +/* + * cpu_sa110_set_pmd(pmdp, pmd) + * + * Set a level 1 translation table entry, and clean it out of + * any caches such that the MMUs can load it correctly. + * + * pmdp: pointer to PMD entry + * pmd: PMD value to store + */ + .align 5 +ENTRY(cpu_sa110_set_pmd) +ENTRY(cpu_sa1100_set_pmd) + str r1, [r0] + mcr p15, 0, r0, c7, c10, 1 @ clean D entry + mcr p15, 0, r0, c7, c10, 4 @ drain WB + mov pc, lr -cpu_manu_name: .asciz "Intel" -cpu_sa110_name: .asciz "StrongARM-110" +/* + * cpu_sa110_arm920_set_pte(ptep, pte) + * + * Set a PTE and flush it out + */ + .align 5 +ENTRY(cpu_sa110_set_pte) +ENTRY(cpu_sa1100_set_pte) + str r1, [r0], #-1024 @ linux version + + eor r1, r1, #LPTE_PRESENT | LPTE_YOUNG | LPTE_WRITE | LPTE_DIRTY + + bic r2, r1, #0xff0 + bic r2, r2, #3 + orr r2, r2, #HPTE_TYPE_SMALL + + tst r1, #LPTE_USER | LPTE_EXEC @ User or Exec? + orrne r2, r2, #HPTE_AP_READ + + tst r1, #LPTE_WRITE | LPTE_DIRTY @ Write and Dirty? + orreq r2, r2, #HPTE_AP_WRITE + + tst r1, #LPTE_PRESENT | LPTE_YOUNG @ Present and Young? + movne r2, #0 + + str r2, [r0] @ hardware version + mov r0, r0 + mcr p15, 0, r0, c7, c10, 1 @ clean D entry + mcr p15, 0, r0, c7, c10, 4 @ drain WB + mov pc, lr + + +cpu_manu_name: + .asciz "Intel" +cpu_sa110_name: + .asciz "StrongARM-110" cpu_sa1100_name: - .asciz "StrongARM-1100" + .asciz "StrongARM-1100" cpu_sa1110_name: - .asciz "StrongARM-1110" - .align + .asciz "StrongARM-1110" + .align - .section ".text.init", #alloc, #execinstr + .section ".text.init", #alloc, #execinstr __sa1100_setup: @ Allow read-buffer operations from userland - mcr p15, 0, r0, c9, c0, 5 + mcr p15, 0, r0, c9, c0, 5 -__sa110_setup: mov r0, #F_BIT | I_BIT | SVC_MODE - msr cpsr_c, r0 - 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 - mcr p15, 0, r4, c2, c0 @ load page table pointer - mov r0, #0x1f @ Domains 0, 1 = client - mcr p15, 0, r0, c3, c0 @ load domain access register - mrc p15, 0, r0, c1, c0 @ get control register v4 - bic r0, r0, #0x0e00 @ ....??r......... - bic r0, r0, #0x0002 @ ..............a. - orr r0, r0, #0x003d @ ..........DPWC.M - orr r0, r0, #0x1100 @ ...I...S........ - mov pc, lr +__sa110_setup: + mov r0, #F_BIT | I_BIT | SVC_MODE + msr cpsr_c, r0 + mov r0, #0 + mcr p15, 0, r0, c7, c7 @ invalidate I,D caches on v4 + mcr p15, 0, r0, c7, c10, 4 @ drain write buffer on v4 + mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4 + mcr p15, 0, r4, c2, c0 @ load page table pointer + mov r0, #0x1f @ Domains 0, 1 = client + mcr p15, 0, r0, c3, c0 @ load domain access register + mrc p15, 0, r0, c1, c0 @ get control register v4 + bic r0, r0, #0x0e00 @ ....??r......... + bic r0, r0, #0x0002 @ ..............a. + orr r0, r0, #0x003d @ ..........DPWC.M + orr r0, r0, #0x1100 @ ...I...S........ + mov pc, lr - .text + .text /* * Purpose : Function pointers used to access above functions - all calls * come through these */ - .type sa110_processor_functions, #object + .type sa110_processor_functions, #object ENTRY(sa110_processor_functions) - .word cpu_sa110_data_abort - .word cpu_sa110_check_bugs - .word cpu_sa110_proc_init - .word cpu_sa110_proc_fin - .word cpu_sa110_flush_cache_all - .word cpu_sa110_flush_cache_area - .word cpu_sa110_flush_cache_entry - .word cpu_sa110_clean_cache_area - .word cpu_sa110_flush_ram_page - .word cpu_sa110_flush_tlb_all - .word cpu_sa110_flush_tlb_area - .word cpu_sa110_set_pgd - .word cpu_sa110_set_pmd - .word cpu_sa110_set_pte - .word cpu_sa110_reset - .word cpu_sa110_flush_icache_area - .word cpu_sa110_cache_wback_area - .word cpu_sa110_cache_purge_area - .word cpu_sa110_flush_tlb_page - .word cpu_sa110_do_idle - .word cpu_sa110_flush_icache_page - .size sa110_processor_functions, . - sa110_processor_functions + .word cpu_sa110_data_abort + .word cpu_sa110_check_bugs + .word cpu_sa110_proc_init + .word cpu_sa110_proc_fin + .word cpu_sa110_reset + .word cpu_sa110_do_idle + + /* cache */ + .word cpu_sa110_cache_clean_invalidate_all + .word cpu_sa110_cache_clean_invalidate_range + .word cpu_sa110_flush_ram_page + + /* dcache */ + .word cpu_sa110_dcache_invalidate_range + .word cpu_sa110_dcache_clean_range + .word cpu_sa110_dcache_clean_page + .word cpu_sa110_dcache_clean_entry + + /* icache */ + .word cpu_sa110_icache_invalidate_range + .word cpu_sa110_icache_invalidate_page + + /* tlb */ + .word cpu_sa110_tlb_invalidate_all + .word cpu_sa110_tlb_invalidate_range + .word cpu_sa110_tlb_invalidate_page + + /* pgtable */ + .word cpu_sa110_set_pgd + .word cpu_sa110_set_pmd + .word cpu_sa110_set_pte + .size sa110_processor_functions, . - sa110_processor_functions - .type cpu_sa110_info, #object + .type cpu_sa110_info, #object cpu_sa110_info: - .long cpu_manu_name - .long cpu_sa110_name - .size cpu_sa110_info, . - cpu_sa110_info + .long cpu_manu_name + .long cpu_sa110_name + .size cpu_sa110_info, . - cpu_sa110_info /* * SA1100 and SA1110 share the same function calls */ - .type sa1100_processor_functions, #object + .type sa1100_processor_functions, #object ENTRY(sa1100_processor_functions) - .word cpu_sa1100_data_abort - .word cpu_sa1100_check_bugs - .word cpu_sa1100_proc_init - .word cpu_sa1100_proc_fin - .word cpu_sa1100_flush_cache_all - .word cpu_sa1100_flush_cache_area - .word cpu_sa1100_flush_cache_entry - .word cpu_sa1100_clean_cache_area - .word cpu_sa1100_flush_ram_page - .word cpu_sa1100_flush_tlb_all - .word cpu_sa1100_flush_tlb_area - .word cpu_sa1100_set_pgd - .word cpu_sa1100_set_pmd - .word cpu_sa1100_set_pte - .word cpu_sa1100_reset - .word cpu_sa1100_flush_icache_area - .word cpu_sa1100_cache_wback_area - .word cpu_sa1100_cache_purge_area - .word cpu_sa1100_flush_tlb_page - .word cpu_sa1100_do_idle - .word cpu_sa1100_flush_icache_page - .size sa1100_processor_functions, . - sa1100_processor_functions + .word cpu_sa1100_data_abort + .word cpu_sa1100_check_bugs + .word cpu_sa1100_proc_init + .word cpu_sa1100_proc_fin + .word cpu_sa1100_reset + .word cpu_sa1100_do_idle + + /* cache */ + .word cpu_sa1100_cache_clean_invalidate_all + .word cpu_sa1100_cache_clean_invalidate_range + .word cpu_sa1100_flush_ram_page + + /* dcache */ + .word cpu_sa1100_dcache_invalidate_range + .word cpu_sa1100_dcache_clean_range + .word cpu_sa1100_dcache_clean_page + .word cpu_sa1100_dcache_clean_entry + + /* icache */ + .word cpu_sa1100_icache_invalidate_range + .word cpu_sa1100_icache_invalidate_page + + /* tlb */ + .word cpu_sa1100_tlb_invalidate_all + .word cpu_sa1100_tlb_invalidate_range + .word cpu_sa1100_tlb_invalidate_page + + /* pgtable */ + .word cpu_sa1100_set_pgd + .word cpu_sa1100_set_pmd + .word cpu_sa1100_set_pte + .size sa1100_processor_functions, . - sa1100_processor_functions cpu_sa1100_info: - .long cpu_manu_name - .long cpu_sa1100_name - .size cpu_sa1100_info, . - cpu_sa1100_info + .long cpu_manu_name + .long cpu_sa1100_name + .size cpu_sa1100_info, . - cpu_sa1100_info cpu_sa1110_info: - .long cpu_manu_name - .long cpu_sa1110_name - .size cpu_sa1110_info, . - cpu_sa1110_info - + .long cpu_manu_name + .long cpu_sa1110_name + .size cpu_sa1110_info, . - cpu_sa1110_info + + .type cpu_arch_name, #object +cpu_arch_name: + .asciz "armv4" + .size cpu_arch_name, . - cpu_arch_name + + .type cpu_elf_name, #object +cpu_elf_name: + .asciz "v4" + .size cpu_elf_name, . - cpu_elf_name + .align - .type cpu_arch_name, #object -cpu_arch_name: .asciz "armv4" - .size cpu_arch_name, . - cpu_arch_name + .section ".proc.info", #alloc, #execinstr - .type cpu_elf_name, #object -cpu_elf_name: .asciz "v4" - .size cpu_elf_name, . - cpu_elf_name - .align - - .section ".proc.info", #alloc, #execinstr - - .type __sa110_proc_info,#object + .type __sa110_proc_info,#object __sa110_proc_info: - .long 0x4401a100 - .long 0xfffffff0 - .long 0x00000c02 - b __sa110_setup - .long cpu_arch_name - .long cpu_elf_name - .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT - .long cpu_sa110_info - .long sa110_processor_functions - .size __sa110_proc_info, . - __sa110_proc_info + .long 0x4401a100 + .long 0xfffffff0 + .long 0x00000c0e + b __sa110_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT + .long cpu_sa110_info + .long sa110_processor_functions + .size __sa110_proc_info, . - __sa110_proc_info - .type __sa1100_proc_info,#object + .type __sa1100_proc_info,#object __sa1100_proc_info: - .long 0x4401a110 - .long 0xfffffff0 - .long 0x00000c02 - b __sa1100_setup - .long cpu_arch_name - .long cpu_elf_name - .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT - .long cpu_sa1100_info - .long sa1100_processor_functions - .size __sa1100_proc_info, . - __sa1100_proc_info + .long 0x4401a110 + .long 0xfffffff0 + .long 0x00000c0e + b __sa1100_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT + .long cpu_sa1100_info + .long sa1100_processor_functions + .size __sa1100_proc_info, . - __sa1100_proc_info - .type __sa1110_proc_info,#object + .type __sa1110_proc_info,#object __sa1110_proc_info: - .long 0x6901b110 - .long 0xfffffff0 - .long 0x00000c02 - b __sa1100_setup - .long cpu_arch_name - .long cpu_elf_name - .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT - .long cpu_sa1110_info - .long sa1100_processor_functions - .size __sa1110_proc_info, . - __sa1110_proc_info - - + .long 0x6901b110 + .long 0xfffffff0 + .long 0x00000c0e + b __sa1100_setup + .long cpu_arch_name + .long cpu_elf_name + .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT + .long cpu_sa1110_info + .long sa1100_processor_functions + .size __sa1110_proc_info, . - __sa1110_proc_info diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/mm/proc-syms.c linux/arch/arm/mm/proc-syms.c --- v2.4.0-test8/linux/arch/arm/mm/proc-syms.c Wed Dec 31 16:00:00 1969 +++ linux/arch/arm/mm/proc-syms.c Mon Sep 18 15:15:25 2000 @@ -0,0 +1,31 @@ +/* + * linux/arch/arm/mm/proc-syms.c + * + * Copyright (C) 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 + +#ifndef MULTI_CPU +EXPORT_SYMBOL(cpu_cache_clean_invalidate_all); +EXPORT_SYMBOL(cpu_cache_clean_invalidate_range); +EXPORT_SYMBOL(cpu_flush_ram_page); +EXPORT_SYMBOL(cpu_dcache_clean_page); +EXPORT_SYMBOL(cpu_dcache_clean_entry); +EXPORT_SYMBOL(cpu_dcache_clean_range); +EXPORT_SYMBOL(cpu_dcache_invalidate_range); +EXPORT_SYMBOL(cpu_icache_invalidate_range); +EXPORT_SYMBOL(cpu_icache_invalidate_page); +EXPORT_SYMBOL(cpu_tlb_invalidate_all); +EXPORT_SYMBOL(cpu_tlb_invalidate_range); +EXPORT_SYMBOL(cpu_tlb_invalidate_page); +EXPORT_SYMBOL(cpu_set_pgd); +EXPORT_SYMBOL(cpu_set_pmd); +EXPORT_SYMBOL(cpu_set_pte); +#else +EXPORT_SYMBOL(processor); +#endif diff -u --recursive --new-file v2.4.0-test8/linux/arch/arm/mm/small_page.c linux/arch/arm/mm/small_page.c --- v2.4.0-test8/linux/arch/arm/mm/small_page.c Mon Aug 7 21:02:27 2000 +++ linux/arch/arm/mm/small_page.c Mon Sep 18 15:15:25 2000 @@ -3,12 +3,15 @@ * * Copyright (C) 1996 Russell King * - * Changelog: - * 26/01/1996 RMK Cleaned up various areas to make little more generic - * 07/02/1999 RMK Support added for 16K and 32K page sizes + * 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. + * + * Changelog: + * 26/01/1996 RMK Cleaned up various areas to make little more generic + * 07/02/1999 RMK Support added for 16K and 32K page sizes * containing 8K blocks */ - #include #include #include @@ -70,6 +73,8 @@ #define TEST_AND_CLEAR_USED(pg,off) (test_and_clear_bit(off, &USED_MAP(pg))) #define SET_USED(pg,off) (set_bit(off, &USED_MAP(pg))) +static spinlock_t small_page_lock = SPIN_LOCK_UNLOCKED; + static void add_page_to_queue(struct page *page, struct page **p) { #ifdef PEDANTIC @@ -99,11 +104,10 @@ struct page *page; int offset; - save_flags(flags); if (!order->queue) goto need_new_page; - cli(); + spin_lock_irqsave(&small_page_lock, flags); page = order->queue; again: #ifdef PEDANTIC @@ -114,12 +118,14 @@ SET_USED(page, offset); if (USED_MAP(page) == order->all_used) remove_page_from_queue(page); - restore_flags(flags); + spin_unlock_irqrestore(&small_page_lock, flags); return (unsigned long) page_address(page) + (offset << order->shift); need_new_page: page = alloc_page(priority); + + spin_lock_irqsave(&small_page_lock, flags); if (!order->queue) { if (!page) goto no_page; @@ -135,7 +141,7 @@ goto again; no_page: - restore_flags(flags); + spin_unlock_irqrestore(&small_page_lock, flags); return 0; } @@ -164,7 +170,7 @@ /* * the following must be atomic wrt get_page */ - save_flags_cli(flags); + spin_lock_irqsave(&small_page_lock, flags); if (USED_MAP(page) == order->all_used) add_page_to_queue(page, &order->queue); @@ -175,7 +181,7 @@ if (USED_MAP(page) == 0) goto free_page; - restore_flags(flags); + spin_unlock_irqrestore(&small_page_lock, flags); } return; @@ -184,7 +190,7 @@ * unlink the page from the small page queue and free it */ remove_page_from_queue(page); - restore_flags(flags); + spin_unlock_irqrestore(&small_page_lock, flags); ClearPageReserved(page); __free_page(page); return; diff -u --recursive --new-file v2.4.0-test8/linux/arch/i386/config.in linux/arch/i386/config.in --- v2.4.0-test8/linux/arch/i386/config.in Tue Aug 22 11:57:15 2000 +++ linux/arch/i386/config.in Tue Sep 19 10:57:30 2000 @@ -128,6 +128,7 @@ define_bool CONFIG_X86_USE_PPRO_CHECKSUM y define_bool CONFIG_X86_USE_3DNOW y fi +tristate 'Toshiba Laptop support' CONFIG_TOSHIBA tristate '/dev/cpu/microcode - Intel P6 CPU microcode support' CONFIG_MICROCODE tristate '/dev/cpu/*/msr - Model-specific register support' CONFIG_X86_MSR @@ -247,6 +248,8 @@ source drivers/pnp/Config.in source drivers/block/Config.in + +source drivers/md/Config.in if [ "$CONFIG_NET" = "y" ]; then source net/Config.in diff -u --recursive --new-file v2.4.0-test8/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v2.4.0-test8/linux/arch/i386/defconfig Sat Sep 2 11:45:00 2000 +++ linux/arch/i386/defconfig Mon Oct 2 12:48:34 2000 @@ -26,8 +26,8 @@ # CONFIG_M586 is not set # CONFIG_M586TSC is not set # CONFIG_M586MMX is not set -CONFIG_M686=y -# CONFIG_M686FXSR is not set +# CONFIG_M686 is not set +CONFIG_M686FXSR=y # CONFIG_MK6 is not set # CONFIG_MK7 is not set # CONFIG_MCRUSOE is not set @@ -44,13 +44,15 @@ CONFIG_X86_GOOD_APIC=y CONFIG_X86_PGE=y CONFIG_X86_USE_PPRO_CHECKSUM=y +CONFIG_X86_FXSR=y +CONFIG_X86_XMM=y +# CONFIG_TOSHIBA is not set # CONFIG_MICROCODE is not set # CONFIG_X86_MSR is not set # CONFIG_X86_CPUID is not set CONFIG_NOHIGHMEM=y # CONFIG_HIGHMEM4G is not set # CONFIG_HIGHMEM64G is not set -# CONFIG_MATH_EMULATION is not set # CONFIG_MTRR is not set CONFIG_SMP=y CONFIG_HAVE_DEC_LOCK=y @@ -112,17 +114,24 @@ # 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_LVM is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set # CONFIG_BLK_DEV_MD is not set # CONFIG_MD_LINEAR is not set # CONFIG_MD_RAID0 is not set # CONFIG_MD_RAID1 is not set # CONFIG_MD_RAID5 is not set -# CONFIG_BLK_DEV_RAM is not set -# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_BLK_DEV_LVM is not set +# CONFIG_LVM_PROC_FS is not set # # Networking options @@ -224,7 +233,6 @@ # CONFIG_BLK_DEV_SIS5513 is not set # CONFIG_BLK_DEV_TRM290 is not set # CONFIG_BLK_DEV_VIA82CXXX is not set -# CONFIG_VIA82CXXX_TUNING is not set # CONFIG_IDE_CHIPSETS is not set # CONFIG_IDEDMA_AUTO is not set # CONFIG_DMA_NONPCI is not set @@ -262,12 +270,12 @@ # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set # CONFIG_SCSI_AIC7XXX is not set -# CONFIG_SCSI_IPS is not set # CONFIG_SCSI_ADVANSYS is not set # CONFIG_SCSI_IN2000 is not set # CONFIG_SCSI_AM53C974 is not set # CONFIG_SCSI_MEGARAID is not set # CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_CPQFCTS is not set # CONFIG_SCSI_DMX3191D is not set # CONFIG_SCSI_DTC3280 is not set # CONFIG_SCSI_EATA is not set @@ -276,11 +284,10 @@ # CONFIG_SCSI_FUTURE_DOMAIN is not set # CONFIG_SCSI_GDTH is not set # CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_IPS is not set # CONFIG_SCSI_INITIO is not set # CONFIG_SCSI_INIA100 is not set # CONFIG_SCSI_NCR53C406A is not set -# CONFIG_SCSI_SYM53C416 is not set -# CONFIG_SCSI_SIM710 is not set # CONFIG_SCSI_NCR53C7xx is not set # CONFIG_SCSI_NCR53C8XX is not set CONFIG_SCSI_SYM53C8XX=y @@ -299,6 +306,8 @@ # CONFIG_SCSI_QLOGIC_FC is not set # CONFIG_SCSI_QLOGIC_1280 is not set # CONFIG_SCSI_SEAGATE is not set +# CONFIG_SCSI_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set # CONFIG_SCSI_DC390T is not set # CONFIG_SCSI_T128 is not set # CONFIG_SCSI_U14_34F is not set @@ -357,14 +366,18 @@ # CONFIG_NE2K_PCI is not set # CONFIG_8139TOO is not set # CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set # CONFIG_TLAN is not set # CONFIG_VIA_RHINE is not set +# CONFIG_WINBOND_840 is not set # CONFIG_NET_POCKET is not set # # Ethernet (1000 Mbit) # # CONFIG_ACENIC is not set +# CONFIG_HAMACHI is not set # CONFIG_SK98LIN is not set # CONFIG_FDDI is not set # CONFIG_PPP is not set @@ -584,12 +597,64 @@ # # Sound # -# CONFIG_SOUND is not set +CONFIG_SOUND=y +# CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_EMU10K1 is not set +# CONFIG_SOUND_FUSION is not set +# CONFIG_SOUND_CS4281 is not set +# CONFIG_SOUND_ES1370 is not set +CONFIG_SOUND_ES1371=y +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_MAESTRO is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_TRIDENT is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set +# CONFIG_SOUND_OSS is not set +# CONFIG_SOUND_TVMIXER is not set # # USB support # -# CONFIG_USB is not set +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +# CONFIG_USB_DEVICEFS is not set +# CONFIG_USB_BANDWIDTH is not set + +# +# USB Controllers +# +CONFIG_USB_UHCI_ALT=y +# CONFIG_USB_OHCI is not set + +# +# USB Devices +# +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_SCANNER is not set +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_SERIAL is not set +# CONFIG_USB_IBMCAM is not set +# CONFIG_USB_OV511 is not set +# CONFIG_USB_DC2XX is not set +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_USS720 is not set +# CONFIG_USB_DABUSB is not set + +# +# USB Human Interface Devices (HID) +# + +# +# Input core support is needed for USB HID +# # # Kernel hacking diff -u --recursive --new-file v2.4.0-test8/linux/arch/i386/kernel/Makefile linux/arch/i386/kernel/Makefile --- v2.4.0-test8/linux/arch/i386/kernel/Makefile Wed Jul 5 11:23:12 2000 +++ linux/arch/i386/kernel/Makefile Mon Sep 18 15:02:02 2000 @@ -18,7 +18,7 @@ obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \ ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_i386.o \ - pci-dma.o i386_ksyms.o i387.o + pci-dma.o i386_ksyms.o i387.o bluesmoke.o ifdef CONFIG_PCI diff -u --recursive --new-file v2.4.0-test8/linux/arch/i386/kernel/acpi.c linux/arch/i386/kernel/acpi.c --- v2.4.0-test8/linux/arch/i386/kernel/acpi.c Mon Jul 17 17:54:25 2000 +++ linux/arch/i386/kernel/acpi.c Sun Sep 17 09:41:29 2000 @@ -21,6 +21,12 @@ /* * See http://www.geocities.com/SiliconValley/Hardware/3165/ * for the user-level ACPI stuff + * + * Changes: + * Arnaldo Carvalho de Melo - 2000/08/31 + * - check copy*user return + * - get rid of check_region + * - get rid of verify_area */ #include @@ -135,8 +141,7 @@ *len = 0; return 0; } - copy_to_user(buffer, str, size); - return 0; + return copy_to_user(buffer, str, size) ? -EFAULT : 0; } static void cx_statistics(unsigned int x, unsigned long time) @@ -1283,11 +1288,9 @@ */ static int acpi_claim(unsigned long start, unsigned long size) { - if (start && size) { - if (check_region(start, size)) + if (start && size) + if (!request_region(start, size, "acpi")) return -EBUSY; - request_region(start, size, "acpi"); - } return 0; } @@ -1391,7 +1394,8 @@ val = *(unsigned long*) ctl->data; size = sprintf(str, "0x%08lx\n", val); if (*len >= size) { - copy_to_user(buffer, str, size); + if (copy_to_user(buffer, str, size)) + return -EFAULT; *len = size; } else @@ -1404,7 +1408,8 @@ size = sizeof(str) - 1; if (size > *len) size = *len; - copy_from_user(str, buffer, size); + if (copy_from_user(str, buffer, size)) + return -EFAULT; str[size] = '\0'; val = simple_strtoul(str, &strend, 0); if (strend == str) @@ -1423,22 +1428,22 @@ size_t size, struct acpi_table_info *info) { + struct acpi_table hdr; + size_t table_size; + if (size < sizeof(struct acpi_table)) return -EINVAL; - else if (verify_area(VERIFY_READ, buffer, size)) + + if (copy_from_user(&hdr, buffer, sizeof(hdr))) return -EFAULT; - else { - struct acpi_table hdr; - size_t table_size; - copy_from_user(&hdr, buffer, sizeof(hdr)); - table_size = (size_t) hdr.length; - if (hdr.signature != info->expected_signature - || table_size < size - || (info->expected_size - && table_size != info->expected_size)) - return -EINVAL; - } + table_size = (size_t) hdr.length; + if (hdr.signature != info->expected_signature + || table_size < size + || (info->expected_size + && table_size != info->expected_size)) + return -EINVAL; + return 0; } @@ -1496,7 +1501,8 @@ error = acpi_verify_table(buffer, *len, info); if (error) return error; - copy_from_user(&hdr, buffer, sizeof(hdr)); + if (copy_from_user(&hdr, buffer, sizeof(hdr))) + return -EFAULT; table_size = (size_t) hdr.length; write_lock(&acpi_do_table_lock); @@ -1517,7 +1523,8 @@ error = -ENOMEM; } if (data) - copy_from_user(data, buffer, size); + if (copy_from_user(data, buffer, size)) + error = -EFAULT; write_unlock(&acpi_do_table_lock); } @@ -1565,7 +1572,8 @@ size = sprintf(str, "0x%08x\n", val); if (*len >= size) { - copy_to_user(buffer, str, size); + if (copy_to_user(buffer, str, size)) + return -EFAULT; *len = size; } else @@ -1580,7 +1588,8 @@ size = sizeof(str) - 1; if (size > *len) size = *len; - copy_from_user(str, buffer, size); + if (copy_from_user(str, buffer, size)) + return -EFAULT; str[size] = '\0'; val = (u32) simple_strtoul(str, &strend, 0); if (strend == str) @@ -1682,7 +1691,8 @@ pm1_status, gpe_status, event_state); - copy_to_user(buffer, str, size); + if (copy_to_user(buffer, str, size)) + return -EFAULT; *len = size; file->f_pos += size; diff -u --recursive --new-file v2.4.0-test8/linux/arch/i386/kernel/apic.c linux/arch/i386/kernel/apic.c --- v2.4.0-test8/linux/arch/i386/kernel/apic.c Mon Aug 28 11:57:29 2000 +++ linux/arch/i386/kernel/apic.c Sun Oct 1 20:35:15 2000 @@ -695,7 +695,7 @@ * [ if a single-CPU system runs an SMP kernel then we call the local * interrupt as well. Thus we cannot inline the local irq ... ] */ -unsigned int apic_timer_irqs [NR_CPUS] = { 0, }; +unsigned int apic_timer_irqs [NR_CPUS]; void smp_apic_timer_interrupt(struct pt_regs * regs) { diff -u --recursive --new-file v2.4.0-test8/linux/arch/i386/kernel/bluesmoke.c linux/arch/i386/kernel/bluesmoke.c --- v2.4.0-test8/linux/arch/i386/kernel/bluesmoke.c Wed Dec 31 16:00:00 1969 +++ linux/arch/i386/kernel/bluesmoke.c Tue Sep 19 08:31:53 2000 @@ -0,0 +1,109 @@ +/* + * Machine Check Handler For PII/PIII + */ + +#include +#include +#include +#include +#include + +static int banks = 0; + +void mcheck_fault(void) +{ + int recover=1; + u32 alow, ahigh, high, low; + u32 mcgstl, mcgsth; + int i; + + rdmsr(0x17a, mcgstl, mcgsth); + if(mcgstl&(1<<0)) /* Recoverable ? */ + recover=0; + + printk(KERN_EMERG "CPU %d: Machine Check Exception: %08x%08x\n", smp_processor_id(), mcgsth, mcgstl); + + for(i=0;ix86_vendor!=X86_VENDOR_INTEL) + return; + + if(!(c->x86_capability&X86_FEATURE_MCE)) + return; + + if(!(c->x86_capability&X86_FEATURE_MCA)) + return; + + /* Ok machine check is available */ + + if(done==0) + printk(KERN_INFO "Intel machine check architecture supported.\n"); + rdmsr(0x179, l, h); + if(l&(1<<8)) + wrmsr(0x17b, 0xffffffff, 0xffffffff); + banks = l&0xff; + for(i=1;i /* Have we found an MP table */ -int smp_found_config = 0; +int smp_found_config; /* * Various Linux-internal data structures created from the @@ -37,17 +37,17 @@ int apic_version [MAX_APICS]; int mp_bus_id_to_type [MAX_MP_BUSSES]; int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { -1, }; -int mp_current_pci_id = 0; +int mp_current_pci_id; int pic_mode; -unsigned long mp_lapic_addr = 0; +unsigned long mp_lapic_addr; /* Processor that is doing the boot up */ unsigned int boot_cpu_id = -1U; /* Internal processor count */ -static unsigned int num_processors = 0; +static unsigned int num_processors; /* Bitmask of physically existing CPUs */ -unsigned long phys_cpu_present_map = 0; +unsigned long phys_cpu_present_map; /* * Intel MP BIOS table parsing routines: diff -u --recursive --new-file v2.4.0-test8/linux/arch/i386/kernel/mtrr.c linux/arch/i386/kernel/mtrr.c --- v2.4.0-test8/linux/arch/i386/kernel/mtrr.c Wed Jul 12 21:58:41 2000 +++ linux/arch/i386/kernel/mtrr.c Sun Oct 1 20:35:15 2000 @@ -319,10 +319,10 @@ #endif #ifdef USERSPACE_INTERFACE -static char *ascii_buffer = NULL; -static unsigned int ascii_buf_bytes = 0; +static char *ascii_buffer; +static unsigned int ascii_buf_bytes; #endif -static unsigned int *usage_table = NULL; +static unsigned int *usage_table; static DECLARE_MUTEX(main_lock); /* Private functions */ @@ -356,7 +356,8 @@ if (boot_cpu_data.x86 >= 6) break; /* Athlon and post-Athlon CPUs */ /* else fall through */ case X86_VENDOR_CENTAUR: - return; + if(boot_cpu_data.x86 != 6) + return; /*break;*/ } /* Save value of CR4 and clear Page Global Enable (bit 7) */ @@ -380,6 +381,7 @@ { case X86_VENDOR_AMD: case X86_VENDOR_INTEL: + case X86_VENDOR_CENTAUR: /* Disable MTRRs, and set the default type to uncached */ rdmsr (MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi); wrmsr (MTRRdefType_MSR, ctxt->deftype_lo & 0xf300UL, ctxt->deftype_hi); @@ -403,8 +405,11 @@ if (boot_cpu_data.x86 >= 6) break; /* Athlon and post-Athlon CPUs */ /* else fall through */ case X86_VENDOR_CENTAUR: - __restore_flags (ctxt->flags); - return; + if(boot_cpu_data.x86 != 6) + { + __restore_flags (ctxt->flags); + return; + } /*break;*/ } /* Flush caches and TLBs */ @@ -415,6 +420,7 @@ { case X86_VENDOR_AMD: case X86_VENDOR_INTEL: + case X86_VENDOR_CENTAUR: wrmsr (MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi); break; case X86_VENDOR_CYRIX: @@ -453,9 +459,17 @@ /*break;*/ case X86_VENDOR_CYRIX: /* Cyrix have 8 ARRs */ + return 8; case X86_VENDOR_CENTAUR: /* and Centaur has 8 MCR's */ - return 8; + if(boot_cpu_data.x86==5) + return 8; + /* the cyrix III has intel compatible MTRR */ + if(boot_cpu_data.x86==6) + { + rdmsr (MTRRcap_MSR, config, dummy); + return (config & 0xff); + } /*break;*/ } return 0; @@ -471,12 +485,15 @@ case X86_VENDOR_AMD: if (boot_cpu_data.x86 < 6) return 1; /* pre-Athlon CPUs */ /* else fall through */ + case X86_VENDOR_CENTAUR: + if (boot_cpu_data.x86 == 5) + return 1; /* C6 */ + /* CyrixIII is Intel like */ case X86_VENDOR_INTEL: rdmsr (MTRRcap_MSR, config, dummy); return (config & (1<<10)); /*break;*/ case X86_VENDOR_CYRIX: - case X86_VENDOR_CENTAUR: return 1; /*break;*/ } @@ -623,7 +640,7 @@ } /* End Function centaur_get_mcr */ static void (*get_mtrr) (unsigned int reg, unsigned long *base, - unsigned long *size, mtrr_type *type) = NULL; + unsigned long *size, mtrr_type *type); static void intel_set_mtrr_up (unsigned int reg, unsigned long base, unsigned long size, mtrr_type type, int do_safe) @@ -766,7 +783,7 @@ static void (*set_mtrr_up) (unsigned int reg, unsigned long base, unsigned long size, mtrr_type type, - int do_safe) = NULL; + int do_safe); #ifdef CONFIG_SMP @@ -1194,7 +1211,7 @@ printk ("mtrr: size: %lx base: %lx\n", size, base); return -EINVAL; } - if (boot_cpu_data.x86_vendor == X86_VENDOR_CENTAUR) + if (boot_cpu_data.x86_vendor == X86_VENDOR_CENTAUR && boot_cpu_data.x86 == 5) { if (type != MTRR_TYPE_WRCOMB) { @@ -1779,8 +1796,16 @@ get_free_region = cyrix_get_free_region; break; case X86_VENDOR_CENTAUR: - get_mtrr = centaur_get_mcr; - set_mtrr_up = centaur_set_mcr_up; + if(boot_cpu_data.x86 == 5) + { + get_mtrr = centaur_get_mcr; + set_mtrr_up = centaur_set_mcr_up; + } + if(boot_cpu_data.x86 == 6) + { + get_mtrr = intel_get_mtrr; + set_mtrr_up = intel_set_mtrr_up; + } break; } } /* End Function mtrr_setup */ @@ -1804,8 +1829,11 @@ case X86_VENDOR_CYRIX: cyrix_arr_init (); break; - case X86_VENDOR_CENTAUR: - centaur_mcr_init (); + case X86_VENDOR_CENTAUR: /* C6 and Cyrix III have different ones */ + if(boot_cpu_data.x86 == 5) + centaur_mcr_init (); + if(boot_cpu_data.x86 == 6) + get_mtrr_state(&smp_mtrr_state); break; } } /* End Function mtrr_init_boot_cpu */ @@ -1877,7 +1905,8 @@ cyrix_arr_init (); break; case X86_VENDOR_CENTAUR: - centaur_mcr_init (); + if(boot_cpu_data.x86 == 5) + centaur_mcr_init (); break; } #endif /* !CONFIG_SMP */ diff -u --recursive --new-file v2.4.0-test8/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c --- v2.4.0-test8/linux/arch/i386/kernel/process.c Tue Sep 5 13:50:02 2000 +++ linux/arch/i386/kernel/process.c Sun Oct 1 20:35:15 2000 @@ -50,17 +50,17 @@ asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); -int hlt_counter=0; +int hlt_counter; /* * Powermanagement idle function, if any.. */ -void (*pm_idle)(void) = NULL; +void (*pm_idle)(void); /* * Power off function, if any */ -void (*pm_power_off)(void) = NULL; +void (*pm_power_off)(void); void disable_hlt(void) { @@ -149,9 +149,9 @@ __setup("idle=", idle_setup); -static long no_idt[2] = {0, 0}; -static int reboot_mode = 0; -static int reboot_thru_bios = 0; +static long no_idt[2]; +static int reboot_mode; +static int reboot_thru_bios; static int __init reboot_setup(char *str) { diff -u --recursive --new-file v2.4.0-test8/linux/arch/i386/kernel/ptrace.c linux/arch/i386/kernel/ptrace.c --- v2.4.0-test8/linux/arch/i386/kernel/ptrace.c Sat Sep 2 12:00:02 2000 +++ linux/arch/i386/kernel/ptrace.c Fri Sep 22 12:25:19 2000 @@ -100,10 +100,6 @@ value &= FLAG_MASK; value |= get_stack_long(child, EFL_OFFSET) & ~FLAG_MASK; break; - case EIP: - /* Mark us as not being in a system call, so that no restart issues happen */ - put_stack_long(child, 4*ORIG_EAX - sizeof(struct pt_regs), -1); - break; } if (regno > GS*4) regno -= 2*4; diff -u --recursive --new-file v2.4.0-test8/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c --- v2.4.0-test8/linux/arch/i386/kernel/setup.c Wed Sep 6 14:05:57 2000 +++ linux/arch/i386/kernel/setup.c Sun Oct 1 20:35:15 2000 @@ -95,22 +95,22 @@ * Machine setup.. */ -char ignore_irq13 = 0; /* set if exception 16 works */ +char ignore_irq13; /* set if exception 16 works */ struct cpuinfo_x86 boot_cpu_data = { 0, 0, 0, 0, -1, 1, 0, 0, -1 }; -unsigned long mmu_cr4_features = 0; +unsigned long mmu_cr4_features; /* * Bus types .. */ -int EISA_bus = 0; -int MCA_bus = 0; +int EISA_bus; +int MCA_bus; /* for MCA, but anyone else can use it if they want */ -unsigned int machine_id = 0; -unsigned int machine_submodel_id = 0; -unsigned int BIOS_revision = 0; -unsigned int mca_pentium_flag = 0; +unsigned int machine_id; +unsigned int machine_submodel_id; +unsigned int BIOS_revision; +unsigned int mca_pentium_flag; /* * Setup options @@ -123,7 +123,7 @@ unsigned char table[0]; }; -struct e820map e820 = { 0 }; +struct e820map e820; unsigned char aux_device_present; @@ -135,7 +135,7 @@ extern int root_mountflags; extern char _text, _etext, _edata, _end; -extern unsigned long cpu_hz; +extern unsigned long cpu_khz; /* * This is set up by the setup-routine at boot-time @@ -291,7 +291,7 @@ #endif -static char command_line[COMMAND_LINE_SIZE] = { 0, }; +static char command_line[COMMAND_LINE_SIZE]; char saved_command_line[COMMAND_LINE_SIZE]; struct resource standard_io_resources[] = { @@ -875,7 +875,8 @@ * Set MTRR capability flag if appropriate */ if(boot_cpu_data.x86 == 5) { - if((boot_cpu_data.x86_model == 9) || + if((boot_cpu_data.x86_model == 13) || + (boot_cpu_data.x86_model == 9) || ((boot_cpu_data.x86_model == 8) && (boot_cpu_data.x86_mask >= 8))) c->x86_capability |= X86_FEATURE_MTRR; @@ -916,7 +917,7 @@ } break; } - if (c->x86_model == 8 || c->x86_model == 9) + if (c->x86_model == 8 || c->x86_model == 9 || c->x86_model == 13) { /* The more serious chips .. */ @@ -1673,7 +1674,7 @@ if (c->x86_capability & X86_FEATURE_TSC) { p += sprintf(p, "cpu MHz\t\t: %lu.%06lu\n", - cpu_hz / 1000000, (cpu_hz % 1000000)); + cpu_khz / 1000, (cpu_khz % 1000)); } /* Cache size */ diff -u --recursive --new-file v2.4.0-test8/linux/arch/i386/kernel/signal.c linux/arch/i386/kernel/signal.c --- v2.4.0-test8/linux/arch/i386/kernel/signal.c Fri Sep 1 14:10:57 2000 +++ linux/arch/i386/kernel/signal.c Mon Sep 25 13:10:28 2000 @@ -690,6 +690,13 @@ } } + /* Reenable any watchpoints before delivering the + * signal to user space. The processor register will + * have been cleared if the watchpoint triggered + * inside the kernel. + */ + __asm__("movl %0,%%db7" : : "r" (current->thread.debugreg[7])); + /* Whee! Actually deliver the signal. */ handle_signal(signr, ka, &info, oldset, regs); return 1; diff -u --recursive --new-file v2.4.0-test8/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c --- v2.4.0-test8/linux/arch/i386/kernel/smp.c Tue Jul 25 09:17:20 2000 +++ linux/arch/i386/kernel/smp.c Sun Oct 1 19:55:17 2000 @@ -414,13 +414,15 @@ */ static spinlock_t call_lock = SPIN_LOCK_UNLOCKED; -static volatile struct call_data_struct { +struct call_data_struct { void (*func) (void *info); void *info; atomic_t started; atomic_t finished; int wait; -} *call_data = NULL; +}; + +static struct call_data_struct * call_data = NULL; /* * this function sends a 'generic call function' IPI to all other CPUs @@ -443,7 +445,7 @@ */ { struct call_data_struct data; - int ret, cpus = smp_num_cpus-1; + int cpus = smp_num_cpus-1; if (!cpus) return 0; @@ -464,7 +466,6 @@ while (atomic_read(&data.started) != cpus) barrier(); - ret = 0; if (wait) while (atomic_read(&data.finished) != cpus) barrier(); diff -u --recursive --new-file v2.4.0-test8/linux/arch/i386/kernel/smpboot.c linux/arch/i386/kernel/smpboot.c --- v2.4.0-test8/linux/arch/i386/kernel/smpboot.c Tue Sep 5 13:50:02 2000 +++ linux/arch/i386/kernel/smpboot.c Sun Oct 1 20:35:15 2000 @@ -46,7 +46,7 @@ #include /* Set if we find a B stepping CPU */ -static int smp_b_stepping = 0; +static int smp_b_stepping; /* Setup configured maximum number of CPUs to activate */ static int max_cpus = -1; @@ -55,21 +55,21 @@ int smp_num_cpus = 1; /* Bitmask of currently online CPUs */ -unsigned long cpu_online_map = 0; +unsigned long cpu_online_map; /* which CPU (physical APIC ID) maps to which logical CPU number */ volatile int x86_apicid_to_cpu[NR_CPUS]; /* which logical CPU number maps to which CPU (physical APIC ID) */ volatile int x86_cpu_to_apicid[NR_CPUS]; -static volatile unsigned long cpu_callin_map = 0; -static volatile unsigned long cpu_callout_map = 0; +static volatile unsigned long cpu_callin_map; +static volatile unsigned long cpu_callout_map; /* Per CPU bogomips and other parameters */ struct cpuinfo_x86 cpu_data[NR_CPUS]; /* Set when the idlers are all forked */ -int smp_threads_ready = 0; +int smp_threads_ready; /* * Setup routine for controlling SMP activation @@ -194,7 +194,7 @@ static atomic_t tsc_start_flag = ATOMIC_INIT(0); static atomic_t tsc_count_start = ATOMIC_INIT(0); static atomic_t tsc_count_stop = ATOMIC_INIT(0); -static unsigned long long tsc_values[NR_CPUS] = { 0, }; +static unsigned long long tsc_values[NR_CPUS]; #define NR_LOOPS 5 @@ -438,7 +438,7 @@ synchronize_tsc_ap(); } -int cpucount = 0; +int cpucount; extern int cpu_idle(void); @@ -774,7 +774,7 @@ } cycles_t cacheflush_time; -extern unsigned long cpu_hz; +extern unsigned long cpu_khz; static void smp_tune_scheduling (void) { @@ -791,7 +791,7 @@ * the cache size) */ - if (!cpu_hz) { + if (!cpu_khz) { /* * this basically disables processor-affinity * scheduling on SMP without a TSC. @@ -805,12 +805,12 @@ bandwidth = 100; } - cacheflush_time = (cpu_hz>>20) * (cachesize<<10) / bandwidth; + cacheflush_time = (cpu_khz>>10) * (cachesize<<10) / bandwidth; } printk("per-CPU timeslice cutoff: %ld.%02ld usecs.\n", - (long)cacheflush_time/(cpu_hz/1000000), - ((long)cacheflush_time*100/(cpu_hz/1000000)) % 100); + (long)cacheflush_time/(cpu_khz/1000), + ((long)cacheflush_time*100/(cpu_khz/1000)) % 100); } /* diff -u --recursive --new-file v2.4.0-test8/linux/arch/i386/kernel/time.c linux/arch/i386/kernel/time.c --- v2.4.0-test8/linux/arch/i386/kernel/time.c Mon Jul 10 14:33:03 2000 +++ linux/arch/i386/kernel/time.c Mon Sep 18 15:43:16 2000 @@ -64,7 +64,7 @@ #include -unsigned long cpu_hz; /* Detected as we calibrate the TSC */ +unsigned long cpu_khz; /* Detected as we calibrate the TSC */ /* Number of usecs that the last interrupt was delayed */ static int delay_at_last_interrupt; @@ -504,37 +504,6 @@ } -/* Converts Gregorian date to seconds since 1970-01-01 00:00:00. - * Assumes input in normal date format, i.e. 1980-12-31 23:59:59 - * => year=1980, mon=12, day=31, hour=23, min=59, sec=59. - * - * [For the Julian calendar (which was used in Russia before 1917, - * Britain & colonies before 1752, anywhere else before 1582, - * and is still in use by some communities) leave out the - * -year/100+year/400 terms, and add 10.] - * - * This algorithm was first published by Gauss (I think). - * - * WARNING: this function will overflow on 2106-02-07 06:28:16 on - * machines were long is 32-bit! (However, as time_t is signed, we - * will already get problems at other places on 2038-01-19 03:14:08) - */ -static inline unsigned long mktime(unsigned int year, unsigned int mon, - unsigned int day, unsigned int hour, - unsigned int min, unsigned int sec) -{ - if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */ - mon += 12; /* Puts Feb last since it has leap day */ - year -= 1; - } - return ((( - (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) + - year*365 - 719499 - )*24 + hour /* now have hours */ - )*60 + min /* now have minutes */ - )*60 + sec; /* finally seconds */ -} - /* not static: needed by APM */ unsigned long get_cmos_time(void) { @@ -707,12 +676,12 @@ * The formula is (10^6 * 2^32) / (2^32 * 1 / (clocks/us)) = * clock/second. Our precision is about 100 ppm. */ - { unsigned long eax=0, edx=1000000; + { unsigned long eax=0, edx=1000; __asm__("divl %2" - :"=a" (cpu_hz), "=d" (edx) + :"=a" (cpu_khz), "=d" (edx) :"r" (tsc_quotient), "0" (eax), "1" (edx)); - printk("Detected %ld Hz processor.\n", cpu_hz); + printk("Detected %lu.%03lu MHz processor.\n", cpu_khz / 1000, cpu_khz % 1000); } } } diff -u --recursive --new-file v2.4.0-test8/linux/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c --- v2.4.0-test8/linux/arch/i386/kernel/traps.c Wed Sep 6 13:51:55 2000 +++ linux/arch/i386/kernel/traps.c Mon Oct 2 11:57:01 2000 @@ -95,6 +95,7 @@ asmlinkage void reserved(void); asmlinkage void alignment_check(void); asmlinkage void spurious_interrupt_bug(void); +asmlinkage void machine_check(void); int kstack_depth_to_print = 24; @@ -415,8 +416,8 @@ * here too!] */ - static unsigned int last_irq_sums [NR_CPUS] = { 0, }, - alert_counter [NR_CPUS] = { 0, }; + static unsigned int last_irq_sums [NR_CPUS], + alert_counter [NR_CPUS]; /* * Since current-> is always on the stack, and we always switch @@ -491,17 +492,26 @@ } /* - * Careful - we must not do a lock-kernel until we have checked that the - * debug fault happened in user mode. Getting debug exceptions while - * in the kernel has to be handled without locking, to avoid deadlocks.. + * Our handling of the processor debug registers is non-trivial. + * We do not clear them on entry and exit from the kernel. Therefore + * it is possible to get a watchpoint trap here from inside the kernel. + * However, the code in ./ptrace.c has ensured that the user can + * only set watchpoints on userspace addresses. Therefore the in-kernel + * watchpoint trap can only occur in code which is reading/writing + * from user space. Such code must not hold kernel locks (since it + * can equally take a page fault), therefore it is safe to call + * force_sig_info even though that claims and releases locks. + * + * Code in ./signal.c ensures that the debug control register + * is restored before we deliver any signal, and therefore that + * user code runs with the correct debug control register even though + * we clear it here. * * Being careful here means that we don't have to be as careful in a * lot of more complicated places (task switching can be a bit lazy * about restoring all the debug state, and ptrace doesn't have to * find every occurrence of the TF bit that could be saved away even - * by user code - and we don't have to be careful about what values - * can be written to the debug registers because there are no really - * bad cases). + * by user code) */ asmlinkage void do_debug(struct pt_regs * regs, long error_code) { @@ -520,6 +530,9 @@ if (regs->eflags & VM_MASK) goto debug_vm86; + /* Save debug status register where ptrace can see it */ + tsk->thread.debugreg[6] = condition; + /* Mask out spurious TF errors due to lazy TF clearing */ if (condition & DR_STEP) { /* @@ -535,30 +548,33 @@ goto clear_TF; } - /* If this is a kernel mode trap, we need to reset db7 to allow us to continue sanely */ - if ((regs->xcs & 3) == 0) - goto clear_dr7; - /* Ok, finally something we can handle */ tsk->thread.trap_no = 1; tsk->thread.error_code = error_code; info.si_signo = SIGTRAP; info.si_errno = 0; info.si_code = TRAP_BRKPT; - info.si_addr = (void *)regs->eip; + + /* If this is a kernel mode trap, save the user PC on entry to + * the kernel, that's what the debugger can make sense of. + */ + info.si_addr = ((regs->xcs & 3) == 0) ? (void *)tsk->thread.eip : + (void *)regs->eip; force_sig_info(SIGTRAP, &info, tsk); - return; - -debug_vm86: - handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1); - return; + /* Disable additional traps. They'll be re-enabled when + * the signal is delivered. + */ clear_dr7: __asm__("movl %0,%%db7" : /* no output */ : "r" (0)); return; +debug_vm86: + handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1); + return; + clear_TF: regs->eflags &= ~TF_MASK; return; @@ -963,6 +979,7 @@ set_trap_gate(15,&spurious_interrupt_bug); set_trap_gate(16,&coprocessor_error); set_trap_gate(17,&alignment_check); + set_trap_gate(18,&machine_check); set_trap_gate(19,&simd_coprocessor_error); set_system_gate(SYSCALL_VECTOR,&system_call); diff -u --recursive --new-file v2.4.0-test8/linux/arch/i386/kernel/vm86.c linux/arch/i386/kernel/vm86.c --- v2.4.0-test8/linux/arch/i386/kernel/vm86.c Wed Jul 5 22:08:27 2000 +++ linux/arch/i386/kernel/vm86.c Sun Oct 1 20:35:15 2000 @@ -565,8 +565,8 @@ static struct vm86_irqs { struct task_struct *tsk; int sig; -} vm86_irqs[16] = {{0},}; -static int irqbits=0; +} vm86_irqs[16]; +static int irqbits; #define ALLOWED_SIGS ( 1 /* 0 = don't send a signal */ \ | (1 << SIGUSR1) | (1 << SIGUSR2) | (1 << SIGIO) | (1 << SIGURG) \ diff -u --recursive --new-file v2.4.0-test8/linux/arch/i386/mm/ioremap.c linux/arch/i386/mm/ioremap.c --- v2.4.0-test8/linux/arch/i386/mm/ioremap.c Mon Aug 7 21:02:27 2000 +++ linux/arch/i386/mm/ioremap.c Sun Oct 1 19:59:59 2000 @@ -126,7 +126,7 @@ t_addr = __va(phys_addr); t_end = t_addr + (size - 1); - for(page = virt_to_page(t_addr); page < virt_to_page(t_end); page++) + for(page = virt_to_page(t_addr); page <= virt_to_page(t_end); page++) if(!PageReserved(page)) return NULL; } diff -u --recursive --new-file v2.4.0-test8/linux/arch/ia64/config.in linux/arch/ia64/config.in --- v2.4.0-test8/linux/arch/ia64/config.in Tue Aug 22 11:41:14 2000 +++ linux/arch/ia64/config.in Tue Sep 19 10:57:30 2000 @@ -99,6 +99,7 @@ source drivers/pnp/Config.in source drivers/block/Config.in source drivers/i2o/Config.in +source drivers/md/Config.in mainmenu_option next_comment comment 'ATA/IDE/MFM/RLL support' diff -u --recursive --new-file v2.4.0-test8/linux/arch/ia64/kernel/efi.c linux/arch/ia64/kernel/efi.c --- v2.4.0-test8/linux/arch/ia64/kernel/efi.c Fri Aug 11 19:09:06 2000 +++ linux/arch/ia64/kernel/efi.c Mon Sep 11 08:39:48 2000 @@ -98,37 +98,6 @@ efi_call_phys(__va(runtime->reset_system), status, data_size, __pa(data)); } -/* - * Converts Gregorian date to seconds since 1970-01-01 00:00:00. - * Assumes input in normal date format, i.e. 1980-12-31 23:59:59 - * => year=1980, mon=12, day=31, hour=23, min=59, sec=59. - * - * [For the Julian calendar (which was used in Russia before 1917, - * Britain & colonies before 1752, anywhere else before 1582, - * and is still in use by some communities) leave out the - * -year/100+year/400 terms, and add 10.] - * - * This algorithm was first published by Gauss (I think). - * - * WARNING: this function will overflow on 2106-02-07 06:28:16 on - * machines were long is 32-bit! (However, as time_t is signed, we - * will already get problems at other places on 2038-01-19 03:14:08) - */ -static inline unsigned long -mktime (unsigned int year, unsigned int mon, unsigned int day, unsigned int hour, - unsigned int min, unsigned int sec) -{ - if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */ - mon += 12; /* Puts Feb last since it has leap day */ - year -= 1; - } - return ((((unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) - + year*365 - 719499 - )*24 + hour /* now have hours */ - )*60 + min /* now have minutes */ - )*60 + sec; /* finally seconds */ -} - void efi_gettimeofday (struct timeval *tv) { diff -u --recursive --new-file v2.4.0-test8/linux/arch/m68k/config.in linux/arch/m68k/config.in --- v2.4.0-test8/linux/arch/m68k/config.in Wed Jul 12 15:12:11 2000 +++ linux/arch/m68k/config.in Tue Sep 19 10:57:30 2000 @@ -149,6 +149,8 @@ source drivers/block/Config.in +source drivers/md/Config.in + if [ "$CONFIG_NET" = "y" ]; then source net/Config.in fi diff -u --recursive --new-file v2.4.0-test8/linux/arch/m68k/kernel/time.c linux/arch/m68k/kernel/time.c --- v2.4.0-test8/linux/arch/m68k/kernel/time.c Tue May 11 09:57:14 1999 +++ linux/arch/m68k/kernel/time.c Mon Sep 11 08:39:48 2000 @@ -102,37 +102,6 @@ #endif /* CONFIG_HEARTBEAT */ } -/* Converts Gregorian date to seconds since 1970-01-01 00:00:00. - * Assumes input in normal date format, i.e. 1980-12-31 23:59:59 - * => year=1980, mon=12, day=31, hour=23, min=59, sec=59. - * - * [For the Julian calendar (which was used in Russia before 1917, - * Britain & colonies before 1752, anywhere else before 1582, - * and is still in use by some communities) leave out the - * -year/100+year/400 terms, and add 10.] - * - * This algorithm was first published by Gauss (I think). - * - * WARNING: this function will overflow on 2106-02-07 06:28:16 on - * machines were long is 32-bit! (However, as time_t is signed, we - * will already get problems at other places on 2038-01-19 03:14:08) - */ -static inline unsigned long mktime(unsigned int year, unsigned int mon, - unsigned int day, unsigned int hour, - unsigned int min, unsigned int sec) -{ - if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */ - mon += 12; /* Puts Feb last since it has leap day */ - year -= 1; - } - return ((( - (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) + - year*365 - 719499 - )*24 + hour /* now have hours */ - )*60 + min /* now have minutes */ - )*60 + sec; /* finally seconds */ -} - void time_init(void) { unsigned int year, mon, day, hour, min, sec; diff -u --recursive --new-file v2.4.0-test8/linux/arch/m68k/mac/misc.c linux/arch/m68k/mac/misc.c --- v2.4.0-test8/linux/arch/m68k/mac/misc.c Tue Feb 15 22:39:01 2000 +++ linux/arch/m68k/mac/misc.c Mon Sep 11 08:39:48 2000 @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -497,37 +498,6 @@ sti(); printk ("Restart failed. Please restart manually.\n"); while(1); -} - -/* Converts Gregorian date to seconds since 1970-01-01 00:00:00. - * Assumes input in normal date format, i.e. 1980-12-31 23:59:59 - * => year=1980, mon=12, day=31, hour=23, min=59, sec=59. - * - * [For the Julian calendar (which was used in Russia before 1917, - * Britain & colonies before 1752, anywhere else before 1582, - * and is still in use by some communities) leave out the - * -year/100+year/400 terms, and add 10.] - * - * This algorithm was first published by Gauss (I think). - * - * WARNING: this function will overflow on 2106-02-07 06:28:16 on - * machines were long is 32-bit! (However, as time_t is signed, we - * will already get problems at other places on 2038-01-19 03:14:08) - */ -static unsigned long mktime(unsigned int year, unsigned int mon, - unsigned int day, unsigned int hour, - unsigned int min, unsigned int sec) -{ - if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */ - mon += 12; /* Puts Feb last since it has leap day */ - year -= 1; - } - return ((( - (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) + - year*365 - 719499 - )*24 + hour /* now have hours */ - )*60 + min /* now have minutes */ - )*60 + sec; /* finally seconds */ } /* diff -u --recursive --new-file v2.4.0-test8/linux/arch/mips/baget/vacserial.c linux/arch/mips/baget/vacserial.c --- v2.4.0-test8/linux/arch/mips/baget/vacserial.c Tue Jul 18 16:52:35 2000 +++ linux/arch/mips/baget/vacserial.c Sun Oct 1 20:35:15 2000 @@ -2843,7 +2843,7 @@ * device more directly. */ -static int initialized = 0; +static int initialized; static int rs_debug_init(struct async_struct *info) { diff -u --recursive --new-file v2.4.0-test8/linux/arch/mips/config.in linux/arch/mips/config.in --- v2.4.0-test8/linux/arch/mips/config.in Tue Aug 22 11:41:14 2000 +++ linux/arch/mips/config.in Tue Sep 19 10:57:30 2000 @@ -189,6 +189,8 @@ source drivers/block/Config.in +source drivers/md/Config.in + if [ "$CONFIG_NET" = "y" ]; then source net/Config.in fi diff -u --recursive --new-file v2.4.0-test8/linux/arch/mips/dec/time.c linux/arch/mips/dec/time.c --- v2.4.0-test8/linux/arch/mips/dec/time.c Wed Jul 12 15:14:41 2000 +++ linux/arch/mips/dec/time.c Mon Sep 11 08:39:48 2000 @@ -346,37 +346,6 @@ } } -/* Converts Gregorian date to seconds since 1970-01-01 00:00:00. - * Assumes input in normal date format, i.e. 1980-12-31 23:59:59 - * => year=1980, mon=12, day=31, hour=23, min=59, sec=59. - * - * [For the Julian calendar (which was used in Russia before 1917, - * Britain & colonies before 1752, anywhere else before 1582, - * and is still in use by some communities) leave out the - * -year/100+year/400 terms, and add 10.] - * - * This algorithm was first published by Gauss (I think). - * - * WARNING: this function will overflow on 2106-02-07 06:28:16 on - * machines were long is 32-bit! (However, as time_t is signed, we - * will already get problems at other places on 2038-01-19 03:14:08) - */ -static inline unsigned long mktime(unsigned int year, unsigned int mon, - unsigned int day, unsigned int hour, - unsigned int min, unsigned int sec) -{ - if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */ - mon += 12; /* Puts Feb last since it has leap day */ - year -= 1; - } - return ((( - (unsigned long) (year / 4 - year / 100 + year / 400 + 367 * mon / 12 + day) + - year * 365 - 719499 - ) * 24 + hour /* now have hours */ - ) * 60 + min /* now have minutes */ - ) * 60 + sec; /* finally seconds */ -} - char cyclecounter_available; static inline void init_cycle_counter(void) diff -u --recursive --new-file v2.4.0-test8/linux/arch/mips/kernel/gdb-stub.c linux/arch/mips/kernel/gdb-stub.c --- v2.4.0-test8/linux/arch/mips/kernel/gdb-stub.c Sat May 13 08:29:14 2000 +++ linux/arch/mips/kernel/gdb-stub.c Sun Oct 1 20:35:15 2000 @@ -115,7 +115,7 @@ static char input_buffer[BUFMAX]; static char output_buffer[BUFMAX]; -static int initialized = 0; /* !0 means we've been initialized */ +static int initialized; /* !0 means we've been initialized */ static const char hexchars[]="0123456789abcdef"; diff -u --recursive --new-file v2.4.0-test8/linux/arch/mips/kernel/time.c linux/arch/mips/kernel/time.c --- v2.4.0-test8/linux/arch/mips/kernel/time.c Tue Jul 11 11:14:48 2000 +++ linux/arch/mips/kernel/time.c Mon Sep 11 08:39:48 2000 @@ -443,37 +443,6 @@ r4k_timer_interrupt (INDY_R4K_TIMER_IRQ, NULL, regs); } -/* Converts Gregorian date to seconds since 1970-01-01 00:00:00. - * Assumes input in normal date format, i.e. 1980-12-31 23:59:59 - * => year=1980, mon=12, day=31, hour=23, min=59, sec=59. - * - * [For the Julian calendar (which was used in Russia before 1917, - * Britain & colonies before 1752, anywhere else before 1582, - * and is still in use by some communities) leave out the - * -year/100+year/400 terms, and add 10.] - * - * This algorithm was first published by Gauss (I think). - * - * WARNING: this function will overflow on 2106-02-07 06:28:16 on - * machines were long is 32-bit! (However, as time_t is signed, we - * will already get problems at other places on 2038-01-19 03:14:08) - */ -static inline unsigned long mktime(unsigned int year, unsigned int mon, - unsigned int day, unsigned int hour, - unsigned int min, unsigned int sec) -{ - if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */ - mon += 12; /* Puts Feb last since it has leap day */ - year -= 1; - } - return ((( - (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) + - year*365 - 719499 - )*24 + hour /* now have hours */ - )*60 + min /* now have minutes */ - )*60 + sec; /* finally seconds */ -} - char cyclecounter_available; static inline void init_cycle_counter(void) diff -u --recursive --new-file v2.4.0-test8/linux/arch/mips/sgi/kernel/indy_timer.c linux/arch/mips/sgi/kernel/indy_timer.c --- v2.4.0-test8/linux/arch/mips/sgi/kernel/indy_timer.c Sat May 13 08:29:14 2000 +++ linux/arch/mips/sgi/kernel/indy_timer.c Mon Sep 11 08:39:48 2000 @@ -151,37 +151,6 @@ return ct1 - ct0; } -/* Converts Gregorian date to seconds since 1970-01-01 00:00:00. - * Assumes input in normal date format, i.e. 1980-12-31 23:59:59 - * => year=1980, mon=12, day=31, hour=23, min=59, sec=59. - * - * [For the Julian calendar (which was used in Russia before 1917, - * Britain & colonies before 1752, anywhere else before 1582, - * and is still in use by some communities) leave out the - * -year/100+year/400 terms, and add 10.] - * - * This algorithm was first published by Gauss (I think). - * - * WARNING: this function will overflow on 2106-02-07 06:28:16 on - * machines were long is 32-bit! (However, as time_t is signed, we - * will already get problems at other places on 2038-01-19 03:14:08) - */ -static inline unsigned long mktime(unsigned int year, unsigned int mon, - unsigned int day, unsigned int hour, - unsigned int min, unsigned int sec) -{ - if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */ - mon += 12; /* Puts Feb last since it has leap day */ - year -= 1; - } - return ((( - (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) + - year*365 - 719499 - )*24 + hour /* now have hours */ - )*60 + min /* now have minutes */ - )*60 + sec; /* finally seconds */ -} - static unsigned long __init get_indy_time(void) { struct indy_clock *clock = (struct indy_clock *)INDY_CLOCK_REGS; diff -u --recursive --new-file v2.4.0-test8/linux/arch/mips64/config.in linux/arch/mips64/config.in --- v2.4.0-test8/linux/arch/mips64/config.in Tue Aug 22 11:41:14 2000 +++ linux/arch/mips64/config.in Tue Sep 19 10:57:30 2000 @@ -129,6 +129,8 @@ source drivers/block/Config.in +source drivers/md/Config.in + if [ "$CONFIG_NET" = "y" ]; then source net/Config.in fi diff -u --recursive --new-file v2.4.0-test8/linux/arch/mips64/sgi-ip22/ip22-timer.c linux/arch/mips64/sgi-ip22/ip22-timer.c --- v2.4.0-test8/linux/arch/mips64/sgi-ip22/ip22-timer.c Sat May 13 08:30:17 2000 +++ linux/arch/mips64/sgi-ip22/ip22-timer.c Mon Sep 11 08:39:48 2000 @@ -151,37 +151,6 @@ return ct1 - ct0; } -/* Converts Gregorian date to seconds since 1970-01-01 00:00:00. - * Assumes input in normal date format, i.e. 1980-12-31 23:59:59 - * => year=1980, mon=12, day=31, hour=23, min=59, sec=59. - * - * [For the Julian calendar (which was used in Russia before 1917, - * Britain & colonies before 1752, anywhere else before 1582, - * and is still in use by some communities) leave out the - * -year/100+year/400 terms, and add 10.] - * - * This algorithm was first published by Gauss (I think). - * - * WARNING: this function will overflow on 2106-02-07 06:28:16 on - * machines were long is 32-bit! (However, as time_t is signed, we - * will already get problems at other places on 2038-01-19 03:14:08) - */ -static inline unsigned long mktime(unsigned int year, unsigned int mon, - unsigned int day, unsigned int hour, - unsigned int min, unsigned int sec) -{ - if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */ - mon += 12; /* Puts Feb last since it has leap day */ - year -= 1; - } - return ((( - (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) + - year*365 - 719499 - )*24 + hour /* now have hours */ - )*60 + min /* now have minutes */ - )*60 + sec; /* finally seconds */ -} - static unsigned long __init get_indy_time(void) { struct indy_clock *clock = (struct indy_clock *)INDY_CLOCK_REGS; diff -u --recursive --new-file v2.4.0-test8/linux/arch/mips64/sgi-ip27/ip27-timer.c linux/arch/mips64/sgi-ip27/ip27-timer.c --- v2.4.0-test8/linux/arch/mips64/sgi-ip27/ip27-timer.c Tue Jul 11 11:18:53 2000 +++ linux/arch/mips64/sgi-ip27/ip27-timer.c Mon Sep 11 08:39:48 2000 @@ -219,37 +219,6 @@ #include #include -/* Converts Gregorian date to seconds since 1970-01-01 00:00:00. - * Assumes input in normal date format, i.e. 1980-12-31 23:59:59 - * => year=1980, mon=12, day=31, hour=23, min=59, sec=59. - * - * [For the Julian calendar (which was used in Russia before 1917, - * Britain & colonies before 1752, anywhere else before 1582, - * and is still in use by some communities) leave out the - * -year/100+year/400 terms, and add 10.] - * - * This algorithm was first published by Gauss (I think). - * - * WARNING: this function will overflow on 2106-02-07 06:28:16 on - * machines were long is 32-bit! (However, as time_t is signed, we - * will already get problems at other places on 2038-01-19 03:14:08) - */ -static inline unsigned long mktime(unsigned int year, unsigned int mon, - unsigned int day, unsigned int hour, - unsigned int min, unsigned int sec) -{ - if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */ - mon += 12; /* Puts Feb last since it has leap day */ - year -= 1; - } - return ((( - (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) + - year*365 - 719499 - )*24 + hour /* now have hours */ - )*60 + min /* now have minutes */ - )*60 + sec; /* finally seconds */ -} - #define DEBUG_RTC static unsigned long __init get_m48t35_time(void) diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/8260_io/Config.in linux/arch/ppc/8260_io/Config.in --- v2.4.0-test8/linux/arch/ppc/8260_io/Config.in Tue May 2 13:05:39 2000 +++ linux/arch/ppc/8260_io/Config.in Sun Sep 17 09:48:05 2000 @@ -11,12 +11,15 @@ bool 'Ethernet on SCC2' CONFIG_SCC2_ENET fi fi - bool 'FCC Ethernet' CONFIG_FCC_ENET - if [ "$CONFIG_FCC_ENET" = "y" ]; then - bool 'Ethernet on FCC1' CONFIG_FCC1_ENET - if [ "$CONFIG_FCC1_ENET" != "y" ]; then - bool 'Ethernet on FCC2' CONFIG_FCC2_ENET - fi +# +# CONFIG_FEC_ENET is only used to get netdevices to call our init +# function. Any combination of FCC1,2,3 are supported. +# + bool 'FCC Ethernet' CONFIG_FEC_ENET + if [ "$CONFIG_FEC_ENET" = "y" ]; then + bool 'Ethernet on FCC1' CONFIG_FCC1_ENET + bool 'Ethernet on FCC2' CONFIG_FCC2_ENET + bool 'Ethernet on FCC3' CONFIG_FCC3_ENET fi endmenu fi diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/8260_io/Makefile linux/arch/ppc/8260_io/Makefile --- v2.4.0-test8/linux/arch/ppc/8260_io/Makefile Tue May 2 13:05:39 2000 +++ linux/arch/ppc/8260_io/Makefile Sun Sep 17 09:48:05 2000 @@ -10,8 +10,8 @@ O_TARGET := 8260_io.a O_OBJS = commproc.o uart.o -ifdef CONFIG_FCC_ENET -O_OBJS += fcc.o +ifdef CONFIG_FEC_ENET +O_OBJS += fcc_enet.o endif ifdef CONFIG_SCC_ENET O_OBJS += enet.o diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/8260_io/commproc.c linux/arch/ppc/8260_io/commproc.c --- v2.4.0-test8/linux/arch/ppc/8260_io/commproc.c Wed May 3 01:47:56 2000 +++ linux/arch/ppc/8260_io/commproc.c Sun Sep 17 09:48:05 2000 @@ -69,17 +69,27 @@ cpmp = (cpm8260_t *)commproc; } -/* Allocate some memory from the dual ported ram. We may want to - * enforce alignment restrictions, but right now everyone is a good - * citizen. +/* Allocate some memory from the dual ported ram. + * To help protocols with object alignment restrictions, we do that + * if they ask. */ uint -m8260_cpm_dpalloc(uint size) +m8260_cpm_dpalloc(uint size, uint align) { uint retloc; + uint align_mask, off; + uint savebase; - if ((dp_alloc_base + size) >= dp_alloc_top) + align_mask = align - 1; + savebase = dp_alloc_base; + + if ((off = (dp_alloc_base & align_mask)) != 0) + dp_alloc_base += (align - off); + + if ((dp_alloc_base + size) >= dp_alloc_top) { + dp_alloc_base = savebase; return(CPM_DP_NOSPACE); + } retloc = dp_alloc_base; dp_alloc_base += size; @@ -91,12 +101,22 @@ * UART "fifos" and the like. */ uint -m8260_cpm_hostalloc(uint size) +m8260_cpm_hostalloc(uint size, uint align) { uint retloc; + uint align_mask, off; + uint savebase; + + align_mask = align - 1; + savebase = host_buffer; + + if ((off = (host_buffer & align_mask)) != 0) + host_buffer += (align - off); - if ((host_buffer + size) >= host_end) + if ((host_buffer + size) >= host_end) { + host_buffer = savebase; return(0); + } retloc = host_buffer; host_buffer += size; diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/8260_io/enet.c linux/arch/ppc/8260_io/enet.c --- v2.4.0-test8/linux/arch/ppc/8260_io/enet.c Mon Jun 19 13:25:05 2000 +++ linux/arch/ppc/8260_io/enet.c Sun Sep 17 09:48:05 2000 @@ -466,8 +466,11 @@ cep->stats.rx_bytes += pkt_len; /* This does 16 byte alignment, much more than we need. - */ - skb = dev_alloc_skb(pkt_len); + * The packet length includes FCS, but we don't want to + * include that when passing upstream as it messes up + * bridging applications. + */ + skb = dev_alloc_skb(pkt_len-4); if (skb == NULL) { printk("%s: Memory squeeze, dropping packet.\n", dev->name); @@ -475,10 +478,10 @@ } else { skb->dev = dev; - skb_put(skb,pkt_len); /* Make room */ + skb_put(skb,pkt_len-4); /* Make room */ eth_copy_and_sum(skb, (unsigned char *)__va(bdp->cbd_bufaddr), - pkt_len, 0); + pkt_len-4, 0); skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); } @@ -549,10 +552,10 @@ /* Log any net taps. */ printk("%s: Promiscuous mode enabled.\n", dev->name); - cep->sccp->scc_pmsr |= SCC_PMSR_PRO; + cep->sccp->scc_pmsr |= SCC_PSMR_PRO; } else { - cep->sccp->scc_pmsr &= ~SCC_PMSR_PRO; + cep->sccp->scc_pmsr &= ~SCC_PSMR_PRO; if (dev->flags & IFF_ALLMULTI) { /* Catch all multicast addresses, so set the @@ -678,11 +681,11 @@ * These are relative offsets in the DP ram address space. * Initialize base addresses for the buffer descriptors. */ - i = m8260_cpm_dpalloc(sizeof(cbd_t) * RX_RING_SIZE); + i = m8260_cpm_dpalloc(sizeof(cbd_t) * RX_RING_SIZE, 8); ep->sen_genscc.scc_rbase = i; cep->rx_bd_base = (cbd_t *)&immap->im_dprambase[i]; - i = m8260_cpm_dpalloc(sizeof(cbd_t) * TX_RING_SIZE); + i = m8260_cpm_dpalloc(sizeof(cbd_t) * TX_RING_SIZE, 8); ep->sen_genscc.scc_tbase = i; cep->tx_bd_base = (cbd_t *)&immap->im_dprambase[i]; @@ -816,7 +819,7 @@ /* Set processing mode. Use Ethernet CRC, catch broadcast, and * start frame search 22 bit times after RENA. */ - sccp->scc_pmsr = (SCC_PMSR_ENCRC | SCC_PMSR_NIB22); + sccp->scc_pmsr = (SCC_PSMR_ENCRC | SCC_PSMR_NIB22); /* It is now OK to enable the Ethernet transmitter. * Unfortunately, there are board implementation differences here. diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/8260_io/fcc_enet.c linux/arch/ppc/8260_io/fcc_enet.c --- v2.4.0-test8/linux/arch/ppc/8260_io/fcc_enet.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/8260_io/fcc_enet.c Tue Sep 19 08:31:53 2000 @@ -0,0 +1,1601 @@ +/* + * Fast Ethernet Controller (FCC) driver for Motorola MPC8260. + * Copyright (c) 2000 MontaVista Software, Inc. Dan Malek (dmalek@jlc.net) + * + * This version of the driver is a combination of the 8xx fec and + * 8260 SCC Ethernet drivers. People seem to be choosing common I/O + * configurations, so this driver will work on the EST8260 boards and + * others yet to be announced. + * + * Right now, I am very watseful with the buffers. I allocate memory + * pages and then divide them into 2K frame buffers. This way I know I + * have buffers large enough to hold one frame within one buffer descriptor. + * Once I get this working, I will use 64 or 128 byte CPM buffers, which + * will be much more memory efficient and will easily handle lots of + * small packets. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* The transmitter timeout + */ +#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 + * to keep them that size. + * We don't need to allocate pages for the transmitter. We just use + * the skbuffer directly. + */ +#define FCC_ENET_RX_PAGES 16 +#define FCC_ENET_RX_FRSIZE 2048 +#define FCC_ENET_RX_FRPPG (PAGE_SIZE / FCC_ENET_RX_FRSIZE) +#define RX_RING_SIZE (FCC_ENET_RX_FRPPG * FCC_ENET_RX_PAGES) +#define TX_RING_SIZE 16 /* Must be power of two */ +#define TX_RING_MOD_MASK 15 /* for this to work */ + +/* The FCC stores dest/src/type, data, and checksum for receive packets. + */ +#define PKT_MAXBUF_SIZE 1518 +#define PKT_MINBUF_SIZE 64 + +/* Maximum input DMA size. Must be a should(?) be a multiple of 4. +*/ +#define PKT_MAXDMA_SIZE 1520 + +/* Maximum input buffer size. Must be a multiple of 32. +*/ +#define PKT_MAXBLR_SIZE 1536 + +static int fcc_enet_open(struct net_device *dev); +static int fcc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev); +static int fcc_enet_rx(struct net_device *dev); +static void fcc_enet_mii(struct net_device *dev); +static void fcc_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs); +static int fcc_enet_close(struct net_device *dev); +static struct net_device_stats *fcc_enet_get_stats(struct net_device *dev); +static void set_multicast_list(struct net_device *dev); +static void restart_fcc(struct net_device *dev); + +/* These will be configurable for the FCC choice. + * Multiple ports can be configured. There is little choice among the + * I/O pins to the PHY, except the clocks. We will need some board + * dependent clock selection. + * Why in the hell did I put these inside #ifdef's? I dunno, maybe to + * help show what pins are used for each device. + */ + +/* I/O Pin assignment for FCC1. I don't yet know the best way to do this, + * but there is little variation among the choices. + */ +#define PA1_COL ((uint)0x00000001) +#define PA1_CRS ((uint)0x00000002) +#define PA1_TXER ((uint)0x00000004) +#define PA1_TXEN ((uint)0x00000008) +#define PA1_RXDV ((uint)0x00000010) +#define PA1_RXER ((uint)0x00000020) +#define PA1_TXDAT ((uint)0x00003c00) +#define PA1_RXDAT ((uint)0x0003c000) +#define PA1_PSORA0 (PA1_RXDAT | PA1_TXDAT) +#define PA1_PSORA1 (PA1_COL | PA1_CRS | PA1_TXER | PA1_TXEN | \ + PA1_RXDV | PA1_RXER) +#define PA1_DIRA0 (PA1_RXDAT | PA1_CRS | PA1_COL | PA1_RXER | PA1_RXDV) +#define PA1_DIRA1 (PA1_TXDAT | PA1_TXEN | PA1_TXER) + +/* CLK12 is receive, CLK11 is transmit. These are board specific. +*/ +#define PC_F1RXCLK ((uint)0x00000800) +#define PC_F1TXCLK ((uint)0x00000400) +#define CMX1_CLK_ROUTE ((uint)0x3e000000) +#define CMX1_CLK_MASK ((uint)0xff000000) + +/* I/O Pin assignment for FCC2. I don't yet know the best way to do this, + * but there is little variation among the choices. + */ +#define PB2_TXER ((uint)0x00000001) +#define PB2_RXDV ((uint)0x00000002) +#define PB2_TXEN ((uint)0x00000004) +#define PB2_RXER ((uint)0x00000008) +#define PB2_COL ((uint)0x00000010) +#define PB2_CRS ((uint)0x00000020) +#define PB2_TXDAT ((uint)0x000003c0) +#define PB2_RXDAT ((uint)0x00003c00) +#define PB2_PSORB0 (PB2_RXDAT | PB2_TXDAT | PB2_CRS | PB2_COL | \ + PB2_RXER | PB2_RXDV | PB2_TXER) +#define PB2_PSORB1 (PB2_TXEN) +#define PB2_DIRB0 (PB2_RXDAT | PB2_CRS | PB2_COL | PB2_RXER | PB2_RXDV) +#define PB2_DIRB1 (PB2_TXDAT | PB2_TXEN | PB2_TXER) + +/* CLK13 is receive, CLK14 is transmit. These are board dependent. +*/ +#define PC_F2RXCLK ((uint)0x00001000) +#define PC_F2TXCLK ((uint)0x00002000) +#define CMX2_CLK_ROUTE ((uint)0x00250000) +#define CMX2_CLK_MASK ((uint)0x00ff0000) + +/* I/O Pin assignment for FCC3. I don't yet know the best way to do this, + * but there is little variation among the choices. + */ +#define PB3_RXDV ((uint)0x00004000) +#define PB3_RXER ((uint)0x00008000) +#define PB3_TXER ((uint)0x00010000) +#define PB3_TXEN ((uint)0x00020000) +#define PB3_COL ((uint)0x00040000) +#define PB3_CRS ((uint)0x00080000) +#define PB3_TXDAT ((uint)0x0f000000) +#define PB3_RXDAT ((uint)0x00f00000) +#define PB3_PSORB0 (PB3_RXDAT | PB3_TXDAT | PB3_CRS | PB3_COL | \ + PB3_RXER | PB3_RXDV | PB3_TXER | PB3_TXEN) +#define PB3_PSORB1 (0) +#define PB3_DIRB0 (PB3_RXDAT | PB3_CRS | PB3_COL | PB3_RXER | PB3_RXDV) +#define PB3_DIRB1 (PB3_TXDAT | PB3_TXEN | PB3_TXER) + +/* CLK15 is receive, CLK16 is transmit. These are board dependent. +*/ +#define PC_F3RXCLK ((uint)0x00004000) +#define PC_F3TXCLK ((uint)0x00008000) +#define CMX3_CLK_ROUTE ((uint)0x00003700) +#define CMX3_CLK_MASK ((uint)0x0000ff00) + +/* MII status/control serial interface. +*/ +#define PC_MDIO ((uint)0x00400000) +#define PC_MDCK ((uint)0x00200000) + +/* A table of information for supporting FCCs. This does two things. + * First, we know how many FCCs we have and they are always externally + * numbered from zero. Second, it holds control register and I/O + * information that could be different among board designs. + */ +typedef struct fcc_info { + uint fc_fccnum; + uint fc_cpmblock; + uint fc_cpmpage; + uint fc_proff; + uint fc_interrupt; + uint fc_trxclocks; + uint fc_clockroute; + uint fc_clockmask; + uint fc_mdio; + uint fc_mdck; +} fcc_info_t; + +static fcc_info_t fcc_ports[] = { +#ifdef CONFIG_FCC1_ENET + { 0, CPM_CR_FCC1_SBLOCK, CPM_CR_FCC1_PAGE, PROFF_FCC1, SIU_INT_FCC1, + (PC_F1RXCLK | PC_F1TXCLK), CMX1_CLK_ROUTE, CMX1_CLK_MASK, + PC_MDIO, PC_MDCK }, +#endif +#ifdef CONFIG_FCC2_ENET + { 1, CPM_CR_FCC2_SBLOCK, CPM_CR_FCC2_PAGE, PROFF_FCC2, SIU_INT_FCC2, + (PC_F2RXCLK | PC_F2TXCLK), CMX2_CLK_ROUTE, CMX2_CLK_MASK, + PC_MDIO, PC_MDCK }, +#endif +#ifdef CONFIG_FCC3_ENET + { 2, CPM_CR_FCC3_SBLOCK, CPM_CR_FCC3_PAGE, PROFF_FCC3, SIU_INT_FCC3, + (PC_F3RXCLK | PC_F3TXCLK), CMX3_CLK_ROUTE, CMX3_CLK_MASK, + PC_MDIO, PC_MDCK }, +#endif +}; + +/* The FCC buffer descriptors track the ring buffers. The rx_bd_base and + * tx_bd_base always point to the base of the buffer descriptors. The + * cur_rx and cur_tx point to the currently available buffer. + * The dirty_tx tracks the current buffer that is being sent by the + * controller. The cur_tx and dirty_tx are equal under both completely + * empty and completely full conditions. The empty/ready indicator in + * the buffer descriptor determines the actual condition. + */ +struct fcc_enet_private { + /* The saved address of a sent-in-place packet/buffer, for skfree(). */ + struct sk_buff* tx_skbuff[TX_RING_SIZE]; + ushort skb_cur; + ushort skb_dirty; + + /* CPM dual port RAM relative addresses. + */ + cbd_t *rx_bd_base; /* Address of Rx and Tx buffers. */ + cbd_t *tx_bd_base; + cbd_t *cur_rx, *cur_tx; /* The next free ring entry */ + cbd_t *dirty_tx; /* The ring entries to be free()ed. */ + volatile fcc_t *fccp; + volatile fcc_enet_t *ep; + struct net_device_stats stats; + uint tx_full; + spinlock_t lock; + uint phy_address; + uint phy_type; + uint phy_duplex; + fcc_info_t *fip; +}; + +static void init_fcc_shutdown(fcc_info_t *fip, struct fcc_enet_private *cep, + volatile immap_t *immap); +static void init_fcc_startup(fcc_info_t *fip, struct net_device *dev); +static void init_fcc_ioports(fcc_info_t *fip, volatile iop8260_t *io, + volatile immap_t *immap); +static void init_fcc_param(fcc_info_t *fip, struct net_device *dev, + volatile immap_t *immap); + +/* MII processing. We keep this as simple as possible. Requests are + * placed on the list (if there is room). When the request is finished + * by the MII, an optional function may be called. + */ +typedef struct mii_list { + uint mii_regval; + void (*mii_func)(uint val, struct net_device *dev); + struct mii_list *mii_next; +} mii_list_t; + +#define NMII 20 +mii_list_t mii_cmds[NMII]; +mii_list_t *mii_free; +mii_list_t *mii_head; +mii_list_t *mii_tail; + +static int phyaddr; +static uint phytype; + +static int mii_queue(int request, void (*func)(uint, struct net_device *)); +static void mii_startup_cmds(void); +static uint mii_send_receive(fcc_info_t *fip, uint cmd); + +/* Make MII read/write commands for the FCC. +*/ + +#define mk_mii_phyaddr(ADDR) (0x60020000 | ((ADDR) << 23) | (2 << 18)) + +#define mk_mii_read(REG) (0x60020000 | ((phyaddr << 23) | \ + (REG & 0x1f) << 18)) + +#define mk_mii_write(REG, VAL) (0x50020000 | ((phyaddr << 23) | \ + (REG & 0x1f) << 18) | \ + (VAL & 0xffff)) + + +static int +fcc_enet_open(struct net_device *dev) +{ + netif_start_queue(dev); + return 0; /* Always succeed */ +} + +static int +fcc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct fcc_enet_private *cep = (struct fcc_enet_private *)dev->priv; + volatile cbd_t *bdp; + + + /* Fill in a Tx ring entry */ + bdp = cep->cur_tx; + +#ifndef final_version + if (bdp->cbd_sc & BD_ENET_TX_READY) { + /* Ooops. All transmit buffers are full. Bail out. + * This should not happen, since cep->tx_full should be set. + */ + printk("%s: tx queue full!.\n", dev->name); + return 1; + } +#endif + + /* Clear all of the status flags. + */ + bdp->cbd_sc &= ~BD_ENET_TX_STATS; + + /* If the frame is short, tell CPM to pad it. + */ + if (skb->len <= ETH_ZLEN) + bdp->cbd_sc |= BD_ENET_TX_PAD; + else + bdp->cbd_sc &= ~BD_ENET_TX_PAD; + + /* Set buffer length and buffer pointer. + */ + bdp->cbd_datlen = skb->len; + bdp->cbd_bufaddr = __pa(skb->data); + + /* Save skb pointer. + */ + cep->tx_skbuff[cep->skb_cur] = skb; + + cep->stats.tx_bytes += skb->len; + cep->skb_cur = (cep->skb_cur+1) & TX_RING_MOD_MASK; + + spin_lock_irq(&cep->lock); + + /* Send it on its way. Tell CPM its ready, interrupt when done, + * its the last BD of the frame, and to put the CRC on the end. + */ + bdp->cbd_sc |= (BD_ENET_TX_READY | BD_ENET_TX_INTR | BD_ENET_TX_LAST | BD_ENET_TX_TC); + +#if 0 + /* Errata says don't do this. + */ + cep->fccp->fcc_ftodr = 0x8000; +#endif + dev->trans_start = jiffies; + + /* If this was the last BD in the ring, start at the beginning again. + */ + if (bdp->cbd_sc & BD_ENET_TX_WRAP) + bdp = cep->tx_bd_base; + else + bdp++; + + if (bdp->cbd_sc & BD_ENET_TX_READY) { + netif_stop_queue(dev); + cep->tx_full = 1; + } + + cep->cur_tx = (cbd_t *)bdp; + + spin_unlock_irq(&cep->lock); + + return 0; +} + + +static void +fcc_enet_timeout(struct net_device *dev) +{ + struct fcc_enet_private *cep = (struct fcc_enet_private *)dev->priv; + + printk("%s: transmit timed out.\n", dev->name); + cep->stats.tx_errors++; +#ifndef final_version + { + int i; + cbd_t *bdp; + printk(" Ring data dump: cur_tx %p%s cur_rx %p.\n", + cep->cur_tx, cep->tx_full ? " (full)" : "", + cep->cur_rx); + bdp = cep->tx_bd_base; + printk(" Tx @base %p :\n", bdp); + for (i = 0 ; i < TX_RING_SIZE; i++, bdp++) + printk("%04x %04x %08x\n", + bdp->cbd_sc, + bdp->cbd_datlen, + bdp->cbd_bufaddr); + bdp = cep->rx_bd_base; + printk(" Rx @base %p :\n", bdp); + for (i = 0 ; i < RX_RING_SIZE; i++, bdp++) + printk("%04x %04x %08x\n", + bdp->cbd_sc, + bdp->cbd_datlen, + bdp->cbd_bufaddr); + } +#endif + if (!cep->tx_full) + netif_wake_queue(dev); +} + +/* The interrupt handler. + */ +static void +fcc_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs) +{ + struct net_device *dev = dev_id; + volatile struct fcc_enet_private *cep; + volatile cbd_t *bdp; + ushort int_events; + int must_restart; + + cep = (struct fcc_enet_private *)dev->priv; + + /* Get the interrupt events that caused us to be here. + */ + int_events = cep->fccp->fcc_fcce; + cep->fccp->fcc_fcce = int_events; + must_restart = 0; + + /* Handle receive event in its own function. + */ + if (int_events & FCC_ENET_RXF) + fcc_enet_rx(dev_id); + + /* Check for a transmit error. The manual is a little unclear + * about this, so the debug code until I get it figured out. It + * appears that if TXE is set, then TXB is not set. However, + * if carrier sense is lost during frame transmission, the TXE + * bit is set, "and continues the buffer transmission normally." + * I don't know if "normally" implies TXB is set when the buffer + * descriptor is closed.....trial and error :-). + */ + + /* Transmit OK, or non-fatal error. Update the buffer descriptors. + */ + if (int_events & (FCC_ENET_TXE | FCC_ENET_TXB)) { + spin_lock(&cep->lock); + bdp = cep->dirty_tx; + while ((bdp->cbd_sc&BD_ENET_TX_READY)==0) { + if ((bdp==cep->cur_tx) && (cep->tx_full == 0)) + break; + + if (bdp->cbd_sc & BD_ENET_TX_HB) /* No heartbeat */ + cep->stats.tx_heartbeat_errors++; + if (bdp->cbd_sc & BD_ENET_TX_LC) /* Late collision */ + cep->stats.tx_window_errors++; + if (bdp->cbd_sc & BD_ENET_TX_RL) /* Retrans limit */ + cep->stats.tx_aborted_errors++; + if (bdp->cbd_sc & BD_ENET_TX_UN) /* Underrun */ + cep->stats.tx_fifo_errors++; + if (bdp->cbd_sc & BD_ENET_TX_CSL) /* Carrier lost */ + cep->stats.tx_carrier_errors++; + + + /* No heartbeat or Lost carrier are not really bad errors. + * The others require a restart transmit command. + */ + if (bdp->cbd_sc & + (BD_ENET_TX_LC | BD_ENET_TX_RL | BD_ENET_TX_UN)) { + must_restart = 1; + cep->stats.tx_errors++; + } + + cep->stats.tx_packets++; + + /* Deferred means some collisions occurred during transmit, + * but we eventually sent the packet OK. + */ + if (bdp->cbd_sc & BD_ENET_TX_DEF) + cep->stats.collisions++; + + /* Free the sk buffer associated with this last transmit. + */ + dev_kfree_skb_irq(cep->tx_skbuff[cep->skb_dirty]); + cep->skb_dirty = (cep->skb_dirty + 1) & TX_RING_MOD_MASK; + + /* Update pointer to next buffer descriptor to be transmitted. + */ + if (bdp->cbd_sc & BD_ENET_TX_WRAP) + bdp = cep->tx_bd_base; + else + bdp++; + + /* I don't know if we can be held off from processing these + * interrupts for more than one frame time. I really hope + * not. In such a case, we would now want to check the + * currently available BD (cur_tx) and determine if any + * buffers between the dirty_tx and cur_tx have also been + * sent. We would want to process anything in between that + * does not have BD_ENET_TX_READY set. + */ + + /* Since we have freed up a buffer, the ring is no longer + * full. + */ + if (cep->tx_full) { + cep->tx_full = 0; + if (netif_queue_stopped(dev)) { + netif_wake_queue(dev); + } + } + + cep->dirty_tx = (cbd_t *)bdp; + } + + if (must_restart) { + volatile cpm8260_t *cp; + + /* Some transmit errors cause the transmitter to shut + * down. We now issue a restart transmit. Since the + * errors close the BD and update the pointers, the restart + * _should_ pick up without having to reset any of our + * pointers either. + */ + + cp = cpmp; + cp->cp_cpcr = + mk_cr_cmd(cep->fip->fc_cpmpage, cep->fip->fc_cpmblock, + 0x0c, CPM_CR_RESTART_TX) | CPM_CR_FLG; + while (cp->cp_cpcr & CPM_CR_FLG); + } + spin_unlock(&cep->lock); + } + + /* Check for receive busy, i.e. packets coming but no place to + * put them. + */ + if (int_events & FCC_ENET_BSY) { + cep->stats.rx_dropped++; + } + return; +} + +/* During a receive, the cur_rx points to the current incoming buffer. + * When we update through the ring, if the next incoming buffer has + * not been given to the system, we just set the empty indicator, + * effectively tossing the packet. + */ +static int +fcc_enet_rx(struct net_device *dev) +{ + struct fcc_enet_private *cep; + volatile cbd_t *bdp; + struct sk_buff *skb; + ushort pkt_len; + + cep = (struct fcc_enet_private *)dev->priv; + + /* First, grab all of the stats for the incoming packet. + * These get messed up if we get called due to a busy condition. + */ + bdp = cep->cur_rx; + +for (;;) { + if (bdp->cbd_sc & BD_ENET_RX_EMPTY) + break; + +#ifndef final_version + /* Since we have allocated space to hold a complete frame, both + * the first and last indicators should be set. + */ + if ((bdp->cbd_sc & (BD_ENET_RX_FIRST | BD_ENET_RX_LAST)) != + (BD_ENET_RX_FIRST | BD_ENET_RX_LAST)) + printk("CPM ENET: rcv is not first+last\n"); +#endif + + /* Frame too long or too short. + */ + if (bdp->cbd_sc & (BD_ENET_RX_LG | BD_ENET_RX_SH)) + cep->stats.rx_length_errors++; + if (bdp->cbd_sc & BD_ENET_RX_NO) /* Frame alignment */ + cep->stats.rx_frame_errors++; + if (bdp->cbd_sc & BD_ENET_RX_CR) /* CRC Error */ + cep->stats.rx_crc_errors++; + if (bdp->cbd_sc & BD_ENET_RX_OV) /* FIFO overrun */ + cep->stats.rx_crc_errors++; + + /* Report late collisions as a frame error. + * On this error, the BD is closed, but we don't know what we + * have in the buffer. So, just drop this frame on the floor. + */ + if (bdp->cbd_sc & BD_ENET_RX_CL) { + cep->stats.rx_frame_errors++; + } + else { + + /* Process the incoming frame. + */ + cep->stats.rx_packets++; + pkt_len = bdp->cbd_datlen; + cep->stats.rx_bytes += pkt_len; + + /* This does 16 byte alignment, much more than we need. + * The packet length includes FCS, but we don't want to + * include that when passing upstream as it messes up + * bridging applications. + */ + skb = dev_alloc_skb(pkt_len-4); + + if (skb == NULL) { + printk("%s: Memory squeeze, dropping packet.\n", dev->name); + cep->stats.rx_dropped++; + } + else { + skb->dev = dev; + skb_put(skb,pkt_len-4); /* Make room */ + eth_copy_and_sum(skb, + (unsigned char *)__va(bdp->cbd_bufaddr), + pkt_len-4, 0); + skb->protocol=eth_type_trans(skb,dev); + netif_rx(skb); + } + } + + /* Clear the status flags for this buffer. + */ + bdp->cbd_sc &= ~BD_ENET_RX_STATS; + + /* Mark the buffer empty. + */ + bdp->cbd_sc |= BD_ENET_RX_EMPTY; + + /* Update BD pointer to next entry. + */ + if (bdp->cbd_sc & BD_ENET_RX_WRAP) + bdp = cep->rx_bd_base; + else + bdp++; + + } + cep->cur_rx = (cbd_t *)bdp; + + return 0; +} + +static int +fcc_enet_close(struct net_device *dev) +{ + /* Don't know what to do yet. + */ + netif_stop_queue(dev); + + return 0; +} + +static struct net_device_stats *fcc_enet_get_stats(struct net_device *dev) +{ + struct fcc_enet_private *cep = (struct fcc_enet_private *)dev->priv; + + return &cep->stats; +} + +/* The MII is simulated from the 8xx FEC implementation. The FCC + * is not responsible for the MII control/status interface. + */ +static void +fcc_enet_mii(struct net_device *dev) +{ + struct fcc_enet_private *fep; + mii_list_t *mip; + uint mii_reg; + + fep = (struct fcc_enet_private *)dev->priv; +#if 0 + ep = &(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec); + mii_reg = ep->fec_mii_data; +#endif + + if ((mip = mii_head) == NULL) { + printk("MII and no head!\n"); + return; + } + + if (mip->mii_func != NULL) + (*(mip->mii_func))(mii_reg, dev); + + mii_head = mip->mii_next; + mip->mii_next = mii_free; + mii_free = mip; + +#if 0 + if ((mip = mii_head) != NULL) + ep->fec_mii_data = mip->mii_regval; +#endif +} + +static int +mii_queue(int regval, void (*func)(uint, struct net_device *)) +{ + unsigned long flags; + mii_list_t *mip; + int retval; + + retval = 0; + + save_flags(flags); + cli(); + + if ((mip = mii_free) != NULL) { + mii_free = mip->mii_next; + mip->mii_regval = regval; + mip->mii_func = func; + mip->mii_next = NULL; + if (mii_head) { + mii_tail->mii_next = mip; + mii_tail = mip; + } + else { + mii_head = mii_tail = mip; +#if 0 + (&(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec))->fec_mii_data = regval; +#endif + } + } + else { + retval = 1; + } + + restore_flags(flags); + + return(retval); +} + +static volatile uint full_duplex; + +static void +mii_status(uint mii_reg, struct net_device *dev) +{ + volatile uint prev_duplex; + + if (((mii_reg >> 18) & 0x1f) == 1) { + /* status register. + */ + printk("fec: "); + if (mii_reg & 0x0004) + printk("link up"); + else + printk("link down"); + + if (mii_reg & 0x0010) + printk(",remote fault"); + if (mii_reg & 0x0020) + printk(",auto complete"); + printk("\n"); + } + if (((mii_reg >> 18) & 0x1f) == 0x14) { + /* Extended chip status register. + */ + prev_duplex = full_duplex; + printk("fec: "); + if (mii_reg & 0x0800) + printk("100 Mbps"); + else + printk("10 Mbps"); + + if (mii_reg & 0x1000) { + printk(", Full-Duplex\n"); + full_duplex = 1; + } + else { + printk(", Half-Duplex\n"); + full_duplex = 0; + } +#if 0 + if (prev_duplex != full_duplex) + restart_fec(dev); +#endif + } + if (((mii_reg >> 18) & 0x1f) == 31) { + /* QS6612 PHY Control/Status. + * OK, now we have it all, so figure out what is going on. + */ + prev_duplex = full_duplex; + printk("fec: "); + + mii_reg = (mii_reg >> 2) & 7; + + if (mii_reg & 1) + printk("10 Mbps"); + else + printk("100 Mbps"); + + if (mii_reg > 4) { + printk(", Full-Duplex\n"); + full_duplex = 1; + } + else { + printk(", Half-Duplex\n"); + full_duplex = 0; + } + +#if 0 + if (prev_duplex != full_duplex) + restart_fec(dev); +#endif + } +} + +static uint phyno; + +static void +mii_discover_phy3(uint mii_reg, struct net_device *dev) +{ + phytype <<= 16; + phytype |= (mii_reg & 0xffff); + printk("fec: Phy @ 0x%x, type 0x%08x\n", phyno, phytype); + mii_startup_cmds(); +} + +static void +mii_discover_phy(uint mii_reg, struct net_device *dev) +{ + if (phyno < 32) { + if ((phytype = (mii_reg & 0xffff)) != 0xffff) { + phyaddr = phyno; + mii_queue(mk_mii_read(3), mii_discover_phy3); + } + else { + phyno++; + mii_queue(mk_mii_phyaddr(phyno), mii_discover_phy); + } + } + else { + printk("FEC: No PHY device found.\n"); + } +} + +static void +mii_discover_phy_poll(fcc_info_t *fip) +{ + uint rv; + int i; + + for (i=0; i<32; i++) { + rv = mii_send_receive(fip, mk_mii_phyaddr(i)); + if ((phytype = (rv & 0xffff)) != 0xffff) { + phyaddr = i; + rv = mii_send_receive(fip, mk_mii_read(3)); + phytype <<= 16; + phytype |= (rv & 0xffff); + printk("fec: Phy @ 0x%x, type 0x%08x\n", phyaddr, phytype); + } + } +} + +static void +mii_startup_cmds(void) +{ + +#if 1 + /* Level One PHY. + */ + + /* Read status registers to clear any pending interrupt. + */ + mii_queue(mk_mii_read(1), mii_status); + mii_queue(mk_mii_read(18), mii_status); + + /* Read extended chip status register. + */ + mii_queue(mk_mii_read(0x14), mii_status); + + /* Set default operation of 100-TX....for some reason + * some of these bits are set on power up, which is wrong. + */ + mii_queue(mk_mii_write(0x13, 0), NULL); + + /* Enable Link status change interrupts. + */ + mii_queue(mk_mii_write(0x11, 0x0002), NULL); + + /* Don't advertize Full duplex. + mii_queue(mk_mii_write(0x04, 0x0021), NULL); + */ +#endif + +} + +/* This supports the mii_link interrupt below. + * We should get called three times. Once for register 1, once for + * register 18, and once for register 20. + */ +static uint mii_saved_reg1; + +static void +mii_relink(uint mii_reg, struct net_device *dev) +{ + volatile uint prev_duplex; + unsigned long flags; + + if (((mii_reg >> 18) & 0x1f) == 1) { + /* Just save the status register and get out. + */ + mii_saved_reg1 = mii_reg; + return; + } + if (((mii_reg >> 18) & 0x1f) == 18) { + /* Not much here, but has to be read to clear the + * interrupt condition. + */ + if ((mii_reg & 0x8000) == 0) + printk("fec: re-link and no IRQ?\n"); + if ((mii_reg & 0x4000) == 0) + printk("fec: no PHY power?\n"); + } + if (((mii_reg >> 18) & 0x1f) == 20) { + /* Extended chip status register. + * OK, now we have it all, so figure out what is going on. + */ + prev_duplex = full_duplex; + printk("fec: "); + if (mii_saved_reg1 & 0x0004) + printk("link up"); + else + printk("link down"); + + if (mii_saved_reg1 & 0x0010) + printk(", remote fault"); + if (mii_saved_reg1 & 0x0020) + printk(", auto complete"); + + if (mii_reg & 0x0800) + printk(", 100 Mbps"); + else + printk(", 10 Mbps"); + + if (mii_reg & 0x1000) { + printk(", Full-Duplex\n"); + full_duplex = 1; + } + else { + printk(", Half-Duplex\n"); + full_duplex = 0; + } + if (prev_duplex != full_duplex) { + save_flags(flags); + cli(); +#if 0 + restart_fec(dev); +#endif + restore_flags(flags); + } + } + if (((mii_reg >> 18) & 0x1f) == 31) { + /* QS6612 PHY Control/Status. + * OK, now we have it all, so figure out what is going on. + */ + prev_duplex = full_duplex; + printk("fec: "); + if (mii_saved_reg1 & 0x0004) + printk("link up"); + else + printk("link down"); + + if (mii_saved_reg1 & 0x0010) + printk(", remote fault"); + if (mii_saved_reg1 & 0x0020) + printk(", auto complete"); + + mii_reg = (mii_reg >> 2) & 7; + + if (mii_reg & 1) + printk(", 10 Mbps"); + else + printk(", 100 Mbps"); + + if (mii_reg > 4) { + printk(", Full-Duplex\n"); + full_duplex = 1; + } + else { + printk(", Half-Duplex\n"); + full_duplex = 0; + } + +#if 0 + if (prev_duplex != full_duplex) { + save_flags(flags); + cli(); + restart_fec(dev); + restore_flags(flags); + } +#endif + } +} + +/* Set or clear the multicast filter for this adaptor. + * Skeleton taken from sunlance driver. + * The CPM Ethernet implementation allows Multicast as well as individual + * MAC address filtering. Some of the drivers check to make sure it is + * a group multicast address, and discard those that are not. I guess I + * will do the same for now, but just remove the test if you want + * individual filtering as well (do the upper net layers want or support + * this kind of feature?). + */ +static void +set_multicast_list(struct net_device *dev) +{ + struct fcc_enet_private *cep; + struct dev_mc_list *dmi; + u_char *mcptr, *tdptr; + volatile fcc_enet_t *ep; + int i, j; + + cep = (struct fcc_enet_private *)dev->priv; + +return; + /* Get pointer to FCC area in parameter RAM. + */ + ep = (fcc_enet_t *)dev->base_addr; + + if (dev->flags&IFF_PROMISC) { + + /* Log any net taps. */ + printk("%s: Promiscuous mode enabled.\n", dev->name); + cep->fccp->fcc_fpsmr |= FCC_PSMR_PRO; + } else { + + cep->fccp->fcc_fpsmr &= ~FCC_PSMR_PRO; + + if (dev->flags & IFF_ALLMULTI) { + /* Catch all multicast addresses, so set the + * filter to all 1's. + */ + ep->fen_gaddrh = 0xffffffff; + ep->fen_gaddrl = 0xffffffff; + } + else { + /* Clear filter and add the addresses in the list. + */ + ep->fen_gaddrh = 0; + ep->fen_gaddrl = 0; + + dmi = dev->mc_list; + + for (i=0; imc_count; i++) { + + /* Only support group multicast for now. + */ + if (!(dmi->dmi_addr[0] & 1)) + continue; + + /* The address in dmi_addr is LSB first, + * and taddr is MSB first. We have to + * copy bytes MSB first from dmi_addr. + */ + mcptr = (u_char *)dmi->dmi_addr + 5; + tdptr = (u_char *)&ep->fen_taddrh; + for (j=0; j<6; j++) + *tdptr++ = *mcptr--; + + /* Ask CPM to run CRC and set bit in + * filter mask. + */ + cpmp->cp_cpcr = mk_cr_cmd(cep->fip->fc_cpmpage, + cep->fip->fc_cpmblock, 0x0c, + CPM_CR_SET_GADDR) | CPM_CR_FLG; + udelay(10); + while (cpmp->cp_cpcr & CPM_CR_FLG); + } + } + } +} + +/* Initialize the CPM Ethernet on FCC. + */ +int __init fec_enet_init(void) +{ + struct net_device *dev; + struct fcc_enet_private *cep; + fcc_info_t *fip; + int i, np; + volatile immap_t *immap; + volatile iop8260_t *io; + + immap = (immap_t *)IMAP_ADDR; /* and to internal registers */ + io = &immap->im_ioport; + + np = sizeof(fcc_ports) / sizeof(fcc_info_t); + fip = fcc_ports; + + while (np-- > 0) { + + /* Allocate some private information. + */ + cep = (struct fcc_enet_private *) + kmalloc(sizeof(*cep), GFP_KERNEL); + __clear_user(cep,sizeof(*cep)); + spin_lock_init(&cep->lock); + cep->fip = fip; + + /* Create an Ethernet device instance. + */ + dev = init_etherdev(0, 0); + dev->priv = cep; + + init_fcc_shutdown(fip, cep, immap); + init_fcc_ioports(fip, io, immap); + init_fcc_param(fip, dev, immap); + + dev->base_addr = (unsigned long)(cep->ep); + + /* The CPM Ethernet specific entries in the device + * structure. + */ + dev->open = fcc_enet_open; + dev->hard_start_xmit = fcc_enet_start_xmit; + dev->tx_timeout = fcc_enet_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + dev->stop = fcc_enet_close; + dev->get_stats = fcc_enet_get_stats; + dev->set_multicast_list = set_multicast_list; + + init_fcc_startup(fip, dev); + + printk("%s: FCC ENET Version 0.2, ", dev->name); + for (i=0; i<5; i++) + printk("%02x:", dev->dev_addr[i]); + printk("%02x\n", dev->dev_addr[5]); + + /* This is just a hack for now that works only on the EST + * board, or anything else that has MDIO/CK configured. + * It is mainly to test the MII software clocking. + */ + mii_discover_phy_poll(fip); + + fip++; + } + + return 0; +} + +/* Make sure the device is shut down during initialization. +*/ +static void __init +init_fcc_shutdown(fcc_info_t *fip, struct fcc_enet_private *cep, + volatile immap_t *immap) +{ + volatile fcc_enet_t *ep; + volatile fcc_t *fccp; + + /* Get pointer to FCC area in parameter RAM. + */ + ep = (fcc_enet_t *)(&immap->im_dprambase[fip->fc_proff]); + + /* And another to the FCC register area. + */ + fccp = (volatile fcc_t *)(&immap->im_fcc[fip->fc_fccnum]); + cep->fccp = fccp; /* Keep the pointers handy */ + cep->ep = ep; + + /* Disable receive and transmit in case someone left it running. + */ + fccp->fcc_gfmr &= ~(FCC_GFMR_ENR | FCC_GFMR_ENT); +} + +/* Initialize the I/O pins for the FCC Ethernet. +*/ +static void __init +init_fcc_ioports(fcc_info_t *fip, volatile iop8260_t *io, + volatile immap_t *immap) +{ + + /* FCC1 pins are on port A/C. FCC2/3 are port B/C. + */ + if (fip->fc_proff == PROFF_FCC1) { + /* Configure port A and C pins for FCC1 Ethernet. + */ + io->iop_pdira &= ~PA1_DIRA0; + io->iop_pdira |= PA1_DIRA1; + io->iop_psora &= ~PA1_PSORA0; + io->iop_psora |= PA1_PSORA1; + io->iop_ppara |= (PA1_DIRA0 | PA1_DIRA1); + } + if (fip->fc_proff == PROFF_FCC2) { + /* Configure port B and C pins for FCC Ethernet. + */ + io->iop_pdirb &= ~PB2_DIRB0; + io->iop_pdirb |= PB2_DIRB1; + io->iop_psorb &= ~PB2_PSORB0; + io->iop_psorb |= PB2_PSORB1; + io->iop_pparb |= (PB2_DIRB0 | PB2_DIRB1); + } + if (fip->fc_proff == PROFF_FCC3) { + /* Configure port B and C pins for FCC Ethernet. + */ + io->iop_pdirb &= ~PB3_DIRB0; + io->iop_pdirb |= PB3_DIRB1; + io->iop_psorb &= ~PB3_PSORB0; + io->iop_psorb |= PB3_PSORB1; + io->iop_pparb |= (PB3_DIRB0 | PB3_DIRB1); + } + + /* Port C has clocks...... + */ + io->iop_psorc &= ~(fip->fc_trxclocks); + io->iop_pdirc &= ~(fip->fc_trxclocks); + io->iop_pparc |= fip->fc_trxclocks; + + /* ....and the MII serial clock/data. + */ + io->iop_pdatc |= (fip->fc_mdio | fip->fc_mdck); + io->iop_podrc |= fip->fc_mdio; + io->iop_pdirc |= (fip->fc_mdio | fip->fc_mdck); + io->iop_pparc &= ~(fip->fc_mdio | fip->fc_mdck); + + /* Configure Serial Interface clock routing. + * First, clear all FCC bits to zero, + * then set the ones we want. + */ + immap->im_cpmux.cmx_fcr &= ~(fip->fc_clockmask); + immap->im_cpmux.cmx_fcr |= fip->fc_clockroute; +} + +static void __init +init_fcc_param(fcc_info_t *fip, struct net_device *dev, + volatile immap_t *immap) +{ + unsigned char *eap; + unsigned long mem_addr; + bd_t *bd; + int i, j; + struct fcc_enet_private *cep; + volatile fcc_enet_t *ep; + volatile cbd_t *bdp; + volatile cpm8260_t *cp; + + cep = (struct fcc_enet_private *)(dev->priv); + ep = cep->ep; + cp = cpmp; + + bd = (bd_t *)__res; + + /* Zero the whole thing.....I must have missed some individually. + * It works when I do this. + */ + memset((char *)ep, 0, sizeof(fcc_enet_t)); + + /* Allocate space for the buffer descriptors in the DP ram. + * These are relative offsets in the DP ram address space. + * Initialize base addresses for the buffer descriptors. + */ +#if 0 + /* I really want to do this, but for some reason it doesn't + * work with the data cache enabled, so I allocate from the + * main memory instead. + */ + i = m8260_cpm_dpalloc(sizeof(cbd_t) * RX_RING_SIZE, 8); + ep->fen_genfcc.fcc_rbase = (uint)&immap->im_dprambase[i]; + cep->rx_bd_base = (cbd_t *)&immap->im_dprambase[i]; + + i = m8260_cpm_dpalloc(sizeof(cbd_t) * TX_RING_SIZE, 8); + ep->fen_genfcc.fcc_tbase = (uint)&immap->im_dprambase[i]; + cep->tx_bd_base = (cbd_t *)&immap->im_dprambase[i]; +#else + cep->rx_bd_base = (cbd_t *)m8260_cpm_hostalloc(sizeof(cbd_t) * RX_RING_SIZE, 8); + ep->fen_genfcc.fcc_rbase = __pa(cep->rx_bd_base); + cep->tx_bd_base = (cbd_t *)m8260_cpm_hostalloc(sizeof(cbd_t) * TX_RING_SIZE, 8); + ep->fen_genfcc.fcc_tbase = __pa(cep->tx_bd_base); +#endif + + cep->dirty_tx = cep->cur_tx = cep->tx_bd_base; + cep->cur_rx = cep->rx_bd_base; + + ep->fen_genfcc.fcc_rstate = (CPMFCR_GBL | CPMFCR_EB) << 24; + ep->fen_genfcc.fcc_tstate = (CPMFCR_GBL | CPMFCR_EB) << 24; + + /* Set maximum bytes per receive buffer. + * It must be a multiple of 32. + */ + ep->fen_genfcc.fcc_mrblr = PKT_MAXBLR_SIZE; + + /* Allocate space in the reserved FCC area of DPRAM for the + * internal buffers. No one uses this space (yet), so we + * can do this. Later, we will add resource management for + * this area. + */ + mem_addr = CPM_FCC_SPECIAL_BASE + (fip->fc_fccnum * 128); + ep->fen_genfcc.fcc_riptr = mem_addr; + ep->fen_genfcc.fcc_tiptr = mem_addr+32; + ep->fen_padptr = mem_addr+64; + memset((char *)(&(immap->im_dprambase[(mem_addr+64)])), 0x88, 32); + + ep->fen_genfcc.fcc_rbptr = 0; + ep->fen_genfcc.fcc_tbptr = 0; + ep->fen_genfcc.fcc_rcrc = 0; + ep->fen_genfcc.fcc_tcrc = 0; + ep->fen_genfcc.fcc_res1 = 0; + ep->fen_genfcc.fcc_res2 = 0; + + ep->fen_camptr = 0; /* CAM isn't used in this driver */ + + /* Set CRC preset and mask. + */ + ep->fen_cmask = 0xdebb20e3; + ep->fen_cpres = 0xffffffff; + + ep->fen_crcec = 0; /* CRC Error counter */ + ep->fen_alec = 0; /* alignment error counter */ + ep->fen_disfc = 0; /* discard frame counter */ + ep->fen_retlim = 15; /* Retry limit threshold */ + ep->fen_pper = 0; /* Normal persistence */ + + /* Clear hash filter tables. + */ + ep->fen_gaddrh = 0; + ep->fen_gaddrl = 0; + ep->fen_iaddrh = 0; + ep->fen_iaddrl = 0; + + /* Clear the Out-of-sequence TxBD. + */ + ep->fen_tfcstat = 0; + ep->fen_tfclen = 0; + ep->fen_tfcptr = 0; + + ep->fen_mflr = PKT_MAXBUF_SIZE; /* maximum frame length register */ + ep->fen_minflr = PKT_MINBUF_SIZE; /* minimum frame length register */ + + /* Set Ethernet station address. + * + * This is supplied in the board information structure, so we + * copy that into the controller. + * So, far we have only been given one Ethernet address. We make + * it unique by setting a few bits in the upper byte of the + * non-static part of the address. + */ + eap = (unsigned char *)&(ep->fen_paddrh); + for (i=5; i>=0; i--) { + if (i == 3) { + dev->dev_addr[i] = bd->bi_enetaddr[i]; + dev->dev_addr[i] |= (1 << (7 - fip->fc_fccnum)); + *eap++ = dev->dev_addr[i]; + } + else { + *eap++ = dev->dev_addr[i] = bd->bi_enetaddr[i]; + } + } + + ep->fen_taddrh = 0; + ep->fen_taddrm = 0; + ep->fen_taddrl = 0; + + ep->fen_maxd1 = PKT_MAXDMA_SIZE; /* maximum DMA1 length */ + ep->fen_maxd2 = PKT_MAXDMA_SIZE; /* maximum DMA2 length */ + + /* Clear stat counters, in case we ever enable RMON. + */ + ep->fen_octc = 0; + ep->fen_colc = 0; + ep->fen_broc = 0; + ep->fen_mulc = 0; + ep->fen_uspc = 0; + ep->fen_frgc = 0; + ep->fen_ospc = 0; + ep->fen_jbrc = 0; + ep->fen_p64c = 0; + ep->fen_p65c = 0; + ep->fen_p128c = 0; + ep->fen_p256c = 0; + ep->fen_p512c = 0; + ep->fen_p1024c = 0; + + ep->fen_rfthr = 0; /* Suggested by manual */ + ep->fen_rfcnt = 0; + ep->fen_cftype = 0; + + /* Now allocate the host memory pages and initialize the + * buffer descriptors. + */ + bdp = cep->tx_bd_base; + for (i=0; icbd_sc = 0; + bdp->cbd_datlen = 0; + bdp->cbd_bufaddr = 0; + bdp++; + } + + /* Set the last buffer to wrap. + */ + bdp--; + bdp->cbd_sc |= BD_SC_WRAP; + + bdp = cep->rx_bd_base; + for (i=0; icbd_sc = BD_ENET_RX_EMPTY | BD_ENET_RX_INTR; + bdp->cbd_datlen = 0; + bdp->cbd_bufaddr = __pa(mem_addr); + mem_addr += FCC_ENET_RX_FRSIZE; + bdp++; + } + } + + /* Set the last buffer to wrap. + */ + bdp--; + bdp->cbd_sc |= BD_SC_WRAP; + + /* Let's re-initialize the channel now. We have to do it later + * than the manual describes because we have just now finished + * the BD initialization. + */ + cp->cp_cpcr = mk_cr_cmd(fip->fc_cpmpage, fip->fc_cpmblock, 0x0c, + CPM_CR_INIT_TRX) | CPM_CR_FLG; + while (cp->cp_cpcr & CPM_CR_FLG); + + cep->skb_cur = cep->skb_dirty = 0; +} + +/* Let 'er rip. +*/ +static void __init +init_fcc_startup(fcc_info_t *fip, struct net_device *dev) +{ + volatile fcc_t *fccp; + struct fcc_enet_private *cep; + + cep = (struct fcc_enet_private *)(dev->priv); + fccp = cep->fccp; + + fccp->fcc_fcce = 0xffff; /* Clear any pending events */ + + /* Enable interrupts for transmit error, complete frame + * received, and any transmit buffer we have also set the + * interrupt flag. + */ + fccp->fcc_fccm = (FCC_ENET_TXE | FCC_ENET_RXF | FCC_ENET_TXB); + + /* Install our interrupt handler. + */ + if (request_8xxirq(fip->fc_interrupt, fcc_enet_interrupt, 0, + "fenet", dev) < 0) + printk("Can't get FCC IRQ %d\n", fip->fc_interrupt); + + /* Set GFMR to enable Ethernet operating mode. + */ + fccp->fcc_gfmr = (FCC_GFMR_TCI | FCC_GFMR_MODE_ENET); + + /* Set sync/delimiters. + */ + fccp->fcc_fdsr = 0xd555; + + /* Set protocol specific processing mode for Ethernet. + * This has to be adjusted for Full Duplex operation after we can + * determine how to detect that. + */ + fccp->fcc_fpsmr = FCC_PSMR_ENCRC; + + /* And last, enable the transmit and receive processing. + */ + fccp->fcc_gfmr |= (FCC_GFMR_ENR | FCC_GFMR_ENT); +} + +/* MII command/status interface. + * I'm not going to describe all of the details. You can find the + * protocol definition in many other places, including the data sheet + * of most PHY parts. + * I wonder what "they" were thinking (maybe weren't) when they leave + * the I2C in the CPM but I have to toggle these bits...... + */ +static uint +mii_send_receive(fcc_info_t *fip, uint cmd) +{ + unsigned long flags; + uint retval; + int read_op, i; + volatile immap_t *immap; + volatile iop8260_t *io; + + immap = (immap_t *)IMAP_ADDR; + io = &immap->im_ioport; + + /* When we get here, both clock and data are high, outputs. + * Output is open drain. + * Data transitions on high->low clock, is valid on low->high clock. + * Spec says edge transitions no closer than 160 nSec, minimum clock + * cycle 400 nSec. I could only manage about 500 nSec edges with + * an XOR loop, so I won't worry about delays yet. + * I disable interrupts during bit flipping to ensure atomic + * updates of the registers. I do lots of interrupt disable/enable + * to ensure we don't hang out too long with interrupts disabled. + */ + + /* First, crank out 32 1-bits as preamble. + * This is 64 transitions to clock the bits, with clock/data + * left high. + */ + save_flags(flags); + cli(); + for (i=0; i<64; i++) { + io->iop_pdatc ^= fip->fc_mdck; + udelay(0); + } + restore_flags(flags); + + read_op = ((cmd & 0xf0000000) == 0x60000000); + + /* We return the command word on a write op, or the command portion + * plus the new data on a read op. This is what the 8xx FEC does, + * and it allows the functions to simply look at the returned value + * and know the PHY/register as well. + */ + if (read_op) + retval = cmd; + else + retval = (cmd >> 16); + + /* Clock out the first 16 MS bits of the command. + */ + save_flags(flags); + cli(); + for (i=0; i<16; i++) { + io->iop_pdatc &= ~(fip->fc_mdck); + if (cmd & 0x80000000) + io->iop_pdatc |= fip->fc_mdio; + else + io->iop_pdatc &= ~(fip->fc_mdio); + cmd <<= 1; + io->iop_pdatc |= fip->fc_mdck; + udelay(0); + } + + /* Do the turn-around. If read op, we make the IO and input. + * If write op, do the 1/0 thing. + */ + io->iop_pdatc &= ~(fip->fc_mdck); + if (read_op) + io->iop_pdirc &= ~(fip->fc_mdio); + else + io->iop_pdatc |= fip->fc_mdio; + io->iop_pdatc |= fip->fc_mdck; + + /* I do this mainly to get just a little delay. + */ + restore_flags(flags); + save_flags(flags); + cli(); + io->iop_pdatc &= ~(fip->fc_mdck); + io->iop_pdirc &= ~(fip->fc_mdio); + io->iop_pdatc |= fip->fc_mdck; + + restore_flags(flags); + save_flags(flags); + cli(); + + /* For read, clock in 16 bits. For write, clock out + * rest of command. + */ + if (read_op) { + io->iop_pdatc &= ~(fip->fc_mdck); + udelay(0); + for (i=0; i<16; i++) { + io->iop_pdatc |= fip->fc_mdck; + udelay(0); + retval <<= 1; + if (io->iop_pdatc & fip->fc_mdio) + retval |= 1; + io->iop_pdatc &= ~(fip->fc_mdck); + udelay(0); + } + } + else { + for (i=0; i<16; i++) { + io->iop_pdatc &= ~(fip->fc_mdck); + if (cmd & 0x80000000) + io->iop_pdatc |= fip->fc_mdio; + else + io->iop_pdatc &= ~(fip->fc_mdio); + cmd <<= 1; + io->iop_pdatc |= fip->fc_mdck; + udelay(0); + } + io->iop_pdatc &= ~(fip->fc_mdck); + } + restore_flags(flags); + + /* Some diagrams show two 1 bits for "idle". I don't know if + * this is really necessary or if it was just to indicate nothing + * is going to happen for a while. + * Make the data pin an output, set the data high, and clock it. + */ + save_flags(flags); + cli(); + io->iop_pdatc |= fip->fc_mdio; + io->iop_pdirc |= fip->fc_mdio; + for (i=0; i<3; i++) + io->iop_pdatc ^= fip->fc_mdck; + restore_flags(flags); + + /* We exit with the same conditions as entry. + */ + return(retval); +} diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/8260_io/uart.c linux/arch/ppc/8260_io/uart.c --- v2.4.0-test8/linux/arch/ppc/8260_io/uart.c Wed Jul 5 11:24:40 2000 +++ linux/arch/ppc/8260_io/uart.c Sun Sep 17 09:48:05 2000 @@ -977,8 +977,7 @@ } if (from_user) { - if (c != - copy_from_user(__va(bdp->cbd_bufaddr), buf, c)) { + if (copy_from_user(__va(bdp->cbd_bufaddr), buf, c)) { if (!ret) ret = -EFAULT; break; @@ -2396,10 +2395,10 @@ io->iop_pdird &= ~0x00800000; io->iop_psord &= ~0x00c00000; #if USE_SMC2 - io->iop_ppara |= 0x01800000; - io->iop_pdira |= 0x00800000; - io->iop_pdira &= ~0x01000000; - io->iop_psora &= ~0x01800000; + io->iop_ppara |= 0x00c00000; + io->iop_pdira |= 0x00400000; + io->iop_pdira &= ~0x00800000; + io->iop_psora &= ~0x00c00000; #endif /* Configure SCC2 and SCC3. Be careful about the fine print. @@ -2473,11 +2472,11 @@ * descriptors from dual port ram, and a character * buffer area from host mem. */ - dp_addr = m8260_cpm_dpalloc(sizeof(cbd_t) * RX_NUM_FIFO); + dp_addr = m8260_cpm_dpalloc(sizeof(cbd_t) * RX_NUM_FIFO, 8); /* Allocate space for FIFOs in the host memory. */ - mem_addr = m8260_cpm_hostalloc(RX_NUM_FIFO * RX_BUF_SIZE); + mem_addr = m8260_cpm_hostalloc(RX_NUM_FIFO * RX_BUF_SIZE, 1); /* Set the physical address of the host memory * buffers in the buffer descriptors, and the @@ -2506,11 +2505,11 @@ sup->scc_genscc.scc_rbase = dp_addr; } - dp_addr = m8260_cpm_dpalloc(sizeof(cbd_t) * TX_NUM_FIFO); + dp_addr = m8260_cpm_dpalloc(sizeof(cbd_t) * TX_NUM_FIFO, 8); /* Allocate space for FIFOs in the host memory. */ - mem_addr = m8260_cpm_hostalloc(TX_NUM_FIFO * TX_BUF_SIZE); + mem_addr = m8260_cpm_hostalloc(TX_NUM_FIFO * TX_BUF_SIZE, 1); /* Set the physical address of the host memory * buffers in the buffer descriptors, and the @@ -2716,11 +2715,11 @@ /* Allocate space for two buffer descriptors in the DP ram. */ - dp_addr = m8260_cpm_dpalloc(sizeof(cbd_t) * 2); + dp_addr = m8260_cpm_dpalloc(sizeof(cbd_t) * 2, 8); /* Allocate space for two 2 byte FIFOs in the host memory. */ - mem_addr = m8260_cpm_hostalloc(4); + mem_addr = m8260_cpm_hostalloc(4, 1); /* Set the physical address of the host memory buffers in * the buffer descriptors. diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/8xx_io/enet.c linux/arch/ppc/8xx_io/enet.c --- v2.4.0-test8/linux/arch/ppc/8xx_io/enet.c Thu Jul 13 09:42:50 2000 +++ linux/arch/ppc/8xx_io/enet.c Sun Sep 17 09:48:05 2000 @@ -484,8 +484,11 @@ cep->stats.rx_bytes += pkt_len; /* This does 16 byte alignment, much more than we need. - */ - skb = dev_alloc_skb(pkt_len); + * The packet length includes FCS, but we don't want to + * include that when passing upstream as it messes up + * bridging applications. + */ + skb = dev_alloc_skb(pkt_len-4); if (skb == NULL) { printk("%s: Memory squeeze, dropping packet.\n", dev->name); @@ -493,10 +496,10 @@ } else { skb->dev = dev; - skb_put(skb,pkt_len); /* Make room */ + skb_put(skb,pkt_len-4); /* Make room */ eth_copy_and_sum(skb, (unsigned char *)__va(bdp->cbd_bufaddr), - pkt_len, 0); + pkt_len-4, 0); skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); } diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/8xx_io/fec.c linux/arch/ppc/8xx_io/fec.c --- v2.4.0-test8/linux/arch/ppc/8xx_io/fec.c Mon Jun 19 13:25:06 2000 +++ linux/arch/ppc/8xx_io/fec.c Sun Sep 17 09:48:06 2000 @@ -669,18 +669,21 @@ #endif /* This does 16 byte alignment, exactly what we need. + * The packet length includes FCS, but we don't want to + * include that when passing upstream as it messes up + * bridging applications. */ - skb = dev_alloc_skb(pkt_len); + skb = dev_alloc_skb(pkt_len-4); if (skb == NULL) { printk("%s: Memory squeeze, dropping packet.\n", dev->name); fep->stats.rx_dropped++; } else { skb->dev = dev; - skb_put(skb,pkt_len); /* Make room */ + skb_put(skb,pkt_len-4); /* Make room */ eth_copy_and_sum(skb, (unsigned char *)__va(bdp->cbd_bufaddr), - pkt_len, 0); + pkt_len-4, 0); skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); } diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/amiga/time.c linux/arch/ppc/amiga/time.c --- v2.4.0-test8/linux/arch/ppc/amiga/time.c Thu Oct 7 10:17:08 1999 +++ linux/arch/ppc/amiga/time.c Mon Sep 11 08:39:48 2000 @@ -11,10 +11,6 @@ #include -static inline unsigned long mktime(unsigned int year, unsigned int mon, - unsigned int day, unsigned int hour, - unsigned int min, unsigned int sec); - unsigned long m68k_get_rtc_time(void) { unsigned int year, mon, day, hour, min, sec; @@ -36,38 +32,6 @@ return mach_set_clock_mmss (nowtime); return -1; } - -/* Converts Gregorian date to seconds since 1970-01-01 00:00:00. - * Assumes input in normal date format, i.e. 1980-12-31 23:59:59 - * => year=1980, mon=12, day=31, hour=23, min=59, sec=59. - * - * [For the Julian calendar (which was used in Russia before 1917, - * Britain & colonies before 1752, anywhere else before 1582, - * and is still in use by some communities) leave out the - * -year/100+year/400 terms, and add 10.] - * - * This algorithm was first published by Gauss (I think). - * - * WARNING: this function will overflow on 2106-02-07 06:28:16 on - * machines were long is 32-bit! (However, as time_t is signed, we - * will already get problems at other places on 2038-01-19 03:14:08) - */ -static inline unsigned long mktime(unsigned int year, unsigned int mon, - unsigned int day, unsigned int hour, - unsigned int min, unsigned int sec) -{ - if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */ - mon += 12; /* Puts Feb last since it has leap day */ - year -= 1; - } - return ((( - (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) + - year*365 - 719499 - )*24 + hour /* now have hours */ - )*60 + min /* now have minutes */ - )*60 + sec; /* finally seconds */ -} - void apus_heartbeat (void) { diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/chrpboot/Makefile linux/arch/ppc/chrpboot/Makefile --- v2.4.0-test8/linux/arch/ppc/chrpboot/Makefile Mon Jun 19 17:59:35 2000 +++ linux/arch/ppc/chrpboot/Makefile Sun Sep 17 09:48:06 2000 @@ -67,11 +67,13 @@ zImage: $(OBJS) no_initrd.o addnote $(LD) $(LD_ARGS) -o $@ $(OBJS) no_initrd.o $(LIBS) - ./addnote $@ + cp $@ $@.rs6k + ./addnote $@.rs6k zImage.initrd: $(OBJS) initrd.o addnote $(LD) $(LD_ARGS) -o $@ $(OBJS) initrd.o $(LIBS) - ./addnote $@ + cp $@ $@.rs6k + ./addnote $@.rs6k else znetboot: diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/chrpboot/addnote.c linux/arch/ppc/chrpboot/addnote.c --- v2.4.0-test8/linux/arch/ppc/chrpboot/addnote.c Mon Jun 19 17:59:35 2000 +++ linux/arch/ppc/chrpboot/addnote.c Sun Sep 17 09:48:06 2000 @@ -22,12 +22,23 @@ #define N_DESCR 6 unsigned int descr[N_DESCR] = { +#if 1 + /* values for IBM RS/6000 machines */ 0xffffffff, /* real-mode = true */ 0x00c00000, /* real-base, i.e. where we expect OF to be */ 0xffffffff, /* real-size */ 0xffffffff, /* virt-base */ 0xffffffff, /* virt-size */ 0x4000, /* load-base */ +#else + /* values for longtrail CHRP */ + 0, /* real-mode = false */ + 0xffffffff, /* real-base */ + 0xffffffff, /* real-size */ + 0xffffffff, /* virt-base */ + 0xffffffff, /* virt-size */ + 0x00600000, /* load-base */ +#endif }; unsigned char buf[512]; @@ -63,7 +74,7 @@ unsigned char elf_magic[4] = { 0x7f, 'E', 'L', 'F' }; -main(int ac, char **av) +int main(int ac, char **av) { int fd, n, i; int ph, ps, np; diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/coffboot/Makefile linux/arch/ppc/coffboot/Makefile --- v2.4.0-test8/linux/arch/ppc/coffboot/Makefile Thu Jul 13 09:42:50 2000 +++ linux/arch/ppc/coffboot/Makefile Sun Sep 17 09:48:06 2000 @@ -8,7 +8,7 @@ CFLAGS = $(CPPFLAGS) -O -fno-builtin OBJCOPY_ARGS = -O aixcoff-rs6000 -R .stab -R .stabstr -R .comment COFF_LD_ARGS = -e _start -T ld.script -Ttext 500000 -Tdata 510000 -Bstatic -CHRP_LD_ARGS = -Ttext 0x00400000 +CHRP_LD_ARGS = -Ttext 0x01000000 COFFOBJS = coffcrt0.o start.o coffmain.o misc.o string.o zlib.o image.o CHRPOBJS = crt0.o start.o chrpmain.o misc.o string.o zlib.o image.o diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/coffboot/chrpmain.c linux/arch/ppc/coffboot/chrpmain.c --- v2.4.0-test8/linux/arch/ppc/coffboot/chrpmain.c Wed Feb 9 19:43:47 2000 +++ linux/arch/ppc/coffboot/chrpmain.c Sun Sep 17 09:48:06 2000 @@ -22,13 +22,18 @@ #define get_16be(x) (*(unsigned short *)(x)) #define get_32be(x) (*(unsigned *)(x)) -#define RAM_START 0x00000000 -#define RAM_END (8<<20) +#define RAM_END (16 << 20) #define PROG_START 0x00010000 +#define PROG_SIZE 0x003f0000 + +#define SCRATCH_SIZE (128 << 10) char *avail_ram; -char *end_avail; +char *begin_avail, *end_avail; +char *avail_high; +unsigned int heap_use; +unsigned int heap_max; extern char _end[]; extern char image_data[]; @@ -60,29 +65,30 @@ im = image_data; len = image_len; /* claim 3MB starting at PROG_START */ - claim(PROG_START, 3 << 20, 0); + claim(PROG_START, PROG_SIZE, 0); dst = (void *) PROG_START; if (im[0] == 0x1f && im[1] == 0x8b) { - /* claim 512kB for scratch space */ - avail_ram = (char *) claim(0, 512 << 10, 0x10); - end_avail = avail_ram + (512 << 10); - printf("avail_ram = %x\n", avail_ram); + /* claim some memory for scratch space */ + avail_ram = (char *) claim(0, SCRATCH_SIZE, 0x10); + begin_avail = avail_high = avail_ram; + end_avail = avail_ram + SCRATCH_SIZE; + printf("heap at 0x%x\n", avail_ram); printf("gunzipping (0x%x <- 0x%x:0x%0x)...", dst, im, im+len); - gunzip(dst, 3 << 20, im, &len); + gunzip(dst, PROG_SIZE, im, &len); printf("done %u bytes\n", len); + printf("%u bytes of heap consumed, max in use %u\n", + avail_high - begin_avail, heap_max); } else { memmove(dst, im, len); } flush_cache(dst, len); - stop_imac_ethernet(); - stop_imac_usb(); make_bi_recs((unsigned long) dst + len); sa = (unsigned long)PROG_START; printf("start address = 0x%x\n", sa); - (*(void (*)())sa)(0, 0, prom, a1, a2); + (*(void (*)())sa)(a1, a2, prom); printf("returned?\n"); @@ -122,6 +128,7 @@ rec = (struct bi_record *)((unsigned long)rec + rec->size); } +#if 0 #define eieio() asm volatile("eieio"); void stop_imac_ethernet(void) @@ -172,14 +179,35 @@ *usb_ctrl = 0x01000000; /* cpu_to_le32(1) */ eieio(); } +#endif + +struct memchunk { + unsigned int size; + struct memchunk *next; +}; + +static struct memchunk *freechunks; void *zalloc(void *x, unsigned items, unsigned size) { - void *p = avail_ram; + void *p; + struct memchunk **mpp, *mp; size *= items; size = (size + 7) & -8; + heap_use += size; + if (heap_use > heap_max) + heap_max = heap_use; + for (mpp = &freechunks; (mp = *mpp) != 0; mpp = &mp->next) { + if (mp->size == size) { + *mpp = mp->next; + return mp; + } + } + p = avail_ram; avail_ram += size; + if (avail_ram > avail_high) + avail_high = avail_ram; if (avail_ram > end_avail) { printf("oops... out of memory\n"); pause(); @@ -189,6 +217,17 @@ void zfree(void *x, void *addr, unsigned nb) { + struct memchunk *mp = addr; + + nb = (nb + 7) & -8; + heap_use -= nb; + if (avail_ram == addr + nb) { + avail_ram = addr; + return; + } + mp->size = nb; + mp->next = freechunks; + freechunks = mp; } #define HEAD_CRC 2 diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/config.in linux/arch/ppc/config.in --- v2.4.0-test8/linux/arch/ppc/config.in Tue Aug 22 11:41:14 2000 +++ linux/arch/ppc/config.in Tue Sep 19 10:57:30 2000 @@ -88,11 +88,15 @@ if [ "$CONFIG_4xx" = "y" -o "$CONFIG_8xx" = "y" ]; then bool 'Math emulation' CONFIG_MATH_EMULATION fi + endmenu mainmenu_option next_comment comment 'General setup' +bool 'High memory support (experimental)' CONFIG_HIGHMEM +bool 'Mac-on-Linux support' CONFIG_MOL + define_bool CONFIG_ISA n define_bool CONFIG_SBUS n @@ -140,20 +144,6 @@ bool 'Backward compatibility mode for Xpmac' CONFIG_FB_COMPAT_XPMAC fi - bool 'Power management support for PowerBooks' CONFIG_PMAC_PBOOK - bool 'Support for PowerMac floppy' CONFIG_MAC_FLOPPY - tristate 'Support for PowerMac serial ports' CONFIG_MAC_SERIAL - if [ "$CONFIG_MAC_SERIAL" = "y" ]; then - bool ' Support for console on serial port' CONFIG_SERIAL_CONSOLE - fi - bool 'Apple Desktop Bus (ADB) support' CONFIG_ADB - if [ "$CONFIG_ADB" = "y" ]; then - bool ' Include CUDA ADB driver' CONFIG_ADB_CUDA - bool ' Include MacIO ADB driver' CONFIG_ADB_MACIO - bool ' Include PMU (Powerbook) ADB driver' CONFIG_ADB_PMU - bool 'Support for ADB keyboard' CONFIG_ADB_KEYBOARD - bool 'Support for ADB mouse' CONFIG_ADBMOUSE - fi tristate 'Support for /dev/rtc' CONFIG_PPC_RTC bool 'Support for Open Firmware device tree in /proc' CONFIG_PROC_DEVICETREE bool 'Support for early boot text console (BootX only)' CONFIG_BOOTX_TEXT @@ -192,7 +182,7 @@ source drivers/mtd/Config.in source drivers/pnp/Config.in source drivers/block/Config.in -#source drivers.new/Config.in +source drivers/md/Config.in if [ "$CONFIG_NET" = "y" ]; then source net/Config.in @@ -262,6 +252,43 @@ source drivers/video/Config.in endmenu +source drivers/input/Config.in + +mainmenu_option next_comment +comment 'Macintosh device drivers' + +if [ "$CONFIG_ALL_PPC" = "y" ]; then + # we want to change this to something like CONFIG_SYSCTRL_CUDA/PMU + bool 'Support for CUDA based PowerMacs' CONFIG_ADB_CUDA + bool 'Support for PMU based PowerMacs' CONFIG_ADB_PMU + if [ "$CONFIG_ADB_PMU" = "y" ]; then + bool ' Power management support for PowerBooks' CONFIG_PMAC_PBOOK + # made a separate option since backlight may end up beeing used + # on non-powerbook machines (but only on PMU based ones AFAIK) + bool ' Backlight control for LCD screens' CONFIG_PMAC_BACKLIGHT + fi + bool 'Support for PowerMac floppy' CONFIG_MAC_FLOPPY + tristate 'Support for PowerMac serial ports' CONFIG_MAC_SERIAL + if [ "$CONFIG_MAC_SERIAL" = "y" ]; then + bool ' Support for console on serial port' CONFIG_SERIAL_CONSOLE + fi + bool 'Apple Desktop Bus (ADB) support' CONFIG_ADB + if [ "$CONFIG_ADB" = "y" ]; then + bool ' Include MacIO (CHRP) ADB driver' CONFIG_ADB_MACIO + fi +fi +if [ "$CONFIG_ADB" = "y" ]; then + dep_bool ' Use input layer for ADB devices' CONFIG_INPUT_ADBHID $CONFIG_INPUT + if [ "$CONFIG_INPUT_ADBHID" = "y" ]; then + define_bool CONFIG_MAC_HID y + bool ' Support for ADB raw keycodes' CONFIG_MAC_ADBKEYCODES + bool ' Support for mouse button 2+3 emulation' CONFIG_MAC_EMUMOUSEBTN + else + bool ' Support for ADB keyboard (old driver)' CONFIG_ADB_KEYBOARD + fi +fi +endmenu + source drivers/char/Config.in source drivers/media/Config.in @@ -287,7 +314,6 @@ fi source drivers/usb/Config.in -source drivers/input/Config.in mainmenu_option next_comment comment 'Kernel hacking' diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/configs/common_defconfig linux/arch/ppc/configs/common_defconfig --- v2.4.0-test8/linux/arch/ppc/configs/common_defconfig Mon Jun 19 17:59:36 2000 +++ linux/arch/ppc/configs/common_defconfig Sun Sep 17 09:48:06 2000 @@ -1,5 +1,5 @@ # -# Automatically generated by make menuconfig: don't edit +# Automatically generated make config: don't edit # # CONFIG_UID16 is not set @@ -9,12 +9,20 @@ CONFIG_EXPERIMENTAL=y # +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODVERSIONS=y +CONFIG_KMOD=y + +# # Platform support # CONFIG_PPC=y CONFIG_6xx=y # CONFIG_4xx is not set -# CONFIG_PPC64BRIDGE is not set +# CONFIG_POWER3 is not set +# CONFIG_POWER4 is not set # CONFIG_8260 is not set # CONFIG_8xx is not set CONFIG_ALL_PPC=y @@ -25,15 +33,9 @@ CONFIG_ALTIVEC=y # -# Loadable module support -# -CONFIG_MODULES=y -CONFIG_MODVERSIONS=y -CONFIG_KMOD=y - -# # General setup # +# CONFIG_HIGHMEM is not set # CONFIG_ISA is not set # CONFIG_SBUS is not set CONFIG_PCI=y @@ -44,8 +46,8 @@ CONFIG_KCORE_ELF=y CONFIG_BINFMT_ELF=y CONFIG_KERNEL_ELF=y -# CONFIG_BINFMT_MISC is not set -# CONFIG_PCI_NAMES is not set +CONFIG_BINFMT_MISC=m +CONFIG_PCI_NAMES=y # CONFIG_HOTPLUG is not set # CONFIG_PCMCIA is not set @@ -57,21 +59,18 @@ CONFIG_FB=y CONFIG_FB_COMPAT_XPMAC=y CONFIG_PMAC_PBOOK=y -CONFIG_MAC_FLOPPY=y -CONFIG_MAC_SERIAL=y -# CONFIG_SERIAL_CONSOLE is not set -CONFIG_ADB=y -CONFIG_ADB_CUDA=y -CONFIG_ADB_MACIO=y -CONFIG_ADB_PMU=y -CONFIG_ADB_KEYBOARD=y -CONFIG_ADBMOUSE=y +CONFIG_PPC_RTC=y CONFIG_PROC_DEVICETREE=y CONFIG_BOOTX_TEXT=y # CONFIG_MOTOROLA_HOTSWAP is not set # CONFIG_CMDLINE_BOOL is not set # +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# # Plug and Play configuration # # CONFIG_PNP is not set @@ -90,8 +89,11 @@ # CONFIG_BLK_DEV_LVM is not set # CONFIG_BLK_DEV_MD is not set # CONFIG_MD_LINEAR is not set -# CONFIG_MD_STRIPED is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y # @@ -109,22 +111,24 @@ 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_MROUTE is not set -CONFIG_IP_ALIAS=y +# CONFIG_INET_ECN is not set CONFIG_SYN_COOKIES=y -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=m # 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_ECONET is not set # CONFIG_WAN_ROUTER is not set @@ -145,26 +149,42 @@ # IDE, ATA and ATAPI Block devices # CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# # CONFIG_BLK_DEV_HD_IDE is not set # CONFIG_BLK_DEV_HD is not set CONFIG_BLK_DEV_IDEDISK=y # CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set # CONFIG_BLK_DEV_IDECS is not set CONFIG_BLK_DEV_IDECD=y # CONFIG_BLK_DEV_IDETAPE is not set -# CONFIG_BLK_DEV_IDEFLOPPY is not set +CONFIG_BLK_DEV_IDEFLOPPY=y CONFIG_BLK_DEV_IDESCSI=y + +# +# IDE chipset support/bugfixes +# # CONFIG_BLK_DEV_CMD640 is not set # CONFIG_BLK_DEV_CMD640_ENHANCED is not set # CONFIG_BLK_DEV_ISAPNP is not set # CONFIG_BLK_DEV_RZ1000 is not set CONFIG_BLK_DEV_IDEPCI=y -# CONFIG_IDEPCI_SHARE_IRQ is not set +CONFIG_IDEPCI_SHARE_IRQ=y CONFIG_BLK_DEV_IDEDMA_PCI=y # CONFIG_BLK_DEV_OFFBOARD is not set CONFIG_IDEDMA_PCI_AUTO=y CONFIG_BLK_DEV_IDEDMA=y -CONFIG_IDEDMA_PCI_EXPERIMENTAL=y # CONFIG_IDEDMA_PCI_WIP is not set # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set # CONFIG_BLK_DEV_AEC62XX is not set @@ -173,37 +193,40 @@ # CONFIG_WDC_ALI15X3 is not set # CONFIG_BLK_DEV_AMD7409 is not set # CONFIG_AMD7409_OVERRIDE is not set -# CONFIG_BLK_DEV_CMD64X is not set -# CONFIG_CMD64X_RAID is not set +CONFIG_BLK_DEV_CMD64X=y # CONFIG_BLK_DEV_CY82C693 is not set # CONFIG_BLK_DEV_CS5530 is not set # CONFIG_BLK_DEV_HPT34X is not set # CONFIG_HPT34X_AUTODMA is not set # CONFIG_BLK_DEV_HPT366 is not set -# CONFIG_HPT366_FIP is not set -# CONFIG_HPT366_MODE3 is not set # CONFIG_BLK_DEV_NS87415 is not set # CONFIG_BLK_DEV_OPTI621 is not set # CONFIG_BLK_DEV_PDC202XX is not set # CONFIG_PDC202XX_BURST is not set -# CONFIG_PDC202XX_MASTER is not set # CONFIG_BLK_DEV_SIS5513 is not set # CONFIG_BLK_DEV_TRM290 is not set # CONFIG_BLK_DEV_VIA82CXXX is not set # CONFIG_VIA82CXXX_TUNING is not set -# CONFIG_BLK_DEV_SL82C105 is not set +CONFIG_BLK_DEV_SL82C105=y CONFIG_BLK_DEV_IDE_PMAC=y CONFIG_BLK_DEV_IDEDMA_PMAC=y -CONFIG_IDEDMA_PMAC_AUTO=y +CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO=y CONFIG_BLK_DEV_IDEDMA=y +CONFIG_BLK_DEV_IDEPCI=y # CONFIG_IDE_CHIPSETS is not set CONFIG_IDEDMA_AUTO=y +# CONFIG_IDEDMA_IVB is not set +# CONFIG_DMA_NONPCI is not set CONFIG_BLK_DEV_IDE_MODES=y # # SCSI support # CONFIG_SCSI=y + +# +# SCSI support type (disk, tape, CD-ROM) +# CONFIG_BLK_DEV_SD=y CONFIG_SD_EXTRA_DEVS=40 CONFIG_CHR_DEV_ST=y @@ -211,6 +234,10 @@ CONFIG_BLK_DEV_SR_VENDOR=y CONFIG_SR_EXTRA_DEVS=2 CONFIG_CHR_DEV_SG=y + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# # CONFIG_SCSI_DEBUG_QUEUES is not set # CONFIG_SCSI_MULTI_LUN is not set CONFIG_SCSI_CONSTANTS=y @@ -296,6 +323,7 @@ # CONFIG_DUMMY is not set # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set # CONFIG_ETHERTAP is not set # CONFIG_NET_SB1000 is not set @@ -327,8 +355,9 @@ # CONFIG_DM9102 is not set # CONFIG_EEPRO100 is not set # CONFIG_LNE390 is not set -# CONFIG_NE3210 is not set +# CONFIG_NATSEMI is not set # CONFIG_NE2K_PCI is not set +# CONFIG_NE3210 is not set # CONFIG_RTL8129 is not set # CONFIG_8139TOO is not set # CONFIG_SIS900 is not set @@ -347,11 +376,13 @@ # CONFIG_FDDI is not set # CONFIG_HIPPI is not set CONFIG_PPP=y -# CONFIG_PPP_MULTILINK is not set -# CONFIG_PPP_ASYNC is not set +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=y # CONFIG_PPP_SYNC_TTY is not set -# CONFIG_PPP_DEFLATE is not set +CONFIG_PPP_DEFLATE=y # CONFIG_PPP_BSDCOMP is not set +# CONFIG_PPPOE is not set # CONFIG_SLIP is not set # @@ -404,12 +435,13 @@ # CONFIG_FB_RIVA is not set # CONFIG_FB_CLGEN is not set # CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set CONFIG_FB_OF=y CONFIG_FB_CONTROL=y CONFIG_FB_PLATINUM=y CONFIG_FB_VALKYRIE=y -CONFIG_FB_IMSTT=y CONFIG_FB_CT65550=y +CONFIG_FB_IMSTT=y # CONFIG_FB_S3TRIO is not set # CONFIG_FB_VGA16 is not set CONFIG_FB_MATROX=y @@ -420,6 +452,7 @@ CONFIG_FB_ATY=y CONFIG_FB_ATY128=y CONFIG_FB_3DFX=y +# CONFIG_FB_SIS is not set # CONFIG_FB_VIRTUAL is not set # CONFIG_FBCON_ADVANCED is not set CONFIG_FBCON_CFB8=y @@ -437,6 +470,32 @@ # CONFIG_FONT_ACORN_8x8 is not set # +# Input core support +# +CONFIG_INPUT=y +CONFIG_INPUT_KEYBDEV=y +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y + +# +# Macintosh device drivers +# +CONFIG_MAC_FLOPPY=y +CONFIG_MAC_SERIAL=y +# CONFIG_SERIAL_CONSOLE is not set +CONFIG_ADB=y +CONFIG_ADB_CUDA=y +CONFIG_ADB_MACIO=y +CONFIG_ADB_PMU=y +CONFIG_INPUT_ADBHID=y +CONFIG_MAC_HID=y +CONFIG_MAC_ADBKEYCODES=y +CONFIG_MAC_EMUMOUSEBTN=y + +# # Character devices # CONFIG_VT=y @@ -459,7 +518,6 @@ # CONFIG_ATIXL_BUSMOUSE is not set # CONFIG_LOGIBUSMOUSE is not set # CONFIG_MS_BUSMOUSE is not set -CONFIG_ADBMOUSE=y CONFIG_MOUSE=y CONFIG_PSMOUSE=y # CONFIG_82C710_MOUSE is not set @@ -469,19 +527,19 @@ # 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=y # CONFIG_RTC is not set - -# -# Video For Linux -# -# CONFIG_VIDEO_DEV is not set # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set @@ -490,26 +548,31 @@ # Ftape, the floppy tape device driver # # CONFIG_FTAPE is not set -# CONFIG_DRM is not set -# CONFIG_DRM_TDFX is not set # CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set # # File systems # # CONFIG_QUOTA is not set CONFIG_AUTOFS_FS=y -# CONFIG_AUTOFS4_FS is not set +CONFIG_AUTOFS4_FS=y # CONFIG_ADFS_FS is not set # CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set -CONFIG_HFS_FS=y +# CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set CONFIG_FAT_FS=y CONFIG_MSDOS_FS=y # CONFIG_UMSDOS_FS is not set CONFIG_VFAT_FS=y # CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set # CONFIG_CRAMFS is not set # CONFIG_RAMFS is not set CONFIG_ISO9660_FS=y @@ -519,7 +582,8 @@ # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y -# CONFIG_DEVFS_FS is not set +CONFIG_DEVFS_FS=y +# CONFIG_DEVFS_MOUNT is not set # CONFIG_DEVFS_DEBUG is not set CONFIG_DEVPTS_FS=y # CONFIG_QNX4FS_FS is not set @@ -571,12 +635,14 @@ # CONFIG_SOLARIS_X86_PARTITION is not set # CONFIG_UNIXWARE_DISKLABEL is not set # CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set # CONFIG_SUN_PARTITION is not set CONFIG_NLS=y # # Native Language Support # +CONFIG_NLS_DEFAULT="iso8859-1" # CONFIG_NLS_CODEPAGE_437 is not set # CONFIG_NLS_CODEPAGE_737 is not set # CONFIG_NLS_CODEPAGE_775 is not set @@ -593,6 +659,10 @@ # CONFIG_NLS_CODEPAGE_866 is not set # CONFIG_NLS_CODEPAGE_869 is not set # CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_950 is not set # CONFIG_NLS_ISO8859_1 is not set # CONFIG_NLS_ISO8859_2 is not set # CONFIG_NLS_ISO8859_3 is not set @@ -605,6 +675,7 @@ # CONFIG_NLS_ISO8859_14 is not set # CONFIG_NLS_ISO8859_15 is not set # CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_UTF8 is not set # # Sound @@ -614,6 +685,7 @@ CONFIG_DMASOUND=y # CONFIG_SOUND_CMPCI is not set # CONFIG_SOUND_EMU10K1 is not set +# CONFIG_SOUND_FUSION is not set # CONFIG_SOUND_ES1370 is not set # CONFIG_SOUND_ES1371 is not set # CONFIG_SOUND_ESSSOLO1 is not set @@ -622,6 +694,7 @@ # CONFIG_SOUND_TRIDENT is not set # CONFIG_SOUND_MSNDCLAS is not set # CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set CONFIG_SOUND_OSS=y # CONFIG_SOUND_TRACEINIT is not set # CONFIG_SOUND_DMAP is not set @@ -647,24 +720,39 @@ # CONFIG_SOUND_AWE32_SYNTH is not set # CONFIG_SOUND_WAVEFRONT is not set # CONFIG_SOUND_MAUI is not set -# CONFIG_SOUND_VIA82CXXX is not set # CONFIG_SOUND_YM3812 is not set # CONFIG_SOUND_OPL3SA1 is not set # CONFIG_SOUND_OPL3SA2 is not set +# CONFIG_SOUND_YMPCI is not set # CONFIG_SOUND_UART6850 is not set # CONFIG_SOUND_AEDSP16 is not set +# CONFIG_SOUND_TVMIXER is not set # # USB support # CONFIG_USB=y CONFIG_USB_DEBUG=y -# CONFIG_USB_DEVICEFS is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set + +# +# USB Controllers +# # CONFIG_USB_UHCI is not set # CONFIG_USB_UHCI_ALT is not set CONFIG_USB_OHCI=y + +# +# USB Devices +# # CONFIG_USB_PRINTER is not set # CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set # CONFIG_USB_AUDIO is not set # CONFIG_USB_ACM is not set # CONFIG_USB_SERIAL is not set @@ -679,15 +767,13 @@ # CONFIG_USB_PEGASUS is not set # CONFIG_USB_RIO500 is not set # CONFIG_USB_DSBR is not set +# CONFIG_USB_BLUETOOTH is not set + +# +# USB Human Interface Devices (HID) +# CONFIG_USB_HID=y # CONFIG_USB_WACOM is not set -# CONFIG_USB_WMFORCE is not set -CONFIG_INPUT_KEYBDEV=y -CONFIG_INPUT_MOUSEDEV=y -CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 -CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 -# CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_EVDEV is not set # # Kernel hacking @@ -695,4 +781,3 @@ CONFIG_MAGIC_SYSRQ=y # CONFIG_KGDB is not set CONFIG_XMON=y - diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/configs/est8260_defconfig linux/arch/ppc/configs/est8260_defconfig --- v2.4.0-test8/linux/arch/ppc/configs/est8260_defconfig Mon Jun 19 17:59:36 2000 +++ linux/arch/ppc/configs/est8260_defconfig Sun Sep 17 09:48:06 2000 @@ -9,12 +9,18 @@ CONFIG_EXPERIMENTAL=y # +# Loadable module support +# +# CONFIG_MODULES is not set + +# # Platform support # CONFIG_PPC=y # CONFIG_6xx is not set # CONFIG_4xx is not set -# CONFIG_PPC64BRIDGE is not set +# CONFIG_POWER3 is not set +# CONFIG_POWER4 is not set CONFIG_8260=y # CONFIG_8xx is not set CONFIG_6xx=y @@ -29,13 +35,9 @@ CONFIG_MACH_SPECIFIC=y # -# Loadable module support -# -# CONFIG_MODULES is not set - -# # General setup # +# CONFIG_HIGHMEM is not set # CONFIG_ISA is not set # CONFIG_SBUS is not set # CONFIG_PCI is not set @@ -56,15 +58,17 @@ # CONFIG_PARPORT is not set # CONFIG_VGA_CONSOLE is not set # CONFIG_FB is not set -# CONFIG_PMAC_PBOOK is not set -# CONFIG_MAC_FLOPPY is not set -# CONFIG_MAC_SERIAL is not set -# CONFIG_ADB is not set +# CONFIG_PPC_RTC is not set # CONFIG_PROC_DEVICETREE is not set # CONFIG_BOOTX_TEXT is not set # CONFIG_MOTOROLA_HOTSWAP is not set # +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# # Plug and Play configuration # # CONFIG_PNP is not set @@ -84,8 +88,10 @@ # CONFIG_BLK_DEV_MD is not set # CONFIG_MD_LINEAR is not set # CONFIG_MD_RAID0 is not set -# CONFIG_RAID15_DANGEROUS is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y # @@ -105,17 +111,11 @@ CONFIG_IP_PNP=y CONFIG_IP_PNP_BOOTP=y # CONFIG_IP_PNP_RARP is not set -# CONFIG_IP_ROUTER is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set # CONFIG_IP_MROUTE is not set -CONFIG_IP_ALIAS=y +# CONFIG_INET_ECN is not set CONFIG_SYN_COOKIES=y - -# -# (it is safe to leave these untouched) -# -CONFIG_SKB_LARGE=y # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set @@ -126,9 +126,9 @@ # 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_ECONET is not set # CONFIG_WAN_ROUTER is not set @@ -164,6 +164,7 @@ # CONFIG_DUMMY is not set # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set # CONFIG_ETHERTAP is not set # CONFIG_NET_SB1000 is not set @@ -245,6 +246,15 @@ # CONFIG_FB is not set # +# Input core support +# +# CONFIG_INPUT is not set + +# +# Macintosh device drivers +# + +# # Character devices # # CONFIG_VT is not set @@ -269,19 +279,19 @@ # 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 - -# -# Video For Linux -# -# CONFIG_VIDEO_DEV is not set # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set @@ -290,9 +300,13 @@ # Ftape, the floppy tape device driver # # CONFIG_FTAPE is not set -# CONFIG_DRM is not set -# CONFIG_DRM_TDFX is not set # CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set # # File systems @@ -310,6 +324,7 @@ # 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 @@ -369,6 +384,7 @@ # 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 @@ -382,7 +398,7 @@ # CONFIG_SCC_ENET=y CONFIG_SCC1_ENET=y -# CONFIG_FCC_ENET is not set +# CONFIG_FEC_ENET is not set # # USB support diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/configs/gemini_defconfig linux/arch/ppc/configs/gemini_defconfig --- v2.4.0-test8/linux/arch/ppc/configs/gemini_defconfig Mon Jun 19 17:59:36 2000 +++ linux/arch/ppc/configs/gemini_defconfig Sun Sep 17 09:48:06 2000 @@ -14,14 +14,12 @@ CONFIG_PPC=y CONFIG_6xx=y # CONFIG_4xx is not set -# CONFIG_PPC64BRIDGE is not set -# CONFIG_82xx is not set +# CONFIG_PPC64 is not set +# CONFIG_8260 is not set # CONFIG_8xx is not set -# CONFIG_PMAC is not set -# CONFIG_PREP is not set -# CONFIG_CHRP is not set # CONFIG_ALL_PPC is not set CONFIG_GEMINI=y +# CONFIG_EST8260 is not set # CONFIG_APUS is not set # CONFIG_SMP is not set CONFIG_ALTIVEC=y @@ -37,7 +35,8 @@ # # General setup # -# CONFIG_PCI is not set +# CONFIG_ISA is not set +# CONFIG_SBUS is not set CONFIG_PCI=y CONFIG_NET=y CONFIG_SYSCTL=y @@ -47,8 +46,12 @@ CONFIG_BINFMT_ELF=y CONFIG_KERNEL_ELF=y # CONFIG_BINFMT_MISC is not set -# CONFIG_PCI_NAMES is not set # CONFIG_HOTPLUG is not set +# CONFIG_PCMCIA is not set + +# +# Parallel port support +# # CONFIG_PARPORT is not set # CONFIG_VGA_CONSOLE is not set # CONFIG_FB is not set @@ -57,7 +60,6 @@ # CONFIG_MAC_SERIAL is not set # CONFIG_ADB is not set # CONFIG_PROC_DEVICETREE is not set -# CONFIG_TOTALMP is not set # CONFIG_BOOTX_TEXT is not set # CONFIG_MOTOROLA_HOTSWAP is not set @@ -70,22 +72,16 @@ # Block devices # # CONFIG_BLK_DEV_FD is not set -# CONFIG_BLK_DEV_IDE is not set # -# Please see Documentation/ide.txt for help/info on IDE drives +# Additional Block Devices # -# CONFIG_BLK_DEV_HD_ONLY is not set -# CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_LVM is not set # CONFIG_BLK_DEV_MD is not set +# CONFIG_RAID15_DANGEROUS is not set # CONFIG_BLK_DEV_RAM is not set -# CONFIG_BLK_DEV_XD is not set -# CONFIG_BLK_DEV_DAC960 is not set -# CONFIG_PARIDE is not set -# CONFIG_BLK_DEV_IDE_MODES is not set -# CONFIG_BLK_DEV_HD is not set # # Networking options @@ -138,6 +134,13 @@ # CONFIG_NET_SCHED is not set # +# ATA/IDE/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_IDE_MODES is not set +# CONFIG_BLK_DEV_HD is not set + +# # SCSI support # CONFIG_SCSI=y @@ -148,7 +151,6 @@ CONFIG_BLK_DEV_SD=y CONFIG_SD_EXTRA_DEVS=40 # CONFIG_CHR_DEV_ST is not set -CONFIG_ST_EXTRA_DEVS=2 CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y CONFIG_SR_EXTRA_DEVS=2 @@ -171,7 +173,6 @@ # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set # CONFIG_SCSI_AIC7XXX is not set -# CONFIG_SCSI_IPS is not set # CONFIG_SCSI_ADVANSYS is not set # CONFIG_SCSI_IN2000 is not set # CONFIG_SCSI_AM53C974 is not set @@ -184,43 +185,22 @@ # CONFIG_SCSI_FUTURE_DOMAIN is not set # CONFIG_SCSI_GDTH is not set # CONFIG_SCSI_GENERIC_NCR5380 is not set -# CONFIG_SCSI_INITIO is not set -# CONFIG_SCSI_INIA100 is not set # CONFIG_SCSI_NCR53C406A is not set # CONFIG_SCSI_SYM53C416 is not set # CONFIG_SCSI_SIM710 is not set -# CONFIG_SCSI_NCR53C7xx is not set -# CONFIG_SCSI_NCR53C8XX is not set -CONFIG_SCSI_SYM53C8XX=y -CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8 -CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32 -CONFIG_SCSI_NCR53C8XX_SYNC=20 -# CONFIG_SCSI_NCR53C8XX_PROFILE is not set -# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set -# CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set -# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set +# CONFIG_SCSI_NCR53C7xx_sync is not set +# CONFIG_SCSI_NCR53C7xx_FAST is not set +# CONFIG_SCSI_NCR53C7xx_DISCONNECT is not set # CONFIG_SCSI_PAS16 is not set # CONFIG_SCSI_PCI2000 is not set # CONFIG_SCSI_PCI2220I is not set # CONFIG_SCSI_PSI240I is not set # CONFIG_SCSI_QLOGIC_FAS is not set -# CONFIG_SCSI_QLOGIC_ISP is not set -# CONFIG_SCSI_QLOGIC_FC is not set -# CONFIG_SCSI_QLOGIC_1280 is not set -# CONFIG_SCSI_SEAGATE is not set -# CONFIG_SCSI_DC390T is not set # CONFIG_SCSI_T128 is not set # CONFIG_SCSI_U14_34F is not set -# CONFIG_SCSI_ULTRASTOR is not set # CONFIG_SCSI_DEBUG is not set # CONFIG_SCSI_MESH is not set # CONFIG_SCSI_MAC53C94 is not set -# CONFIG_BLK_DEV_3W_XXXX_RAID is not set - -# -# IEEE 1394 (FireWire) support -# -# CONFIG_IEEE1394 is not set # # Network device support @@ -232,6 +212,7 @@ # # CONFIG_ARCNET is not set # CONFIG_DUMMY is not set +# CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set # CONFIG_ETHERTAP is not set # CONFIG_NET_SB1000 is not set @@ -249,12 +230,10 @@ # CONFIG_LANCE is not set # CONFIG_NET_VENDOR_SMC is not set # CONFIG_NET_VENDOR_RACAL is not set -# CONFIG_RTL8139 is not set -# CONFIG_DM9102 is not set # CONFIG_AT1700 is not set # CONFIG_DEPCA is not set # CONFIG_NET_ISA is not set -# CONFIG_NET_EISA is not set +# CONFIG_NET_PCI is not set # CONFIG_NET_POCKET is not set # @@ -274,7 +253,7 @@ # CONFIG_NET_RADIO is not set # -# Token Ring driver support +# Token Ring devices # # CONFIG_TR is not set # CONFIG_NET_FC is not set @@ -292,6 +271,11 @@ # CONFIG_HAMRADIO is not set # +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# # ISDN subsystem # # CONFIG_ISDN is not set @@ -361,12 +345,7 @@ # CONFIG_AGP is not set # -# USB support -# -# CONFIG_USB is not set - -# -# Filesystems +# File systems # # CONFIG_QUOTA is not set # CONFIG_AUTOFS_FS is not set @@ -378,12 +357,14 @@ # CONFIG_FAT_FS is not set # CONFIG_EFS_FS is not set # CONFIG_CRAMFS is not set +# CONFIG_RAMFS is not set CONFIG_ISO9660_FS=y # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set CONFIG_DEVPTS_FS=y # CONFIG_QNX4FS_FS is not set # CONFIG_ROMFS_FS is not set @@ -397,6 +378,7 @@ # # CONFIG_CODA_FS is not set CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set # CONFIG_NFSD is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y @@ -414,6 +396,11 @@ # Sound # # CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set # # Kernel hacking diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/configs/rpxcllf_defconfig linux/arch/ppc/configs/rpxcllf_defconfig --- v2.4.0-test8/linux/arch/ppc/configs/rpxcllf_defconfig Mon Jun 19 17:59:36 2000 +++ linux/arch/ppc/configs/rpxcllf_defconfig Sun Sep 17 09:48:06 2000 @@ -9,18 +9,27 @@ CONFIG_EXPERIMENTAL=y # +# Loadable module support +# +# CONFIG_MODULES is not set + +# # Platform support # CONFIG_PPC=y # CONFIG_6xx is not set # CONFIG_4xx is not set -# CONFIG_PPC64BRIDGE is not set +# CONFIG_POWER3 is not set +# CONFIG_POWER4 is not set # CONFIG_8260 is not set CONFIG_8xx=y CONFIG_SERIAL_CONSOLE=y # CONFIG_RPXLITE is not set CONFIG_RPXCLASSIC=y # CONFIG_BSEIP is not set +# CONFIG_TQM8xxL is not set +# CONFIG_TQM860L is not set +# CONFIG_TQM860 is not set # CONFIG_MBX is not set # CONFIG_WINCEPT is not set # CONFIG_ALL_PPC is not set @@ -29,13 +38,9 @@ CONFIG_MATH_EMULATION=y # -# Loadable module support -# -# CONFIG_MODULES is not set - -# # General setup # +# CONFIG_HIGHMEM is not set # CONFIG_ISA is not set # CONFIG_SBUS is not set # CONFIG_PCI is not set @@ -56,6 +61,11 @@ # CONFIG_PARPORT is not set # +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# # Plug and Play configuration # # CONFIG_PNP is not set @@ -75,8 +85,10 @@ # CONFIG_BLK_DEV_MD is not set # CONFIG_MD_LINEAR is not set # CONFIG_MD_RAID0 is not set -# CONFIG_RAID15_DANGEROUS is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y # @@ -96,17 +108,11 @@ CONFIG_IP_PNP=y CONFIG_IP_PNP_BOOTP=y # CONFIG_IP_PNP_RARP is not set -# CONFIG_IP_ROUTER is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set # CONFIG_IP_MROUTE is not set -CONFIG_IP_ALIAS=y +# CONFIG_INET_ECN is not set CONFIG_SYN_COOKIES=y - -# -# (it is safe to leave these untouched) -# -CONFIG_SKB_LARGE=y # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set @@ -117,9 +123,9 @@ # 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_ECONET is not set # CONFIG_WAN_ROUTER is not set @@ -155,6 +161,7 @@ # CONFIG_DUMMY is not set # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set # CONFIG_ETHERTAP is not set # CONFIG_NET_SB1000 is not set @@ -236,6 +243,15 @@ # CONFIG_FB is not set # +# Input core support +# +# CONFIG_INPUT is not set + +# +# Macintosh device drivers +# + +# # Character devices # # CONFIG_VT is not set @@ -260,19 +276,19 @@ # 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 - -# -# Video For Linux -# -# CONFIG_VIDEO_DEV is not set # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set @@ -281,9 +297,13 @@ # Ftape, the floppy tape device driver # # CONFIG_FTAPE is not set -# CONFIG_DRM is not set -# CONFIG_DRM_TDFX is not set # CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set # # File systems @@ -301,6 +321,7 @@ # 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 @@ -360,6 +381,7 @@ # 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 @@ -374,7 +396,9 @@ CONFIG_SCC_ENET=y CONFIG_SCC1_ENET=y CONFIG_FEC_ENET=y +CONFIG_ENET_BIG_BUFFERS=y CONFIG_8xxSMC2=y +# CONFIG_8xx_ALTSMC2 is not set CONFIG_8xxSCC=y # diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/defconfig linux/arch/ppc/defconfig --- v2.4.0-test8/linux/arch/ppc/defconfig Mon Jun 19 17:59:36 2000 +++ linux/arch/ppc/defconfig Sun Sep 17 09:48:06 2000 @@ -1,5 +1,5 @@ # -# Automatically generated by make menuconfig: don't edit +# Automatically generated make config: don't edit # # CONFIG_UID16 is not set @@ -9,12 +9,20 @@ CONFIG_EXPERIMENTAL=y # +# Loadable module support +# +CONFIG_MODULES=y +CONFIG_MODVERSIONS=y +CONFIG_KMOD=y + +# # Platform support # CONFIG_PPC=y CONFIG_6xx=y # CONFIG_4xx is not set -# CONFIG_PPC64BRIDGE is not set +# CONFIG_POWER3 is not set +# CONFIG_POWER4 is not set # CONFIG_8260 is not set # CONFIG_8xx is not set CONFIG_ALL_PPC=y @@ -25,15 +33,9 @@ CONFIG_ALTIVEC=y # -# Loadable module support -# -CONFIG_MODULES=y -CONFIG_MODVERSIONS=y -CONFIG_KMOD=y - -# # General setup # +# CONFIG_HIGHMEM is not set # CONFIG_ISA is not set # CONFIG_SBUS is not set CONFIG_PCI=y @@ -44,8 +46,8 @@ CONFIG_KCORE_ELF=y CONFIG_BINFMT_ELF=y CONFIG_KERNEL_ELF=y -# CONFIG_BINFMT_MISC is not set -# CONFIG_PCI_NAMES is not set +CONFIG_BINFMT_MISC=m +CONFIG_PCI_NAMES=y # CONFIG_HOTPLUG is not set # CONFIG_PCMCIA is not set @@ -57,21 +59,18 @@ CONFIG_FB=y CONFIG_FB_COMPAT_XPMAC=y CONFIG_PMAC_PBOOK=y -CONFIG_MAC_FLOPPY=y -CONFIG_MAC_SERIAL=y -# CONFIG_SERIAL_CONSOLE is not set -CONFIG_ADB=y -CONFIG_ADB_CUDA=y -CONFIG_ADB_MACIO=y -CONFIG_ADB_PMU=y -CONFIG_ADB_KEYBOARD=y -CONFIG_ADBMOUSE=y +CONFIG_PPC_RTC=y CONFIG_PROC_DEVICETREE=y CONFIG_BOOTX_TEXT=y # CONFIG_MOTOROLA_HOTSWAP is not set # CONFIG_CMDLINE_BOOL is not set # +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# # Plug and Play configuration # # CONFIG_PNP is not set @@ -90,8 +89,11 @@ # CONFIG_BLK_DEV_LVM is not set # CONFIG_BLK_DEV_MD is not set # CONFIG_MD_LINEAR is not set -# CONFIG_MD_STRIPED is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y # @@ -109,22 +111,24 @@ 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_MROUTE is not set -CONFIG_IP_ALIAS=y +# CONFIG_INET_ECN is not set CONFIG_SYN_COOKIES=y -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=m # 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_ECONET is not set # CONFIG_WAN_ROUTER is not set @@ -145,26 +149,42 @@ # IDE, ATA and ATAPI Block devices # CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# # CONFIG_BLK_DEV_HD_IDE is not set # CONFIG_BLK_DEV_HD is not set CONFIG_BLK_DEV_IDEDISK=y # CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set +# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set +# CONFIG_BLK_DEV_IDEDISK_IBM is not set +# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set +# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set +# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set +# CONFIG_BLK_DEV_IDEDISK_WD is not set +# CONFIG_BLK_DEV_COMMERIAL is not set +# CONFIG_BLK_DEV_TIVO is not set # CONFIG_BLK_DEV_IDECS is not set CONFIG_BLK_DEV_IDECD=y # CONFIG_BLK_DEV_IDETAPE is not set -# CONFIG_BLK_DEV_IDEFLOPPY is not set +CONFIG_BLK_DEV_IDEFLOPPY=y CONFIG_BLK_DEV_IDESCSI=y + +# +# IDE chipset support/bugfixes +# # CONFIG_BLK_DEV_CMD640 is not set # CONFIG_BLK_DEV_CMD640_ENHANCED is not set # CONFIG_BLK_DEV_ISAPNP is not set # CONFIG_BLK_DEV_RZ1000 is not set CONFIG_BLK_DEV_IDEPCI=y -# CONFIG_IDEPCI_SHARE_IRQ is not set +CONFIG_IDEPCI_SHARE_IRQ=y CONFIG_BLK_DEV_IDEDMA_PCI=y # CONFIG_BLK_DEV_OFFBOARD is not set CONFIG_IDEDMA_PCI_AUTO=y CONFIG_BLK_DEV_IDEDMA=y -CONFIG_IDEDMA_PCI_EXPERIMENTAL=y # CONFIG_IDEDMA_PCI_WIP is not set # CONFIG_IDEDMA_NEW_DRIVE_LISTINGS is not set # CONFIG_BLK_DEV_AEC62XX is not set @@ -173,37 +193,40 @@ # CONFIG_WDC_ALI15X3 is not set # CONFIG_BLK_DEV_AMD7409 is not set # CONFIG_AMD7409_OVERRIDE is not set -# CONFIG_BLK_DEV_CMD64X is not set -# CONFIG_CMD64X_RAID is not set +CONFIG_BLK_DEV_CMD64X=y # CONFIG_BLK_DEV_CY82C693 is not set # CONFIG_BLK_DEV_CS5530 is not set # CONFIG_BLK_DEV_HPT34X is not set # CONFIG_HPT34X_AUTODMA is not set # CONFIG_BLK_DEV_HPT366 is not set -# CONFIG_HPT366_FIP is not set -# CONFIG_HPT366_MODE3 is not set # CONFIG_BLK_DEV_NS87415 is not set # CONFIG_BLK_DEV_OPTI621 is not set # CONFIG_BLK_DEV_PDC202XX is not set # CONFIG_PDC202XX_BURST is not set -# CONFIG_PDC202XX_MASTER is not set # CONFIG_BLK_DEV_SIS5513 is not set # CONFIG_BLK_DEV_TRM290 is not set # CONFIG_BLK_DEV_VIA82CXXX is not set # CONFIG_VIA82CXXX_TUNING is not set -# CONFIG_BLK_DEV_SL82C105 is not set +CONFIG_BLK_DEV_SL82C105=y CONFIG_BLK_DEV_IDE_PMAC=y CONFIG_BLK_DEV_IDEDMA_PMAC=y -CONFIG_IDEDMA_PMAC_AUTO=y +CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO=y CONFIG_BLK_DEV_IDEDMA=y +CONFIG_BLK_DEV_IDEPCI=y # CONFIG_IDE_CHIPSETS is not set CONFIG_IDEDMA_AUTO=y +# CONFIG_IDEDMA_IVB is not set +# CONFIG_DMA_NONPCI is not set CONFIG_BLK_DEV_IDE_MODES=y # # SCSI support # CONFIG_SCSI=y + +# +# SCSI support type (disk, tape, CD-ROM) +# CONFIG_BLK_DEV_SD=y CONFIG_SD_EXTRA_DEVS=40 CONFIG_CHR_DEV_ST=y @@ -211,6 +234,10 @@ CONFIG_BLK_DEV_SR_VENDOR=y CONFIG_SR_EXTRA_DEVS=2 CONFIG_CHR_DEV_SG=y + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# # CONFIG_SCSI_DEBUG_QUEUES is not set # CONFIG_SCSI_MULTI_LUN is not set CONFIG_SCSI_CONSTANTS=y @@ -296,6 +323,7 @@ # CONFIG_DUMMY is not set # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set # CONFIG_ETHERTAP is not set # CONFIG_NET_SB1000 is not set @@ -327,8 +355,9 @@ # CONFIG_DM9102 is not set # CONFIG_EEPRO100 is not set # CONFIG_LNE390 is not set -# CONFIG_NE3210 is not set +# CONFIG_NATSEMI is not set # CONFIG_NE2K_PCI is not set +# CONFIG_NE3210 is not set # CONFIG_RTL8129 is not set # CONFIG_8139TOO is not set # CONFIG_SIS900 is not set @@ -347,11 +376,13 @@ # CONFIG_FDDI is not set # CONFIG_HIPPI is not set CONFIG_PPP=y -# CONFIG_PPP_MULTILINK is not set -# CONFIG_PPP_ASYNC is not set +CONFIG_PPP_MULTILINK=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_ASYNC=y # CONFIG_PPP_SYNC_TTY is not set -# CONFIG_PPP_DEFLATE is not set +CONFIG_PPP_DEFLATE=y # CONFIG_PPP_BSDCOMP is not set +# CONFIG_PPPOE is not set # CONFIG_SLIP is not set # @@ -404,12 +435,13 @@ # CONFIG_FB_RIVA is not set # CONFIG_FB_CLGEN is not set # CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set CONFIG_FB_OF=y CONFIG_FB_CONTROL=y CONFIG_FB_PLATINUM=y CONFIG_FB_VALKYRIE=y -CONFIG_FB_IMSTT=y CONFIG_FB_CT65550=y +CONFIG_FB_IMSTT=y # CONFIG_FB_S3TRIO is not set # CONFIG_FB_VGA16 is not set CONFIG_FB_MATROX=y @@ -420,6 +452,7 @@ CONFIG_FB_ATY=y CONFIG_FB_ATY128=y CONFIG_FB_3DFX=y +# CONFIG_FB_SIS is not set # CONFIG_FB_VIRTUAL is not set # CONFIG_FBCON_ADVANCED is not set CONFIG_FBCON_CFB8=y @@ -437,6 +470,32 @@ # CONFIG_FONT_ACORN_8x8 is not set # +# Input core support +# +CONFIG_INPUT=y +CONFIG_INPUT_KEYBDEV=y +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y + +# +# Macintosh device drivers +# +CONFIG_MAC_FLOPPY=y +CONFIG_MAC_SERIAL=y +# CONFIG_SERIAL_CONSOLE is not set +CONFIG_ADB=y +CONFIG_ADB_CUDA=y +CONFIG_ADB_MACIO=y +CONFIG_ADB_PMU=y +CONFIG_INPUT_ADBHID=y +CONFIG_MAC_HID=y +CONFIG_MAC_ADBKEYCODES=y +CONFIG_MAC_EMUMOUSEBTN=y + +# # Character devices # CONFIG_VT=y @@ -459,7 +518,6 @@ # CONFIG_ATIXL_BUSMOUSE is not set # CONFIG_LOGIBUSMOUSE is not set # CONFIG_MS_BUSMOUSE is not set -CONFIG_ADBMOUSE=y CONFIG_MOUSE=y CONFIG_PSMOUSE=y # CONFIG_82C710_MOUSE is not set @@ -469,19 +527,19 @@ # 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=y # CONFIG_RTC is not set - -# -# Video For Linux -# -# CONFIG_VIDEO_DEV is not set # CONFIG_DTLK is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set @@ -490,26 +548,31 @@ # Ftape, the floppy tape device driver # # CONFIG_FTAPE is not set -# CONFIG_DRM is not set -# CONFIG_DRM_TDFX is not set # CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set # # File systems # # CONFIG_QUOTA is not set CONFIG_AUTOFS_FS=y -# CONFIG_AUTOFS4_FS is not set +CONFIG_AUTOFS4_FS=y # CONFIG_ADFS_FS is not set # CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set -CONFIG_HFS_FS=y +# CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set CONFIG_FAT_FS=y CONFIG_MSDOS_FS=y # CONFIG_UMSDOS_FS is not set CONFIG_VFAT_FS=y # CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set # CONFIG_CRAMFS is not set # CONFIG_RAMFS is not set CONFIG_ISO9660_FS=y @@ -519,7 +582,7 @@ # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y -# CONFIG_DEVFS_FS is not set +CONFIG_DEVFS_FS=y # CONFIG_DEVFS_MOUNT is not set # CONFIG_DEVFS_DEBUG is not set CONFIG_DEVPTS_FS=y @@ -572,12 +635,14 @@ # CONFIG_SOLARIS_X86_PARTITION is not set # CONFIG_UNIXWARE_DISKLABEL is not set # CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set # CONFIG_SUN_PARTITION is not set CONFIG_NLS=y # # Native Language Support # +CONFIG_NLS_DEFAULT="iso8859-1" # CONFIG_NLS_CODEPAGE_437 is not set # CONFIG_NLS_CODEPAGE_737 is not set # CONFIG_NLS_CODEPAGE_775 is not set @@ -594,6 +659,10 @@ # CONFIG_NLS_CODEPAGE_866 is not set # CONFIG_NLS_CODEPAGE_869 is not set # CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_950 is not set # CONFIG_NLS_ISO8859_1 is not set # CONFIG_NLS_ISO8859_2 is not set # CONFIG_NLS_ISO8859_3 is not set @@ -606,6 +675,7 @@ # CONFIG_NLS_ISO8859_14 is not set # CONFIG_NLS_ISO8859_15 is not set # CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_UTF8 is not set # # Sound @@ -615,6 +685,7 @@ CONFIG_DMASOUND=y # CONFIG_SOUND_CMPCI is not set # CONFIG_SOUND_EMU10K1 is not set +# CONFIG_SOUND_FUSION is not set # CONFIG_SOUND_ES1370 is not set # CONFIG_SOUND_ES1371 is not set # CONFIG_SOUND_ESSSOLO1 is not set @@ -623,6 +694,7 @@ # CONFIG_SOUND_TRIDENT is not set # CONFIG_SOUND_MSNDCLAS is not set # CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set CONFIG_SOUND_OSS=y # CONFIG_SOUND_TRACEINIT is not set # CONFIG_SOUND_DMAP is not set @@ -648,24 +720,39 @@ # CONFIG_SOUND_AWE32_SYNTH is not set # CONFIG_SOUND_WAVEFRONT is not set # CONFIG_SOUND_MAUI is not set -# CONFIG_SOUND_VIA82CXXX is not set # CONFIG_SOUND_YM3812 is not set # CONFIG_SOUND_OPL3SA1 is not set # CONFIG_SOUND_OPL3SA2 is not set +# CONFIG_SOUND_YMPCI is not set # CONFIG_SOUND_UART6850 is not set # CONFIG_SOUND_AEDSP16 is not set +# CONFIG_SOUND_TVMIXER is not set # # USB support # CONFIG_USB=y CONFIG_USB_DEBUG=y -# CONFIG_USB_DEVICEFS is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_BANDWIDTH is not set + +# +# USB Controllers +# # CONFIG_USB_UHCI is not set # CONFIG_USB_UHCI_ALT is not set CONFIG_USB_OHCI=y + +# +# USB Devices +# # CONFIG_USB_PRINTER is not set # CONFIG_USB_SCANNER is not set +# CONFIG_USB_MICROTEK is not set # CONFIG_USB_AUDIO is not set # CONFIG_USB_ACM is not set # CONFIG_USB_SERIAL is not set @@ -680,15 +767,18 @@ # CONFIG_USB_PEGASUS is not set # CONFIG_USB_RIO500 is not set # CONFIG_USB_DSBR is not set +# CONFIG_USB_BLUETOOTH is not set + +# +# USB Human Interface Devices (HID) +# CONFIG_USB_HID=y # CONFIG_USB_WACOM is not set -# CONFIG_USB_WMFORCE is not set -CONFIG_INPUT_KEYBDEV=y -CONFIG_INPUT_MOUSEDEV=y -CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 -CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 -# CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_EVDEV is not set + +# +# Mac-on-Linux (MOL) support +# +# CONFIG_MOL is not set # # Kernel hacking diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/kernel/Makefile linux/arch/ppc/kernel/Makefile --- v2.4.0-test8/linux/arch/ppc/kernel/Makefile Thu Jul 13 09:42:50 2000 +++ linux/arch/ppc/kernel/Makefile Sun Sep 17 09:48:06 2000 @@ -99,8 +99,10 @@ ifeq ($(CONFIG_ALL_PPC),y) O_OBJS += pmac_pic.o pmac_setup.o pmac_time.o feature.o pmac_pci.o prom.o \ chrp_setup.o chrp_time.o chrp_pci.o open_pic.o indirect_pci.o \ - prep_pci.o i8259.o prep_nvram.o prep_time.o residual.o \ - pmac_backlight.o + prep_pci.o i8259.o prep_nvram.o prep_time.o residual.o + ifeq ($(CONFIG_PMAC_BACKLIGHT),y) + O_OBJS += pmac_backlight.o + endif OX_OBJS += prep_setup.o endif ifeq ($(CONFIG_GEMINI),y) diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/kernel/apus_setup.c linux/arch/ppc/kernel/apus_setup.c --- v2.4.0-test8/linux/arch/ppc/kernel/apus_setup.c Tue Apr 25 17:58:46 2000 +++ linux/arch/ppc/kernel/apus_setup.c Sun Sep 17 09:48:06 2000 @@ -304,7 +304,7 @@ void apus_calibrate_decr(void) { #ifdef CONFIG_APUS - int freq, divisor; + unsigned long freq; /* This algorithm for determining the bus speed was contributed by Ralph Schmidt. */ @@ -335,8 +335,8 @@ bus_speed = 60; freq = 15000000; } else if ((bus_speed >= 63) && (bus_speed < 69)) { - bus_speed = 66; - freq = 16500000; + bus_speed = 67; + freq = 16666667; } else { printk ("APUS: Unable to determine bus speed (%d). " "Defaulting to 50MHz", bus_speed); @@ -375,12 +375,10 @@ } - freq *= 60; /* try to make freq/1e6 an integer */ - divisor = 60; - printk("time_init: decrementer frequency = %d/%d\n", freq, divisor); - decrementer_count = freq / HZ / divisor; - count_period_num = divisor; - count_period_den = freq / 1000000; + printk("time_init: decrementer frequency = %lu.%.6lu MHz\n", + freq/1000000, freq%1000000); + tb_ticks_per_jiffy = freq / HZ; + tb_to_us = mulhwu_scale_factor(freq, 1000000); __bus_speed = bus_speed; __speed_test_failed = speed_test_failed; diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/kernel/chrp_pci.c linux/arch/ppc/kernel/chrp_pci.c --- v2.4.0-test8/linux/arch/ppc/kernel/chrp_pci.c Thu Jul 13 09:42:50 2000 +++ linux/arch/ppc/kernel/chrp_pci.c Sun Sep 17 09:48:06 2000 @@ -284,13 +284,38 @@ return 1; } +#ifdef CONFIG_POWER4 +static void +power4_fixup_dev(struct pci_dev *dev) +{ + int i; + unsigned long offset; + + for (i = 0; i < 6; ++i) { + if (dev->resource[i].start == 0) + continue; + offset = pci_address_offset(dev->bus->number, + dev->resource[i].flags); + if (offset) { + dev->resource[i].start += offset; + dev->resource[i].end += offset; + printk("device %x.%x[%d] now [%lx..%lx]\n", + dev->bus->number, dev->devfn, i, + dev->resource[i].start, + dev->resource[i].end); + } + /* zap the 2nd function of the winbond chip */ + if (dev->resource[i].flags & IORESOURCE_IO + && dev->bus->number == 0 && dev->devfn == 0x81) + dev->resource[i].flags &= ~IORESOURCE_IO; + } +} +#endif /* CONFIG_POWER4 */ + void __init chrp_pcibios_fixup(void) { struct pci_dev *dev; -#ifdef CONFIG_POWER4 - int i; -#endif int *brp; struct device_node *np; extern struct pci_ops generic_pci_ops; @@ -316,10 +341,8 @@ /* PCI interrupts are controlled by the OpenPIC */ pci_for_each_dev(dev) { np = find_pci_device_OFnode(dev->bus->number, dev->devfn); - if ( (np != 0) && (np->n_intrs > 0) && (np->intrs[0].line != 0)) + if ((np != 0) && (np->n_intrs > 0) && (np->intrs[0].line != 0)) dev->irq = np->intrs[0].line; - if ( dev->irq ) - dev->irq = openpic_to_irq( dev->irq ); /* these need to be absolute addrs for OF and Matrox FB -- Cort */ if ( dev->vendor == PCI_VENDOR_ID_MATROX ) { @@ -337,25 +360,7 @@ dev->devfn, PCI_VENDOR_ID, PCI_VENDOR_ID_AMD); } #ifdef CONFIG_POWER4 - for (i = 0; i < 6; ++i) { - unsigned long offset; - if (dev->resource[i].start == 0) - continue; - offset = pci_address_offset(dev->bus->number, - dev->resource[i].flags); - if (offset) { - dev->resource[i].start += offset; - dev->resource[i].end += offset; - printk("device %x.%x[%d] now [%lx..%lx]\n", - dev->bus->number, dev->devfn, i, - dev->resource[i].start, - dev->resource[i].end); - } - /* zap the 2nd function of the winbond chip */ - if (dev->resource[i].flags & IORESOURCE_IO - && dev->bus->number == 0 && dev->devfn == 0x81) - dev->resource[i].flags &= ~IORESOURCE_IO; - } + power4_fixup_dev(dev); #else if (dev->bus->number > 0 && python_busnr > 0) dev->resource[0].start += dev->bus->number*0x01000000; @@ -363,6 +368,40 @@ } } +static struct { + /* parent is iomem */ + struct resource ram, pci_mem, isa_mem, pci_io, pci_cfg, rom_exp, flash; + /* parent is isa_mem */ + struct resource nvram; +} gg2_resources = { + ram: { "RAM", 0x00000000, 0xbfffffff, IORESOURCE_MEM }, + pci_mem: { "GG2 PCI mem", 0xc0000000, 0xf6ffffff, IORESOURCE_MEM }, + isa_mem: { "GG2 ISA mem", 0xf7000000, 0xf7ffffff }, + pci_io: { "GG2 PCI I/O", 0xf8000000, 0xf8ffffff }, + pci_cfg: { "GG2 PCI cfg", 0xfec00000, 0xfec7ffff }, + rom_exp: { "ROM exp", 0xff000000, 0xff7fffff, }, + flash: { "Flash ROM", 0xfff80000, 0xffffffff }, + nvram: { "NVRAM", 0xf70e0000, 0xf70e7fff }, +}; + +static void __init gg2_pcibios_fixup(void) +{ + int i; + extern unsigned long *end_of_DRAM; + + chrp_pcibios_fixup(); + gg2_resources.ram.end = (unsigned long)end_of_DRAM-PAGE_OFFSET; + for (i = 0; i < 7; i++) + request_resource(&iomem_resource, + &((struct resource *)&gg2_resources)[i]); + request_resource(&gg2_resources.isa_mem, &gg2_resources.nvram); +} + +static void __init gg2_pcibios_fixup_bus(struct pci_bus *bus) +{ + bus->resource[1] = &gg2_resources.pci_mem; +} + decl_config_access_method(grackle); decl_config_access_method(indirect); decl_config_access_method(rtas); @@ -372,6 +411,7 @@ { struct device_node *py; + ppc_md.pcibios_fixup = chrp_pcibios_fixup; #ifdef CONFIG_POWER4 set_config_access_method(rtas); pci_dram_offset = 0; @@ -428,16 +468,17 @@ } else { + /* LongTrail */ pci_dram_offset = 0; isa_mem_base = 0xf7000000; isa_io_base = 0xf8000000; set_config_access_method(gg2); + ppc_md.pcibios_fixup = gg2_pcibios_fixup; + ppc_md.pcibios_fixup_bus = gg2_pcibios_fixup_bus; } } } #endif /* CONFIG_POWER4 */ - - ppc_md.pcibios_fixup = chrp_pcibios_fixup; } #ifdef CONFIG_PPC64BRIDGE diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/kernel/chrp_setup.c linux/arch/ppc/kernel/chrp_setup.c --- v2.4.0-test8/linux/arch/ppc/kernel/chrp_setup.c Thu Jul 13 09:42:50 2000 +++ linux/arch/ppc/kernel/chrp_setup.c Sun Sep 17 09:48:06 2000 @@ -62,11 +62,13 @@ unsigned long chrp_get_rtc_time(void); int chrp_set_rtc_time(unsigned long nowtime); void chrp_calibrate_decr(void); -void chrp_time_init(void); +long chrp_time_init(void); void chrp_setup_pci_ptrs(void); -extern void chrp_progress(char *, unsigned short); void chrp_event_scan(void); +void rtas_display_progress(char *, unsigned short); +void rtas_indicator_progress(char *, unsigned short); +void bootx_text_progress(char *, unsigned short); extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode); extern int pckbd_getkeycode(unsigned int scancode); @@ -91,6 +93,8 @@ extern unsigned long Hash_size, Hash_mask; extern int probingmem; extern unsigned long loops_per_sec; +extern int bootx_text_mapped; +static int max_width; unsigned long empty_zero_page[1024]; @@ -252,13 +256,6 @@ #endif ROOT_DEV = to_kdev_t(0x0802); /* sda2 (sda1 is for the kernel) */ printk("Boot arguments: %s\n", cmd_line); - - request_region(0x20,0x20,"pic1"); - request_region(0xa0,0x20,"pic2"); - request_region(0x00,0x20,"dma1"); - request_region(0x40,0x20,"timer"); - request_region(0x80,0x10,"dma page reg"); - request_region(0xc0,0x20,"dma2"); #ifndef CONFIG_PPC64BRIDGE /* PCI bridge config space access area - @@ -446,11 +443,43 @@ void __init chrp_init2(void) { +#if defined(CONFIG_VT) && defined(CONFIG_ADB_KEYBOARD) + struct device_node *kbd; +#endif #ifdef CONFIG_NVRAM pmac_nvram_init(); #endif + + request_region(0x20,0x20,"pic1"); + request_region(0xa0,0x20,"pic2"); + request_region(0x00,0x20,"dma1"); + request_region(0x40,0x20,"timer"); + request_region(0x80,0x10,"dma page reg"); + request_region(0xc0,0x20,"dma2"); + if (ppc_md.progress) ppc_md.progress(" Have fun! ", 0x7777); + +#if defined(CONFIG_VT) && defined(CONFIG_ADB_KEYBOARD) + /* see if there is a keyboard in the device tree + with a parent of type "adb" */ + for (kbd = find_devices("keyboard"); kbd; kbd = kbd->next) + if (kbd->parent && kbd->parent->type + && strcmp(kbd->parent->type, "adb") == 0) + break; + if (kbd) { + ppc_md.kbd_setkeycode = mackbd_setkeycode; + ppc_md.kbd_getkeycode = mackbd_getkeycode; + ppc_md.kbd_translate = mackbd_translate; + ppc_md.kbd_unexpected_up = mackbd_unexpected_up; + ppc_md.kbd_leds = mackbd_leds; + ppc_md.kbd_init_hw = mackbd_init_hw; +#ifdef CONFIG_MAGIC_SYSRQ + ppc_md.ppc_kbd_sysrq_xlate = mackbd_sysrq_xlate; + SYSRQ_KEY = 0x69; +#endif /* CONFIG_MAGIC_SYSRQ */ + } +#endif /* CONFIG_VT && CONFIG_ADB_KEYBOARD */ } #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) @@ -598,40 +627,40 @@ ppc_md.calibrate_decr = chrp_calibrate_decr; #ifdef CONFIG_VT -#ifdef CONFIG_MAC_KEYBOARD - if (adb_driver == NULL) - { -#endif /* CONFIG_MAC_KEYBOAD */ - ppc_md.kbd_setkeycode = pckbd_setkeycode; - ppc_md.kbd_getkeycode = pckbd_getkeycode; - ppc_md.kbd_translate = pckbd_translate; - ppc_md.kbd_unexpected_up = pckbd_unexpected_up; - ppc_md.kbd_leds = pckbd_leds; - ppc_md.kbd_init_hw = pckbd_init_hw; -#ifdef CONFIG_MAGIC_SYSRQ - ppc_md.ppc_kbd_sysrq_xlate = pckbd_sysrq_xlate; - SYSRQ_KEY = 0x54; -#endif /* CONFIG_MAGIC_SYSRQ */ -#ifdef CONFIG_MAC_KEYBOARD - } - else - { - ppc_md.kbd_setkeycode = mackbd_setkeycode; - ppc_md.kbd_getkeycode = mackbd_getkeycode; - ppc_md.kbd_translate = mackbd_translate; - ppc_md.kbd_unexpected_up = mackbd_unexpected_up; - ppc_md.kbd_leds = mackbd_leds; - ppc_md.kbd_init_hw = mackbd_init_hw; + /* these are adjusted in chrp_init2 if we have an ADB keyboard */ + ppc_md.kbd_setkeycode = pckbd_setkeycode; + ppc_md.kbd_getkeycode = pckbd_getkeycode; + ppc_md.kbd_translate = pckbd_translate; + ppc_md.kbd_unexpected_up = pckbd_unexpected_up; + ppc_md.kbd_leds = pckbd_leds; + ppc_md.kbd_init_hw = pckbd_init_hw; #ifdef CONFIG_MAGIC_SYSRQ - ppc_md.ppc_kbd_sysrq_xlate = mackbd_sysrq_xlate; - SYSRQ_KEY = 0x69; + ppc_md.ppc_kbd_sysrq_xlate = pckbd_sysrq_xlate; + SYSRQ_KEY = 0x54; #endif /* CONFIG_MAGIC_SYSRQ */ - } -#endif /* CONFIG_MAC_KEYBOARD */ #endif /* CONFIG_VT */ - if ( rtas_data ) - ppc_md.progress = chrp_progress; - + + if (rtas_data) { + struct device_node *rtas; + unsigned int *p; + + rtas = find_devices("rtas"); + if (rtas != NULL) { + if (get_property(rtas, "display-character", NULL)) { + ppc_md.progress = rtas_display_progress; + p = (unsigned int *) get_property + (rtas, "ibm,display-line-length", NULL); + if (p) + max_width = *p; + } else if (get_property(rtas, "set-indicator", NULL)) + ppc_md.progress = rtas_indicator_progress; + } + } +#ifdef CONFIG_BOOTX_TEXT + if (ppc_md.progress == NULL && bootx_text_mapped) + ppc_md.progress = bootx_text_progress; +#endif + #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) ppc_ide_md.insw = chrp_ide_insw; ppc_ide_md.outsw = chrp_ide_outsw; @@ -653,30 +682,13 @@ } void __chrp -chrp_progress(char *s, unsigned short hex) +rtas_display_progress(char *s, unsigned short hex) { - extern unsigned int rtas_data; - int max_width, width; - struct device_node *root; + int width; char *os = s; - unsigned long *p; - if ( (root = find_path_device("/rtas")) && - (p = (unsigned long *)get_property(root, - "ibm,display-line-length", - NULL)) ) - max_width = *p; - else - max_width = 0x10; - - if ( (_machine != _MACH_chrp) || !rtas_data ) - return; if ( call_rtas( "display-character", 1, 1, NULL, '\r' ) ) - { - /* assume no display-character RTAS method - use hex display */ - call_rtas("set-indicator", 3, 1, NULL, 6, 0, hex); return; - } width = max_width; while ( *os ) @@ -696,3 +708,17 @@ call_rtas( "display-character", 1, 1, NULL, ' ' ); } +void __chrp +rtas_indicator_progress(char *s, unsigned short hex) +{ + call_rtas("set-indicator", 3, 1, NULL, 6, 0, hex); +} + +#ifdef CONFIG_BOOTX_TEXT +void +bootx_text_progress(char *s, unsigned short hex) +{ + prom_print(s); + prom_print("\n"); +} +#endif /* CONFIG_BOOTX_TEXT */ diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/kernel/chrp_time.c linux/arch/ppc/kernel/chrp_time.c --- v2.4.0-test8/linux/arch/ppc/kernel/chrp_time.c Thu Jul 13 09:42:50 2000 +++ linux/arch/ppc/kernel/chrp_time.c Sun Sep 17 09:48:06 2000 @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -32,18 +33,20 @@ static int nvram_as0 = NVRAM_AS0; static int nvram_data = NVRAM_DATA; -void __init chrp_time_init(void) +long __init chrp_time_init(void) { struct device_node *rtcs; int base; rtcs = find_compatible_devices("rtc", "pnpPNP,b00"); if (rtcs == NULL || rtcs->addrs == NULL) - return; + return 0; base = rtcs->addrs[0].address; nvram_as1 = 0; nvram_as0 = base; nvram_data = base + 1; + + return 0; } int __chrp chrp_cmos_clock_read(int addr) @@ -115,28 +118,34 @@ unsigned long __chrp chrp_get_rtc_time(void) { unsigned int year, mon, day, hour, min, sec; - int i; + int uip, i; /* The Linux interpretation of the CMOS clock register contents: * When the Update-In-Progress (UIP) flag goes from 1 to 0, the * RTC registers show the second which has precisely just started. * Let's hope other operating systems interpret the RTC the same way. */ - /* read RTC exactly on falling edge of update flag */ - for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */ - if (chrp_cmos_clock_read(RTC_FREQ_SELECT) & RTC_UIP) - break; - for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */ - if (!(chrp_cmos_clock_read(RTC_FREQ_SELECT) & RTC_UIP)) - break; - do { /* Isn't this overkill ? UIP above should guarantee consistency */ + + /* Since the UIP flag is set for about 2.2 ms and the clock + * is typically written with a precision of 1 jiffy, trying + * to obtain a precision better than a few milliseconds is + * an illusion. Only consistency is interesting, this also + * allows to use the routine for /dev/rtc without a potential + * 1 second kernel busy loop triggered by any reader of /dev/rtc. + */ + + for ( i = 0; i<1000000; i++) { + uip = chrp_cmos_clock_read(RTC_FREQ_SELECT); sec = chrp_cmos_clock_read(RTC_SECONDS); min = chrp_cmos_clock_read(RTC_MINUTES); hour = chrp_cmos_clock_read(RTC_HOURS); day = chrp_cmos_clock_read(RTC_DAY_OF_MONTH); mon = chrp_cmos_clock_read(RTC_MONTH); year = chrp_cmos_clock_read(RTC_YEAR); - } while (sec != chrp_cmos_clock_read(RTC_SECONDS)); + uip |= chrp_cmos_clock_read(RTC_FREQ_SELECT); + if ((uip & RTC_UIP)==0) break; + } + if (!(chrp_cmos_clock_read(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { BCD_TO_BIN(sec); @@ -155,8 +164,7 @@ void __init chrp_calibrate_decr(void) { struct device_node *cpu; - int *fp, divisor; - unsigned long freq; + unsigned int freq, *fp; if (via_calibrate_decr()) return; @@ -168,15 +176,13 @@ freq = 16666000; /* hardcoded default */ cpu = find_type_devices("cpu"); if (cpu != 0) { - fp = (int *) get_property(cpu, "timebase-frequency", NULL); + fp = (unsigned int *) + get_property(cpu, "timebase-frequency", NULL); if (fp != 0) freq = *fp; } - freq *= 30; - divisor = 30; - printk("time_init: decrementer frequency = %lu/%d (%ld MHz)\n", freq, - divisor, (freq/divisor)>>20); - decrementer_count = freq / HZ / divisor; - count_period_num = divisor; - count_period_den = freq / 1000000; + printk("time_init: decrementer frequency = %u.%.6u MHz\n", + freq/1000000, freq%1000000); + tb_ticks_per_jiffy = freq / HZ; + tb_to_us = mulhwu_scale_factor(freq, 1000000); } diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/kernel/entry.S linux/arch/ppc/kernel/entry.S --- v2.4.0-test8/linux/arch/ppc/kernel/entry.S Fri Aug 4 16:15:37 2000 +++ linux/arch/ppc/kernel/entry.S Sun Sep 17 09:48:06 2000 @@ -30,6 +30,7 @@ #include #include #include +#include "mol.h" #undef SHOW_SYSCALLS #undef SHOW_SYSCALLS_TASK @@ -85,7 +86,7 @@ beq- 10f cmpi 0,r0,0x6666 /* Special case for 'sys_rt_sigreturn' */ beq- 16f - lwz r10,TASK_FLAGS(r2) + lwz r10,TASK_PTRACE(r2) andi. r10,r10,PT_TRACESYS bne- 50f cmpli 0,r0,NR_syscalls @@ -241,6 +242,13 @@ /* XXX it would be nice to find a SPRGx for this on 6xx,7xx too */ lwz r9,PGDIR(r4) /* cache the page table root */ tophys(r9,r9) /* convert to phys addr */ +#ifdef CONFIG_8xx_CPU6 + lis r6, cpu6_errata_word@h + ori r6, r6, cpu6_errata_word@l + li r5, 0x3980 + stw r5, 8(r6) + lwz r5, 8(r6) +#endif mtspr M_TWB,r9 /* Update MMU base address */ tlbia SYNC @@ -349,21 +357,18 @@ beq+ restore li r3,0 addi r4,r1,STACK_FRAME_OVERHEAD + MOL_HOOK_MMU(8,r8) bl do_signal .globl do_signal_ret do_signal_ret: -restore: - lwz r3,_CTR(r1) - lwz r0,_LINK(r1) - mtctr r3 - mtlr r0 +restore: lwz r3,_XER(r1) mtspr XER,r3 - REST_10GPRS(3, r1) - REST_10GPRS(13, r1) - REST_8GPRS(23, r1) - REST_GPR(31, r1) - + REST_10GPRS(9,r1) + REST_10GPRS(19,r1) + REST_2GPRS(29,r1) + REST_GPR(31,r1) + /* make sure we hard disable here, even if rtl is active, to protect * SRR[01] and SPRG2 -- Cort */ @@ -376,12 +381,28 @@ lwz r0,_MSR(r1) andi. r0,r0,MSR_PR beq+ 1f +#ifdef CONFIG_ALTIVEC + mfpvr r8 /* check if we are on a G4 */ + srwi r8,r8,16 + cmpwi r8,PVR_7400@h + bne 2f + lwz r0,THREAD+THREAD_VRSAVE(r2) + mtspr SPRN_VRSAVE,r0 /* if so, restore VRSAVE reg */ +2: +#endif /* CONFIG_ALTIVEC */ addi r0,r1,INT_FRAME_SIZE /* size of frame */ stw r0,THREAD+KSP(r2) /* save kernel stack pointer */ - tophys(r2,r1) - CLR_TOP32(r2) - mtspr SPRG2,r2 /* phys exception stack pointer */ + tophys(r8,r1) + CLR_TOP32(r8) + MOL_HOOK_MMU(9, r4) /* mod. r0,r2-r7, lr, ctr */ + mtspr SPRG2,r8 /* phys exception stack pointer */ 1: + lwz r3,_CTR(r1) + lwz r0,_LINK(r1) + mtctr r3 + mtlr r0 + REST_4GPRS(3, r1) + REST_2GPRS(7, r1) lwz r0,_MSR(r1) FIX_SRR1(r0,r2) mtspr SRR1,r0 diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/kernel/feature.c linux/arch/ppc/kernel/feature.c --- v2.4.0-test8/linux/arch/ppc/kernel/feature.c Thu Jul 13 09:42:50 2000 +++ linux/arch/ppc/kernel/feature.c Sun Sep 17 09:48:06 2000 @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include #include #include @@ -34,6 +36,20 @@ #define MAX_FEATURE_OFFSET 0x100 #define FREG(c,r) (&(((c)->reg)[(r)>>2])) +/* Keylargo reg. access. */ +#define KL_FCR(r) (keylargo_base + ((r) >> 2)) +#define KL_IN(r) (in_le32(KL_FCR(r))) +#define KL_OUT(r,v) (out_le32(KL_FCR(r), (v))) +#define KL_BIS(r,v) (KL_OUT((r), KL_IN(r) | (v))) +#define KL_BIC(r,v) (KL_OUT((r), KL_IN(r) & ~(v))) + +/* Uni-N reg. access. Note that Uni-N regs are big endian */ +#define UN_REG(r) (uninorth_base + ((r) >> 2)) +#define UN_IN(r) (in_be32(UN_REG(r))) +#define UN_OUT(r,v) (out_be32(UN_REG(r), (v))) +#define UN_BIS(r,v) (UN_OUT((r), UN_IN(r) | (v))) +#define UN_BIC(r,v) (UN_OUT((r), UN_IN(r) & ~(v))) + typedef struct feature_bit { int reg; /* reg. offset from mac-io base */ unsigned int polarity; /* 0 = normal, 1 = inverse */ @@ -74,11 +90,45 @@ {0x38,0,0}, /* FEATURE_Airport_reset */ }; -/* Those bits are from a PowerBook. It's possible that desktop machines - * based on heathrow need a different definition or some bits removed +/* Those bits concern heathrow-based desktop machines (Beige G3s). We have removed + * the SCC related bits and init them once. They have proven to occasionally cause + * problems with the desktop units. */ static fbit feature_bits_heathrow[] = { {0x38,0,0}, /* FEATURE_null */ + {0x38,0,0}, /* FEATURE_Serial_reset */ + {0x38,0,0}, /* FEATURE_Serial_enable */ + {0x38,0,0}, /* FEATURE_Serial_IO_A */ + {0x38,0,0}, /* FEATURE_Serial_IO_B */ + {0x38,0,HRW_SWIM_ENABLE}, /* FEATURE_SWIM3_enable */ + {0x38,0,HRW_MESH_ENABLE}, /* FEATURE_MESH_enable */ + {0x38,0,HRW_IDE0_ENABLE}, /* FEATURE_IDE0_enable */ + {0x38,1,HRW_IDE0_RESET_N}, /* FEATURE_IDE0_reset */ + {0x38,0,HRW_IOBUS_ENABLE}, /* FEATURE_IOBUS_enable */ + {0x38,1,0}, /* FEATURE_Mediabay_reset */ + {0x38,1,0}, /* FEATURE_Mediabay_power */ + {0x38,0,0}, /* FEATURE_Mediabay_PCI_enable */ + {0x38,0,HRW_BAY_IDE_ENABLE}, /* FEATURE_IDE1_enable */ + {0x38,1,HRW_IDE1_RESET_N}, /* FEATURE_IDE1_reset */ + {0x38,0,0}, /* FEATURE_Mediabay_floppy_enable */ + {0x38,0,HRW_BMAC_RESET}, /* FEATURE_BMac_reset */ + {0x38,0,HRW_BMAC_IO_ENABLE}, /* FEATURE_BMac_IO_enable */ + {0x38,1,0}, /* FEATURE_Modem_power */ + {0x38,0,HRW_SLOW_SCC_PCLK}, /* FEATURE_Slow_SCC_PCLK */ + {0x38,1,0}, /* FEATURE_Sound_Power */ + {0x38,0,0}, /* FEATURE_Sound_CLK_Enable */ + {0x38,0,0}, /* FEATURE_IDE2_enable */ + {0x38,0,0}, /* FEATURE_IDE2_reset */ + {0x38,0,0}, /* FEATURE_Mediabay_IDE_switch */ + {0x38,0,0}, /* FEATURE_Mediabay_content */ + {0x38,0,0}, /* FEATURE_Airport_reset */ +}; + +/* Those bits concern heathrow-based PowerBooks (wallstreet/mainstreet). + * Heathrow-based desktop macs (Beige G3s) are _not_ handled here + */ +static fbit feature_bits_wallstreet[] = { + {0x38,0,0}, /* FEATURE_null */ {0x38,0,HRW_RESET_SCC}, /* FEATURE_Serial_reset */ {0x38,0,HRW_SCC_ENABLE}, /* FEATURE_Serial_enable */ {0x38,0,HRW_SCCA_IO}, /* FEATURE_Serial_IO_A */ @@ -145,32 +195,32 @@ */ static fbit feature_bits_keylargo[] = { {0x38,0,0}, /* FEATURE_null */ - {0x38,0,0}, /* FEATURE_Serial_reset */ - {0x38,0,0x00000054}, /* FEATURE_Serial_enable */ - {0x38,0,0}, /* FEATURE_Serial_IO_A */ - {0x38,0,0}, /* FEATURE_Serial_IO_B */ + {0x38,0,KL0_SCC_RESET}, /* FEATURE_Serial_reset */ + {0x38,0,KL0_SERIAL_ENABLE}, /* FEATURE_Serial_enable */ + {0x38,0,KL0_SCC_A_INTF_ENABLE}, /* FEATURE_Serial_IO_A */ + {0x38,0,KL0_SCC_B_INTF_ENABLE}, /* FEATURE_Serial_IO_B */ {0x38,0,0}, /* FEATURE_SWIM3_enable */ {0x38,0,0}, /* FEATURE_MESH_enable */ {0x3c,0,0}, /* FEATURE_IDE0_enable */ - {0x3c,1,0x01000000}, /* FEATURE_IDE0_reset */ + {0x3c,1,KL1_EIDE0_RESET_N}, /* FEATURE_IDE0_reset */ {0x38,0,0}, /* FEATURE_IOBUS_enable */ {0x34,1,0x00000200}, /* FEATURE_Mediabay_reset */ {0x34,1,0x00000400}, /* FEATURE_Mediabay_power */ {0x38,0,0}, /* FEATURE_Mediabay_PCI_enable */ {0x3c,0,0x0}, /* FEATURE_IDE1_enable */ - {0x3c,1,0x08000000}, /* FEATURE_IDE1_reset */ + {0x3c,1,KL1_EIDE1_RESET_N}, /* FEATURE_IDE1_reset */ {0x38,0,0}, /* FEATURE_Mediabay_floppy_enable */ {0x38,0,0}, /* FEATURE_BMac_reset */ {0x38,0,0}, /* FEATURE_BMac_IO_enable */ - {0x40,1,0x02000000}, /* FEATURE_Modem_power */ + {0x40,1,KL2_MODEM_POWER_N}, /* FEATURE_Modem_power */ {0x38,0,0}, /* FEATURE_Slow_SCC_PCLK */ {0x38,0,0}, /* FEATURE_Sound_Power */ {0x38,0,0}, /* FEATURE_Sound_CLK_Enable */ {0x38,0,0}, /* FEATURE_IDE2_enable */ - {0x3c,1,0x40000000}, /* FEATURE_IDE2_reset */ - {0x34,0,0x00001000}, /* FEATURE_Mediabay_IDE_switch */ + {0x3c,1,KL1_UIDE_RESET_N}, /* FEATURE_IDE2_reset */ + {0x34,0,KL_MBCR_MBDEV_ENABLE}, /* FEATURE_Mediabay_IDE_switch */ {0x34,0,0x00000100}, /* FEATURE_Mediabay_content */ - {0x40,1,0x08000000}, /* FEATURE_Airport_reset */ + {0x40,1,KL2_AIRPORT_RESET_N}, /* FEATURE_Airport_reset */ }; /* definition of a feature controller object */ @@ -190,6 +240,8 @@ static void heathrow_prepare_for_sleep(struct feature_controller* ctrler); static void heathrow_wakeup(struct feature_controller* ctrler); +static void keylargo_init(void); +static void uninorth_init(void); static void core99_prepare_for_sleep(struct feature_controller* ctrler); static void core99_wake_up(struct feature_controller* ctrler); @@ -228,8 +280,15 @@ } } else if (device_is_compatible(np, "paddington")) { feature_add_controller(np, feature_bits_paddington); + } else if (machine_is_compatible("AAPL,PowerBook1998")) { + feature_add_controller(np, feature_bits_wallstreet); } else { - feature_add_controller(np, feature_bits_heathrow); + struct feature_controller* ctrler = + feature_add_controller(np, feature_bits_heathrow); + if (ctrler) + out_le32(FREG(ctrler,HEATHROW_FEATURE_REG), + in_le32(FREG(ctrler,HEATHROW_FEATURE_REG)) | HRW_DEFAULTS); + } np = np->next; } @@ -249,14 +308,17 @@ np = find_devices("uni-n"); if (np && np->n_addrs > 0) { uninorth_base = ioremap(np->addrs[0].address, 0x1000); - rev = (u32 *)get_property(np, "device-rev", NULL); - if (rev) - uninorth_rev = *rev; + uninorth_rev = in_be32(UN_REG(UNI_N_VERSION)); } if (uninorth_base && keylargo_base) printk("Uni-N revision: %d, KeyLargo revision: %d\n", uninorth_rev, keylargo_rev); + if (uninorth_base) + uninorth_init(); + if (keylargo_base) + keylargo_init(); + if (controller_count) printk(KERN_INFO "Registered %d feature controller(s)\n", controller_count); @@ -440,14 +502,21 @@ if (!uninorth_base) return; if (power) - out_le32(uninorth_base + 0x20/4, - in_le32(uninorth_base + 0x20/4) | 0x02000000); + UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC); else - out_le32(uninorth_base + 0x20/4, - in_le32(uninorth_base + 0x20/4) & ~0x02000000); + UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC); udelay(20); } +void +feature_set_gmac_phy_reset(struct device_node* device, int reset) +{ + if (!keylargo_base) + return; + out_8((volatile u8 *)KL_FCR(KL_GPIO_ETH_PHY_RESET), reset); + (void)in_8((volatile u8 *)KL_FCR(KL_GPIO_ETH_PHY_RESET)); +} + /* Pass the node of the correct controller, please */ void feature_set_usb_power(struct device_node* device, int power) @@ -460,6 +529,53 @@ { } +/* Initialize the Core99 UniNorth host bridge and memory controller + */ +static void +uninorth_init(void) +{ + struct device_node* gmac; + unsigned long actrl; + + /* Set the arbitrer QAck delay according to what Apple does + */ + actrl = in_be32(UN_REG(UNI_N_ARB_CTRL)) & ~UNI_N_ARB_CTRL_QACK_DELAY_MASK; + actrl |= ((uninorth_rev < 3) ? UNI_N_ARB_CTRL_QACK_DELAY105 : UNI_N_ARB_CTRL_QACK_DELAY) + << UNI_N_ARB_CTRL_QACK_DELAY_SHIFT; + UN_OUT(UNI_N_ARB_CTRL, actrl); + + /* + * Turns OFF the gmac clock. The gmac driver will turn + * it back ON when the interface is enabled. This save + * power on portables. + * + * Note: We could also try to turn OFF the PHY. Since this + * has to be done by both the gmac driver and this code, + * I'll probably end-up moving some of this out of the + * modular gmac driver into a non-modular stub containing + * some basic PHY management and power management stuffs + */ + gmac = find_devices("ethernet"); + + while(gmac) { + if (device_is_compatible(gmac, "gmac")) + break; + gmac = gmac->next; + } + if (gmac) + feature_set_gmac_power(gmac, 0); +} + +/* Initialize the Core99 KeyLargo ASIC. Currently, we just make sure + * OpenPIC is enabled + */ +static void +keylargo_init(void) +{ + KL_BIS(KEYLARGO_FCR2, KL2_MPIC_ENABLE); +} + +#ifdef CONFIG_PMAC_PBOOK void feature_prepare_for_sleep(void) { @@ -506,27 +622,28 @@ } } -static u32 save_fcr0; -//static u32 save_fcr1; -//static u32 save_fcr2; +static u32 save_fcr[5]; static u32 save_mbcr; static void heathrow_prepare_for_sleep(struct feature_controller* ctrler) { save_mbcr = in_le32(FREG(ctrler, 0x34)); - save_fcr0 = in_le32(FREG(ctrler, 0x38)); + save_fcr[0] = in_le32(FREG(ctrler, 0x38)); + save_fcr[1] = in_le32(FREG(ctrler, 0x3c)); - out_le32(FREG(ctrler, 0x38), save_fcr0 & ~HRW_IOBUS_ENABLE); + out_le32(FREG(ctrler, 0x38), save_fcr[0] & ~HRW_IOBUS_ENABLE); } static void heathrow_wakeup(struct feature_controller* ctrler) { - out_le32(FREG(ctrler, 0x38), save_fcr0); + out_le32(FREG(ctrler, 0x38), save_fcr[0]); + out_le32(FREG(ctrler, 0x3c), save_fcr[1]); out_le32(FREG(ctrler, 0x34), save_mbcr); - - out_le32(FREG(ctrler, 0x38), save_fcr0 | HRW_IOBUS_ENABLE); + mdelay(1); + out_le32(FREG(ctrler, 0x38), save_fcr[0] | HRW_IOBUS_ENABLE); + mdelay(1); } static void @@ -540,4 +657,4 @@ { /* Not yet implemented */ } - +#endif /* CONFIG_PMAC_PBOOK */ diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/kernel/gemini_setup.c linux/arch/ppc/kernel/gemini_setup.c --- v2.4.0-test8/linux/arch/ppc/kernel/gemini_setup.c Thu Jul 13 09:42:50 2000 +++ linux/arch/ppc/kernel/gemini_setup.c Sun Sep 17 09:48:06 2000 @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -335,7 +336,7 @@ #define gemini_rtc_write(val,x) (writeb((val),(GEMINI_RTC+(x)))) /* ensure that the RTC is up and running */ -void __init gemini_time_init(void) +long __init gemini_time_init(void) { unsigned char reg; @@ -346,6 +347,7 @@ gemini_rtc_write((reg & ~(M48T35_RTC_STOPPED)), M48T35_RTC_CONTROL); gemini_rtc_write((reg | M48T35_RTC_SET), M48T35_RTC_CONTROL); } + return 0; } #undef DEBUG_RTC diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/kernel/hashtable.S linux/arch/ppc/kernel/hashtable.S --- v2.4.0-test8/linux/arch/ppc/kernel/hashtable.S Mon Jun 19 17:59:36 2000 +++ linux/arch/ppc/kernel/hashtable.S Sun Sep 17 09:48:06 2000 @@ -27,6 +27,7 @@ #include #include #include +#include "mol.h" /* * Load a PTE into the hash table, if possible. @@ -593,6 +594,11 @@ * flush_hash_page(unsigned context, unsigned long va) */ _GLOBAL(flush_hash_page) +#ifdef CONFIG_MOL + mflr r10 + MOL_HOOK_MMU(10, r6) + mtlr r10 +#endif lis r6,Hash@ha lwz r6,Hash@l(r6) /* hash table base */ cmpwi 0,r6,0 /* hash table in use? */ diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/kernel/head.S linux/arch/ppc/kernel/head.S --- v2.4.0-test8/linux/arch/ppc/kernel/head.S Thu Jul 13 09:42:50 2000 +++ linux/arch/ppc/kernel/head.S Sun Sep 17 09:48:06 2000 @@ -31,6 +31,7 @@ #include #include #include +#include "mol.h" #ifdef CONFIG_APUS #include @@ -78,7 +79,7 @@ mtspr DBAT##n##L,RB; \ 1: #endif /* CONFIG_PPC64BRIDGE */ - + .text .globl _stext _stext: @@ -162,8 +163,8 @@ /* Switch MMU off, clear BATs and flush TLB. At this point, r3 contains * the physical address we are running at, returned by prom_init() */ -__after_prom_start: bl mmu_off +__after_mmu_off: bl clear_bats bl flush_tlbs #endif @@ -202,15 +203,7 @@ mr r26,r3 addis r4,r3,KERNELBASE@h /* current address of _start */ cmpwi 0,r4,0 /* are we already running at 0? */ - beq 2f /* assume it's OK if so */ - li r3,0 - mfmsr r0 - andi. r0,r0,MSR_DR /* MMU enabled? */ - beq relocate_kernel - lis r3,KERNELBASE@h /* if so, are we */ - cmpw 0,r4,r3 /* already running at KERNELBASE? */ bne relocate_kernel -2: #endif /* CONFIG_APUS */ /* * we now have the 1st 16M of ram mapped with the bats. @@ -300,6 +293,17 @@ .long hdlr; \ .long ret_from_except +#define STD_MOL_EXCEPTION(n, label, hdlr, hook) \ + . = n; \ +label: \ + EXCEPTION_PROLOG; \ + MOL_HOOK(hook); \ + addi r3,r1,STACK_FRAME_OVERHEAD; \ + li r20,MSR_KERNEL; \ + bl transfer_to_handler; \ + .long hdlr; \ + .long ret_from_except + /* System reset */ #ifdef CONFIG_SMP /* MVME/MTX and gemini start the secondary here */ #ifdef CONFIG_GEMINI @@ -324,6 +328,7 @@ DataAccess: EXCEPTION_PROLOG #endif /* CONFIG_PPC64BRIDGE */ + MOL_HOOK(0) mfspr r20,DSISR andis. r0,r20,0xa470 /* weird error? */ bne 1f /* if not, try to put a PTE */ @@ -366,6 +371,7 @@ InstructionAccess: EXCEPTION_PROLOG #endif /* CONFIG_PPC64BRIDGE */ + MOL_HOOK(1) andis. r0,r23,0x4000 /* no pte found? */ beq 1f /* if so, try to put a PTE */ mr r3,r22 /* into the hash table */ @@ -430,6 +436,7 @@ . = 0x700 ProgramCheck: EXCEPTION_PROLOG + MOL_HOOK(2) addi r3,r1,STACK_FRAME_OVERHEAD li r20,MSR_KERNEL rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */ @@ -441,6 +448,7 @@ . = 0x800 FPUnavailable: EXCEPTION_PROLOG + MOL_HOOK_RESTORE(3) bne load_up_fpu /* if from user, just load it up */ li r20,MSR_KERNEL bl transfer_to_handler /* if from kernel, take a trap */ @@ -450,6 +458,7 @@ . = 0x900 Decrementer: EXCEPTION_PROLOG + MOL_HOOK(4) addi r3,r1,STACK_FRAME_OVERHEAD li r20,MSR_KERNEL bl transfer_to_handler @@ -473,12 +482,9 @@ .long ret_from_except /* Single step - not used on 601 */ - STD_EXCEPTION(0xd00, SingleStep, SingleStepException) - + STD_MOL_EXCEPTION(0xd00, SingleStep, SingleStepException, 5) STD_EXCEPTION(0xe00, Trap_0e, UnknownException) -#ifndef CONFIG_ALTIVEC - STD_EXCEPTION(0xf00, Trap_0f, UnknownException) -#else + /* * The Altivec unavailable trap is at 0x0f20. Foo. * We effectively remap it to 0x3000. @@ -493,15 +499,20 @@ .long ret_from_except . = 0xf20 +#ifdef CONFIG_ALTIVEC b AltiVecUnavailable -#endif /* CONFIG_ALTIVEC */ - +#endif +Trap_0f: + EXCEPTION_PROLOG + b trap_0f_cont + /* * Handle TLB miss for instruction on 603/603e. * Note: we get an alternate set of r0 - r3 to use automatically. */ . = 0x1000 InstructionTLBMiss: + MOL_HOOK_TLBMISS( 14 ) /* * r0: stored ctr * r1: linux style pte ( later becomes ppc hardware pte ) @@ -568,6 +579,7 @@ */ . = 0x1100 DataLoadTLBMiss: + MOL_HOOK_TLBMISS( 15 ) /* * r0: stored ctr * r1: linux style pte ( later becomes ppc hardware pte ) @@ -633,6 +645,7 @@ */ . = 0x1200 DataStoreTLBMiss: + MOL_HOOK_TLBMISS( 16 ) /* * r0: stored ctr * r1: linux style pte ( later becomes ppc hardware pte ) @@ -674,7 +687,7 @@ mtcrf 0x80,r3 rfi - STD_EXCEPTION(0x1300, Trap_13, InstructionBreakpoint) + STD_MOL_EXCEPTION(0x1300, Trap_13, InstructionBreakpoint, 11) STD_EXCEPTION(0x1400, SMI, SMIException) STD_EXCEPTION(0x1500, Trap_15, UnknownException) STD_EXCEPTION(0x1600, Trap_16, UnknownException) @@ -687,7 +700,7 @@ STD_EXCEPTION(0x1d00, Trap_1d, UnknownException) STD_EXCEPTION(0x1e00, Trap_1e, UnknownException) STD_EXCEPTION(0x1f00, Trap_1f, UnknownException) - STD_EXCEPTION(0x2000, RunMode, RunModeException) + STD_MOL_EXCEPTION(0x2000, RunMode, RunModeException, 5) STD_EXCEPTION(0x2100, Trap_21, UnknownException) STD_EXCEPTION(0x2200, Trap_22, UnknownException) STD_EXCEPTION(0x2300, Trap_23, UnknownException) @@ -709,16 +722,12 @@ #ifdef CONFIG_ALTIVEC AltiVecUnavailable: EXCEPTION_PROLOG + MOL_HOOK_RESTORE(12) bne load_up_altivec /* if from user, just load it up */ li r20,MSR_KERNEL bl transfer_to_handler /* if from kernel, take a trap */ .long KernelAltiVec .long ret_from_except - -/* here are the bits of trap 0xf00 which got displaced */ -Trap_0f: - EXCEPTION_PROLOG - b trap_0f_cont #endif /* CONFIG_ALTIVEC */ #ifdef CONFIG_PPC64BRIDGE @@ -753,6 +762,14 @@ beq 2f addi r24,r1,STACK_FRAME_OVERHEAD stw r24,PT_REGS(r23) +#ifdef CONFIG_ALTIVEC + mfpvr r24 /* check if we are on a G4 */ + srwi r24,r24,16 + cmpwi r24,PVR_7400@h + bne 2f + mfspr r22,SPRN_VRSAVE /* if so, save vrsave register value */ + stw r22,THREAD_VRSAVE(r23) +#endif /* CONFIG_ALTIVEC */ 2: addi r2,r23,-THREAD /* set r2 to current */ tovirt(r2,r2) mflr r23 @@ -771,6 +788,7 @@ lwz r24,0(r23) /* virtual address of handler */ lwz r23,4(r23) /* where to go when done */ FIX_SRR1(r20,r22) + MOL_HOOK(6) mtspr SRR0,r24 mtspr SRR1,r20 mtlr r23 @@ -981,6 +999,11 @@ .globl giveup_altivec giveup_altivec: +#ifdef CONFIG_MOL + mflr r4 + MOL_HOOK_MMU(13, r5) + mtlr r4 +#endif mfmsr r5 oris r5,r5,MSR_VEC@h SYNC @@ -1017,6 +1040,11 @@ */ .globl giveup_fpu giveup_fpu: +#ifdef CONFIG_MOL + mflr r4 + MOL_HOOK_MMU(7, r5) + mtlr r4 +#endif mfmsr r5 ori r5,r5,MSR_FP SYNC @@ -1048,19 +1076,10 @@ * the kernel image to physical address 0. */ relocate_kernel: -#if 0 /* Is this still needed ? I don't think so. It breaks new - * boot-with-mmu-off stuff - */ - lis r9,0x426f /* if booted from BootX, don't */ - addi r9,r9,0x6f58 /* translate source addr */ - cmpw r31,r9 /* (we have to on chrp) */ - beq 7f - rlwinm r4,r4,0,8,31 /* translate source address */ - add r4,r4,r3 /* to region mapped with BATs */ -#endif -7: addis r9,r26,klimit@ha /* fetch klimit */ + addis r9,r26,klimit@ha /* fetch klimit */ lwz r25,klimit@l(r9) addis r25,r25,-KERNELBASE@h + li r3,0 /* Destination base address */ li r6,0 /* Destination offset */ li r5,0x4000 /* # bytes of memory to copy */ bl copy_and_flush /* copy the first 0x4000 bytes */ @@ -1307,7 +1326,7 @@ mfspr r9,PVR rlwinm r9,r9,16,16,31 cmpi 0,r9,1 - beq 4f /* not needed for 601 */ + beq 6f /* not needed for 601 */ mfspr r11,HID0 andi. r0,r11,HID0_DCE ori r11,r11,HID0_ICE|HID0_DCE @@ -1323,26 +1342,33 @@ isync cmpi 0,r9,4 /* check for 604 */ cmpi 1,r9,9 /* or 604e */ - cmpi 2,r9,10 /* or mach5 */ + cmpi 2,r9,10 /* or mach5 / 604r */ cmpi 3,r9,8 /* check for 750 (G3) */ cmpi 4,r9,12 /* or 7400 (G4) */ cror 2,2,6 cror 2,2,10 bne 4f - ori r11,r11,HID0_SIED|HID0_BHTE /* for 604[e], enable */ + ori r11,r11,HID0_SIED|HID0_BHTE /* for 604[e|r], enable */ bne 2,5f - ori r11,r11,HID0_BTCD + ori r11,r11,HID0_BTCD /* superscalar exec & br history tbl */ b 5f 4: cror 14,14,18 bne 3,6f - /* We should add ABE here if we want to use Store Gathering - * and other nifty bridge features + /* for G3/G4: + * enable Store Gathering (SGE), Address Brodcast (ABE), + * Branch History Table (BHTE), Branch Target ICache (BTIC) */ - ori r11,r11,HID0_SGE|HID0_BHTE|HID0_BTIC /* for g3/g4, enable */ + ori r11,r11,HID0_SGE | HID0_ABE | HID0_BHTE | HID0_BTIC + oris r11,r11,HID0_DPM@h /* enable dynamic power mgmt */ + li r3,HID0_SPD + andc r11,r11,r3 /* clear SPD: enable speculative */ li r3,0 - mtspr ICTC,r3 -5: mtspr HID0,r11 /* superscalar exec & br history tbl */ + mtspr ICTC,r3 /* Instruction Cache Throttling off */ +5: isync + mtspr HID0,r11 + sync + isync 6: blr /* @@ -1548,12 +1574,11 @@ blr mmu_off: - addi r4, r3, __after_prom_start - _start + addi r4, r3, __after_mmu_off - _start mfmsr r3 andi. r0,r3,MSR_DR|MSR_IR /* MMU enabled? */ beqlr - ori r3,r3,MSR_DR|MSR_IR - xori r3,r3,MSR_DR|MSR_IR + andc r3,r3,r0 mtspr SRR0,r4 mtspr SRR1,r3 sync @@ -1617,23 +1642,19 @@ mflr r8 bl reloc_offset mtlr r8 - lis r8, disp_BATL@h - ori r8, r8, disp_BATL@l - add r8, r3, r8 - lwz r8, 0(r8) - lis r11, disp_BATU@h - ori r11, r11, disp_BATU@l - add r11, r3, r11 - lwz r11, 0(r11) - mtspr IBAT3L,r8 - mtspr IBAT3U,r11 + addis r8,r3,disp_BAT@ha + addi r8,r8,disp_BAT@l + lwz r11,0(r8) + lwz r8,4(r8) mfspr r9,PVR rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */ cmpi 0,r9,1 beq 1f mtspr DBAT3L,r8 mtspr DBAT3U,r11 -1: + blr +1: mtspr IBAT3L,r8 + mtspr IBAT3U,r11 blr #endif /* !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT) */ @@ -1649,17 +1670,42 @@ */ .globl m8260_gorom m8260_gorom: - li r5,MSR_KERNEL & ~(MSR_IR|MSR_DR) - lis r6,2f@h - addis r6,r6,-KERNELBASE@h - ori r6,r6,2f@l - mtspr SRR0,r6 - mtspr SRR1,r5 - rfi + mfmsr r0 + rlwinm r0,r0,0,17,15 /* clear MSR_EE in r0 */ + sync + mtmsr r0 + sync + mfspr r11, HID0 + lis r10, 0 + ori r10,r10,HID0_ICE|HID0_DCE + andc r11, r11, r10 + mtspr HID0, r11 + isync + li r5, MSR_ + lis r6,2f@h + addis r6,r6,-KERNELBASE@h + ori r6,r6,2f@l + mtspr SRR0,r6 + mtspr SRR1,r5 + isync + sync + rfi 2: - mtlr r4 - blr + mtlr r4 + blr +#endif + +#ifdef CONFIG_MOL +/* + * Mac-on-linux hook_table. Don't put this in the data section - + * the base address must be within the first 32KB of RAM. + */ + .globl mol_interface +mol_interface: + .long MOL_INTERFACE_VERSION + .fill 24,4,0 /* space for 24 hooks */ #endif + /* * We put a few things here that have to be page-aligned. diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/kernel/head_8xx.S linux/arch/ppc/kernel/head_8xx.S --- v2.4.0-test8/linux/arch/ppc/kernel/head_8xx.S Mon Jun 19 17:59:36 2000 +++ linux/arch/ppc/kernel/head_8xx.S Sun Sep 17 09:48:06 2000 @@ -874,6 +874,13 @@ lis r6, swapper_pg_dir@h tophys(r6,r6) ori r6, r6, swapper_pg_dir@l +#ifdef CONFIG_8xx_CPU6 + lis r4, cpu6_errata_word@h + ori r4, r4, cpu6_errata_word@l + li r3, 0x3980 + stw r3, 12(r4) + lwz r3, 12(r4) +#endif mtspr M_TWB, r6 lis r4,2f@h ori r4,r4,2f@l @@ -940,9 +947,23 @@ * ASID compare register with the new "context". */ _GLOBAL(set_context) +#ifdef CONFIG_8xx_CPU6 + lis r6, cpu6_errata_word@h + ori r6, r6, cpu6_errata_word@l + tophys (r4, r4) + li r7, 0x3980 + stw r7, 12(r6) + lwz r7, 12(r6) + mtspr M_TWB, r4 /* Update MMU base address */ + li r7, 0x3380 + stw r7, 12(r6) + lwz r7, 12(r6) + mtspr M_CASID, r3 /* Update context */ +#else mtspr M_CASID,r3 /* Update context */ tophys (r4, r4) mtspr M_TWB, r4 /* and pgd */ +#endif tlbia SYNC blr @@ -966,6 +987,24 @@ 2: mtlr r4 blr + +#ifdef CONFIG_8xx_CPU6 +/* It's here because it is unique to the 8xx. + * It is important we get called with interrupts disabled. I used to + * do that, but it appears that all code that calls this already had + * interrupt disabled. + */ + .globl set_dec_cpu6 +set_dec_cpu6: + lis r7, cpu6_errata_word@h + ori r7, r7, cpu6_errata_word@l + li r4, 0x2c00 + stw r4, 8(r7) + lwz r4, 8(r7) + mtspr 22, r3 /* Update Decrementer */ + SYNC + blr +#endif /* * We put a few things here that have to be page-aligned. @@ -990,4 +1029,10 @@ .globl cmd_line cmd_line: .space 512 + +#ifdef CONFIG_8xx_CPU6 + .globl cpu6_errata_word +cpu6_errata_word: + .space 16 +#endif diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/kernel/idle.c linux/arch/ppc/kernel/idle.c --- v2.4.0-test8/linux/arch/ppc/kernel/idle.c Thu Jul 13 09:42:50 2000 +++ linux/arch/ppc/kernel/idle.c Sun Sep 17 09:48:06 2000 @@ -286,6 +286,7 @@ case 6: /* 603e */ case 7: /* 603ev */ case 8: /* 750 */ + case 12: /* 7400 */ save_flags(msr); __cli(); if (!current->need_resched) { diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/kernel/irq.c linux/arch/ppc/kernel/irq.c --- v2.4.0-test8/linux/arch/ppc/kernel/irq.c Fri Aug 4 16:15:37 2000 +++ linux/arch/ppc/kernel/irq.c Sun Sep 17 09:48:06 2000 @@ -137,17 +137,21 @@ if (!handler) { /* Free */ - for (p = &irq_desc[irq].action; (action = *p) != NULL; p = &action->next) - { - /* Found it - now free it */ - save_flags(flags); - cli(); - *p = action->next; - restore_flags(flags); - irq_kfree(action); - return 0; - } - return -ENOENT; + p = &irq_desc[irq].action; + while ((action = *p) != NULL && action->dev_id != dev_id) + p = &action->next; + if (action == NULL) + return -ENOENT; + + /* Found it - now free it */ + save_flags(flags); + cli(); + *p = action->next; + if (irq_desc[irq].action == NULL) + disable_irq(irq); + restore_flags(flags); + irq_kfree(action); + return 0; } action = (struct irqaction *) @@ -300,7 +304,7 @@ } } -asmlinkage int do_IRQ(struct pt_regs *regs, int isfake) +int do_IRQ(struct pt_regs *regs, int isfake) { int cpu = smp_processor_id(); int irq; diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/kernel/m8260_setup.c linux/arch/ppc/kernel/m8260_setup.c --- v2.4.0-test8/linux/arch/ppc/kernel/m8260_setup.c Thu Jul 13 09:42:50 2000 +++ linux/arch/ppc/kernel/m8260_setup.c Sun Sep 17 09:48:07 2000 @@ -112,11 +112,10 @@ bd_t *binfo = (bd_t *)__res; int freq, divisor; - freq = (binfo->bi_intfreq * 1000000); - divisor = 16; - decrementer_count = freq / HZ / divisor; - count_period_num = divisor; - count_period_den = freq / 1000000; + freq = (binfo->bi_busfreq * 1000000); + divisor = 4; + tb_ticks_per_jiffy = freq / HZ / divisor; + tb_to_us = mulhwu_scale_factor(freq / divisor, 1000000); } /* The 8260 has an internal 1-second timer update register that @@ -143,8 +142,20 @@ m8260_restart(char *cmd) { extern void m8260_gorom(bd_t *bi, uint addr); + uint startaddr; - m8260_gorom(NULL, 0xff000100); + /* Most boot roms have a warmstart as the second instruction + * of the reset vector. If that doesn't work for you, change this + * or the reboot program to send a proper address. + */ + startaddr = 0xff000104; + + if (cmd != NULL) { + if (!strncmp(cmd, "startaddr=", 10)) + startaddr = simple_strtoul(&cmd[10], NULL, 0); + } + + m8260_gorom((uint)__pa(__res), startaddr); } void diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/kernel/m8xx_setup.c linux/arch/ppc/kernel/m8xx_setup.c --- v2.4.0-test8/linux/arch/ppc/kernel/m8xx_setup.c Thu Jul 13 09:42:50 2000 +++ linux/arch/ppc/kernel/m8xx_setup.c Sun Sep 17 09:48:07 2000 @@ -135,6 +135,13 @@ machine_restart(NULL); } +/* A place holder for time base interrupts, if they are ever enabled. +*/ +void timebase_interrupt(int irq, void * dev, struct pt_regs * regs) +{ + printk("timebase_interrupt()\n"); +} + /* The decrementer counts at the system (internal) clock frequency divided by * sixteen, or external oscillator divided by four. We force the processor * to use system clock divided by sixteen. @@ -160,35 +167,14 @@ freq = fp*60; /* try to make freq/1e6 an integer */ divisor = 60; printk("time_init: decrementer frequency = %d/%d\n", freq, divisor); - decrementer_count = freq / HZ / divisor; - count_period_num = divisor; - count_period_den = freq / 1000000; -} + tb_ticks_per_jiffy = freq / HZ / divisor; + tb_to_us = mulhwu_scale_factor(freq / divisor, 1000000); -/* A place holder for time base interrupts, if they are ever enabled. -*/ -void timebase_interrupt(int irq, void * dev, struct pt_regs * regs) -{ - printk("timebase_interrupt()\n"); -} - -/* The RTC on the MPC8xx is an internal register. - * We want to protect this during power down, so we need to unlock, - * modify, and re-lock. - */ -static int -m8xx_set_rtc_time(unsigned long time) -{ - ((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_rtck = KAPWR_KEY; - ((volatile immap_t *)IMAP_ADDR)->im_sit.sit_rtc = time; - ((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_rtck = ~KAPWR_KEY; - return(0); -} - -unsigned long __init -m8xx_get_rtc_time(void) -{ - /* First, unlock all of the registers we are going to modify. + /* Perform some more timer/timebase initialization. This used + * to be done elsewhere, but other changes caused it to get + * called more than once....that is a bad thing. + * + * First, unlock all of the registers we are going to modify. * To protect them from corruption during power down, registers * that are maintained by keep alive power are "locked". To * modify these registers we have to write the key value to @@ -219,9 +205,27 @@ ((volatile immap_t *)IMAP_ADDR)->im_sit.sit_tbscr = ((mk_int_int_mask(DEC_INTERRUPT) << 8) | (TBSCR_TBF | TBSCR_TBE)); + if (request_8xxirq(DEC_INTERRUPT, timebase_interrupt, 0, "tbint", NULL) != 0) panic("Could not allocate timer IRQ!"); +} + +/* The RTC on the MPC8xx is an internal register. + * We want to protect this during power down, so we need to unlock, + * modify, and re-lock. + */ +static int +m8xx_set_rtc_time(unsigned long time) +{ + ((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_rtck = KAPWR_KEY; + ((volatile immap_t *)IMAP_ADDR)->im_sit.sit_rtc = time; + ((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_rtck = ~KAPWR_KEY; + return(0); +} +unsigned long __init +m8xx_get_rtc_time(void) +{ /* Get time from the RTC. */ return((unsigned long)(((immap_t *)IMAP_ADDR)->im_sit.sit_rtc)); diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/kernel/misc.S linux/arch/ppc/kernel/misc.S --- v2.4.0-test8/linux/arch/ppc/kernel/misc.S Fri Aug 11 14:29:04 2000 +++ linux/arch/ppc/kernel/misc.S Sun Sep 17 09:48:07 2000 @@ -24,12 +24,15 @@ #if defined(CONFIG_4xx) || defined(CONFIG_8xx) #define CACHE_LINE_SIZE 16 #define LG_CACHE_LINE_SIZE 4 +#define MAX_COPY_PREFETCH 1 #elif !defined(CONFIG_PPC64BRIDGE) #define CACHE_LINE_SIZE 32 #define LG_CACHE_LINE_SIZE 5 +#define MAX_COPY_PREFETCH 4 #else #define CACHE_LINE_SIZE 128 #define LG_CACHE_LINE_SIZE 7 +#define MAX_COPY_PREFETCH 1 #endif /* CONFIG_4xx || CONFIG_8xx */ .text @@ -339,7 +342,15 @@ _GLOBAL(clear_page) li r0,4096/CACHE_LINE_SIZE mtctr r0 +#ifdef CONFIG_8xx + li r4, 0 +1: stw r4, 0(r3) + stw r4, 4(r3) + stw r4, 8(r3) + stw r4, 12(r3) +#else 1: dcbz 0,r3 +#endif addi r3,r3,CACHE_LINE_SIZE bdnz 1b blr @@ -361,12 +372,31 @@ stwu r9,16(r3) _GLOBAL(copy_page) - li r0,4096/CACHE_LINE_SIZE - mtctr r0 addi r3,r3,-4 addi r4,r4,-4 li r5,4 -1: dcbz r5,r3 + +#ifndef CONFIG_8xx +#if MAX_COPY_PREFETCH > 1 + li r0,MAX_COPY_PREFETCH + li r11,4 + mtctr r0 +11: dcbt r11,r4 + addi r11,r11,CACHE_LINE_SIZE + bdnz 11b +#else /* MAX_COPY_PREFETCH == 1 */ + dcbt r5,r4 + li r11,CACHE_LINE_SIZE+4 +#endif /* MAX_COPY_PREFETCH */ +#endif /* CONFIG_8xx */ + + li r0,4096/CACHE_LINE_SIZE + mtctr r0 +1: +#ifndef CONFIG_8xx + dcbt r11,r4 + dcbz r5,r3 +#endif COPY_16_BYTES #if CACHE_LINE_SIZE >= 32 COPY_16_BYTES @@ -484,7 +514,7 @@ stwcx. r5,0,r3 /* Update with new value */ bne- 10b /* Retry if "reservation" (i.e. lock) lost */ cntlzw r3,r5 - srwi r3,r3,5 + srwi r3,r3,5 blr #endif /* 0 */ _GLOBAL(atomic_clear_mask) @@ -629,48 +659,59 @@ blr /* - * Extended precision shifts + * Extended precision shifts. + * + * Updated to be valid for shift counts from 0 to 63 inclusive. + * -- Gabriel * * R3/R4 has 64 bit value * R5 has shift count * result in R3/R4 * - * ashrdi3: XXXYYY/ZZZAAA -> SSSXXX/YYYZZZ - * ashldi3: XXXYYY/ZZZAAA -> YYYZZZ/AAA000 - * lshrdi3: XXXYYY/ZZZAAA -> 000XXX/YYYZZZ + * ashrdi3: arithmetic right shift (sign propagation) + * lshrdi3: logical right shift + * ashldi3: left shift */ _GLOBAL(__ashrdi3) - li r6,32 - sub r6,r6,r5 - slw r7,r3,r6 /* isolate YYY */ - srw r4,r4,r5 /* isolate ZZZ */ - or r4,r4,r7 /* YYYZZZ */ - sraw r3,r3,r5 /* SSSXXX */ + subfic r6,r5,32 + srw r4,r4,r5 # LSW = count > 31 ? 0 : LSW >> count + addi r7,r5,32 # could be xori, or addi with -32 + slw r6,r3,r6 # t1 = count > 31 ? 0 : MSW << (32-count) + rlwinm r8,r7,0,32 # t3 = (count < 32) ? 32 : 0 + sraw r7,r3,r7 # t2 = MSW >> (count-32) + or r4,r4,r6 # LSW |= t1 + slw r7,r7,r8 # t2 = (count < 32) ? 0 : t2 + sraw r3,r3,r5 # MSW = MSW >> count + or r4,r4,r7 # LSW |= t2 blr _GLOBAL(__ashldi3) - li r6,32 - sub r6,r6,r5 - srw r7,r4,r6 /* isolate ZZZ */ - slw r4,r4,r5 /* AAA000 */ - slw r3,r3,r5 /* YYY--- */ - or r3,r3,r7 /* YYYZZZ */ + subfic r6,r5,32 + slw r3,r3,r5 # MSW = count > 31 ? 0 : MSW << count + addi r7,r5,32 # could be xori, or addi with -32 + srw r6,r4,r6 # t1 = count > 31 ? 0 : LSW >> (32-count) + slw r7,r4,r7 # t2 = count < 32 ? 0 : LSW << (count-32) + or r3,r3,r6 # MSW |= t1 + slw r4,r4,r5 # LSW = LSW << count + or r3,r3,r7 # MSW |= t2 blr _GLOBAL(__lshrdi3) - li r6,32 - sub r6,r6,r5 - slw r7,r3,r6 /* isolate YYY */ - srw r4,r4,r5 /* isolate ZZZ */ - or r4,r4,r7 /* YYYZZZ */ - srw r3,r3,r5 /* 000XXX */ + subfic r6,r5,32 + srw r4,r4,r5 # LSW = count > 31 ? 0 : LSW >> count + addi r7,r5,32 # could be xori, or addi with -32 + slw r6,r3,r6 # t1 = count > 31 ? 0 : MSW << (32-count) + srw r7,r3,r7 # t2 = count < 32 ? 0 : MSW >> (count-32) + or r4,r4,r6 # LSW |= t1 + srw r3,r3,r5 # MSW = MSW >> count + or r4,r4,r7 # LSW |= t2 blr _GLOBAL(abs) - cmpi 0,r3,0 - bge 10f - neg r3,r3 -10: blr + srawi r4,r3,31 + xor r3,r3,r4 + sub r3,r3,r4 + blr _GLOBAL(_get_SP) mr r3,r1 /* Close enough */ @@ -1217,6 +1258,6 @@ .long sys_pciconfig_iobase /* 200 */ .long sys_ni_syscall /* 201 - reserved - MacOnLinux - new */ .long sys_getdents64 /* 202 */ - .rept NR_syscalls-201 + .rept NR_syscalls-(.-sys_call_table)/4 .long sys_ni_syscall .endr diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/kernel/mol.h linux/arch/ppc/kernel/mol.h --- v2.4.0-test8/linux/arch/ppc/kernel/mol.h Wed Dec 31 16:00:00 1969 +++ linux/arch/ppc/kernel/mol.h Sun Sep 17 09:48:07 2000 @@ -0,0 +1,68 @@ +/* + * arch/ppc/kernel/mol.h + * + * + * + * Mac-on-Linux hook macros + * + * + * Copyright (C) 2000 Samuel Rydh (samuel@ibrium.se) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation + * + */ + +#ifndef _PPC_KERNEL_MOL +#define _PPC_KERNEL_MOL + +#include + +#ifdef CONFIG_MOL +#define MOL_INTERFACE_VERSION 3 + +#define MOL_HOOK(hook_num) \ + lwz r0,(mol_interface + 4 * hook_num + 4)@l(0); \ + cmpwi cr1,r0,0; \ + beq+ cr1,777f; \ + mtctr r0; \ + bctrl; \ +777: lwz r0,GPR0(r21) + +#define MOL_HOOK_RESTORE(hook_num) \ + mfcr r2; \ + MOL_HOOK(hook_num); \ + mtcrf 0x80,r2; \ + lwz r2,_CTR(r21); \ + mtctr r2; \ + lwz r2,GPR2(r21) + +#define MOL_HOOK_MMU(hook_num, scr) \ + lis scr,(mol_interface + 4 * hook_num + 4)@ha; \ + lwz scr,(mol_interface + 4 * hook_num + 4)@l(scr); \ + cmpwi cr1,scr,0; \ + beq+ cr1,778f; \ + mtctr scr; \ + bctrl; \ +778: + +#define MOL_HOOK_TLBMISS(hook_num) \ + lwz r0,(mol_interface + 4 * hook_num + 4)@l(0); \ + cmpwi r0,0; \ + beq+ 779f; \ + mflr r3; \ + mtlr r0; \ + blrl; \ + mtlr r3; \ +779: + +#else +#define MOL_HOOK(num) +#define MOL_HOOK_RESTORE(num) +#define MOL_HOOK_MMU(num, scr) +#define MOL_HOOK_TLBMISS(num) +#endif + + +#endif /* _PPC_KERNEL_MOL */ diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/kernel/oak_setup.c linux/arch/ppc/kernel/oak_setup.c --- v2.4.0-test8/linux/arch/ppc/kernel/oak_setup.c Thu Jul 13 09:42:50 2000 +++ linux/arch/ppc/kernel/oak_setup.c Sun Sep 17 09:48:07 2000 @@ -231,10 +231,11 @@ /* * Document me. */ -void __init +long __init oak_time_init(void) { /* XXX - Implement me */ + return 0; } /* diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/kernel/open_pic.c linux/arch/ppc/kernel/open_pic.c --- v2.4.0-test8/linux/arch/ppc/kernel/open_pic.c Thu Jul 13 09:42:50 2000 +++ linux/arch/ppc/kernel/open_pic.c Sun Sep 17 09:48:07 2000 @@ -100,7 +100,7 @@ #ifdef CONFIG_SMP void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs) { - smp_message_recv(cpl-OPENPIC_VEC_IPI); + smp_message_recv(cpl-OPENPIC_VEC_IPI, regs); } #endif /* CONFIG_SMP */ @@ -262,11 +262,11 @@ int j, pri; pri = strcmp(np->name, "programmer-switch") ? 2 : 7; for (j=0;jn_intrs;j++) { - openpic_initirq( np->intrs[j].line, - pri, - np->intrs[j].line, - 0, - np->intrs[j].sense); + openpic_initirq(np->intrs[j].line, + pri, + np->intrs[j].line, + 0, + np->intrs[j].sense); if (np->intrs[j].sense) irq_desc[np->intrs[j].line].status = IRQ_LEVEL; } diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/kernel/pci.c linux/arch/ppc/kernel/pci.c --- v2.4.0-test8/linux/arch/ppc/kernel/pci.c Mon Aug 7 14:31:40 2000 +++ linux/arch/ppc/kernel/pci.c Sun Sep 17 09:48:07 2000 @@ -25,7 +25,13 @@ #include "pci.h" -static void __init pcibios_claim_resources(struct list_head *); +#undef DEBUG + +#ifdef DEBUG +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif unsigned long isa_io_base = 0; unsigned long isa_mem_base = 0; @@ -70,95 +76,297 @@ generic_pcibios_write_dword }; -void __init pcibios_init(void) -{ - printk("PCI: Probing PCI hardware\n"); - pci_scan_bus(0, &generic_pci_ops, NULL); - if (ppc_md.pcibios_fixup) - ppc_md.pcibios_fixup(); - pcibios_claim_resources(&pci_root_buses); -} -void __init -pcibios_fixup_pbus_ranges(struct pci_bus * bus, struct pbus_set_ranges_data * ranges) + +void pcibios_update_resource(struct pci_dev *dev, struct resource *root, + struct resource *res, int resource) { - 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; + u32 new, check; + int reg; + + new = res->start | (res->flags & PCI_REGION_FLAG_MASK); + if (resource < 6) { + reg = PCI_BASE_ADDRESS_0 + 4*resource; + } else if (resource == PCI_ROM_RESOURCE) { + res->flags |= PCI_ROM_ADDRESS_ENABLE; + reg = dev->rom_base_reg; + } else { + /* Somebody might have asked allocation of a non-standard resource */ + return; + } + + pci_write_config_dword(dev, reg, new); + pci_read_config_dword(dev, reg, &check); + if ((new ^ check) & ((new & PCI_BASE_ADDRESS_SPACE_IO) ? PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK)) { + printk(KERN_ERR "PCI: Error while updating region " + "%s/%d (%08x != %08x)\n", dev->slot_name, resource, + new, check); + } } -unsigned long resource_fixup(struct pci_dev * dev, struct resource * res, - unsigned long start, unsigned long size) +/* + * We need to avoid collisions with `mirrored' VGA ports + * and other strange ISA hardware, so we always want the + * addresses to be allocated in the 0x000-0x0ff region + * modulo 0x400. + * + * Why? Because some silly external IO cards only decode + * the low 10 bits of the IO address. The 0x00-0xff region + * is reserved for motherboard devices that decode all 16 + * bits, so it's ok to allocate at, say, 0x2800-0x28ff, + * but we want to try to avoid allocating at 0x2900-0x2bff + * which might have be mirrored at 0x0100-0x03ff.. + */ +void +pcibios_align_resource(void *data, struct resource *res, unsigned long size) { - return start; + struct pci_dev *dev = data; + + if (res->flags & IORESOURCE_IO) { + unsigned long start = res->start; + + if (size > 0x100) { + printk(KERN_ERR "PCI: I/O Region %s/%d too large" + " (%ld bytes)\n", dev->slot_name, + dev->resource - res, size); + } + + if (start & 0x300) { + start = (start + 0x3ff) & ~0x3ff; + res->start = start; + } + } } -static void __init pcibios_claim_resources(struct list_head *bus_list) + +/* + * Handle resources of PCI devices. If the world were perfect, we could + * just allocate all the resource regions and do nothing more. It isn't. + * On the other hand, we cannot just re-allocate all devices, as it would + * require us to know lots of host bridge internals. So we attempt to + * keep as much of the original configuration as possible, but tweak it + * when it's found to be wrong. + * + * Known BIOS problems we have to work around: + * - I/O or memory regions not configured + * - regions configured, but not enabled in the command register + * - bogus I/O addresses above 64K used + * - expansion ROMs left enabled (this may sound harmless, but given + * the fact the PCI specs explicitly allow address decoders to be + * shared between expansion ROMs and other resource regions, it's + * at least dangerous) + * + * Our solution: + * (1) Allocate resources for all buses behind PCI-to-PCI bridges. + * This gives us fixed barriers on where we can allocate. + * (2) Allocate resources for all enabled devices. If there is + * a collision, just mark the resource as unallocated. Also + * disable expansion ROMs during this step. + * (3) Try to allocate resources for disabled devices. If the + * resources were assigned correctly, everything goes well, + * if they weren't, they won't disturb allocation of other + * resources. + * (4) Assign new addresses to resources which were either + * not configured at all or misconfigured. If explicitly + * requested by the user, configure expansion ROM address + * as well. + */ + +static void __init pcibios_allocate_bus_resources(struct list_head *bus_list) { - struct list_head *ln, *dn; + struct list_head *ln; struct pci_bus *bus; struct pci_dev *dev; int idx; + struct resource *r, *pr; + /* Depth-First Search on bus tree */ for (ln=bus_list->next; ln != bus_list; ln=ln->next) { bus = pci_bus_b(ln); - for (dn=bus->devices.next; dn != &bus->devices; dn=dn->next) { - dev = pci_dev_b(dn); - for (idx = 0; idx < PCI_NUM_RESOURCES; idx++) - { - struct resource *r = &dev->resource[idx]; - struct resource *pr; + if ((dev = bus->self)) { + for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) { + r = &dev->resource[idx]; if (!r->start) continue; pr = pci_find_parent_resource(dev, r); if (!pr || request_resource(pr, r) < 0) - { - printk(KERN_ERR "PCI: Address space collision on region %d of device %s\n", idx, dev->name); - /* We probably should disable the region, shouldn't we? */ + printk(KERN_ERR "PCI: Cannot allocate resource region %d of bridge %s\n", idx, dev->slot_name); + } + } + pcibios_allocate_bus_resources(&bus->children); + } +} + +static void __init pcibios_allocate_resources(int pass) +{ + struct pci_dev *dev; + int idx, disabled; + u16 command; + struct resource *r, *pr; + + pci_for_each_dev(dev) { + pci_read_config_word(dev, PCI_COMMAND, &command); + for(idx = 0; idx < 6; idx++) { + r = &dev->resource[idx]; + if (r->parent) /* Already allocated */ + continue; + if (!r->start) /* Address not assigned at all */ + continue; + if (r->end == 0xffffffff) { + /* LongTrail OF quirk: unassigned */ + DBG("PCI: Resource %08lx-%08lx was unassigned\n", r->start, r->end); + r->end -= r->start; + r->start = 0; + continue; + } + + if (r->flags & IORESOURCE_IO) + disabled = !(command & PCI_COMMAND_IO); + else + disabled = !(command & PCI_COMMAND_MEMORY); + if (pass == disabled) { + DBG("PCI: Resource %08lx-%08lx (f=%lx, d=%d, p=%d)\n", + r->start, r->end, r->flags, disabled, pass); + pr = pci_find_parent_resource(dev, r); + if (!pr || request_resource(pr, r) < 0) { + printk(KERN_ERR "PCI: Cannot allocate resource region %d of device %s\n", idx, dev->slot_name); + /* We'll assign a new address later */ + r->end -= r->start; + r->start = 0; } } } - pcibios_claim_resources(&bus->children); + if (!pass) { + r = &dev->resource[PCI_ROM_RESOURCE]; + if (r->flags & PCI_ROM_ADDRESS_ENABLE) { + /* Turn the ROM off, leave the resource region, but keep it unregistered. */ + u32 reg; + DBG("PCI: Switching off ROM of %s\n", dev->slot_name); + r->flags &= ~PCI_ROM_ADDRESS_ENABLE; + pci_read_config_dword(dev, dev->rom_base_reg, ®); + pci_write_config_dword(dev, dev->rom_base_reg, reg & ~PCI_ROM_ADDRESS_ENABLE); + } + } } } -void __init pcibios_fixup_bus(struct pci_bus *bus) +static void __init pcibios_assign_resources(void) { - if ( ppc_md.pcibios_fixup_bus ) - ppc_md.pcibios_fixup_bus(bus); + struct pci_dev *dev; + int idx; + struct resource *r; + + pci_for_each_dev(dev) { + int class = dev->class >> 8; + + /* Don't touch classless devices and host bridges */ + if (!class || class == PCI_CLASS_BRIDGE_HOST) + continue; + + for(idx=0; idx<6; idx++) { + r = &dev->resource[idx]; + + /* + * Don't touch IDE controllers and I/O ports of video cards! + */ + if ((class == PCI_CLASS_STORAGE_IDE && idx < 4) || + (class == PCI_CLASS_DISPLAY_VGA && (r->flags & IORESOURCE_IO))) + continue; + + /* + * We shall assign a new address to this resource, either because + * the BIOS forgot to do so or because we have decided the old + * address was unusable for some reason. + */ + if (!r->start && r->end) + pci_assign_resource(dev, idx); + } + + if (0) { /* don't assign ROMs */ + r = &dev->resource[PCI_ROM_RESOURCE]; + r->end -= r->start; + r->start = 0; + if (r->end) + pci_assign_resource(dev, PCI_ROM_RESOURCE); + } + } } -char __init *pcibios_setup(char *str) + +int pcibios_enable_resources(struct pci_dev *dev) { - return str; + u16 cmd, old_cmd; + int idx; + struct resource *r; + + pci_read_config_word(dev, PCI_COMMAND, &cmd); + old_cmd = cmd; + for(idx=0; idx<6; idx++) { + r = &dev->resource[idx]; + if (!r->start && r->end) { + printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name); + return -EINVAL; + } + if (r->flags & IORESOURCE_IO) + cmd |= PCI_COMMAND_IO; + if (r->flags & IORESOURCE_MEM) + cmd |= PCI_COMMAND_MEMORY; + } + if (dev->resource[PCI_ROM_RESOURCE].start) + cmd |= PCI_COMMAND_MEMORY; + if (cmd != old_cmd) { + printk("PCI: Enabling device %s (%04x -> %04x)\n", dev->slot_name, old_cmd, cmd); + pci_write_config_word(dev, PCI_COMMAND, cmd); + } + return 0; +} + + + +void __init pcibios_init(void) +{ + printk("PCI: Probing PCI hardware\n"); + pci_scan_bus(0, &generic_pci_ops, NULL); + if (ppc_md.pcibios_fixup) + ppc_md.pcibios_fixup(); + pcibios_allocate_bus_resources(&pci_root_buses); + pcibios_allocate_resources(0); + pcibios_allocate_resources(1); + pcibios_assign_resources(); } -/* the next two are stolen from the alpha port... */ void __init -pcibios_update_resource(struct pci_dev *dev, struct resource *root, - struct resource *res, int resource) +pcibios_fixup_pbus_ranges(struct pci_bus * bus, struct pbus_set_ranges_data * ranges) { - unsigned long where, size; - u32 reg; + 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; +} - where = PCI_BASE_ADDRESS_0 + (resource * 4); - size = res->end - res->start; - pci_read_config_dword(dev, where, ®); - reg = (reg & size) | (((u32)(res->start - root->start)) & ~size); - pci_write_config_dword(dev, where, reg); +unsigned long resource_fixup(struct pci_dev * dev, struct resource * res, + unsigned long start, unsigned long size) +{ + return start; } -void __init -pcibios_update_irq(struct pci_dev *dev, int irq) +void __init pcibios_fixup_bus(struct pci_bus *bus) { - pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); - /* XXX FIXME - update OF device tree node interrupt property */ + if ( ppc_md.pcibios_fixup_bus ) + ppc_md.pcibios_fixup_bus(bus); } +char __init *pcibios_setup(char *str) +{ + return str; +} + +/* the next one is stolen from the alpha port... */ void __init -pcibios_align_resource(void *data, struct resource *res, unsigned long size) +pcibios_update_irq(struct pci_dev *dev, int irq) { + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); + /* XXX FIXME - update OF device tree node interrupt property */ } int pcibios_enable_device(struct pci_dev *dev) @@ -188,114 +396,26 @@ return 0; } -/* - * Those syscalls are derived from the Alpha versions, they - * allow userland apps to retreive the per-device iobase and - * mem-base. They also provide wrapper for userland to do - * config space accesses. - * The "host_number" returns the number of the Uni-N sub bridge - */ - -asmlinkage int -sys_pciconfig_read(unsigned long bus, unsigned long dfn, - unsigned long off, unsigned long len, - unsigned char *buf) -{ - unsigned char ubyte; - unsigned short ushort; - unsigned int uint; - long err = 0; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (!pcibios_present()) - return -ENOSYS; - - switch (len) { - case 1: - err = pcibios_read_config_byte(bus, dfn, off, &ubyte); - put_user(ubyte, buf); - break; - case 2: - err = pcibios_read_config_word(bus, dfn, off, &ushort); - put_user(ushort, (unsigned short *)buf); - break; - case 4: - err = pcibios_read_config_dword(bus, dfn, off, &uint); - put_user(uint, (unsigned int *)buf); - break; - default: - err = -EINVAL; - break; - } - return err; -} - -asmlinkage int -sys_pciconfig_write(unsigned long bus, unsigned long dfn, - unsigned long off, unsigned long len, - unsigned char *buf) -{ - unsigned char ubyte; - unsigned short ushort; - unsigned int uint; - long err = 0; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (!pcibios_present()) - return -ENOSYS; - - switch (len) { - case 1: - err = get_user(ubyte, buf); - if (err) - break; - err = pcibios_write_config_byte(bus, dfn, off, ubyte); - if (err != PCIBIOS_SUCCESSFUL) { - err = -EFAULT; - } - break; - case 2: - err = get_user(ushort, (unsigned short *)buf); - if (err) - break; - err = pcibios_write_config_word(bus, dfn, off, ushort); - if (err != PCIBIOS_SUCCESSFUL) { - err = -EFAULT; - } - break; - case 4: - err = get_user(uint, (unsigned int *)buf); - if (err) - break; - err = pcibios_write_config_dword(bus, dfn, off, uint); - if (err != PCIBIOS_SUCCESSFUL) { - err = -EFAULT; - } - break; - default: - err = -EINVAL; - break; - } - return err; -} - void * -pci_dev_io_base(unsigned char bus, unsigned char devfn) +pci_dev_io_base(unsigned char bus, unsigned char devfn, int physical) { - /* Defaults to old way */ - if (!ppc_md.pci_dev_io_base) - return pci_io_base(bus); - return ppc_md.pci_dev_io_base(bus, devfn); + if (!ppc_md.pci_dev_io_base) { + /* Please, someone fix this for non-pmac machines, we + * need either the virtual or physical PCI IO base + */ + return 0; + } + return ppc_md.pci_dev_io_base(bus, devfn, physical); } void * pci_dev_mem_base(unsigned char bus, unsigned char devfn) { /* Default memory base is 0 (1:1 mapping) */ - if (!ppc_md.pci_dev_mem_base) + if (!ppc_md.pci_dev_mem_base) { + /* Please, someone fix this for non-pmac machines.*/ return 0; + } return ppc_md.pci_dev_mem_base(bus, devfn); } @@ -318,15 +438,20 @@ asmlinkage long sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn) { + long result = -EOPNOTSUPP; + switch (which) { case IOBASE_BRIDGE_NUMBER: return (long)pci_dev_root_bridge(bus, devfn); case IOBASE_MEMORY: return (long)pci_dev_mem_base(bus, devfn); case IOBASE_IO: - return (long)pci_dev_io_base(bus, devfn); + result = (long)pci_dev_io_base(bus, devfn, 1); + if (result == 0) + result = -EOPNOTSUPP; + break; } - return -EOPNOTSUPP; + return result; } diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/kernel/pmac_backlight.c linux/arch/ppc/kernel/pmac_backlight.c --- v2.4.0-test8/linux/arch/ppc/kernel/pmac_backlight.c Tue Jul 18 15:03:55 2000 +++ linux/arch/ppc/kernel/pmac_backlight.c Sun Sep 17 09:48:07 2000 @@ -41,16 +41,16 @@ #ifdef CONFIG_ADB_PMU /* Special case for the old PowerBook since I can't test on it */ - if ((machine_is_compatible("AAPL,3400/2400") || machine_is_compatible("AAPL,3500") - || machine_is_compatible("AAPL,PowerBook1998") - || machine_is_compatible("AAPL,PowerBook1999")) - && !strcmp(type, "pmu")) + backlight_autosave = machine_is_compatible("AAPL,3400/2400") + || machine_is_compatible("AAPL,3500"); + if ((backlight_autosave + || machine_is_compatible("AAPL,PowerBook1998") + || machine_is_compatible("PowerBook1,1")) + && !strcmp(type, "pmu")) valid = 1; - else #endif - { - if (bk_node) - prop = get_property(bk_node, "backlight-control", NULL); + if (bk_node) { + prop = get_property(bk_node, "backlight-control", NULL); if (prop && !strncmp(prop, type, strlen(type))) valid = 1; } @@ -70,8 +70,6 @@ } #ifdef CONFIG_ADB_PMU - backlight_autosave = machine_is_compatible("AAPL,3400/2400") - || machine_is_compatible("AAPL,3500"); if (backlight_autosave) { struct adb_request req; pmu_request(&req, NULL, 2, 0xd9, 0); diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/kernel/pmac_nvram.c linux/arch/ppc/kernel/pmac_nvram.c --- v2.4.0-test8/linux/arch/ppc/kernel/pmac_nvram.c Thu Jul 13 09:42:50 2000 +++ linux/arch/ppc/kernel/pmac_nvram.c Sun Sep 17 09:48:07 2000 @@ -312,17 +312,18 @@ __openfirmware unsigned char nvram_read_byte(int addr) { - struct adb_request req; - switch (nvram_naddrs) { #ifdef CONFIG_ADB_PMU - case -1: + case -1: { + struct adb_request req; + if (pmu_request(&req, NULL, 3, PMU_READ_NVRAM, (addr >> 8) & 0xff, addr & 0xff)) break; while (!req.complete) pmu_poll(); return req.reply[1]; + } #endif case 1: if (is_core_99) @@ -339,17 +340,18 @@ __openfirmware void nvram_write_byte(unsigned char val, int addr) { - struct adb_request req; - switch (nvram_naddrs) { #ifdef CONFIG_ADB_PMU - case -1: + case -1: { + struct adb_request req; + if (pmu_request(&req, NULL, 4, PMU_WRITE_NVRAM, (addr >> 8) & 0xff, addr & 0xff, val)) break; while (!req.complete) pmu_poll(); break; + } #endif case 1: if (is_core_99) { diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/kernel/pmac_pci.c linux/arch/ppc/kernel/pmac_pci.c --- v2.4.0-test8/linux/arch/ppc/kernel/pmac_pci.c Thu Jul 13 09:42:50 2000 +++ linux/arch/ppc/kernel/pmac_pci.c Sun Sep 17 09:48:07 2000 @@ -35,6 +35,7 @@ volatile unsigned int* cfg_addr; volatile unsigned int* cfg_data; void* iobase; + unsigned long iobase_phys; }; static struct uninorth_data uninorth_bridges[3]; @@ -133,15 +134,20 @@ __pmac void * -pmac_pci_dev_io_base(unsigned char bus, unsigned char devfn) +pmac_pci_dev_io_base(unsigned char bus, unsigned char devfn, int physical) { - int bridge; - if (uninorth_count == 0) - return pci_io_base(bus); - bridge = pmac_pci_dev_root_bridge(bus, devfn); - if (bridge == -1) - return pci_io_base(bus); - return uninorth_bridges[bridge].iobase; + int bridge = -1; + if (uninorth_count != 0) + bridge = pmac_pci_dev_root_bridge(bus, devfn); + if (bridge == -1) { + struct bridge_data *bp; + + if (bus > max_bus || (bp = bridges[bus]) == 0) + return 0; + return physical ? (void *) bp->io_base_phys : bp->io_base; + } + return physical ? (void *) uninorth_bridges[bridge].iobase_phys + : uninorth_bridges[bridge].iobase; } __pmac @@ -649,7 +655,9 @@ uninorth_bridges[i].cfg_addr = ioremap(addr->address + 0x800000, 0x1000); uninorth_bridges[i].cfg_data = ioremap(addr->address + 0xc00000, 0x1000); uninorth_bridges[i].node = dev; - uninorth_bridges[i].iobase = (void *)addr->address; + uninorth_bridges[i].iobase_phys = addr->address; + /* is 0x10000 enough for io space ? */ + uninorth_bridges[i].iobase = (void *)ioremap(addr->address, 0x10000); /* XXX This is the bridge with the PCI expansion bus. This is also the * address of the bus that will receive type 1 config accesses and io * accesses. Appears to be correct for iMac DV and G4 Sawtooth too. @@ -667,14 +675,15 @@ if (device_is_compatible(dev, "uni-north")) { bp->cfg_addr = 0; bp->cfg_data = 0; - /* is 0x10000 enough for io space ? */ - bp->io_base = (void *)ioremap(addr->address, 0x10000); + bp->io_base = uninorth_bridges[uninorth_count-1].iobase; + bp->io_base_phys = uninorth_bridges[uninorth_count-1].iobase_phys; } else if (strcmp(dev->name, "pci") == 0) { /* XXX assume this is a mpc106 (grackle) */ bp->cfg_addr = (volatile unsigned int *) ioremap(0xfec00000, 0x1000); bp->cfg_data = (volatile unsigned char *) ioremap(0xfee00000, 0x1000); + bp->io_base_phys = 0xfe000000; bp->io_base = (void *) ioremap(0xfe000000, 0x20000); if (machine_is_compatible("AAPL,PowerBook1998")) grackle_set_loop_snoop(bp, 1); @@ -687,6 +696,7 @@ ioremap(addr->address + 0x800000, 0x1000); bp->cfg_data = (volatile unsigned char *) ioremap(addr->address + 0xc00000, 0x1000); + bp->io_base_phys = addr->address; bp->io_base = (void *) ioremap(addr->address, 0x10000); } if (isa_io_base == 0) diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/kernel/pmac_pic.c linux/arch/ppc/kernel/pmac_pic.c --- v2.4.0-test8/linux/arch/ppc/kernel/pmac_pic.c Thu Jul 13 09:42:50 2000 +++ linux/arch/ppc/kernel/pmac_pic.c Sun Sep 17 09:48:07 2000 @@ -204,17 +204,12 @@ unsigned long bits = 0; #ifdef CONFIG_SMP - void pmac_smp_message_recv(void); + void pmac_smp_message_recv(struct pt_regs *); /* IPI's are a hack on the powersurge -- Cort */ if ( smp_processor_id() != 0 ) { -#ifdef CONFIG_XMON - static int xmon_2nd; - if (xmon_2nd) - xmon(regs); -#endif - pmac_smp_message_recv(); + pmac_smp_message_recv(regs); return -2; /* ignore, already handled */ } #endif /* CONFIG_SMP */ diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/kernel/pmac_setup.c linux/arch/ppc/kernel/pmac_setup.c --- v2.4.0-test8/linux/arch/ppc/kernel/pmac_setup.c Tue Jul 18 23:02:09 2000 +++ linux/arch/ppc/kernel/pmac_setup.c Sun Sep 17 09:48:07 2000 @@ -68,7 +68,7 @@ #undef SHOW_GATWICK_IRQS -extern void pmac_time_init(void); +extern long pmac_time_init(void); extern unsigned long pmac_get_rtc_time(void); extern int pmac_set_rtc_time(unsigned long nowtime); extern void pmac_read_rtc_time(void); @@ -77,24 +77,29 @@ extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode); extern int mackbd_getkeycode(unsigned int scancode); -extern int mackbd_translate(unsigned char scancode, unsigned char *keycode, - char raw_mode); -extern char mackbd_unexpected_up(unsigned char keycode); +extern int mackbd_translate(unsigned char keycode, unsigned char *keycodep, + char raw_mode); +extern int mackbd_unexpected_up(unsigned char keycode); extern void mackbd_leds(unsigned char leds); -extern void mackbd_init_hw(void); +extern void __init mackbd_init_hw(void); +extern int mac_hid_kbd_translate(unsigned char scancode, unsigned char *keycode, + char raw_mode); +extern char mac_hid_kbd_unexpected_up(unsigned char keycode); +extern void mac_hid_init_hw(void); #ifdef CONFIG_MAGIC_SYSRQ -unsigned char mackbd_sysrq_xlate[128]; +extern unsigned char mac_hid_kbd_sysrq_xlate[128]; +extern unsigned char pckbd_sysrq_xlate[128]; +extern unsigned char mackbd_sysrq_xlate[128]; #endif /* CONFIG_MAGIC_SYSRQ */ extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode); extern int pckbd_getkeycode(unsigned int scancode); extern int pckbd_translate(unsigned char scancode, unsigned char *keycode, char raw_mode); extern char pckbd_unexpected_up(unsigned char keycode); -extern void pckbd_leds(unsigned char leds); -extern void pckbd_init_hw(void); +extern int keyboard_sends_linux_keycodes; extern void pmac_nvram_update(void); -extern void *pmac_pci_dev_io_base(unsigned char bus, unsigned char devfn); +extern void *pmac_pci_dev_io_base(unsigned char bus, unsigned char devfn, int physical); extern void *pmac_pci_dev_mem_base(unsigned char bus, unsigned char devfn); extern int pmac_pci_dev_root_bridge(unsigned char bus, unsigned char devfn); @@ -115,7 +120,6 @@ extern void zs_kgdb_hook(int tty_num); static void ohare_init(void); static void init_p2pbridge(void); -static void init_uninorth(void); #ifdef CONFIG_BOOTX_TEXT void pmac_progress(char *s, unsigned short hex); #endif @@ -276,7 +280,6 @@ pmac_find_bridges(); init_p2pbridge(); - init_uninorth(); /* Checks "l2cr-value" property in the registry */ if ( (_get_PVR() >> 16) == 8 || (_get_PVR() >> 16) == 12 ) { @@ -372,31 +375,6 @@ } } -static void __init -init_uninorth(void) -{ - /* - * Turns OFF the gmac clock. The gmac driver will turn - * it back ON when the interface is enabled. This save - * power on portables. - * - * Note: We could also try to turn OFF the PHY. Since this - * has to be done by both the gmac driver and this code, - * I'll probably end-up moving some of this out of the - * modular gmac driver into a non-modular stub containing - * some basic PHY management and power management stuffs - */ - struct device_node* gmac = find_devices("ethernet"); - - while(gmac) { - if (device_is_compatible(gmac, "gmac")) - break; - gmac = gmac->next; - } - if (gmac) - feature_set_gmac_power(gmac, 0); -} - extern char *bootpath; extern char *bootdevice; void *boot_host; @@ -404,14 +382,15 @@ int boot_part; kdev_t boot_dev; -extern void via_pmu_start(void); - void __init pmac_init2(void) { #ifdef CONFIG_ADB_PMU via_pmu_start(); #endif +#ifdef CONFIG_ADB_CUDA + via_cuda_start(); +#endif #ifdef CONFIG_PMAC_PBOOK media_bay_init(); #endif @@ -683,7 +662,26 @@ ppc_md.pci_dev_mem_base = pmac_pci_dev_mem_base; ppc_md.pci_dev_root_bridge = pmac_pci_dev_root_bridge; -#if defined(CONFIG_VT) && defined(CONFIG_ADB_KEYBOARD) +#ifdef CONFIG_VT +#ifdef CONFIG_INPUT_ADBHID + ppc_md.kbd_init_hw = mac_hid_init_hw; + ppc_md.kbd_translate = mac_hid_kbd_translate; + ppc_md.kbd_unexpected_up = mac_hid_kbd_unexpected_up; + ppc_md.kbd_setkeycode = 0; + ppc_md.kbd_getkeycode = 0; +#ifdef CONFIG_MAGIC_SYSRQ +#ifdef CONFIG_MAC_ADBKEYCODES + if (!keyboard_sends_linux_keycodes) { + ppc_md.ppc_kbd_sysrq_xlate = mac_hid_kbd_sysrq_xlate; + SYSRQ_KEY = 0x69; + } else +#endif /* CONFIG_MAC_ADBKEYCODES */ + { + ppc_md.ppc_kbd_sysrq_xlate = pckbd_sysrq_xlate; + SYSRQ_KEY = 0x54; + } +#endif /* CONFIG_MAGIC_SYSRQ */ +#elif defined(CONFIG_ADB_KEYBOARD) ppc_md.kbd_setkeycode = mackbd_setkeycode; ppc_md.kbd_getkeycode = mackbd_getkeycode; ppc_md.kbd_translate = mackbd_translate; @@ -691,10 +689,11 @@ ppc_md.kbd_leds = mackbd_leds; ppc_md.kbd_init_hw = mackbd_init_hw; #ifdef CONFIG_MAGIC_SYSRQ - ppc_md.ppc_kbd_sysrq_xlate = mackbd_sysrq_xlate; + ppc_md.ppc_kbd_sysrq_xlate = mackbd_sysrq_xlate; SYSRQ_KEY = 0x69; -#endif -#endif +#endif /* CONFIG_MAGIC_SYSRQ */ +#endif /* CONFIG_INPUT_ADBHID/CONFIG_ADB_KEYBOARD */ +#endif /* CONFIG_VT */ #if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC) ppc_ide_md.insw = pmac_ide_insw; diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/kernel/pmac_time.c linux/arch/ppc/kernel/pmac_time.c --- v2.4.0-test8/linux/arch/ppc/kernel/pmac_time.c Thu Jul 13 09:42:50 2000 +++ linux/arch/ppc/kernel/pmac_time.c Sun Sep 17 09:48:07 2000 @@ -25,7 +25,7 @@ #include #include #include - +#include #include #include @@ -58,7 +58,7 @@ extern struct timezone sys_tz; __init -void pmac_time_init(void) +long pmac_time_init(void) { #ifdef CONFIG_NVRAM s32 delta = 0; @@ -72,17 +72,18 @@ dst = ((pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x8) & 0x80) != 0); printk("GMT Delta read from XPRAM: %d minutes, DST: %s\n", delta/60, dst ? "on" : "off"); - sys_tz.tz_minuteswest = -delta/60; - /* I _suppose_ this is 0:off, 1:on */ - sys_tz.tz_dsttime = dst; + return delta; +#else + return 0; #endif } __pmac unsigned long pmac_get_rtc_time(void) { -#ifdef CONFIG_ADB +#if defined(CONFIG_ADB_CUDA) || defined(CONFIG_ADB_PMU) struct adb_request req; + unsigned long now; #endif /* Get the time from the RTC */ @@ -96,8 +97,9 @@ if (req.reply_len != 7) printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n", req.reply_len); - return (req.reply[3] << 24) + (req.reply[4] << 16) - + (req.reply[5] << 8) + req.reply[6] - RTC_OFFSET; + now = (req.reply[3] << 24) + (req.reply[4] << 16) + + (req.reply[5] << 8) + req.reply[6]; + return now - RTC_OFFSET; #endif /* CONFIG_ADB_CUDA */ #ifdef CONFIG_ADB_PMU case SYS_CTRLER_PMU: @@ -108,21 +110,25 @@ if (req.reply_len != 5) printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n", req.reply_len); - return (req.reply[1] << 24) + (req.reply[2] << 16) - + (req.reply[3] << 8) + req.reply[4] - RTC_OFFSET; + now = (req.reply[1] << 24) + (req.reply[2] << 16) + + (req.reply[3] << 8) + req.reply[4]; + return now - RTC_OFFSET; #endif /* CONFIG_ADB_PMU */ default: - return 0; } + return 0; } int pmac_set_rtc_time(unsigned long nowtime) { +#if defined(CONFIG_ADB_CUDA) || defined(CONFIG_ADB_PMU) struct adb_request req; +#endif - nowtime += RTC_OFFSET - sys_tz.tz_minuteswest * 60; + nowtime += RTC_OFFSET; switch (sys_ctrler) { +#ifdef CONFIG_ADB_CUDA case SYS_CTRLER_CUDA: if (cuda_request(&req, NULL, 6, CUDA_PACKET, CUDA_SET_TIME, nowtime >> 24, nowtime >> 16, nowtime >> 8, nowtime) < 0) @@ -133,16 +139,19 @@ printk(KERN_ERR "pmac_set_rtc_time: got %d byte reply\n", req.reply_len); return 1; +#endif /* CONFIG_ADB_CUDA */ +#ifdef CONFIG_ADB_PMU case SYS_CTRLER_PMU: if (pmu_request(&req, NULL, 5, PMU_SET_RTC, nowtime >> 24, nowtime >> 16, nowtime >> 8, nowtime) < 0) return 0; while (!req.complete) pmu_poll(); - if (req.reply_len != 5) + if (req.reply_len != 0) printk(KERN_ERR "pmac_set_rtc_time: got %d byte reply\n", req.reply_len); return 1; +#endif /* CONFIG_ADB_PMU */ default: return 0; } @@ -186,12 +195,11 @@ ; dend = get_dec(); - decrementer_count = (dstart - dend) / 6; - count_period_num = 60; - count_period_den = decrementer_count * 6 * HZ / 100000; + tb_ticks_per_jiffy = (dstart - dend) / 6; + tb_to_us = mulhwu_scale_factor(dstart - dend, 60000); - printk(KERN_INFO "via_calibrate_decr: decrementer_count = %u (%u ticks)\n", - decrementer_count, dstart - dend); + printk(KERN_INFO "via_calibrate_decr: ticks per jiffy = %u (%u ticks)\n", + tb_ticks_per_jiffy, dstart - dend); return 1; } @@ -214,8 +222,11 @@ case PBOOK_WAKE: write_lock_irqsave(&xtime_lock, flags); xtime.tv_sec = pmac_get_rtc_time() + time_diff; + set_dec(tb_ticks_per_jiffy); + /* No currently-supported powerbook has a 601, + so use get_tbl, not native */ + last_jiffy_stamp(0) = tb_last_stamp = get_tbl(); xtime.tv_usec = 0; - set_dec(decrementer_count); last_rtc_update = xtime.tv_sec; write_unlock_irqrestore(&xtime_lock, flags); break; @@ -236,7 +247,7 @@ void __init pmac_calibrate_decr(void) { struct device_node *cpu; - int freq, *fp, divisor; + unsigned int freq, *fp; #ifdef CONFIG_PMAC_PBOOK pmu_register_sleep_notifier(&time_sleep_notifier); @@ -252,15 +263,13 @@ cpu = find_type_devices("cpu"); if (cpu == 0) panic("can't find cpu node in time_init"); - fp = (int *) get_property(cpu, "timebase-frequency", NULL); + fp = (unsigned int *) get_property(cpu, "timebase-frequency", NULL); if (fp == 0) panic("can't get cpu timebase frequency"); - freq = *fp * 60; /* try to make freq/1e6 an integer */ - divisor = 60; - printk("time_init: decrementer frequency = %d/%d\n", - freq, divisor); - decrementer_count = freq / HZ / divisor; - count_period_num = divisor; - count_period_den = freq / 1000000; + freq = *fp; + printk("time_init: decrementer frequency = %u.%.6u MHz\n", + freq/1000000, freq%1000000); + tb_ticks_per_jiffy = freq / HZ; + tb_to_us = mulhwu_scale_factor(freq, 1000000); } diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/kernel/ppc-stub.c linux/arch/ppc/kernel/ppc-stub.c --- v2.4.0-test8/linux/arch/ppc/kernel/ppc-stub.c Wed May 3 01:47:57 2000 +++ linux/arch/ppc/kernel/ppc-stub.c Sun Oct 1 20:35:15 2000 @@ -122,9 +122,9 @@ static char remcomInBuffer[BUFMAX]; static char remcomOutBuffer[BUFMAX]; -static int initialized = 0; -static int kgdb_active = 0; -static int kgdb_started = 0; +static int initialized; +static int kgdb_active; +static int kgdb_started; static u_int fault_jmp_buf[100]; static int kdebug; diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/kernel/ppc_ksyms.c linux/arch/ppc/kernel/ppc_ksyms.c --- v2.4.0-test8/linux/arch/ppc/kernel/ppc_ksyms.c Fri Aug 4 16:15:37 2000 +++ linux/arch/ppc/kernel/ppc_ksyms.c Sun Sep 17 09:48:07 2000 @@ -37,6 +37,7 @@ #include #include #include +#include #ifdef CONFIG_SMP #include #endif /* CONFIG_SMP */ @@ -184,6 +185,10 @@ EXPORT_SYMBOL(enable_kernel_fp); EXPORT_SYMBOL(flush_icache_range); EXPORT_SYMBOL(xchg_u32); +#ifdef CONFIG_ALTIVEC +EXPORT_SYMBOL(last_task_used_altivec); +EXPORT_SYMBOL(giveup_altivec); +#endif /* CONFIG_ALTIVEC */ #ifdef CONFIG_SMP EXPORT_SYMBOL(__global_cli); EXPORT_SYMBOL(__global_sti); @@ -204,26 +209,34 @@ EXPORT_SYMBOL(ppc_md); #ifdef CONFIG_ADB -/* - * This could be more fine-grained, but for now assume if we have - * ADB we have it all -- Cort - */ EXPORT_SYMBOL(adb_request); EXPORT_SYMBOL(adb_register); +EXPORT_SYMBOL(adb_unregister); +EXPORT_SYMBOL(adb_poll); +EXPORT_SYMBOL(adb_try_handler_change); +#endif /* CONFIG_ADB */ +#ifdef CONFIG_ADB_CUDA EXPORT_SYMBOL(cuda_request); EXPORT_SYMBOL(cuda_poll); +#endif /* CONFIG_ADB_CUDA */ #ifdef CONFIG_ADB_PMU EXPORT_SYMBOL(pmu_request); EXPORT_SYMBOL(pmu_poll); #endif /* CONFIG_ADB_PMU */ -#endif /* CONFIG_ADB */ #ifdef CONFIG_PMAC_PBOOK EXPORT_SYMBOL(pmu_register_sleep_notifier); EXPORT_SYMBOL(pmu_unregister_sleep_notifier); EXPORT_SYMBOL(pmu_enable_irled); -#endif CONFIG_PMAC_PBOOK +#endif /* CONFIG_PMAC_PBOOK */ +#ifdef CONFIG_PMAC_BACKLIGHT +EXPORT_SYMBOL(get_backlight_level); +EXPORT_SYMBOL(set_backlight_level); +#endif /* CONFIG_PMAC_BACKLIGHT */ #if defined(CONFIG_ALL_PPC) EXPORT_SYMBOL_NOVERS(sys_ctrler); +#ifndef CONFIG_MACH_SPECIFIC +EXPORT_SYMBOL_NOVERS(have_of); +#endif /* CONFIG_MACH_SPECIFIC */ EXPORT_SYMBOL(find_devices); EXPORT_SYMBOL(find_type_devices); EXPORT_SYMBOL(find_compatible_devices); @@ -253,10 +266,7 @@ EXPORT_SYMBOL(pmac_xpram_read); EXPORT_SYMBOL(pmac_xpram_write); #endif /* CONFIG_NVRAM */ -#ifdef CONFIG_PPC_RTC -EXPORT_SYMBOL(mktime); EXPORT_SYMBOL(to_tm); -#endif EXPORT_SYMBOL_NOVERS(__ashrdi3); EXPORT_SYMBOL_NOVERS(__ashldi3); @@ -280,7 +290,7 @@ EXPORT_SYMBOL(irq_desc); void ppc_irq_dispatch_handler(struct pt_regs *, int); EXPORT_SYMBOL(ppc_irq_dispatch_handler); -EXPORT_SYMBOL(decrementer_count); +EXPORT_SYMBOL(tb_ticks_per_jiffy); EXPORT_SYMBOL(get_wchan); EXPORT_SYMBOL(console_drivers); EXPORT_SYMBOL(console_lock); @@ -310,3 +320,17 @@ EXPORT_SYMBOL(next_mmu_context); EXPORT_SYMBOL(set_context); EXPORT_SYMBOL(mmu_context_overflow); + +#ifdef CONFIG_MOL +extern ulong mol_interface[]; +extern PTE *Hash; +extern unsigned long Hash_mask; +extern void (*ret_from_except)(void); +extern struct task_struct *last_task_used_altivec; +EXPORT_SYMBOL_NOVERS(mol_interface); +EXPORT_SYMBOL(Hash); +EXPORT_SYMBOL(Hash_mask); +EXPORT_SYMBOL(handle_mm_fault); +EXPORT_SYMBOL(last_task_used_math); +EXPORT_SYMBOL(ret_from_except); +#endif /* CONFIG_MOL */ diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/kernel/prep_setup.c linux/arch/ppc/kernel/prep_setup.c --- v2.4.0-test8/linux/arch/ppc/kernel/prep_setup.c Thu Jul 13 09:42:50 2000 +++ linux/arch/ppc/kernel/prep_setup.c Sun Sep 17 09:48:07 2000 @@ -365,14 +365,13 @@ */ void __init prep_res_calibrate_decr(void) { - int freq, divisor; + unsigned long freq, divisor=4; freq = res->VitalProductData.ProcessorBusHz; - divisor = 4; - printk("time_init: decrementer frequency = %d/%d\n", freq, divisor); - decrementer_count = freq / HZ / divisor; - count_period_num = divisor; - count_period_den = freq / 1000000; + printk("time_init: decrementer frequency = %lu.%.6lu MHz\n", + (freq/divisor)/1000000, (freq/divisor)%1000000); + tb_ticks_per_jiffy = freq / HZ / divisor; + tb_to_us = mulhwu_scale_factor(freq/divisor, 1000000); } /* @@ -381,32 +380,30 @@ * but on prep we have to figure it out. * -- Cort */ -int calibrate_done = 0; -volatile int *done_ptr = &calibrate_done; +/* Done with 3 interrupts: the first one primes the cache and the + * 2 following ones measure the interval. The precision of the method + * is still doubtful due to the short interval sampled. + */ +static __initdata volatile int calibrate_steps = 3; +static __initdata unsigned tbstamp; void __init prep_calibrate_decr_handler(int irq, void *dev, struct pt_regs *regs) { - unsigned long freq, divisor; - static unsigned long t1 = 0, t2 = 0; - - if ( !t1 ) - t1 = get_dec(); - else if (!t2) - { - t2 = get_dec(); - t2 = t1-t2; /* decr's in 1/HZ */ - t2 = t2*HZ; /* # decrs in 1s - thus in Hz */ - freq = t2 * 60; /* try to make freq/1e6 an integer */ - divisor = 60; - printk("time_init: decrementer frequency = %lu/%lu (%luMHz)\n", - freq, divisor,t2>>20); - decrementer_count = freq / HZ / divisor; - count_period_num = divisor; - count_period_den = freq / 1000000; - *done_ptr = 1; + unsigned long t, freq; + int step=--calibrate_steps; + + t = get_tbl(); + if (step > 0) { + tbstamp = t; + } else { + freq = (t - tbstamp)*HZ; + printk("time_init: decrementer frequency = %lu.%.6lu MHz\n", + freq/1000000, freq%1000000); + tb_ticks_per_jiffy = freq / HZ; + tb_to_us = mulhwu_scale_factor(freq, 1000000); } } @@ -428,17 +425,43 @@ if (request_irq(0, prep_calibrate_decr_handler, 0, "timer", NULL) != 0) panic("Could not allocate timer IRQ!"); __sti(); - while ( ! *done_ptr ) /* nothing */; /* wait for calibrate */ + while ( calibrate_steps ) /* nothing */; /* wait for calibrate */ restore_flags(flags); free_irq( 0, NULL); } -/* We use the NVRAM RTC to time a second to calibrate the decrementer. */ +static long __init mk48t59_init(void) { + unsigned char tmp; + + tmp = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLB); + if (tmp & MK48T59_RTC_CB_STOP) { + printk("Warning: RTC was stopped, date will be wrong.\n"); + ppc_md.nvram_write_val(MK48T59_RTC_CONTROLB, + tmp & ~MK48T59_RTC_CB_STOP); + /* Low frequency crystal oscillators may take a very long + * time to startup and stabilize. For now just ignore the + * the issue, but attempting to calibrate the decrementer + * from the RTC just after this wakeup is likely to be very + * inaccurate. Firmware should not allow to load + * the OS with the clock stopped anyway... + */ + } + /* Ensure that the clock registers are updated */ + tmp = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLA); + tmp &= ~(MK48T59_RTC_CA_READ | MK48T59_RTC_CA_WRITE); + ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, tmp); + return 0; +} + +/* We use the NVRAM RTC to time a second to calibrate the decrementer, + * the RTC registers have just been set up in the right state by the + * preceding routine. + */ void __init mk48t59_calibrate_decr(void) { - unsigned long freq, divisor; - unsigned long t1, t2; + unsigned long freq; + unsigned long t1; unsigned char save_control; long i; unsigned char sec; @@ -458,29 +481,31 @@ /* Read the seconds value to see when it changes. */ sec = ppc_md.nvram_read_val(MK48T59_RTC_SECONDS); + /* Actually this is bad for precision, we should have a loop in + * which we only read the seconds counter. nvram_read_val writes + * the address bytes on every call and this takes a lot of time. + * Perhaps an nvram_wait_change method returning a time + * stamp with a loop count as parameter would be the solution. + */ for (i = 0 ; i < 1000000 ; i++) { /* may take up to 1 second... */ + t1 = get_tbl(); if (ppc_md.nvram_read_val(MK48T59_RTC_SECONDS) != sec) { break; } } - t1 = get_dec(); sec = ppc_md.nvram_read_val(MK48T59_RTC_SECONDS); for (i = 0 ; i < 1000000 ; i++) { /* Should take up 1 second... */ + freq = get_tbl()-t1; if (ppc_md.nvram_read_val(MK48T59_RTC_SECONDS) != sec) { break; } } - t2 = t1 - get_dec(); - - freq = t2 * 60; /* try to make freq/1e6 an integer */ - divisor = 60; - printk("time_init: decrementer frequency = %lu/%lu (%luMHz)\n", - freq, divisor,t2>>20); - decrementer_count = freq / HZ / divisor; - count_period_num = divisor; - count_period_den = freq / 1000000; + printk("time_init: decrementer frequency = %lu.%.6lu MHz\n", + freq/1000000, freq%1000000); + tb_ticks_per_jiffy = freq / HZ; + tb_to_us = mulhwu_scale_factor(freq, 1000000); } void __prep @@ -788,6 +813,7 @@ { ppc_md.set_rtc_time = mk48t59_set_rtc_time; ppc_md.get_rtc_time = mk48t59_get_rtc_time; + ppc_md.time_init = mk48t59_init; } else { @@ -808,6 +834,7 @@ ppc_md.set_rtc_time = mk48t59_set_rtc_time; ppc_md.get_rtc_time = mk48t59_get_rtc_time; ppc_md.calibrate_decr = mk48t59_calibrate_decr; + ppc_md.time_init = mk48t59_init; } #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/kernel/prep_time.c linux/arch/ppc/kernel/prep_time.c --- v2.4.0-test8/linux/arch/ppc/kernel/prep_time.c Thu Jul 13 09:42:50 2000 +++ linux/arch/ppc/kernel/prep_time.c Sun Sep 17 09:48:07 2000 @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -99,28 +100,34 @@ unsigned long mc146818_get_rtc_time(void) { unsigned int year, mon, day, hour, min, sec; - int i; + int uip, i; /* The Linux interpretation of the CMOS clock register contents: * When the Update-In-Progress (UIP) flag goes from 1 to 0, the * RTC registers show the second which has precisely just started. * Let's hope other operating systems interpret the RTC the same way. */ - /* read RTC exactly on falling edge of update flag */ - for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */ - if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) - break; - for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */ - if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)) - break; - do { /* Isn't this overkill ? UIP above should guarantee consistency */ + + /* Since the UIP flag is set for about 2.2 ms and the clock + * is typically written with a precision of 1 jiffy, trying + * to obtain a precision better than a few milliseconds is + * an illusion. Only consistency is interesting, this also + * allows to use the routine for /dev/rtc without a potential + * 1 second kernel busy loop triggered by any reader of /dev/rtc. + */ + + for ( i = 0; i<1000000; i++) { + uip = CMOS_READ(RTC_FREQ_SELECT); sec = CMOS_READ(RTC_SECONDS); min = CMOS_READ(RTC_MINUTES); hour = CMOS_READ(RTC_HOURS); day = CMOS_READ(RTC_DAY_OF_MONTH); mon = CMOS_READ(RTC_MONTH); year = CMOS_READ(RTC_YEAR); - } while (sec != CMOS_READ(RTC_SECONDS)); + uip |= CMOS_READ(RTC_FREQ_SELECT); + if ((uip & RTC_UIP)==0) break; + } + if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { @@ -177,28 +184,11 @@ { unsigned char save_control; unsigned int year, mon, day, hour, min, sec; - int i; - /* Make sure the time is not stopped. */ - save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLB); - - ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, - (save_control & (~MK48T59_RTC_CB_STOP))); - - /* Now make sure the read bit is off so the value will change. */ + /* Simple: freeze the clock, read it and allow updates again */ save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLA); save_control &= ~MK48T59_RTC_CA_READ; ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, save_control); - - /* Read the seconds value to see when it changes. */ - sec = ppc_md.nvram_read_val(MK48T59_RTC_SECONDS); - - /* Wait until the seconds value changes, then read the value. */ - for (i = 0 ; i < 1000000 ; i++) { /* may take up to 1 second... */ - if (ppc_md.nvram_read_val(MK48T59_RTC_SECONDS) != sec) { - break; - } - } /* Set the register to read the value. */ ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/kernel/process.c linux/arch/ppc/kernel/process.c --- v2.4.0-test8/linux/arch/ppc/kernel/process.c Tue Sep 5 13:50:02 2000 +++ linux/arch/ppc/kernel/process.c Sun Sep 17 09:48:07 2000 @@ -234,7 +234,6 @@ prev->thread.vrsave ) giveup_altivec(prev); #endif /* CONFIG_ALTIVEC */ - prev->last_processor = prev->processor; current_set[smp_processor_id()] = new; #endif /* CONFIG_SMP */ /* Avoid the trap. On smp this this never happens since @@ -266,7 +265,7 @@ last_task_used_altivec); #ifdef CONFIG_SMP - printk(" CPU: %d last CPU: %d", current->processor,current->last_processor); + printk(" CPU: %d", current->processor); #endif /* CONFIG_SMP */ printk("\n"); @@ -379,9 +378,6 @@ childregs->msr &= ~MSR_VEC; #endif /* CONFIG_ALTIVEC */ -#ifdef CONFIG_SMP - p->last_processor = NO_PROC_ID; -#endif /* CONFIG_SMP */ return 0; } @@ -441,8 +437,8 @@ current->thread.fpscr = 0; } -asmlinkage int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6, - struct pt_regs *regs) +int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6, + struct pt_regs *regs) { unsigned long clone_flags = p1; int res; @@ -460,8 +456,8 @@ return res; } -asmlinkage int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6, - struct pt_regs *regs) +int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6, + struct pt_regs *regs) { int res; @@ -478,15 +474,15 @@ return res; } -asmlinkage int sys_vfork(int p1, int p2, int p3, int p4, int p5, int p6, - struct pt_regs *regs) +int sys_vfork(int p1, int p2, int p3, int p4, int p5, int p6, + struct pt_regs *regs) { return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->gpr[1], regs, 0); } -asmlinkage int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2, - unsigned long a3, unsigned long a4, unsigned long a5, - struct pt_regs *regs) +int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2, + unsigned long a3, unsigned long a4, unsigned long a5, + struct pt_regs *regs) { int error; char * filename; diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/kernel/prom.c linux/arch/ppc/kernel/prom.c --- v2.4.0-test8/linux/arch/ppc/kernel/prom.c Thu Jul 13 09:42:50 2000 +++ linux/arch/ppc/kernel/prom.c Sun Sep 17 09:48:07 2000 @@ -140,8 +140,7 @@ static long g_max_loc_X = 0; static long g_max_loc_Y = 0; -unsigned long disp_BATL = 0; -unsigned long disp_BATU = 0; +unsigned long disp_BAT[2] = {0, 0}; #define cmapsz (16*256) @@ -276,8 +275,7 @@ prom_drawstring(msg); #endif return; - } - + } for (p = msg; *p != 0; p = q) { for (q = p; *q != 0 && *q != '\n'; ++q) @@ -362,7 +360,7 @@ /* copy the holding pattern code to someplace safe (0) */ /* the holding pattern is now within the first 0x100 bytes of the kernel image -- paulus */ - memcpy((void *)0, KERNELBASE + offset, 0x100); + memcpy((void *)0, (void *)(KERNELBASE + offset), 0x100); flush_icache_range(0, 0x100); /* look for cpus */ @@ -556,6 +554,54 @@ } #endif /* CONFIG_PPC64BRIDGE */ +static __init void +prom_instantiate_rtas(void) +{ + ihandle prom_rtas; + unsigned int i; + struct prom_args prom_args; + unsigned long offset = reloc_offset(); + + prom_rtas = call_prom(RELOC("finddevice"), 1, 1, RELOC("/rtas")); + if (prom_rtas == (void *) -1) + return; + + RELOC(rtas_size) = 0; + call_prom(RELOC("getprop"), 4, 1, prom_rtas, + RELOC("rtas-size"), &RELOC(rtas_size), sizeof(rtas_size)); + prom_print(RELOC("instantiating rtas")); + if (RELOC(rtas_size) == 0) { + RELOC(rtas_data) = 0; + } else { + /* + * Ask OF for some space for RTAS. + * Actually OF has bugs so we just arbitrarily + * use memory at the 6MB point. + */ + RELOC(rtas_data) = 6 << 20; + prom_print(RELOC(" at ")); + prom_print_hex(RELOC(rtas_data)); + } + + prom_rtas = call_prom(RELOC("open"), 1, 1, RELOC("/rtas")); + prom_print(RELOC("...")); + prom_args.service = RELOC("call-method"); + prom_args.nargs = 3; + prom_args.nret = 2; + prom_args.args[0] = RELOC("instantiate-rtas"); + prom_args.args[1] = prom_rtas; + prom_args.args[2] = (void *) RELOC(rtas_data); + RELOC(prom)(&prom_args); + i = 0; + if (prom_args.args[3] == 0) + i = (unsigned int)prom_args.args[4]; + RELOC(rtas_entry) = i; + if ((RELOC(rtas_entry) == -1) || (RELOC(rtas_entry) == 0)) + prom_print(RELOC(" failed\n")); + else + prom_print(RELOC(" done\n")); +} + /* * We enter here early on, when the Open Firmware prom is still * handling exceptions and the MMU hash table for us. @@ -566,7 +612,7 @@ { int chrp = 0; unsigned long mem; - ihandle prom_rtas, prom_mmu, prom_op; + ihandle prom_mmu, prom_op; unsigned long offset = reloc_offset(); int l; char *p, *d; @@ -650,47 +696,7 @@ mem = ALIGN(mem + strlen(d) + 1); } - prom_rtas = call_prom(RELOC("finddevice"), 1, 1, RELOC("/rtas")); - if (prom_rtas != (void *) -1) { - int i, nargs; - struct prom_args prom_args; - - RELOC(rtas_size) = 0; - call_prom(RELOC("getprop"), 4, 1, prom_rtas, - RELOC("rtas-size"), &RELOC(rtas_size), sizeof(rtas_size)); - prom_print(RELOC("instantiating rtas")); - if (RELOC(rtas_size) == 0) { - RELOC(rtas_data) = 0; - } else { - /* - * Ask OF for some space for RTAS. - * Actually OF has bugs so we just arbitrarily - * use memory at the 6MB point. - */ - RELOC(rtas_data) = 6 << 20; - prom_print(RELOC(" at ")); - prom_print_hex(RELOC(rtas_data)); - } - prom_rtas = call_prom(RELOC("open"), 1, 1, RELOC("/rtas")); - prom_print(RELOC("...")); - nargs = 3; - prom_args.service = RELOC("call-method"); - prom_args.nargs = nargs; - prom_args.nret = 2; - prom_args.args[0] = RELOC("instantiate-rtas"); - prom_args.args[1] = prom_rtas; - prom_args.args[2] = (void *) RELOC(rtas_data); - RELOC(prom)(&prom_args); - if (prom_args.args[nargs] != 0) - i = 0; - else - i = (int)prom_args.args[nargs+1]; - RELOC(rtas_entry) = i; - if ((RELOC(rtas_entry) == -1) || (RELOC(rtas_entry) == 0)) - prom_print(RELOC(" failed\n")); - else - prom_print(RELOC(" done\n")); - } + prom_instantiate_rtas(); #ifdef CONFIG_PPC64BRIDGE /* @@ -737,7 +743,7 @@ /* We assume the phys. address size is 3 cells */ if (prom_args.args[nargs] != 0) - prom_print(RELOC(" (translate failed) ")); + prom_print(RELOC(" (translate failed)\n")); else phys = (unsigned long)prom_args.args[nargs+3]; } @@ -752,8 +758,6 @@ if (prom_version >= 3) { prom_print(RELOC("Calling quiesce ...\n")); call_prom(RELOC("quiesce"), 0, 0); - offset = reloc_offset(); - phys = offset + KERNELBASE; } #ifdef CONFIG_BOOTX_TEXT @@ -769,7 +773,9 @@ } #endif - prom_print(RELOC("returning from prom_init\n")); + prom_print(RELOC("returning ")); + prom_print_hex(phys); + prom_print(RELOC(" from prom_init\n")); RELOC(prom_stdout) = 0; return phys; } @@ -836,9 +842,8 @@ } /* Calc BAT values for mapping the display and store them - * in disp_BATH and disp_BATL. Those values are then used - * from head.S to map the display during identify_machine() - * and MMU_Init() + * in disp_BAT. Those values are then used from head.S to map + * the display during identify_machine() and MMU_Init() * * For now, the display is mapped in place (1:1). This should * be changed if the display physical address overlaps @@ -862,13 +867,13 @@ if ((_get_PVR() >> 16) != 1) { /* 603, 604, G3, G4, ... */ addr &= 0xFF000000UL; - RELOC(disp_BATU) = addr | (BL_16M<<2) | 2; - RELOC(disp_BATL) = addr | (_PAGE_NO_CACHE | _PAGE_GUARDED | BPP_RW); + RELOC(disp_BAT[0]) = addr | (BL_16M<<2) | 2; + RELOC(disp_BAT[1]) = addr | (_PAGE_NO_CACHE | _PAGE_GUARDED | BPP_RW); } else { /* 601 */ addr &= 0xFF800000UL; - RELOC(disp_BATU) = addr | (_PAGE_NO_CACHE | PP_RWXX) | 4; - RELOC(disp_BATL) = addr | BL_8M | 0x40; + RELOC(disp_BAT[0]) = addr | (_PAGE_NO_CACHE | PP_RWXX) | 4; + RELOC(disp_BAT[1]) = addr | BL_8M | 0x40; } bi->logicalDisplayBase = bi->dispDeviceBase; } @@ -1003,34 +1008,52 @@ unsigned address; boot_infos_t* bi; unsigned long offset = reloc_offset(); - - prom_print(RELOC("Initializing fake screen\n")); - - call_prom(RELOC("getprop"), 4, 1, dp, RELOC("width"), - &width, sizeof(width)); - call_prom(RELOC("getprop"), 4, 1, dp, RELOC("height"), - &height, sizeof(height)); - call_prom(RELOC("getprop"), 4, 1, dp, RELOC("depth"), - &depth, sizeof(depth)); + struct pci_reg_property addrs[8]; + int i, naddrs; + char name[32]; + char *getprop = RELOC("getprop"); + + prom_print(RELOC("Initializing fake screen: ")); + + memset(name, 0, sizeof(name)); + call_prom(getprop, 4, 1, dp, RELOC("name"), name, sizeof(name)); + name[sizeof(name)-1] = 0; + prom_print(name); + prom_print(RELOC("\n")); + call_prom(getprop, 4, 1, dp, RELOC("width"), &width, sizeof(width)); + call_prom(getprop, 4, 1, dp, RELOC("height"), &height, sizeof(height)); + call_prom(getprop, 4, 1, dp, RELOC("depth"), &depth, sizeof(depth)); pitch = width * ((depth + 7) / 8); - call_prom(RELOC("getprop"), 4, 1, dp, RELOC("linebytes"), + call_prom(getprop, 4, 1, dp, RELOC("linebytes"), &pitch, sizeof(pitch)); - address = 0; - if (pitch == 1) { - address = 0xfa000000; + if (pitch == 1) pitch = 0x1000; /* for strange IBM display */ - } - call_prom(RELOC("getprop"), 4, 1, dp, RELOC("address"), + address = 0; + call_prom(getprop, 4, 1, dp, RELOC("address"), &address, sizeof(address)); if (address == 0) { - prom_print(RELOC("Failed to get address\n")); - return; + /* look for an assigned address with a size of >= 1MB */ + naddrs = (int) call_prom(getprop, 4, 1, dp, + RELOC("assigned-addresses"), + addrs, sizeof(addrs)); + naddrs /= sizeof(struct pci_reg_property); + for (i = 0; i < naddrs; ++i) { + if (addrs[i].size_lo >= (1 << 20)) { + address = addrs[i].addr.a_lo; + /* use the BE aperture if possible */ + if (addrs[i].size_lo >= (16 << 20)) + address += (8 << 20); + break; + } + } + if (address == 0) { + prom_print(RELOC("Failed to get address\n")); + return; + } } -#if 0 /* kludge for valkyrie */ - if (strcmp(dp->name, "valkyrie") == 0) - address += 0x1000; -#endif + if (strcmp(name, RELOC("valkyrie")) == 0) + address += 0x1000; RELOC(disp_bi) = &fake_bi; bi = PTRRELOC((&fake_bi)); @@ -1334,11 +1357,19 @@ */ if (get_property(node, "interrupt-controller", &l)) { int i,j; + int cvt_irq; + + /* XXX on chrp, offset interrupt numbers for the + 8259 by 0, those for the openpic by 16 */ + cvt_irq = _machine == _MACH_chrp + && get_property(node, "interrupt-parent", NULL) == 0; np->intrs = (struct interrupt_info *) mem_start; np->n_intrs = ipsize / isize; mem_start += np->n_intrs * sizeof(struct interrupt_info); for (i = 0; i < np->n_intrs; ++i) { np->intrs[i].line = *interrupts++; + if (cvt_irq) + np->intrs[i].line = openpic_to_irq(np->intrs[i].line); np->intrs[i].sense = 0; if (isize > 1) np->intrs[i].sense = *interrupts++; @@ -2072,7 +2103,6 @@ * changes. */ -__init void map_bootx_text(void) { @@ -2083,7 +2113,10 @@ offset = ((unsigned long) disp_bi->dispDeviceBase) - base; size = disp_bi->dispDeviceRowBytes * disp_bi->dispDeviceRect[3] + offset + disp_bi->dispDeviceRect[0]; - disp_bi->logicalDisplayBase = ioremap(base, size) + offset; + disp_bi->logicalDisplayBase = ioremap(base, size); + if (disp_bi->logicalDisplayBase == 0) + return; + disp_bi->logicalDisplayBase += offset; bootx_text_mapped = 1; } @@ -2102,6 +2135,35 @@ return base; } +/* Adjust the display to a new resolution */ +void +bootx_update_display(unsigned long phys, int width, int height, + int depth, int pitch) +{ + if (disp_bi == 0) + return; + /* check it's the same frame buffer (within 16MB) */ + if ((phys ^ (unsigned long)disp_bi->dispDeviceBase) & 0xff000000) + return; + + disp_bi->dispDeviceBase = (__u8 *) phys; + disp_bi->dispDeviceRect[0] = 0; + disp_bi->dispDeviceRect[1] = 0; + disp_bi->dispDeviceRect[2] = width; + disp_bi->dispDeviceRect[3] = height; + disp_bi->dispDeviceDepth = depth; + disp_bi->dispDeviceRowBytes = pitch; + if (bootx_text_mapped) { + iounmap(disp_bi->logicalDisplayBase); + bootx_text_mapped = 0; + } + map_bootx_text(); + g_loc_X = 0; + g_loc_Y = 0; + g_max_loc_X = width / 8; + g_max_loc_Y = height / 16; +} + __pmac static void clearscreen(void) @@ -2162,6 +2224,9 @@ (bi->dispDeviceDepth >> 3)) >> 2; int i,j; +#ifdef CONFIG_ADB_PMU + pmu_suspend(); /* PMU will not shut us down ! */ +#endif for (i=0; i<(bi->dispDeviceRect[3] - bi->dispDeviceRect[1] - 16); i++) { unsigned long *src_ptr = src; @@ -2178,6 +2243,9 @@ *(dst_ptr++) = 0; dst += (bi->dispDeviceRowBytes >> 2); } +#ifdef CONFIG_ADB_PMU + pmu_resume(); /* PMU will not shut us down ! */ +#endif } #endif /* ndef NO_SCROLL */ diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/kernel/setup.c linux/arch/ppc/kernel/setup.c --- v2.4.0-test8/linux/arch/ppc/kernel/setup.c Thu Jul 13 09:42:50 2000 +++ linux/arch/ppc/kernel/setup.c Sun Sep 17 09:48:07 2000 @@ -35,6 +35,8 @@ #include #include #include +#include + #ifdef CONFIG_OAK #include "oak_setup.h" #endif /* CONFIG_OAK */ @@ -655,16 +657,18 @@ } /* Checks "l2cr=xxxx" command-line option */ -void ppc_setup_l2cr(char *str, int *ints) +int ppc_setup_l2cr(char *str) { if ( ((_get_PVR() >> 16) == 8) || ((_get_PVR() >> 16) == 12) ) { unsigned long val = simple_strtoul(str, NULL, 0); printk(KERN_INFO "l2cr set to %lx\n", val); - _set_L2CR(0); - _set_L2CR(val); + _set_L2CR(0); /* force invalidate by disable cache */ + _set_L2CR(val); /* and enable it */ } + return 1; } +__setup("l2cr=", ppc_setup_l2cr); void __init ppc_init(void) { @@ -683,6 +687,9 @@ extern char *klimit; extern void do_init_bootmem(void); + /* so udelay does something sensible, assume <= 1000 bogomips */ + loops_per_sec = 500000000; + #ifdef CONFIG_ALL_PPC feature_init(); #endif @@ -737,6 +744,7 @@ if ( ppc_md.progress ) ppc_md.progress("arch: exit", 0x3eab); paging_init(); + sort_exception_table(); } void ppc_generic_ide_fix_driveid(struct hd_driveid *id) diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/kernel/signal.c linux/arch/ppc/kernel/signal.c --- v2.4.0-test8/linux/arch/ppc/kernel/signal.c Sun Sep 3 11:50:26 2000 +++ linux/arch/ppc/kernel/signal.c Sun Sep 17 09:48:07 2000 @@ -154,7 +154,7 @@ } -asmlinkage int +int sys_sigaltstack(const stack_t *uss, stack_t *uoss) { struct pt_regs *regs = (struct pt_regs *) &uss; @@ -232,7 +232,7 @@ * Each of these things must be a multiple of 16 bytes in size. * */ -asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) +int sys_rt_sigreturn(struct pt_regs *regs) { struct rt_sigframe *rt_sf; struct sigcontext_struct sigctx; @@ -301,7 +301,6 @@ return ret; badframe: - lock_kernel(); do_exit(SIGSEGV); } @@ -351,7 +350,6 @@ printk("badframe in setup_rt_frame, regs=%p frame=%p newsp=%lx\n", regs, frame, newsp); #endif - lock_kernel(); do_exit(SIGSEGV); } @@ -418,7 +416,6 @@ return ret; badframe: - lock_kernel(); do_exit(SIGSEGV); } @@ -460,7 +457,6 @@ printk("badframe in setup_frame, regs=%p frame=%p newsp=%lx\n", regs, frame, newsp); #endif - lock_kernel(); do_exit(SIGSEGV); } @@ -541,7 +537,6 @@ regs, frame, *newspp); printk("sc=%p sig=%d ka=%p info=%p oldset=%p\n", sc, sig, ka, info, oldset); #endif - lock_kernel(); do_exit(SIGSEGV); } @@ -645,7 +640,6 @@ /* FALLTHRU */ default: - lock_kernel(); sigaddset(¤t->pending.signal, signr); recalc_sigpending(current); current->flags |= PF_SIGNALED; @@ -663,6 +657,7 @@ /* Whee! Actually deliver the signal. */ handle_signal(signr, ka, &info, oldset, regs, &newsp, frame); + break; } if (regs->trap == 0x0C00 /* System Call! */ && diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/kernel/smp.c linux/arch/ppc/kernel/smp.c --- v2.4.0-test8/linux/arch/ppc/kernel/smp.c Tue Sep 5 13:50:02 2000 +++ linux/arch/ppc/kernel/smp.c Sun Sep 17 09:48:07 2000 @@ -62,72 +62,62 @@ int start_secondary(void *); extern int cpu_idle(void *unused); u_int openpic_read(volatile u_int *addr); +void smp_call_function_interrupt(void); +void smp_message_pass(int target, int msg, unsigned long data, int wait); +/* register for interrupting the primary processor on the powersurge */ +/* N.B. this is actually the ethernet ROM! */ +#define PSURGE_PRI_INTR 0xf3019000 /* register for interrupting the secondary processor on the powersurge */ -#define PSURGE_INTR ((volatile unsigned *)0xf80000c0) +#define PSURGE_SEC_INTR 0xf80000c0 +/* register for storing the start address for the secondary processor */ +#define PSURGE_START 0xf2800000 +/* virtual addresses for the above */ +volatile u32 *psurge_pri_intr; +volatile u32 *psurge_sec_intr; +volatile u32 *psurge_start; + +/* Since OpenPIC has only 4 IPIs, we use slightly different message numbers. */ +#define PPC_MSG_CALL_FUNCTION 0 +#define PPC_MSG_RESCHEDULE 1 +#define PPC_MSG_INVALIDATE_TLB 2 +#define PPC_MSG_XMON_BREAK 3 + +static inline void set_tb(unsigned int upper, unsigned int lower) +{ + mtspr(SPRN_TBWU, upper); + mtspr(SPRN_TBWL, lower); +} void smp_local_timer_interrupt(struct pt_regs * regs) { int cpu = smp_processor_id(); - extern void update_one_process(struct task_struct *,unsigned long, - unsigned long,unsigned long,int); - if (!--prof_counter[cpu]) { - int user=0,system=0; - struct task_struct * p = current; - - /* - * After doing the above, we need to make like - * a normal interrupt - otherwise timer interrupts - * ignore the global interrupt lock, which is the - * WrongThing (tm) to do. - */ - - if (user_mode(regs)) - user=1; - else - system=1; - - if (p->pid) { - update_one_process(p, 1, user, system, cpu); - - p->counter -= 1; - if (p->counter <= 0) { - p->counter = 0; - current->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; - } + if (!--prof_counter[cpu]) { + update_process_times(user_mode(regs)); prof_counter[cpu]=prof_multiplier[cpu]; } } -void smp_message_recv(int msg) +void smp_message_recv(int msg, struct pt_regs *regs) { ipi_count++; - switch( msg ) - { - case MSG_STOP_CPU: - __cli(); - while (1) ; + switch( msg ) { + case PPC_MSG_CALL_FUNCTION: + smp_call_function_interrupt(); break; - case MSG_RESCHEDULE: + case PPC_MSG_RESCHEDULE: current->need_resched = 1; break; - case MSG_INVALIDATE_TLB: + case PPC_MSG_INVALIDATE_TLB: _tlbia(); - case 0xf0f0: /* pmac syncing time bases - just return */ break; +#ifdef CONFIG_XMON + case PPC_MSG_XMON_BREAK: + xmon(regs); + break; +#endif /* CONFIG_XMON */ default: printk("SMP %d: smp_message_recv(): unknown msg %d\n", smp_processor_id(), msg); @@ -142,25 +132,38 @@ * smp_message[]. * * This is because don't have several IPI's on the PowerSurge even though - * we do on the chrp. It would be nice to use actual IPI's such as with openpic - * rather than this. + * we do on the chrp. It would be nice to use actual IPI's such as with + * openpic rather than this. * -- Cort */ int pmac_smp_message[NR_CPUS]; -void pmac_smp_message_recv(void) +void pmac_smp_message_recv(struct pt_regs *regs) { - int msg = pmac_smp_message[smp_processor_id()]; - + int cpu = smp_processor_id(); + int msg; + /* clear interrupt */ - out_be32(PSURGE_INTR, ~0); - - /* make sure msg is for us */ - if ( msg == -1 ) return; + if (cpu == 1) + out_be32(psurge_sec_intr, ~0); + + if (smp_num_cpus < 2) + return; + + /* make sure there is a message there */ + msg = pmac_smp_message[cpu]; + if (msg == 0) + return; - smp_message_recv(msg); - /* reset message */ - pmac_smp_message[smp_processor_id()] = -1; + pmac_smp_message[cpu] = 0; + + smp_message_recv(msg - 1, regs); +} + +void +pmac_primary_intr(int irq, void *d, struct pt_regs *regs) +{ + pmac_smp_message_recv(regs); } /* @@ -171,7 +174,7 @@ void smp_send_tlb_invalidate(int cpu) { if ( (_get_PVR()>>16) == 8 ) - smp_message_pass(MSG_ALL_BUT_SELF, MSG_INVALIDATE_TLB, 0, 0); + smp_message_pass(MSG_ALL_BUT_SELF, PPC_MSG_INVALIDATE_TLB, 0, 0); } void smp_send_reschedule(int cpu) @@ -187,18 +190,135 @@ */ /* This is only used if `cpu' is running an idle task, so it will reschedule itself anyway... */ - smp_message_pass(cpu, MSG_RESCHEDULE, 0, 0); + smp_message_pass(cpu, PPC_MSG_RESCHEDULE, 0, 0); +} + +#ifdef CONFIG_XMON +void smp_send_xmon_break(int cpu) +{ + smp_message_pass(cpu, PPC_MSG_XMON_BREAK, 0, 0); +} +#endif /* CONFIG_XMON */ + +static void stop_this_cpu(void *dummy) +{ + __cli(); + while (1) + ; } void smp_send_stop(void) { - smp_message_pass(MSG_ALL_BUT_SELF, MSG_STOP_CPU, 0, 0); + smp_call_function(stop_this_cpu, NULL, 1, 0); + smp_num_cpus = 1; +} + +/* + * Structure and data for smp_call_function(). This is designed to minimise + * static memory requirements. It also looks cleaner. + * Stolen from the i386 version. + */ +static spinlock_t call_lock = SPIN_LOCK_UNLOCKED; + +static volatile struct call_data_struct { + void (*func) (void *info); + void *info; + atomic_t started; + atomic_t finished; + int wait; +} *call_data = NULL; + +/* + * this function sends a 'generic call function' IPI to all other CPUs + * in the system. + */ + +int smp_call_function (void (*func) (void *info), void *info, int nonatomic, + 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. + */ +{ + struct call_data_struct data; + int ret = -1, cpus = smp_num_cpus-1; + int timeout; + + if (!cpus) + return 0; + + data.func = func; + data.info = info; + atomic_set(&data.started, 0); + data.wait = wait; + if (wait) + atomic_set(&data.finished, 0); + + spin_lock_bh(&call_lock); + call_data = &data; + /* Send a message to all other CPUs and wait for them to respond */ + smp_message_pass(MSG_ALL_BUT_SELF, PPC_MSG_CALL_FUNCTION, 0, 0); + + /* Wait for response */ + timeout = 1000000; + while (atomic_read(&data.started) != cpus) { + if (--timeout == 0) { + printk("smp_call_function on cpu %d: other cpus not responding (%d)\n", + smp_processor_id(), atomic_read(&data.started)); + goto out; + } + barrier(); + udelay(1); + } + + if (wait) { + timeout = 1000000; + while (atomic_read(&data.finished) != cpus) { + if (--timeout == 0) { + printk("smp_call_function on cpu %d: other cpus not finishing (%d/%d)\n", + smp_processor_id(), atomic_read(&data.finished), atomic_read(&data.started)); + goto out; + } + barrier(); + udelay(1); + } + } + ret = 0; + + out: + spin_unlock_bh(&call_lock); + return ret; +} + +void smp_call_function_interrupt(void) +{ + void (*func) (void *info) = call_data->func; + void *info = call_data->info; + int wait = call_data->wait; + + /* + * Notify initiating CPU that I've grabbed the data and am + * about to execute the function + */ + atomic_inc(&call_data->started); + /* + * At this point the info structure may be out of scope unless wait==1 + */ + (*func)(info); + if (wait) + atomic_inc(&call_data->finished); } void smp_message_pass(int target, int msg, unsigned long data, int wait) { - int i; - if ( !(_machine & (_MACH_Pmac|_MACH_chrp|_MACH_prep|_MACH_gemini)) ) return; @@ -212,31 +332,29 @@ * the recipient won't know the message was destined * for it. -- Cort */ - for ( i = 0; i <= smp_num_cpus ; i++ ) - pmac_smp_message[i] = -1; - switch( target ) - { - case MSG_ALL: - pmac_smp_message[smp_processor_id()] = msg; - /* fall through */ - case MSG_ALL_BUT_SELF: - for ( i = 0 ; i < smp_num_cpus ; i++ ) - if ( i != smp_processor_id () ) - pmac_smp_message[i] = msg; - break; - default: - pmac_smp_message[target] = msg; - break; + if (smp_processor_id() == 0) { + /* primary cpu */ + if (target == 1 || target == MSG_ALL_BUT_SELF + || target == MSG_ALL) { + pmac_smp_message[1] = msg + 1; + /* interrupt secondary processor */ + out_be32(psurge_sec_intr, ~0); + out_be32(psurge_sec_intr, 0); + } + } else { + /* secondary cpu */ + if (target == 0 || target == MSG_ALL_BUT_SELF + || target == MSG_ALL) { + pmac_smp_message[0] = msg + 1; + /* interrupt primary processor */ + in_be32(psurge_pri_intr); + } + } + if (target == smp_processor_id() || target == MSG_ALL) { + /* sending a message to ourself */ + /* XXX maybe we shouldn't do this if ints are off */ + smp_message_recv(msg, NULL); } - /* interrupt secondary processor */ - out_be32(PSURGE_INTR, ~0); - out_be32(PSURGE_INTR, 0); - /* - * Assume for now that the secondary doesn't send - * IPI's -- Cort - */ - /* interrupt primary */ - /**(volatile unsigned long *)(0xf3019000);*/ break; case _MACH_chrp: case _MACH_prep: @@ -261,7 +379,7 @@ #else /* CONFIG_POWER4 */ /* for now, only do reschedule messages since we only have one IPI */ - if (msg != MSG_RESCHEDULE) + if (msg != PPC_MSG_RESCHEDULE) break; for (i = 0; i < smp_num_cpus; ++i) { if (target == MSG_ALL || target == i @@ -319,7 +437,10 @@ { case _MACH_Pmac: /* assume powersurge board - 2 processors -- Cort */ - cpu_nr = 2; + cpu_nr = 2; + psurge_pri_intr = ioremap(PSURGE_PRI_INTR, 4); + psurge_sec_intr = ioremap(PSURGE_SEC_INTR, 4); + psurge_start = ioremap(PSURGE_START, 4); break; case _MACH_chrp: if (OpenPIC) @@ -370,13 +491,11 @@ { case _MACH_Pmac: /* setup entry point of secondary processor */ - *(volatile unsigned long *)(0xf2800000) = - (unsigned long)__secondary_start_psurge-KERNELBASE; - eieio(); + out_be32(psurge_start, __pa(__secondary_start_psurge)); /* interrupt secondary to begin executing code */ - out_be32(PSURGE_INTR, ~0); + out_be32(psurge_sec_intr, ~0); udelay(1); - out_be32(PSURGE_INTR, 0); + out_be32(psurge_sec_intr, 0); break; case _MACH_chrp: *(unsigned long *)KERNELBASE = i; @@ -399,9 +518,6 @@ if ( cpu_callin_map[i] ) { printk("Processor %d found.\n", i); - /* this sync's the decr's -- Cort */ - if ( _machine == _MACH_Pmac ) - set_dec(decrementer_count); smp_num_cpus++; } else { printk("Processor %d is stuck.\n", i); @@ -415,9 +531,25 @@ { /* reset the entry point so if we get another intr we won't * try to startup again */ - *(volatile unsigned long *)(0xf2800000) = 0x100; - /* send interrupt to other processors to start decr's on all cpus */ - smp_message_pass(1,0xf0f0, 0, 0); + out_be32(psurge_start, 0x100); + if (request_irq(30, pmac_primary_intr, 0, "primary IPI", 0)) + printk(KERN_ERR "Couldn't get primary IPI interrupt"); + /* + * The decrementers of both cpus are frozen at this point + * until we give the secondary cpu another interrupt. + * We set them both to decrementer_count and then send + * the interrupt. This should get the decrementers + * synchronized. + * -- paulus. + */ + set_dec(tb_ticks_per_jiffy); + if ((_get_PVR() >> 16) != 1) { + set_tb(0, 0); /* set timebase if not 601 */ + last_jiffy_stamp(0) = 0; + } + out_be32(psurge_sec_intr, ~0); + udelay(1); + out_be32(psurge_sec_intr, 0); } } @@ -447,8 +579,11 @@ void __init smp_callin(void) { smp_store_cpu_info(current->processor); - set_dec(decrementer_count); - + set_dec(tb_ticks_per_jiffy); + if (_machine == _MACH_Pmac && (_get_PVR() >> 16) != 1) { + set_tb(0, 0); /* set timebase if not 601 */ + last_jiffy_stamp(current->processor) = 0; + } init_idle(); cpu_callin_map[current->processor] = 1; diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/kernel/syscalls.c linux/arch/ppc/kernel/syscalls.c --- v2.4.0-test8/linux/arch/ppc/kernel/syscalls.c Tue Jul 18 15:03:56 2000 +++ linux/arch/ppc/kernel/syscalls.c Sun Sep 17 09:48:07 2000 @@ -45,7 +45,7 @@ { } -asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on) +int sys_ioperm(unsigned long from, unsigned long num, int on) { printk(KERN_ERR "sys_ioperm()\n"); return -EIO; @@ -74,7 +74,7 @@ * * This is really horribly ugly. */ -asmlinkage int +int sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth) { int version, ret; @@ -172,7 +172,7 @@ * sys_pipe() is the normal C calling standard for creating * a pipe. It's not the way unix traditionally does this, though. */ -asmlinkage int sys_pipe(int *fildes) +int sys_pipe(int *fildes) { int fd[2]; int error; @@ -185,19 +185,19 @@ return error; } -asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len, - unsigned long prot, unsigned long flags, - unsigned long fd, off_t offset) +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; + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); 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); @@ -207,7 +207,7 @@ return ret; } -extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *); +extern int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *); /* * Due to some executables calling the wrong select we sometimes @@ -215,7 +215,7 @@ * (a single ptr to them all args passed) then calls * sys_select() with the appropriate args. -- Cort */ -asmlinkage int +int ppc_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp) { if ( (unsigned long)n >= 4096 ) @@ -232,14 +232,14 @@ return sys_select(n, inp, outp, exp, tvp); } -asmlinkage int sys_pause(void) +int sys_pause(void) { current->state = TASK_INTERRUPTIBLE; schedule(); return -ERESTARTNOHAND; } -asmlinkage int sys_uname(struct old_utsname * name) +int sys_uname(struct old_utsname * name) { int err = -EFAULT; @@ -250,7 +250,7 @@ return err; } -asmlinkage int sys_olduname(struct oldold_utsname * name) +int sys_olduname(struct oldold_utsname * name) { int error; diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/kernel/time.c linux/arch/ppc/kernel/time.c --- v2.4.0-test8/linux/arch/ppc/kernel/time.c Thu Jul 13 09:42:50 2000 +++ linux/arch/ppc/kernel/time.c Sun Sep 17 09:48:07 2000 @@ -6,6 +6,27 @@ * Paul Mackerras' version and mine for PReP and Pmac. * MPC8xx/MBX changes by Dan Malek (dmalek@jlc.net). * + * First round of bugfixes by Gabriel Paubert (paubert@iram.es) + * to make clock more stable (2.4.0-test5). The only thing + * that this code assumes is that the timebases have been synchronized + * by firmware on SMP and are never stopped (never do sleep + * on SMP then, nap and doze are OK). + * + * TODO (not necessarily in this file): + * - improve precision and reproducibility of timebase frequency + * measurement at boot time. + * - get rid of xtime_lock for gettimeofday (generic kernel problem + * to be implemented on all architectures for SMP scalability and + * eventually implementing gettimeofday without entering the kernel). + * - put all time/clock related variables in a single structure + * to minimize number of cache lines touched by gettimeofday() + * - for astronomical applications: add a new function to get + * non ambiguous timestamps even around leap seconds. This needs + * a new timestamp format and a good name. + * + * + * The following comment is partially obsolete (at least the long wait + * is no more a valid reason): * Since the MPC8xx has a programmable interrupt timer, I decided to * use that rather than the decrementer. Two reasons: 1.) the clock * frequency is low, causing 2.) a long wait in the timer interrupt @@ -49,18 +70,32 @@ void smp_local_timer_interrupt(struct pt_regs *); /* keep track of when we need to update the rtc */ -time_t last_rtc_update = 0; +time_t last_rtc_update; extern rwlock_t xtime_lock; /* The decrementer counts down by 128 every 128ns on a 601. */ #define DECREMENTER_COUNT_601 (1000000000 / HZ) -#define COUNT_PERIOD_NUM_601 1 -#define COUNT_PERIOD_DEN_601 1000 -unsigned decrementer_count; /* count value for 1e6/HZ microseconds */ -unsigned count_period_num; /* 1 decrementer count equals */ -unsigned count_period_den; /* count_period_num / count_period_den us */ -unsigned long last_tb; +unsigned tb_ticks_per_jiffy; +unsigned tb_to_us; +unsigned tb_last_stamp; + +extern unsigned long wall_jiffies; + +static long time_offset; + +/* Timer interrupt helper function */ +static inline int tb_delta(unsigned *jiffy_stamp) { + int delta; + if (__USE_RTC()) { + delta = get_rtcl(); + if (delta < *jiffy_stamp) *jiffy_stamp -= 1000000000; + delta -= *jiffy_stamp; + } else { + delta = get_tbl() - *jiffy_stamp; + } + return delta; +} /* * timer_interrupt - gets called when the decrementer overflows, @@ -69,88 +104,56 @@ */ int timer_interrupt(struct pt_regs * regs) { - int dval, d; -#if 0 - unsigned long flags; -#endif + int next_dec; unsigned long cpu = smp_processor_id(); - + unsigned jiffy_stamp = last_jiffy_stamp(cpu); + hardirq_enter(cpu); -#ifdef CONFIG_SMP - { - unsigned int loops = 100000000; - while (test_bit(0, &global_irq_lock)) { - if (smp_processor_id() == global_irq_holder) { - printk("uh oh, interrupt while we hold global irq lock!\n"); -#ifdef CONFIG_XMON - xmon(0); -#endif - break; - } - if (loops-- == 0) { - printk("do_IRQ waiting for irq lock (holder=%d)\n", global_irq_holder); -#ifdef CONFIG_XMON - xmon(0); -#endif - } - } - } -#endif /* CONFIG_SMP */ - dval = get_dec(); - /* - * Wait for the decrementer to change, then jump - * in and add decrementer_count to its value - * (quickly, before it changes again!) - */ - while ((d = get_dec()) == dval) - ; - asm volatile("mftb %0" : "=r" (last_tb) ); - /* - * Don't play catchup between the call to time_init() - * and sti() in init/main.c. - * - * This also means if we're delayed for > HZ - * we lose those ticks. If we're delayed for > HZ - * then we have something wrong anyway, though. - * - * -- Cort - */ - if ( d < (-1*decrementer_count) ) - d = 0; - set_dec(d + decrementer_count); - if ( !smp_processor_id() ) - { + do { + jiffy_stamp += tb_ticks_per_jiffy; + if (smp_processor_id()) continue; + /* We are in an interrupt, no need to save/restore flags */ + write_lock(&xtime_lock); + tb_last_stamp = jiffy_stamp; do_timer(regs); -#if 0 - /* -- BenH -- I'm removing this for now since it can cause various - * troubles with local-time RTCs. Now that we have a - * /dev/rtc that uses ppc_md.set_rtc_time() on mac, it - * should be possible to program the RTC from userland - * in all cases. - */ + /* - * update the rtc when needed + * update the rtc when needed, this should be performed on the + * right fraction of a second. Half or full second ? + * Full second works on mk48t59 clocks, others need testing. + * Note that this update is basically only used through + * the adjtimex system calls. Setting the HW clock in + * any other way is a /dev/rtc and userland business. + * This is still wrong by -0.5/+1.5 jiffies because of the + * timer interrupt resolution and possible delay, but here we + * hit a quantization limit which can only be solved by higher + * resolution timers and decoupling time management from timer + * interrupts. This is also wrong on the clocks + * which require being written at the half second boundary. + * We should have an rtc call that only sets the minutes and + * seconds like on Intel to avoid problems with non UTC clocks. */ - read_lock_irqsave(&xtime_lock, flags); - if ( (time_status & STA_UNSYNC) && - ((xtime.tv_sec > last_rtc_update + 60) || - (xtime.tv_sec < last_rtc_update)) ) - { - if (ppc_md.set_rtc_time(xtime.tv_sec) == 0) - last_rtc_update = xtime.tv_sec; + if ( (time_status & STA_UNSYNC) == 0 && + xtime.tv_sec - last_rtc_update >= 659 && + abs(xtime.tv_usec - (1000000-1000000/HZ)) < 500000/HZ && + jiffies - wall_jiffies == 1) { + if (ppc_md.set_rtc_time(xtime.tv_sec+1 + time_offset) == 0) + last_rtc_update = xtime.tv_sec+1; else - /* do it again in 60 s */ - last_rtc_update = xtime.tv_sec; + /* Try again one minute later */ + last_rtc_update += 60; } - read_unlock_irqrestore(&xtime_lock, flags); -#endif - } + write_unlock(&xtime_lock); + } while((next_dec = tb_ticks_per_jiffy - tb_delta(&jiffy_stamp)) < 0); + set_dec(next_dec); + last_jiffy_stamp(cpu) = jiffy_stamp; + #ifdef CONFIG_SMP smp_local_timer_interrupt(regs); #endif - if ( ppc_md.heartbeat && !ppc_md.heartbeat_count--) + if (ppc_md.heartbeat && !ppc_md.heartbeat_count--) ppc_md.heartbeat(); hardirq_exit(cpu); @@ -162,106 +165,138 @@ */ void do_gettimeofday(struct timeval *tv) { - unsigned long flags, diff; + unsigned long flags; + unsigned delta, lost_ticks, usec, sec; - save_flags(flags); - cli(); read_lock_irqsave(&xtime_lock, flags); - *tv = xtime; + sec = xtime.tv_sec; + usec = xtime.tv_usec; + delta = tb_ticks_since(tb_last_stamp); +#ifdef CONFIG_SMP + /* As long as timebases are not in sync, gettimeofday can only + * have jiffy resolution on SMP. + */ + if (_machine != _MACH_Pmac) + delta = 0; +#endif /* CONFIG_SMP */ + lost_ticks = jiffies - wall_jiffies; read_unlock_irqrestore(&xtime_lock, flags); - /* XXX we don't seem to have the decrementers synced properly yet */ -#ifndef CONFIG_SMP - asm volatile("mftb %0" : "=r" (diff) ); - diff -= last_tb; - tv->tv_usec += diff * count_period_num / count_period_den; - tv->tv_sec += tv->tv_usec / 1000000; - tv->tv_usec = tv->tv_usec % 1000000; -#endif - - restore_flags(flags); + + usec += mulhwu(tb_to_us, tb_ticks_per_jiffy * lost_ticks + delta); + while (usec > 1000000) { + sec++; + usec -= 1000000; + } + tv->tv_sec = sec; + tv->tv_usec = usec; } void do_settimeofday(struct timeval *tv) { unsigned long flags; - int frac_tick; - - last_rtc_update = 0; /* so the rtc gets updated soon */ - - frac_tick = tv->tv_usec % (1000000 / HZ); - save_flags(flags); - cli(); + int tb_delta, new_usec, new_sec; + write_lock_irqsave(&xtime_lock, flags); - xtime.tv_sec = tv->tv_sec; - xtime.tv_usec = tv->tv_usec - frac_tick; - write_unlock_irqrestore(&xtime_lock, flags); - set_dec(frac_tick * count_period_den / count_period_num); + /* Updating the RTC is not the job of this code. If the time is + * stepped under NTP, the RTC will be update after STA_UNSYNC + * is cleared. Tool like clock/hwclock either copy the RTC + * to the system time, in which case there is no point in writing + * to the RTC again, or write to the RTC but then they don't call + * settimeofday to perform this operation. Note also that + * we don't touch the decrementer since: + * a) it would lose timer interrupt synchronization on SMP + * (if it is working one day) + * b) it could make one jiffy spuriously shorter or longer + * which would introduce another source of uncertainty potentially + * harmful to relatively short timers. + */ + + /* This works perfectly on SMP only if the tb are in sync but + * guarantees an error < 1 jiffy even if they are off by eons, + * still reasonable when gettimeofday resolution is 1 jiffy. + */ + tb_delta = tb_ticks_since(last_jiffy_stamp(smp_processor_id())); + tb_delta += (jiffies - wall_jiffies) * tb_ticks_per_jiffy; + new_sec = tv->tv_sec; + new_usec = tv->tv_usec - mulhwu(tb_to_us, tb_delta); + while (new_usec <0) { + new_sec--; + new_usec += 1000000; + } + xtime.tv_usec = new_usec; + xtime.tv_sec = new_sec; + + /* In case of a large backwards jump in time with NTP, we want the + * clock to be updated as soon as the PLL is again in lock. + */ + last_rtc_update = new_sec - 658; + time_adjust = 0; /* stop active adjtime() */ time_status |= STA_UNSYNC; time_state = TIME_ERROR; /* p. 24, (a) */ time_maxerror = NTP_PHASE_LIMIT; time_esterror = NTP_PHASE_LIMIT; - restore_flags(flags); + write_unlock_irqrestore(&xtime_lock, flags); } void __init time_init(void) { + time_t sec, old_sec; + unsigned old_stamp, stamp, elapsed; + /* This function is only called on the boot processor */ unsigned long flags; + if (ppc_md.time_init != NULL) - { - ppc_md.time_init(); - } + time_offset = ppc_md.time_init(); - if ((_get_PVR() >> 16) == 1) { + if (__USE_RTC()) { /* 601 processor: dec counts down by 128 every 128ns */ - decrementer_count = DECREMENTER_COUNT_601; - count_period_num = COUNT_PERIOD_NUM_601; - count_period_den = COUNT_PERIOD_DEN_601; - } else if (!smp_processor_id()) { + tb_ticks_per_jiffy = DECREMENTER_COUNT_601; + /* mulhwu_scale_factor(1000000000, 1000000) is 0x418937 */ + tb_to_us = 0x418937; + } else { ppc_md.calibrate_decr(); } + /* Now that the decrementer is calibrated, it can be used in case the + * clock is stuck, but the fact that we have to handle the 601 + * makes things more complex. Repeatedly read the RTC until the + * next second boundary to try to achieve some precision... + */ + stamp = get_native_tbl(); + sec = ppc_md.get_rtc_time(); + elapsed = 0; + do { + old_stamp = stamp; + old_sec = sec; + stamp = get_native_tbl(); + if (__USE_RTC() && stamp < old_stamp) old_stamp -= 1000000000; + elapsed += stamp - old_stamp; + sec = ppc_md.get_rtc_time(); + } while ( sec == old_sec && elapsed < 2*HZ*tb_ticks_per_jiffy); + if (sec==old_sec) { + printk("Warning: real time clock seems stuck!\n"); + } write_lock_irqsave(&xtime_lock, flags); - xtime.tv_sec = ppc_md.get_rtc_time(); + xtime.tv_sec = sec; + last_jiffy_stamp(0) = tb_last_stamp = stamp; xtime.tv_usec = 0; + /* No update now, we just read the time from the RTC ! */ + last_rtc_update = xtime.tv_sec; write_unlock_irqrestore(&xtime_lock, flags); + /* Not exact, but the timer interrupt takes care of this */ + set_dec(tb_ticks_per_jiffy); - set_dec(decrementer_count); - /* allow setting the time right away */ - last_rtc_update = 0; -} - -/* Converts Gregorian date to seconds since 1970-01-01 00:00:00. - * Assumes input in normal date format, i.e. 1980-12-31 23:59:59 - * => year=1980, mon=12, day=31, hour=23, min=59, sec=59. - * - * [For the Julian calendar (which was used in Russia before 1917, - * Britain & colonies before 1752, anywhere else before 1582, - * and is still in use by some communities) leave out the - * -year/100+year/400 terms, and add 10.] - * - * This algorithm was first published by Gauss (I think). - * - * WARNING: this function will overflow on 2106-02-07 06:28:16 on - * machines were long is 32-bit! (However, as time_t is signed, we - * will already get problems at other places on 2038-01-19 03:14:08) - */ -unsigned long mktime(unsigned int year, unsigned int mon, - unsigned int day, unsigned int hour, - unsigned int min, unsigned int sec) -{ - - if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */ - mon += 12; /* Puts Feb last since it has leap day */ - year -= 1; - } - return ((( - (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) + - year*365 - 719499 - )*24 + hour /* now have hours */ - )*60 + min /* now have minutes */ - )*60 + sec; /* finally seconds */ + /* If platform provided a timezone (pmac), we correct the time + * using do_sys_settimeofday() which in turn calls warp_clock() + */ + if (time_offset) { + struct timezone tz; + tz.tz_minuteswest = -time_offset / 60; + tz.tz_dsttime = 0; + do_sys_settimeofday(NULL, &tz); + } } #define TICK_SIZE tick @@ -354,3 +389,31 @@ */ GregorianDay(tm); } + +/* Auxiliary function to compute scaling factors */ +/* Actually the choice of a timebase running at 1/4 the of the bus + * frequency giving resolution of a few tens of nanoseconds is quite nice. + * It makes this computation very precise (27-28 bits typically) which + * is optimistic considering the stability of most processor clock + * oscillators and the precision with which the timebase frequency + * is measured but does not harm. + */ +unsigned mulhwu_scale_factor(unsigned inscale, unsigned outscale) { + unsigned mlt=0, tmp, err; + /* No concern for performance, it's done once: use a stupid + * but safe and compact method to find the multiplier. + */ + for (tmp = 1U<<31; tmp != 0; tmp >>= 1) { + if (mulhwu(inscale, mlt|tmp) < outscale) mlt|=tmp; + } + /* We might still be off by 1 for the best approximation. + * A side effect of this is that if outscale is too large + * the returned value will be zero. + * Many corner cases have been checked and seem to work, + * some might have been forgotten in the test however. + */ + err = inscale*(mlt+1); + if (err <= inscale/2) mlt++; + return mlt; +} + diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/kernel/traps.c linux/arch/ppc/kernel/traps.c --- v2.4.0-test8/linux/arch/ppc/kernel/traps.c Mon May 15 14:53:30 2000 +++ linux/arch/ppc/kernel/traps.c Sun Sep 17 09:48:07 2000 @@ -87,45 +87,76 @@ void MachineCheckException(struct pt_regs *regs) { - if ( !user_mode(regs) ) - { -#if defined(CONFIG_8xx) && defined(CONFIG_PCI) - /* the qspan pci read routines can cause machine checks -- Cort */ - bad_page_fault(regs, regs->dar); +#ifdef CONFIG_ALL_PPC + unsigned long fixup; +#endif /* CONFIG_ALL_PPC */ + + if (user_mode(regs)) { + _exception(SIGSEGV, regs); return; + } + +#if defined(CONFIG_8xx) && defined(CONFIG_PCI) + /* the qspan pci read routines can cause machine checks -- Cort */ + bad_page_fault(regs, regs->dar); + return; #endif #if defined(CONFIG_XMON) || defined(CONFIG_KGDB) - if (debugger_fault_handler) { - debugger_fault_handler(regs); - return; - } + if (debugger_fault_handler) { + debugger_fault_handler(regs); + return; + } #endif - printk("Machine check in kernel mode.\n"); - printk("Caused by (from SRR1=%lx): ", regs->msr); - switch (regs->msr & 0xF0000) { - case 0x80000: - printk("Machine check signal\n"); - break; - case 0x40000: - printk("Transfer error ack signal\n"); - break; - case 0x20000: - printk("Data parity error signal\n"); - break; - case 0x10000: - printk("Address parity error signal\n"); - break; - default: - printk("Unknown values in msr\n"); + +#ifdef CONFIG_ALL_PPC + /* + * I/O accesses can cause machine checks on powermacs. + * Check if the NIP corresponds to the address of a sync + * instruction for which there is an entry in the exception + * table. + */ + if (regs->msr & (0x80000 | 0x40000) + && (fixup = search_exception_table(regs->nip)) != 0) { + /* + * Check that it's a sync instruction. + * As the address is in the exception table + * we should be able to read the instr there. + */ + if (*(unsigned int *)regs->nip == 0x7c0004ac) { + unsigned int lsi = ((unsigned int *)regs->nip)[-1]; + int rb = (lsi >> 11) & 0x1f; + printk(KERN_DEBUG "%s bad port %lx at %lx\n", + (lsi & 0x100)? "OUT to": "IN from", + regs->gpr[rb] - _IO_BASE, regs->nip); + regs->nip = fixup; + return; } - show_regs(regs); + } +#endif /* CONFIG_ALL_PPC */ + printk("Machine check in kernel mode.\n"); + printk("Caused by (from SRR1=%lx): ", regs->msr); + switch (regs->msr & 0xF0000) { + case 0x80000: + printk("Machine check signal\n"); + break; + case 0x40000: + printk("Transfer error ack signal\n"); + break; + case 0x20000: + printk("Data parity error signal\n"); + break; + case 0x10000: + printk("Address parity error signal\n"); + break; + default: + printk("Unknown values in msr\n"); + } + show_regs(regs); #if defined(CONFIG_XMON) || defined(CONFIG_KGDB) - debugger(regs); + debugger(regs); #endif - print_backtrace((unsigned long *)regs->gpr[1]); - panic("machine check"); - } - _exception(SIGSEGV, regs); + print_backtrace((unsigned long *)regs->gpr[1]); + panic("machine check"); } void @@ -166,6 +197,46 @@ _exception(SIGTRAP, regs); } +/* Illegal instruction emulation support. Originally written to + * provide the PVR to user applications using the mfspr rd, PVR. + * Return non-zero if we can't emulate, or EFAULT if the associated + * memory access caused an access fault. Return zero on success. + * + * There are a couple of ways to do this, either "decode" the instruction + * or directly match lots of bits. In this case, matching lots of + * bits is faster and easier. + * + */ +#define INST_MFSPR_PVR 0x7c1f42a6 +#define INST_MFSPR_PVR_MASK 0xfc1fffff + +static int +emulate_instruction(struct pt_regs *regs) +{ + uint instword; + uint rd; + uint retval; + + retval = EFAULT; + + if (!user_mode(regs)) + return retval; + + if (get_user(instword, (uint *)(regs->nip))) + return retval; + + /* Emulate the mfspr rD, PVR. + */ + if ((instword & INST_MFSPR_PVR_MASK) == INST_MFSPR_PVR) { + rd = (instword >> 21) & 0x1f; + regs->gpr[rd] = _get_PVR(); + retval = 0; + } + if (retval == 0) + regs->nip += 4; + return(retval); +} + void ProgramCheckException(struct pt_regs *regs) { @@ -193,7 +264,14 @@ #endif _exception(SIGTRAP, regs); } else { - _exception(SIGILL, regs); + /* Try to emulate it if we should. */ + int errcode; + if ((errcode = emulate_instruction(regs))) { + if (errcode == EFAULT) + _exception(SIGBUS, regs); + else + _exception(SIGILL, regs); + } } #endif } diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/kernel/walnut_setup.c linux/arch/ppc/kernel/walnut_setup.c --- v2.4.0-test8/linux/arch/ppc/kernel/walnut_setup.c Thu Jul 13 09:42:51 2000 +++ linux/arch/ppc/kernel/walnut_setup.c Sun Sep 17 09:48:07 2000 @@ -226,10 +226,11 @@ /* * Document me. */ -void __init +long __init walnut_time_init(void) { /* XXX - Implement me */ + return 0; } /* diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/kernel/xics.c linux/arch/ppc/kernel/xics.c --- v2.4.0-test8/linux/arch/ppc/kernel/xics.c Mon Jun 19 17:59:36 2000 +++ linux/arch/ppc/kernel/xics.c Sun Sep 17 09:48:07 2000 @@ -166,7 +166,7 @@ void xics_ipi_action(int irq, void *dev_id, struct pt_regs *regs) { qirr_info(smp_processor_id()) = 0xff; - smp_message_recv(MSG_RESCHEDULE); + smp_message_recv(MSG_RESCHEDULE, regs); } void xics_cause_IPI(int cpu) diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/lib/string.S linux/arch/ppc/lib/string.S --- v2.4.0-test8/linux/arch/ppc/lib/string.S Sun Feb 13 10:47:01 2000 +++ linux/arch/ppc/lib/string.S Tue Sep 19 08:31:53 2000 @@ -9,13 +9,74 @@ * 2 of the License, or (at your option) any later version. */ #include "../kernel/ppc_asm.tmpl" +#include #include #include -CACHELINE_BYTES = 32 -LG_CACHELINE_BYTES = 5 -CACHELINE_MASK = 0x1f -CACHELINE_WORDS = 8 +#if defined(CONFIG_4xx) || defined(CONFIG_8xx) +#define CACHE_LINE_SIZE 16 +#define LG_CACHE_LINE_SIZE 4 +#define MAX_COPY_PREFETCH 1 +#elif !defined(CONFIG_PPC64BRIDGE) +#define CACHE_LINE_SIZE 32 +#define LG_CACHE_LINE_SIZE 5 +#define MAX_COPY_PREFETCH 4 +#else +#define CACHE_LINE_SIZE 128 +#define LG_CACHE_LINE_SIZE 7 +#define MAX_COPY_PREFETCH 1 +#endif /* CONFIG_4xx || CONFIG_8xx */ + +#define COPY_16_BYTES \ + lwz r7,4(r4); \ + lwz r8,8(r4); \ + lwz r9,12(r4); \ + lwzu r10,16(r4); \ + stw r7,4(r6); \ + stw r8,8(r6); \ + stw r9,12(r6); \ + stwu r10,16(r6) + +#define COPY_16_BYTES_WITHEX(n) \ +8 ## n ## 0: \ + lwz r7,4(r4); \ +8 ## n ## 1: \ + lwz r8,8(r4); \ +8 ## n ## 2: \ + lwz r9,12(r4); \ +8 ## n ## 3: \ + lwzu r10,16(r4); \ +8 ## n ## 4: \ + stw r7,4(r6); \ +8 ## n ## 5: \ + stw r8,8(r6); \ +8 ## n ## 6: \ + stw r9,12(r6); \ +8 ## n ## 7: \ + stwu r10,16(r6) + +#define COPY_16_BYTES_EXCODE(n) \ +9 ## n ## 0: \ + addi r5,r5,-(16 * n); \ + b 104f; \ +9 ## n ## 1: \ + addi r5,r5,-(16 * n); \ + b 105f; \ +.section __ex_table,"a"; \ + .align 2; \ + .long 8 ## n ## 0b,9 ## n ## 0b; \ + .long 8 ## n ## 1b,9 ## n ## 0b; \ + .long 8 ## n ## 2b,9 ## n ## 0b; \ + .long 8 ## n ## 3b,9 ## n ## 0b; \ + .long 8 ## n ## 4b,9 ## n ## 1b; \ + .long 8 ## n ## 5b,9 ## n ## 1b; \ + .long 8 ## n ## 6b,9 ## n ## 1b; \ + .long 8 ## n ## 7b,9 ## n ## 1b; \ +.text + +CACHELINE_BYTES = CACHE_LINE_SIZE +LG_CACHELINE_BYTES = LG_CACHE_LINE_SIZE +CACHELINE_MASK = (CACHE_LINE_SIZE-1) .globl strcpy strcpy: @@ -105,7 +166,14 @@ bdnz 4b 3: mtctr r9 li r7,4 +#if !defined(CONFIG_8xx) 10: dcbz r7,r6 +#else +10: stw r4, 4(r6) + stw r4, 8(r6) + stw r4, 12(r6) + stw r4, 16(r6) +#endif addi r6,r6,CACHELINE_BYTES bdnz 10b clrlwi r5,r8,32-LG_CACHELINE_BYTES @@ -202,23 +270,24 @@ li r11,4 mtctr r0 beq 63f -53: dcbz r11,r6 - lwz r7,4(r4) - lwz r8,8(r4) - lwz r9,12(r4) - lwzu r10,16(r4) - stw r7,4(r6) - stw r8,8(r6) - stw r9,12(r6) - stwu r10,16(r6) - lwz r7,4(r4) - lwz r8,8(r4) - lwz r9,12(r4) - lwzu r10,16(r4) - stw r7,4(r6) - stw r8,8(r6) - stw r9,12(r6) - stwu r10,16(r6) +53: +#if !defined(CONFIG_8xx) + dcbz r11,r6 +#endif + COPY_16_BYTES +#if CACHE_LINE_SIZE >= 32 + COPY_16_BYTES +#if CACHE_LINE_SIZE >= 64 + COPY_16_BYTES + COPY_16_BYTES +#if CACHE_LINE_SIZE >= 128 + COPY_16_BYTES + COPY_16_BYTES + COPY_16_BYTES + COPY_16_BYTES +#endif +#endif +#endif bdnz 53b 63: srwi. r0,r5,2 @@ -380,25 +449,59 @@ 58: srwi. r0,r5,LG_CACHELINE_BYTES /* # complete cachelines */ clrlwi r5,r5,32-LG_CACHELINE_BYTES li r11,4 - mtctr r0 beq 63f -53: dcbz r11,r6 -10: lwz r7,4(r4) -11: lwz r8,8(r4) -12: lwz r9,12(r4) -13: lwzu r10,16(r4) -14: stw r7,4(r6) -15: stw r8,8(r6) -16: stw r9,12(r6) -17: stwu r10,16(r6) -20: lwz r7,4(r4) -21: lwz r8,8(r4) -22: lwz r9,12(r4) -23: lwzu r10,16(r4) -24: stw r7,4(r6) -25: stw r8,8(r6) -26: stw r9,12(r6) -27: stwu r10,16(r6) + +#if !defined(CONFIG_8xx) + /* Here we decide how far ahead to prefetch the source */ +#if MAX_COPY_PREFETCH > 1 + /* Heuristically, for large transfers we prefetch + MAX_COPY_PREFETCH cachelines ahead. For small transfers + we prefetch 1 cacheline ahead. */ + cmpwi r0,MAX_COPY_PREFETCH + li r7,1 + li r3,4 + ble 111f + li r7,MAX_COPY_PREFETCH +111: mtctr r7 +112: dcbt r3,r4 + addi r3,r3,CACHELINE_BYTES + bdnz 112b +#else /* MAX_COPY_PREFETCH == 1 */ + li r3,CACHELINE_BYTES + 4 + dcbt r11,r4 +#endif /* MAX_COPY_PREFETCH */ +#endif /* CONFIG_8xx */ + + mtctr r0 +53: +#if !defined(CONFIG_8xx) + dcbt r3,r4 + dcbz r11,r6 +#endif +/* had to move these to keep extable in order */ + .section __ex_table,"a" + .align 2 + .long 70b,100f + .long 71b,101f + .long 72b,102f + .long 73b,103f + .long 53b,105f + .text +/* the main body of the cacheline loop */ + COPY_16_BYTES_WITHEX(0) +#if CACHE_LINE_SIZE >= 32 + COPY_16_BYTES_WITHEX(1) +#if CACHE_LINE_SIZE >= 64 + COPY_16_BYTES_WITHEX(2) + COPY_16_BYTES_WITHEX(3) +#if CACHE_LINE_SIZE >= 128 + COPY_16_BYTES_WITHEX(4) + COPY_16_BYTES_WITHEX(5) + COPY_16_BYTES_WITHEX(6) + COPY_16_BYTES_WITHEX(7) +#endif +#endif +#endif bdnz 53b 63: srwi. r0,r5,2 @@ -434,15 +537,31 @@ 103: li r4,1 91: li r3,2 b 99f -/* read fault in 2nd half of cacheline loop */ -106: addi r5,r5,-16 -/* read fault in 1st half of cacheline loop */ + +/* + * this stuff handles faults in the cacheline loop and branches to either + * 104f (if in read part) or 105f (if in write part), after updating r5 + */ + COPY_16_BYTES_EXCODE(0) +#if CACHE_LINE_SIZE >= 32 + COPY_16_BYTES_EXCODE(1) +#if CACHE_LINE_SIZE >= 64 + COPY_16_BYTES_EXCODE(2) + COPY_16_BYTES_EXCODE(3) +#if CACHE_LINE_SIZE >= 128 + COPY_16_BYTES_EXCODE(4) + COPY_16_BYTES_EXCODE(5) + COPY_16_BYTES_EXCODE(6) + COPY_16_BYTES_EXCODE(7) +#endif +#endif +#endif + +/* read fault in cacheline loop */ 104: li r4,0 b 92f -/* write fault in 2nd half of cacheline loop */ -107: addi r5,r5,-16 /* fault on dcbz (effectively a write fault) */ -/* or write fault in 1st half of cacheline loop */ +/* or write fault in cacheline loop */ 105: li r4,1 92: li r3,LG_CACHELINE_BYTES b 99f @@ -485,36 +604,15 @@ bdnz 114b 120: blr -.section __ex_table,"a" + .section __ex_table,"a" .align 2 - .long 70b,100b - .long 71b,101b - .long 72b,102b - .long 73b,103b - .long 53b,105b - .long 10b,104b - .long 11b,104b - .long 12b,104b - .long 13b,104b - .long 14b,105b - .long 15b,105b - .long 16b,105b - .long 17b,105b - .long 20b,106b - .long 21b,106b - .long 22b,106b - .long 23b,106b - .long 24b,107b - .long 25b,107b - .long 26b,107b - .long 27b,107b .long 30b,108b .long 31b,109b .long 40b,110b .long 41b,111b .long 112b,120b .long 114b,120b -.text + .text .globl __clear_user __clear_user: @@ -546,12 +644,13 @@ blr 99: li r3,-EFAULT blr -.section __ex_table,"a" + + .section __ex_table,"a" .align 2 .long 11b,99b .long 1b,99b .long 8b,99b -.text + .text .globl __strncpy_from_user __strncpy_from_user: @@ -570,10 +669,11 @@ blr 99: li r3,-EFAULT blr -.section __ex_table,"a" + + .section __ex_table,"a" .align 2 .long 1b,99b -.text + .text /* r3 = str, r4 = len (> 0), r5 = top (highest addr) */ .globl __strnlen_user @@ -596,6 +696,7 @@ blr 99: li r3,0 /* bad address, return 0 */ blr -.section __ex_table,"a" + + .section __ex_table,"a" .align 2 .long 1b,99b diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/mbxboot/misc.c linux/arch/ppc/mbxboot/misc.c --- v2.4.0-test8/linux/arch/ppc/mbxboot/misc.c Thu Jul 13 09:42:51 2000 +++ linux/arch/ppc/mbxboot/misc.c Sun Sep 17 09:48:07 2000 @@ -269,6 +269,11 @@ */ #ifdef CONFIG_MBX cmd_line = (char *)(load_addr - 0x10000); + + /* To be like everyone else, we need one too, although this + * board information is passed from the boot rom. + */ + bp->bi_baudrate = 9600; #else cmd_line = (char *)(0x200000); #endif diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/mm/extable.c linux/arch/ppc/mm/extable.c --- v2.4.0-test8/linux/arch/ppc/mm/extable.c Wed Nov 10 22:18:39 1999 +++ linux/arch/ppc/mm/extable.c Tue Sep 19 08:31:53 2000 @@ -4,11 +4,47 @@ * from linux/arch/i386/mm/extable.c */ +#include #include #include -extern const struct exception_table_entry __start___ex_table[]; -extern const struct exception_table_entry __stop___ex_table[]; +extern struct exception_table_entry __start___ex_table[]; +extern struct exception_table_entry __stop___ex_table[]; + +/* + * The exception table needs to be sorted because we use the macros + * which put things into the exception table in a variety of segments + * such as the prep, pmac, chrp, etc. segments as well as the init + * segment and the main kernel text segment. + */ +static inline void +sort_ex_table(struct exception_table_entry *start, + struct exception_table_entry *finish) +{ + struct exception_table_entry el, *p, *q; + + /* insertion sort */ + for (p = start + 1; p < finish; ++p) { + /* start .. p-1 is sorted */ + if (p[0].insn < p[-1].insn) { + /* move element p down to its right place */ + el = *p; + q = p; + do { + /* el comes before q[-1], move q[-1] up one */ + q[0] = q[-1]; + --q; + } while (q > start && el.insn < q[-1].insn); + *q = el; + } + } +} + +void +sort_exception_table(void) +{ + sort_ex_table(__start___ex_table, __stop___ex_table); +} static inline unsigned long search_one_table(const struct exception_table_entry *first, @@ -36,25 +72,21 @@ { unsigned long ret; -#if 1 /*ndef CONFIG_MODULES*/ +#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; - read_lock(&modlist_lock); 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) { - read_unlock(&modlist_lock); + if (ret) return ret; - } } - read_unlock(&modlist_lock); #endif return 0; diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/mm/fault.c linux/arch/ppc/mm/fault.c --- v2.4.0-test8/linux/arch/ppc/mm/fault.c Mon Jun 19 17:59:37 2000 +++ linux/arch/ppc/mm/fault.c Sun Sep 17 09:48:07 2000 @@ -67,7 +67,7 @@ #if defined(CONFIG_4xx) int is_write = error_code & ESR_DST; #else - int is_write = error_code & 0x02000000; + int is_write = 0; /* * Fortunately the bit assignments in SRR1 for an instruction @@ -77,6 +77,8 @@ */ if (regs->trap == 0x400) error_code &= 0x48200000; + else + is_write = error_code & 0x02000000; #endif /* CONFIG_4xx */ #if defined(CONFIG_XMON) || defined(CONFIG_KGDB) diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c --- v2.4.0-test8/linux/arch/ppc/mm/init.c Mon Aug 7 21:02:27 2000 +++ linux/arch/ppc/mm/init.c Sun Sep 17 09:48:07 2000 @@ -36,6 +36,7 @@ #include #include #include +#include #ifdef CONFIG_BLK_DEV_INITRD #include /* for initrd_* */ #endif @@ -69,15 +70,20 @@ #include "4xx_tlb.h" #endif +#define MAX_LOW_MEM (640 << 20) + #define PGTOKB(pages) (((pages) * PAGE_SIZE) >> 10) int prom_trashed; atomic_t next_mmu_context; unsigned long *end_of_DRAM; +unsigned long total_memory; +unsigned long total_lowmem; int mem_init_done; int init_bootmem_done; int boot_mapsize; unsigned long totalram_pages = 0; +unsigned long totalhigh_pages = 0; extern pgd_t swapper_pg_dir[]; extern char _start[], _end[]; extern char etext[], _stext[]; @@ -98,22 +104,26 @@ #ifndef CONFIG_SMP struct pgtable_cache_struct quicklists; #endif +#ifdef CONFIG_HIGHMEM +pte_t *kmap_pte; +pgprot_t kmap_prot; +#endif void MMU_init(void); static void *MMU_get_page(void); -unsigned long *prep_find_end_of_memory(void); -unsigned long *pmac_find_end_of_memory(void); -unsigned long *apus_find_end_of_memory(void); -unsigned long *gemini_find_end_of_memory(void); -extern unsigned long *find_end_of_memory(void); +unsigned long prep_find_end_of_memory(void); +unsigned long pmac_find_end_of_memory(void); +unsigned long apus_find_end_of_memory(void); +unsigned long gemini_find_end_of_memory(void); +extern unsigned long find_end_of_memory(void); #ifdef CONFIG_8xx -unsigned long *m8xx_find_end_of_memory(void); +unsigned long m8xx_find_end_of_memory(void); #endif /* CONFIG_8xx */ #ifdef CONFIG_4xx -unsigned long *oak_find_end_of_memory(void); +unsigned long oak_find_end_of_memory(void); #endif #ifdef CONFIG_8260 -unsigned long *m8260_find_end_of_memory(void); +unsigned long m8260_find_end_of_memory(void); #endif /* CONFIG_8260 */ static void mapin_ram(void); void map_page(unsigned long va, unsigned long pa, int flags); @@ -269,6 +279,7 @@ int i,free = 0,total = 0,reserved = 0; int shared = 0, cached = 0; struct task_struct *p; + int highmem = 0; printk("Mem-info:\n"); show_free_areas(); @@ -276,6 +287,8 @@ i = max_mapnr; while (i-- > 0) { total++; + if (PageHighMem(mem_map+i)) + highmem++; if (PageReserved(mem_map+i)) reserved++; else if (PageSwapCache(mem_map+i)) @@ -286,6 +299,7 @@ shared += atomic_read(&mem_map[i].count) - 1; } printk("%d pages of RAM\n",total); + printk("%d pages of HIGHMEM\n", highmem); printk("%d free pages\n",free); printk("%d reserved pages\n",reserved); printk("%d pages shared\n",shared); @@ -354,6 +368,8 @@ continue; val->sharedram += atomic_read(&mem_map[i].count) - 1; } + val->totalhigh = totalhigh_pages; + val->freehigh = nr_free_highpages(); val->mem_unit = PAGE_SIZE; } @@ -443,7 +459,8 @@ void iounmap(void *addr) { - /* XXX todo */ + if (addr > high_memory && (unsigned long) addr < ioremap_bot) + vfree((void *) (PAGE_MASK & (unsigned long) addr)); } unsigned long iopa(unsigned long addr) @@ -476,7 +493,7 @@ { pmd_t *pd, oldpd; pte_t *pg; - + /* Use upper 10 bits of VA to index the first level map */ pd = pmd_offset(pgd_offset_k(va), va); oldpd = *pd; @@ -516,6 +533,7 @@ flush_hash_segments(0xd, 0xffffff); #else __clear_user(Hash, Hash_size); + _tlbia(); #ifdef CONFIG_SMP smp_send_tlb_invalidate(0); #endif /* CONFIG_SMP */ @@ -610,6 +628,13 @@ } #endif /* CONFIG_8xx */ +void flush_page_to_ram(struct page *page) +{ + unsigned long vaddr = kmap(page); + __flush_page_to_ram(vaddr); + kunmap(page); +} + #if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) static void get_mem_prop(char *, struct mem_pieces *); @@ -722,7 +747,7 @@ if (align && align < max_size) max_size = align; - tot = (unsigned long)end_of_DRAM - KERNELBASE; + tot = total_lowmem; for (bl = 128<<10; bl < max_size; bl <<= 1) { if (bl * 2 > tot) break; @@ -745,6 +770,8 @@ for (i = 0; i < phys_mem.n_regions; ++i) { v = (ulong)__va(phys_mem.regions[i].address); p = phys_mem.regions[i].address; + if (p >= total_lowmem) + break; for (s = 0; s < phys_mem.regions[i].size; s += PAGE_SIZE) { /* On the MPC8xx, we want the page shared so we * don't get ASID compares on kernel space. @@ -766,6 +793,8 @@ map_page(v, p, f); v += PAGE_SIZE; p += PAGE_SIZE; + if (p >= total_lowmem) + break; } } } @@ -788,77 +817,42 @@ return p; } -void __init free_initmem(void) +static void free_sec(unsigned long start, unsigned long end, const char *name) { - unsigned long a; - unsigned long num_freed_pages = 0, num_prep_pages = 0, - num_pmac_pages = 0, num_openfirmware_pages = 0, - num_apus_pages = 0, num_chrp_pages = 0; -#define FREESEC(START,END,CNT) do { \ - a = (unsigned long)(&START); \ - for (; a < (unsigned long)(&END); a += PAGE_SIZE) { \ - clear_bit(PG_reserved, &virt_to_page(a)->flags); \ - set_page_count(virt_to_page(a), 1); \ - free_page(a); \ - CNT++; \ - } \ -} while (0) - - FREESEC(__init_begin,__init_end,num_freed_pages); - switch (_machine) - { - case _MACH_Pmac: - FREESEC(__apus_begin,__apus_end,num_apus_pages); - FREESEC(__prep_begin,__prep_end,num_prep_pages); - FREESEC(__chrp_begin,__chrp_end,num_chrp_pages); - break; - case _MACH_chrp: - FREESEC(__apus_begin,__apus_end,num_apus_pages); - FREESEC(__pmac_begin,__pmac_end,num_pmac_pages); - FREESEC(__prep_begin,__prep_end,num_prep_pages); - break; - case _MACH_prep: - FREESEC(__apus_begin,__apus_end,num_apus_pages); - FREESEC(__pmac_begin,__pmac_end,num_pmac_pages); - FREESEC(__chrp_begin,__chrp_end,num_chrp_pages); - break; - case _MACH_mbx: - FREESEC(__apus_begin,__apus_end,num_apus_pages); - FREESEC(__pmac_begin,__pmac_end,num_pmac_pages); - FREESEC(__prep_begin,__prep_end,num_prep_pages); - FREESEC(__chrp_begin,__chrp_end,num_chrp_pages); - break; - case _MACH_apus: - FREESEC(__pmac_begin,__pmac_end,num_pmac_pages); - FREESEC(__prep_begin,__prep_end,num_prep_pages); - FREESEC(__chrp_begin,__chrp_end,num_chrp_pages); - break; - case _MACH_gemini: - FREESEC(__apus_begin,__apus_end,num_apus_pages); - FREESEC(__pmac_begin,__pmac_end,num_pmac_pages); - FREESEC(__prep_begin,__prep_end,num_prep_pages); - FREESEC(__chrp_begin,__chrp_end,num_chrp_pages); - break; - } + unsigned long cnt = 0; - if ( !have_of ) - FREESEC( __openfirmware_begin, __openfirmware_end, - num_openfirmware_pages ); - - printk ("Freeing unused kernel memory: %ldk init", - PGTOKB(num_freed_pages)); + while (start < end) { + clear_bit(PG_reserved, &virt_to_page(start)->flags); + set_page_count(virt_to_page(start), 1); + free_page(start); + cnt++; + start += PAGE_SIZE; + } + if (cnt) + printk(" %ldk %s", PGTOKB(cnt), name); +} - if ( num_prep_pages ) - printk(" %ldk prep", PGTOKB(num_prep_pages)); - if ( num_chrp_pages ) - printk(" %ldk chrp", PGTOKB(num_chrp_pages)); - if ( num_pmac_pages ) - printk(" %ldk pmac", PGTOKB(num_pmac_pages)); - if ( num_openfirmware_pages ) - printk(" %ldk open firmware", PGTOKB(num_openfirmware_pages)); - if ( num_apus_pages ) - printk(" %ldk apus", PGTOKB(num_apus_pages)); - printk("\n"); +void free_initmem(void) +{ +#define FREESEC(TYPE) \ + free_sec((unsigned long)(&__ ## TYPE ## _begin), \ + (unsigned long)(&__ ## TYPE ## _end), \ + #TYPE); + + printk ("Freeing unused kernel memory:"); + FREESEC(init); + if (_machine != _MACH_Pmac) + FREESEC(pmac); + if (_machine != _MACH_chrp) + FREESEC(chrp); + if (_machine != _MACH_prep) + FREESEC(prep); + if (_machine != _MACH_apus) + FREESEC(apus); + if (!have_of) + FREESEC(openfirmware); + printk("\n"); +#undef FREESEC } #ifdef CONFIG_BLK_DEV_INITRD @@ -909,7 +903,8 @@ * at KERNELBASE. */ - end_of_DRAM = oak_find_end_of_memory(); + total_memory = total_lowmem = oak_find_end_of_memory(); + end_of_DRAM = __va(total_memory); mapin_ram(); /* @@ -939,23 +934,33 @@ if ( ppc_md.progress ) ppc_md.progress("MMU:enter", 0x111); #ifndef CONFIG_8xx if (have_of) - end_of_DRAM = pmac_find_end_of_memory(); + total_memory = pmac_find_end_of_memory(); #ifdef CONFIG_APUS else if (_machine == _MACH_apus ) - end_of_DRAM = apus_find_end_of_memory(); + total_memory = apus_find_end_of_memory(); #endif #ifdef CONFIG_GEMINI else if ( _machine == _MACH_gemini ) - end_of_DRAM = gemini_find_end_of_memory(); + total_memory = gemini_find_end_of_memory(); #endif /* CONFIG_GEMINI */ #if defined(CONFIG_8260) else - end_of_DRAM = m8260_find_end_of_memory(); + total_memory = m8260_find_end_of_memory(); #else else /* prep */ - end_of_DRAM = prep_find_end_of_memory(); + total_memory = prep_find_end_of_memory(); #endif + total_lowmem = total_memory; +#ifdef CONFIG_HIGHMEM + if (total_lowmem > MAX_LOW_MEM) { + total_lowmem = MAX_LOW_MEM; + mem_pieces_remove(&phys_avail, total_lowmem, + total_memory - total_lowmem, 0); + } +#endif /* CONFIG_HIGHMEM */ + end_of_DRAM = __va(total_lowmem); + if ( ppc_md.progress ) ppc_md.progress("MMU:hash init", 0x300); hash_init(); #ifndef CONFIG_PPC64BRIDGE @@ -995,7 +1000,7 @@ #endif break; case _MACH_Pmac: - ioremap_base = 0xf8000000; + ioremap_base = 0xfe000000; break; case _MACH_apus: /* Map PPC exception vectors. */ @@ -1022,7 +1027,15 @@ #endif /* CONFIG_POWER4 */ #else /* CONFIG_8xx */ - end_of_DRAM = m8xx_find_end_of_memory(); + total_memory = total_lowmem = m8xx_find_end_of_memory(); +#ifdef CONFIG_HIGHMEM + if (total_lowmem > MAX_LOW_MEM) { + total_lowmem = MAX_LOW_MEM; + mem_pieces_remove(&phys_avail, total_lowmem, + total_memory - total_lowmem, 0); + } +#endif /* CONFIG_HIGHMEM */ + end_of_DRAM = __va(total_lowmem); /* Map in all of RAM starting at KERNELBASE */ mapin_ram(); @@ -1055,7 +1068,7 @@ if ( ppc_md.progress ) ppc_md.progress("MMU:exit", 0x211); #ifdef CONFIG_BOOTX_TEXT /* Must be done last, or ppc_md.progress will die */ - if (_machine == _MACH_Pmac) + if (_machine == _MACH_Pmac || _machine == _MACH_chrp) map_bootx_text(); #endif } @@ -1092,7 +1105,7 @@ start = PAGE_ALIGN(start); boot_mapsize = init_bootmem(start >> PAGE_SHIFT, - __pa(end_of_DRAM) >> PAGE_SHIFT); + total_lowmem >> PAGE_SHIFT); /* remove the bootmem bitmap from the available memory */ mem_pieces_remove(&phys_avail, start, boot_mapsize, 1); @@ -1105,47 +1118,6 @@ init_bootmem_done = 1; } -#if 0 -/* - * Find some memory for setup_arch to return. - * We use the largest chunk of available memory as the area - * that setup_arch returns, making sure that there are at - * least 32 pages unused before this for MMU_get_page to use. - */ -unsigned long __init find_available_memory(void) -{ - int i, rn; - unsigned long a, free; - unsigned long start, end; - - if (_machine == _MACH_mbx) { - /* Return the first, not the last region, because we - * may not yet have properly initialized the additonal - * memory DIMM. - */ - a = PAGE_ALIGN(phys_avail.regions[0].address); - avail_start = (unsigned long) __va(a); - return avail_start; - } - - rn = 0; - for (i = 1; i < phys_avail.n_regions; ++i) - if (phys_avail.regions[i].size > phys_avail.regions[rn].size) - rn = i; - free = 0; - for (i = 0; i < rn; ++i) { - start = phys_avail.regions[i].address; - end = start + phys_avail.regions[i].size; - free += (end & PAGE_MASK) - PAGE_ALIGN(start); - } - a = PAGE_ALIGN(phys_avail.regions[rn].address); - if (free < 32 * PAGE_SIZE) - a += 32 * PAGE_SIZE - free; - avail_start = (unsigned long) __va(a); - return avail_start; -} -#endif /* 0 */ - /* * paging_init() sets up the page tables - in fact we've already done this. */ @@ -1153,6 +1125,14 @@ { unsigned long zones_size[MAX_NR_ZONES], i; +#ifdef CONFIG_HIGHMEM + map_page(PKMAP_BASE, 0, 0); /* XXX gross */ + pkmap_page_table = pte_offset(pmd_offset(pgd_offset_k(PKMAP_BASE), PKMAP_BASE), PKMAP_BASE); + map_page(KMAP_FIX_BEGIN, 0, 0); /* XXX gross */ + kmap_pte = pte_offset(pmd_offset(pgd_offset_k(KMAP_FIX_BEGIN), KMAP_FIX_BEGIN), KMAP_FIX_BEGIN); + kmap_prot = PAGE_KERNEL; +#endif /* CONFIG_HIGHMEM */ + /* * Grab some memory for bad_page and bad_pagetable to use. */ @@ -1162,9 +1142,14 @@ /* * All pages are DMA-able so we put them all in the DMA zone. */ - zones_size[0] = ((unsigned long)end_of_DRAM - KERNELBASE) >> PAGE_SHIFT; + zones_size[ZONE_DMA] = total_lowmem >> PAGE_SHIFT; for (i = 1; i < MAX_NR_ZONES; i++) zones_size[i] = 0; + +#ifdef CONFIG_HIGHMEM + zones_size[ZONE_HIGHMEM] = (total_memory - total_lowmem) >> PAGE_SHIFT; +#endif /* CONFIG_HIGHMEM */ + free_area_init(zones_size); } @@ -1176,7 +1161,17 @@ int codepages = 0; int datapages = 0; int initpages = 0; +#ifdef CONFIG_HIGHMEM + unsigned long highmem_mapnr; + + highmem_mapnr = total_lowmem >> PAGE_SHIFT; + highmem_start_page = mem_map + highmem_mapnr; + max_mapnr = total_memory >> PAGE_SHIFT; + totalram_pages += max_mapnr - highmem_mapnr; +#else max_mapnr = max_low_pfn; +#endif /* CONFIG_HIGHMEM */ + high_memory = (void *) __va(max_low_pfn * PAGE_SIZE); num_physpages = max_mapnr; /* RAM is assumed contiguous */ @@ -1217,11 +1212,28 @@ datapages++; } - printk("Memory: %luk available (%dk kernel code, %dk data, %dk init) [%08x,%08lx]\n", +#ifdef CONFIG_HIGHMEM + { + unsigned long pfn; + + for (pfn = highmem_mapnr; pfn < max_mapnr; ++pfn) { + struct page *page = mem_map + pfn; + + ClearPageReserved(page); + set_bit(PG_highmem, &page->flags); + atomic_set(&page->count, 1); + __free_page(page); + totalhigh_pages++; + } + totalram_pages += totalhigh_pages; + } +#endif /* CONFIG_HIGHMEM */ + + printk("Memory: %luk available (%dk kernel code, %dk data, %dk init, %ldk highmem)\n", (unsigned long)nr_free_pages()<< (PAGE_SHIFT-10), codepages<< (PAGE_SHIFT-10), datapages<< (PAGE_SHIFT-10), initpages<< (PAGE_SHIFT-10), - PAGE_OFFSET, (unsigned long) end_of_DRAM); + (unsigned long) (totalhigh_pages << (PAGE_SHIFT-10))); mem_init_done = 1; } @@ -1234,7 +1246,7 @@ * Our text, data, bss use something over 1MB, starting at 0. * Open Firmware may be using 1MB at the 4MB point. */ -unsigned long __init *pmac_find_end_of_memory(void) +unsigned long __init pmac_find_end_of_memory(void) { unsigned long a, total; unsigned long ram_limit = 0xe0000000 - KERNELBASE; @@ -1279,7 +1291,7 @@ set_phys_avail(&phys_mem); - return __va(total); + return total; } #endif /* CONFIG_ALL_PPC */ @@ -1290,7 +1302,7 @@ * this will likely stay separate from the pmac. * -- Cort */ -unsigned long __init *prep_find_end_of_memory(void) +unsigned long __init prep_find_end_of_memory(void) { unsigned long total; total = res->TotalMemory; @@ -1308,15 +1320,15 @@ mem_pieces_append(&phys_mem, 0, total); set_phys_avail(&phys_mem); - return (__va(total)); + return (total); } #endif /* defined(CONFIG_ALL_PPC) */ #if defined(CONFIG_GEMINI) -unsigned long __init *gemini_find_end_of_memory(void) +unsigned long __init gemini_find_end_of_memory(void) { - unsigned long total, *ret; + unsigned long total; unsigned char reg; reg = readb(GEMINI_MEMCFG); @@ -1327,9 +1339,8 @@ phys_mem.regions[0].size = total; phys_mem.n_regions = 1; - ret = __va(phys_mem.regions[0].size); set_phys_avail(&phys_mem); - return ret; + return phys_mem.regions[0].size; } #endif /* defined(CONFIG_GEMINI) */ @@ -1337,10 +1348,9 @@ /* * Same hack as 8xx. */ -unsigned long __init *m8260_find_end_of_memory(void) +unsigned long __init m8260_find_end_of_memory(void) { bd_t *binfo; - unsigned long *ret; extern unsigned char __res[]; binfo = (bd_t *)__res; @@ -1349,15 +1359,14 @@ phys_mem.regions[0].size = binfo->bi_memsize; phys_mem.n_regions = 1; - ret = __va(phys_mem.regions[0].size); set_phys_avail(&phys_mem); - return ret; + return phys_mem.regions[0].size; } #endif /* CONFIG_8260 */ #ifdef CONFIG_APUS #define HARDWARE_MAPPED_SIZE (512*1024) -unsigned long __init *apus_find_end_of_memory(void) +unsigned long __init apus_find_end_of_memory(void) { int shadow = 0; @@ -1421,7 +1430,7 @@ the PowerUP board. Other system memory is horrible slow in comparison. The user can use other memory for swapping using the z2ram device. */ - return __va(memory[0].addr + memory[0].size); + return memory[0].addr + memory[0].size; } #endif /* CONFIG_APUS */ @@ -1484,7 +1493,7 @@ /* Find some memory for the hash table. */ if ( Hash_size ) { Hash = mem_pieces_find(Hash_size, Hash_size); - /*__clear_user(Hash, Hash_size);*/ + cacheable_memzero(Hash, Hash_size); } else Hash = 0; #endif /* CONFIG_PPC64BRIDGE */ @@ -1544,10 +1553,9 @@ * functions in the image just to get prom_init, all we really need right * now is the initialization of the physical memory region. */ -unsigned long __init *m8xx_find_end_of_memory(void) +unsigned long __init m8xx_find_end_of_memory(void) { bd_t *binfo; - unsigned long *ret; extern unsigned char __res[]; binfo = (bd_t *)__res; @@ -1555,12 +1563,9 @@ phys_mem.regions[0].address = 0; phys_mem.regions[0].size = binfo->bi_memsize; phys_mem.n_regions = 1; - - ret = __va(phys_mem.regions[0].address+ - phys_mem.regions[0].size); set_phys_avail(&phys_mem); - return ret; + return phys_mem.regions[0].address + phys_mem.regions[0].size; } #endif /* !CONFIG_4xx && !CONFIG_8xx */ @@ -1569,7 +1574,7 @@ * Return the virtual address representing the top of physical RAM * on the Oak board. */ -unsigned long __init * +unsigned long __init oak_find_end_of_memory(void) { extern unsigned char __res[]; @@ -1580,12 +1585,9 @@ phys_mem.regions[0].address = 0; phys_mem.regions[0].size = bip->bi_memsize; phys_mem.n_regions = 1; - - ret = __va(phys_mem.regions[0].address + - phys_mem.regions[0].size); set_phys_avail(&phys_mem); - return (ret); + return (phys_mem.regions[0].address + phys_mem.regions[0].size); } #endif diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/xmon/start.c linux/arch/ppc/xmon/start.c --- v2.4.0-test8/linux/arch/ppc/xmon/start.c Mon Jun 19 17:59:37 2000 +++ linux/arch/ppc/xmon/start.c Sun Sep 17 09:48:07 2000 @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -67,6 +68,12 @@ use_screen = 1; } #endif +#ifdef CONFIG_ADB_CUDA + if (!via_modem && disp_bi ) { + prom_drawstring("xmon uses screen and keyboard\n"); + use_screen = 1; + } +#endif #endif #ifdef CHRP_ESCC @@ -100,6 +107,10 @@ /* should already be mapped by the kernel boot */ sccc = (volatile unsigned char *) (isa_io_base + 0x3fd); sccd = (volatile unsigned char *) (isa_io_base + 0x3f8); + if (xmon_use_sccb) { + sccc -= 0x100; + sccd -= 0x100; + } TXRDY = 0x20; RXRDY = 1; } @@ -109,6 +120,19 @@ void xmon_init_scc(void); extern void pmu_poll(void); +extern void cuda_poll(void); + +static inline void do_poll_adb(void) +{ +#ifdef CONFIG_ADB_PMU + if (sys_ctrler == SYS_CTRLER_PMU) + pmu_poll(); +#endif /* CONFIG_ADB_PMU */ +#ifdef CONFIG_ADB_CUDA + if (sys_ctrler == SYS_CTRLER_CUDA) + cuda_poll(); +#endif /* CONFIG_ADB_CUDA */ +} int xmon_write(void *handle, void *ptr, int nb) @@ -128,12 +152,8 @@ xmon_init_scc(); ct = 0; for (i = 0; i < nb; ++i) { - while ((*sccc & TXRDY) == 0) { -#ifdef CONFIG_ADB_PMU - if (sys_ctrler == SYS_CTRLER_PMU) - pmu_poll(); -#endif /* CONFIG_ADB_PMU */ - } + while ((*sccc & TXRDY) == 0) + do_poll_adb(); c = p[i]; if (c == '\n' && !ct) { c = '\r'; @@ -189,9 +209,7 @@ prom_drawchar('\b'); t = 200000; } -#ifdef CONFIG_ADB_PMU - pmu_poll(); -#endif /* CONFIG_ADB_PMU */ + do_poll_adb(); } while (xmon_adb_keycode == -1); k = xmon_adb_keycode; if (on) @@ -230,14 +248,9 @@ xmon_init_scc(); for (i = 0; i < nb; ++i) { while ((*sccc & RXRDY) == 0) -#ifdef CONFIG_ADB_PMU - if (sys_ctrler == SYS_CTRLER_PMU) - pmu_poll(); -#else - ; -#endif /* CONFIG_ADB_PMU */ + do_poll_adb(); buf_access(); - *p++ = *sccd; + *p++ = *sccd; } return i; } @@ -246,10 +259,7 @@ xmon_read_poll(void) { if ((*sccc & RXRDY) == 0) { -#ifdef CONFIG_ADB_PMU - if (sys_ctrler == SYS_CTRLER_PMU) - pmu_poll(); -#endif /* CONFIG_ADB_PMU */ + do_poll_adb(); return -1; } buf_access(); @@ -490,4 +500,20 @@ } *p = 0; return str; +} + +void +xmon_enter(void) +{ +#ifdef CONFIG_ADB_PMU + pmu_suspend(); +#endif +} + +void +xmon_leave(void) +{ +#ifdef CONFIG_ADB_PMU + pmu_resume(); +#endif } diff -u --recursive --new-file v2.4.0-test8/linux/arch/ppc/xmon/xmon.c linux/arch/ppc/xmon/xmon.c --- v2.4.0-test8/linux/arch/ppc/xmon/xmon.c Thu Jul 13 09:42:51 2000 +++ linux/arch/ppc/xmon/xmon.c Sun Sep 17 09:48:07 2000 @@ -6,15 +6,23 @@ #include #include #include +#include #include #include #include +#include #include "nonstdio.h" #include "privinst.h" #define scanhex xmon_scanhex #define skipbl xmon_skipbl +#ifdef CONFIG_SMP +static unsigned long cpus_in_xmon = 0; +static unsigned long got_xmon = 0; +static volatile int take_xmon = -1; +#endif /* CONFIG_SMP */ + static unsigned adrs; static int size = 1; static unsigned ndump = 64; @@ -84,6 +92,9 @@ static struct bpt *at_breakpoint(unsigned pc); static void bpt_cmds(void); static void cacheflush(void); +#ifdef CONFIG_SMP +static void cpu_cmd(void); +#endif /* CONFIG_SMP */ #if 0 /* Makes compile with -Wall */ static char *pretty_print_addr(unsigned long addr); static char *lookup_name(unsigned long addr); @@ -96,8 +107,18 @@ extern int setjmp(u_int *); extern void longjmp(u_int *, int); +extern void xmon_enter(void); +extern void xmon_leave(void); + #define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3]) +#define isxdigit(c) (('0' <= (c) && (c) <= '9') \ + || ('a' <= (c) && (c) <= 'f') \ + || ('A' <= (c) && (c) <= 'F')) +#define isalnum(c) (('0' <= (c) && (c) <= '9') \ + || ('a' <= (c) && (c) <= 'z') \ + || ('A' <= (c) && (c) <= 'Z')) + static char *help_string = "\ Commands:\n\ d dump bytes\n\ @@ -117,10 +138,12 @@ x exit monitor\n\ "; -static int xmon_trace; +static int xmon_trace[NR_CPUS]; #define SSTEP 1 /* stepping because of 's' command */ #define BRSTEP 2 /* stepping over breakpoint */ +static struct pt_regs *xmon_regs[NR_CPUS]; + void xmon(struct pt_regs *excp) { @@ -143,27 +166,52 @@ msr = get_msr(); set_msr(msr & ~0x8000); /* disable interrupts */ - remove_bpts(); + xmon_regs[smp_processor_id()] = excp; + xmon_enter(); excprint(excp); +#ifdef CONFIG_SMP + if (test_and_set_bit(smp_processor_id(), &cpus_in_xmon)) + for (;;) + ; + while (test_and_set_bit(0, &got_xmon)) { + if (take_xmon == smp_processor_id()) { + take_xmon = -1; + break; + } + } + /* + * XXX: breakpoints are removed while any cpu is in xmon + */ +#endif /* CONFIG_SMP */ + remove_bpts(); cmd = cmds(excp); if (cmd == 's') { - xmon_trace = SSTEP; + xmon_trace[smp_processor_id()] = SSTEP; excp->msr |= 0x400; } else if (at_breakpoint(excp->nip)) { - xmon_trace = BRSTEP; + xmon_trace[smp_processor_id()] = BRSTEP; excp->msr |= 0x400; } else { - xmon_trace = 0; + xmon_trace[smp_processor_id()] = 0; insert_bpts(); } + xmon_leave(); + xmon_regs[smp_processor_id()] = 0; +#ifdef CONFIG_SMP + clear_bit(0, &got_xmon); + clear_bit(smp_processor_id(), &cpus_in_xmon); +#endif /* CONFIG_SMP */ set_msr(msr); /* restore interrupt enable */ } void xmon_irq(int irq, void *d, struct pt_regs *regs) { + unsigned long flags; + save_flags(flags);cli(); printf("Keyboard interrupt\n"); xmon(regs); + restore_flags(flags); } int @@ -178,7 +226,7 @@ --bp->count; remove_bpts(); excprint(regs); - xmon_trace = BRSTEP; + xmon_trace[smp_processor_id()] = BRSTEP; regs->msr |= 0x400; } else { xmon(regs); @@ -189,10 +237,10 @@ int xmon_sstep(struct pt_regs *regs) { - if (!xmon_trace) + if (!xmon_trace[smp_processor_id()]) return 0; - if (xmon_trace == BRSTEP) { - xmon_trace = 0; + if (xmon_trace[smp_processor_id()] == BRSTEP) { + xmon_trace[smp_processor_id()] = 0; insert_bpts(); } else { xmon(regs); @@ -207,7 +255,7 @@ --dabr.count; remove_bpts(); excprint(regs); - xmon_trace = BRSTEP; + xmon_trace[smp_processor_id()] = BRSTEP; regs->msr |= 0x400; } else { dabr.instr = regs->nip; @@ -223,7 +271,7 @@ --iabr.count; remove_bpts(); excprint(regs); - xmon_trace = BRSTEP; + xmon_trace[smp_processor_id()] = BRSTEP; regs->msr |= 0x400; } else { xmon(regs); @@ -264,6 +312,7 @@ bp->address); bp->enabled = 0; } + store_inst((void *) bp->address); } #if !defined(CONFIG_8xx) && !defined(CONFIG_POWER4) if (dabr.enabled) @@ -293,6 +342,7 @@ && mwrite(bp->address, &bp->instr, 4) != 4) printf("Couldn't remove breakpoint at %x\n", bp->address); + store_inst((void *) bp->address); } } @@ -306,6 +356,9 @@ last_cmd = NULL; for(;;) { +#ifdef CONFIG_SMP + printf("%d:", smp_processor_id()); +#endif /* CONFIG_SMP */ printf("mon> "); fflush(stdout); flush_input(); @@ -383,12 +436,67 @@ case 'b': bpt_cmds(); break; - case 'c': + case 'C': csum(); break; +#ifdef CONFIG_SMP + case 'c': + cpu_cmd(); + break; +#endif /* CONFIG_SMP */ + } + } +} + +#ifdef CONFIG_SMP +static void cpu_cmd(void) +{ + unsigned cpu; + int timeout; + int cmd; + + cmd = inchar(); + if (cmd == 'i') { + /* interrupt other cpu(s) */ + cpu = MSG_ALL_BUT_SELF; + scanhex(&cpu); + smp_send_xmon_break(cpu); + return; + } + termch = cmd; + if (!scanhex(&cpu)) { + /* print cpus waiting or in xmon */ + printf("cpus stopped:"); + for (cpu = 0; cpu < NR_CPUS; ++cpu) { + if (test_bit(cpu, &cpus_in_xmon)) { + printf(" %d", cpu); + if (cpu == smp_processor_id()) + printf("*", cpu); + } + } + printf("\n"); + return; + } + /* try to switch to cpu specified */ + take_xmon = cpu; + timeout = 10000000; + while (take_xmon >= 0) { + if (--timeout == 0) { + /* yes there's a race here */ + take_xmon = -1; + printf("cpu %u didn't take control\n", cpu); + return; + } + } + /* now have to wait to be given control back */ + while (test_and_set_bit(0, &got_xmon)) { + if (take_xmon == smp_processor_id()) { + take_xmon = -1; + break; } } } +#endif /* CONFIG_SMP */ static unsigned short fcstab[256] = { 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, @@ -551,6 +659,8 @@ extern char lost_irq_ret, do_bottom_half_ret, do_signal_ret; extern char ret_from_except; + printf("backtrace:\n"); + if (excp != NULL) sp = excp->gpr[1]; else @@ -592,6 +702,9 @@ void excprint(struct pt_regs *fp) { +#ifdef CONFIG_SMP + printf("cpu %d: ", smp_processor_id()); +#endif /* CONFIG_SMP */ printf("vector: %x at pc = %x", fp->trap, fp->nip); printf(", lr = %x, msr = %x, sp = %x [%x]\n", @@ -1163,9 +1276,6 @@ return c; } -#define isxdigit(c) (('0' <= (c) && (c) <= '9') \ - || ('a' <= (c) && (c) <= 'f') \ - || ('A' <= (c) && (c) <= 'F')) void dump() { @@ -1402,6 +1512,16 @@ return c; } +#define N_PTREGS 44 +static char *regnames[N_PTREGS] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", + "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", + "pc", "msr", "or3", "ctr", "lr", "xer", "ccr", "mq", + "trap", "dar", "dsisr", "res" +}; + int scanhex(vp) unsigned *vp; @@ -1410,6 +1530,36 @@ unsigned v; c = skipbl(); + if (c == '%') { + /* parse register name */ + char regname[8]; + int i; + + for (i = 0; i < sizeof(regname) - 1; ++i) { + c = inchar(); + if (!isalnum(c)) { + termch = c; + break; + } + regname[i] = c; + } + regname[i] = 0; + for (i = 0; i < N_PTREGS; ++i) { + if (strcmp(regnames[i], regname) == 0) { + unsigned *rp = (unsigned *) + xmon_regs[smp_processor_id()]; + if (rp == NULL) { + printf("regs not available\n"); + return 0; + } + *vp = rp[i]; + return 1; + } + } + printf("invalid register name '%%%s'\n", regname); + return 0; + } + d = hexdigit(c); if( d == EOF ){ termch = c; diff -u --recursive --new-file v2.4.0-test8/linux/arch/sh/boot/compressed/Makefile linux/arch/sh/boot/compressed/Makefile --- v2.4.0-test8/linux/arch/sh/boot/compressed/Makefile Wed Aug 9 13:59:04 2000 +++ linux/arch/sh/boot/compressed/Makefile Mon Oct 2 11:57:33 2000 @@ -36,7 +36,7 @@ $(OBJCOPY) -R .empty_zero_page $(SYSTEM) $$tmppiggy; \ gzip -f -9 < $$tmppiggy > $$tmppiggy.gz; \ echo "SECTIONS { .data : { input_len = .; LONG(input_data_end - input_data) input_data = .; *(.data) input_data_end = .; }}" > $$tmppiggy.lnk; \ - $(LD) -r -o piggy.o -b binary $$tmppiggy.gz -b elf32-shl -T $$tmppiggy.lnk; \ + $(LD) -r -o piggy.o -b binary $$tmppiggy.gz -b elf32-sh-linux -T $$tmppiggy.lnk; \ rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk clean: diff -u --recursive --new-file v2.4.0-test8/linux/arch/sh/config.in linux/arch/sh/config.in --- v2.4.0-test8/linux/arch/sh/config.in Wed Aug 9 13:59:04 2000 +++ linux/arch/sh/config.in Tue Sep 19 10:57:30 2000 @@ -123,6 +123,8 @@ source drivers/block/Config.in +source drivers/md/Config.in + if [ "$CONFIG_NET" = "y" ]; then source net/Config.in fi diff -u --recursive --new-file v2.4.0-test8/linux/arch/sh/kernel/entry.S linux/arch/sh/kernel/entry.S --- v2.4.0-test8/linux/arch/sh/kernel/entry.S Fri Aug 11 14:29:05 2000 +++ linux/arch/sh/kernel/entry.S Mon Oct 2 11:57:34 2000 @@ -14,7 +14,12 @@ #include #include -#define COMPAT_OLD_SYSCALL_ABI 1 + +/* + * Define this to turn on compatibility with the previous + * system call ABI. This feature is not properly maintained. + */ +#undef COMPAT_OLD_SYSCALL_ABI ! NOTE: ! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address @@ -28,6 +33,12 @@ * NOTE: This code handles signal-recognition, which happens every time * after a timer-interrupt and after each system call. * + * NOTE: This code uses a convention that instructions in the delay slot + * of a transfer-control instruction are indented by an extra space, thus: + * + * jmp @$k0 ! control-transfer instruction + * ldc $k1, $ssr ! delay slot + * * Stack layout in 'ret_from_syscall': * ptrace needs to have all regs on the stack. * if the order here is changed, it needs to be @@ -58,6 +69,7 @@ PF_USEDFPU = 0x00100000 ENOSYS = 38 +EINVAL = 22 #if defined(__sh3__) TRA = 0xffffffd0 @@ -76,7 +88,14 @@ #endif /* Offsets to the stack */ -R0 = 0 /* Return value */ +R0 = 0 /* Return value. New ABI also arg4 */ +R1 = 4 /* New ABI: arg5 */ +R2 = 8 /* New ABI: arg6 */ +R3 = 12 /* New ABI: syscall_nr */ +R4 = 16 /* New ABI: arg0 */ +R5 = 20 /* New ABI: arg1 */ +R6 = 24 /* New ABI: arg2 */ +R7 = 28 /* New ABI: arg3 */ SP = (15*4) SR = (16*4+8) SYSCALL_NR = (16*4+6*4) @@ -132,7 +151,6 @@ tlb_miss_load: mov.l 2f, $r0 mov.l @$r0, $r6 - STI() mov $r15, $r4 mov.l 1f, $r0 jmp @$r0 @@ -142,7 +160,6 @@ tlb_miss_store: mov.l 2f, $r0 mov.l @$r0, $r6 - STI() mov $r15, $r4 mov.l 1f, $r0 jmp @$r0 @@ -152,7 +169,6 @@ initial_page_write: mov.l 2f, $r0 mov.l @$r0, $r6 - STI() mov $r15, $r4 mov.l 1f, $r0 jmp @$r0 @@ -162,7 +178,6 @@ tlb_protection_violation_load: mov.l 2f, $r0 mov.l @$r0, $r6 - STI() mov $r15, $r4 mov.l 1f, $r0 jmp @$r0 @@ -172,14 +187,13 @@ tlb_protection_violation_store: mov.l 2f, $r0 mov.l @$r0, $r6 - STI() mov $r15, $r4 mov.l 1f, $r0 jmp @$r0 mov #1, $r5 .align 2 -1: .long SYMBOL_NAME(do_page_fault) +1: .long SYMBOL_NAME(__do_page_fault) 2: .long MMU_TEA #if defined(CONFIG_DEBUG_KERNEL_WITH_GDB_STUB) || defined(CONFIG_SH_STANDARD_BIOS) @@ -249,9 +263,6 @@ .align 2 1: .long SYMBOL_NAME(do_exception_error) -badsys: mov #-ENOSYS, $r0 - rts ! go to ret_from_syscall.. - mov.l $r0, @(R0,$r15) ! ! @@ -291,7 +302,7 @@ */ system_call: - mov.l 1f, $r9 + mov.l __TRA, $r9 mov.l @$r9, $r8 ! ! Is the trap argument >= 0x20? (TRA will be >= 0x80) @@ -304,122 +315,160 @@ mov #SYSCALL_NR, $r14 add $r15, $r14 ! - mov #0x40, $r9 #ifdef COMPAT_OLD_SYSCALL_ABI + mov #0x40, $r9 cmp/hs $r9, $r8 - mov $r0, $r10 - bf/s 0f - mov $r0, $r9 + bf/s old_abi_system_call + nop #endif ! New Syscall ABI add #-0x40, $r8 shlr2 $r8 shll8 $r8 - shll8 $r8 + shll8 $r8 ! $r8 = num_args<<16 mov $r3, $r10 or $r8, $r10 ! Encode syscall # and # of arguments - ! - mov $r3, $r9 - mov #0, $r8 -0: mov.l $r10, @$r14 ! set syscall_nr STI() - mov.l __n_sys, $r10 - cmp/hs $r10, $r9 - bt badsys ! -#ifdef COMPAT_OLD_SYSCALL_ABI - ! Build the stack frame if TRA > 0 - mov $r8, $r10 - cmp/pl $r10 - bf 0f - mov.l @(SP,$r15), $r0 ! get original stack -7: add #-4, $r10 -4: mov.l @($r0,$r10), $r1 ! May cause address error exception.. - mov.l $r1, @-$r15 - cmp/pl $r10 - bt 7b -#endif -0: stc $k_current, $r11 - mov.l @(tsk_ptrace,$r11), $r10 ! Is it trace? + stc $k_current, $r11 + mov.l @(tsk_ptrace,$r11), $r10 ! Is current PTRACE_SYSCALL'd? mov #PT_TRACESYS, $r11 tst $r11, $r10 bt 5f - ! Trace system call - mov #-ENOSYS, $r11 - mov.l $r11, @(R0,$r15) - ! Push up $R0--$R2, and $R4--$R7 - mov.l $r0, @-$r15 - mov.l $r1, @-$r15 - mov.l $r2, @-$r15 - mov.l $r4, @-$r15 - mov.l $r5, @-$r15 - mov.l $r6, @-$r15 - mov.l $r7, @-$r15 - ! - mov.l 2f, $r11 - jsr @$r11 + ! Yes it is traced. + mov.l __syscall_trace, $r11 ! Call syscall_trace() which notifies + jsr @$r11 ! superior (will chomp $R[0-7]) nop - ! Pop down $R0--$R2, and $R4--$R7 - mov.l @$r15+, $r7 - mov.l @$r15+, $r6 - mov.l @$r15+, $r5 - mov.l @$r15+, $r4 - mov.l @$r15+, $r2 - mov.l @$r15+, $r1 - mov.l @$r15+, $r0 - ! + ! Reload $R0-$R4 from kernel stack, where the + ! parent may have modified them using + ! ptrace(POKEUSR). (Note that $R0-$R2 are + ! used by the system call handler directly + ! from the kernel stack anyway, so don't need + ! to be reloaded here.) This allows the parent + ! to rewrite system calls and args on the fly. + mov.l @(R4,$r15), $r4 ! arg0 + mov.l @(R5,$r15), $r5 + mov.l @(R6,$r15), $r6 + mov.l @(R7,$r15), $r7 ! arg3 + mov.l @(R3,$r15), $r3 ! syscall_nr + ! Arrange for syscall_trace() to be called + ! again as the system call returns. mov.l __syscall_ret_trace, $r10 bra 6f lds $r10, $pr - ! + ! No it isn't traced. + ! Arrange for normal system call return. 5: mov.l __syscall_ret, $r10 lds $r10, $pr - ! -6: mov $r9, $r10 - shll2 $r10 ! x4 + ! Call the system call handler through the table. + ! (both normal and ptrace'd) + ! First check for bad syscall number +6: mov $r3, $r9 + mov.l __n_sys, $r10 + cmp/hs $r10, $r9 + bf 2f + ! Bad syscall number + rts ! go to syscall_ret or syscall_ret_trace + mov #-ENOSYS, $r0 + ! Good syscall number +2: shll2 $r9 ! x4 mov.l __sct, $r11 - add $r11, $r10 - mov.l @$r10, $r11 - jmp @$r11 + add $r11, $r9 + mov.l @$r9, $r11 + jmp @$r11 ! jump to specific syscall handler nop ! In case of trace - .align 2 -3: -#ifdef COMPAT_OLD_SYSCALL_ABI - add $r8, $r15 ! pop off the arguments -#endif +syscall_ret_trace: mov.l $r0, @(R0,$r15) ! save the return value - mov.l 2f, $r1 + mov.l __syscall_trace, $r1 mova SYMBOL_NAME(ret_from_syscall), $r0 - jmp @$r1 - lds $r0, $pr - .align 2 -1: .long TRA -2: .long SYMBOL_NAME(syscall_trace) -__n_sys: .long NR_syscalls -__sct: .long SYMBOL_NAME(sys_call_table) -__syscall_ret_trace: - .long 3b -__syscall_ret: - .long SYMBOL_NAME(syscall_ret) + jmp @$r1 ! Call syscall_trace() which notifies superior + lds $r0, $pr ! Then return to ret_from_syscall() + + #ifdef COMPAT_OLD_SYSCALL_ABI +! Handle old ABI system call. +! Note that ptrace(SYSCALL) is not supported for the old ABI. +! At this point: +! $r0, $r4-7 as per ABI +! $r8 = value of TRA register (= num_args<<2) +! $r14 = points to SYSCALL_NR in stack frame +old_abi_system_call: + mov $r0, $r9 ! Save system call number in $r9 + ! ! arrange for return which pops stack + mov.l __old_abi_syscall_ret, $r10 + lds $r10, $pr + ! Build the stack frame if TRA > 0 + mov $r8, $r10 + cmp/pl $r10 + bf 0f + mov.l @(SP,$r15), $r0 ! get original user stack +7: add #-4, $r10 +4: mov.l @($r0,$r10), $r1 ! May cause address error exception.. + mov.l $r1, @-$r15 + cmp/pl $r10 + bt 7b +0: + mov.l $r9, @$r14 ! set syscall_nr + STI() + ! Call the system call handler through the table. + ! First check for bad syscall number + mov.l __n_sys, $r10 + cmp/hs $r10, $r9 + bf 2f + ! Bad syscall number + rts ! return to old_abi_syscall_ret + mov #-ENOSYS, $r0 + ! Good syscall number +2: shll2 $r9 ! x4 + mov.l __sct, $r11 + add $r11, $r9 + mov.l @$r9, $r11 + jmp @$r11 ! call specific syscall handler, + nop + + .align 2 +__old_abi_syscall_ret: + .long old_abi_syscall_ret + + ! This code gets called on address error exception when copying + ! syscall arguments from user stack to kernel stack. It is + ! supposed to return -EINVAL through old_abi_syscall_ret, but it + ! appears to have been broken for a long time in that the $r0 + ! return value will be saved into the kernel stack relative to $r15 + ! but the value of $r15 is not correct partway through the loop. + ! So the user prog is returned its old $r0 value, not -EINVAL. + ! Greg Banks 28 Aug 2000. .section .fixup,"ax" fixup_syscall_argerr: + ! First get $r15 back to rts - mov.l 1f, $r0 -1: .long -22 ! -EINVAL -.previous + mov #-EINVAL, $r0 + .previous .section __ex_table, "a" .align 2 .long 4b,fixup_syscall_argerr -.previous + .previous #endif .align 2 +__TRA: .long TRA +__syscall_trace: + .long SYMBOL_NAME(syscall_trace) +__n_sys:.long NR_syscalls +__sct: .long SYMBOL_NAME(sys_call_table) +__syscall_ret_trace: + .long syscall_ret_trace +__syscall_ret: + .long SYMBOL_NAME(syscall_ret) + + + + .align 2 reschedule: mova SYMBOL_NAME(ret_from_syscall), $r0 mov.l 1f, $r1 @@ -454,10 +503,12 @@ .long 0xffffff0f ! ~(IMASK) .align 2 -syscall_ret: #ifdef COMPAT_OLD_SYSCALL_ABI +old_abi_syscall_ret: add $r8, $r15 ! pop off the arguments + /* fall through */ #endif +syscall_ret: mov.l $r0, @(R0,$r15) ! save the return value /* fall through */ @@ -707,7 +758,7 @@ #endif 8: /* User space to kernel */ mov #0x20, $k1 - shll8 $k1 ! $k1 <= 8192 + shll8 $k1 ! $k1 <= 8192 == THREAD_SIZE add $current, $k1 mov $k1, $r15 ! change to kernel stack ! @@ -1107,6 +1158,7 @@ .long SYMBOL_NAME(sys_mincore) .long SYMBOL_NAME(sys_madvise) .long SYMBOL_NAME(sys_getdents64) /* 220 */ + .long SYMBOL_NAME(sys_fcntl64) /* * NOTE!! This doesn't have to be exact - we just have @@ -1114,7 +1166,7 @@ * entries. Don't panic if you notice that this hasn't * been shrunk every time we add a new system call. */ - .rept NR_syscalls-220 + .rept NR_syscalls-221 .long SYMBOL_NAME(sys_ni_syscall) .endr diff -u --recursive --new-file v2.4.0-test8/linux/arch/sh/kernel/head.S linux/arch/sh/kernel/head.S --- v2.4.0-test8/linux/arch/sh/kernel/head.S Mon Apr 24 13:54:17 2000 +++ linux/arch/sh/kernel/head.S Mon Oct 2 11:57:34 2000 @@ -21,9 +21,9 @@ .long 0x00360000 /* INITRD_START */ .long 0x000a0000 /* INITRD_SIZE */ .long 0 + .balign 4096,0,4096 .text - .balign 4096,0,4096 /* * Condition at the entry of _stext: * diff -u --recursive --new-file v2.4.0-test8/linux/arch/sh/kernel/io.c linux/arch/sh/kernel/io.c --- v2.4.0-test8/linux/arch/sh/kernel/io.c Thu Aug 10 13:03:25 2000 +++ linux/arch/sh/kernel/io.c Mon Oct 2 11:57:34 2000 @@ -1,5 +1,5 @@ /* - * linux/arch/sh/kernel/io_generic.c + * linux/arch/sh/kernel/io.c * * Copyright (C) 2000 Stuart Menefy * diff -u --recursive --new-file v2.4.0-test8/linux/arch/sh/kernel/irq_imask.c linux/arch/sh/kernel/irq_imask.c --- v2.4.0-test8/linux/arch/sh/kernel/irq_imask.c Wed Aug 9 13:59:04 2000 +++ linux/arch/sh/kernel/irq_imask.c Mon Oct 2 11:57:34 2000 @@ -41,7 +41,7 @@ static unsigned int startup_imask_irq(unsigned int irq) { - enable_imask_irq(irq); + /* Nothing to do */ return 0; /* never anything pending */ } @@ -71,7 +71,8 @@ "ldc %0, $sr\n" "1:" : "=&z" (__dummy) - : "r" (~0xf0), "r" (ip << 4)); + : "r" (~0xf0), "r" (ip << 4) + : "t"); } static void disable_imask_irq(unsigned int irq) @@ -103,7 +104,7 @@ static void shutdown_imask_irq(unsigned int irq) { - disable_imask_irq(irq); + /* Nothing to do */ } void make_imask_irq(unsigned int irq) diff -u --recursive --new-file v2.4.0-test8/linux/arch/sh/kernel/irq_ipr.c linux/arch/sh/kernel/irq_ipr.c --- v2.4.0-test8/linux/arch/sh/kernel/irq_ipr.c Wed Aug 9 13:59:04 2000 +++ linux/arch/sh/kernel/irq_ipr.c Mon Oct 2 11:57:34 2000 @@ -128,12 +128,14 @@ #ifdef SCIF_ERI_IRQ make_ipr_irq(SCIF_ERI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY); make_ipr_irq(SCIF_RXI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY); + make_ipr_irq(SCIF_BRI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY); make_ipr_irq(SCIF_TXI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY); #endif #ifdef IRDA_ERI_IRQ make_ipr_irq(IRDA_ERI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY); make_ipr_irq(IRDA_RXI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY); + make_ipr_irq(IRDA_BRI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY); make_ipr_irq(IRDA_TXI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY); #endif diff -u --recursive --new-file v2.4.0-test8/linux/arch/sh/kernel/process.c linux/arch/sh/kernel/process.c --- v2.4.0-test8/linux/arch/sh/kernel/process.c Tue Sep 5 13:50:01 2000 +++ linux/arch/sh/kernel/process.c Mon Oct 2 11:57:34 2000 @@ -136,11 +136,12 @@ */ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) { /* Don't use this in BL=1(cli). Or else, CPU resets! */ - register unsigned long __sc0 __asm__ ("$r3") = __NR_clone; - register unsigned long __sc4 __asm__ ("$r4") = (long) flags | CLONE_VM; - register unsigned long __sc5 __asm__ ("$r5") = 0; - register unsigned long __sc8 __asm__ ("$r8") = (long) arg; - register unsigned long __sc9 __asm__ ("$r9") = (long) fn; + register unsigned long __sc0 __asm__ ("r0"); + register unsigned long __sc3 __asm__ ("r3") = __NR_clone; + register unsigned long __sc4 __asm__ ("r4") = (long) flags | CLONE_VM; + register unsigned long __sc5 __asm__ ("r5") = 0; + register unsigned long __sc8 __asm__ ("r8") = (long) arg; + register unsigned long __sc9 __asm__ ("r9") = (long) fn; __asm__("trapa #0x12\n\t" /* Linux/SH system call */ "tst #0xff, $r0\n\t" /* child or parent? */ @@ -148,13 +149,13 @@ "jsr @$r9\n\t" /* call fn */ " mov $r8, $r4\n\t" /* push argument */ "mov $r0, $r4\n\t" /* return value to arg of exit */ - "mov %2, $r3\n\t" /* exit */ + "mov %1, $r3\n\t" /* exit */ "trapa #0x11\n" "1:" : "=z" (__sc0) - : "0" (__sc0), "i" (__NR_exit), - "r" (__sc4), "r" (__sc5), "r" (__sc8), "r" (__sc9) - : "memory"); + : "i" (__NR_exit), "r" (__sc3), "r" (__sc4), "r" (__sc5), + "r" (__sc8), "r" (__sc9) + : "memory", "t"); return __sc0; } diff -u --recursive --new-file v2.4.0-test8/linux/arch/sh/kernel/setup_cqreek.c linux/arch/sh/kernel/setup_cqreek.c --- v2.4.0-test8/linux/arch/sh/kernel/setup_cqreek.c Thu Aug 10 13:03:25 2000 +++ linux/arch/sh/kernel/setup_cqreek.c Mon Oct 2 11:57:34 2000 @@ -1,4 +1,4 @@ -/* $Id: setup_cqreek.c,v 1.1 2000/08/05 06:25:23 gniibe Exp $ +/* $Id: setup_cqreek.c,v 1.5 2000/09/18 05:51:24 gniibe Exp $ * * arch/sh/kernel/setup_cqreek.c * @@ -44,15 +44,24 @@ return ISA_OFFSET + port; } +struct cqreek_irq_data { + unsigned short mask_port; /* Port of Interrupt Mask Register */ + unsigned short stat_port; /* Port of Interrupt Status Register */ + unsigned short bit; /* Value of the bit */ +}; +static struct cqreek_irq_data cqreek_irq_data[NR_IRQS]; + static void disable_cqreek_irq(unsigned int irq) { unsigned long flags; unsigned short mask; + unsigned short mask_port = cqreek_irq_data[irq].mask_port; + unsigned short bit = cqreek_irq_data[irq].bit; save_and_cli(flags); /* Disable IRQ */ - mask = inw(BRIDGE_ISA_INTR_MASK) & ~(1 << irq); - outw_p(mask, BRIDGE_ISA_INTR_MASK); + mask = inw(mask_port) & ~bit; + outw_p(mask, mask_port); restore_flags(flags); } @@ -60,32 +69,29 @@ { unsigned long flags; unsigned short mask; + unsigned short mask_port = cqreek_irq_data[irq].mask_port; + unsigned short bit = cqreek_irq_data[irq].bit; save_and_cli(flags); /* Enable IRQ */ - mask = inw(BRIDGE_ISA_INTR_MASK) | (1 << irq); - outw_p(mask, BRIDGE_ISA_INTR_MASK); + mask = inw(mask_port) | bit; + outw_p(mask, mask_port); restore_flags(flags); } -#define CLEAR_AT_ACCEPT - static void mask_and_ack_cqreek(unsigned int irq) { - inw(BRIDGE_ISA_INTR_STAT); + unsigned short stat_port = cqreek_irq_data[irq].stat_port; + unsigned short bit = cqreek_irq_data[irq].bit; + + inw(stat_port); disable_cqreek_irq(irq); -#ifdef CLEAR_AT_ACCEPT /* Clear IRQ (it might be edge IRQ) */ - outw_p((1< #include #include +#include extern void dump_thread(struct pt_regs *, struct user *); extern int dump_fpu(elf_fpregset_t *); @@ -35,7 +36,35 @@ EXPORT_SYMBOL(strtok); EXPORT_SYMBOL(strpbrk); EXPORT_SYMBOL(strstr); +EXPORT_SYMBOL(strlen); + +/* mem exports */ +EXPORT_SYMBOL(memcpy); +EXPORT_SYMBOL(memset); +EXPORT_SYMBOL(memmove); + +/* this is not provided by arch/sh/lib/*.S but is + potentially needed by modules (af_packet.o/unix.o + use memcmp, for instance) */ +EXPORT_SYMBOL(memcmp); #ifdef CONFIG_VT EXPORT_SYMBOL(screen_info); +#endif + + +#define DECLARE_EXPORT(name) extern void name(void);EXPORT_SYMBOL_NOVERS(name) + +/* These symbols are generated by the compiler itself */ +#ifdef __SH4__ + +DECLARE_EXPORT(__udivsi3_i4); +DECLARE_EXPORT(__sdivsi3_i4); +DECLARE_EXPORT(__movstr_i4_even); +DECLARE_EXPORT(__movstr_i4_odd); +DECLARE_EXPORT(__ashrdi3); +DECLARE_EXPORT(__ashldi3); + +/* needed by some modules */ +EXPORT_SYMBOL(flush_dcache_page); #endif diff -u --recursive --new-file v2.4.0-test8/linux/arch/sh/kernel/time.c linux/arch/sh/kernel/time.c --- v2.4.0-test8/linux/arch/sh/kernel/time.c Wed Aug 9 13:59:04 2000 +++ linux/arch/sh/kernel/time.c Mon Oct 2 11:57:34 2000 @@ -274,37 +274,6 @@ write_unlock(&xtime_lock); } -/* Converts Gregorian date to seconds since 1970-01-01 00:00:00. - * Assumes input in normal date format, i.e. 1980-12-31 23:59:59 - * => year=1980, mon=12, day=31, hour=23, min=59, sec=59. - * - * [For the Julian calendar (which was used in Russia before 1917, - * Britain & colonies before 1752, anywhere else before 1582, - * and is still in use by some communities) leave out the - * -year/100+year/400 terms, and add 10.] - * - * This algorithm was first published by Gauss (I think). - * - * WARNING: this function will overflow on 2106-02-07 06:28:16 on - * machines were long is 32-bit! (However, as time_t is signed, we - * will already get problems at other places on 2038-01-19 03:14:08) - */ -static inline unsigned long mktime(unsigned int year, unsigned int mon, - unsigned int day, unsigned int hour, - unsigned int min, unsigned int sec) -{ - if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */ - mon += 12; /* Puts Feb last since it has leap day */ - year -= 1; - } - return ((( - (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) + - year*365 - 719499 - )*24 + hour /* now have hours */ - )*60 + min /* now have minutes */ - )*60 + sec; /* finally seconds */ -} - static unsigned long get_rtc_time(void) { unsigned int sec, min, hr, wk, day, mon, yr, yr100; @@ -373,7 +342,8 @@ "bt/s 1b\n\t" " add #1,%0" : "=r"(count), "=z" (__dummy) - : "0" (0), "1" (0)); + : "0" (0), "1" (0) + : "t"); cli(); /* * SH-3: diff -u --recursive --new-file v2.4.0-test8/linux/arch/sh/kernel/traps.c linux/arch/sh/kernel/traps.c --- v2.4.0-test8/linux/arch/sh/kernel/traps.c Mon Apr 24 13:54:17 2000 +++ linux/arch/sh/kernel/traps.c Mon Oct 2 11:57:34 2000 @@ -131,9 +131,16 @@ asm("mov $r15, %0" : "=r" (start)); asm("stc $r7_bank, %0" : "=r" (end)); - end += 8192; + end += 8192/4; printk("%08lx:%08lx\n", (unsigned long)start, (unsigned long)end); - for (p=start; p < end; p++) - printk("%08lx\n", *p); + for (p=start; p < end; p++) { + extern long _text, _etext; + unsigned long v=*p; + + if ((v >= (unsigned long )&_text) + && (v <= (unsigned long )&_etext)) { + printk("%08lx\n", v); + } + } } diff -u --recursive --new-file v2.4.0-test8/linux/arch/sh/lib/checksum.S linux/arch/sh/lib/checksum.S --- v2.4.0-test8/linux/arch/sh/lib/checksum.S Wed Aug 9 13:59:04 2000 +++ linux/arch/sh/lib/checksum.S Mon Oct 2 11:57:34 2000 @@ -159,14 +159,14 @@ * them all but there's no guarantee. */ -#define SRC(y...) \ - 9999: y; \ +#define SRC(x,y) \ + 9999: x,y; \ .section __ex_table, "a"; \ .long 9999b, 6001f ; \ .previous -#define DST(y...) \ - 9999: y; \ +#define DST(x,y) \ + 9999: x,y; \ .section __ex_table, "a"; \ .long 9999b, 6002f ; \ .previous @@ -276,7 +276,7 @@ DST( mov.l r1,@r5 ) add #4,r5 -SRC( mov.l @r4+,r0 ) +SRC( mov.l @r4+,r0 ) SRC( mov.l @r4+,r1 ) addc r0,r7 DST( mov.l r0,@r5 ) diff -u --recursive --new-file v2.4.0-test8/linux/arch/sh/mm/cache.c linux/arch/sh/mm/cache.c --- v2.4.0-test8/linux/arch/sh/mm/cache.c Wed Aug 9 13:59:04 2000 +++ linux/arch/sh/mm/cache.c Mon Oct 2 11:57:34 2000 @@ -64,9 +64,9 @@ #define CACHE_IC_WAY_SHIFT 13 #define CACHE_OC_ENTRY_SHIFT 5 #define CACHE_IC_ENTRY_SHIFT 5 -#define CACHE_OC_ENTRY_MASK 0x3fe0 -#define CACHE_OC_ENTRY_PHYS_MASK 0x0fe0 -#define CACHE_IC_ENTRY_MASK 0x1fe0 +#define CACHE_OC_ENTRY_MASK 0x3fe0 +#define CACHE_OC_ENTRY_PHYS_MASK 0x0fe0 +#define CACHE_IC_ENTRY_MASK 0x1fe0 #define CACHE_IC_NUM_ENTRIES 256 #define CACHE_OC_NUM_ENTRIES 512 #define CACHE_OC_NUM_WAYS 1 @@ -92,7 +92,8 @@ addr = CACHE_OC_ADDRESS_ARRAY|(j<>CACHE_OC_ENTRY_SHIFT; jump_to_P2(); /* Loop all the D-cache */ for (i=0; i extern void die(const char *,struct pt_regs *,long); -static void __flush_tlb_page(struct mm_struct *mm, unsigned long page); +static void __flush_tlb_page(unsigned long asid, unsigned long page); #if defined(__SH4__) -static void __flush_tlb_phys(struct mm_struct *mm, unsigned long phys); +static void __flush_tlb_phys(unsigned long phys); #endif /* @@ -85,42 +85,6 @@ return 0; } -static void handle_vmalloc_fault(struct mm_struct *mm, unsigned long address) -{ - pgd_t *dir; - pmd_t *pmd; - pte_t *pte; - pte_t entry; - - dir = pgd_offset_k(address); - pmd = pmd_offset(dir, address); - if (pmd_none(*pmd)) { - printk(KERN_ERR "vmalloced area %08lx bad\n", address); - return; - } - if (pmd_bad(*pmd)) { - pmd_ERROR(*pmd); - pmd_clear(pmd); - return; - } - pte = pte_offset(pmd, address); - entry = *pte; - if (pte_none(entry) || !pte_present(entry) || !pte_write(entry)) { - printk(KERN_ERR "vmalloced area %08lx bad\n", address); - return; - } - -#if defined(__SH4__) - /* - * ITLB is not affected by "ldtlb" instruction. - * So, we need to flush the entry by ourselves. - */ - if (mm) - __flush_tlb_page(mm, address&PAGE_MASK); -#endif - update_mmu_cache(NULL, address, entry); -} - /* * This routine handles page faults. It determines the address, * and the problem, and then passes it off to one of the appropriate @@ -138,11 +102,6 @@ tsk = current; mm = tsk->mm; - if (address >= VMALLOC_START && address < VMALLOC_END) { - handle_vmalloc_fault(mm, address); - return; - } - /* * If we're in an interrupt or have no user * context, we must not take the fault.. @@ -272,6 +231,67 @@ goto no_context; } +static int __do_page_fault1(struct pt_regs *regs, unsigned long writeaccess, + unsigned long address) +{ + pgd_t *dir; + pmd_t *pmd; + pte_t *pte; + pte_t entry; + + if (address >= VMALLOC_START && address < VMALLOC_END) + /* We can change the implementation of P3 area pte entries. + set_pgdir and such. */ + dir = pgd_offset_k(address); + else + dir = pgd_offset(current->mm, address); + + pmd = pmd_offset(dir, address); + if (pmd_none(*pmd)) + return 1; + if (pmd_bad(*pmd)) { + pmd_ERROR(*pmd); + pmd_clear(pmd); + return 1; + } + pte = pte_offset(pmd, address); + entry = *pte; + if (pte_none(entry) || !pte_present(entry) + || (writeaccess && !pte_write(entry))) + return 1; + + if (writeaccess) + entry = pte_mkdirty(entry); + entry = pte_mkyoung(entry); +#if defined(__SH4__) + /* + * ITLB is not affected by "ldtlb" instruction. + * So, we need to flush the entry by ourselves. + */ + __flush_tlb_page(get_asid(), address&PAGE_MASK); +#endif + set_pte(pte, entry); + update_mmu_cache(NULL, address, entry); + return 0; +} + +/* + * Called with interrupt disabled. + */ +asmlinkage void __do_page_fault(struct pt_regs *regs, unsigned long writeaccess, + unsigned long address) +{ + /* + * XXX: Could you please implement this (calling __do_page_fault1) + * in assembler language in entry.S? + */ + if (__do_page_fault1(regs, writeaccess, address) == 0) + /* Done. */ + return; + sti(); + do_page_fault(regs, writeaccess, address); +} + void update_mmu_cache(struct vm_area_struct * vma, unsigned long address, pte_t pte) { @@ -282,28 +302,30 @@ save_and_cli(flags); #if defined(__SH4__) - if (vma && (vma->vm_flags & VM_SHARED)) { + if (pte_shared(pte)) { struct page *pg; pteval = pte_val(pte); pteval &= PAGE_MASK; /* Physicall page address */ - __flush_tlb_phys(vma->vm_mm, pteval); + __flush_tlb_phys(pteval); pg = virt_to_page(__va(pteval)); flush_dcache_page(pg); } #endif - /* Set PTEH register */ - if (vma) { - pteaddr = (address & MMU_VPN_MASK) | - (vma->vm_mm->context & MMU_CONTEXT_ASID_MASK); - ctrl_outl(pteaddr, MMU_PTEH); + /* Ptrace may call this routine. */ + if (vma && current->active_mm != vma->vm_mm) { + restore_flags(flags); + return; } + /* Set PTEH register */ + pteaddr = (address & MMU_VPN_MASK) | get_asid(); + ctrl_outl(pteaddr, MMU_PTEH); + /* Set PTEL register */ pteval = pte_val(pte); pteval &= _PAGE_FLAGS_HARDWARE_MASK; /* drop software flags */ - pteval |= _PAGE_FLAGS_HARDWARE_DEFAULT; /* add default flags */ ctrl_outl(pteval, MMU_PTEL); /* Load the TLB */ @@ -311,24 +333,16 @@ restore_flags(flags); } -static void __flush_tlb_page(struct mm_struct *mm, unsigned long page) +static void __flush_tlb_page(unsigned long asid, unsigned long page) { - unsigned long addr, data, asid; - unsigned long saved_asid = MMU_NO_ASID; - - if (mm->context == NO_CONTEXT) - return; - - asid = mm->context & MMU_CONTEXT_ASID_MASK; - if (mm != current->mm) { - saved_asid = get_asid(); - /* - * We need to set ASID of the target entry to flush, - * because TLB is indexed by (ASID and PAGE). - */ - set_asid(asid); - } + unsigned long addr, data; + /* + * NOTE: PTEH.ASID should be set to this MM + * _AND_ we need to write ASID to the array. + * + * It would be simple if we didn't need to set PTEH.ASID... + */ #if defined(__sh3__) addr = MMU_TLB_ADDRESS_ARRAY |(page & 0x1F000)| MMU_PAGE_ASSOC_BIT; data = (page & 0xfffe0000) | asid; /* VALID bit is off */ @@ -340,12 +354,10 @@ ctrl_outl(data, addr); back_to_P1(); #endif - if (saved_asid != MMU_NO_ASID) - set_asid(saved_asid); } #if defined(__SH4__) -static void __flush_tlb_phys(struct mm_struct *mm, unsigned long phys) +static void __flush_tlb_phys(unsigned long phys) { int i; unsigned long addr, data; @@ -373,12 +385,22 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long page) { - unsigned long flags; + if (vma->vm_mm && vma->vm_mm->context != NO_CONTEXT) { + unsigned long flags; + unsigned long asid; + unsigned long saved_asid = MMU_NO_ASID; - if (vma->vm_mm) { + asid = vma->vm_mm->context & MMU_CONTEXT_ASID_MASK; page &= PAGE_MASK; + save_and_cli(flags); - __flush_tlb_page(vma->vm_mm, page); + if (vma->vm_mm != current->mm) { + saved_asid = get_asid(); + set_asid(asid); + } + __flush_tlb_page(asid, page); + if (saved_asid != MMU_NO_ASID) + set_asid(saved_asid); restore_flags(flags); } } @@ -397,13 +419,22 @@ if (mm == current->mm) activate_context(mm); } else { + unsigned long asid = mm->context&MMU_CONTEXT_ASID_MASK; + unsigned long saved_asid = MMU_NO_ASID; + start &= PAGE_MASK; end += (PAGE_SIZE - 1); end &= PAGE_MASK; + if (mm != current->mm) { + saved_asid = get_asid(); + set_asid(asid); + } while (start < end) { - __flush_tlb_page(mm, start); + __flush_tlb_page(asid, start); start += PAGE_SIZE; } + if (saved_asid != MMU_NO_ASID) + set_asid(saved_asid); } restore_flags(flags); } diff -u --recursive --new-file v2.4.0-test8/linux/arch/sh/mm/init.c linux/arch/sh/mm/init.c --- v2.4.0-test8/linux/arch/sh/mm/init.c Thu Sep 7 08:44:50 2000 +++ linux/arch/sh/mm/init.c Mon Oct 2 11:57:34 2000 @@ -241,6 +241,7 @@ /* clear the zero-page */ memset(empty_zero_page, 0, PAGE_SIZE); + flush_page_to_ram(virt_to_page(empty_zero_page)); /* this will put all low memory onto the freelists */ totalram_pages += free_all_bootmem(); diff -u --recursive --new-file v2.4.0-test8/linux/arch/sh/vmlinux.lds.S linux/arch/sh/vmlinux.lds.S --- v2.4.0-test8/linux/arch/sh/vmlinux.lds.S Wed Aug 9 13:59:04 2000 +++ linux/arch/sh/vmlinux.lds.S Mon Oct 2 11:57:34 2000 @@ -4,9 +4,9 @@ */ #include #ifdef CONFIG_CPU_LITTLE_ENDIAN -OUTPUT_FORMAT("elf32-shl", "elf32-shl", "elf32-shl") +OUTPUT_FORMAT("elf32-sh-linux", "elf32-sh-linux", "elf32-sh-linux") #else -OUTPUT_FORMAT("elf32-sh", "elf32-sh", "elf32-sh") +OUTPUT_FORMAT("elf32-shbig-linux", "elf32-shbig-linux", "elf32-shbig-linux") #endif OUTPUT_ARCH(sh) ENTRY(_start) @@ -89,6 +89,7 @@ /DISCARD/ : { *(.text.exit) *(.data.exit) + *(.exitcall.exit) } /* Stabs debugging sections. */ diff -u --recursive --new-file v2.4.0-test8/linux/arch/sparc/config.in linux/arch/sparc/config.in --- v2.4.0-test8/linux/arch/sparc/config.in Wed Aug 23 09:30:13 2000 +++ linux/arch/sparc/config.in Tue Sep 19 10:59:52 2000 @@ -94,15 +94,7 @@ # bool ' LVM information in proc filesystem' CONFIG_LVM_PROC_FS Y #fi -tristate 'Multiple devices driver support' CONFIG_BLK_DEV_MD -dep_tristate ' Linear (append) mode' CONFIG_MD_LINEAR $CONFIG_BLK_DEV_MD -dep_tristate ' RAID-0 (striping) mode' CONFIG_MD_RAID0 $CONFIG_BLK_DEV_MD -dep_tristate ' RAID-1 (mirroring) mode' CONFIG_MD_RAID1 $CONFIG_BLK_DEV_MD -#dep_tristate ' RAID-4/RAID-5 mode' CONFIG_MD_RAID5 $CONFIG_BLK_DEV_MD -#if [ "$CONFIG_MD_LINEAR" = "y" -o "$CONFIG_MD_RAID0" = "y" -o "$CONFIG_MD_RAID1" = "y" -o "$CONFIG_MD_RAID5" = "y" ]; then -# bool ' Boot support' CONFIG_MD_BOOT -# bool ' Auto Detect support' CONFIG_AUTODETECT_RAID -#fi +include drivers/md/Config.in tristate 'RAM disk support' CONFIG_BLK_DEV_RAM if [ "$CONFIG_BLK_DEV_RAM" = "y" -o "$CONFIG_BLK_DEV_RAM" = "m" ]; then diff -u --recursive --new-file v2.4.0-test8/linux/arch/sparc/kernel/pcic.c linux/arch/sparc/kernel/pcic.c --- v2.4.0-test8/linux/arch/sparc/kernel/pcic.c Thu Sep 7 08:32:00 2000 +++ linux/arch/sparc/kernel/pcic.c Tue Oct 3 09:24:41 2000 @@ -1,4 +1,4 @@ -/* $Id: pcic.c,v 1.17 2000/09/05 06:49:44 anton Exp $ +/* $Id: pcic.c,v 1.18 2000/09/25 06:09:12 anton Exp $ * pcic.c: Sparc/PCI controller support * * Copyright (C) 1998 V. Roganov and G. Raiko @@ -35,11 +35,6 @@ #ifndef CONFIG_PCI -int pcibios_present(void) -{ - return 0; -} - asmlinkage int sys_pciconfig_read(unsigned long bus, unsigned long dfn, unsigned long off, @@ -976,7 +971,6 @@ if(!suser()) return -EPERM; - lock_kernel(); switch(len) { case 1: err = get_user(ubyte, (unsigned char *)buf); @@ -1004,7 +998,6 @@ break; }; - unlock_kernel(); return err; } diff -u --recursive --new-file v2.4.0-test8/linux/arch/sparc/kernel/sparc-stub.c linux/arch/sparc/kernel/sparc-stub.c --- v2.4.0-test8/linux/arch/sparc/kernel/sparc-stub.c Mon Jan 3 12:01:31 2000 +++ linux/arch/sparc/kernel/sparc-stub.c Sun Oct 1 20:35:15 2000 @@ -123,7 +123,7 @@ */ #define BUFMAX 2048 -static int initialized = 0; /* !0 means we've been initialized */ +static int initialized; /* !0 means we've been initialized */ static const char hexchars[]="0123456789abcdef"; diff -u --recursive --new-file v2.4.0-test8/linux/arch/sparc/kernel/time.c linux/arch/sparc/kernel/time.c --- v2.4.0-test8/linux/arch/sparc/kernel/time.c Mon Jun 19 17:59:38 2000 +++ linux/arch/sparc/kernel/time.c Sun Sep 17 10:01:49 2000 @@ -1,4 +1,4 @@ -/* $Id: time.c,v 1.56 2000/06/13 22:51:28 anton Exp $ +/* $Id: time.c,v 1.57 2000/09/16 07:33:45 davem Exp $ * linux/arch/sparc/kernel/time.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -147,37 +147,6 @@ last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ } write_unlock(&xtime_lock); -} - -/* Converts Gregorian date to seconds since 1970-01-01 00:00:00. - * Assumes input in normal date format, i.e. 1980-12-31 23:59:59 - * => year=1980, mon=12, day=31, hour=23, min=59, sec=59. - * - * [For the Julian calendar (which was used in Russia before 1917, - * Britain & colonies before 1752, anywhere else before 1582, - * and is still in use by some communities) leave out the - * -year/100+year/400 terms, and add 10.] - * - * This algorithm was first published by Gauss (I think). - * - * WARNING: this function will overflow on 2106-02-07 06:28:16 on - * machines were long is 32-bit! (However, as time_t is signed, we - * will already get problems at other places on 2038-01-19 03:14:08) - */ -static inline unsigned long mktime(unsigned int year, unsigned int mon, - unsigned int day, unsigned int hour, - unsigned int min, unsigned int sec) -{ - if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */ - mon += 12; /* Puts Feb last since it has leap day */ - year -= 1; - } - return ((( - (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) + - year*365 - 719499 - )*24 + hour /* now have hours */ - )*60 + min /* now have minutes */ - )*60 + sec; /* finally seconds */ } /* Kick start a stopped clock (procedure from the Sun NVRAM/hostid FAQ). */ diff -u --recursive --new-file v2.4.0-test8/linux/arch/sparc64/boot/piggyback.c linux/arch/sparc64/boot/piggyback.c --- v2.4.0-test8/linux/arch/sparc64/boot/piggyback.c Wed Jul 16 19:22:50 1997 +++ linux/arch/sparc64/boot/piggyback.c Tue Oct 3 09:24:41 2000 @@ -1,4 +1,4 @@ -/* $Id: piggyback.c,v 1.1 1997/07/11 11:05:26 jj Exp $ +/* $Id: piggyback.c,v 1.2 2000/09/19 14:34:39 anton Exp $ Simple utility to make a single-image install kernel with initial ramdisk for Sparc64 tftpbooting without need to set up nfs. @@ -50,9 +50,9 @@ map = fopen (argv[2], "r"); if (!map) die(argv[2]); while (fgets (buffer, 1024, map)) { - if (!strcmp (buffer + 19, "start\n")) + if (!strcmp (buffer + 19, "_start\n")) start = strtoul (buffer + 8, NULL, 16); - else if (!strcmp (buffer + 19, "end\n")) + else if (!strcmp (buffer + 19, "_end\n")) end = strtoul (buffer + 8, NULL, 16); } fclose (map); diff -u --recursive --new-file v2.4.0-test8/linux/arch/sparc64/config.in linux/arch/sparc64/config.in --- v2.4.0-test8/linux/arch/sparc64/config.in Wed Aug 23 09:30:13 2000 +++ linux/arch/sparc64/config.in Tue Sep 19 10:59:52 2000 @@ -94,15 +94,7 @@ # bool ' LVM information in proc filesystem' CONFIG_LVM_PROC_FS Y #fi -tristate 'Multiple devices driver support' CONFIG_BLK_DEV_MD -dep_tristate ' Linear (append) mode' CONFIG_MD_LINEAR $CONFIG_BLK_DEV_MD -dep_tristate ' RAID-0 (striping) mode' CONFIG_MD_RAID0 $CONFIG_BLK_DEV_MD -dep_tristate ' RAID-1 (mirroring) mode' CONFIG_MD_RAID1 $CONFIG_BLK_DEV_MD -#dep_tristate ' RAID-4/RAID-5 mode' CONFIG_MD_RAID5 $CONFIG_BLK_DEV_MD -#if [ "$CONFIG_MD_LINEAR" = "y" -o "$CONFIG_MD_RAID0" = "y" -o "$CONFIG_MD_RAID1" = "y" -o "$CONFIG_MD_RAID5" = "y" ]; then -# bool ' Boot support' CONFIG_MD_BOOT -# bool ' Auto Detect support' CONFIG_AUTODETECT_RAID -#fi +include drivers/md/Config.in tristate 'RAM disk support' CONFIG_BLK_DEV_RAM if [ "$CONFIG_BLK_DEV_RAM" = "y" -o "$CONFIG_BLK_DEV_RAM" = "m" ]; then diff -u --recursive --new-file v2.4.0-test8/linux/arch/sparc64/kernel/auxio.c linux/arch/sparc64/kernel/auxio.c --- v2.4.0-test8/linux/arch/sparc64/kernel/auxio.c Mon Dec 20 22:05:52 1999 +++ linux/arch/sparc64/kernel/auxio.c Tue Oct 3 09:24:41 2000 @@ -18,6 +18,7 @@ #include #include #include +#include /* Probe and map in the Auxiliary I/O register */ unsigned long auxio_register = 0; @@ -55,7 +56,7 @@ return; } #endif - if(central_bus) { + if(central_bus || this_is_starfire) { auxio_register = 0UL; return; } diff -u --recursive --new-file v2.4.0-test8/linux/arch/sparc64/kernel/central.c linux/arch/sparc64/kernel/central.c --- v2.4.0-test8/linux/arch/sparc64/kernel/central.c Mon Dec 20 22:05:52 1999 +++ linux/arch/sparc64/kernel/central.c Tue Oct 3 09:24:41 2000 @@ -1,4 +1,4 @@ -/* $Id: central.c,v 1.13 1999/12/01 10:44:43 davem Exp $ +/* $Id: central.c,v 1.14 2000/09/21 06:25:14 anton Exp $ * central.c: Central FHC driver for Sunfire/Starfire/Wildfire. * * Copyright (C) 1997, 1999 David S. Miller (davem@redhat.com) @@ -15,6 +15,7 @@ #include #include +#include struct linux_central *central_bus = NULL; struct linux_fhc *fhc_list = NULL; @@ -254,9 +255,8 @@ cnode = prom_finddevice("/central"); if(cnode == 0 || cnode == -1) { - extern void starfire_check(void); - - starfire_check(); + if (this_is_starfire) + starfire_cpu_setup(); return; } diff -u --recursive --new-file v2.4.0-test8/linux/arch/sparc64/kernel/entry.S linux/arch/sparc64/kernel/entry.S --- v2.4.0-test8/linux/arch/sparc64/kernel/entry.S Thu Sep 7 08:32:00 2000 +++ linux/arch/sparc64/kernel/entry.S Fri Sep 8 17:55:17 2000 @@ -1,4 +1,4 @@ -/* $Id: entry.S,v 1.119 2000/09/06 00:45:01 davem Exp $ +/* $Id: entry.S,v 1.120 2000/09/08 13:58:12 jj Exp $ * arch/sparc64/kernel/entry.S: Sparc64 trap low-level entry points. * * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu) @@ -940,8 +940,8 @@ 1: b,pt %xcc, ret_sys_call ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %o0 -sparc_exit: rdpr %otherwin, %g1 - wrpr %g0, (PSTATE_RMO | PSTATE_PEF | PSTATE_PRIV), %pstate +sparc_exit: wrpr %g0, (PSTATE_RMO | PSTATE_PEF | PSTATE_PRIV), %pstate + rdpr %otherwin, %g1 rdpr %cansave, %g3 add %g3, %g1, %g3 wrpr %g3, 0x0, %cansave diff -u --recursive --new-file v2.4.0-test8/linux/arch/sparc64/kernel/irq.c linux/arch/sparc64/kernel/irq.c --- v2.4.0-test8/linux/arch/sparc64/kernel/irq.c Thu Sep 7 08:32:00 2000 +++ linux/arch/sparc64/kernel/irq.c Tue Oct 3 09:24:41 2000 @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.93 2000/08/31 10:00:39 anton Exp $ +/* $Id: irq.c,v 1.94 2000/09/21 06:27:10 anton Exp $ * irq.c: UltraSparc IRQ handling/init/registry. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -31,6 +31,7 @@ #include #include #include +#include /* Internal flag, should not be visible elsewhere at all. */ #define SA_IMAP_MASKED 0x100 @@ -123,7 +124,6 @@ /* Now these are always passed a true fully specified sun4u INO. */ void enable_irq(unsigned int irq) { - extern int this_is_starfire; struct ino_bucket *bucket = __bucket(irq); unsigned long imap; unsigned long tid; @@ -139,9 +139,6 @@ : "i" (ASI_UPA_CONFIG)); tid = ((tid & UPA_CONFIG_MID) << 9); } else { - extern unsigned int starfire_translate(unsigned long imap, - unsigned int upaid); - tid = (starfire_translate(imap, current->processor) << 26); } @@ -715,7 +712,6 @@ struct ino_bucket *bp, *nbp; int cpu = smp_processor_id(); #ifdef CONFIG_SMP - extern int this_is_starfire; int should_forward = (this_is_starfire == 0 && irq < 10 && current->pid != 0); @@ -1029,7 +1025,6 @@ #ifdef CONFIG_SMP static int retarget_one_irq(struct irqaction *p, int goal_cpu) { - extern int this_is_starfire; struct ino_bucket *bucket = __bucket(p->mask); unsigned long imap = bucket->imap; unsigned int tid; @@ -1041,9 +1036,6 @@ if(this_is_starfire == 0) { tid = __cpu_logical_map[goal_cpu] << 26; } else { - extern unsigned int starfire_translate(unsigned long imap, - unsigned int upaid); - tid = (starfire_translate(imap, __cpu_logical_map[goal_cpu]) << 26); } upa_writel(IMAP_VALID | (tid & IMAP_TID), imap); diff -u --recursive --new-file v2.4.0-test8/linux/arch/sparc64/kernel/pci.c linux/arch/sparc64/kernel/pci.c --- v2.4.0-test8/linux/arch/sparc64/kernel/pci.c Thu Sep 7 08:32:00 2000 +++ linux/arch/sparc64/kernel/pci.c Tue Oct 3 09:24:41 2000 @@ -24,7 +24,6 @@ #ifndef CONFIG_PCI /* A "nop" PCI implementation. */ -int pcibios_present(void) { return 0; } asmlinkage int sys_pciconfig_read(unsigned long bus, unsigned long dfn, unsigned long off, unsigned long len, unsigned char *buf) @@ -316,7 +315,6 @@ goto out; } - lock_kernel(); switch(len) { case 1: err = get_user(byte, (u8 *)buf); @@ -344,7 +342,6 @@ break; }; - unlock_kernel(); out: return err; diff -u --recursive --new-file v2.4.0-test8/linux/arch/sparc64/kernel/pci_psycho.c linux/arch/sparc64/kernel/pci_psycho.c --- v2.4.0-test8/linux/arch/sparc64/kernel/pci_psycho.c Mon Apr 24 13:59:58 2000 +++ linux/arch/sparc64/kernel/pci_psycho.c Tue Oct 3 09:24:41 2000 @@ -1,4 +1,4 @@ -/* $Id: pci_psycho.c,v 1.16 2000/04/15 10:06:16 davem Exp $ +/* $Id: pci_psycho.c,v 1.17 2000/09/21 06:25:14 anton Exp $ * pci_psycho.c: PSYCHO/U2P specific PCI controller support. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu) @@ -15,6 +15,7 @@ #include #include #include +#include #include "pci_impl.h" @@ -1254,8 +1255,6 @@ static void __init psycho_iommu_init(struct pci_controller_info *p) { - extern int this_is_starfire; - extern void *starfire_hookup(int); unsigned long tsbbase, i; u64 control; diff -u --recursive --new-file v2.4.0-test8/linux/arch/sparc64/kernel/sbus.c linux/arch/sparc64/kernel/sbus.c --- v2.4.0-test8/linux/arch/sparc64/kernel/sbus.c Fri Apr 14 09:37:09 2000 +++ linux/arch/sparc64/kernel/sbus.c Tue Oct 3 09:24:41 2000 @@ -1,4 +1,4 @@ -/* $Id: sbus.c,v 1.11 2000/04/14 09:13:04 davem Exp $ +/* $Id: sbus.c,v 1.12 2000/09/21 06:25:14 anton Exp $ * sbus.c: UltraSparc SBUS controller support. * * Copyright (C) 1999 David S. Miller (davem@redhat.com) @@ -18,6 +18,7 @@ #include #include #include +#include #include "iommu_common.h" @@ -1151,15 +1152,10 @@ upa_writeq(control, iommu->sbus_control_reg); /* Now some Xfire specific grot... */ - { - extern void *starfire_hookup(int); - extern int this_is_starfire; - - if (this_is_starfire) - sbus->starfire_cookie = starfire_hookup(sbus->portid); - else - sbus->starfire_cookie = NULL; - } + if (this_is_starfire) + sbus->starfire_cookie = starfire_hookup(sbus->portid); + else + sbus->starfire_cookie = NULL; sysio_register_error_handlers(sbus); } diff -u --recursive --new-file v2.4.0-test8/linux/arch/sparc64/kernel/setup.c linux/arch/sparc64/kernel/setup.c --- v2.4.0-test8/linux/arch/sparc64/kernel/setup.c Wed Jul 26 18:36:44 2000 +++ linux/arch/sparc64/kernel/setup.c Tue Oct 3 09:24:41 2000 @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.55 2000/07/24 14:13:13 anton Exp $ +/* $Id: setup.c,v 1.56 2000/09/21 06:29:01 anton Exp $ * linux/arch/sparc64/kernel/setup.c * * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu) @@ -37,6 +37,7 @@ #include #include #include +#include #ifdef CONFIG_IP_PNP #include @@ -478,6 +479,9 @@ #elif defined(CONFIG_PROM_CONSOLE) conswitchp = &prom_con; #endif + + /* Work out if we are starfire early on */ + check_if_starfire(); boot_flags_init(*cmdline_p); diff -u --recursive --new-file v2.4.0-test8/linux/arch/sparc64/kernel/starfire.c linux/arch/sparc64/kernel/starfire.c --- v2.4.0-test8/linux/arch/sparc64/kernel/starfire.c Mon Jan 31 23:37:19 2000 +++ linux/arch/sparc64/kernel/starfire.c Tue Oct 3 09:24:41 2000 @@ -1,7 +1,8 @@ -/* $Id: starfire.c,v 1.5 2000/01/31 04:59:12 davem Exp $ +/* $Id: starfire.c,v 1.7 2000/09/22 23:02:13 davem Exp $ * starfire.c: Starfire/E10000 support. * * Copyright (C) 1998 David S. Miller (davem@redhat.com) + * Copyright (C) 2000 Anton Blanchard (anton@linuxcare.com) */ #include @@ -11,23 +12,31 @@ #include #include #include +#include -/* A few places around the kernel check this to see if +/* + * A few places around the kernel check this to see if * they need to call us to do things in a Starfire specific * way. */ int this_is_starfire = 0; -void starfire_check(void) +void check_if_starfire(void) { int ssnode = prom_finddevice("/ssp-serial"); + if(ssnode != 0 && ssnode != -1) + this_is_starfire = 1; +} - if(ssnode != 0 && ssnode != -1) { +void starfire_cpu_setup(void) +{ + if (this_is_starfire) { +/* We do this in starfire_translate - Anton */ +#if 0 int i; - this_is_starfire = 1; - - /* Now must fixup cpu MIDs. OBP gave us a logical + /* + * Now must fixup cpu MIDs. OBP gave us a logical * linear cpuid number, not the real upaid. */ for(i = 0; i < linux_num_cpus; i++) { @@ -39,6 +48,7 @@ linux_cpus[i].mid = mid; } +#endif } } @@ -47,7 +57,8 @@ return upa_readl(0x1fff40000d0UL); } -/* Each Starfire board has 32 registers which perform translation +/* + * Each Starfire board has 32 registers which perform translation * and delivery of traditional interrupt packets into the extended * Starfire hardware format. Essentially UPAID's now have 2 more * bits than in all previous Sun5 systems. @@ -82,6 +93,9 @@ for(i = 0; i < 32; i++) { p->imap_slots[i] = 0UL; p->tregs[i] = treg_base + (i * 0x10UL); + /* Lets play it safe and not overwrite existing mappings */ + if (upa_readl(p->tregs[i]) != 0) + p->imap_slots[i] = 0xdeadbeaf; } p->upaid = upaid; p->next = sflist; @@ -116,6 +130,12 @@ panic("Lucy in the sky...."); } p->imap_slots[i] = imap; + + /* map to real upaid */ + upaid = (((upaid & 0x3c) << 1) | + ((upaid & 0x40) >> 4) | + (upaid & 0x3)); + upa_writel(upaid, p->tregs[i]); return i; diff -u --recursive --new-file v2.4.0-test8/linux/arch/sparc64/kernel/sys_sparc32.c linux/arch/sparc64/kernel/sys_sparc32.c --- v2.4.0-test8/linux/arch/sparc64/kernel/sys_sparc32.c Wed Aug 23 09:30:13 2000 +++ linux/arch/sparc64/kernel/sys_sparc32.c Sun Sep 17 10:01:49 2000 @@ -1,4 +1,4 @@ -/* $Id: sys_sparc32.c,v 1.163 2000/08/22 10:09:10 jj Exp $ +/* $Id: sys_sparc32.c,v 1.164 2000/09/14 10:42:47 davem Exp $ * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -1621,7 +1621,7 @@ static void *do_ncp_super_data_conv(void *raw_data) { - struct ncp_mount_data *n = (struct ncp_mount_data *)raw_data; + struct ncp_mount_data news, *n = &news; struct ncp_mount_data32 *n32 = (struct ncp_mount_data32 *)raw_data; n->dir_mode = n32->dir_mode; @@ -1631,6 +1631,7 @@ memmove (n->mounted_vol, n32->mounted_vol, (sizeof (n32->mounted_vol) + 3 * sizeof (unsigned int))); n->wdog_pid = n32->wdog_pid; n->mounted_uid = low2highuid(n32->mounted_uid); + memcpy(raw_data, n, sizeof(struct ncp_mount_data)); return raw_data; } @@ -1645,7 +1646,7 @@ static void *do_smb_super_data_conv(void *raw_data) { - struct smb_mount_data *s = (struct smb_mount_data *)raw_data; + struct smb_mount_data news, *s = &news; struct smb_mount_data32 *s32 = (struct smb_mount_data32 *)raw_data; s->version = s32->version; @@ -1654,6 +1655,7 @@ s->gid = low2highgid(s32->gid); s->file_mode = s32->file_mode; s->dir_mode = s32->dir_mode; + memcpy(raw_data, s, sizeof(struct smb_mount_data)); return raw_data; } diff -u --recursive --new-file v2.4.0-test8/linux/arch/sparc64/kernel/time.c linux/arch/sparc64/kernel/time.c --- v2.4.0-test8/linux/arch/sparc64/kernel/time.c Tue Jul 11 15:46:08 2000 +++ linux/arch/sparc64/kernel/time.c Tue Oct 3 09:24:41 2000 @@ -1,4 +1,4 @@ -/* $Id: time.c,v 1.28 2000/07/11 02:21:12 davem Exp $ +/* $Id: time.c,v 1.32 2000/09/22 23:02:13 davem Exp $ * time.c: UltraSparc timer and TOD clock support. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -30,6 +30,7 @@ #include #include #include +#include extern rwlock_t xtime_lock; @@ -177,37 +178,6 @@ } #endif -/* Converts Gregorian date to seconds since 1970-01-01 00:00:00. - * Assumes input in normal date format, i.e. 1980-12-31 23:59:59 - * => year=1980, mon=12, day=31, hour=23, min=59, sec=59. - * - * [For the Julian calendar (which was used in Russia before 1917, - * Britain & colonies before 1752, anywhere else before 1582, - * and is still in use by some communities) leave out the - * -year/100+year/400 terms, and add 10.] - * - * This algorithm was first published by Gauss (I think). - * - * WARNING: this function will overflow on 2106-02-07 06:28:16 on - * machines were long is 32-bit! (However, as time_t is signed, we - * will already get problems at other places on 2038-01-19 03:14:08) - */ -static inline unsigned long mktime(unsigned int year, unsigned int mon, - unsigned int day, unsigned int hour, - unsigned int min, unsigned int sec) -{ - if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */ - mon += 12; /* Puts Feb last since it has leap day */ - year -= 1; - } - return ((( - (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) + - year*365 - 719499 - )*24 + hour /* now have hours */ - )*60 + min /* now have minutes */ - )*60 + sec; /* finally seconds */ -} - /* Kick start a stopped clock (procedure from the Sun NVRAM/hostid FAQ). */ static void __init kick_start_clock(void) { @@ -336,6 +306,20 @@ struct linux_ebus *ebus = NULL; #endif + + if (this_is_starfire) { + /* davem suggests we keep this within the 4M locked kernel image */ + static char obp_gettod[256]; + static u32 unix_tod; + + sprintf(obp_gettod, "h# %08x unix-gettod", + (unsigned int) (long) &unix_tod); + prom_feval(obp_gettod); + xtime.tv_sec = unix_tod; + xtime.tv_usec = 0; + return; + } + __save_and_cli(flags); if(central_bus != NULL) { @@ -504,6 +488,9 @@ void do_settimeofday(struct timeval *tv) { + if (this_is_starfire) + return; + write_lock_irq(&xtime_lock); tv->tv_usec -= do_gettimeoffset(); @@ -527,7 +514,10 @@ unsigned long regs = mstk48t02_regs; u8 tmp; - /* Not having a register set can lead to trouble. */ + /* + * Not having a register set can lead to trouble. + * Also starfire doesnt have a tod clock. + */ if (!regs) return -1; diff -u --recursive --new-file v2.4.0-test8/linux/arch/sparc64/lib/rwlock.S linux/arch/sparc64/lib/rwlock.S --- v2.4.0-test8/linux/arch/sparc64/lib/rwlock.S Thu Mar 16 11:40:17 2000 +++ linux/arch/sparc64/lib/rwlock.S Fri Sep 8 17:55:17 2000 @@ -1,4 +1,4 @@ -/* $Id: rwlock.S,v 1.3 2000/03/16 16:44:38 davem Exp $ +/* $Id: rwlock.S,v 1.4 2000/09/09 00:00:34 davem Exp $ * rwlocks.S: These things are too big to do inline. * * Copyright (C) 1999 David S. Miller (davem@redhat.com) @@ -30,54 +30,38 @@ cmp %g5, %g7 be,pt %xcc, 99b membar #StoreLoad | #StoreStore - b,a,pt %xcc, __read_unlock + ba,a,pt %xcc, __read_unlock __read_wait_for_writer: ldsw [%o0], %g5 brlz,pt %g5, __read_wait_for_writer membar #LoadLoad - b,a,pt %xcc, 4b -__write_wait_for_writer: - ldsw [%o0], %g5 - brlz,pt %g5, __write_wait_for_writer + ba,a,pt %xcc, 4b +__write_wait_for_any: + lduw [%o0], %g5 + brnz,pt %g5, __write_wait_for_any membar #LoadLoad - b,a,pt %xcc, 4f - - /* Similarly, 2 cache lines for non-contention write locks. */ + ba,a,pt %xcc, 4f .align 64 .globl __write_unlock __write_unlock: /* %o0 = lock_ptr */ - sethi %hi(0x80000000), %g2 -1: lduw [%o0], %g5 - andn %g5, %g2, %g7 - cas [%o0], %g5, %g7 - cmp %g5, %g7 - be,pt %icc, 99b - membar #StoreLoad | #StoreStore - b,a,pt %xcc, 1b + membar #LoadStore | #StoreStore + retl + stw %g0, [%o0] .globl __write_lock __write_lock: /* %o0 = lock_ptr */ sethi %hi(0x80000000), %g2 -1: ldsw [%o0], %g5 -4: brnz,pn %g5, 5f - or %g5, %g2, %g7 + +1: lduw [%o0], %g5 + brnz,pn %g5, __write_wait_for_any +4: or %g5, %g2, %g7 cas [%o0], %g5, %g7 + cmp %g5, %g7 be,pt %icc, 99b membar #StoreLoad | #StoreStore - - b,a,pt %xcc, 1b -5: brlz %g5, __write_wait_for_writer - or %g5, %g2, %g7 - cas [%o0], %g5, %g7 - cmp %g5, %g7 - bne,pn %icc, 5b -8: ldsw [%o0], %g5 - cmp %g5, %g2 - be,pn %icc, 99b - membar #LoadLoad - b,a,pt %xcc, 99b + ba,a,pt %xcc, 1b rwlock_impl_end: diff -u --recursive --new-file v2.4.0-test8/linux/arch/sparc64/mm/fault.c linux/arch/sparc64/mm/fault.c --- v2.4.0-test8/linux/arch/sparc64/mm/fault.c Sat Aug 12 12:08:50 2000 +++ linux/arch/sparc64/mm/fault.c Sun Sep 17 10:01:50 2000 @@ -1,4 +1,4 @@ -/* $Id: fault.c,v 1.50 2000/08/11 03:00:13 davem Exp $ +/* $Id: fault.c,v 1.51 2000/09/14 06:22:32 anton Exp $ * arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -145,7 +145,7 @@ if (!insn) { if (regs->tstate & TSTATE_PRIV) { - if (regs->tpc & 0x3) + if (!regs->tpc || (regs->tpc & 0x3)) goto cannot_handle; insn = *(unsigned int *)regs->tpc; } else { diff -u --recursive --new-file v2.4.0-test8/linux/arch/sparc64/mm/init.c linux/arch/sparc64/mm/init.c --- v2.4.0-test8/linux/arch/sparc64/mm/init.c Thu Sep 7 08:44:50 2000 +++ linux/arch/sparc64/mm/init.c Tue Oct 3 09:24:41 2000 @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.154 2000/08/09 00:00:15 davem Exp $ +/* $Id: init.c,v 1.156 2000/09/21 06:34:48 anton Exp $ * arch/sparc64/mm/init.c * * Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu) @@ -29,6 +29,7 @@ #include #include #include +#include extern void device_scan(void); @@ -200,7 +201,7 @@ for (i = 0; i < n; i++) { unsigned long vaddr; - + if (trans[i].virt >= 0xf0000000 && trans[i].virt < 0x100000000) { for (vaddr = trans[i].virt; vaddr < trans[i].virt + trans[i].size; @@ -808,7 +809,6 @@ unsigned long bootmap_pfn, bytes_avail, size; int i; - bytes_avail = 0UL; for (i = 0; sp_banks[i].num_bytes != 0; i++) { end_of_phys_memory = sp_banks[i].base_addr + @@ -999,12 +999,7 @@ */ { extern void setup_tba(int); - int is_starfire = prom_finddevice("/ssp-serial"); - if (is_starfire != 0 && is_starfire != -1) - is_starfire = 1; - else - is_starfire = 0; - setup_tba(is_starfire); + setup_tba(this_is_starfire); } inherit_locked_prom_mappings(1); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/Makefile linux/drivers/Makefile --- v2.4.0-test8/linux/drivers/Makefile Tue Aug 22 11:41:14 2000 +++ linux/drivers/Makefile Wed Sep 27 14:14:34 2000 @@ -1,205 +1,59 @@ # # Makefile for the Linux kernel device drivers. # -# Note! Dependencies are done automagically by 'make dep', which also -# removes any old dependencies. DON'T put your own dependencies here -# unless it's something special (not a .c file). +# 15 Sep 2000, Christoph Hellwig +# Rewritten to use lists instead of if-statements. # -# Note 2! The CFLAGS definitions are now in the main makefile. -SUB_DIRS := block char net parport sound misc media -MOD_SUB_DIRS := $(SUB_DIRS) -ALL_SUB_DIRS := $(SUB_DIRS) pci sgi ide scsi sbus cdrom isdn pnp i2o \ - ieee1394 macintosh video dio zorro fc4 \ - usb nubus tc atm pcmcia i2c telephony \ - acpi mtd input - -ifdef CONFIG_DIO -SUB_DIRS += dio -MOD_SUB_DIRS += dio -endif - -ifdef CONFIG_PCI -SUB_DIRS += pci -endif - -ifeq ($(CONFIG_PCMCIA),y) -SUB_DIRS += pcmcia -else - ifeq ($(CONFIG_PCMCIA),m) - MOD_SUB_DIRS += pcmcia - endif -endif - -ifdef CONFIG_MTD -SUB_DIRS += mtd -MOD_SUB_DIRS += mtd -endif - -ifdef CONFIG_SBUS -SUB_DIRS += sbus -MOD_SUB_DIRS += sbus -endif - -ifdef CONFIG_ZORRO -SUB_DIRS += zorro -endif - -ifdef CONFIG_NUBUS -SUB_DIRS += nubus -endif - -ifdef CONFIG_TC -SUB_DIRS += tc -endif - -ifdef CONFIG_VT -SUB_DIRS += video -MOD_SUB_DIRS += video -endif - -ifdef CONFIG_MAC -SUB_DIRS += macintosh -MOD_SUB_DIRS += macintosh -endif - -ifdef CONFIG_PPC -SUB_DIRS += macintosh -MOD_SUB_DIRS += macintosh -endif - -ifeq ($(CONFIG_USB),y) -SUB_DIRS += usb -MOD_SUB_DIRS += usb -else - ifeq ($(CONFIG_USB),m) - MOD_SUB_DIRS += usb - endif -endif - -ifeq ($(CONFIG_INPUT),y) -SUB_DIRS += input -MOD_SUB_DIRS += input -else - ifeq ($(CONFIG_INPUT),m) - MOD_SUB_DIRS += input - endif -endif - -ifeq ($(CONFIG_PHONE),y) -SUB_DIRS += telephony -MOD_SUB_DIRS += telephony -else - ifeq ($(CONFIG_PHONE),m) - MOD_SUB_DIRS += telephony - endif -endif - -ifdef CONFIG_SGI -SUB_DIRS += sgi -MOD_SUB_DIRS += sgi -endif - -ifeq ($(CONFIG_I2O),y) -SUB_DIRS += i2o -MOD_SUB_DIRS += i2o -else - ifeq ($(CONFIG_I2O),m) - MOD_SUB_DIRS += i2o - endif -endif - -# If CONFIG_IDE is set, the core of ATA support will be added to the kernel, -# but some of the low-level things may also be modules. -ifeq ($(CONFIG_IDE),y) -SUB_DIRS += ide -MOD_SUB_DIRS += ide -else - ifeq ($(CONFIG_IDE),m) - MOD_SUB_DIRS += ide - endif -endif - -# If CONFIG_SCSI is set, the core of SCSI support will be added to the kernel, -# but some of the low-level things may also be modules. -ifeq ($(CONFIG_SCSI),y) -SUB_DIRS += scsi -MOD_SUB_DIRS += scsi -else - ifeq ($(CONFIG_SCSI),m) - MOD_SUB_DIRS += scsi - endif -endif - -ifeq ($(CONFIG_IEEE1394),y) -SUB_DIRS += ieee1394 -MOD_SUB_DIRS += ieee1394 -else - ifeq ($(CONFIG_IEEE1394),m) - MOD_SUB_DIRS += ieee1394 - endif -endif - -ifeq ($(CONFIG_PNP),y) -SUB_DIRS += pnp -MOD_SUB_DIRS += pnp -else - ifeq ($(CONFIG_PNP),m) - MOD_SUB_DIRS += pnp - endif -endif - -ifneq ($(CONFIG_CD_NO_IDESCSI)$(CONFIG_BLK_DEV_IDECD)$(CONFIG_BLK_DEV_SR)$(CONFIG_PARIDE_PCD),) -SUB_DIRS += cdrom -MOD_SUB_DIRS += cdrom -endif - -ifeq ($(CONFIG_ISDN),y) -SUB_DIRS += isdn -MOD_SUB_DIRS += isdn -else - ifeq ($(CONFIG_ISDN),m) - MOD_SUB_DIRS += isdn - endif -endif - -ifdef CONFIG_ATM -SUB_DIRS += atm -MOD_SUB_DIRS += atm -endif - -ifeq ($(CONFIG_FC4),y) -SUB_DIRS += fc4 -MOD_SUB_DIRS += fc4 -else - ifeq ($(CONFIG_FC4),m) - MOD_SUB_DIRS += fc4 - endif -endif - -# When MOD_LIST_NAME is set, make will try to add $(MOD_SUB_DIRS).o to -# modules/MOD_LIST_NAME. We don't have hamradio.o and Linus -# sort of insisted on making hamradio/ a subdirectory of drivers/net/. -# #FIXME# MOD_LIST_NAME doesn't exist any more -- does this comment -# #FIXME# still mean anything? - -ifeq ($(CONFIG_HAMRADIO),y) - SUB_DIRS += net/hamradio - MOD_SUB_DIRS += net/hamradio -endif - -ifeq ($(CONFIG_I2C),y) -SUB_DIRS += i2c -MOD_SUB_DIRS += i2c -else - ifeq ($(CONFIG_I2C),m) - MOD_SUB_DIRS += i2c - endif -endif - -ifeq ($(CONFIG_ACPI),y) -SUB_DIRS += acpi -MOD_SUB_DIRS += acpi -endif + +mod-subdirs := dio mtd sbus video macintosh usb input telephony sgi i2o ide \ + scsi md ieee1394 pnp isdn atm fc4 net/hamradio i2c acpi + +subdir-y := block char net parport sound misc media cdrom +subdir-m := $(subdir-y) + + +subdir-$(CONFIG_DIO) += dio +subdir-$(CONFIG_PCI) += pci +subdir-$(CONFIG_PCMCIA) += pcmcia +subdir-$(CONFIG_MTD) += mtd +subdir-$(CONFIG_SBUS) += sbus +subdir-$(CONFIG_ZORRO) += zorro +subdir-$(CONFIG_NUBUS) += nubus +subdir-$(CONFIG_TC) += tc +subdir-$(CONFIG_VT) += video +subdir-$(CONFIG_MAC) += macintosh +subdir-$(CONFIG_ALL_PPC) += macintosh +subdir-$(CONFIG_USB) += usb +subdir-$(CONFIG_INPUT) += input +subdir-$(CONFIG_PHONE) += telephony +subdir-$(CONFIG_SGI) += sgi +subdir-$(CONFIG_I2O) += i2o +subdir-$(CONFIG_IDE) += ide +subdir-$(CONFIG_SCSI) += scsi +subdir-$(CONFIG_MD) += md +subdir-$(CONFIG_IEEE1394) += ieee1394 +subdir-$(CONFIG_PNP) += pnp +subdir-$(CONFIG_ISDN) += isdn +subdir-$(CONFIG_ATM) += atm +subdir-$(CONFIG_FC4) += fc4 + +# CONFIG_HAMRADIO can be set without CONFIG_NETDEVICE being set -- ch +subdir-$(CONFIG_HAMRADIO) += net/hamradio +subdir-$(CONFIG_I2C) += i2c +subdir-$(CONFIG_ACPI) += acpi + + +# Subdirectories that should be entered when MAKING_MODULES=1, even if set to 'y'. +both-m := $(filter $(mod-subdirs), $(subdir-y)) + +# Translate to Rules.make lists. +SUB_DIRS := $(subdir-y) +MOD_SUB_DIRS := $(sort $(subdir-m) $(both-m)) +ALL_SUB_DIRS := $(sort $(subdir-y) $(subdir-m) $(subdir-n) $(subdir-)) + +# net/hamradio is already in ALL_SUB_DIRS of drivers/net/Makefile +ALL_SUB_DIRS := $(filter-out net/hamradio, $(ALL_SUB_DIRS)) include $(TOPDIR)/Rules.make + diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acorn/block/fd1772.c linux/drivers/acorn/block/fd1772.c --- v2.4.0-test8/linux/drivers/acorn/block/fd1772.c Sun Aug 13 09:54:15 2000 +++ linux/drivers/acorn/block/fd1772.c Sun Oct 1 20:35:15 2000 @@ -198,7 +198,7 @@ #define MAX_DISK_SIZE 720 static int floppy_sizes[256]; -static int floppy_blocksizes[256] = {0,}; +static int floppy_blocksizes[256]; /* current info on each unit */ static struct archy_floppy_struct { diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acorn/block/mfmhd.c linux/drivers/acorn/block/mfmhd.c --- v2.4.0-test8/linux/drivers/acorn/block/mfmhd.c Mon Feb 28 14:16:37 2000 +++ linux/drivers/acorn/block/mfmhd.c Mon Sep 18 15:15:21 2000 @@ -124,7 +124,7 @@ #include #include #include -#include +#include /* * This sort of stuff should be in a header file shared with ide.c, hd.c, xd.c etc diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acorn/char/Makefile linux/drivers/acorn/char/Makefile --- v2.4.0-test8/linux/drivers/acorn/char/Makefile Sun Aug 13 09:54:15 2000 +++ linux/drivers/acorn/char/Makefile Mon Sep 18 15:15:21 2000 @@ -28,19 +28,15 @@ obj-arc := keyb_arc.o obj-rpc := keyb_ps2.o +obj-clps7500 := keyb_ps2.o defkeymap-acorn.o obj-$(CONFIG_RPCMOUSE) += mouse_rpc.o obj-$(CONFIG_ATOMWIDE_SERIAL) += serial-atomwide.o obj-$(CONFIG_DUALSP_SERIAL) += serial-dualsp.o -obj-$(CONFIG_ARCH_ACORN) += defkeymap-acorn.o +obj-$(CONFIG_ARCH_ACORN) += defkeymap-acorn.o i2c.o pcf8583.o # Do the i2c and rtc last obj-y += $(obj-$(MACHINE)) - -# CL-PS7500 does not have these devices. -ifneq ($(CONFIG_ARCH_CLPS7500),y) -obj-y += i2c.o pcf8583.o -endif O_OBJS := $(filter-out $(export-objs), $(obj-y)) OX_OBJS := $(filter $(export-objs), $(obj-y)) diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acorn/char/defkeymap-acorn.c linux/drivers/acorn/char/defkeymap-acorn.c --- v2.4.0-test8/linux/drivers/acorn/char/defkeymap-acorn.c Mon Jun 26 12:04:42 2000 +++ linux/drivers/acorn/char/defkeymap-acorn.c Mon Sep 18 15:15:21 2000 @@ -1,9 +1,12 @@ /* - * linux/arch/arm/drivers/char/defkeymap.c + * linux/drivers/acorn/char/defkeymap.c * - * Copyright (C) 1995, 1996 Russell King + * Copyright (C) 1995, 1996 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 diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acorn/char/i2c.c linux/drivers/acorn/char/i2c.c --- v2.4.0-test8/linux/drivers/acorn/char/i2c.c Sun Feb 6 17:45:25 2000 +++ linux/drivers/acorn/char/i2c.c Mon Sep 18 15:15:21 2000 @@ -1,11 +1,15 @@ /* - * linux/drivers/acorn/char/i2c.c + * linux/drivers/acorn/char/i2c.c * - * Copyright (C) 2000 Russell King + * Copyright (C) 2000 Russell King * - * ARM IOC/IOMD i2c driver. + * 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. * - * On Acorn machines, the following i2c devices are on the bus: + * ARM IOC/IOMD i2c driver. + * + * On Acorn machines, the following i2c devices are on the bus: * - PCF8583 real time clock & static RAM */ #include @@ -15,7 +19,7 @@ #include #include -#include +#include #include #include "pcf8583.h" diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acorn/char/keyb_arc.c linux/drivers/acorn/char/keyb_arc.c --- v2.4.0-test8/linux/drivers/acorn/char/keyb_arc.c Wed Aug 9 14:11:11 2000 +++ linux/drivers/acorn/char/keyb_arc.c Mon Sep 18 15:15:21 2000 @@ -1,13 +1,18 @@ /* - * linux/arch/arm/drivers/char1/keyb_arc.c + * linux/drivers/acorn/char/keyb_arc.c * - * Acorn keyboard driver for ARM Linux. + * Copyright (C) 2000 Russell King * - * The Acorn keyboard appears to have a ***very*** buggy reset protocol - - * every reset behaves differently. We try to get round this by attempting - * a few things... + * 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. + * + * Acorn keyboard driver for ARM Linux. + * + * The Acorn keyboard appears to have a ***very*** buggy reset protocol - + * every reset behaves differently. We try to get round this by attempting + * a few things... */ - #include #include #include @@ -28,8 +33,8 @@ #include #include #include -#include #include +#include #include "../../char/busmouse.h" @@ -424,14 +429,11 @@ { unsigned long flags; - save_flags_cli (flags); if (request_irq (IRQ_KEYBOARDTX, a5kkbd_tx, 0, "keyboard", NULL) != 0) panic("Could not allocate keyboard transmit IRQ!"); - disable_irq (IRQ_KEYBOARDTX); + (void)inb(IOC_KARTRX); if (request_irq (IRQ_KEYBOARDRX, a5kkbd_rx, 0, "keyboard", NULL) != 0) panic("Could not allocate keyboard receive IRQ!"); - (void)inb(IOC_KARTRX); - restore_flags (flags); a5kkbd_sendbyte (HRST); /* send HRST (expect HRST) */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acorn/char/keyb_ps2.c linux/drivers/acorn/char/keyb_ps2.c --- v2.4.0-test8/linux/drivers/acorn/char/keyb_ps2.c Wed Aug 9 14:11:11 2000 +++ linux/drivers/acorn/char/keyb_ps2.c Mon Sep 18 15:15:21 2000 @@ -1,11 +1,16 @@ /* - * linux/arch/arm/drivers/block/keyb_ps2.c + * linux/drivers/acorn/char/keyb_ps2.c * - * Keyboard driver for RPC ARM Linux. + * Copyright (C) 2000 Russell King * - * Note!!! This driver talks directly to the keyboard. + * 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. + * + * Keyboard driver for RiscPC ARM Linux. + * + * Note!!! This driver talks directly to the keyboard. */ - #include #include #include @@ -25,7 +30,7 @@ #include #include #include -#include +#include #include extern struct tasklet_struct keyboard_tasklet; @@ -326,20 +331,15 @@ int __init ps2kbd_init_hw(void) { - unsigned long flags; - /* Reset the keyboard state machine. */ outb(0, IOMD_KCTRL); outb(8, IOMD_KCTRL); - save_flags_cli (flags); + (void)IOMD_KARTRX; if (request_irq (IRQ_KEYBOARDRX, ps2kbd_rx, 0, "keyboard", NULL) != 0) panic("Could not allocate keyboard receive IRQ!"); if (request_irq (IRQ_KEYBOARDTX, ps2kbd_tx, 0, "keyboard", NULL) != 0) panic("Could not allocate keyboard transmit IRQ!"); - disable_irq (IRQ_KEYBOARDTX); - (void)IOMD_KARTRX; - restore_flags (flags); return 0; } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acorn/char/mouse_rpc.c linux/drivers/acorn/char/mouse_rpc.c --- v2.4.0-test8/linux/drivers/acorn/char/mouse_rpc.c Tue Jun 20 07:24:52 2000 +++ linux/drivers/acorn/char/mouse_rpc.c Mon Sep 18 15:15:21 2000 @@ -1,12 +1,16 @@ /* - * linux/drivers/char/mouse_rpc.c + * linux/drivers/char/mouse_rpc.c * - * Copyright (C) 1996-1998 Russell King + * Copyright (C) 1996-1998 Russell King * - * This handles the Acorn RiscPCs mouse. We basically have a couple - * of hardware registers that track the sensor count for the X-Y movement - * and another register holding the button state. On every VSYNC interrupt - * we read the complete state and then work out if something has changed. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This handles the Acorn RiscPCs mouse. We basically have a couple + * of hardware registers that track the sensor count for the X-Y movement + * and another register holding the button state. On every VSYNC interrupt + * we read the complete state and then work out if something has changed. */ #include #include @@ -17,7 +21,7 @@ #include #include #include -#include +#include #include "../../char/busmouse.h" diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acorn/char/pcf8583.c linux/drivers/acorn/char/pcf8583.c --- v2.4.0-test8/linux/drivers/acorn/char/pcf8583.c Sun Feb 6 17:45:25 2000 +++ linux/drivers/acorn/char/pcf8583.c Mon Sep 18 15:15:21 2000 @@ -1,11 +1,14 @@ /* - * linux/drivers/i2c/pcf8583.c + * linux/drivers/acorn/char/pcf8583.c * - * Copyright (C) 2000 Russell King + * Copyright (C) 2000 Russell King * - * Driver for PCF8583 RTC & RAM chip + * 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. + * + * Driver for PCF8583 RTC & RAM chip */ - #include #include #include diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acorn/char/pcf8583.h linux/drivers/acorn/char/pcf8583.h --- v2.4.0-test8/linux/drivers/acorn/char/pcf8583.h Sun Feb 6 17:45:25 2000 +++ linux/drivers/acorn/char/pcf8583.h Mon Sep 18 15:15:21 2000 @@ -1,3 +1,12 @@ +/* + * linux/drivers/acorn/char/pcf8583.h + * + * Copyright (C) 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. + */ struct rtc_tm { unsigned char cs; unsigned char secs; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acorn/char/serial-atomwide.c linux/drivers/acorn/char/serial-atomwide.c --- v2.4.0-test8/linux/drivers/acorn/char/serial-atomwide.c Thu Dec 2 15:41:02 1999 +++ linux/drivers/acorn/char/serial-atomwide.c Mon Sep 18 15:15:22 2000 @@ -1,14 +1,17 @@ /* - * linux/arch/arm/drivers/char/serial-atomwide.c + * linux/arch/arm/drivers/char/serial-atomwide.c * - * Copyright (c) 1996 Russell King. + * Copyright (C) 1996 Russell King. * - * Changelog: - * 02-05-1996 RMK Created - * 07-05-1996 RMK Altered for greater number of cards. - * 30-07-1996 RMK Now uses generic card code. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Changelog: + * 02-05-1996 RMK Created + * 07-05-1996 RMK Altered for greater number of cards. + * 30-07-1996 RMK Now uses generic card code. */ - #define MY_CARD_LIST { MANU_ATOMWIDE, PROD_ATOMWIDE_3PSERIAL } #define MY_NUMPORTS 3 #define MY_BAUD_BASE (7372800 / 16) diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acorn/char/serial-card.c linux/drivers/acorn/char/serial-card.c --- v2.4.0-test8/linux/drivers/acorn/char/serial-card.c Thu Dec 2 15:41:02 1999 +++ linux/drivers/acorn/char/serial-card.c Mon Sep 18 15:15:22 2000 @@ -1,7 +1,11 @@ /* - * linux/arch/arm/drivers/char/serial-card.c + * linux/drivers/acorn/char/serial-card.c * - * Copyright (c) 1996-1999 Russell King. + * Copyright (C) 1996-1999 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. * * A generic handler of serial expansion cards that use 16550s or * the like. diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acorn/char/serial-dualsp.c linux/drivers/acorn/char/serial-dualsp.c --- v2.4.0-test8/linux/drivers/acorn/char/serial-dualsp.c Thu Dec 2 15:41:02 1999 +++ linux/drivers/acorn/char/serial-dualsp.c Mon Sep 18 15:15:22 2000 @@ -1,10 +1,14 @@ /* - * linux/arch/arm/drivers/char/serial-dualsp.c + * linux/drivers/acorn/char/serial-dualsp.c * - * Copyright (c) 1996 Russell King. + * Copyright (C) 1996 Russell King. * - * Changelog: - * 30-07-1996 RMK Created + * 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. + * + * Changelog: + * 30-07-1996 RMK Created */ #define MY_CARD_LIST { MANU_SERPORT, PROD_SERPORT_DSPORT } #define MY_NUMPORTS 2 diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acorn/net/ether1.c linux/drivers/acorn/net/ether1.c --- v2.4.0-test8/linux/drivers/acorn/net/ether1.c Tue Jul 11 11:12:23 2000 +++ linux/drivers/acorn/net/ether1.c Mon Sep 18 15:15:22 2000 @@ -1,13 +1,14 @@ /* - * linux/arch/arm/drivers/net/ether1.c + * linux/drivers/acorn/net/ether1.c * - * (C) Copyright 1996-2000 Russell King + * Copyright (C) 1996-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. + * + * Acorn ether1 driver (82586 chip) for Acorn machines * - * Acorn ether1 driver (82586 chip) - * for Acorn machines - */ - -/* * We basically keep two queues in the cards memory - one for transmit * and one for receive. Each has a head and a tail. The head is where * we/the chip adds packets to be transmitted/received, and the tail @@ -15,9 +16,7 @@ * Both of these queues are circular, and since the chip is running * all the time, we have to be careful when we modify the pointers etc * so that the buffer memory contents is valid all the time. - */ - -/* + * * Change log: * 1.00 RMK Released * 1.01 RMK 19/03/1996 Transfers the last odd byte onto/off of the card now. @@ -132,135 +131,128 @@ * This routine is essentially an optimised memcpy from the card's * onboard RAM to kernel memory. */ -static inline void * -ether1_inswb (unsigned int addr, void *data, unsigned int len) -{ - int used; - - addr = ioaddr(addr); - - __asm__ __volatile__( - "subs %3, %3, #2 - bmi 2f -1: ldr %0, [%1], #4 - strb %0, [%2], #1 - mov %0, %0, lsr #8 - strb %0, [%2], #1 - subs %3, %3, #2 - bmi 2f - ldr %0, [%1], #4 - strb %0, [%2], #1 - mov %0, %0, lsr #8 - strb %0, [%2], #1 - subs %3, %3, #2 - bmi 2f - ldr %0, [%1], #4 - strb %0, [%2], #1 - mov %0, %0, lsr #8 - strb %0, [%2], #1 - subs %3, %3, #2 - bmi 2f - ldr %0, [%1], #4 - strb %0, [%2], #1 - mov %0, %0, lsr #8 - strb %0, [%2], #1 - subs %3, %3, #2 - bpl 1b -2: adds %3, %3, #1 - ldreqb %0, [%1] - streqb %0, [%2]" - : "=&r" (used), "=&r" (addr), "=&r" (data), "=&r" (len) - : "1" (addr), "2" (data), "3" (len)); - - return data; -} - -static inline void * -ether1_outswb (unsigned int addr, void *data, unsigned int len) -{ - int used; - - addr = ioaddr(addr); - - __asm__ __volatile__( - "subs %3, %3, #2 - bmi 2f -1: ldr %0, [%2], #2 - mov %0, %0, lsl #16 - orr %0, %0, %0, lsr #16 - str %0, [%1], #4 - subs %3, %3, #2 - bmi 2f - ldr %0, [%2], #2 - mov %0, %0, lsl #16 - orr %0, %0, %0, lsr #16 - str %0, [%1], #4 - subs %3, %3, #2 - bmi 2f - ldr %0, [%2], #2 - mov %0, %0, lsl #16 - orr %0, %0, %0, lsr #16 - str %0, [%1], #4 - subs %3, %3, #2 - bmi 2f - ldr %0, [%2], #2 - mov %0, %0, lsl #16 - orr %0, %0, %0, lsr #16 - str %0, [%1], #4 - subs %3, %3, #2 - bpl 1b -2: adds %3, %3, #1 - ldreqb %0, [%2] - streqb %0, [%1]" - : "=&r" (used), "=&r" (addr), "=&r" (data), "=&r" (len) - : "1" (addr), "2" (data), "3" (len)); - - return data; -} - - static void ether1_writebuffer (struct net_device *dev, void *data, unsigned int start, unsigned int length) { - unsigned int page, thislen, offset; + unsigned int page, thislen, offset, addr; offset = start & 4095; + page = start >> 12; + addr = ioaddr(ETHER1_RAM + (offset >> 1)); - for (page = start >> 12; length; page++) { - outb (page, REG_PAGE); - if (offset + length > 4096) { - length -= 4096 - offset; - thislen = 4096 - offset; - } else { - thislen = length; - length = 0; - } - - data = ether1_outswb (ETHER1_RAM + (offset >> 1), data, thislen); - offset = 0; - } + if (offset + length > 4096) + thislen = 4096 - offset; + else + thislen = length; + + do { + int used; + + outb(page, REG_PAGE); + length -= thislen; + + __asm__ __volatile__( + "subs %3, %3, #2 + bmi 2f +1: ldr %0, [%1], #2 + mov %0, %0, lsl #16 + orr %0, %0, %0, lsr #16 + str %0, [%2], #4 + subs %3, %3, #2 + bmi 2f + ldr %0, [%1], #2 + mov %0, %0, lsl #16 + orr %0, %0, %0, lsr #16 + str %0, [%2], #4 + subs %3, %3, #2 + bmi 2f + ldr %0, [%1], #2 + mov %0, %0, lsl #16 + orr %0, %0, %0, lsr #16 + str %0, [%2], #4 + subs %3, %3, #2 + bmi 2f + ldr %0, [%1], #2 + mov %0, %0, lsl #16 + orr %0, %0, %0, lsr #16 + str %0, [%2], #4 + subs %3, %3, #2 + bpl 1b +2: adds %3, %3, #1 + ldreqb %0, [%1] + streqb %0, [%2]" + : "=&r" (used), "=&r" (data) + : "r" (addr), "r" (thislen), "1" (data)); + + addr = ioaddr(ETHER1_RAM); + + thislen = length; + if (thislen > 4096) + thislen = 4096; + page++; + } while (thislen); } static void ether1_readbuffer (struct net_device *dev, void *data, unsigned int start, unsigned int length) { - unsigned int page, thislen, offset; + unsigned int page, thislen, offset, addr; offset = start & 4095; + page = start >> 12; + addr = ioaddr(ETHER1_RAM + (offset >> 1)); - for (page = start >> 12; length; page++) { - outb (page, REG_PAGE); - if (offset + length > 4096) { - length -= 4096 - offset; - thislen = 4096 - offset; - } else { - thislen = length; - length = 0; - } - - data = ether1_inswb (ETHER1_RAM + (offset >> 1), data, thislen); - offset = 0; - } + if (offset + length > 4096) + thislen = 4096 - offset; + else + thislen = length; + + do { + int used; + + outb(page, REG_PAGE); + length -= thislen; + + __asm__ __volatile__( + "subs %3, %3, #2 + bmi 2f +1: ldr %0, [%2], #4 + strb %0, [%1], #1 + mov %0, %0, lsr #8 + strb %0, [%1], #1 + subs %3, %3, #2 + bmi 2f + ldr %0, [%2], #4 + strb %0, [%1], #1 + mov %0, %0, lsr #8 + strb %0, [%1], #1 + subs %3, %3, #2 + bmi 2f + ldr %0, [%2], #4 + strb %0, [%1], #1 + mov %0, %0, lsr #8 + strb %0, [%1], #1 + subs %3, %3, #2 + bmi 2f + ldr %0, [%2], #4 + strb %0, [%1], #1 + mov %0, %0, lsr #8 + strb %0, [%1], #1 + subs %3, %3, #2 + bpl 1b +2: adds %3, %3, #1 + ldreqb %0, [%2] + streqb %0, [%1]" + : "=&r" (used), "=&r" (data) + : "r" (addr), "r" (thislen), "1" (data)); + + addr = ioaddr(ETHER1_RAM); + + thislen = length; + if (thislen > 4096) + thislen = 4096; + page++; + } while (thislen); } static int __init diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acorn/net/ether1.h linux/drivers/acorn/net/ether1.h --- v2.4.0-test8/linux/drivers/acorn/net/ether1.h Tue Jul 11 11:12:23 2000 +++ linux/drivers/acorn/net/ether1.h Mon Sep 18 15:15:22 2000 @@ -1,9 +1,13 @@ /* - * linux/arch/arm/drivers/net/ether1.h + * linux/drivers/acorn/net/ether1.h * - * network driver for Acorn Ether1 cards. + * Copyright (C) 1996 Russell King * - * (c) 1996 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. + * + * Network driver for Acorn Ether1 cards. */ #ifndef _LINUX_ether1_H diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acorn/net/ether3.c linux/drivers/acorn/net/ether3.c --- v2.4.0-test8/linux/drivers/acorn/net/ether3.c Tue Jul 11 11:12:23 2000 +++ linux/drivers/acorn/net/ether3.c Mon Sep 18 15:15:22 2000 @@ -1,5 +1,11 @@ /* - * linux/drivers/net/ether3.c + * linux/drivers/acorn/net/ether3.c + * + * 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. * * SEEQ nq8005 ethernet driver for Acorn/ANT Ether3 card * for Acorn machines diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acorn/net/ether3.h linux/drivers/acorn/net/ether3.h --- v2.4.0-test8/linux/drivers/acorn/net/ether3.h Tue Jul 11 11:12:23 2000 +++ linux/drivers/acorn/net/ether3.h Mon Sep 18 15:15:22 2000 @@ -1,7 +1,13 @@ /* - * linux/drivers/net/ether3.h + * linux/drivers/acorn/net/ether3.h * - * network driver for Acorn/ANT Ether3 cards + * 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. + * + * network driver for Acorn/ANT Ether3 cards */ #ifndef _LINUX_ether3_H diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acorn/net/etherh.c linux/drivers/acorn/net/etherh.c --- v2.4.0-test8/linux/drivers/acorn/net/etherh.c Tue Jun 20 07:24:52 2000 +++ linux/drivers/acorn/net/etherh.c Mon Oct 2 14:22:40 2000 @@ -1,13 +1,17 @@ /* - * linux/drivers/net/etherh.c + * linux/drivers/acorn/net/etherh.c + * + * Copyright (C) 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. * * NS8390 ANT etherh specific driver * For Acorn machines * * Thanks to I-Cubed for information on their cards. * - * By Russell King. - * * Changelog: * 08-12-1996 RMK 1.00 Created * RMK 1.03 Added support for EtherLan500 cards @@ -63,7 +67,7 @@ MODULE_AUTHOR("Russell King"); MODULE_DESCRIPTION("i3 EtherH driver"); -static char *version __initdata = +static char version[] __initdata = "etherh [500/600/600A] ethernet driver (c) 2000 R.M.King v1.07\n"; #define ETHERH500_DATAPORT 0x200 /* MEMC */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acorn/scsi/acornscsi-io.S linux/drivers/acorn/scsi/acornscsi-io.S --- v2.4.0-test8/linux/drivers/acorn/scsi/acornscsi-io.S Sun Jan 11 16:45:53 1998 +++ linux/drivers/acorn/scsi/acornscsi-io.S Mon Sep 18 15:15:22 2000 @@ -1,4 +1,10 @@ -@ linux/arch/arm/drivers/scsi/acornscsi-io.S: Acorn SCSI card IO +/* + * linux/drivers/acorn/scsi/acornscsi-io.S: Acorn SCSI card IO + * + * 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 diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acorn/scsi/acornscsi.c linux/drivers/acorn/scsi/acornscsi.c --- v2.4.0-test8/linux/drivers/acorn/scsi/acornscsi.c Thu Nov 11 16:57:30 1999 +++ linux/drivers/acorn/scsi/acornscsi.c Mon Sep 18 15:15:22 2000 @@ -1,9 +1,13 @@ /* - * linux/arch/arm/drivers/scsi/acornscsi.c + * linux/drivers/acorn/scsi/acornscsi.c * * Acorn SCSI 3 driver * By R.M.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. + * * Abandoned using the Select and Transfer command since there were * some nasty races between our software and the target devices that * were not easy to solve, and the device errata had a lot of entries @@ -2621,7 +2625,7 @@ { enum res_abort res = res_not_running; - if (queue_removecmd(&host->queues.issue, SCpnt)) { + if (queue_remove_cmd(&host->queues.issue, SCpnt)) { /* * The command was on the issue queue, and has not been * issued yet. We can remove the command from the queue, @@ -2632,7 +2636,7 @@ printk("on issue queue "); //#endif res = res_success; - } else if (queue_removecmd(&host->queues.disconnected, SCpnt)) { + } else if (queue_remove_cmd(&host->queues.disconnected, SCpnt)) { /* * The command was on the disconnected queue. Simply * acknowledge the abort condition, and when the target diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acorn/scsi/acornscsi.h linux/drivers/acorn/scsi/acornscsi.h --- v2.4.0-test8/linux/drivers/acorn/scsi/acornscsi.h Sun Apr 2 17:28:21 2000 +++ linux/drivers/acorn/scsi/acornscsi.h Mon Sep 18 15:15:22 2000 @@ -1,7 +1,13 @@ /* - * Acorn SCSI driver + * linux/drivers/acorn/scsi/acornscsi.h * - * Copyright (C) 1997 Russell King + * Copyright (C) 1997 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. + * + * Acorn SCSI driver */ #ifndef ACORNSCSI_H #define ACORNSCSI_H diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acorn/scsi/arxescsi.c linux/drivers/acorn/scsi/arxescsi.c --- v2.4.0-test8/linux/drivers/acorn/scsi/arxescsi.c Fri May 12 11:21:20 2000 +++ linux/drivers/acorn/scsi/arxescsi.c Mon Sep 18 15:15:22 2000 @@ -17,7 +17,6 @@ * (arxescsi_pseudo_dma_write) * 02-04-2000 RMK 0.1.1 Updated for new error handling code. */ - #include #include #include diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acorn/scsi/cumana_2.c linux/drivers/acorn/scsi/cumana_2.c --- v2.4.0-test8/linux/drivers/acorn/scsi/cumana_2.c Sun Apr 2 17:28:22 2000 +++ linux/drivers/acorn/scsi/cumana_2.c Mon Sep 18 15:15:22 2000 @@ -1,18 +1,21 @@ /* - * linux/arch/arm/drivers/scsi/cumana_2.c + * linux/drivers/acorn/scsi/cumana_2.c * - * Copyright (C) 1997-2000 Russell King + * Copyright (C) 1997-2000 Russell King * - * Changelog: - * 30-08-1997 RMK 0.0.0 Created, READONLY version. - * 22-01-1998 RMK 0.0.1 Updated to 2.1.80. - * 15-04-1998 RMK 0.0.1 Only do PIO if FAS216 will allow it. - * 02-05-1998 RMK 0.0.2 Updated & added DMA support. - * 27-06-1998 RMK Changed asm/delay.h to linux/delay.h - * 18-08-1998 RMK 0.0.3 Fixed synchronous transfer depth. - * 02-04-2000 RMK 0.0.4 Updated for new error handling code. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Changelog: + * 30-08-1997 RMK 0.0.0 Created, READONLY version. + * 22-01-1998 RMK 0.0.1 Updated to 2.1.80. + * 15-04-1998 RMK 0.0.1 Only do PIO if FAS216 will allow it. + * 02-05-1998 RMK 0.0.2 Updated & added DMA support. + * 27-06-1998 RMK Changed asm/delay.h to linux/delay.h + * 18-08-1998 RMK 0.0.3 Fixed synchronous transfer depth. + * 02-04-2000 RMK 0.0.4 Updated for new error handling code. */ - #include #include #include @@ -23,6 +26,7 @@ #include #include #include +#include #include #include @@ -151,15 +155,6 @@ fas216_intr(host); } -static void -cumanascsi_2_invalidate(char *addr, long len, fasdmadir_t direction) -{ - if (direction == DMA_OUT) - dma_cache_wback((unsigned long)addr, (unsigned long)len); - else - dma_cache_inv((unsigned long)addr, (unsigned long)len); -} - /* Prototype: fasdmatype_t cumanascsi_2_dma_setup(host, SCpnt, direction, min_type) * Purpose : initialises DMA/PIO * Params : host - host @@ -179,33 +174,30 @@ if (dmach != NO_DMA && (min_type == fasdma_real_all || SCp->this_residual >= 512)) { - int buf; + int bufs = SCp->buffers_residual; + int pci_dir, dma_dir, alatch_dir; + + if (bufs) + memcpy(info->sg + 1, SCp->buffer + 1, + sizeof(struct scatterlist) * bufs); + info->sg[0].address = SCp->ptr; + info->sg[0].length = SCp->this_residual; + + if (direction == DMA_OUT) + pci_dir = PCI_DMA_TODEVICE, + dma_dir = DMA_MODE_WRITE, + alatch_dir = ALATCH_DMA_OUT; + else + pci_dir = PCI_DMA_FROMDEVICE, + dma_dir = DMA_MODE_READ, + alatch_dir = ALATCH_DMA_IN; - for (buf = 1; buf <= SCp->buffers_residual && - buf < NR_SG; buf++) { - info->dmasg[buf].address = __virt_to_bus( - (unsigned long)SCp->buffer[buf].address); - info->dmasg[buf].length = SCp->buffer[buf].length; - - cumanascsi_2_invalidate(SCp->buffer[buf].address, - SCp->buffer[buf].length, - direction); - } - - info->dmasg[0].address = __virt_to_phys((unsigned long)SCp->ptr); - info->dmasg[0].length = SCp->this_residual; - cumanascsi_2_invalidate(SCp->ptr, - SCp->this_residual, direction); + pci_map_sg(NULL, info->sg, bufs + 1, pci_dir); disable_dma(dmach); - set_dma_sg(dmach, info->dmasg, buf); - if (direction == DMA_OUT) { - outb(ALATCH_DMA_OUT, info->alatch); - set_dma_mode(dmach, DMA_MODE_WRITE); - } else { - outb(ALATCH_DMA_IN, info->alatch); - set_dma_mode(dmach, DMA_MODE_READ); - } + set_dma_sg(dmach, info->sg, bufs + 1); + outb(alatch_dir, info->alatch); + set_dma_mode(dmach, dma_dir); enable_dma(dmach); outb(ALATCH_ENA_DMA, info->alatch); outb(ALATCH_DIS_BIT32, info->alatch); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acorn/scsi/cumana_2.h linux/drivers/acorn/scsi/cumana_2.h --- v2.4.0-test8/linux/drivers/acorn/scsi/cumana_2.h Fri May 12 11:21:20 2000 +++ linux/drivers/acorn/scsi/cumana_2.h Mon Sep 18 15:15:22 2000 @@ -1,7 +1,13 @@ /* - * Cumana SCSI II driver + * linux/drivers/acorn/scsi/cumana_2.h * - * Copyright (C) 1997-2000 Russell King + * Copyright (C) 1997-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. + * + * Cumana SCSI II driver */ #ifndef CUMANA_2_H #define CUMANA_2_H @@ -76,7 +82,7 @@ unsigned int alatch; /* Control register */ unsigned int terms; /* Terminator state */ unsigned int dmaarea; /* Pseudo DMA area */ - dmasg_t dmasg[NR_SG]; /* Scatter DMA list */ + struct scatterlist sg[NR_SG]; /* Scatter DMA list */ } CumanaScsi2_Info; #define CSTATUS_IRQ (1 << 0) diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acorn/scsi/eesox.c linux/drivers/acorn/scsi/eesox.c --- v2.4.0-test8/linux/drivers/acorn/scsi/eesox.c Sun Apr 2 17:28:22 2000 +++ linux/drivers/acorn/scsi/eesox.c Mon Sep 18 15:15:22 2000 @@ -1,24 +1,27 @@ /* - * linux/arch/arm/drivers/scsi/eesox.c + * linux/drivers/acorn/scsi/eesox.c * - * Copyright (C) 1997-2000 Russell King + * Copyright (C) 1997-2000 Russell King * - * This driver is based on experimentation. Hence, it may have made - * assumptions about the particular card that I have available, and - * may not be reliable! + * 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. * - * Changelog: - * 01-10-1997 RMK Created, READONLY version - * 15-02-1998 RMK READ/WRITE version + * This driver is based on experimentation. Hence, it may have made + * assumptions about the particular card that I have available, and + * may not be reliable! + * + * Changelog: + * 01-10-1997 RMK Created, READONLY version + * 15-02-1998 RMK READ/WRITE version * added DMA support and hardware definitions - * 14-03-1998 RMK Updated DMA support + * 14-03-1998 RMK Updated DMA support * Added terminator control - * 15-04-1998 RMK Only do PIO if FAS216 will allow it. - * 27-06-1998 RMK Changed asm/delay.h to linux/delay.h - * 02-04-2000 RMK 0.0.3 Fixed NO_IRQ/NO_DMA problem, updated for new + * 15-04-1998 RMK Only do PIO if FAS216 will allow it. + * 27-06-1998 RMK Changed asm/delay.h to linux/delay.h + * 02-04-2000 RMK 0.0.3 Fixed NO_IRQ/NO_DMA problem, updated for new * error handling code. */ - #include #include #include @@ -29,6 +32,7 @@ #include #include #include +#include #include #include @@ -157,15 +161,6 @@ fas216_intr(host); } -static void -eesoxscsi_invalidate(char *addr, long len, fasdmadir_t direction) -{ - if (direction == DMA_OUT) - dma_cache_wback((unsigned long)addr, (unsigned long)len); - else - dma_cache_inv((unsigned long)addr, (unsigned long)len); -} - /* Prototype: fasdmatype_t eesoxscsi_dma_setup(host, SCpnt, direction, min_type) * Purpose : initialises DMA/PIO * Params : host - host @@ -183,29 +178,27 @@ if (dmach != NO_DMA && (min_type == fasdma_real_all || SCp->this_residual >= 512)) { - int buf; + int bufs = SCp->buffers_residual; + int pci_dir, dma_dir; + + if (bufs) + memcpy(info->sg + 1, SCp->buffer + 1, + sizeof(struct scatterlist) * bufs); + info->sg[0].address = SCp->ptr; + info->sg[0].length = SCp->this_residual; + + if (direction == DMA_OUT) + pci_dir = PCI_DMA_TODEVICE, + dma_dir = DMA_MODE_WRITE; + else + pci_dir = PCI_DMA_FROMDEVICE, + dma_dir = DMA_MODE_READ; - for(buf = 1; buf <= SCp->buffers_residual && - buf < NR_SG; buf++) { - info->dmasg[buf].address = __virt_to_bus( - (unsigned long)SCp->buffer[buf].address); - info->dmasg[buf].length = SCp->buffer[buf].length; - - eesoxscsi_invalidate(SCp->buffer[buf].address, - SCp->buffer[buf].length, - direction); - } - - info->dmasg[0].address = __virt_to_phys((unsigned long)SCp->ptr); - info->dmasg[0].length = SCp->this_residual; - eesoxscsi_invalidate(SCp->ptr, - SCp->this_residual, direction); + pci_map_sg(NULL, info->sg, bufs + 1, pci_dir); disable_dma(dmach); - set_dma_sg(dmach, info->dmasg, buf); - set_dma_mode(dmach, - direction == DMA_OUT ? DMA_MODE_WRITE : - DMA_MODE_READ); + set_dma_sg(dmach, info->sg, bufs + 1); + set_dma_mode(dmach, dma_dir); enable_dma(dmach); return fasdma_real_all; } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acorn/scsi/eesox.h linux/drivers/acorn/scsi/eesox.h --- v2.4.0-test8/linux/drivers/acorn/scsi/eesox.h Sun Apr 2 17:28:22 2000 +++ linux/drivers/acorn/scsi/eesox.h Mon Sep 18 15:15:22 2000 @@ -1,7 +1,13 @@ /* - * EESOX SCSI driver + * linux/drivers/acorn/scsi/eesox.h * - * Copyright (C) 1997-2000 Russell King + * Copyright (C) 1997-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. + * + * EESOX SCSI driver */ #ifndef EESOXSCSI_H #define EESOXSCSI_H @@ -76,7 +82,7 @@ struct control control; unsigned int dmaarea; /* Pseudo DMA area */ - dmasg_t dmasg[NR_SG]; /* Scatter DMA list */ + struct scatterlist sg[NR_SG]; /* Scatter DMA list */ } EESOXScsi_Info; #endif /* HOSTS_C */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acorn/scsi/fas216.c linux/drivers/acorn/scsi/fas216.c --- v2.4.0-test8/linux/drivers/acorn/scsi/fas216.c Wed Aug 9 14:11:11 2000 +++ linux/drivers/acorn/scsi/fas216.c Mon Sep 18 15:15:22 2000 @@ -1,7 +1,11 @@ /* - * linux/arch/arm/drivers/scsi/fas216.c + * linux/arch/arm/drivers/scsi/fas216.c * - * Copyright (C) 1997-2000 Russell King + * Copyright (C) 1997-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. * * Based on information in qlogicfas.c by Tom Zerucha, Michael Griffith, and * other sources, including: @@ -33,7 +37,6 @@ * Todo: * - allow individual devices to enable sync xfers. */ - #include #include #include @@ -2177,7 +2180,7 @@ { enum res_abort res = res_failed; - if (queue_removecmd(&info->queues.issue, SCpnt)) { + if (queue_remove_cmd(&info->queues.issue, SCpnt)) { /* * The command was on the issue queue, and has not been * issued yet. We can remove the command from the queue, @@ -2187,7 +2190,7 @@ printk("on issue queue "); res = res_success; - } else if (queue_removecmd(&info->queues.disconnected, SCpnt)) { + } else if (queue_remove_cmd(&info->queues.disconnected, SCpnt)) { /* * The command was on the disconnected queue. We must * reconnect with the device if possible, and send it diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acorn/scsi/fas216.h linux/drivers/acorn/scsi/fas216.h --- v2.4.0-test8/linux/drivers/acorn/scsi/fas216.h Sun Apr 2 17:28:22 2000 +++ linux/drivers/acorn/scsi/fas216.h Mon Sep 18 15:15:22 2000 @@ -1,7 +1,13 @@ /* - * FAS216 generic driver + * linux/drivers/acorn/scsi/fas216.h * - * Copyright (C) 1997-2000 Russell King + * Copyright (C) 1997-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. + * + * FAS216 generic driver */ #ifndef FAS216_H #define FAS216_H diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acorn/scsi/msgqueue.c linux/drivers/acorn/scsi/msgqueue.c --- v2.4.0-test8/linux/drivers/acorn/scsi/msgqueue.c Thu Jun 17 01:11:35 1999 +++ linux/drivers/acorn/scsi/msgqueue.c Mon Sep 18 15:15:22 2000 @@ -1,9 +1,14 @@ /* - * drivers/acorn/scsi/msgqueue.c: message queue handling + * linux/drivers/acorn/scsi/msgqueue.c * - * Copyright (C) 1997-1998 Russell King + * Copyright (C) 1997-1998 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. + * + * message queue handling */ - #include #include #include diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acorn/scsi/msgqueue.h linux/drivers/acorn/scsi/msgqueue.h --- v2.4.0-test8/linux/drivers/acorn/scsi/msgqueue.h Sun Apr 2 17:28:22 2000 +++ linux/drivers/acorn/scsi/msgqueue.h Mon Sep 18 15:15:22 2000 @@ -1,7 +1,13 @@ /* - * msgqueue.h: message queue handling + * linux/drivers/acorn/scsi/msgqueue.h * - * Copyright (C) 1997 Russell King + * Copyright (C) 1997 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. + * + * message queue handling */ #ifndef MSGQUEUE_H #define MSGQUEUE_H diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acorn/scsi/powertec.c linux/drivers/acorn/scsi/powertec.c --- v2.4.0-test8/linux/drivers/acorn/scsi/powertec.c Sun Apr 2 17:28:22 2000 +++ linux/drivers/acorn/scsi/powertec.c Mon Sep 18 15:15:22 2000 @@ -1,7 +1,11 @@ /* - * linux/arch/arm/drivers/scsi/powertec.c + * linux/drivers/acorn/scsi/powertec.c * - * Copyright (C) 1997-2000 Russell King + * Copyright (C) 1997-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. * * This driver is based on experimentation. Hence, it may have made * assumptions about the particular card that I have available, and @@ -15,7 +19,6 @@ * 27-06-1998 RMK Changed asm/delay.h to linux/delay.h * 02-04-2000 RMK Updated for new error handling code. */ - #include #include #include @@ -26,6 +29,7 @@ #include #include #include +#include #include #include @@ -147,15 +151,6 @@ fas216_intr(host); } -static void -powertecscsi_invalidate(char *addr, long len, fasdmadir_t direction) -{ - if (direction == DMA_OUT) - dma_cache_wback((unsigned long)addr, (unsigned long)len); - else - dma_cache_inv((unsigned long)addr, (unsigned long)len); -} - /* Prototype: fasdmatype_t powertecscsi_dma_setup(host, SCpnt, direction, min_type) * Purpose : initialises DMA/PIO * Params : host - host @@ -173,29 +168,27 @@ if (dmach != NO_DMA && (min_type == fasdma_real_all || SCp->this_residual >= 512)) { - int buf; + int bufs = SCp->buffers_residual; + int pci_dir, dma_dir; + + if (bufs) + memcpy(info->sg + 1, SCp->buffer + 1, + sizeof(struct scatterlist) * bufs); + info->sg[0].address = SCp->ptr; + info->sg[0].length = SCp->this_residual; + + if (direction == DMA_OUT) + pci_dir = PCI_DMA_TODEVICE, + dma_dir = DMA_MODE_WRITE; + else + pci_dir = PCI_DMA_FROMDEVICE, + dma_dir = DMA_MODE_READ; - for (buf = 1; buf <= SCp->buffers_residual && - buf < NR_SG; buf++) { - info->dmasg[buf].address = __virt_to_bus( - (unsigned long)SCp->buffer[buf].address); - info->dmasg[buf].length = SCp->buffer[buf].length; - - powertecscsi_invalidate(SCp->buffer[buf].address, - SCp->buffer[buf].length, - direction); - } - - info->dmasg[0].address = __virt_to_phys((unsigned long)SCp->ptr); - info->dmasg[0].length = SCp->this_residual; - powertecscsi_invalidate(SCp->ptr, - SCp->this_residual, direction); + pci_map_sg(NULL, info->sg, bufs + 1, pci_dir); disable_dma(dmach); - set_dma_sg(dmach, info->dmasg, buf); - set_dma_mode(dmach, - direction == DMA_OUT ? DMA_MODE_WRITE : - DMA_MODE_READ); + set_dma_sg(dmach, info->sg, bufs + 1); + set_dma_mode(dmach, dma_dir); enable_dma(dmach); return fasdma_real_all; } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acorn/scsi/powertec.h linux/drivers/acorn/scsi/powertec.h --- v2.4.0-test8/linux/drivers/acorn/scsi/powertec.h Sun Apr 2 17:28:22 2000 +++ linux/drivers/acorn/scsi/powertec.h Mon Sep 18 15:15:22 2000 @@ -1,7 +1,13 @@ /* - * PowerTec SCSI driver + * linux/drivers/acorn/scsi/powertec.h * - * Copyright (C) 1997-2000 Russell King + * Copyright (C) 1997-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. + * + * PowerTec SCSI driver */ #ifndef POWERTECSCSI_H #define POWERTECSCSI_H @@ -74,7 +80,7 @@ } control; /* other info... */ - dmasg_t dmasg[NR_SG]; /* Scatter DMA list */ + struct scatterlist sg[NR_SG]; /* Scatter DMA list */ } PowerTecScsi_Info; #endif /* HOSTS_C */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acorn/scsi/queue.c linux/drivers/acorn/scsi/queue.c --- v2.4.0-test8/linux/drivers/acorn/scsi/queue.c Thu Jun 17 01:11:35 1999 +++ linux/drivers/acorn/scsi/queue.c Mon Sep 18 15:15:22 2000 @@ -1,40 +1,57 @@ /* - * queue.c: queue handling primitives + * linux/drivers/acorn/scsi/queue.c: queue handling primitives * - * (c) 1997 Russell King + * Copyright (C) 1997-2000 Russell King * - * Changelog: - * 15-Sep-1997 RMK Created. - * 11-Oct-1997 RMK Corrected problem with queue_remove_exclude + * 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. + * + * Changelog: + * 15-Sep-1997 RMK Created. + * 11-Oct-1997 RMK Corrected problem with queue_remove_exclude * not updating internal linked list properly * (was causing commands to go missing). + * 30-Aug-2000 RMK Use Linux list handling and spinlocks */ - -#define SECTOR_SIZE 512 - #include #include #include #include #include +#include +#include #include "../../scsi/scsi.h" MODULE_AUTHOR("Russell King"); MODULE_DESCRIPTION("SCSI command queueing"); +#define DEBUG + typedef struct queue_entry { - struct queue_entry *next; - struct queue_entry *prev; - unsigned long magic; + struct list_head list; Scsi_Cmnd *SCpnt; +#ifdef DEBUG + unsigned long magic; +#endif } QE_t; +#ifdef DEBUG #define QUEUE_MAGIC_FREE 0xf7e1c9a3 #define QUEUE_MAGIC_USED 0xf7e1cc33 +#define SET_MAGIC(q,m) ((q)->magic = (m)) +#define BAD_MAGIC(q,m) ((q)->magic != (m)) +#else +#define SET_MAGIC(q,m) do { } while (0) +#define BAD_MAGIC(q,m) (0) +#endif + #include "queue.h" +#define NR_QE 32 + /* * Function: void queue_initialise (Queue_t *queue) * Purpose : initialise a queue @@ -42,24 +59,29 @@ */ int queue_initialise (Queue_t *queue) { - unsigned int nqueues; + unsigned int nqueues = NR_QE; QE_t *q; - queue->alloc = queue->free = q = (QE_t *) kmalloc (SECTOR_SIZE, GFP_KERNEL); + spin_lock_init(&queue->queue_lock); + INIT_LIST_HEAD(&queue->head); + INIT_LIST_HEAD(&queue->free); + + /* + * If life was easier, then SCpnt would have a + * host-available list head, and we wouldn't + * need to keep free lists or allocate this + * memory. + */ + queue->alloc = q = kmalloc(sizeof(QE_t) * nqueues, GFP_KERNEL); if (q) { - nqueues = SECTOR_SIZE / sizeof (QE_t); - for (; nqueues; q++, nqueues--) { - q->next = q + 1; - q->prev = NULL; - q->magic = QUEUE_MAGIC_FREE; + SET_MAGIC(q, QUEUE_MAGIC_FREE); q->SCpnt = NULL; + list_add(&q->list, &queue->free); } - q -= 1; - q->next = NULL; } - return q != NULL; + return queue->alloc != NULL; } /* @@ -69,103 +91,69 @@ */ void queue_free (Queue_t *queue) { + if (!list_empty(&queue->head)) + printk(KERN_WARNING "freeing non-empty queue %p\n", queue); if (queue->alloc) - kfree (queue->alloc); + kfree(queue->alloc); } /* - * Function: int queue_add_cmd_ordered (Queue_t *queue, Scsi_Cmnd *SCpnt) + * Function: int queue_add_cmd(Queue_t *queue, Scsi_Cmnd *SCpnt, int head) * Purpose : Add a new command onto a queue, adding REQUEST_SENSE to head. * Params : queue - destination queue * SCpnt - command to add + * head - add command to head of queue * Returns : 0 on error, !0 on success */ -int queue_add_cmd_ordered (Queue_t *queue, Scsi_Cmnd *SCpnt) +int __queue_add(Queue_t *queue, Scsi_Cmnd *SCpnt, int head) { unsigned long flags; + struct list_head *l; QE_t *q; + int ret = 0; - save_flags_cli (flags); - q = queue->free; - if (q) - queue->free = q->next; - - if (q) { - if (q->magic != QUEUE_MAGIC_FREE) { - restore_flags (flags); - panic ("scsi queues corrupted - queue entry not free"); - } - - q->magic = QUEUE_MAGIC_USED; - q->SCpnt = SCpnt; - - if (SCpnt->cmnd[0] == REQUEST_SENSE) { /* request_sense gets put on the queue head */ - if (queue->head) { - q->prev = NULL; - q->next = queue->head; - queue->head->prev = q; - queue->head = q; - } else { - q->next = q->prev = NULL; - queue->head = queue->tail = q; - } - } else { /* others get put on the tail */ - if (queue->tail) { - q->next = NULL; - q->prev = queue->tail; - queue->tail->next = q; - queue->tail = q; - } else { - q->next = q->prev = NULL; - queue->head = queue->tail = q; - } - } - } - restore_flags (flags); - - return q != NULL; + spin_lock_irqsave(&queue->queue_lock, flags); + if (list_empty(&queue->free)) + goto empty; + + l = queue->free.next; + list_del(l); + + q = list_entry(l, QE_t, list); + if (BAD_MAGIC(q, QUEUE_MAGIC_FREE)) + BUG(); + + SET_MAGIC(q, QUEUE_MAGIC_USED); + q->SCpnt = SCpnt; + + if (head) + list_add(l, &queue->head); + else + list_add_tail(l, &queue->head); + + ret = 1; +empty: + spin_unlock_irqrestore(&queue->queue_lock, flags); + return ret; } -/* - * Function: int queue_add_cmd_tail (Queue_t *queue, Scsi_Cmnd *SCpnt) - * Purpose : Add a new command onto a queue, adding onto tail of list - * Params : queue - destination queue - * SCpnt - command to add - * Returns : 0 on error, !0 on success - */ -int queue_add_cmd_tail (Queue_t *queue, Scsi_Cmnd *SCpnt) +static Scsi_Cmnd *__queue_remove(Queue_t *queue, struct list_head *ent) { - unsigned long flags; QE_t *q; - save_flags_cli (flags); - q = queue->free; - if (q) - queue->free = q->next; - - if (q) { - if (q->magic != QUEUE_MAGIC_FREE) { - restore_flags (flags); - panic ("scsi queues corrupted - queue entry not free"); - } - - q->magic = QUEUE_MAGIC_USED; - q->SCpnt = SCpnt; + /* + * Move the entry from the "used" list onto the "free" list + */ + list_del(ent); + q = list_entry(ent, QE_t, list); + if (BAD_MAGIC(q, QUEUE_MAGIC_USED)) + BUG(); - if (queue->tail) { - q->next = NULL; - q->prev = queue->tail; - queue->tail->next = q; - queue->tail = q; - } else { - q->next = q->prev = NULL; - queue->head = queue->tail = q; - } - } - restore_flags (flags); + SET_MAGIC(q, QUEUE_MAGIC_FREE); + list_add(ent, &queue->free); - return q != NULL; + return q->SCpnt; } /* @@ -175,50 +163,21 @@ * exclude - bit array of target&lun which is busy * Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available */ -Scsi_Cmnd *queue_remove_exclude (Queue_t *queue, unsigned char *exclude) +Scsi_Cmnd *queue_remove_exclude(Queue_t *queue, void *exclude) { unsigned long flags; - Scsi_Cmnd *SCpnt; - QE_t *q, *prev; + struct list_head *l; + Scsi_Cmnd *SCpnt = NULL; - save_flags_cli (flags); - for (q = queue->head, prev = NULL; q; q = q->next) { - if (exclude && !test_bit (q->SCpnt->target * 8 + q->SCpnt->lun, exclude)) + spin_lock_irqsave(&queue->queue_lock, flags); + list_for_each(l, &queue->head) { + QE_t *q = list_entry(l, QE_t, list); + if (!test_bit(q->SCpnt->target * 8 + q->SCpnt->lun, exclude)) { + SCpnt = __queue_remove(queue, l); break; - prev = q; - } - - if (q) { - if (q->magic != QUEUE_MAGIC_USED) { - restore_flags (flags); - panic ("q_remove_exclude: scsi queues corrupted - queue entry not used"); - } - if (q->prev != prev) - panic ("q_remove_exclude: scsi queues corrupted - q->prev != prev"); - - if (!prev) { - queue->head = q->next; - if (queue->head) - queue->head->prev = NULL; - else - queue->tail = NULL; - } else { - prev->next = q->next; - if (prev->next) - prev->next->prev = prev; - else - queue->tail = prev; } - - SCpnt = q->SCpnt; - - q->next = queue->free; - queue->free = q; - q->magic = QUEUE_MAGIC_FREE; - } else - SCpnt = NULL; - - restore_flags (flags); + } + spin_unlock_irqrestore(&queue->queue_lock, flags); return SCpnt; } @@ -229,35 +188,15 @@ * Params : queue - queue to remove command from * Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available */ -Scsi_Cmnd *queue_remove (Queue_t *queue) +Scsi_Cmnd *queue_remove(Queue_t *queue) { unsigned long flags; - Scsi_Cmnd *SCpnt; - QE_t *q; - - save_flags_cli (flags); - q = queue->head; - if (q) { - queue->head = q->next; - if (queue->head) - queue->head->prev = NULL; - else - queue->tail = NULL; - - if (q->magic != QUEUE_MAGIC_USED) { - restore_flags (flags); - panic ("scsi queues corrupted - queue entry not used"); - } - - SCpnt = q->SCpnt; + Scsi_Cmnd *SCpnt = NULL; - q->next = queue->free; - queue->free = q; - q->magic = QUEUE_MAGIC_FREE; - } else - SCpnt = NULL; - - restore_flags (flags); + spin_lock_irqsave(&queue->queue_lock, flags); + if (!list_empty(&queue->head)) + SCpnt = __queue_remove(queue, queue->head.next); + spin_unlock_irqrestore(&queue->queue_lock, flags); return SCpnt; } @@ -274,50 +213,19 @@ Scsi_Cmnd *queue_remove_tgtluntag (Queue_t *queue, int target, int lun, int tag) { unsigned long flags; - Scsi_Cmnd *SCpnt; - QE_t *q, *prev; + struct list_head *l; + Scsi_Cmnd *SCpnt = NULL; - save_flags_cli (flags); - for (q = queue->head, prev = NULL; q; q = q->next) { - if (q->SCpnt->target == target && - q->SCpnt->lun == lun && - q->SCpnt->tag == tag) + spin_lock_irqsave(&queue->queue_lock, flags); + list_for_each(l, &queue->head) { + QE_t *q = list_entry(l, QE_t, list); + if (q->SCpnt->target == target && q->SCpnt->lun == lun && + q->SCpnt->tag == tag) { + SCpnt = __queue_remove(queue, l); break; - - prev = q; - } - - if (q) { - if (q->magic != QUEUE_MAGIC_USED) { - restore_flags (flags); - panic ("q_remove_tgtluntag: scsi queues corrupted - queue entry not used"); - } - if (q->prev != prev) - panic ("q_remove_tgtluntag: scsi queues corrupted - q->prev != prev"); - - if (!prev) { - queue->head = q->next; - if (queue->head) - queue->head->prev = NULL; - else - queue->tail = NULL; - } else { - prev->next = q->next; - if (prev->next) - prev->next->prev = prev; - else - queue->tail = prev; } - - SCpnt = q->SCpnt; - - q->magic = QUEUE_MAGIC_FREE; - q->next = queue->free; - queue->free = q; - } else - SCpnt = NULL; - - restore_flags (flags); + } + spin_unlock_irqrestore(&queue->queue_lock, flags); return SCpnt; } @@ -333,96 +241,58 @@ */ int queue_probetgtlun (Queue_t *queue, int target, int lun) { - QE_t *q; - - for (q = queue->head; q; q = q->next) - if (q->SCpnt->target == target && - q->SCpnt->lun == lun) - break; - - return q != NULL; -} - -/* - * Function: int queue_cmdonqueue (queue, SCpnt) - * Purpose : check to see if we have a command on the queue - * Params : queue - queue to look in - * SCpnt - command to find - * Returns : 0 if not found, != 0 if found - */ -int queue_cmdonqueue (Queue_t *queue, Scsi_Cmnd *SCpnt) -{ - QE_t *q; + unsigned long flags; + struct list_head *l; + int found = 0; - for (q = queue->head; q; q = q->next) - if (q->SCpnt == SCpnt) + spin_lock_irqsave(&queue->queue_lock, flags); + list_for_each(l, &queue->head) { + QE_t *q = list_entry(l, QE_t, list); + if (q->SCpnt->target == target && q->SCpnt->lun == lun) { + found = 1; break; + } + } + spin_unlock_irqrestore(&queue->queue_lock, flags); - return q != NULL; + return found; } /* - * Function: int queue_removecmd (Queue_t *queue, Scsi_Cmnd *SCpnt) + * Function: int queue_remove_cmd(Queue_t *queue, Scsi_Cmnd *SCpnt) * Purpose : remove a specific command from the queues * Params : queue - queue to look in * SCpnt - command to find * Returns : 0 if not found */ -int queue_removecmd (Queue_t *queue, Scsi_Cmnd *SCpnt) +int queue_remove_cmd(Queue_t *queue, Scsi_Cmnd *SCpnt) { unsigned long flags; - QE_t *q, *prev; + struct list_head *l; + int found = 0; - save_flags_cli (flags); - for (q = queue->head, prev = NULL; q; q = q->next) { - if (q->SCpnt == SCpnt) + spin_lock_irqsave(&queue->queue_lock, flags); + list_for_each(l, &queue->head) { + QE_t *q = list_entry(l, QE_t, list); + if (q->SCpnt == SCpnt) { + __queue_remove(queue, l); + found = 1; break; - - prev = q; - } - - if (q) { - if (q->magic != QUEUE_MAGIC_USED) { - restore_flags (flags); - panic ("q_removecmd: scsi queues corrupted - queue entry not used"); } - if (q->prev != prev) - panic ("q_removecmd: scsi queues corrupted - q->prev != prev"); - - if (!prev) { - queue->head = q->next; - if (queue->head) - queue->head->prev = NULL; - else - queue->tail = NULL; - } else { - prev->next = q->next; - if (prev->next) - prev->next->prev = prev; - else - queue->tail = prev; - } - - q->magic = QUEUE_MAGIC_FREE; - q->next = queue->free; - queue->free = q; } + spin_unlock_irqrestore(&queue->queue_lock, flags); - restore_flags (flags); - - return q != NULL; + return found; } EXPORT_SYMBOL(queue_initialise); EXPORT_SYMBOL(queue_free); +EXPORT_SYMBOL(__queue_add); EXPORT_SYMBOL(queue_remove); EXPORT_SYMBOL(queue_remove_exclude); -EXPORT_SYMBOL(queue_add_cmd_ordered); -EXPORT_SYMBOL(queue_add_cmd_tail); EXPORT_SYMBOL(queue_remove_tgtluntag); +EXPORT_SYMBOL(queue_remove_cmd); EXPORT_SYMBOL(queue_probetgtlun); -EXPORT_SYMBOL(queue_cmdonqueue); -EXPORT_SYMBOL(queue_removecmd); #ifdef MODULE int init_module (void) diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acorn/scsi/queue.h linux/drivers/acorn/scsi/queue.h --- v2.4.0-test8/linux/drivers/acorn/scsi/queue.h Sun Apr 2 17:28:22 2000 +++ linux/drivers/acorn/scsi/queue.h Mon Sep 18 15:15:22 2000 @@ -1,16 +1,20 @@ /* - * queue.h: queue handling + * linux/drivers/acorn/scsi/queue.h: queue handling * - * Copyright (C) 1997 Russell King + * Copyright (C) 1997 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. */ #ifndef QUEUE_H #define QUEUE_H typedef struct { - struct queue_entry *head; /* head of queue */ - struct queue_entry *tail; /* tail of queue */ - struct queue_entry *free; /* free list */ - void *alloc; /* start of allocated mem */ + struct list_head head; + struct list_head free; + spinlock_t queue_lock; + void *alloc; /* start of allocated mem */ } Queue_t; /* @@ -36,32 +40,27 @@ extern Scsi_Cmnd *queue_remove (Queue_t *queue); /* - * Function: Scsi_Cmnd *queue_remove_exclude_ref (queue, exclude, ref) + * Function: Scsi_Cmnd *queue_remove_exclude_ref (queue, exclude) * Purpose : remove a SCSI command from a queue * Params : queue - queue to remove command from * exclude - array of busy LUNs - * ref - a reference that can be used to put the command back * Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available */ -extern Scsi_Cmnd *queue_remove_exclude (Queue_t *queue, unsigned char *exclude); - -/* - * Function: int queue_add_cmd_ordered (Queue_t *queue, Scsi_Cmnd *SCpnt) - * Purpose : Add a new command onto a queue, queueing REQUEST_SENSE first - * Params : queue - destination queue - * SCpnt - command to add - * Returns : 0 on error, !0 on success - */ -extern int queue_add_cmd_ordered (Queue_t *queue, Scsi_Cmnd *SCpnt); +extern Scsi_Cmnd *queue_remove_exclude (Queue_t *queue, void *exclude); +#define queue_add_cmd_ordered(queue,SCpnt) \ + __queue_add(queue,SCpnt,(SCpnt)->cmnd[0] == REQUEST_SENSE) +#define queue_add_cmd_tail(queue,SCpnt) \ + __queue_add(queue,SCpnt,0) /* - * Function: int queue_add_cmd_tail (Queue_t *queue, Scsi_Cmnd *SCpnt) - * Purpose : Add a new command onto a queue, queueing at end of list + * Function: int __queue_add(Queue_t *queue, Scsi_Cmnd *SCpnt, int head) + * Purpose : Add a new command onto a queue * Params : queue - destination queue * SCpnt - command to add + * head - add command to head of queue * Returns : 0 on error, !0 on success */ -extern int queue_add_cmd_tail (Queue_t *queue, Scsi_Cmnd *SCpnt); +extern int __queue_add(Queue_t *queue, Scsi_Cmnd *SCpnt, int head); /* * Function: Scsi_Cmnd *queue_remove_tgtluntag (queue, target, lun, tag) @@ -86,21 +85,12 @@ extern int queue_probetgtlun (Queue_t *queue, int target, int lun); /* - * Function: int queue_cmdonqueue (queue, SCpnt) - * Purpose : check to see if we have a command on the queue - * Params : queue - queue to look in - * SCpnt - command to find - * Returns : 0 if not found, != 0 if found - */ -int queue_cmdonqueue (Queue_t *queue, Scsi_Cmnd *SCpnt); - -/* - * Function: int queue_removecmd (Queue_t *queue, Scsi_Cmnd *SCpnt) + * Function: int queue_remove_cmd (Queue_t *queue, Scsi_Cmnd *SCpnt) * Purpose : remove a specific command from the queues * Params : queue - queue to look in * SCpnt - command to find * Returns : 0 if not found */ -int queue_removecmd (Queue_t *queue, Scsi_Cmnd *SCpnt); +int queue_remove_cmd(Queue_t *queue, Scsi_Cmnd *SCpnt); #endif /* QUEUE_H */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/Makefile linux/drivers/acpi/Makefile --- v2.4.0-test8/linux/drivers/acpi/Makefile Wed Jul 12 13:21:57 2000 +++ linux/drivers/acpi/Makefile Fri Sep 15 18:21:43 2000 @@ -2,7 +2,7 @@ # Makefile for the Linux ACPI interpreter # -SUB_DIRS := +SUB_DIRS := MOD_SUB_DIRS := $(SUB_DIRS) MOD_IN_SUB_DIRS := ALL_SUB_DIRS := $(SUB_DIRS) @@ -11,13 +11,22 @@ O_OBJS := M_OBJS := -ACPI_OBJS := driver.o ec.o cpu.o os.o sys.o tables.o -ACPI_OBJS += $(patsubst %.c,%.o,$(wildcard */*.c)) +export ACPI_CFLAGS +ACPI_CFLAGS := -D_LINUX -EXTRA_CFLAGS += -I./include -D_LINUX +EXTRA_CFLAGS += -I./include + +EXTRA_CFLAGS += $(ACPI_CFLAGS) # if the interpreter is used, it overrides arch/i386/kernel/acpi.c ifeq ($(CONFIG_ACPI_INTERPRETER),y) + + SUB_DIRS += common dispatcher events hardware\ + interpreter namespace parser resources tables + + ACPI_OBJS := $(patsubst %,%.o,$(SUB_DIRS)) + ACPI_OBJS += $(patsubst %.c,%.o,$(wildcard *.c)) + O_OBJS += $(ACPI_OBJS) endif diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/common/Makefile linux/drivers/acpi/common/Makefile --- v2.4.0-test8/linux/drivers/acpi/common/Makefile Wed Dec 31 16:00:00 1969 +++ linux/drivers/acpi/common/Makefile Fri Sep 15 18:21:43 2000 @@ -0,0 +1,28 @@ +# +# Makefile for all Linux ACPI interpreter subdirectories +# + +SUB_DIRS := +MOD_SUB_DIRS := $(SUB_DIRS) +MOD_IN_SUB_DIRS := +ALL_SUB_DIRS := $(SUB_DIRS) + +O_TARGET := ../$(shell basename `pwd`).o +O_OBJS := +M_OBJS := + +ACPI_OBJS := $(patsubst %.c,%.o,$(wildcard *.c)) + +EXTRA_CFLAGS += -I../include + +EXTRA_CFLAGS += $(ACPI_CFLAGS) + +# if the interpreter is used, it overrides arch/i386/kernel/acpi.c +ifeq ($(CONFIG_ACPI_INTERPRETER),y) + O_OBJS := $(ACPI_OBJS) +endif + +include $(TOPDIR)/Rules.make + +clean: + $(RM) *.o diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/common/cmalloc.c linux/drivers/acpi/common/cmalloc.c --- v2.4.0-test8/linux/drivers/acpi/common/cmalloc.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/common/cmalloc.c Fri Sep 15 14:30:29 2000 @@ -1,6 +1,7 @@ /****************************************************************************** * * Module Name: cmalloc - local memory allocation routines + * $Revision: 73 $ * *****************************************************************************/ @@ -24,13 +25,13 @@ #include "acpi.h" -#include "parser.h" -#include "interp.h" -#include "namesp.h" -#include "globals.h" +#include "acparser.h" +#include "acinterp.h" +#include "acnamesp.h" +#include "acglobal.h" #define _COMPONENT MISCELLANEOUS - MODULE_NAME ("cmalloc"); + MODULE_NAME ("cmalloc") /***************************************************************************** @@ -52,8 +53,8 @@ _cm_allocate ( u32 size, u32 component, - ACPI_STRING module, - s32 line) + NATIVE_CHAR *module, + u32 line) { void *address = NULL; @@ -98,8 +99,8 @@ _cm_callocate ( u32 size, u32 component, - ACPI_STRING module, - s32 line) + NATIVE_CHAR *module, + u32 line) { void *address = NULL; @@ -146,8 +147,8 @@ _cm_free ( void *address, u32 component, - ACPI_STRING module, - s32 line) + NATIVE_CHAR *module, + u32 line) { if (NULL == address) { diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/common/cmclib.c linux/drivers/acpi/common/cmclib.c --- v2.4.0-test8/linux/drivers/acpi/common/cmclib.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/acpi/common/cmclib.c Fri Sep 15 14:30:29 2000 @@ -0,0 +1,821 @@ +/****************************************************************************** + * + * Module Name: cmclib - Local implementation of C library functions + * $Revision: 24 $ + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 R. Byron Moore + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "acpi.h" +#include "acevents.h" +#include "achware.h" +#include "acnamesp.h" +#include "acinterp.h" +#include "amlcode.h" + +/* + * These implementations of standard C Library routines can optionally be + * used if a C library is not available. In general, they are less efficient + * than an inline or assembly implementation + */ + +#define _COMPONENT MISCELLANEOUS + MODULE_NAME ("cmclib") + + +#ifdef _MSC_VER /* disable some level-4 warnings for VC++ */ +#pragma warning(disable:4706) /* warning C4706: assignment within conditional expression */ +#endif + +#ifndef ACPI_USE_SYSTEM_CLIBRARY + +/******************************************************************************* + * + * FUNCTION: strlen + * + * PARAMETERS: String - Null terminated string + * + * RETURN: Length + * + * DESCRIPTION: Returns the length of the input string + * + ******************************************************************************/ + + +NATIVE_UINT +acpi_cm_strlen ( + const NATIVE_CHAR *string) +{ + NATIVE_UINT length = 0; + + + /* Count the string until a null is encountered */ + + while (*string) { + length++; + string++; + } + + return (length); +} + + +/******************************************************************************* + * + * FUNCTION: strcpy + * + * PARAMETERS: Dst_string - Target of the copy + * Src_string - The source string to copy + * + * RETURN: Dst_string + * + * DESCRIPTION: Copy a null terminated string + * + ******************************************************************************/ + +NATIVE_CHAR * +acpi_cm_strcpy ( + NATIVE_CHAR *dst_string, + const NATIVE_CHAR *src_string) +{ + NATIVE_CHAR *string = dst_string; + + + /* Move bytes brute force */ + + while (*src_string) { + *string = *src_string; + + string++; + src_string++; + } + + /* Null terminate */ + + *string = 0; + + return (dst_string); +} + + +/******************************************************************************* + * + * FUNCTION: strncpy + * + * PARAMETERS: Dst_string - Target of the copy + * Src_string - The source string to copy + * Count - Maximum # of bytes to copy + * + * RETURN: Dst_string + * + * DESCRIPTION: Copy a null terminated string, with a maximum length + * + ******************************************************************************/ + +NATIVE_CHAR * +acpi_cm_strncpy ( + NATIVE_CHAR *dst_string, + const NATIVE_CHAR *src_string, + NATIVE_UINT count) +{ + NATIVE_CHAR *string = dst_string; + + + /* Copy the string */ + + for (string = dst_string; + count && (count--, (*string++ = *src_string++)); ) + {;} + + /* Pad with nulls if necessary */ + + while (count--) { + *string = 0; + string++; + } + + /* Return original pointer */ + + return (dst_string); +} + + +/******************************************************************************* + * + * FUNCTION: strcmp + * + * PARAMETERS: String1 - First string + * String2 - Second string + * + * RETURN: Index where strings mismatched, or 0 if strings matched + * + * DESCRIPTION: Compare two null terminated strings + * + ******************************************************************************/ + +u32 +acpi_cm_strcmp ( + const NATIVE_CHAR *string1, + const NATIVE_CHAR *string2) +{ + + + for ( ; (*string1 == *string2); string2++) { + if (!*string1++) { + return (0); + } + } + + + return ((unsigned char) *string1 - (unsigned char) *string2); +} + + +/******************************************************************************* + * + * FUNCTION: strncmp + * + * PARAMETERS: String1 - First string + * String2 - Second string + * Count - Maximum # of bytes to compare + * + * RETURN: Index where strings mismatched, or 0 if strings matched + * + * DESCRIPTION: Compare two null terminated strings, with a maximum length + * + ******************************************************************************/ + +u32 +acpi_cm_strncmp ( + const NATIVE_CHAR *string1, + const NATIVE_CHAR *string2, + NATIVE_UINT count) +{ + + + for ( ; count-- && (*string1 == *string2); string2++) { + if (!*string1++) { + return (0); + } + } + + return ((count == -1) ? 0 : ((unsigned char) *string1 - + (unsigned char) *string2)); +} + + +/******************************************************************************* + * + * FUNCTION: Strcat + * + * PARAMETERS: Dst_string - Target of the copy + * Src_string - The source string to copy + * + * RETURN: Dst_string + * + * DESCRIPTION: Append a null terminated string to a null terminated string + * + ******************************************************************************/ + +NATIVE_CHAR * +acpi_cm_strcat ( + NATIVE_CHAR *dst_string, + const NATIVE_CHAR *src_string) +{ + NATIVE_CHAR *string; + + + /* Find end of the destination string */ + + for (string = dst_string; *string++; ) { ; } + + /* Concatinate the string */ + + for (--string; (*string++ = *src_string++); ) { ; } + + return (dst_string); +} + + +/******************************************************************************* + * + * FUNCTION: strncat + * + * PARAMETERS: Dst_string - Target of the copy + * Src_string - The source string to copy + * Count - Maximum # of bytes to copy + * + * RETURN: Dst_string + * + * DESCRIPTION: Append a null terminated string to a null terminated string, + * with a maximum count. + * + ******************************************************************************/ + +NATIVE_CHAR * +acpi_cm_strncat ( + NATIVE_CHAR *dst_string, + const NATIVE_CHAR *src_string, + NATIVE_UINT count) +{ + NATIVE_CHAR *string; + + + if (count) { + /* Find end of the destination string */ + + for (string = dst_string; *string++; ) { ; } + + /* Concatinate the string */ + + for (--string; (*string++ = *src_string++) && --count; ) { ; } + + /* Null terminate if necessary */ + + if (!count) { + *string = 0; + } + } + + return (dst_string); +} + + +/******************************************************************************* + * + * FUNCTION: memcpy + * + * PARAMETERS: Dest - Target of the copy + * Src - Source buffer to copy + * Count - Number of bytes to copy + * + * RETURN: Dest + * + * DESCRIPTION: Copy arbitrary bytes of memory + * + ******************************************************************************/ + +void * +acpi_cm_memcpy ( + void *dest, + const void *src, + NATIVE_UINT count) +{ + NATIVE_CHAR *new = (NATIVE_CHAR *) dest; + NATIVE_CHAR *old = (NATIVE_CHAR *) src; + + + while (count) { + *new = *old; + new++; + old++; + count--; + } + + return (dest); +} + + +/******************************************************************************* + * + * FUNCTION: memset + * + * PARAMETERS: Dest - Buffer to set + * Value - Value to set each byte of memory + * Count - Number of bytes to set + * + * RETURN: Dest + * + * DESCRIPTION: Initialize a buffer to a known value. + * + ******************************************************************************/ + +void * +acpi_cm_memset ( + void *dest, + u32 value, + NATIVE_UINT count) +{ + NATIVE_CHAR *new = (NATIVE_CHAR *) dest; + + + while (count) { + *new = (char) value; + new++; + count--; + } + + return (dest); +} + + +#define NEGATIVE 1 +#define POSITIVE 0 + + +#define _XA 0x00 /* extra alphabetic - not supported */ +#define _XS 0x40 /* extra space */ +#define _BB 0x00 /* BEL, BS, etc. - not supported */ +#define _CN 0x20 /* CR, FF, HT, NL, VT */ +#define _DI 0x04 /* '0'-'9' */ +#define _LO 0x02 /* 'a'-'z' */ +#define _PU 0x10 /* punctuation */ +#define _SP 0x08 /* space */ +#define _UP 0x01 /* 'A'-'Z' */ +#define _XD 0x80 /* '0'-'9', 'A'-'F', 'a'-'f' */ + +const u8 _ctype[257] = { + _CN, /* 0x0 0. */ + _CN, /* 0x1 1. */ + _CN, /* 0x2 2. */ + _CN, /* 0x3 3. */ + _CN, /* 0x4 4. */ + _CN, /* 0x5 5. */ + _CN, /* 0x6 6. */ + _CN, /* 0x7 7. */ + _CN, /* 0x8 8. */ + _CN|_SP, /* 0x9 9. */ + _CN|_SP, /* 0xA 10. */ + _CN|_SP, /* 0xB 11. */ + _CN|_SP, /* 0xC 12. */ + _CN|_SP, /* 0xD 13. */ + _CN, /* 0xE 14. */ + _CN, /* 0xF 15. */ + _CN, /* 0x10 16. */ + _CN, /* 0x11 17. */ + _CN, /* 0x12 18. */ + _CN, /* 0x13 19. */ + _CN, /* 0x14 20. */ + _CN, /* 0x15 21. */ + _CN, /* 0x16 22. */ + _CN, /* 0x17 23. */ + _CN, /* 0x18 24. */ + _CN, /* 0x19 25. */ + _CN, /* 0x1A 26. */ + _CN, /* 0x1B 27. */ + _CN, /* 0x1C 28. */ + _CN, /* 0x1D 29. */ + _CN, /* 0x1E 30. */ + _CN, /* 0x1F 31. */ + _XS|_SP, /* 0x20 32. ' ' */ + _PU, /* 0x21 33. '!' */ + _PU, /* 0x22 34. '"' */ + _PU, /* 0x23 35. '#' */ + _PU, /* 0x24 36. '$' */ + _PU, /* 0x25 37. '%' */ + _PU, /* 0x26 38. '&' */ + _PU, /* 0x27 39. ''' */ + _PU, /* 0x28 40. '(' */ + _PU, /* 0x29 41. ')' */ + _PU, /* 0x2A 42. '*' */ + _PU, /* 0x2B 43. '+' */ + _PU, /* 0x2C 44. ',' */ + _PU, /* 0x2D 45. '-' */ + _PU, /* 0x2E 46. '.' */ + _PU, /* 0x2F 47. '/' */ + _XD|_DI, /* 0x30 48. '0' */ + _XD|_DI, /* 0x31 49. '1' */ + _XD|_DI, /* 0x32 50. '2' */ + _XD|_DI, /* 0x33 51. '3' */ + _XD|_DI, /* 0x34 52. '4' */ + _XD|_DI, /* 0x35 53. '5' */ + _XD|_DI, /* 0x36 54. '6' */ + _XD|_DI, /* 0x37 55. '7' */ + _XD|_DI, /* 0x38 56. '8' */ + _XD|_DI, /* 0x39 57. '9' */ + _PU, /* 0x3A 58. ':' */ + _PU, /* 0x3B 59. ';' */ + _PU, /* 0x3C 60. '<' */ + _PU, /* 0x3D 61. '=' */ + _PU, /* 0x3E 62. '>' */ + _PU, /* 0x3F 63. '?' */ + _PU, /* 0x40 64. '@' */ + _XD|_UP, /* 0x41 65. 'A' */ + _XD|_UP, /* 0x42 66. 'B' */ + _XD|_UP, /* 0x43 67. 'C' */ + _XD|_UP, /* 0x44 68. 'D' */ + _XD|_UP, /* 0x45 69. 'E' */ + _XD|_UP, /* 0x46 70. 'F' */ + _UP, /* 0x47 71. 'G' */ + _UP, /* 0x48 72. 'H' */ + _UP, /* 0x49 73. 'I' */ + _UP, /* 0x4A 74. 'J' */ + _UP, /* 0x4B 75. 'K' */ + _UP, /* 0x4C 76. 'L' */ + _UP, /* 0x4D 77. 'M' */ + _UP, /* 0x4E 78. 'N' */ + _UP, /* 0x4F 79. 'O' */ + _UP, /* 0x50 80. 'P' */ + _UP, /* 0x51 81. 'Q' */ + _UP, /* 0x52 82. 'R' */ + _UP, /* 0x53 83. 'S' */ + _UP, /* 0x54 84. 'T' */ + _UP, /* 0x55 85. 'U' */ + _UP, /* 0x56 86. 'V' */ + _UP, /* 0x57 87. 'W' */ + _UP, /* 0x58 88. 'X' */ + _UP, /* 0x59 89. 'Y' */ + _UP, /* 0x5A 90. 'Z' */ + _PU, /* 0x5B 91. '[' */ + _PU, /* 0x5C 92. '\' */ + _PU, /* 0x5D 93. ']' */ + _PU, /* 0x5E 94. '^' */ + _PU, /* 0x5F 95. '_' */ + _PU, /* 0x60 96. '`' */ + _XD|_LO, /* 0x61 97. 'a' */ + _XD|_LO, /* 0x62 98. 'b' */ + _XD|_LO, /* 0x63 99. 'c' */ + _XD|_LO, /* 0x64 100. 'd' */ + _XD|_LO, /* 0x65 101. 'e' */ + _XD|_LO, /* 0x66 102. 'f' */ + _LO, /* 0x67 103. 'g' */ + _LO, /* 0x68 104. 'h' */ + _LO, /* 0x69 105. 'i' */ + _LO, /* 0x6A 106. 'j' */ + _LO, /* 0x6B 107. 'k' */ + _LO, /* 0x6C 108. 'l' */ + _LO, /* 0x6D 109. 'm' */ + _LO, /* 0x6E 110. 'n' */ + _LO, /* 0x6F 111. 'o' */ + _LO, /* 0x70 112. 'p' */ + _LO, /* 0x71 113. 'q' */ + _LO, /* 0x72 114. 'r' */ + _LO, /* 0x73 115. 's' */ + _LO, /* 0x74 116. 't' */ + _LO, /* 0x75 117. 'u' */ + _LO, /* 0x76 118. 'v' */ + _LO, /* 0x77 119. 'w' */ + _LO, /* 0x78 120. 'x' */ + _LO, /* 0x79 121. 'y' */ + _LO, /* 0x7A 122. 'z' */ + _PU, /* 0x7B 123. '{' */ + _PU, /* 0x7C 124. '|' */ + _PU, /* 0x7D 125. '}' */ + _PU, /* 0x7E 126. '~' */ + _CN, /* 0x7F 127. */ + + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x80 to 0x8F */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x90 to 0x9F */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xA0 to 0xAF */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xB0 to 0xBF */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xC0 to 0xCF */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xD0 to 0xDF */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xE0 to 0xEF */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* 0xF0 to 0x100 */ +}; + +#define IS_UPPER(c) (_ctype[(unsigned char)(c)] & (_UP)) +#define IS_LOWER(c) (_ctype[(unsigned char)(c)] & (_LO)) +#define IS_DIGIT(c) (_ctype[(unsigned char)(c)] & (_DI)) +#define IS_SPACE(c) (_ctype[(unsigned char)(c)] & (_SP)) + + +/******************************************************************************* + * + * FUNCTION: Acpi_cm_to_upper + * + * PARAMETERS: + * + * RETURN: + * + * DESCRIPTION: Convert character to uppercase + * + ******************************************************************************/ + +u32 +acpi_cm_to_upper ( + u32 c) +{ + + return (IS_LOWER(c) ? ((c)-0x20) : (c)); +} + + +/******************************************************************************* + * + * FUNCTION: Acpi_cm_to_lower + * + * PARAMETERS: + * + * RETURN: + * + * DESCRIPTION: Convert character to lowercase + * + ******************************************************************************/ + +u32 +acpi_cm_to_lower ( + u32 c) +{ + + return (IS_UPPER(c) ? ((c)+0x20) : (c)); +} + + +/******************************************************************************* + * + * FUNCTION: strupr + * + * PARAMETERS: Src_string - The source string to convert to + * + * RETURN: Src_string + * + * DESCRIPTION: Convert string to uppercase + * + ******************************************************************************/ + +NATIVE_CHAR * +acpi_cm_strupr ( + NATIVE_CHAR *src_string) +{ + NATIVE_CHAR *string; + + + /* Walk entire string, uppercasing the letters */ + + for (string = src_string; *string; ) { + *string = (char) acpi_cm_to_upper (*string); + string++; + } + + + return (src_string); +} + + +/******************************************************************************* + * + * FUNCTION: strstr + * + * PARAMETERS: String1 - + * String2 + * + * RETURN: + * + * DESCRIPTION: Checks if String2 occurs in String1. This is not really a + * full implementation of strstr, only sufficient for command + * matching + * + ******************************************************************************/ + +NATIVE_CHAR * +acpi_cm_strstr ( + NATIVE_CHAR *string1, + NATIVE_CHAR *string2) +{ + NATIVE_CHAR *string; + + + if (acpi_cm_strlen (string2) > acpi_cm_strlen (string1)) { + return (NULL); + } + + /* Walk entire string, uppercasing the letters */ + + for (string = string1; *string2; ) { + if (*string2 != *string) { + return (NULL); + } + + string2++; + string++; + } + + + return (string1); +} + + +/******************************************************************************* + * + * FUNCTION: strtoul + * + * PARAMETERS: String - Null terminated string + * Terminater - Where a pointer to the terminating byte is returned + * Base - Radix of the string + * + * RETURN: Converted value + * + * DESCRIPTION: Convert a string into an unsigned value. + * + ******************************************************************************/ + +u32 +acpi_cm_strtoul ( + const NATIVE_CHAR *string, + NATIVE_CHAR **terminator, + u32 base) +{ + u32 converted = 0; + u32 index; + u32 sign; + const NATIVE_CHAR *string_start; + u32 return_value = 0; + ACPI_STATUS status = AE_OK; + + + /* + * Save the value of the pointer to the buffer's first + * character, save the current errno value, and then + * skip over any white space in the buffer: + */ + string_start = string; + while (IS_SPACE (*string) || *string == '\t') { + ++string; + } + + /* + * The buffer may contain an optional plus or minus sign. + * If it does, then skip over it but remember what is was: + */ + if (*string == '-') { + sign = NEGATIVE; + ++string; + } + + else if (*string == '+') { + ++string; + sign = POSITIVE; + } + + else { + sign = POSITIVE; + } + + /* + * If the input parameter Base is zero, then we need to + * determine if it is octal, decimal, or hexadecimal: + */ + if (base == 0) { + if (*string == '0') { + if (acpi_cm_to_lower (*(++string)) == 'x') { + base = 16; + ++string; + } + + else { + base = 8; + } + } + + else { + base = 10; + } + } + + else if (base < 2 || base > 36) { + /* + * The specified Base parameter is not in the domain of + * this function: + */ + goto done; + } + + /* + * For octal and hexadecimal bases, skip over the leading + * 0 or 0x, if they are present. + */ + if (base == 8 && *string == '0') { + string++; + } + + if (base == 16 && + *string == '0' && + acpi_cm_to_lower (*(++string)) == 'x') + { + string++; + } + + + /* + * Main loop: convert the string to an unsigned long: + */ + while (*string) { + if (IS_DIGIT (*string)) { + index = *string - '0'; + } + + else { + index = acpi_cm_to_upper (*string); + if (IS_UPPER (index)) { + index = index - 'A' + 10; + } + + else { + goto done; + } + } + + if (index >= base) { + goto done; + } + + /* + * Check to see if value is out of range: + */ + + if (return_value > ((ACPI_UINT32_MAX - (u32) index) / + (u32) base)) + { + status = AE_ERROR; + return_value = 0L; /* reset */ + } + + else { + return_value *= base; + return_value += index; + converted = 1; + } + + ++string; + } + +done: + /* + * If appropriate, update the caller's pointer to the next + * unconverted character in the buffer. + */ + if (terminator) { + if (converted == 0 && return_value == 0L && string != NULL) { + *terminator = (NATIVE_CHAR *) string_start; + } + + else { + *terminator = (NATIVE_CHAR *) string; + } + } + + if (status == AE_ERROR) { + return_value = ACPI_UINT32_MAX; + } + + /* + * If a minus sign was present, then "the conversion is negated": + */ + if (sign == NEGATIVE) { + return_value = (ACPI_UINT32_MAX - return_value) + 1; + } + + return (return_value); +} + +#endif /* ACPI_USE_SYSTEM_CLIBRARY */ + diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/common/cmcopy.c linux/drivers/acpi/common/cmcopy.c --- v2.4.0-test8/linux/drivers/acpi/common/cmcopy.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/common/cmcopy.c Fri Sep 15 14:30:29 2000 @@ -1,6 +1,7 @@ /****************************************************************************** * * Module Name: cmcopy - Internal to external object translation utilities + * $Revision: 56 $ * *****************************************************************************/ @@ -24,17 +25,17 @@ #include "acpi.h" -#include "interp.h" -#include "namesp.h" +#include "acinterp.h" +#include "acnamesp.h" #define _COMPONENT MISCELLANEOUS - MODULE_NAME ("cmcopy"); + MODULE_NAME ("cmcopy") typedef struct search_st { - ACPI_OBJECT_INTERNAL *internal_obj; + ACPI_OPERAND_OBJECT *internal_obj; u32 index; ACPI_OBJECT *external_obj; @@ -64,13 +65,13 @@ ACPI_STATUS acpi_cm_build_external_simple_object ( - ACPI_OBJECT_INTERNAL *internal_obj, + ACPI_OPERAND_OBJECT *internal_obj, ACPI_OBJECT *external_obj, u8 *data_space, u32 *buffer_space_used) { u32 length = 0; - char *source_ptr = NULL; + u8 *source_ptr = NULL; /* @@ -103,8 +104,8 @@ length = internal_obj->string.length; external_obj->string.length = internal_obj->string.length; - external_obj->string.pointer = (char *) data_space; - source_ptr = internal_obj->string.pointer; + external_obj->string.pointer = (NATIVE_CHAR *) data_space; + source_ptr = (u8 *) internal_obj->string.pointer; break; @@ -113,7 +114,7 @@ length = internal_obj->buffer.length; external_obj->buffer.length = internal_obj->buffer.length; external_obj->buffer.pointer = data_space; - source_ptr = (char *) internal_obj->buffer.pointer; + source_ptr = (u8 *) internal_obj->buffer.pointer; break; @@ -132,7 +133,7 @@ */ external_obj->type = ACPI_TYPE_ANY; - external_obj->reference.handle = internal_obj->reference.nte; + external_obj->reference.handle = internal_obj->reference.node; break; @@ -142,10 +143,10 @@ internal_obj->processor.proc_id; external_obj->processor.pblk_address = - internal_obj->processor.pblk_address; + internal_obj->processor.address; external_obj->processor.pblk_length = - internal_obj->processor.pblk_length; + internal_obj->processor.length; break; case ACPI_TYPE_POWER: @@ -200,7 +201,7 @@ ACPI_STATUS acpi_cm_build_external_package_object ( - ACPI_OBJECT_INTERNAL *internal_obj, + ACPI_OPERAND_OBJECT *internal_obj, u8 *buffer, u32 *space_used) { @@ -211,7 +212,7 @@ u32 length = 0; u32 this_index; u32 object_space; - ACPI_OBJECT_INTERNAL *this_internal_obj; + ACPI_OPERAND_OBJECT *this_internal_obj; ACPI_OBJECT *this_external_obj; PKG_SEARCH_INFO *level_ptr; @@ -256,7 +257,7 @@ while (1) { this_index = level_ptr->index; this_internal_obj = - (ACPI_OBJECT_INTERNAL *) + (ACPI_OPERAND_OBJECT *) level_ptr->internal_obj->package.elements[this_index]; this_external_obj = (ACPI_OBJECT *) @@ -264,10 +265,11 @@ /* - * Check for 1) Null object -- OK, this can happen if package + * Check for + * 1) Null object -- OK, this can happen if package * element is never initialized - * 2) Not an internal object - can be an NTE instead - * 3) Any internal object other than a package. + * 2) Not an internal object - can be Node instead + * 3) Any internal object other than a package. * * The more complex package case is handled later */ @@ -367,8 +369,6 @@ level_ptr->index = 0; } } - - return (AE_OK); } @@ -388,7 +388,7 @@ ACPI_STATUS acpi_cm_build_external_object ( - ACPI_OBJECT_INTERNAL *internal_obj, + ACPI_OPERAND_OBJECT *internal_obj, ACPI_BUFFER *ret_buffer) { ACPI_STATUS status; @@ -446,7 +446,7 @@ ACPI_STATUS acpi_cm_build_internal_simple_object ( ACPI_OBJECT *external_obj, - ACPI_OBJECT_INTERNAL *internal_obj) + ACPI_OPERAND_OBJECT *internal_obj) { @@ -508,18 +508,17 @@ ACPI_STATUS acpi_cm_build_internal_package_object ( - ACPI_OBJECT_INTERNAL *internal_obj, + ACPI_OPERAND_OBJECT *internal_obj, u8 *buffer, u32 *space_used) { u8 *free_space; ACPI_OBJECT *external_obj; u32 current_depth = 0; - ACPI_STATUS status = AE_OK; u32 length = 0; u32 this_index; u32 object_space = 0; - ACPI_OBJECT_INTERNAL *this_internal_obj; + ACPI_OPERAND_OBJECT *this_internal_obj; ACPI_OBJECT *this_external_obj; PKG_SEARCH_INFO *level_ptr; @@ -562,7 +561,7 @@ while (1) { this_index = level_ptr->index; - this_internal_obj = (ACPI_OBJECT_INTERNAL *) + this_internal_obj = (ACPI_OPERAND_OBJECT *) &level_ptr->internal_obj->package.elements[this_index]; this_external_obj = (ACPI_OBJECT *) @@ -605,17 +604,6 @@ } /* if object is a package */ else { -/* Status = Acpi_cm_build_simple_object(This_internal_obj, - This_external_obj, Free_space, - &Object_space); -*/ - if (status != AE_OK) { - /* - * Failure get out - */ - return (status); - } - free_space += object_space; length += object_space; @@ -651,13 +639,6 @@ } } /* else object is NOT a package */ } /* while (1) */ - - - /* - * We'll never get here, but the compiler whines about - * return value - */ - return (AE_OK); } @@ -677,7 +658,7 @@ ACPI_STATUS acpi_cm_build_internal_object ( ACPI_OBJECT *external_obj, - ACPI_OBJECT_INTERNAL *internal_obj) + ACPI_OPERAND_OBJECT *internal_obj) { ACPI_STATUS status; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/common/cmdebug.c linux/drivers/acpi/common/cmdebug.c --- v2.4.0-test8/linux/drivers/acpi/common/cmdebug.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/common/cmdebug.c Fri Sep 15 14:30:29 2000 @@ -1,7 +1,7 @@ - /****************************************************************************** * * Module Name: cmdebug - Debug print routines + * $Revision: 60 $ * *****************************************************************************/ @@ -27,7 +27,7 @@ #include "acpi.h" #define _COMPONENT MISCELLANEOUS - MODULE_NAME ("cmdebug"); + MODULE_NAME ("cmdebug") /***************************************************************************** @@ -41,16 +41,16 @@ ****************************************************************************/ -s32 +u32 get_debug_level (void) { - return acpi_dbg_level; + return (acpi_dbg_level); } void set_debug_level ( - s32 new_debug_level) + u32 new_debug_level) { acpi_dbg_level = new_debug_level; @@ -75,10 +75,10 @@ void function_trace ( - char *module_name, - s32 line_number, - s32 component_id, - char *function_name) + NATIVE_CHAR *module_name, + u32 line_number, + u32 component_id, + NATIVE_CHAR *function_name) { acpi_gbl_nesting_level++; @@ -109,10 +109,10 @@ void function_trace_ptr ( - char *module_name, - s32 line_number, - s32 component_id, - char *function_name, + NATIVE_CHAR *module_name, + u32 line_number, + u32 component_id, + NATIVE_CHAR *function_name, void *pointer) { @@ -142,11 +142,11 @@ void function_trace_str ( - char *module_name, - s32 line_number, - s32 component_id, - char *function_name, - char *string) + NATIVE_CHAR *module_name, + u32 line_number, + u32 component_id, + NATIVE_CHAR *function_name, + NATIVE_CHAR *string) { acpi_gbl_nesting_level++; @@ -175,16 +175,16 @@ void function_trace_u32 ( - char *module_name, - s32 line_number, - s32 component_id, - char *function_name, + NATIVE_CHAR *module_name, + u32 line_number, + u32 component_id, + NATIVE_CHAR *function_name, u32 integer) { acpi_gbl_nesting_level++; debug_print (module_name, line_number, component_id, TRACE_FUNCTIONS, - " %2.2ld Entered Function: %s, 0x%l_x\n", + " %2.2ld Entered Function: %s, 0x%lX\n", acpi_gbl_nesting_level, function_name, integer); } @@ -207,10 +207,10 @@ void function_exit ( - char *module_name, - s32 line_number, - s32 component_id, - char *function_name) + NATIVE_CHAR *module_name, + u32 line_number, + u32 component_id, + NATIVE_CHAR *function_name) { debug_print (module_name, line_number, component_id, TRACE_FUNCTIONS, @@ -240,30 +240,19 @@ void function_status_exit ( - char *module_name, - s32 line_number, - s32 component_id, - char *function_name, + NATIVE_CHAR *module_name, + u32 line_number, + u32 component_id, + NATIVE_CHAR *function_name, ACPI_STATUS status) { - if (status > ACPI_MAX_STATUS) { - debug_print (module_name, line_number, component_id, - TRACE_FUNCTIONS, - " %2.2ld Exiting Function: %s, [Unknown Status] 0x%X\n", - acpi_gbl_nesting_level, - function_name, - status); - } - - else { - debug_print (module_name, line_number, component_id, - TRACE_FUNCTIONS, - " %2.2ld Exiting Function: %s, %s\n", - acpi_gbl_nesting_level, - function_name, - acpi_cm_format_exception (status)); - } + debug_print (module_name, line_number, component_id, + TRACE_FUNCTIONS, + " %2.2ld Exiting Function: %s, %s\n", + acpi_gbl_nesting_level, + function_name, + acpi_cm_format_exception (status)); acpi_gbl_nesting_level--; } @@ -288,10 +277,10 @@ void function_value_exit ( - char *module_name, - s32 line_number, - s32 component_id, - char *function_name, + NATIVE_CHAR *module_name, + u32 line_number, + u32 component_id, + NATIVE_CHAR *function_name, NATIVE_UINT value) { @@ -322,11 +311,11 @@ void function_ptr_exit ( - char *module_name, - s32 line_number, - s32 component_id, - char *function_name, - char *ptr) + NATIVE_CHAR *module_name, + u32 line_number, + u32 component_id, + NATIVE_CHAR *function_name, + u8 *ptr) { debug_print (module_name, line_number, component_id, TRACE_FUNCTIONS, @@ -357,11 +346,11 @@ void debug_print ( - char *module_name, - s32 line_number, - s32 component_id, - s32 print_level, - char *format, + NATIVE_CHAR *module_name, + u32 line_number, + u32 component_id, + u32 print_level, + NATIVE_CHAR *format, ...) { va_list args; @@ -397,8 +386,8 @@ void debug_print_prefix ( - char *module_name, - s32 line_number) + NATIVE_CHAR *module_name, + u32 line_number) { @@ -421,7 +410,7 @@ void debug_print_raw ( - char *format, + NATIVE_CHAR *format, ...) { va_list args; @@ -451,10 +440,10 @@ void acpi_cm_dump_buffer ( - char *buffer, + u8 *buffer, u32 count, u32 display, - s32 component_id) + u32 component_id) { u32 i = 0; u32 j; @@ -477,7 +466,7 @@ while (i < count) { /* Print current offset */ - acpi_os_printf ("%05_x ", i); + acpi_os_printf ("%05X ", i); /* Print 16 hex chars */ @@ -488,7 +477,7 @@ return; } - /* Make sure that the char doesn't get sign-extended! */ + /* Make sure that the s8 doesn't get sign-extended! */ switch (display) { @@ -496,7 +485,7 @@ default: - acpi_os_printf ("%02_x ", + acpi_os_printf ("%02X ", *((u8 *) &buffer[i + j])); j += 1; break; @@ -506,7 +495,7 @@ MOVE_UNALIGNED16_TO_32 (&temp32, &buffer[i + j]); - acpi_os_printf ("%04_x ", temp32); + acpi_os_printf ("%04X ", temp32); j += 2; break; @@ -515,7 +504,7 @@ MOVE_UNALIGNED32_TO_32 (&temp32, &buffer[i + j]); - acpi_os_printf ("%08_x ", temp32); + acpi_os_printf ("%08X ", temp32); j += 4; break; @@ -524,11 +513,11 @@ MOVE_UNALIGNED32_TO_32 (&temp32, &buffer[i + j]); - acpi_os_printf ("%08_x", temp32); + acpi_os_printf ("%08X", temp32); MOVE_UNALIGNED32_TO_32 (&temp32, &buffer[i + j + 4]); - acpi_os_printf ("%08_x ", temp32); + acpi_os_printf ("%08X ", temp32); j += 8; break; } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/common/cmdelete.c linux/drivers/acpi/common/cmdelete.c --- v2.4.0-test8/linux/drivers/acpi/common/cmdelete.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/common/cmdelete.c Fri Sep 15 14:30:29 2000 @@ -1,7 +1,7 @@ - /****************************************************************************** * * Module Name: cmdelete - object deletion and reference count utilities + * $Revision: 53 $ * *****************************************************************************/ @@ -25,13 +25,13 @@ #include "acpi.h" -#include "interp.h" -#include "namesp.h" -#include "tables.h" -#include "parser.h" +#include "acinterp.h" +#include "acnamesp.h" +#include "actables.h" +#include "acparser.h" #define _COMPONENT MISCELLANEOUS - MODULE_NAME ("cmdelete"); + MODULE_NAME ("cmdelete") /****************************************************************************** @@ -49,7 +49,7 @@ void acpi_cm_delete_internal_obj ( - ACPI_OBJECT_INTERNAL *object) + ACPI_OPERAND_OBJECT *object) { void *obj_pointer = NULL; @@ -110,14 +110,7 @@ case ACPI_TYPE_METHOD: - /* Delete parse tree if it exists */ - - if (object->method.parser_op) { - acpi_ps_delete_parse_tree (object->method.parser_op); - object->method.parser_op = NULL; - } - - /* Delete semaphore if it exists */ + /* Delete the method semaphore if it exists */ if (object->method.semaphore) { acpi_os_delete_semaphore (object->method.semaphore); @@ -146,7 +139,7 @@ /* Only delete the object if it was dynamically allocated */ - if (!(object->common.flags & AO_STATIC_ALLOCATION)) { + if (!(object->common.flags & AOPOBJ_STATIC_ALLOCATION)) { acpi_cm_delete_object_desc (object); } @@ -170,9 +163,9 @@ ACPI_STATUS acpi_cm_delete_internal_object_list ( - ACPI_OBJECT_INTERNAL **obj_list) + ACPI_OPERAND_OBJECT **obj_list) { - ACPI_OBJECT_INTERNAL **internal_obj; + ACPI_OPERAND_OBJECT **internal_obj; /* Walk the null-terminated internal list */ @@ -220,8 +213,8 @@ void acpi_cm_update_ref_count ( - ACPI_OBJECT_INTERNAL *object, - s32 action) + ACPI_OPERAND_OBJECT *object, + u32 action) { u16 count; u16 new_count; @@ -308,23 +301,23 @@ * DESCRIPTION: Increment the object reference count * * Object references are incremented when: - * 1) An object is added as a value in an Name Table Entry (NTE) + * 1) An object is attached to a Node (namespace object) * 2) An object is copied (all subobjects must be incremented) * * Object references are decremented when: - * 1) An object is removed from an NTE + * 1) An object is detached from an Node * ******************************************************************************/ ACPI_STATUS acpi_cm_update_object_reference ( - ACPI_OBJECT_INTERNAL *object, + ACPI_OPERAND_OBJECT *object, u16 action) { ACPI_STATUS status; u32 i; - ACPI_OBJECT_INTERNAL *next; - ACPI_OBJECT_INTERNAL *new; + ACPI_OPERAND_OBJECT *next; + ACPI_OPERAND_OBJECT *new; ACPI_GENERIC_STATE *state_list = NULL; ACPI_GENERIC_STATE *state; @@ -381,9 +374,9 @@ /* Must walk list of address handlers */ - next = object->addr_handler.link; + next = object->addr_handler.next; while (next) { - new = next->addr_handler.link; + new = next->addr_handler.next; acpi_cm_update_ref_count (next, action); next = new; @@ -512,7 +505,7 @@ void acpi_cm_add_reference ( - ACPI_OBJECT_INTERNAL *object) + ACPI_OPERAND_OBJECT *object) { @@ -549,7 +542,7 @@ void acpi_cm_remove_reference ( - ACPI_OBJECT_INTERNAL *object) + ACPI_OPERAND_OBJECT *object) { diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/common/cmeval.c linux/drivers/acpi/common/cmeval.c --- v2.4.0-test8/linux/drivers/acpi/common/cmeval.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/common/cmeval.c Fri Sep 15 14:30:29 2000 @@ -1,7 +1,7 @@ - /****************************************************************************** * * Module Name: cmeval - Object evaluation + * $Revision: 14 $ * *****************************************************************************/ @@ -25,19 +25,19 @@ #include "acpi.h" -#include "namesp.h" -#include "interp.h" +#include "acnamesp.h" +#include "acinterp.h" #define _COMPONENT MISCELLANEOUS - MODULE_NAME ("cmeval"); + MODULE_NAME ("cmeval") /**************************************************************************** * * FUNCTION: Acpi_cm_evaluate_numeric_object * - * PARAMETERS: Acpi_device - NTE for the device + * PARAMETERS: Device_node - Node for the device * *Address - Where the value is returned * * RETURN: Status @@ -51,17 +51,17 @@ ACPI_STATUS acpi_cm_evaluate_numeric_object ( - char *object_name, - ACPI_NAMED_OBJECT *acpi_device, + NATIVE_CHAR *object_name, + ACPI_NAMESPACE_NODE *device_node, u32 *address) { - ACPI_OBJECT_INTERNAL *obj_desc; + ACPI_OPERAND_OBJECT *obj_desc; ACPI_STATUS status; /* Execute the method */ - status = acpi_ns_evaluate_relative (acpi_device, object_name, NULL, &obj_desc); + status = acpi_ns_evaluate_relative (device_node, object_name, NULL, &obj_desc); if (ACPI_FAILURE (status)) { return (status); @@ -99,7 +99,7 @@ * * FUNCTION: Acpi_cm_execute_HID * - * PARAMETERS: Acpi_device - NTE for the device + * PARAMETERS: Device_node - Node for the device * *Hid - Where the HID is returned * * RETURN: Status @@ -113,16 +113,16 @@ ACPI_STATUS acpi_cm_execute_HID ( - ACPI_NAMED_OBJECT *acpi_device, + ACPI_NAMESPACE_NODE *device_node, DEVICE_ID *hid) { - ACPI_OBJECT_INTERNAL *obj_desc; + ACPI_OPERAND_OBJECT *obj_desc; ACPI_STATUS status; /* Execute the method */ - status = acpi_ns_evaluate_relative (acpi_device, + status = acpi_ns_evaluate_relative (device_node, METHOD_NAME__HID, NULL, &obj_desc); if (ACPI_FAILURE (status)) { @@ -176,7 +176,7 @@ * * FUNCTION: Acpi_cm_execute_UID * - * PARAMETERS: Acpi_device - NTE for the device + * PARAMETERS: Device_node - Node for the device * *Uid - Where the UID is returned * * RETURN: Status @@ -190,16 +190,16 @@ ACPI_STATUS acpi_cm_execute_UID ( - ACPI_NAMED_OBJECT *acpi_device, + ACPI_NAMESPACE_NODE *device_node, DEVICE_ID *uid) { - ACPI_OBJECT_INTERNAL *obj_desc; + ACPI_OPERAND_OBJECT *obj_desc; ACPI_STATUS status; /* Execute the method */ - status = acpi_ns_evaluate_relative (acpi_device, + status = acpi_ns_evaluate_relative (device_node, METHOD_NAME__UID, NULL, &obj_desc); if (ACPI_FAILURE (status)) { @@ -251,7 +251,7 @@ * * FUNCTION: Acpi_cm_execute_STA * - * PARAMETERS: Acpi_device - NTE for the device + * PARAMETERS: Device_node - Node for the device * *Flags - Where the status flags are returned * * RETURN: Status @@ -265,16 +265,16 @@ ACPI_STATUS acpi_cm_execute_STA ( - ACPI_NAMED_OBJECT *acpi_device, + ACPI_NAMESPACE_NODE *device_node, u32 *flags) { - ACPI_OBJECT_INTERNAL *obj_desc; + ACPI_OPERAND_OBJECT *obj_desc; ACPI_STATUS status; /* Execute the method */ - status = acpi_ns_evaluate_relative (acpi_device, + status = acpi_ns_evaluate_relative (device_node, METHOD_NAME__STA, NULL, &obj_desc); if (ACPI_FAILURE (status)) { diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/common/cmglobal.c linux/drivers/acpi/common/cmglobal.c --- v2.4.0-test8/linux/drivers/acpi/common/cmglobal.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/common/cmglobal.c Fri Sep 15 14:30:29 2000 @@ -1,7 +1,7 @@ - /****************************************************************************** * * Module Name: cmglobal - Global variables for the ACPI subsystem + * $Revision: 99 $ * *****************************************************************************/ @@ -26,13 +26,13 @@ #define DEFINE_ACPI_GLOBALS #include "acpi.h" -#include "events.h" -#include "namesp.h" -#include "interp.h" +#include "acevents.h" +#include "acnamesp.h" +#include "acinterp.h" #define _COMPONENT MISCELLANEOUS - MODULE_NAME ("cmglobal"); + MODULE_NAME ("cmglobal") /****************************************************************************** @@ -126,31 +126,25 @@ NSP_NEWSCOPE | NSP_LOCAL, /* 13 Thermal */ NSP_NORMAL, /* 14 Buffer_field */ NSP_NORMAL, /* 15 Ddb_handle */ - NSP_NORMAL, /* 16 reserved */ - NSP_NORMAL, /* 17 reserved */ - NSP_NORMAL, /* 18 reserved */ - NSP_NORMAL, /* 19 reserved */ - NSP_NORMAL, /* 20 reserved */ - NSP_NORMAL, /* 21 reserved */ - NSP_NORMAL, /* 22 reserved */ - NSP_NORMAL, /* 23 reserved */ - NSP_NORMAL, /* 24 reserved */ - NSP_NORMAL, /* 25 Def_field */ - NSP_NORMAL, /* 26 Bank_field */ - NSP_NORMAL, /* 27 Index_field */ - NSP_NORMAL, /* 28 Def_field_defn */ - NSP_NORMAL, /* 29 Bank_field_defn */ - NSP_NORMAL, /* 30 Index_field_defn */ - NSP_NORMAL, /* 31 If */ - NSP_NORMAL, /* 32 Else */ - NSP_NORMAL, /* 33 While */ - NSP_NEWSCOPE, /* 34 Scope */ - NSP_LOCAL, /* 35 Def_any */ - NSP_NORMAL, /* 36 Reference */ - NSP_NORMAL, /* 37 Alias */ - NSP_NORMAL, /* 38 Notify */ - NSP_NORMAL, /* 39 Address Handler */ - NSP_NORMAL /* 40 Invalid */ + NSP_NORMAL, /* 16 Debug Object */ + NSP_NORMAL, /* 17 Def_field */ + NSP_NORMAL, /* 18 Bank_field */ + NSP_NORMAL, /* 19 Index_field */ + NSP_NORMAL, /* 20 Reference */ + NSP_NORMAL, /* 21 Alias */ + NSP_NORMAL, /* 22 Notify */ + NSP_NORMAL, /* 23 Address Handler */ + NSP_NORMAL, /* 24 Def_field_defn */ + NSP_NORMAL, /* 25 Bank_field_defn */ + NSP_NORMAL, /* 26 Index_field_defn */ + NSP_NORMAL, /* 27 If */ + NSP_NORMAL, /* 28 Else */ + NSP_NORMAL, /* 29 While */ + NSP_NEWSCOPE, /* 30 Scope */ + NSP_LOCAL, /* 31 Def_any */ + NSP_NORMAL, /* 32 Method Arg */ + NSP_NORMAL, /* 33 Method Local */ + NSP_NORMAL /* 34 Invalid */ }; @@ -204,11 +198,11 @@ if ((type < INTERNAL_TYPE_BEGIN) || (type > INTERNAL_TYPE_MAX)) { - return FALSE; + return (FALSE); } } - return TRUE; + return (TRUE); } @@ -224,16 +218,60 @@ * ****************************************************************************/ -char * +NATIVE_CHAR * acpi_cm_format_exception ( ACPI_STATUS status) { + NATIVE_CHAR *exception = "UNKNOWN_STATUS"; + ACPI_STATUS sub_status; + + + sub_status = (status & ~AE_CODE_MASK); + - if (status > ACPI_MAX_STATUS) { - return "UNKNOWN_STATUS"; + switch (status & AE_CODE_MASK) + { + case AE_CODE_ENVIRONMENTAL: + + if (sub_status <= AE_CODE_ENV_MAX) { + exception = acpi_gbl_exception_names_env [sub_status]; + } + break; + + case AE_CODE_PROGRAMMER: + + if (sub_status <= AE_CODE_PGM_MAX) { + exception = acpi_gbl_exception_names_pgm [sub_status -1]; + } + break; + + case AE_CODE_ACPI_TABLES: + + if (sub_status <= AE_CODE_TBL_MAX) { + exception = acpi_gbl_exception_names_tbl [sub_status -1]; + } + break; + + case AE_CODE_AML: + + if (sub_status <= AE_CODE_AML_MAX) { + exception = acpi_gbl_exception_names_aml [sub_status -1]; + } + break; + + case AE_CODE_CONTROL: + + if (sub_status <= AE_CODE_CTRL_MAX) { + exception = acpi_gbl_exception_names_ctrl [sub_status -1]; + } + break; + + default: + break; } - return (acpi_gbl_exception_names [status]); + + return (exception); } @@ -389,6 +427,11 @@ acpi_gbl_parse_cache_requests = 0; acpi_gbl_parse_cache_hits = 0; + acpi_gbl_ext_parse_cache = NULL; + acpi_gbl_ext_parse_cache_depth = 0; + acpi_gbl_ext_parse_cache_requests = 0; + acpi_gbl_ext_parse_cache_hits = 0; + acpi_gbl_object_cache = NULL; acpi_gbl_object_cache_depth = 0; acpi_gbl_object_cache_requests = 0; @@ -402,7 +445,7 @@ /* Interpreter */ acpi_gbl_buf_seq = 0; - acpi_gbl_named_object_err = FALSE; + acpi_gbl_node_err = FALSE; /* Parser */ @@ -418,18 +461,15 @@ /* Namespace */ - acpi_gbl_root_name_table.next_table = NULL; - acpi_gbl_root_name_table.parent_entry = NULL; - acpi_gbl_root_name_table.parent_table = NULL; - - acpi_gbl_root_object = acpi_gbl_root_name_table.entries; - - acpi_gbl_root_object->name = ACPI_ROOT_NAME; - acpi_gbl_root_object->data_type = ACPI_DESC_TYPE_NAMED; - acpi_gbl_root_object->type = ACPI_TYPE_ANY; - acpi_gbl_root_object->this_index = 0; - acpi_gbl_root_object->child_table = NULL; - acpi_gbl_root_object->object = NULL; + acpi_gbl_root_node = NULL; + + acpi_gbl_root_node_struct.name = ACPI_ROOT_NAME; + acpi_gbl_root_node_struct.data_type = ACPI_DESC_TYPE_NAMED; + acpi_gbl_root_node_struct.type = ACPI_TYPE_ANY; + acpi_gbl_root_node_struct.child = NULL; + acpi_gbl_root_node_struct.peer = NULL; + acpi_gbl_root_node_struct.object = NULL; + acpi_gbl_root_node_struct.flags = ANOBJ_END_OF_PEER_LIST; /* Memory allocation metrics - compiled out in non-debug mode. */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/common/cminit.c linux/drivers/acpi/common/cminit.c --- v2.4.0-test8/linux/drivers/acpi/common/cminit.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/common/cminit.c Fri Sep 15 14:30:29 2000 @@ -1,7 +1,7 @@ - /****************************************************************************** * * Module Name: cminit - Common ACPI subsystem initialization + * $Revision: 79 $ * *****************************************************************************/ @@ -25,14 +25,14 @@ #include "acpi.h" -#include "hardware.h" -#include "namesp.h" -#include "events.h" -#include "parser.h" -#include "dispatch.h" +#include "achware.h" +#include "acnamesp.h" +#include "acevents.h" +#include "acparser.h" +#include "acdispat.h" #define _COMPONENT MISCELLANEOUS - MODULE_NAME ("cminit"); + MODULE_NAME ("cminit") /******************************************************************************* @@ -52,7 +52,7 @@ void acpi_cm_facp_register_error ( - char *register_name, + NATIVE_CHAR *register_name, u32 value) { @@ -77,7 +77,7 @@ acpi_cm_hardware_initialize (void) { ACPI_STATUS status = AE_OK; - s32 index; + u32 index; /* Are we running on the actual hardware */ @@ -351,8 +351,9 @@ acpi_ps_delete_parse_cache (); /* Debug only - display leftover memory allocation, if any */ - +#ifdef ENABLE_DEBUGGER acpi_cm_dump_current_allocations (ACPI_UINT32_MAX, NULL); +#endif BREAKPOINT3; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/common/cmobject.c linux/drivers/acpi/common/cmobject.c --- v2.4.0-test8/linux/drivers/acpi/common/cmobject.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/common/cmobject.c Fri Sep 15 14:30:29 2000 @@ -1,7 +1,7 @@ - /****************************************************************************** * * Module Name: cmobject - ACPI object create/delete/size/cache routines + * $Revision: 27 $ * *****************************************************************************/ @@ -25,14 +25,14 @@ #include "acpi.h" -#include "interp.h" -#include "namesp.h" -#include "tables.h" +#include "acinterp.h" +#include "acnamesp.h" +#include "actables.h" #include "amlcode.h" #define _COMPONENT MISCELLANEOUS - MODULE_NAME ("cmobject"); + MODULE_NAME ("cmobject") /****************************************************************************** @@ -57,14 +57,14 @@ * ******************************************************************************/ -ACPI_OBJECT_INTERNAL * +ACPI_OPERAND_OBJECT * _cm_create_internal_object ( - char *module_name, - s32 line_number, - s32 component_id, + NATIVE_CHAR *module_name, + u32 line_number, + u32 component_id, OBJECT_TYPE_INTERNAL type) { - ACPI_OBJECT_INTERNAL *object; + ACPI_OPERAND_OBJECT *object; /* Allocate the raw object descriptor */ @@ -79,7 +79,6 @@ /* Save the object type in the object descriptor */ object->common.type = type; - object->common.size = (u8) sizeof (ACPI_OBJECT_INTERNAL); /* Init the reference count */ @@ -88,10 +87,6 @@ /* Any per-type initialization should go here */ - /* Memory allocation metrics - compiled out in non debug mode. */ - - INCREMENT_OBJECT_METRICS (sizeof (ACPI_OBJECT_INTERNAL)); - return (object); } @@ -102,7 +97,7 @@ * * PARAMETERS: Operand - Object to be validated * - * RETURN: Validate a pointer to be an ACPI_OBJECT_INTERNAL + * RETURN: Validate a pointer to be an ACPI_OPERAND_OBJECT * *****************************************************************************/ @@ -114,13 +109,13 @@ /* Check for a null pointer */ if (!object) { - return FALSE; + return (FALSE); } /* Check for a pointer within one of the ACPI tables */ if (acpi_tb_system_table_pointer (object)) { - return FALSE; + return (FALSE); } /* Check the descriptor type field */ @@ -131,13 +126,13 @@ - return FALSE; + return (FALSE); } - /* The object appears to be a valid ACPI_OBJECT_INTERNAL */ + /* The object appears to be a valid ACPI_OPERAND_OBJECT */ - return TRUE; + return (TRUE); } @@ -159,11 +154,11 @@ void * _cm_allocate_object_desc ( - char *module_name, - s32 line_number, - s32 component_id) + NATIVE_CHAR *module_name, + u32 line_number, + u32 component_id) { - ACPI_OBJECT_INTERNAL *object; + ACPI_OPERAND_OBJECT *object; acpi_cm_acquire_mutex (ACPI_MTX_CACHES); @@ -176,8 +171,8 @@ /* There is an object available, use it */ object = acpi_gbl_object_cache; - acpi_gbl_object_cache = object->common.next; - object->common.next = NULL; + acpi_gbl_object_cache = object->cache.next; + object->cache.next = NULL; acpi_gbl_object_cache_hits++; acpi_gbl_object_cache_depth--; @@ -192,9 +187,8 @@ /* Attempt to allocate new descriptor */ - object = _cm_callocate (sizeof (ACPI_OBJECT_INTERNAL), component_id, + object = _cm_callocate (sizeof (ACPI_OPERAND_OBJECT), component_id, module_name, line_number); - if (!object) { /* Allocation failed */ @@ -203,6 +197,10 @@ return (NULL); } + + /* Memory allocation metrics - compiled out in non debug mode. */ + + INCREMENT_OBJECT_METRICS (sizeof (ACPI_OPERAND_OBJECT)); } /* Mark the descriptor type */ @@ -227,19 +225,19 @@ void acpi_cm_delete_object_desc ( - ACPI_OBJECT_INTERNAL *object) + ACPI_OPERAND_OBJECT *object) { - /* Object must be an ACPI_OBJECT_INTERNAL */ + /* Make sure that the object isn't already in the cache */ - if (object->common.data_type != ACPI_DESC_TYPE_INTERNAL) { + if (object->common.data_type == (ACPI_DESC_TYPE_INTERNAL | ACPI_CACHED_OBJECT)) { return; } - /* Make sure that the object isn't already in the cache */ + /* Object must be an ACPI_OPERAND_OBJECT */ - if (object->common.next) { + if (object->common.data_type != ACPI_DESC_TYPE_INTERNAL) { return; } @@ -251,7 +249,7 @@ * Memory allocation metrics. Call the macro here since we only * care about dynamically allocated objects. */ - DECREMENT_OBJECT_METRICS (acpi_gbl_object_cache->common.size); + DECREMENT_OBJECT_METRICS (sizeof (ACPI_OPERAND_OBJECT)); acpi_cm_free (object); return; @@ -261,17 +259,18 @@ /* Clear the entire object. This is important! */ - MEMSET (object, 0, sizeof (ACPI_OBJECT_INTERNAL)); - object->common.data_type = ACPI_DESC_TYPE_INTERNAL; + MEMSET (object, 0, sizeof (ACPI_OPERAND_OBJECT)); + object->common.data_type = ACPI_DESC_TYPE_INTERNAL | ACPI_CACHED_OBJECT; /* Put the object at the head of the global cache list */ - object->common.next = acpi_gbl_object_cache; + object->cache.next = acpi_gbl_object_cache; acpi_gbl_object_cache = object; acpi_gbl_object_cache_depth++; acpi_cm_release_mutex (ACPI_MTX_CACHES); + return; } @@ -292,7 +291,7 @@ acpi_cm_delete_object_cache ( void) { - ACPI_OBJECT_INTERNAL *next; + ACPI_OPERAND_OBJECT *next; /* Traverse the global cache list */ @@ -300,17 +299,18 @@ while (acpi_gbl_object_cache) { /* Delete one cached state object */ - next = acpi_gbl_object_cache->common.next; - acpi_gbl_object_cache->common.next = NULL; + next = acpi_gbl_object_cache->cache.next; + acpi_gbl_object_cache->cache.next = NULL; /* * Memory allocation metrics. Call the macro here since we only * care about dynamically allocated objects. */ - DECREMENT_OBJECT_METRICS (acpi_gbl_object_cache->common.size); + DECREMENT_OBJECT_METRICS (sizeof (ACPI_OPERAND_OBJECT)); acpi_cm_free (acpi_gbl_object_cache); acpi_gbl_object_cache = next; + acpi_gbl_object_cache_depth--; } return; @@ -333,7 +333,7 @@ void acpi_cm_init_static_object ( - ACPI_OBJECT_INTERNAL *obj_desc) + ACPI_OPERAND_OBJECT *obj_desc) { @@ -345,12 +345,12 @@ /* * Clear the entire descriptor */ - MEMSET ((void *) obj_desc, 0, sizeof (ACPI_OBJECT_INTERNAL)); + MEMSET ((void *) obj_desc, 0, sizeof (ACPI_OPERAND_OBJECT)); /* * Initialize the header fields - * 1) This is an ACPI_OBJECT_INTERNAL descriptor + * 1) This is an ACPI_OPERAND_OBJECT descriptor * 2) The size is the full object (worst case) * 3) The flags field indicates static allocation * 4) Reference count starts at one (not really necessary since the @@ -358,8 +358,7 @@ */ obj_desc->common.data_type = ACPI_DESC_TYPE_INTERNAL; - obj_desc->common.size = sizeof (ACPI_OBJECT_INTERNAL); - obj_desc->common.flags = AO_STATIC_ALLOCATION; + obj_desc->common.flags = AOPOBJ_STATIC_ALLOCATION; obj_desc->common.reference_count = 1; return; @@ -385,7 +384,7 @@ ACPI_STATUS acpi_cm_get_simple_object_size ( - ACPI_OBJECT_INTERNAL *internal_obj, + ACPI_OPERAND_OBJECT *internal_obj, u32 *obj_length) { u32 length; @@ -405,7 +404,7 @@ length = sizeof (ACPI_OBJECT); if (VALID_DESCRIPTOR_TYPE (internal_obj, ACPI_DESC_TYPE_NAMED)) { - /* Object is an NTE (reference), just return the length */ + /* Object is a named object (reference), just return the length */ *obj_length = (u32) ROUND_UP_TO_NATIVE_WORD (length); return (status); @@ -495,13 +494,13 @@ ACPI_STATUS acpi_cm_get_package_object_size ( - ACPI_OBJECT_INTERNAL *internal_obj, + ACPI_OPERAND_OBJECT *internal_obj, u32 *obj_length) { - ACPI_OBJECT_INTERNAL *this_internal_obj; - ACPI_OBJECT_INTERNAL *parent_obj[MAX_PACKAGE_DEPTH] = { 0,0,0,0,0 }; - ACPI_OBJECT_INTERNAL *this_parent; + ACPI_OPERAND_OBJECT *this_internal_obj; + ACPI_OPERAND_OBJECT *parent_obj[MAX_PACKAGE_DEPTH] = { 0,0,0,0,0 }; + ACPI_OPERAND_OBJECT *this_parent; u32 this_index; u32 index[MAX_PACKAGE_DEPTH] = { 0,0,0,0,0 }; u32 length = 0; @@ -537,7 +536,7 @@ status = acpi_cm_get_simple_object_size (this_internal_obj, &object_space); - if (status != AE_OK) { + if (ACPI_FAILURE (status)) { return (status); } @@ -603,8 +602,6 @@ } } } - - return (AE_OK); } @@ -624,7 +621,7 @@ ACPI_STATUS acpi_cm_get_object_size( - ACPI_OBJECT_INTERNAL *internal_obj, + ACPI_OPERAND_OBJECT *internal_obj, u32 *obj_length) { ACPI_STATUS status; @@ -642,7 +639,7 @@ acpi_cm_get_simple_object_size (internal_obj, obj_length); } - return status; + return (status); } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/common/cmutils.c linux/drivers/acpi/common/cmutils.c --- v2.4.0-test8/linux/drivers/acpi/common/cmutils.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/common/cmutils.c Fri Sep 15 14:30:29 2000 @@ -1,8 +1,9 @@ -/****************************************************************************** +/******************************************************************************* * * Module Name: cmutils - common utility procedures + * $Revision: 18 $ * - *****************************************************************************/ + ******************************************************************************/ /* * Copyright (C) 2000 R. Byron Moore @@ -24,19 +25,19 @@ #include "acpi.h" -#include "events.h" -#include "hardware.h" -#include "namesp.h" -#include "interp.h" +#include "acevents.h" +#include "achware.h" +#include "acnamesp.h" +#include "acinterp.h" #include "amlcode.h" -#include "debugger.h" +#include "acdebug.h" #define _COMPONENT MISCELLANEOUS - MODULE_NAME ("cmutils"); + MODULE_NAME ("cmutils") -/***************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_cm_valid_acpi_name * @@ -49,13 +50,13 @@ * 2) numeric * 3) underscore * - ****************************************************************************/ + ******************************************************************************/ u8 acpi_cm_valid_acpi_name ( u32 name) { - char *name_ptr = (char *) &name; + NATIVE_CHAR *name_ptr = (NATIVE_CHAR *) &name; u32 i; @@ -64,16 +65,16 @@ (name_ptr[i] >= 'A' && name_ptr[i] <= 'Z') || (name_ptr[i] >= '0' && name_ptr[i] <= '9'))) { - return FALSE; + return (FALSE); } } - return TRUE; + return (TRUE); } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_cm_valid_acpi_character * @@ -83,11 +84,11 @@ * * DESCRIPTION: Check for a printable character * - ****************************************************************************/ + ******************************************************************************/ u8 acpi_cm_valid_acpi_character ( - char character) + NATIVE_CHAR character) { return ((u8) ((character == '_') || @@ -96,7 +97,7 @@ } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_cm_mutex_initialize * @@ -106,7 +107,7 @@ * * DESCRIPTION: Create the system mutex objects. * - ****************************************************************************/ + ******************************************************************************/ ACPI_STATUS acpi_cm_mutex_initialize ( @@ -130,7 +131,7 @@ } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_cm_mutex_terminate * @@ -140,7 +141,7 @@ * * DESCRIPTION: Delete all of the system mutex objects. * - ****************************************************************************/ + ******************************************************************************/ void acpi_cm_mutex_terminate ( @@ -160,7 +161,7 @@ } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_cm_create_mutex * @@ -170,7 +171,7 @@ * * DESCRIPTION: Create a mutex object. * - ****************************************************************************/ + ******************************************************************************/ ACPI_STATUS acpi_cm_create_mutex ( @@ -195,7 +196,7 @@ } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_cm_delete_mutex * @@ -205,7 +206,7 @@ * * DESCRIPTION: Delete a mutex object. * - ****************************************************************************/ + ******************************************************************************/ ACPI_STATUS acpi_cm_delete_mutex ( @@ -228,7 +229,7 @@ } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_cm_acquire_mutex * @@ -238,7 +239,7 @@ * * DESCRIPTION: Acquire a mutex object. * - ****************************************************************************/ + ******************************************************************************/ ACPI_STATUS acpi_cm_acquire_mutex ( @@ -252,9 +253,8 @@ } - status = - acpi_os_wait_semaphore (acpi_gbl_acpi_mutex_info[mutex_id].mutex, - 1, WAIT_FOREVER); + status = acpi_os_wait_semaphore (acpi_gbl_acpi_mutex_info[mutex_id].mutex, + 1, WAIT_FOREVER); if (ACPI_SUCCESS (status)) { acpi_gbl_acpi_mutex_info[mutex_id].locked = TRUE; @@ -265,7 +265,7 @@ } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_cm_release_mutex * @@ -275,7 +275,7 @@ * * DESCRIPTION: Release a mutex object. * - ****************************************************************************/ + ******************************************************************************/ ACPI_STATUS acpi_cm_release_mutex ( @@ -291,14 +291,14 @@ acpi_gbl_acpi_mutex_info[mutex_id].locked = FALSE; /* Mark before unlocking */ - status = - acpi_os_signal_semaphore (acpi_gbl_acpi_mutex_info[mutex_id].mutex, 1); + status = acpi_os_signal_semaphore (acpi_gbl_acpi_mutex_info[mutex_id].mutex, 1); + return (status); } -/****************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_cm_create_update_state_and_push * @@ -314,7 +314,7 @@ ACPI_STATUS acpi_cm_create_update_state_and_push ( - ACPI_OBJECT_INTERNAL *object, + ACPI_OPERAND_OBJECT *object, u16 action, ACPI_GENERIC_STATE **state_list) { @@ -324,21 +324,21 @@ /* Ignore null objects; these are expected */ if (!object) { - return AE_OK; + return (AE_OK); } state = acpi_cm_create_update_state (object, action); if (!state) { - return AE_NO_MEMORY; + return (AE_NO_MEMORY); } acpi_cm_push_generic_state (state_list, state); - return AE_OK; + return (AE_OK); } -/****************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_cm_push_generic_state * @@ -365,7 +365,7 @@ } -/****************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_cm_pop_generic_state * @@ -397,7 +397,7 @@ } -/****************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_cm_create_generic_state * @@ -433,6 +433,7 @@ acpi_gbl_generic_state_cache_depth--; acpi_cm_release_mutex (ACPI_MTX_CACHES); + } else { @@ -446,18 +447,23 @@ /* Initialize */ if (state) { + /* Always zero out the object before init */ + + MEMSET (state, 0, sizeof (ACPI_GENERIC_STATE)); + state->common.data_type = ACPI_DESC_TYPE_STATE; } - return state; + return (state); } -/****************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_cm_create_update_state * - * PARAMETERS: Object - Initial Object to be installed in the state + * PARAMETERS: Object - Initial Object to be installed in the + * state * Action - Update action to be performed * * RETURN: Status @@ -470,7 +476,7 @@ ACPI_GENERIC_STATE * acpi_cm_create_update_state ( - ACPI_OBJECT_INTERNAL *object, + ACPI_OPERAND_OBJECT *object, u16 action) { ACPI_GENERIC_STATE *state; @@ -480,7 +486,7 @@ state = acpi_cm_create_generic_state (); if (!state) { - return NULL; + return (NULL); } /* Init fields specific to the update struct */ @@ -492,7 +498,7 @@ } -/****************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_cm_create_control_state * @@ -516,7 +522,7 @@ state = acpi_cm_create_generic_state (); if (!state) { - return NULL; + return (NULL); } @@ -528,7 +534,7 @@ } -/****************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_cm_delete_generic_state * @@ -575,7 +581,7 @@ } -/****************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_cm_delete_generic_state_cache * @@ -603,13 +609,14 @@ next = acpi_gbl_generic_state_cache->common.next; acpi_cm_free (acpi_gbl_generic_state_cache); acpi_gbl_generic_state_cache = next; + acpi_gbl_generic_state_cache_depth--; } return; } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: _Report_error * @@ -622,14 +629,14 @@ * * DESCRIPTION: Print error message from KD table * - ****************************************************************************/ + ******************************************************************************/ void _report_error ( - char *module_name, - s32 line_number, - s32 component_id, - char *message) + NATIVE_CHAR *module_name, + u32 line_number, + u32 component_id, + NATIVE_CHAR *message) { debug_print (module_name, line_number, component_id, ACPI_ERROR, @@ -638,7 +645,7 @@ } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: _Report_warning * @@ -651,14 +658,14 @@ * * DESCRIPTION: Print warning message from KD table * - ****************************************************************************/ + ******************************************************************************/ void _report_warning ( - char *module_name, - s32 line_number, - s32 component_id, - char *message) + NATIVE_CHAR *module_name, + u32 line_number, + u32 component_id, + NATIVE_CHAR *message) { debug_print (module_name, line_number, component_id, ACPI_WARN, @@ -667,35 +674,7 @@ } -/***************************************************************************** - * - * FUNCTION: _Report_success - * - * PARAMETERS: Module_name - Caller's module name (for error output) - * Line_number - Caller's line number (for error output) - * Component_id - Caller's component ID (for error output) - * Message - Error message to use on failure - * - * RETURN: None - * - * DESCRIPTION: Print warning message from KD table - * - ****************************************************************************/ - -void -_report_success ( - char *module_name, - s32 line_number, - s32 component_id, - char *message) -{ - - debug_print (module_name, line_number, component_id, ACPI_OK, - "*** Success: %s\n", message); -} - - -/***************************************************************************** +/******************************************************************************* * * FUNCTION: _Report_info * @@ -708,14 +687,14 @@ * * DESCRIPTION: Print information message from KD table * - ****************************************************************************/ + ******************************************************************************/ void _report_info ( - char *module_name, - s32 line_number, - s32 component_id, - char *message) + NATIVE_CHAR *module_name, + u32 line_number, + u32 component_id, + NATIVE_CHAR *message) { debug_print (module_name, line_number, component_id, ACPI_INFO, diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/common/cmxface.c linux/drivers/acpi/common/cmxface.c --- v2.4.0-test8/linux/drivers/acpi/common/cmxface.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/common/cmxface.c Fri Sep 15 14:30:29 2000 @@ -1,6 +1,7 @@ /****************************************************************************** * * Module Name: cmxface - External interfaces for "global" ACPI functions + * $Revision: 43 $ * *****************************************************************************/ @@ -24,16 +25,16 @@ #include "acpi.h" -#include "events.h" -#include "hardware.h" -#include "namesp.h" -#include "interp.h" +#include "acevents.h" +#include "achware.h" +#include "acnamesp.h" +#include "acinterp.h" #include "amlcode.h" -#include "debugger.h" +#include "acdebug.h" #define _COMPONENT MISCELLANEOUS - MODULE_NAME ("cmxface"); + MODULE_NAME ("cmxface") /******************************************************************************* @@ -77,6 +78,8 @@ /* If configured, initialize the AML debugger */ + DEBUGGER_EXEC (acpi_db_initialize ()); + return (status); } @@ -100,7 +103,9 @@ /* Terminate the AML Debuger if present */ acpi_gbl_db_terminate_threads = TRUE; - acpi_cm_release_mutex (ACPI_MTX_DEBUG_CMD_READY); + + /* TBD: [Investigate] This is no longer needed?*/ +/* Acpi_cm_release_mutex (ACPI_MTX_DEBUG_CMD_READY); */ /* Shutdown and free all resources */ @@ -224,7 +229,7 @@ ACPI_BUFFER *out_buffer) { u32 length; - char *formatted_exception; + NATIVE_CHAR *formatted_exception; /* @@ -237,14 +242,7 @@ } - /* Exception must be within range */ - - if (exception > ACPI_MAX_STATUS) { - return (AE_BAD_PARAMETER); - } - - - /* Convert the exception code */ + /* Convert the exception code (Handles bad exception codes) */ formatted_exception = acpi_cm_format_exception (exception); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/cpu.c linux/drivers/acpi/cpu.c --- v2.4.0-test8/linux/drivers/acpi/cpu.c Wed Jul 12 13:21:57 2000 +++ linux/drivers/acpi/cpu.c Fri Sep 15 14:30:29 2000 @@ -25,6 +25,9 @@ #include "acpi.h" #include "driver.h" +#define _COMPONENT OS_DEPENDENT + MODULE_NAME ("cpu") + unsigned long acpi_c2_exit_latency = ACPI_INFINITE; unsigned long acpi_c3_exit_latency = ACPI_INFINITE; unsigned long acpi_c2_enter_latency = ACPI_INFINITE; @@ -33,6 +36,7 @@ static unsigned long acpi_pblk = ACPI_INVALID; static int acpi_c2_tested = 0; static int acpi_c3_tested = 0; +static int acpi_max_c_state = 1; /* * Clear busmaster activity flag @@ -101,10 +105,14 @@ /* * start from the previous sleep level.. */ - if (sleep_level == 1) + if (sleep_level == 1 + || acpi_max_c_state < 2) goto sleep1; - if (sleep_level == 2) + + if (sleep_level == 2 + || acpi_max_c_state < 3) goto sleep2; + sleep3: sleep_level = 3; if (!acpi_c3_tested) { @@ -193,7 +201,8 @@ acpi_clear_bm_activity(facp); continue; } - if (time > acpi_c3_enter_latency) + if (time > acpi_c3_enter_latency + && acpi_max_c_state >= 3) goto sleep3; } @@ -210,7 +219,8 @@ time = TIME_BEGIN(pm_tmr); safe_halt(); time = TIME_END(pm_tmr, time); - if (time > acpi_c2_enter_latency) + if (time > acpi_c2_enter_latency + && acpi_max_c_state >= 2) goto sleep2; } @@ -260,12 +270,19 @@ return AE_OK; if (lat[2].latency < MAX_CX_STATE_LATENCY) { - printk(KERN_INFO "ACPI: C2 supported\n"); + printk(KERN_INFO "ACPI: C2"); acpi_c2_exit_latency = lat[2].latency; - } - if (lat[3].latency < MAX_CX_STATE_LATENCY) { - printk(KERN_INFO "ACPI: C3 supported\n"); - acpi_c3_exit_latency = lat[3].latency; + acpi_max_c_state = 2; + + if (lat[3].latency < MAX_CX_STATE_LATENCY) { + printk(", C3 supported\n"); + acpi_c3_exit_latency = lat[3].latency; + acpi_max_c_state = 3; + } + else { + printk(" supported\n"); + } + } memset(throttle, 0, sizeof(throttle)); @@ -291,7 +308,7 @@ { acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT, - ACPI_INT32_MAX, + ACPI_UINT32_MAX, acpi_find_cpu, NULL, NULL); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/dispatcher/Makefile linux/drivers/acpi/dispatcher/Makefile --- v2.4.0-test8/linux/drivers/acpi/dispatcher/Makefile Wed Dec 31 16:00:00 1969 +++ linux/drivers/acpi/dispatcher/Makefile Fri Sep 15 18:21:43 2000 @@ -0,0 +1,28 @@ +# +# Makefile for all Linux ACPI interpreter subdirectories +# + +SUB_DIRS := +MOD_SUB_DIRS := $(SUB_DIRS) +MOD_IN_SUB_DIRS := +ALL_SUB_DIRS := $(SUB_DIRS) + +O_TARGET := ../$(shell basename `pwd`).o +O_OBJS := +M_OBJS := + +ACPI_OBJS := $(patsubst %.c,%.o,$(wildcard *.c)) + +EXTRA_CFLAGS += -I../include + +EXTRA_CFLAGS += $(ACPI_CFLAGS) + +# if the interpreter is used, it overrides arch/i386/kernel/acpi.c +ifeq ($(CONFIG_ACPI_INTERPRETER),y) + O_OBJS := $(ACPI_OBJS) +endif + +include $(TOPDIR)/Rules.make + +clean: + $(RM) *.o diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/dispatcher/dsfield.c linux/drivers/acpi/dispatcher/dsfield.c --- v2.4.0-test8/linux/drivers/acpi/dispatcher/dsfield.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/dispatcher/dsfield.c Fri Sep 15 14:30:29 2000 @@ -1,7 +1,7 @@ - /****************************************************************************** * * Module Name: dsfield - Dispatcher field routines + * $Revision: 29 $ * *****************************************************************************/ @@ -26,13 +26,13 @@ #include "acpi.h" #include "amlcode.h" -#include "dispatch.h" -#include "interp.h" -#include "namesp.h" +#include "acdispat.h" +#include "acinterp.h" +#include "acnamesp.h" #define _COMPONENT DISPATCHER - MODULE_NAME ("dsfield"); + MODULE_NAME ("dsfield") /* @@ -46,28 +46,28 @@ #define FIELD_UPDATE_RULE_MASK 0x60 -/***************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_ds_create_field * * PARAMETERS: Op - Op containing the Field definition and args - * Region - NTE for the containing Operation Region + * Region_node - Object for the containing Operation Region * * RETURN: Status * * DESCRIPTION: Create a new field in the specified operation region * - ****************************************************************************/ + ******************************************************************************/ ACPI_STATUS acpi_ds_create_field ( - ACPI_GENERIC_OP *op, - ACPI_HANDLE region, + ACPI_PARSE_OBJECT *op, + ACPI_NAMESPACE_NODE *region_node, ACPI_WALK_STATE *walk_state) { ACPI_STATUS status = AE_AML_ERROR; - ACPI_GENERIC_OP *arg; - ACPI_NAMED_OBJECT *entry; + ACPI_PARSE_OBJECT *arg; + ACPI_NAMESPACE_NODE *node; u8 field_flags; u8 access_attribute = 0; u32 field_bit_position = 0; @@ -76,6 +76,16 @@ /* First arg is the name of the parent Op_region */ arg = op->value.arg; + if (!region_node) { + status = acpi_ns_lookup (walk_state->scope_info, arg->value.name, + ACPI_TYPE_REGION, IMODE_EXECUTE, + NS_SEARCH_PARENT, walk_state, + ®ion_node); + + if (ACPI_FAILURE (status)) { + return (status); + } + } /* Second arg is the field flags */ @@ -111,32 +121,29 @@ case AML_NAMEDFIELD_OP: status = acpi_ns_lookup (walk_state->scope_info, - (char *) &((ACPI_NAMED_OP *)arg)->name, + (NATIVE_CHAR *) &((ACPI_PARSE2_OBJECT *)arg)->name, INTERNAL_TYPE_DEF_FIELD, IMODE_LOAD_PASS1, NS_NO_UPSEARCH | NS_DONT_OPEN_SCOPE, - NULL, &entry); + NULL, &node); if (ACPI_FAILURE (status)) { return (status); } /* - * Initialize an object for the new NTE that is on + * Initialize an object for the new Node that is on * the object stack */ - status = acpi_aml_prep_def_field_value (entry, region, - field_flags, - access_attribute, - field_bit_position, - arg->value.size); + status = acpi_aml_prep_def_field_value (node, region_node, field_flags, + access_attribute, field_bit_position, arg->value.size); if (ACPI_FAILURE (status)) { return (status); } - /* Keep track of bit position for the *next* field */ + /* Keep track of bit position for *next* field */ field_bit_position += arg->value.size; break; @@ -149,29 +156,29 @@ } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_ds_create_bank_field * * PARAMETERS: Op - Op containing the Field definition and args - * Region - NTE for the containing Operation Region + * Region_node - Object for the containing Operation Region * * RETURN: Status * * DESCRIPTION: Create a new bank field in the specified operation region * - ****************************************************************************/ + ******************************************************************************/ ACPI_STATUS acpi_ds_create_bank_field ( - ACPI_GENERIC_OP *op, - ACPI_HANDLE region, + ACPI_PARSE_OBJECT *op, + ACPI_NAMESPACE_NODE *region_node, ACPI_WALK_STATE *walk_state) { ACPI_STATUS status = AE_AML_ERROR; - ACPI_GENERIC_OP *arg; - ACPI_NAMED_OBJECT *bank_reg; - ACPI_NAMED_OBJECT *entry; + ACPI_PARSE_OBJECT *arg; + ACPI_NAMESPACE_NODE *register_node; + ACPI_NAMESPACE_NODE *node; u32 bank_value; u8 field_flags; u8 access_attribute = 0; @@ -181,8 +188,18 @@ /* First arg is the name of the parent Op_region */ arg = op->value.arg; + if (!region_node) { + status = acpi_ns_lookup (walk_state->scope_info, arg->value.name, + ACPI_TYPE_REGION, IMODE_EXECUTE, + NS_SEARCH_PARENT, walk_state, + ®ion_node); + + if (ACPI_FAILURE (status)) { + return (status); + } + } - /* Socond arg is the Bank Register */ + /* Second arg is the Bank Register */ arg = arg->next; @@ -190,7 +207,7 @@ INTERNAL_TYPE_BANK_FIELD_DEFN, IMODE_LOAD_PASS1, NS_NO_UPSEARCH | NS_DONT_OPEN_SCOPE, - NULL, &bank_reg); + NULL, ®ister_node); if (ACPI_FAILURE (status)) { return (status); @@ -236,27 +253,24 @@ case AML_NAMEDFIELD_OP: status = acpi_ns_lookup (walk_state->scope_info, - (char *) &((ACPI_NAMED_OP *)arg)->name, + (NATIVE_CHAR *) &((ACPI_PARSE2_OBJECT *)arg)->name, INTERNAL_TYPE_DEF_FIELD, IMODE_LOAD_PASS1, NS_NO_UPSEARCH | NS_DONT_OPEN_SCOPE, - NULL, &entry); + NULL, &node); if (ACPI_FAILURE (status)) { return (status); } /* - * Initialize an object for the new NTE that is on + * Initialize an object for the new Node that is on * the object stack */ - status = acpi_aml_prep_bank_field_value (entry, region, - bank_reg, bank_value, - field_flags, - access_attribute, - field_bit_position, - arg->value.size); + status = acpi_aml_prep_bank_field_value (node, region_node, register_node, + bank_value, field_flags, access_attribute, + field_bit_position, arg->value.size); if (ACPI_FAILURE (status)) { return (status); @@ -276,30 +290,30 @@ } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_ds_create_index_field * * PARAMETERS: Op - Op containing the Field definition and args - * Region - NTE for the containing Operation Region + * Region_node - Object for the containing Operation Region * * RETURN: Status * * DESCRIPTION: Create a new index field in the specified operation region * - ****************************************************************************/ + ******************************************************************************/ ACPI_STATUS acpi_ds_create_index_field ( - ACPI_GENERIC_OP *op, - ACPI_HANDLE region, + ACPI_PARSE_OBJECT *op, + ACPI_HANDLE region_node, ACPI_WALK_STATE *walk_state) { ACPI_STATUS status; - ACPI_GENERIC_OP *arg; - ACPI_NAMED_OBJECT *entry; - ACPI_NAMED_OBJECT *index_reg; - ACPI_NAMED_OBJECT *data_reg; + ACPI_PARSE_OBJECT *arg; + ACPI_NAMESPACE_NODE *node; + ACPI_NAMESPACE_NODE *index_register_node; + ACPI_NAMESPACE_NODE *data_register_node; u8 field_flags; u8 access_attribute = 0; u32 field_bit_position = 0; @@ -312,7 +326,7 @@ status = acpi_ns_lookup (walk_state->scope_info, arg->value.string, ACPI_TYPE_ANY, IMODE_LOAD_PASS1, NS_NO_UPSEARCH | NS_DONT_OPEN_SCOPE, - NULL, &index_reg); + NULL, &index_register_node); if (ACPI_FAILURE (status)) { return (status); @@ -326,7 +340,7 @@ INTERNAL_TYPE_INDEX_FIELD_DEFN, IMODE_LOAD_PASS1, NS_NO_UPSEARCH | NS_DONT_OPEN_SCOPE, - NULL, &data_reg); + NULL, &data_register_node); if (ACPI_FAILURE (status)) { return (status); @@ -368,26 +382,24 @@ case AML_NAMEDFIELD_OP: status = acpi_ns_lookup (walk_state->scope_info, - (char *) &((ACPI_NAMED_OP *)arg)->name, + (NATIVE_CHAR *) &((ACPI_PARSE2_OBJECT *)arg)->name, INTERNAL_TYPE_INDEX_FIELD, IMODE_LOAD_PASS1, NS_NO_UPSEARCH | NS_DONT_OPEN_SCOPE, - NULL, &entry); + NULL, &node); if (ACPI_FAILURE (status)) { return (status); } /* - * Initialize an object for the new NTE that is on + * Initialize an object for the new Node that is on * the object stack */ - status = acpi_aml_prep_index_field_value (entry, index_reg, - data_reg, field_flags, - access_attribute, - field_bit_position, - arg->value.size); + status = acpi_aml_prep_index_field_value (node, index_register_node, data_register_node, + field_flags, access_attribute, + field_bit_position, arg->value.size); if (ACPI_FAILURE (status)) { return (status); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/dispatcher/dsmethod.c linux/drivers/acpi/dispatcher/dsmethod.c --- v2.4.0-test8/linux/drivers/acpi/dispatcher/dsmethod.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/dispatcher/dsmethod.c Fri Sep 15 14:30:29 2000 @@ -1,7 +1,7 @@ - /****************************************************************************** * * Module Name: dsmethod - Parser/Interpreter interface - control method parsing + * $Revision: 52 $ * *****************************************************************************/ @@ -25,24 +25,24 @@ #include "acpi.h" -#include "parser.h" +#include "acparser.h" #include "amlcode.h" -#include "dispatch.h" -#include "interp.h" -#include "namesp.h" -#include "tables.h" -#include "debugger.h" +#include "acdispat.h" +#include "acinterp.h" +#include "acnamesp.h" +#include "actables.h" +#include "acdebug.h" #define _COMPONENT DISPATCHER - MODULE_NAME ("dsmethod"); + MODULE_NAME ("dsmethod") /******************************************************************************* * * FUNCTION: Acpi_ds_parse_method * - * PARAMETERS: Obj_handle - NTE of the method + * PARAMETERS: Obj_handle - Node of the method * Level - Current nesting level * Context - Points to a method counter * Return_value - Not used @@ -61,9 +61,9 @@ ACPI_HANDLE obj_handle) { ACPI_STATUS status; - ACPI_OBJECT_INTERNAL *obj_desc; - ACPI_GENERIC_OP *op; - ACPI_NAMED_OBJECT *entry; + ACPI_OPERAND_OBJECT *obj_desc; + ACPI_PARSE_OBJECT *op; + ACPI_NAMESPACE_NODE *node; ACPI_OWNER_ID owner_id; @@ -74,10 +74,10 @@ } - /* Extract the method object from the method NTE */ + /* Extract the method object from the method Node */ - entry = (ACPI_NAMED_OBJECT*) obj_handle; - obj_desc = entry->object; + node = (ACPI_NAMESPACE_NODE *) obj_handle; + obj_desc = node->object; if (!obj_desc) { return (AE_NULL_OBJECT); } @@ -87,8 +87,7 @@ if ((obj_desc->method.concurrency != INFINITE_CONCURRENCY) && (!obj_desc->method.semaphore)) { - status = acpi_os_create_semaphore (1, - obj_desc->method.concurrency, + status = acpi_os_create_semaphore (1,obj_desc->method.concurrency, &obj_desc->method.semaphore); if (ACPI_FAILURE (status)) { return (status); @@ -105,17 +104,17 @@ return (AE_NO_MEMORY); } - /* Init new op with the method name and pointer back to the NTE */ + /* Init new op with the method name and pointer back to the Node */ - acpi_ps_set_name (op, entry->name); - op->acpi_named_object = entry; + acpi_ps_set_name (op, node->name); + op->node = node; /* - * Parse the method, creating a parse tree. + * Parse the method, first pass * - * The parse also includes a first pass load of the - * namespace where newly declared named objects are + * The first pass load is + * where newly declared named objects are * added into the namespace. Actual evaluation of * the named objects (what would be called a "second * pass") happens during the actual execution of the @@ -124,7 +123,10 @@ */ status = acpi_ps_parse_aml (op, obj_desc->method.pcode, - obj_desc->method.pcode_length, 0); + obj_desc->method.pcode_length, + ACPI_PARSE_LOAD_PASS1 | ACPI_PARSE_DELETE_TREE, + node, NULL, NULL, + acpi_ds_load1_begin_op, acpi_ds_load1_end_op); if (ACPI_FAILURE (status)) { return (status); @@ -133,11 +135,13 @@ /* Get a new Owner_id for objects created by this method */ owner_id = acpi_cm_allocate_owner_id (OWNER_TYPE_METHOD); + obj_desc->method.owning_id = owner_id; /* Install the parsed tree in the method object */ + /* TBD: [Restructure] Obsolete field? */ + + acpi_ps_delete_parse_tree (op); - obj_desc->method.parser_op = op; - obj_desc->method.owning_id = owner_id; return (status); } @@ -147,7 +151,7 @@ * * FUNCTION: Acpi_ds_begin_method_execution * - * PARAMETERS: Method_entry - NTE of the method + * PARAMETERS: Method_node - Node of the method * Obj_desc - The method object * * RETURN: Status @@ -162,38 +166,31 @@ ACPI_STATUS acpi_ds_begin_method_execution ( - ACPI_NAMED_OBJECT *method_entry, - ACPI_OBJECT_INTERNAL *obj_desc) + ACPI_NAMESPACE_NODE *method_node, + ACPI_OPERAND_OBJECT *obj_desc) { ACPI_STATUS status = AE_OK; - if (!method_entry) { + if (!method_node) { return (AE_NULL_ENTRY); } - obj_desc = acpi_ns_get_attached_object (method_entry); + obj_desc = acpi_ns_get_attached_object (method_node); if (!obj_desc) { return (AE_NULL_OBJECT); } + /* - * Lock the parser while we check for and possibly parse the - * control method + * If there is a concurrency limit on this method, we need to + * obtain a unit from the method semaphore. This releases the + * interpreter if we block */ - acpi_cm_acquire_mutex (ACPI_MTX_PARSER); - - - /* If method is not parsed at this time, we must parse it first */ - - if (!obj_desc->method.parser_op) { - - status = acpi_ds_parse_method (method_entry); - if (ACPI_FAILURE (status)) { - acpi_cm_release_mutex (ACPI_MTX_PARSER); - return (status); - } + if (obj_desc->method.semaphore) { + status = acpi_aml_system_wait_semaphore (obj_desc->method.semaphore, + WAIT_FOREVER); } @@ -204,29 +201,10 @@ * the last thread completes execution of the method */ - ((ACPI_DEFERRED_OP *) obj_desc->method.parser_op)->thread_count++; - - /* - * Parsing is complete, we can unlock the parser. Parse tree - * cannot be deleted at least until this thread completes. - */ - - acpi_cm_release_mutex (ACPI_MTX_PARSER); - - /* - * If there is a concurrency limit on this method, we need to - * obtain a unit from the method semaphore. This releases the - * interpreter if we block - */ - - if (obj_desc->method.semaphore) { - status = acpi_aml_system_wait_semaphore (obj_desc->method.semaphore, - WAIT_FOREVER); - } + obj_desc->method.thread_count++; return (status); - } @@ -247,61 +225,76 @@ acpi_ds_call_control_method ( ACPI_WALK_LIST *walk_list, ACPI_WALK_STATE *this_walk_state, - ACPI_GENERIC_OP *op) + ACPI_PARSE_OBJECT *op) { ACPI_STATUS status; - ACPI_DEFERRED_OP *method; - ACPI_NAMED_OBJECT *method_entry; - ACPI_OBJECT_INTERNAL *obj_desc; + ACPI_NAMESPACE_NODE *method_node; + ACPI_OPERAND_OBJECT *obj_desc; ACPI_WALK_STATE *next_walk_state; + ACPI_PARSE_STATE *parser_state; u32 i; /* - * Prev_op points to the METHOD_CALL Op. - * Get the NTE entry (in the METHOD_CALL->NAME Op) and the - * corresponding METHOD Op + * Get the namespace entry for the control method we are about to call */ - method_entry = (this_walk_state->prev_op->value.arg)->acpi_named_object; - if (!method_entry) { + method_node = this_walk_state->method_call_node; + if (!method_node) { return (AE_NULL_ENTRY); } - obj_desc = acpi_ns_get_attached_object (method_entry); + obj_desc = acpi_ns_get_attached_object (method_node); if (!obj_desc) { return (AE_NULL_OBJECT); } - /* Parse method if necessary, wait on concurrency semaphore */ - status = acpi_ds_begin_method_execution (method_entry, obj_desc); + /* Init for new method, wait on concurrency semaphore */ + + status = acpi_ds_begin_method_execution (method_node, obj_desc); if (ACPI_FAILURE (status)) { return (status); } - /* Save the (current) Op for when this walk is restarted */ - this_walk_state->method_call_op = this_walk_state->prev_op; - this_walk_state->prev_op = op; - method = obj_desc->method.parser_op; + /* Create and initialize a new parser state */ + + parser_state = acpi_ps_create_state (obj_desc->method.pcode, + obj_desc->method.pcode_length); + if (!parser_state) { + return (AE_NO_MEMORY); + } + + acpi_ps_init_scope (parser_state, NULL); + parser_state->start_node = method_node; + /* Create a new state for the preempting walk */ next_walk_state = acpi_ds_create_walk_state (obj_desc->method.owning_id, - (ACPI_GENERIC_OP *) method, - obj_desc, walk_list); + NULL, obj_desc, walk_list); if (!next_walk_state) { + /* TBD: delete parser state */ + return (AE_NO_MEMORY); } + next_walk_state->walk_type = WALK_METHOD; + next_walk_state->method_node = method_node; + next_walk_state->parser_state = parser_state; + next_walk_state->parse_flags = this_walk_state->parse_flags; + next_walk_state->descending_callback = this_walk_state->descending_callback; + next_walk_state->ascending_callback = this_walk_state->ascending_callback; + /* The Next_op of the Next_walk will be the beginning of the method */ + /* TBD: [Restructure] -- obsolete? */ - next_walk_state->next_op = (ACPI_GENERIC_OP *) method; + next_walk_state->next_op = NULL; /* Open a new scope */ - status = acpi_ds_scope_stack_push (method_entry->child_table, + status = acpi_ds_scope_stack_push (method_node, ACPI_TYPE_METHOD, next_walk_state); if (ACPI_FAILURE (status)) { goto cleanup; @@ -316,11 +309,28 @@ */ status = acpi_ds_method_data_init_args (&this_walk_state->operands[0], - this_walk_state->num_operands); + this_walk_state->num_operands, + next_walk_state); if (ACPI_FAILURE (status)) { goto cleanup; } + + /* Create and init a Root Node */ + + op = acpi_ps_alloc_op (AML_SCOPE_OP); + if (!op) { + return (AE_NO_MEMORY); + } + + status = acpi_ps_parse_aml (op, obj_desc->method.pcode, + obj_desc->method.pcode_length, + ACPI_PARSE_LOAD_PASS1 | ACPI_PARSE_DELETE_TREE, + method_node, NULL, NULL, + acpi_ds_load1_begin_op, acpi_ds_load1_end_op); + acpi_ps_delete_parse_tree (op); + + /* * Delete the operands on the previous walkstate operand stack * (they were copied to new objects) @@ -328,6 +338,7 @@ for (i = 0; i < obj_desc->method.param_count; i++) { acpi_cm_remove_reference (this_walk_state->operands [i]); + this_walk_state->operands [i] = NULL; } /* Clear the operand stack */ @@ -364,30 +375,33 @@ ACPI_STATUS acpi_ds_restart_control_method ( ACPI_WALK_STATE *walk_state, - ACPI_OBJECT_INTERNAL *return_desc) + ACPI_OPERAND_OBJECT *return_desc) { ACPI_STATUS status; if (return_desc) { - /* - * Get the return value (if any) from the previous method. - * NULL if no return value - */ + if (walk_state->return_used) { + /* + * Get the return value (if any) from the previous method. + * NULL if no return value + */ + + status = acpi_ds_result_stack_push (return_desc, walk_state); + if (ACPI_FAILURE (status)) { + acpi_cm_remove_reference (return_desc); + return (status); + } + } - status = acpi_ds_result_stack_push (return_desc, walk_state); - if (ACPI_FAILURE (status)) { + else { + /* + * Delete the return value if it will not be used by the + * calling method + */ acpi_cm_remove_reference (return_desc); - return (status); } - /* - * Delete the return value if it will not be used by the - * calling method - */ - - acpi_ds_delete_result_if_not_used (walk_state->method_call_op, - return_desc, walk_state); } @@ -414,9 +428,8 @@ ACPI_WALK_STATE *walk_state) { ACPI_STATUS status; - ACPI_OBJECT_INTERNAL *obj_desc; - ACPI_DEFERRED_OP *op; - ACPI_NAMED_OBJECT *method_entry; + ACPI_OPERAND_OBJECT *obj_desc; + ACPI_NAMESPACE_NODE *method_node; /* The method object should be stored in the walk state */ @@ -438,66 +451,41 @@ acpi_cm_acquire_mutex (ACPI_MTX_PARSER); - /* - * The root of the method parse tree should be stored - * in the method object - */ - - op = obj_desc->method.parser_op; - if (!op) { - goto unlock_and_exit; - } /* Signal completion of the execution of this method if necessary */ if (walk_state->method_desc->method.semaphore) { status = acpi_os_signal_semaphore ( - walk_state->method_desc->method.semaphore, 1); + walk_state->method_desc->method.semaphore, 1); } /* Decrement the thread count on the method parse tree */ - op->thread_count--; - if (!op->thread_count) { + walk_state->method_desc->method.thread_count--; + if (!walk_state->method_desc->method.thread_count) { /* * There are no more threads executing this method. Perform * additional cleanup. * - * The method NTE is stored in the method Op + * The method Node is stored in the walk state */ - method_entry = op->acpi_named_object; - + method_node = walk_state->method_node; /* * Delete any namespace entries created immediately underneath * the method */ acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE); - if (method_entry->child_table) { - acpi_ns_delete_namespace_subtree (method_entry); + if (method_node->child) { + acpi_ns_delete_namespace_subtree (method_node); } /* * Delete any namespace entries created anywhere else within * the namespace */ - - acpi_ns_delete_namespace_by_owner ( - walk_state->method_desc->method.owning_id); - + acpi_ns_delete_namespace_by_owner (walk_state->method_desc->method.owning_id); acpi_cm_release_mutex (ACPI_MTX_NAMESPACE); - - /* - * Delete the method's parse tree if asked to - */ - if (acpi_gbl_when_to_parse_methods & METHOD_DELETE_AT_COMPLETION) { - acpi_ps_delete_parse_tree ( - walk_state->method_desc->method.parser_op); - - walk_state->method_desc->method.parser_op = NULL; - } } - -unlock_and_exit: acpi_cm_release_mutex (ACPI_MTX_PARSER); return (AE_OK); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/dispatcher/dsmthdat.c linux/drivers/acpi/dispatcher/dsmthdat.c --- v2.4.0-test8/linux/drivers/acpi/dispatcher/dsmthdat.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/dispatcher/dsmthdat.c Fri Sep 15 14:30:29 2000 @@ -1,9 +1,9 @@ - -/****************************************************************************** +/******************************************************************************* * * Module Name: dsmthdat - control method arguments and local variables + * $Revision: 34 $ * - *****************************************************************************/ + ******************************************************************************/ /* * Copyright (C) 2000 R. Byron Moore @@ -25,18 +25,18 @@ #include "acpi.h" -#include "parser.h" -#include "dispatch.h" -#include "interp.h" +#include "acparser.h" +#include "acdispat.h" +#include "acinterp.h" #include "amlcode.h" -#include "namesp.h" +#include "acnamesp.h" #define _COMPONENT DISPATCHER - MODULE_NAME ("dsmthdat"); + MODULE_NAME ("dsmthdat") -/***************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_ds_method_data_init * @@ -49,7 +49,7 @@ * This allows Ref_of and De_ref_of to work properly for these * special data types. * - ****************************************************************************/ + ******************************************************************************/ ACPI_STATUS acpi_ds_method_data_init ( @@ -62,8 +62,8 @@ * Walk_state fields are initialized to zero by the * Acpi_cm_callocate(). * - * An NTE is assigned to each argument and local so - * that Ref_of() can return a pointer to the NTE. + * An Node is assigned to each argument and local so + * that Ref_of() can return a pointer to the Node. */ /* Init the method arguments */ @@ -72,10 +72,9 @@ MOVE_UNALIGNED32_TO_32 (&walk_state->arguments[i].name, NAMEOF_ARG_NTE); - walk_state->arguments[i].name |= (i << 24); - walk_state->arguments[i].data_type = ACPI_DESC_TYPE_NAMED; - walk_state->arguments[i].type = - INTERNAL_TYPE_METHOD_ARGUMENT; + walk_state->arguments[i].name |= (i << 24); + walk_state->arguments[i].data_type = ACPI_DESC_TYPE_NAMED; + walk_state->arguments[i].type = INTERNAL_TYPE_METHOD_ARGUMENT; } /* Init the method locals */ @@ -84,18 +83,16 @@ MOVE_UNALIGNED32_TO_32 (&walk_state->local_variables[i].name, NAMEOF_LOCAL_NTE); - walk_state->local_variables[i].name |= (i << 24); + walk_state->local_variables[i].name |= (i << 24); walk_state->local_variables[i].data_type = ACPI_DESC_TYPE_NAMED; - walk_state->local_variables[i].type = - INTERNAL_TYPE_METHOD_LOCAL_VAR; + walk_state->local_variables[i].type = INTERNAL_TYPE_METHOD_LOCAL_VAR; } - return (AE_OK); } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_ds_method_data_delete_all * @@ -106,14 +103,14 @@ * DESCRIPTION: Delete method locals and arguments. Arguments are only * deleted if this method was called from another method. * - ****************************************************************************/ + ******************************************************************************/ ACPI_STATUS acpi_ds_method_data_delete_all ( ACPI_WALK_STATE *walk_state) { u32 index; - ACPI_OBJECT_INTERNAL *object; + ACPI_OPERAND_OBJECT *object; /* Delete the locals */ @@ -122,8 +119,11 @@ object = walk_state->local_variables[index].object; if (object) { /* Remove first */ + walk_state->local_variables[index].object = NULL; + /* Was given a ref when stored */ + acpi_cm_remove_reference (object); } } @@ -135,8 +135,11 @@ object = walk_state->arguments[index].object; if (object) { /* Remove first */ + walk_state->arguments[index].object = NULL; + /* Was given a ref when stored */ + acpi_cm_remove_reference (object); } } @@ -145,7 +148,7 @@ } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_ds_method_data_init_args * @@ -155,12 +158,13 @@ * * DESCRIPTION: Initialize arguments for a method * - ****************************************************************************/ + ******************************************************************************/ ACPI_STATUS acpi_ds_method_data_init_args ( - ACPI_OBJECT_INTERNAL **params, - u32 max_param_count) + ACPI_OPERAND_OBJECT **params, + u32 max_param_count, + ACPI_WALK_STATE *walk_state) { ACPI_STATUS status; u32 mindex; @@ -183,9 +187,8 @@ * Set the current method argument to the * Params[Pindex++] argument object descriptor */ - status = acpi_ds_method_data_set_value (MTH_TYPE_ARG, - mindex, - params[pindex]); + status = acpi_ds_method_data_set_value (MTH_TYPE_ARG, mindex, + params[pindex], walk_state); if (ACPI_FAILURE (status)) { break; } @@ -202,7 +205,7 @@ } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_ds_method_data_get_entry * @@ -215,18 +218,16 @@ * * DESCRIPTION: Get the address of the stack entry given by Type:Index * - ****************************************************************************/ + ******************************************************************************/ ACPI_STATUS acpi_ds_method_data_get_entry ( u32 type, u32 index, - ACPI_OBJECT_INTERNAL ***entry) + ACPI_WALK_STATE *walk_state, + ACPI_OPERAND_OBJECT ***entry) { - ACPI_WALK_STATE *walk_state; - - walk_state = acpi_ds_get_current_walk_state (acpi_gbl_current_walk_list); /* * Get the requested object. @@ -243,7 +244,7 @@ } *entry = - (ACPI_OBJECT_INTERNAL **) &walk_state->local_variables[index].object; + (ACPI_OPERAND_OBJECT **) &walk_state->local_variables[index].object; break; @@ -254,7 +255,7 @@ } *entry = - (ACPI_OBJECT_INTERNAL **) &walk_state->arguments[index].object; + (ACPI_OPERAND_OBJECT **) &walk_state->arguments[index].object; break; @@ -267,7 +268,7 @@ } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_ds_method_data_set_entry * @@ -279,21 +280,22 @@ * * DESCRIPTION: Insert an object onto the method stack at entry Type:Index. * - ****************************************************************************/ + ******************************************************************************/ ACPI_STATUS acpi_ds_method_data_set_entry ( u32 type, u32 index, - ACPI_OBJECT_INTERNAL *object) + ACPI_OPERAND_OBJECT *object, + ACPI_WALK_STATE *walk_state) { ACPI_STATUS status; - ACPI_OBJECT_INTERNAL **entry; + ACPI_OPERAND_OBJECT **entry; /* Get a pointer to the stack entry to set */ - status = acpi_ds_method_data_get_entry (type, index, &entry); + status = acpi_ds_method_data_get_entry (type, index, walk_state, &entry); if (ACPI_FAILURE (status)) { return (status); } @@ -310,7 +312,7 @@ } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_ds_method_data_get_type * @@ -321,21 +323,22 @@ * RETURN: Data type of selected Arg or Local * Used only in Exec_monadic2()/Type_op. * - ****************************************************************************/ + ******************************************************************************/ OBJECT_TYPE_INTERNAL acpi_ds_method_data_get_type ( u32 type, - u32 index) + u32 index, + ACPI_WALK_STATE *walk_state) { ACPI_STATUS status; - ACPI_OBJECT_INTERNAL **entry; - ACPI_OBJECT_INTERNAL *object; + ACPI_OPERAND_OBJECT **entry; + ACPI_OPERAND_OBJECT *object; /* Get a pointer to the requested stack entry */ - status = acpi_ds_method_data_get_entry (type, index, &entry); + status = acpi_ds_method_data_get_entry (type, index, walk_state, &entry); if (ACPI_FAILURE (status)) { return ((ACPI_TYPE_NOT_FOUND)); } @@ -355,7 +358,7 @@ } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_ds_method_data_get_nte * @@ -363,20 +366,17 @@ * Index - Which local_var or argument whose type * to get * - * RETURN: Get the NTE associated with a local or arg. + * RETURN: Get the Node associated with a local or arg. * - ****************************************************************************/ + ******************************************************************************/ -ACPI_NAMED_OBJECT* +ACPI_NAMESPACE_NODE * acpi_ds_method_data_get_nte ( u32 type, - u32 index) + u32 index, + ACPI_WALK_STATE *walk_state) { - ACPI_NAMED_OBJECT *entry = NULL; - ACPI_WALK_STATE *walk_state; - - - walk_state = acpi_ds_get_current_walk_state (acpi_gbl_current_walk_list); + ACPI_NAMESPACE_NODE *node = NULL; switch (type) @@ -385,20 +385,20 @@ case MTH_TYPE_LOCAL: if (index > MTH_MAX_LOCAL) { - return (entry); + return (node); } - entry = &walk_state->local_variables[index]; + node = &walk_state->local_variables[index]; break; case MTH_TYPE_ARG: if (index > MTH_MAX_ARG) { - return (entry); + return (node); } - entry = &walk_state->arguments[index]; + node = &walk_state->arguments[index]; break; @@ -407,11 +407,11 @@ } - return (entry); + return (node); } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_ds_method_data_get_value * @@ -426,17 +426,18 @@ * at the current top of the method stack. * Used only in Acpi_aml_resolve_to_value(). * - ****************************************************************************/ + ******************************************************************************/ ACPI_STATUS acpi_ds_method_data_get_value ( u32 type, u32 index, - ACPI_OBJECT_INTERNAL **dest_desc) + ACPI_WALK_STATE *walk_state, + ACPI_OPERAND_OBJECT **dest_desc) { ACPI_STATUS status; - ACPI_OBJECT_INTERNAL **entry; - ACPI_OBJECT_INTERNAL *object; + ACPI_OPERAND_OBJECT **entry; + ACPI_OPERAND_OBJECT *object; /* Validate the object descriptor */ @@ -448,7 +449,7 @@ /* Get a pointer to the requested method stack entry */ - status = acpi_ds_method_data_get_entry (type, index, &entry); + status = acpi_ds_method_data_get_entry (type, index, walk_state, &entry); if (ACPI_FAILURE (status)) { return (status); } @@ -494,7 +495,7 @@ } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_ds_method_data_delete_value * @@ -506,21 +507,22 @@ * DESCRIPTION: Delete the entry at Type:Index on the method stack. Inserts * a null into the stack slot after the object is deleted. * - ****************************************************************************/ + ******************************************************************************/ ACPI_STATUS acpi_ds_method_data_delete_value ( u32 type, - u32 index) + u32 index, + ACPI_WALK_STATE *walk_state) { ACPI_STATUS status; - ACPI_OBJECT_INTERNAL **entry; - ACPI_OBJECT_INTERNAL *object; + ACPI_OPERAND_OBJECT **entry; + ACPI_OPERAND_OBJECT *object; /* Get a pointer to the requested entry */ - status = acpi_ds_method_data_get_entry (type, index, &entry); + status = acpi_ds_method_data_get_entry (type, index, walk_state, &entry); if (ACPI_FAILURE (status)) { return (status); } @@ -532,7 +534,7 @@ /* * Undefine the Arg or Local by setting its descriptor * pointer to NULL. Locals/Args can contain both - * ACPI_OBJECT_INTERNALS and ACPI_NAMED_OBJECTs + * ACPI_OPERAND_OBJECTS and ACPI_NAMESPACE_NODEs */ *entry = NULL; @@ -554,7 +556,7 @@ } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_ds_method_data_set_value * @@ -573,16 +575,17 @@ * as the new value for the Arg or Local and the reference count * is incremented. * - ****************************************************************************/ + ******************************************************************************/ ACPI_STATUS acpi_ds_method_data_set_value ( u32 type, u32 index, - ACPI_OBJECT_INTERNAL *src_desc) + ACPI_OPERAND_OBJECT *src_desc, + ACPI_WALK_STATE *walk_state) { ACPI_STATUS status; - ACPI_OBJECT_INTERNAL **entry; + ACPI_OPERAND_OBJECT **entry; /* Parameter validation */ @@ -594,7 +597,7 @@ /* Get a pointer to the requested method stack entry */ - status = acpi_ds_method_data_get_entry (type, index, &entry); + status = acpi_ds_method_data_get_entry (type, index, walk_state, &entry); if (ACPI_FAILURE (status)) { goto cleanup; } @@ -614,7 +617,7 @@ if (*entry) { /* * Check for an indirect store if an argument - * contains an object reference (stored as an NTE). + * contains an object reference (stored as an Node). * We don't allow this automatic dereferencing for * locals, since a store to a local should overwrite * anything there, including an object reference. @@ -632,16 +635,16 @@ if ((type == MTH_TYPE_ARG) && (VALID_DESCRIPTOR_TYPE (*entry, ACPI_DESC_TYPE_NAMED))) { - /* Detach an existing object from the NTE */ + /* Detach an existing object from the Node */ - acpi_ns_detach_object (*entry); + acpi_ns_detach_object ((ACPI_NAMESPACE_NODE *) *entry); /* - * Store this object into the NTE + * Store this object into the Node * (do the indirect store) */ - status = acpi_ns_attach_object (*entry, src_desc, + status = acpi_ns_attach_object ((ACPI_NAMESPACE_NODE *) *entry, src_desc, src_desc->common.type); return (status); } @@ -652,7 +655,7 @@ * before storing the new one */ - acpi_ds_method_data_delete_value (type, index); + acpi_ds_method_data_delete_value (type, index, walk_state); } @@ -663,7 +666,7 @@ * (increments the object reference count by one) */ - status = acpi_ds_method_data_set_entry (type, index, src_desc); + status = acpi_ds_method_data_set_entry (type, index, src_desc, walk_state); if (ACPI_FAILURE (status)) { goto cleanup; } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/dispatcher/dsobject.c linux/drivers/acpi/dispatcher/dsobject.c --- v2.4.0-test8/linux/drivers/acpi/dispatcher/dsobject.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/dispatcher/dsobject.c Fri Sep 15 14:30:29 2000 @@ -1,7 +1,7 @@ - /****************************************************************************** * * Module Name: dsobject - Dispatcher object management routines + * $Revision: 43 $ * *****************************************************************************/ @@ -25,21 +25,21 @@ #include "acpi.h" -#include "parser.h" +#include "acparser.h" #include "amlcode.h" -#include "dispatch.h" -#include "interp.h" -#include "namesp.h" +#include "acdispat.h" +#include "acinterp.h" +#include "acnamesp.h" #define _COMPONENT DISPATCHER - MODULE_NAME ("dsobject"); + MODULE_NAME ("dsobject") /******************************************************************************* * * FUNCTION: Acpi_ds_init_one_object * - * PARAMETERS: Obj_handle - NTE of the object + * PARAMETERS: Obj_handle - Node * Level - Current nesting level * Context - Points to a init info struct * Return_value - Not used @@ -64,7 +64,6 @@ { OBJECT_TYPE_INTERNAL type; ACPI_STATUS status; - ACPI_OBJECT_INTERNAL *obj_desc; INIT_WALK_INFO *info = (INIT_WALK_INFO *) context; @@ -73,10 +72,10 @@ * was just loaded */ - if (((ACPI_NAMED_OBJECT*) obj_handle)->owner_id != + if (((ACPI_NAMESPACE_NODE *) obj_handle)->owner_id != info->table_desc->table_id) { - return AE_OK; + return (AE_OK); } @@ -119,12 +118,7 @@ */ if (acpi_gbl_when_to_parse_methods != METHOD_PARSE_AT_INIT) { - acpi_ns_delete_namespace_subtree (obj_handle); - - obj_desc = ((ACPI_NAMED_OBJECT*)obj_handle)->object; - acpi_ps_delete_parse_tree (obj_desc->method.parser_op); - obj_desc->method.parser_op = NULL; } break; @@ -149,15 +143,15 @@ * * RETURN: Status * - * DESCRIPTION: Walk the entire namespace and perform any necessary initialization - * on the objects found therein + * DESCRIPTION: Walk the entire namespace and perform any necessary + * initialization on the objects found therein * ******************************************************************************/ ACPI_STATUS acpi_ds_initialize_objects ( ACPI_TABLE_DESC *table_desc, - ACPI_NAMED_OBJECT *start_entry) + ACPI_NAMESPACE_NODE *start_node) { ACPI_STATUS status; INIT_WALK_INFO info; @@ -170,8 +164,8 @@ /* Walk entire namespace from the supplied root */ - status = acpi_walk_namespace (ACPI_TYPE_ANY, start_entry, - ACPI_INT32_MAX, acpi_ds_init_one_object, + status = acpi_walk_namespace (ACPI_TYPE_ANY, start_node, + ACPI_UINT32_MAX, acpi_ds_init_one_object, &info, NULL); return (AE_OK); @@ -197,28 +191,28 @@ ACPI_STATUS acpi_ds_init_object_from_op ( ACPI_WALK_STATE *walk_state, - ACPI_GENERIC_OP *op, + ACPI_PARSE_OBJECT *op, u16 opcode, - ACPI_OBJECT_INTERNAL *obj_desc) + ACPI_OPERAND_OBJECT **obj_desc) { ACPI_STATUS status; - ACPI_GENERIC_OP *arg; - ACPI_BYTELIST_OP *byte_list; - ACPI_OBJECT_INTERNAL *arg_desc; - ACPI_OP_INFO *op_info; + ACPI_PARSE_OBJECT *arg; + ACPI_PARSE2_OBJECT *byte_list; + ACPI_OPERAND_OBJECT *arg_desc; + ACPI_OPCODE_INFO *op_info; op_info = acpi_ps_get_opcode_info (opcode); - if (!op_info) { + if (ACPI_GET_OP_TYPE (op_info) != ACPI_OP_TYPE_OPCODE) { /* Unknown opcode */ - return AE_TYPE; + return (AE_TYPE); } /* Get and prepare the first argument */ - switch (obj_desc->common.type) + switch ((*obj_desc)->common.type) { case ACPI_TYPE_BUFFER: @@ -230,31 +224,31 @@ /* Resolve the object (could be an arg or local) */ - status = acpi_aml_resolve_to_value (&arg_desc); + status = acpi_aml_resolve_to_value (&arg_desc, walk_state); if (ACPI_FAILURE (status)) { acpi_cm_remove_reference (arg_desc); - return status; + return (status); } /* We are expecting a number */ if (arg_desc->common.type != ACPI_TYPE_NUMBER) { acpi_cm_remove_reference (arg_desc); - return AE_TYPE; + return (AE_TYPE); } /* Get the value, delete the internal object */ - obj_desc->buffer.length = arg_desc->number.value; + (*obj_desc)->buffer.length = arg_desc->number.value; acpi_cm_remove_reference (arg_desc); /* Allocate the buffer */ - obj_desc->buffer.pointer = - acpi_cm_callocate (obj_desc->buffer.length); + (*obj_desc)->buffer.pointer = + acpi_cm_callocate ((*obj_desc)->buffer.length); - if (!obj_desc->buffer.pointer) { - return AE_NO_MEMORY; + if (!(*obj_desc)->buffer.pointer) { + return (AE_NO_MEMORY); } /* @@ -265,27 +259,42 @@ /* skip first arg */ arg = op->value.arg; - byte_list = (ACPI_BYTELIST_OP *) arg->next; + byte_list = (ACPI_PARSE2_OBJECT *) arg->next; if (byte_list) { if (byte_list->opcode != AML_BYTELIST_OP) { - return AE_TYPE; + return (AE_TYPE); } - MEMCPY (obj_desc->buffer.pointer, byte_list->data, - obj_desc->buffer.length); + MEMCPY ((*obj_desc)->buffer.pointer, byte_list->data, + (*obj_desc)->buffer.length); } break; + case ACPI_TYPE_PACKAGE: + + /* + * When called, an internal package object has already + * been built and is pointed to by *Obj_desc. + * Acpi_ds_build_internal_object build another internal + * package object, so remove reference to the original + * so that it is deleted. Error checking is done + * within the remove reference function. + */ + acpi_cm_remove_reference(*obj_desc); + + status = acpi_ds_build_internal_object (walk_state, op, obj_desc); + break; + case ACPI_TYPE_NUMBER: - obj_desc->number.value = op->value.integer; + (*obj_desc)->number.value = op->value.integer; break; case ACPI_TYPE_STRING: - obj_desc->string.pointer = op->value.string; - obj_desc->string.length = STRLEN (op->value.string); + (*obj_desc)->string.pointer = op->value.string; + (*obj_desc)->string.length = STRLEN (op->value.string); break; @@ -295,33 +304,33 @@ case INTERNAL_TYPE_REFERENCE: - switch (op_info->flags & OP_INFO_TYPE) + switch (ACPI_GET_OP_CLASS (op_info)) { case OPTYPE_LOCAL_VARIABLE: /* Split the opcode into a base opcode + offset */ - obj_desc->reference.op_code = AML_LOCAL_OP; - obj_desc->reference.offset = opcode - AML_LOCAL_OP; + (*obj_desc)->reference.op_code = AML_LOCAL_OP; + (*obj_desc)->reference.offset = opcode - AML_LOCAL_OP; break; case OPTYPE_METHOD_ARGUMENT: /* Split the opcode into a base opcode + offset */ - obj_desc->reference.op_code = AML_ARG_OP; - obj_desc->reference.offset = opcode - AML_ARG_OP; + (*obj_desc)->reference.op_code = AML_ARG_OP; + (*obj_desc)->reference.offset = opcode - AML_ARG_OP; break; default: /* Constants, Literals, etc.. */ if (op->opcode == AML_NAMEPATH_OP) { - /* Nte was saved in Op */ + /* Node was saved in Op */ - obj_desc->reference.nte = op->acpi_named_object; + (*obj_desc)->reference.node = op->node; } - obj_desc->reference.op_code = opcode; + (*obj_desc)->reference.op_code = opcode; break; } @@ -333,7 +342,7 @@ break; } - return AE_OK; + return (AE_OK); } @@ -354,10 +363,10 @@ ACPI_STATUS acpi_ds_build_internal_simple_obj ( ACPI_WALK_STATE *walk_state, - ACPI_GENERIC_OP *op, - ACPI_OBJECT_INTERNAL **obj_desc_ptr) + ACPI_PARSE_OBJECT *op, + ACPI_OPERAND_OBJECT **obj_desc_ptr) { - ACPI_OBJECT_INTERNAL *obj_desc; + ACPI_OPERAND_OBJECT *obj_desc; OBJECT_TYPE_INTERNAL type; ACPI_STATUS status; @@ -369,13 +378,13 @@ * Otherwise, go ahead and look it up now */ - if (!op->acpi_named_object) { + if (!op->node) { status = acpi_ns_lookup (walk_state->scope_info, op->value.string, ACPI_TYPE_ANY, IMODE_EXECUTE, NS_SEARCH_PARENT | NS_DONT_OPEN_SCOPE, NULL, - (ACPI_NAMED_OBJECT**)&(op->acpi_named_object)); + (ACPI_NAMESPACE_NODE **)&(op->node)); if (ACPI_FAILURE (status)) { return (status); @@ -403,7 +412,7 @@ } status = acpi_ds_init_object_from_op (walk_state, op, - op->opcode, obj_desc); + op->opcode, &obj_desc); if (ACPI_FAILURE (status)) { acpi_cm_remove_reference (obj_desc); @@ -433,11 +442,11 @@ ACPI_STATUS acpi_ds_build_internal_package_obj ( ACPI_WALK_STATE *walk_state, - ACPI_GENERIC_OP *op, - ACPI_OBJECT_INTERNAL **obj_desc_ptr) + ACPI_PARSE_OBJECT *op, + ACPI_OPERAND_OBJECT **obj_desc_ptr) { - ACPI_GENERIC_OP *arg; - ACPI_OBJECT_INTERNAL *obj_desc; + ACPI_PARSE_OBJECT *arg; + ACPI_OPERAND_OBJECT *obj_desc; ACPI_STATUS status = AE_OK; @@ -466,7 +475,7 @@ REPORT_ERROR ("Ds_build_internal_package_obj: Package vector allocation failure"); - acpi_cm_free (obj_desc); + acpi_cm_delete_object_desc (obj_desc); return (AE_NO_MEMORY); } @@ -514,8 +523,8 @@ ACPI_STATUS acpi_ds_build_internal_object ( ACPI_WALK_STATE *walk_state, - ACPI_GENERIC_OP *op, - ACPI_OBJECT_INTERNAL **obj_desc_ptr) + ACPI_PARSE_OBJECT *op, + ACPI_OPERAND_OBJECT **obj_desc_ptr) { ACPI_STATUS status; @@ -536,7 +545,7 @@ /***************************************************************************** * - * FUNCTION: Acpi_ds_create_named_object + * FUNCTION: Acpi_ds_create_node * * PARAMETERS: Op - Parser object to be translated * Obj_desc_ptr - Where the ACPI internal object is returned @@ -548,13 +557,13 @@ ****************************************************************************/ ACPI_STATUS -acpi_ds_create_named_object ( +acpi_ds_create_node ( ACPI_WALK_STATE *walk_state, - ACPI_NAMED_OBJECT *entry, - ACPI_GENERIC_OP *op) + ACPI_NAMESPACE_NODE *node, + ACPI_PARSE_OBJECT *op) { ACPI_STATUS status; - ACPI_OBJECT_INTERNAL *obj_desc; + ACPI_OPERAND_OBJECT *obj_desc; if (!op->value.arg) { @@ -575,12 +584,12 @@ /* Re-type the object according to it's argument */ - entry->type = obj_desc->common.type; + node->type = obj_desc->common.type; /* Init obj */ - status = acpi_ns_attach_object ((ACPI_HANDLE) entry, obj_desc, - (u8) entry->type); + status = acpi_ns_attach_object ((ACPI_HANDLE) node, obj_desc, + (u8) node->type); if (ACPI_FAILURE (status)) { goto cleanup; } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/dispatcher/dsopcode.c linux/drivers/acpi/dispatcher/dsopcode.c --- v2.4.0-test8/linux/drivers/acpi/dispatcher/dsopcode.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/dispatcher/dsopcode.c Fri Sep 15 14:30:29 2000 @@ -1,8 +1,8 @@ - /****************************************************************************** * - * Module Name: dsopcode - Dispatcher Op Region support - * and handling of "control" opcodes + * Module Name: dsopcode - Dispatcher Op Region support and handling of + * "control" opcodes + * $Revision: 17 $ * *****************************************************************************/ @@ -26,16 +26,16 @@ #include "acpi.h" -#include "parser.h" +#include "acparser.h" #include "amlcode.h" -#include "dispatch.h" -#include "interp.h" -#include "namesp.h" -#include "events.h" -#include "tables.h" +#include "acdispat.h" +#include "acinterp.h" +#include "acnamesp.h" +#include "acevents.h" +#include "actables.h" #define _COMPONENT DISPATCHER - MODULE_NAME ("dsopcode"); + MODULE_NAME ("dsopcode") /***************************************************************************** @@ -53,23 +53,23 @@ ACPI_STATUS acpi_ds_get_region_arguments ( - ACPI_OBJECT_INTERNAL *rgn_desc) + ACPI_OPERAND_OBJECT *rgn_desc) { - ACPI_OBJECT_INTERNAL *method_desc; - ACPI_NAMED_OBJECT *entry; - ACPI_GENERIC_OP *op; - ACPI_GENERIC_OP *region_op; + ACPI_OPERAND_OBJECT *method_desc; + ACPI_NAMESPACE_NODE *node; + ACPI_PARSE_OBJECT *op; + ACPI_PARSE_OBJECT *region_op; ACPI_STATUS status; ACPI_TABLE_DESC *table_desc; - if (rgn_desc->region.region_flags & REGION_AGRUMENT_DATA_VALID) { + if (rgn_desc->region.flags & AOPOBJ_DATA_VALID) { return (AE_OK); } method_desc = rgn_desc->region.method; - entry = rgn_desc->region.nte; + node = rgn_desc->region.node; /* @@ -77,18 +77,18 @@ * Op_region tree */ - op = acpi_ps_alloc_op (AML_REGION_OP); + op = acpi_ps_alloc_op (AML_SCOPE_OP); if (!op) { - return AE_NO_MEMORY; + return (AE_NO_MEMORY); } - /* Save the NTE for use in Acpi_ps_parse_aml */ + /* Save the Node for use in Acpi_ps_parse_aml */ - op->acpi_named_object = acpi_ns_get_parent_entry (entry); + op->node = acpi_ns_get_parent_object (node); /* Get a handle to the parent ACPI table */ - status = acpi_tb_handle_to_object (entry->owner_id, &table_desc); + status = acpi_tb_handle_to_object (node->owner_id, &table_desc); if (ACPI_FAILURE (status)) { return (status); } @@ -96,20 +96,44 @@ /* Parse the entire Op_region declaration, creating a parse tree */ status = acpi_ps_parse_aml (op, method_desc->method.pcode, - method_desc->method.pcode_length, 0); - if (ACPI_SUCCESS (status)) { - /* Get and init the actual Region_op created above */ - - region_op = op->value.arg; - region_op->acpi_named_object = entry; - - /* Acpi_evaluate the address and length arguments for the Op_region */ - - acpi_ps_walk_parsed_aml (region_op, region_op, NULL, NULL, NULL, - NULL, table_desc->table_id, - acpi_ds_exec_begin_op, acpi_ds_exec_end_op); + method_desc->method.pcode_length, 0, + NULL, NULL, NULL, acpi_ds_load1_begin_op, acpi_ds_load1_end_op); + + if (ACPI_FAILURE (status)) { + acpi_ps_delete_parse_tree (op); + return (status); } + + /* Get and init the actual Region_op created above */ + +/* Region_op = Op->Value.Arg; + Op->Node = Node;*/ + + + region_op = op->value.arg; + region_op->node = node; + acpi_ps_delete_parse_tree (op); + + /* Acpi_evaluate the address and length arguments for the Op_region */ + + op = acpi_ps_alloc_op (AML_SCOPE_OP); + if (!op) { + return (AE_NO_MEMORY); + } + + op->node = acpi_ns_get_parent_object (node); + + status = acpi_ps_parse_aml (op, method_desc->method.pcode, + method_desc->method.pcode_length, + ACPI_PARSE_EXECUTE | ACPI_PARSE_DELETE_TREE, + NULL /*Method_desc*/, NULL, NULL, + acpi_ds_exec_begin_op, acpi_ds_exec_end_op); +/* + Acpi_ps_walk_parsed_aml (Region_op, Region_op, NULL, NULL, NULL, + NULL, Table_desc->Table_id, + Acpi_ds_exec_begin_op, Acpi_ds_exec_end_op); +*/ /* All done with the parse tree, delete it */ acpi_ps_delete_parse_tree (op); @@ -134,7 +158,7 @@ acpi_ds_initialize_region ( ACPI_HANDLE obj_handle) { - ACPI_OBJECT_INTERNAL *obj_desc; + ACPI_OPERAND_OBJECT *obj_desc; ACPI_STATUS status; @@ -144,7 +168,7 @@ status = acpi_ev_initialize_region (obj_desc, FALSE); - return status; + return (status); } @@ -164,20 +188,20 @@ ACPI_STATUS acpi_ds_eval_region_operands ( ACPI_WALK_STATE *walk_state, - ACPI_GENERIC_OP *op) + ACPI_PARSE_OBJECT *op) { ACPI_STATUS status; - ACPI_OBJECT_INTERNAL *obj_desc; - ACPI_OBJECT_INTERNAL *region_desc; - ACPI_NAMED_OBJECT *entry; - ACPI_GENERIC_OP *next_op; + ACPI_OPERAND_OBJECT *obj_desc; + ACPI_OPERAND_OBJECT *region_desc; + ACPI_NAMESPACE_NODE *node; + ACPI_PARSE_OBJECT *next_op; /* * This is where we evaluate the address and length fields of the Op_region declaration */ - entry = op->acpi_named_object; + node = op->node; /* Next_op points to the op that holds the Space_iD */ next_op = op->value.arg; @@ -192,7 +216,7 @@ return (status); } - region_desc = acpi_ns_get_attached_object (entry); + region_desc = acpi_ns_get_attached_object (node); if (!region_desc) { return (AE_NOT_EXIST); } @@ -216,7 +240,7 @@ /* Now the address and length are valid for this opregion */ - region_desc->region.region_flags |= REGION_AGRUMENT_DATA_VALID; + region_desc->region.flags |= AOPOBJ_DATA_VALID; return (status); } @@ -239,7 +263,7 @@ ACPI_STATUS acpi_ds_exec_begin_control_op ( ACPI_WALK_STATE *walk_state, - ACPI_GENERIC_OP *op) + ACPI_PARSE_OBJECT *op) { ACPI_STATUS status = AE_OK; ACPI_GENERIC_STATE *control_state; @@ -263,6 +287,14 @@ } acpi_cm_push_generic_state (&walk_state->control_state, control_state); + + /* + * Save a pointer to the predicate for multiple executions + * of a loop + */ + walk_state->control_state->control.aml_predicate_start = + walk_state->parser_state->aml - 1; + /*Acpi_ps_pkg_length_encoding_size (GET8 (Walk_state->Parser_state->Aml));*/ break; @@ -287,7 +319,7 @@ break; } - return status; + return (status); } @@ -309,7 +341,7 @@ ACPI_STATUS acpi_ds_exec_end_control_op ( ACPI_WALK_STATE *walk_state, - ACPI_GENERIC_OP *op) + ACPI_PARSE_OBJECT *op) { ACPI_STATUS status = AE_OK; ACPI_GENERIC_STATE *control_state; @@ -350,16 +382,18 @@ if (walk_state->control_state->common.value) { /* Predicate was true, go back and evaluate it again! */ - status = AE_CTRL_TRUE; + status = AE_CTRL_PENDING; } - else { +/* else {*/ /* Pop this control state and free it */ control_state = acpi_cm_pop_generic_state (&walk_state->control_state); + + walk_state->aml_last_while = control_state->control.aml_predicate_start; acpi_cm_delete_generic_state (control_state); - } +/* }*/ break; @@ -367,44 +401,62 @@ case AML_RETURN_OP: - /* One optional operand -- the return value */ - + /* + * One optional operand -- the return value + * It can be either an immediate operand or a result that + * has been bubbled up the tree + */ if (op->value.arg) { + /* Return statement has an immediate operand */ + status = acpi_ds_create_operands (walk_state, op->value.arg); if (ACPI_FAILURE (status)) { - return status; + return (status); } /* - * TBD: [Restructure] Just check for NULL arg - * to signify no return value??? - */ - - /* * If value being returned is a Reference (such as * an arg or local), resolve it now because it may * cease to exist at the end of the method. */ - status = acpi_aml_resolve_to_value (&walk_state->operands [0]); + status = acpi_aml_resolve_to_value (&walk_state->operands [0], walk_state); if (ACPI_FAILURE (status)) { - return status; + return (status); } /* * Get the return value and save as the last result - * value - * This is the only place where Walk_state->Return_desc + * value. This is the only place where Walk_state->Return_desc * is set to anything other than zero! */ walk_state->return_desc = walk_state->operands[0]; } + else if (walk_state->num_results > 0) { + /* + * The return value has come from a previous calculation. + * + * If value being returned is a Reference (such as + * an arg or local), resolve it now because it may + * cease to exist at the end of the method. + */ + + status = acpi_aml_resolve_to_value (&walk_state->results [0], walk_state); + if (ACPI_FAILURE (status)) { + return (status); + } + + walk_state->return_desc = walk_state->results [0]; + } + else { /* No return operand */ - acpi_cm_remove_reference (walk_state->operands [0]); + if (walk_state->num_operands) { + acpi_cm_remove_reference (walk_state->operands [0]); + } walk_state->operands [0] = NULL; walk_state->num_operands = 0; @@ -417,7 +469,7 @@ break; - case AML_NOOP_CODE: + case AML_NOOP_OP: /* Just do nothing! */ break; @@ -459,6 +511,6 @@ } - return status; + return (status); } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/dispatcher/dsutils.c linux/drivers/acpi/dispatcher/dsutils.c --- v2.4.0-test8/linux/drivers/acpi/dispatcher/dsutils.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/dispatcher/dsutils.c Fri Sep 15 14:30:29 2000 @@ -1,9 +1,9 @@ - -/****************************************************************************** +/******************************************************************************* * * Module Name: dsutils - Dispatcher utilities + * $Revision: 44 $ * - *****************************************************************************/ + ******************************************************************************/ /* * Copyright (C) 2000 R. Byron Moore @@ -25,20 +25,20 @@ #include "acpi.h" -#include "parser.h" +#include "acparser.h" #include "amlcode.h" -#include "dispatch.h" -#include "interp.h" -#include "namesp.h" -#include "debugger.h" +#include "acdispat.h" +#include "acinterp.h" +#include "acnamesp.h" +#include "acdebug.h" #define _COMPONENT PARSER - MODULE_NAME ("dsutils"); + MODULE_NAME ("dsutils") -/***************************************************************************** +/******************************************************************************* * - * FUNCTION: Acpi_ds_delete_result_if_not_used + * FUNCTION: Acpi_ds_is_result_used * * PARAMETERS: Op * Result_obj @@ -46,52 +46,32 @@ * * RETURN: Status * - * DESCRIPTION: Used after interpretation of an opcode. If there is an internal - * result descriptor, check if the parent opcode will actually use - * this result. If not, delete the result now so that it will - * not become orphaned. + * DESCRIPTION: Check if a result object will be used by the parent * - ****************************************************************************/ + ******************************************************************************/ -void -acpi_ds_delete_result_if_not_used ( - ACPI_GENERIC_OP *op, - ACPI_OBJECT_INTERNAL *result_obj, - ACPI_WALK_STATE *walk_state) +u8 +acpi_ds_is_result_used ( + ACPI_PARSE_OBJECT *op) { - ACPI_OP_INFO *parent_info; - ACPI_OBJECT_INTERNAL *obj_desc; - ACPI_STATUS status; + ACPI_OPCODE_INFO *parent_info; + + /* Must have both an Op and a Result Object */ if (!op) { - return; + return (TRUE); } - if (!result_obj) { - return; - } + /* + * If there is no parent, the result can't possibly be used! + * (An executing method typically has no parent, since each + * method is parsed separately) However, a method that is + * invoked from another method has a parent. + */ if (!op->parent) { - /* - * If there is no parent, the result can't possibly be used! - * (An executing method typically has no parent, since each - * method is parsed separately - */ - - /* - * Must pop the result stack (Obj_desc should be equal - * to Result_obj) - */ - - status = acpi_ds_result_stack_pop (&obj_desc, walk_state); - if (ACPI_FAILURE (status)) { - return; - } - - acpi_cm_remove_reference (result_obj); - - return; + return (FALSE); } @@ -100,15 +80,15 @@ */ parent_info = acpi_ps_get_opcode_info (op->parent->opcode); - if (!parent_info) { - return; + if (ACPI_GET_OP_TYPE (parent_info) != ACPI_OP_TYPE_OPCODE) { + return (FALSE); } /* Never delete the return value associated with a return opcode */ if (op->parent->opcode == AML_RETURN_OP) { - return; + return (TRUE); } @@ -119,26 +99,15 @@ * as an operand later. */ - switch (parent_info->flags & OP_INFO_TYPE) + switch (ACPI_GET_OP_CLASS (parent_info)) { /* - * In these cases, the parent will never use the return object, - * so delete it here and now. + * In these cases, the parent will never use the return object */ case OPTYPE_CONTROL: /* IF, ELSE, WHILE only */ case OPTYPE_NAMED_OBJECT: /* Scope, method, etc. */ - /* - * Must pop the result stack (Obj_desc should be equal - * to Result_obj) - */ - - status = acpi_ds_result_stack_pop (&obj_desc, walk_state); - if (ACPI_FAILURE (status)) { - return; - } - - acpi_cm_remove_reference (result_obj); + return (FALSE); break; /* @@ -149,11 +118,63 @@ break; } + return (TRUE); +} + + +/******************************************************************************* + * + * FUNCTION: Acpi_ds_delete_result_if_not_used + * + * PARAMETERS: Op + * Result_obj + * Walk_state + * + * RETURN: Status + * + * DESCRIPTION: Used after interpretation of an opcode. If there is an internal + * result descriptor, check if the parent opcode will actually use + * this result. If not, delete the result now so that it will + * not become orphaned. + * + ******************************************************************************/ + +void +acpi_ds_delete_result_if_not_used ( + ACPI_PARSE_OBJECT *op, + ACPI_OPERAND_OBJECT *result_obj, + ACPI_WALK_STATE *walk_state) +{ + ACPI_OPERAND_OBJECT *obj_desc; + ACPI_STATUS status; + + + if (!op) { + return; + } + + if (!result_obj) { + return; + } + + + if (!acpi_ds_is_result_used (op)) { + /* + * Must pop the result stack (Obj_desc should be equal + * to Result_obj) + */ + + status = acpi_ds_result_stack_pop (&obj_desc, walk_state); + if (ACPI_SUCCESS (status)) { + acpi_cm_remove_reference (result_obj); + } + } + return; } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_ds_create_operand * @@ -167,19 +188,19 @@ * looking up a name or entering a new name into the internal * namespace. * - ****************************************************************************/ + ******************************************************************************/ ACPI_STATUS acpi_ds_create_operand ( ACPI_WALK_STATE *walk_state, - ACPI_GENERIC_OP *arg) + ACPI_PARSE_OBJECT *arg) { ACPI_STATUS status = AE_OK; - char *name_string; + NATIVE_CHAR *name_string; u32 name_length; OBJECT_TYPE_INTERNAL data_type; - ACPI_OBJECT_INTERNAL *obj_desc; - ACPI_GENERIC_OP *parent_op; + ACPI_OPERAND_OBJECT *obj_desc; + ACPI_PARSE_OBJECT *parent_op; u16 opcode; u32 flags; OPERATING_MODE interpreter_mode; @@ -214,7 +235,7 @@ */ parent_op = arg->parent; - if ((acpi_ps_is_named_object_op (parent_op->opcode)) && + if ((acpi_ps_is_node_op (parent_op->opcode)) && (parent_op->opcode != AML_METHODCALL_OP) && (parent_op->opcode != AML_NAMEPATH_OP)) { @@ -233,7 +254,7 @@ ACPI_TYPE_ANY, interpreter_mode, NS_SEARCH_PARENT | NS_DONT_OPEN_SCOPE, walk_state, - (ACPI_NAMED_OBJECT**) &obj_desc); + (ACPI_NAMESPACE_NODE **) &obj_desc); /* Free the namestring created above */ @@ -252,7 +273,7 @@ * indicate this to the interpreter, set the * object to the root */ - obj_desc = (ACPI_OBJECT_INTERNAL *) acpi_gbl_root_object; + obj_desc = (ACPI_OPERAND_OBJECT *) acpi_gbl_root_node; status = AE_OK; } @@ -277,6 +298,7 @@ if (ACPI_FAILURE (status)) { return (status); } + DEBUGGER_EXEC (acpi_db_display_argument_object (obj_desc, walk_state)); } @@ -311,6 +333,8 @@ } if (flags & OP_HAS_RETURN_VALUE) { + DEBUGGER_EXEC (acpi_db_display_argument_object (walk_state->operands [walk_state->num_operands - 1], walk_state)); + /* * Use value that was already previously returned * by the evaluation of this argument @@ -338,9 +362,9 @@ /* Initialize the new object */ status = acpi_ds_init_object_from_op (walk_state, arg, - opcode, obj_desc); + opcode, &obj_desc); if (ACPI_FAILURE (status)) { - acpi_cm_free (obj_desc); + acpi_cm_delete_object_desc (obj_desc); return (status); } } @@ -352,13 +376,14 @@ return (status); } + DEBUGGER_EXEC (acpi_db_display_argument_object (obj_desc, walk_state)); } return (AE_OK); } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_ds_create_operands * @@ -370,15 +395,15 @@ * namespace objects and place those argument object on the object * stack in preparation for evaluation by the interpreter. * - ****************************************************************************/ + ******************************************************************************/ ACPI_STATUS acpi_ds_create_operands ( ACPI_WALK_STATE *walk_state, - ACPI_GENERIC_OP *first_arg) + ACPI_PARSE_OBJECT *first_arg) { ACPI_STATUS status = AE_OK; - ACPI_GENERIC_OP *arg; + ACPI_PARSE_OBJECT *arg; u32 args_pushed = 0; @@ -416,7 +441,7 @@ } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_ds_resolve_operands * @@ -428,7 +453,7 @@ * arguments to a control method invocation (a call from one * method to another.) * - ****************************************************************************/ + ******************************************************************************/ ACPI_STATUS acpi_ds_resolve_operands ( @@ -449,7 +474,7 @@ */ for (i = 0; i < walk_state->num_operands; i++) { - status = acpi_aml_resolve_to_value (&walk_state->operands[i]); + status = acpi_aml_resolve_to_value (&walk_state->operands[i], walk_state); if (ACPI_FAILURE (status)) { break; } @@ -459,7 +484,7 @@ } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_ds_map_opcode_to_data_type * @@ -472,7 +497,7 @@ * if any. If the opcode returns a value as part of the * intepreter execution, a flag is returned in Out_flags. * - ****************************************************************************/ + ******************************************************************************/ OBJECT_TYPE_INTERNAL acpi_ds_map_opcode_to_data_type ( @@ -480,18 +505,18 @@ u32 *out_flags) { OBJECT_TYPE_INTERNAL data_type = INTERNAL_TYPE_INVALID; - ACPI_OP_INFO *op_info; + ACPI_OPCODE_INFO *op_info; u32 flags = 0; op_info = acpi_ps_get_opcode_info (opcode); - if (!op_info) { + if (ACPI_GET_OP_TYPE (op_info) != ACPI_OP_TYPE_OPCODE) { /* Unknown opcode */ - return data_type; + return (data_type); } - switch (op_info->flags & OP_INFO_TYPE) + switch (ACPI_GET_OP_CLASS (op_info)) { case OPTYPE_LITERAL: @@ -552,6 +577,7 @@ case OPTYPE_DYADIC2_s: case OPTYPE_INDEX: case OPTYPE_MATCH: + case OPTYPE_RETURN: flags = OP_HAS_RETURN_VALUE; data_type = ACPI_TYPE_ANY; @@ -592,11 +618,11 @@ *out_flags = flags; } - return data_type; + return (data_type); } -/***************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_ds_map_named_opcode_to_data_type * @@ -607,7 +633,7 @@ * DESCRIPTION: Convert a raw Named AML opcode to the associated data type. * Named opcodes are a subsystem of the AML opcodes. * - ****************************************************************************/ + ******************************************************************************/ OBJECT_TYPE_INTERNAL acpi_ds_map_named_opcode_to_data_type ( @@ -688,7 +714,7 @@ } - return data_type; + return (data_type); } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/dispatcher/dswexec.c linux/drivers/acpi/dispatcher/dswexec.c --- v2.4.0-test8/linux/drivers/acpi/dispatcher/dswexec.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/dispatcher/dswexec.c Fri Sep 15 14:30:29 2000 @@ -1,7 +1,8 @@ /****************************************************************************** * * Module Name: dswexec - Dispatcher method execution callbacks; - * Dispatch to interpreter. + * dispatch to interpreter. + * $Revision: 42 $ * *****************************************************************************/ @@ -25,16 +26,16 @@ #include "acpi.h" -#include "parser.h" +#include "acparser.h" #include "amlcode.h" -#include "dispatch.h" -#include "interp.h" -#include "namesp.h" -#include "debugger.h" +#include "acdispat.h" +#include "acinterp.h" +#include "acnamesp.h" +#include "acdebug.h" #define _COMPONENT DISPATCHER - MODULE_NAME ("dswexec"); + MODULE_NAME ("dswexec") /***************************************************************************** @@ -55,14 +56,29 @@ ACPI_STATUS acpi_ds_exec_begin_op ( + u16 opcode, + ACPI_PARSE_OBJECT *op, ACPI_WALK_STATE *walk_state, - ACPI_GENERIC_OP *op) + ACPI_PARSE_OBJECT **out_op) { - ACPI_OP_INFO *op_info; + ACPI_OPCODE_INFO *op_info; ACPI_STATUS status = AE_OK; + if (!op) { + status = acpi_ds_load2_begin_op (opcode, NULL, walk_state, out_op); + if (ACPI_FAILURE (status)) { + return (status); + } + + op = *out_op; + } + if (op == walk_state->origin) { + if (out_op) { + *out_op = op; + } + return (AE_OK); } @@ -97,7 +113,7 @@ * Handle the opcode based upon the opcode type */ - switch (op_info->flags & OP_INFO_TYPE) + switch (ACPI_GET_OP_CLASS (op_info)) { case OPTYPE_CONTROL: @@ -107,7 +123,7 @@ case OPTYPE_NAMED_OBJECT: - if (walk_state->origin->opcode == AML_METHOD_OP) { + if (walk_state->walk_type == WALK_METHOD) { /* * Found a named object declaration during method * execution; we must enter this object into the @@ -116,7 +132,7 @@ * of this method. */ - status = acpi_ds_load2_begin_op (walk_state, op); + status = acpi_ds_load2_begin_op (op->opcode, op, walk_state, NULL); } break; @@ -150,17 +166,17 @@ ACPI_STATUS acpi_ds_exec_end_op ( ACPI_WALK_STATE *walk_state, - ACPI_GENERIC_OP *op) + ACPI_PARSE_OBJECT *op) { ACPI_STATUS status = AE_OK; u16 opcode; u8 optype; - ACPI_OBJECT_INTERNAL *obj_desc; - ACPI_GENERIC_OP *next_op; - ACPI_NAMED_OBJECT *entry; - ACPI_GENERIC_OP *first_arg; - ACPI_OBJECT_INTERNAL *result_obj = NULL; - ACPI_OP_INFO *op_info; + ACPI_OPERAND_OBJECT *obj_desc; + ACPI_PARSE_OBJECT *next_op; + ACPI_NAMESPACE_NODE *node; + ACPI_PARSE_OBJECT *first_arg; + ACPI_OPERAND_OBJECT *result_obj = NULL; + ACPI_OPCODE_INFO *op_info; u32 operand_index; @@ -168,11 +184,11 @@ op_info = acpi_ps_get_opcode_info (op->opcode); - if (!op_info) { + if (ACPI_GET_OP_TYPE (op_info) != ACPI_OP_TYPE_OPCODE) { return (AE_NOT_IMPLEMENTED); } - optype = (u8) (op_info->flags & OP_INFO_TYPE); + optype = (u8) ACPI_GET_OP_CLASS (op_info); first_arg = op->value.arg; /* Init the walk state */ @@ -183,6 +199,9 @@ /* Call debugger for single step support (DEBUG build only) */ + DEBUGGER_EXEC (status = acpi_db_single_step (walk_state, op, optype)); + DEBUGGER_EXEC (if (ACPI_FAILURE (status)) {return (status);}); + /* Decode the opcode */ @@ -220,6 +239,7 @@ case OPTYPE_CREATE_FIELD: case OPTYPE_FATAL: + status = acpi_ds_create_operands (walk_state, first_arg); if (ACPI_FAILURE (status)) { goto cleanup; @@ -376,12 +396,12 @@ case OPTYPE_METHOD_CALL: /* - * (AML_METHODCALL) Op->Value->Arg->Acpi_named_object contains - * the method NTE pointer + * (AML_METHODCALL) Op->Value->Arg->Node contains + * the method Node pointer */ /* Next_op points to the op that holds the method name */ next_op = first_arg; - entry = next_op->acpi_named_object; + node = next_op->node; /* Next_op points to first argument op */ next_op = next_op->next; @@ -410,7 +430,7 @@ /* Open new scope on the scope stack */ /* - Status = Acpi_ns_scope_stack_push_entry (Entry); + Status = Acpi_ns_scope_stack_push_entry (Node); if (ACPI_FAILURE (Status)) { break; } @@ -419,7 +439,7 @@ /* Tell the walk loop to preempt this running method and execute the new method */ - status = AE_CTRL_PENDING; + status = AE_CTRL_TRANSFER; /* Return now; we don't want to disturb anything, especially the operand count! */ @@ -431,14 +451,20 @@ case OPTYPE_NAMED_OBJECT: - if ((walk_state->origin->opcode == AML_METHOD_OP) && - (walk_state->origin != op)) + status = acpi_ds_load2_end_op (walk_state, op); + if (ACPI_FAILURE (status)) { + break; + } +/* + if ((Walk_state->Origin->Opcode == AML_METHOD_OP) && + (Walk_state->Origin != Op)) { - status = acpi_ds_load2_end_op (walk_state, op); - if (ACPI_FAILURE (status)) { + Status = Acpi_ds_load2_end_op (Walk_state, Op); + if (ACPI_FAILURE (Status)) { break; } } +*/ switch (op->opcode) { @@ -504,7 +530,7 @@ goto cleanup; } - status = acpi_aml_resolve_to_value (&walk_state->operands [0]); + status = acpi_aml_resolve_to_value (&walk_state->operands [0], walk_state); if (ACPI_FAILURE (status)) { goto cleanup; } @@ -537,6 +563,8 @@ /* Break to debugger to display result */ + DEBUGGER_EXEC (acpi_db_display_result_object (obj_desc, walk_state)); + /* Delete the predicate result object (we know that we don't need it anymore) and cleanup the stack */ @@ -551,6 +579,8 @@ if (result_obj) { /* Break to debugger to display result */ + + DEBUGGER_EXEC (acpi_db_display_result_object (result_obj, walk_state)); /* * Delete the result op if and only if: diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/dispatcher/dswload.c linux/drivers/acpi/dispatcher/dswload.c --- v2.4.0-test8/linux/drivers/acpi/dispatcher/dswload.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/dispatcher/dswload.c Fri Sep 15 14:30:29 2000 @@ -1,7 +1,7 @@ - /****************************************************************************** * * Module Name: dswload - Dispatcher namespace load callbacks + * $Revision: 19 $ * *****************************************************************************/ @@ -25,16 +25,16 @@ #include "acpi.h" -#include "parser.h" +#include "acparser.h" #include "amlcode.h" -#include "dispatch.h" -#include "interp.h" -#include "namesp.h" -#include "events.h" +#include "acdispat.h" +#include "acinterp.h" +#include "acnamesp.h" +#include "acevents.h" #define _COMPONENT DISPATCHER - MODULE_NAME ("dswload"); + MODULE_NAME ("dswload") /***************************************************************************** @@ -53,61 +53,75 @@ ACPI_STATUS acpi_ds_load1_begin_op ( + u16 opcode, + ACPI_PARSE_OBJECT *op, ACPI_WALK_STATE *walk_state, - ACPI_GENERIC_OP *op) + ACPI_PARSE_OBJECT **out_op) { - ACPI_NAMED_OBJECT *new_entry; + ACPI_NAMESPACE_NODE *node; ACPI_STATUS status; OBJECT_TYPE_INTERNAL data_type; + NATIVE_CHAR *path; /* We are only interested in opcodes that have an associated name */ - if (!acpi_ps_is_named_op (op->opcode)) { - return AE_OK; + if (!acpi_ps_is_named_op (opcode)) { + *out_op = op; + return (AE_OK); } /* Check if this object has already been installed in the namespace */ - if (op->acpi_named_object) { - return AE_OK; + if (op && op->node) { + *out_op = op; + return (AE_OK); } + path = acpi_ps_get_next_namestring (walk_state->parser_state); + /* Map the raw opcode into an internal object type */ - data_type = acpi_ds_map_named_opcode_to_data_type (op->opcode); + data_type = acpi_ds_map_named_opcode_to_data_type (opcode); - /* Attempt to type a NAME opcode by examining the argument */ - /* TBD: [Investigate] is this the right place to do this? */ + /* + * Enter the named type into the internal namespace. We enter the name + * as we go downward in the parse tree. Any necessary subobjects that involve + * arguments to the opcode must be created as we go back up the parse tree later. + */ + status = acpi_ns_lookup (walk_state->scope_info, path, + data_type, IMODE_LOAD_PASS1, + NS_NO_UPSEARCH, walk_state, &(node)); - if (op->opcode == AML_NAME_OP) { - if (op->value.arg) { + if (ACPI_FAILURE (status)) { + return (status); + } - data_type = acpi_ds_map_opcode_to_data_type ((op->value.arg)->opcode, - NULL); + if (!op) { + /* Create a new op */ + + op = acpi_ps_alloc_op (opcode); + if (!op) { + return (AE_NO_MEMORY); } } + /* Initialize */ + + ((ACPI_PARSE2_OBJECT *)op)->name = node->name; /* - * Enter the named type into the internal namespace. We enter the name - * as we go downward in the parse tree. Any necessary subobjects that involve - * arguments to the opcode must be created as we go back up the parse tree later. + * Put the Node in the "op" object that the parser uses, so we + * can get it again quickly when this scope is closed */ - status = acpi_ns_lookup (walk_state->scope_info, - (char *) &((ACPI_NAMED_OP *)op)->name, - data_type, IMODE_LOAD_PASS1, - NS_NO_UPSEARCH, walk_state, &(new_entry)); + op->node = node; - if (ACPI_SUCCESS (status)) { - /* - * Put the NTE in the "op" object that the parser uses, so we - * can get it again quickly when this scope is closed - */ - op->acpi_named_object = new_entry; - } + + acpi_ps_append_arg (acpi_ps_get_parent_scope (walk_state->parser_state), op); + + *out_op = op; return (status); } @@ -131,7 +145,7 @@ ACPI_STATUS acpi_ds_load1_end_op ( ACPI_WALK_STATE *walk_state, - ACPI_GENERIC_OP *op) + ACPI_PARSE_OBJECT *op) { OBJECT_TYPE_INTERNAL data_type; @@ -139,20 +153,26 @@ /* We are only interested in opcodes that have an associated name */ if (!acpi_ps_is_named_op (op->opcode)) { - return AE_OK; + return (AE_OK); } - /* TBD: [Investigate] can this be removed? */ - if (op->opcode == AML_SCOPE_OP) { - if (((ACPI_NAMED_OP *)op)->name == -1) { - return AE_OK; + /* Get the type to determine if we should pop the scope */ + + data_type = acpi_ds_map_named_opcode_to_data_type (op->opcode); + + if (op->opcode == AML_NAME_OP) { + /* For Name opcode, check the argument */ + + if (op->value.arg) { + data_type = acpi_ds_map_opcode_to_data_type ( + (op->value.arg)->opcode, NULL); + ((ACPI_NAMESPACE_NODE *)op->node)->type = + (u8) data_type; } } - data_type = acpi_ds_map_named_opcode_to_data_type (op->opcode); - /* Pop the scope stack */ if (acpi_ns_opens_scope (data_type)) { @@ -160,7 +180,7 @@ acpi_ds_scope_stack_pop (walk_state); } - return AE_OK; + return (AE_OK); } @@ -181,60 +201,74 @@ ACPI_STATUS acpi_ds_load2_begin_op ( + u16 opcode, + ACPI_PARSE_OBJECT *op, ACPI_WALK_STATE *walk_state, - ACPI_GENERIC_OP *op) + ACPI_PARSE_OBJECT **out_op) { - ACPI_NAMED_OBJECT *new_entry; + ACPI_NAMESPACE_NODE *node; ACPI_STATUS status; OBJECT_TYPE_INTERNAL data_type; - char *buffer_ptr; + NATIVE_CHAR *buffer_ptr; void *original = NULL; /* We only care about Namespace opcodes here */ - if (!acpi_ps_is_namespace_op (op->opcode) && - op->opcode != AML_NAMEPATH_OP) + if (!acpi_ps_is_namespace_op (opcode) && + opcode != AML_NAMEPATH_OP) { - return AE_OK; + return (AE_OK); } - /* - * Get the name we are going to enter or lookup in the namespace - */ - if (op->opcode == AML_NAMEPATH_OP) { - /* For Namepath op , get the path string */ + /* Temp! same code as in psparse */ + + if (!acpi_ps_is_named_op (opcode)) { + return (AE_OK); + } + + if (op) { + /* + * Get the name we are going to enter or lookup in the namespace + */ + if (opcode == AML_NAMEPATH_OP) { + /* For Namepath op, get the path string */ + + buffer_ptr = op->value.string; + if (!buffer_ptr) { + /* No name, just exit */ + + return (AE_OK); + } + } - buffer_ptr = op->value.string; - if (!buffer_ptr) { - /* No name, just exit */ + else { + /* Get name from the op */ - return AE_OK; + buffer_ptr = (NATIVE_CHAR *) &((ACPI_PARSE2_OBJECT *)op)->name; } } else { - /* Get name from the op */ - - buffer_ptr = (char *) &((ACPI_NAMED_OP *)op)->name; + buffer_ptr = acpi_ps_get_next_namestring (walk_state->parser_state); } /* Map the raw opcode into an internal object type */ - data_type = acpi_ds_map_named_opcode_to_data_type (op->opcode); + data_type = acpi_ds_map_named_opcode_to_data_type (opcode); - if (op->opcode == AML_DEF_FIELD_OP || - op->opcode == AML_BANK_FIELD_OP || - op->opcode == AML_INDEX_FIELD_OP) + if (opcode == AML_DEF_FIELD_OP || + opcode == AML_BANK_FIELD_OP || + opcode == AML_INDEX_FIELD_OP) { - new_entry = NULL; + node = NULL; status = AE_OK; } - else if (op->opcode == AML_NAMEPATH_OP) { + else if (opcode == AML_NAMEPATH_OP) { /* * The Name_path is an object reference to an existing object. Don't enter the * name into the namespace, but look it up for use later @@ -242,16 +276,16 @@ status = acpi_ns_lookup (walk_state->scope_info, buffer_ptr, data_type, IMODE_EXECUTE, NS_SEARCH_PARENT, walk_state, - &(new_entry)); + &(node)); } else { - if (op->acpi_named_object) { - original = op->acpi_named_object; - new_entry = op->acpi_named_object; + if (op && op->node) { + original = op->node; + node = op->node; if (acpi_ns_opens_scope (data_type)) { - status = acpi_ds_scope_stack_push (new_entry->child_table, + status = acpi_ds_scope_stack_push (node, data_type, walk_state); if (ACPI_FAILURE (status)) { @@ -259,7 +293,7 @@ } } - return AE_OK; + return (AE_OK); } /* @@ -270,15 +304,30 @@ status = acpi_ns_lookup (walk_state->scope_info, buffer_ptr, data_type, IMODE_EXECUTE, NS_NO_UPSEARCH, walk_state, - &(new_entry)); + &(node)); } if (ACPI_SUCCESS (status)) { + if (!op) { + /* Create a new op */ + + op = acpi_ps_alloc_op (opcode); + if (!op) { + return (AE_NO_MEMORY); + } + + /* Initialize */ + + ((ACPI_PARSE2_OBJECT *)op)->name = node->name; + *out_op = op; + } + + /* - * Put the NTE in the "op" object that the parser uses, so we + * Put the Node in the "op" object that the parser uses, so we * can get it again quickly when this scope is closed */ - op->acpi_named_object = new_entry; + op->node = node; } @@ -305,22 +354,22 @@ ACPI_STATUS acpi_ds_load2_end_op ( ACPI_WALK_STATE *walk_state, - ACPI_GENERIC_OP *op) + ACPI_PARSE_OBJECT *op) { ACPI_STATUS status = AE_OK; OBJECT_TYPE_INTERNAL data_type; - ACPI_NAMED_OBJECT *entry; - ACPI_GENERIC_OP *arg; - ACPI_NAMED_OBJECT *new_entry; + ACPI_NAMESPACE_NODE *node; + ACPI_PARSE_OBJECT *arg; + ACPI_NAMESPACE_NODE *new_node; if (!acpi_ps_is_namespace_object_op (op->opcode)) { - return AE_OK; + return (AE_OK); } if (op->opcode == AML_SCOPE_OP) { - if (((ACPI_NAMED_OP *)op)->name == -1) { - return AE_OK; + if (((ACPI_PARSE2_OBJECT *)op)->name == -1) { + return (AE_OK); } } @@ -328,17 +377,17 @@ data_type = acpi_ds_map_named_opcode_to_data_type (op->opcode); /* - * Get the NTE/name from the earlier lookup + * Get the Node/name from the earlier lookup * (It was saved in the *op structure) */ - entry = op->acpi_named_object; + node = op->node; /* - * Put the NTE on the object stack (Contains the ACPI Name of + * Put the Node on the object stack (Contains the ACPI Name of * this object) */ - walk_state->operands[0] = (void *) entry; + walk_state->operands[0] = (void *) node; walk_state->num_operands = 1; /* Pop the scope stack */ @@ -409,29 +458,38 @@ INTERNAL_TYPE_DEF_ANY, IMODE_LOAD_PASS1, NS_NO_UPSEARCH | NS_DONT_OPEN_SCOPE, - walk_state, &(new_entry)); + walk_state, &(new_node)); if (ACPI_SUCCESS (status)) { - /* We could put the returned object (NTE) on the object stack for later, but + /* We could put the returned object (Node) on the object stack for later, but * for now, we will put it in the "op" object that the parser uses, so we * can get it again at the end of this scope */ - op->acpi_named_object = new_entry; - } + op->node = new_node; + /* + * If this is NOT a control method, we need to evaluate this opcode now. + */ + + /* THIS WON"T WORK. Must execute all operands like Add(). => Must do an execute pass + if (!Walk_state->Method_desc) { + Status = Acpi_ds_exec_end_op (Walk_state, Op); + } + */ + } break; case AML_METHODCALL_OP: /* - * Lookup the method name and save the NTE + * Lookup the method name and save the Node */ status = acpi_ns_lookup (walk_state->scope_info, arg->value.string, ACPI_TYPE_ANY, IMODE_LOAD_PASS2, NS_SEARCH_PARENT | NS_DONT_OPEN_SCOPE, - walk_state, &(new_entry)); + walk_state, &(new_node)); if (ACPI_SUCCESS (status)) { @@ -440,11 +498,11 @@ /* TBD: [Restructure] Make sure that what we found is indeed a method! */ /* We didn't search for a method on purpose, to see if the name would resolve! */ - /* We could put the returned object (NTE) on the object stack for later, but + /* We could put the returned object (Node) on the object stack for later, but * for now, we will put it in the "op" object that the parser uses, so we * can get it again at the end of this scope */ - op->acpi_named_object = new_entry; + op->node = new_node; } @@ -455,7 +513,7 @@ /* Nothing to do other than enter object into namespace */ - status = acpi_aml_exec_create_processor (op, (ACPI_HANDLE) entry); + status = acpi_aml_exec_create_processor (op, (ACPI_HANDLE) node); if (ACPI_FAILURE (status)) { goto cleanup; } @@ -467,7 +525,7 @@ /* Nothing to do other than enter object into namespace */ - status = acpi_aml_exec_create_power_resource (op, (ACPI_HANDLE) entry); + status = acpi_aml_exec_create_power_resource (op, (ACPI_HANDLE) node); if (ACPI_FAILURE (status)) { goto cleanup; } @@ -487,7 +545,7 @@ arg = op->value.arg; status = acpi_ds_create_field (op, - (ACPI_HANDLE) arg->acpi_named_object, + arg->node, walk_state); break; @@ -497,7 +555,7 @@ arg = op->value.arg; status = acpi_ds_create_index_field (op, - (ACPI_HANDLE) arg->acpi_named_object, + (ACPI_HANDLE) arg->node, walk_state); break; @@ -506,7 +564,7 @@ arg = op->value.arg; status = acpi_ds_create_bank_field (op, - (ACPI_HANDLE) arg->acpi_named_object, + arg->node, walk_state); break; @@ -516,10 +574,10 @@ */ case AML_METHOD_OP: - if (!entry->object) { - status = acpi_aml_exec_create_method (((ACPI_DEFERRED_OP *) op)->body, - ((ACPI_DEFERRED_OP *) op)->body_length, - arg->value.integer, (ACPI_HANDLE) entry); + if (!node->object) { + status = acpi_aml_exec_create_method (((ACPI_PARSE2_OBJECT *) op)->data, + ((ACPI_PARSE2_OBJECT *) op)->length, + arg->value.integer, (ACPI_HANDLE) node); } break; @@ -549,14 +607,18 @@ case AML_REGION_OP: + if (node->object) { + break; + } + /* * The Op_region is not fully parsed at this time. Only valid argument is the Space_id. * (We must save the address of the AML of the address and length operands) */ - status = acpi_aml_exec_create_region (((ACPI_DEFERRED_OP *) op)->body, - ((ACPI_DEFERRED_OP *) op)->body_length, + status = acpi_aml_exec_create_region (((ACPI_PARSE2_OBJECT *) op)->data, + ((ACPI_PARSE2_OBJECT *) op)->length, arg->value.integer, walk_state); break; @@ -577,7 +639,7 @@ case AML_NAME_OP: - status = acpi_ds_create_named_object (walk_state, entry, op); + status = acpi_ds_create_node (walk_state, node, op); break; @@ -593,7 +655,9 @@ cleanup: - /* Remove the NTE pushed at the very beginning */ + + /* Remove the Node pushed at the very beginning */ + acpi_ds_obj_stack_pop (1, walk_state); return (status); } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/dispatcher/dswscope.c linux/drivers/acpi/dispatcher/dswscope.c --- v2.4.0-test8/linux/drivers/acpi/dispatcher/dswscope.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/dispatcher/dswscope.c Fri Sep 15 14:30:29 2000 @@ -1,7 +1,7 @@ - /****************************************************************************** * * Module Name: dswscope - Scope stack manipulation + * $Revision: 38 $ * *****************************************************************************/ @@ -25,12 +25,12 @@ #include "acpi.h" -#include "interp.h" -#include "dispatch.h" +#include "acinterp.h" +#include "acdispat.h" #define _COMPONENT NAMESPACE - MODULE_NAME ("dswscope"); + MODULE_NAME ("dswscope") #define STACK_POP(head) head @@ -69,24 +69,24 @@ * * FUNCTION: Acpi_ds_scope_stack_push * - * PARAMETERS: *New_scope, - Name to be made current - * Type, - Type of frame being pushed + * PARAMETERS: *Node, - Name to be made current + * Type, - Type of frame being pushed * * DESCRIPTION: Push the current scope on the scope stack, and make the - * passed nte current. + * passed Node current. * ***************************************************************************/ ACPI_STATUS acpi_ds_scope_stack_push ( - ACPI_NAME_TABLE *new_scope, + ACPI_NAMESPACE_NODE *node, OBJECT_TYPE_INTERNAL type, ACPI_WALK_STATE *walk_state) { ACPI_GENERIC_STATE *scope_info; - if (!new_scope) { + if (!node) { /* invalid scope */ REPORT_ERROR ("Ds_scope_stack_push: null scope passed"); @@ -109,7 +109,7 @@ /* Init new scope object */ - scope_info->scope.name_table = new_scope; + scope_info->scope.node = node; scope_info->common.value = (u16) type; /* Push new scope object onto stack */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/dispatcher/dswstate.c linux/drivers/acpi/dispatcher/dswstate.c --- v2.4.0-test8/linux/drivers/acpi/dispatcher/dswstate.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/dispatcher/dswstate.c Fri Sep 15 14:30:29 2000 @@ -1,6 +1,7 @@ /****************************************************************************** * * Module Name: dswstate - Dispatcher parse tree walk management routines + * $Revision: 31 $ * *****************************************************************************/ @@ -25,13 +26,13 @@ #include "acpi.h" #include "amlcode.h" -#include "parser.h" -#include "dispatch.h" -#include "namesp.h" -#include "interp.h" +#include "acparser.h" +#include "acdispat.h" +#include "acnamesp.h" +#include "acinterp.h" #define _COMPONENT DISPATCHER - MODULE_NAME ("dswstate"); + MODULE_NAME ("dswstate") /******************************************************************************* @@ -55,7 +56,7 @@ walk_state->num_results = 0; walk_state->current_result = 0; - return AE_OK; + return (AE_OK); } @@ -80,13 +81,13 @@ if (walk_state->num_results >= OBJ_NUM_OPERANDS) { - return AE_STACK_OVERFLOW; + return (AE_STACK_OVERFLOW); } walk_state->results [walk_state->num_results] = object; walk_state->num_results++; - return AE_OK; + return (AE_OK); } @@ -106,7 +107,7 @@ ACPI_STATUS acpi_ds_result_stack_pop ( - ACPI_OBJECT_INTERNAL **object, + ACPI_OPERAND_OBJECT **object, ACPI_WALK_STATE *walk_state) { @@ -114,7 +115,7 @@ /* Check for stack underflow */ if (walk_state->num_results == 0) { - return AE_AML_NO_OPERAND; + return (AE_AML_NO_OPERAND); } @@ -125,13 +126,13 @@ /* Check for a valid result object */ if (!walk_state->results [walk_state->num_results]) { - return AE_AML_NO_OPERAND; + return (AE_AML_NO_OPERAND); } *object = walk_state->results [walk_state->num_results]; walk_state->results [walk_state->num_results] = NULL; - return AE_OK; + return (AE_OK); } @@ -191,7 +192,7 @@ /* Check for stack overflow */ if (walk_state->num_operands >= OBJ_NUM_OPERANDS) { - return AE_STACK_OVERFLOW; + return (AE_STACK_OVERFLOW); } /* Put the object onto the stack */ @@ -199,7 +200,7 @@ walk_state->operands [walk_state->num_operands] = object; walk_state->num_operands++; - return AE_OK; + return (AE_OK); } @@ -219,7 +220,7 @@ ACPI_STATUS acpi_ds_obj_stack_pop_object ( - ACPI_OBJECT_INTERNAL **object, + ACPI_OPERAND_OBJECT **object, ACPI_WALK_STATE *walk_state) { @@ -227,7 +228,7 @@ /* Check for stack underflow */ if (walk_state->num_operands == 0) { - return AE_AML_NO_OPERAND; + return (AE_AML_NO_OPERAND); } @@ -238,7 +239,7 @@ /* Check for a valid operand */ if (!walk_state->operands [walk_state->num_operands]) { - return AE_AML_NO_OPERAND; + return (AE_AML_NO_OPERAND); } /* Get operand and set stack entry to null */ @@ -246,7 +247,7 @@ *object = walk_state->operands [walk_state->num_operands]; walk_state->operands [walk_state->num_operands] = NULL; - return AE_OK; + return (AE_OK); } @@ -276,7 +277,7 @@ /* Check for stack underflow */ if (walk_state->num_operands == 0) { - return AE_STACK_UNDERFLOW; + return (AE_STACK_UNDERFLOW); } /* Just set the stack entry to null */ @@ -285,7 +286,7 @@ walk_state->operands [walk_state->num_operands] = NULL; } - return AE_OK; + return (AE_OK); } @@ -309,14 +310,14 @@ ACPI_WALK_STATE *walk_state) { u32 i; - ACPI_OBJECT_INTERNAL *obj_desc; + ACPI_OPERAND_OBJECT *obj_desc; for (i = 0; i < pop_count; i++) { /* Check for stack underflow */ if (walk_state->num_operands == 0) { - return AE_STACK_UNDERFLOW; + return (AE_STACK_UNDERFLOW); } /* Pop the stack and delete an object if present in this stack entry */ @@ -329,7 +330,7 @@ } } - return AE_OK; + return (AE_OK); } @@ -393,10 +394,10 @@ { if (!walk_list) { - return NULL; + return (NULL); } - return walk_list->walk_state; + return (walk_list->walk_state); } @@ -483,8 +484,8 @@ ACPI_WALK_STATE * acpi_ds_create_walk_state ( ACPI_OWNER_ID owner_id, - ACPI_GENERIC_OP *origin, - ACPI_OBJECT_INTERNAL *mth_desc, + ACPI_PARSE_OBJECT *origin, + ACPI_OPERAND_OBJECT *mth_desc, ACPI_WALK_LIST *walk_list) { ACPI_WALK_STATE *walk_state; @@ -511,6 +512,7 @@ /* The cache is empty, create a new object */ /* Avoid deadlock with Acpi_cm_callocate */ + acpi_cm_release_mutex (ACPI_MTX_CACHES); walk_state = acpi_cm_callocate (sizeof (ACPI_WALK_STATE)); @@ -640,6 +642,7 @@ next = acpi_gbl_walk_state_cache->next; acpi_cm_free (acpi_gbl_walk_state_cache); acpi_gbl_walk_state_cache = next; + acpi_gbl_walk_state_cache_depth--; } return; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/driver.c linux/drivers/acpi/driver.c --- v2.4.0-test8/linux/drivers/acpi/driver.c Wed Jul 12 13:21:57 2000 +++ linux/drivers/acpi/driver.c Fri Sep 15 14:30:30 2000 @@ -32,6 +32,9 @@ #include "acpi.h" #include "driver.h" +#define _COMPONENT OS_DEPENDENT + MODULE_NAME ("driver") + struct acpi_run_entry { void (*callback)(void*); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/ec.c linux/drivers/acpi/ec.c --- v2.4.0-test8/linux/drivers/acpi/ec.c Thu Jul 13 09:39:49 2000 +++ linux/drivers/acpi/ec.c Fri Sep 15 14:30:30 2000 @@ -1,21 +1,21 @@ /* - * ec.c - Embedded controller support + * ec.c - Embedded controller support * - * Copyright (C) 2000 Andrew Henroid + * Copyright (C) 2000 Andrew Henroid * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include @@ -28,28 +28,28 @@ #include "acpi.h" #include "driver.h" -enum -{ - ACPI_EC_HID = 0x090cd041, -}; +#define _COMPONENT OS_DEPENDENT + MODULE_NAME ("ec") + +#define ACPI_EC_HID "PNP0A09" enum { - ACPI_EC_SMI = 0x40, - ACPI_EC_SCI = 0x20, - ACPI_EC_BURST = 0x10, - ACPI_EC_CMD = 0x08, - ACPI_EC_IBF = 0x02, - ACPI_EC_OBF = 0x01 + ACPI_EC_SMI = 0x40, + ACPI_EC_SCI = 0x20, + ACPI_EC_BURST = 0x10, + ACPI_EC_CMD = 0x08, + ACPI_EC_IBF = 0x02, + ACPI_EC_OBF = 0x01 }; enum { - ACPI_EC_READ = 0x80, - ACPI_EC_WRITE = 0x81, - ACPI_EC_BURST_ENABLE = 0x82, - ACPI_EC_BURST_DISABLE = 0x83, - ACPI_EC_QUERY = 0x84, + ACPI_EC_READ = 0x80, + ACPI_EC_WRITE = 0x81, + ACPI_EC_BURST_ENABLE = 0x82, + ACPI_EC_BURST_DISABLE = 0x83, + ACPI_EC_QUERY = 0x84, }; @@ -74,9 +74,9 @@ static void acpi_ec_wait_control(void) { - udelay(1); - while(inb(acpi_ec_status) & ACPI_EC_IBF) - udelay(10); + udelay(1); + while(inb(acpi_ec_status) & ACPI_EC_IBF) + udelay(10); } /* @@ -88,12 +88,12 @@ if (!acpi_ec_data || !acpi_ec_status) return -1; - outb(ACPI_EC_READ, acpi_ec_status); - acpi_ec_wait_control(); - outb(addr, acpi_ec_data); - acpi_ec_wait_control(); - interruptible_sleep_on(&acpi_ec_wait); - *value = inb(acpi_ec_data); + outb(ACPI_EC_READ, acpi_ec_status); + acpi_ec_wait_control(); + outb(addr, acpi_ec_data); + acpi_ec_wait_control(); + interruptible_sleep_on(&acpi_ec_wait); + *value = inb(acpi_ec_data); return 0; } @@ -107,33 +107,32 @@ if (!acpi_ec_data || !acpi_ec_status) return -1; - outb(ACPI_EC_WRITE, acpi_ec_status); - acpi_ec_wait_control(); - outb(addr, acpi_ec_data); - acpi_ec_wait_control(); - outb(value, acpi_ec_data); - acpi_ec_wait_control(); - interruptible_sleep_on(&acpi_ec_wait); + outb(ACPI_EC_WRITE, acpi_ec_status); + acpi_ec_wait_control(); + outb(addr, acpi_ec_data); + acpi_ec_wait_control(); + outb(value, acpi_ec_data); + acpi_ec_wait_control(); + interruptible_sleep_on(&acpi_ec_wait); return 0; } /* - * Get processor information + * Get Embedded Controller information */ static ACPI_STATUS acpi_find_ec(ACPI_HANDLE handle, u32 level, void *ctx, void **value) { - ACPI_BUFFER buf; + ACPI_DEVICE_INFO dev_info; ACPI_OBJECT obj; + ACPI_BUFFER buf; RESOURCE *res; int gpe; - buf.length = sizeof(obj); - buf.pointer = &obj; - if (!ACPI_SUCCESS(acpi_evaluate_object(handle, "_HID", NULL, &buf)) - || obj.type != ACPI_TYPE_NUMBER - || obj.number.value != ACPI_EC_HID) + if (!ACPI_SUCCESS(acpi_get_object_info(handle, &dev_info)) + || !(dev_info.valid & ACPI_VALID_HID) + || 0 != STRCMP(dev_info.hardware_id, ACPI_EC_HID)) return AE_OK; buf.length = 0; @@ -160,20 +159,23 @@ buf.length = sizeof(obj); buf.pointer = &obj; if (!ACPI_SUCCESS(acpi_evaluate_object(handle, "_GPE", NULL, &buf)) - || obj.type != ACPI_TYPE_NUMBER) + || obj.type != ACPI_TYPE_NUMBER) return AE_OK; gpe = (int) obj.number.value; printk(KERN_INFO "ACPI: found EC @ (0x%02x,0x%02x,%d)\n", - acpi_ec_data, acpi_ec_status, gpe); + acpi_ec_data, acpi_ec_status, gpe); if (!ACPI_SUCCESS(acpi_install_gpe_handler( gpe, (ACPI_EVENT_LEVEL_TRIGGERED | ACPI_EVENT_EDGE_TRIGGERED), acpi_ec_gpe, - NULL))) + NULL))) { + + DEBUG_PRINT(ACPI_ERROR, ("Could not install GPE handler for EC.\n")); return AE_OK; + } return AE_OK; } @@ -182,10 +184,10 @@ acpi_ec_init(void) { acpi_walk_namespace(ACPI_TYPE_DEVICE, - ACPI_ROOT_OBJECT, - ACPI_INT32_MAX, - acpi_find_ec, - NULL, - NULL); + ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, + acpi_find_ec, + NULL, + NULL); return 0; } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/events/Makefile linux/drivers/acpi/events/Makefile --- v2.4.0-test8/linux/drivers/acpi/events/Makefile Wed Dec 31 16:00:00 1969 +++ linux/drivers/acpi/events/Makefile Fri Sep 15 18:21:43 2000 @@ -0,0 +1,28 @@ +# +# Makefile for all Linux ACPI interpreter subdirectories +# + +SUB_DIRS := +MOD_SUB_DIRS := $(SUB_DIRS) +MOD_IN_SUB_DIRS := +ALL_SUB_DIRS := $(SUB_DIRS) + +O_TARGET := ../$(shell basename `pwd`).o +O_OBJS := +M_OBJS := + +ACPI_OBJS := $(patsubst %.c,%.o,$(wildcard *.c)) + +EXTRA_CFLAGS += -I../include + +EXTRA_CFLAGS += $(ACPI_CFLAGS) + +# if the interpreter is used, it overrides arch/i386/kernel/acpi.c +ifeq ($(CONFIG_ACPI_INTERPRETER),y) + O_OBJS := $(ACPI_OBJS) +endif + +include $(TOPDIR)/Rules.make + +clean: + $(RM) *.o diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/events/evevent.c linux/drivers/acpi/events/evevent.c --- v2.4.0-test8/linux/drivers/acpi/events/evevent.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/events/evevent.c Fri Sep 15 14:30:30 2000 @@ -2,6 +2,7 @@ * * Module Name: evevent - Fixed and General Purpose Acpi_event * handling and dispatch + * $Revision: 13 $ * *****************************************************************************/ @@ -24,13 +25,13 @@ */ #include "acpi.h" -#include "hardware.h" -#include "events.h" -#include "namesp.h" -#include "common.h" +#include "achware.h" +#include "acevents.h" +#include "acnamesp.h" +#include "accommon.h" #define _COMPONENT EVENT_HANDLING - MODULE_NAME ("evevent"); + MODULE_NAME ("evevent") /****************************************************************************** @@ -68,7 +69,7 @@ acpi_hw_register_access (ACPI_WRITE, ACPI_MTX_LOCK, ACPI_EVENT_RTC + TMR_EN, 0); - return AE_OK; + return (AE_OK); } @@ -140,7 +141,7 @@ int_status |= acpi_ev_fixed_event_dispatch (ACPI_EVENT_SLEEP_BUTTON); } - return int_status; + return (int_status); } @@ -163,7 +164,7 @@ { /* Clear the status bit */ - acpi_hw_register_access (ACPI_WRITE, ACPI_MTX_DO_NOT_LOCK, (s32)TMR_STS + + acpi_hw_register_access (ACPI_WRITE, ACPI_MTX_DO_NOT_LOCK, TMR_STS + event, 1); /* @@ -175,13 +176,13 @@ TMR_EN + event, 0); REPORT_ERROR("No installed handler for fixed event."); - return INTERRUPT_NOT_HANDLED; + return (INTERRUPT_NOT_HANDLED); } /* Invoke the handler */ - return (acpi_gbl_fixed_event_handlers[event].handler)( - acpi_gbl_fixed_event_handlers[event].context); + return ((acpi_gbl_fixed_event_handlers[event].handler)( + acpi_gbl_fixed_event_handlers[event].context)); } @@ -216,6 +217,11 @@ gpe1_register_count = (u16) DIV_2 (acpi_gbl_FACP->gpe1_blk_len); acpi_gbl_gpe_register_count = gpe0register_count + gpe1_register_count; + if (!acpi_gbl_gpe_register_count) { + REPORT_WARNING ("No GPEs defined in the FACP"); + return (AE_OK); + } + /* * Allocate the Gpe information block */ @@ -341,17 +347,17 @@ void **return_value) { u32 gpe_number; - char name[ACPI_NAME_SIZE + 1]; + NATIVE_CHAR name[ACPI_NAME_SIZE + 1]; u8 type; /* Extract the name from the object and convert to a string */ - MOVE_UNALIGNED32_TO_32 (name, &((ACPI_NAMED_OBJECT*) obj_handle)->name); + MOVE_UNALIGNED32_TO_32 (name, &((ACPI_NAMESPACE_NODE *) obj_handle)->name); name[ACPI_NAME_SIZE] = 0; /* - * Edge/Level determination is based on the 2nd char of the method name + * Edge/Level determination is based on the 2nd s8 of the method name */ if (name[1] == 'L') { type = ACPI_EVENT_LEVEL_TRIGGERED; @@ -362,7 +368,7 @@ else { /* Unknown method type, just ignore it! */ - return AE_OK; + return (AE_OK); } /* Convert the last two characters of the name to the Gpe Number */ @@ -371,7 +377,7 @@ if (gpe_number == ACPI_UINT32_MAX) { /* Conversion failed; invalid method, just ignore it */ - return AE_OK; + return (AE_OK); } /* Ensure that we have a valid GPE number */ @@ -379,7 +385,7 @@ if (acpi_gbl_gpe_valid[gpe_number] == ACPI_GPE_INVALID) { /* Not valid, all we can do here is ignore it */ - return AE_OK; + return (AE_OK); } /* @@ -397,7 +403,7 @@ acpi_hw_enable_gpe (gpe_number); - return AE_OK; + return (AE_OK); } @@ -431,7 +437,7 @@ /* Traverse the namespace under \_GPE to find all methods there */ status = acpi_walk_namespace (ACPI_TYPE_METHOD, acpi_gbl_gpe_obj_handle, - ACPI_INT32_MAX, acpi_ev_save_method_info, + ACPI_UINT32_MAX, acpi_ev_save_method_info, NULL, NULL); return (status); @@ -523,7 +529,7 @@ } } - return int_status; + return (int_status); } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/events/evmisc.c linux/drivers/acpi/events/evmisc.c --- v2.4.0-test8/linux/drivers/acpi/events/evmisc.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/events/evmisc.c Fri Sep 15 14:30:30 2000 @@ -2,6 +2,7 @@ * * Module Name: evmisc - ACPI device notification handler dispatch * and ACPI Global Lock support + * $Revision: 13 $ * *****************************************************************************/ @@ -24,13 +25,13 @@ */ #include "acpi.h" -#include "events.h" -#include "namesp.h" -#include "interp.h" -#include "hardware.h" +#include "acevents.h" +#include "acnamesp.h" +#include "acinterp.h" +#include "achware.h" #define _COMPONENT EVENT_HANDLING - MODULE_NAME ("evmisc"); + MODULE_NAME ("evmisc") /************************************************************************** @@ -51,8 +52,8 @@ ACPI_HANDLE device, u32 notify_value) { - ACPI_OBJECT_INTERNAL *obj_desc; - ACPI_OBJECT_INTERNAL *handler_obj; + ACPI_OPERAND_OBJECT *obj_desc; + ACPI_OPERAND_OBJECT *handler_obj; NOTIFY_HANDLER handler; @@ -108,7 +109,7 @@ /* - * Get the notify object which must be attached to the device NTE + * Get the notify object which must be attached to the device Node */ obj_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) device); @@ -211,7 +212,7 @@ context); } - return INTERRUPT_HANDLED; + return (INTERRUPT_HANDLED); } @@ -349,7 +350,7 @@ */ if (pending) { acpi_hw_register_access (ACPI_WRITE, ACPI_MTX_LOCK, - (s32)PM1_CONTROL | GBL_RLS, 1); + PM1_CONTROL | GBL_RLS, 1); } } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/events/evregion.c linux/drivers/acpi/events/evregion.c --- v2.4.0-test8/linux/drivers/acpi/events/evregion.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/events/evregion.c Fri Sep 15 14:30:30 2000 @@ -1,6 +1,7 @@ /****************************************************************************** * * Module Name: evregion - ACPI Address_space / Op_region handler dispatch + * $Revision: 76 $ * *****************************************************************************/ @@ -24,13 +25,13 @@ #include "acpi.h" -#include "events.h" -#include "namesp.h" -#include "interp.h" +#include "acevents.h" +#include "acnamesp.h" +#include "acinterp.h" #include "amlcode.h" #define _COMPONENT EVENT_HANDLING - MODULE_NAME ("evregion"); + MODULE_NAME ("evregion") #define PCI_ROOT_HID_STRING "PNP0A03" @@ -56,23 +57,23 @@ void *context, void **return_value) { - ACPI_NAMED_OBJECT *entry; - ACPI_OBJECT_INTERNAL *obj_desc; + ACPI_NAMESPACE_NODE *node; + ACPI_OPERAND_OBJECT *obj_desc; ACPI_STATUS status; - entry = (ACPI_NAMED_OBJECT*) obj_handle; - obj_desc = ((ACPI_NAMED_OBJECT*)obj_handle)->object; + node = (ACPI_NAMESPACE_NODE *) obj_handle; + obj_desc = ((ACPI_NAMESPACE_NODE *) obj_handle)->object; /* * We are looking for all valid _HID objects. */ - if (STRNCMP ((char *)&entry->name, METHOD_NAME__HID, ACPI_NAME_SIZE) || + if (STRNCMP ((NATIVE_CHAR *) &node->name, METHOD_NAME__HID, ACPI_NAME_SIZE) || (!obj_desc)) { - return AE_OK; + return (AE_OK); } @@ -87,7 +88,7 @@ case ACPI_TYPE_NUMBER: if (obj_desc->number.value != PCI_ROOT_HID_VALUE) { - return AE_OK; + return (AE_OK); } break; @@ -97,14 +98,14 @@ if (STRNCMP (obj_desc->string.pointer, PCI_ROOT_HID_STRING, sizeof (PCI_ROOT_HID_STRING))) { - return AE_OK; + return (AE_OK); } break; default: - return AE_OK; + return (AE_OK); } @@ -114,11 +115,11 @@ * handler for this PCI device. */ - status = acpi_install_address_space_handler (acpi_ns_get_parent_entry (entry), + status = acpi_install_address_space_handler (acpi_ns_get_parent_object (node), ADDRESS_SPACE_PCI_CONFIG, ACPI_DEFAULT_HANDLER, NULL, NULL); - return AE_OK; + return (AE_OK); } @@ -142,7 +143,90 @@ acpi_ns_walk_namespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, FALSE, acpi_ev_find_one_pci_root_bus, NULL, NULL); - return AE_OK; + return (AE_OK); +} + +/****************************************************************************** + * + * FUNCTION: Acpi_ev_init_one_device + * + * PARAMETERS: The usual "I'm a namespace callback" stuff + * + * RETURN: ACPI_STATUS + * + * DESCRIPTION: This is called once per device soon after ACPI is enabled + * to initialize each device. It determines if the device is + * present, and if so, calls _INI. + * + *****************************************************************************/ + +ACPI_STATUS +acpi_ev_init_one_device ( + ACPI_HANDLE obj_handle, + u32 nesting_level, + void *context, + void **return_value) +{ + ACPI_STATUS status; + ACPI_OPERAND_OBJECT *ret_obj; + + + /* + * Run _STA to determine if we can run _INI on the device. + */ + status = acpi_ns_evaluate_relative(obj_handle, "_STA", NULL, &ret_obj); + if (AE_NOT_FOUND == status) { + /* No _STA means device is present */ + } + else if (ACPI_FAILURE (status)) { + return (status); + } + else if (ret_obj) { + if (ACPI_TYPE_NUMBER != ret_obj->common.type) { + status = AE_AML_OPERAND_TYPE; + goto cleanup; + } + + /* + * if _STA "present" bit not set, we're done. + */ + if (!(ret_obj->number.value & 1)) { + goto cleanup; + } + } + + /* + * The device is present. Run _INI. + */ + + status = acpi_ns_evaluate_relative(obj_handle, "_INI", NULL, NULL); + +cleanup: + + acpi_cm_remove_reference (ret_obj); + return (status); +} + +/****************************************************************************** + * + * FUNCTION: Acpi_ev_init_devices + * + * PARAMETERS: None + * + * RETURN: ACPI_STATUS + * + * DESCRIPTION: This initializes all ACPI devices. + * + *****************************************************************************/ + +ACPI_STATUS +acpi_ev_init_devices ( + void) +{ + acpi_ns_walk_namespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, + FALSE, acpi_ev_init_one_device, NULL, NULL); + + return (AE_OK); } @@ -172,28 +256,20 @@ * associated with the address space. For these we use the root. */ - status = acpi_install_address_space_handler (acpi_gbl_root_object, + status = acpi_install_address_space_handler (acpi_gbl_root_node, ADDRESS_SPACE_SYSTEM_MEMORY, ACPI_DEFAULT_HANDLER, NULL, NULL); if (ACPI_FAILURE (status)) { return (status); } - status = acpi_install_address_space_handler (acpi_gbl_root_object, + status = acpi_install_address_space_handler (acpi_gbl_root_node, ADDRESS_SPACE_SYSTEM_IO, ACPI_DEFAULT_HANDLER, NULL, NULL); if (ACPI_FAILURE (status)) { return (status); } - /* - * Install PCI config space handler for all PCI root bridges. A PCI root - * bridge is found by searching for devices containing a HID with the value - * EISAID("PNP0A03") - */ - - acpi_ev_find_pci_root_buses (); - return (AE_OK); } @@ -216,12 +292,12 @@ ACPI_STATUS acpi_ev_execute_reg_method ( - ACPI_OBJECT_INTERNAL *region_obj, + ACPI_OPERAND_OBJECT *region_obj, u32 function) { - ACPI_OBJECT_INTERNAL *params[3]; - ACPI_OBJECT_INTERNAL space_iD_obj; - ACPI_OBJECT_INTERNAL function_obj; + ACPI_OPERAND_OBJECT *params[3]; + ACPI_OPERAND_OBJECT space_iD_obj; + ACPI_OPERAND_OBJECT function_obj; ACPI_STATUS status; @@ -286,7 +362,7 @@ ACPI_STATUS acpi_ev_address_space_dispatch ( - ACPI_OBJECT_INTERNAL *region_obj, + ACPI_OPERAND_OBJECT *region_obj, u32 function, u32 address, u32 bit_width, @@ -295,8 +371,8 @@ ACPI_STATUS status; ADDRESS_SPACE_HANDLER handler; ADDRESS_SPACE_SETUP region_setup; - ACPI_OBJECT_INTERNAL *handler_desc; - void *region_context; + ACPI_OPERAND_OBJECT *handler_desc; + void *region_context = NULL; /* @@ -312,7 +388,7 @@ * It may be the case that the region has never been initialized * Some types of regions require special init code */ - if (!(region_obj->region.region_flags & REGION_INITIALIZED)) { + if (!(region_obj->region.flags & AOPOBJ_INITIALIZED)) { /* * This region has not been initialized yet, do it */ @@ -346,9 +422,10 @@ } /* - * Save the returned context for use in all accesses to the region + * Save the returned context for use in all accesses to + * this particular region. */ - handler_desc->addr_handler.context = region_context; + region_obj->region.region_context = region_context; } /* @@ -369,7 +446,8 @@ * Invoke the handler. */ status = handler (function, address, bit_width, value, - handler_desc->addr_handler.context); + handler_desc->addr_handler.context, + region_obj->region.region_context); if (!(handler_desc->addr_handler.flags & ADDR_HANDLER_DEFAULT_INSTALLED)) { @@ -398,13 +476,13 @@ void acpi_ev_disassociate_region_from_handler( - ACPI_OBJECT_INTERNAL *region_obj) + ACPI_OPERAND_OBJECT *region_obj) { - ACPI_OBJECT_INTERNAL *handler_obj; - ACPI_OBJECT_INTERNAL *obj_desc; - ACPI_OBJECT_INTERNAL **last_obj_ptr; + ACPI_OPERAND_OBJECT *handler_obj; + ACPI_OPERAND_OBJECT *obj_desc; + ACPI_OPERAND_OBJECT **last_obj_ptr; ADDRESS_SPACE_SETUP region_setup; - void *region_context; + void *region_context = region_obj->region.region_context; ACPI_STATUS status; @@ -436,7 +514,8 @@ /* * This is it, remove it from the handler's list */ - *last_obj_ptr = obj_desc->region.link; + *last_obj_ptr = obj_desc->region.next; + obj_desc->region.next = NULL; /* Must clear field */ /* * Now stop region accesses by executing the _REG method @@ -452,12 +531,6 @@ ®ion_context); /* - * Save the returned context (It is the original context - * passed into Install) - */ - handler_obj->addr_handler.context = region_context; - - /* * Init routine may fail, Just ignore errors */ @@ -482,8 +555,8 @@ /* * Move through the linked list of handlers */ - last_obj_ptr = &obj_desc->region.link; - obj_desc = obj_desc->region.link; + last_obj_ptr = &obj_desc->region.next; + obj_desc = obj_desc->region.next; } /* @@ -508,9 +581,10 @@ ******************************************************************************/ ACPI_STATUS -acpi_ev_associate_region_and_handler( - ACPI_OBJECT_INTERNAL *handler_obj, - ACPI_OBJECT_INTERNAL *region_obj) +acpi_ev_associate_region_and_handler ( + ACPI_OPERAND_OBJECT *handler_obj, + ACPI_OPERAND_OBJECT *region_obj, + u8 acpi_ns_is_locked) { ACPI_STATUS status; @@ -522,7 +596,7 @@ * Link this region to the front of the handler's list */ - region_obj->region.link = handler_obj->addr_handler.region_list; + region_obj->region.next = handler_obj->addr_handler.region_list; handler_obj->addr_handler.region_list = region_obj; /* @@ -539,9 +613,15 @@ /* * Last thing, tell all users that this region is usable */ - acpi_cm_release_mutex (ACPI_MTX_NAMESPACE); + if (acpi_ns_is_locked) { + acpi_cm_release_mutex (ACPI_MTX_NAMESPACE); + } + status = acpi_ev_execute_reg_method (region_obj, 1); - acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE); + + if (acpi_ns_is_locked) { + acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE); + } return (status); } @@ -551,7 +631,7 @@ * * FUNCTION: Acpi_ev_addr_handler_helper * - * PARAMETERS: Handle - Entry to be dumped + * PARAMETERS: Handle - Node to be dumped * Level - Nesting level of the handle * Context - Passed into Acpi_ns_walk_namespace * @@ -573,14 +653,14 @@ void *context, void **return_value) { - ACPI_OBJECT_INTERNAL *handler_obj; - ACPI_OBJECT_INTERNAL *tmp_obj; - ACPI_OBJECT_INTERNAL *obj_desc; - ACPI_NAMED_OBJECT *obj_entry; + ACPI_OPERAND_OBJECT *handler_obj; + ACPI_OPERAND_OBJECT *tmp_obj; + ACPI_OPERAND_OBJECT *obj_desc; + ACPI_NAMESPACE_NODE *node; ACPI_STATUS status; - handler_obj = (ACPI_OBJECT_INTERNAL *) context; + handler_obj = (ACPI_OPERAND_OBJECT *) context; /* Parameter validation */ @@ -590,8 +670,8 @@ /* Convert and validate the device handle */ - obj_entry = acpi_ns_convert_handle_to_entry (obj_handle); - if (!obj_entry) { + node = acpi_ns_convert_handle_to_entry (obj_handle); + if (!node) { return (AE_BAD_PARAMETER); } @@ -600,16 +680,16 @@ * that can have address handlers */ - if ((obj_entry->type != ACPI_TYPE_DEVICE) && - (obj_entry->type != ACPI_TYPE_REGION) && - (obj_entry != acpi_gbl_root_object)) + if ((node->type != ACPI_TYPE_DEVICE) && + (node->type != ACPI_TYPE_REGION) && + (node != acpi_gbl_root_node)) { return (AE_OK); } /* Check for an existing internal object */ - obj_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) obj_entry); + obj_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) node); if (!obj_desc) { /* * The object DNE, we don't care about it @@ -647,7 +727,7 @@ /* * Move through the linked list of handlers */ - tmp_obj = tmp_obj->addr_handler.link; + tmp_obj = tmp_obj->addr_handler.next; } /* @@ -682,7 +762,7 @@ /* * Then connect the region to the new handler */ - status = acpi_ev_associate_region_and_handler (handler_obj, obj_desc); + status = acpi_ev_associate_region_and_handler (handler_obj, obj_desc, FALSE); return (status); } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/events/evrgnini.c linux/drivers/acpi/events/evrgnini.c --- v2.4.0-test8/linux/drivers/acpi/events/evrgnini.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/events/evrgnini.c Fri Sep 15 14:30:30 2000 @@ -1,6 +1,7 @@ /****************************************************************************** * * Module Name: evrgnini- ACPI Address_space / Op_region init + * $Revision: 22 $ * *****************************************************************************/ @@ -24,13 +25,13 @@ #include "acpi.h" -#include "events.h" -#include "namesp.h" -#include "interp.h" +#include "acevents.h" +#include "acnamesp.h" +#include "acinterp.h" #include "amlcode.h" #define _COMPONENT EVENT_HANDLING - MODULE_NAME ("evrgnini"); + MODULE_NAME ("evrgnini") /***************************************************************************** @@ -40,8 +41,8 @@ * PARAMETERS: Region_obj - region we are interested in * Function - start or stop * Handler_context - Address space handler context - * Returned context - context to be used with each call to the - * handler for this region + * Region_context - Region specific context + * * RETURN: Status * * DESCRIPTION: Do any prep work for region handling, a nop for now @@ -53,21 +54,17 @@ ACPI_HANDLE handle, u32 function, void *handler_context, - void **return_context) + void **region_context) { - MEM_HANDLER_CONTEXT *mem_context; - ACPI_OBJECT_INTERNAL *region_obj = (ACPI_OBJECT_INTERNAL *) handle; + ACPI_OPERAND_OBJECT *region_obj = (ACPI_OPERAND_OBJECT *) handle; if (function == ACPI_REGION_DEACTIVATE) { - region_obj->region.region_flags &= ~(REGION_INITIALIZED); - - *return_context = NULL; - if (handler_context) { - mem_context = handler_context; - *return_context = mem_context->handler_context; + region_obj->region.flags &= ~(AOPOBJ_INITIALIZED); - acpi_cm_free (mem_context); + if (*region_context) { + acpi_cm_free (*region_context); + *region_context = NULL; } return (AE_OK); } @@ -75,17 +72,15 @@ /* Activate. Create a new context */ - mem_context = acpi_cm_callocate (sizeof (MEM_HANDLER_CONTEXT)); - if (!mem_context) { + *region_context = acpi_cm_callocate (sizeof (MEM_HANDLER_CONTEXT)); + if (!(*region_context)) { return (AE_NO_MEMORY); } /* Init. (Mapping fields are all set to zeros above) */ - mem_context->handler_context = handler_context; - region_obj->region.region_flags |= REGION_INITIALIZED; + region_obj->region.flags |= AOPOBJ_INITIALIZED; - *return_context = mem_context; return (AE_OK); } @@ -97,8 +92,8 @@ * PARAMETERS: Region_obj - region we are interested in * Function - start or stop * Handler_context - Address space handler context - * Returned context - context to be used with each call to the - * handler for this region + * Region_context - Region specific context + * * RETURN: Status * * DESCRIPTION: Do any prep work for region handling @@ -110,21 +105,18 @@ ACPI_HANDLE handle, u32 function, void *handler_context, - void **return_context) + void **region_context) { - ACPI_OBJECT_INTERNAL *region_obj = (ACPI_OBJECT_INTERNAL *) handle; - + ACPI_OPERAND_OBJECT *region_obj = (ACPI_OPERAND_OBJECT *) handle; if (function == ACPI_REGION_DEACTIVATE) { - region_obj->region.region_flags &= ~(REGION_INITIALIZED); - *return_context = handler_context; - return (AE_OK); + *region_context = NULL; + region_obj->region.flags &= ~(AOPOBJ_INITIALIZED); + } + else { + *region_context = handler_context; + region_obj->region.flags |= AOPOBJ_INITIALIZED; } - - /* Activate the region */ - - region_obj->region.region_flags |= REGION_INITIALIZED; - *return_context = handler_context; return (AE_OK); } @@ -137,8 +129,8 @@ * PARAMETERS: Region_obj - region we are interested in * Function - start or stop * Handler_context - Address space handler context - * Returned context - context to be used with each call to the - * handler for this region + * Region_context - Region specific context + * * RETURN: Status * * DESCRIPTION: Do any prep work for region handling @@ -152,14 +144,14 @@ ACPI_HANDLE handle, u32 function, void *handler_context, - void **return_context) + void **region_context) { ACPI_STATUS status = AE_OK; u32 temp; - PCI_HANDLER_CONTEXT *pci_context; - ACPI_OBJECT_INTERNAL *handler_obj; - ACPI_NAMED_OBJECT *search_scope; - ACPI_OBJECT_INTERNAL *region_obj = (ACPI_OBJECT_INTERNAL *) handle; + PCI_HANDLER_CONTEXT *pci_context = *region_context; + ACPI_OPERAND_OBJECT *handler_obj; + ACPI_NAMESPACE_NODE *node; + ACPI_OPERAND_OBJECT *region_obj = (ACPI_OPERAND_OBJECT *) handle; handler_obj = region_obj->region.addr_handler; @@ -173,14 +165,11 @@ } if (function == ACPI_REGION_DEACTIVATE) { - region_obj->region.region_flags &= ~(REGION_INITIALIZED); - - *return_context = NULL; - if (handler_context) { - pci_context = handler_context; - *return_context = pci_context->handler_context; + region_obj->region.flags &= ~(AOPOBJ_INITIALIZED); + if (pci_context) { acpi_cm_free (pci_context); + *region_context = NULL; } return (status); @@ -189,7 +178,7 @@ /* Create a new context */ - pci_context = acpi_cm_allocate (sizeof(PCI_HANDLER_CONTEXT)); + pci_context = acpi_cm_callocate (sizeof(PCI_HANDLER_CONTEXT)); if (!pci_context) { return (AE_NO_MEMORY); } @@ -203,16 +192,16 @@ * First get device and function numbers from the _ADR object * in the parent's scope. */ - ACPI_ASSERT(region_obj->region.nte); + ACPI_ASSERT(region_obj->region.node); - search_scope = acpi_ns_get_parent_entry (region_obj->region.nte); + node = acpi_ns_get_parent_object (region_obj->region.node); acpi_cm_release_mutex (ACPI_MTX_NAMESPACE); /* Acpi_evaluate the _ADR object */ - status = acpi_cm_evaluate_numeric_object (METHOD_NAME__ADR, search_scope, &temp); + status = acpi_cm_evaluate_numeric_object (METHOD_NAME__ADR, node, &temp); /* * The default is zero, since the allocation above zeroed the data, just * do nothing on failures. @@ -232,9 +221,9 @@ * This is the device the handler has been registered to handle. */ - search_scope = handler_obj->addr_handler.nte; + node = handler_obj->addr_handler.node; - status = acpi_cm_evaluate_numeric_object (METHOD_NAME__SEG, search_scope, &temp); + status = acpi_cm_evaluate_numeric_object (METHOD_NAME__SEG, node, &temp); if (ACPI_SUCCESS (status)) { /* * Got it.. @@ -242,7 +231,7 @@ pci_context->seg = temp; } - status = acpi_cm_evaluate_numeric_object (METHOD_NAME__BBN, search_scope, &temp); + status = acpi_cm_evaluate_numeric_object (METHOD_NAME__BBN, node, &temp); if (ACPI_SUCCESS (status)) { /* * Got it.. @@ -250,11 +239,12 @@ pci_context->bus = temp; } + *region_context = pci_context; + acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE); - *return_context = pci_context; + region_obj->region.flags |= AOPOBJ_INITIALIZED; - region_obj->region.region_flags |= REGION_INITIALIZED; return (AE_OK); } @@ -266,8 +256,8 @@ * PARAMETERS: Region_obj - region we are interested in * Function - start or stop * Handler_context - Address space handler context - * Returned context - context to be used with each call to the - * handler for this region + * Region_context - Region specific context + * * RETURN: Status * * DESCRIPTION: Do any prep work for region handling @@ -279,18 +269,18 @@ ACPI_HANDLE handle, u32 function, void *handler_context, - void **return_context) + void **region_context) { - ACPI_OBJECT_INTERNAL *region_obj = (ACPI_OBJECT_INTERNAL *) handle; + ACPI_OPERAND_OBJECT *region_obj = (ACPI_OPERAND_OBJECT *) handle; if (function == ACPI_REGION_DEACTIVATE) { - region_obj->region.region_flags &= ~(REGION_INITIALIZED); - *return_context = NULL; + *region_context = NULL; + region_obj->region.flags &= ~(AOPOBJ_INITIALIZED); } else { - region_obj->region.region_flags |= REGION_INITIALIZED; - *return_context = handler_context; + *region_context = handler_context; + region_obj->region.flags |= AOPOBJ_INITIALIZED; } return (AE_OK); @@ -320,15 +310,15 @@ ACPI_STATUS acpi_ev_initialize_region ( - ACPI_OBJECT_INTERNAL *region_obj, + ACPI_OPERAND_OBJECT *region_obj, u8 acpi_ns_locked) { - ACPI_OBJECT_INTERNAL *handler_obj; - ACPI_OBJECT_INTERNAL *obj_desc; + ACPI_OPERAND_OBJECT *handler_obj; + ACPI_OPERAND_OBJECT *obj_desc; u32 space_id; - ACPI_NAMED_OBJECT *entry; /* Namespace Object */ + ACPI_NAMESPACE_NODE *node; ACPI_STATUS status; - ACPI_NAMED_OBJECT *reg_entry; + ACPI_NAMESPACE_NODE *method_node; ACPI_NAME *reg_name_ptr = (ACPI_NAME *) METHOD_NAME__REG; @@ -336,44 +326,44 @@ return (AE_BAD_PARAMETER); } - ACPI_ASSERT(region_obj->region.nte); + ACPI_ASSERT(region_obj->region.node); - entry = acpi_ns_get_parent_entry (region_obj->region.nte); + node = acpi_ns_get_parent_object (region_obj->region.node); space_id = region_obj->region.space_id; region_obj->region.addr_handler = NULL; region_obj->region.REGmethod = NULL; - region_obj->region.region_flags = INITIAL_REGION_FLAGS; + region_obj->region.flags &= ~(AOPOBJ_INITIALIZED); /* * Find any "_REG" associated with this region definition */ - status = acpi_ns_search_one_scope (*reg_name_ptr, entry->child_table, - ACPI_TYPE_METHOD, ®_entry, NULL); - if (status == AE_OK) { + status = acpi_ns_search_node (*reg_name_ptr, node, + ACPI_TYPE_METHOD, &method_node); + if (ACPI_SUCCESS (status)) { /* * The _REG method is optional and there can be only one per region * definition. This will be executed when the handler is attached * or removed */ - region_obj->region.REGmethod = reg_entry; + region_obj->region.REGmethod = method_node; } /* - * The following loop depends upon the root nte having no parent - * ie: Acpi_gbl_Root_object->Parent_entry being set to NULL + * The following loop depends upon the root Node having no parent + * ie: Acpi_gbl_Root_node->Parent_entry being set to NULL */ - while (entry) { + while (node) { /* * Check to see if a handler exists */ handler_obj = NULL; - obj_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) entry); + obj_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) node); if (obj_desc) { /* * can only be a handler if the object exists */ - switch (entry->type) + switch (node->type) { case ACPI_TYPE_DEVICE: @@ -400,11 +390,11 @@ /* * Found it! Now update the region and the handler */ - acpi_ev_associate_region_and_handler(handler_obj, region_obj); + acpi_ev_associate_region_and_handler (handler_obj, region_obj, acpi_ns_locked); return (AE_OK); } - handler_obj = handler_obj->addr_handler.link; + handler_obj = handler_obj->addr_handler.next; } /* while handlerobj */ } @@ -413,9 +403,9 @@ * This one does not have the handler we need * Pop up one level */ - entry = acpi_ns_get_parent_entry (entry); + node = acpi_ns_get_parent_object (node); - } /* while Entry != ROOT */ + } /* while Node != ROOT */ /* * If we get here, there is no handler for this region diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/events/evsci.c linux/drivers/acpi/events/evsci.c --- v2.4.0-test8/linux/drivers/acpi/events/evsci.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/events/evsci.c Fri Sep 15 14:30:30 2000 @@ -1,9 +1,10 @@ -/****************************************************************************** +/******************************************************************************* * * Module Name: evsci - System Control Interrupt configuration and * legacy to ACPI mode state transition functions + * $Revision: 59 $ * - *****************************************************************************/ + ******************************************************************************/ /* * Copyright (C) 2000 R. Byron Moore @@ -24,27 +25,26 @@ */ #include "acpi.h" -#include "namesp.h" -#include "hardware.h" -#include "events.h" +#include "acnamesp.h" +#include "achware.h" +#include "acevents.h" #define _COMPONENT EVENT_HANDLING - MODULE_NAME ("evsci"); + MODULE_NAME ("evsci") /* - * Elements correspond to counts for - * TMR, NOT_USED, GBL, PWR_BTN, SLP_BTN, RTC, - * and GENERAL respectively. These counts - * are modified by the ACPI interrupt handler... - * Note that GENERAL should probably be split out - * into one element for each bit in the GPE - * registers + * Elements correspond to counts for TMR, NOT_USED, GBL, PWR_BTN, SLP_BTN, RTC, + * and GENERAL respectively. These counts are modified by the ACPI interrupt + * handler. + * + * TBD: [Investigate] Note that GENERAL should probably be split out into + * one element for each bit in the GPE registers */ -/****************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_ev_sci_handler * @@ -61,16 +61,16 @@ u32 acpi_ev_sci_handler (void *context) { - u32 interrupt_handled = INTERRUPT_NOT_HANDLED; + u32 interrupt_handled = INTERRUPT_NOT_HANDLED; + /* - * ACPI Enabled? - * ------------- * Make sure that ACPI is enabled by checking SCI_EN. Note that we are * required to treat the SCI interrupt as sharable, level, active low. */ - if (!acpi_hw_register_access (ACPI_READ, ACPI_MTX_DO_NOT_LOCK, (s32)SCI_EN)) { - REPORT_ERROR ("Received and SCI but ACPI is not enabled."); + if (!acpi_hw_register_access (ACPI_READ, ACPI_MTX_DO_NOT_LOCK, SCI_EN)) { + /* ACPI is not enabled; this interrupt cannot be for us */ + return (INTERRUPT_NOT_HANDLED); } @@ -107,12 +107,12 @@ u32 acpi_ev_install_sci_handler (void) { - u32 except = AE_OK; + u32 except = AE_OK; + - except = acpi_os_install_interrupt_handler ( - (u32) acpi_gbl_FACP->sci_int, - acpi_ev_sci_handler, - NULL); + except = acpi_os_install_interrupt_handler ((u32) acpi_gbl_FACP->sci_int, + acpi_ev_sci_handler, + NULL); return (except); } @@ -163,24 +163,21 @@ #endif - acpi_os_remove_interrupt_handler ( - (u32) acpi_gbl_FACP->sci_int, - acpi_ev_sci_handler); + acpi_os_remove_interrupt_handler ((u32) acpi_gbl_FACP->sci_int, + acpi_ev_sci_handler); return (AE_OK); } -/****************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_ev_sci_count * - * PARAMETERS: char * Event_name name (fully qualified name from namespace - * or one of the fixed event names defined above) - * of the event to check if it's generated an SCI. + * PARAMETERS: Event Event that generated an SCI. * - * RETURN: Number of SCI's for requested event since last time i_sci_occured() - * was called for this event. + * RETURN: Number of SCI's for requested event since last time + * Sci_occured() was called for this event. * * DESCRIPTION: Checks to see if SCI has been generated from requested source * since the last time this function was called. @@ -188,7 +185,7 @@ ******************************************************************************/ -/****************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_ev_restore_acpi_state * @@ -203,7 +200,7 @@ void acpi_ev_restore_acpi_state (void) { - s32 index; + u32 index; /* Restore the state of the chipset enable bits. */ @@ -283,6 +280,7 @@ void acpi_ev_terminate (void) { + /* * Free global tables, etc. diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/events/evxface.c linux/drivers/acpi/events/evxface.c --- v2.4.0-test8/linux/drivers/acpi/events/evxface.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/events/evxface.c Fri Sep 15 14:30:30 2000 @@ -1,6 +1,7 @@ /****************************************************************************** * * Module Name: evxface - External interfaces for ACPI events + * $Revision: 88 $ * *****************************************************************************/ @@ -24,14 +25,14 @@ #include "acpi.h" -#include "hardware.h" -#include "namesp.h" -#include "events.h" +#include "achware.h" +#include "acnamesp.h" +#include "acevents.h" #include "amlcode.h" -#include "interp.h" +#include "acinterp.h" #define _COMPONENT EVENT_HANDLING - MODULE_NAME ("evxface"); + MODULE_NAME ("evxface") /****************************************************************************** @@ -172,9 +173,9 @@ NOTIFY_HANDLER handler, void *context) { - ACPI_OBJECT_INTERNAL *obj_desc; - ACPI_OBJECT_INTERNAL *notify_obj; - ACPI_NAMED_OBJECT *obj_entry; + ACPI_OPERAND_OBJECT *obj_desc; + ACPI_OPERAND_OBJECT *notify_obj; + ACPI_NAMESPACE_NODE *device_node; ACPI_STATUS status = AE_OK; @@ -190,8 +191,8 @@ acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE); - obj_entry = acpi_ns_convert_handle_to_entry (device); - if (!obj_entry) { + device_node = acpi_ns_convert_handle_to_entry (device); + if (!device_node) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } @@ -217,13 +218,13 @@ } if (handler_type == ACPI_SYSTEM_NOTIFY) { - acpi_gbl_sys_notify.nte = obj_entry; + acpi_gbl_sys_notify.node = device_node; acpi_gbl_sys_notify.handler = handler; acpi_gbl_sys_notify.context = context; } else { - acpi_gbl_drv_notify.nte = obj_entry; + acpi_gbl_drv_notify.node = device_node; acpi_gbl_drv_notify.handler = handler; acpi_gbl_drv_notify.context = context; } @@ -239,10 +240,10 @@ * These are the ONLY objects that can receive ACPI notifications */ - if ((obj_entry->type != ACPI_TYPE_DEVICE) && - (obj_entry->type != ACPI_TYPE_PROCESSOR) && - (obj_entry->type != ACPI_TYPE_POWER) && - (obj_entry->type != ACPI_TYPE_THERMAL)) + if ((device_node->type != ACPI_TYPE_DEVICE) && + (device_node->type != ACPI_TYPE_PROCESSOR) && + (device_node->type != ACPI_TYPE_POWER) && + (device_node->type != ACPI_TYPE_THERMAL)) { status = AE_BAD_PARAMETER; goto unlock_and_exit; @@ -250,7 +251,7 @@ /* Check for an existing internal object */ - obj_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) obj_entry); + obj_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) device_node); if (obj_desc) { /* * The object exists. @@ -270,15 +271,15 @@ else { /* Create a new object */ - obj_desc = acpi_cm_create_internal_object (obj_entry->type); + obj_desc = acpi_cm_create_internal_object (device_node->type); if (!obj_desc) { status = AE_NO_MEMORY; goto unlock_and_exit; } - /* Attach new object to the NTE */ + /* Attach new object to the Node */ - status = acpi_ns_attach_object (device, obj_desc, (u8) obj_entry->type); + status = acpi_ns_attach_object (device, obj_desc, (u8) device_node->type); if (ACPI_FAILURE (status)) { goto unlock_and_exit; @@ -296,7 +297,7 @@ goto unlock_and_exit; } - notify_obj->notify_handler.nte = obj_entry; + notify_obj->notify_handler.node = device_node; notify_obj->notify_handler.handler = handler; notify_obj->notify_handler.context = context; @@ -337,9 +338,9 @@ u32 handler_type, NOTIFY_HANDLER handler) { - ACPI_OBJECT_INTERNAL *notify_obj; - ACPI_OBJECT_INTERNAL *obj_desc; - ACPI_NAMED_OBJECT *obj_entry; + ACPI_OPERAND_OBJECT *notify_obj; + ACPI_OPERAND_OBJECT *obj_desc; + ACPI_NAMESPACE_NODE *device_node; ACPI_STATUS status = AE_OK; @@ -355,8 +356,8 @@ /* Convert and validate the device handle */ - obj_entry = acpi_ns_convert_handle_to_entry (device); - if (!obj_entry) { + device_node = acpi_ns_convert_handle_to_entry (device); + if (!device_node) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } @@ -365,10 +366,10 @@ * These are the ONLY objects that can receive ACPI notifications */ - if ((obj_entry->type != ACPI_TYPE_DEVICE) && - (obj_entry->type != ACPI_TYPE_PROCESSOR) && - (obj_entry->type != ACPI_TYPE_POWER) && - (obj_entry->type != ACPI_TYPE_THERMAL)) + if ((device_node->type != ACPI_TYPE_DEVICE) && + (device_node->type != ACPI_TYPE_PROCESSOR) && + (device_node->type != ACPI_TYPE_POWER) && + (device_node->type != ACPI_TYPE_THERMAL)) { status = AE_BAD_PARAMETER; goto unlock_and_exit; @@ -376,7 +377,7 @@ /* Check for an existing internal object */ - obj_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) obj_entry); + obj_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) device_node); if (!obj_desc) { status = AE_NOT_EXIST; goto unlock_and_exit; @@ -573,7 +574,7 @@ acpi_aml_exit_interpreter (); *out_handle = 0; - return status; + return (status); } @@ -598,7 +599,7 @@ /* TBD: [Restructure] Validate handle */ acpi_ev_release_global_lock (); - return AE_OK; + return (AE_OK); } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/events/evxfevnt.c linux/drivers/acpi/events/evxfevnt.c --- v2.4.0-test8/linux/drivers/acpi/events/evxfevnt.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/events/evxfevnt.c Fri Sep 15 14:30:30 2000 @@ -1,6 +1,7 @@ /****************************************************************************** * * Module Name: evxfevnt - External Interfaces, ACPI event disable/enable + * $Revision: 19 $ * *****************************************************************************/ @@ -24,16 +25,24 @@ #include "acpi.h" -#include "hardware.h" -#include "namesp.h" -#include "events.h" +#include "achware.h" +#include "acnamesp.h" +#include "acevents.h" #include "amlcode.h" -#include "interp.h" +#include "acinterp.h" #define _COMPONENT EVENT_HANDLING - MODULE_NAME ("evxfevnt"); + MODULE_NAME ("evxfevnt") +ACPI_STATUS +acpi_ev_find_pci_root_buses ( + void); + +ACPI_STATUS +acpi_ev_init_devices ( + void); + /************************************************************************** * * FUNCTION: Acpi_enable @@ -60,12 +69,27 @@ return (AE_NO_ACPI_TABLES); } + /* Init the hardware */ + + /* + * With the advent of a 3-pass parser, we need to be + * prepared to execute on initialized HW before the + * namespace has completed its load. + */ + + status = acpi_cm_hardware_initialize (); + if (ACPI_FAILURE (status)) { + return (status); + } + + /* Make sure the BIOS supports ACPI mode */ if (SYS_MODE_LEGACY == acpi_hw_get_mode_capabilities()) { return (AE_ERROR); } + acpi_gbl_original_mode = acpi_hw_get_mode(); /* @@ -74,24 +98,28 @@ * before handers are installed. */ - if (ACPI_FAILURE (acpi_ev_fixed_event_initialize ())) { - return (AE_ERROR); + status = acpi_ev_fixed_event_initialize (); + if (ACPI_FAILURE (status)) { + return (status); } - if (ACPI_FAILURE (acpi_ev_gpe_initialize())) { - return (AE_ERROR); + status = acpi_ev_gpe_initialize (); + if (ACPI_FAILURE (status)) { + return (status); } /* Install the SCI handler */ - if (ACPI_FAILURE (acpi_ev_install_sci_handler ())) { - return (AE_ERROR); + status = acpi_ev_install_sci_handler (); + if (ACPI_FAILURE (status)) { + return (status); } /* Transition to ACPI mode */ - if (AE_OK != acpi_hw_set_mode (SYS_MODE_ACPI)) { - return (AE_ERROR); + status = acpi_hw_set_mode (SYS_MODE_ACPI); + if (ACPI_FAILURE (status)) { + return (status); } /* Install handlers for control method GPE handlers (_Lxx, _Exx) */ @@ -100,6 +128,26 @@ status = acpi_ev_init_global_lock_handler (); + /* + * Perform additional initialization that may cause control methods + * to be executed + * + * It may be wise to move this code to a new interface + */ + + + /* + * Install PCI config space handler for all PCI root bridges. A PCI root + * bridge is found by searching for devices containing a HID with the value + * EISAID("PNP0A03") + */ + + acpi_ev_find_pci_root_buses (); + + /* Call _INI on all devices */ + + acpi_ev_init_devices (); + return (status); } @@ -120,12 +168,14 @@ ACPI_STATUS acpi_disable (void) { + ACPI_STATUS status; /* Restore original mode */ - if (AE_OK != acpi_hw_set_mode (acpi_gbl_original_mode)) { - return (AE_ERROR); + status = acpi_hw_set_mode (acpi_gbl_original_mode); + if (ACPI_FAILURE (status)) { + return (status); } /* Unload the SCI interrupt handler */ @@ -133,7 +183,7 @@ acpi_ev_remove_sci_handler (); acpi_ev_restore_acpi_state (); - return (AE_OK); + return (status); } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/events/evxfregn.c linux/drivers/acpi/events/evxfregn.c --- v2.4.0-test8/linux/drivers/acpi/events/evxfregn.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/events/evxfregn.c Fri Sep 15 14:30:30 2000 @@ -2,6 +2,7 @@ * * Module Name: evxfregn - External Interfaces, ACPI Operation Regions and * Address Spaces. + * $Revision: 20 $ * *****************************************************************************/ @@ -25,14 +26,14 @@ #include "acpi.h" -#include "hardware.h" -#include "namesp.h" -#include "events.h" +#include "achware.h" +#include "acnamesp.h" +#include "acevents.h" #include "amlcode.h" -#include "interp.h" +#include "acinterp.h" #define _COMPONENT EVENT_HANDLING - MODULE_NAME ("evxfregn"); + MODULE_NAME ("evxfregn") /****************************************************************************** @@ -59,9 +60,9 @@ ADDRESS_SPACE_SETUP setup, void *context) { - ACPI_OBJECT_INTERNAL *obj_desc; - ACPI_OBJECT_INTERNAL *handler_obj; - ACPI_NAMED_OBJECT *obj_entry; + ACPI_OPERAND_OBJECT *obj_desc; + ACPI_OPERAND_OBJECT *handler_obj; + ACPI_NAMESPACE_NODE *node; ACPI_STATUS status = AE_OK; OBJECT_TYPE_INTERNAL type; u16 flags = 0; @@ -80,8 +81,8 @@ /* Convert and validate the device handle */ - obj_entry = acpi_ns_convert_handle_to_entry (device); - if (!obj_entry) { + node = acpi_ns_convert_handle_to_entry (device); + if (!node) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } @@ -92,10 +93,10 @@ * get placed. */ - if ((obj_entry->type != ACPI_TYPE_DEVICE) && - (obj_entry->type != ACPI_TYPE_PROCESSOR) && - (obj_entry->type != ACPI_TYPE_THERMAL) && - (obj_entry != acpi_gbl_root_object)) + if ((node->type != ACPI_TYPE_DEVICE) && + (node->type != ACPI_TYPE_PROCESSOR) && + (node->type != ACPI_TYPE_THERMAL) && + (node != acpi_gbl_root_node)) { status = AE_BAD_PARAMETER; goto unlock_and_exit; @@ -139,7 +140,7 @@ * Check for an existing internal object */ - obj_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) obj_entry); + obj_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) node); if (obj_desc) { /* * The object exists. @@ -162,19 +163,19 @@ /* * Move through the linked list of handlers */ - handler_obj = handler_obj->addr_handler.link; + handler_obj = handler_obj->addr_handler.next; } } else { /* Obj_desc does not exist, create one */ - if (obj_entry->type == ACPI_TYPE_ANY) { + if (node->type == ACPI_TYPE_ANY) { type = ACPI_TYPE_DEVICE; } else { - type = obj_entry->type; + type = node->type; } obj_desc = acpi_cm_create_internal_object (type); @@ -187,19 +188,13 @@ obj_desc->common.type = (u8) type; - /* Attach the new object to the NTE */ + /* Attach the new object to the Node */ status = acpi_ns_attach_object (device, obj_desc, (u8) type); if (ACPI_FAILURE (status)) { acpi_cm_remove_reference (obj_desc); goto unlock_and_exit; } - - /* TBD: [Investigate] Will this always be of type DEVICE? */ - - if (type == ACPI_TYPE_DEVICE) { - obj_desc->device.handle = device; - } } /* @@ -215,11 +210,11 @@ goto unlock_and_exit; } - handler_obj->addr_handler.space_id = (u16) space_id; + handler_obj->addr_handler.space_id = (u8) space_id; handler_obj->addr_handler.hflags = flags; - handler_obj->addr_handler.link = obj_desc->device.addr_handler; + handler_obj->addr_handler.next = obj_desc->device.addr_handler; handler_obj->addr_handler.region_list = NULL; - handler_obj->addr_handler.nte = obj_entry; + handler_obj->addr_handler.node = node; handler_obj->addr_handler.handler = handler; handler_obj->addr_handler.context = context; handler_obj->addr_handler.setup = setup; @@ -237,7 +232,7 @@ * of the branch */ status = acpi_ns_walk_namespace (ACPI_TYPE_ANY, device, - ACPI_INT32_MAX, NS_WALK_NO_UNLOCK, + ACPI_UINT32_MAX, NS_WALK_UNLOCK, acpi_ev_addr_handler_helper, handler_obj, NULL); @@ -276,11 +271,11 @@ ACPI_ADDRESS_SPACE_TYPE space_id, ADDRESS_SPACE_HANDLER handler) { - ACPI_OBJECT_INTERNAL *obj_desc; - ACPI_OBJECT_INTERNAL *handler_obj; - ACPI_OBJECT_INTERNAL *region_obj; - ACPI_OBJECT_INTERNAL **last_obj_ptr; - ACPI_NAMED_OBJECT *obj_entry; + ACPI_OPERAND_OBJECT *obj_desc; + ACPI_OPERAND_OBJECT *handler_obj; + ACPI_OPERAND_OBJECT *region_obj; + ACPI_OPERAND_OBJECT **last_obj_ptr; + ACPI_NAMESPACE_NODE *node; ACPI_STATUS status = AE_OK; @@ -297,8 +292,8 @@ /* Convert and validate the device handle */ - obj_entry = acpi_ns_convert_handle_to_entry (device); - if (!obj_entry) { + node = acpi_ns_convert_handle_to_entry (device); + if (!node) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } @@ -306,7 +301,7 @@ /* Make sure the internal object exists */ - obj_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) obj_entry); + obj_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) node); if (!obj_desc) { /* * The object DNE. @@ -356,7 +351,7 @@ /* * Remove this Handler object from the list */ - *last_obj_ptr = handler_obj->addr_handler.link; + *last_obj_ptr = handler_obj->addr_handler.next; /* * Now we can delete the handler object @@ -370,8 +365,8 @@ /* * Move through the linked list of handlers */ - last_obj_ptr = &handler_obj->addr_handler.link; - handler_obj = handler_obj->addr_handler.link; + last_obj_ptr = &handler_obj->addr_handler.next; + handler_obj = handler_obj->addr_handler.next; } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/hardware/Makefile linux/drivers/acpi/hardware/Makefile --- v2.4.0-test8/linux/drivers/acpi/hardware/Makefile Wed Dec 31 16:00:00 1969 +++ linux/drivers/acpi/hardware/Makefile Fri Sep 15 18:21:43 2000 @@ -0,0 +1,28 @@ +# +# Makefile for all Linux ACPI interpreter subdirectories +# + +SUB_DIRS := +MOD_SUB_DIRS := $(SUB_DIRS) +MOD_IN_SUB_DIRS := +ALL_SUB_DIRS := $(SUB_DIRS) + +O_TARGET := ../$(shell basename `pwd`).o +O_OBJS := +M_OBJS := + +ACPI_OBJS := $(patsubst %.c,%.o,$(wildcard *.c)) + +EXTRA_CFLAGS += -I../include + +EXTRA_CFLAGS += $(ACPI_CFLAGS) + +# if the interpreter is used, it overrides arch/i386/kernel/acpi.c +ifeq ($(CONFIG_ACPI_INTERPRETER),y) + O_OBJS := $(ACPI_OBJS) +endif + +include $(TOPDIR)/Rules.make + +clean: + $(RM) *.o diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/hardware/hwacpi.c linux/drivers/acpi/hardware/hwacpi.c --- v2.4.0-test8/linux/drivers/acpi/hardware/hwacpi.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/hardware/hwacpi.c Fri Sep 15 14:30:30 2000 @@ -1,7 +1,7 @@ - /****************************************************************************** * * Module Name: hwacpi - ACPI hardware functions - mode and timer + * $Revision: 22 $ * *****************************************************************************/ @@ -25,11 +25,11 @@ #include "acpi.h" -#include "hardware.h" +#include "achware.h" #define _COMPONENT HARDWARE - MODULE_NAME ("hwacpi"); + MODULE_NAME ("hwacpi") /****************************************************************************** @@ -95,7 +95,7 @@ { - if (acpi_hw_register_access (ACPI_READ, ACPI_MTX_LOCK, (s32)SCI_EN)) { + if (acpi_hw_register_access (ACPI_READ, ACPI_MTX_LOCK, SCI_EN)) { return (SYS_MODE_ACPI); } else { diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/hardware/hwcpu32.c linux/drivers/acpi/hardware/hwcpu32.c --- v2.4.0-test8/linux/drivers/acpi/hardware/hwcpu32.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/hardware/hwcpu32.c Fri Sep 15 14:30:30 2000 @@ -1,6 +1,7 @@ /****************************************************************************** * * Name: hwcpu32.c - CPU support for IA32 (Throttling, Cx_states) + * $Revision: 33 $ * *****************************************************************************/ @@ -23,11 +24,11 @@ */ #include "acpi.h" -#include "namesp.h" -#include "hardware.h" +#include "acnamesp.h" +#include "achware.h" #define _COMPONENT HARDWARE - MODULE_NAME ("Hwcpu32"); + MODULE_NAME ("Hwcpu32") #define BIT_4 0x10 /* TBD: [investigate] is this correct? */ @@ -82,7 +83,7 @@ *pm_timer_ticks = timer; } - return AE_OK; + return (AE_OK); } @@ -108,7 +109,7 @@ if (!pblk_address || !pm_timer_ticks) { - return AE_BAD_PARAMETER; + return (AE_BAD_PARAMETER); } /* @@ -146,7 +147,7 @@ */ enable (); - return AE_OK; + return (AE_OK); } @@ -175,7 +176,7 @@ if (!pblk_address || !pm_timer_ticks) { - return AE_BAD_PARAMETER; + return (AE_BAD_PARAMETER); } /* @@ -186,14 +187,14 @@ * eventually cause a demotion to C2 */ if (1 == (bus_master_status = - acpi_hw_register_access (ACPI_READ, ACPI_MTX_LOCK, (s32)BM_STS))) + acpi_hw_register_access (ACPI_READ, ACPI_MTX_LOCK, BM_STS))) { /* * Clear the BM_STS bit by setting it. */ - acpi_hw_register_access (ACPI_WRITE, ACPI_MTX_LOCK, (s32)BM_STS, 1); + acpi_hw_register_access (ACPI_WRITE, ACPI_MTX_LOCK, BM_STS, 1); *pm_timer_ticks = 0; - return AE_OK; + return (AE_OK); } /* @@ -253,7 +254,7 @@ */ enable(); - return AE_OK; + return (AE_OK); } @@ -277,7 +278,7 @@ { if (!acpi_hw_cx_handlers[acpi_hw_active_cx_state]) { - return AE_SUPPORT; + return (AE_SUPPORT); } return (acpi_hw_cx_handlers[acpi_hw_active_cx_state] (pblk_address, pm_timer_ticks)); @@ -305,11 +306,11 @@ * ---------------- */ if ((cx_state < 1) || (cx_state > 3)) { - return AE_BAD_PARAMETER; + return (AE_BAD_PARAMETER); } if (!acpi_hw_cx_handlers[cx_state]) { - return AE_SUPPORT; + return (AE_SUPPORT); } /* @@ -318,7 +319,7 @@ * We only care when moving from one state to another... */ if (acpi_hw_active_cx_state == cx_state) { - return AE_OK; + return (AE_OK); } /* @@ -331,7 +332,7 @@ switch (cx_state) { case 3: - acpi_hw_register_access (ACPI_WRITE, ACPI_MTX_LOCK, (s32)BM_RLD, 1); + acpi_hw_register_access (ACPI_WRITE, ACPI_MTX_LOCK, BM_RLD, 1); break; } @@ -345,7 +346,7 @@ switch (acpi_hw_active_cx_state) { case 3: - acpi_hw_register_access (ACPI_WRITE, ACPI_MTX_LOCK, (s32)BM_RLD, 0); + acpi_hw_register_access (ACPI_WRITE, ACPI_MTX_LOCK, BM_RLD, 0); break; } @@ -355,7 +356,7 @@ */ acpi_hw_active_cx_state = cx_state; - return AE_OK; + return (AE_OK); } @@ -526,7 +527,7 @@ result = result * x; } - return result; + return (result); } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/hardware/hwgpe.c linux/drivers/acpi/hardware/hwgpe.c --- v2.4.0-test8/linux/drivers/acpi/hardware/hwgpe.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/hardware/hwgpe.c Fri Sep 15 14:30:30 2000 @@ -1,6 +1,7 @@ /****************************************************************************** * * Module Name: hwgpe - Low level GPE enable/disable/clear functions + * $Revision: 22 $ * *****************************************************************************/ @@ -23,12 +24,12 @@ */ #include "acpi.h" -#include "hardware.h" -#include "namesp.h" -#include "events.h" +#include "achware.h" +#include "acnamesp.h" +#include "acevents.h" #define _COMPONENT HARDWARE - MODULE_NAME ("hwgpe"); + MODULE_NAME ("hwgpe") u8 decode_to8bit [8] = {1,2,4,8,16,32,64,128}; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/hardware/hwregs.c linux/drivers/acpi/hardware/hwregs.c --- v2.4.0-test8/linux/drivers/acpi/hardware/hwregs.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/hardware/hwregs.c Fri Sep 15 14:30:30 2000 @@ -1,10 +1,11 @@ -/****************************************************************************** +/******************************************************************************* * * Module Name: hwregs - Read/write access functions for the various ACPI * control and status registers. + * $Revision: 67 $ * - *****************************************************************************/ + ******************************************************************************/ /* * Copyright (C) 2000 R. Byron Moore @@ -26,20 +27,20 @@ #include "acpi.h" -#include "hardware.h" -#include "namesp.h" +#include "achware.h" +#include "acnamesp.h" #define _COMPONENT HARDWARE - MODULE_NAME ("hwregs"); + MODULE_NAME ("hwregs") /* This matches the #defines in actypes.h. */ -ACPI_STRING sleep_state_table[] = {"\\_S0_","\\_S1_","\\_S2_","\\_S3_", +NATIVE_CHAR *sleep_state_table[] = {"\\_S0_","\\_S1_","\\_S2_","\\_S3_", "\\_S4_","\\_S4_b","\\_S5_"}; -/****************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_hw_get_bit_shift * @@ -52,11 +53,11 @@ * ******************************************************************************/ -s32 +u32 acpi_hw_get_bit_shift ( u32 mask) { - s32 shift; + u32 shift; for (shift = 0; ((mask >> shift) & 1) == 0; shift++) { ; } @@ -65,7 +66,7 @@ } -/****************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_hw_clear_acpi_status * @@ -116,7 +117,7 @@ } -/**************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_hw_obtain_sleep_type_register_data * @@ -129,8 +130,7 @@ * DESCRIPTION: Acpi_hw_obtain_sleep_type_register_data() obtains the SLP_TYP and * SLP_TYPb values for the sleep state requested. * - - ***************************************************************************/ + ******************************************************************************/ ACPI_STATUS acpi_hw_obtain_sleep_type_register_data ( @@ -139,7 +139,7 @@ u8 *slp_typ_b) { ACPI_STATUS status = AE_OK; - ACPI_OBJECT_INTERNAL *obj_desc; + ACPI_OPERAND_OBJECT *obj_desc; /* @@ -157,45 +157,64 @@ */ status = acpi_ns_evaluate_by_name (sleep_state_table[sleep_state], NULL, &obj_desc); - if (AE_OK == status) { - if (obj_desc) { - /* - * We got something, now ensure it is correct. The object must - * be a package and must have at least 2 numeric values as the - * two elements - */ + if (ACPI_FAILURE (status)) { + return (status); + } - if ((obj_desc->common.type != ACPI_TYPE_PACKAGE) || - ((obj_desc->package.elements[0])->common.type != - ACPI_TYPE_NUMBER) || - ((obj_desc->package.elements[1])->common.type != - ACPI_TYPE_NUMBER)) - { - /* Invalid _Sx_ package type or value */ + if (!obj_desc) { + REPORT_ERROR ("Missing Sleep State object"); + return (AE_NOT_EXIST); + } - REPORT_ERROR ("Object type returned from interpreter differs from expected value"); - status = AE_ERROR; - } - else { - /* - * Valid _Sx_ package size, type, and value - */ - *slp_typ_a = - (u8) (obj_desc->package.elements[0])->number.value; + /* + * We got something, now ensure it is correct. The object must + * be a package and must have at least 2 numeric values as the + * two elements + */ - *slp_typ_b = - (u8) (obj_desc->package.elements[1])->number.value; - } + if (obj_desc->common.type != ACPI_TYPE_PACKAGE) { + /* Must be a package */ - acpi_cm_remove_reference (obj_desc); - } + REPORT_ERROR ("Sleep State object is not of type Package"); + status = AE_ERROR; + } + + else if (obj_desc->package.count < 2) { + /* Must have at least two elements */ + + REPORT_ERROR ("Sleep State package does not have at least two elements"); + status = AE_ERROR; + } + + else if (((obj_desc->package.elements[0])->common.type != + ACPI_TYPE_NUMBER) || + ((obj_desc->package.elements[1])->common.type != + ACPI_TYPE_NUMBER)) + { + /* Must have two */ + + REPORT_ERROR ("Sleep State package elements are not both of type Number"); + status = AE_ERROR; } + else { + /* + * Valid _Sx_ package size, type, and value + */ + *slp_typ_a = (u8) (obj_desc->package.elements[0])->number.value; + + *slp_typ_b = (u8) (obj_desc->package.elements[1])->number.value; + } + + + + acpi_cm_remove_reference (obj_desc); + return (status); } -/****************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_hw_register_access * @@ -229,7 +248,7 @@ va_list marker; va_start (marker, register_id); - value = va_arg (marker, s32); + value = va_arg (marker, u32); va_end (marker); } @@ -407,7 +426,7 @@ register_value = (u32) acpi_os_in16 (acpi_gbl_FACP->pm1a_cnt_blk); } - if (acpi_gbl_FACP->pm1b_cnt_blk && register_id != (s32) SLP_TYPE_A) { + if (acpi_gbl_FACP->pm1b_cnt_blk && register_id != (u32) SLP_TYPE_A) { register_value |= (u32) acpi_os_in16 (acpi_gbl_FACP->pm1b_cnt_blk); } @@ -469,7 +488,7 @@ } } - if (acpi_gbl_FACP->pm1b_cnt_blk && register_id != (s32) SLP_TYPE_A) { + if (acpi_gbl_FACP->pm1b_cnt_blk && register_id != (u32) SLP_TYPE_A) { acpi_os_out16 (acpi_gbl_FACP->pm1b_cnt_blk, (u16) register_value); } } @@ -551,13 +570,17 @@ mask = (((u32) register_id) & BIT_IN_REGISTER_MASK); mask = 1 << (mask-1); - /* The base address of the GPE 0 Register Block */ - /* Plus 1/2 the length of the GPE 0 Register Block */ - /* The enable register is the register following the Status Register */ - /* and each register is defined as 1/2 of the total Register Block */ - - /* This sets the bit within Enable_bit that needs to be written to */ - /* the register indicated in Mask to a 1, all others are 0 */ + /* + * The base address of the GPE 0 Register Block + * Plus 1/2 the length of the GPE 0 Register Block + * The enable register is the register following the Status Register + * and each register is defined as 1/2 of the total Register Block + */ + + /* + * This sets the bit within Enable_bit that needs to be written to + * the register indicated in Mask to a 1, all others are 0 + */ if (mask > LOW_BYTE) { /* Shift the value 1 byte to the right and add 1 to the register */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/hardware/hwxface.c linux/drivers/acpi/hardware/hwxface.c --- v2.4.0-test8/linux/drivers/acpi/hardware/hwxface.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/hardware/hwxface.c Fri Sep 15 14:30:30 2000 @@ -2,6 +2,7 @@ /****************************************************************************** * * Name: hwxface.c - Hardware access external interfaces + * $Revision: 31 $ * *****************************************************************************/ @@ -24,11 +25,11 @@ */ #include "acpi.h" -#include "namesp.h" -#include "hardware.h" +#include "acnamesp.h" +#include "achware.h" #define _COMPONENT HARDWARE - MODULE_NAME ("hwxface"); + MODULE_NAME ("hwxface") /****************************************************************************** @@ -68,10 +69,9 @@ NATIVE_UINT num_throttle_states; NATIVE_UINT buffer_space_needed; NATIVE_UINT i; - u8 duty_offset; - u8 duty_width; - ACPI_NAMED_OBJECT *cpu_entry; - ACPI_OBJECT_INTERNAL *cpu_obj; + u8 duty_width = 0; + ACPI_NAMESPACE_NODE *cpu_node; + ACPI_OPERAND_OBJECT *cpu_obj; ACPI_CPU_THROTTLING_STATE *state_ptr; @@ -86,8 +86,8 @@ * Convert and validate the device handle */ - cpu_entry = acpi_ns_convert_handle_to_entry (processor_handle); - if (!cpu_entry) { + cpu_node = acpi_ns_convert_handle_to_entry (processor_handle); + if (!cpu_node) { return (AE_BAD_PARAMETER); } @@ -95,23 +95,27 @@ * Check for an existing internal object */ - cpu_obj = acpi_ns_get_attached_object ((ACPI_HANDLE) cpu_entry); + cpu_obj = acpi_ns_get_attached_object ((ACPI_HANDLE) cpu_node); if (!cpu_obj) { return (AE_NOT_FOUND); } - duty_offset = acpi_gbl_FACP->duty_offset; +#ifndef _IA64 + /* + * No Duty fields in IA64 tables + */ duty_width = acpi_gbl_FACP->duty_width; +#endif /* * P0 must always have a P_BLK all others may be null - * in either case, we can't thottle a processor that has no P_BLK + * in either case, we can't throttle a processor that has no P_BLK * * Also if no Duty width, one state and it is 100% * */ - if (!cpu_obj->processor.pblk_length || !duty_width || - (0xFFFF < cpu_obj->processor.pblk_address)) + if (!cpu_obj->processor.length || !duty_width || + (0xFFFF < cpu_obj->processor.address)) { /* * Acpi_even though we can't throttle, we still have one state (100%) @@ -169,30 +173,35 @@ ACPI_HANDLE processor_handle, u32 *throttle_state) { - ACPI_NAMED_OBJECT *cpu_entry; - ACPI_OBJECT_INTERNAL *cpu_obj; + ACPI_NAMESPACE_NODE *cpu_node; + ACPI_OPERAND_OBJECT *cpu_obj; u32 num_throttle_states; u32 duty_cycle; - u8 duty_offset; - u8 duty_width; + u8 duty_offset = 0; + u8 duty_width = 0; /* Convert and validate the device handle */ - cpu_entry = acpi_ns_convert_handle_to_entry (processor_handle); - if (!cpu_entry || !throttle_state) { + cpu_node = acpi_ns_convert_handle_to_entry (processor_handle); + if (!cpu_node || !throttle_state) { return (AE_BAD_PARAMETER); } /* Check for an existing internal object */ - cpu_obj = acpi_ns_get_attached_object ((ACPI_HANDLE) cpu_entry); + cpu_obj = acpi_ns_get_attached_object ((ACPI_HANDLE) cpu_node); if (!cpu_obj) { return (AE_NOT_FOUND); } +#ifndef _IA64 + /* + * No Duty fields in IA64 tables + */ duty_offset = acpi_gbl_FACP->duty_offset; duty_width = acpi_gbl_FACP->duty_width; +#endif /* * Must have a valid P_BLK P0 must have a P_BLK all others may be null @@ -201,8 +210,8 @@ * * also, if Duty_width is zero there are no additional states */ - if (!cpu_obj->processor.pblk_length || !duty_width || - (0xFFFF < cpu_obj->processor.pblk_address)) + if (!cpu_obj->processor.length || !duty_width || + (0xFFFF < cpu_obj->processor.address)) { *throttle_state = 0; return(AE_OK); @@ -214,7 +223,7 @@ * Get the current duty cycle value. */ duty_cycle = acpi_hw_get_duty_cycle (duty_offset, - cpu_obj->processor.pblk_address, + cpu_obj->processor.address, num_throttle_states); /* @@ -251,8 +260,8 @@ ACPI_HANDLE processor_handle, u32 throttle_state) { - ACPI_NAMED_OBJECT *cpu_entry; - ACPI_OBJECT_INTERNAL *cpu_obj; + ACPI_NAMESPACE_NODE *cpu_node; + ACPI_OPERAND_OBJECT *cpu_obj; u32 num_throttle_states = 0; u8 duty_offset = 0; u8 duty_width = 0; @@ -261,20 +270,25 @@ /* Convert and validate the device handle */ - cpu_entry = acpi_ns_convert_handle_to_entry (processor_handle); - if (!cpu_entry) { + cpu_node = acpi_ns_convert_handle_to_entry (processor_handle); + if (!cpu_node) { return (AE_BAD_PARAMETER); } /* Check for an existing internal object */ - cpu_obj = acpi_ns_get_attached_object ((ACPI_HANDLE) cpu_entry); + cpu_obj = acpi_ns_get_attached_object ((ACPI_HANDLE) cpu_node); if (!cpu_obj) { return (AE_NOT_FOUND); } +#ifndef _IA64 + /* + * No Duty fields in IA64 tables + */ duty_offset = acpi_gbl_FACP->duty_offset; duty_width = acpi_gbl_FACP->duty_width; +#endif /* * Must have a valid P_BLK P0 must have a P_BLK all others may be null @@ -283,8 +297,8 @@ * * also, if Duty_width is zero there are no additional states */ - if (!cpu_obj->processor.pblk_length || !duty_width || - (0xFFFF < cpu_obj->processor.pblk_address)) + if (!cpu_obj->processor.length || !duty_width || + (0xFFFF < cpu_obj->processor.address)) { /* * If caller wants to set the state to the only state we handle @@ -312,19 +326,19 @@ /* * Turn off throttling (don't muck with the h/w while throttling). */ - acpi_hw_disable_throttling (cpu_obj->processor.pblk_address); + acpi_hw_disable_throttling (cpu_obj->processor.address); /* * Program the throttling state. */ acpi_hw_program_duty_cycle (duty_offset, duty_cycle, - cpu_obj->processor.pblk_address, num_throttle_states); + cpu_obj->processor.address, num_throttle_states); /* * Only enable throttling for non-zero states (0 - 100%) */ if (throttle_state) { - acpi_hw_enable_throttling (cpu_obj->processor.pblk_address); + acpi_hw_enable_throttling (cpu_obj->processor.address); } return(AE_OK); @@ -438,9 +452,9 @@ ACPI_HANDLE processor_handle, u32 *pm_timer_ticks) { - ACPI_NAMED_OBJECT *cpu_entry = NULL; - ACPI_OBJECT_INTERNAL *cpu_obj = NULL; - ACPI_IO_ADDRESS pblk_address = 0; + ACPI_NAMESPACE_NODE *cpu_node = NULL; + ACPI_OPERAND_OBJECT *cpu_obj = NULL; + ACPI_IO_ADDRESS address = 0; /* @@ -449,31 +463,31 @@ /* Convert and validate the device handle */ - cpu_entry = acpi_ns_convert_handle_to_entry (processor_handle); - if (!cpu_entry) { - return AE_BAD_PARAMETER; + cpu_node = acpi_ns_convert_handle_to_entry (processor_handle); + if (!cpu_node) { + return (AE_BAD_PARAMETER); } /* Check for an existing internal object */ - cpu_obj = acpi_ns_get_attached_object ((ACPI_HANDLE) cpu_entry); + cpu_obj = acpi_ns_get_attached_object ((ACPI_HANDLE) cpu_node); if (!cpu_obj) { - return AE_NOT_FOUND; + return (AE_NOT_FOUND); } /* Get the processor register block (P_BLK) address */ - pblk_address = cpu_obj->processor.pblk_address; - if (!cpu_obj->processor.pblk_length) { + address = cpu_obj->processor.address; + if (!cpu_obj->processor.length) { /* Ensure a NULL addresss (note that P_BLK isn't required for C1) */ - pblk_address = 0; + address = 0; } /* * Enter the currently active Cx sleep state. */ - return acpi_hw_enter_cx (pblk_address, pm_timer_ticks); + return (acpi_hw_enter_cx (address, pm_timer_ticks)); } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/include/accommon.h linux/drivers/acpi/include/accommon.h --- v2.4.0-test8/linux/drivers/acpi/include/accommon.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/acpi/include/accommon.h Fri Sep 15 14:30:30 2000 @@ -0,0 +1,661 @@ +/****************************************************************************** + * + * Name: accommon.h -- prototypes for the common (subsystem-wide) procedures + * $Revision: 74 $ + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 R. Byron Moore + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _ACCOMMON_H +#define _ACCOMMON_H + + +#define REF_INCREMENT (u16) 0 +#define REF_DECREMENT (u16) 1 +#define REF_FORCE_DELETE (u16) 2 + +/* Acpi_cm_dump_buffer */ + +#define DB_BYTE_DISPLAY 1 +#define DB_WORD_DISPLAY 2 +#define DB_DWORD_DISPLAY 4 +#define DB_QWORD_DISPLAY 8 + + +/* Global initialization interfaces */ + +void +acpi_cm_init_globals ( + ACPI_INIT_DATA *init_data); + +void +acpi_cm_terminate ( + void); + + +/* + * Acpi_cm_init - miscellaneous initialization and shutdown + */ + +ACPI_STATUS +acpi_cm_hardware_initialize ( + void); + +ACPI_STATUS +acpi_cm_subsystem_shutdown ( + void); + +/* + * Acpi_cm_global - Global data structures and procedures + */ + +NATIVE_CHAR * +acpi_cm_get_mutex_name ( + u32 mutex_id); + +NATIVE_CHAR * +acpi_cm_get_type_name ( + u32 type); + +u8 +acpi_cm_valid_object_type ( + u32 type); + +ACPI_OWNER_ID +acpi_cm_allocate_owner_id ( + u32 id_type); + + +/* + * Acpi_cm_clib - Local implementations of C library functions + */ + +NATIVE_UINT +acpi_cm_strlen ( + const NATIVE_CHAR *string); + +NATIVE_CHAR * +acpi_cm_strcpy ( + NATIVE_CHAR *dst_string, + const NATIVE_CHAR *src_string); + +NATIVE_CHAR * +acpi_cm_strncpy ( + NATIVE_CHAR *dst_string, + const NATIVE_CHAR *src_string, + NATIVE_UINT count); + +u32 +acpi_cm_strncmp ( + const NATIVE_CHAR *string1, + const NATIVE_CHAR *string2, + NATIVE_UINT count); + +u32 +acpi_cm_strcmp ( + const NATIVE_CHAR *string1, + const NATIVE_CHAR *string2); + +NATIVE_CHAR * +acpi_cm_strcat ( + NATIVE_CHAR *dst_string, + const NATIVE_CHAR *src_string); + +NATIVE_CHAR * +acpi_cm_strncat ( + NATIVE_CHAR *dst_string, + const NATIVE_CHAR *src_string, + NATIVE_UINT count); + +u32 +acpi_cm_strtoul ( + const NATIVE_CHAR *string, + NATIVE_CHAR **terminator, + u32 base); + +NATIVE_CHAR * +acpi_cm_strstr ( + NATIVE_CHAR *string1, + NATIVE_CHAR *string2); + +NATIVE_CHAR * +acpi_cm_strupr ( + NATIVE_CHAR *src_string); + +void * +acpi_cm_memcpy ( + void *dest, + const void *src, + NATIVE_UINT count); + +void * +acpi_cm_memset ( + void *dest, + u32 value, + NATIVE_UINT count); + +u32 +acpi_cm_to_upper ( + u32 c); + +u32 +acpi_cm_to_lower ( + u32 c); + + +/* + * Acpi_cm_copy - Object construction and conversion interfaces + */ + +ACPI_STATUS +acpi_cm_build_simple_object( + ACPI_OPERAND_OBJECT *obj, + ACPI_OBJECT *user_obj, + u8 *data_space, + u32 *buffer_space_used); + +ACPI_STATUS +acpi_cm_build_package_object ( + ACPI_OPERAND_OBJECT *obj, + u8 *buffer, + u32 *space_used); + +ACPI_STATUS +acpi_cm_build_external_object ( + ACPI_OPERAND_OBJECT *obj, + ACPI_BUFFER *ret_buffer); + +ACPI_STATUS +acpi_cm_build_internal_simple_object( + ACPI_OBJECT *user_obj, + ACPI_OPERAND_OBJECT *obj); + +ACPI_STATUS +acpi_cm_build_internal_object ( + ACPI_OBJECT *obj, + ACPI_OPERAND_OBJECT *internal_obj); + +ACPI_STATUS +acpi_cm_copy_internal_simple_object ( + ACPI_OPERAND_OBJECT *source_obj, + ACPI_OPERAND_OBJECT *dest_obj); + +ACPI_STATUS +acpi_cm_build_copy_internal_package_object ( + ACPI_OPERAND_OBJECT *source_obj, + ACPI_OPERAND_OBJECT *dest_obj); + + +/* + * Acpi_cm_create - Object creation + */ + +ACPI_STATUS +acpi_cm_update_object_reference ( + ACPI_OPERAND_OBJECT *object, + u16 action); + +ACPI_OPERAND_OBJECT * +_cm_create_internal_object ( + NATIVE_CHAR *module_name, + u32 line_number, + u32 component_id, + OBJECT_TYPE_INTERNAL type); + + +/* + * Acpi_cm_debug - Debug interfaces + */ + +u32 +get_debug_level ( + void); + +void +set_debug_level ( + u32 level); + +void +function_trace ( + NATIVE_CHAR *module_name, + u32 line_number, + u32 component_id, + NATIVE_CHAR *function_name); + +void +function_trace_ptr ( + NATIVE_CHAR *module_name, + u32 line_number, + u32 component_id, + NATIVE_CHAR *function_name, + void *pointer); + +void +function_trace_u32 ( + NATIVE_CHAR *module_name, + u32 line_number, + u32 component_id, + NATIVE_CHAR *function_name, + u32 integer); + +void +function_trace_str ( + NATIVE_CHAR *module_name, + u32 line_number, + u32 component_id, + NATIVE_CHAR *function_name, + NATIVE_CHAR *string); + +void +function_exit ( + NATIVE_CHAR *module_name, + u32 line_number, + u32 component_id, + NATIVE_CHAR *function_name); + +void +function_status_exit ( + NATIVE_CHAR *module_name, + u32 line_number, + u32 component_id, + NATIVE_CHAR *function_name, + ACPI_STATUS status); + +void +function_value_exit ( + NATIVE_CHAR *module_name, + u32 line_number, + u32 component_id, + NATIVE_CHAR *function_name, + NATIVE_UINT value); + +void +function_ptr_exit ( + NATIVE_CHAR *module_name, + u32 line_number, + u32 component_id, + NATIVE_CHAR *function_name, + u8 *ptr); + +void +debug_print_prefix ( + NATIVE_CHAR *module_name, + u32 line_number); + +void +debug_print ( + NATIVE_CHAR *module_name, + u32 line_number, + u32 component_id, + u32 print_level, + NATIVE_CHAR *format, ...); + +void +debug_print_raw ( + NATIVE_CHAR *format, ...); + +void +_report_info ( + NATIVE_CHAR *module_name, + u32 line_number, + u32 component_id, + NATIVE_CHAR *message); + +void +_report_error ( + NATIVE_CHAR *module_name, + u32 line_number, + u32 component_id, + NATIVE_CHAR *message); + +void +_report_warning ( + NATIVE_CHAR *module_name, + u32 line_number, + u32 component_id, + NATIVE_CHAR *message); + +void +acpi_cm_dump_buffer ( + u8 *buffer, + u32 count, + u32 display, + u32 component_id); + + +/* + * Acpi_cm_delete - Object deletion + */ + +void +acpi_cm_delete_internal_obj ( + ACPI_OPERAND_OBJECT *object); + +void +acpi_cm_delete_internal_package_object ( + ACPI_OPERAND_OBJECT *object); + +void +acpi_cm_delete_internal_simple_object ( + ACPI_OPERAND_OBJECT *object); + +ACPI_STATUS +acpi_cm_delete_internal_object_list ( + ACPI_OPERAND_OBJECT **obj_list); + + +/* + * Acpi_cm_eval - object evaluation + */ + +/* Method name strings */ + +#define METHOD_NAME__HID "_HID" +#define METHOD_NAME__UID "_UID" +#define METHOD_NAME__ADR "_ADR" +#define METHOD_NAME__STA "_STA" +#define METHOD_NAME__REG "_REG" +#define METHOD_NAME__SEG "_SEG" +#define METHOD_NAME__BBN "_BBN" + + +ACPI_STATUS +acpi_cm_evaluate_numeric_object ( + NATIVE_CHAR *method_name, + ACPI_NAMESPACE_NODE *device_node, + u32 *address); + +ACPI_STATUS +acpi_cm_execute_HID ( + ACPI_NAMESPACE_NODE *device_node, + DEVICE_ID *hid); + +ACPI_STATUS +acpi_cm_execute_STA ( + ACPI_NAMESPACE_NODE *device_node, + u32 *status_flags); + +ACPI_STATUS +acpi_cm_execute_UID ( + ACPI_NAMESPACE_NODE *device_node, + DEVICE_ID *uid); + + +/* + * Acpi_cm_error - exception interfaces + */ + +NATIVE_CHAR * +acpi_cm_format_exception ( + ACPI_STATUS status); + + +/* + * Acpi_cm_mutex - mutual exclusion interfaces + */ + +ACPI_STATUS +acpi_cm_mutex_initialize ( + void); + +void +acpi_cm_mutex_terminate ( + void); + +ACPI_STATUS +acpi_cm_create_mutex ( + ACPI_MUTEX_HANDLE mutex_id); + +ACPI_STATUS +acpi_cm_delete_mutex ( + ACPI_MUTEX_HANDLE mutex_id); + +ACPI_STATUS +acpi_cm_acquire_mutex ( + ACPI_MUTEX_HANDLE mutex_id); + +ACPI_STATUS +acpi_cm_release_mutex ( + ACPI_MUTEX_HANDLE mutex_id); + + +/* + * Acpi_cm_object - internal object create/delete/cache routines + */ + +void * +_cm_allocate_object_desc ( + NATIVE_CHAR *module_name, + u32 line_number, + u32 component_id); + +#define acpi_cm_create_internal_object(t) _cm_create_internal_object(_THIS_MODULE,__LINE__,_COMPONENT,t) +#define acpi_cm_allocate_object_desc() _cm_allocate_object_desc(_THIS_MODULE,__LINE__,_COMPONENT) + +void +acpi_cm_delete_object_desc ( + ACPI_OPERAND_OBJECT *object); + +u8 +acpi_cm_valid_internal_object ( + void *object); + + +/* + * Acpi_cm_ref_cnt - Object reference count management + */ + +void +acpi_cm_add_reference ( + ACPI_OPERAND_OBJECT *object); + +void +acpi_cm_remove_reference ( + ACPI_OPERAND_OBJECT *object); + +/* + * Acpi_cm_size - Object size routines + */ + +ACPI_STATUS +acpi_cm_get_simple_object_size ( + ACPI_OPERAND_OBJECT *obj, + u32 *obj_length); + +ACPI_STATUS +acpi_cm_get_package_object_size ( + ACPI_OPERAND_OBJECT *obj, + u32 *obj_length); + +ACPI_STATUS +acpi_cm_get_object_size( + ACPI_OPERAND_OBJECT *obj, + u32 *obj_length); + + +/* + * Acpi_cm_state - Generic state creation/cache routines + */ + +void +acpi_cm_push_generic_state ( + ACPI_GENERIC_STATE **list_head, + ACPI_GENERIC_STATE *state); + +ACPI_GENERIC_STATE * +acpi_cm_pop_generic_state ( + ACPI_GENERIC_STATE **list_head); + + +ACPI_GENERIC_STATE * +acpi_cm_create_generic_state ( + void); + +ACPI_GENERIC_STATE * +acpi_cm_create_update_state ( + ACPI_OPERAND_OBJECT *object, + u16 action); + +ACPI_STATUS +acpi_cm_create_update_state_and_push ( + ACPI_OPERAND_OBJECT *object, + u16 action, + ACPI_GENERIC_STATE **state_list); + +ACPI_GENERIC_STATE * +acpi_cm_create_control_state ( + void); + +void +acpi_cm_delete_generic_state ( + ACPI_GENERIC_STATE *state); + +void +acpi_cm_delete_generic_state_cache ( + void); + +void +acpi_cm_delete_object_cache ( + void); + +/* + * Acpi_cmutils + */ + +u8 +acpi_cm_valid_acpi_name ( + u32 name); + +u8 +acpi_cm_valid_acpi_character ( + NATIVE_CHAR character); + + +/* + * Memory allocation functions and related macros. + * Macros that expand to include filename and line number + */ + +void * +_cm_allocate ( + u32 size, + u32 component, + NATIVE_CHAR *module, + u32 line); + +void * +_cm_callocate ( + u32 size, + u32 component, + NATIVE_CHAR *module, + u32 line); + +void +_cm_free ( + void *address, + u32 component, + NATIVE_CHAR *module, + u32 line); + +void +acpi_cm_init_static_object ( + ACPI_OPERAND_OBJECT *obj_desc); + +#define acpi_cm_allocate(a) _cm_allocate(a,_COMPONENT,_THIS_MODULE,__LINE__) +#define acpi_cm_callocate(a) _cm_callocate(a, _COMPONENT,_THIS_MODULE,__LINE__) +#define acpi_cm_free(a) _cm_free(a,_COMPONENT,_THIS_MODULE,__LINE__) + +#ifndef ACPI_DEBUG + +#define acpi_cm_add_element_to_alloc_list(a,b,c,d,e,f) +#define acpi_cm_delete_element_from_alloc_list(a,b,c,d) +#define acpi_cm_dump_current_allocations(a,b) +#define acpi_cm_dump_allocation_info() + +#define DECREMENT_OBJECT_METRICS(a) +#define INCREMENT_OBJECT_METRICS(a) +#define INITIALIZE_ALLOCATION_METRICS() +#define DECREMENT_NAME_TABLE_METRICS(a) +#define INCREMENT_NAME_TABLE_METRICS(a) + +#else + +#define INITIALIZE_ALLOCATION_METRICS() \ + acpi_gbl_current_object_count = 0; \ + acpi_gbl_current_object_size = 0; \ + acpi_gbl_running_object_count = 0; \ + acpi_gbl_running_object_size = 0; \ + acpi_gbl_max_concurrent_object_count = 0; \ + acpi_gbl_max_concurrent_object_size = 0; \ + acpi_gbl_current_alloc_size = 0; \ + acpi_gbl_current_alloc_count = 0; \ + acpi_gbl_running_alloc_size = 0; \ + acpi_gbl_running_alloc_count = 0; \ + acpi_gbl_max_concurrent_alloc_size = 0; \ + acpi_gbl_max_concurrent_alloc_count = 0; \ + acpi_gbl_current_node_count = 0; \ + acpi_gbl_current_node_size = 0; \ + acpi_gbl_max_concurrent_node_count = 0 + + +#define DECREMENT_OBJECT_METRICS(a) \ + acpi_gbl_current_object_count--; \ + acpi_gbl_current_object_size -= a + +#define INCREMENT_OBJECT_METRICS(a) \ + acpi_gbl_current_object_count++; \ + acpi_gbl_running_object_count++; \ + if (acpi_gbl_max_concurrent_object_count < acpi_gbl_current_object_count) \ + { \ + acpi_gbl_max_concurrent_object_count = acpi_gbl_current_object_count; \ + } \ + acpi_gbl_running_object_size += a; \ + acpi_gbl_current_object_size += a; \ + if (acpi_gbl_max_concurrent_object_size < acpi_gbl_current_object_size) \ + { \ + acpi_gbl_max_concurrent_object_size = acpi_gbl_current_object_size; \ + } + +#define DECREMENT_NAME_TABLE_METRICS(a) \ + acpi_gbl_current_node_count--; \ + acpi_gbl_current_node_size -= (a) + +#define INCREMENT_NAME_TABLE_METRICS(a) \ + acpi_gbl_current_node_count++; \ + acpi_gbl_current_node_size+= (a); \ + if (acpi_gbl_max_concurrent_node_count < acpi_gbl_current_node_count) \ + { \ + acpi_gbl_max_concurrent_node_count = acpi_gbl_current_node_count; \ + } \ + + +void +acpi_cm_dump_allocation_info ( + void); + +void +acpi_cm_dump_current_allocations ( + u32 component, + NATIVE_CHAR *module); + +#endif + + +#endif /* _ACCOMMON_H */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/include/acconfig.h linux/drivers/acpi/include/acconfig.h --- v2.4.0-test8/linux/drivers/acpi/include/acconfig.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/acpi/include/acconfig.h Fri Sep 15 14:30:30 2000 @@ -0,0 +1,186 @@ +/****************************************************************************** + * + * Name: acconfig.h - Global configuration constants + * $Revision: 42 $ + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 R. Byron Moore + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _ACCONFIG_H +#define _ACCONFIG_H + + +/****************************************************************************** + * + * Compile-time options + * + *****************************************************************************/ + +/* + * ACPI_DEBUG - This switch enables all the debug facilities of the ACPI + * subsystem. This includes the DEBUG_PRINT output statements + * When disabled, all DEBUG_PRINT statements are compiled out. + * + * ACPI_APPLICATION - Use this switch if the subsystem is going to be run + * at the application level. + * + */ + + +/****************************************************************************** + * + * Subsystem Constants + * + *****************************************************************************/ + + +/* Version string */ + +#define ACPI_CA_VERSION __DATE__ + +/* Name of host operating system (returned by the _OS_ namespace object) */ + +#ifdef _LINUX +#define ACPI_OS_NAME "Linux" +#else +#define ACPI_OS_NAME "Intel ACPI/CA Core Subsystem" +#endif + + +/* + * How and when control methods will be parsed + * The default action is to parse all methods at table load time to verify them, but delete the parse trees + * to conserve memory. Methods are parsed just in time before execution and the parse tree is deleted + * when execution completes. + */ +#define METHOD_PARSE_AT_INIT 0x0 /* Parse at table init, never delete the method parse tree */ +#define METHOD_PARSE_JUST_IN_TIME 0x1 /* Parse only when a method is invoked */ +#define METHOD_DELETE_AT_COMPLETION 0x2 /* Delete parse tree on method completion */ + +/* Default parsing configuration */ + +#define METHOD_PARSE_CONFIGURATION (METHOD_PARSE_JUST_IN_TIME | METHOD_DELETE_AT_COMPLETION) + + +/* Maximum objects in the various object caches */ + +#define MAX_STATE_CACHE_DEPTH 64 /* State objects for stacks */ +#define MAX_PARSE_CACHE_DEPTH 96 /* Parse tree objects */ +#define MAX_EXTPARSE_CACHE_DEPTH 64 /* Parse tree objects */ +#define MAX_OBJECT_CACHE_DEPTH 64 /* Interpreter operand objects */ +#define MAX_WALK_CACHE_DEPTH 2 /* Objects for parse tree walks (method execution) */ + +/* + * Name_space Table size + * + * All tables are the same size to simplify the implementation. + * Tables may be extended by allocating additional tables that + * are in turn linked together to form a chain of tables. + */ + +#define NS_TABLE_SIZE 4 + +/* String size constants */ + +#define MAX_STRING_LENGTH 512 +#define PATHNAME_MAX 256 /* A full namespace pathname */ + + +/* Maximum count for a semaphore object */ + +#define MAX_SEMAPHORE_COUNT 256 + + +/* Max reference count (for debug only) */ + +#define MAX_REFERENCE_COUNT 0x200 + + +/* Size of cached memory mapping for system memory operation region */ + +#define SYSMEM_REGION_WINDOW_SIZE 4096 + + +/* + * Debugger threading model + * Use single threaded if the entire subsystem is contained in an application + * Use multiple threaded when the the subsystem is running in the kernel. + * + * By default the model is single threaded if ACPI_APPLICATION is set, + * multi-threaded if ACPI_APPLICATION is not set. + */ + +#define DEBUGGER_SINGLE_THREADED 0 +#define DEBUGGER_MULTI_THREADED 1 + +#ifdef ACPI_APPLICATION +#define DEBUGGER_THREADING DEBUGGER_SINGLE_THREADED + +#else +#define DEBUGGER_THREADING DEBUGGER_MULTI_THREADED +#endif + + +/****************************************************************************** + * + * ACPI Specification constants (Do not change unless the specification changes) + * + *****************************************************************************/ + +/* + * Method info (in WALK_STATE), containing local variables and argumetns + */ + +#define MTH_NUM_LOCALS 8 +#define MTH_MAX_LOCAL 7 + +#define MTH_NUM_ARGS 7 +#define MTH_MAX_ARG 6 + +/* + * Operand Stack (in WALK_STATE), Must be large enough to contain MTH_MAX_ARG + */ + +#define OBJ_NUM_OPERANDS 8 +#define OBJ_MAX_OPERAND 7 + +/* Names within the namespace are 4 bytes long */ + +#define ACPI_NAME_SIZE 4 +#define PATH_SEGMENT_LENGTH 5 /* 4 chars for name + 1 s8 for separator */ +#define PATH_SEPARATOR '.' + + +/* Constants used in searching for the RSDP in low memory */ + +#define LO_RSDP_WINDOW_BASE (void *) 0 +#define HI_RSDP_WINDOW_BASE (void *) 0xE0000 +#define LO_RSDP_WINDOW_SIZE 0x400 +#define HI_RSDP_WINDOW_SIZE 0x20000 +#define RSDP_SCAN_STEP 16 + + +/* Maximum nesting of package objects */ + +#define MAX_PACKAGE_DEPTH 16 + + +#endif /* _ACCONFIG_H */ + diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/include/acdebug.h linux/drivers/acpi/include/acdebug.h --- v2.4.0-test8/linux/drivers/acpi/include/acdebug.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/acpi/include/acdebug.h Fri Sep 15 14:30:30 2000 @@ -0,0 +1,396 @@ +/****************************************************************************** + * + * Name: acdebug.h - ACPI/AML debugger + * $Revision: 35 $ + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 R. Byron Moore + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __ACDEBUG_H__ +#define __ACDEBUG_H__ + + +#define DB_MAX_ARGS 8 /* Must be max method args + 1 */ + +#define DB_COMMAND_PROMPT '-' +#define DB_EXECUTE_PROMPT '%' + + +extern int optind; +extern NATIVE_CHAR *optarg; +extern u8 *aml_ptr; +extern u32 acpi_aml_length; + +extern u8 opt_tables; +extern u8 opt_disasm; +extern u8 opt_stats; +extern u8 opt_parse_jit; +extern u8 opt_verbose; + + +extern NATIVE_CHAR *args[DB_MAX_ARGS]; +extern NATIVE_CHAR line_buf[80]; +extern NATIVE_CHAR scope_buf[40]; +extern NATIVE_CHAR debug_filename[40]; +extern u8 output_to_file; +extern NATIVE_CHAR *buffer; +extern NATIVE_CHAR *filename; +extern NATIVE_CHAR *INDENT_STRING; +extern u8 acpi_gbl_db_output_flags; +extern u32 acpi_gbl_db_debug_level; +extern u32 acpi_gbl_db_console_debug_level; + +extern u32 num_names; +extern u32 num_methods; +extern u32 num_regions; +extern u32 num_packages; +extern u32 num_aliases; +extern u32 num_devices; +extern u32 num_field_defs; +extern u32 num_thermal_zones; +extern u32 num_nodes; +extern u32 num_grammar_elements; +extern u32 num_method_elements ; +extern u32 num_mutexes; +extern u32 num_power_resources; +extern u32 num_bank_fields ; +extern u32 num_index_fields; +extern u32 num_events; + +extern u32 size_of_parse_tree; +extern u32 size_of_method_trees; +extern u32 size_of_nTes; +extern u32 size_of_acpi_objects; + + +#define BUFFER_SIZE 4196 + +#define DB_REDIRECTABLE_OUTPUT 0x01 +#define DB_CONSOLE_OUTPUT 0x02 +#define DB_DUPLICATE_OUTPUT 0x03 + + +typedef struct command_info +{ + NATIVE_CHAR *name; /* Command Name */ + u8 min_args; /* Minimum arguments required */ + +} COMMAND_INFO; + + +typedef struct argument_info +{ + NATIVE_CHAR *name; /* Argument Name */ + +} ARGUMENT_INFO; + + +#define PARAM_LIST(pl) pl + +#define DBTEST_OUTPUT_LEVEL(lvl) if (opt_verbose) + +#define VERBOSE_PRINT(fp) DBTEST_OUTPUT_LEVEL(lvl) {\ + acpi_os_printf PARAM_LIST(fp);} + +#define EX_NO_SINGLE_STEP 1 +#define EX_SINGLE_STEP 2 + + +/* Prototypes */ + + +/* + * dbapi - external debugger interfaces + */ + +int +acpi_db_initialize ( + void); + +ACPI_STATUS +acpi_db_single_step ( + ACPI_WALK_STATE *walk_state, + ACPI_PARSE_OBJECT *op, + u8 op_type); + + +/* + * dbcmds - debug commands and output routines + */ + + +void +acpi_db_display_table_info ( + NATIVE_CHAR *table_arg); + +void +acpi_db_unload_acpi_table ( + NATIVE_CHAR *table_arg, + NATIVE_CHAR *instance_arg); + +void +acpi_db_set_method_breakpoint ( + NATIVE_CHAR *location, + ACPI_WALK_STATE *walk_state, + ACPI_PARSE_OBJECT *op); + +void +acpi_db_set_method_call_breakpoint ( + ACPI_PARSE_OBJECT *op); + +void +acpi_db_disassemble_aml ( + NATIVE_CHAR *statements, + ACPI_PARSE_OBJECT *op); + +void +acpi_db_dump_namespace ( + NATIVE_CHAR *start_arg, + NATIVE_CHAR *depth_arg); + +void +acpi_db_dump_namespace_by_owner ( + NATIVE_CHAR *owner_arg, + NATIVE_CHAR *depth_arg); + +void +acpi_db_send_notify ( + NATIVE_CHAR *name, + u32 value); + +void +acpi_db_set_method_data ( + NATIVE_CHAR *type_arg, + NATIVE_CHAR *index_arg, + NATIVE_CHAR *value_arg); + +ACPI_STATUS +acpi_db_display_objects ( + NATIVE_CHAR *obj_type_arg, + NATIVE_CHAR *display_count_arg); + +ACPI_STATUS +acpi_db_find_name_in_namespace ( + NATIVE_CHAR *name_arg); + +void +acpi_db_set_scope ( + NATIVE_CHAR *name); + +void +acpi_db_find_references ( + NATIVE_CHAR *object_arg); + + +/* + * dbdisasm - AML disassembler + */ + +void +acpi_db_display_op ( + ACPI_PARSE_OBJECT *origin, + u32 num_opcodes); + +void +acpi_db_display_namestring ( + NATIVE_CHAR *name); + +void +acpi_db_display_path ( + ACPI_PARSE_OBJECT *op); + +void +acpi_db_display_opcode ( + ACPI_PARSE_OBJECT *op); + + +/* + * dbdisply - debug display commands + */ + + +void +acpi_db_display_method_info ( + ACPI_PARSE_OBJECT *op); + +void +acpi_db_decode_and_display_object ( + NATIVE_CHAR *target, + NATIVE_CHAR *output_type); + +void +acpi_db_display_result_object ( + ACPI_OPERAND_OBJECT *obj_desc, + ACPI_WALK_STATE *walk_state); + +ACPI_STATUS +acpi_db_display_all_methods ( + NATIVE_CHAR *display_count_arg); + +void +acpi_db_display_internal_object ( + ACPI_OPERAND_OBJECT *obj_desc, + ACPI_WALK_STATE *walk_state); + +void +acpi_db_display_arguments ( + void); + +void +acpi_db_display_locals ( + void); + +void +acpi_db_display_results ( + void); + +void +acpi_db_display_calling_tree ( + void); + +void +acpi_db_display_argument_object ( + ACPI_OPERAND_OBJECT *obj_desc, + ACPI_WALK_STATE *walk_state); + + +/* + * dbexec - debugger control method execution + */ + +void +acpi_db_execute ( + NATIVE_CHAR *name, + NATIVE_CHAR **args, + u32 flags); + +void +acpi_db_create_execution_threads ( + NATIVE_CHAR *num_threads_arg, + NATIVE_CHAR *num_loops_arg, + NATIVE_CHAR *method_name_arg); + + +/* + * dbfileio - Debugger file I/O commands + */ + +OBJECT_TYPE_INTERNAL +acpi_db_match_argument ( + NATIVE_CHAR *user_argument, + ARGUMENT_INFO *arguments); + + +void +acpi_db_close_debug_file ( + void); + +void +acpi_db_open_debug_file ( + NATIVE_CHAR *name); + +ACPI_STATUS +acpi_db_load_acpi_table ( + NATIVE_CHAR *filename); + + +/* + * dbhistry - debugger HISTORY command + */ + +void +acpi_db_add_to_history ( + NATIVE_CHAR *command_line); + +void +acpi_db_display_history (void); + +NATIVE_CHAR * +acpi_db_get_from_history ( + NATIVE_CHAR *command_num_arg); + + +/* + * dbinput - user front-end to the AML debugger + */ + +ACPI_STATUS +acpi_db_command_dispatch ( + NATIVE_CHAR *input_buffer, + ACPI_WALK_STATE *walk_state, + ACPI_PARSE_OBJECT *op); + +void +acpi_db_execute_thread ( + void *context); + +ACPI_STATUS +acpi_db_user_commands ( + NATIVE_CHAR prompt, + ACPI_PARSE_OBJECT *op); + + +/* + * dbstats - Generation and display of ACPI table statistics + */ + +void +acpi_db_generate_statistics ( + ACPI_PARSE_OBJECT *root, + u8 is_method); + + +ACPI_STATUS +acpi_db_display_statistics ( + NATIVE_CHAR *type_arg); + + +/* + * dbutils - AML debugger utilities + */ + +void +acpi_db_set_output_destination ( + u32 where); + +void +acpi_db_dump_buffer ( + u32 address); + +void +acpi_db_dump_object ( + ACPI_OBJECT *obj_desc, + u32 level); + +void +acpi_db_prep_namestring ( + NATIVE_CHAR *name); + + +ACPI_STATUS +acpi_db_second_pass_parse ( + ACPI_PARSE_OBJECT *root); + +ACPI_NAMESPACE_NODE * +acpi_db_local_ns_lookup ( + NATIVE_CHAR *name); + + +#endif /* __ACDEBUG_H__ */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/include/acdispat.h linux/drivers/acpi/include/acdispat.h --- v2.4.0-test8/linux/drivers/acpi/include/acdispat.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/acpi/include/acdispat.h Fri Sep 15 14:30:30 2000 @@ -0,0 +1,401 @@ +/****************************************************************************** + * + * Name: acdispat.h - dispatcher (parser to interpreter interface) + * $Revision: 29 $ + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 R. Byron Moore + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _ACDISPAT_H_ +#define _ACDISPAT_H_ + + +#define NAMEOF_LOCAL_NTE "__L0" +#define NAMEOF_ARG_NTE "__A0" + + +/* For Acpi_ds_method_data_set_value */ + +#define MTH_TYPE_LOCAL 0 +#define MTH_TYPE_ARG 1 + + +/* Common interfaces */ + +ACPI_STATUS +acpi_ds_obj_stack_push ( + void *object, + ACPI_WALK_STATE *walk_state); + +ACPI_STATUS +acpi_ds_obj_stack_pop ( + u32 pop_count, + ACPI_WALK_STATE *walk_state); + +void * +acpi_ds_obj_stack_get_value ( + u32 index, + ACPI_WALK_STATE *walk_state); + +ACPI_STATUS +acpi_ds_obj_stack_pop_object ( + ACPI_OPERAND_OBJECT **object, + ACPI_WALK_STATE *walk_state); + + +/* dsregion - Op region support */ + +ACPI_STATUS +acpi_ds_get_region_arguments ( + ACPI_OPERAND_OBJECT *rgn_desc); + + +/* dsctrl - Parser/Interpreter interface, control stack routines */ + + +ACPI_STATUS +acpi_ds_exec_begin_control_op ( + ACPI_WALK_STATE *walk_state, + ACPI_PARSE_OBJECT *op); + +ACPI_STATUS +acpi_ds_exec_end_control_op ( + ACPI_WALK_STATE *walk_state, + ACPI_PARSE_OBJECT *op); + + +/* dsexec - Parser/Interpreter interface, method execution callbacks */ + +ACPI_STATUS +acpi_ds_exec_begin_op ( + u16 opcode, + ACPI_PARSE_OBJECT *op, + ACPI_WALK_STATE *walk_state, + ACPI_PARSE_OBJECT **out_op); + +ACPI_STATUS +acpi_ds_exec_end_op ( + ACPI_WALK_STATE *state, + ACPI_PARSE_OBJECT *op); + + +/* dsfield - Parser/Interpreter interface for AML fields */ + + +ACPI_STATUS +acpi_ds_create_field ( + ACPI_PARSE_OBJECT *op, + ACPI_NAMESPACE_NODE *region_node, + ACPI_WALK_STATE *walk_state); + +ACPI_STATUS +acpi_ds_create_bank_field ( + ACPI_PARSE_OBJECT *op, + ACPI_NAMESPACE_NODE *region_node, + ACPI_WALK_STATE *walk_state); + +ACPI_STATUS +acpi_ds_create_index_field ( + ACPI_PARSE_OBJECT *op, + ACPI_HANDLE region_node, + ACPI_WALK_STATE *walk_state); + + +/* dsload - Parser/Interpreter interface, namespace load callbacks */ + +ACPI_STATUS +acpi_ds_load1_begin_op ( + u16 opcode, + ACPI_PARSE_OBJECT *op, + ACPI_WALK_STATE *walk_state, + ACPI_PARSE_OBJECT **out_op); + +ACPI_STATUS +acpi_ds_load1_end_op ( + ACPI_WALK_STATE *walk_state, + ACPI_PARSE_OBJECT *op); + +ACPI_STATUS +acpi_ds_load2_begin_op ( + u16 opcode, + ACPI_PARSE_OBJECT *op, + ACPI_WALK_STATE *walk_state, + ACPI_PARSE_OBJECT **out_op); + +ACPI_STATUS +acpi_ds_load2_end_op ( + ACPI_WALK_STATE *state, + ACPI_PARSE_OBJECT *op); + + +/* dsmthdat - method data (locals/args) */ + + +ACPI_STATUS +acpi_ds_method_data_get_entry ( + u32 type, + u32 index, + ACPI_WALK_STATE *walk_state, + ACPI_OPERAND_OBJECT ***node); + +ACPI_STATUS +acpi_ds_method_data_delete_all ( + ACPI_WALK_STATE *walk_state); + +u8 +acpi_ds_is_method_value ( + ACPI_OPERAND_OBJECT *obj_desc); + +OBJECT_TYPE_INTERNAL +acpi_ds_method_data_get_type ( + u32 type, + u32 index, + ACPI_WALK_STATE *walk_state); + +ACPI_STATUS +acpi_ds_method_data_get_value ( + u32 type, + u32 index, + ACPI_WALK_STATE *walk_state, + ACPI_OPERAND_OBJECT **dest_desc); + +ACPI_STATUS +acpi_ds_method_data_set_value ( + u32 type, + u32 index, + ACPI_OPERAND_OBJECT *src_desc, + ACPI_WALK_STATE *walk_state); + +ACPI_STATUS +acpi_ds_method_data_delete_value ( + u32 type, + u32 index, + ACPI_WALK_STATE *walk_state); + +ACPI_STATUS +acpi_ds_method_data_init_args ( + ACPI_OPERAND_OBJECT **params, + u32 max_param_count, + ACPI_WALK_STATE *walk_state); + +ACPI_NAMESPACE_NODE * +acpi_ds_method_data_get_nte ( + u32 type, + u32 index, + ACPI_WALK_STATE *walk_state); + +ACPI_STATUS +acpi_ds_method_data_init ( + ACPI_WALK_STATE *walk_state); + +ACPI_STATUS +acpi_ds_method_data_set_entry ( + u32 type, + u32 index, + ACPI_OPERAND_OBJECT *object, + ACPI_WALK_STATE *walk_state); + + +/* dsmethod - Parser/Interpreter interface - control method parsing */ + +ACPI_STATUS +acpi_ds_parse_method ( + ACPI_HANDLE obj_handle); + +ACPI_STATUS +acpi_ds_call_control_method ( + ACPI_WALK_LIST *walk_list, + ACPI_WALK_STATE *walk_state, + ACPI_PARSE_OBJECT *op); + +ACPI_STATUS +acpi_ds_restart_control_method ( + ACPI_WALK_STATE *walk_state, + ACPI_OPERAND_OBJECT *return_desc); + +ACPI_STATUS +acpi_ds_terminate_control_method ( + ACPI_WALK_STATE *walk_state); + +ACPI_STATUS +acpi_ds_begin_method_execution ( + ACPI_NAMESPACE_NODE *method_node, + ACPI_OPERAND_OBJECT *obj_desc); + + +/* dsobj - Parser/Interpreter interface - object initialization and conversion */ + +ACPI_STATUS +acpi_ds_init_one_object ( + ACPI_HANDLE obj_handle, + u32 level, + void *context, + void **return_value); + +ACPI_STATUS +acpi_ds_initialize_objects ( + ACPI_TABLE_DESC *table_desc, + ACPI_NAMESPACE_NODE *start_node); + +ACPI_STATUS +acpi_ds_build_internal_package_obj ( + ACPI_WALK_STATE *walk_state, + ACPI_PARSE_OBJECT *op, + ACPI_OPERAND_OBJECT **obj_desc); + +ACPI_STATUS +acpi_ds_build_internal_object ( + ACPI_WALK_STATE *walk_state, + ACPI_PARSE_OBJECT *op, + ACPI_OPERAND_OBJECT **obj_desc_ptr); + +ACPI_STATUS +acpi_ds_init_object_from_op ( + ACPI_WALK_STATE *walk_state, + ACPI_PARSE_OBJECT *op, + u16 opcode, + ACPI_OPERAND_OBJECT **obj_desc); + +ACPI_STATUS +acpi_ds_create_node ( + ACPI_WALK_STATE *walk_state, + ACPI_NAMESPACE_NODE *node, + ACPI_PARSE_OBJECT *op); + + +/* dsregn - Parser/Interpreter interface - Op Region parsing */ + +ACPI_STATUS +acpi_ds_eval_region_operands ( + ACPI_WALK_STATE *walk_state, + ACPI_PARSE_OBJECT *op); + +ACPI_STATUS +acpi_ds_initialize_region ( + ACPI_HANDLE obj_handle); + + +/* dsutils - Parser/Interpreter interface utility routines */ + +u8 +acpi_ds_is_result_used ( + ACPI_PARSE_OBJECT *op); + +void +acpi_ds_delete_result_if_not_used ( + ACPI_PARSE_OBJECT *op, + ACPI_OPERAND_OBJECT *result_obj, + ACPI_WALK_STATE *walk_state); + +ACPI_STATUS +acpi_ds_create_operand ( + ACPI_WALK_STATE *walk_state, + ACPI_PARSE_OBJECT *arg); + +ACPI_STATUS +acpi_ds_create_operands ( + ACPI_WALK_STATE *walk_state, + ACPI_PARSE_OBJECT *first_arg); + +ACPI_STATUS +acpi_ds_resolve_operands ( + ACPI_WALK_STATE *walk_state); + +OBJECT_TYPE_INTERNAL +acpi_ds_map_opcode_to_data_type ( + u16 opcode, + u32 *out_flags); + +OBJECT_TYPE_INTERNAL +acpi_ds_map_named_opcode_to_data_type ( + u16 opcode); + + +/* + * dswscope - Scope Stack manipulation + */ + +ACPI_STATUS +acpi_ds_scope_stack_push ( + ACPI_NAMESPACE_NODE *node, + OBJECT_TYPE_INTERNAL type, + ACPI_WALK_STATE *walk_state); + + +ACPI_STATUS +acpi_ds_scope_stack_pop ( + ACPI_WALK_STATE *walk_state); + +void +acpi_ds_scope_stack_clear ( + ACPI_WALK_STATE *walk_state); + + +/* Acpi_dswstate - parser WALK_STATE management routines */ + +ACPI_WALK_STATE * +acpi_ds_create_walk_state ( + ACPI_OWNER_ID owner_id, + ACPI_PARSE_OBJECT *origin, + ACPI_OPERAND_OBJECT *mth_desc, + ACPI_WALK_LIST *walk_list); + +ACPI_STATUS +acpi_ds_obj_stack_delete_all ( + ACPI_WALK_STATE *walk_state); + +ACPI_STATUS +acpi_ds_obj_stack_pop_and_delete ( + u32 pop_count, + ACPI_WALK_STATE *walk_state); + +void +acpi_ds_delete_walk_state ( + ACPI_WALK_STATE *walk_state); + +ACPI_WALK_STATE * +acpi_ds_pop_walk_state ( + ACPI_WALK_LIST *walk_list); + +ACPI_STATUS +acpi_ds_result_stack_pop ( + ACPI_OPERAND_OBJECT **object, + ACPI_WALK_STATE *walk_state); + +ACPI_STATUS +acpi_ds_result_stack_push ( + void *object, + ACPI_WALK_STATE *walk_state); + +ACPI_STATUS +acpi_ds_result_stack_clear ( + ACPI_WALK_STATE *walk_state); + +ACPI_WALK_STATE * +acpi_ds_get_current_walk_state ( + ACPI_WALK_LIST *walk_list); + +void +acpi_ds_delete_walk_state_cache ( + void); + + +#endif /* _ACDISPAT_H_ */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/include/acenv.h linux/drivers/acpi/include/acenv.h --- v2.4.0-test8/linux/drivers/acpi/include/acenv.h Thu Jul 6 01:22:24 2000 +++ linux/drivers/acpi/include/acenv.h Fri Sep 15 21:37:23 2000 @@ -1,7 +1,7 @@ - /****************************************************************************** * * Name: acenv.h - Generation environment specific items + * $Revision: 53 $ * *****************************************************************************/ @@ -75,10 +75,7 @@ #include #include #include - -/* Single threaded */ - -#define ACPI_APPLICATION +#include /* Use native Linux string library */ @@ -88,13 +85,27 @@ #define strtoul simple_strtoul +/* Linux clib doesn't to strupr, but we do. */ +char * +strupr(char *str); + +#else + +#ifdef _AED_EFI + +#include +#include +#include + #else + /* All other environments */ #define ACPI_USE_STANDARD_HEADERS #endif +#endif /****************************************************************************** @@ -117,6 +128,7 @@ #include #include #include +#include #endif /* ACPI_USE_STANDARD_HEADERS */ @@ -124,20 +136,20 @@ * We will be linking to the standard Clib functions */ -#define STRSTR(s1,s2) strstr((char *) (s1), (char *) (s2)) -#define STRUPR(s) strupr((char *) (s)) -#define STRLEN(s) strlen((char *) (s)) -#define STRCPY(d,s) strcpy((char *) (d), (char *) (s)) -#define STRNCPY(d,s,n) strncpy((char *) (d), (char *) (s), (n)) -#define STRNCMP(d,s,n) strncmp((char *) (d), (char *) (s), (n)) -#define STRCMP(d,s) strcmp((char *) (d), (char *) (s)) -#define STRCAT(d,s) strcat((char *) (d), (char *) (s)) -#define STRNCAT(d,s,n) strncat((char *) (d), (char *) (s), (n)) -#define STRTOUL(d,s,n) strtoul((char *) (d), (char **) (s), (n)) -#define MEMCPY(d,s,n) memcpy(d, s, (size_t) n) -#define MEMSET(d,s,n) memset(d, s, (size_t) n) -#define TOUPPER toupper -#define TOLOWER tolower +#define STRSTR(s1,s2) strstr((s1), (s2)) +#define STRUPR(s) strupr((s)) +#define STRLEN(s) strlen((s)) +#define STRCPY(d,s) strcpy((d), (s)) +#define STRNCPY(d,s,n) strncpy((d), (s), (n)) +#define STRNCMP(d,s,n) strncmp((d), (s), (n)) +#define STRCMP(d,s) strcmp((d), (s)) +#define STRCAT(d,s) strcat((d), (s)) +#define STRNCAT(d,s,n) strncat((d), (s), (n)) +#define STRTOUL(d,s,n) strtoul((d), (s), (n)) +#define MEMCPY(d,s,n) memcpy((d), (s), (n)) +#define MEMSET(d,s,n) memset((d), (s), (n)) +#define TOUPPER toupper +#define TOLOWER tolower /****************************************************************************** @@ -165,37 +177,35 @@ * Storage alignment properties */ -#define _AUPBND (sizeof(int) - 1) -#define _ADNBND (sizeof(int) - 1) +#define _AUPBND (sizeof(int) - 1) +#define _ADNBND (sizeof(int) - 1) /* * Variable argument list macro definitions */ -#define _bnd(X, bnd) (((sizeof(X)) + (bnd)) & (~(bnd))) -#define va_arg(ap, T) (*(T *)(((ap) += ((_bnd(T, _AUPBND))) \ - - (_bnd(T, _ADNBND))))) -#define va_end(ap) (void)0 -#define va_start(ap, A) (void) ((ap) = (((char *)&(A)) \ - + (_bnd(A, _AUPBND)))) +#define _bnd(X, bnd) (((sizeof(X)) + (bnd)) & (~(bnd))) +#define va_arg(ap, T) (*(T *)(((ap)+=((_bnd(T, _AUPBND)))-(_bnd(T,_ADNBND))))) +#define va_end(ap) (void)0 +#define va_start(ap, A) (void)((ap)=(((char*)&(A))+(_bnd(A,_AUPBND)))) #endif /* va_arg */ -#define STRSTR(s1,s2) acpi_cm_strstr ((char *) (s1), (char *) (s2)) -#define STRUPR(s) acpi_cm_strupr ((char *) (s)) -#define STRLEN(s) acpi_cm_strlen ((char *) (s)) -#define STRCPY(d,s) acpi_cm_strcpy ((char *) (d), (char *) (s)) -#define STRNCPY(d,s,n) acpi_cm_strncpy ((char *) (d), (char *) (s), (n)) -#define STRNCMP(d,s,n) acpi_cm_strncmp ((char *) (d), (char *) (s), (n)) -#define STRCMP(d,s) acpi_cm_strcmp ((char *) (d), (char *) (s)) -#define STRCAT(d,s) acpi_cm_strcat ((char *) (d), (char *) (s)) -#define STRNCAT(d,s,n) acpi_cm_strncat ((char *) (d), (char *) (s), (n)) -#define STRTOUL(d,s,n) acpi_cm_strtoul ((char *) (d), (char **) (s), (n)) -#define MEMCPY(d,s,n) acpi_cm_memcpy ((void *) (d), (const void *) (s), (n)) -#define MEMSET(d,v,n) acpi_cm_memset ((void *) (d), (v), (n)) -#define TOUPPER acpi_cm_to_upper -#define TOLOWER acpi_cm_to_lower +#define STRSTR(s1,s2) acpi_cm_strstr ((s1), (s2)) +#define STRUPR(s) acpi_cm_strupr ((s)) +#define STRLEN(s) acpi_cm_strlen ((s)) +#define STRCPY(d,s) acpi_cm_strcpy ((d), (s)) +#define STRNCPY(d,s,n) acpi_cm_strncpy ((d), (s), (n)) +#define STRNCMP(d,s,n) acpi_cm_strncmp ((d), (s), (n)) +#define STRCMP(d,s) acpi_cm_strcmp ((d), (s)) +#define STRCAT(d,s) acpi_cm_strcat ((d), (s)) +#define STRNCAT(d,s,n) acpi_cm_strncat ((d), (s), (n)) +#define STRTOUL(d,s,n) acpi_cm_strtoul ((d), (s),(n)) +#define MEMCPY(d,s,n) acpi_cm_memcpy ((d), (s), (n)) +#define MEMSET(d,v,n) acpi_cm_memset ((d), (v), (n)) +#define TOUPPER acpi_cm_to_upper +#define TOLOWER acpi_cm_to_lower #endif /* ACPI_USE_SYSTEM_CLIBRARY */ @@ -217,27 +227,90 @@ #ifdef __GNUC__ + #ifdef __ia64__ -#define _IA64 -#endif + +/* Single threaded */ +#define ACPI_APPLICATION #define ACPI_ASM_MACROS #define causeinterrupt(level) #define BREAKPOINT3 #define disable() __cli() #define enable() __sti() -#define halt() __asm__ __volatile__ ("sti; hlt":::"memory") #define wbinvd() +/*! [Begin] no source code translation */ +#include + +/* PAL_HALT[_LIGHT] */ +#define halt() ia64_pal_halt_light() + +/* PAL_HALT */ +#define safe_halt() ia64_pal_halt(1) + +#define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acq) \ + do { \ + __asm__ volatile ("1: ld4 r29=%1\n" \ + ";;\n" \ + "mov ar.ccv=r29\n" \ + "mov r2=r29\n" \ + "shr.u r30=r29,1\n" \ + "and r29=-4,r29\n" \ + ";;\n" \ + "add r29=2,r29\n" \ + "and r30=1,r30\n" \ + ";;\n" \ + "add r29=r29,r30\n" \ + ";;\n" \ + "cmpxchg4.acq r30=%1,r29,ar.ccv\n" \ + ";;\n" \ + "cmp.eq p6,p7=r2,r30\n" \ + "(p7) br.dpnt.few 1b\n" \ + "cmp.gt p8,p9=3,r29\n" \ + ";;\n" \ + "(p8) mov %0=-1\n" \ + "(p9) mov %0=r0\n" \ + :"=r"(Acq):"m" __atomic_fool_gcc((GLptr)):"r2","r29","r30","memory"); \ + } while (0) + +#define ACPI_RELEASE_GLOBAL_LOCK(GLptr, Acq) \ + do { \ + __asm__ volatile ("1: ld4 r29=%1\n" \ + ";;\n" \ + "mov ar.ccv=r29\n" \ + "mov r2=r29\n" \ + "and r29=-4,r29\n" \ + ";;\n" \ + "cmpxchg4.acq r30=%1,r29,ar.ccv\n" \ + ";;\n" \ + "cmp.eq p6,p7=r2,r30\n" \ + "(p7) br.dpnt.few 1b\n" \ + "and %0=1,r2\n" \ + ";;\n" \ + :"=r"(Acq):"m" __atomic_fool_gcc((GLptr)):"r2","r29","r30","memory"); \ + } while (0) +/*! [End] no source code translation !*/ + +#else /* DO IA32 */ + +#define ACPI_ASM_MACROS +#define causeinterrupt(level) +#define BREAKPOINT3 +#define disable() __cli() +#define enable() __sti() +#define halt() __asm__ __volatile__ ("sti; hlt":::"memory") +#define wbinvd() /*! [Begin] no source code translation * * A brief explanation as GNU inline assembly is a bit hairy * %0 is the output parameter in EAX ("=a") - * %1 and %2 are the input parameters in ECX ("c") and an immediate value ("i") respectively + * %1 and %2 are the input parameters in ECX ("c") + * and an immediate value ("i") respectively * All actual register references are preceded with "%%" as in "%%edx" * Immediate values in the assembly are preceded by "$" as in "$0x1" - * The final asm parameter is the non-output registers altered by the operation + * The final asm parameter are the operation altered non-output registers. */ #define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acq) \ do { \ @@ -267,12 +340,12 @@ } while(0) /*! [End] no source code translation !*/ +#endif /* IA 32 */ #endif /* __GNUC__ */ -#ifndef ACPI_ASM_MACROS - /* Unrecognized compiler, use defaults */ +#ifndef ACPI_ASM_MACROS #define ACPI_ASM_MACROS #define causeinterrupt(level) @@ -280,7 +353,6 @@ #define disable() #define enable() #define halt() - #define ACPI_ACQUIRE_GLOBAL_LOCK(Glptr, acq) #define ACPI_RELEASE_GLOBAL_LOCK(Glptr, acq) diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/include/acevents.h linux/drivers/acpi/include/acevents.h --- v2.4.0-test8/linux/drivers/acpi/include/acevents.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/acpi/include/acevents.h Fri Sep 15 14:30:30 2000 @@ -0,0 +1,210 @@ +/****************************************************************************** + * + * Name: acevents.h - Event subcomponent prototypes and defines + * $Revision: 56 $ + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 R. Byron Moore + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __ACEVENTS_H__ +#define __ACEVENTS_H__ + + +/* + * Acpi_evfixed - Fixed event handling + */ + +ACPI_STATUS +acpi_ev_fixed_event_initialize ( + void); + +u32 +acpi_ev_fixed_event_detect ( + void); + +u32 +acpi_ev_fixed_event_dispatch ( + u32 acpi_event); + + +/* + * Acpi_evglock - Global Lock support + */ + +ACPI_STATUS +acpi_ev_acquire_global_lock( + void); + +void +acpi_ev_release_global_lock( + void); + +ACPI_STATUS +acpi_ev_init_global_lock_handler ( + void); + + +/* + * Acpi_evgpe - GPE handling and dispatch + */ + +ACPI_STATUS +acpi_ev_gpe_initialize ( + void); + +ACPI_STATUS +acpi_ev_init_gpe_control_methods ( + void); + +u32 +acpi_ev_gpe_dispatch ( + u32 gpe_number); + +u32 +acpi_ev_gpe_detect ( + void); + + +/* + * Acpi_evnotify - Device Notify handling and dispatch + */ + +void +acpi_ev_notify_dispatch ( + ACPI_HANDLE device, + u32 notify_value); + + +/* + * Acpi_evregion - Address Space handling + */ + +ACPI_STATUS +acpi_ev_install_default_address_space_handlers ( + void); + +ACPI_STATUS +acpi_ev_address_space_dispatch ( + ACPI_OPERAND_OBJECT *region_obj, + u32 function, + u32 address, + u32 bit_width, + u32 *value); + + +ACPI_STATUS +acpi_ev_addr_handler_helper ( + ACPI_HANDLE obj_handle, + u32 level, + void *context, + void **return_value); + +void +acpi_ev_disassociate_region_from_handler( + ACPI_OPERAND_OBJECT *region_obj); + + +ACPI_STATUS +acpi_ev_associate_region_and_handler ( + ACPI_OPERAND_OBJECT *handler_obj, + ACPI_OPERAND_OBJECT *region_obj, + u8 acpi_ns_is_locked); + + +/* + * Acpi_evregini - Region initialization and setup + */ + +ACPI_STATUS +acpi_ev_system_memory_region_setup ( + ACPI_HANDLE handle, + u32 function, + void *handler_context, + void **region_context); + +ACPI_STATUS +acpi_ev_io_space_region_setup ( + ACPI_HANDLE handle, + u32 function, + void *handler_context, + void **region_context); + +ACPI_STATUS +acpi_ev_pci_config_region_setup ( + ACPI_HANDLE handle, + u32 function, + void *handler_context, + void **region_context); + +ACPI_STATUS +acpi_ev_default_region_setup ( + ACPI_HANDLE handle, + u32 function, + void *handler_context, + void **region_context); + +ACPI_STATUS +acpi_ev_initialize_region ( + ACPI_OPERAND_OBJECT *region_obj, + u8 acpi_ns_locked); + + +/* + * Evsci - SCI (System Control Interrupt) handling/dispatch + */ + +u32 +acpi_ev_install_sci_handler ( + void); + +ACPI_STATUS +acpi_ev_remove_sci_handler ( + void); + +u32 +acpi_ev_initialize_sCI ( + u32 program_sCI); + +void +acpi_ev_restore_acpi_state ( + void); + +void +acpi_ev_terminate ( + void); + + +/* Debug support */ + +#ifdef ACPI_DEBUG + +u32 +acpi_ev_sci_count ( + u32 acpi_event); + +#define DEBUG_INCREMENT_EVENT_COUNT(a) acpi_gbl_event_count[a]++; + +#else + +#define DEBUG_INCREMENT_EVENT_COUNT(a) +#endif + + +#endif /* __ACEVENTS_H__ */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/include/acexcep.h linux/drivers/acpi/include/acexcep.h --- v2.4.0-test8/linux/drivers/acpi/include/acexcep.h Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/include/acexcep.h Fri Sep 15 14:30:30 2000 @@ -1,7 +1,7 @@ - /****************************************************************************** * * Name: acexcep.h - Exception codes returned by the ACPI subsystem + * $Revision: 35 $ * *****************************************************************************/ @@ -31,65 +31,105 @@ * Exceptions returned by external ACPI interfaces */ +#define AE_CODE_ENVIRONMENTAL 0x0000 +#define AE_CODE_PROGRAMMER 0x1000 +#define AE_CODE_ACPI_TABLES 0x2000 +#define AE_CODE_AML 0x3000 +#define AE_CODE_CONTROL 0x4000 +#define AE_CODE_MASK 0xF000 + + #define ACPI_SUCCESS(a) (!(a)) #define ACPI_FAILURE(a) (a) + #define AE_OK (ACPI_STATUS) 0x0000 -#define AE_CTRL_RETURN_VALUE (ACPI_STATUS) 0x0001 -#define AE_CTRL_PENDING (ACPI_STATUS) 0x0002 -#define AE_CTRL_TERMINATE (ACPI_STATUS) 0x0003 -#define AE_CTRL_TRUE (ACPI_STATUS) 0x0004 -#define AE_CTRL_FALSE (ACPI_STATUS) 0x0005 -#define AE_CTRL_DEPTH (ACPI_STATUS) 0x0006 -#define AE_CTRL_RESERVED (ACPI_STATUS) 0x0007 -#define AE_AML_ERROR (ACPI_STATUS) 0x0008 -#define AE_AML_PARSE (ACPI_STATUS) 0x0009 -#define AE_AML_BAD_OPCODE (ACPI_STATUS) 0x000A -#define AE_AML_NO_OPERAND (ACPI_STATUS) 0x000B -#define AE_AML_OPERAND_TYPE (ACPI_STATUS) 0x000C -#define AE_AML_OPERAND_VALUE (ACPI_STATUS) 0x000D -#define AE_AML_UNINITIALIZED_LOCAL (ACPI_STATUS) 0x000E -#define AE_AML_UNINITIALIZED_ARG (ACPI_STATUS) 0x000F -#define AE_AML_UNINITIALIZED_ELEMENT (ACPI_STATUS) 0x0010 -#define AE_AML_NUMERIC_OVERFLOW (ACPI_STATUS) 0x0011 -#define AE_AML_REGION_LIMIT (ACPI_STATUS) 0x0012 -#define AE_AML_BUFFER_LIMIT (ACPI_STATUS) 0x0013 -#define AE_AML_PACKAGE_LIMIT (ACPI_STATUS) 0x0014 -#define AE_AML_DIVIDE_BY_ZERO (ACPI_STATUS) 0x0015 -#define AE_AML_BAD_NAME (ACPI_STATUS) 0x0016 -#define AE_AML_NAME_NOT_FOUND (ACPI_STATUS) 0x0017 -#define AE_AML_INTERNAL (ACPI_STATUS) 0x0018 -#define AE_AML_RESERVED (ACPI_STATUS) 0x0019 -#define AE_ERROR (ACPI_STATUS) 0x001A -#define AE_NO_ACPI_TABLES (ACPI_STATUS) 0x001B -#define AE_NO_NAMESPACE (ACPI_STATUS) 0x001C -#define AE_NO_MEMORY (ACPI_STATUS) 0x001D -#define AE_BAD_SIGNATURE (ACPI_STATUS) 0x001E -#define AE_BAD_HEADER (ACPI_STATUS) 0x001F -#define AE_BAD_CHECKSUM (ACPI_STATUS) 0x0020 -#define AE_BAD_PARAMETER (ACPI_STATUS) 0x0021 -#define AE_BAD_CHARACTER (ACPI_STATUS) 0x0022 -#define AE_BAD_PATHNAME (ACPI_STATUS) 0x0023 -#define AE_BAD_DATA (ACPI_STATUS) 0x0024 -#define AE_BAD_ADDRESS (ACPI_STATUS) 0x0025 -#define AE_NOT_FOUND (ACPI_STATUS) 0x0026 -#define AE_NOT_EXIST (ACPI_STATUS) 0x0027 -#define AE_EXIST (ACPI_STATUS) 0x0028 -#define AE_TYPE (ACPI_STATUS) 0x0029 -#define AE_NULL_OBJECT (ACPI_STATUS) 0x002A -#define AE_NULL_ENTRY (ACPI_STATUS) 0x002B -#define AE_BUFFER_OVERFLOW (ACPI_STATUS) 0x002C -#define AE_STACK_OVERFLOW (ACPI_STATUS) 0x002D -#define AE_STACK_UNDERFLOW (ACPI_STATUS) 0x002E -#define AE_NOT_IMPLEMENTED (ACPI_STATUS) 0x002F -#define AE_VERSION_MISMATCH (ACPI_STATUS) 0x0030 -#define AE_SUPPORT (ACPI_STATUS) 0x0031 -#define AE_SHARE (ACPI_STATUS) 0x0032 -#define AE_LIMIT (ACPI_STATUS) 0x0033 -#define AE_TIME (ACPI_STATUS) 0x0034 -#define AE_UNKNOWN_STATUS (ACPI_STATUS) 0x0035 -#define ACPI_MAX_STATUS (ACPI_STATUS) 0x0035 -#define ACPI_NUM_STATUS (ACPI_STATUS) 0x0036 + +/* + * Environmental exceptions + */ +#define AE_ERROR (ACPI_STATUS) (0x0001 | AE_CODE_ENVIRONMENTAL) +#define AE_NO_ACPI_TABLES (ACPI_STATUS) (0x0002 | AE_CODE_ENVIRONMENTAL) +#define AE_NO_NAMESPACE (ACPI_STATUS) (0x0003 | AE_CODE_ENVIRONMENTAL) +#define AE_NO_MEMORY (ACPI_STATUS) (0x0004 | AE_CODE_ENVIRONMENTAL) +#define AE_NOT_FOUND (ACPI_STATUS) (0x0005 | AE_CODE_ENVIRONMENTAL) +#define AE_NOT_EXIST (ACPI_STATUS) (0x0006 | AE_CODE_ENVIRONMENTAL) +#define AE_EXIST (ACPI_STATUS) (0x0007 | AE_CODE_ENVIRONMENTAL) +#define AE_TYPE (ACPI_STATUS) (0x0008 | AE_CODE_ENVIRONMENTAL) +#define AE_NULL_OBJECT (ACPI_STATUS) (0x0009 | AE_CODE_ENVIRONMENTAL) +#define AE_NULL_ENTRY (ACPI_STATUS) (0x000A | AE_CODE_ENVIRONMENTAL) +#define AE_BUFFER_OVERFLOW (ACPI_STATUS) (0x000B | AE_CODE_ENVIRONMENTAL) +#define AE_STACK_OVERFLOW (ACPI_STATUS) (0x000C | AE_CODE_ENVIRONMENTAL) +#define AE_STACK_UNDERFLOW (ACPI_STATUS) (0x000D | AE_CODE_ENVIRONMENTAL) +#define AE_NOT_IMPLEMENTED (ACPI_STATUS) (0x000E | AE_CODE_ENVIRONMENTAL) +#define AE_VERSION_MISMATCH (ACPI_STATUS) (0x000F | AE_CODE_ENVIRONMENTAL) +#define AE_SUPPORT (ACPI_STATUS) (0x0010 | AE_CODE_ENVIRONMENTAL) +#define AE_SHARE (ACPI_STATUS) (0x0011 | AE_CODE_ENVIRONMENTAL) +#define AE_LIMIT (ACPI_STATUS) (0x0012 | AE_CODE_ENVIRONMENTAL) +#define AE_TIME (ACPI_STATUS) (0x0013 | AE_CODE_ENVIRONMENTAL) +#define AE_UNKNOWN_STATUS (ACPI_STATUS) (0x0014 | AE_CODE_ENVIRONMENTAL) + +#define AE_CODE_ENV_MAX 0x0014 + +/* + * Programmer exceptions + */ +#define AE_BAD_PARAMETER (ACPI_STATUS) (0x0001 | AE_CODE_PROGRAMMER) +#define AE_BAD_CHARACTER (ACPI_STATUS) (0x0002 | AE_CODE_PROGRAMMER) +#define AE_BAD_PATHNAME (ACPI_STATUS) (0x0003 | AE_CODE_PROGRAMMER) +#define AE_BAD_DATA (ACPI_STATUS) (0x0004 | AE_CODE_PROGRAMMER) +#define AE_BAD_ADDRESS (ACPI_STATUS) (0x0005 | AE_CODE_PROGRAMMER) + +#define AE_CODE_PGM_MAX 0x0005 + + +/* + * Acpi table exceptions + */ +#define AE_BAD_SIGNATURE (ACPI_STATUS) (0x0001 | AE_CODE_ACPI_TABLES) +#define AE_BAD_HEADER (ACPI_STATUS) (0x0002 | AE_CODE_ACPI_TABLES) +#define AE_BAD_CHECKSUM (ACPI_STATUS) (0x0003 | AE_CODE_ACPI_TABLES) + +#define AE_CODE_TBL_MAX 0x0003 + + +/* + * AML exceptions. These are caused by problems with + * the actual AML byte stream + */ +#define AE_AML_ERROR (ACPI_STATUS) (0x0001 | AE_CODE_AML) +#define AE_AML_PARSE (ACPI_STATUS) (0x0002 | AE_CODE_AML) +#define AE_AML_BAD_OPCODE (ACPI_STATUS) (0x0003 | AE_CODE_AML) +#define AE_AML_NO_OPERAND (ACPI_STATUS) (0x0004 | AE_CODE_AML) +#define AE_AML_OPERAND_TYPE (ACPI_STATUS) (0x0005 | AE_CODE_AML) +#define AE_AML_OPERAND_VALUE (ACPI_STATUS) (0x0006 | AE_CODE_AML) +#define AE_AML_UNINITIALIZED_LOCAL (ACPI_STATUS) (0x0007 | AE_CODE_AML) +#define AE_AML_UNINITIALIZED_ARG (ACPI_STATUS) (0x0008 | AE_CODE_AML) +#define AE_AML_UNINITIALIZED_ELEMENT (ACPI_STATUS) (0x0009 | AE_CODE_AML) +#define AE_AML_NUMERIC_OVERFLOW (ACPI_STATUS) (0x000A | AE_CODE_AML) +#define AE_AML_REGION_LIMIT (ACPI_STATUS) (0x000B | AE_CODE_AML) +#define AE_AML_BUFFER_LIMIT (ACPI_STATUS) (0x000C | AE_CODE_AML) +#define AE_AML_PACKAGE_LIMIT (ACPI_STATUS) (0x000D | AE_CODE_AML) +#define AE_AML_DIVIDE_BY_ZERO (ACPI_STATUS) (0x000E | AE_CODE_AML) +#define AE_AML_BAD_NAME (ACPI_STATUS) (0x000F | AE_CODE_AML) +#define AE_AML_NAME_NOT_FOUND (ACPI_STATUS) (0x0010 | AE_CODE_AML) +#define AE_AML_INTERNAL (ACPI_STATUS) (0x0011 | AE_CODE_AML) + +#define AE_CODE_AML_MAX 0x0011 + +/* + * Internal exceptions used for control + */ +#define AE_CTRL_RETURN_VALUE (ACPI_STATUS) (0x0001 | AE_CODE_CONTROL) +#define AE_CTRL_PENDING (ACPI_STATUS) (0x0002 | AE_CODE_CONTROL) +#define AE_CTRL_TERMINATE (ACPI_STATUS) (0x0003 | AE_CODE_CONTROL) +#define AE_CTRL_TRUE (ACPI_STATUS) (0x0004 | AE_CODE_CONTROL) +#define AE_CTRL_FALSE (ACPI_STATUS) (0x0005 | AE_CODE_CONTROL) +#define AE_CTRL_DEPTH (ACPI_STATUS) (0x0006 | AE_CODE_CONTROL) +#define AE_CTRL_END (ACPI_STATUS) (0x0007 | AE_CODE_CONTROL) +#define AE_CTRL_TRANSFER (ACPI_STATUS) (0x0008 | AE_CODE_CONTROL) + +#define AE_CODE_CTRL_MAX 0x0008 #ifdef DEFINE_ACPI_GLOBALS @@ -98,46 +138,13 @@ * String versions of the exception codes above * These strings must match the corresponding defines exactly */ -static char *acpi_gbl_exception_names[] = +static NATIVE_CHAR *acpi_gbl_exception_names_env[] = { "AE_OK", - "AE_CTRL_RETURN_VALUE", - "AE_CTRL_PENDING", - "AE_CTRL_TERMINATE", - "AE_CTRL_TRUE", - "AE_CTRL_FALSE", - "AE_CTRL_DEPTH", - "AE_CTRL_RESERVED", - "AE_AML_ERROR", - "AE_AML_PARSE", - "AE_AML_BAD_OPCODE", - "AE_AML_NO_OPERAND", - "AE_AML_OPERAND_TYPE", - "AE_AML_OPERAND_VALUE", - "AE_AML_UNINITIALIZED_LOCAL", - "AE_AML_UNINITIALIZED_ARG", - "AE_AML_UNINITIALIZED_ELEMENT", - "AE_AML_NUMERIC_OVERFLOW", - "AE_AML_REGION_LIMIT", - "AE_AML_BUFFER_LIMIT", - "AE_AML_PACKAGE_LIMIT", - "AE_AML_DIVIDE_BY_ZERO", - "AE_AML_BAD_NAME", - "AE_AML_NAME_NOT_FOUND", - "AE_AML_INTERNAL", - "AE_AML_RESERVED", "AE_ERROR", "AE_NO_ACPI_TABLES", "AE_NO_NAMESPACE", "AE_NO_MEMORY", - "AE_BAD_SIGNATURE", - "AE_BAD_HEADER", - "AE_BAD_CHECKSUM", - "AE_BAD_PARAMETER", - "AE_BAD_CHARACTER", - "AE_BAD_PATHNAME", - "AE_BAD_DATA", - "AE_BAD_ADDRESS", "AE_NOT_FOUND", "AE_NOT_EXIST", "AE_EXIST", @@ -153,8 +160,58 @@ "AE_SHARE", "AE_LIMIT", "AE_TIME", - "AE_UNKNOWN_STATUS" + "AE_UNKNOWN_STATUS", +}; + +static NATIVE_CHAR *acpi_gbl_exception_names_pgm[] = +{ + "AE_BAD_PARAMETER", + "AE_BAD_CHARACTER", + "AE_BAD_PATHNAME", + "AE_BAD_DATA", + "AE_BAD_ADDRESS", +}; + +static NATIVE_CHAR *acpi_gbl_exception_names_tbl[] = +{ + "AE_BAD_SIGNATURE", + "AE_BAD_HEADER", + "AE_BAD_CHECKSUM", +}; + +static NATIVE_CHAR *acpi_gbl_exception_names_aml[] = +{ + "AE_AML_ERROR", + "AE_AML_PARSE", + "AE_AML_BAD_OPCODE", + "AE_AML_NO_OPERAND", + "AE_AML_OPERAND_TYPE", + "AE_AML_OPERAND_VALUE", + "AE_AML_UNINITIALIZED_LOCAL", + "AE_AML_UNINITIALIZED_ARG", + "AE_AML_UNINITIALIZED_ELEMENT", + "AE_AML_NUMERIC_OVERFLOW", + "AE_AML_REGION_LIMIT", + "AE_AML_BUFFER_LIMIT", + "AE_AML_PACKAGE_LIMIT", + "AE_AML_DIVIDE_BY_ZERO", + "AE_AML_BAD_NAME", + "AE_AML_NAME_NOT_FOUND", + "AE_AML_INTERNAL", +}; + +static NATIVE_CHAR *acpi_gbl_exception_names_ctrl[] = +{ + "AE_CTRL_RETURN_VALUE", + "AE_CTRL_PENDING", + "AE_CTRL_TERMINATE", + "AE_CTRL_TRUE", + "AE_CTRL_FALSE", + "AE_CTRL_DEPTH", + "AE_CTRL_END", + "AE_CTRL_TRANSFER", }; + #endif /* DEFINE_ACPI_GLOBALS */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/include/acglobal.h linux/drivers/acpi/include/acglobal.h --- v2.4.0-test8/linux/drivers/acpi/include/acglobal.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/acpi/include/acglobal.h Fri Sep 15 14:30:30 2000 @@ -0,0 +1,320 @@ +/****************************************************************************** + * + * Name: acglobal.h - Declarations for global variables + * $Revision: 84 $ + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 R. Byron Moore + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __ACGLOBAL_H__ +#define __ACGLOBAL_H__ + + +/* + * Ensure that the globals are actually defined only once. + * + * The use of these defines allows a single list of globals (here) in order + * to simplify maintenance of the code. + */ +#ifdef DEFINE_ACPI_GLOBALS +#define ACPI_EXTERN +#else +#define ACPI_EXTERN extern +#endif + + +extern NATIVE_CHAR *msg_acpi_error_break; + +/***************************************************************************** + * + * Debug support + * + ****************************************************************************/ + +/* Runtime configuration of debug print levels */ + +extern u32 acpi_dbg_level; +extern u32 acpi_dbg_layer; + + +/* Procedure nesting level for debug output */ + +extern u32 acpi_gbl_nesting_level; + + +/***************************************************************************** + * + * ACPI Table globals + * + ****************************************************************************/ + +/* + * Table pointers. + * Although these pointers are somewhat redundant with the global Acpi_table, + * they are convenient because they are typed pointers. + * + * These tables are single-table only; meaning that there can be at most one + * of each in the system. Each global points to the actual table. + * + */ +ACPI_EXTERN ROOT_SYSTEM_DESCRIPTOR_POINTER *acpi_gbl_RSDP; +ACPI_EXTERN ROOT_SYSTEM_DESCRIPTION_TABLE *acpi_gbl_RSDT; +ACPI_EXTERN FIRMWARE_ACPI_CONTROL_STRUCTURE *acpi_gbl_FACS; +ACPI_EXTERN FIXED_ACPI_DESCRIPTION_TABLE *acpi_gbl_FACP; +ACPI_EXTERN APIC_TABLE *acpi_gbl_APIC; +ACPI_EXTERN ACPI_TABLE_HEADER *acpi_gbl_DSDT; +ACPI_EXTERN ACPI_TABLE_HEADER *acpi_gbl_SBST; +/* + * Since there may be multiple SSDTs and PSDTS, a single pointer is not + * sufficient; Therefore, there isn't one! + */ + + +/* + * ACPI Table info arrays + */ +extern ACPI_TABLE_DESC acpi_gbl_acpi_tables[NUM_ACPI_TABLES]; +extern ACPI_TABLE_SUPPORT acpi_gbl_acpi_table_data[NUM_ACPI_TABLES]; + +/* + * Predefined mutex objects. This array contains the + * actual OS mutex handles, indexed by the local ACPI_MUTEX_HANDLEs. + * (The table maps local handles to the real OS handles) + */ +ACPI_EXTERN ACPI_MUTEX_INFO acpi_gbl_acpi_mutex_info [NUM_MTX]; +extern ACPI_INIT_DATA acpi_gbl_acpi_init_data; + + +/***************************************************************************** + * + * Miscellaneous globals + * + ****************************************************************************/ + + +ACPI_EXTERN u8 *acpi_gbl_gpe0enable_register_save; +ACPI_EXTERN u8 *acpi_gbl_gpe1_enable_register_save; +ACPI_EXTERN ACPI_WALK_STATE *acpi_gbl_breakpoint_walk; +ACPI_EXTERN ACPI_GENERIC_STATE *acpi_gbl_generic_state_cache; +ACPI_EXTERN ACPI_PARSE_OBJECT *acpi_gbl_parse_cache; +ACPI_EXTERN ACPI_PARSE2_OBJECT *acpi_gbl_ext_parse_cache; +ACPI_EXTERN ACPI_OPERAND_OBJECT *acpi_gbl_object_cache; +ACPI_EXTERN ACPI_WALK_STATE *acpi_gbl_walk_state_cache; +ACPI_EXTERN ACPI_HANDLE acpi_gbl_global_lock_semaphore; + + +ACPI_EXTERN u32 acpi_gbl_global_lock_thread_count; +ACPI_EXTERN u32 acpi_gbl_restore_acpi_chipset; +ACPI_EXTERN u32 acpi_gbl_original_mode; +ACPI_EXTERN u32 acpi_gbl_edge_level_save; +ACPI_EXTERN u32 acpi_gbl_irq_enable_save; +ACPI_EXTERN u32 acpi_gbl_rsdp_original_location; + +ACPI_EXTERN u32 acpi_gbl_state_cache_requests; +ACPI_EXTERN u32 acpi_gbl_state_cache_hits; +ACPI_EXTERN u32 acpi_gbl_parse_cache_requests; +ACPI_EXTERN u32 acpi_gbl_parse_cache_hits; +ACPI_EXTERN u32 acpi_gbl_ext_parse_cache_requests; +ACPI_EXTERN u32 acpi_gbl_ext_parse_cache_hits; +ACPI_EXTERN u32 acpi_gbl_object_cache_requests; +ACPI_EXTERN u32 acpi_gbl_object_cache_hits; +ACPI_EXTERN u32 acpi_gbl_walk_state_cache_requests; +ACPI_EXTERN u32 acpi_gbl_walk_state_cache_hits; +ACPI_EXTERN u32 acpi_gbl_ns_lookup_count; +ACPI_EXTERN u32 acpi_gbl_ps_find_count; + + +ACPI_EXTERN u16 acpi_gbl_generic_state_cache_depth; +ACPI_EXTERN u16 acpi_gbl_parse_cache_depth; +ACPI_EXTERN u16 acpi_gbl_ext_parse_cache_depth; +ACPI_EXTERN u16 acpi_gbl_object_cache_depth; +ACPI_EXTERN u16 acpi_gbl_walk_state_cache_depth; +ACPI_EXTERN u16 acpi_gbl_pm1_enable_register_save; +ACPI_EXTERN u16 acpi_gbl_next_table_owner_id; +ACPI_EXTERN u16 acpi_gbl_next_method_owner_id; + +ACPI_EXTERN u8 acpi_gbl_debugger_configuration; +ACPI_EXTERN u8 acpi_gbl_global_lock_acquired; +ACPI_EXTERN u8 acpi_gbl_global_lock_set; /* TBD: [Restructure] OBSOLETE?? */ +ACPI_EXTERN u8 acpi_gbl_step_to_next_call; +ACPI_EXTERN u8 acpi_gbl_acpi_hardware_present; + + +ACPI_EXTERN ACPI_OBJECT_NOTIFY_HANDLER acpi_gbl_drv_notify; +ACPI_EXTERN ACPI_OBJECT_NOTIFY_HANDLER acpi_gbl_sys_notify; + + +extern u8 acpi_gbl_shutdown; +extern u32 acpi_gbl_system_flags; +extern u32 acpi_gbl_startup_flags; + + +/***************************************************************************** + * + * Namespace globals + * + ****************************************************************************/ + +#define NUM_NS_TYPES INTERNAL_TYPE_INVALID+1 +#define NUM_PREDEFINED_NAMES 9 + + +ACPI_EXTERN ACPI_NAMESPACE_NODE acpi_gbl_root_node_struct; +ACPI_EXTERN ACPI_NAMESPACE_NODE *acpi_gbl_root_node; + +extern u8 acpi_gbl_ns_properties[NUM_NS_TYPES]; +extern PREDEFINED_NAMES acpi_gbl_pre_defined_names [NUM_PREDEFINED_NAMES]; + + +/* Used to detect memory leaks (DEBUG ONLY) */ + +#ifdef ACPI_DEBUG +ACPI_EXTERN ALLOCATION_INFO *acpi_gbl_head_alloc_ptr; +ACPI_EXTERN ALLOCATION_INFO *acpi_gbl_tail_alloc_ptr; +#endif + + +/***************************************************************************** + * + * Interpreter globals + * + ****************************************************************************/ + + +ACPI_EXTERN u32 acpi_gbl_when_to_parse_methods; +ACPI_EXTERN ACPI_WALK_LIST *acpi_gbl_current_walk_list; + +/* Base of AML block, and pointer to current location in it */ + +ACPI_EXTERN u8 *acpi_gbl_Pcode_base; +ACPI_EXTERN u8 *acpi_gbl_Pcode; + +/* + * Length of AML block, and remaining length of current package. + */ +ACPI_EXTERN u32 acpi_gbl_Pcode_block_len; +ACPI_EXTERN u32 acpi_gbl_Pcode_len; + +ACPI_EXTERN u32 acpi_gbl_buf_seq; /* Counts allocated Buffer descriptors */ +ACPI_EXTERN u32 acpi_gbl_node_err; /* Indicate if inc_error should be called */ + +/* + * Handle to the last method found - used during pass1 of load + */ +ACPI_EXTERN ACPI_HANDLE acpi_gbl_last_method; + +/* + * Table of Address Space handlers + */ + +ACPI_EXTERN ACPI_ADDRESS_SPACE_INFO acpi_gbl_address_spaces[ACPI_NUM_ADDRESS_SPACES]; + + +/* Control method single step flag */ + +ACPI_EXTERN u8 acpi_gbl_cm_single_step; + + +/***************************************************************************** + * + * Parser globals + * + ****************************************************************************/ + +ACPI_EXTERN ACPI_PARSE_OBJECT *acpi_gbl_parsed_namespace_root; + +extern ACPI_OPCODE_INFO acpi_gbl_aml_op_info[]; +extern u8 acpi_gbl_aml_op_info_index[256]; + + +/***************************************************************************** + * + * Hardware globals + * + ****************************************************************************/ + +extern ACPI_C_STATE_HANDLER acpi_hw_cx_handlers[MAX_CX_STATES]; +extern u32 acpi_hw_active_cx_state; + + +/***************************************************************************** + * + * Event globals + * + ****************************************************************************/ + +ACPI_EXTERN ACPI_FIXED_EVENT_INFO acpi_gbl_fixed_event_handlers[NUM_FIXED_EVENTS]; + +ACPI_EXTERN ACPI_HANDLE acpi_gbl_gpe_obj_handle; +ACPI_EXTERN u32 acpi_gbl_gpe_register_count; +ACPI_EXTERN ACPI_GPE_REGISTERS *acpi_gbl_gpe_registers; +ACPI_EXTERN ACPI_GPE_LEVEL_INFO *acpi_gbl_gpe_info; + +/* + * Gpe validation and translation table + * Indexed by the GPE number, returns GPE_INVALID if the GPE is not supported. + * Otherwise, returns a valid index into the global GPE table. + * + * This table is needed because the GPE numbers supported by block 1 do not + * have to be contiguous with the GPE numbers supported by block 0. + */ +ACPI_EXTERN u8 acpi_gbl_gpe_valid [NUM_GPE]; + +/* Acpi_event counter for debug only */ + +#ifdef ACPI_DEBUG +ACPI_EXTERN u32 acpi_gbl_event_count[NUM_FIXED_EVENTS]; +#endif + + +/***************************************************************************** + * + * Debugger globals + * + ****************************************************************************/ + +ACPI_EXTERN u8 acpi_gbl_method_executing; +ACPI_EXTERN u8 acpi_gbl_db_terminate_threads; + + +/* Memory allocation metrics - Debug Only! */ + +#ifdef ACPI_DEBUG + +ACPI_EXTERN u32 acpi_gbl_current_alloc_size; +ACPI_EXTERN u32 acpi_gbl_current_alloc_count; +ACPI_EXTERN u32 acpi_gbl_running_alloc_size; +ACPI_EXTERN u32 acpi_gbl_running_alloc_count; +ACPI_EXTERN u32 acpi_gbl_max_concurrent_alloc_size; +ACPI_EXTERN u32 acpi_gbl_max_concurrent_alloc_count; +ACPI_EXTERN u32 acpi_gbl_current_object_count; +ACPI_EXTERN u32 acpi_gbl_current_object_size; +ACPI_EXTERN u32 acpi_gbl_max_concurrent_object_count; +ACPI_EXTERN u32 acpi_gbl_max_concurrent_object_size; +ACPI_EXTERN u32 acpi_gbl_running_object_count; +ACPI_EXTERN u32 acpi_gbl_running_object_size; +ACPI_EXTERN u32 acpi_gbl_current_node_count; +ACPI_EXTERN u32 acpi_gbl_current_node_size; +ACPI_EXTERN u32 acpi_gbl_max_concurrent_node_count; + +#endif + + +#endif /* __ACGLOBAL_H__ */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/include/achware.h linux/drivers/acpi/include/achware.h --- v2.4.0-test8/linux/drivers/acpi/include/achware.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/acpi/include/achware.h Fri Sep 15 14:30:30 2000 @@ -0,0 +1,169 @@ +/****************************************************************************** + * + * Name: achware.h -- hardware specific interfaces + * $Revision: 41 $ + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 R. Byron Moore + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __ACHWARE_H__ +#define __ACHWARE_H__ + + +/* Prototypes */ + + +ACPI_STATUS +acpi_hw_initialize( + void); + +ACPI_STATUS +acpi_hw_shutdown( + void); + +ACPI_STATUS +acpi_hw_initialize_system_info( + void); + +ACPI_STATUS +acpi_hw_set_mode ( + u32 mode); + +u32 +acpi_hw_get_mode ( + void); + +u32 +acpi_hw_get_mode_capabilities ( + void); + +/* Register I/O Prototypes */ + +u32 +acpi_hw_register_access ( + NATIVE_UINT read_write, + u8 use_lock, + u32 register_id, ... /* DWORD Value */); + +void +acpi_hw_clear_acpi_status ( + void); + + +/* GPE support */ + +void +acpi_hw_enable_gpe ( + u32 gpe_index); + +void +acpi_hw_disable_gpe ( + u32 gpe_index); + +void +acpi_hw_clear_gpe ( + u32 gpe_index); + +void +acpi_hw_get_gpe_status ( + u32 gpe_number, + ACPI_EVENT_STATUS *event_status); + +/* Sleep Prototypes */ + +ACPI_STATUS +acpi_hw_obtain_sleep_type_register_data ( + u8 sleep_state, + u8 *slp_typ_a, + u8 *slp_typ_b); + + +/* Cx State Prototypes */ + +ACPI_STATUS +acpi_hw_enter_c1( + ACPI_IO_ADDRESS pblk_address, + u32 *pm_timer_ticks); + +ACPI_STATUS +acpi_hw_enter_c2( + ACPI_IO_ADDRESS pblk_address, + u32 *pm_timer_ticks); + +ACPI_STATUS +acpi_hw_enter_c3( + ACPI_IO_ADDRESS pblk_address, + u32 *pm_timer_ticks); + +ACPI_STATUS +acpi_hw_enter_cx ( + ACPI_IO_ADDRESS pblk_address, + u32 *pm_timer_ticks); + +ACPI_STATUS +acpi_hw_set_cx ( + u32 cx_state); + +ACPI_STATUS +acpi_hw_get_cx_info ( + u32 cx_states[]); + + +/* Throttling Prototypes */ + +void +acpi_hw_enable_throttling ( + ACPI_IO_ADDRESS pblk_address); + +void +acpi_hw_disable_throttling ( + ACPI_IO_ADDRESS pblk_address); + +u32 +acpi_hw_get_duty_cycle ( + u8 duty_offset, + ACPI_IO_ADDRESS pblk_address, + u32 num_throttle_states); + +void +acpi_hw_program_duty_cycle ( + u8 duty_offset, + u32 duty_cycle, + ACPI_IO_ADDRESS pblk_address, + u32 num_throttle_states); + +NATIVE_UINT +acpi_hw_local_pow ( + NATIVE_UINT x, + NATIVE_UINT y); + + +/* ACPI Timer prototypes */ + +u32 +acpi_hw_pmt_ticks ( + void); + +u32 +acpi_hw_pmt_resolution ( + void); + + +#endif /* __ACHWARE_H__ */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/include/acinterp.h linux/drivers/acpi/include/acinterp.h --- v2.4.0-test8/linux/drivers/acpi/include/acinterp.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/acpi/include/acinterp.h Fri Sep 15 14:30:30 2000 @@ -0,0 +1,526 @@ +/****************************************************************************** + * + * Name: acinterp.h - Interpreter subcomponent prototypes and defines + * $Revision: 79 $ + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 R. Byron Moore + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __ACINTERP_H__ +#define __ACINTERP_H__ + + +#define WALK_OPERANDS &(walk_state->operands [walk_state->num_operands -1]) + + +/* Interpreter constants */ + +#define AML_END_OF_BLOCK -1 +#define PUSH_PKG_LENGTH 1 +#define DO_NOT_PUSH_PKG_LENGTH 0 + + +#define STACK_TOP 0 +#define STACK_BOTTOM (u32) -1 + +/* Constants for global "When_to_parse_methods" */ + +#define METHOD_PARSE_AT_INIT 0x0 +#define METHOD_PARSE_JUST_IN_TIME 0x1 +#define METHOD_DELETE_AT_COMPLETION 0x2 + + +ACPI_STATUS +acpi_aml_resolve_operands ( + u16 opcode, + ACPI_OPERAND_OBJECT **stack_ptr, + ACPI_WALK_STATE *walk_state); + + +/* + * amxface - External interpreter interfaces + */ + +ACPI_STATUS +acpi_aml_load_table ( + ACPI_TABLE_TYPE table_id); + +ACPI_STATUS +acpi_aml_execute_method ( + ACPI_NAMESPACE_NODE *method_node, + ACPI_OPERAND_OBJECT **params, + ACPI_OPERAND_OBJECT **return_obj_desc); + + +/* + * amfield - ACPI AML (p-code) execution - field manipulation + */ + + +ACPI_STATUS +acpi_aml_read_field ( + ACPI_OPERAND_OBJECT *obj_desc, + void *buffer, + u32 buffer_length, + u32 byte_length, + u32 datum_length, + u32 bit_granularity, + u32 byte_granularity); + +ACPI_STATUS +acpi_aml_write_field ( + ACPI_OPERAND_OBJECT *obj_desc, + void *buffer, + u32 buffer_length, + u32 byte_length, + u32 datum_length, + u32 bit_granularity, + u32 byte_granularity); + +ACPI_STATUS +acpi_aml_setup_field ( + ACPI_OPERAND_OBJECT *obj_desc, + ACPI_OPERAND_OBJECT *rgn_desc, + u32 field_bit_width); + +ACPI_STATUS +acpi_aml_read_field_data ( + ACPI_OPERAND_OBJECT *obj_desc, + u32 field_byte_offset, + u32 field_bit_width, + u32 *value); + +ACPI_STATUS +acpi_aml_access_named_field ( + u32 mode, + ACPI_HANDLE named_field, + void *buffer, + u32 length); + +/* + * ammisc - ACPI AML (p-code) execution - specific opcodes + */ + +ACPI_STATUS +acpi_aml_exec_create_field ( + u16 opcode, + ACPI_WALK_STATE *walk_state); + +ACPI_STATUS +acpi_aml_exec_reconfiguration ( + u16 opcode, + ACPI_WALK_STATE *walk_state); + +ACPI_STATUS +acpi_aml_exec_fatal ( + ACPI_WALK_STATE *walk_state); + +ACPI_STATUS +acpi_aml_exec_index ( + ACPI_WALK_STATE *walk_state, + ACPI_OPERAND_OBJECT **return_desc); + +ACPI_STATUS +acpi_aml_exec_match ( + ACPI_WALK_STATE *walk_state, + ACPI_OPERAND_OBJECT **return_desc); + +ACPI_STATUS +acpi_aml_exec_create_mutex ( + ACPI_WALK_STATE *walk_state); + +ACPI_STATUS +acpi_aml_exec_create_processor ( + ACPI_PARSE_OBJECT *op, + ACPI_HANDLE processor_nTE); + +ACPI_STATUS +acpi_aml_exec_create_power_resource ( + ACPI_PARSE_OBJECT *op, + ACPI_HANDLE processor_nTE); + +ACPI_STATUS +acpi_aml_exec_create_region ( + u8 *aml_ptr, + u32 acpi_aml_length, + u32 region_space, + ACPI_WALK_STATE *walk_state); + +ACPI_STATUS +acpi_aml_exec_create_event ( + ACPI_WALK_STATE *walk_state); + +ACPI_STATUS +acpi_aml_exec_create_alias ( + ACPI_WALK_STATE *walk_state); + +ACPI_STATUS +acpi_aml_exec_create_method ( + u8 *aml_ptr, + u32 acpi_aml_length, + u32 method_flags, + ACPI_HANDLE method); + + +/* + * amprep - ACPI AML (p-code) execution - prep utilities + */ + +ACPI_STATUS +acpi_aml_prep_def_field_value ( + ACPI_NAMESPACE_NODE *node, + ACPI_HANDLE region, + u8 field_flags, + u8 field_attribute, + u32 field_position, + u32 field_length); + +ACPI_STATUS +acpi_aml_prep_bank_field_value ( + ACPI_NAMESPACE_NODE *node, + ACPI_HANDLE region, + ACPI_HANDLE bank_reg, + u32 bank_val, + u8 field_flags, + u8 field_attribute, + u32 field_position, + u32 field_length); + +ACPI_STATUS +acpi_aml_prep_index_field_value ( + ACPI_NAMESPACE_NODE *node, + ACPI_HANDLE index_reg, + ACPI_HANDLE data_reg, + u8 field_flags, + u8 field_attribute, + u32 field_position, + u32 field_length); + + +/* + * amsystem - Interface to OS services + */ + +u16 +acpi_aml_system_thread_id ( + void); + +ACPI_STATUS +acpi_aml_system_do_notify_op ( + ACPI_OPERAND_OBJECT *value, + ACPI_OPERAND_OBJECT *obj_desc); + +void +acpi_aml_system_do_suspend( + u32 time); + +void +acpi_aml_system_do_stall ( + u32 time); + +ACPI_STATUS +acpi_aml_system_acquire_mutex( + ACPI_OPERAND_OBJECT *time, + ACPI_OPERAND_OBJECT *obj_desc); + +ACPI_STATUS +acpi_aml_system_release_mutex( + ACPI_OPERAND_OBJECT *obj_desc); + +ACPI_STATUS +acpi_aml_system_signal_event( + ACPI_OPERAND_OBJECT *obj_desc); + +ACPI_STATUS +acpi_aml_system_wait_event( + ACPI_OPERAND_OBJECT *time, + ACPI_OPERAND_OBJECT *obj_desc); + +ACPI_STATUS +acpi_aml_system_reset_event( + ACPI_OPERAND_OBJECT *obj_desc); + +ACPI_STATUS +acpi_aml_system_wait_semaphore ( + ACPI_HANDLE semaphore, + u32 timeout); + + +/* + * ammonadic - ACPI AML (p-code) execution, monadic operators + */ + +ACPI_STATUS +acpi_aml_exec_monadic1 ( + u16 opcode, + ACPI_WALK_STATE *walk_state); + +ACPI_STATUS +acpi_aml_exec_monadic2 ( + u16 opcode, + ACPI_WALK_STATE *walk_state, + ACPI_OPERAND_OBJECT **return_desc); + +ACPI_STATUS +acpi_aml_exec_monadic2_r ( + u16 opcode, + ACPI_WALK_STATE *walk_state, + ACPI_OPERAND_OBJECT **return_desc); + + +/* + * amdyadic - ACPI AML (p-code) execution, dyadic operators + */ + +ACPI_STATUS +acpi_aml_exec_dyadic1 ( + u16 opcode, + ACPI_WALK_STATE *walk_state); + +ACPI_STATUS +acpi_aml_exec_dyadic2 ( + u16 opcode, + ACPI_WALK_STATE *walk_state, + ACPI_OPERAND_OBJECT **return_desc); + +ACPI_STATUS +acpi_aml_exec_dyadic2_r ( + u16 opcode, + ACPI_WALK_STATE *walk_state, + ACPI_OPERAND_OBJECT **return_desc); + +ACPI_STATUS +acpi_aml_exec_dyadic2_s ( + u16 opcode, + ACPI_WALK_STATE *walk_state, + ACPI_OPERAND_OBJECT **return_desc); + + +/* + * amresolv - Object resolution and get value functions + */ + +ACPI_STATUS +acpi_aml_resolve_to_value ( + ACPI_OPERAND_OBJECT **stack_ptr, + ACPI_WALK_STATE *walk_state); + +ACPI_STATUS +acpi_aml_resolve_node_to_value ( + ACPI_NAMESPACE_NODE **stack_ptr); + +ACPI_STATUS +acpi_aml_resolve_object_to_value ( + ACPI_OPERAND_OBJECT **stack_ptr, + ACPI_WALK_STATE *walk_state); + +ACPI_STATUS +acpi_aml_get_field_unit_value ( + ACPI_OPERAND_OBJECT *field_desc, + ACPI_OPERAND_OBJECT *result_desc); + + +/* + * amdump - Scanner debug output routines + */ + +void +acpi_aml_show_hex_value ( + u32 byte_count, + u8 *aml_ptr, + u32 lead_space); + + +ACPI_STATUS +acpi_aml_dump_operand ( + ACPI_OPERAND_OBJECT *entry_desc); + +void +acpi_aml_dump_operands ( + ACPI_OPERAND_OBJECT **operands, + OPERATING_MODE interpreter_mode, + NATIVE_CHAR *ident, + u32 num_levels, + NATIVE_CHAR *note, + NATIVE_CHAR *module_name, + u32 line_number); + +void +acpi_aml_dump_object_descriptor ( + ACPI_OPERAND_OBJECT *object, + u32 flags); + + +void +acpi_aml_dump_node ( + ACPI_NAMESPACE_NODE *node, + u32 flags); + + +/* + * amnames - interpreter/scanner name load/execute + */ + +NATIVE_CHAR * +acpi_aml_allocate_name_string ( + u32 prefix_count, + u32 num_name_segs); + +u32 +acpi_aml_good_char ( + u32 character); + +ACPI_STATUS +acpi_aml_exec_name_segment ( + u8 **in_aml_address, + NATIVE_CHAR *name_string); + +ACPI_STATUS +acpi_aml_get_name_string ( + OBJECT_TYPE_INTERNAL data_type, + u8 *in_aml_address, + NATIVE_CHAR **out_name_string, + u32 *out_name_length); + +ACPI_STATUS +acpi_aml_do_name ( + ACPI_OBJECT_TYPE data_type, + OPERATING_MODE load_exec_mode); + + +/* + * amstore - Object store support + */ + +ACPI_STATUS +acpi_aml_exec_store ( + ACPI_OPERAND_OBJECT *val_desc, + ACPI_OPERAND_OBJECT *dest_desc, + ACPI_WALK_STATE *walk_state); + +ACPI_STATUS +acpi_aml_store_object_to_object ( + ACPI_OPERAND_OBJECT *val_desc, + ACPI_OPERAND_OBJECT *dest_desc, + ACPI_WALK_STATE *walk_state); + +ACPI_STATUS +acpi_aml_store_object_to_node ( + ACPI_OPERAND_OBJECT *val_desc, + ACPI_NAMESPACE_NODE *node, + ACPI_WALK_STATE *walk_state); + + +/* + * amutils - interpreter/scanner utilities + */ + +void +acpi_aml_enter_interpreter ( + void); + +void +acpi_aml_exit_interpreter ( + void); + +u8 +acpi_aml_validate_object_type ( + ACPI_OBJECT_TYPE type); + +u8 +acpi_aml_acquire_global_lock ( + u32 rule); + +ACPI_STATUS +acpi_aml_release_global_lock ( + u8 locked); + +u32 +acpi_aml_buf_seq ( + void); + +u32 +acpi_aml_digits_needed ( + u32 value, + u32 base); + +ACPI_STATUS +acpi_aml_eisa_id_to_string ( + u32 numeric_id, + NATIVE_CHAR *out_string); + +ACPI_STATUS +acpi_aml_build_copy_internal_package_object ( + ACPI_OPERAND_OBJECT *source_obj, + ACPI_OPERAND_OBJECT *dest_obj, + ACPI_WALK_STATE *walk_state); + + +/* + * amregion - default Op_region handlers + */ + +ACPI_STATUS +acpi_aml_system_memory_space_handler ( + u32 function, + u32 address, + u32 bit_width, + u32 *value, + void *handler_context, + void *region_context); + +ACPI_STATUS +acpi_aml_system_io_space_handler ( + u32 function, + u32 address, + u32 bit_width, + u32 *value, + void *handler_context, + void *region_context); + +ACPI_STATUS +acpi_aml_pci_config_space_handler ( + u32 function, + u32 address, + u32 bit_width, + u32 *value, + void *handler_context, + void *region_context); + +ACPI_STATUS +acpi_aml_embedded_controller_space_handler ( + u32 function, + u32 address, + u32 bit_width, + u32 *value, + void *handler_context, + void *region_context); + +ACPI_STATUS +acpi_aml_sm_bus_space_handler ( + u32 function, + u32 address, + u32 bit_width, + u32 *value, + void *handler_context, + void *region_context); + + +#endif /* __INTERP_H__ */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/include/aclocal.h linux/drivers/acpi/include/aclocal.h --- v2.4.0-test8/linux/drivers/acpi/include/aclocal.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/acpi/include/aclocal.h Fri Sep 15 14:30:30 2000 @@ -0,0 +1,851 @@ +/****************************************************************************** + * + * Name: aclocal.h - Internal data types used across the ACPI subsystem + * $Revision: 77 $ + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 R. Byron Moore + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __ACLOCAL_H__ +#define __ACLOCAL_H__ + + +#define WAIT_FOREVER ((u32) -1) + +typedef void* ACPI_MUTEX; +typedef u32 ACPI_MUTEX_HANDLE; + + +/* Object descriptor types */ + +#define ACPI_CACHED_OBJECT 0x11 /* ORed in when object is cached */ +#define ACPI_DESC_TYPE_STATE 0x22 +#define ACPI_DESC_TYPE_WALK 0x44 +#define ACPI_DESC_TYPE_PARSER 0x66 +#define ACPI_DESC_TYPE_INTERNAL 0x88 +#define ACPI_DESC_TYPE_NAMED 0xAA + + +/***************************************************************************** + * + * Mutex typedefs and structs + * + ****************************************************************************/ + + +/* + * Predefined handles for the mutex objects used within the subsystem + * All mutex objects are automatically created by Acpi_cm_mutex_initialize. + * NOTE: any changes here must be reflected in the Acpi_gbl_Mutex_names table also! + */ + +#define ACPI_MTX_HARDWARE 0 +#define ACPI_MTX_MEMORY 1 +#define ACPI_MTX_CACHES 2 +#define ACPI_MTX_TABLES 3 +#define ACPI_MTX_PARSER 4 +#define ACPI_MTX_DISPATCHER 5 +#define ACPI_MTX_INTERPRETER 6 +#define ACPI_MTX_EXECUTE 7 +#define ACPI_MTX_NAMESPACE 8 +#define ACPI_MTX_EVENTS 9 +#define ACPI_MTX_OP_REGIONS 10 +#define ACPI_MTX_DEBUG_CMD_READY 11 +#define ACPI_MTX_DEBUG_CMD_COMPLETE 12 + +#define MAX_MTX 12 +#define NUM_MTX MAX_MTX+1 + + +#ifdef ACPI_DEBUG +#ifdef DEFINE_ACPI_GLOBALS + +/* Names for the mutexes used in the subsystem */ + +static NATIVE_CHAR *acpi_gbl_mutex_names[] = +{ + "ACPI_MTX_Hardware", + "ACPI_MTX_Memory", + "ACPI_MTX_Caches", + "ACPI_MTX_Tables", + "ACPI_MTX_Parser", + "ACPI_MTX_Dispatcher", + "ACPI_MTX_Interpreter", + "ACPI_MTX_Execute", + "ACPI_MTX_Namespace", + "ACPI_MTX_Events", + "ACPI_MTX_Op_regions", + "ACPI_MTX_Debug_cmd_ready", + "ACPI_MTX_Debug_cmd_complete" +}; + +#endif +#endif + + +/* Table for the global mutexes */ + +typedef struct acpi_mutex_info +{ + ACPI_MUTEX mutex; + u32 use_count; + u8 locked; + +} ACPI_MUTEX_INFO; + + +/* Lock flag parameter for various interfaces */ + +#define ACPI_MTX_DO_NOT_LOCK 0 +#define ACPI_MTX_LOCK 1 + + +typedef u16 ACPI_OWNER_ID; +#define OWNER_TYPE_TABLE 0x0 +#define OWNER_TYPE_METHOD 0x1 +#define FIRST_METHOD_ID 0x0000 +#define FIRST_TABLE_ID 0x8000 + +/* TBD: [Restructure] get rid of the need for this! */ + +#define TABLE_ID_DSDT (ACPI_OWNER_ID) 0xD1D1 + +/***************************************************************************** + * + * Namespace typedefs and structs + * + ****************************************************************************/ + + +/* Operational modes of the AML interpreter/scanner */ + +typedef enum +{ + IMODE_LOAD_PASS1 = 0x01, + IMODE_LOAD_PASS2 = 0x02, + IMODE_EXECUTE = 0x0E + +} OPERATING_MODE; + + +/* + * The Node describes a named object that appears in the AML + * An Acpi_node is used to store Nodes. + * + * Data_type is used to differentiate between internal descriptors, and MUST + * be the first byte in this structure. + */ + +typedef struct acpi_node +{ + u8 data_type; + u8 type; /* Type associated with this name */ + u32 name; /* ACPI Name, always 4 chars per ACPI spec */ + u16 owner_id; + + + void *object; /* Pointer to attached ACPI object (optional) */ + struct acpi_node *child; /* first child */ + struct acpi_node *peer; /* Next peer*/ + u16 reference_count; /* Current count of references and children */ + u8 flags; + +} ACPI_NAMESPACE_NODE; + + +#define ENTRY_NOT_FOUND NULL + + +/* Node flags */ + +#define ANOBJ_AML_ATTACHMENT 0x1 +#define ANOBJ_END_OF_PEER_LIST 0x2 + + +/* + * ACPI Table Descriptor. One per ACPI table + */ +typedef struct acpi_table_desc +{ + struct acpi_table_desc *prev; + struct acpi_table_desc *next; + struct acpi_table_desc *installed_desc; + ACPI_TABLE_HEADER *pointer; + void *base_pointer; + u8 *aml_pointer; + u32 aml_length; + u32 length; + u32 count; + ACPI_OWNER_ID table_id; + u8 type; + u8 allocation; + u8 loaded_into_namespace; + +} ACPI_TABLE_DESC; + + +typedef struct +{ + NATIVE_CHAR *search_for; + ACPI_HANDLE *list; + u32 *count; + +} FIND_CONTEXT; + + +typedef struct +{ + ACPI_NAMESPACE_NODE *node; +} NS_SEARCH_DATA; + + +/* + * Predefined Namespace items + */ +#define ACPI_MAX_ADDRESS_SPACE 255 +#define ACPI_NUM_ADDRESS_SPACES 256 + + +typedef struct +{ + NATIVE_CHAR *name; + ACPI_OBJECT_TYPE type; + NATIVE_CHAR *val; + +} PREDEFINED_NAMES; + + +/***************************************************************************** + * + * Event typedefs and structs + * + ****************************************************************************/ + + +/* Status bits. */ + +#define ACPI_STATUS_PMTIMER 0x0001 +#define ACPI_STATUS_GLOBAL 0x0020 +#define ACPI_STATUS_POWER_BUTTON 0x0100 +#define ACPI_STATUS_SLEEP_BUTTON 0x0200 +#define ACPI_STATUS_RTC_ALARM 0x0400 + +/* Enable bits. */ + +#define ACPI_ENABLE_PMTIMER 0x0001 +#define ACPI_ENABLE_GLOBAL 0x0020 +#define ACPI_ENABLE_POWER_BUTTON 0x0100 +#define ACPI_ENABLE_SLEEP_BUTTON 0x0200 +#define ACPI_ENABLE_RTC_ALARM 0x0400 + + +/* + * Entry in the Address_space (AKA Operation Region) table + */ + +typedef struct +{ + ADDRESS_SPACE_HANDLER handler; + void *context; + +} ACPI_ADDRESS_SPACE_INFO; + + +/* Values and addresses of the GPE registers (both banks) */ + +typedef struct +{ + u8 status; /* Current value of status reg */ + u8 enable; /* Current value of enable reg */ + u16 status_addr; /* Address of status reg */ + u16 enable_addr; /* Address of enable reg */ + u8 gpe_base; /* Base GPE number */ + +} ACPI_GPE_REGISTERS; + + +#define ACPI_GPE_LEVEL_TRIGGERED 1 +#define ACPI_GPE_EDGE_TRIGGERED 2 + + +/* Information about each particular GPE level */ + +typedef struct +{ + u8 type; /* Level or Edge */ + + ACPI_HANDLE method_handle; /* Method handle for direct (fast) execution */ + GPE_HANDLER handler; /* Address of handler, if any */ + void *context; /* Context to be passed to handler */ + +} ACPI_GPE_LEVEL_INFO; + + +/* Information about each particular fixed event */ + +typedef struct +{ + FIXED_EVENT_HANDLER handler; /* Address of handler. */ + void *context; /* Context to be passed to handler */ + +} ACPI_FIXED_EVENT_INFO; + + +/* Information used during field processing */ + +typedef struct +{ + u8 skip_field; + u8 field_flag; + u32 pkg_length; + +} ACPI_FIELD_INFO; + + +/***************************************************************************** + * + * Generic "state" object for stacks + * + ****************************************************************************/ + + +#define CONTROL_NORMAL 0xC0 +#define CONTROL_CONDITIONAL_EXECUTING 0xC1 +#define CONTROL_PREDICATE_EXECUTING 0xC2 +#define CONTROL_PREDICATE_FALSE 0xC3 +#define CONTROL_PREDICATE_TRUE 0xC4 + + +/* Forward declaration */ +struct acpi_walk_state; +struct acpi_parse_obj ; + + +#define ACPI_STATE_COMMON /* Two 32-bit fields and a pointer */\ + u8 data_type; /* To differentiate various internal objs */\ + u8 flags; \ + u16 value; \ + u16 state; \ + u16 acpi_eval; \ + void *next; \ + +typedef struct acpi_common_state +{ + ACPI_STATE_COMMON +} ACPI_COMMON_STATE; + + +/* + * Update state - used to traverse complex objects such as packages + */ +typedef struct acpi_update_state +{ + ACPI_STATE_COMMON + union acpi_operand_obj *object; + +} ACPI_UPDATE_STATE; + +/* + * Control state - one per if/else and while constructs. + * Allows nesting of these constructs + */ +typedef struct acpi_control_state +{ + ACPI_STATE_COMMON + struct acpi_parse_obj *predicate_op; + u8 *aml_predicate_start; /* Start of if/while predicate */ + +} ACPI_CONTROL_STATE; + + +/* + * Scope state - current scope during namespace lookups + */ + +typedef struct acpi_scope_state +{ + ACPI_STATE_COMMON + ACPI_NAMESPACE_NODE *node; + +} ACPI_SCOPE_STATE; + + +typedef struct acpi_pscope_state +{ + ACPI_STATE_COMMON + struct acpi_parse_obj *op; /* current op being parsed */ + u8 *arg_end; /* current argument end */ + u8 *pkg_end; /* current package end */ + u32 arg_list; /* next argument to parse */ + u32 arg_count; /* Number of fixed arguments */ + +} ACPI_PSCOPE_STATE; + + +typedef union acpi_gen_state +{ + ACPI_COMMON_STATE common; + ACPI_CONTROL_STATE control; + ACPI_UPDATE_STATE update; + ACPI_SCOPE_STATE scope; + ACPI_PSCOPE_STATE parse_scope; + +} ACPI_GENERIC_STATE; + + +typedef +ACPI_STATUS (*ACPI_PARSE_DOWNWARDS) ( + u16 opcode, + struct acpi_parse_obj *op, + struct acpi_walk_state *walk_state, + struct acpi_parse_obj **out_op); + +typedef +ACPI_STATUS (*ACPI_PARSE_UPWARDS) ( + struct acpi_walk_state *walk_state, + struct acpi_parse_obj *op); + + +/***************************************************************************** + * + * Parser typedefs and structs + * + ****************************************************************************/ + + +#define ACPI_OP_CLASS_MASK 0x1F +#define ACPI_OP_ARGS_MASK 0x20 +#define ACPI_OP_TYPE_MASK 0xC0 + +#define ACPI_OP_TYPE_OPCODE 0x00 +#define ACPI_OP_TYPE_ASCII 0x40 +#define ACPI_OP_TYPE_PREFIX 0x80 +#define ACPI_OP_TYPE_UNKNOWN 0xC0 + +#define ACPI_GET_OP_CLASS(a) ((a)->flags & ACPI_OP_CLASS_MASK) +#define ACPI_GET_OP_ARGS(a) ((a)->flags & ACPI_OP_ARGS_MASK) +#define ACPI_GET_OP_TYPE(a) ((a)->flags & ACPI_OP_TYPE_MASK) + + +/* + * AML opcode, name, and argument layout + */ +typedef struct acpi_opcode_info +{ + u8 flags; /* Opcode type, Has_args flag */ + u32 parse_args; /* Grammar/Parse time arguments */ + u32 runtime_args; /* Interpret time arguments */ + + DEBUG_ONLY_MEMBERS ( + NATIVE_CHAR *name) /* op name (debug only) */ + +} ACPI_OPCODE_INFO; + + +typedef union acpi_parse_val +{ + u32 integer; /* integer constant */ + u32 size; /* bytelist or field size */ + NATIVE_CHAR *string; /* NULL terminated string */ + u8 *buffer; /* buffer or string */ + NATIVE_CHAR *name; /* NULL terminated string */ + struct acpi_parse_obj *arg; /* arguments and contained ops */ + +} ACPI_PARSE_VALUE; + + +#define ACPI_PARSE_COMMON \ + u8 data_type; /* To differentiate various internal objs */\ + u8 flags; /* Type of Op */\ + u16 opcode; /* AML opcode */\ + u32 aml_offset; /* offset of declaration in AML */\ + struct acpi_parse_obj *parent; /* parent op */\ + struct acpi_parse_obj *next; /* next op */\ + DEBUG_ONLY_MEMBERS (\ + NATIVE_CHAR op_name[16]) /* op name (debug only) */\ + /* NON-DEBUG members below: */\ + ACPI_NAMESPACE_NODE *node;/* for use by interpreter */\ + ACPI_PARSE_VALUE value; /* Value or args associated with the opcode */\ + + +/* + * generic operation (eg. If, While, Store) + */ +typedef struct acpi_parse_obj +{ + ACPI_PARSE_COMMON +} ACPI_PARSE_OBJECT; + + +/* + * Extended Op for named ops (Scope, Method, etc.), deferred ops (Methods and Op_regions), + * and bytelists. + */ +typedef struct acpi_parse2_obj +{ + ACPI_PARSE_COMMON + u8 *data; /* AML body or bytelist data */ + u32 length; /* AML length */ + u32 name; /* 4-byte name or zero if no name */ + +} ACPI_PARSE2_OBJECT; + + +/* + * Parse state - one state per parser invocation and each control + * method. + */ + +typedef struct acpi_parse_state +{ + u8 *aml_start; /* first AML byte */ + u8 *aml; /* next AML byte */ + u8 *aml_end; /* (last + 1) AML byte */ + u8 *pkg_start; /* current package begin */ + u8 *pkg_end; /* current package end */ + ACPI_PARSE_OBJECT *start_op; /* root of parse tree */ + struct acpi_node *start_node; + ACPI_GENERIC_STATE *scope; /* current scope */ + struct acpi_parse_state *next; + +} ACPI_PARSE_STATE; + + +/***************************************************************************** + * + * Tree walking typedefs and structs + * + ****************************************************************************/ + + +/* + * Walk state - current state of a parse tree walk. Used for both a leisurely stroll through + * the tree (for whatever reason), and for control method execution. + */ + +#define NEXT_OP_DOWNWARD 1 +#define NEXT_OP_UPWARD 2 + +#define WALK_METHOD 1 +#define WALK_NON_METHOD 0 + +typedef struct acpi_walk_state +{ + u8 data_type; /* To differentiate various internal objs */\ + ACPI_OWNER_ID owner_id; /* Owner of objects created during the walk */ + u8 last_predicate; /* Result of last predicate */ + u8 next_op_info; /* Info about Next_op */ + u8 num_operands; /* Stack pointer for Operands[] array */ + u8 num_results; /* Stack pointer for Results[] array */ + u8 current_result; /* */ + + struct acpi_walk_state *next; /* Next Walk_state in list */ + ACPI_PARSE_OBJECT *origin; /* Start of walk */ + +/* TBD: Obsolete with removal of WALK procedure ? */ + ACPI_PARSE_OBJECT *prev_op; /* Last op that was processed */ + ACPI_PARSE_OBJECT *next_op; /* next op to be processed */ + + + ACPI_GENERIC_STATE *control_state; /* List of control states (nested IFs) */ + ACPI_GENERIC_STATE *scope_info; /* Stack of nested scopes */ + ACPI_PARSE_STATE *parser_state; /* Current state of parser */ + u8 *aml_last_while; + ACPI_PARSE_DOWNWARDS descending_callback; + ACPI_PARSE_UPWARDS ascending_callback; + + union acpi_operand_obj *return_desc; /* Return object, if any */ + union acpi_operand_obj *method_desc; /* Method descriptor if running a method */ + struct acpi_node *method_node; /* Method Node if running a method */ + ACPI_PARSE_OBJECT *method_call_op; /* Method_call Op if running a method */ + struct acpi_node *method_call_node; /* Called method Node*/ + union acpi_operand_obj *operands[OBJ_NUM_OPERANDS]; /* Operands passed to the interpreter */ + union acpi_operand_obj *results[OBJ_NUM_OPERANDS]; /* Accumulated results */ + struct acpi_node arguments[MTH_NUM_ARGS]; /* Control method arguments */ + struct acpi_node local_variables[MTH_NUM_LOCALS]; /* Control method locals */ + u32 parse_flags; + u8 walk_type; + u8 return_used; + u32 prev_arg_types; + + /* Debug support */ + + u32 method_breakpoint; + + +} ACPI_WALK_STATE; + + +/* + * Walk list - head of a tree of walk states. Multiple walk states are created when there + * are nested control methods executing. + */ +typedef struct acpi_walk_list +{ + + ACPI_WALK_STATE *walk_state; + +} ACPI_WALK_LIST; + + +/* Info used by Acpi_ps_init_objects */ + +typedef struct init_walk_info +{ + u32 method_count; + u32 op_region_count; + ACPI_TABLE_DESC *table_desc; + +} INIT_WALK_INFO; + + +/* TBD: [Restructure] Merge with struct above */ + +typedef struct acpi_walk_info +{ + u32 debug_level; + u32 owner_id; + +} ACPI_WALK_INFO; + + +/***************************************************************************** + * + * Hardware and PNP + * + ****************************************************************************/ + + +/* Sleep states */ + +#define SLWA_DEBUG_LEVEL 4 +#define GTS_CALL 0 +#define GTS_WAKE 1 + +/* Cx States */ + +#define MAX_CX_STATE_LATENCY 0xFFFFFFFF +#define MAX_CX_STATES 4 + +/* + * The #define's and enum below establish an abstract way of identifying what + * register block and register is to be accessed. Do not change any of the + * values as they are used in switch statements and offset calculations. + */ + +#define REGISTER_BLOCK_MASK 0xFF00 +#define BIT_IN_REGISTER_MASK 0x00FF +#define PM1_EVT 0x0100 +#define PM1_CONTROL 0x0200 +#define PM2_CONTROL 0x0300 +#define PM_TIMER 0x0400 +#define PROCESSOR_BLOCK 0x0500 +#define GPE0_STS_BLOCK 0x0600 +#define GPE0_EN_BLOCK 0x0700 +#define GPE1_STS_BLOCK 0x0800 +#define GPE1_EN_BLOCK 0x0900 + +enum +{ + /* PM1 status register ids */ + + TMR_STS = (PM1_EVT | 0x01), + BM_STS, + GBL_STS, + PWRBTN_STS, + SLPBTN_STS, + RTC_STS, + WAK_STS, + + /* PM1 enable register ids */ + + TMR_EN, + /* need to skip 1 enable number since there's no bus master enable register */ + GBL_EN = (PM1_EVT | 0x0A), + PWRBTN_EN, + SLPBTN_EN, + RTC_EN, + + /* PM1 control register ids */ + + SCI_EN = (PM1_CONTROL | 0x01), + BM_RLD, + GBL_RLS, + SLP_TYPE_A, + SLP_TYPE_B, + SLP_EN, + + /* PM2 control register ids */ + + ARB_DIS = (PM2_CONTROL | 0x01), + + /* PM Timer register ids */ + + TMR_VAL = (PM_TIMER | 0x01), + + GPE0_STS = (GPE0_STS_BLOCK | 0x01), + GPE0_EN = (GPE0_EN_BLOCK | 0x01), + + GPE1_STS = (GPE1_STS_BLOCK | 0x01), + GPE1_EN = (GPE0_EN_BLOCK | 0x01), + + /* Last register value is one less than LAST_REG */ + + LAST_REG +}; + + +#define TMR_STS_MASK 0x0001 +#define BM_STS_MASK 0x0010 +#define GBL_STS_MASK 0x0020 +#define PWRBTN_STS_MASK 0x0100 +#define SLPBTN_STS_MASK 0x0200 +#define RTC_STS_MASK 0x0400 +#define WAK_STS_MASK 0x8000 + +#define ALL_FIXED_STS_BITS (TMR_STS_MASK | BM_STS_MASK | GBL_STS_MASK | PWRBTN_STS_MASK | \ + SLPBTN_STS_MASK | RTC_STS_MASK | WAK_STS_MASK) + +#define TMR_EN_MASK 0x0001 +#define GBL_EN_MASK 0x0020 +#define PWRBTN_EN_MASK 0x0100 +#define SLPBTN_EN_MASK 0x0200 +#define RTC_EN_MASK 0x0400 + +#define SCI_EN_MASK 0x0001 +#define BM_RLD_MASK 0x0002 +#define GBL_RLS_MASK 0x0004 +#define SLP_TYPE_X_MASK 0x1C00 +#define SLP_EN_MASK 0x2000 + +#define ARB_DIS_MASK 0x0001 + +#define GPE0_STS_MASK +#define GPE0_EN_MASK + +#define GPE1_STS_MASK +#define GPE1_EN_MASK + + +#define ACPI_READ 1 +#define ACPI_WRITE 2 + +#define LOW_BYTE 0x00FF +#define ONE_BYTE 0x08 + +#ifndef SET + #define SET 1 +#endif +#ifndef CLEAR + #define CLEAR 0 +#endif + + +/* Plug and play */ + +/* Pnp and ACPI data */ + +#define VERSION_NO 0x01 +#define LOGICAL_DEVICE_ID 0x02 +#define COMPATIBLE_DEVICE_ID 0x03 +#define IRQ_FORMAT 0x04 +#define DMA_FORMAT 0x05 +#define START_DEPENDENT_TAG 0x06 +#define END_DEPENDENT_TAG 0x07 +#define IO_PORT_DESCRIPTOR 0x08 +#define FIXED_LOCATION_IO_DESCRIPTOR 0x09 +#define RESERVED_TYPE0 0x0A +#define RESERVED_TYPE1 0x0B +#define RESERVED_TYPE2 0x0C +#define RESERVED_TYPE3 0x0D +#define SMALL_VENDOR_DEFINED 0x0E +#define END_TAG 0x0F + +/* Pnp and ACPI data */ + +#define MEMORY_RANGE_24 0x81 +#define ISA_MEMORY_RANGE 0x81 +#define LARGE_VENDOR_DEFINED 0x84 +#define EISA_MEMORY_RANGE 0x85 +#define MEMORY_RANGE_32 0x85 +#define FIXED_EISA_MEMORY_RANGE 0x86 +#define FIXED_MEMORY_RANGE_32 0x86 + +/* ACPI only data */ + +#define DWORD_ADDRESS_SPACE 0x87 +#define WORD_ADDRESS_SPACE 0x88 +#define EXTENDED_IRQ 0x89 + +/* MUST HAVES */ + + +typedef enum +{ + DWORD_DEVICE_ID, + STRING_PTR_DEVICE_ID, + STRING_DEVICE_ID + +} DEVICE_ID_TYPE; + +typedef struct +{ + DEVICE_ID_TYPE type; + union + { + u32 number; + NATIVE_CHAR *string_ptr; + NATIVE_CHAR buffer[9]; + } data; + +} DEVICE_ID; + + +/***************************************************************************** + * + * Debug + * + ****************************************************************************/ + + +/* Entry for a memory allocation (debug only) */ + +#ifdef ACPI_DEBUG + +#define MEM_MALLOC 0 +#define MEM_CALLOC 1 +#define MAX_MODULE_NAME 16 + +typedef struct allocation_info +{ + struct allocation_info *previous; + struct allocation_info *next; + void *address; + u32 size; + u32 component; + u32 line; + NATIVE_CHAR module[MAX_MODULE_NAME]; + u8 alloc_type; + +} ALLOCATION_INFO; + +#endif + +#endif /* __ACLOCAL_H__ */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/include/acmacros.h linux/drivers/acpi/include/acmacros.h --- v2.4.0-test8/linux/drivers/acpi/include/acmacros.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/acpi/include/acmacros.h Fri Sep 15 14:30:30 2000 @@ -0,0 +1,435 @@ +/****************************************************************************** + * + * Name: acmacros.h - C macros for the entire subsystem. + * $Revision: 48 $ + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 R. Byron Moore + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __ACMACROS_H__ +#define __ACMACROS_H__ + +/* + * Data manipulation macros + */ + +#ifndef LOWORD +#define LOWORD(l) ((u16)(NATIVE_UINT)(l)) +#endif + +#ifndef HIWORD +#define HIWORD(l) ((u16)((((NATIVE_UINT)(l)) >> 16) & 0xFFFF)) +#endif + +#ifndef LOBYTE +#define LOBYTE(l) ((u8)(u16)(l)) +#endif + +#ifndef HIBYTE +#define HIBYTE(l) ((u8)((((u16)(l)) >> 8) & 0xFF)) +#endif + +#define BIT0(x) ((((x) & 0x01) > 0) ? 1 : 0) +#define BIT1(x) ((((x) & 0x02) > 0) ? 1 : 0) +#define BIT2(x) ((((x) & 0x04) > 0) ? 1 : 0) + +#define BIT3(x) ((((x) & 0x08) > 0) ? 1 : 0) +#define BIT4(x) ((((x) & 0x10) > 0) ? 1 : 0) +#define BIT5(x) ((((x) & 0x20) > 0) ? 1 : 0) +#define BIT6(x) ((((x) & 0x40) > 0) ? 1 : 0) +#define BIT7(x) ((((x) & 0x80) > 0) ? 1 : 0) + +#define LOW_BASE(w) ((u16) ((w) & 0x0000FFFF)) +#define MID_BASE(b) ((u8) (((b) & 0x00FF0000) >> 16)) +#define HI_BASE(b) ((u8) (((b) & 0xFF000000) >> 24)) +#define LOW_LIMIT(w) ((u16) ((w) & 0x0000FFFF)) +#define HI_LIMIT(b) ((u8) (((b) & 0x00FF0000) >> 16)) + + + /* + * Extract a byte of data using a pointer. Any more than a byte and we + * get into potential aligment issues -- see the STORE macros below + */ +#define GET8(addr) (*(u8*)(addr)) + + +/* + * Macros for moving data around to/from buffers that are possibly unaligned. + * If the hardware supports the transfer of unaligned data, just do the store. + * Otherwise, we have to move one byte at a time. + */ + +#ifdef _HW_ALIGNMENT_SUPPORT + +/* The hardware supports unaligned transfers, just do the move */ + +#define MOVE_UNALIGNED16_TO_16(d,s) *(u16*)(d) = *(u16*)(s) +#define MOVE_UNALIGNED32_TO_32(d,s) *(u32*)(d) = *(u32*)(s) +#define MOVE_UNALIGNED16_TO_32(d,s) *(u32*)(d) = *(u16*)(s) + +#else +/* + * The hardware does not support unaligned transfers. We must move the + * data one byte at a time. These macros work whether the source or + * the destination (or both) is/are unaligned. + */ + +#define MOVE_UNALIGNED16_TO_16(d,s) {((u8 *)(d))[0] = ((u8 *)(s))[0];\ + ((u8 *)(d))[1] = ((u8 *)(s))[1];} + +#define MOVE_UNALIGNED32_TO_32(d,s) {((u8 *)(d))[0] = ((u8 *)(s))[0];\ + ((u8 *)(d))[1] = ((u8 *)(s))[1];\ + ((u8 *)(d))[2] = ((u8 *)(s))[2];\ + ((u8 *)(d))[3] = ((u8 *)(s))[3];} + +#define MOVE_UNALIGNED16_TO_32(d,s) {(*(u32*)(d)) = 0; MOVE_UNALIGNED16_TO_16(d,s);} + +#endif + + +/* + * Fast power-of-two math macros for non-optimized compilers + */ + +#define _DIV(value,power_of2) ((u32) ((value) >> (power_of2))) +#define _MUL(value,power_of2) ((u32) ((value) << (power_of2))) +#define _MOD(value,divisor) ((u32) ((value) & ((divisor) -1))) + +#define DIV_2(a) _DIV(a,1) +#define MUL_2(a) _MUL(a,1) +#define MOD_2(a) _MOD(a,2) + +#define DIV_4(a) _DIV(a,2) +#define MUL_4(a) _MUL(a,2) +#define MOD_4(a) _MOD(a,4) + +#define DIV_8(a) _DIV(a,3) +#define MUL_8(a) _MUL(a,3) +#define MOD_8(a) _MOD(a,8) + +#define DIV_16(a) _DIV(a,4) +#define MUL_16(a) _MUL(a,4) +#define MOD_16(a) _MOD(a,16) + + +/* + * Rounding macros (Power of two boundaries only) + */ + +#define ROUND_DOWN(value,boundary) ((value) & (~((boundary)-1))) +#define ROUND_UP(value,boundary) (((value) + ((boundary)-1)) & (~((boundary)-1))) + +#define ROUND_DOWN_TO_32_BITS(a) ROUND_DOWN(a,4) +#define ROUND_DOWN_TO_NATIVE_WORD(a) ROUND_DOWN(a,ALIGNED_ADDRESS_BOUNDARY) + +#define ROUND_UP_TO_32_bITS(a) ROUND_UP(a,4) +#define ROUND_UP_TO_NATIVE_WORD(a) ROUND_UP(a,ALIGNED_ADDRESS_BOUNDARY) + + +#ifdef DEBUG_ASSERT +#undef DEBUG_ASSERT +#endif + + +/* + * An ACPI_HANDLE (which is actually an ACPI_NAMESPACE_NODE *) can appear in some contexts, + * such as on ap_obj_stack, where a pointer to an ACPI_OPERAND_OBJECT can also + * appear. This macro is used to distinguish them. + * + * The Data_type field is the first field in both structures. + */ + +#define VALID_DESCRIPTOR_TYPE(d,t) (((ACPI_NAMESPACE_NODE *)d)->data_type == t) + + +/* Macro to test the object type */ + +#define IS_THIS_OBJECT_TYPE(d,t) (((ACPI_OPERAND_OBJECT *)d)->common.type == (u8)t) + +/* Macro to check the table flags for SINGLE or MULTIPLE tables are allowed */ + +#define IS_SINGLE_TABLE(x) (((x) & 0x01) == ACPI_TABLE_SINGLE ? 1 : 0) + +/* + * Macro to check if a pointer is within an ACPI table. + * Parameter (a) is the pointer to check. Parameter (b) must be defined + * as a pointer to an ACPI_TABLE_HEADER. (b+1) then points past the header, + * and ((u8 *)b+b->Length) points one byte past the end of the table. + */ + +#ifndef _IA16 +#define IS_IN_ACPI_TABLE(a,b) (((u8 *)(a) >= (u8 *)(b + 1)) &&\ + ((u8 *)(a) < ((u8 *)b + b->length))) + +#else +#define IS_IN_ACPI_TABLE(a,b) (_segment)(a) == (_segment)(b) &&\ + (((u8 *)(a) >= (u8 *)(b + 1)) &&\ + ((u8 *)(a) < ((u8 *)b + b->length))) +#endif + +/* + * Macros for the master AML opcode table + */ + +#ifdef ACPI_DEBUG +#define OP_INFO_ENTRY(flags,name,Pargs,Iargs) {flags,Pargs,Iargs,name} +#else +#define OP_INFO_ENTRY(flags,name,Pargs,Iargs) {flags,Pargs,Iargs} +#endif + +#define ARG_TYPE_WIDTH 5 +#define ARG_1(x) ((u32)(x)) +#define ARG_2(x) ((u32)(x) << (1 * ARG_TYPE_WIDTH)) +#define ARG_3(x) ((u32)(x) << (2 * ARG_TYPE_WIDTH)) +#define ARG_4(x) ((u32)(x) << (3 * ARG_TYPE_WIDTH)) +#define ARG_5(x) ((u32)(x) << (4 * ARG_TYPE_WIDTH)) +#define ARG_6(x) ((u32)(x) << (5 * ARG_TYPE_WIDTH)) + +#define ARGI_LIST1(a) (ARG_1(a)) +#define ARGI_LIST2(a,b) (ARG_1(b)|ARG_2(a)) +#define ARGI_LIST3(a,b,c) (ARG_1(c)|ARG_2(b)|ARG_3(a)) +#define ARGI_LIST4(a,b,c,d) (ARG_1(d)|ARG_2(c)|ARG_3(b)|ARG_4(a)) +#define ARGI_LIST5(a,b,c,d,e) (ARG_1(e)|ARG_2(d)|ARG_3(c)|ARG_4(b)|ARG_5(a)) +#define ARGI_LIST6(a,b,c,d,e,f) (ARG_1(f)|ARG_2(e)|ARG_3(d)|ARG_4(c)|ARG_5(b)|ARG_6(a)) + +#define ARGP_LIST1(a) (ARG_1(a)) +#define ARGP_LIST2(a,b) (ARG_1(a)|ARG_2(b)) +#define ARGP_LIST3(a,b,c) (ARG_1(a)|ARG_2(b)|ARG_3(c)) +#define ARGP_LIST4(a,b,c,d) (ARG_1(a)|ARG_2(b)|ARG_3(c)|ARG_4(d)) +#define ARGP_LIST5(a,b,c,d,e) (ARG_1(a)|ARG_2(b)|ARG_3(c)|ARG_4(d)|ARG_5(e)) +#define ARGP_LIST6(a,b,c,d,e,f) (ARG_1(a)|ARG_2(b)|ARG_3(c)|ARG_4(d)|ARG_5(e)|ARG_6(f)) + +#define GET_CURRENT_ARG_TYPE(list) (list & 0x1F) +#define INCREMENT_ARG_LIST(list) (list >>= ARG_TYPE_WIDTH) + + +/* + * Reporting macros that are never compiled out + */ + +/* + * Error reporting. These versions add callers module and line#. Since + * _THIS_MODULE gets compiled out when ACPI_DEBUG isn't defined, only + * use it in debug mode. + */ + +#ifdef ACPI_DEBUG + +#define REPORT_INFO(a) _report_info(_THIS_MODULE,__LINE__,_COMPONENT,a) +#define REPORT_ERROR(a) _report_error(_THIS_MODULE,__LINE__,_COMPONENT,a) +#define REPORT_WARNING(a) _report_warning(_THIS_MODULE,__LINE__,_COMPONENT,a) + +#else + +#define REPORT_INFO(a) _report_info("",__LINE__,_COMPONENT,a) +#define REPORT_ERROR(a) _report_error("",__LINE__,_COMPONENT,a) +#define REPORT_WARNING(a) _report_warning("",__LINE__,_COMPONENT,a) + +#endif + +/* Error reporting. These versions pass thru the module and line# */ + +#define _REPORT_INFO(a,b,c,d) _report_info(a,b,c,d) +#define _REPORT_ERROR(a,b,c,d) _report_error(a,b,c,d) +#define _REPORT_WARNING(a,b,c,d) _report_warning(a,b,c,d) + +/* Buffer dump macros */ + +#define DUMP_BUFFER(a,b) acpi_cm_dump_buffer((u8 *)a,b,DB_BYTE_DISPLAY,_COMPONENT) + +/* + * Debug macros that are conditionally compiled + */ + +#ifdef ACPI_DEBUG + +#define MODULE_NAME(name) static char *_THIS_MODULE = name; + +/* + * Function entry tracing. + * The first parameter should be the procedure name as a quoted string. This is declared + * as a local string ("_Proc_name) so that it can be also used by the function exit macros below. + */ + +#define FUNCTION_TRACE(a) char * _proc_name = a;\ + function_trace(_THIS_MODULE,__LINE__,_COMPONENT,a) +#define FUNCTION_TRACE_PTR(a,b) char * _proc_name = a;\ + function_trace_ptr(_THIS_MODULE,__LINE__,_COMPONENT,a,(void *)b) +#define FUNCTION_TRACE_U32(a,b) char * _proc_name = a;\ + function_trace_u32(_THIS_MODULE,__LINE__,_COMPONENT,a,(u32)b) +#define FUNCTION_TRACE_STR(a,b) char * _proc_name = a;\ + function_trace_str(_THIS_MODULE,__LINE__,_COMPONENT,a,(NATIVE_CHAR *)b) +/* + * Function exit tracing. + * WARNING: These macros include a return statement. This is usually considered + * bad form, but having a separate exit macro is very ugly and difficult to maintain. + * One of the FUNCTION_TRACE macros above must be used in conjunction with these macros + * so that "_Proc_name" is defined. + */ +#define return_VOID {function_exit(_THIS_MODULE,__LINE__,_COMPONENT,_proc_name);return;} +#define return_ACPI_STATUS(s) {function_status_exit(_THIS_MODULE,__LINE__,_COMPONENT,_proc_name,s);return(s);} +#define return_VALUE(s) {function_value_exit(_THIS_MODULE,__LINE__,_COMPONENT,_proc_name,(NATIVE_UINT)s);return(s);} +#define return_PTR(s) {function_ptr_exit(_THIS_MODULE,__LINE__,_COMPONENT,_proc_name,(u8 *)s);return(s);} + + +/* Conditional execution */ + +#define DEBUG_EXEC(a) a; +#define NORMAL_EXEC(a) + +#define DEBUG_DEFINE(a) a; +#define DEBUG_ONLY_MEMBERS(a) a; + + +/* Stack and buffer dumping */ + +#define DUMP_STACK_ENTRY(a) acpi_aml_dump_operand(a) +#define DUMP_OPERANDS(a,b,c,d,e) acpi_aml_dump_operands(a,b,c,d,e,_THIS_MODULE,__LINE__) + + +#define DUMP_ENTRY(a,b) acpi_ns_dump_entry (a,b) +#define DUMP_TABLES(a,b) acpi_ns_dump_tables(a,b) +#define DUMP_PATHNAME(a,b,c,d) acpi_ns_dump_pathname(a,b,c,d) +#define DUMP_RESOURCE_LIST(a) acpi_rs_dump_resource_list(a) +#define BREAK_MSG(a) acpi_os_breakpoint (a) + +/* + * Generate INT3 on ACPI_ERROR (Debug only!) + */ + +#define ERROR_BREAK +#ifdef ERROR_BREAK +#define BREAK_ON_ERROR(lvl) if ((lvl)&ACPI_ERROR) acpi_os_breakpoint("Fatal error encountered\n") +#else +#define BREAK_ON_ERROR(lvl) +#endif + +/* + * Master debug print macros + * Print iff: + * 1) Debug print for the current component is enabled + * 2) Debug error level or trace level for the print statement is enabled + * + */ + +#define PARAM_LIST(pl) pl + +#define TEST_DEBUG_SWITCH(lvl) if (((lvl) & acpi_dbg_level) && (_COMPONENT & acpi_dbg_layer)) + +#define DEBUG_PRINT(lvl,fp) TEST_DEBUG_SWITCH(lvl) {\ + debug_print_prefix (_THIS_MODULE,__LINE__);\ + debug_print_raw PARAM_LIST(fp);\ + BREAK_ON_ERROR(lvl);} + +#define DEBUG_PRINT_RAW(lvl,fp) TEST_DEBUG_SWITCH(lvl) {\ + debug_print_raw PARAM_LIST(fp);} + + +/* Assert macros */ + +#define ACPI_ASSERT(exp) if(!(exp)) \ + acpi_os_dbg_assert(#exp, __FILE__, __LINE__, "Failed Assertion") + +#define DEBUG_ASSERT(msg, exp) if(!(exp)) \ + acpi_os_dbg_assert(#exp, __FILE__, __LINE__, msg) + + +#else +/* + * This is the non-debug case -- make everything go away, + * leaving no executable debug code! + */ + +#define MODULE_NAME(name) +#define _THIS_MODULE "" + +#define DEBUG_EXEC(a) +#define NORMAL_EXEC(a) a; + +#define DEBUG_DEFINE(a) +#define DEBUG_ONLY_MEMBERS(a) +#define FUNCTION_TRACE(a) +#define FUNCTION_TRACE_PTR(a,b) +#define FUNCTION_TRACE_U32(a,b) +#define FUNCTION_TRACE_STR(a,b) +#define FUNCTION_EXIT +#define FUNCTION_STATUS_EXIT(s) +#define FUNCTION_VALUE_EXIT(s) +#define DUMP_STACK_ENTRY(a) +#define DUMP_OPERANDS(a,b,c,d,e) +#define DUMP_ENTRY(a,b) +#define DUMP_TABLES(a,b) +#define DUMP_PATHNAME(a,b,c,d) +#define DUMP_RESOURCE_LIST(a) +#define DEBUG_PRINT(l,f) +#define DEBUG_PRINT_RAW(l,f) +#define BREAK_MSG(a) + +#define return_VOID return +#define return_ACPI_STATUS(s) return(s) +#define return_VALUE(s) return(s) +#define return_PTR(s) return(s) + +#define ACPI_ASSERT(exp) +#define DEBUG_ASSERT(msg, exp) + +#endif + +/* + * Some code only gets executed when the debugger is built in. + * Note that this is entirely independent of whether the + * DEBUG_PRINT stuff (set by ACPI_DEBUG) is on, or not. + */ +#ifdef ENABLE_DEBUGGER +#define DEBUGGER_EXEC(a) a; +#else +#define DEBUGGER_EXEC(a) +#endif + + +/* + * For 16-bit code, we want to shrink some things even though + * we are using ACPI_DEBUG to get the debug output + */ +#ifdef _IA16 +#undef DEBUG_ONLY_MEMBERS +#define DEBUG_ONLY_MEMBERS(a) +#undef OP_INFO_ENTRY +#define OP_INFO_ENTRY(opcode,flags,name,Pargs,Iargs) {opcode,flags,Pargs,Iargs} +#endif + + +#ifdef ACPI_DEBUG + +/* + * 1) Set name to blanks + * 2) Copy the object name + */ + +#define ADD_OBJECT_NAME(a,b) MEMSET (a->common.name, ' ', sizeof (a->common.name));\ + STRNCPY (a->common.name, acpi_gbl_ns_type_names[b], sizeof (a->common.name)) + +#else + +#define ADD_OBJECT_NAME(a,b) + +#endif + +#endif /* ACMACROS_H */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/include/acnamesp.h linux/drivers/acpi/include/acnamesp.h --- v2.4.0-test8/linux/drivers/acpi/include/acnamesp.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/acpi/include/acnamesp.h Fri Sep 15 14:30:30 2000 @@ -0,0 +1,393 @@ +/****************************************************************************** + * + * Name: acnamesp.h - Namespace subcomponent prototypes and defines + * $Revision: 94 $ + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 R. Byron Moore + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __ACNAMESP_H__ +#define __ACNAMESP_H__ + + +/* To search the entire name space, pass this as Search_base */ + +#define NS_ALL ((ACPI_HANDLE)0) + +/* + * Elements of Acpi_ns_properties are bit significant + * and should be one-to-one with values of ACPI_OBJECT_TYPE + */ +#define NSP_NORMAL 0 +#define NSP_NEWSCOPE 1 /* a definition of this type opens a name scope */ +#define NSP_LOCAL 2 /* suppress search of enclosing scopes */ + + +/* Definitions of the predefined namespace names */ + +#define ACPI_UNKNOWN_NAME (u32) 0x3F3F3F3F /* Unknown name is "????" */ +#define ACPI_ROOT_NAME (u32) 0x2F202020 /* Root name is "/ " */ +#define ACPI_SYS_BUS_NAME (u32) 0x5F53425F /* Sys bus name is "_SB_" */ + +#define NS_ROOT_PATH "/" +#define NS_SYSTEM_BUS "_SB_" + + +/* Flags for Acpi_ns_lookup, Acpi_ns_search_and_enter */ + +#define NS_NO_UPSEARCH 0 +#define NS_SEARCH_PARENT 0x01 +#define NS_DONT_OPEN_SCOPE 0x02 +#define NS_NO_PEER_SEARCH 0x04 + +#define NS_WALK_UNLOCK TRUE +#define NS_WALK_NO_UNLOCK FALSE + + +ACPI_STATUS +acpi_ns_walk_namespace ( + OBJECT_TYPE_INTERNAL type, + ACPI_HANDLE start_object, + u32 max_depth, + u8 unlock_before_callback, + WALK_CALLBACK user_function, + void *context, + void **return_value); + + +ACPI_NAMESPACE_NODE * +acpi_ns_get_next_object ( + OBJECT_TYPE_INTERNAL type, + ACPI_NAMESPACE_NODE *parent, + ACPI_NAMESPACE_NODE *child); + + +ACPI_STATUS +acpi_ns_delete_namespace_by_owner ( + u16 table_id); + + +/* Namespace loading - nsload */ + +ACPI_STATUS +acpi_ns_parse_table ( + ACPI_TABLE_DESC *table_desc, + ACPI_NAMESPACE_NODE *scope); + +ACPI_STATUS +acpi_ns_load_table ( + ACPI_TABLE_DESC *table_desc, + ACPI_NAMESPACE_NODE *node); + +ACPI_STATUS +acpi_ns_load_table_by_type ( + ACPI_TABLE_TYPE table_type); + + +/* + * Top-level namespace access - nsaccess + */ + + +ACPI_STATUS +acpi_ns_root_initialize ( + void); + +ACPI_STATUS +acpi_ns_lookup ( + ACPI_GENERIC_STATE *scope_info, + NATIVE_CHAR *name, + OBJECT_TYPE_INTERNAL type, + OPERATING_MODE interpreter_mode, + u32 flags, + ACPI_WALK_STATE *walk_state, + ACPI_NAMESPACE_NODE **ret_node); + + +/* + * Named object allocation/deallocation - nsalloc + */ + + +ACPI_NAMESPACE_NODE * +acpi_ns_create_node ( + u32 acpi_name); + +void +acpi_ns_delete_node ( + ACPI_NAMESPACE_NODE *node); + +ACPI_STATUS +acpi_ns_delete_namespace_subtree ( + ACPI_NAMESPACE_NODE *parent_handle); + +void +acpi_ns_detach_object ( + ACPI_NAMESPACE_NODE *node); + +void +acpi_ns_delete_children ( + ACPI_NAMESPACE_NODE *parent); + + +/* + * Namespace modification - nsmodify + */ + +ACPI_STATUS +acpi_ns_unload_namespace ( + ACPI_HANDLE handle); + +ACPI_STATUS +acpi_ns_delete_subtree ( + ACPI_HANDLE start_handle); + + +/* + * Namespace dump/print utilities - nsdump + */ + +void +acpi_ns_dump_tables ( + ACPI_HANDLE search_base, + u32 max_depth); + +void +acpi_ns_dump_entry ( + ACPI_HANDLE handle, + u32 debug_level); + +ACPI_STATUS +acpi_ns_dump_pathname ( + ACPI_HANDLE handle, + NATIVE_CHAR *msg, + u32 level, + u32 component); + +void +acpi_ns_dump_root_devices ( + void); + +void +acpi_ns_dump_objects ( + OBJECT_TYPE_INTERNAL type, + u32 max_depth, + u32 ownder_id, + ACPI_HANDLE start_handle); + + +/* + * Namespace evaluation functions - nseval + */ + +ACPI_STATUS +acpi_ns_evaluate_by_handle ( + ACPI_NAMESPACE_NODE *prefix_node, + ACPI_OPERAND_OBJECT **params, + ACPI_OPERAND_OBJECT **return_object); + +ACPI_STATUS +acpi_ns_evaluate_by_name ( + NATIVE_CHAR *pathname, + ACPI_OPERAND_OBJECT **params, + ACPI_OPERAND_OBJECT **return_object); + +ACPI_STATUS +acpi_ns_evaluate_relative ( + ACPI_NAMESPACE_NODE *prefix_node, + NATIVE_CHAR *pathname, + ACPI_OPERAND_OBJECT **params, + ACPI_OPERAND_OBJECT **return_object); + +ACPI_STATUS +acpi_ns_execute_control_method ( + ACPI_NAMESPACE_NODE *method_node, + ACPI_OPERAND_OBJECT **params, + ACPI_OPERAND_OBJECT **return_obj_desc); + +ACPI_STATUS +acpi_ns_get_object_value ( + ACPI_NAMESPACE_NODE *object_node, + ACPI_OPERAND_OBJECT **return_obj_desc); + + +/* + * Parent/Child/Peer utility functions - nsfamily + */ + +ACPI_NAME +acpi_ns_find_parent_name ( + ACPI_NAMESPACE_NODE *node_to_search); + +u8 +acpi_ns_exist_downstream_sibling ( + ACPI_NAMESPACE_NODE *this_node); + + +/* + * Scope manipulation - nsscope + */ + +u32 +acpi_ns_opens_scope ( + OBJECT_TYPE_INTERNAL type); + +NATIVE_CHAR * +acpi_ns_get_table_pathname ( + ACPI_NAMESPACE_NODE *node); + +NATIVE_CHAR * +acpi_ns_name_of_current_scope ( + ACPI_WALK_STATE *walk_state); + +ACPI_STATUS +acpi_ns_handle_to_pathname ( + ACPI_HANDLE obj_handle, + u32 *buf_size, + NATIVE_CHAR *user_buffer); + +u8 +acpi_ns_pattern_match ( + ACPI_NAMESPACE_NODE *obj_node, + NATIVE_CHAR *search_for); + +ACPI_STATUS +acpi_ns_name_compare ( + ACPI_HANDLE obj_handle, + u32 level, + void *context, + void **return_value); + +ACPI_STATUS +acpi_ns_get_node ( + NATIVE_CHAR *pathname, + ACPI_NAMESPACE_NODE *in_prefix_node, + ACPI_NAMESPACE_NODE **out_node); + +/* + * Object management for NTEs - nsobject + */ + +ACPI_STATUS +acpi_ns_attach_object ( + ACPI_NAMESPACE_NODE *node, + ACPI_OPERAND_OBJECT *object, + OBJECT_TYPE_INTERNAL type); + + +void * +acpi_ns_compare_value ( + ACPI_HANDLE obj_handle, + u32 level, + void *obj_desc); + + +/* + * Namespace searching and entry - nssearch + */ + +ACPI_STATUS +acpi_ns_search_and_enter ( + u32 entry_name, + ACPI_WALK_STATE *walk_state, + ACPI_NAMESPACE_NODE *node, + OPERATING_MODE interpreter_mode, + OBJECT_TYPE_INTERNAL type, + u32 flags, + ACPI_NAMESPACE_NODE **ret_node); + +ACPI_STATUS +acpi_ns_search_node ( + u32 entry_name, + ACPI_NAMESPACE_NODE *node, + OBJECT_TYPE_INTERNAL type, + ACPI_NAMESPACE_NODE **ret_node); + +ACPI_NAMESPACE_NODE * +acpi_ns_create_node ( + u32 acpi_name); + +void +acpi_ns_install_node ( + ACPI_WALK_STATE *walk_state, + ACPI_NAMESPACE_NODE *parent_node, /* Parent */ + ACPI_NAMESPACE_NODE *node, /* New Child*/ + OBJECT_TYPE_INTERNAL type); + + +/* + * Utility functions - nsutils + */ + +u8 +acpi_ns_valid_root_prefix ( + NATIVE_CHAR prefix); + +u8 +acpi_ns_valid_path_separator ( + NATIVE_CHAR sep); + +OBJECT_TYPE_INTERNAL +acpi_ns_get_type ( + ACPI_HANDLE obj_handle); + +void * +acpi_ns_get_attached_object ( + ACPI_HANDLE obj_handle); + +u32 +acpi_ns_local ( + OBJECT_TYPE_INTERNAL type); + +ACPI_STATUS +acpi_ns_internalize_name ( + NATIVE_CHAR *dotted_name, + NATIVE_CHAR **converted_name); + +ACPI_STATUS +acpi_ns_externalize_name ( + u32 internal_name_length, + NATIVE_CHAR *internal_name, + u32 *converted_name_length, + NATIVE_CHAR **converted_name); + +ACPI_NAMESPACE_NODE * +acpi_ns_convert_handle_to_entry ( + ACPI_HANDLE handle); + +ACPI_HANDLE +acpi_ns_convert_entry_to_handle( + ACPI_NAMESPACE_NODE *node); + +void +acpi_ns_terminate ( + void); + +ACPI_NAMESPACE_NODE * +acpi_ns_get_parent_object ( + ACPI_NAMESPACE_NODE *node); + + +ACPI_NAMESPACE_NODE * +acpi_ns_get_next_valid_object ( + ACPI_NAMESPACE_NODE *node); + + +#endif /* __ACNAMESP_H__ */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/include/acobject.h linux/drivers/acpi/include/acobject.h --- v2.4.0-test8/linux/drivers/acpi/include/acobject.h Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/include/acobject.h Fri Sep 15 14:30:30 2000 @@ -1,7 +1,8 @@ /****************************************************************************** * - * Name: acobject.h - Definition of ACPI_OBJECT_INTERNAL (Internal object only) + * Name: acobject.h - Definition of ACPI_OPERAND_OBJECT (Internal object only) + * $Revision: 71 $ * *****************************************************************************/ @@ -26,17 +27,14 @@ #ifndef _ACOBJECT_H #define _ACOBJECT_H -#include "actypes.h" -#include "macros.h" -#include "internal.h" /* - * The ACPI_OBJECT_INTERNAL is used to pass AML operands from the dispatcher + * The ACPI_OPERAND_OBJECT is used to pass AML operands from the dispatcher * to the interpreter, and to keep track of the various handlers such as * address space handlers and notify handlers. The object is a constant * size in order to allow them to be cached and reused. * - * All variants of the ACPI_OBJECT_INTERNAL are defined with the same + * All variants of the ACPI_OPERAND_OBJECT are defined with the same * sequence of field types, with fields that are not used in a particular * variant being named "Reserved". This is not strictly necessary, but * may in some circumstances simplify understanding if these structures @@ -60,32 +58,31 @@ */ -#define ACPI_OBJECT_COMMON_HEADER /* Two 32-bit fields */\ - u8 data_type; /* To differentiate various internal objs */\ - u8 type; /* ACPI_OBJECT_TYPE */\ - u8 size; /* Size of entire descriptor */\ - u8 flags;\ - u16 reference_count; /* For object deletion management */\ - u16 acpi_cm_fill2;\ - union acpi_obj_internal *next; \ +#define ACPI_OBJECT_COMMON_HEADER /* Two 32-bit fields, one pointer, 8-bit flag */\ + u8 data_type; /* To differentiate various internal objs */\ + u8 type; /* ACPI_OBJECT_TYPE */\ + u16 reference_count; /* For object deletion management */\ + u8 flags; \ /* Defines for flag byte above */ -#define AO_STATIC_ALLOCATION 0x1 +#define AOPOBJ_STATIC_ALLOCATION 0x1 +#define AOPOBJ_DATA_VALID 0x2 +#define AOPOBJ_INITIALIZED 0x4 /* * Common bitfield for the field objects */ #define ACPI_COMMON_FIELD_INFO /* Three 32-bit values */\ - u32 offset; /* Byte offset within containing object */\ - u16 length; /* # of bits in buffer */ \ - u8 granularity;\ - u8 bit_offset; /* Bit offset within min read/write data unit */\ - u8 access; /* Access_type */\ - u8 lock_rule;\ - u8 update_rule;\ - u8 access_attribute; + u8 granularity;\ + u16 length; \ + u32 offset; /* Byte offset within containing object */\ + u8 bit_offset; /* Bit offset within min read/write data unit */\ + u8 access; /* Access_type */\ + u8 lock_rule;\ + u8 update_rule;\ + u8 access_attribute; /****************************************************************************** @@ -98,25 +95,23 @@ typedef struct /* COMMON */ { ACPI_OBJECT_COMMON_HEADER - UCHAR first_non_common_byte; } ACPI_OBJECT_COMMON; +typedef struct /* CACHE_LIST */ +{ + ACPI_OBJECT_COMMON_HEADER + union acpi_operand_obj *next; /* Link for object cache and internal lists*/ + +} ACPI_OBJECT_CACHE_LIST; + + typedef struct /* NUMBER - has value */ { ACPI_OBJECT_COMMON_HEADER - u32 value; - u32 reserved2; - u32 reserved3; - u32 reserved4; - - void *reserved_p1; - void *reserved_p2; - void *reserved_p3; - void *reserved_p4; - void *reserved_p5; + u32 value; } ACPI_OBJECT_NUMBER; @@ -125,16 +120,8 @@ { ACPI_OBJECT_COMMON_HEADER - u32 length; /* # of bytes in string, excluding trailing null */ - u32 reserved2; - u32 reserved3; - u32 reserved4; - - char *pointer; /* String value in AML stream or in allocated space */ - void *reserved_p2; - void *reserved_p3; - void *reserved_p4; - void *reserved_p5; + u32 length; + NATIVE_CHAR *pointer; /* String value in AML stream or in allocated space */ } ACPI_OBJECT_STRING; @@ -143,16 +130,10 @@ { ACPI_OBJECT_COMMON_HEADER - u32 length; /* # of bytes in buffer */ - u32 sequence; /* Sequential count of buffers created */ - u32 reserved3; - u32 reserved4; - - u8 *pointer; /* points to the buffer in allocated space */ - void *reserved_p2; - void *reserved_p3; - void *reserved_p4; - void *reserved_p5; + u32 length; + u32 sequence; /* Sequential count of buffers created */ + + u8 *pointer; /* points to the buffer in allocated space */ } ACPI_OBJECT_BUFFER; @@ -161,16 +142,10 @@ { ACPI_OBJECT_COMMON_HEADER - u32 count; /* # of elements in package */ - u32 reserved2; - u32 reserved3; - u32 reserved4; - - union acpi_obj_internal **elements; /* Array of pointers to Acpi_objects */ - union acpi_obj_internal **next_element; /* used only while initializing */ - void *reserved_p3; - void *reserved_p4; - void *reserved_p5; + u32 count; /* # of elements in package */ + + union acpi_operand_obj **elements; /* Array of pointers to Acpi_objects */ + union acpi_operand_obj **next_element; /* used only while initializing */ } ACPI_OBJECT_PACKAGE; @@ -180,13 +155,9 @@ ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_FIELD_INFO - u32 sequence; /* Container's sequence number */ + u32 sequence; /* Container's sequence number */ - union acpi_obj_internal *container; /* Containing object (Buffer) */ - void *reserved_p2; - void *reserved_p3; - void *reserved_p4; - void *reserved_p5; + union acpi_operand_obj *container; /* Containing object (Buffer) */ } ACPI_OBJECT_FIELD_UNIT; @@ -195,16 +166,9 @@ { ACPI_OBJECT_COMMON_HEADER - u32 reserved1; - u32 reserved2; - u32 reserved3; - u32 reserved4; - - ACPI_HANDLE handle; - union acpi_obj_internal *sys_handler; /* Handler for system notifies */ - union acpi_obj_internal *drv_handler; /* Handler for driver notifies */ - union acpi_obj_internal *addr_handler; /* Handler for Address space */ - void *reserved_p5; + union acpi_operand_obj *sys_handler; /* Handler for system notifies */ + union acpi_operand_obj *drv_handler; /* Handler for driver notifies */ + union acpi_operand_obj *addr_handler; /* Handler for Address space */ } ACPI_OBJECT_DEVICE; @@ -213,18 +177,7 @@ { ACPI_OBJECT_COMMON_HEADER - u16 lock_count; - u16 thread_id; - u16 signal_count; - u16 fill1; - u32 reserved3; - u32 reserved4; - - void *semaphore; - void *reserved_p2; - void *reserved_p3; - void *reserved_p4; - void *reserved_p5; + void *semaphore; } ACPI_OBJECT_EVENT; @@ -234,21 +187,17 @@ typedef struct /* METHOD */ { ACPI_OBJECT_COMMON_HEADER + u8 method_flags; + u8 param_count; + + u32 pcode_length; - u8 method_flags; - u8 param_count; - u8 concurrency; - u8 fill1; - u32 pcode_length; - u32 table_length; - ACPI_OWNER_ID owning_id; - u16 reserved4; - - u8 *pcode; - u8 *acpi_table; - void *parser_op; - void *semaphore; - void *reserved_p5; + void *semaphore; + u8 *pcode; + + u8 concurrency; + u8 thread_count; + ACPI_OWNER_ID owning_id; } ACPI_OBJECT_METHOD; @@ -256,45 +205,31 @@ typedef struct /* MUTEX */ { ACPI_OBJECT_COMMON_HEADER + u16 sync_level; - u16 lock_count; - u16 thread_id; - u16 sync_level; - u16 fill1; - u32 reserved3; - u32 reserved4; - - void *semaphore; - void *reserved_p2; - void *reserved_p3; - void *reserved_p4; - void *reserved_p5; + void *semaphore; } ACPI_OBJECT_MUTEX; -/* Flags for Region */ - -#define INITIAL_REGION_FLAGS 0x0000 /* value set when the region is created */ -#define REGION_AGRUMENT_DATA_VALID 0x0001 /* Addr/Len are set */ -#define REGION_INITIALIZED 0x0002 /* region init handler has been called */ - /* this includes _REG method, if any */ typedef struct /* REGION */ { ACPI_OBJECT_COMMON_HEADER - u16 space_id; - u16 region_flags; /* bits defined above */ - u32 address; - u32 length; - u32 reserved4; /* Region Specific data (PCI _ADR) */ - - union acpi_obj_internal *method; /* Associated control method */ - union acpi_obj_internal *addr_handler; /* Handler for system notifies */ - union acpi_obj_internal *link; /* Link in list of regions */ - /* list is owned by Addr_handler */ - ACPI_NAMED_OBJECT *REGmethod; /* _REG method for this region (if any) */ - ACPI_NAMED_OBJECT *nte; /* containing object */ + u8 space_id; + u32 length; + u32 address; + void *region_context; /* Region Specific data (Handler->Context + optional things like PCI _ADR) */ + + /* TBD: [Restructure] This field can go away when Pass3 is implemented */ + union acpi_operand_obj *method; /* Associated control method */ + + + union acpi_operand_obj *addr_handler; /* Handler for system notifies */ + ACPI_NAMESPACE_NODE *REGmethod; /* _REG method for this region (if any) */ + ACPI_NAMESPACE_NODE *node; /* containing object */ + union acpi_operand_obj *next; } ACPI_OBJECT_REGION; @@ -303,16 +238,11 @@ { ACPI_OBJECT_COMMON_HEADER - u32 system_level; - u32 resource_order; - u32 reserved3; - u32 reserved4; - - ACPI_HANDLE handle; - union acpi_obj_internal *sys_handler; /* Handler for system notifies */ - union acpi_obj_internal *drv_handler; /* Handler for driver notifies */ - void *reserved_p4; - void *reserved_p5; + u32 system_level; + u32 resource_order; + + union acpi_operand_obj *sys_handler; /* Handler for system notifies */ + union acpi_operand_obj *drv_handler; /* Handler for driver notifies */ } ACPI_OBJECT_POWER_RESOURCE; @@ -321,17 +251,13 @@ { ACPI_OBJECT_COMMON_HEADER - u32 proc_id; - ACPI_IO_ADDRESS pblk_address; - u16 fill1; - u32 pblk_length; - u32 reserved4; - - ACPI_HANDLE handle; - union acpi_obj_internal *sys_handler; /* Handler for system notifies */ - union acpi_obj_internal *drv_handler; /* Handler for driver notifies */ - union acpi_obj_internal *addr_handler; /* Handler for Address space */ - void *reserved_p5; + u32 proc_id; + u32 length; + ACPI_IO_ADDRESS address; + + union acpi_operand_obj *sys_handler; /* Handler for system notifies */ + union acpi_operand_obj *drv_handler; /* Handler for driver notifies */ + union acpi_operand_obj *addr_handler; /* Handler for Address space */ } ACPI_OBJECT_PROCESSOR; @@ -340,16 +266,9 @@ { ACPI_OBJECT_COMMON_HEADER - u32 reserved1; - u32 reserved2; - u32 reserved3; - u32 reserved4; - - ACPI_HANDLE handle; - union acpi_obj_internal *sys_handler; /* Handler for system notifies */ - union acpi_obj_internal *drv_handler; /* Handler for driver notifies */ - union acpi_obj_internal *addr_handler; /* Handler for Address space */ - void *reserved_p5; + union acpi_operand_obj *sys_handler; /* Handler for system notifies */ + union acpi_operand_obj *drv_handler; /* Handler for driver notifies */ + union acpi_operand_obj *addr_handler; /* Handler for Address space */ } ACPI_OBJECT_THERMAL_ZONE; @@ -358,18 +277,14 @@ * Internal types */ + typedef struct /* FIELD */ { ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_FIELD_INFO - u32 reserved4; - union acpi_obj_internal *container; /* Containing object */ - void *reserved_p2; - void *reserved_p3; - void *reserved_p4; - void *reserved_p5; + union acpi_operand_obj *container; /* Containing object */ } ACPI_OBJECT_FIELD; @@ -379,13 +294,10 @@ ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_FIELD_INFO - u32 value; /* Value to store into Bank_select */ + u32 value; /* Value to store into Bank_select */ - ACPI_HANDLE bank_select; /* Bank select register */ - union acpi_obj_internal *container; /* Containing object */ - void *reserved_p3; - void *reserved_p4; - void *reserved_p5; + ACPI_HANDLE bank_select; /* Bank select register */ + union acpi_operand_obj *container; /* Containing object */ } ACPI_OBJECT_BANK_FIELD; @@ -399,13 +311,10 @@ ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_FIELD_INFO - u32 value; /* Value to store into Index register */ + u32 value; /* Value to store into Index register */ - ACPI_HANDLE index; /* Index register */ - ACPI_HANDLE data; /* Data register */ - void *reserved_p3; - void *reserved_p4; - void *reserved_p5; + ACPI_HANDLE index; /* Index register */ + ACPI_HANDLE data; /* Data register */ } ACPI_OBJECT_INDEX_FIELD; @@ -414,16 +323,9 @@ { ACPI_OBJECT_COMMON_HEADER - u32 reserved1; - u32 reserved2; - u32 reserved3; - u32 reserved4; - - ACPI_NAMED_OBJECT *nte; /* Parent device */ - NOTIFY_HANDLER handler; - void *context; - void *reserved_p4; - void *reserved_p5; + ACPI_NAMESPACE_NODE *node; /* Parent device */ + NOTIFY_HANDLER handler; + void *context; } ACPI_OBJECT_NOTIFY_HANDLER; @@ -432,19 +334,20 @@ #define ADDR_HANDLER_DEFAULT_INSTALLED 0x1 + typedef struct /* ADDRESS HANDLER */ { ACPI_OBJECT_COMMON_HEADER - u16 space_id; - u16 hflags; - ADDRESS_SPACE_HANDLER handler; - - ACPI_NAMED_OBJECT *nte; /* Parent device */ - void *context; - ADDRESS_SPACE_SETUP setup; - union acpi_obj_internal *link; /* Link to next handler on device */ - union acpi_obj_internal *region_list; /* regions using this handler */ + u8 space_id; + u16 hflags; + ADDRESS_SPACE_HANDLER handler; + + ACPI_NAMESPACE_NODE *node; /* Parent device */ + void *context; + ADDRESS_SPACE_SETUP setup; + union acpi_operand_obj *region_list; /* regions using this handler */ + union acpi_operand_obj *next; } ACPI_OBJECT_ADDR_HANDLER; @@ -458,31 +361,27 @@ { ACPI_OBJECT_COMMON_HEADER - u16 op_code; - u8 fill1; - u8 target_type; /* Used for Index_op */ - u32 offset; /* Used for Arg_op, Local_op, and Index_op */ - u32 reserved3; - u32 reserved4; - - void *object; /* Name_op=>HANDLE to obj, Index_op=>ACPI_OBJECT_INTERNAL */ - ACPI_NAMED_OBJECT *nte; - union acpi_obj_internal **where; - void *reserved_p4; - void *reserved_p5; + u8 target_type; /* Used for Index_op */ + u16 op_code; + u32 offset; /* Used for Arg_op, Local_op, and Index_op */ + + void *object; /* Name_op=>HANDLE to obj, Index_op=>ACPI_OPERAND_OBJECT */ + ACPI_NAMESPACE_NODE *node; + union acpi_operand_obj **where; } ACPI_OBJECT_REFERENCE; /****************************************************************************** * - * ACPI_OBJECT_INTERNAL Descriptor - a giant union of all of the above + * ACPI_OPERAND_OBJECT Descriptor - a giant union of all of the above * *****************************************************************************/ -typedef union acpi_obj_internal +typedef union acpi_operand_obj { ACPI_OBJECT_COMMON common; + ACPI_OBJECT_CACHE_LIST cache; ACPI_OBJECT_NUMBER number; ACPI_OBJECT_STRING string; ACPI_OBJECT_BUFFER buffer; @@ -503,6 +402,6 @@ ACPI_OBJECT_NOTIFY_HANDLER notify_handler; ACPI_OBJECT_ADDR_HANDLER addr_handler; -} ACPI_OBJECT_INTERNAL; +} ACPI_OPERAND_OBJECT; #endif /* _ACOBJECT_H */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/include/acoutput.h linux/drivers/acpi/include/acoutput.h --- v2.4.0-test8/linux/drivers/acpi/include/acoutput.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/acpi/include/acoutput.h Fri Sep 15 14:30:30 2000 @@ -0,0 +1,124 @@ +/****************************************************************************** + * + * Name: acoutput.h -- debug output + * $Revision: 63 $ + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 R. Byron Moore + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __ACOUTPUT_H__ +#define __ACOUTPUT_H__ + +/* + * Debug levels and component IDs. These are used to control the + * granularity of the output of the DEBUG_PRINT macro -- on a per- + * component basis and a per-exception-type basis. + */ + +/* Component IDs -- used in the global "Debug_layer" */ + +#define GLOBAL 0x00000001 +#define COMMON 0x00000002 +#define PARSER 0x00000004 +#define DISPATCHER 0x00000008 +#define INTERPRETER 0x00000010 +#define NAMESPACE 0x00000020 +#define RESOURCE_MANAGER 0x00000040 +#define TABLE_MANAGER 0x00000080 +#define EVENT_HANDLING 0x00000100 +#define HARDWARE 0x00000200 +#define MISCELLANEOUS 0x00000400 +#define OS_DEPENDENT 0x00000800 + +#define BUS_MANAGER 0x00001000 + +#define PROCESSOR_CONTROL 0x00002000 +#define SYSTEM_CONTROL 0x00004000 +#define THERMAL_CONTROL 0x00008000 +#define POWER_CONTROL 0x00010000 + +#define EMBEDDED_CONTROLLER 0x00020000 +#define BATTERY 0x00040000 + +#define DEBUGGER 0x00100000 +#define ALL_COMPONENTS 0x001FFFFF + + +/* Exception level -- used in the global "Debug_level" */ + +#define ACPI_OK 0x00000001 +#define ACPI_INFO 0x00000002 +#define ACPI_WARN 0x00000004 +#define ACPI_ERROR 0x00000008 +#define ACPI_FATAL 0x00000010 +#define ACPI_DEBUG_OBJECT 0x00000020 +#define ACPI_ALL 0x0000003F + + +/* Trace level -- also used in the global "Debug_level" */ + +#define TRACE_PARSE 0x00000100 +#define TRACE_DISPATCH 0x00000200 +#define TRACE_LOAD 0x00000400 +#define TRACE_EXEC 0x00000800 +#define TRACE_NAMES 0x00001000 +#define TRACE_OPREGION 0x00002000 +#define TRACE_BFIELD 0x00004000 +#define TRACE_TRASH 0x00008000 +#define TRACE_TABLES 0x00010000 +#define TRACE_FUNCTIONS 0x00020000 +#define TRACE_VALUES 0x00040000 +#define TRACE_OBJECTS 0x00080000 +#define TRACE_ALLOCATIONS 0x00100000 +#define TRACE_RESOURCES 0x00200000 +#define TRACE_IO 0x00400000 +#define TRACE_INTERRUPTS 0x00800000 +#define TRACE_USER_REQUESTS 0x01000000 +#define TRACE_PACKAGE 0x02000000 +#define TRACE_MUTEX 0x04000000 + +#define TRACE_ALL 0x0FFFFF00 + + +/* Exceptionally verbose output -- also used in the global "Debug_level" */ + +#define VERBOSE_AML_DISASSEMBLE 0x10000000 +#define VERBOSE_INFO 0x20000000 +#define VERBOSE_TABLES 0x40000000 +#define VERBOSE_EVENTS 0x80000000 + +#define VERBOSE_ALL 0x70000000 + + +/* Defaults for Debug_level, debug and normal */ + +#define DEBUG_DEFAULT (ACPI_OK | ACPI_WARN | ACPI_ERROR | ACPI_DEBUG_OBJECT | TRACE_TABLES | TRACE_IO) +#define NORMAL_DEFAULT (ACPI_OK | ACPI_WARN | ACPI_ERROR | ACPI_DEBUG_OBJECT) +#define DEBUG_ALL (VERBOSE_AML_DISASSEMBLE | TRACE_ALL | ACPI_ALL) + +/* Misc defines */ + +#define HEX 0x01 +#define ASCII 0x02 +#define FULL_ADDRESS 0x04 +#define CHARS_PER_LINE 16 /* used in Dump_buf function */ + + +#endif /* __ACOUTPUT_H__ */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/include/acparser.h linux/drivers/acpi/include/acparser.h --- v2.4.0-test8/linux/drivers/acpi/include/acparser.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/acpi/include/acparser.h Fri Sep 15 14:30:30 2000 @@ -0,0 +1,345 @@ +/****************************************************************************** + * + * Module Name: acparser.h - AML Parser subcomponent prototypes and defines + * $Revision: 46 $ + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 R. Byron Moore + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef __ACPARSER_H__ +#define __ACPARSER_H__ + + +#define OP_HAS_RETURN_VALUE 1 + +/* variable # arguments */ + +#define ACPI_VAR_ARGS ACPI_UINT32_MAX + +/* maximum virtual address */ + +#define ACPI_MAX_AML ((u8 *)(~0UL)) + + +#define ACPI_PARSE_DELETE_TREE 0x0001 +#define ACPI_PARSE_NO_TREE_DELETE 0x0000 +#define ACPI_PARSE_TREE_MASK 0x0001 + +#define ACPI_PARSE_LOAD_PASS1 0x0010 +#define ACPI_PARSE_LOAD_PASS2 0x0020 +#define ACPI_PARSE_EXECUTE 0x0030 +#define ACPI_PARSE_MODE_MASK 0x0030 + +/* psapi - Parser external interfaces */ + +ACPI_STATUS +acpi_psx_load_table ( + u8 *pcode_addr, + u32 pcode_length); + +ACPI_STATUS +acpi_psx_execute ( + ACPI_NAMESPACE_NODE *method_node, + ACPI_OPERAND_OBJECT **params, + ACPI_OPERAND_OBJECT **return_obj_desc); + + +u8 +acpi_ps_is_namespace_object_op ( + u16 opcode); +u8 +acpi_ps_is_namespace_op ( + u16 opcode); + + +/****************************************************************************** + * + * Parser interfaces + * + *****************************************************************************/ + + +/* psargs - Parse AML opcode arguments */ + +u8 * +acpi_ps_get_next_package_end ( + ACPI_PARSE_STATE *parser_state); + +u32 +acpi_ps_get_next_package_length ( + ACPI_PARSE_STATE *parser_state); + +NATIVE_CHAR * +acpi_ps_get_next_namestring ( + ACPI_PARSE_STATE *parser_state); + +void +acpi_ps_get_next_simple_arg ( + ACPI_PARSE_STATE *parser_state, + u32 arg_type, /* type of argument */ + ACPI_PARSE_OBJECT *arg); /* (OUT) argument data */ + +void +acpi_ps_get_next_namepath ( + ACPI_PARSE_STATE *parser_state, + ACPI_PARSE_OBJECT *arg, + u32 *arg_count, + u8 method_call); + +ACPI_PARSE_OBJECT * +acpi_ps_get_next_field ( + ACPI_PARSE_STATE *parser_state); + +ACPI_PARSE_OBJECT * +acpi_ps_get_next_arg ( + ACPI_PARSE_STATE *parser_state, + u32 arg_type, + u32 *arg_count); + + +/* psopcode - AML Opcode information */ + +ACPI_OPCODE_INFO * +acpi_ps_get_opcode_info ( + u16 opcode); + +NATIVE_CHAR * +acpi_ps_get_opcode_name ( + u16 opcode); + + +/* psparse - top level parsing routines */ + +ACPI_STATUS +acpi_ps_find_object ( + u16 opcode, + ACPI_PARSE_OBJECT *op, + ACPI_WALK_STATE *walk_state, + ACPI_PARSE_OBJECT **out_op); + +void +acpi_ps_delete_parse_tree ( + ACPI_PARSE_OBJECT *root); + +ACPI_STATUS +acpi_ps_parse_loop ( + ACPI_WALK_STATE *walk_state); + +ACPI_STATUS +acpi_ps_parse_aml ( + ACPI_PARSE_OBJECT *start_scope, + u8 *aml, + u32 aml_size, + u32 parse_flags, + ACPI_NAMESPACE_NODE *method_node, + ACPI_OPERAND_OBJECT **params, + ACPI_OPERAND_OBJECT **caller_return_desc, + ACPI_PARSE_DOWNWARDS descending_callback, + ACPI_PARSE_UPWARDS ascending_callback); + +ACPI_STATUS +acpi_ps_parse_table ( + u8 *aml, + u32 aml_size, + ACPI_PARSE_DOWNWARDS descending_callback, + ACPI_PARSE_UPWARDS ascending_callback, + ACPI_PARSE_OBJECT **root_object); + +u16 +acpi_ps_peek_opcode ( + ACPI_PARSE_STATE *state); + + +/* psscope - Scope stack management routines */ + + +ACPI_STATUS +acpi_ps_init_scope ( + ACPI_PARSE_STATE *parser_state, + ACPI_PARSE_OBJECT *root); + +ACPI_PARSE_OBJECT * +acpi_ps_get_parent_scope ( + ACPI_PARSE_STATE *state); + +u8 +acpi_ps_has_completed_scope ( + ACPI_PARSE_STATE *parser_state); + +void +acpi_ps_pop_scope ( + ACPI_PARSE_STATE *parser_state, + ACPI_PARSE_OBJECT **op, + u32 *arg_list); + +ACPI_STATUS +acpi_ps_push_scope ( + ACPI_PARSE_STATE *parser_state, + ACPI_PARSE_OBJECT *op, + u32 remaining_args, + u32 arg_count); + +void +acpi_ps_cleanup_scope ( + ACPI_PARSE_STATE *state); + + +/* pstree - parse tree manipulation routines */ + +void +acpi_ps_append_arg( + ACPI_PARSE_OBJECT *op, + ACPI_PARSE_OBJECT *arg); + +ACPI_PARSE_OBJECT* +acpi_ps_find ( + ACPI_PARSE_OBJECT *scope, + NATIVE_CHAR *path, + u16 opcode, + u32 create); + +ACPI_PARSE_OBJECT * +acpi_ps_get_arg( + ACPI_PARSE_OBJECT *op, + u32 argn); + +ACPI_PARSE_OBJECT * +acpi_ps_get_child ( + ACPI_PARSE_OBJECT *op); + +ACPI_PARSE_OBJECT * +acpi_ps_get_depth_next ( + ACPI_PARSE_OBJECT *origin, + ACPI_PARSE_OBJECT *op); + + +/* pswalk - parse tree walk routines */ + +ACPI_STATUS +acpi_ps_walk_parsed_aml ( + ACPI_PARSE_OBJECT *start_op, + ACPI_PARSE_OBJECT *end_op, + ACPI_OPERAND_OBJECT *mth_desc, + ACPI_NAMESPACE_NODE *start_node, + ACPI_OPERAND_OBJECT **params, + ACPI_OPERAND_OBJECT **caller_return_desc, + ACPI_OWNER_ID owner_id, + ACPI_PARSE_DOWNWARDS descending_callback, + ACPI_PARSE_UPWARDS ascending_callback); + +ACPI_STATUS +acpi_ps_get_next_walk_op ( + ACPI_WALK_STATE *walk_state, + ACPI_PARSE_OBJECT *op, + ACPI_PARSE_UPWARDS ascending_callback); + + +/* psutils - parser utilities */ + + +ACPI_PARSE_STATE * +acpi_ps_create_state ( + u8 *aml, + u32 aml_size); + +void +acpi_ps_init_op ( + ACPI_PARSE_OBJECT *op, + u16 opcode); + +ACPI_PARSE_OBJECT * +acpi_ps_alloc_op ( + u16 opcode); + +void +acpi_ps_free_op ( + ACPI_PARSE_OBJECT *op); + +void +acpi_ps_delete_parse_cache ( + void); + +u8 +acpi_ps_is_leading_char ( + u32 c); + +u8 +acpi_ps_is_prefix_char ( + u32 c); + +u8 +acpi_ps_is_named_op ( + u16 opcode); + +u8 +acpi_ps_is_node_op ( + u16 opcode); + +u8 +acpi_ps_is_deferred_op ( + u16 opcode); + +u8 +acpi_ps_is_bytelist_op( + u16 opcode); + +u8 +acpi_ps_is_field_op( + u16 opcode); + +u8 +acpi_ps_is_create_field_op ( + u16 opcode); + +ACPI_PARSE2_OBJECT* +acpi_ps_to_extended_op( + ACPI_PARSE_OBJECT *op); + +u32 +acpi_ps_get_name( + ACPI_PARSE_OBJECT *op); + +void +acpi_ps_set_name( + ACPI_PARSE_OBJECT *op, + u32 name); + + +/* psdump - display parser tree */ + +u32 +acpi_ps_sprint_path ( + NATIVE_CHAR *buffer_start, + u32 buffer_size, + ACPI_PARSE_OBJECT *op); + +u32 +acpi_ps_sprint_op ( + NATIVE_CHAR *buffer_start, + u32 buffer_size, + ACPI_PARSE_OBJECT *op); + +void +acpi_ps_show ( + ACPI_PARSE_OBJECT *op); + + +#endif /* __ACPARSER_H__ */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/include/acpi.h linux/drivers/acpi/include/acpi.h --- v2.4.0-test8/linux/drivers/acpi/include/acpi.h Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/include/acpi.h Fri Sep 15 14:30:30 2000 @@ -1,7 +1,7 @@ - /****************************************************************************** * * Name: acpi.h - Master include file, Publics and external data. + * $Revision: 48 $ * *****************************************************************************/ @@ -31,20 +31,20 @@ * We put them here because we don't want to duplicate them * in the rest of the source code again and again. */ -#include "config.h" /* Configuration constants */ +#include "acconfig.h" /* Configuration constants */ #include "acenv.h" /* Target environment specific items */ #include "actypes.h" /* Fundamental data types */ #include "acexcep.h" /* Local exception codes */ -#include "macros.h" /* C macros */ -#include "actables.h" /* Acpi table definitions */ -#include "internal.h" /* Internal data types */ -#include "output.h" /* Error output and Debug macros */ +#include "acmacros.h" /* C macros */ +#include "actbl.h" /* Acpi table definitions */ +#include "aclocal.h" /* Internal data types */ +#include "acoutput.h" /* Error output and Debug macros */ #include "acpiosxf.h" /* Interfaces to the Acpi-to-OS layer*/ #include "acpixf.h" /* Acpi core external interfaces */ #include "acobject.h" /* Acpi internal object */ -#include "globals.h" /* All global variables */ -#include "hardware.h" /* Hardware defines and interfaces */ -#include "common.h" /* Common (global) interfaces */ +#include "acglobal.h" /* All global variables */ +#include "achware.h" /* Hardware defines and interfaces */ +#include "accommon.h" /* Common (global) interfaces */ #endif /* __ACPI_H__ */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/include/acpiosxf.h linux/drivers/acpi/include/acpiosxf.h --- v2.4.0-test8/linux/drivers/acpi/include/acpiosxf.h Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/include/acpiosxf.h Fri Sep 15 14:30:30 2000 @@ -244,7 +244,7 @@ ACPI_STATUS acpi_os_breakpoint ( - char *message); + NATIVE_CHAR *message); u8 acpi_os_readable ( @@ -264,12 +264,12 @@ s32 acpi_os_printf ( - const char *format, + const NATIVE_CHAR *format, ...); s32 acpi_os_vprintf ( - const char *format, + const NATIVE_CHAR *format, va_list args); /* @@ -278,7 +278,7 @@ u32 acpi_os_get_line ( - char *buffer); + NATIVE_CHAR *buffer); /* @@ -290,7 +290,7 @@ void *failed_assertion, void *file_name, u32 line_number, - char *message); + NATIVE_CHAR *message); #endif /* __ACPIOSD_H__ */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/include/acpixf.h linux/drivers/acpi/include/acpixf.h --- v2.4.0-test8/linux/drivers/acpi/include/acpixf.h Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/include/acpixf.h Fri Sep 15 14:30:30 2000 @@ -28,7 +28,7 @@ #define __ACXFACE_H__ #include "actypes.h" -#include "actables.h" +#include "actbl.h" /* * Global interfaces diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/include/acresrc.h linux/drivers/acpi/include/acresrc.h --- v2.4.0-test8/linux/drivers/acpi/include/acresrc.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/acpi/include/acresrc.h Fri Sep 15 14:30:30 2000 @@ -0,0 +1,304 @@ +/****************************************************************************** + * + * Name: acresrc.h - Resource Manager function prototypes + * $Revision: 20 $ + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 R. Byron Moore + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __ACRESRC_H__ +#define __ACRESRC_H__ + + +/* + * Function prototypes called from Acpi* APIs + */ + +ACPI_STATUS +acpi_rs_get_prt_method_data ( + ACPI_HANDLE handle, + ACPI_BUFFER *ret_buffer); + + +ACPI_STATUS +acpi_rs_get_crs_method_data ( + ACPI_HANDLE handle, + ACPI_BUFFER *ret_buffer); + +ACPI_STATUS +acpi_rs_get_prs_method_data ( + ACPI_HANDLE handle, + ACPI_BUFFER *ret_buffer); + +ACPI_STATUS +acpi_rs_set_srs_method_data ( + ACPI_HANDLE handle, + ACPI_BUFFER *ret_buffer); + +ACPI_STATUS +acpi_rs_create_resource_list ( + ACPI_OPERAND_OBJECT *byte_stream_buffer, + u8 *output_buffer, + u32 *output_buffer_length); + +ACPI_STATUS +acpi_rs_create_byte_stream ( + RESOURCE *linked_list_buffer, + u8 *output_buffer, + u32 *output_buffer_length); + +ACPI_STATUS +acpi_rs_create_pci_routing_table ( + ACPI_OPERAND_OBJECT *method_return_object, + u8 *output_buffer, + u32 *output_buffer_length); + + +/* + *Function prototypes called from Acpi_rs_create*APIs + */ + +void +acpi_rs_dump_resource_list ( + RESOURCE *resource); + +void +acpi_rs_dump_irq_list ( + u8 *route_table); + +ACPI_STATUS +acpi_rs_get_byte_stream_start ( + u8 *byte_stream_buffer, + u8 **byte_stream_start, + u32 *size); + +ACPI_STATUS +acpi_rs_calculate_list_length ( + u8 *byte_stream_buffer, + u32 byte_stream_buffer_length, + u32 *size_needed); + +ACPI_STATUS +acpi_rs_calculate_byte_stream_length ( + RESOURCE *linked_list_buffer, + u32 *size_needed); + +ACPI_STATUS +acpi_rs_calculate_pci_routing_table_length ( + ACPI_OPERAND_OBJECT *package_object, + u32 *buffer_size_needed); + +ACPI_STATUS +acpi_rs_byte_stream_to_list ( + u8 *byte_stream_buffer, + u32 byte_stream_buffer_length, + u8 **output_buffer); + +ACPI_STATUS +acpi_rs_list_to_byte_stream ( + RESOURCE *linked_list, + u32 byte_stream_size_needed, + u8 **output_buffer); + +ACPI_STATUS +acpi_rs_io_resource ( + u8 *byte_stream_buffer, + u32 *bytes_consumed, + u8 **output_buffer, + u32 *structure_size); + +ACPI_STATUS +acpi_rs_fixed_io_resource ( + u8 *byte_stream_buffer, + u32 *bytes_consumed, + u8 **output_buffer, + u32 *structure_size); + +ACPI_STATUS +acpi_rs_io_stream ( + RESOURCE *linked_list, + u8 **output_buffer, + u32 *bytes_consumed); + +ACPI_STATUS +acpi_rs_fixed_io_stream ( + RESOURCE *linked_list, + u8 **output_buffer, + u32 *bytes_consumed); + +ACPI_STATUS +acpi_rs_irq_resource ( + u8 *byte_stream_buffer, + u32 *bytes_consumed, + u8 **output_buffer, + u32 *structure_size); + +ACPI_STATUS +acpi_rs_irq_stream ( + RESOURCE *linked_list, + u8 **output_buffer, + u32 *bytes_consumed); + +ACPI_STATUS +acpi_rs_dma_resource ( + u8 *byte_stream_buffer, + u32 *bytes_consumed, + u8 **output_buffer, + u32 *structure_size); + +ACPI_STATUS +acpi_rs_dma_stream ( + RESOURCE *linked_list, + u8 **output_buffer, + u32 *bytes_consumed); + +ACPI_STATUS +acpi_rs_address16_resource ( + u8 *byte_stream_buffer, + u32 *bytes_consumed, + u8 **output_buffer, + u32 *structure_size); + +ACPI_STATUS +acpi_rs_address16_stream ( + RESOURCE *linked_list, + u8 **output_buffer, + u32 *bytes_consumed); + +ACPI_STATUS +acpi_rs_address32_resource ( + u8 *byte_stream_buffer, + u32 *bytes_consumed, + u8 **output_buffer, + u32 *structure_size); + +ACPI_STATUS +acpi_rs_address32_stream ( + RESOURCE *linked_list, + u8 **output_buffer, + u32 *bytes_consumed); + +ACPI_STATUS +acpi_rs_start_dependent_functions_resource ( + u8 *byte_stream_buffer, + u32 *bytes_consumed, + u8 **output_buffer, + u32 *structure_size); + +ACPI_STATUS +acpi_rs_end_dependent_functions_resource ( + u8 *byte_stream_buffer, + u32 *bytes_consumed, + u8 **output_buffer, + u32 *structure_size); + +ACPI_STATUS +acpi_rs_start_dependent_functions_stream ( + RESOURCE *linked_list, + u8 **output_buffer, + u32 *bytes_consumed); + +ACPI_STATUS +acpi_rs_end_dependent_functions_stream ( + RESOURCE *linked_list, + u8 **output_buffer, + u32 *bytes_consumed); + +ACPI_STATUS +acpi_rs_memory24_resource ( + u8 *byte_stream_buffer, + u32 *bytes_consumed, + u8 **output_buffer, + u32 *structure_size); + +ACPI_STATUS +acpi_rs_memory24_stream ( + RESOURCE *linked_list, + u8 **output_buffer, + u32 *bytes_consumed); + +ACPI_STATUS +acpi_rs_memory32_range_resource ( + u8 *byte_stream_buffer, + u32 *bytes_consumed, + u8 **output_buffer, + u32 *structure_size +); + +ACPI_STATUS +acpi_rs_fixed_memory32_resource ( + u8 *byte_stream_buffer, + u32 *bytes_consumed, + u8 **output_buffer, + u32 *structure_size); + +ACPI_STATUS +acpi_rs_memory32_range_stream ( + RESOURCE *linked_list, + u8 **output_buffer, + u32 *bytes_consumed); + +ACPI_STATUS +acpi_rs_fixed_memory32_stream ( + RESOURCE *linked_list, + u8 **output_buffer, + u32 *bytes_consumed); + +ACPI_STATUS +acpi_rs_extended_irq_resource ( + u8 *byte_stream_buffer, + u32 *bytes_consumed, + u8 **output_buffer, + u32 *structure_size); + +ACPI_STATUS +acpi_rs_extended_irq_stream ( + RESOURCE *linked_list, + u8 **output_buffer, + u32 *bytes_consumed); + +ACPI_STATUS +acpi_rs_end_tag_resource ( + u8 *byte_stream_buffer, + u32 *bytes_consumed, + u8 **output_buffer, + u32 *structure_size); + +ACPI_STATUS +acpi_rs_end_tag_stream ( + RESOURCE *linked_list, + u8 **output_buffer, + u32 *bytes_consumed); + +ACPI_STATUS +acpi_rs_vendor_resource ( + u8 *byte_stream_buffer, + u32 *bytes_consumed, + u8 **output_buffer, + u32 *structure_size); + +ACPI_STATUS +acpi_rs_vendor_stream ( + RESOURCE *linked_list, + u8 **output_buffer, + u32 *bytes_consumed); + + +#endif /* __ACRESRC_H__ */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/include/actables.h linux/drivers/acpi/include/actables.h --- v2.4.0-test8/linux/drivers/acpi/include/actables.h Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/include/actables.h Fri Sep 15 14:30:30 2000 @@ -1,7 +1,7 @@ - /****************************************************************************** * - * Name: actables.h - Table data structures defined in ACPI specification + * Name: actables.h - ACPI table management + * $Revision: 20 $ * *****************************************************************************/ @@ -27,162 +27,139 @@ #define __ACTABLES_H__ -/* - * Values for description table header signatures - */ - -#define RSDP_SIG "RSD PTR " /* RSDT Pointer signature */ -#define APIC_SIG "APIC" /* Multiple APIC Description Table */ -#define DSDT_SIG "DSDT" /* Differentiated System Description Table */ -#define FACP_SIG "FACP" /* Fixed ACPI Description Table */ -#define FACS_SIG "FACS" /* Firmware ACPI Control Structure */ -#define PSDT_SIG "PSDT" /* Persistent System Description Table */ -#define RSDT_SIG "RSDT" /* Root System Description Table */ -#define SSDT_SIG "SSDT" /* Secondary System Description Table */ -#define SBST_SIG "SBST" /* Smart Battery Specification Table */ -#define BOOT_SIG "BOOT" /* Boot table */ - - -#define GL_OWNED 0x02 /* Ownership of global lock is bit 1 */ +/* Used in Acpi_tb_map_acpi_table for size parameter if table header is to be used */ -/* values of Mapic.Model */ +#define SIZE_IN_HEADER 0 -#define DUAL_PIC 0 -#define MULTIPLE_APIC 1 -/* values of Type in APIC_HEADER */ - -#define APIC_PROC 0 -#define APIC_IO 1 +ACPI_STATUS +acpi_tb_handle_to_object ( + u16 table_id, + ACPI_TABLE_DESC **table_desc); /* - * Architecture-independent tables - * The architecture dependent tables are in separate files + * Acpi_tbfac - FACP, FACS utilities */ -typedef struct /* Root System Descriptor Pointer */ -{ - char signature [8]; /* contains "RSD PTR " */ - u8 checksum; /* to make sum of struct == 0 */ - char oem_id [6]; /* OEM identification */ - u8 reserved; /* reserved - must be zero */ - u32 rsdt_physical_address; /* physical address of RSDT */ - -} ROOT_SYSTEM_DESCRIPTOR_POINTER; +ACPI_STATUS +acpi_tb_get_table_facs ( + ACPI_TABLE_HEADER *buffer_ptr, + ACPI_TABLE_DESC *table_info); -typedef struct /* ACPI common table header */ -{ - char signature [4]; /* identifies type of table */ - u32 length; /* length of table, in bytes, - * including header */ - u8 revision; /* specification minor version # */ - u8 checksum; /* to make sum of entire table == 0 */ - char oem_id [6]; /* OEM identification */ - char oem_table_id [8]; /* OEM table identification */ - u32 oem_revision; /* OEM revision number */ - char asl_compiler_id [4]; /* ASL compiler vendor ID */ - u32 asl_compiler_revision; /* ASL compiler revision number */ +/* + * Acpi_tbget - Table "get" routines + */ -} ACPI_TABLE_HEADER; +ACPI_STATUS +acpi_tb_get_table_ptr ( + ACPI_TABLE_TYPE table_type, + u32 instance, + ACPI_TABLE_HEADER **table_ptr_loc); +ACPI_STATUS +acpi_tb_get_table ( + void *physical_address, + ACPI_TABLE_HEADER *buffer_ptr, + ACPI_TABLE_DESC *table_info); -typedef struct /* APIC Table */ -{ - ACPI_TABLE_HEADER header; /* table header */ - u32 local_apic_address; /* Physical address for accessing local APICs */ - u32 PCATcompat : 1; /* a one indicates system also has dual 8259s */ - u32 reserved1 : 31; -} APIC_TABLE; +/* + * Acpi_tbgetall - Get all firmware ACPI tables + */ +ACPI_STATUS +acpi_tb_get_all_tables ( + u32 number_of_tables, + ACPI_TABLE_HEADER *buffer_ptr); -typedef struct /* APIC Header */ -{ - u8 type; /* APIC type. Either APIC_PROC or APIC_IO */ - u8 length; /* Length of APIC structure */ -} APIC_HEADER; +/* + * Acpi_tbinstall - Table installation + */ +ACPI_STATUS +acpi_tb_install_table ( + ACPI_TABLE_HEADER *table_ptr, + ACPI_TABLE_DESC *table_info); -typedef struct /* Processor APIC */ -{ - APIC_HEADER header; - u8 processor_apic_id; /* ACPI processor id */ - u8 local_apic_id; /* processor's local APIC id */ - u32 processor_enabled: 1; /* Processor is usable if set */ - u32 reserved1 : 32; +ACPI_STATUS +acpi_tb_recognize_table ( + ACPI_TABLE_HEADER *table_ptr, + ACPI_TABLE_DESC *table_info); -} PROCESSOR_APIC; +ACPI_STATUS +acpi_tb_init_table_descriptor ( + ACPI_TABLE_TYPE table_type, + ACPI_TABLE_DESC *table_info); -typedef struct /* IO APIC */ -{ - APIC_HEADER header; - u8 io_apic_id; /* I/O APIC ID */ - u8 reserved; /* reserved - must be zero */ - u32 io_apic_address; /* APIC's physical address */ - u32 vector; /* interrupt vector index where INTI - * lines start */ -} IO_APIC; +/* + * Acpi_tbremove - Table removal and deletion + */ +void +acpi_tb_delete_acpi_tables ( + void); -/* -** IA64 TODO: Add SAPIC Tables -*/ +void +acpi_tb_delete_acpi_table ( + ACPI_TABLE_TYPE type); -/* -** IA64 TODO: Modify Smart Battery Description to comply with ACPI IA64 -** extensions. -*/ -typedef struct /* Smart Battery Description Table */ -{ - ACPI_TABLE_HEADER header; - u32 warning_level; - u32 low_level; - u32 critical_level; +ACPI_TABLE_DESC * +acpi_tb_delete_single_table ( + ACPI_TABLE_DESC *table_desc); -} SMART_BATTERY_DESCRIPTION_TABLE; +void +acpi_tb_free_acpi_tables_of_type ( + ACPI_TABLE_DESC *table_info); /* - * ACPI Table information. We save the table address, length, - * and type of memory allocation (mapped or allocated) for each - * table for 1) when we exit, and 2) if a new table is installed + * Acpi_tbrsd - RSDP, RSDT utilities */ -#define ACPI_MEM_NOT_ALLOCATED 0 -#define ACPI_MEM_ALLOCATED 1 -#define ACPI_MEM_MAPPED 2 - -#define ACPI_TABLE_SINGLE 0 -#define ACPI_TABLE_MULTIPLE 1 - - -/* Data about each known table type */ +ACPI_STATUS +acpi_tb_get_table_rsdt ( + u32 *number_of_tables); -typedef struct _acpi_table_support -{ - char *name; - char *signature; - u8 sig_length; - u8 flags; - u16 status; - void **global_ptr; +u8 * +acpi_tb_scan_memory_for_rsdp ( + u8 *start_address, + u32 length); -} ACPI_TABLE_SUPPORT; +ACPI_STATUS +acpi_tb_find_rsdp ( + ACPI_TABLE_DESC *table_info); /* - * Get the architecture-specific tables + * Acpi_tbutils - common table utilities */ -#ifdef IA64 -#include "actbl64.h" -#else -#include "actbl32.h" -#endif +u8 +acpi_tb_system_table_pointer ( + void *where); + +ACPI_STATUS +acpi_tb_map_acpi_table ( + void *physical_address, + u32 *size, + void **logical_address); + +ACPI_STATUS +acpi_tb_verify_table_checksum ( + ACPI_TABLE_HEADER *table_header); + +u8 +acpi_tb_checksum ( + void *buffer, + u32 length); + +ACPI_STATUS +acpi_tb_validate_table_header ( + ACPI_TABLE_HEADER *table_header); #endif /* __ACTABLES_H__ */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/include/actbl.h linux/drivers/acpi/include/actbl.h --- v2.4.0-test8/linux/drivers/acpi/include/actbl.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/acpi/include/actbl.h Fri Sep 15 14:30:30 2000 @@ -0,0 +1,190 @@ +/****************************************************************************** + * + * Name: actbl.h - Table data structures defined in ACPI specification + * $Revision: 34 $ + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 R. Byron Moore + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __ACTBL_H__ +#define __ACTBL_H__ + + +/* + * Values for description table header signatures + */ + +#define RSDP_SIG "RSD PTR " /* RSDT Pointer signature */ +#define APIC_SIG "APIC" /* Multiple APIC Description Table */ +#define DSDT_SIG "DSDT" /* Differentiated System Description Table */ +#define FACP_SIG "FACP" /* Fixed ACPI Description Table */ +#define FACS_SIG "FACS" /* Firmware ACPI Control Structure */ +#define PSDT_SIG "PSDT" /* Persistent System Description Table */ +#define RSDT_SIG "RSDT" /* Root System Description Table */ +#define SSDT_SIG "SSDT" /* Secondary System Description Table */ +#define SBST_SIG "SBST" /* Smart Battery Specification Table */ +#define BOOT_SIG "BOOT" /* Boot table */ + + +#define GL_OWNED 0x02 /* Ownership of global lock is bit 1 */ + +/* values of Mapic.Model */ + +#define DUAL_PIC 0 +#define MULTIPLE_APIC 1 + +/* values of Type in APIC_HEADER */ + +#define APIC_PROC 0 +#define APIC_IO 1 + + +/* + * Architecture-independent tables + * The architecture dependent tables are in separate files + */ + +typedef struct /* Root System Descriptor Pointer */ +{ + NATIVE_CHAR signature [8]; /* contains "RSD PTR " */ + u8 checksum; /* to make sum of struct == 0 */ + NATIVE_CHAR oem_id [6]; /* OEM identification */ + u8 reserved; /* reserved - must be zero */ + u32 rsdt_physical_address; /* physical address of RSDT */ + +} ROOT_SYSTEM_DESCRIPTOR_POINTER; + + +typedef struct /* ACPI common table header */ +{ + NATIVE_CHAR signature [4]; /* identifies type of table */ + u32 length; /* length of table, in bytes, + * including header */ + u8 revision; /* specification minor version # */ + u8 checksum; /* to make sum of entire table == 0 */ + NATIVE_CHAR oem_id [6]; /* OEM identification */ + NATIVE_CHAR oem_table_id [8]; /* OEM table identification */ + u32 oem_revision; /* OEM revision number */ + NATIVE_CHAR asl_compiler_id [4]; /* ASL compiler vendor ID */ + u32 asl_compiler_revision; /* ASL compiler revision number */ + +} ACPI_TABLE_HEADER; + + +typedef struct /* APIC Table */ +{ + ACPI_TABLE_HEADER header; /* table header */ + u32 local_apic_address; /* Physical address for accessing local APICs */ + u32 PCATcompat : 1; /* a one indicates system also has dual 8259s */ + u32 reserved1 : 31; + +} APIC_TABLE; + + +typedef struct /* APIC Header */ +{ + u8 type; /* APIC type. Either APIC_PROC or APIC_IO */ + u8 length; /* Length of APIC structure */ + +} APIC_HEADER; + + +typedef struct /* Processor APIC */ +{ + APIC_HEADER header; + u8 processor_apic_id; /* ACPI processor id */ + u8 local_apic_id; /* processor's local APIC id */ + u32 processor_enabled: 1; /* Processor is usable if set */ + u32 reserved1 : 32; + +} PROCESSOR_APIC; + + +typedef struct /* IO APIC */ +{ + APIC_HEADER header; + u8 io_apic_id; /* I/O APIC ID */ + u8 reserved; /* reserved - must be zero */ + u32 io_apic_address; /* APIC's physical address */ + u32 vector; /* interrupt vector index where INTI + * lines start */ +} IO_APIC; + + +/* +** IA64 TODO: Add SAPIC Tables +*/ + +/* +** IA64 TODO: Modify Smart Battery Description to comply with ACPI IA64 +** extensions. +*/ +typedef struct /* Smart Battery Description Table */ +{ + ACPI_TABLE_HEADER header; + u32 warning_level; + u32 low_level; + u32 critical_level; + +} SMART_BATTERY_DESCRIPTION_TABLE; + + +/* + * ACPI Table information. We save the table address, length, + * and type of memory allocation (mapped or allocated) for each + * table for 1) when we exit, and 2) if a new table is installed + */ + +#define ACPI_MEM_NOT_ALLOCATED 0 +#define ACPI_MEM_ALLOCATED 1 +#define ACPI_MEM_MAPPED 2 + +/* Definitions for the Flags bitfield member of ACPI_TABLE_SUPPORT */ + +#define ACPI_TABLE_SINGLE 0 +#define ACPI_TABLE_MULTIPLE 1 + + +/* Data about each known table type */ + +typedef struct _acpi_table_support +{ + NATIVE_CHAR *name; + NATIVE_CHAR *signature; + u8 sig_length; + u8 flags; + u16 status; + void **global_ptr; + +} ACPI_TABLE_SUPPORT; + + +/* + * Get the architecture-specific tables + */ + +#ifdef IA64 +#include "actbl64.h" +#else +#include "actbl32.h" +#endif + + +#endif /* __ACTBL_H__ */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/include/actbl32.h linux/drivers/acpi/include/actbl32.h --- v2.4.0-test8/linux/drivers/acpi/include/actbl32.h Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/include/actbl32.h Fri Sep 15 14:30:30 2000 @@ -1,6 +1,7 @@ /****************************************************************************** * * Name: actbl32.h - ACPI tables specific to IA32 + * $Revision: 11 $ * *****************************************************************************/ @@ -40,7 +41,7 @@ typedef struct { - char signature[4]; /* signature "FACS" */ + NATIVE_CHAR signature[4]; /* signature "FACS" */ u32 length; /* length of structure, in bytes */ u32 hardware_signature; /* hardware configuration signature */ u32 firmware_waking_vector; /* ACPI OS waking vector */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/include/actbl64.h linux/drivers/acpi/include/actbl64.h --- v2.4.0-test8/linux/drivers/acpi/include/actbl64.h Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/include/actbl64.h Fri Sep 15 14:30:30 2000 @@ -1,7 +1,7 @@ - /****************************************************************************** * * Name: actbl64.h - ACPI tables specific to IA64 + * $Revision: 12 $ * *****************************************************************************/ @@ -45,7 +45,7 @@ typedef struct { - char signature[4]; /* signature "FACS" */ + NATIVE_CHAR signature[4]; /* signature "FACS" */ u32 length; /* length of structure, in bytes */ u32 hardware_signature; /* hardware configuration signature */ u32 reserved4; /* must be 0 */ @@ -65,7 +65,7 @@ ACPI_TABLE_HEADER header; /* table header */ u32 reserved_pad; /* IA64 alignment, must be 0 */ ACPI_TBLPTR firmware_ctrl; /* Physical address of FACS */ - ACPI_TBLPTR acpi_dsdt; /* Physical address of DSDT */ + ACPI_TBLPTR dsdt; /* Physical address of DSDT */ u8 model; /* System Interrupt Model */ u8 address_space; /* Address Space Bitmask */ u16 sci_int; /* System vector of SCI interrupt */ @@ -90,8 +90,8 @@ u8 gpe1_blk_len; /* Byte Length of ports at gpe1_blk */ u8 gpe1_base; /* offset in gpe model where gpe1 events start */ u8 reserved3; /* reserved */ - u16 Plvl2_lat; /* worst case HW latency to enter/exit C2 state */ - u16 Plvl3_lat; /* worst case HW latency to enter/exit C3 state */ + u16 plvl2_lat; /* worst case HW latency to enter/exit C2 state */ + u16 plvl3_lat; /* worst case HW latency to enter/exit C3 state */ u8 day_alrm; /* index to day-of-month alarm in RTC CMOS RAM */ u8 mon_alrm; /* index to month-of-year alarm in RTC CMOS RAM */ u8 century; /* index to century in RTC CMOS RAM */ @@ -99,11 +99,11 @@ u32 flush_cash : 1; /* PAL_FLUSH_CACHE is correctly supported */ u32 reserved5 : 1; /* reserved - must be zero */ u32 proc_c1 : 1; /* all processors support C1 state */ - u32 Plvl2_up : 1; /* C2 state works on MP system */ + u32 plvl2_up : 1; /* C2 state works on MP system */ u32 pwr_button : 1; /* Power button is handled as a generic feature */ u32 sleep_button : 1; /* Sleep button is handled as a generic feature, or not present */ u32 fixed_rTC : 1; /* RTC wakeup stat not in fixed register space */ - u32 RTCS4 : 1; /* RTC wakeup stat not possible from S4 */ + u32 rtcs4 : 1; /* RTC wakeup stat not possible from S4 */ u32 tmr_val_ext : 1; /* tmr_val is 32 bits */ u32 dock_cap : 1; /* Supports Docking */ u32 reserved6 : 22; /* reserved - must be zero */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/include/actypes.h linux/drivers/acpi/include/actypes.h --- v2.4.0-test8/linux/drivers/acpi/include/actypes.h Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/include/actypes.h Fri Sep 15 14:30:30 2000 @@ -1,7 +1,7 @@ - /****************************************************************************** * * Name: actypes.h - Common data types for the entire ACPI subsystem + * $Revision: 131 $ * *****************************************************************************/ @@ -23,15 +23,18 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _ACTYPES_H -#define _ACTYPES_H +#ifndef __ACTYPES_H__ +#define __ACTYPES_H__ /*! [Begin] no source code translation (keep the typedefs) */ /* * Data types - Fixed across all compilation models * - * BOOLEAN Logical Boolean. 1 byte value containing a 0 for FALSE or a 1 for TRUE. Other values are undefined. + * BOOLEAN Logical Boolean. + * 1 byte value containing a 0 for FALSE or a 1 for TRUE. + * Other values are undefined. + * * INT8 8-bit (1 byte) signed value * UINT8 8-bit (1 byte) unsigned value * INT16 16-bit (2 byte) signed value @@ -45,14 +48,17 @@ * UCHAR Character. 1 byte unsigned value. */ +#ifdef __ia64__ +#define _IA64 +#endif + #ifdef _IA64 /* * 64-bit type definitions */ -typedef signed char INT8; typedef unsigned char UINT8; +typedef unsigned char BOOLEAN; typedef unsigned char UCHAR; -typedef short INT16; typedef unsigned short UINT16; typedef int INT32; typedef unsigned int UINT32; @@ -74,10 +80,9 @@ /* * 16-bit type definitions */ -typedef signed char INT8; typedef unsigned char UINT8; +typedef unsigned char BOOLEAN; typedef unsigned char UCHAR; -typedef int INT16; typedef unsigned int UINT16; typedef long INT32; typedef unsigned long UINT32; @@ -96,10 +101,9 @@ /* * 32-bit type definitions (default) */ -typedef signed char INT8; typedef unsigned char UINT8; +typedef unsigned char BOOLEAN; typedef unsigned char UCHAR; -typedef short INT16; typedef unsigned short UINT16; typedef int INT32; typedef unsigned int UINT32; @@ -113,19 +117,15 @@ #define ALIGNED_ADDRESS_BOUNDARY 0x00000004 #define _HW_ALIGNMENT_SUPPORT - #endif - - /* * Miscellaneous common types */ -typedef UINT8 BOOLEAN; typedef UINT32 UINT32_BIT; -typedef NATIVE_INT ACPI_PTRDIFF; -typedef NATIVE_UINT ACPI_SIZE; +typedef NATIVE_UINT ACPI_PTRDIFF; +typedef char NATIVE_CHAR; /* @@ -133,7 +133,6 @@ */ #define ACPI_UCHAR_MAX (UCHAR) 0xFF -#define ACPI_INT32_MAX (INT32) 0x7FFFFFFF #define ACPI_UINT32_MAX (UINT32) 0xFFFFFFFF @@ -141,14 +140,11 @@ /* * Types used only in translated source */ -typedef INT8 s8; -typedef INT16 s16; typedef INT32 s32; typedef UINT8 u8; typedef UINT16 u16; typedef UINT32 u32; #endif - /*! [End] no source code translation !*/ @@ -176,9 +172,9 @@ */ typedef u32 ACPI_STATUS; /* All ACPI Exceptions */ -typedef u32 ACPI_NAME; /* 4-char ACPI name */ +typedef u32 ACPI_NAME; /* 4-s8 ACPI name */ typedef char* ACPI_STRING; /* Null terminated ASCII string */ -typedef void* ACPI_HANDLE; /* Actually a ptr to an NTE */ +typedef void* ACPI_HANDLE; /* Actually a ptr to an Node */ /* @@ -223,10 +219,12 @@ /* * Types associated with names. The first group of - * values correspond to the definition of the ACPI Object_type operator (See the ACPI Spec). - * Therefore, only add to the first group if the spec changes! + * values correspond to the definition of the ACPI + * Object_type operator (See the ACPI Spec). Therefore, + * only add to the first group if the spec changes! * - * Types must be kept in sync with the Acpi_ns_properties and Acpi_ns_type_names arrays + * Types must be kept in sync with the Acpi_ns_properties + * and Acpi_ns_type_names arrays */ typedef u32 ACPI_OBJECT_TYPE; @@ -238,14 +236,14 @@ #define ACPI_TYPE_BUFFER 3 /* 0x03 */ #define ACPI_TYPE_PACKAGE 4 /* 0x04 Byte_const, multiple Data_term/Constant/Super_name */ #define ACPI_TYPE_FIELD_UNIT 5 /* 0x05 */ -#define ACPI_TYPE_DEVICE 6 /* 0x06 Name, multiple Named_object */ +#define ACPI_TYPE_DEVICE 6 /* 0x06 Name, multiple Node */ #define ACPI_TYPE_EVENT 7 /* 0x07 */ #define ACPI_TYPE_METHOD 8 /* 0x08 Name, Byte_const, multiple Code */ #define ACPI_TYPE_MUTEX 9 /* 0x09 */ #define ACPI_TYPE_REGION 10 /* 0x0A */ -#define ACPI_TYPE_POWER 11 /* 0x0B Name,Byte_const,Word_const,multi Named_object */ +#define ACPI_TYPE_POWER 11 /* 0x0B Name,Byte_const,Word_const,multi Node */ #define ACPI_TYPE_PROCESSOR 12 /* 0x0C Name,Byte_const,DWord_const,Byte_const,multi Nm_o */ -#define ACPI_TYPE_THERMAL 13 /* 0x0D Name, multiple Named_object */ +#define ACPI_TYPE_THERMAL 13 /* 0x0D Name, multiple Node */ #define ACPI_TYPE_BUFFER_FIELD 14 /* 0x0E */ #define ACPI_TYPE_DDB_HANDLE 15 /* 0x0F */ #define ACPI_TYPE_DEBUG_OBJECT 16 /* 0x10 */ @@ -254,32 +252,39 @@ /* * This section contains object types that do not relate to the ACPI Object_type operator. - * They are used for various internal purposes only. A numerical gap is provided in - * case additional "official" Object_types are added in the future. Also, values exceeding - * the largest official ACPI Object_type must not overlap with defined AML opcodes. - */ -#define INTERNAL_TYPE_BEGIN 25 -#define INTERNAL_TYPE_DEF_FIELD 25 /* 0x19 */ -#define INTERNAL_TYPE_BANK_FIELD 26 /* 0x1A */ -#define INTERNAL_TYPE_INDEX_FIELD 27 /* 0x1B */ -#define INTERNAL_TYPE_DEF_FIELD_DEFN 28 /* 0x1C Name, Byte_const, multiple Field_element */ -#define INTERNAL_TYPE_BANK_FIELD_DEFN 29 /* 0x1D 2 Name,DWord_const,Byte_const,multi Field_element */ -#define INTERNAL_TYPE_INDEX_FIELD_DEFN 30 /* 0x1E 2 Name, Byte_const, multiple Field_element */ -#define INTERNAL_TYPE_IF 31 /* 0x1F Op_code, multiple Code */ -#define INTERNAL_TYPE_ELSE 32 /* 0x20 multiple Code */ -#define INTERNAL_TYPE_WHILE 33 /* 0x21 Op_code, multiple Code */ -#define INTERNAL_TYPE_SCOPE 34 /* 0x22 Name, multiple Named_object */ -#define INTERNAL_TYPE_DEF_ANY 35 /* 0x23 type is Any, suppress search of enclosing scopes */ -#define INTERNAL_TYPE_REFERENCE 36 /* 0x24 Arg#, Local#, Name, Debug; used only in descriptors */ -#define INTERNAL_TYPE_ALIAS 37 /* 0x25 */ -#define INTERNAL_TYPE_NOTIFY 38 /* 0x26 */ -#define INTERNAL_TYPE_ADDRESS_HANDLER 39 /* 0x27 */ -#define INTERNAL_TYPE_METHOD_ARGUMENT 40 /* 0x28 */ -#define INTERNAL_TYPE_METHOD_LOCAL_VAR 41 /* 0x29 */ + * They are used for various internal purposes only. If new predefined ACPI_TYPEs are + * added (via the ACPI specification), these internal types must move upwards. + * Also, values exceeding the largest official ACPI Object_type must not overlap with + * defined AML opcodes. + */ +#define INTERNAL_TYPE_BEGIN 17 + +#define INTERNAL_TYPE_DEF_FIELD 17 /* 0x11 */ +#define INTERNAL_TYPE_BANK_FIELD 18 /* 0x12 */ +#define INTERNAL_TYPE_INDEX_FIELD 19 /* 0x13 */ +#define INTERNAL_TYPE_REFERENCE 20 /* 0x14 Arg#, Local#, Name, Debug; used only in descriptors */ +#define INTERNAL_TYPE_ALIAS 21 /* 0x15 */ +#define INTERNAL_TYPE_NOTIFY 22 /* 0x16 */ +#define INTERNAL_TYPE_ADDRESS_HANDLER 23 /* 0x17 */ + +#define INTERNAL_TYPE_NODE_MAX 23 + +/* These are pseudo-types because there are never any namespace nodes with these types */ + +#define INTERNAL_TYPE_DEF_FIELD_DEFN 24 /* 0x18 Name, Byte_const, multiple Field_element */ +#define INTERNAL_TYPE_BANK_FIELD_DEFN 25 /* 0x19 2 Name,DWord_const,Byte_const,multi Field_element */ +#define INTERNAL_TYPE_INDEX_FIELD_DEFN 26 /* 0x1A 2 Name, Byte_const, multiple Field_element */ +#define INTERNAL_TYPE_IF 27 /* 0x1B Op_code, multiple Code */ +#define INTERNAL_TYPE_ELSE 28 /* 0x1C multiple Code */ +#define INTERNAL_TYPE_WHILE 29 /* 0x1D Op_code, multiple Code */ +#define INTERNAL_TYPE_SCOPE 30 /* 0x1E Name, multiple Node */ +#define INTERNAL_TYPE_DEF_ANY 31 /* 0x1F type is Any, suppress search of enclosing scopes */ +#define INTERNAL_TYPE_METHOD_ARGUMENT 32 /* 0x20 */ +#define INTERNAL_TYPE_METHOD_LOCAL_VAR 33 /* 0x21 */ -#define INTERNAL_TYPE_MAX 41 +#define INTERNAL_TYPE_MAX 33 -#define INTERNAL_TYPE_INVALID 42 +#define INTERNAL_TYPE_INVALID 34 #define ACPI_TYPE_NOT_FOUND 0xFF /* @@ -375,7 +380,7 @@ { ACPI_OBJECT_TYPE type; u32 length; /* # of bytes in string, excluding trailing null */ - char *pointer; /* points to the string value */ + NATIVE_CHAR *pointer; /* points to the string value */ } string; struct @@ -551,7 +556,8 @@ u32 address, u32 bit_width, u32 *value, - void *context); + void *handler_context, + void *region_context); #define ACPI_DEFAULT_HANDLER ((ADDRESS_SPACE_HANDLER) NULL) @@ -561,7 +567,7 @@ ACPI_HANDLE region_handle, u32 function, void *handler_context, - void **return_context); + void **region_context); #define ACPI_REGION_ACTIVATE 0 #define ACPI_REGION_DEACTIVATE 1 @@ -589,13 +595,11 @@ #define ACPI_COMMON_OBJ_INFO \ - ACPI_OBJECT_TYPE type; /* ACPI object type */\ - ACPI_NAME name; /* ACPI object Name */\ - /*\ - * TBD: [Restructure] Do we want or need these next two??\ - */\ - ACPI_HANDLE parent; /* Parent object */\ - ACPI_HANDLE children; /* Linked list of children */\ + ACPI_OBJECT_TYPE type; /* ACPI object type */ \ + ACPI_NAME name; /* ACPI object Name */ \ + /* TBD: [Restructure] Do we want or need these next two??*/ \ + ACPI_HANDLE parent; /* Parent object */ \ + ACPI_HANDLE children; /* Linked list of children */ \ u32 valid /* ????? */ typedef struct @@ -611,8 +615,8 @@ /* * TBD: [Restructure]: a HID or a _UID can return either a number or a string */ - char hardware_id [9]; /* _HID value if any */ - char unique_id[9]; /* _UID value if any */ + NATIVE_CHAR hardware_id [9]; /* _HID value if any */ + NATIVE_CHAR unique_id[9]; /* _UID value if any */ u32 address; /* _ADR value if any */ u32 current_status; /* _STA value */ } ACPI_DEVICE_INFO; @@ -622,7 +626,6 @@ typedef struct { - void *handler_context; u32 seg; u32 bus; u32 dev_func; @@ -631,11 +634,9 @@ typedef struct { - void *handler_context; - char *mapped_physical_address; - char *mapped_logical_address; + u8 *mapped_physical_address; + u8 *mapped_logical_address; u32 mapped_length; - } MEM_HANDLER_CONTEXT; @@ -858,7 +859,7 @@ u32 address_length; u32 resource_source_index; u32 resource_source_string_length; - u8 resource_source[1]; + NATIVE_CHAR resource_source[1]; } ADDRESS16_RESOURCE; @@ -877,7 +878,7 @@ u32 address_length; u32 resource_source_index; u32 resource_source_string_length; - u8 resource_source[1]; + NATIVE_CHAR resource_source[1]; } ADDRESS32_RESOURCE; @@ -891,7 +892,7 @@ u32 interrupts[1]; u32 resource_source_index; u32 resource_source_string_length; - u8 resource_source[1]; + NATIVE_CHAR resource_source[1]; } EXTENDED_IRQ_RESOURCE; @@ -951,7 +952,7 @@ u32 address; u32 pin; u32 source_index; - u8 source[1]; + NATIVE_CHAR source[1]; } PRT_ENTRY; @@ -967,4 +968,4 @@ * END: Definitions for PCI Routing tables */ -#endif /* ACTYPES_H */ +#endif /* __ACTYPES_H__ */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/include/amlcode.h linux/drivers/acpi/include/amlcode.h --- v2.4.0-test8/linux/drivers/acpi/include/amlcode.h Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/include/amlcode.h Fri Sep 15 14:30:30 2000 @@ -1,9 +1,9 @@ - /****************************************************************************** * * Name: amlcode.h - Definitions for AML, as included in "definition blocks" * Declarations and definitions contained herein are derived * directly from the ACPI specification. + * $Revision: 39 $ * *****************************************************************************/ @@ -108,7 +108,7 @@ #define AML_IF_OP (u16) 0xa0 #define AML_ELSE_OP (u16) 0xa1 #define AML_WHILE_OP (u16) 0xa2 -#define AML_NOOP_CODE (u16) 0xa3 +#define AML_NOOP_OP (u16) 0xa3 #define AML_RETURN_OP (u16) 0xa4 #define AML_BREAK_OP (u16) 0xa5 #define AML_BREAK_POINT_OP (u16) 0xcc @@ -133,9 +133,9 @@ #define AML_WAIT_OP (u16) 0x5b25 #define AML_RESET_OP (u16) 0x5b26 #define AML_RELEASE_OP (u16) 0x5b27 -#define AML_FROM_BCDOP (u16) 0x5b28 -#define AML_TO_BCDOP (u16) 0x5b29 -#define AML_UN_LOAD_OP (u16) 0x5b2a +#define AML_FROM_BCD_OP (u16) 0x5b28 +#define AML_TO_BCD_OP (u16) 0x5b29 +#define AML_UNLOAD_OP (u16) 0x5b2a #define AML_REVISION_OP (u16) 0x5b30 #define AML_DEBUG_OP (u16) 0x5b31 #define AML_FATAL_OP (u16) 0x5b32 @@ -156,7 +156,11 @@ #define AML_LNOTEQUAL_OP (u16) 0x9293 -/* Internal opcodes */ +/* + * Internal opcodes + * Use only "Unknown" AML opcodes, don't attempt to use + * any valid ACPI ASCII values (A-Z, 0-9, '-') + */ #define AML_NAMEPATH_OP (u16) 0x002d #define AML_NAMEDFIELD_OP (u16) 0x0030 @@ -165,29 +169,7 @@ #define AML_BYTELIST_OP (u16) 0x0033 #define AML_STATICSTRING_OP (u16) 0x0034 #define AML_METHODCALL_OP (u16) 0x0035 - - -/* - * argument types - */ - -/* -#define AML_ASCIICHARLIST_ARG 'A' -#define AML_BYTEDATA_ARG 'b' -#define AML_BYTELIST_ARG 'B' -#define AML_DWORDDATA_ARG 'd' -#define AML_DATAOBJECT_ARG 'o' -#define AML_DATAOBJECTLIST_ARG 'O' -#define AML_FIELDLIST_ARG 'F' -#define AML_NAMESTRING_ARG 'n' -#define AML_OBJECTLIST_ARG 'P' -#define AML_PKGLENGTH_ARG 'p' -#define AML_SUPERNAME_ARG 's' -#define AML_TARGET_ARG 'l' -#define AML_TERMARG_ARG 't' -#define AML_TERMLIST_ARG 'T' -#define AML_WORDDATA_ARG 'w' -*/ +#define AML_RETURN_VALUE_OP (u16) 0x0036 #define ARG_NONE 0x0 @@ -229,7 +211,7 @@ #define ARGI_STRING 0x06 #define ARGI_BUFFER 0x07 #define ARGI_PACKAGE 0x08 -#define ARGI_DATAOBJECT 0x09 /* Buffer, string, package or NTE reference - Used only by Size_of operator*/ +#define ARGI_DATAOBJECT 0x09 /* Buffer, string, package or reference to a Node - Used only by Size_of operator*/ #define ARGI_COMPLEXOBJ 0x0A /* Buffer or package */ #define ARGI_MUTEX 0x0B #define ARGI_EVENT 0x0C @@ -291,8 +273,9 @@ #define OPTYPE_CONTROL 18 #define OPTYPE_RECONFIGURATION 19 #define OPTYPE_NAMED_OBJECT 20 +#define OPTYPE_RETURN 21 -#define OPTYPE_BOGUS 21 +#define OPTYPE_BOGUS 22 /* Comparison operation codes for Match_op operator */ @@ -375,13 +358,11 @@ extern u8 acpi_gbl_aml [NUM_OPCODES]; extern u16 acpi_gbl_pfx [NUM_OPCODES]; -extern char *acpi_gbl_short_ops [NUM_OPCODES]; -extern char *acpi_gbl_long_ops [NUM_OPCODES]; -extern char *acpi_gbl_region_types [NUM_REGION_TYPES]; -extern char *acpi_gbl_match_ops [NUM_MATCH_OPS]; -extern char *acpi_gbl_access_types [NUM_ACCESS_TYPES]; -extern char *acpi_gbl_update_rules [NUM_UPDATE_RULES]; -extern char *acpi_gbl_FEnames [NUM_FIELD_NAMES]; +extern NATIVE_CHAR *acpi_gbl_region_types [NUM_REGION_TYPES]; +extern NATIVE_CHAR *acpi_gbl_match_ops [NUM_MATCH_OPS]; +extern NATIVE_CHAR *acpi_gbl_access_types [NUM_ACCESS_TYPES]; +extern NATIVE_CHAR *acpi_gbl_update_rules [NUM_UPDATE_RULES]; +extern NATIVE_CHAR *acpi_gbl_FEnames [NUM_FIELD_NAMES]; /* @@ -392,7 +373,7 @@ /* Data used in keeping track of fields */ -char *acpi_gbl_FEnames[NUM_FIELD_NAMES] = +NATIVE_CHAR *acpi_gbl_FEnames[NUM_FIELD_NAMES] = { "skip", "?access?" @@ -401,7 +382,7 @@ /* Region type decoding */ -char *acpi_gbl_region_types[NUM_REGION_TYPES] = +NATIVE_CHAR *acpi_gbl_region_types[NUM_REGION_TYPES] = { "System_memory", "System_iO", @@ -411,7 +392,7 @@ }; -char *acpi_gbl_match_ops[NUM_MATCH_OPS] = +NATIVE_CHAR *acpi_gbl_match_ops[NUM_MATCH_OPS] = { "Error", "MTR", @@ -425,7 +406,7 @@ /* Access type decoding */ -char *acpi_gbl_access_types[NUM_ACCESS_TYPES] = +NATIVE_CHAR *acpi_gbl_access_types[NUM_ACCESS_TYPES] = { "Any_acc", "Byte_acc", @@ -439,7 +420,7 @@ /* Update rule decoding */ -char *acpi_gbl_update_rules[NUM_UPDATE_RULES] = +NATIVE_CHAR *acpi_gbl_update_rules[NUM_UPDATE_RULES] = { "Preserve", "Write_as_ones", diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/include/common.h linux/drivers/acpi/include/common.h --- v2.4.0-test8/linux/drivers/acpi/include/common.h Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/include/common.h Wed Dec 31 16:00:00 1969 @@ -1,650 +0,0 @@ - -/****************************************************************************** - * - * Name: common.h -- prototypes for the common (subsystem-wide) procedures - * - *****************************************************************************/ - -/* - * Copyright (C) 2000 R. Byron Moore - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _COMMON_H -#define _COMMON_H - - -#define REF_INCREMENT (u16) 0 -#define REF_DECREMENT (u16) 1 -#define REF_FORCE_DELETE (u16) 2 - -/* Acpi_cm_dump_buffer */ - -#define DB_BYTE_DISPLAY 1 -#define DB_WORD_DISPLAY 2 -#define DB_DWORD_DISPLAY 4 -#define DB_QWORD_DISPLAY 8 - - -/* Global initialization interfaces */ - -void -acpi_cm_init_globals ( - ACPI_INIT_DATA *init_data); - -void -acpi_cm_terminate ( - void); - - -/* - * Acpi_cm_init - miscellaneous initialization and shutdown - */ - -ACPI_STATUS -acpi_cm_hardware_initialize ( - void); - -ACPI_STATUS -acpi_cm_subsystem_shutdown ( - void); - -/* - * Acpi_cm_global - Global data structures and procedures - */ - -char * -acpi_cm_get_mutex_name ( - u32 mutex_id); - -char * -acpi_cm_get_type_name ( - u32 type); - -u8 -acpi_cm_valid_object_type ( - u32 type); - -ACPI_OWNER_ID -acpi_cm_allocate_owner_id ( - u32 id_type); - - -/* - * Acpi_cm_clib - Local implementations of C library functions - */ - -ACPI_SIZE -acpi_cm_strlen ( - const char *string); - -char * -acpi_cm_strcpy ( - char *dst_string, - const char *src_string); - -char * -acpi_cm_strncpy ( - char *dst_string, - const char *src_string, - ACPI_SIZE count); - -u32 -acpi_cm_strncmp ( - const char *string1, - const char *string2, - ACPI_SIZE count); - -u32 -acpi_cm_strcmp ( - const char *string1, - const char *string2); - -char * -acpi_cm_strcat ( - char *dst_string, - const char *src_string); - -char * -acpi_cm_strncat ( - char *dst_string, - const char *src_string, - ACPI_SIZE count); - -u32 -acpi_cm_strtoul ( - const char *string, - char **terminator, - s32 base); - -char * -acpi_cm_strstr ( - char *string1, - char *string2); - -char * -acpi_cm_strupr ( - char *src_string); - -void * -acpi_cm_memcpy ( - void *dest, - const void *src, - ACPI_SIZE count); - -void * -acpi_cm_memset ( - void *dest, - s32 value, - ACPI_SIZE count); - -s32 -acpi_cm_to_upper ( - s32 c); - -s32 -acpi_cm_to_lower ( - s32 c); - - -/* - * Acpi_cm_copy - Object construction and conversion interfaces - */ - -ACPI_STATUS -acpi_cm_build_simple_object( - ACPI_OBJECT_INTERNAL *obj, - ACPI_OBJECT *user_obj, - char *data_space, - u32 *buffer_space_used); - -ACPI_STATUS -acpi_cm_build_package_object ( - ACPI_OBJECT_INTERNAL *obj, - char *buffer, - u32 *space_used); - -ACPI_STATUS -acpi_cm_build_external_object ( - ACPI_OBJECT_INTERNAL *obj, - ACPI_BUFFER *ret_buffer); - -ACPI_STATUS -acpi_cm_build_internal_simple_object( - ACPI_OBJECT *user_obj, - ACPI_OBJECT_INTERNAL *obj); - -ACPI_STATUS -acpi_cm_build_internal_object ( - ACPI_OBJECT *obj, - ACPI_OBJECT_INTERNAL *internal_obj); - -ACPI_STATUS -acpi_cm_copy_internal_simple_object ( - ACPI_OBJECT_INTERNAL *source_obj, - ACPI_OBJECT_INTERNAL *dest_obj); - -ACPI_STATUS -acpi_cm_build_copy_internal_package_object ( - ACPI_OBJECT_INTERNAL *source_obj, - ACPI_OBJECT_INTERNAL *dest_obj); - - -/* - * Acpi_cm_create - Object creation - */ - -ACPI_STATUS -acpi_cm_update_object_reference ( - ACPI_OBJECT_INTERNAL *object, - u16 action); - -ACPI_OBJECT_INTERNAL * -_cm_create_internal_object ( - char *module_name, - s32 line_number, - s32 component_id, - OBJECT_TYPE_INTERNAL type); - - -/* - * Acpi_cm_debug - Debug interfaces - */ - -s32 -get_debug_level ( - void); - -void -set_debug_level ( - s32 level); - -void -function_trace ( - ACPI_STRING module_name, - s32 line_number, - s32 component_id, - ACPI_STRING function_name); - -void -function_trace_ptr ( - ACPI_STRING module_name, - s32 line_number, - s32 component_id, - ACPI_STRING function_name, - void *pointer); - -void -function_trace_u32 ( - ACPI_STRING module_name, - s32 line_number, - s32 component_id, - ACPI_STRING function_name, - u32 integer); - -void -function_trace_str ( - ACPI_STRING module_name, - s32 line_number, - s32 component_id, - ACPI_STRING function_name, - char *string); - -void -function_exit ( - ACPI_STRING module_name, - s32 line_number, - s32 component_id, - ACPI_STRING function_name); - -void -function_status_exit ( - ACPI_STRING module_name, - s32 line_number, - s32 component_id, - ACPI_STRING function_name, - ACPI_STATUS status); - -void -function_value_exit ( - ACPI_STRING module_name, - s32 line_number, - s32 component_id, - ACPI_STRING function_name, - NATIVE_UINT value); - -void -function_ptr_exit ( - ACPI_STRING module_name, - s32 line_number, - s32 component_id, - ACPI_STRING function_name, - char *ptr); - -void -debug_print_prefix ( - ACPI_STRING module_name, - s32 line_number); - -void -debug_print ( - ACPI_STRING module_name, - s32 line_number, - s32 component_id, - s32 print_level, - char *format, ...); - -void -debug_print_raw ( - char *format, ...); - -void -_report_info ( - ACPI_STRING module_name, - s32 line_number, - s32 component_id, - ACPI_STRING message); - -void -_report_error ( - ACPI_STRING module_name, - s32 line_number, - s32 component_id, - ACPI_STRING message); - -void -_report_warning ( - ACPI_STRING module_name, - s32 line_number, - s32 component_id, - ACPI_STRING message); - -void -_report_success ( - ACPI_STRING module_name, - s32 line_number, - s32 component_id, - ACPI_STRING message); - -void -acpi_cm_dump_buffer ( - char *buffer, - u32 count, - u32 display, - s32 component_id); - - -/* - * Acpi_cm_delete - Object deletion - */ - -void -acpi_cm_delete_internal_obj ( - ACPI_OBJECT_INTERNAL *object); - -void -acpi_cm_delete_internal_package_object ( - ACPI_OBJECT_INTERNAL *object); - -void -acpi_cm_delete_internal_simple_object ( - ACPI_OBJECT_INTERNAL *object); - -ACPI_STATUS -acpi_cm_delete_internal_object_list ( - ACPI_OBJECT_INTERNAL **obj_list); - - -/* - * Acpi_cm_eval - object evaluation - */ - -/* Method name strings */ - -#define METHOD_NAME__HID "_HID" -#define METHOD_NAME__UID "_UID" -#define METHOD_NAME__ADR "_ADR" -#define METHOD_NAME__STA "_STA" -#define METHOD_NAME__REG "_REG" -#define METHOD_NAME__SEG "_SEG" -#define METHOD_NAME__BBN "_BBN" - - -ACPI_STATUS -acpi_cm_evaluate_numeric_object ( - char *method_name, - ACPI_NAMED_OBJECT *acpi_device, - u32 *address); - -ACPI_STATUS -acpi_cm_execute_HID ( - ACPI_NAMED_OBJECT *acpi_device, - DEVICE_ID *hid); - -ACPI_STATUS -acpi_cm_execute_STA ( - ACPI_NAMED_OBJECT *acpi_device, - u32 *status_flags); - -ACPI_STATUS -acpi_cm_execute_UID ( - ACPI_NAMED_OBJECT *acpi_device, - DEVICE_ID *uid); - - -/* - * Acpi_cm_error - exception interfaces - */ - -char * -acpi_cm_format_exception ( - ACPI_STATUS status); - - -/* - * Acpi_cm_mutex - mutual exclusion interfaces - */ - -ACPI_STATUS -acpi_cm_mutex_initialize ( - void); - -void -acpi_cm_mutex_terminate ( - void); - -ACPI_STATUS -acpi_cm_create_mutex ( - ACPI_MUTEX_HANDLE mutex_id); - -ACPI_STATUS -acpi_cm_delete_mutex ( - ACPI_MUTEX_HANDLE mutex_id); - -ACPI_STATUS -acpi_cm_acquire_mutex ( - ACPI_MUTEX_HANDLE mutex_id); - -ACPI_STATUS -acpi_cm_release_mutex ( - ACPI_MUTEX_HANDLE mutex_id); - - -/* - * Acpi_cm_object - internal object create/delete/cache routines - */ - -#define acpi_cm_create_internal_object(t) _cm_create_internal_object(_THIS_MODULE,__LINE__,_COMPONENT,t) -#define acpi_cm_allocate_object_desc() _cm_allocate_object_desc(_THIS_MODULE,__LINE__,_COMPONENT) - -void * -_cm_allocate_object_desc ( - char *module_name, - s32 line_number, - s32 component_id); - -void -acpi_cm_delete_object_desc ( - ACPI_OBJECT_INTERNAL *object); - -u8 -acpi_cm_valid_internal_object ( - void *object); - - -/* - * Acpi_cm_ref_cnt - Object reference count management - */ - -void -acpi_cm_add_reference ( - ACPI_OBJECT_INTERNAL *object); - -void -acpi_cm_remove_reference ( - ACPI_OBJECT_INTERNAL *object); - -/* - * Acpi_cm_size - Object size routines - */ - -ACPI_STATUS -acpi_cm_get_simple_object_size ( - ACPI_OBJECT_INTERNAL *obj, - u32 *obj_length); - -ACPI_STATUS -acpi_cm_get_package_object_size ( - ACPI_OBJECT_INTERNAL *obj, - u32 *obj_length); - -ACPI_STATUS -acpi_cm_get_object_size( - ACPI_OBJECT_INTERNAL *obj, - u32 *obj_length); - - -/* - * Acpi_cm_state - Generic state creation/cache routines - */ - -void -acpi_cm_push_generic_state ( - ACPI_GENERIC_STATE **list_head, - ACPI_GENERIC_STATE *state); - -ACPI_GENERIC_STATE * -acpi_cm_pop_generic_state ( - ACPI_GENERIC_STATE **list_head); - - -ACPI_GENERIC_STATE * -acpi_cm_create_generic_state ( - void); - -ACPI_GENERIC_STATE * -acpi_cm_create_update_state ( - ACPI_OBJECT_INTERNAL *object, - u16 action); - -ACPI_STATUS -acpi_cm_create_update_state_and_push ( - ACPI_OBJECT_INTERNAL *object, - u16 action, - ACPI_GENERIC_STATE **state_list); - -ACPI_GENERIC_STATE * -acpi_cm_create_control_state ( - void); - -void -acpi_cm_delete_generic_state ( - ACPI_GENERIC_STATE *state); - -void -acpi_cm_delete_generic_state_cache ( - void); - -void -acpi_cm_delete_object_cache ( - void); - -/* - * Acpi_cmutils - */ - -u8 -acpi_cm_valid_acpi_name ( - u32 name); - -u8 -acpi_cm_valid_acpi_character ( - char character); - - -/* - * Memory allocation functions and related macros. - * Macros that expand to include filename and line number - */ - -void * -_cm_allocate ( - u32 size, - u32 component, - ACPI_STRING module, - s32 line); - -void * -_cm_callocate ( - u32 size, - u32 component, - ACPI_STRING module, - s32 line); - -void -_cm_free ( - void *address, - u32 component, - ACPI_STRING module, - s32 line); - -void -acpi_cm_init_static_object ( - ACPI_OBJECT_INTERNAL *obj_desc); - -#define acpi_cm_allocate(a) _cm_allocate(a,_COMPONENT,_THIS_MODULE,__LINE__) -#define acpi_cm_callocate(a) _cm_callocate(a, _COMPONENT,_THIS_MODULE,__LINE__) -#define acpi_cm_free(a) _cm_free(a,_COMPONENT,_THIS_MODULE,__LINE__) - -#ifndef ACPI_DEBUG - -#define acpi_cm_add_element_to_alloc_list(a,b,c,d,e,f) -#define acpi_cm_delete_element_from_alloc_list(a,b,c,d) -#define acpi_cm_dump_current_allocations(a,b) -#define acpi_cm_dump_allocation_info() - -#define DECREMENT_OBJECT_METRICS(a) -#define INCREMENT_OBJECT_METRICS(a) -#define INITIALIZE_ALLOCATION_METRICS() - -#else - -#define INITIALIZE_ALLOCATION_METRICS() \ - acpi_gbl_current_object_count = 0; \ - acpi_gbl_current_object_size = 0; \ - acpi_gbl_running_object_count = 0; \ - acpi_gbl_running_object_size = 0; \ - acpi_gbl_max_concurrent_object_count = 0; \ - acpi_gbl_max_concurrent_object_size = 0; \ - acpi_gbl_current_alloc_size = 0; \ - acpi_gbl_current_alloc_count = 0; \ - acpi_gbl_running_alloc_size = 0; \ - acpi_gbl_running_alloc_count = 0; \ - acpi_gbl_max_concurrent_alloc_size = 0; \ - acpi_gbl_max_concurrent_alloc_count = 0 - -#define DECREMENT_OBJECT_METRICS(a) \ - acpi_gbl_current_object_count--; \ - acpi_gbl_current_object_size -= a - -#define INCREMENT_OBJECT_METRICS(a) \ - acpi_gbl_current_object_count++; \ - acpi_gbl_running_object_count++; \ - if (acpi_gbl_max_concurrent_object_count < acpi_gbl_current_object_count) \ - { \ - acpi_gbl_max_concurrent_object_count = acpi_gbl_current_object_count; \ - } \ - acpi_gbl_running_object_size += a; \ - acpi_gbl_current_object_size += a; \ - if (acpi_gbl_max_concurrent_object_size < acpi_gbl_current_object_size) \ - { \ - acpi_gbl_max_concurrent_object_size = acpi_gbl_current_object_size; \ - } - - -void -acpi_cm_dump_allocation_info ( - void); - -void -acpi_cm_dump_current_allocations ( - u32 component, - ACPI_STRING module); - -#endif - - -#endif /* _COMMON_H */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/include/config.h linux/drivers/acpi/include/config.h --- v2.4.0-test8/linux/drivers/acpi/include/config.h Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/include/config.h Wed Dec 31 16:00:00 1969 @@ -1,185 +0,0 @@ - -/****************************************************************************** - * - * Name: config.h - Global configuration constants - * - *****************************************************************************/ - -/* - * Copyright (C) 2000 R. Byron Moore - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _CONFIG_H -#define _CONFIG_H - - -/****************************************************************************** - * - * Compile-time options - * - *****************************************************************************/ - -/* - * ACPI_DEBUG - This switch enables all the debug facilities of the ACPI - * subsystem. This includes the DEBUG_PRINT output statements - * When disabled, all DEBUG_PRINT statements are compiled out. - * - * ACPI_APPLICATION - Use this switch if the subsystem is going to be run - * at the application level. - * - */ - - -/****************************************************************************** - * - * Subsystem Constants - * - *****************************************************************************/ - - -/* Version string */ - -#define ACPI_CA_VERSION __DATE__ - -/* Name of host operating system (returned by the _OS_ namespace object) */ - -#ifdef _LINUX -#define ACPI_OS_NAME "Linux" -#else -#define ACPI_OS_NAME "Intel ACPI/CA Core Subsystem" -#endif - - -/* - * How and when control methods will be parsed - * The default action is to parse all methods at table load time to verify them, but delete the parse trees - * to conserve memory. Methods are parsed just in time before execution and the parse tree is deleted - * when execution completes. - */ -#define METHOD_PARSE_AT_INIT 0x0 /* Parse at table init, never delete the method parse tree */ -#define METHOD_PARSE_JUST_IN_TIME 0x1 /* Parse only when a method is invoked */ -#define METHOD_DELETE_AT_COMPLETION 0x2 /* Delete parse tree on method completion */ - -/* Default parsing configuration */ - -#define METHOD_PARSE_CONFIGURATION (METHOD_PARSE_JUST_IN_TIME | METHOD_DELETE_AT_COMPLETION) - - -/* Maximum objects in the various object caches */ - -#define MAX_STATE_CACHE_DEPTH 24 /* State objects for stacks */ -#define MAX_PARSE_CACHE_DEPTH 512 /* Parse tree objects */ -#define MAX_OBJECT_CACHE_DEPTH 32 /* Interpreter operand objects */ -#define MAX_WALK_CACHE_DEPTH 2 /* Objects for parse tree walks (method execution) */ - -/* - * Name_space Table size - * - * All tables are the same size to simplify the implementation. - * Tables may be extended by allocating additional tables that - * are in turn linked together to form a chain of tables. - */ - -#define NS_TABLE_SIZE 16 - -/* String size constants */ - -#define MAX_STRING_LENGTH 512 -#define PATHNAME_MAX 256 /* A full namespace pathname */ - - -/* Maximum count for a semaphore object */ - -#define MAX_SEMAPHORE_COUNT 256 - - -/* Max reference count (for debug only) */ - -#define MAX_REFERENCE_COUNT 0x200 - - -/* Size of cached memory mapping for system memory operation region */ - -#define SYSMEM_REGION_WINDOW_SIZE 4096 - - -/* - * Debugger threading model - * Use single threaded if the entire subsystem is contained in an application - * Use multiple threaded when the the subsystem is running in the kernel. - * - * By default the model is single threaded if ACPI_APPLICATION is set, - * multi-threaded if ACPI_APPLICATION is not set. - */ - -#define DEBUGGER_SINGLE_THREADED 0 -#define DEBUGGER_MULTI_THREADED 1 - -#ifdef ACPI_APPLICATION -#define DEBUGGER_THREADING DEBUGGER_SINGLE_THREADED - -#else -#define DEBUGGER_THREADING DEBUGGER_MULTI_THREADED -#endif - - -/****************************************************************************** - * - * ACPI Specification constants (Do not change unless the specification changes) - * - *****************************************************************************/ - -/* - * Method info (in WALK_STATE), containing local variables and argumetns - */ - -#define MTH_NUM_LOCALS 8 -#define MTH_MAX_LOCAL 7 - -#define MTH_NUM_ARGS 7 -#define MTH_MAX_ARG 6 - -/* - * Operand Stack (in WALK_STATE), Must be large enough to contain MTH_MAX_ARG - */ - -#define OBJ_NUM_OPERANDS 8 -#define OBJ_MAX_OPERAND 7 - -/* Names within the namespace are 4 bytes long */ - -#define ACPI_NAME_SIZE 4 -#define PATH_SEGMENT_LENGTH 5 /* 4 chars for name + 1 char for separator */ -#define PATH_SEPARATOR '.' - - -/* Constants used in searching for the RSDP in low memory */ - -#define LO_RSDP_WINDOW_BASE (void *) 0 -#define HI_RSDP_WINDOW_BASE (void *) 0xE0000 -#define LO_RSDP_WINDOW_SIZE 0x400 -#define HI_RSDP_WINDOW_SIZE 0x20000 -#define RSDP_SCAN_STEP 16 - - -/* Maximum nesting of package objects */ - -#define MAX_PACKAGE_DEPTH 16 - - -#endif /* _CONFIG_H */ - diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/include/debugger.h linux/drivers/acpi/include/debugger.h --- v2.4.0-test8/linux/drivers/acpi/include/debugger.h Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/include/debugger.h Wed Dec 31 16:00:00 1969 @@ -1,394 +0,0 @@ - -/****************************************************************************** - * - * Name: debugger.h - ACPI/AML debugger - * - *****************************************************************************/ - -/* - * Copyright (C) 2000 R. Byron Moore - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __DEBUGGER_H__ -#define __DEBUGGER_H__ - - -#define DB_MAX_ARGS 8 /* Must be max method args + 1 */ - -#define DB_COMMAND_PROMPT '-' -#define DB_EXECUTE_PROMPT '%' - - -extern int optind; -extern char *optarg; -extern u8 *aml_ptr; -extern u32 acpi_aml_length; - -extern u8 opt_tables; -extern u8 opt_disasm; -extern u8 opt_stats; -extern u8 opt_parse_jit; -extern u8 opt_verbose; - - -extern char *args[DB_MAX_ARGS]; -extern char line_buf[80]; -extern char scope_buf[40]; -extern char debug_filename[40]; -extern u8 output_to_file; -extern char *buffer; -extern char *filename; -extern char *INDENT_STRING; -extern u32 acpi_gbl_method_breakpoint; -extern u8 acpi_gbl_db_output_flags; -extern u32 acpi_gbl_db_debug_level; -extern u32 acpi_gbl_db_console_debug_level; - -extern u32 num_names; -extern u32 num_methods; -extern u32 num_regions; -extern u32 num_packages; -extern u32 num_aliases; -extern u32 num_devices; -extern u32 num_field_defs; -extern u32 num_thermal_zones; -extern u32 num_named_objects; -extern u32 num_grammar_elements; -extern u32 num_method_elements ; -extern u32 num_mutexes; -extern u32 num_power_resources; -extern u32 num_bank_fields ; -extern u32 num_index_fields; -extern u32 num_events; - -extern u32 size_of_parse_tree; -extern u32 size_of_method_trees; -extern u32 size_of_nTes; -extern u32 size_of_acpi_objects; - - -#define BUFFER_SIZE 4196 - -#define DB_REDIRECTABLE_OUTPUT 0x01 -#define DB_CONSOLE_OUTPUT 0x02 -#define DB_DUPLICATE_OUTPUT 0x03 - - -typedef struct command_info -{ - char *name; /* Command Name */ - char min_args; /* Minimum arguments required */ - -} COMMAND_INFO; - - -typedef struct argument_info -{ - char *name; /* Argument Name */ - -} ARGUMENT_INFO; - - -#define PARAM_LIST(pl) pl - -#define DBTEST_OUTPUT_LEVEL(lvl) if (opt_verbose) - -#define VERBOSE_PRINT(fp) DBTEST_OUTPUT_LEVEL(lvl) {\ - acpi_os_printf PARAM_LIST(fp);} - -#define EX_NO_SINGLE_STEP 1 -#define EX_SINGLE_STEP 2 - - -/* Prototypes */ - - -/* - * dbapi - external debugger interfaces - */ - -int -acpi_db_initialize ( - void); - -ACPI_STATUS -acpi_db_single_step ( - ACPI_WALK_STATE *walk_state, - ACPI_GENERIC_OP *op, - u8 op_type); - - -/* - * dbcmds - debug commands and output routines - */ - - -void -acpi_db_display_table_info ( - char *table_arg); - -void -acpi_db_unload_acpi_table ( - char *table_arg, - char *instance_arg); - -void -acpi_db_set_method_breakpoint ( - char *location, - ACPI_WALK_STATE *walk_state, - ACPI_GENERIC_OP *op); - -void -acpi_db_set_method_call_breakpoint ( - ACPI_GENERIC_OP *op); - -void -acpi_db_disassemble_aml ( - char *statements, - ACPI_GENERIC_OP *op); - -void -acpi_db_dump_namespace ( - char *start_arg, - char *depth_arg); - -void -acpi_db_dump_namespace_by_owner ( - char *owner_arg, - char *depth_arg); - -void -acpi_db_send_notify ( - char *name, - u32 value); - -void -acpi_db_set_method_data ( - char *type_arg, - char *index_arg, - char *value_arg); - -ACPI_STATUS -acpi_db_display_objects ( - char *obj_type_arg, - char *display_count_arg); - -ACPI_STATUS -acpi_db_find_name_in_namespace ( - char *name_arg); - -void -acpi_db_set_scope ( - char *name); - -void -acpi_db_find_references ( - char *object_arg); - - -/* - * dbdisasm - AML disassembler - */ - -void -acpi_db_display_op ( - ACPI_GENERIC_OP *origin, - u32 num_opcodes); - -void -acpi_db_display_namestring ( - char *name); - -void -acpi_db_display_path ( - ACPI_GENERIC_OP *op); - -void -acpi_db_display_opcode ( - ACPI_GENERIC_OP *op); - - -/* - * dbdisply - debug display commands - */ - - -void -acpi_db_display_method_info ( - ACPI_GENERIC_OP *op); - -void -acpi_db_decode_and_display_object ( - char *target, - char *output_type); - -void -acpi_db_display_result_object ( - ACPI_OBJECT_INTERNAL *ret_desc); - -ACPI_STATUS -acpi_db_display_all_methods ( - char *display_count_arg); - -void -acpi_db_display_internal_object ( - ACPI_OBJECT_INTERNAL *obj_desc); - -void -acpi_db_display_arguments ( - void); - -void -acpi_db_display_locals ( - void); - -void -acpi_db_display_results ( - void); - -void -acpi_db_display_calling_tree ( - void); - -void -acpi_db_display_argument_object ( - ACPI_OBJECT_INTERNAL *obj_desc); - - -/* - * dbexec - debugger control method execution - */ - -void -acpi_db_execute ( - char *name, - char **args, - u32 flags); - -void -acpi_db_create_execution_threads ( - char *num_threads_arg, - char *num_loops_arg, - char *method_name_arg); - - -/* - * dbfileio - Debugger file I/O commands - */ - -OBJECT_TYPE_INTERNAL -acpi_db_match_argument ( - char *user_argument, - ARGUMENT_INFO *arguments); - - -void -acpi_db_close_debug_file ( - void); - -void -acpi_db_open_debug_file ( - char *name); - -ACPI_STATUS -acpi_db_load_acpi_table ( - char *filename); - - -/* - * dbhistry - debugger HISTORY command - */ - -void -acpi_db_add_to_history ( - char *command_line); - -void -acpi_db_display_history (void); - -char * -acpi_db_get_from_history ( - char *command_num_arg); - - -/* - * dbinput - user front-end to the AML debugger - */ - -ACPI_STATUS -acpi_db_command_dispatch ( - char *input_buffer, - ACPI_WALK_STATE *walk_state, - ACPI_GENERIC_OP *op); - -void -acpi_db_execute_thread ( - void *context); - -ACPI_STATUS -acpi_db_user_commands ( - char prompt, - ACPI_GENERIC_OP *op); - - -/* - * dbstats - Generation and display of ACPI table statistics - */ - -void -acpi_db_generate_statistics ( - ACPI_GENERIC_OP *root, - u8 is_method); - - -ACPI_STATUS -acpi_db_display_statistics ( - char *type_arg); - - -/* - * dbutils - AML debugger utilities - */ - -void -acpi_db_set_output_destination ( - s32 where); - -void -acpi_db_dump_buffer ( - u32 address); - -void -acpi_db_dump_object ( - ACPI_OBJECT *obj_desc, - u32 level); - -void -acpi_db_prep_namestring ( - char *name); - - -ACPI_STATUS -acpi_db_second_pass_parse ( - ACPI_GENERIC_OP *root); - -ACPI_NAMED_OBJECT* -acpi_db_local_ns_lookup ( - char *name); - - -#endif /* __DEBUGGER_H__ */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/include/dispatch.h linux/drivers/acpi/include/dispatch.h --- v2.4.0-test8/linux/drivers/acpi/include/dispatch.h Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/include/dispatch.h Wed Dec 31 16:00:00 1969 @@ -1,383 +0,0 @@ -/****************************************************************************** - * - * Module Name: dispatch.h - * - *****************************************************************************/ - -/* - * Copyright (C) 2000 R. Byron Moore - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#ifndef _DISPATCH_H_ -#define _DISPATCH_H_ - - -#define NAMEOF_LOCAL_NTE "__L0" -#define NAMEOF_ARG_NTE "__A0" - - -/* For Acpi_ds_method_data_set_value */ - -#define MTH_TYPE_LOCAL 0 -#define MTH_TYPE_ARG 1 - - -/* Common interfaces */ - -ACPI_STATUS -acpi_ds_obj_stack_push ( - void *object, - ACPI_WALK_STATE *walk_state); - -ACPI_STATUS -acpi_ds_obj_stack_pop ( - u32 pop_count, - ACPI_WALK_STATE *walk_state); - -void * -acpi_ds_obj_stack_get_value ( - u32 index, - ACPI_WALK_STATE *walk_state); - -ACPI_STATUS -acpi_ds_obj_stack_pop_object ( - ACPI_OBJECT_INTERNAL **object, - ACPI_WALK_STATE *walk_state); - - -/* dsregion - Op region support */ - -ACPI_STATUS -acpi_ds_get_region_arguments ( - ACPI_OBJECT_INTERNAL *rgn_desc); - - -/* dsctrl - Parser/Interpreter interface, control stack routines */ - -/* -ACPI_CTRL_STATE * -Acpi_ds_create_control_state (void); - -void -Acpi_ds_push_control_state ( - ACPI_CTRL_STATE *Control_state, - ACPI_WALK_STATE *Walk_state); - -ACPI_CTRL_STATE * -Acpi_ds_pop_control_state ( - ACPI_WALK_STATE *Walk_state); -*/ - -ACPI_STATUS -acpi_ds_exec_begin_control_op ( - ACPI_WALK_STATE *walk_state, - ACPI_GENERIC_OP *op); - -ACPI_STATUS -acpi_ds_exec_end_control_op ( - ACPI_WALK_STATE *walk_state, - ACPI_GENERIC_OP *op); - - -/* dsexec - Parser/Interpreter interface, method execution callbacks */ - -ACPI_STATUS -acpi_ds_exec_begin_op ( - ACPI_WALK_STATE *state, - ACPI_GENERIC_OP *op); - -ACPI_STATUS -acpi_ds_exec_end_op ( - ACPI_WALK_STATE *state, - ACPI_GENERIC_OP *op); - - -/* dsfield - Parser/Interpreter interface for AML fields */ - - -ACPI_STATUS -acpi_ds_create_field ( - ACPI_GENERIC_OP *op, - ACPI_HANDLE region, - ACPI_WALK_STATE *walk_state); - -ACPI_STATUS -acpi_ds_create_bank_field ( - ACPI_GENERIC_OP *op, - ACPI_HANDLE region, - ACPI_WALK_STATE *walk_state); - -ACPI_STATUS -acpi_ds_create_index_field ( - ACPI_GENERIC_OP *op, - ACPI_HANDLE region, - ACPI_WALK_STATE *walk_state); - - -/* dsload - Parser/Interpreter interface, namespace load callbacks */ - -ACPI_STATUS -acpi_ds_load1_begin_op ( - ACPI_WALK_STATE *walk_state, - ACPI_GENERIC_OP *op); - -ACPI_STATUS -acpi_ds_load1_end_op ( - ACPI_WALK_STATE *walk_state, - ACPI_GENERIC_OP *op); - -ACPI_STATUS -acpi_ds_load2_begin_op ( - ACPI_WALK_STATE *state, - ACPI_GENERIC_OP *op); - -ACPI_STATUS -acpi_ds_load2_end_op ( - ACPI_WALK_STATE *state, - ACPI_GENERIC_OP *op); - - -/* dsmthdat - method data (locals/args) */ - - -ACPI_STATUS -acpi_ds_method_data_delete_all ( - ACPI_WALK_STATE *walk_state); - -u8 -acpi_ds_is_method_value ( - ACPI_OBJECT_INTERNAL *obj_desc); - -OBJECT_TYPE_INTERNAL -acpi_ds_method_data_get_type ( - u32 type, - u32 index); - -ACPI_STATUS -acpi_ds_method_data_get_value ( - u32 type, - u32 index, - ACPI_OBJECT_INTERNAL **obj_desc); - -ACPI_STATUS -acpi_ds_method_data_set_value ( - u32 type, - u32 index, - ACPI_OBJECT_INTERNAL *obj_desc); - -ACPI_STATUS -acpi_ds_method_data_delete_value ( - u32 type, - u32 index); - -ACPI_STATUS -acpi_ds_method_data_init_args ( - ACPI_OBJECT_INTERNAL **params, - u32 param_count); - -ACPI_NAMED_OBJECT* -acpi_ds_method_data_get_nte ( - u32 type, - u32 index); - -ACPI_STATUS -acpi_ds_method_data_init ( - ACPI_WALK_STATE *walk_state); - - -/* dsmethod - Parser/Interpreter interface - control method parsing */ - -ACPI_STATUS -acpi_ds_parse_method ( - ACPI_HANDLE obj_handle); - -ACPI_STATUS -acpi_ds_call_control_method ( - ACPI_WALK_LIST *walk_list, - ACPI_WALK_STATE *walk_state, - ACPI_GENERIC_OP *op); - -ACPI_STATUS -acpi_ds_restart_control_method ( - ACPI_WALK_STATE *walk_state, - ACPI_OBJECT_INTERNAL *return_desc); - -ACPI_STATUS -acpi_ds_terminate_control_method ( - ACPI_WALK_STATE *walk_state); - -ACPI_STATUS -acpi_ds_begin_method_execution ( - ACPI_NAMED_OBJECT *method_entry, - ACPI_OBJECT_INTERNAL *obj_desc); - - -/* dsobj - Parser/Interpreter interface - object initialization and conversion */ - -ACPI_STATUS -acpi_ds_init_one_object ( - ACPI_HANDLE obj_handle, - u32 level, - void *context, - void **return_value); - -ACPI_STATUS -acpi_ds_initialize_objects ( - ACPI_TABLE_DESC *table_desc, - ACPI_NAMED_OBJECT *start_entry); - -ACPI_STATUS -acpi_ds_build_internal_package_obj ( - ACPI_WALK_STATE *walk_state, - ACPI_GENERIC_OP *op, - ACPI_OBJECT_INTERNAL **obj_desc); - -ACPI_STATUS -acpi_ds_build_internal_object ( - ACPI_WALK_STATE *walk_state, - ACPI_GENERIC_OP *op, - ACPI_OBJECT_INTERNAL **obj_desc_ptr); - -ACPI_STATUS -acpi_ds_init_object_from_op ( - ACPI_WALK_STATE *walk_state, - ACPI_GENERIC_OP *op, - u16 opcode, - ACPI_OBJECT_INTERNAL *obj_desc); - -ACPI_STATUS -acpi_ds_create_named_object ( - ACPI_WALK_STATE *walk_state, - ACPI_NAMED_OBJECT *entry, - ACPI_GENERIC_OP *op); - - -/* dsregn - Parser/Interpreter interface - Op Region parsing */ - -ACPI_STATUS -acpi_ds_eval_region_operands ( - ACPI_WALK_STATE *walk_state, - ACPI_GENERIC_OP *op); - -ACPI_STATUS -acpi_ds_initialize_region ( - ACPI_HANDLE obj_handle); - - -/* dsutils - Parser/Interpreter interface utility routines */ - -void -acpi_ds_delete_result_if_not_used ( - ACPI_GENERIC_OP *op, - ACPI_OBJECT_INTERNAL *result_obj, - ACPI_WALK_STATE *walk_state); - -ACPI_STATUS -acpi_ds_create_operand ( - ACPI_WALK_STATE *walk_state, - ACPI_GENERIC_OP *arg); - -ACPI_STATUS -acpi_ds_create_operands ( - ACPI_WALK_STATE *walk_state, - ACPI_GENERIC_OP *first_arg); - -ACPI_STATUS -acpi_ds_resolve_operands ( - ACPI_WALK_STATE *walk_state); - -OBJECT_TYPE_INTERNAL -acpi_ds_map_opcode_to_data_type ( - u16 opcode, - u32 *out_flags); - -OBJECT_TYPE_INTERNAL -acpi_ds_map_named_opcode_to_data_type ( - u16 opcode); - - -/* - * dswscope - Scope Stack manipulation - */ - -ACPI_STATUS -acpi_ds_scope_stack_push ( - ACPI_NAME_TABLE *new_scope, - OBJECT_TYPE_INTERNAL type, - ACPI_WALK_STATE *walk_state); - - -ACPI_STATUS -acpi_ds_scope_stack_pop ( - ACPI_WALK_STATE *walk_state); - -void -acpi_ds_scope_stack_clear ( - ACPI_WALK_STATE *walk_state); - - -/* Acpi_dswstate - parser WALK_STATE management routines */ - -ACPI_WALK_STATE * -acpi_ds_create_walk_state ( - ACPI_OWNER_ID owner_id, - ACPI_GENERIC_OP *origin, - ACPI_OBJECT_INTERNAL *mth_desc, - ACPI_WALK_LIST *walk_list); - -ACPI_STATUS -acpi_ds_obj_stack_delete_all ( - ACPI_WALK_STATE *walk_state); - -ACPI_STATUS -acpi_ds_obj_stack_pop_and_delete ( - u32 pop_count, - ACPI_WALK_STATE *walk_state); - -void -acpi_ds_delete_walk_state ( - ACPI_WALK_STATE *walk_state); - -ACPI_WALK_STATE * -acpi_ds_pop_walk_state ( - ACPI_WALK_LIST *walk_list); - -ACPI_STATUS -acpi_ds_result_stack_pop ( - ACPI_OBJECT_INTERNAL **object, - ACPI_WALK_STATE *walk_state); - -ACPI_STATUS -acpi_ds_result_stack_push ( - void *object, - ACPI_WALK_STATE *walk_state); - -ACPI_STATUS -acpi_ds_result_stack_clear ( - ACPI_WALK_STATE *walk_state); - -ACPI_WALK_STATE * -acpi_ds_get_current_walk_state ( - ACPI_WALK_LIST *walk_list); - -void -acpi_ds_delete_walk_state_cache ( - void); - - -#endif /* _DISPATCH_H_ */ \ No newline at end of file diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/include/events.h linux/drivers/acpi/include/events.h --- v2.4.0-test8/linux/drivers/acpi/include/events.h Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/include/events.h Wed Dec 31 16:00:00 1969 @@ -1,209 +0,0 @@ - -/****************************************************************************** - * - * Name: events.h - Acpi_event subcomponent prototypes and defines - * - *****************************************************************************/ - -/* - * Copyright (C) 2000 R. Byron Moore - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __EVENTS_H__ -#define __EVENTS_H__ - - -/* - * Acpi_evfixed - Fixed event handling - */ - -ACPI_STATUS -acpi_ev_fixed_event_initialize ( - void); - -u32 -acpi_ev_fixed_event_detect ( - void); - -u32 -acpi_ev_fixed_event_dispatch ( - u32 acpi_event); - - -/* - * Acpi_evglock - Global Lock support - */ - -ACPI_STATUS -acpi_ev_acquire_global_lock( - void); - -void -acpi_ev_release_global_lock( - void); - -ACPI_STATUS -acpi_ev_init_global_lock_handler ( - void); - - -/* - * Acpi_evgpe - GPE handling and dispatch - */ - -ACPI_STATUS -acpi_ev_gpe_initialize ( - void); - -ACPI_STATUS -acpi_ev_init_gpe_control_methods ( - void); - -u32 -acpi_ev_gpe_dispatch ( - u32 gpe_number); - -u32 -acpi_ev_gpe_detect ( - void); - - -/* - * Acpi_evnotify - Device Notify handling and dispatch - */ - -void -acpi_ev_notify_dispatch ( - ACPI_HANDLE device, - u32 notify_value); - - -/* - * Acpi_evregion - Address Space handling - */ - -ACPI_STATUS -acpi_ev_install_default_address_space_handlers ( - void); - -ACPI_STATUS -acpi_ev_address_space_dispatch ( - ACPI_OBJECT_INTERNAL *region_obj, - u32 function, - u32 address, - u32 bit_width, - u32 *value); - - -ACPI_STATUS -acpi_ev_addr_handler_helper ( - ACPI_HANDLE obj_handle, - u32 level, - void *context, - void **return_value); - -void -acpi_ev_disassociate_region_from_handler( - ACPI_OBJECT_INTERNAL *region_obj); - - -ACPI_STATUS -acpi_ev_associate_region_and_handler( - ACPI_OBJECT_INTERNAL *handler_obj, - ACPI_OBJECT_INTERNAL *region_obj); - - -/* - * Acpi_evregini - Region initialization and setup - */ - -ACPI_STATUS -acpi_ev_system_memory_region_setup ( - ACPI_HANDLE handle, - u32 function, - void *handler_context, - void **return_context); - -ACPI_STATUS -acpi_ev_io_space_region_setup ( - ACPI_HANDLE handle, - u32 function, - void *handler_context, - void **return_context); - -ACPI_STATUS -acpi_ev_pci_config_region_setup ( - ACPI_HANDLE handle, - u32 function, - void *handler_context, - void **return_context); - -ACPI_STATUS -acpi_ev_default_region_setup ( - ACPI_HANDLE handle, - u32 function, - void *handler_context, - void **return_context); - -ACPI_STATUS -acpi_ev_initialize_region ( - ACPI_OBJECT_INTERNAL *region_obj, - u8 acpi_ns_locked); - - -/* - * Acpi_evsci - SCI (System Control Interrupt) handling/dispatch - */ - -u32 -acpi_ev_install_sci_handler ( - void); - -ACPI_STATUS -acpi_ev_remove_sci_handler ( - void); - -s32 -acpi_ev_initialize_sCI ( - s32 program_sCI); - -void -acpi_ev_restore_acpi_state ( - void); - -void -acpi_ev_terminate ( - void); - - -/* Debug support */ - -#ifdef ACPI_DEBUG - -s32 -acpi_ev_sci_count ( - u32 acpi_event); - -#define DEBUG_INCREMENT_EVENT_COUNT(a) acpi_gbl_event_count[a]++; - -#else - -#define DEBUG_INCREMENT_EVENT_COUNT(a) -#endif - - -#endif /* __EVENTS_H__ */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/include/globals.h linux/drivers/acpi/include/globals.h --- v2.4.0-test8/linux/drivers/acpi/include/globals.h Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/include/globals.h Wed Dec 31 16:00:00 1969 @@ -1,311 +0,0 @@ - -/****************************************************************************** - * - * Name: globals.h - Declarations for global variables - * - *****************************************************************************/ - -/* - * Copyright (C) 2000 R. Byron Moore - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __GLOBALS_H__ -#define __GLOBALS_H__ - - -/* - * Ensure that the globals are actually defined only once - */ -#ifdef DEFINE_ACPI_GLOBALS -#define ACPI_EXTERN -#else -#define ACPI_EXTERN extern -#endif - - -extern char *msg_acpi_error_break; - -/***************************************************************************** - * - * Debug support - * - ****************************************************************************/ - -/* Runtime configuration of debug print levels */ - -extern u32 acpi_dbg_level; -extern u32 acpi_dbg_layer; - - -/* Procedure nesting level for debug output */ - -extern u32 acpi_gbl_nesting_level; - - -/***************************************************************************** - * - * ACPI Table globals - * - ****************************************************************************/ - -/* - * Table pointers. - * Although these pointers are somewhat redundant with the global Acpi_table, - * they are convenient because they are typed pointers. - * - * These tables are single-table only; meaning that there can be at most one - * of each in the system. Each global points to the actual table. - * - */ -ACPI_EXTERN ROOT_SYSTEM_DESCRIPTOR_POINTER *acpi_gbl_RSDP; -ACPI_EXTERN ROOT_SYSTEM_DESCRIPTION_TABLE *acpi_gbl_RSDT; -ACPI_EXTERN FIRMWARE_ACPI_CONTROL_STRUCTURE *acpi_gbl_FACS; -ACPI_EXTERN FIXED_ACPI_DESCRIPTION_TABLE *acpi_gbl_FACP; -ACPI_EXTERN APIC_TABLE *acpi_gbl_APIC; -ACPI_EXTERN ACPI_TABLE_HEADER *acpi_gbl_DSDT; -ACPI_EXTERN ACPI_TABLE_HEADER *acpi_gbl_SBST; -/* - * Since there may be multiple SSDTs and PSDTS, a single pointer is not - * sufficient; Therefore, there isn't one! - */ - - -/* - * ACPI Table info arrays - */ -extern ACPI_TABLE_DESC acpi_gbl_acpi_tables[NUM_ACPI_TABLES]; -extern ACPI_TABLE_SUPPORT acpi_gbl_acpi_table_data[NUM_ACPI_TABLES]; - -/* - * Predefined mutex objects. This array contains the - * actual OS mutex handles, indexed by the local ACPI_MUTEX_HANDLEs. - * (The table maps local handles to the real OS handles) - */ -ACPI_EXTERN ACPI_MUTEX_INFO acpi_gbl_acpi_mutex_info [NUM_MTX]; -extern ACPI_INIT_DATA acpi_gbl_acpi_init_data; - - -/***************************************************************************** - * - * Miscellaneous globals - * - ****************************************************************************/ - - -ACPI_EXTERN u8 *acpi_gbl_gpe0enable_register_save; -ACPI_EXTERN u8 *acpi_gbl_gpe1_enable_register_save; -ACPI_EXTERN ACPI_WALK_STATE *acpi_gbl_breakpoint_walk; -ACPI_EXTERN ACPI_GENERIC_STATE *acpi_gbl_generic_state_cache; -ACPI_EXTERN ACPI_GENERIC_OP *acpi_gbl_parse_cache; -ACPI_EXTERN ACPI_OBJECT_INTERNAL *acpi_gbl_object_cache; -ACPI_EXTERN ACPI_WALK_STATE *acpi_gbl_walk_state_cache; -ACPI_EXTERN ACPI_HANDLE acpi_gbl_global_lock_semaphore; - - -ACPI_EXTERN u32 acpi_gbl_global_lock_thread_count; -ACPI_EXTERN u32 acpi_gbl_restore_acpi_chipset; -ACPI_EXTERN u32 acpi_gbl_original_mode; -ACPI_EXTERN u32 acpi_gbl_edge_level_save; -ACPI_EXTERN u32 acpi_gbl_irq_enable_save; -ACPI_EXTERN u32 acpi_gbl_rsdp_original_location; - -ACPI_EXTERN u32 acpi_gbl_state_cache_requests; -ACPI_EXTERN u32 acpi_gbl_state_cache_hits; -ACPI_EXTERN u32 acpi_gbl_parse_cache_requests; -ACPI_EXTERN u32 acpi_gbl_parse_cache_hits; -ACPI_EXTERN u32 acpi_gbl_object_cache_requests; -ACPI_EXTERN u32 acpi_gbl_object_cache_hits; -ACPI_EXTERN u32 acpi_gbl_walk_state_cache_requests; -ACPI_EXTERN u32 acpi_gbl_walk_state_cache_hits; -ACPI_EXTERN u32 acpi_gbl_ns_lookup_count; -ACPI_EXTERN u32 acpi_gbl_ps_find_count; - - -ACPI_EXTERN u16 acpi_gbl_generic_state_cache_depth; -ACPI_EXTERN u16 acpi_gbl_parse_cache_depth; -ACPI_EXTERN u16 acpi_gbl_object_cache_depth; -ACPI_EXTERN u16 acpi_gbl_walk_state_cache_depth; -ACPI_EXTERN u16 acpi_gbl_pm1_enable_register_save; -ACPI_EXTERN u16 acpi_gbl_next_table_owner_id; -ACPI_EXTERN u16 acpi_gbl_next_method_owner_id; - -ACPI_EXTERN u8 acpi_gbl_debugger_configuration; -ACPI_EXTERN u8 acpi_gbl_global_lock_acquired; -ACPI_EXTERN u8 acpi_gbl_global_lock_set; /* TBD: [Restructure] OBSOLETE?? */ -ACPI_EXTERN u8 acpi_gbl_step_to_next_call; -ACPI_EXTERN u8 acpi_gbl_acpi_hardware_present; - - -ACPI_EXTERN ACPI_OBJECT_NOTIFY_HANDLER acpi_gbl_drv_notify; -ACPI_EXTERN ACPI_OBJECT_NOTIFY_HANDLER acpi_gbl_sys_notify; - - -extern u8 acpi_gbl_shutdown; -extern u32 acpi_gbl_system_flags; -extern u32 acpi_gbl_startup_flags; - - -/***************************************************************************** - * - * Namespace globals - * - ****************************************************************************/ - -#define NUM_NS_TYPES INTERNAL_TYPE_INVALID+1 -#define NUM_PREDEFINED_NAMES 9 - - -ACPI_EXTERN ACPI_NAME_TABLE acpi_gbl_root_name_table; -ACPI_EXTERN ACPI_NAMED_OBJECT *acpi_gbl_root_object; - -extern u8 acpi_gbl_ns_properties[NUM_NS_TYPES]; -extern PREDEFINED_NAMES acpi_gbl_pre_defined_names [NUM_PREDEFINED_NAMES]; - - -/* Used to detect memory leaks (DEBUG ONLY) */ - -#ifdef ACPI_DEBUG -ACPI_EXTERN ALLOCATION_INFO *acpi_gbl_head_alloc_ptr; -ACPI_EXTERN ALLOCATION_INFO *acpi_gbl_tail_alloc_ptr; -#endif - - -/***************************************************************************** - * - * Interpreter globals - * - ****************************************************************************/ - - -ACPI_EXTERN u32 acpi_gbl_when_to_parse_methods; -ACPI_EXTERN ACPI_WALK_LIST *acpi_gbl_current_walk_list; - -/* Base of AML block, and pointer to current location in it */ - -ACPI_EXTERN u8 *acpi_gbl_Pcode_base; -ACPI_EXTERN u8 *acpi_gbl_Pcode; - -/* - * Length of AML block, and remaining length of current package. - */ -ACPI_EXTERN u32 acpi_gbl_Pcode_block_len; -ACPI_EXTERN u32 acpi_gbl_Pcode_len; - -ACPI_EXTERN u32 acpi_gbl_buf_seq; /* Counts allocated Buffer descriptors */ -ACPI_EXTERN s32 acpi_gbl_named_object_err; /* Indicate if inc_error should be called */ - -/* - * Handle to the last method found - used during pass1 of load - */ -ACPI_EXTERN ACPI_HANDLE acpi_gbl_last_method; - -/* - * Table of Address Space handlers - */ - -ACPI_EXTERN ACPI_ADDRESS_SPACE_INFO acpi_gbl_address_spaces[ACPI_NUM_ADDRESS_SPACES]; - - -/* Control method single step flag */ - -ACPI_EXTERN u8 acpi_gbl_cm_single_step; - - -/***************************************************************************** - * - * Parser globals - * - ****************************************************************************/ - -ACPI_EXTERN ACPI_GENERIC_OP *acpi_gbl_parsed_namespace_root; - -extern ACPI_OP_INFO acpi_gbl_aml_op_info[]; -extern u8 acpi_gbl_aml_op_info_index[256]; -extern char *acpi_gbl_parser_id; - - -/***************************************************************************** - * - * Hardware globals - * - ****************************************************************************/ - -extern ACPI_C_STATE_HANDLER acpi_hw_cx_handlers[MAX_CX_STATES]; -extern u32 acpi_hw_active_cx_state; - - -/***************************************************************************** - * - * Event globals - * - ****************************************************************************/ - -ACPI_EXTERN ACPI_FIXED_EVENT_INFO acpi_gbl_fixed_event_handlers[NUM_FIXED_EVENTS]; - -ACPI_EXTERN ACPI_HANDLE acpi_gbl_gpe_obj_handle; -ACPI_EXTERN u32 acpi_gbl_gpe_register_count; -ACPI_EXTERN ACPI_GPE_REGISTERS *acpi_gbl_gpe_registers; -ACPI_EXTERN ACPI_GPE_LEVEL_INFO *acpi_gbl_gpe_info; - -/* - * Gpe validation and translation table - * Indexed by the GPE number, returns GPE_INVALID if the GPE is not supported. - * Otherwise, returns a valid index into the global GPE table. - * - * This table is needed because the GPE numbers supported by block 1 do not - * have to be contiguous with the GPE numbers supported by block 0. - */ -ACPI_EXTERN u8 acpi_gbl_gpe_valid [NUM_GPE]; - -/* Acpi_event counter for debug only */ - -#ifdef ACPI_DEBUG -ACPI_EXTERN u32 acpi_gbl_event_count[NUM_FIXED_EVENTS]; -#endif - - -/***************************************************************************** - * - * Debugger globals - * - ****************************************************************************/ - -ACPI_EXTERN u8 acpi_gbl_method_executing; -ACPI_EXTERN u8 acpi_gbl_db_terminate_threads; - - -/* Memory allocation metrics - Debug Only! */ - -#ifdef ACPI_DEBUG - -ACPI_EXTERN u32 acpi_gbl_current_alloc_size; -ACPI_EXTERN u32 acpi_gbl_current_alloc_count; -ACPI_EXTERN u32 acpi_gbl_running_alloc_size; -ACPI_EXTERN u32 acpi_gbl_running_alloc_count; -ACPI_EXTERN u32 acpi_gbl_max_concurrent_alloc_size; -ACPI_EXTERN u32 acpi_gbl_max_concurrent_alloc_count; -ACPI_EXTERN u32 acpi_gbl_current_object_count; -ACPI_EXTERN u32 acpi_gbl_current_object_size; -ACPI_EXTERN u32 acpi_gbl_max_concurrent_object_count; -ACPI_EXTERN u32 acpi_gbl_max_concurrent_object_size; -ACPI_EXTERN u32 acpi_gbl_running_object_count; -ACPI_EXTERN u32 acpi_gbl_running_object_size; - -#endif - - -#endif /* __GLOBALS_H__ */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/include/hardware.h linux/drivers/acpi/include/hardware.h --- v2.4.0-test8/linux/drivers/acpi/include/hardware.h Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/include/hardware.h Wed Dec 31 16:00:00 1969 @@ -1,169 +0,0 @@ - -/****************************************************************************** - * - * Name: hardware.h -- hardware specific interfaces - * - *****************************************************************************/ - -/* - * Copyright (C) 2000 R. Byron Moore - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __HARDWARE_H__ -#define __HARDWARE_H__ - - -/* Prototypes */ - - -ACPI_STATUS -acpi_hw_initialize( - void); - -ACPI_STATUS -acpi_hw_shutdown( - void); - -ACPI_STATUS -acpi_hw_initialize_system_info( - void); - -ACPI_STATUS -acpi_hw_set_mode ( - u32 mode); - -u32 -acpi_hw_get_mode ( - void); - -u32 -acpi_hw_get_mode_capabilities ( - void); - -/* Register I/O Prototypes */ - -u32 -acpi_hw_register_access ( - NATIVE_UINT read_write, - u8 use_lock, - u32 register_id, ... /* DWORD Value */); - -void -acpi_hw_clear_acpi_status ( - void); - - -/* GPE support */ - -void -acpi_hw_enable_gpe ( - u32 gpe_index); - -void -acpi_hw_disable_gpe ( - u32 gpe_index); - -void -acpi_hw_clear_gpe ( - u32 gpe_index); - -void -acpi_hw_get_gpe_status ( - u32 gpe_number, - ACPI_EVENT_STATUS *event_status); - -/* Sleep Prototypes */ - -ACPI_STATUS -acpi_hw_obtain_sleep_type_register_data ( - u8 sleep_state, - u8 *slp_typ_a, - u8 *slp_typ_b); - - -/* Cx State Prototypes */ - -ACPI_STATUS -acpi_hw_enter_c1( - ACPI_IO_ADDRESS pblk_address, - u32 *pm_timer_ticks); - -ACPI_STATUS -acpi_hw_enter_c2( - ACPI_IO_ADDRESS pblk_address, - u32 *pm_timer_ticks); - -ACPI_STATUS -acpi_hw_enter_c3( - ACPI_IO_ADDRESS pblk_address, - u32 *pm_timer_ticks); - -ACPI_STATUS -acpi_hw_enter_cx ( - ACPI_IO_ADDRESS pblk_address, - u32 *pm_timer_ticks); - -ACPI_STATUS -acpi_hw_set_cx ( - u32 cx_state); - -ACPI_STATUS -acpi_hw_get_cx_info ( - u32 cx_states[]); - - -/* Throttling Prototypes */ - -void -acpi_hw_enable_throttling ( - ACPI_IO_ADDRESS pblk_address); - -void -acpi_hw_disable_throttling ( - ACPI_IO_ADDRESS pblk_address); - -u32 -acpi_hw_get_duty_cycle ( - u8 duty_offset, - ACPI_IO_ADDRESS pblk_address, - u32 num_throttle_states); - -void -acpi_hw_program_duty_cycle ( - u8 duty_offset, - u32 duty_cycle, - ACPI_IO_ADDRESS pblk_address, - u32 num_throttle_states); - -NATIVE_UINT -acpi_hw_local_pow ( - NATIVE_UINT x, - NATIVE_UINT y); - - -/* ACPI Timer prototypes */ - -u32 -acpi_hw_pmt_ticks ( - void); - -u32 -acpi_hw_pmt_resolution ( - void); - - -#endif /* __HARDWARE_H__ */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/include/internal.h linux/drivers/acpi/include/internal.h --- v2.4.0-test8/linux/drivers/acpi/include/internal.h Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/include/internal.h Wed Dec 31 16:00:00 1969 @@ -1,850 +0,0 @@ - -/****************************************************************************** - * - * Name: internal.h - Internal data types used across the ACPI subsystem - * - *****************************************************************************/ - -/* - * Copyright (C) 2000 R. Byron Moore - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _ACPI_INTERNAL_H -#define _ACPI_INTERNAL_H - -#include "config.h" - - -#define WAIT_FOREVER ((u32) -1) - -typedef void* ACPI_MUTEX; -typedef u32 ACPI_MUTEX_HANDLE; - - -/* Object descriptor types */ - -#define ACPI_DESC_TYPE_INTERNAL 0xAA -#define ACPI_DESC_TYPE_PARSER 0xBB -#define ACPI_DESC_TYPE_STATE 0xCC -#define ACPI_DESC_TYPE_WALK 0xDD -#define ACPI_DESC_TYPE_NAMED 0xEE - - -/***************************************************************************** - * - * Mutex typedefs and structs - * - ****************************************************************************/ - - -/* - * Predefined handles for the mutex objects used within the subsystem - * All mutex objects are automatically created by Acpi_cm_mutex_initialize. - * NOTE: any changes here must be reflected in the Acpi_gbl_Mutex_names table also! - */ - -#define ACPI_MTX_HARDWARE 0 -#define ACPI_MTX_MEMORY 1 -#define ACPI_MTX_CACHES 2 -#define ACPI_MTX_TABLES 3 -#define ACPI_MTX_PARSER 4 -#define ACPI_MTX_DISPATCHER 5 -#define ACPI_MTX_INTERPRETER 6 -#define ACPI_MTX_EXECUTE 7 -#define ACPI_MTX_NAMESPACE 8 -#define ACPI_MTX_EVENTS 9 -#define ACPI_MTX_OP_REGIONS 10 -#define ACPI_MTX_DEBUG_CMD_READY 11 -#define ACPI_MTX_DEBUG_CMD_COMPLETE 12 - -#define MAX_MTX 12 -#define NUM_MTX MAX_MTX+1 - - -#ifdef ACPI_DEBUG -#ifdef DEFINE_ACPI_GLOBALS - -/* Names for the mutexes used in the subsystem */ - -static char *acpi_gbl_mutex_names[] = -{ - "ACPI_MTX_Hardware", - "ACPI_MTX_Memory", - "ACPI_MTX_Caches", - "ACPI_MTX_Tables", - "ACPI_MTX_Parser", - "ACPI_MTX_Dispatcher", - "ACPI_MTX_Interpreter", - "ACPI_MTX_Execute", - "ACPI_MTX_Namespace", - "ACPI_MTX_Events", - "ACPI_MTX_Op_regions", - "ACPI_MTX_Debug_cmd_ready", - "ACPI_MTX_Debug_cmd_complete" -}; - -#endif -#endif - - -/* Table for the global mutexes */ - -typedef struct acpi_mutex_info -{ - ACPI_MUTEX mutex; - u32 use_count; - u8 locked; - -} ACPI_MUTEX_INFO; - - -/* Lock flag parameter for various interfaces */ - -#define ACPI_MTX_DO_NOT_LOCK 0 -#define ACPI_MTX_LOCK 1 - - -typedef u16 ACPI_OWNER_ID; -#define OWNER_TYPE_TABLE 0x0 -#define OWNER_TYPE_METHOD 0x1 -#define FIRST_METHOD_ID 0x0000 -#define FIRST_TABLE_ID 0x8000 - -/* TBD: [Restructure] get rid of the need for this! */ - -#define TABLE_ID_DSDT (ACPI_OWNER_ID) 0xD1D1 - -/***************************************************************************** - * - * Namespace typedefs and structs - * - ****************************************************************************/ - - -/* Operational modes of the AML interpreter/scanner */ - -typedef enum -{ - IMODE_LOAD_PASS1 = 0x01, - IMODE_LOAD_PASS2 = 0x02, - IMODE_EXECUTE = 0x0E - -} OPERATING_MODE; - - -/* - * The Acpi_named_object describes a named object that appears in the AML - * An Acpi_name_table is used to store Acpi_named_objects. - * - * Data_type is used to differentiate between internal descriptors, and MUST - * be the first byte in this structure. - */ - -typedef struct acpi_named_object -{ - u8 data_type; - u8 type; /* Type associated with this name */ - u8 this_index; /* Entry number */ - u8 flags; - u32 name; /* ACPI Name, always 4 chars per ACPI spec */ - - - void *object; /* Pointer to attached ACPI object (optional) */ - struct acpi_name_table *child_table; /* Scope owned by this name (optional) */ - ACPI_OWNER_ID owner_id; /* ID of owner - either an ACPI table or a method */ - u16 reference_count; /* Current count of references and children */ - -#ifdef _IA64 - u32 fill1; /* 64-bit alignment */ -#endif - -} ACPI_NAMED_OBJECT; - - -typedef struct acpi_name_table -{ - struct acpi_name_table *next_table; - struct acpi_name_table *parent_table; - ACPI_NAMED_OBJECT *parent_entry; - ACPI_NAMED_OBJECT entries[1]; - -} ACPI_NAME_TABLE; - - -#define ENTRY_NOT_FOUND NULL - - -/* NTE flags */ - -#define NTE_AML_ATTACHMENT 0x1 - - -/* - * ACPI Table Descriptor. One per ACPI table - */ -typedef struct acpi_table_desc -{ - struct acpi_table_desc *prev; - struct acpi_table_desc *next; - struct acpi_table_desc *installed_desc; - ACPI_TABLE_HEADER *pointer; - void *base_pointer; - u8 *aml_pointer; - u32 aml_length; - u32 length; - u32 count; - ACPI_OWNER_ID table_id; - u8 type; - u8 allocation; - u8 loaded_into_namespace; - -} ACPI_TABLE_DESC; - - -typedef struct -{ - char *search_for; - ACPI_HANDLE *list; - s32 *count; - -} FIND_CONTEXT; - - -typedef struct -{ - ACPI_NAME_TABLE *name_table; - u32 position; - u8 table_full; - -} NS_SEARCH_DATA; - - -/* - * Predefined Namespace items - */ -#define ACPI_MAX_ADDRESS_SPACE 255 -#define ACPI_NUM_ADDRESS_SPACES 256 - - -typedef struct -{ - char *name; - ACPI_OBJECT_TYPE type; - char *val; - -} PREDEFINED_NAMES; - - -/***************************************************************************** - * - * Event typedefs and structs - * - ****************************************************************************/ - - -/* Status bits. */ - -#define ACPI_STATUS_PMTIMER 0x0001 -#define ACPI_STATUS_GLOBAL 0x0020 -#define ACPI_STATUS_POWER_BUTTON 0x0100 -#define ACPI_STATUS_SLEEP_BUTTON 0x0200 -#define ACPI_STATUS_RTC_ALARM 0x0400 - -/* Enable bits. */ - -#define ACPI_ENABLE_PMTIMER 0x0001 -#define ACPI_ENABLE_GLOBAL 0x0020 -#define ACPI_ENABLE_POWER_BUTTON 0x0100 -#define ACPI_ENABLE_SLEEP_BUTTON 0x0200 -#define ACPI_ENABLE_RTC_ALARM 0x0400 - - -/* - * Entry in the Address_space (AKA Operation Region) table - */ - -typedef struct -{ - ADDRESS_SPACE_HANDLER handler; - void *context; - -} ACPI_ADDRESS_SPACE_INFO; - - -/* Values and addresses of the GPE registers (both banks) */ - -typedef struct -{ - u8 status; /* Current value of status reg */ - u8 enable; /* Current value of enable reg */ - u16 status_addr; /* Address of status reg */ - u16 enable_addr; /* Address of enable reg */ - u8 gpe_base; /* Base GPE number */ - -} ACPI_GPE_REGISTERS; - - -#define ACPI_GPE_LEVEL_TRIGGERED 1 -#define ACPI_GPE_EDGE_TRIGGERED 2 - - -/* Information about each particular GPE level */ - -typedef struct -{ - u8 type; /* Level or Edge */ - - ACPI_HANDLE method_handle; /* Method handle for direct (fast) execution */ - GPE_HANDLER handler; /* Address of handler, if any */ - void *context; /* Context to be passed to handler */ - -} ACPI_GPE_LEVEL_INFO; - - -/* Information about each particular fixed event */ - -typedef struct -{ - FIXED_EVENT_HANDLER handler; /* Address of handler. */ - void *context; /* Context to be passed to handler */ - -} ACPI_FIXED_EVENT_INFO; - - -/* Information used during field processing */ - -typedef struct -{ - u8 skip_field; - u8 field_flag; - u32 pkg_length; - -} ACPI_FIELD_INFO; - - -/***************************************************************************** - * - * Parser typedefs and structs - * - ****************************************************************************/ - - -#define OP_INFO_TYPE 0x1F -#define OP_INFO_HAS_ARGS 0x20 -#define OP_INFO_CHILD_LOCATION 0xC0 - -/* - * AML opcode, name, and argument layout - */ -typedef struct acpi_op_info -{ - u16 opcode; /* AML opcode */ - u8 flags; /* Opcode type, Has_args flag */ - u32 parse_args; /* Grammar/Parse time arguments */ - u32 runtime_args; /* Interpret time arguments */ - - DEBUG_ONLY_MEMBERS ( - char *name) /* op name (debug only) */ - -} ACPI_OP_INFO; - - -typedef union acpi_op_value -{ - u32 integer; /* integer constant */ - u32 size; /* bytelist or field size */ - char *string; /* NULL terminated string */ - u8 *buffer; /* buffer or string */ - char *name; /* NULL terminated string */ - struct acpi_generic_op *arg; /* arguments and contained ops */ - ACPI_NAMED_OBJECT *entry; /* entry in interpreter namespace tbl */ - -} ACPI_OP_VALUE; - - -#define ACPI_COMMON_OP \ - u8 data_type; /* To differentiate various internal objs */\ - u8 flags; /* Type of Op */\ - u16 opcode; /* AML opcode */\ - u32 aml_offset; /* offset of declaration in AML */\ - struct acpi_generic_op *parent; /* parent op */\ - struct acpi_generic_op *next; /* next op */\ - DEBUG_ONLY_MEMBERS (\ - char op_name[16]) /* op name (debug only) */\ - /* NON-DEBUG members below: */\ - void *acpi_named_object;/* for use by interpreter */\ - ACPI_OP_VALUE value; /* Value or args associated with the opcode */\ - - -/* - * generic operation (eg. If, While, Store) - */ -typedef struct acpi_generic_op -{ - ACPI_COMMON_OP -} ACPI_GENERIC_OP; - - -/* - * operation with a name (eg. Scope, Method, Name, Named_field, ...) - */ -typedef struct acpi_named_op -{ - ACPI_COMMON_OP - u32 name; /* 4-byte name or zero if no name */ - -} ACPI_NAMED_OP; - - -/* - * special operation for methods and regions (parsing must be deferred - * until a first pass parse is completed) - */ -typedef struct acpi_deferred_op -{ - ACPI_COMMON_OP - u32 name; /* 4-byte name or 0 if none */ - u32 body_length; /* AML body size */ - u8 *body; /* AML body */ - u16 thread_count; /* Count of threads currently executing a method */ - -} ACPI_DEFERRED_OP; - - -/* - * special operation for bytelists (Byte_list only) - */ -typedef struct acpi_bytelist_op -{ - ACPI_COMMON_OP - u8 *data; /* bytelist data */ - -} ACPI_BYTELIST_OP; - - -/* - * Parse state - one state per parser invocation and each control - * method. - */ - -typedef struct acpi_parse_state -{ - u8 *aml_start; /* first AML byte */ - u8 *aml; /* next AML byte */ - u8 *aml_end; /* (last + 1) AML byte */ - u8 *pkg_end; /* current package end */ - ACPI_GENERIC_OP *start_op; /* root of parse tree */ - struct acpi_parse_scope *scope; /* current scope */ - struct acpi_parse_scope *scope_avail; /* unused (extra) scope structs */ - struct acpi_parse_state *next; - -} ACPI_PARSE_STATE; - - -/* - * Parse scope - one per ACPI scope - */ - -typedef struct acpi_parse_scope -{ - ACPI_GENERIC_OP *op; /* current op being parsed */ - u8 *arg_end; /* current argument end */ - u8 *pkg_end; /* current package end */ - struct acpi_parse_scope *parent; /* parent scope */ - u32 arg_list; /* next argument to parse */ - u32 arg_count; /* Number of fixed arguments */ - -} ACPI_PARSE_SCOPE; - - -/***************************************************************************** - * - * Generic "state" object for stacks - * - ****************************************************************************/ - - -#define CONTROL_NORMAL 0xC0 -#define CONTROL_CONDITIONAL_EXECUTING 0xC1 -#define CONTROL_PREDICATE_EXECUTING 0xC2 -#define CONTROL_PREDICATE_FALSE 0xC3 -#define CONTROL_PREDICATE_TRUE 0xC4 - - -#define ACPI_STATE_COMMON /* Two 32-bit fields and a pointer */\ - u8 data_type; /* To differentiate various internal objs */\ - u8 flags; \ - u16 value; \ - u16 state; \ - u16 acpi_eval; \ - void *next; \ - -typedef struct acpi_common_state -{ - ACPI_STATE_COMMON -} ACPI_COMMON_STATE; - - -/* - * Update state - used to traverse complex objects such as packages - */ -typedef struct acpi_update_state -{ - ACPI_STATE_COMMON - union acpi_obj_internal *object; - -} ACPI_UPDATE_STATE; - -/* - * Control state - one per if/else and while constructs. - * Allows nesting of these constructs - */ -typedef struct acpi_control_state -{ - ACPI_STATE_COMMON - ACPI_GENERIC_OP *predicate_op; /* Start of if/while predicate */ - -} ACPI_CONTROL_STATE; - - -/* - * Scope state - current scope during namespace lookups - */ - -typedef struct acpi_scope_state -{ - ACPI_STATE_COMMON - ACPI_NAME_TABLE *name_table; - -} ACPI_SCOPE_STATE; - - -typedef union acpi_gen_state -{ - ACPI_COMMON_STATE common; - ACPI_CONTROL_STATE control; - ACPI_UPDATE_STATE update; - ACPI_SCOPE_STATE scope; - -} ACPI_GENERIC_STATE; - - -/***************************************************************************** - * - * Tree walking typedefs and structs - * - ****************************************************************************/ - - -/* - * Walk state - current state of a parse tree walk. Used for both a leisurely stroll through - * the tree (for whatever reason), and for control method execution. - */ - -#define NEXT_OP_DOWNWARD 1 -#define NEXT_OP_UPWARD 2 - -typedef struct acpi_walk_state -{ - u8 data_type; /* To differentiate various internal objs */\ - ACPI_OWNER_ID owner_id; /* Owner of objects created during the walk */ - u8 last_predicate; /* Result of last predicate */ - u8 next_op_info; /* Info about Next_op */ - u8 num_operands; /* Stack pointer for Operands[] array */ - u8 num_results; /* Stack pointer for Results[] array */ - u8 current_result; /* */ - - struct acpi_walk_state *next; /* Next Walk_state in list */ - ACPI_GENERIC_OP *origin; /* Start of walk */ - ACPI_GENERIC_OP *prev_op; /* Last op that was processed */ - ACPI_GENERIC_OP *next_op; /* next op to be processed */ - ACPI_GENERIC_STATE *control_state; /* List of control states (nested IFs) */ - ACPI_GENERIC_STATE *scope_info; /* Stack of nested scopes */ - union acpi_obj_internal *return_desc; /* Return object, if any */ - union acpi_obj_internal *method_desc; /* Method descriptor if running a method */ - ACPI_GENERIC_OP *method_call_op; /* Method_call Op if running a method */ - union acpi_obj_internal *operands[OBJ_NUM_OPERANDS]; /* Operands passed to the interpreter */ - union acpi_obj_internal *results[OBJ_NUM_OPERANDS]; /* Accumulated results */ - struct acpi_named_object arguments[MTH_NUM_ARGS]; /* Control method arguments */ - struct acpi_named_object local_variables[MTH_NUM_LOCALS]; /* Control method locals */ - - -} ACPI_WALK_STATE; - - -/* - * Walk list - head of a tree of walk states. Multiple walk states are created when there - * are nested control methods executing. - */ -typedef struct acpi_walk_list -{ - - ACPI_WALK_STATE *walk_state; - -} ACPI_WALK_LIST; - - -typedef -ACPI_STATUS (*INTERPRETER_CALLBACK) ( - ACPI_WALK_STATE *state, - ACPI_GENERIC_OP *op); - - -/* Info used by Acpi_ps_init_objects */ - -typedef struct init_walk_info -{ - u32 method_count; - u32 op_region_count; - ACPI_TABLE_DESC *table_desc; - -} INIT_WALK_INFO; - - -/* TBD: [Restructure] Merge with struct above */ - -typedef struct acpi_walk_info -{ - u32 debug_level; - u32 owner_id; - -} ACPI_WALK_INFO; - - -/***************************************************************************** - * - * Hardware and PNP - * - ****************************************************************************/ - - -/* Sleep states */ - -#define SLWA_DEBUG_LEVEL 4 -#define GTS_CALL 0 -#define GTS_WAKE 1 - -/* Cx States */ - -#define MAX_CX_STATE_LATENCY 0xFFFFFFFF -#define MAX_CX_STATES 4 - -/* - * The #define's and enum below establish an abstract way of identifying what - * register block and register is to be accessed. Do not change any of the - * values as they are used in switch statements and offset calculations. - */ - -#define REGISTER_BLOCK_MASK 0xFF00 -#define BIT_IN_REGISTER_MASK 0x00FF -#define PM1_EVT 0x0100 -#define PM1_CONTROL 0x0200 -#define PM2_CONTROL 0x0300 -#define PM_TIMER 0x0400 -#define PROCESSOR_BLOCK 0x0500 -#define GPE0_STS_BLOCK 0x0600 -#define GPE0_EN_BLOCK 0x0700 -#define GPE1_STS_BLOCK 0x0800 -#define GPE1_EN_BLOCK 0x0900 - -enum -{ - /* PM1 status register ids */ - - TMR_STS = (PM1_EVT | 0x01), - BM_STS, - GBL_STS, - PWRBTN_STS, - SLPBTN_STS, - RTC_STS, - WAK_STS, - - /* PM1 enable register ids */ - - TMR_EN, - /* need to skip 1 enable number since there's no bus master enable register */ - GBL_EN = (PM1_EVT | 0x0A), - PWRBTN_EN, - SLPBTN_EN, - RTC_EN, - - /* PM1 control register ids */ - - SCI_EN = (PM1_CONTROL | 0x01), - BM_RLD, - GBL_RLS, - SLP_TYPE_A, - SLP_TYPE_B, - SLP_EN, - - /* PM2 control register ids */ - - ARB_DIS = (PM2_CONTROL | 0x01), - - /* PM Timer register ids */ - - TMR_VAL = (PM_TIMER | 0x01), - - GPE0_STS = (GPE0_STS_BLOCK | 0x01), - GPE0_EN = (GPE0_EN_BLOCK | 0x01), - - GPE1_STS = (GPE1_STS_BLOCK | 0x01), - GPE1_EN = (GPE0_EN_BLOCK | 0x01), - - /* Last register value is one less than LAST_REG */ - - LAST_REG -}; - - -#define TMR_STS_MASK 0x0001 -#define BM_STS_MASK 0x0010 -#define GBL_STS_MASK 0x0020 -#define PWRBTN_STS_MASK 0x0100 -#define SLPBTN_STS_MASK 0x0200 -#define RTC_STS_MASK 0x0400 -#define WAK_STS_MASK 0x8000 - -#define ALL_FIXED_STS_BITS (TMR_STS_MASK | BM_STS_MASK | GBL_STS_MASK | PWRBTN_STS_MASK | \ - SLPBTN_STS_MASK | RTC_STS_MASK | WAK_STS_MASK) - -#define TMR_EN_MASK 0x0001 -#define GBL_EN_MASK 0x0020 -#define PWRBTN_EN_MASK 0x0100 -#define SLPBTN_EN_MASK 0x0200 -#define RTC_EN_MASK 0x0400 - -#define SCI_EN_MASK 0x0001 -#define BM_RLD_MASK 0x0002 -#define GBL_RLS_MASK 0x0004 -#define SLP_TYPE_X_MASK 0x1C00 -#define SLP_EN_MASK 0x2000 - -#define ARB_DIS_MASK 0x0001 - -#define GPE0_STS_MASK -#define GPE0_EN_MASK - -#define GPE1_STS_MASK -#define GPE1_EN_MASK - - -#define ACPI_READ 1 -#define ACPI_WRITE 2 - -#define LOW_BYTE 0x00FF -#define ONE_BYTE 0x08 - -#ifndef SET - #define SET 1 -#endif -#ifndef CLEAR - #define CLEAR 0 -#endif - - -/* Plug and play */ - -/* Pnp and ACPI data */ - -#define VERSION_NO 0x01 -#define LOGICAL_DEVICE_ID 0x02 -#define COMPATIBLE_DEVICE_ID 0x03 -#define IRQ_FORMAT 0x04 -#define DMA_FORMAT 0x05 -#define START_DEPENDENT_TAG 0x06 -#define END_DEPENDENT_TAG 0x07 -#define IO_PORT_DESCRIPTOR 0x08 -#define FIXED_LOCATION_IO_DESCRIPTOR 0x09 -#define RESERVED_TYPE0 0x0A -#define RESERVED_TYPE1 0x0B -#define RESERVED_TYPE2 0x0C -#define RESERVED_TYPE3 0x0D -#define SMALL_VENDOR_DEFINED 0x0E -#define END_TAG 0x0F - -/* Pnp and ACPI data */ - -#define MEMORY_RANGE_24 0x81 -#define ISA_MEMORY_RANGE 0x81 -#define LARGE_VENDOR_DEFINED 0x84 -#define EISA_MEMORY_RANGE 0x85 -#define MEMORY_RANGE_32 0x85 -#define FIXED_EISA_MEMORY_RANGE 0x86 -#define FIXED_MEMORY_RANGE_32 0x86 - -/* ACPI only data */ - -#define DWORD_ADDRESS_SPACE 0x87 -#define WORD_ADDRESS_SPACE 0x88 -#define EXTENDED_IRQ 0x89 - -/* MUST HAVES */ - - -typedef enum -{ - DWORD_DEVICE_ID, - STRING_PTR_DEVICE_ID, - STRING_DEVICE_ID - -} DEVICE_ID_TYPE; - -typedef struct -{ - DEVICE_ID_TYPE type; - union - { - u32 number; - char *string_ptr; - char buffer[9]; - } data; - -} DEVICE_ID; - - -/***************************************************************************** - * - * Debug - * - ****************************************************************************/ - - -/* Entry for a memory allocation (debug only) */ - -#ifdef ACPI_DEBUG - -#define MEM_MALLOC 0 -#define MEM_CALLOC 1 -#define MAX_MODULE_NAME 16 - -typedef struct allocation_info -{ - struct allocation_info *previous; - struct allocation_info *next; - void *address; - u32 size; - u32 component; - u32 line; - char module[MAX_MODULE_NAME]; - u8 alloc_type; - -} ALLOCATION_INFO; - -#endif - -#endif diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/include/interp.h linux/drivers/acpi/include/interp.h --- v2.4.0-test8/linux/drivers/acpi/include/interp.h Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/include/interp.h Wed Dec 31 16:00:00 1969 @@ -1,660 +0,0 @@ - -/****************************************************************************** - * - * Name: interp.h - Interpreter subcomponent prototypes and defines - * - *****************************************************************************/ - -/* - * Copyright (C) 2000 R. Byron Moore - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __INTERP_H__ -#define __INTERP_H__ - - -#include "actypes.h" -#include "acobject.h" - - -#define WALK_OPERANDS &(walk_state->operands [walk_state->num_operands -1]) - - -/* Interpreter constants */ - -#define AML_END_OF_BLOCK -1 -#define PUSH_PKG_LENGTH 1 -#define DO_NOT_PUSH_PKG_LENGTH 0 - - -#define STACK_TOP 0 -#define STACK_BOTTOM (u32) -1 - -/* Constants for global "When_to_parse_methods" */ - -#define METHOD_PARSE_AT_INIT 0x0 -#define METHOD_PARSE_JUST_IN_TIME 0x1 -#define METHOD_DELETE_AT_COMPLETION 0x2 - - -ACPI_STATUS -acpi_aml_resolve_operands ( - u16 opcode, - ACPI_OBJECT_INTERNAL **stack_ptr); - - -/* - * amxface - External interpreter interfaces - */ - -ACPI_STATUS -acpi_aml_load_table ( - ACPI_TABLE_TYPE table_id); - -ACPI_STATUS -acpi_aml_execute_method ( - ACPI_NAMED_OBJECT *method_entry, - ACPI_OBJECT_INTERNAL **params, - ACPI_OBJECT_INTERNAL **return_obj_desc); - - -/* - * amcopy - Interpreter object copy support - */ - -ACPI_STATUS -acpi_aml_build_copy_internal_package_object ( - ACPI_OBJECT_INTERNAL *source_obj, - ACPI_OBJECT_INTERNAL *dest_obj); - - -/* - * amfield - ACPI AML (p-code) execution - field manipulation - */ - - -ACPI_STATUS -acpi_aml_read_field ( - ACPI_OBJECT_INTERNAL *obj_desc, - void *buffer, - u32 buffer_length, - u32 byte_length, - u32 datum_length, - u32 bit_granularity, - u32 byte_granularity); - -ACPI_STATUS -acpi_aml_write_field ( - ACPI_OBJECT_INTERNAL *obj_desc, - void *buffer, - u32 buffer_length, - u32 byte_length, - u32 datum_length, - u32 bit_granularity, - u32 byte_granularity); - -ACPI_STATUS -acpi_aml_setup_field ( - ACPI_OBJECT_INTERNAL *obj_desc, - ACPI_OBJECT_INTERNAL *rgn_desc, - s32 field_bit_width); - -ACPI_STATUS -acpi_aml_read_field_data ( - ACPI_OBJECT_INTERNAL *obj_desc, - u32 field_byte_offset, - u32 field_bit_width, - u32 *value); - -ACPI_STATUS -acpi_aml_access_named_field ( - s32 mode, - ACPI_HANDLE named_field, - void *buffer, - u32 length); - -ACPI_STATUS -acpi_aml_set_named_field_value ( - ACPI_HANDLE named_field, - void *buffer, - u32 length); - -ACPI_STATUS -acpi_aml_get_named_field_value ( - ACPI_HANDLE named_field, - void *buffer, - u32 length); - - -/* - * ammisc - ACPI AML (p-code) execution - specific opcodes - */ - -ACPI_STATUS -acpi_aml_exec_create_field ( - u16 opcode, - ACPI_WALK_STATE *walk_state); - -ACPI_STATUS -acpi_aml_exec_reconfiguration ( - u16 opcode, - ACPI_WALK_STATE *walk_state); - -ACPI_STATUS -acpi_aml_exec_fatal ( - ACPI_WALK_STATE *walk_state); - -ACPI_STATUS -acpi_aml_exec_index ( - ACPI_WALK_STATE *walk_state, - ACPI_OBJECT_INTERNAL **return_desc); - -ACPI_STATUS -acpi_aml_exec_match ( - ACPI_WALK_STATE *walk_state, - ACPI_OBJECT_INTERNAL **return_desc); - -ACPI_STATUS -acpi_aml_exec_create_mutex ( - ACPI_WALK_STATE *walk_state); - -ACPI_STATUS -acpi_aml_exec_create_processor ( - ACPI_GENERIC_OP *op, - ACPI_HANDLE processor_nTE); - -ACPI_STATUS -acpi_aml_exec_create_power_resource ( - ACPI_GENERIC_OP *op, - ACPI_HANDLE processor_nTE); - -ACPI_STATUS -acpi_aml_exec_create_region ( - u8 *aml_ptr, - u32 acpi_aml_length, - u32 region_space, - ACPI_WALK_STATE *walk_state); - -ACPI_STATUS -acpi_aml_exec_create_event ( - ACPI_WALK_STATE *walk_state); - -ACPI_STATUS -acpi_aml_exec_create_alias ( - ACPI_WALK_STATE *walk_state); - -ACPI_STATUS -acpi_aml_exec_create_method ( - u8 *aml_ptr, - u32 acpi_aml_length, - u32 method_flags, - ACPI_HANDLE method); - - -/* - * amprep - ACPI AML (p-code) execution - prep utilities - */ - -ACPI_STATUS -acpi_aml_prep_def_field_value ( - ACPI_NAMED_OBJECT *this_entry, - ACPI_HANDLE region, - u8 field_flags, - u8 field_attribute, - u32 field_position, - u32 field_length); - -ACPI_STATUS -acpi_aml_prep_bank_field_value ( - ACPI_NAMED_OBJECT *this_entry, - ACPI_HANDLE region, - ACPI_HANDLE bank_reg, - u32 bank_val, - u8 field_flags, - u8 field_attribute, - u32 field_position, - u32 field_length); - -ACPI_STATUS -acpi_aml_prep_index_field_value ( - ACPI_NAMED_OBJECT *this_entry, - ACPI_HANDLE index_reg, - ACPI_HANDLE data_reg, - u8 field_flags, - u8 field_attribute, - u32 field_position, - u32 field_length); - -ACPI_STATUS -acpi_aml_prep_operands ( - char *types, - ACPI_OBJECT_INTERNAL **stack_ptr); - - -/* - * iepstack - package stack utilities - */ - -/* -u32 -Acpi_aml_pkg_stack_level ( - void); - -void -Acpi_aml_clear_pkg_stack ( - void); - -ACPI_STATUS -Acpi_aml_pkg_push_length ( - u32 Length, - OPERATING_MODE Load_exec_mode); - -ACPI_STATUS -Acpi_aml_pkg_push_exec_length ( - u32 Length); - -ACPI_STATUS -Acpi_aml_pkg_push_exec ( - u8 *Code, - u32 Len); - -ACPI_STATUS -Acpi_aml_pkg_pop_length ( - s32 No_err_under, - OPERATING_MODE Load_exec_mode); - -ACPI_STATUS -Acpi_aml_pkg_pop_exec_length ( - void); - -ACPI_STATUS -Acpi_aml_pkg_pop_exec ( - void); - -*/ - -/* - * amsystem - Interface to OS services - */ - -u16 -acpi_aml_system_thread_id ( - void); - -ACPI_STATUS -acpi_aml_system_do_notify_op ( - ACPI_OBJECT_INTERNAL *value, - ACPI_OBJECT_INTERNAL *obj_desc); - -void -acpi_aml_system_do_suspend( - u32 time); - -void -acpi_aml_system_do_stall ( - u32 time); - -ACPI_STATUS -acpi_aml_system_acquire_mutex( - ACPI_OBJECT_INTERNAL *time, - ACPI_OBJECT_INTERNAL *obj_desc); - -ACPI_STATUS -acpi_aml_system_release_mutex( - ACPI_OBJECT_INTERNAL *obj_desc); - -ACPI_STATUS -acpi_aml_system_signal_event( - ACPI_OBJECT_INTERNAL *obj_desc); - -ACPI_STATUS -acpi_aml_system_wait_event( - ACPI_OBJECT_INTERNAL *time, - ACPI_OBJECT_INTERNAL *obj_desc); - -ACPI_STATUS -acpi_aml_system_reset_event( - ACPI_OBJECT_INTERNAL *obj_desc); - -ACPI_STATUS -acpi_aml_system_wait_semaphore ( - ACPI_HANDLE semaphore, - u32 timeout); - - -/* - * ammonadic - ACPI AML (p-code) execution, monadic operators - */ - -ACPI_STATUS -acpi_aml_exec_monadic1 ( - u16 opcode, - ACPI_WALK_STATE *walk_state); - -ACPI_STATUS -acpi_aml_exec_monadic2 ( - u16 opcode, - ACPI_WALK_STATE *walk_state, - ACPI_OBJECT_INTERNAL **return_desc); - -ACPI_STATUS -acpi_aml_exec_monadic2_r ( - u16 opcode, - ACPI_WALK_STATE *walk_state, - ACPI_OBJECT_INTERNAL **return_desc); - - -/* - * amdyadic - ACPI AML (p-code) execution, dyadic operators - */ - -ACPI_STATUS -acpi_aml_exec_dyadic1 ( - u16 opcode, - ACPI_WALK_STATE *walk_state); - -ACPI_STATUS -acpi_aml_exec_dyadic2 ( - u16 opcode, - ACPI_WALK_STATE *walk_state, - ACPI_OBJECT_INTERNAL **return_desc); - -ACPI_STATUS -acpi_aml_exec_dyadic2_r ( - u16 opcode, - ACPI_WALK_STATE *walk_state, - ACPI_OBJECT_INTERNAL **return_desc); - -ACPI_STATUS -acpi_aml_exec_dyadic2_s ( - u16 opcode, - ACPI_WALK_STATE *walk_state, - ACPI_OBJECT_INTERNAL **return_desc); - - -/* - * amresolv - Object resolution and get value functions - */ - -ACPI_STATUS -acpi_aml_resolve_to_value ( - ACPI_OBJECT_INTERNAL **stack_ptr); - -ACPI_STATUS -acpi_aml_resolve_entry_to_value ( - ACPI_NAMED_OBJECT **stack_ptr); - -ACPI_STATUS -acpi_aml_resolve_object_to_value ( - ACPI_OBJECT_INTERNAL **stack_ptr); - -ACPI_STATUS -acpi_aml_get_field_unit_value ( - ACPI_OBJECT_INTERNAL *field_desc, - ACPI_OBJECT_INTERNAL *result_desc); - - -/* - * amcode - Scanner AML code manipulation routines - */ - -s32 -acpi_aml_avail ( - ACPI_SIZE n); - -s32 -acpi_aml_peek ( - void); - -s32 -acpi_aml_get_pcode_byte ( - u8 *pcode); - -u16 -acpi_aml_peek_op ( - void); - -u8 * -acpi_aml_consume_bytes ( - ACPI_SIZE bytes); - -ACPI_SIZE -acpi_aml_consume_stream_bytes ( - ACPI_SIZE bytes_to_get, - u8 *aml_buffer); - -void -acpi_aml_consume_package ( - OPERATING_MODE load_exec_mode); - -void -acpi_aml_set_pcode_input ( - u8 *base, - u32 length); - -ACPI_STATUS -acpi_aml_set_method ( - void *object); - -ACPI_STATUS -acpi_aml_prep_exec ( - u8 *pcode, - u32 pcode_length); - -ACPI_HANDLE -acpi_aml_get_pcode_handle ( - void); - -void -acpi_aml_get_current_location ( - ACPI_OBJECT_INTERNAL *method_desc); - -void -acpi_aml_set_current_location ( - ACPI_OBJECT_INTERNAL *method_desc); - - -/* - * amdump - Scanner debug output routines - */ - -void -acpi_aml_show_hex_value ( - s32 byte_count, - u8 *aml_ptr, - s32 lead_space); - -void -acpi_aml_dump_buffer ( - ACPI_SIZE length); - - -ACPI_STATUS -acpi_aml_dump_operand ( - ACPI_OBJECT_INTERNAL *entry_desc); - -void -acpi_aml_dump_operands ( - ACPI_OBJECT_INTERNAL **operands, - OPERATING_MODE interpreter_mode, - char *ident, - s32 num_levels, - char *note, - char *module_name, - s32 line_number); - -void -acpi_aml_dump_object_descriptor ( - ACPI_OBJECT_INTERNAL *object, - u32 flags); - - -void -acpi_aml_dump_acpi_named_object ( - ACPI_NAMED_OBJECT *entry, - u32 flags); - - -/* - * amnames - interpreter/scanner name load/execute - */ - -char * -acpi_aml_allocate_name_string ( - u32 prefix_count, - u32 num_name_segs); - -s32 -acpi_aml_good_char ( - s32 character); - -ACPI_STATUS -acpi_aml_exec_name_segment ( - u8 **in_aml_address, - char *name_string); - -ACPI_STATUS -acpi_aml_get_name_string ( - OBJECT_TYPE_INTERNAL data_type, - u8 *in_aml_address, - char **out_name_string, - u32 *out_name_length); - -u32 -acpi_aml_decode_package_length ( - u32 last_pkg_len); - - -ACPI_STATUS -acpi_aml_do_name ( - ACPI_OBJECT_TYPE data_type, - OPERATING_MODE load_exec_mode); - - -/* - * amstore - Object store support - */ - -ACPI_STATUS -acpi_aml_exec_store ( - ACPI_OBJECT_INTERNAL *op1, - ACPI_OBJECT_INTERNAL *res); - -ACPI_STATUS -acpi_aml_store_object_to_object ( - ACPI_OBJECT_INTERNAL *val_desc, - ACPI_OBJECT_INTERNAL *dest_desc); - -ACPI_STATUS -acpi_aml_store_object_to_nte ( - ACPI_OBJECT_INTERNAL *val_desc, - ACPI_NAMED_OBJECT *entry); - - -/* - * amutils - interpreter/scanner utilities - */ - -void -acpi_aml_enter_interpreter ( - void); - -void -acpi_aml_exit_interpreter ( - void); - -u8 -acpi_aml_validate_object_type ( - ACPI_OBJECT_TYPE type); - -u8 -acpi_aml_acquire_global_lock ( - u32 rule); - -ACPI_STATUS -acpi_aml_release_global_lock ( - u8 locked); - -void -acpi_aml_append_operand_diag( - char *name, - s32 line, - u16 op_code, - ACPI_OBJECT_INTERNAL **operands, - s32 Noperands); - -u32 -acpi_aml_buf_seq ( - void); - -s32 -acpi_aml_digits_needed ( - s32 value, - s32 base); - -ACPI_STATUS -acpi_aml_eisa_id_to_string ( - u32 numeric_id, - char *out_string); - - -/* - * amregion - default Op_region handlers - */ - -ACPI_STATUS -acpi_aml_system_memory_space_handler ( - u32 function, - u32 address, - u32 bit_width, - u32 *value, - void *context); - -ACPI_STATUS -acpi_aml_system_io_space_handler ( - u32 function, - u32 address, - u32 bit_width, - u32 *value, - void *context); - -ACPI_STATUS -acpi_aml_pci_config_space_handler ( - u32 function, - u32 address, - u32 bit_width, - u32 *value, - void *context); - -ACPI_STATUS -acpi_aml_embedded_controller_space_handler ( - u32 function, - u32 address, - u32 bit_width, - u32 *value, - void *context); - -ACPI_STATUS -acpi_aml_sm_bus_space_handler ( - u32 function, - u32 address, - u32 bit_width, - u32 *value, - void *context); - - -#endif /* __INTERP_H__ */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/include/macros.h linux/drivers/acpi/include/macros.h --- v2.4.0-test8/linux/drivers/acpi/include/macros.h Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/include/macros.h Wed Dec 31 16:00:00 1969 @@ -1,423 +0,0 @@ - -/****************************************************************************** - * - * Name: macros.h - C macros for the entire subsystem. - * - *****************************************************************************/ - -/* - * Copyright (C) 2000 R. Byron Moore - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __MACROS_H__ -#define __MACROS_H__ - -/* - * Data manipulation macros - */ - -#ifndef LOWORD -#define LOWORD(l) ((u16)(NATIVE_UINT)(l)) -#endif - -#ifndef HIWORD -#define HIWORD(l) ((u16)((((NATIVE_UINT)(l)) >> 16) & 0xFFFF)) -#endif - -#ifndef LOBYTE -#define LOBYTE(l) ((u8)(u16)(l)) -#endif - -#ifndef HIBYTE -#define HIBYTE(l) ((u8)((((u16)(l)) >> 8) & 0xFF)) -#endif - -#define BIT0(x) ((((x) & 0x01) > 0) ? 1 : 0) -#define BIT1(x) ((((x) & 0x02) > 0) ? 1 : 0) -#define BIT2(x) ((((x) & 0x04) > 0) ? 1 : 0) - -#define BIT3(x) ((((x) & 0x08) > 0) ? 1 : 0) -#define BIT4(x) ((((x) & 0x10) > 0) ? 1 : 0) -#define BIT5(x) ((((x) & 0x20) > 0) ? 1 : 0) -#define BIT6(x) ((((x) & 0x40) > 0) ? 1 : 0) -#define BIT7(x) ((((x) & 0x80) > 0) ? 1 : 0) - -#define LOW_BASE(w) ((u16) ((w) & 0x0000FFFF)) -#define MID_BASE(b) ((u8) (((b) & 0x00FF0000) >> 16)) -#define HI_BASE(b) ((u8) (((b) & 0xFF000000) >> 24)) -#define LOW_LIMIT(w) ((u16) ((w) & 0x0000FFFF)) -#define HI_LIMIT(b) ((u8) (((b) & 0x00FF0000) >> 16)) - - - /* - * Extract a byte of data using a pointer. Any more than a byte and we - * get into potential aligment issues -- see the STORE macros below - */ -#define GET8(addr) (*(u8*)(addr)) - - -/* - * Macros for moving data around to/from buffers that are possibly unaligned. - * If the hardware supports the transfer of unaligned data, just do the store. - * Otherwise, we have to move one byte at a time. - */ - -#ifdef _HW_ALIGNMENT_SUPPORT - -/* The hardware supports unaligned transfers, just do the move */ - -#define MOVE_UNALIGNED16_TO_16(d,s) *(u16*)(d) = *(u16*)(s) -#define MOVE_UNALIGNED32_TO_32(d,s) *(u32*)(d) = *(u32*)(s) -#define MOVE_UNALIGNED16_TO_32(d,s) *(u32*)(d) = *(u16*)(s) - -#else -/* - * The hardware does not support unaligned transfers. We must move the - * data one byte at a time. These macros work whether the source or - * the destination (or both) is/are unaligned. - */ - -#define MOVE_UNALIGNED16_TO_16(d,s) {((char *)(d))[0] = ((char *)(s))[0];\ - ((char *)(d))[1] = ((char *)(s))[1];} - -#define MOVE_UNALIGNED32_TO_32(d,s) {((char *)(d))[0] = ((char *)(s))[0];\ - ((char *)(d))[1] = ((char *)(s))[1];\ - ((char *)(d))[2] = ((char *)(s))[2];\ - ((char *)(d))[3] = ((char *)(s))[3];} - -#define MOVE_UNALIGNED16_TO_32(d,s) {(*(u32*)(d)) = 0; MOVE_UNALIGNED16_TO_16(d,s);} - -#endif - - -/* - * Fast power-of-two math macros for non-optimized compilers - */ - -#define _DIV(value,power_of2) ((value) >> (power_of2)) -#define _MUL(value,power_of2) ((value) << (power_of2)) -#define _MOD(value,divisor) ((value) & ((divisor) -1)) - -#define DIV_2(a) _DIV(a,1) -#define MUL_2(a) _MUL(a,1) -#define MOD_2(a) _MOD(a,2) - -#define DIV_4(a) _DIV(a,2) -#define MUL_4(a) _MUL(a,2) -#define MOD_4(a) _MOD(a,4) - -#define DIV_8(a) _DIV(a,3) -#define MUL_8(a) _MUL(a,3) -#define MOD_8(a) _MOD(a,8) - -#define DIV_16(a) _DIV(a,4) -#define MUL_16(a) _MUL(a,4) -#define MOD_16(a) _MOD(a,16) - - -/* - * Rounding macros (Power of two boundaries only) - */ - -#define ROUND_DOWN(value,boundary) ((value) & (~((boundary)-1))) -#define ROUND_UP(value,boundary) (((value) + ((boundary)-1)) & (~((boundary)-1))) - -#define ROUND_DOWN_TO_32_BITS(a) ROUND_DOWN(a,4) -#define ROUND_DOWN_TO_NATIVE_WORD(a) ROUND_DOWN(a,ALIGNED_ADDRESS_BOUNDARY) - -#define ROUND_UP_TO_32_bITS(a) ROUND_UP(a,4) -#define ROUND_UP_TO_NATIVE_WORD(a) ROUND_UP(a,ALIGNED_ADDRESS_BOUNDARY) - - -#ifdef DEBUG_ASSERT -#undef DEBUG_ASSERT -#endif - - -/* - * An ACPI_HANDLE (which is actually an ACPI_NAMED_OBJECT*) can appear in some contexts, - * such as on ap_obj_stack, where a pointer to an ACPI_OBJECT_INTERNAL can also - * appear. This macro is used to distinguish them. - * - * The Data_type field is the first field in both structures. - */ - -#define VALID_DESCRIPTOR_TYPE(d,t) (((ACPI_NAMED_OBJECT*)d)->data_type == t) - - -/* Macro to test the object type */ - -#define IS_THIS_OBJECT_TYPE(d,t) (((ACPI_OBJECT_INTERNAL *)d)->common.type == (u8)t) - - -/* - * Macro to check if a pointer is within an ACPI table. - * Parameter (a) is the pointer to check. Parameter (b) must be defined - * as a pointer to an ACPI_TABLE_HEADER. (b+1) then points past the header, - * and ((u8 *)b+b->Length) points one byte past the end of the table. - */ - -#ifndef _IA16 -#define IS_IN_ACPI_TABLE(a,b) (((u8 *)(a) >= (u8 *)(b + 1)) &&\ - ((u8 *)(a) < ((u8 *)b + b->length))) - -#else -#define IS_IN_ACPI_TABLE(a,b) (_segment)(a) == (_segment)(b) &&\ - (((u8 *)(a) >= (u8 *)(b + 1)) &&\ - ((u8 *)(a) < ((u8 *)b + b->length))) -#endif - -/* - * Macros for the master AML opcode table - */ - -#ifdef ACPI_DEBUG -#define OP_INFO_ENTRY(opcode,flags,name,Pargs,Iargs) {opcode,flags,Pargs,Iargs,name} -#else -#define OP_INFO_ENTRY(opcode,flags,name,Pargs,Iargs) {opcode,flags,Pargs,Iargs} -#endif - -#define ARG_TYPE_WIDTH 5 -#define ARG_1(x) ((u32)(x)) -#define ARG_2(x) ((u32)(x) << (1 * ARG_TYPE_WIDTH)) -#define ARG_3(x) ((u32)(x) << (2 * ARG_TYPE_WIDTH)) -#define ARG_4(x) ((u32)(x) << (3 * ARG_TYPE_WIDTH)) -#define ARG_5(x) ((u32)(x) << (4 * ARG_TYPE_WIDTH)) -#define ARG_6(x) ((u32)(x) << (5 * ARG_TYPE_WIDTH)) - -#define ARGI_LIST1(a) (ARG_1(a)) -#define ARGI_LIST2(a,b) (ARG_1(b)|ARG_2(a)) -#define ARGI_LIST3(a,b,c) (ARG_1(c)|ARG_2(b)|ARG_3(a)) -#define ARGI_LIST4(a,b,c,d) (ARG_1(d)|ARG_2(c)|ARG_3(b)|ARG_4(a)) -#define ARGI_LIST5(a,b,c,d,e) (ARG_1(e)|ARG_2(d)|ARG_3(c)|ARG_4(b)|ARG_5(a)) -#define ARGI_LIST6(a,b,c,d,e,f) (ARG_1(f)|ARG_2(e)|ARG_3(d)|ARG_4(c)|ARG_5(b)|ARG_6(a)) - -#define ARGP_LIST1(a) (ARG_1(a)) -#define ARGP_LIST2(a,b) (ARG_1(a)|ARG_2(b)) -#define ARGP_LIST3(a,b,c) (ARG_1(a)|ARG_2(b)|ARG_3(c)) -#define ARGP_LIST4(a,b,c,d) (ARG_1(a)|ARG_2(b)|ARG_3(c)|ARG_4(d)) -#define ARGP_LIST5(a,b,c,d,e) (ARG_1(a)|ARG_2(b)|ARG_3(c)|ARG_4(d)|ARG_5(e)) -#define ARGP_LIST6(a,b,c,d,e,f) (ARG_1(a)|ARG_2(b)|ARG_3(c)|ARG_4(d)|ARG_5(e)|ARG_6(f)) - -#define GET_CURRENT_ARG_TYPE(list) (list & 0x1F) -#define INCREMENT_ARG_LIST(list) (list >>= ARG_TYPE_WIDTH) - - -/* - * Reporting macros that are never compiled out - */ - -/* - * Error reporting. These versions add callers module and line#. Since - * _THIS_MODULE gets compiled out when ACPI_DEBUG isn't defined, only - * use it in debug mode. - */ - -#ifdef ACPI_DEBUG - -#define REPORT_INFO(a) _report_info(_THIS_MODULE,__LINE__,_COMPONENT,a) -#define REPORT_ERROR(a) _report_error(_THIS_MODULE,__LINE__,_COMPONENT,a) -#define REPORT_WARNING(a) _report_warning(_THIS_MODULE,__LINE__,_COMPONENT,a) -#define REPORT_SUCCESS(a) _report_success(_THIS_MODULE,__LINE__,_COMPONENT,a) - -#else - -#define REPORT_INFO(a) _report_info("",__LINE__,_COMPONENT,a) -#define REPORT_ERROR(a) _report_error("",__LINE__,_COMPONENT,a) -#define REPORT_WARNING(a) _report_warning("",__LINE__,_COMPONENT,a) -#define REPORT_SUCCESS(a) _report_success("",__LINE__,_COMPONENT,a) - -#endif - -/* Error reporting. These versions pass thru the module and line# */ - -#define _REPORT_INFO(a,b,c,d) _report_info(a,b,c,d) -#define _REPORT_ERROR(a,b,c,d) _report_error(a,b,c,d) -#define _REPORT_WARNING(a,b,c,d) _report_warning(a,b,c,d) - -/* Buffer dump macros */ - -#define DUMP_BUFFER(a,b) acpi_cm_dump_buffer((char *)a,b,DB_BYTE_DISPLAY,_COMPONENT) - -/* - * Debug macros that are conditionally compiled - */ - -#ifdef ACPI_DEBUG - -#define MODULE_NAME(name) static char *_THIS_MODULE = name - -/* - * Function entry tracing. - * The first parameter should be the procedure name as a quoted string. This is declared - * as a local string ("_Proc_name) so that it can be also used by the function exit macros below. - */ - -#define FUNCTION_TRACE(a) char * _proc_name = a;\ - function_trace(_THIS_MODULE,__LINE__,_COMPONENT,a) -#define FUNCTION_TRACE_PTR(a,b) char * _proc_name = a;\ - function_trace_ptr(_THIS_MODULE,__LINE__,_COMPONENT,a,(void *)b) -#define FUNCTION_TRACE_U32(a,b) char * _proc_name = a;\ - function_trace_u32(_THIS_MODULE,__LINE__,_COMPONENT,a,(u32)b) -#define FUNCTION_TRACE_STR(a,b) char * _proc_name = a;\ - function_trace_str(_THIS_MODULE,__LINE__,_COMPONENT,a,(char *)b) -/* - * Function exit tracing. - * WARNING: These macros include a return statement. This is usually considered - * bad form, but having a separate exit macro is very ugly and difficult to maintain. - * One of the FUNCTION_TRACE macros above must be used in conjunction with these macros - * so that "_Proc_name" is defined. - */ -#define return_VOID {function_exit(_THIS_MODULE,__LINE__,_COMPONENT,_proc_name);return;} -#define return_ACPI_STATUS(s) {function_status_exit(_THIS_MODULE,__LINE__,_COMPONENT,_proc_name,s);return(s);} -#define return_VALUE(s) {function_value_exit(_THIS_MODULE,__LINE__,_COMPONENT,_proc_name,(NATIVE_UINT)s);return(s);} -#define return_PTR(s) {function_ptr_exit(_THIS_MODULE,__LINE__,_COMPONENT,_proc_name,(char *)s);return(s);} - - -/* Conditional execution */ - -#define DEBUG_EXEC(a) a; -#define NORMAL_EXEC(a) - -#define DEBUG_DEFINE(a) a; -#define DEBUG_ONLY_MEMBERS(a) a; - - -/* Stack and buffer dumping */ - -#define DUMP_STACK_ENTRY(a) acpi_aml_dump_operand(a) -#define DUMP_OPERANDS(a,b,c,d,e) acpi_aml_dump_operands(a,b,c,d,e,_THIS_MODULE,__LINE__) - - -#define DUMP_ENTRY(a,b) acpi_ns_dump_entry (a,b) -#define DUMP_TABLES(a,b) acpi_ns_dump_tables(a,b) -#define DUMP_PATHNAME(a,b,c,d) acpi_ns_dump_pathname(a,b,c,d) -#define BREAK_MSG(a) acpi_os_breakpoint (a) - -/* - * Generate INT3 on ACPI_ERROR (Debug only!) - */ - -#define ERROR_BREAK -#ifdef ERROR_BREAK -#define BREAK_ON_ERROR(lvl) if ((lvl)&ACPI_ERROR) acpi_os_breakpoint("Fatal error encountered\n") -#else -#define BREAK_ON_ERROR(lvl) -#endif - -/* - * Master debug print macros - * Print iff: - * 1) Debug print for the current component is enabled - * 2) Debug error level or trace level for the print statement is enabled - * - */ - -#define PARAM_LIST(pl) pl - -#define TEST_DEBUG_SWITCH(lvl) if (((lvl) & acpi_dbg_level) && (_COMPONENT & acpi_dbg_layer)) - -#define DEBUG_PRINT(lvl,fp) TEST_DEBUG_SWITCH(lvl) {\ - debug_print_prefix (_THIS_MODULE,__LINE__);\ - debug_print_raw PARAM_LIST(fp);\ - BREAK_ON_ERROR(lvl);} - -#define DEBUG_PRINT_RAW(lvl,fp) TEST_DEBUG_SWITCH(lvl) {\ - debug_print_raw PARAM_LIST(fp);} - - -/* Assert macros */ - -#define ACPI_ASSERT(exp) if(!(exp)) \ - acpi_os_dbg_assert(#exp, __FILE__, __LINE__, "Failed Assertion") - -#define DEBUG_ASSERT(msg, exp) if(!(exp)) \ - acpi_os_dbg_assert(#exp, __FILE__, __LINE__, msg) - - -#else -/* - * This is the non-debug case -- make everything go away, - * leaving no executable debug code! - */ - -#define MODULE_NAME(name) -#define _THIS_MODULE "" - -#define DEBUG_EXEC(a) -#define NORMAL_EXEC(a) a; - -#define DEBUG_DEFINE(a) -#define DEBUG_ONLY_MEMBERS(a) -#define FUNCTION_TRACE(a) -#define FUNCTION_TRACE_PTR(a,b) -#define FUNCTION_TRACE_U32(a,b) -#define FUNCTION_TRACE_STR(a,b) -#define FUNCTION_EXIT -#define FUNCTION_STATUS_EXIT(s) -#define FUNCTION_VALUE_EXIT(s) -#define DUMP_STACK_ENTRY(a) -#define DUMP_OPERANDS(a,b,c,d,e) -#define DUMP_ENTRY(a,b) -#define DUMP_TABLES(a,b) -#define DUMP_PATHNAME(a,b,c,d) -#define DEBUG_PRINT(l,f) -#define DEBUG_PRINT_RAW(l,f) -#define BREAK_MSG(a) - -#define return_VOID return -#define return_ACPI_STATUS(s) return(s) -#define return_VALUE(s) return(s) -#define return_PTR(s) return(s) - -#define ACPI_ASSERT(exp) -#define DEBUG_ASSERT(msg, exp) - -#endif - - -/* - * For 16-bit code, we want to shrink some things even though - * we are using ACPI_DEBUG to get the debug output - */ -#ifdef _IA16 -#undef DEBUG_ONLY_MEMBERS -#define DEBUG_ONLY_MEMBERS(a) -#undef OP_INFO_ENTRY -#define OP_INFO_ENTRY(opcode,flags,name,Pargs,Iargs) {opcode,flags,Pargs,Iargs} -#endif - - -#ifndef ACPI_DEBUG - -#define ADD_OBJECT_NAME(a,b) - -#else - - -/* - * 1) Set name to blanks - * 2) Copy the object name - */ - -#define ADD_OBJECT_NAME(a,b) MEMSET (a->common.name, ' ', sizeof (a->common.name));\ - STRNCPY (a->common.name, acpi_gbl_ns_type_names[b], sizeof (a->common.name)) - -#endif - - -#endif /* MACROS_H */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/include/namesp.h linux/drivers/acpi/include/namesp.h --- v2.4.0-test8/linux/drivers/acpi/include/namesp.h Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/include/namesp.h Wed Dec 31 16:00:00 1969 @@ -1,424 +0,0 @@ - -/****************************************************************************** - * - * Name: namesp.h - Namespace subcomponent prototypes and defines - * - *****************************************************************************/ - -/* - * Copyright (C) 2000 R. Byron Moore - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __NAMESPACE_H__ -#define __NAMESPACE_H__ - -#include "actables.h" - - -/* To search the entire name space, pass this as Search_base */ - -#define NS_ALL ((ACPI_HANDLE)0) - -/* - * Elements of Acpi_ns_properties are bit significant - * and should be one-to-one with values of ACPI_OBJECT_TYPE - */ -#define NSP_NORMAL 0 -#define NSP_NEWSCOPE 1 /* a definition of this type opens a name scope */ -#define NSP_LOCAL 2 /* suppress search of enclosing scopes */ - - -/* Definitions of the predefined namespace names */ - -#define ACPI_UNKNOWN_NAME (u32) 0x3F3F3F3F /* Unknown name is "????" */ -#define ACPI_ROOT_NAME (u32) 0x2F202020 /* Root name is "/ " */ -#define ACPI_SYS_BUS_NAME (u32) 0x5F53425F /* Sys bus name is "_SB_" */ - -#define NS_ROOT_PATH "/" -#define NS_SYSTEM_BUS "_SB_" - - -/* Flags for Acpi_ns_lookup, Acpi_ns_search_and_enter */ - -#define NS_NO_UPSEARCH 0 -#define NS_SEARCH_PARENT 0x01 -#define NS_DONT_OPEN_SCOPE 0x02 -#define NS_NO_PEER_SEARCH 0x04 - -#define NS_WALK_UNLOCK TRUE -#define NS_WALK_NO_UNLOCK FALSE - - -ACPI_STATUS -acpi_ns_walk_namespace ( - OBJECT_TYPE_INTERNAL type, - ACPI_HANDLE start_object, - u32 max_depth, - u8 unlock_before_callback, - WALK_CALLBACK user_function, - void *context, - void **return_value); - - -ACPI_NAMED_OBJECT* -acpi_ns_get_next_object ( - OBJECT_TYPE_INTERNAL type, - ACPI_NAMED_OBJECT *parent, - ACPI_NAMED_OBJECT *child); - - -ACPI_STATUS -acpi_ns_delete_namespace_by_owner ( - u16 table_id); - -void -acpi_ns_free_table_entry ( - ACPI_NAMED_OBJECT *entry); - - -/* Namespace loading - nsload */ - -ACPI_STATUS -acpi_ns_parse_table ( - ACPI_TABLE_DESC *table_desc, - ACPI_NAME_TABLE *scope); - -ACPI_STATUS -acpi_ns_load_table ( - ACPI_TABLE_DESC *table_desc, - ACPI_NAMED_OBJECT *entry); - -ACPI_STATUS -acpi_ns_load_table_by_type ( - ACPI_TABLE_TYPE table_type); - - -/* - * Top-level namespace access - nsaccess - */ - - -ACPI_STATUS -acpi_ns_root_initialize ( - void); - -ACPI_STATUS -acpi_ns_lookup ( - ACPI_GENERIC_STATE *scope_info, - char *name, - OBJECT_TYPE_INTERNAL type, - OPERATING_MODE interpreter_mode, - u32 flags, - ACPI_WALK_STATE *walk_state, - ACPI_NAMED_OBJECT **ret_entry); - - -/* - * Table allocation/deallocation - nsalloc - */ - -ACPI_NAME_TABLE * -acpi_ns_allocate_name_table ( - u32 num_entries); - -ACPI_STATUS -acpi_ns_delete_namespace_subtree ( - ACPI_NAMED_OBJECT *parent_handle); - -void -acpi_ns_detach_object ( - ACPI_HANDLE object); - -void -acpi_ns_delete_name_table ( - ACPI_NAME_TABLE *name_table); - - -/* - * Namespace modification - nsmodify - */ - -ACPI_STATUS -acpi_ns_unload_namespace ( - ACPI_HANDLE handle); - -ACPI_STATUS -acpi_ns_delete_subtree ( - ACPI_HANDLE start_handle); - - -/* - * Namespace dump/print utilities - nsdump - */ - -void -acpi_ns_dump_tables ( - ACPI_HANDLE search_base, - s32 max_depth); - -void -acpi_ns_dump_entry ( - ACPI_HANDLE handle, - u32 debug_level); - -ACPI_STATUS -acpi_ns_dump_pathname ( - ACPI_HANDLE handle, - char *msg, - u32 level, - u32 component); - -void -acpi_ns_dump_root_devices ( - void); - -void -acpi_ns_dump_objects ( - OBJECT_TYPE_INTERNAL type, - u32 max_depth, - u32 ownder_id, - ACPI_HANDLE start_handle); - - -/* - * Namespace evaluation functions - nseval - */ - -ACPI_STATUS -acpi_ns_evaluate_by_handle ( - ACPI_NAMED_OBJECT *object_nte, - ACPI_OBJECT_INTERNAL **params, - ACPI_OBJECT_INTERNAL **return_object); - -ACPI_STATUS -acpi_ns_evaluate_by_name ( - char *pathname, - ACPI_OBJECT_INTERNAL **params, - ACPI_OBJECT_INTERNAL **return_object); - -ACPI_STATUS -acpi_ns_evaluate_relative ( - ACPI_NAMED_OBJECT *object_nte, - char *pathname, - ACPI_OBJECT_INTERNAL **params, - ACPI_OBJECT_INTERNAL **return_object); - -ACPI_STATUS -acpi_ns_execute_control_method ( - ACPI_NAMED_OBJECT *method_entry, - ACPI_OBJECT_INTERNAL **params, - ACPI_OBJECT_INTERNAL **return_obj_desc); - -ACPI_STATUS -acpi_ns_get_object_value ( - ACPI_NAMED_OBJECT *object_entry, - ACPI_OBJECT_INTERNAL **return_obj_desc); - - -/* - * Parent/Child/Peer utility functions - nsfamily - */ - -ACPI_NAME -acpi_ns_find_parent_name ( - ACPI_NAMED_OBJECT *entry_to_search); - -u8 -acpi_ns_exist_downstream_sibling ( - ACPI_NAMED_OBJECT *this_entry); - - -/* - * Scope manipulation - nsscope - */ - -s32 -acpi_ns_opens_scope ( - OBJECT_TYPE_INTERNAL type); - -char * -acpi_ns_name_of_scope ( - ACPI_NAME_TABLE *scope); - -char * -acpi_ns_name_of_current_scope ( - ACPI_WALK_STATE *walk_state); - -ACPI_STATUS -acpi_ns_handle_to_pathname ( - ACPI_HANDLE obj_handle, - u32 *buf_size, - char *user_buffer); - -u8 -acpi_ns_pattern_match ( - ACPI_NAMED_OBJECT *obj_entry, - char *search_for); - -ACPI_STATUS -acpi_ns_name_compare ( - ACPI_HANDLE obj_handle, - u32 level, - void *context, - void **return_value); - -void -acpi_ns_low_find_names ( - ACPI_NAMED_OBJECT *this_entry, - char *search_for, - s32 *count, - ACPI_HANDLE list[], - s32 max_depth); - -ACPI_HANDLE * -acpi_ns_find_names ( - char *search_for, - ACPI_HANDLE search_base, - s32 max_depth); - -ACPI_STATUS -acpi_ns_get_named_object ( - char *pathname, - ACPI_NAME_TABLE *in_scope, - ACPI_NAMED_OBJECT **out_nte); - -/* - * Object management for NTEs - nsobject - */ - -ACPI_STATUS -acpi_ns_attach_method ( - ACPI_HANDLE obj_handle, - u8 *pcode_addr, - u32 pcode_length); - -ACPI_STATUS -acpi_ns_attach_object ( - ACPI_HANDLE obj_handle, - ACPI_HANDLE value, - OBJECT_TYPE_INTERNAL type); - - -void * -acpi_ns_compare_value ( - ACPI_HANDLE obj_handle, - u32 level, - void *obj_desc); - -ACPI_HANDLE -acpi_ns_find_attached_object ( - ACPI_OBJECT_INTERNAL *obj_desc, - ACPI_HANDLE search_base, - s32 max_depth); - - -/* - * Namespace searching and entry - nssearch - */ - -ACPI_STATUS -acpi_ns_search_and_enter ( - u32 entry_name, - ACPI_WALK_STATE *walk_state, - ACPI_NAME_TABLE *name_table, - OPERATING_MODE interpreter_mode, - OBJECT_TYPE_INTERNAL type, - u32 flags, - ACPI_NAMED_OBJECT **ret_entry); - -void -acpi_ns_initialize_table ( - ACPI_NAME_TABLE *new_table, - ACPI_NAME_TABLE *parent_scope, - ACPI_NAMED_OBJECT *parent_entry); - -ACPI_STATUS -acpi_ns_search_one_scope ( - u32 entry_name, - ACPI_NAME_TABLE *name_table, - OBJECT_TYPE_INTERNAL type, - ACPI_NAMED_OBJECT **ret_entry, - NS_SEARCH_DATA *ret_info); - - -/* - * Utility functions - nsutils - */ - -u8 -acpi_ns_valid_root_prefix ( - char prefix); - -u8 -acpi_ns_valid_path_separator ( - char sep); - -OBJECT_TYPE_INTERNAL -acpi_ns_get_type ( - ACPI_HANDLE obj_handle); - -void * -acpi_ns_get_attached_object ( - ACPI_HANDLE obj_handle); - -s32 -acpi_ns_local ( - OBJECT_TYPE_INTERNAL type); - -ACPI_STATUS -acpi_ns_internalize_name ( - char *dotted_name, - char **converted_name); - -ACPI_STATUS -acpi_ns_externalize_name ( - u32 internal_name_length, - char *internal_name, - u32 *converted_name_length, - char **converted_name); - -s32 -is_ns_object ( - ACPI_OBJECT_INTERNAL *p_oD); - -s32 -acpi_ns_mark_nS( - void); - -ACPI_NAMED_OBJECT* -acpi_ns_convert_handle_to_entry ( - ACPI_HANDLE handle); - -ACPI_HANDLE -acpi_ns_convert_entry_to_handle( - ACPI_NAMED_OBJECT*nte); - -void -acpi_ns_terminate ( - void); - -ACPI_NAMED_OBJECT * -acpi_ns_get_parent_entry ( - ACPI_NAMED_OBJECT *this_entry); - - -ACPI_NAMED_OBJECT * -acpi_ns_get_next_valid_entry ( - ACPI_NAMED_OBJECT *this_entry); - - -#endif /* __NAMESPACE_H__ */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/include/output.h linux/drivers/acpi/include/output.h --- v2.4.0-test8/linux/drivers/acpi/include/output.h Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/include/output.h Wed Dec 31 16:00:00 1969 @@ -1,124 +0,0 @@ - -/****************************************************************************** - * - * Name: output.h -- debug output - * - *****************************************************************************/ - -/* - * Copyright (C) 2000 R. Byron Moore - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _OUTPUT_H -#define _OUTPUT_H - -/* - * Debug levels and component IDs. These are used to control the - * granularity of the output of the DEBUG_PRINT macro -- on a per- - * component basis and a per-exception-type basis. - */ - -/* Component IDs -- used in the global "Debug_layer" */ - -#define GLOBAL 0x00000001 -#define COMMON 0x00000002 -#define PARSER 0x00000004 -#define DISPATCHER 0x00000008 -#define INTERPRETER 0x00000010 -#define NAMESPACE 0x00000020 -#define RESOURCE_MANAGER 0x00000040 -#define TABLE_MANAGER 0x00000080 -#define EVENT_HANDLING 0x00000100 -#define HARDWARE 0x00000200 -#define MISCELLANEOUS 0x00000400 -#define OS_DEPENDENT 0x00000800 - -#define BUS_MANAGER 0x00001000 - -#define PROCESSOR_CONTROL 0x00002000 -#define SYSTEM_CONTROL 0x00004000 -#define THERMAL_CONTROL 0x00008000 -#define POWER_CONTROL 0x00010000 - -#define EMBEDDED_CONTROLLER 0x00020000 -#define BATTERY 0x00040000 - -#define DEBUGGER 0x00100000 -#define ALL_COMPONENTS 0x001FFFFF - - -/* Exception level -- used in the global "Debug_level" */ - -#define ACPI_OK 0x00000001 -#define ACPI_INFO 0x00000002 -#define ACPI_WARN 0x00000004 -#define ACPI_ERROR 0x00000008 -#define ACPI_FATAL 0x00000010 -#define ACPI_DEBUG_OBJECT 0x00000020 -#define ACPI_ALL 0x0000003F - - -/* Trace level -- also used in the global "Debug_level" */ - -#define TRACE_PARSE 0x00000100 -#define TRACE_DISPATCH 0x00000200 -#define TRACE_LOAD 0x00000400 -#define TRACE_EXEC 0x00000800 -#define TRACE_NAMES 0x00001000 -#define TRACE_OPREGION 0x00002000 -#define TRACE_BFIELD 0x00004000 -#define TRACE_TRASH 0x00008000 -#define TRACE_TABLES 0x00010000 -#define TRACE_FUNCTIONS 0x00020000 -#define TRACE_VALUES 0x00040000 -#define TRACE_OBJECTS 0x00080000 -#define TRACE_ALLOCATIONS 0x00100000 -#define TRACE_RESOURCES 0x00200000 -#define TRACE_IO 0x00400000 -#define TRACE_INTERRUPTS 0x00800000 -#define TRACE_USER_REQUESTS 0x01000000 -#define TRACE_PACKAGE 0x02000000 -#define TRACE_MUTEX 0x04000000 - -#define TRACE_ALL 0x0FFFFF00 - - -/* Exceptionally verbose output -- also used in the global "Debug_level" */ - -#define VERBOSE_AML_DISASSEMBLE 0x10000000 -#define VERBOSE_INFO 0x20000000 -#define VERBOSE_TABLES 0x40000000 -#define VERBOSE_EVENTS 0x80000000 - -#define VERBOSE_ALL 0x70000000 - - -/* Defaults for Debug_level, debug and normal */ - -#define DEBUG_DEFAULT (ACPI_OK | ACPI_WARN | ACPI_ERROR | ACPI_DEBUG_OBJECT | TRACE_TABLES | TRACE_IO) -#define NORMAL_DEFAULT (ACPI_OK | ACPI_WARN | ACPI_ERROR | ACPI_DEBUG_OBJECT) -#define DEBUG_ALL (VERBOSE_AML_DISASSEMBLE | TRACE_ALL | ACPI_ALL) - -/* Misc defines */ - -#define HEX 0x01 -#define ASCII 0x02 -#define FULL_ADDRESS 0x04 -#define CHARS_PER_LINE 16 /* used in Dump_buf function */ - - -#endif /* _OUTPUT_H */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/include/parser.h linux/drivers/acpi/include/parser.h --- v2.4.0-test8/linux/drivers/acpi/include/parser.h Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/include/parser.h Wed Dec 31 16:00:00 1969 @@ -1,327 +0,0 @@ -/****************************************************************************** - * - * Module Name: parser.h - AML Parser subcomponent prototypes and defines - * - *****************************************************************************/ - -/* - * Copyright (C) 2000 R. Byron Moore - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#ifndef _PARSER_H_ -#define _PARSER_H_ - - -#define OP_HAS_RETURN_VALUE 1 - -/* variable # arguments */ - -#define ACPI_VAR_ARGS ACPI_UINT32_MAX - -/* maximum virtual address */ - -#define ACPI_MAX_AML ((u8 *)(~0UL)) - - -#define PARSE_DELETE_TREE 1 - - -/* psapi - Parser external interfaces */ - -ACPI_STATUS -acpi_psx_load_table ( - u8 *pcode_addr, - s32 pcode_length); - -ACPI_STATUS -acpi_psx_execute ( - ACPI_NAMED_OBJECT *method_entry, - ACPI_OBJECT_INTERNAL **params, - ACPI_OBJECT_INTERNAL **return_obj_desc); - - -u8 -acpi_ps_is_namespace_object_op ( - u16 opcode); -u8 -acpi_ps_is_namespace_op ( - u16 opcode); - - -/****************************************************************************** - * - * Parser interfaces - * - *****************************************************************************/ - - -/* psargs - Parse AML opcode arguments */ - -u8 * -acpi_ps_get_next_package_end ( - ACPI_PARSE_STATE *parser_state); - -char * -acpi_ps_get_next_namestring ( - ACPI_PARSE_STATE *parser_state); - -void -acpi_ps_get_next_simple_arg ( - ACPI_PARSE_STATE *parser_state, - s32 arg_type, /* type of argument */ - ACPI_GENERIC_OP *arg); /* (OUT) argument data */ - -void -acpi_ps_get_next_namepath ( - ACPI_PARSE_STATE *parser_state, - ACPI_GENERIC_OP *arg, - u32 *arg_count, - u8 method_call); - -ACPI_GENERIC_OP * -acpi_ps_get_next_field ( - ACPI_PARSE_STATE *parser_state); - -ACPI_GENERIC_OP * -acpi_ps_get_next_arg ( - ACPI_PARSE_STATE *parser_state, - s32 arg_type, - u32 *arg_count); - - -/* psopcode - AML Opcode information */ - -ACPI_OP_INFO * -acpi_ps_get_opcode_info ( - u16 opcode); - -char * -acpi_ps_get_opcode_name ( - u16 opcode); - - -/* psparse - top level parsing routines */ - -void -acpi_ps_delete_parse_tree ( - ACPI_GENERIC_OP *root); - -ACPI_STATUS -acpi_ps_parse_loop ( - ACPI_PARSE_STATE *parser_state, - ACPI_WALK_STATE *walk_state, - u32 parse_flags); - - -ACPI_STATUS -acpi_ps_parse_aml ( - ACPI_GENERIC_OP *start_scope, - u8 *aml, - u32 acpi_aml_size, - u32 parse_flags); - -ACPI_STATUS -acpi_ps_parse_table ( - u8 *aml, - s32 aml_size, - INTERPRETER_CALLBACK descending_callback, - INTERPRETER_CALLBACK ascending_callback, - ACPI_GENERIC_OP **root_object); - -u16 -acpi_ps_peek_opcode ( - ACPI_PARSE_STATE *state); - - -/* psscope - Scope stack management routines */ - - -ACPI_STATUS -acpi_ps_init_scope ( - ACPI_PARSE_STATE *parser_state, - ACPI_GENERIC_OP *root); - -ACPI_GENERIC_OP * -acpi_ps_get_parent_scope ( - ACPI_PARSE_STATE *state); - -u8 -acpi_ps_has_completed_scope ( - ACPI_PARSE_STATE *parser_state); - -void -acpi_ps_pop_scope ( - ACPI_PARSE_STATE *parser_state, - ACPI_GENERIC_OP **op, - u32 *arg_list); - -ACPI_STATUS -acpi_ps_push_scope ( - ACPI_PARSE_STATE *parser_state, - ACPI_GENERIC_OP *op, - u32 remaining_args, - u32 arg_count); - -void -acpi_ps_cleanup_scope ( - ACPI_PARSE_STATE *state); - - -/* pstree - parse tree manipulation routines */ - -void -acpi_ps_append_arg( - ACPI_GENERIC_OP *op, - ACPI_GENERIC_OP *arg); - -ACPI_GENERIC_OP* -acpi_ps_find ( - ACPI_GENERIC_OP *scope, - char *path, - u16 opcode, - u32 create); - -ACPI_GENERIC_OP * -acpi_ps_get_arg( - ACPI_GENERIC_OP *op, - u32 argn); - -ACPI_GENERIC_OP * -acpi_ps_get_child ( - ACPI_GENERIC_OP *op); - -ACPI_GENERIC_OP * -acpi_ps_get_depth_next ( - ACPI_GENERIC_OP *origin, - ACPI_GENERIC_OP *op); - - -/* pswalk - parse tree walk routines */ - -ACPI_STATUS -acpi_ps_walk_parsed_aml ( - ACPI_GENERIC_OP *start_op, - ACPI_GENERIC_OP *end_op, - ACPI_OBJECT_INTERNAL *mth_desc, - ACPI_NAME_TABLE *start_scope, - ACPI_OBJECT_INTERNAL **params, - ACPI_OBJECT_INTERNAL **caller_return_desc, - ACPI_OWNER_ID owner_id, - INTERPRETER_CALLBACK descending_callback, - INTERPRETER_CALLBACK ascending_callback); - -ACPI_STATUS -acpi_ps_get_next_walk_op ( - ACPI_WALK_STATE *walk_state, - ACPI_GENERIC_OP *op, - INTERPRETER_CALLBACK ascending_callback); - - -/* psutils - parser utilities */ - -void -acpi_ps_init_op ( - ACPI_GENERIC_OP *op, - u16 opcode); - -ACPI_GENERIC_OP * -acpi_ps_alloc_op ( - u16 opcode); - -void -acpi_ps_free_op ( - ACPI_GENERIC_OP *op); - -void -acpi_ps_delete_parse_cache ( - void); - -u8 -acpi_ps_is_leading_char ( - s32 c); - -u8 -acpi_ps_is_prefix_char ( - s32 c); - -u8 -acpi_ps_is_named_op ( - u16 opcode); - -u8 -acpi_ps_is_named_object_op ( - u16 opcode); - -u8 -acpi_ps_is_deferred_op ( - u16 opcode); - -u8 -acpi_ps_is_bytelist_op( - u16 opcode); - -u8 -acpi_ps_is_field_op( - u16 opcode); - -u8 -acpi_ps_is_create_field_op ( - u16 opcode); - -ACPI_NAMED_OP* -acpi_ps_to_named_op( - ACPI_GENERIC_OP *op); - -ACPI_DEFERRED_OP * -acpi_ps_to_deferred_op ( - ACPI_GENERIC_OP *op); - -ACPI_BYTELIST_OP* -acpi_ps_to_bytelist_op( - ACPI_GENERIC_OP *op); - -u32 -acpi_ps_get_name( - ACPI_GENERIC_OP *op); - -void -acpi_ps_set_name( - ACPI_GENERIC_OP *op, - u32 name); - - -/* psdump - display parser tree */ - -s32 -acpi_ps_sprint_path ( - char *buffer_start, - u32 buffer_size, - ACPI_GENERIC_OP *op); - -s32 -acpi_ps_sprint_op ( - char *buffer_start, - u32 buffer_size, - ACPI_GENERIC_OP *op); - -void -acpi_ps_show ( - ACPI_GENERIC_OP *op); - - -#endif /* _PARSER_H_ */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/include/resource.h linux/drivers/acpi/include/resource.h --- v2.4.0-test8/linux/drivers/acpi/include/resource.h Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/include/resource.h Wed Dec 31 16:00:00 1969 @@ -1,300 +0,0 @@ -/****************************************************************************** - * - * Name: resource.h - Resource Manager function prototypes - * - *****************************************************************************/ - -/* - * Copyright (C) 2000 R. Byron Moore - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __RESOURCE_H__ -#define __RESOURCE_H__ - -#include "actypes.h" -#include "acobject.h" - -/* - * Function prototypes called from Acpi* APIs - */ - -ACPI_STATUS -acpi_rs_get_prt_method_data ( - ACPI_HANDLE handle, - ACPI_BUFFER *ret_buffer); - - -ACPI_STATUS -acpi_rs_get_crs_method_data ( - ACPI_HANDLE handle, - ACPI_BUFFER *ret_buffer); - -ACPI_STATUS -acpi_rs_get_prs_method_data ( - ACPI_HANDLE handle, - ACPI_BUFFER *ret_buffer); - -ACPI_STATUS -acpi_rs_set_srs_method_data ( - ACPI_HANDLE handle, - ACPI_BUFFER *ret_buffer); - -ACPI_STATUS -acpi_rs_create_resource_list ( - ACPI_OBJECT_INTERNAL *byte_stream_buffer, - u8 *output_buffer, - u32 *output_buffer_length); - -ACPI_STATUS -acpi_rs_create_byte_stream ( - RESOURCE *linked_list_buffer, - u8 *output_buffer, - u32 *output_buffer_length); - -ACPI_STATUS -acpi_rs_create_pci_routing_table ( - ACPI_OBJECT_INTERNAL *method_return_object, - u8 *output_buffer, - u32 *output_buffer_length); - - -/* - *Function prototypes called from Acpi_rs_create*APIs - */ - -void -acpi_rs_dump_resource_list ( - RESOURCE *resource); - -void -acpi_rs_dump_irq_list ( - u8 *route_table); - -ACPI_STATUS -acpi_rs_get_byte_stream_start ( - u8 *byte_stream_buffer, - u8 **byte_stream_start, - u32 *size); - -ACPI_STATUS -acpi_rs_calculate_list_length ( - u8 *byte_stream_buffer, - u32 byte_stream_buffer_length, - u32 *size_needed); - -ACPI_STATUS -acpi_rs_calculate_byte_stream_length ( - RESOURCE *linked_list_buffer, - u32 *size_needed); - -ACPI_STATUS -acpi_rs_byte_stream_to_list ( - u8 *byte_stream_buffer, - u32 byte_stream_buffer_length, - u8 **output_buffer); - -ACPI_STATUS -acpi_rs_list_to_byte_stream ( - RESOURCE *linked_list, - u32 byte_stream_size_needed, - u8 **output_buffer); - -ACPI_STATUS -acpi_rs_io_resource ( - u8 *byte_stream_buffer, - u32 *bytes_consumed, - u8 **output_buffer, - u32 *structure_size); - -ACPI_STATUS -acpi_rs_fixed_io_resource ( - u8 *byte_stream_buffer, - u32 *bytes_consumed, - u8 **output_buffer, - u32 *structure_size); - -ACPI_STATUS -acpi_rs_io_stream ( - RESOURCE *linked_list, - u8 **output_buffer, - u32 *bytes_consumed); - -ACPI_STATUS -acpi_rs_fixed_io_stream ( - RESOURCE *linked_list, - u8 **output_buffer, - u32 *bytes_consumed); - -ACPI_STATUS -acpi_rs_irq_resource ( - u8 *byte_stream_buffer, - u32 *bytes_consumed, - u8 **output_buffer, - u32 *structure_size); - -ACPI_STATUS -acpi_rs_irq_stream ( - RESOURCE *linked_list, - u8 **output_buffer, - u32 *bytes_consumed); - -ACPI_STATUS -acpi_rs_dma_resource ( - u8 *byte_stream_buffer, - u32 *bytes_consumed, - u8 **output_buffer, - u32 *structure_size); - -ACPI_STATUS -acpi_rs_dma_stream ( - RESOURCE *linked_list, - u8 **output_buffer, - u32 *bytes_consumed); - -ACPI_STATUS -acpi_rs_address16_resource ( - u8 *byte_stream_buffer, - u32 *bytes_consumed, - u8 **output_buffer, - u32 *structure_size); - -ACPI_STATUS -acpi_rs_address16_stream ( - RESOURCE *linked_list, - u8 **output_buffer, - u32 *bytes_consumed); - -ACPI_STATUS -acpi_rs_address32_resource ( - u8 *byte_stream_buffer, - u32 *bytes_consumed, - u8 **output_buffer, - u32 *structure_size); - -ACPI_STATUS -acpi_rs_address32_stream ( - RESOURCE *linked_list, - u8 **output_buffer, - u32 *bytes_consumed); - -ACPI_STATUS -acpi_rs_start_dependent_functions_resource ( - u8 *byte_stream_buffer, - u32 *bytes_consumed, - u8 **output_buffer, - u32 *structure_size); - -ACPI_STATUS -acpi_rs_end_dependent_functions_resource ( - u8 *byte_stream_buffer, - u32 *bytes_consumed, - u8 **output_buffer, - u32 *structure_size); - -ACPI_STATUS -acpi_rs_start_dependent_functions_stream ( - RESOURCE *linked_list, - u8 **output_buffer, - u32 *bytes_consumed); - -ACPI_STATUS -acpi_rs_end_dependent_functions_stream ( - RESOURCE *linked_list, - u8 **output_buffer, - u32 *bytes_consumed); - -ACPI_STATUS -acpi_rs_memory24_resource ( - u8 *byte_stream_buffer, - u32 *bytes_consumed, - u8 **output_buffer, - u32 *structure_size); - -ACPI_STATUS -acpi_rs_memory24_stream ( - RESOURCE *linked_list, - u8 **output_buffer, - u32 *bytes_consumed); - -ACPI_STATUS -acpi_rs_memory32_range_resource ( - u8 *byte_stream_buffer, - u32 *bytes_consumed, - u8 **output_buffer, - u32 *structure_size -); - -ACPI_STATUS -acpi_rs_fixed_memory32_resource ( - u8 *byte_stream_buffer, - u32 *bytes_consumed, - u8 **output_buffer, - u32 *structure_size); - -ACPI_STATUS -acpi_rs_memory32_range_stream ( - RESOURCE *linked_list, - u8 **output_buffer, - u32 *bytes_consumed); - -ACPI_STATUS -acpi_rs_fixed_memory32_stream ( - RESOURCE *linked_list, - u8 **output_buffer, - u32 *bytes_consumed); - -ACPI_STATUS -acpi_rs_extended_irq_resource ( - u8 *byte_stream_buffer, - u32 *bytes_consumed, - u8 **output_buffer, - u32 *structure_size); - -ACPI_STATUS -acpi_rs_extended_irq_stream ( - RESOURCE *linked_list, - u8 **output_buffer, - u32 *bytes_consumed); - -ACPI_STATUS -acpi_rs_end_tag_resource ( - u8 *byte_stream_buffer, - u32 *bytes_consumed, - u8 **output_buffer, - u32 *structure_size); - -ACPI_STATUS -acpi_rs_end_tag_stream ( - RESOURCE *linked_list, - u8 **output_buffer, - u32 *bytes_consumed); - -ACPI_STATUS -acpi_rs_vendor_resource ( - u8 *byte_stream_buffer, - u32 *bytes_consumed, - u8 **output_buffer, - u32 *structure_size); - -ACPI_STATUS -acpi_rs_vendor_stream ( - RESOURCE *linked_list, - u8 **output_buffer, - u32 *bytes_consumed); - - -#endif /*__RESOURCE_H__ */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/include/tables.h linux/drivers/acpi/include/tables.h --- v2.4.0-test8/linux/drivers/acpi/include/tables.h Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/include/tables.h Wed Dec 31 16:00:00 1969 @@ -1,168 +0,0 @@ - -/****************************************************************************** - * - * Name: tables.h - ACPI table management - * - *****************************************************************************/ - -/* - * Copyright (C) 2000 R. Byron Moore - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __TABLES_H__ -#define __TABLES_H__ - -#include "actypes.h" -#include "actables.h" - - -/* Used in Acpi_tb_map_acpi_table for size parameter if table header is to be used */ - -#define SIZE_IN_HEADER 0 - - -ACPI_STATUS -acpi_tb_handle_to_object ( - u16 table_id, - ACPI_TABLE_DESC **table_desc); - - -/* - * Acpi_tbfac - FACP, FACS utilities - */ - -ACPI_STATUS -acpi_tb_get_table_facs ( - char *buffer_ptr, - ACPI_TABLE_DESC *table_info); - - -/* - * Acpi_tbget - Table "get" routines - */ - -ACPI_STATUS -acpi_tb_get_table_ptr ( - ACPI_TABLE_TYPE table_type, - u32 instance, - ACPI_TABLE_HEADER **table_ptr_loc); - -ACPI_STATUS -acpi_tb_get_table ( - void *physical_address, - char *buffer_ptr, - ACPI_TABLE_DESC *table_info); - - -/* - * Acpi_tbgetall - Get all firmware ACPI tables - */ - -ACPI_STATUS -acpi_tb_get_all_tables ( - u32 number_of_tables, - char *buffer_ptr); - - -/* - * Acpi_tbinstall - Table installation - */ - -ACPI_STATUS -acpi_tb_install_table ( - char *table_ptr, - ACPI_TABLE_DESC *table_info); - -ACPI_STATUS -acpi_tb_recognize_table ( - char *table_ptr, - ACPI_TABLE_DESC *table_info); - -ACPI_STATUS -acpi_tb_init_table_descriptor ( - ACPI_TABLE_TYPE table_type, - ACPI_TABLE_DESC *table_info); - - -/* - * Acpi_tbremove - Table removal and deletion - */ - -void -acpi_tb_delete_acpi_tables ( - void); - -void -acpi_tb_delete_acpi_table ( - ACPI_TABLE_TYPE type); - -ACPI_TABLE_DESC * -acpi_tb_delete_single_table ( - ACPI_TABLE_DESC *table_desc); - -void -acpi_tb_free_acpi_tables_of_type ( - ACPI_TABLE_DESC *table_info); - - -/* - * Acpi_tbrsd - RSDP, RSDT utilities - */ - -ACPI_STATUS -acpi_tb_get_table_rsdt ( - u32 *number_of_tables); - -char * -acpi_tb_scan_memory_for_rsdp ( - char *start_address, - u32 length); - -ACPI_STATUS -acpi_tb_find_rsdp ( - ACPI_TABLE_DESC *table_info); - - -/* - * Acpi_tbutils - common table utilities - */ - -u8 -acpi_tb_system_table_pointer ( - void *where); - -ACPI_STATUS -acpi_tb_map_acpi_table ( - void *physical_address, - u32 *size, - void **logical_address); - -ACPI_STATUS -acpi_tb_verify_table_checksum ( - ACPI_TABLE_HEADER *table_header); - -u8 -acpi_tb_checksum ( - void *buffer, - u32 length); - -ACPI_STATUS -acpi_tb_validate_table_header ( - ACPI_TABLE_HEADER *table_header); - - -#endif /* __TABLES_H__ */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/interpreter/Makefile linux/drivers/acpi/interpreter/Makefile --- v2.4.0-test8/linux/drivers/acpi/interpreter/Makefile Wed Dec 31 16:00:00 1969 +++ linux/drivers/acpi/interpreter/Makefile Fri Sep 15 18:21:44 2000 @@ -0,0 +1,28 @@ +# +# Makefile for all Linux ACPI interpreter subdirectories +# + +SUB_DIRS := +MOD_SUB_DIRS := $(SUB_DIRS) +MOD_IN_SUB_DIRS := +ALL_SUB_DIRS := $(SUB_DIRS) + +O_TARGET := ../$(shell basename `pwd`).o +O_OBJS := +M_OBJS := + +ACPI_OBJS := $(patsubst %.c,%.o,$(wildcard *.c)) + +EXTRA_CFLAGS += -I../include + +EXTRA_CFLAGS += $(ACPI_CFLAGS) + +# if the interpreter is used, it overrides arch/i386/kernel/acpi.c +ifeq ($(CONFIG_ACPI_INTERPRETER),y) + O_OBJS := $(ACPI_OBJS) +endif + +include $(TOPDIR)/Rules.make + +clean: + $(RM) *.o diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/interpreter/amconfig.c linux/drivers/acpi/interpreter/amconfig.c --- v2.4.0-test8/linux/drivers/acpi/interpreter/amconfig.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/interpreter/amconfig.c Fri Sep 15 14:30:30 2000 @@ -1,7 +1,7 @@ - /****************************************************************************** * * Module Name: amconfig - Namespace reconfiguration (Load/Unload opcodes) + * $Revision: 23 $ * *****************************************************************************/ @@ -25,17 +25,17 @@ #include "acpi.h" -#include "parser.h" -#include "interp.h" +#include "acparser.h" +#include "acinterp.h" #include "amlcode.h" -#include "namesp.h" -#include "events.h" -#include "tables.h" -#include "dispatch.h" +#include "acnamesp.h" +#include "acevents.h" +#include "actables.h" +#include "acdispat.h" #define _COMPONENT INTERPRETER - MODULE_NAME ("amconfig"); + MODULE_NAME ("amconfig") /***************************************************************************** @@ -53,13 +53,13 @@ ACPI_STATUS acpi_aml_exec_load_table ( - ACPI_OBJECT_INTERNAL *rgn_desc, + ACPI_OPERAND_OBJECT *rgn_desc, ACPI_HANDLE *ddb_handle) { ACPI_STATUS status; - ACPI_OBJECT_INTERNAL *table_desc = NULL; - char *table_ptr; - char *table_data_ptr; + ACPI_OPERAND_OBJECT *table_desc = NULL; + u8 *table_ptr; + u8 *table_data_ptr; ACPI_TABLE_HEADER table_header; ACPI_TABLE_DESC table_info; u32 i; @@ -73,7 +73,7 @@ table_header.length = 0; for (i = 0; i < sizeof (ACPI_TABLE_HEADER); i++) { status = acpi_ev_address_space_dispatch (rgn_desc, ADDRESS_SPACE_READ, - i, 8, (u32 *) ((char *) &table_header + i)); + i, 8, (u32 *) ((u8 *) &table_header + i)); if (ACPI_FAILURE (status)) { return (status); } @@ -184,16 +184,19 @@ ACPI_HANDLE ddb_handle) { ACPI_STATUS status = AE_NOT_IMPLEMENTED; - ACPI_OBJECT_INTERNAL *table_desc = (ACPI_OBJECT_INTERNAL *) ddb_handle; + ACPI_OPERAND_OBJECT *table_desc = (ACPI_OPERAND_OBJECT *) ddb_handle; ACPI_TABLE_DESC *table_info; /* Validate the handle */ - /* TBD: [Errors] Wasn't this done earlier? */ + /* Although the handle is partially validated in Acpi_aml_exec_reconfiguration(), + * when it calls Acpi_aml_resolve_operands(), the handle is more completely + * validated here. + */ if ((!ddb_handle) || (!VALID_DESCRIPTOR_TYPE (ddb_handle, ACPI_DESC_TYPE_INTERNAL)) || - (((ACPI_OBJECT_INTERNAL *)ddb_handle)->common.type != + (((ACPI_OPERAND_OBJECT *)ddb_handle)->common.type != INTERNAL_TYPE_REFERENCE)) { return (AE_BAD_PARAMETER); @@ -205,7 +208,7 @@ table_info = (ACPI_TABLE_DESC *) table_desc->reference.object; /* - * Delete the entire namespace under this table NTE + * Delete the entire namespace under this table Node * (Offset contains the Table_id) */ @@ -245,16 +248,16 @@ ACPI_WALK_STATE *walk_state) { ACPI_STATUS status; - ACPI_OBJECT_INTERNAL *region_desc = NULL; + ACPI_OPERAND_OBJECT *region_desc = NULL; ACPI_HANDLE *ddb_handle; /* Resolve the operands */ - status = acpi_aml_resolve_operands (opcode, WALK_OPERANDS); + status = acpi_aml_resolve_operands (opcode, WALK_OPERANDS, walk_state); /* Get the table handle, common for both opcodes */ - status |= acpi_ds_obj_stack_pop_object ((ACPI_OBJECT_INTERNAL **) &ddb_handle, + status |= acpi_ds_obj_stack_pop_object ((ACPI_OPERAND_OBJECT **) &ddb_handle, walk_state); switch (opcode) @@ -265,22 +268,19 @@ /* Get the region or field descriptor */ status |= acpi_ds_obj_stack_pop_object (®ion_desc, walk_state); - if (status != AE_OK) { - acpi_aml_append_operand_diag (_THIS_MODULE, __LINE__, opcode, - WALK_OPERANDS, 2); - goto cleanup2; + if (ACPI_FAILURE (status)) { + acpi_cm_remove_reference (region_desc); + return (status); } status = acpi_aml_exec_load_table (region_desc, ddb_handle); break; - case AML_UN_LOAD_OP: + case AML_UNLOAD_OP: - if (status != AE_OK) { - acpi_aml_append_operand_diag (_THIS_MODULE, __LINE__, opcode, - WALK_OPERANDS, 1); - goto cleanup1; + if (ACPI_FAILURE (status)) { + return (status); } status = acpi_aml_exec_unload_table (ddb_handle); @@ -294,10 +294,6 @@ } -cleanup2: - acpi_cm_remove_reference (region_desc); - -cleanup1: return (status); } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/interpreter/amcreate.c linux/drivers/acpi/interpreter/amcreate.c --- v2.4.0-test8/linux/drivers/acpi/interpreter/amcreate.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/interpreter/amcreate.c Fri Sep 15 14:30:30 2000 @@ -1,7 +1,7 @@ - /****************************************************************************** * * Module Name: amcreate - Named object creation + * $Revision: 44 $ * *****************************************************************************/ @@ -25,19 +25,19 @@ #include "acpi.h" -#include "parser.h" -#include "interp.h" +#include "acparser.h" +#include "acinterp.h" #include "amlcode.h" -#include "namesp.h" -#include "events.h" -#include "dispatch.h" +#include "acnamesp.h" +#include "acevents.h" +#include "acdispat.h" #define _COMPONENT INTERPRETER - MODULE_NAME ("amcreate"); + MODULE_NAME ("amcreate") -/***************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_aml_exec_create_field * @@ -64,19 +64,19 @@ * Num_bits := Term_arg=>Integer * Source_buff := Term_arg=>Buffer * - ****************************************************************************/ + ******************************************************************************/ ACPI_STATUS acpi_aml_exec_create_field ( u16 opcode, ACPI_WALK_STATE *walk_state) { - ACPI_OBJECT_INTERNAL *res_desc = NULL; - ACPI_OBJECT_INTERNAL *cnt_desc = NULL; - ACPI_OBJECT_INTERNAL *off_desc = NULL; - ACPI_OBJECT_INTERNAL *src_desc = NULL; - ACPI_OBJECT_INTERNAL *field_desc; - ACPI_OBJECT_INTERNAL *obj_desc; + ACPI_OPERAND_OBJECT *res_desc = NULL; + ACPI_OPERAND_OBJECT *cnt_desc = NULL; + ACPI_OPERAND_OBJECT *off_desc = NULL; + ACPI_OPERAND_OBJECT *src_desc = NULL; + ACPI_OPERAND_OBJECT *field_desc; + ACPI_OPERAND_OBJECT *obj_desc; OBJECT_TYPE_INTERNAL res_type; ACPI_STATUS status; u32 num_operands = 3; @@ -88,7 +88,7 @@ /* Resolve the operands */ - status = acpi_aml_resolve_operands (opcode, WALK_OPERANDS); + status = acpi_aml_resolve_operands (opcode, WALK_OPERANDS, walk_state); /* Get the operands */ @@ -101,11 +101,9 @@ status |= acpi_ds_obj_stack_pop_object (&off_desc, walk_state); status |= acpi_ds_obj_stack_pop_object (&src_desc, walk_state); - if (status != AE_OK) { + if (ACPI_FAILURE (status)) { /* Invalid parameters on object stack */ - acpi_aml_append_operand_diag (_THIS_MODULE, __LINE__, opcode, - WALK_OPERANDS, 3); goto cleanup; } @@ -288,16 +286,17 @@ if (obj_desc) { /* * There is an existing object here; delete it and zero out the - * NTE + * object field within the Node */ acpi_cm_remove_reference (obj_desc); - acpi_ns_attach_object (res_desc, NULL, ACPI_TYPE_ANY); + acpi_ns_attach_object ((ACPI_NAMESPACE_NODE *) res_desc, NULL, + ACPI_TYPE_ANY); } /* Set the type to ANY (or the store below will fail) */ - ((ACPI_NAMED_OBJECT*) res_desc)->type = ACPI_TYPE_ANY; + ((ACPI_NAMESPACE_NODE *) res_desc)->type = ACPI_TYPE_ANY; break; @@ -310,7 +309,7 @@ /* Store constructed field descriptor in result location */ - status = acpi_aml_exec_store (field_desc, res_desc); + status = acpi_aml_exec_store (field_desc, res_desc, walk_state); /* * If the field descriptor was not physically stored (or if a failure @@ -358,39 +357,41 @@ acpi_aml_exec_create_alias ( ACPI_WALK_STATE *walk_state) { - ACPI_NAMED_OBJECT *src_entry; - ACPI_NAMED_OBJECT *alias_entry; + ACPI_NAMESPACE_NODE *source_node; + ACPI_NAMESPACE_NODE *alias_node; ACPI_STATUS status; /* Get the source/alias operands (both NTEs) */ - status = acpi_ds_obj_stack_pop_object ((ACPI_OBJECT_INTERNAL **) &src_entry, + status = acpi_ds_obj_stack_pop_object ((ACPI_OPERAND_OBJECT **) &source_node, walk_state); if (ACPI_FAILURE (status)) { return (status); } - /* Don't pop it, it gets popped later */ + /* + * Don't pop it, it gets removed in the calling routine + */ - alias_entry = acpi_ds_obj_stack_get_value (0, walk_state); + alias_node = acpi_ds_obj_stack_get_value (0, walk_state); /* Add an additional reference to the object */ - acpi_cm_add_reference (src_entry->object); + acpi_cm_add_reference (source_node->object); /* - * Attach the original source NTE to the new Alias NTE. + * Attach the original source Node to the new Alias Node. */ - status = acpi_ns_attach_object (alias_entry, src_entry->object, - src_entry->type); + status = acpi_ns_attach_object (alias_node, source_node->object, + source_node->type); /* * The new alias assumes the type of the source, but it points * to the same object. The reference count of the object has two * additional references to prevent deletion out from under either the - * source or the alias NTE + * source or the alias Node */ /* Since both operands are NTEs, we don't need to delete them */ @@ -416,7 +417,7 @@ ACPI_WALK_STATE *walk_state) { ACPI_STATUS status; - ACPI_OBJECT_INTERNAL *obj_desc; + ACPI_OPERAND_OBJECT *obj_desc; BREAKPOINT3; @@ -438,7 +439,7 @@ goto cleanup; } - /* Attach object to the NTE */ + /* Attach object to the Node */ status = acpi_ns_attach_object (acpi_ds_obj_stack_get_value (0, walk_state), obj_desc, (u8) ACPI_TYPE_EVENT); @@ -473,8 +474,8 @@ ACPI_WALK_STATE *walk_state) { ACPI_STATUS status = AE_OK; - ACPI_OBJECT_INTERNAL *sync_desc; - ACPI_OBJECT_INTERNAL *obj_desc; + ACPI_OPERAND_OBJECT *sync_desc; + ACPI_OPERAND_OBJECT *obj_desc; /* Get the operand */ @@ -546,22 +547,27 @@ ACPI_WALK_STATE *walk_state) { ACPI_STATUS status; - ACPI_OBJECT_INTERNAL *obj_desc_region; - ACPI_HANDLE *entry; + ACPI_OPERAND_OBJECT *obj_desc_region; + ACPI_NAMESPACE_NODE *node; if (region_space >= NUM_REGION_TYPES) { - /* TBD: [Errors] should this return an error, or should we just keep - * going? */ + /* TBD: [Future] In ACPI 2.0, valid region space + * includes types 0-6 (Adding CMOS and PCIBARTarget). + * Also, types 0x80-0xff are defined as "OEM Region + * Space handler" + * + * Should this return an error, or should we just keep + * going? How do we handle the OEM region handlers? + */ REPORT_WARNING ("Unable to decode the Region_space"); } - /* Get the NTE from the object stack */ - - entry = acpi_ds_obj_stack_get_value (0, walk_state); + /* Get the Node from the object stack */ + node = (ACPI_NAMESPACE_NODE *) acpi_ds_obj_stack_get_value (0, walk_state); /* Create the region descriptor */ @@ -583,10 +589,9 @@ /* Init the region from the operands */ - obj_desc_region->region.space_id = (u16) region_space; + obj_desc_region->region.space_id = (u8) region_space; obj_desc_region->region.address = 0; obj_desc_region->region.length = 0; - obj_desc_region->region.region_flags = 0; /* * Remember location in AML stream of address & length @@ -596,19 +601,38 @@ obj_desc_region->region.method->method.pcode_length = aml_length; - /* Install the new region object in the parent NTE */ + /* Install the new region object in the parent Node */ - obj_desc_region->region.nte = (ACPI_NAMED_OBJECT*) entry; + obj_desc_region->region.node = node; - status = acpi_ns_attach_object (entry, obj_desc_region, + status = acpi_ns_attach_object (node, obj_desc_region, (u8) ACPI_TYPE_REGION); + if (ACPI_FAILURE (status)) { goto cleanup; } + /* + * If we have a valid region, initialize it + * Namespace is NOT locked at this point. + */ + + status = acpi_ev_initialize_region (obj_desc_region, FALSE); + + if (ACPI_FAILURE (status)) { + /* + * If AE_NOT_EXIST is returned, it is not fatal + * because many regions get created before a handler + * is installed for said region. + */ + if (AE_NOT_EXIST == status) { + status = AE_OK; + } + } + cleanup: - if (status != AE_OK) { + if (ACPI_FAILURE (status)) { /* Delete region object and method subobject */ if (obj_desc_region) { @@ -619,22 +643,6 @@ } } - - /* - * If we have a valid region, initialize it - */ - if (obj_desc_region) { - /* - * TBD: [Errors] Is there anything we can or could do when this - * fails? - * We need to do something useful with a failure. - */ - /* Namespace IS locked */ - - (void *) acpi_ev_initialize_region (obj_desc_region, TRUE); - - } - return (status); } @@ -645,7 +653,7 @@ * * PARAMETERS: Op - Op containing the Processor definition and * args - * Processor_nTE - NTE for the containing NTE + * Processor_nTE - Node for the containing Node * * RETURN: Status * @@ -655,12 +663,12 @@ ACPI_STATUS acpi_aml_exec_create_processor ( - ACPI_GENERIC_OP *op, + ACPI_PARSE_OBJECT *op, ACPI_HANDLE processor_nTE) { ACPI_STATUS status; - ACPI_GENERIC_OP *arg; - ACPI_OBJECT_INTERNAL *obj_desc; + ACPI_PARSE_OBJECT *arg; + ACPI_OPERAND_OBJECT *obj_desc; obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_PROCESSOR); @@ -669,7 +677,7 @@ return (status); } - /* Install the new processor object in the parent NTE */ + /* Install the new processor object in the parent Node */ status = acpi_ns_attach_object (processor_nTE, obj_desc, (u8) ACPI_TYPE_PROCESSOR); @@ -700,7 +708,7 @@ /* Second arg is the PBlock Address */ - obj_desc->processor.pblk_address = (ACPI_IO_ADDRESS) arg->value.integer; + obj_desc->processor.address = (ACPI_IO_ADDRESS) arg->value.integer; /* Move to next arg and check existence */ @@ -712,7 +720,7 @@ /* Third arg is the PBlock Length */ - obj_desc->processor.pblk_length = (u8) arg->value.integer; + obj_desc->processor.length = (u8) arg->value.integer; return (AE_OK); } @@ -724,7 +732,7 @@ * * PARAMETERS: Op - Op containing the Power_resource definition * and args - * Power_res_nTE - NTE for the containing NTE + * Power_res_nTE - Node for the containing Node * * RETURN: Status * @@ -734,12 +742,12 @@ ACPI_STATUS acpi_aml_exec_create_power_resource ( - ACPI_GENERIC_OP *op, + ACPI_PARSE_OBJECT *op, ACPI_HANDLE power_res_nTE) { ACPI_STATUS status; - ACPI_GENERIC_OP *arg; - ACPI_OBJECT_INTERNAL *obj_desc; + ACPI_PARSE_OBJECT *arg; + ACPI_OPERAND_OBJECT *obj_desc; obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_POWER); @@ -748,7 +756,7 @@ return (status); } - /* Install the new power resource object in the parent NTE */ + /* Install the new power resource object in the parent Node */ status = acpi_ns_attach_object (power_res_nTE, obj_desc, (u8) ACPI_TYPE_POWER); @@ -789,11 +797,14 @@ * * FUNCTION: Acpi_aml_exec_create_method * - * PARAMETERS: Interpreter_mode - Current running mode (load1/Load2/Exec) + * PARAMETERS: Aml_ptr - First byte of the method's AML + * Aml_length - AML byte count for this method + * Method_flags - AML method flag byte + * Method - Method Node * * RETURN: Status * - * DESCRIPTION: Create a new mutex object + * DESCRIPTION: Create a new method object * ****************************************************************************/ @@ -804,7 +815,7 @@ u32 method_flags, ACPI_HANDLE method) { - ACPI_OBJECT_INTERNAL *obj_desc; + ACPI_OPERAND_OBJECT *obj_desc; ACPI_STATUS status; @@ -830,9 +841,8 @@ METHOD_FLAGS_ARG_COUNT); /* - * Get the concurrency count - * If required, a semaphore will be created for this method when it is - * parsed. + * Get the concurrency count. If required, a semaphore will be + * created for this method when it is parsed. * * TBD: [Future] for APCI 2.0, there will be a Sync_level value, not * just a flag @@ -842,27 +852,16 @@ if (method_flags & METHOD_FLAGS_SERIALIZED) { obj_desc->method.concurrency = 1; } + else { obj_desc->method.concurrency = INFINITE_CONCURRENCY; } - /* Mark the Method as not parsed yet */ - - obj_desc->method.parser_op = NULL; - - /* - * Another +1 gets added when Acpi_psx_execute is called, - * no need for: Obj_desc->Method.Pcode++; - */ - - obj_desc->method.acpi_table = NULL; /* TBD: [Restructure] was (u8 *) Pcode_addr; */ - obj_desc->method.table_length = 0; /* TBD: [Restructure] needed? (u32) (Walk_state->aml_end - Pcode_addr); */ - - /* Attach the new object to the method NTE */ + /* Attach the new object to the method Node */ status = acpi_ns_attach_object (method, obj_desc, (u8) ACPI_TYPE_METHOD); if (ACPI_FAILURE (status)) { - acpi_cm_free (obj_desc); + acpi_cm_delete_object_desc (obj_desc); } return (status); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/interpreter/amdump.c linux/drivers/acpi/interpreter/amdump.c --- v2.4.0-test8/linux/drivers/acpi/interpreter/amdump.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/acpi/interpreter/amdump.c Fri Sep 15 14:30:30 2000 @@ -0,0 +1,41 @@ +/****************************************************************************** + * + * Module Name: amdump - Interpreter debug output routines + * $Revision: 90 $ + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 R. Byron Moore + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "acpi.h" +#include "acinterp.h" +#include "amlcode.h" +#include "acnamesp.h" +#include "actables.h" + +#define _COMPONENT INTERPRETER + MODULE_NAME ("amdump") + + +/* + * The following routines are used for debug output only + */ + + diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/interpreter/amdyadic.c linux/drivers/acpi/interpreter/amdyadic.c --- v2.4.0-test8/linux/drivers/acpi/interpreter/amdyadic.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/interpreter/amdyadic.c Fri Sep 15 14:30:30 2000 @@ -1,7 +1,7 @@ - /****************************************************************************** * * Module Name: amdyadic - ACPI AML (p-code) execution for dyadic operators + * $Revision: 63 $ * *****************************************************************************/ @@ -25,16 +25,16 @@ #include "acpi.h" -#include "parser.h" -#include "namesp.h" -#include "interp.h" -#include "events.h" +#include "acparser.h" +#include "acnamesp.h" +#include "acinterp.h" +#include "acevents.h" #include "amlcode.h" -#include "dispatch.h" +#include "acdispat.h" #define _COMPONENT INTERPRETER - MODULE_NAME ("amdyadic"); + MODULE_NAME ("amdyadic") /***************************************************************************** @@ -57,15 +57,15 @@ u16 opcode, ACPI_WALK_STATE *walk_state) { - ACPI_OBJECT_INTERNAL *obj_desc = NULL; - ACPI_OBJECT_INTERNAL *val_desc = NULL; - ACPI_NAMED_OBJECT *entry; + ACPI_OPERAND_OBJECT *obj_desc = NULL; + ACPI_OPERAND_OBJECT *val_desc = NULL; + ACPI_NAMESPACE_NODE *node; ACPI_STATUS status = AE_OK; /* Resolve all operands */ - status = acpi_aml_resolve_operands (opcode, WALK_OPERANDS); + status = acpi_aml_resolve_operands (opcode, WALK_OPERANDS, walk_state); /* Get the operands */ status |= acpi_ds_obj_stack_pop_object (&val_desc, walk_state); @@ -73,8 +73,6 @@ if (ACPI_FAILURE (status)) { /* Invalid parameters on object stack */ - acpi_aml_append_operand_diag (_THIS_MODULE, __LINE__, opcode, - WALK_OPERANDS, 2); goto cleanup; } @@ -88,15 +86,15 @@ case AML_NOTIFY_OP: - /* The Obj_desc is actually an NTE */ + /* The Obj_desc is actually an Node */ - entry = (ACPI_NAMED_OBJECT*) obj_desc; + node = (ACPI_NAMESPACE_NODE *) obj_desc; obj_desc = NULL; /* Object must be a device or thermal zone */ - if (entry && val_desc) { - switch (entry->type) + if (node && val_desc) { + switch (node->type) { case ACPI_TYPE_DEVICE: case ACPI_TYPE_THERMAL: @@ -108,7 +106,7 @@ /* Dispatch the notify to the appropriate handler */ - acpi_ev_notify_dispatch (entry, val_desc->number.value); + acpi_ev_notify_dispatch (node, val_desc->number.value); break; default: @@ -118,6 +116,8 @@ break; default: + + REPORT_ERROR ("Acpi_aml_exec_dyadic1: Unknown dyadic opcode"); status = AE_AML_BAD_OPCODE; } @@ -153,23 +153,23 @@ acpi_aml_exec_dyadic2_r ( u16 opcode, ACPI_WALK_STATE *walk_state, - ACPI_OBJECT_INTERNAL **return_desc) + ACPI_OPERAND_OBJECT **return_desc) { - ACPI_OBJECT_INTERNAL *obj_desc = NULL; - ACPI_OBJECT_INTERNAL *obj_desc2 = NULL; - ACPI_OBJECT_INTERNAL *res_desc = NULL; - ACPI_OBJECT_INTERNAL *res_desc2 = NULL; - ACPI_OBJECT_INTERNAL *ret_desc = NULL; - ACPI_OBJECT_INTERNAL *ret_desc2 = NULL; + ACPI_OPERAND_OBJECT *obj_desc = NULL; + ACPI_OPERAND_OBJECT *obj_desc2 = NULL; + ACPI_OPERAND_OBJECT *res_desc = NULL; + ACPI_OPERAND_OBJECT *res_desc2 = NULL; + ACPI_OPERAND_OBJECT *ret_desc = NULL; + ACPI_OPERAND_OBJECT *ret_desc2 = NULL; ACPI_STATUS status = AE_OK; u32 remainder; - s32 num_operands = 3; - char *new_buf; + u32 num_operands = 3; + NATIVE_CHAR *new_buf; /* Resolve all operands */ - status = acpi_aml_resolve_operands (opcode, WALK_OPERANDS); + status = acpi_aml_resolve_operands (opcode, WALK_OPERANDS, walk_state); /* Get all operands */ if (AML_DIVIDE_OP == opcode) { @@ -180,10 +180,7 @@ status |= acpi_ds_obj_stack_pop_object (&res_desc, walk_state); status |= acpi_ds_obj_stack_pop_object (&obj_desc2, walk_state); status |= acpi_ds_obj_stack_pop_object (&obj_desc, walk_state); - if (status != AE_OK) { - acpi_aml_append_operand_diag (_THIS_MODULE, __LINE__, opcode, - &(walk_state->operands [walk_state->num_operands -1]), - num_operands); + if (ACPI_FAILURE (status)) { goto cleanup; } @@ -368,9 +365,9 @@ goto cleanup; } - STRCPY (new_buf, (char *) obj_desc->string.pointer); + STRCPY (new_buf, obj_desc->string.pointer); STRCPY (new_buf + obj_desc->string.length, - (char *) obj_desc2->string.pointer); + obj_desc2->string.pointer); /* Point the return object to the new string */ @@ -391,16 +388,8 @@ new_buf = acpi_cm_allocate (obj_desc->buffer.length + obj_desc2->buffer.length); if (!new_buf) { - /* Only bail out if the buffer is small */ - - /* TBD: [Investigate] what is the point of this code? */ - - if (obj_desc->buffer.length + obj_desc2->buffer.length < 1024) { - REPORT_ERROR - ("Aml_exec_dyadic2_r/Concat_op: Buffer allocation failure"); - return (AE_NO_MEMORY); - } - + REPORT_ERROR + ("Aml_exec_dyadic2_r/Concat_op: Buffer allocation failure"); status = AE_NO_MEMORY; goto cleanup; } @@ -423,6 +412,7 @@ default: + REPORT_ERROR ("Acpi_aml_exec_dyadic2_r: Unknown dyadic opcode"); status = AE_AML_BAD_OPCODE; goto cleanup; } @@ -434,12 +424,13 @@ * descriptor (Res_desc). */ - if ((status = acpi_aml_exec_store (ret_desc, res_desc)) != AE_OK) { + status = acpi_aml_exec_store (ret_desc, res_desc, walk_state); + if (ACPI_FAILURE (status)) { goto cleanup; } if (AML_DIVIDE_OP == opcode) { - status = acpi_aml_exec_store (ret_desc2, res_desc2); + status = acpi_aml_exec_store (ret_desc2, res_desc2, walk_state); /* * Since the remainder is not returned, remove a reference to @@ -499,26 +490,24 @@ acpi_aml_exec_dyadic2_s ( u16 opcode, ACPI_WALK_STATE *walk_state, - ACPI_OBJECT_INTERNAL **return_desc) + ACPI_OPERAND_OBJECT **return_desc) { - ACPI_OBJECT_INTERNAL *obj_desc; - ACPI_OBJECT_INTERNAL *time_desc; - ACPI_OBJECT_INTERNAL *ret_desc = NULL; + ACPI_OPERAND_OBJECT *obj_desc; + ACPI_OPERAND_OBJECT *time_desc; + ACPI_OPERAND_OBJECT *ret_desc = NULL; ACPI_STATUS status; /* Resolve all operands */ - status = acpi_aml_resolve_operands (opcode, WALK_OPERANDS); + status = acpi_aml_resolve_operands (opcode, WALK_OPERANDS, walk_state); /* Get all operands */ status |= acpi_ds_obj_stack_pop_object (&time_desc, walk_state); status |= acpi_ds_obj_stack_pop_object (&obj_desc, walk_state); - if (status != AE_OK) { + if (ACPI_FAILURE (status)) { /* Invalid parameters on object stack */ - acpi_aml_append_operand_diag (_THIS_MODULE, __LINE__, opcode, - WALK_OPERANDS, 2); goto cleanup; } @@ -559,6 +548,7 @@ default: + REPORT_ERROR ("Acpi_aml_exec_dyadic2_s: Unknown dyadic synchronization opcode"); status = AE_AML_BAD_OPCODE; goto cleanup; } @@ -619,27 +609,25 @@ acpi_aml_exec_dyadic2 ( u16 opcode, ACPI_WALK_STATE *walk_state, - ACPI_OBJECT_INTERNAL **return_desc) + ACPI_OPERAND_OBJECT **return_desc) { - ACPI_OBJECT_INTERNAL *obj_desc; - ACPI_OBJECT_INTERNAL *obj_desc2; - ACPI_OBJECT_INTERNAL *ret_desc = NULL; + ACPI_OPERAND_OBJECT *obj_desc; + ACPI_OPERAND_OBJECT *obj_desc2; + ACPI_OPERAND_OBJECT *ret_desc = NULL; ACPI_STATUS status; u8 lboolean; /* Resolve all operands */ - status = acpi_aml_resolve_operands (opcode, WALK_OPERANDS); + status = acpi_aml_resolve_operands (opcode, WALK_OPERANDS, walk_state); /* Get all operands */ status |= acpi_ds_obj_stack_pop_object (&obj_desc2, walk_state); status |= acpi_ds_obj_stack_pop_object (&obj_desc, walk_state); - if (status != AE_OK) { + if (ACPI_FAILURE (status)) { /* Invalid parameters on object stack */ - acpi_aml_append_operand_diag (_THIS_MODULE, __LINE__, opcode, - WALK_OPERANDS, 2); goto cleanup; } @@ -707,6 +695,7 @@ default: + REPORT_ERROR ("Acpi_aml_exec_dyadic2: Unknown dyadic opcode"); status = AE_AML_BAD_OPCODE; goto cleanup; break; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/interpreter/amfield.c linux/drivers/acpi/interpreter/amfield.c --- v2.4.0-test8/linux/drivers/acpi/interpreter/amfield.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/interpreter/amfield.c Fri Sep 15 14:30:30 2000 @@ -1,6 +1,7 @@ /****************************************************************************** * * Module Name: amfield - ACPI AML (p-code) execution - field manipulation + * $Revision: 70 $ * *****************************************************************************/ @@ -24,16 +25,16 @@ #include "acpi.h" -#include "dispatch.h" -#include "interp.h" +#include "acdispat.h" +#include "acinterp.h" #include "amlcode.h" -#include "namesp.h" -#include "hardware.h" -#include "events.h" +#include "acnamesp.h" +#include "achware.h" +#include "acevents.h" #define _COMPONENT INTERPRETER - MODULE_NAME ("amfield"); + MODULE_NAME ("amfield") /******************************************************************************* @@ -67,12 +68,12 @@ ACPI_STATUS acpi_aml_setup_field ( - ACPI_OBJECT_INTERNAL *obj_desc, - ACPI_OBJECT_INTERNAL *rgn_desc, - s32 field_bit_width) + ACPI_OPERAND_OBJECT *obj_desc, + ACPI_OPERAND_OBJECT *rgn_desc, + u32 field_bit_width) { ACPI_STATUS status = AE_OK; - s32 field_byte_width; + u32 field_byte_width; /* Parameter validation */ @@ -87,6 +88,8 @@ /* + * TBD: [Future] Acpi 2.0 supports Qword fields + * * Init and validate Field width * Possible values are 1, 2, 4 */ @@ -105,7 +108,7 @@ * If the address and length have not been previously evaluated, * evaluate them and save the results. */ - if (!(rgn_desc->region.region_flags & REGION_AGRUMENT_DATA_VALID)) { + if (!(rgn_desc->region.flags & AOPOBJ_DATA_VALID)) { status = acpi_ds_get_region_arguments (rgn_desc); if (ACPI_FAILURE (status)) { @@ -113,12 +116,6 @@ } } - - /* - * If (offset rounded up to next multiple of field width) - * exceeds region length, indicate an error. - */ - if (rgn_desc->region.length < (obj_desc->field.offset & ~((u32) field_byte_width - 1)) + field_byte_width) @@ -152,12 +149,12 @@ ACPI_STATUS acpi_aml_access_named_field ( - s32 mode, + u32 mode, ACPI_HANDLE named_field, void *buffer, u32 buffer_length) { - ACPI_OBJECT_INTERNAL *obj_desc = NULL; + ACPI_OPERAND_OBJECT *obj_desc = NULL; ACPI_STATUS status = AE_OK; u8 locked = FALSE; u32 bit_granularity = 0; @@ -167,6 +164,11 @@ u32 byte_field_length; + /* Basic data checking */ + if ((!named_field) || (ACPI_READ == mode && !buffer)) { + return (AE_AML_INTERNAL); + } + /* Get the attached field object */ obj_desc = acpi_ns_get_attached_object (named_field); @@ -256,72 +258,6 @@ acpi_aml_release_global_lock (locked); - return (status); -} - - -/******************************************************************************* - * - * FUNCTION: Acpi_aml_set_named_field_value - * - * PARAMETERS: Named_field - Handle for field to be set - * Buffer - Bytes to be stored - * Buffer_length - Number of bytes to be stored - * - * RETURN: Status - * - * DESCRIPTION: Store the given value into the field - * - ******************************************************************************/ - -ACPI_STATUS -acpi_aml_set_named_field_value ( - ACPI_HANDLE named_field, - void *buffer, - u32 buffer_length) -{ - ACPI_STATUS status; - - - if (!named_field) { - return (AE_AML_INTERNAL); - } - - status = acpi_aml_access_named_field (ACPI_WRITE, named_field, buffer, - buffer_length); - return (status); -} - - -/******************************************************************************* - * - * FUNCTION: Acpi_aml_get_named_field_value - * - * PARAMETERS: Named_field - Handle for field to be read - * *Buffer - Where to store value read from field - * Buffer_length - Max length to read - * - * RETURN: Status - * - * DESCRIPTION: Retrieve the value of the given field - * - ******************************************************************************/ - -ACPI_STATUS -acpi_aml_get_named_field_value ( - ACPI_HANDLE named_field, - void *buffer, - u32 buffer_length) -{ - ACPI_STATUS status; - - - if ((!named_field) || (!buffer)) { - return (AE_AML_INTERNAL); - } - - status = acpi_aml_access_named_field (ACPI_READ, named_field, buffer, - buffer_length); return (status); } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/interpreter/amfldio.c linux/drivers/acpi/interpreter/amfldio.c --- v2.4.0-test8/linux/drivers/acpi/interpreter/amfldio.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/interpreter/amfldio.c Fri Sep 15 14:30:30 2000 @@ -1,6 +1,7 @@ /****************************************************************************** * * Module Name: amfldio - Aml Field I/O + * $Revision: 26 $ * *****************************************************************************/ @@ -24,15 +25,15 @@ #include "acpi.h" -#include "interp.h" +#include "acinterp.h" #include "amlcode.h" -#include "namesp.h" -#include "hardware.h" -#include "events.h" +#include "acnamesp.h" +#include "achware.h" +#include "acevents.h" #define _COMPONENT INTERPRETER - MODULE_NAME ("amfldio"); + MODULE_NAME ("amfldio") /******************************************************************************* @@ -51,16 +52,16 @@ ACPI_STATUS acpi_aml_read_field_data ( - ACPI_OBJECT_INTERNAL *obj_desc, + ACPI_OPERAND_OBJECT *obj_desc, u32 field_byte_offset, u32 field_bit_width, u32 *value) { ACPI_STATUS status; - ACPI_OBJECT_INTERNAL *rgn_desc = NULL; + ACPI_OPERAND_OBJECT *rgn_desc = NULL; u32 address; u32 local_value = 0; - s32 field_byte_width; + u32 field_byte_width; /* Obj_desc is validated by callers */ @@ -72,7 +73,7 @@ field_byte_width = DIV_8 (field_bit_width); status = acpi_aml_setup_field (obj_desc, rgn_desc, field_bit_width); - if (AE_OK != status) { + if (ACPI_FAILURE (status)) { return (status); } @@ -84,17 +85,17 @@ /* - * Round offset down to next multiple of - * field width, add region base address and offset within the field + * Set offset to next multiple of field width, + * add region base address and offset within the field */ - address = rgn_desc->region.address + - (obj_desc->field.offset & ~((u32) field_byte_width - 1)) + + (obj_desc->field.offset * field_byte_width) + field_byte_offset; + /* Invoke the appropriate Address_space/Op_region handler */ status = acpi_ev_address_space_dispatch (rgn_desc, ADDRESS_SPACE_READ, @@ -122,7 +123,7 @@ ACPI_STATUS acpi_aml_read_field ( - ACPI_OBJECT_INTERNAL *obj_desc, + ACPI_OPERAND_OBJECT *obj_desc, void *buffer, u32 buffer_length, u32 byte_length, @@ -236,6 +237,7 @@ * field datum */ + if (obj_desc->field.bit_offset != 0) { merged_datum = (previous_raw_datum >> obj_desc->field.bit_offset) | @@ -247,10 +249,27 @@ } /* + * Prepare the merged datum for storing into the caller's + * buffer. It is possible to have a 32-bit buffer + * (Byte_granularity == 4), but a Obj_desc->Field.Length + * of 8 or 16, meaning that the upper bytes of merged data + * are undesired. This section fixes that. + */ + switch (obj_desc->field.length) + { + case 8: + merged_datum &= 0x000000FF; + break; + + case 16: + merged_datum &= 0x0000FFFF; + break; + } + + /* * Now store the datum in the caller's buffer, according to * the data type */ - switch (byte_granularity) { case 1: @@ -266,7 +285,6 @@ break; } - /* * Save the most recent datum since it contains bits of * the *next* field datum @@ -302,15 +320,15 @@ ACPI_STATUS acpi_aml_write_field_data ( - ACPI_OBJECT_INTERNAL *obj_desc, + ACPI_OPERAND_OBJECT *obj_desc, u32 field_byte_offset, u32 field_bit_width, u32 value) { ACPI_STATUS status = AE_OK; - ACPI_OBJECT_INTERNAL *rgn_desc = NULL; + ACPI_OPERAND_OBJECT *rgn_desc = NULL; u32 address; - s32 field_byte_width; + u32 field_byte_width; /* Obj_desc is validated by callers */ @@ -321,21 +339,21 @@ field_byte_width = DIV_8 (field_bit_width); status = acpi_aml_setup_field (obj_desc, rgn_desc, field_bit_width); - if (AE_OK != status) { + if (ACPI_FAILURE (status)) { return (status); } /* - * Round offset down to next multiple of - * field width, add region base address and offset within the field + * Set offset to next multiple of field width, + * add region base address and offset within the field */ - address = rgn_desc->region.address + - (obj_desc->field.offset & ~((u32) field_byte_width - 1)) + + (obj_desc->field.offset * field_byte_width) + field_byte_offset; + /* Invoke the appropriate Address_space/Op_region handler */ status = acpi_ev_address_space_dispatch (rgn_desc, ADDRESS_SPACE_WRITE, @@ -363,7 +381,7 @@ ACPI_STATUS acpi_aml_write_field_data_with_update_rule ( - ACPI_OBJECT_INTERNAL *obj_desc, + ACPI_OPERAND_OBJECT *obj_desc, u32 mask, u32 field_value, u32 this_field_byte_offset, @@ -426,7 +444,7 @@ bit_granularity, merged_value); } - return status; + return (status); } @@ -446,7 +464,7 @@ ACPI_STATUS acpi_aml_write_field ( - ACPI_OBJECT_INTERNAL *obj_desc, + ACPI_OPERAND_OBJECT *obj_desc, void *buffer, u32 buffer_length, u32 byte_length, @@ -638,7 +656,8 @@ field_value = (previous_raw_datum >> (bit_granularity - obj_desc->field.bit_offset)) & mask; - status = acpi_aml_write_field_data_with_update_rule (obj_desc, mask, field_value, this_field_byte_offset + 1, + status = acpi_aml_write_field_data_with_update_rule (obj_desc, mask, field_value, + this_field_byte_offset + byte_granularity, bit_granularity); if (ACPI_FAILURE (status)) { goto cleanup; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/interpreter/ammisc.c linux/drivers/acpi/interpreter/ammisc.c --- v2.4.0-test8/linux/drivers/acpi/interpreter/ammisc.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/interpreter/ammisc.c Fri Sep 15 14:30:30 2000 @@ -2,6 +2,7 @@ /****************************************************************************** * * Module Name: ammisc - ACPI AML (p-code) execution - specific opcodes + * $Revision: 67 $ * *****************************************************************************/ @@ -25,14 +26,14 @@ #include "acpi.h" -#include "parser.h" -#include "interp.h" +#include "acparser.h" +#include "acinterp.h" #include "amlcode.h" -#include "dispatch.h" +#include "acdispat.h" #define _COMPONENT INTERPRETER - MODULE_NAME ("ammisc"); + MODULE_NAME ("ammisc") /******************************************************************************* @@ -58,25 +59,23 @@ acpi_aml_exec_fatal ( ACPI_WALK_STATE *walk_state) { - ACPI_OBJECT_INTERNAL *type_desc; - ACPI_OBJECT_INTERNAL *code_desc; - ACPI_OBJECT_INTERNAL *arg_desc; + ACPI_OPERAND_OBJECT *type_desc; + ACPI_OPERAND_OBJECT *code_desc; + ACPI_OPERAND_OBJECT *arg_desc; ACPI_STATUS status; /* Resolve operands */ - status = acpi_aml_resolve_operands (AML_FATAL_OP, WALK_OPERANDS); + status = acpi_aml_resolve_operands (AML_FATAL_OP, WALK_OPERANDS, walk_state); /* Get operands */ status |= acpi_ds_obj_stack_pop_object (&arg_desc, walk_state); status |= acpi_ds_obj_stack_pop_object (&code_desc, walk_state); status |= acpi_ds_obj_stack_pop_object (&type_desc, walk_state); - if (status != AE_OK) { - /* invalid parameters on object stack */ + if (ACPI_FAILURE (status)) { + /* Invalid parameters on object stack */ - acpi_aml_append_operand_diag (_THIS_MODULE, __LINE__, - (u16) AML_FATAL_OP, WALK_OPERANDS, 3); goto cleanup; } @@ -130,30 +129,28 @@ ACPI_STATUS acpi_aml_exec_index ( ACPI_WALK_STATE *walk_state, - ACPI_OBJECT_INTERNAL **return_desc) + ACPI_OPERAND_OBJECT **return_desc) { - ACPI_OBJECT_INTERNAL *obj_desc; - ACPI_OBJECT_INTERNAL *idx_desc; - ACPI_OBJECT_INTERNAL *res_desc; - ACPI_OBJECT_INTERNAL *ret_desc = NULL; - ACPI_OBJECT_INTERNAL *tmp_desc; + ACPI_OPERAND_OBJECT *obj_desc; + ACPI_OPERAND_OBJECT *idx_desc; + ACPI_OPERAND_OBJECT *res_desc; + ACPI_OPERAND_OBJECT *ret_desc = NULL; + ACPI_OPERAND_OBJECT *tmp_desc; ACPI_STATUS status; /* Resolve operands */ /* First operand can be either a package or a buffer */ - status = acpi_aml_resolve_operands (AML_INDEX_OP, WALK_OPERANDS); + status = acpi_aml_resolve_operands (AML_INDEX_OP, WALK_OPERANDS, walk_state); /* Get all operands */ status |= acpi_ds_obj_stack_pop_object (&res_desc, walk_state); status |= acpi_ds_obj_stack_pop_object (&idx_desc, walk_state); status |= acpi_ds_obj_stack_pop_object (&obj_desc, walk_state); - if (status != AE_OK) { + if (ACPI_FAILURE (status)) { /* Invalid parameters on object stack */ - acpi_aml_append_operand_diag (_THIS_MODULE, __LINE__, - (u16) AML_INDEX_OP, WALK_OPERANDS, 3); goto cleanup; } @@ -202,7 +199,7 @@ ret_desc->reference.target_type = tmp_desc->common.type; ret_desc->reference.object = tmp_desc; - status = acpi_aml_exec_store (ret_desc, res_desc); + status = acpi_aml_exec_store (ret_desc, res_desc, walk_state); ret_desc->reference.object = NULL; } @@ -228,7 +225,7 @@ ret_desc->reference.object = obj_desc; ret_desc->reference.offset = idx_desc->number.value; - status = acpi_aml_exec_store (ret_desc, res_desc); + status = acpi_aml_exec_store (ret_desc, res_desc, walk_state); } @@ -282,15 +279,15 @@ ACPI_STATUS acpi_aml_exec_match ( ACPI_WALK_STATE *walk_state, - ACPI_OBJECT_INTERNAL **return_desc) + ACPI_OPERAND_OBJECT **return_desc) { - ACPI_OBJECT_INTERNAL *pkg_desc; - ACPI_OBJECT_INTERNAL *op1_desc; - ACPI_OBJECT_INTERNAL *V1_desc; - ACPI_OBJECT_INTERNAL *op2_desc; - ACPI_OBJECT_INTERNAL *V2_desc; - ACPI_OBJECT_INTERNAL *start_desc; - ACPI_OBJECT_INTERNAL *ret_desc = NULL; + ACPI_OPERAND_OBJECT *pkg_desc; + ACPI_OPERAND_OBJECT *op1_desc; + ACPI_OPERAND_OBJECT *V1_desc; + ACPI_OPERAND_OBJECT *op2_desc; + ACPI_OPERAND_OBJECT *V2_desc; + ACPI_OPERAND_OBJECT *start_desc; + ACPI_OPERAND_OBJECT *ret_desc = NULL; ACPI_STATUS status; u32 index; u32 match_value = (u32) -1; @@ -298,7 +295,7 @@ /* Resolve all operands */ - status = acpi_aml_resolve_operands (AML_MATCH_OP, WALK_OPERANDS); + status = acpi_aml_resolve_operands (AML_MATCH_OP, WALK_OPERANDS, walk_state); /* Get all operands */ status |= acpi_ds_obj_stack_pop_object (&start_desc, walk_state); @@ -308,11 +305,9 @@ status |= acpi_ds_obj_stack_pop_object (&op1_desc, walk_state); status |= acpi_ds_obj_stack_pop_object (&pkg_desc, walk_state); - if (status != AE_OK) { + if (ACPI_FAILURE (status)) { /* Invalid parameters on object stack */ - acpi_aml_append_operand_diag (_THIS_MODULE, __LINE__, - (u16) AML_MATCH_OP, WALK_OPERANDS, 6); goto cleanup; } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/interpreter/ammonad.c linux/drivers/acpi/interpreter/ammonad.c --- v2.4.0-test8/linux/drivers/acpi/interpreter/ammonad.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/interpreter/ammonad.c Fri Sep 15 14:30:30 2000 @@ -2,6 +2,7 @@ /****************************************************************************** * * Module Name: ammonad - ACPI AML (p-code) execution for monadic operators + * $Revision: 79 $ * *****************************************************************************/ @@ -25,15 +26,15 @@ #include "acpi.h" -#include "parser.h" -#include "dispatch.h" -#include "interp.h" +#include "acparser.h" +#include "acdispat.h" +#include "acinterp.h" #include "amlcode.h" -#include "namesp.h" +#include "acnamesp.h" #define _COMPONENT INTERPRETER - MODULE_NAME ("ammonad"); + MODULE_NAME ("ammonad") /******************************************************************************* @@ -52,8 +53,9 @@ ACPI_STATUS acpi_aml_get_object_reference ( - ACPI_OBJECT_INTERNAL *obj_desc, - ACPI_OBJECT_INTERNAL **ret_desc) + ACPI_OPERAND_OBJECT *obj_desc, + ACPI_OPERAND_OBJECT **ret_desc, + ACPI_WALK_STATE *walk_state) { ACPI_STATUS status = AE_OK; @@ -74,14 +76,14 @@ case AML_LOCAL_OP: *ret_desc = (void *) acpi_ds_method_data_get_nte (MTH_TYPE_LOCAL, - (obj_desc->reference.offset)); + (obj_desc->reference.offset), walk_state); break; case AML_ARG_OP: *ret_desc = (void *) acpi_ds_method_data_get_nte (MTH_TYPE_ARG, - (obj_desc->reference.offset)); + (obj_desc->reference.offset), walk_state); break; @@ -95,7 +97,7 @@ } else if (VALID_DESCRIPTOR_TYPE (obj_desc, ACPI_DESC_TYPE_NAMED)) { - /* Must be a named object; Just return the NTE */ + /* Must be a named object; Just return the Node */ *ret_desc = obj_desc; } @@ -130,19 +132,17 @@ u16 opcode, ACPI_WALK_STATE *walk_state) { - ACPI_OBJECT_INTERNAL *obj_desc; + ACPI_OPERAND_OBJECT *obj_desc; ACPI_STATUS status; /* Resolve all operands */ - status = acpi_aml_resolve_operands (opcode, WALK_OPERANDS); + status = acpi_aml_resolve_operands (opcode, WALK_OPERANDS, walk_state); /* Get all operands */ status |= acpi_ds_obj_stack_pop_object (&obj_desc, walk_state); - if (status != AE_OK) { - acpi_aml_append_operand_diag (_THIS_MODULE, __LINE__, - opcode, WALK_OPERANDS, 1); + if (ACPI_FAILURE (status)) { goto cleanup; } @@ -196,6 +196,7 @@ default: + REPORT_ERROR ("Acpi_aml_exec_monadic1: Unknown monadic opcode"); status = AE_AML_BAD_OPCODE; break; @@ -229,30 +230,28 @@ acpi_aml_exec_monadic2_r ( u16 opcode, ACPI_WALK_STATE *walk_state, - ACPI_OBJECT_INTERNAL **return_desc) + ACPI_OPERAND_OBJECT **return_desc) { - ACPI_OBJECT_INTERNAL *obj_desc; - ACPI_OBJECT_INTERNAL *res_desc; - ACPI_OBJECT_INTERNAL *ret_desc = NULL; - ACPI_OBJECT_INTERNAL *ret_desc2 = NULL; + ACPI_OPERAND_OBJECT *obj_desc; + ACPI_OPERAND_OBJECT *res_desc; + ACPI_OPERAND_OBJECT *ret_desc = NULL; + ACPI_OPERAND_OBJECT *ret_desc2 = NULL; u32 res_val; ACPI_STATUS status; - s32 d0; - s32 d1; - s32 d2; - s32 d3; + u32 d0; + u32 d1; + u32 d2; + u32 d3; /* Resolve all operands */ - status = acpi_aml_resolve_operands (opcode, WALK_OPERANDS); + status = acpi_aml_resolve_operands (opcode, WALK_OPERANDS, walk_state); /* Get all operands */ status |= acpi_ds_obj_stack_pop_object (&res_desc, walk_state); status |= acpi_ds_obj_stack_pop_object (&obj_desc, walk_state); - if (status != AE_OK) { - acpi_aml_append_operand_diag (_THIS_MODULE, __LINE__, - opcode, WALK_OPERANDS, 2); + if (ACPI_FAILURE (status)) { goto cleanup; } @@ -264,8 +263,8 @@ case AML_BIT_NOT_OP: case AML_FIND_SET_LEFT_BIT_OP: case AML_FIND_SET_RIGHT_BIT_OP: - case AML_FROM_BCDOP: - case AML_TO_BCDOP: + case AML_FROM_BCD_OP: + case AML_TO_BCD_OP: case AML_COND_REF_OF_OP: ret_desc = acpi_cm_create_internal_object (ACPI_TYPE_NUMBER); @@ -293,7 +292,13 @@ case AML_FIND_SET_LEFT_BIT_OP: ret_desc->number.value = obj_desc->number.value; - for (res_val = 0; ret_desc->number.value && res_val < 33; ++res_val) { + + /* + * Acpi x1.94 spec, Chapter 16 describes Integer as a 32-bit + * little endian unsigned value, so this boundry condition + * is valid. + */ + for (res_val = 0; ret_desc->number.value && res_val < 32; ++res_val) { ret_desc->number.value >>= 1; } @@ -306,22 +311,29 @@ case AML_FIND_SET_RIGHT_BIT_OP: ret_desc->number.value = obj_desc->number.value; - for (res_val = 0; ret_desc->number.value && res_val < 33; ++res_val) { + + /* + * Acpi x1.94 spec, Chapter 16 describes Integer as a 32-bit + * little endian unsigned value, so this boundry condition + * is valid. + */ + for (res_val = 0; ret_desc->number.value && res_val < 32; ++res_val) { ret_desc->number.value <<= 1; } + /* Since returns must be 1-based, subtract from 33 */ ret_desc->number.value = res_val == 0 ? 0 : 33 - res_val; break; /* Def_from_bDC := From_bCDOp BCDValue Result */ - case AML_FROM_BCDOP: + case AML_FROM_BCD_OP: - d0 = (s32) (obj_desc->number.value & 15); - d1 = (s32) (obj_desc->number.value >> 4 & 15); - d2 = (s32) (obj_desc->number.value >> 8 & 15); - d3 = (s32) (obj_desc->number.value >> 12 & 15); + d0 = (u32) (obj_desc->number.value & 15); + d1 = (u32) (obj_desc->number.value >> 4 & 15); + d2 = (u32) (obj_desc->number.value >> 8 & 15); + d3 = (u32) (obj_desc->number.value >> 12 & 15); if (d0 > 9 || d1 > 9 || d2 > 9 || d3 > 9) { status = AE_AML_NUMERIC_OVERFLOW; @@ -334,7 +346,7 @@ /* Def_to_bDC := To_bCDOp Operand Result */ - case AML_TO_BCDOP: + case AML_TO_BCD_OP: if (obj_desc->number.value > 9999) { @@ -361,7 +373,7 @@ * (There are really two return values) */ - if ((ACPI_NAMED_OBJECT*) obj_desc == acpi_gbl_root_object) { + if ((ACPI_NAMESPACE_NODE *) obj_desc == acpi_gbl_root_node) { /* * This means that the object does not exist in the namespace, * return FALSE @@ -380,12 +392,12 @@ /* Get the object reference and store it */ - status = acpi_aml_get_object_reference (obj_desc, &ret_desc2); + status = acpi_aml_get_object_reference (obj_desc, &ret_desc2, walk_state); if (ACPI_FAILURE (status)) { goto cleanup; } - status = acpi_aml_exec_store (ret_desc2, res_desc); + status = acpi_aml_exec_store (ret_desc2, res_desc, walk_state); /* The object exists in the namespace, return TRUE */ @@ -406,7 +418,7 @@ * since the object itself may have been stored. */ - status = acpi_aml_exec_store (obj_desc, res_desc); + status = acpi_aml_exec_store (obj_desc, res_desc, walk_state); if (ACPI_FAILURE (status)) { /* On failure, just delete the Obj_desc */ @@ -454,12 +466,13 @@ default: + REPORT_ERROR ("Acpi_aml_exec_monadic2_r: Unknown monadic opcode"); status = AE_AML_BAD_OPCODE; goto cleanup; } - status = acpi_aml_exec_store (ret_desc, res_desc); + status = acpi_aml_exec_store (ret_desc, res_desc, walk_state); cleanup: @@ -502,25 +515,32 @@ acpi_aml_exec_monadic2 ( u16 opcode, ACPI_WALK_STATE *walk_state, - ACPI_OBJECT_INTERNAL **return_desc) + ACPI_OPERAND_OBJECT **return_desc) { - ACPI_OBJECT_INTERNAL *obj_desc; - ACPI_OBJECT_INTERNAL *tmp_desc; - ACPI_OBJECT_INTERNAL *ret_desc = NULL; + ACPI_OPERAND_OBJECT *obj_desc; + ACPI_OPERAND_OBJECT *tmp_desc; + ACPI_OPERAND_OBJECT *ret_desc = NULL; + ACPI_STATUS resolve_status; ACPI_STATUS status; u32 type; u32 value; - /* Resolve all operands */ + /* Attempt to resolve the operands */ - status = acpi_aml_resolve_operands (opcode, WALK_OPERANDS); - /* Get all operands */ + resolve_status = acpi_aml_resolve_operands (opcode, WALK_OPERANDS, walk_state); + /* Always get all operands */ - status |= acpi_ds_obj_stack_pop_object (&obj_desc, walk_state); - if (status != AE_OK) { - acpi_aml_append_operand_diag (_THIS_MODULE, __LINE__, - opcode, WALK_OPERANDS, 1); + status = acpi_ds_obj_stack_pop_object (&obj_desc, walk_state); + + + /* Now we can check the status codes */ + + if (ACPI_FAILURE (resolve_status)) { + goto cleanup; + } + + if (ACPI_FAILURE (status)) { goto cleanup; } @@ -553,7 +573,7 @@ /* * Since we are expecting an Reference on the top of the stack, it - * can be either an NTE or an internal object. + * can be either an Node or an internal object. * * TBD: [Future] This may be the prototype code for all cases where * an Reference is expected!! 10/99 @@ -586,10 +606,8 @@ * (This deletes the original Ret_desc) */ - status = acpi_aml_resolve_operands (AML_LNOT_OP, &ret_desc); - if (status != AE_OK) { - acpi_aml_append_operand_diag (_THIS_MODULE, __LINE__, - opcode, WALK_OPERANDS, 1); + status = acpi_aml_resolve_operands (AML_LNOT_OP, &ret_desc, walk_state); + if (ACPI_FAILURE (status)) { goto cleanup; } @@ -604,7 +622,7 @@ /* Store the result back in the original descriptor */ - status = acpi_aml_exec_store (ret_desc, obj_desc); + status = acpi_aml_exec_store (ret_desc, obj_desc, walk_state); /* Objdesc was just deleted (because it is an Reference) */ @@ -662,19 +680,20 @@ case AML_LOCAL_OP: type = acpi_ds_method_data_get_type (MTH_TYPE_LOCAL, - (obj_desc->reference.offset)); + (obj_desc->reference.offset), walk_state); break; case AML_ARG_OP: type = acpi_ds_method_data_get_type (MTH_TYPE_ARG, - (obj_desc->reference.offset)); + (obj_desc->reference.offset), walk_state); break; default: + REPORT_ERROR ("Acpi_aml_exec_monadic2/Type_op:internal error: Unknown Reference subtype"); status = AE_AML_INTERNAL; goto cleanup; } @@ -682,8 +701,7 @@ else { /* - * Since we passed Acpi_aml_resolve_operands("l") and it's not a - * Reference, it must be a direct name pointer. + * It's not a Reference, so it must be a direct name pointer. */ type = acpi_ns_get_type ((ACPI_HANDLE) obj_desc); } @@ -764,7 +782,7 @@ case AML_REF_OF_OP: - status = acpi_aml_get_object_reference (obj_desc, &ret_desc); + status = acpi_aml_get_object_reference (obj_desc, &ret_desc, walk_state); if (ACPI_FAILURE (status)) { goto cleanup; } @@ -789,7 +807,7 @@ case AML_LOCAL_OP: acpi_ds_method_data_get_value (MTH_TYPE_LOCAL, - (obj_desc->reference.offset), &tmp_desc); + (obj_desc->reference.offset), walk_state, &tmp_desc); /* * Delete our reference to the input object and @@ -803,7 +821,7 @@ case AML_ARG_OP: acpi_ds_method_data_get_value (MTH_TYPE_ARG, - (obj_desc->reference.offset), &tmp_desc); + (obj_desc->reference.offset), walk_state, &tmp_desc); /* * Delete our reference to the input object and @@ -824,9 +842,9 @@ /* Obj_desc may have changed from the code above */ if (VALID_DESCRIPTOR_TYPE (obj_desc, ACPI_DESC_TYPE_NAMED)) { - /* Get the actual object from the NTE (This is the dereference) */ + /* Get the actual object from the Node (This is the dereference) */ - ret_desc = ((ACPI_NAMED_OBJECT*) obj_desc)->object; + ret_desc = ((ACPI_NAMESPACE_NODE *) obj_desc)->object; /* Returning a pointer to the object, add another reference! */ @@ -928,6 +946,7 @@ default: + REPORT_ERROR ("Acpi_aml_exec_monadic2: Internal error, unknown monadic opcode"); status = AE_AML_BAD_OPCODE; goto cleanup; } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/interpreter/amnames.c linux/drivers/acpi/interpreter/amnames.c --- v2.4.0-test8/linux/drivers/acpi/interpreter/amnames.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/interpreter/amnames.c Fri Sep 15 14:30:30 2000 @@ -2,6 +2,7 @@ /****************************************************************************** * * Module Name: amnames - interpreter/scanner name load/execute + * $Revision: 70 $ * *****************************************************************************/ @@ -25,12 +26,12 @@ #include "acpi.h" -#include "interp.h" +#include "acinterp.h" #include "amlcode.h" -#include "namesp.h" +#include "acnamesp.h" #define _COMPONENT INTERPRETER - MODULE_NAME ("amnames"); + MODULE_NAME ("amnames") /* AML Package Length encodings */ @@ -57,13 +58,13 @@ * ******************************************************************************/ -char * +NATIVE_CHAR * acpi_aml_allocate_name_string ( u32 prefix_count, u32 num_name_segs) { - char *temp_ptr; - char *name_string; + NATIVE_CHAR *temp_ptr; + NATIVE_CHAR *name_string; u32 size_needed; @@ -87,7 +88,7 @@ * This buffer must be deleted by the caller! */ - name_string = acpi_cm_allocate ((ACPI_SIZE) size_needed); + name_string = acpi_cm_allocate (size_needed); if (!name_string) { REPORT_ERROR ("Aml_allocate_name_string: name allocation failure"); return (NULL); @@ -133,52 +134,6 @@ return (name_string); } - -/******************************************************************************* - * - * FUNCTION: Acpi_aml_decode_package_length - * - * PARAMETERS: Last_pkg_len - latest value decoded by Do_pkg_length() for - * most recently examined package or field - * - * RETURN: Number of bytes contained in package length encoding - * - * DESCRIPTION: Decodes the Package Length. Upper 2 bits are are used to - * tell if type 1, 2, 3, or 4. - * 0x3F = Max 1 byte encoding, - * 0xFFF = Max 2 byte encoding, - * 0xFFFFF = Max 3 Byte encoding, - * 0xFFFFFFFFF = Max 4 Byte encoding. - * - ******************************************************************************/ - -u32 -acpi_aml_decode_package_length ( - u32 last_pkg_len) -{ - u32 num_bytes = 0; - - - if (last_pkg_len < ACPI_AML_PACKAGE_TYPE1) { - num_bytes = 1; - } - - else if (last_pkg_len < ACPI_AML_PACKAGE_TYPE2) { - num_bytes = 2; - } - - else if (last_pkg_len < ACPI_AML_PACKAGE_TYPE3) { - num_bytes = 3; - } - - else if (last_pkg_len < ACPI_AML_PACKAGE_TYPE4) { - num_bytes = 4; - } - - return (num_bytes); -} - - /******************************************************************************* * * FUNCTION: Acpi_aml_exec_name_segment @@ -194,12 +149,12 @@ ACPI_STATUS acpi_aml_exec_name_segment ( u8 **in_aml_address, - char *name_string) + NATIVE_CHAR *name_string) { u8 *aml_address = *in_aml_address; ACPI_STATUS status = AE_OK; - s32 index; - char char_buf[5]; + u32 index; + NATIVE_CHAR char_buf[5]; /* @@ -271,15 +226,16 @@ acpi_aml_get_name_string ( OBJECT_TYPE_INTERNAL data_type, u8 *in_aml_address, - char **out_name_string, + NATIVE_CHAR **out_name_string, u32 *out_name_length) { ACPI_STATUS status = AE_OK; u8 *aml_address = in_aml_address; - char *name_string = NULL; - s32 num_segments; - s32 prefix_count = 0; + NATIVE_CHAR *name_string = NULL; + u32 num_segments; + u32 prefix_count = 0; u8 prefix = 0; + u8 has_prefix = FALSE; if (INTERNAL_TYPE_DEF_FIELD == data_type || @@ -313,7 +269,8 @@ * Remember that we have a Root_prefix -- * see comment in Acpi_aml_allocate_name_string() */ - prefix_count = -1; + prefix_count = (u32) -1; + has_prefix = TRUE; break; @@ -327,7 +284,7 @@ ++prefix_count; } while (*aml_address == AML_PARENT_PREFIX); - + has_prefix = TRUE; break; @@ -351,9 +308,8 @@ break; } - /* Ensure Prefix_count != 0 to remember processing a prefix */ - - prefix_count += 2; + /* Indicate that we processed a prefix */ + has_prefix = TRUE; status = acpi_aml_exec_name_segment (&aml_address, name_string); if (ACPI_SUCCESS (status)) { @@ -375,9 +331,8 @@ break; } - /* Ensure Prefix_count != 0 to remember processing a prefix */ - - prefix_count += 2; + /* Indicate that we processed a prefix */ + has_prefix = TRUE; while (num_segments && (status = acpi_aml_exec_name_segment (&aml_address, name_string)) == AE_OK) @@ -422,7 +377,7 @@ } - if (AE_CTRL_PENDING == status && prefix_count != 0) { + if (AE_CTRL_PENDING == status && has_prefix) { /* Ran out of segments after processing a prefix */ REPORT_ERROR ("Ran out of segments after processing a prefix"); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/interpreter/amprep.c linux/drivers/acpi/interpreter/amprep.c --- v2.4.0-test8/linux/drivers/acpi/interpreter/amprep.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/interpreter/amprep.c Fri Sep 15 14:30:30 2000 @@ -2,6 +2,7 @@ /****************************************************************************** * * Module Name: amprep - ACPI AML (p-code) execution - field prep utilities + * $Revision: 67 $ * *****************************************************************************/ @@ -25,14 +26,14 @@ #include "acpi.h" -#include "interp.h" +#include "acinterp.h" #include "amlcode.h" -#include "namesp.h" -#include "parser.h" +#include "acnamesp.h" +#include "acparser.h" #define _COMPONENT INTERPRETER - MODULE_NAME ("amprep"); + MODULE_NAME ("amprep") /******************************************************************************* @@ -55,25 +56,25 @@ switch (access) { case ACCESS_ANY_ACC: - return 8; + return (8); break; case ACCESS_BYTE_ACC: - return 8; + return (8); break; case ACCESS_WORD_ACC: - return 16; + return (16); break; case ACCESS_DWORD_ACC: - return 32; + return (32); break; default: /* Invalid field access type */ - return 0; + return (0); } } @@ -98,7 +99,7 @@ ACPI_STATUS acpi_aml_prep_common_field_object ( - ACPI_OBJECT_INTERNAL *obj_desc, + ACPI_OPERAND_OBJECT *obj_desc, u8 field_flags, u8 field_attribute, u32 field_position, @@ -150,7 +151,7 @@ * * FUNCTION: Acpi_aml_prep_def_field_value * - * PARAMETERS: This_entry - Owning NTE + * PARAMETERS: Node - Owning Node * Region - Region in which field is being defined * Field_flags - Access, Lock_rule, or Update_rule. * The format of a Field_flag is described @@ -160,22 +161,22 @@ * * RETURN: Status * - * DESCRIPTION: Construct an ACPI_OBJECT_INTERNAL of type Def_field and - * connect it to the parent NTE. + * DESCRIPTION: Construct an ACPI_OPERAND_OBJECT of type Def_field and + * connect it to the parent Node. * ******************************************************************************/ ACPI_STATUS acpi_aml_prep_def_field_value ( - ACPI_NAMED_OBJECT *this_entry, + ACPI_NAMESPACE_NODE *node, ACPI_HANDLE region, u8 field_flags, u8 field_attribute, u32 field_position, u32 field_length) { - ACPI_OBJECT_INTERNAL *obj_desc; - s32 type; + ACPI_OPERAND_OBJECT *obj_desc; + u32 type; ACPI_STATUS status; @@ -220,11 +221,11 @@ /* Debug info */ /* - * Store the constructed descriptor (Obj_desc) into the nte whose - * handle is on TOS, preserving the current type of that nte. + * Store the constructed descriptor (Obj_desc) into the Named_obj whose + * handle is on TOS, preserving the current type of that Named_obj. */ - status = acpi_ns_attach_object ((ACPI_HANDLE) this_entry, obj_desc, - (u8) acpi_ns_get_type ((ACPI_HANDLE) this_entry)); + status = acpi_ns_attach_object ((ACPI_HANDLE) node, obj_desc, + (u8) acpi_ns_get_type ((ACPI_HANDLE) node)); return (status); } @@ -234,7 +235,7 @@ * * FUNCTION: Acpi_aml_prep_bank_field_value * - * PARAMETERS: This_entry - Owning NTE + * PARAMETERS: Node - Owning Node * Region - Region in which field is being defined * Bank_reg - Bank selection register * Bank_val - Value to store in selection register @@ -244,14 +245,14 @@ * * RETURN: Status * - * DESCRIPTION: Construct an ACPI_OBJECT_INTERNAL of type Bank_field and - * connect it to the parent NTE. + * DESCRIPTION: Construct an ACPI_OPERAND_OBJECT of type Bank_field and + * connect it to the parent Node. * ******************************************************************************/ ACPI_STATUS acpi_aml_prep_bank_field_value ( - ACPI_NAMED_OBJECT *this_entry, + ACPI_NAMESPACE_NODE *node, ACPI_HANDLE region, ACPI_HANDLE bank_reg, u32 bank_val, @@ -260,8 +261,8 @@ u32 field_position, u32 field_length) { - ACPI_OBJECT_INTERNAL *obj_desc; - s32 type; + ACPI_OPERAND_OBJECT *obj_desc; + u32 type; ACPI_STATUS status; @@ -308,11 +309,11 @@ /* Debug info */ /* - * Store the constructed descriptor (Obj_desc) into the nte whose - * handle is on TOS, preserving the current type of that nte. + * Store the constructed descriptor (Obj_desc) into the Named_obj whose + * handle is on TOS, preserving the current type of that Named_obj. */ - status = acpi_ns_attach_object ((ACPI_HANDLE) this_entry, obj_desc, - (u8) acpi_ns_get_type ((ACPI_HANDLE) this_entry)); + status = acpi_ns_attach_object ((ACPI_HANDLE) node, obj_desc, + (u8) acpi_ns_get_type ((ACPI_HANDLE) node)); return (status); } @@ -322,7 +323,7 @@ * * FUNCTION: Acpi_aml_prep_index_field_value * - * PARAMETERS: This_entry - Owning NTE + * PARAMETERS: Node - Owning Node * Index_reg - Index register * Data_reg - Data register * Field_flags - Access, Lock_rule, or Update_rule @@ -331,14 +332,14 @@ * * RETURN: Status * - * DESCRIPTION: Construct an ACPI_OBJECT_INTERNAL of type Index_field and - * connect it to the parent NTE. + * DESCRIPTION: Construct an ACPI_OPERAND_OBJECT of type Index_field and + * connect it to the parent Node. * ******************************************************************************/ ACPI_STATUS acpi_aml_prep_index_field_value ( - ACPI_NAMED_OBJECT *this_entry, + ACPI_NAMESPACE_NODE *node, ACPI_HANDLE index_reg, ACPI_HANDLE data_reg, u8 field_flags, @@ -346,7 +347,7 @@ u32 field_position, u32 field_length) { - ACPI_OBJECT_INTERNAL *obj_desc; + ACPI_OPERAND_OBJECT *obj_desc; ACPI_STATUS status; @@ -381,11 +382,11 @@ /* Debug info */ /* - * Store the constructed descriptor (Obj_desc) into the nte whose - * handle is on TOS, preserving the current type of that nte. + * Store the constructed descriptor (Obj_desc) into the Named_obj whose + * handle is on TOS, preserving the current type of that Named_obj. */ - status = acpi_ns_attach_object ((ACPI_HANDLE) this_entry, obj_desc, - (u8) acpi_ns_get_type ((ACPI_HANDLE) this_entry)); + status = acpi_ns_attach_object ((ACPI_HANDLE) node, obj_desc, + (u8) acpi_ns_get_type ((ACPI_HANDLE) node)); return (status); } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/interpreter/amregion.c linux/drivers/acpi/interpreter/amregion.c --- v2.4.0-test8/linux/drivers/acpi/interpreter/amregion.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/interpreter/amregion.c Fri Sep 15 14:30:30 2000 @@ -1,6 +1,8 @@ + /****************************************************************************** * * Module Name: amregion - ACPI default Op_region (address space) handlers + * $Revision: 35 $ * *****************************************************************************/ @@ -24,15 +26,15 @@ #include "acpi.h" -#include "interp.h" +#include "acinterp.h" #include "amlcode.h" -#include "namesp.h" -#include "hardware.h" -#include "events.h" +#include "acnamesp.h" +#include "achware.h" +#include "acevents.h" #define _COMPONENT INTERPRETER - MODULE_NAME ("amregion"); + MODULE_NAME ("amregion") /******************************************************************************* @@ -43,7 +45,9 @@ * Address - Where in the space to read or write * Bit_width - Field width in bits (8, 16, or 32) * Value - Pointer to in or out value - * Context - Context pointer + * Handler_context - Pointer to Handler's context + * Region_context - Pointer to context specific to the + * accessed region * * RETURN: Status * @@ -57,11 +61,12 @@ u32 address, /* TBD: [Future] Should this be A POINTER for 64-bit support? */ u32 bit_width, u32 *value, - void *context) + void *handler_context, + void *region_context) { ACPI_STATUS status = AE_OK; void *logical_addr_ptr = NULL; - MEM_HANDLER_CONTEXT *mem_info = context; + MEM_HANDLER_CONTEXT *mem_info = region_context; u32 length; @@ -93,8 +98,8 @@ * 2) Address beyond the current mapping? */ - if (((char *) address < mem_info->mapped_physical_address) || - (((char *) address + length) > + if (((u8 *) address < mem_info->mapped_physical_address) || + (((u8 *) address + length) > (mem_info->mapped_physical_address + mem_info->mapped_length))) { /* @@ -119,7 +124,7 @@ return (status); } - mem_info->mapped_physical_address = (char *) address; + mem_info->mapped_physical_address = (u8 *) address; mem_info->mapped_length = SYSMEM_REGION_WINDOW_SIZE; } @@ -130,7 +135,7 @@ */ logical_addr_ptr = mem_info->mapped_logical_address + - ((char *) address - mem_info->mapped_physical_address); + ((u8 *) address - mem_info->mapped_physical_address); /* Perform the memory read or write */ @@ -194,7 +199,9 @@ * Address - Where in the space to read or write * Bit_width - Field width in bits (8, 16, or 32) * Value - Pointer to in or out value - * Context - Context pointer + * Handler_context - Pointer to Handler's context + * Region_context - Pointer to context specific to the + * accessed region * * RETURN: Status * @@ -208,7 +215,8 @@ u32 address, u32 bit_width, u32 *value, - void *context) + void *handler_context, + void *region_context) { ACPI_STATUS status = AE_OK; @@ -283,7 +291,9 @@ * Address - Where in the space to read or write * Bit_width - Field width in bits (8, 16, or 32) * Value - Pointer to in or out value - * Context - Context pointer + * Handler_context - Pointer to Handler's context + * Region_context - Pointer to context specific to the + * accessed region * * RETURN: Status * @@ -297,7 +307,8 @@ u32 address, u32 bit_width, u32 *value, - void *context) + void *handler_context, + void *region_context) { ACPI_STATUS status = AE_OK; u32 pci_bus; @@ -321,7 +332,7 @@ * */ - PCIcontext = (PCI_HANDLER_CONTEXT *) context; + PCIcontext = (PCI_HANDLER_CONTEXT *) region_context; pci_bus = LOWORD(PCIcontext->seg) << 16; pci_bus |= LOWORD(PCIcontext->bus); @@ -365,7 +376,6 @@ case ADDRESS_SPACE_WRITE: - switch (bit_width) { diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/interpreter/amresnte.c linux/drivers/acpi/interpreter/amresnte.c --- v2.4.0-test8/linux/drivers/acpi/interpreter/amresnte.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/interpreter/amresnte.c Fri Sep 15 14:30:30 2000 @@ -2,6 +2,7 @@ /****************************************************************************** * * Module Name: amresnte - AML Interpreter object resolution + * $Revision: 21 $ * *****************************************************************************/ @@ -26,32 +27,33 @@ #include "acpi.h" #include "amlcode.h" -#include "parser.h" -#include "dispatch.h" -#include "interp.h" -#include "namesp.h" -#include "tables.h" -#include "events.h" +#include "acparser.h" +#include "acdispat.h" +#include "acinterp.h" +#include "acnamesp.h" +#include "actables.h" +#include "acevents.h" #define _COMPONENT INTERPRETER - MODULE_NAME ("amresnte"); + MODULE_NAME ("amresnte") /******************************************************************************* * - * FUNCTION: Acpi_aml_resolve_entry_to_value + * FUNCTION: Acpi_aml_resolve_node_to_value * * PARAMETERS: Stack_ptr - Pointer to a location on a stack that contains - * a ptr to an NTE + * a pointer to an Node * * RETURN: Status * - * DESCRIPTION: Resolve a ACPI_NAMED_OBJECT(nte, A.K.A. a "direct name pointer") + * DESCRIPTION: Resolve a ACPI_NAMESPACE_NODE (Node, + * A.K.A. a "direct name pointer") * - * Note: for some of the data types, the pointer attached to the NTE can be - * either a pointer to an actual internal object or a pointer into the AML - * stream itself. These types are currently: + * Note: for some of the data types, the pointer attached to the Node + * can be either a pointer to an actual internal object or a pointer into the + * AML stream itself. These types are currently: * * ACPI_TYPE_NUMBER * ACPI_TYPE_STRING @@ -62,13 +64,13 @@ ******************************************************************************/ ACPI_STATUS -acpi_aml_resolve_entry_to_value ( - ACPI_NAMED_OBJECT **stack_ptr) +acpi_aml_resolve_node_to_value ( + ACPI_NAMESPACE_NODE **stack_ptr) { ACPI_STATUS status = AE_OK; - ACPI_OBJECT_INTERNAL *val_desc = NULL; - ACPI_OBJECT_INTERNAL *obj_desc = NULL; - ACPI_NAMED_OBJECT *stack_entry; + ACPI_OPERAND_OBJECT *val_desc = NULL; + ACPI_OPERAND_OBJECT *obj_desc = NULL; + ACPI_NAMESPACE_NODE *node; u8 *aml_pointer = NULL; OBJECT_TYPE_INTERNAL entry_type; u8 locked; @@ -78,20 +80,20 @@ OBJECT_TYPE_INTERNAL object_type; - stack_entry = *stack_ptr; + node = *stack_ptr; /* * The stack pointer is a "Direct name ptr", and points to a - * a ACPI_NAMED_OBJECT(nte). Get the pointer that is attached to - * the nte. + * a ACPI_NAMESPACE_NODE (Node). Get the pointer that is attached to + * the Node. */ - val_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) stack_entry); - entry_type = acpi_ns_get_type ((ACPI_HANDLE) stack_entry); + val_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) node); + entry_type = acpi_ns_get_type ((ACPI_HANDLE) node); /* - * The Val_desc attached to the NTE can be either: + * The Val_desc attached to the Node can be either: * 1) An internal ACPI object * 2) A pointer into the AML stream (into one of the ACPI system tables) */ @@ -105,7 +107,25 @@ /* - * Action is based on the type of the NTE, which indicates the type + * Several Entry_types do not require further processing, so + * we will return immediately + */ + /* Devices rarely have an attached object, return the Node + * and Method locals and arguments have a pseudo-Node + */ + if (entry_type == ACPI_TYPE_DEVICE || + entry_type == INTERNAL_TYPE_METHOD_ARGUMENT || + entry_type == INTERNAL_TYPE_METHOD_LOCAL_VAR) + { + return (AE_OK); + } + + if (!val_desc) { + return (AE_AML_NO_OPERAND); + } + + /* + * Action is based on the type of the Node, which indicates the type * of the attached object or pointer */ switch (entry_type) @@ -113,15 +133,6 @@ case ACPI_TYPE_PACKAGE: - /* - * Val_desc should point to either an ACPI_OBJECT_INTERNAL of - * type Package, or an initialization in the AML stream. - */ - if (!val_desc) { - return (AE_AML_NO_OPERAND); - } - - if (attached_aml_pointer) { /* * This means that the package initialization is not parsed @@ -132,7 +143,7 @@ /* Val_desc is an internal object in all cases by the time we get here */ - if (!val_desc || (ACPI_TYPE_PACKAGE != val_desc->common.type)) { + if (ACPI_TYPE_PACKAGE != val_desc->common.type) { return (AE_AML_OPERAND_TYPE); } @@ -145,10 +156,6 @@ case ACPI_TYPE_BUFFER: - if (!val_desc) { - return (AE_AML_NO_OPERAND); - } - if (attached_aml_pointer) { /* * This means that the buffer initialization is not parsed @@ -159,7 +166,7 @@ /* Val_desc is an internal object in all cases by the time we get here */ - if (!val_desc || (ACPI_TYPE_BUFFER != val_desc->common.type)) { + if (ACPI_TYPE_BUFFER != val_desc->common.type) { return (AE_AML_OPERAND_TYPE); } @@ -183,8 +190,8 @@ /* Init the internal object */ - obj_desc->string.pointer = (char *) aml_pointer; - obj_desc->string.length = STRLEN (aml_pointer); + obj_desc->string.pointer = (NATIVE_CHAR *) aml_pointer; + obj_desc->string.length = STRLEN (obj_desc->string.pointer); } else { @@ -203,11 +210,6 @@ case ACPI_TYPE_NUMBER: - if (!val_desc) { - return (AE_AML_NO_OPERAND); - } - - /* * An ACPI_TYPE_NUMBER can be either an object or an AML pointer */ @@ -279,7 +281,7 @@ else { /* - * The NTE has an attached internal object, make sure that it's a + * The Node has an attached internal object, make sure that it's a * number */ @@ -337,18 +339,21 @@ obj_desc->buffer.length = val_desc->field.length; - status = acpi_aml_get_named_field_value ((ACPI_HANDLE) stack_entry, - obj_desc->buffer.pointer, obj_desc->buffer.length); + status = acpi_aml_access_named_field (ACPI_READ, + (ACPI_HANDLE) node, + obj_desc->buffer.pointer, + obj_desc->buffer.length); - if (AE_OK != status) { + if (ACPI_FAILURE (status)) { return (status); } } else { - status = acpi_aml_get_named_field_value ((ACPI_HANDLE) stack_entry, + status = acpi_aml_access_named_field (ACPI_READ, + (ACPI_HANDLE) node, &temp_val, sizeof (temp_val)); - if (AE_OK != status) { + if (ACPI_FAILURE (status)) { return (status); } @@ -361,10 +366,6 @@ case INTERNAL_TYPE_BANK_FIELD: - if (!val_desc) { - return (AE_AML_NO_OPERAND); - } - if (attached_aml_pointer) { return (AE_AML_OPERAND_TYPE); } @@ -376,30 +377,30 @@ /* Get the global lock if needed */ - obj_desc = (ACPI_OBJECT_INTERNAL *) *stack_ptr; + obj_desc = (ACPI_OPERAND_OBJECT *) *stack_ptr; locked = acpi_aml_acquire_global_lock (obj_desc->field_unit.lock_rule); - { - /* Set Index value to select proper Data register */ - /* perform the update */ + /* Set Index value to select proper Data register */ + /* perform the update */ + + status = acpi_aml_access_named_field (ACPI_WRITE, + val_desc->bank_field.bank_select, + &val_desc->bank_field.value, + sizeof (val_desc->bank_field.value)); - status = acpi_aml_set_named_field_value (val_desc->bank_field.bank_select, - &val_desc->bank_field.value, - sizeof (val_desc->bank_field.value)); - } acpi_aml_release_global_lock (locked); - if (AE_OK != status) { + if (ACPI_FAILURE (status)) { return (status); } /* Read Data value */ - status = acpi_aml_get_named_field_value ( + status = acpi_aml_access_named_field (ACPI_READ, (ACPI_HANDLE) val_desc->bank_field.container, &temp_val, sizeof (temp_val)); - if (AE_OK != status) { + if (ACPI_FAILURE (status)) { return (status); } @@ -414,10 +415,6 @@ case INTERNAL_TYPE_INDEX_FIELD: - if (!val_desc) { - return (AE_AML_NO_OPERAND); - } - if (attached_aml_pointer) { return (AE_AML_OPERAND_TYPE); } @@ -430,25 +427,27 @@ /* Set Index value to select proper Data register */ /* Get the global lock if needed */ - obj_desc = (ACPI_OBJECT_INTERNAL *) *stack_ptr; + obj_desc = (ACPI_OPERAND_OBJECT *) *stack_ptr; locked = acpi_aml_acquire_global_lock (obj_desc->field_unit.lock_rule); - { - /* Perform the update */ - status = acpi_aml_set_named_field_value (val_desc->index_field.index, - &val_desc->index_field.value, - sizeof (val_desc->index_field.value)); - } + /* Perform the update */ + status = acpi_aml_access_named_field (ACPI_WRITE, + val_desc->index_field.index, + &val_desc->index_field.value, + sizeof (val_desc->index_field.value)); + acpi_aml_release_global_lock (locked); - if (AE_OK != status) { + if (ACPI_FAILURE (status)) { return (status); } /* Read Data value */ - status = acpi_aml_get_named_field_value (val_desc->index_field.data, &temp_val, sizeof (temp_val)); - if (AE_OK != status) { + status = acpi_aml_access_named_field (ACPI_READ, + val_desc->index_field.data, + &temp_val, sizeof (temp_val)); + if (ACPI_FAILURE (status)) { return (status); } @@ -463,10 +462,6 @@ case ACPI_TYPE_FIELD_UNIT: - if (!val_desc) { - return (AE_AML_NO_OPERAND); - } - if (attached_aml_pointer) { return (AE_AML_OPERAND_TYPE); } @@ -481,7 +476,8 @@ return (AE_NO_MEMORY); } - if ((status = acpi_aml_get_field_unit_value (val_desc, obj_desc)) != AE_OK) { + status = acpi_aml_get_field_unit_value (val_desc, obj_desc); + if (ACPI_FAILURE (status)) { acpi_cm_remove_reference (obj_desc); return (status); } @@ -490,7 +486,7 @@ /* - * For these objects, just return the object attached to the NTE + * For these objects, just return the object attached to the Node */ case ACPI_TYPE_MUTEX: @@ -502,32 +498,11 @@ case ACPI_TYPE_REGION: - /* There must be an object attached to this NTE */ - - if (!val_desc) { - return (AE_AML_INTERNAL); - } - /* Return an additional reference to the object */ obj_desc = val_desc; acpi_cm_add_reference (obj_desc); break; - - - /* Devices rarely have an attached object, return the NTE */ - - case ACPI_TYPE_DEVICE: - - - /* Method locals and arguments have a pseudo-NTE, just return it */ - - case INTERNAL_TYPE_METHOD_ARGUMENT: - case INTERNAL_TYPE_METHOD_LOCAL_VAR: - - return (AE_OK); - break; - /* TYPE_Any is untyped, and thus there is no object associated with it */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/interpreter/amresolv.c linux/drivers/acpi/interpreter/amresolv.c --- v2.4.0-test8/linux/drivers/acpi/interpreter/amresolv.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/interpreter/amresolv.c Fri Sep 15 14:30:30 2000 @@ -2,6 +2,7 @@ /****************************************************************************** * * Module Name: amresolv - AML Interpreter object resolution + * $Revision: 74 $ * *****************************************************************************/ @@ -26,16 +27,16 @@ #include "acpi.h" #include "amlcode.h" -#include "parser.h" -#include "dispatch.h" -#include "interp.h" -#include "namesp.h" -#include "tables.h" -#include "events.h" +#include "acparser.h" +#include "acdispat.h" +#include "acinterp.h" +#include "acnamesp.h" +#include "actables.h" +#include "acevents.h" #define _COMPONENT INTERPRETER - MODULE_NAME ("amresolv"); + MODULE_NAME ("amresolv") /******************************************************************************* @@ -55,8 +56,8 @@ ACPI_STATUS acpi_aml_get_field_unit_value ( - ACPI_OBJECT_INTERNAL *field_desc, - ACPI_OBJECT_INTERNAL *result_desc) + ACPI_OPERAND_OBJECT *field_desc, + ACPI_OPERAND_OBJECT *result_desc) { ACPI_STATUS status = AE_OK; u32 mask; @@ -143,7 +144,7 @@ * FUNCTION: Acpi_aml_resolve_to_value * * PARAMETERS: **Stack_ptr - Points to entry on Obj_stack, which can - * be either an (ACPI_OBJECT_INTERNAL *) + * be either an (ACPI_OPERAND_OBJECT *) * or an ACPI_HANDLE. * * RETURN: Status @@ -154,7 +155,8 @@ ACPI_STATUS acpi_aml_resolve_to_value ( - ACPI_OBJECT_INTERNAL **stack_ptr) + ACPI_OPERAND_OBJECT **stack_ptr, + ACPI_WALK_STATE *walk_state) { ACPI_STATUS status = AE_OK; @@ -166,13 +168,13 @@ /* * The entity pointed to by the Stack_ptr can be either - * 1) A valid ACPI_OBJECT_INTERNAL, or - * 2) A ACPI_NAMED_OBJECT(nte) + * 1) A valid ACPI_OPERAND_OBJECT, or + * 2) A ACPI_NAMESPACE_NODE (Named_obj) */ if (VALID_DESCRIPTOR_TYPE (*stack_ptr, ACPI_DESC_TYPE_INTERNAL)) { - status = acpi_aml_resolve_object_to_value (stack_ptr); + status = acpi_aml_resolve_object_to_value (stack_ptr, walk_state); if (ACPI_FAILURE (status)) { return (status); } @@ -184,7 +186,7 @@ */ if (VALID_DESCRIPTOR_TYPE (*stack_ptr, ACPI_DESC_TYPE_NAMED)) { - status = acpi_aml_resolve_entry_to_value ((ACPI_NAMED_OBJECT**) stack_ptr); + status = acpi_aml_resolve_node_to_value ((ACPI_NAMESPACE_NODE **) stack_ptr); } @@ -208,19 +210,20 @@ ACPI_STATUS acpi_aml_resolve_object_to_value ( - ACPI_OBJECT_INTERNAL **stack_ptr) + ACPI_OPERAND_OBJECT **stack_ptr, + ACPI_WALK_STATE *walk_state) { - ACPI_OBJECT_INTERNAL *stack_desc; + ACPI_OPERAND_OBJECT *stack_desc; ACPI_STATUS status = AE_OK; ACPI_HANDLE temp_handle = NULL; - ACPI_OBJECT_INTERNAL *obj_desc = NULL; + ACPI_OPERAND_OBJECT *obj_desc = NULL; u32 index = 0; u16 opcode; stack_desc = *stack_ptr; - /* This is an ACPI_OBJECT_INTERNAL */ + /* This is an ACPI_OPERAND_OBJECT */ switch (stack_desc->common.type) { @@ -236,7 +239,7 @@ /* * Convert indirect name ptr to a direct name ptr. - * Then, Acpi_aml_resolve_entry_to_value can be used to get the value + * Then, Acpi_aml_resolve_node_to_value can be used to get the value */ temp_handle = stack_desc->reference.object; @@ -256,24 +259,26 @@ index = stack_desc->reference.offset; - /* Delete the Reference Object */ - - acpi_cm_remove_reference (stack_desc); - /* * Get the local from the method's state info - * Note: this increments the object reference count + * Note: this increments the local's object reference count */ status = acpi_ds_method_data_get_value (MTH_TYPE_LOCAL, index, - stack_ptr); + walk_state, &obj_desc); if (ACPI_FAILURE (status)) { return (status); } - stack_desc = *stack_ptr; + /* + * Now we can delete the original Reference Object and + * replace it with the resolve value + */ + + acpi_cm_remove_reference (stack_desc); + *stack_ptr = obj_desc; - if (ACPI_TYPE_NUMBER == stack_desc->common.type) { + if (ACPI_TYPE_NUMBER == obj_desc->common.type) { /* Value is a Number */ } @@ -285,9 +290,6 @@ index = stack_desc->reference.offset; - /* Delete the Reference Object*/ - - acpi_cm_remove_reference (stack_desc); /* * Get the argument from the method's state info @@ -295,14 +297,20 @@ */ status = acpi_ds_method_data_get_value (MTH_TYPE_ARG, index, - stack_ptr); + walk_state, &obj_desc); if (ACPI_FAILURE (status)) { return (status); } - stack_desc = *stack_ptr; + /* + * Now we can delete the original Reference Object and + * replace it with the resolve value + */ + + acpi_cm_remove_reference (stack_desc); + *stack_ptr = obj_desc; - if (ACPI_TYPE_NUMBER == stack_desc->common.type) { + if (ACPI_TYPE_NUMBER == obj_desc->common.type) { /* Value is a Number */ } @@ -392,7 +400,7 @@ } /* switch (Opcode) */ - if (AE_OK != status) { + if (ACPI_FAILURE (status)) { return (status); } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/interpreter/amresop.c linux/drivers/acpi/interpreter/amresop.c --- v2.4.0-test8/linux/drivers/acpi/interpreter/amresop.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/interpreter/amresop.c Fri Sep 15 14:30:30 2000 @@ -2,6 +2,7 @@ /****************************************************************************** * * Module Name: amresop - AML Interpreter operand/object resolution + * $Revision: 15 $ * *****************************************************************************/ @@ -26,16 +27,16 @@ #include "acpi.h" #include "amlcode.h" -#include "parser.h" -#include "dispatch.h" -#include "interp.h" -#include "namesp.h" -#include "tables.h" -#include "events.h" +#include "acparser.h" +#include "acdispat.h" +#include "acinterp.h" +#include "acnamesp.h" +#include "actables.h" +#include "acevents.h" #define _COMPONENT INTERPRETER - MODULE_NAME ("amresop"); + MODULE_NAME ("amresop") /******************************************************************************* @@ -60,19 +61,20 @@ ACPI_STATUS acpi_aml_resolve_operands ( u16 opcode, - ACPI_OBJECT_INTERNAL **stack_ptr) + ACPI_OPERAND_OBJECT **stack_ptr, + ACPI_WALK_STATE *walk_state) { - ACPI_OBJECT_INTERNAL *obj_desc; + ACPI_OPERAND_OBJECT *obj_desc; ACPI_STATUS status = AE_OK; u8 object_type; ACPI_HANDLE temp_handle; u32 arg_types; - ACPI_OP_INFO *op_info; + ACPI_OPCODE_INFO *op_info; u32 this_arg_type; op_info = acpi_ps_get_opcode_info (opcode); - if (!op_info) { + if (ACPI_GET_OP_TYPE (op_info) != ACPI_OP_TYPE_OPCODE) { return (AE_AML_BAD_OPCODE); } @@ -105,9 +107,9 @@ /* Decode the descriptor type */ if (VALID_DESCRIPTOR_TYPE (obj_desc, ACPI_DESC_TYPE_NAMED)) { - /* NTE */ + /* Node */ - object_type = ((ACPI_NAMED_OBJECT*) obj_desc)->type; + object_type = ((ACPI_NAMESPACE_NODE *) obj_desc)->type; } else if (VALID_DESCRIPTOR_TYPE (obj_desc, ACPI_DESC_TYPE_INTERNAL)) { @@ -128,7 +130,7 @@ */ op_info = acpi_ps_get_opcode_info (opcode); - if (!op_info) { + if (ACPI_GET_OP_TYPE (op_info) != ACPI_OP_TYPE_OPCODE) { return (AE_AML_BAD_OPCODE); } @@ -205,7 +207,8 @@ /* Need an operand of type ACPI_TYPE_NUMBER */ - if ((status = acpi_aml_resolve_to_value (stack_ptr)) != AE_OK) { + status = acpi_aml_resolve_to_value (stack_ptr, walk_state); + if (ACPI_FAILURE (status)) { goto cleanup; } @@ -220,7 +223,8 @@ /* Need an operand of type ACPI_TYPE_STRING or ACPI_TYPE_BUFFER */ - if ((status = acpi_aml_resolve_to_value (stack_ptr)) != AE_OK) { + status = acpi_aml_resolve_to_value (stack_ptr, walk_state); + if (ACPI_FAILURE (status)) { goto cleanup; } @@ -237,7 +241,8 @@ /* Need an operand of type ACPI_TYPE_BUFFER */ - if ((status = acpi_aml_resolve_to_value(stack_ptr)) != AE_OK) { + status = acpi_aml_resolve_to_value (stack_ptr, walk_state); + if (ACPI_FAILURE (status)) { goto cleanup; } @@ -252,7 +257,8 @@ /* Need an operand of type ACPI_TYPE_MUTEX */ - if ((status = acpi_aml_resolve_to_value(stack_ptr)) != AE_OK) { + status = acpi_aml_resolve_to_value (stack_ptr, walk_state); + if (ACPI_FAILURE (status)) { goto cleanup; } @@ -267,7 +273,8 @@ /* Need an operand of type ACPI_TYPE_EVENT */ - if ((status = acpi_aml_resolve_to_value(stack_ptr)) != AE_OK) { + status = acpi_aml_resolve_to_value (stack_ptr, walk_state); + if (ACPI_FAILURE (status)) { goto cleanup; } @@ -282,7 +289,8 @@ /* Need an operand of type ACPI_TYPE_REGION */ - if ((status = acpi_aml_resolve_to_value(stack_ptr)) != AE_OK) { + status = acpi_aml_resolve_to_value (stack_ptr, walk_state); + if (ACPI_FAILURE (status)) { goto cleanup; } @@ -308,7 +316,8 @@ /* Need an operand of type ACPI_TYPE_PACKAGE */ - if ((status = acpi_aml_resolve_to_value (stack_ptr)) != AE_OK) { + status = acpi_aml_resolve_to_value (stack_ptr, walk_state); + if (ACPI_FAILURE (status)) { goto cleanup; } @@ -337,7 +346,8 @@ /* All others must be resolved */ - if ((status = acpi_aml_resolve_to_value (stack_ptr)) != AE_OK) { + status = acpi_aml_resolve_to_value (stack_ptr, walk_state); + if (ACPI_FAILURE (status)) { goto cleanup; } @@ -352,15 +362,16 @@ * * The ACPI specification allows Size_of to return the size of * a Buffer, String or Package. However, the MS ACPI.SYS AML - * Interpreter also allows an NTE reference to return without + * Interpreter also allows an Node reference to return without * error with a size of 4. */ - if ((status = acpi_aml_resolve_to_value (stack_ptr)) != AE_OK) { + status = acpi_aml_resolve_to_value (stack_ptr, walk_state); + if (ACPI_FAILURE (status)) { goto cleanup; } - /* Need a buffer, string, package or NTE reference */ + /* Need a buffer, string, package or Node reference */ if (((*stack_ptr)->common.type != ACPI_TYPE_BUFFER) && ((*stack_ptr)->common.type != ACPI_TYPE_STRING) && @@ -372,10 +383,10 @@ } /* - * If this is a reference, only allow a reference to an NTE. + * If this is a reference, only allow a reference to an Node. */ if ((*stack_ptr)->common.type == INTERNAL_TYPE_REFERENCE) { - if (!(*stack_ptr)->reference.nte) { + if (!(*stack_ptr)->reference.node) { status = AE_AML_OPERAND_TYPE; goto cleanup; } @@ -386,7 +397,8 @@ case ARGI_COMPLEXOBJ: - if ((status = acpi_aml_resolve_to_value (stack_ptr)) != AE_OK) { + status = acpi_aml_resolve_to_value (stack_ptr, walk_state); + if (ACPI_FAILURE (status)) { goto cleanup; } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/interpreter/amstore.c linux/drivers/acpi/interpreter/amstore.c --- v2.4.0-test8/linux/drivers/acpi/interpreter/amstore.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/interpreter/amstore.c Fri Sep 15 14:30:30 2000 @@ -2,6 +2,7 @@ /****************************************************************************** * * Module Name: amstore - AML Interpreter object store support + * $Revision: 116 $ * *****************************************************************************/ @@ -25,16 +26,16 @@ #include "acpi.h" -#include "parser.h" -#include "dispatch.h" -#include "interp.h" +#include "acparser.h" +#include "acdispat.h" +#include "acinterp.h" #include "amlcode.h" -#include "namesp.h" -#include "tables.h" +#include "acnamesp.h" +#include "actables.h" #define _COMPONENT INTERPRETER - MODULE_NAME ("amstore"); + MODULE_NAME ("amstore") /******************************************************************************* @@ -43,7 +44,7 @@ * * PARAMETERS: *Val_desc - Value to be stored * *Dest_desc - Where to store it 0 Must be (ACPI_HANDLE) - * or an ACPI_OBJECT_INTERNAL of type + * or an ACPI_OPERAND_OBJECT of type * Reference; if the latter the descriptor * will be either reused or deleted. * @@ -58,13 +59,14 @@ ACPI_STATUS acpi_aml_exec_store ( - ACPI_OBJECT_INTERNAL *val_desc, - ACPI_OBJECT_INTERNAL *dest_desc) + ACPI_OPERAND_OBJECT *val_desc, + ACPI_OPERAND_OBJECT *dest_desc, + ACPI_WALK_STATE *walk_state) { ACPI_STATUS status = AE_OK; - ACPI_OBJECT_INTERNAL *delete_dest_desc = NULL; - ACPI_OBJECT_INTERNAL *tmp_desc; - ACPI_NAMED_OBJECT *entry = NULL; + ACPI_OPERAND_OBJECT *delete_dest_desc = NULL; + ACPI_OPERAND_OBJECT *tmp_desc; + ACPI_NAMESPACE_NODE *node = NULL; u8 value = 0; u32 length; u32 i; @@ -81,7 +83,7 @@ if (VALID_DESCRIPTOR_TYPE (dest_desc, ACPI_DESC_TYPE_NAMED)) { /* Dest is an ACPI_HANDLE, create a new object */ - entry = (ACPI_NAMED_OBJECT*) dest_desc; + node = (ACPI_NAMESPACE_NODE *) dest_desc; dest_desc = acpi_cm_create_internal_object (INTERNAL_TYPE_REFERENCE); if (!dest_desc) { /* Allocation failure */ @@ -92,7 +94,7 @@ /* Build a new Reference wrapper around the handle */ dest_desc->reference.op_code = AML_NAME_OP; - dest_desc->reference.object = entry; + dest_desc->reference.object = node; } @@ -115,7 +117,8 @@ * Storing into a Name */ delete_dest_desc = dest_desc; - status = acpi_aml_store_object_to_nte (val_desc, dest_desc->reference.object); + status = acpi_aml_store_object_to_node (val_desc, dest_desc->reference.object, + walk_state); break; /* Case Name_op */ @@ -182,7 +185,7 @@ */ if (ACPI_TYPE_PACKAGE == tmp_desc->common.type) { status = acpi_aml_build_copy_internal_package_object ( - val_desc, tmp_desc); + val_desc, tmp_desc, walk_state); if (ACPI_FAILURE (status)) { acpi_cm_remove_reference (tmp_desc); tmp_desc = NULL; @@ -206,7 +209,8 @@ * convert the contents of the source (Val_desc) and copy into * the destination (Tmp_desc) */ - status = acpi_aml_store_object_to_object(val_desc, tmp_desc); + status = acpi_aml_store_object_to_object (val_desc, tmp_desc, + walk_state); if (ACPI_FAILURE (status)) { /* * An error occurrered when copying the internal object @@ -299,7 +303,7 @@ /* * If we had an error, break out of this case statement. */ - if(AE_OK != status) { + if (ACPI_FAILURE (status)) { break; } @@ -315,7 +319,7 @@ case AML_ONES_OP: /* - * Storing to a constant is a no-op -- see spec sec 15.2.3.3.1. + * Storing to a constant is a no-op -- see ACPI Specification * Delete the result descriptor. */ @@ -326,7 +330,7 @@ case AML_LOCAL_OP: status = acpi_ds_method_data_set_value (MTH_TYPE_LOCAL, - (dest_desc->reference.offset), val_desc); + (dest_desc->reference.offset), val_desc, walk_state); delete_dest_desc = dest_desc; break; @@ -334,7 +338,7 @@ case AML_ARG_OP: status = acpi_ds_method_data_set_value (MTH_TYPE_ARG, - (dest_desc->reference.offset), val_desc); + (dest_desc->reference.offset), val_desc, walk_state); delete_dest_desc = dest_desc; break; @@ -343,7 +347,7 @@ /* * Storing to the Debug object causes the value stored to be - * displayed and otherwise has no effect -- see sec. 15.2.3.3.3. + * displayed and otherwise has no effect -- see ACPI Specification */ delete_dest_desc = dest_desc; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/interpreter/amstoren.c linux/drivers/acpi/interpreter/amstoren.c --- v2.4.0-test8/linux/drivers/acpi/interpreter/amstoren.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/interpreter/amstoren.c Fri Sep 15 14:30:30 2000 @@ -1,7 +1,9 @@ /****************************************************************************** * - * Module Name: amstoren - AML Interpreter object store support, store to NTE + * Module Name: amstoren - AML Interpreter object store support, + * Store to Node (namespace object) + * $Revision: 21 $ * *****************************************************************************/ @@ -25,24 +27,24 @@ #include "acpi.h" -#include "parser.h" -#include "dispatch.h" -#include "interp.h" +#include "acparser.h" +#include "acdispat.h" +#include "acinterp.h" #include "amlcode.h" -#include "namesp.h" -#include "tables.h" +#include "acnamesp.h" +#include "actables.h" #define _COMPONENT INTERPRETER - MODULE_NAME ("amstoren"); + MODULE_NAME ("amstoren") /******************************************************************************* * - * FUNCTION: Acpi_aml_store_object_to_nte + * FUNCTION: Acpi_aml_store_object_to_node * * PARAMETERS: *Val_desc - Value to be stored - * *Entry - Named object to recieve the value + * *Node - Named object to recieve the value * * RETURN: Status * @@ -65,9 +67,10 @@ ******************************************************************************/ ACPI_STATUS -acpi_aml_store_object_to_nte ( - ACPI_OBJECT_INTERNAL *val_desc, - ACPI_NAMED_OBJECT *entry) +acpi_aml_store_object_to_node ( + ACPI_OPERAND_OBJECT *val_desc, + ACPI_NAMESPACE_NODE *node, + ACPI_WALK_STATE *walk_state) { ACPI_STATUS status = AE_OK; u8 *buffer = NULL; @@ -76,16 +79,16 @@ u32 new_value; u8 locked = FALSE; u8 *location=NULL; - ACPI_OBJECT_INTERNAL *dest_desc; + ACPI_OPERAND_OBJECT *dest_desc; OBJECT_TYPE_INTERNAL destination_type = ACPI_TYPE_ANY; /* * Assuming the parameters are valid!!! */ - ACPI_ASSERT((entry) && (val_desc)); + ACPI_ASSERT((node) && (val_desc)); - destination_type = acpi_ns_get_type (entry); + destination_type = acpi_ns_get_type (node); /* * First ensure we have a value that can be stored in the target @@ -120,8 +123,8 @@ /* * Initially not a number, convert */ - status = acpi_aml_resolve_to_value (&val_desc); - if ((status == AE_OK) && + status = acpi_aml_resolve_to_value (&val_desc, walk_state); + if (ACPI_SUCCESS (status) && (val_desc->common.type != ACPI_TYPE_NUMBER)) { /* @@ -151,8 +154,8 @@ /* * Initially not a valid type, convert */ - status = acpi_aml_resolve_to_value (&val_desc); - if ((status == AE_OK) && + status = acpi_aml_resolve_to_value (&val_desc, walk_state); + if (ACPI_SUCCESS (status) && (val_desc->common.type != ACPI_TYPE_NUMBER) && (val_desc->common.type != ACPI_TYPE_BUFFER) && (val_desc->common.type != ACPI_TYPE_STRING)) @@ -184,7 +187,7 @@ * Val_desc reference count is incremented by Attach_object. */ - status = acpi_ns_attach_object (entry, val_desc, val_desc->common.type); + status = acpi_ns_attach_object (node, val_desc, val_desc->common.type); goto clean_up_and_bail_out; break; @@ -192,24 +195,24 @@ /* Exit now if failure above */ - if (status != AE_OK) { + if (ACPI_FAILURE (status)) { goto clean_up_and_bail_out; } /* - * Get descriptor for object attached to NTE + * Get descriptor for object attached to Node */ - dest_desc = acpi_ns_get_attached_object (entry); + dest_desc = acpi_ns_get_attached_object (node); if (!dest_desc) { /* - * There is no existing object attached to this NTE + * There is no existing object attached to this Node */ status = AE_AML_INTERNAL; goto clean_up_and_bail_out; } /* - * Make sure the destination Object is the same as the NTE + * Make sure the destination Object is the same as the Node */ if (dest_desc->common.type != (u8) destination_type) { status = AE_AML_INTERNAL; @@ -237,15 +240,17 @@ * Perform the update (Set Bank Select) */ - status = acpi_aml_set_named_field_value (dest_desc->bank_field.bank_select, - &dest_desc->bank_field.value, - sizeof (dest_desc->bank_field.value)); - if (status == AE_OK) { + status = acpi_aml_access_named_field (ACPI_WRITE, + dest_desc->bank_field.bank_select, + &dest_desc->bank_field.value, + sizeof (dest_desc->bank_field.value)); + if (ACPI_SUCCESS (status)) { /* Set bank select successful, set data value */ - status = acpi_aml_set_named_field_value (dest_desc->bank_field.bank_select, - &val_desc->bank_field.value, - sizeof (val_desc->bank_field.value)); + status = acpi_aml_access_named_field (ACPI_WRITE, + dest_desc->bank_field.bank_select, + &val_desc->bank_field.value, + sizeof (val_desc->bank_field.value)); } break; @@ -280,7 +285,9 @@ break; } - status = acpi_aml_set_named_field_value (entry, buffer, length); + status = acpi_aml_access_named_field (ACPI_WRITE, + node, buffer, length); + break; /* Global Lock released below */ @@ -405,16 +412,18 @@ * perform the update (Set index) */ - status = acpi_aml_set_named_field_value (dest_desc->index_field.index, - &dest_desc->index_field.value, - sizeof (dest_desc->index_field.value)); + status = acpi_aml_access_named_field (ACPI_WRITE, + dest_desc->index_field.index, + &dest_desc->index_field.value, + sizeof (dest_desc->index_field.value)); - if (AE_OK == status) { + if (ACPI_SUCCESS (status)) { /* set index successful, next set Data value */ - status = acpi_aml_set_named_field_value (dest_desc->index_field.data, - &val_desc->number.value, - sizeof (val_desc->number.value)); + status = acpi_aml_access_named_field (ACPI_WRITE, + dest_desc->index_field.data, + &val_desc->number.value, + sizeof (val_desc->number.value)); } break; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/interpreter/amstorob.c linux/drivers/acpi/interpreter/amstorob.c --- v2.4.0-test8/linux/drivers/acpi/interpreter/amstorob.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/interpreter/amstorob.c Fri Sep 15 14:30:30 2000 @@ -2,6 +2,7 @@ /****************************************************************************** * * Module Name: amstorob - AML Interpreter object store support, store to object + * $Revision: 16 $ * *****************************************************************************/ @@ -25,16 +26,16 @@ #include "acpi.h" -#include "parser.h" -#include "dispatch.h" -#include "interp.h" +#include "acparser.h" +#include "acdispat.h" +#include "acinterp.h" #include "amlcode.h" -#include "namesp.h" -#include "tables.h" +#include "acnamesp.h" +#include "actables.h" #define _COMPONENT INTERPRETER - MODULE_NAME ("amstorob"); + MODULE_NAME ("amstorob") /******************************************************************************* @@ -65,8 +66,9 @@ ACPI_STATUS acpi_aml_store_object_to_object ( - ACPI_OBJECT_INTERNAL *val_desc, - ACPI_OBJECT_INTERNAL *dest_desc) + ACPI_OPERAND_OBJECT *val_desc, + ACPI_OPERAND_OBJECT *dest_desc, + ACPI_WALK_STATE *walk_state) { ACPI_STATUS status = AE_OK; u8 *buffer = NULL; @@ -99,8 +101,8 @@ /* * Initially not a number, convert */ - status = acpi_aml_resolve_to_value (&val_desc); - if ((status == AE_OK) && + status = acpi_aml_resolve_to_value (&val_desc, walk_state); + if (ACPI_SUCCESS (status) && (val_desc->common.type != ACPI_TYPE_NUMBER)) { /* @@ -129,8 +131,8 @@ /* * Initially not a valid type, convert */ - status = acpi_aml_resolve_to_value (&val_desc); - if ((status == AE_OK) && + status = acpi_aml_resolve_to_value (&val_desc, walk_state); + if (ACPI_SUCCESS (status) && (val_desc->common.type != ACPI_TYPE_NUMBER) && (val_desc->common.type != ACPI_TYPE_BUFFER) && (val_desc->common.type != ACPI_TYPE_STRING)) @@ -155,7 +157,7 @@ /* Exit now if failure above */ - if (status != AE_OK) { + if (ACPI_FAILURE (status)) { goto clean_up_and_bail_out; } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/interpreter/amsystem.c linux/drivers/acpi/interpreter/amsystem.c --- v2.4.0-test8/linux/drivers/acpi/interpreter/amsystem.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/interpreter/amsystem.c Fri Sep 15 14:30:30 2000 @@ -2,6 +2,7 @@ /****************************************************************************** * * Module Name: amsystem - Interface to OS services + * $Revision: 51 $ * *****************************************************************************/ @@ -25,13 +26,13 @@ #include "acpi.h" -#include "interp.h" -#include "namesp.h" -#include "hardware.h" -#include "events.h" +#include "acinterp.h" +#include "acnamesp.h" +#include "achware.h" +#include "acevents.h" #define _COMPONENT INTERPRETER - MODULE_NAME ("amsystem"); + MODULE_NAME ("amsystem") /******************************************************************************* @@ -181,8 +182,8 @@ ACPI_STATUS acpi_aml_system_acquire_mutex ( - ACPI_OBJECT_INTERNAL *time_desc, - ACPI_OBJECT_INTERNAL *obj_desc) + ACPI_OPERAND_OBJECT *time_desc, + ACPI_OPERAND_OBJECT *obj_desc) { ACPI_STATUS status = AE_OK; @@ -223,7 +224,7 @@ ACPI_STATUS acpi_aml_system_release_mutex ( - ACPI_OBJECT_INTERNAL *obj_desc) + ACPI_OPERAND_OBJECT *obj_desc) { ACPI_STATUS status = AE_OK; @@ -260,7 +261,7 @@ ACPI_STATUS acpi_aml_system_signal_event ( - ACPI_OBJECT_INTERNAL *obj_desc) + ACPI_OPERAND_OBJECT *obj_desc) { ACPI_STATUS status = AE_OK; @@ -290,8 +291,8 @@ ACPI_STATUS acpi_aml_system_wait_event ( - ACPI_OBJECT_INTERNAL *time_desc, - ACPI_OBJECT_INTERNAL *obj_desc) + ACPI_OPERAND_OBJECT *time_desc, + ACPI_OPERAND_OBJECT *obj_desc) { ACPI_STATUS status = AE_OK; @@ -321,7 +322,7 @@ ACPI_STATUS acpi_aml_system_reset_event ( - ACPI_OBJECT_INTERNAL *obj_desc) + ACPI_OPERAND_OBJECT *obj_desc) { ACPI_STATUS status = AE_OK; void *temp_semaphore; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/interpreter/amutils.c linux/drivers/acpi/interpreter/amutils.c --- v2.4.0-test8/linux/drivers/acpi/interpreter/amutils.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/interpreter/amutils.c Fri Sep 15 14:30:30 2000 @@ -2,6 +2,7 @@ /****************************************************************************** * * Module Name: amutils - interpreter/scanner utilities + * $Revision: 53 $ * *****************************************************************************/ @@ -25,21 +26,21 @@ #include "acpi.h" -#include "parser.h" -#include "interp.h" +#include "acparser.h" +#include "acinterp.h" #include "amlcode.h" -#include "namesp.h" -#include "events.h" +#include "acnamesp.h" +#include "acevents.h" #define _COMPONENT INTERPRETER - MODULE_NAME ("amutils"); + MODULE_NAME ("amutils") typedef struct internal_search_st { - ACPI_OBJECT_INTERNAL *dest_obj; + ACPI_OPERAND_OBJECT *dest_obj; u32 index; - ACPI_OBJECT_INTERNAL *source_obj; + ACPI_OPERAND_OBJECT *source_obj; } INTERNAL_PKG_SEARCH_INFO; @@ -49,7 +50,7 @@ INTERNAL_PKG_SEARCH_INFO copy_level[MAX_PACKAGE_DEPTH]; -static char hex[] = +static NATIVE_CHAR hex[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; @@ -121,41 +122,10 @@ if ((type > ACPI_TYPE_MAX && type < INTERNAL_TYPE_BEGIN) || (type > INTERNAL_TYPE_MAX)) { - return FALSE; + return (FALSE); } - return TRUE; -} - - -/******************************************************************************* - * - * FUNCTION: Acpi_aml_append_operand_diag - * - * PARAMETERS: *File_name - Name of source file - * Line_num - Line Number in file - * Op_code - Op_code being executed - * Num_operands - Number of operands Prep_stack tried to check - * - * DESCRIPTION: Print diagnostic information about operands. - * This function is intended to be called after Prep_stack - * has returned S_ERROR. - * - ******************************************************************************/ - -void -acpi_aml_append_operand_diag ( - char *file_name, - s32 line_num, - u16 op_code, - ACPI_OBJECT_INTERNAL **operands, - s32 num_operands) -{ - - /* - * This function outputs debug information only - */ - + return (TRUE); } @@ -178,7 +148,7 @@ acpi_aml_buf_seq (void) { - return ++acpi_gbl_buf_seq; + return (++acpi_gbl_buf_seq); } @@ -270,12 +240,12 @@ * ******************************************************************************/ -s32 +u32 acpi_aml_digits_needed ( - s32 val, - s32 base) + u32 val, + u32 base) { - s32 num_digits = 0; + u32 num_digits = 0; if (base < 1) { @@ -309,13 +279,13 @@ union { u32 value; - char bytes[4]; + u8 bytes[4]; } out; union { u32 value; - char bytes[4]; + u8 bytes[4]; } in; @@ -326,7 +296,7 @@ out.bytes[2] = in.bytes[1]; out.bytes[3] = in.bytes[0]; - return out.value; + return (out.value); } @@ -344,7 +314,7 @@ ACPI_STATUS acpi_aml_eisa_id_to_string ( u32 numeric_id, - char *out_string) + NATIVE_CHAR *out_string) { u32 id; @@ -361,7 +331,7 @@ out_string[6] = hex[id & 0xf]; out_string[7] = 0; - return AE_OK; + return (AE_OK); } @@ -381,16 +351,17 @@ ACPI_STATUS acpi_aml_build_copy_internal_package_object ( - ACPI_OBJECT_INTERNAL *source_obj, - ACPI_OBJECT_INTERNAL *dest_obj) + ACPI_OPERAND_OBJECT *source_obj, + ACPI_OPERAND_OBJECT *dest_obj, + ACPI_WALK_STATE *walk_state) { u32 current_depth = 0; ACPI_STATUS status = AE_OK; u32 length = 0; u32 this_index; u32 object_space = 0; - ACPI_OBJECT_INTERNAL *this_dest_obj; - ACPI_OBJECT_INTERNAL *this_source_obj; + ACPI_OPERAND_OBJECT *this_dest_obj; + ACPI_OPERAND_OBJECT *this_source_obj; INTERNAL_PKG_SEARCH_INFO *level_ptr; @@ -429,8 +400,8 @@ while (1) { this_index = level_ptr->index; - this_dest_obj = (ACPI_OBJECT_INTERNAL *) level_ptr->dest_obj->package.elements[this_index]; - this_source_obj = (ACPI_OBJECT_INTERNAL *) level_ptr->source_obj->package.elements[this_index]; + this_dest_obj = (ACPI_OPERAND_OBJECT *) level_ptr->dest_obj->package.elements[this_index]; + this_source_obj = (ACPI_OPERAND_OBJECT *) level_ptr->source_obj->package.elements[this_index]; if (IS_THIS_OBJECT_TYPE (this_source_obj, ACPI_TYPE_PACKAGE)) { /* @@ -458,7 +429,7 @@ * update the buffer length counter */ object_space = this_dest_obj->package.count * - sizeof (ACPI_OBJECT_INTERNAL); + sizeof (ACPI_OPERAND_OBJECT); length += object_space; current_depth++; level_ptr = ©_level[current_depth]; @@ -474,9 +445,9 @@ this_source_obj->common.type); level_ptr->dest_obj->package.elements[this_index] = this_dest_obj; - status = acpi_aml_store_object_to_object(this_source_obj, this_dest_obj); + status = acpi_aml_store_object_to_object(this_source_obj, this_dest_obj, walk_state); - if (status != AE_OK) { + if (ACPI_FAILURE (status)) { /* * Failure get out */ @@ -511,12 +482,6 @@ } } /* else object is NOT a package */ } /* while (1) */ - - - /* - * We'll never get here, but the compiler whines about return value - */ - return (AE_OK); } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/interpreter/amxface.c linux/drivers/acpi/interpreter/amxface.c --- v2.4.0-test8/linux/drivers/acpi/interpreter/amxface.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/interpreter/amxface.c Fri Sep 15 14:30:30 2000 @@ -1,7 +1,8 @@ /****************************************************************************** * - * Module Name: ixface - External interpreter interfaces + * Module Name: amxface - External interpreter interfaces + * $Revision: 22 $ * *****************************************************************************/ @@ -25,11 +26,11 @@ #include "acpi.h" -#include "interp.h" +#include "acinterp.h" #define _COMPONENT INTERPRETER - MODULE_NAME ("amxface"); + MODULE_NAME ("amxface") /* @@ -48,8 +49,8 @@ #define DEFINE_AML_GLOBALS #include "amlcode.h" -#include "parser.h" -#include "namesp.h" +#include "acparser.h" +#include "acnamesp.h" /******************************************************************************* @@ -70,9 +71,9 @@ ACPI_STATUS acpi_aml_execute_method ( - ACPI_NAMED_OBJECT *method_entry, - ACPI_OBJECT_INTERNAL **params, - ACPI_OBJECT_INTERNAL **return_obj_desc) + ACPI_NAMESPACE_NODE *method_node, + ACPI_OPERAND_OBJECT **params, + ACPI_OPERAND_OBJECT **return_obj_desc) { ACPI_STATUS status; @@ -84,7 +85,7 @@ acpi_aml_enter_interpreter (); - status = acpi_psx_execute (method_entry, params, return_obj_desc); + status = acpi_psx_execute (method_node, params, return_obj_desc); acpi_aml_exit_interpreter (); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/namespace/Makefile linux/drivers/acpi/namespace/Makefile --- v2.4.0-test8/linux/drivers/acpi/namespace/Makefile Wed Dec 31 16:00:00 1969 +++ linux/drivers/acpi/namespace/Makefile Fri Sep 15 18:21:44 2000 @@ -0,0 +1,28 @@ +# +# Makefile for all Linux ACPI interpreter subdirectories +# + +SUB_DIRS := +MOD_SUB_DIRS := $(SUB_DIRS) +MOD_IN_SUB_DIRS := +ALL_SUB_DIRS := $(SUB_DIRS) + +O_TARGET := ../$(shell basename `pwd`).o +O_OBJS := +M_OBJS := + +ACPI_OBJS := $(patsubst %.c,%.o,$(wildcard *.c)) + +EXTRA_CFLAGS += -I../include + +EXTRA_CFLAGS += $(ACPI_CFLAGS) + +# if the interpreter is used, it overrides arch/i386/kernel/acpi.c +ifeq ($(CONFIG_ACPI_INTERPRETER),y) + O_OBJS := $(ACPI_OBJS) +endif + +include $(TOPDIR)/Rules.make + +clean: + $(RM) *.o diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/namespace/nsaccess.c linux/drivers/acpi/namespace/nsaccess.c --- v2.4.0-test8/linux/drivers/acpi/namespace/nsaccess.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/namespace/nsaccess.c Fri Sep 15 14:30:30 2000 @@ -1,9 +1,9 @@ - -/****************************************************************************** +/******************************************************************************* * * Module Name: nsaccess - Top-level functions for accessing ACPI namespace + * $Revision: 108 $ * - *****************************************************************************/ + ******************************************************************************/ /* * Copyright (C) 2000 R. Byron Moore @@ -26,59 +26,16 @@ #include "acpi.h" #include "amlcode.h" -#include "interp.h" -#include "namesp.h" -#include "dispatch.h" +#include "acinterp.h" +#include "acnamesp.h" +#include "acdispat.h" #define _COMPONENT NAMESPACE - MODULE_NAME ("nsaccess"); + MODULE_NAME ("nsaccess") -/**************************************************************************** - * - * FUNCTION: Acpi_ns_root_create_scope - * - * PARAMETERS: Entry - NTE for which a scope will be created - * - * RETURN: Status - * - * DESCRIPTION: Create a scope table for the given name table entry - * - * MUTEX: Expects namespace to be locked - * - ***************************************************************************/ - -ACPI_STATUS -acpi_ns_root_create_scope ( - ACPI_NAMED_OBJECT *entry) -{ - - /* Allocate a scope table */ - - if (entry->child_table) { - return (AE_EXIST); - } - - entry->child_table = acpi_ns_allocate_name_table (NS_TABLE_SIZE); - if (!entry->child_table) { - /* root name table allocation failure */ - - REPORT_ERROR ("Root name table allocation failure"); - return (AE_NO_MEMORY); - } - - /* - * Init the scope first entry -- since it is the exemplar of - * the scope (Some fields are duplicated to new entries!) - */ - acpi_ns_initialize_table (entry->child_table, NULL, entry); - return (AE_OK); - -} - - -/**************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_ns_root_initialize * @@ -86,40 +43,41 @@ * * RETURN: Status * - * DESCRIPTION: Allocate and initialize the root name table + * DESCRIPTION: Allocate and initialize the default root named objects * * MUTEX: Locks namespace for entire execution * - ***************************************************************************/ + ******************************************************************************/ ACPI_STATUS acpi_ns_root_initialize (void) { ACPI_STATUS status = AE_OK; PREDEFINED_NAMES *init_val = NULL; - ACPI_NAMED_OBJECT *new_entry; - ACPI_OBJECT_INTERNAL *obj_desc; + ACPI_NAMESPACE_NODE *new_node; + ACPI_OPERAND_OBJECT *obj_desc; acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE); /* - * Root is initially NULL, so a non-NULL value indicates + * The global root ptr is initially NULL, so a non-NULL value indicates * that Acpi_ns_root_initialize() has already been called; just return. */ - if (acpi_gbl_root_object->child_table) { + if (acpi_gbl_root_node) { status = AE_OK; goto unlock_and_exit; } - /* Create the root scope */ + /* + * Tell the rest of the subsystem that the root is initialized + * (This is OK because the namespace is locked) + */ + + acpi_gbl_root_node = &acpi_gbl_root_node_struct; - status = acpi_ns_root_create_scope (acpi_gbl_root_object); - if (ACPI_FAILURE (status)) { - goto unlock_and_exit; - } /* Enter the pre-defined names in the name table */ @@ -127,25 +85,25 @@ status = acpi_ns_lookup (NULL, init_val->name, (OBJECT_TYPE_INTERNAL) init_val->type, IMODE_LOAD_PASS2, NS_NO_UPSEARCH, - NULL, &new_entry); + NULL, &new_node); + + if (ACPI_FAILURE (status) || + (!new_node)) /* - * if name entered successfully - * && its entry in Pre_defined_names[] specifies an - * initial value + * Name entered successfully. + * If entry in Pre_defined_names[] specifies an + * initial value, create the initial value. */ - if ((status == AE_OK) && - new_entry && init_val->val) - { + if (init_val->val) { /* * Entry requests an initial value, allocate a * descriptor for it. */ - obj_desc = - acpi_cm_create_internal_object ( - (OBJECT_TYPE_INTERNAL) init_val->type); + obj_desc = acpi_cm_create_internal_object ( + (OBJECT_TYPE_INTERNAL) init_val->type); if (!obj_desc) { status = AE_NO_MEMORY; @@ -164,23 +122,22 @@ case ACPI_TYPE_NUMBER: obj_desc->number.value = - (u32) STRTOUL (init_val->val, NULL, 10); + (u32) STRTOUL (init_val->val, NULL, 10); break; case ACPI_TYPE_STRING: obj_desc->string.length = - (u16) STRLEN (init_val->val); + (u16) STRLEN (init_val->val); /* * Allocate a buffer for the string. All * String.Pointers must be allocated buffers! * (makes deletion simpler) */ - obj_desc->string.pointer = - acpi_cm_allocate ((ACPI_SIZE) - (obj_desc->string.length + 1)); + obj_desc->string.pointer = acpi_cm_allocate ( + (obj_desc->string.length + 1)); if (!obj_desc->string.pointer) { REPORT_ERROR ("Initial value string" @@ -191,24 +148,22 @@ goto unlock_and_exit; } - STRCPY ((char *) obj_desc->string.pointer, - init_val->val); + STRCPY (obj_desc->string.pointer, init_val->val); break; case ACPI_TYPE_MUTEX: obj_desc->mutex.sync_level = - (u16) STRTOUL (init_val->val, NULL, 10); + (u16) STRTOUL (init_val->val, NULL, 10); if (STRCMP (init_val->name, "_GL_") == 0) { /* * Create a counting semaphore for the * global lock */ - status = - acpi_os_create_semaphore (ACPI_NO_UNIT_LIMIT, - 1, &obj_desc->mutex.semaphore); + status = acpi_os_create_semaphore (ACPI_NO_UNIT_LIMIT, + 1, &obj_desc->mutex.semaphore); if (ACPI_FAILURE (status)) { goto unlock_and_exit; @@ -218,8 +173,7 @@ * global lock, save it */ - acpi_gbl_global_lock_semaphore = - obj_desc->mutex.semaphore; + acpi_gbl_global_lock_semaphore = obj_desc->mutex.semaphore; } else { @@ -232,11 +186,6 @@ goto unlock_and_exit; } } - - /* TBD: [Restructure] These fields may be obsolete */ - - obj_desc->mutex.lock_count = 0; - obj_desc->mutex.thread_id = 0; break; @@ -247,9 +196,9 @@ continue; } - /* Store pointer to value descriptor in nte */ + /* Store pointer to value descriptor in the Node */ - acpi_ns_attach_object (new_entry, obj_desc, + acpi_ns_attach_object (new_node, obj_desc, obj_desc->common.type); } } @@ -261,16 +210,19 @@ } -/**************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_ns_lookup * - * PARAMETERS: Prefix_scope - Search scope if name is not fully qualified + * PARAMETERS: Prefix_node - Search scope if name is not fully qualified * Pathname - Search pathname, in internal format * (as represented in the AML stream) * Type - Type associated with name * Interpreter_mode - IMODE_LOAD_PASS2 => add name if not found - * Ret_entry - Where the new entry (NTE) is placed + * Flags - Flags describing the search restrictions + * Walk_state - Current state of the walk + * Return_node - Where the Node is placed (if found + * or created successfully) * * RETURN: Status * @@ -279,55 +231,42 @@ * * MUTEX: Assumes namespace is locked. * - ***************************************************************************/ + ******************************************************************************/ ACPI_STATUS acpi_ns_lookup ( ACPI_GENERIC_STATE *scope_info, - char *pathname, + NATIVE_CHAR *pathname, OBJECT_TYPE_INTERNAL type, OPERATING_MODE interpreter_mode, u32 flags, ACPI_WALK_STATE *walk_state, - ACPI_NAMED_OBJECT **ret_entry) + ACPI_NAMESPACE_NODE **return_node) { ACPI_STATUS status; - ACPI_NAME_TABLE *prefix_scope; - ACPI_NAME_TABLE *table_to_search = NULL; - ACPI_NAME_TABLE *scope_to_push = NULL; - ACPI_NAMED_OBJECT *this_entry = NULL; + ACPI_NAMESPACE_NODE *prefix_node; + ACPI_NAMESPACE_NODE *current_node = NULL; + ACPI_NAMESPACE_NODE *scope_to_push = NULL; + ACPI_NAMESPACE_NODE *this_node = NULL; u32 num_segments; ACPI_NAME simple_name; u8 null_name_path = FALSE; OBJECT_TYPE_INTERNAL type_to_check_for; OBJECT_TYPE_INTERNAL this_search_type; - if (!ret_entry) { + if (!return_node) { return (AE_BAD_PARAMETER); } acpi_gbl_ns_lookup_count++; - *ret_entry = ENTRY_NOT_FOUND; - if (!acpi_gbl_root_object->child_table) { - /* - * If the name space has not been initialized: - * - In Pass1 of Load mode, we need to initialize it - * before trying to define a name. - * - In Exec mode, there are no names to be found. - */ + *return_node = ENTRY_NOT_FOUND; - if (IMODE_LOAD_PASS1 == interpreter_mode) { - if ((status = acpi_ns_root_initialize ()) != AE_OK) { - return (status); - } - } - else { - return (AE_NOT_FOUND); - } - } + if (!acpi_gbl_root_node) { + return (AE_NO_NAMESPACE); + } /* * Get the prefix scope. @@ -335,12 +274,12 @@ */ if ((!scope_info) || - (!scope_info->scope.name_table)) + (!scope_info->scope.node)) { - prefix_scope = acpi_gbl_root_object->child_table; + prefix_node = acpi_gbl_root_node; } else { - prefix_scope = scope_info->scope.name_table; + prefix_node = scope_info->scope.node; } @@ -369,6 +308,8 @@ } + /* TBD: [Restructure] - Move the pathname stuff into a new procedure */ + /* Examine the name pointer */ if (!pathname) { @@ -376,7 +317,7 @@ null_name_path = TRUE; num_segments = 0; - this_entry = acpi_gbl_root_object; + this_node = acpi_gbl_root_node; } @@ -403,14 +344,16 @@ if (*pathname == AML_ROOT_PREFIX) { /* Pathname is fully qualified, look in root name table */ - table_to_search = acpi_gbl_root_object->child_table; + current_node = acpi_gbl_root_node; + /* point to segment part */ + pathname++; /* Direct reference to root, "\" */ if (!(*pathname)) { - this_entry = acpi_gbl_root_object; + this_node = acpi_gbl_root_node; goto check_for_new_scope_and_exit; } } @@ -418,7 +361,7 @@ else { /* Pathname is relative to current scope, start there */ - table_to_search = prefix_scope; + current_node = prefix_node; /* * Handle up-prefix (carat). More than one prefix @@ -426,23 +369,22 @@ */ while (*pathname == AML_PARENT_PREFIX) { - /* Point to segment part or next Parent_prefix */ pathname++; /* Backup to the parent's scope */ - table_to_search = table_to_search->parent_table; - if (!table_to_search) { + this_node = acpi_ns_get_parent_object (current_node); + if (!this_node) { /* Current scope has no parent scope */ - REPORT_ERROR ("Ns_lookup: Too many parent" - "prefixes or scope has no parent"); - + REPORT_ERROR ("Too many parent prefixes (^) - reached root"); return (AE_NOT_FOUND); } + + current_node = this_node; } } @@ -454,14 +396,18 @@ if (*pathname == AML_DUAL_NAME_PREFIX) { num_segments = 2; + /* point to first segment */ + pathname++; } else if (*pathname == AML_MULTI_NAME_PREFIX_OP) { - num_segments = (s32)* (u8 *) ++pathname; + num_segments = (u32)* (u8 *) ++pathname; + /* point to first segment */ + pathname++; } @@ -484,32 +430,32 @@ */ - while (num_segments-- && table_to_search) { + while (num_segments-- && current_node) { /* - * Search for the current segment in the table where - * it should be. - * Type is significant only at the last (topmost) level. + * Search for the current name segment under the current + * named object. The Type is significant only at the last (topmost) + * level. (We don't care about the types along the path, only + * the type of the final target object.) */ this_search_type = ACPI_TYPE_ANY; if (!num_segments) { this_search_type = type; } + /* Pluck and ACPI name from the front of the pathname */ + MOVE_UNALIGNED32_TO_32 (&simple_name, pathname); + + /* Try to find the ACPI name */ + status = acpi_ns_search_and_enter (simple_name, walk_state, - table_to_search, interpreter_mode, + current_node, interpreter_mode, this_search_type, flags, - &this_entry); + &this_node); - if (status != AE_OK) { + if (ACPI_FAILURE (status)) { if (status == AE_NOT_FOUND) { - /* Name not in ACPI namespace */ - - if (IMODE_LOAD_PASS1 == interpreter_mode || - IMODE_LOAD_PASS2 == interpreter_mode) - { - REPORT_ERROR ("Name table overflow"); - } + /* Name not found in ACPI namespace */ } @@ -518,92 +464,54 @@ /* - * If 1) last segment (Num_segments == 0) + * If 1) This is the last segment (Num_segments == 0) * 2) and looking for a specific type * (Not checking for TYPE_ANY) * 3) which is not a local type (TYPE_DEF_ANY) * 4) which is not a local type (TYPE_SCOPE) * 5) which is not a local type (TYPE_INDEX_FIELD_DEFN) - * 6) and type of entry is known (not TYPE_ANY) - * 7) and entry does not match request + * 6) and type of object is known (not TYPE_ANY) + * 7) and object does not match request * * Then we have a type mismatch. Just warn and ignore it. */ - if ((num_segments == 0) && - (type_to_check_for != ACPI_TYPE_ANY) && - (type_to_check_for != INTERNAL_TYPE_DEF_ANY) && - (type_to_check_for != INTERNAL_TYPE_SCOPE) && - (type_to_check_for != INTERNAL_TYPE_INDEX_FIELD_DEFN) && - (this_entry->type != ACPI_TYPE_ANY) && - (this_entry->type != type_to_check_for)) + if ((num_segments == 0) && + (type_to_check_for != ACPI_TYPE_ANY) && + (type_to_check_for != INTERNAL_TYPE_DEF_ANY) && + (type_to_check_for != INTERNAL_TYPE_SCOPE) && + (type_to_check_for != INTERNAL_TYPE_INDEX_FIELD_DEFN) && + (this_node->type != ACPI_TYPE_ANY) && + (this_node->type != type_to_check_for)) { - /* Complain about type mismatch */ + /* Complain about a type mismatch */ REPORT_WARNING ("Type mismatch"); } /* - * If last segment and not looking for a specific type, but type of - * found entry is known, use that type to see if it opens a scope. + * If this is the last name segment and we are not looking for a + * specific type, but the type of found object is known, use that type + * to see if it opens a scope. */ if ((0 == num_segments) && (ACPI_TYPE_ANY == type)) { - type = this_entry->type; + type = this_node->type; } if ((num_segments || acpi_ns_opens_scope (type)) && - (this_entry->child_table == NULL)) + (this_node->child == NULL)) { /* * More segments or the type implies enclosed scope, * and the next scope has not been allocated. */ - if ((IMODE_LOAD_PASS1 == interpreter_mode) || - (IMODE_LOAD_PASS2 == interpreter_mode)) - { - /* - * First or second pass load mode - * ==> locate the next scope - */ - - this_entry->child_table = - acpi_ns_allocate_name_table (NS_TABLE_SIZE); - - if (!this_entry->child_table) { - return (AE_NO_MEMORY); - } - } - - /* Now complain if there is no next scope */ - - if (this_entry->child_table == NULL) { - if (IMODE_LOAD_PASS1 == interpreter_mode || - IMODE_LOAD_PASS2 == interpreter_mode) - { - REPORT_ERROR ("Name Table allocation failure"); - return (AE_NOT_FOUND); - } - - return (AE_NOT_FOUND); - } - - - /* Scope table initialization */ - - if (IMODE_LOAD_PASS1 == interpreter_mode || - IMODE_LOAD_PASS2 == interpreter_mode) - { - /* Initialize the new table */ - - acpi_ns_initialize_table (this_entry->child_table, - table_to_search, - this_entry); - } } - table_to_search = this_entry->child_table; + current_node = this_node; + /* point to next name segment */ + pathname += ACPI_NAME_SIZE; } @@ -629,7 +537,7 @@ scope_to_push = NULL; } else { - scope_to_push = this_entry->child_table; + scope_to_push = this_node; } status = acpi_ds_scope_stack_push (scope_to_push, type, @@ -641,7 +549,7 @@ } } - *ret_entry = this_entry; + *return_node = this_node; return (AE_OK); } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/namespace/nsalloc.c linux/drivers/acpi/namespace/nsalloc.c --- v2.4.0-test8/linux/drivers/acpi/namespace/nsalloc.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/namespace/nsalloc.c Fri Sep 15 14:30:30 2000 @@ -1,9 +1,9 @@ - -/****************************************************************************** +/******************************************************************************* * * Module Name: nsalloc - Namespace allocation and deletion utilities + * $Revision: 41 $ * - *****************************************************************************/ + ******************************************************************************/ /* * Copyright (C) 2000 R. Byron Moore @@ -25,46 +25,303 @@ #include "acpi.h" -#include "namesp.h" -#include "interp.h" +#include "acnamesp.h" +#include "acinterp.h" #define _COMPONENT NAMESPACE - MODULE_NAME ("nsalloc"); + MODULE_NAME ("nsalloc") + + +/******************************************************************************* + * + * FUNCTION: Acpi_ns_create_node + * + * PARAMETERS: + * + * RETURN: None + * + * DESCRIPTION: + * + ******************************************************************************/ + +ACPI_NAMESPACE_NODE * +acpi_ns_create_node ( + u32 acpi_name) +{ + ACPI_NAMESPACE_NODE *node; + + + node = acpi_cm_callocate (sizeof (ACPI_NAMESPACE_NODE)); + if (!node) { + return (NULL); + } + + INCREMENT_NAME_TABLE_METRICS (sizeof (ACPI_NAMESPACE_NODE)); + + node->data_type = ACPI_DESC_TYPE_NAMED; + node->name = acpi_name; + node->reference_count = 1; + + return (node); +} + + +/******************************************************************************* + * + * FUNCTION: Acpi_ns_delete_node + * + * PARAMETERS: + * + * RETURN: None + * + * DESCRIPTION: + * + ******************************************************************************/ + +void +acpi_ns_delete_node ( + ACPI_NAMESPACE_NODE *node) +{ + ACPI_NAMESPACE_NODE *parent_node; + ACPI_NAMESPACE_NODE *prev_node; + ACPI_NAMESPACE_NODE *next_node; + + + parent_node = acpi_ns_get_parent_object (node); + + prev_node = NULL; + next_node = parent_node->child; + + while (next_node != node) { + prev_node = next_node; + next_node = prev_node->peer; + } + + if (prev_node) { + prev_node->peer = next_node->peer; + if (next_node->flags & ANOBJ_END_OF_PEER_LIST) { + prev_node->flags |= ANOBJ_END_OF_PEER_LIST; + } + } + else { + parent_node->child = next_node->peer; + } + + + DECREMENT_NAME_TABLE_METRICS (sizeof (ACPI_NAMESPACE_NODE)); + + /* + * Detach an object if there is one + */ + + if (node->object) { + acpi_ns_detach_object (node); + } + + acpi_cm_free (node); + + + return; +} + + +/******************************************************************************* + * + * FUNCTION: Acpi_ns_install_node + * + * PARAMETERS: Walk_state - Current state of the walk + * Parent_node - The parent of the new Node + * Node - The new Node to install + * Type - ACPI object type of the new Node + * + * RETURN: None + * + * DESCRIPTION: Initialize a new entry within a namespace table. + * + ******************************************************************************/ + +void +acpi_ns_install_node ( + ACPI_WALK_STATE *walk_state, + ACPI_NAMESPACE_NODE *parent_node, /* Parent */ + ACPI_NAMESPACE_NODE *node, /* New Child*/ + OBJECT_TYPE_INTERNAL type) +{ + u16 owner_id = TABLE_ID_DSDT; + ACPI_NAMESPACE_NODE *child_node; + + + /* + * Get the owner ID from the Walk state + * The owner ID is used to track table deletion and + * deletion of objects created by methods + */ + if (walk_state) { + owner_id = walk_state->owner_id; + } + + + /* link the new entry into the parent and existing children */ + + /* TBD: Could be first, last, or alphabetic */ + + child_node = parent_node->child; + if (!child_node) { + parent_node->child = node; + } + + else { + while (!(child_node->flags & ANOBJ_END_OF_PEER_LIST)) { + child_node = child_node->peer; + } + + child_node->peer = node; + + /* Clear end-of-list flag */ + + child_node->flags &= ~ANOBJ_END_OF_PEER_LIST; + } + + /* Init the new entry */ + + node->owner_id = owner_id; + node->flags |= ANOBJ_END_OF_PEER_LIST; + node->peer = parent_node; + + + /* + * If adding a name with unknown type, or having to + * add the region in order to define fields in it, we + * have a forward reference. + */ + + if ((ACPI_TYPE_ANY == type) || + (INTERNAL_TYPE_DEF_FIELD_DEFN == type) || + (INTERNAL_TYPE_BANK_FIELD_DEFN == type)) + { + /* + * We don't want to abort here, however! + * We will fill in the actual type when the + * real definition is found later. + */ + + } + + /* + * The Def_field_defn and Bank_field_defn cases are actually + * looking up the Region in which the field will be defined + */ + + if ((INTERNAL_TYPE_DEF_FIELD_DEFN == type) || + (INTERNAL_TYPE_BANK_FIELD_DEFN == type)) + { + type = ACPI_TYPE_REGION; + } + + /* + * Scope, Def_any, and Index_field_defn are bogus "types" which do + * not actually have anything to do with the type of the name + * being looked up. Save any other value of Type as the type of + * the entry. + */ + + if ((type != INTERNAL_TYPE_SCOPE) && + (type != INTERNAL_TYPE_DEF_ANY) && + (type != INTERNAL_TYPE_INDEX_FIELD_DEFN)) + { + node->type = (u8) type; + } + + /* + * Increment the reference count(s) of all parents up to + * the root! + */ + + while ((node = acpi_ns_get_parent_object (node)) != NULL) { + node->reference_count++; + } + + return; +} -/**************************************************************************** +/******************************************************************************* * - * FUNCTION: Acpi_ns_allocate_name_table + * FUNCTION: Acpi_ns_delete_children * - * PARAMETERS: Nte_count - Count of NTEs to allocate + * PARAMETERS: Parent_node - Delete this objects children * - * RETURN: The address of the first nte in the array, or NULL + * RETURN: None. * - * DESCRIPTION: Allocate an array of nte, including prepended link space - * Array is set to all zeros via Acpi_os_callcate(). + * DESCRIPTION: Delete all children of the parent object. Deletes a + * "scope". * - ***************************************************************************/ + ******************************************************************************/ -ACPI_NAME_TABLE * -acpi_ns_allocate_name_table ( - u32 num_entries) +void +acpi_ns_delete_children ( + ACPI_NAMESPACE_NODE *parent_node) { - ACPI_NAME_TABLE *name_table = NULL; - ACPI_SIZE alloc_size; + ACPI_NAMESPACE_NODE *child_node; + ACPI_NAMESPACE_NODE *next_node; + u8 flags; + + + if (!parent_node) { + return; + } + + /* If no children, all done! */ + + child_node = parent_node->child; + if (!child_node) { + return; + } + + /* + * Deallocate all children at this level + */ + do + { + /* Get the things we need */ + + next_node = child_node->peer; + flags = child_node->flags; + + /* Grandchildren should have all been deleted already */ + + /* Now we can free this child object */ - alloc_size = sizeof (ACPI_NAME_TABLE) + ((num_entries - 1) * - sizeof (ACPI_NAMED_OBJECT)); + DECREMENT_NAME_TABLE_METRICS (sizeof (ACPI_NAMESPACE_NODE)); - name_table = acpi_cm_callocate (alloc_size); + /* + * Detach an object if there is one + */ + + if (child_node->object) { + acpi_ns_detach_object (child_node); + } + + acpi_cm_free (child_node); + + /* And move on to the next child in the list */ + + child_node = next_node; + } while (!(flags & ANOBJ_END_OF_PEER_LIST)); - return (name_table); + + /* Clear the parent's child pointer */ + + parent_node->child = NULL; + + return; } -/**************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_ns_delete_namespace_subtree * @@ -72,22 +329,27 @@ * * RETURN: None. * - * DESCRIPTION: Delete a subtree of the namespace. This includes all objects stored - * within the subtree. Scope tables are deleted also + * DESCRIPTION: Delete a subtree of the namespace. This includes all objects + * stored within the subtree. Scope tables are deleted also * - ***************************************************************************/ + ******************************************************************************/ ACPI_STATUS acpi_ns_delete_namespace_subtree ( - ACPI_NAMED_OBJECT *parent_entry) + ACPI_NAMESPACE_NODE *parent_node) { - ACPI_NAMED_OBJECT *child_entry; + ACPI_NAMESPACE_NODE *child_node; + ACPI_OPERAND_OBJECT *obj_desc; u32 level; - ACPI_OBJECT_INTERNAL *obj_desc; - child_entry = 0; - level = 1; + if (!parent_node) { + return (AE_OK); + } + + + child_node = 0; + level = 1; /* * Traverse the tree of objects until we bubble back up @@ -100,53 +362,32 @@ * Null returned if not found */ - child_entry = acpi_ns_get_next_object (ACPI_TYPE_ANY, - parent_entry, - child_entry); - - if (child_entry) { + child_node = acpi_ns_get_next_object (ACPI_TYPE_ANY, parent_node, + child_node); + if (child_node) { /* * Found an object - delete the object within * the Value field */ - obj_desc = acpi_ns_get_attached_object (child_entry); + obj_desc = acpi_ns_get_attached_object (child_node); if (obj_desc) { - acpi_ns_detach_object (child_entry); + acpi_ns_detach_object (child_node); acpi_cm_remove_reference (obj_desc); } - /* - * Clear the NTE in case this scope is reused - * (e.g., a control method scope) - */ - - child_entry->type = ACPI_TYPE_ANY; - child_entry->name = 0; - /* Check if this object has any children */ - if (acpi_ns_get_next_object (ACPI_TYPE_ANY, child_entry, 0)) { + if (acpi_ns_get_next_object (ACPI_TYPE_ANY, child_node, 0)) { /* * There is at least one child of this object, * visit the object */ level++; - parent_entry = child_entry; - child_entry = 0; - } - - else { - /* - * There may be a name table even if there are - * no children - */ - - acpi_ns_delete_name_table (child_entry->child_table); - child_entry->child_table = NULL; - + parent_node = child_node; + child_node = 0; } } @@ -158,26 +399,18 @@ level--; /* - * Delete the scope (Name Table) associated with - * the parent object + * Now delete all of the children of this parent + * all at the same time. */ - /* Don't delete the top level scope, this allows - * the dynamic deletion of objects created underneath - * control methods! - */ - - if (level != 0) { - acpi_ns_delete_name_table (parent_entry->child_table); - parent_entry->child_table = NULL; - } + acpi_ns_delete_children (parent_node); /* New "last child" is this parent object */ - child_entry = parent_entry; + child_node = parent_node; /* Now we can move up the tree to the grandparent */ - parent_entry = acpi_ns_get_parent_entry (parent_entry); + parent_node = acpi_ns_get_parent_object (parent_node); } } @@ -186,70 +419,55 @@ } -/**************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_ns_remove_reference * - * PARAMETERS: Entry - NTE whose reference count is to be decremented + * PARAMETERS: Node - Named object whose reference count is to be + * decremented * * RETURN: None. * - * DESCRIPTION: Remove an NTE reference. Decrements the reference count of - * all parent NTEs up to the root. Any NTE along the way that - * reaches zero references is freed. + * DESCRIPTION: Remove a Node reference. Decrements the reference count + * of all parent Nodes up to the root. Any object along + * the way that reaches zero references is freed. * - ***************************************************************************/ + ******************************************************************************/ void acpi_ns_remove_reference ( - ACPI_NAMED_OBJECT *entry) + ACPI_NAMESPACE_NODE *node) { - ACPI_NAMED_OBJECT *this_entry; - - - /* There may be a name table even if there are no children */ - - acpi_ns_delete_name_table (entry->child_table); - entry->child_table = NULL; + ACPI_NAMESPACE_NODE *next_node; /* - * Decrement the reference count(s) of all parents up to the root, - * And delete anything with zero remaining references. + * Decrement the reference count(s) of this object and all + * objects up to the root, Delete anything with zero remaining references. */ - this_entry = entry; - while (this_entry) { - /* Decrement the reference */ + next_node = node; + while (next_node) { + /* Decrement the reference count on this object*/ - this_entry->reference_count--; + next_node->reference_count--; - /* Delete entry if no more references */ - - if (!this_entry->reference_count) { - /* Delete the scope if present */ - - if (this_entry->child_table) { - acpi_ns_delete_name_table (this_entry->child_table); - this_entry->child_table = NULL; - } - - /* - * Mark the entry free - * (This doesn't deallocate anything) - */ + /* Delete the object if no more references */ - acpi_ns_free_table_entry (this_entry); + if (!next_node->reference_count) { + /* Delete all children and delete the object */ + acpi_ns_delete_children (next_node); + acpi_ns_delete_node (next_node); } /* Move up to parent */ - this_entry = acpi_ns_get_parent_entry (this_entry); + next_node = acpi_ns_get_parent_object (next_node); } } -/**************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_ns_delete_namespace_by_owner * @@ -261,21 +479,21 @@ * specific ID. Used to delete entire ACPI tables. All * reference counts are updated. * - ***************************************************************************/ + ******************************************************************************/ ACPI_STATUS acpi_ns_delete_namespace_by_owner ( u16 owner_id) { - ACPI_NAMED_OBJECT *child_entry; + ACPI_NAMESPACE_NODE *child_node; u32 level; - ACPI_OBJECT_INTERNAL *obj_desc; - ACPI_NAMED_OBJECT *parent_entry; + ACPI_OPERAND_OBJECT *obj_desc; + ACPI_NAMESPACE_NODE *parent_node; - parent_entry = acpi_gbl_root_object; - child_entry = 0; - level = 1; + parent_node = acpi_gbl_root_node; + child_node = 0; + level = 1; /* * Traverse the tree of objects until we bubble back up @@ -288,124 +506,65 @@ * Null returned if not found */ - child_entry = acpi_ns_get_next_object (ACPI_TYPE_ANY, - parent_entry, - child_entry); + child_node = acpi_ns_get_next_object (ACPI_TYPE_ANY, parent_node, + child_node); - if (child_entry) { - if (child_entry->owner_id == owner_id) { + if (child_node) { + if (child_node->owner_id == owner_id) { /* * Found an object - delete the object within * the Value field */ - obj_desc = acpi_ns_get_attached_object (child_entry); + obj_desc = acpi_ns_get_attached_object (child_node); if (obj_desc) { - acpi_ns_detach_object (child_entry); + acpi_ns_detach_object (child_node); acpi_cm_remove_reference (obj_desc); } } /* Check if this object has any children */ - if (acpi_ns_get_next_object (ACPI_TYPE_ANY, child_entry, 0)) { + if (acpi_ns_get_next_object (ACPI_TYPE_ANY, child_node, 0)) { /* * There is at least one child of this object, * visit the object */ level++; - parent_entry = child_entry; - child_entry = 0; + parent_node = child_node; + child_node = 0; } - else if (child_entry->owner_id == owner_id) { - acpi_ns_remove_reference (child_entry); + else if (child_node->owner_id == owner_id) { + acpi_ns_remove_reference (child_node); } } else { /* - * No more children in this object. - * We will move up to the grandparent. + * No more children in this object. Move up to grandparent. */ level--; - /* - * Delete the scope (Name Table) associated with - * the parent object - */ - /* Don't delete the top level scope, this allows - * the dynamic deletion of objects created underneath - * control methods! - */ - - if (level != 0) { - if (parent_entry->owner_id == owner_id) { - acpi_ns_remove_reference (parent_entry); + if (parent_node->owner_id == owner_id) { + acpi_ns_remove_reference (parent_node); } } - /* New "last child" is this parent object */ - child_entry = parent_entry; + child_node = parent_node; /* Now we can move up the tree to the grandparent */ - parent_entry = acpi_ns_get_parent_entry (parent_entry); + parent_node = acpi_ns_get_parent_object (parent_node); } } return (AE_OK); -} - - -/**************************************************************************** - * - * FUNCTION: Acpi_ns_delete_name_table - * - * PARAMETERS: Scope - A handle to the scope to be deleted - * - * RETURN: None. - * - * DESCRIPTION: Delete a namespace Name Table with zero or - * more appendages. The table and all appendages are deleted. - * - ***************************************************************************/ - -void -acpi_ns_delete_name_table ( - ACPI_NAME_TABLE *name_table) -{ - ACPI_NAME_TABLE *this_table; - ACPI_NAME_TABLE *next_table; - - - if (!name_table) { - return; - } - - this_table = name_table; - - - /* - * Deallocate the name table and all appendages - */ - do - { - next_table = this_table->next_table; - - /* Now we can free the table */ - - acpi_cm_free (this_table); - this_table = next_table; - - } while (this_table); - - return; } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/namespace/nsdump.c linux/drivers/acpi/namespace/nsdump.c --- v2.4.0-test8/linux/drivers/acpi/namespace/nsdump.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/acpi/namespace/nsdump.c Fri Sep 15 14:30:30 2000 @@ -0,0 +1,36 @@ +/****************************************************************************** + * + * Module Name: nsdump - table dumping routines for debug + * $Revision: 78 $ + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 R. Byron Moore + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "acpi.h" +#include "acinterp.h" +#include "acnamesp.h" +#include "actables.h" + + +#define _COMPONENT NAMESPACE + MODULE_NAME ("nsdump") + + diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/namespace/nseval.c linux/drivers/acpi/namespace/nseval.c --- v2.4.0-test8/linux/drivers/acpi/namespace/nseval.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/namespace/nseval.c Fri Sep 15 14:30:30 2000 @@ -1,10 +1,10 @@ - -/****************************************************************************** +/******************************************************************************* * * Module Name: nseval - Object evaluation interfaces -- includes control * method lookup and execution. + * $Revision: 76 $ * - *****************************************************************************/ + ******************************************************************************/ /* * Copyright (C) 2000 R. Byron Moore @@ -27,20 +27,20 @@ #include "acpi.h" #include "amlcode.h" -#include "parser.h" -#include "interp.h" -#include "namesp.h" +#include "acparser.h" +#include "acinterp.h" +#include "acnamesp.h" #define _COMPONENT NAMESPACE - MODULE_NAME ("nseval"); + MODULE_NAME ("nseval") -/**************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_ns_evaluate_relative * - * PARAMETERS: Rel_obj_entry - NTE of the relative containing object + * PARAMETERS: Handle - The relative containing object * *Pathname - Name of method to execute, If NULL, the * handle is the object to execute * **Params - List of parameters to pass to the method, @@ -56,19 +56,19 @@ * * MUTEX: Locks Namespace * - ****************************************************************************/ + ******************************************************************************/ ACPI_STATUS acpi_ns_evaluate_relative ( - ACPI_NAMED_OBJECT *handle, - char *pathname, - ACPI_OBJECT_INTERNAL **params, - ACPI_OBJECT_INTERNAL **return_object) + ACPI_NAMESPACE_NODE *handle, + NATIVE_CHAR *pathname, + ACPI_OPERAND_OBJECT **params, + ACPI_OPERAND_OBJECT **return_object) { - ACPI_NAMED_OBJECT *rel_obj_entry; + ACPI_NAMESPACE_NODE *prefix_node; ACPI_STATUS status; - ACPI_NAMED_OBJECT *obj_entry = NULL; - char *internal_path = NULL; + ACPI_NAMESPACE_NODE *node = NULL; + NATIVE_CHAR *internal_path = NULL; ACPI_GENERIC_STATE scope_info; @@ -86,12 +86,12 @@ return (status); } - /* Get the prefix handle and NTE */ + /* Get the prefix handle and Node */ acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE); - rel_obj_entry = acpi_ns_convert_handle_to_entry (handle); - if (!rel_obj_entry) { + prefix_node = acpi_ns_convert_handle_to_entry (handle); + if (!prefix_node) { acpi_cm_release_mutex (ACPI_MTX_NAMESPACE); status = AE_BAD_PARAMETER; goto cleanup; @@ -99,15 +99,14 @@ /* Lookup the name in the namespace */ - scope_info.scope.name_table = rel_obj_entry->child_table; + scope_info.scope.node = prefix_node->child; status = acpi_ns_lookup (&scope_info, internal_path, ACPI_TYPE_ANY, - IMODE_EXECUTE, - NS_NO_UPSEARCH, NULL, - &obj_entry); + IMODE_EXECUTE, NS_NO_UPSEARCH, NULL, + &node); acpi_cm_release_mutex (ACPI_MTX_NAMESPACE); - if (status != AE_OK) { + if (ACPI_FAILURE (status)) { goto cleanup; } @@ -116,7 +115,7 @@ * to evaluate it. */ - status = acpi_ns_evaluate_by_handle (obj_entry, params, return_object); + status = acpi_ns_evaluate_by_handle (node, params, return_object); cleanup: @@ -128,7 +127,7 @@ } -/**************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_ns_evaluate_by_name * @@ -146,26 +145,24 @@ * * MUTEX: Locks Namespace * - ****************************************************************************/ + ******************************************************************************/ ACPI_STATUS acpi_ns_evaluate_by_name ( - char *pathname, - ACPI_OBJECT_INTERNAL **params, - ACPI_OBJECT_INTERNAL **return_object) + NATIVE_CHAR *pathname, + ACPI_OPERAND_OBJECT **params, + ACPI_OPERAND_OBJECT **return_object) { ACPI_STATUS status; - ACPI_NAMED_OBJECT *obj_entry = NULL; - char *internal_path = NULL; + ACPI_NAMESPACE_NODE *node = NULL; + NATIVE_CHAR *internal_path = NULL; /* Build an internal name string for the method */ - if (pathname[0] != '\\' || pathname[1] != '/') { - status = acpi_ns_internalize_name (pathname, &internal_path); - if (ACPI_FAILURE (status)) { - return (status); - } + status = acpi_ns_internalize_name (pathname, &internal_path); + if (ACPI_FAILURE (status)) { + return (status); } acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE); @@ -173,13 +170,12 @@ /* Lookup the name in the namespace */ status = acpi_ns_lookup (NULL, internal_path, ACPI_TYPE_ANY, - IMODE_EXECUTE, - NS_NO_UPSEARCH, NULL, - &obj_entry); + IMODE_EXECUTE, NS_NO_UPSEARCH, NULL, + &node); acpi_cm_release_mutex (ACPI_MTX_NAMESPACE); - if (status != AE_OK) { + if (ACPI_FAILURE (status)) { goto cleanup; } @@ -188,7 +184,7 @@ * to evaluate it. */ - status = acpi_ns_evaluate_by_handle (obj_entry, params, return_object); + status = acpi_ns_evaluate_by_handle (node, params, return_object); cleanup: @@ -203,16 +199,16 @@ } -/**************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_ns_evaluate_by_handle * - * PARAMETERS: Obj_entry - NTE of method to execute - * *Return_object - Where to put method's return value (if - * any). If NULL, no value is returned. + * PARAMETERS: Handle - Method Node to execute * **Params - List of parameters to pass to the method, * terminated by NULL. Params itself may be * NULL if no parameters are being passed. + * *Return_object - Where to put method's return value (if + * any). If NULL, no value is returned. * * RETURN: Status * @@ -220,22 +216,22 @@ * * MUTEX: Locks Namespace * - ****************************************************************************/ + ******************************************************************************/ ACPI_STATUS acpi_ns_evaluate_by_handle ( - ACPI_NAMED_OBJECT *handle, - ACPI_OBJECT_INTERNAL **params, - ACPI_OBJECT_INTERNAL **return_object) + ACPI_NAMESPACE_NODE *handle, + ACPI_OPERAND_OBJECT **params, + ACPI_OPERAND_OBJECT **return_object) { - ACPI_NAMED_OBJECT *obj_entry; + ACPI_NAMESPACE_NODE *node; ACPI_STATUS status; - ACPI_OBJECT_INTERNAL *local_return_object; + ACPI_OPERAND_OBJECT *local_return_object; /* Check if namespace has been initialized */ - if (!acpi_gbl_root_object->child_table) { + if (!acpi_gbl_root_node) { return (AE_NO_NAMESPACE); } @@ -251,12 +247,12 @@ *return_object = NULL; } - /* Get the prefix handle and NTE */ + /* Get the prefix handle and Node */ acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE); - obj_entry = acpi_ns_convert_handle_to_entry (handle); - if (!obj_entry) { + node = acpi_ns_convert_handle_to_entry (handle); + if (!node) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } @@ -271,14 +267,11 @@ * In both cases, the namespace is unlocked by the * Acpi_ns* procedure */ - - if (acpi_ns_get_type (obj_entry) == ACPI_TYPE_METHOD) { + if (acpi_ns_get_type (node) == ACPI_TYPE_METHOD) { /* * Case 1) We have an actual control method to execute */ - - status = acpi_ns_execute_control_method (obj_entry, - params, + status = acpi_ns_execute_control_method (node, params, &local_return_object); } @@ -287,9 +280,7 @@ * Case 2) Object is NOT a method, just return its * current value */ - - status = acpi_ns_get_object_value (obj_entry, - &local_return_object); + status = acpi_ns_get_object_value (node, &local_return_object); } @@ -297,7 +288,6 @@ * Check if there is a return value on the stack that must * be dealt with */ - if (status == AE_CTRL_RETURN_VALUE) { /* * If the Method returned a value and the caller @@ -305,13 +295,11 @@ * the returned value to the object descriptor provided * by the caller. */ - if (return_object) { /* * Valid return object, copy the pointer to * the returned object */ - *return_object = local_return_object; } @@ -327,7 +315,6 @@ * Namespace was unlocked by the handling Acpi_ns* function, * so we just return */ - return (status); @@ -338,14 +325,16 @@ } -/**************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_ns_execute_control_method * - * PARAMETERS: Method_entry - The Nte of the object/method + * PARAMETERS: Method_node - The object/method * **Params - List of parameters to pass to the method, * terminated by NULL. Params itself may be * NULL if no parameters are being passed. + * **Return_obj_desc - List of result objects to be returned + * from the method. * * RETURN: Status * @@ -353,36 +342,31 @@ * * MUTEX: Assumes namespace is locked * - ****************************************************************************/ + ******************************************************************************/ ACPI_STATUS acpi_ns_execute_control_method ( - ACPI_NAMED_OBJECT *method_entry, - ACPI_OBJECT_INTERNAL **params, - ACPI_OBJECT_INTERNAL **return_obj_desc) + ACPI_NAMESPACE_NODE *method_node, + ACPI_OPERAND_OBJECT **params, + ACPI_OPERAND_OBJECT **return_obj_desc) { ACPI_STATUS status; - ACPI_OBJECT_INTERNAL *obj_desc; + ACPI_OPERAND_OBJECT *obj_desc; /* Verify that there is a method associated with this object */ - obj_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) method_entry); + obj_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) method_node); if (!obj_desc) { return (AE_ERROR); } - /* - * Valid method, Set the current scope to that of the Method, - * and execute it. - */ - /* * Unlock the namespace before execution. This allows namespace access * via the external Acpi* interfaces while a method is being executed. * However, any namespace deletion must acquire both the namespace and - * interpter locks to ensure that no thread is using the portion of the + * interpreter locks to ensure that no thread is using the portion of the * namespace that is being deleted. */ @@ -391,17 +375,17 @@ /* * Excecute the method via the interpreter */ - status = acpi_aml_execute_method (method_entry, params, return_obj_desc); + status = acpi_aml_execute_method (method_node, params, return_obj_desc); return (status); } -/**************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_ns_get_object_value * - * PARAMETERS: Object_entry - The Nte of the object + * PARAMETERS: Node - The object * * RETURN: Status * @@ -409,30 +393,29 @@ * * MUTEX: Assumes namespace is locked * - ****************************************************************************/ + ******************************************************************************/ ACPI_STATUS acpi_ns_get_object_value ( - ACPI_NAMED_OBJECT *object_entry, - ACPI_OBJECT_INTERNAL **return_obj_desc) + ACPI_NAMESPACE_NODE *node, + ACPI_OPERAND_OBJECT **return_obj_desc) { ACPI_STATUS status = AE_OK; - ACPI_OBJECT_INTERNAL *obj_desc; - ACPI_OBJECT_INTERNAL *val_desc; + ACPI_OPERAND_OBJECT *obj_desc; + ACPI_OPERAND_OBJECT *val_desc; /* * We take the value from certain objects directly */ - if ((object_entry->type == ACPI_TYPE_PROCESSOR) || - (object_entry->type == ACPI_TYPE_POWER)) + if ((node->type == ACPI_TYPE_PROCESSOR) || + (node->type == ACPI_TYPE_POWER)) { - /* * Create a Reference object to contain the object */ - obj_desc = acpi_cm_create_internal_object (object_entry->type); + obj_desc = acpi_cm_create_internal_object (node->type); if (!obj_desc) { status = AE_NO_MEMORY; goto unlock_and_exit; @@ -442,7 +425,7 @@ * Get the attached object */ - val_desc = acpi_ns_get_attached_object (object_entry); + val_desc = acpi_ns_get_attached_object (node); if (!val_desc) { status = AE_NULL_OBJECT; goto unlock_and_exit; @@ -452,10 +435,25 @@ * Just copy from the original to the return object */ - MEMCPY (&obj_desc->common.first_non_common_byte, - &val_desc->common.first_non_common_byte, - (sizeof(ACPI_OBJECT_COMMON) - - sizeof(obj_desc->common.first_non_common_byte))); + switch (node->type) + { + case ACPI_TYPE_PROCESSOR: + obj_desc->processor.proc_id = val_desc->processor.proc_id; + obj_desc->processor.address = val_desc->processor.address; + obj_desc->processor.sys_handler = val_desc->processor.sys_handler; + obj_desc->processor.drv_handler = val_desc->processor.drv_handler; + obj_desc->processor.addr_handler = val_desc->processor.addr_handler; + + break; + + case ACPI_TYPE_POWER: + obj_desc->power_resource.system_level = val_desc->power_resource.system_level; + obj_desc->power_resource.resource_order = val_desc->power_resource.resource_order; + obj_desc->power_resource.sys_handler = val_desc->power_resource.sys_handler; + obj_desc->power_resource.drv_handler = val_desc->power_resource.drv_handler; + + break; + } } @@ -475,15 +473,19 @@ /* Construct a descriptor pointing to the name */ obj_desc->reference.op_code = (u8) AML_NAME_OP; - obj_desc->reference.object = (void *) object_entry; + obj_desc->reference.object = (void *) node; /* * Use Acpi_aml_resolve_to_value() to get the associated value. * The call to Acpi_aml_resolve_to_value causes * Obj_desc (allocated above) to always be deleted. + * + * NOTE: we can get away with passing in NULL for a walk state + * because Obj_desc is guaranteed to not be a reference to either + * a method local or a method argument */ - status = acpi_aml_resolve_to_value (&obj_desc); + status = acpi_aml_resolve_to_value (&obj_desc, NULL); } /* @@ -491,7 +493,7 @@ * placed in Obj_desc. */ - if (status == AE_OK) { + if (ACPI_SUCCESS (status)) { status = AE_CTRL_RETURN_VALUE; *return_obj_desc = obj_desc; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/namespace/nsload.c linux/drivers/acpi/namespace/nsload.c --- v2.4.0-test8/linux/drivers/acpi/namespace/nsload.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/namespace/nsload.c Fri Sep 15 14:30:30 2000 @@ -1,7 +1,7 @@ - /****************************************************************************** * * Module Name: nsload - namespace loading/expanding/contracting procedures + * $Revision: 28 $ * *****************************************************************************/ @@ -25,16 +25,16 @@ #include "acpi.h" -#include "interp.h" -#include "namesp.h" +#include "acinterp.h" +#include "acnamesp.h" #include "amlcode.h" -#include "parser.h" -#include "dispatch.h" -#include "debugger.h" +#include "acparser.h" +#include "acdispat.h" +#include "acdebug.h" #define _COMPONENT NAMESPACE - MODULE_NAME ("nsload"); + MODULE_NAME ("nsload") /******************************************************************************* @@ -42,7 +42,7 @@ * FUNCTION: Acpi_ns_parse_table * * PARAMETERS: Table_desc - An ACPI table descriptor for table to parse - * Scope - Where to enter the table into the namespace + * Start_node - Where to enter the table into the namespace * * RETURN: Status * @@ -53,50 +53,85 @@ ACPI_STATUS acpi_ns_parse_table ( ACPI_TABLE_DESC *table_desc, - ACPI_NAME_TABLE *scope) + ACPI_NAMESPACE_NODE *start_node) { ACPI_STATUS status; - /* Create the root object */ + /* + * AML Parse, pass 1 + * + * In this pass, we load most of the namespace. Control methods + * are not parsed until later. A parse tree is not created. Instead, + * each Parser Op subtree is deleted when it is finished. This saves + * a great deal of memory, and allows a small cache of parse objects + * to service the entire parse. The second pass of the parse then + * performs another complete parse of the AML.. + */ + + /* Create and init a Root Node */ acpi_gbl_parsed_namespace_root = acpi_ps_alloc_op (AML_SCOPE_OP); if (!acpi_gbl_parsed_namespace_root) { return (AE_NO_MEMORY); } - /* Initialize the root object */ + ((ACPI_PARSE2_OBJECT *) acpi_gbl_parsed_namespace_root)->name = ACPI_ROOT_NAME; - ((ACPI_NAMED_OP *) acpi_gbl_parsed_namespace_root)->name = ACPI_ROOT_NAME; /* Pass 1: Parse everything except control method bodies */ status = acpi_ps_parse_aml (acpi_gbl_parsed_namespace_root, table_desc->aml_pointer, - table_desc->aml_length, 0); + table_desc->aml_length, + ACPI_PARSE_LOAD_PASS1 | ACPI_PARSE_DELETE_TREE, + NULL, NULL, NULL, + acpi_ds_load1_begin_op, + acpi_ds_load1_end_op); if (ACPI_FAILURE (status)) { return (status); } - -#ifndef PARSER_ONLY - status = acpi_ps_walk_parsed_aml (acpi_ps_get_child (acpi_gbl_parsed_namespace_root), - acpi_gbl_parsed_namespace_root, NULL, - scope, NULL, NULL, - table_desc->table_id, - acpi_ds_load2_begin_op, - acpi_ds_load2_end_op); + acpi_ps_delete_parse_tree (acpi_gbl_parsed_namespace_root); /* - * Now that the internal namespace has been constructed, we can delete the - * parsed namespace, since it is no longer needed + * AML Parse, pass 2 + * + * In this pass, we resolve forward references and other things + * that could not be completed during the first pass. + * Another complete parse of the AML is performed, but the + * overhead of this is compensated for by the fact that the + * parse objects are all cached. */ + /* Create and init a Root Node */ + + acpi_gbl_parsed_namespace_root = acpi_ps_alloc_op (AML_SCOPE_OP); + if (!acpi_gbl_parsed_namespace_root) { + return (AE_NO_MEMORY); + } + + ((ACPI_PARSE2_OBJECT *) acpi_gbl_parsed_namespace_root)->name = ACPI_ROOT_NAME; + + + /* Pass 2: Resolve forward references */ + + status = acpi_ps_parse_aml (acpi_gbl_parsed_namespace_root, + table_desc->aml_pointer, + table_desc->aml_length, + ACPI_PARSE_LOAD_PASS1 | ACPI_PARSE_DELETE_TREE, + NULL, NULL, NULL, + acpi_ds_load2_begin_op, + acpi_ds_load2_end_op); + + if (ACPI_FAILURE (status)) { + return (status); + } + acpi_ps_delete_parse_tree (acpi_gbl_parsed_namespace_root); acpi_gbl_parsed_namespace_root = NULL; -#endif return (status); @@ -120,7 +155,7 @@ ACPI_STATUS acpi_ns_load_table ( ACPI_TABLE_DESC *table_desc, - ACPI_NAMED_OBJECT *entry) + ACPI_NAMESPACE_NODE *node) { ACPI_STATUS status; @@ -146,7 +181,7 @@ */ acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE); - status = acpi_ns_parse_table (table_desc, entry->child_table); + status = acpi_ns_parse_table (table_desc, node->child); acpi_cm_release_mutex (ACPI_MTX_NAMESPACE); if (ACPI_FAILURE (status)) { @@ -160,7 +195,7 @@ * parse trees. */ - status = acpi_ds_initialize_objects (table_desc, entry); + status = acpi_ds_initialize_objects (table_desc, node); return (status); } @@ -222,7 +257,7 @@ /* Now load the single DSDT */ - status = acpi_ns_load_table (table_desc, acpi_gbl_root_object); + status = acpi_ns_load_table (table_desc, acpi_gbl_root_node); if (ACPI_SUCCESS (status)) { table_desc->loaded_into_namespace = TRUE; } @@ -247,7 +282,7 @@ if (!table_desc->loaded_into_namespace) { status = acpi_ns_load_table (table_desc, - acpi_gbl_root_object); + acpi_gbl_root_node); if (ACPI_FAILURE (status)) { break; } @@ -276,7 +311,7 @@ if (!table_desc->loaded_into_namespace) { status = acpi_ns_load_table (table_desc, - acpi_gbl_root_object); + acpi_gbl_root_node); if (ACPI_FAILURE (status)) { break; } @@ -306,52 +341,6 @@ /****************************************************************************** * - * FUNCTION: Acpi_ns_free_table_entry - * - * PARAMETERS: Entry - The entry to be deleted - * - * RETURNS None - * - * DESCRIPTION: Free an entry in a namespace table. Delete any objects contained - * in the entry, unlink the entry, then mark it unused. - * - ******************************************************************************/ - -void -acpi_ns_free_table_entry ( - ACPI_NAMED_OBJECT *entry) -{ - - if (!entry) { - return; - } - - /* - * Need to delete - * 1) The scope, if any - * 2) An attached object, if any - */ - - if (entry->child_table) { - acpi_cm_free (entry->child_table); - entry->child_table = NULL; - } - - if (entry->object) { - acpi_ns_detach_object (entry->object); - entry->object = NULL; - } - - /* Mark the entry unallocated */ - - entry->name = 0; - - return; -} - - -/****************************************************************************** - * * FUNCTION: Acpi_ns_delete_subtree * * PARAMETERS: Start_handle - Handle in namespace where search begins @@ -394,15 +383,6 @@ child_handle, &next_child_handle); - /* - * Regardless of the success or failure of the - * previous operation, we are done with the previous - * object (if there was one), and any children it - * may have had. So we can now safely delete it (and - * its scope, if any) - */ - - acpi_ns_free_table_entry (child_handle); child_handle = next_child_handle; @@ -432,6 +412,11 @@ * the object's parent */ level--; + + /* Delete all children now */ + + acpi_ns_delete_children (child_handle); + child_handle = parent_handle; acpi_get_parent (parent_handle, &parent_handle); } @@ -439,7 +424,7 @@ /* Now delete the starting object, and we are done */ - acpi_ns_free_table_entry ((ACPI_NAMED_OBJECT*) child_handle); + acpi_ns_delete_node (child_handle); return (AE_OK); @@ -469,7 +454,7 @@ /* Parameter validation */ - if (!acpi_gbl_root_object->child_table) { + if (!acpi_gbl_root_node) { return (AE_NO_NAMESPACE); } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/namespace/nsnames.c linux/drivers/acpi/namespace/nsnames.c --- v2.4.0-test8/linux/drivers/acpi/namespace/nsnames.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/namespace/nsnames.c Fri Sep 15 14:30:30 2000 @@ -1,9 +1,9 @@ - -/****************************************************************************** +/******************************************************************************* * * Module Name: nsnames - Name manipulation and search + * $Revision: 48 $ * - *****************************************************************************/ + ******************************************************************************/ /* * Copyright (C) 2000 R. Byron Moore @@ -26,42 +26,40 @@ #include "acpi.h" #include "amlcode.h" -#include "interp.h" -#include "namesp.h" +#include "acinterp.h" +#include "acnamesp.h" #define _COMPONENT NAMESPACE - MODULE_NAME ("nsnames"); + MODULE_NAME ("nsnames") -/**************************************************************************** +/******************************************************************************* * - * FUNCTION: Acpi_ns_name_of_scope + * FUNCTION: Acpi_ns_get_table_pathname * - * PARAMETERS: Scope - Scope whose name is needed + * PARAMETERS: Node - Scope whose name is needed * * RETURN: Pointer to storage containing the fully qualified name of * the scope, in Label format (all segments strung together * with no separators) * - * DESCRIPTION: Used via Acpi_ns_name_of_current_scope() and Acpi_ns_last_fQN() - * for label generation in the interpreter, and for debug - * printing in Acpi_ns_search_table(). - * - ***************************************************************************/ - -char * -acpi_ns_name_of_scope ( - ACPI_NAME_TABLE *scope) + * DESCRIPTION: Used for debug printing in Acpi_ns_search_table(). + * + ******************************************************************************/ + +NATIVE_CHAR * +acpi_ns_get_table_pathname ( + ACPI_NAMESPACE_NODE *node) { - char *name_buffer; - ACPI_SIZE size; + NATIVE_CHAR *name_buffer; + u32 size; ACPI_NAME name; - ACPI_NAMED_OBJECT *entry_to_search; - ACPI_NAMED_OBJECT *parent_entry; + ACPI_NAMESPACE_NODE *child_node; + ACPI_NAMESPACE_NODE *parent_node; - if (!acpi_gbl_root_object->child_table || !scope) { + if (!acpi_gbl_root_node || !node) { /* * If the name space has not been initialized, * this function should not have been called. @@ -69,26 +67,26 @@ return (NULL); } - entry_to_search = scope->entries; + child_node = node->child; - /* Calculate required buffer size based on depth below root NT */ + /* Calculate required buffer size based on depth below root */ size = 1; - parent_entry = entry_to_search; - while (parent_entry) { - parent_entry = acpi_ns_get_parent_entry (parent_entry); - if (parent_entry) { + parent_node = child_node; + while (parent_node) { + parent_node = acpi_ns_get_parent_object (parent_node); + if (parent_node) { size += ACPI_NAME_SIZE; } } - /* Allocate the buffer */ + /* Allocate a buffer to be returned to caller */ name_buffer = acpi_cm_callocate (size + 1); if (!name_buffer) { - REPORT_ERROR ("Ns_name_of_scope: allocation failure"); + REPORT_ERROR ("Ns_get_table_pathname: allocation failure"); return (NULL); } @@ -97,15 +95,15 @@ name_buffer[size] = '\0'; while ((size > ACPI_NAME_SIZE) && - acpi_ns_get_parent_entry (entry_to_search)) + acpi_ns_get_parent_object (child_node)) { size -= ACPI_NAME_SIZE; - name = acpi_ns_find_parent_name (entry_to_search); + name = acpi_ns_find_parent_name (child_node); /* Put the name into the buffer */ MOVE_UNALIGNED32_TO_32 ((name_buffer + size), &name); - entry_to_search = acpi_ns_get_parent_entry (entry_to_search); + child_node = acpi_ns_get_parent_object (child_node); } name_buffer[--size] = AML_ROOT_PREFIX; @@ -115,69 +113,39 @@ } -/**************************************************************************** - * - * FUNCTION: Acpi_ns_name_of_current_scope - * - * PARAMETERS: none - * - * RETURN: pointer to storage containing the name of the current scope - * - ***************************************************************************/ - -char * -acpi_ns_name_of_current_scope ( - ACPI_WALK_STATE *walk_state) -{ - char *scope_name; - - - if (walk_state && walk_state->scope_info) { - scope_name = - acpi_ns_name_of_scope (walk_state->scope_info->scope.name_table); - - return (scope_name); - } - - REPORT_ERROR ("Current scope pointer is invalid"); - - return (NULL); -} - - -/**************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_ns_handle_to_pathname * - * PARAMETERS: Target_handle - Handle of nte whose name is to be found + * PARAMETERS: Target_handle - Handle of named object whose name is + * to be found * Buf_size - Size of the buffer provided * User_buffer - Where the pathname is returned * - * RETURN: Status, Buffer is filled with pathname if status == AE_OK + * RETURN: Status, Buffer is filled with pathname if status is AE_OK * * DESCRIPTION: Build and return a full namespace pathname * * MUTEX: Locks Namespace * - ***************************************************************************/ + ******************************************************************************/ ACPI_STATUS acpi_ns_handle_to_pathname ( ACPI_HANDLE target_handle, u32 *buf_size, - char *user_buffer) + NATIVE_CHAR *user_buffer) { ACPI_STATUS status = AE_OK; - ACPI_NAMED_OBJECT *entry_to_search = NULL; - ACPI_NAMED_OBJECT *temp = NULL; - ACPI_SIZE path_length = 0; - ACPI_SIZE size; + ACPI_NAMESPACE_NODE *node; + ACPI_NAMESPACE_NODE *next_node; + u32 path_length; + u32 size; u32 user_buf_size; ACPI_NAME name; - u8 namespace_was_locked; - if (!acpi_gbl_root_object->child_table || !target_handle) { + if (!acpi_gbl_root_node || !target_handle) { /* * If the name space has not been initialized, * this function should not have been called. @@ -186,13 +154,8 @@ return (AE_NO_NAMESPACE); } - namespace_was_locked = acpi_gbl_acpi_mutex_info[ACPI_MTX_NAMESPACE].locked; - if (!namespace_was_locked) { - acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE); - } - - entry_to_search = acpi_ns_convert_handle_to_entry (target_handle); - if (!entry_to_search) { + node = acpi_ns_convert_handle_to_entry (target_handle); + if (!node) { return (AE_BAD_PARAMETER); } @@ -200,9 +163,9 @@ * Compute length of pathname as 5 * number of name segments. * Go back up the parent tree to the root */ - for (size = 0, temp = entry_to_search; - acpi_ns_get_parent_entry (temp); - temp = acpi_ns_get_parent_entry (temp)) + for (size = 0, next_node = node; + acpi_ns_get_parent_object (next_node); + next_node = acpi_ns_get_parent_object (next_node)) { size += PATH_SEGMENT_LENGTH; } @@ -217,7 +180,7 @@ if (path_length > user_buf_size) { status = AE_BUFFER_OVERFLOW; - goto unlock_and_exit; + goto exit; } /* Store null terminator */ @@ -228,19 +191,19 @@ /* Put the original ACPI name at the end of the path */ MOVE_UNALIGNED32_TO_32 ((user_buffer + size), - &entry_to_search->name); + &node->name); user_buffer[--size] = PATH_SEPARATOR; /* Build name backwards, putting "." between segments */ - while ((size > ACPI_NAME_SIZE) && entry_to_search) { + while ((size > ACPI_NAME_SIZE) && node) { size -= ACPI_NAME_SIZE; - name = acpi_ns_find_parent_name (entry_to_search); + name = acpi_ns_find_parent_name (node); MOVE_UNALIGNED32_TO_32 ((user_buffer + size), &name); user_buffer[--size] = PATH_SEPARATOR; - entry_to_search = acpi_ns_get_parent_entry (entry_to_search); + node = acpi_ns_get_parent_object (node); } /* @@ -250,254 +213,8 @@ user_buffer[size] = '\\'; - -unlock_and_exit: - - if (!namespace_was_locked) { - acpi_cm_release_mutex (ACPI_MTX_NAMESPACE); - } - +exit: return (status); -} - - -/**************************************************************************** - * - * FUNCTION: Acpi_ns_pattern_match - * - * PARAMETERS: Obj_entry - A namespace entry - * Search_for - Wildcard pattern string - * - * DESCRIPTION: Matches a namespace name against a wildcard pattern. Only - * a very simple pattern - 4 chars, either a valid char or a "?" - * to match any. - * - ***************************************************************************/ - -u8 -acpi_ns_pattern_match ( - ACPI_NAMED_OBJECT *obj_entry, - char *search_for) -{ - s32 i; - - - for (i = 0; i < ACPI_NAME_SIZE; i++) { - if (search_for[i] != '?' && - search_for[i] != ((char *) &obj_entry->name)[i]) - { - /* No match */ - - return FALSE; - } - } - - /* name matches pattern */ - - return TRUE; -} - - -/**************************************************************************** - * - * FUNCTION: Acpi_ns_name_compare - * - * PARAMETERS: Obj_handle - A namespace entry - * Level - Current nesting level - * Context - A FIND_CONTEXT structure - * - * DESCRIPTION: A User_function called by Acpi_ns_walk_namespace(). It performs - * a pattern match for Acpi_ns_low_find_names(), and updates the list - * and count as required. - * - ***************************************************************************/ - -ACPI_STATUS -acpi_ns_name_compare ( - ACPI_HANDLE obj_handle, - u32 level, - void *context, - void **return_value) -{ - FIND_CONTEXT *find = context; - - - /* Match, yes or no? */ - - if (acpi_ns_pattern_match ((ACPI_NAMED_OBJECT*) obj_handle, - find->search_for)) - { - /* Name matches pattern */ - - if (find->list) { - find->list[*(find->count)] = obj_handle; - } - - ++*(find->count); - } - - /* Don't terminate the walk */ - return AE_OK; -} - - -/**************************************************************************** - * - * FUNCTION: Acpi_ns_low_find_names - * - * PARAMETERS: *This_entry - Table to be searched - * *Search_for - Pattern to be found. - * 4 bytes, ? matches any character. - * *Count - Output count of matches found. - * Outermost caller should preset to 0 - * List[] - Output array of handles. If - * null, only the count is obtained. - * Max_depth - Maximum depth of search. Use - * INT_MAX for an effectively - * unlimited depth. - * - * DESCRIPTION: Low-level find name. - * Traverse the name space finding names which match a search - * pattern, and return an array of handles in List[]. - * - ***************************************************************************/ - -void -acpi_ns_low_find_names ( - ACPI_NAMED_OBJECT *this_entry, - char *search_for, - s32 *count, - ACPI_HANDLE list[], - s32 max_depth) -{ - FIND_CONTEXT find; - - - if (0 == max_depth || !this_entry || !search_for || !count) { - /* - * Zero requested depth, nothing to search, - * nothing to search for, or count pointer bad - */ - - return; - } - - /* Init the context structure used by compare routine */ - - find.list = list; - find.count = count; - find.search_for = search_for; - - /* Walk the namespace and find all matches */ - - acpi_ns_walk_namespace (ACPI_TYPE_ANY, (ACPI_HANDLE) this_entry, - max_depth, NS_WALK_NO_UNLOCK, - acpi_ns_name_compare, &find, NULL); - - if (list) { - /* null-terminate the output array */ - - list[*count] = (ACPI_HANDLE) 0; - } - - return; -} - - -/**************************************************************************** - * - * FUNCTION: Acpi_ns_find_names - - * - * PARAMETERS: *Search_for - pattern to be found. - * 4 bytes, ? matches any character. - * If NULL, "????" will be used. - * Start_handle - Root of subtree to be searched, or - * NS_ALL to search the entire namespace - * Max_depth - Maximum depth of search. Use INT_MAX - * for an effectively unlimited depth. - * - * DESCRIPTION: Traverse the name space finding names which match a search - * pattern, and return an array of handles. The end of the - * array is marked by the value (ACPI_HANDLE)0. A return value - * of (ACPI_HANDLE *)0 indicates that no matching names were - * found or that space for the list could not be allocated. - * if Start_handle is NS_ALL (null) search from the root, - * else it is a handle whose children are to be searched. - * - ***************************************************************************/ - -ACPI_HANDLE * -acpi_ns_find_names ( - char *search_for, - ACPI_HANDLE start_handle, - s32 max_depth) -{ - ACPI_HANDLE *list = NULL; - s32 count; - - - if (!acpi_gbl_root_object->child_table) { - /* - * If the name space has not been initialized, - * there surely are no matching names. - */ - return (NULL); - } - - if (NS_ALL == start_handle) { - /* base is root */ - - start_handle = acpi_gbl_root_object; - } - - else if (((ACPI_NAMED_OBJECT *) start_handle)->child_table) { - /* base has children to search */ - - start_handle = - ((ACPI_NAMED_OBJECT *) start_handle)->child_table->entries; - } - - else { - /* - * If base is not the root and has no children, - * there is nothing to search. - */ - return (NULL); - } - - if (!search_for) { - /* Search name not specified */ - - search_for = "????"; - } - - - /* Pass 1. Get required buffer size, don't try to build list */ - - count = 0; - acpi_ns_low_find_names (start_handle, search_for, &count, - NULL, max_depth); - - if (0 == count) { - return (NULL); - } - - /* Allow for trailing null */ - count++; - - list = acpi_cm_callocate (count * sizeof(ACPI_HANDLE)); - if (!list) { - REPORT_ERROR ("Ns_find_names: allocation failure"); - return (NULL); - } - - /* Pass 2. Fill buffer */ - - count = 0; - acpi_ns_low_find_names (start_handle, search_for, &count, list, max_depth); - - return (list); } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/namespace/nsobject.c linux/drivers/acpi/namespace/nsobject.c --- v2.4.0-test8/linux/drivers/acpi/namespace/nsobject.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/namespace/nsobject.c Fri Sep 15 14:30:30 2000 @@ -1,10 +1,10 @@ - -/****************************************************************************** +/******************************************************************************* * * Module Name: nsobject - Utilities for objects attached to namespace - * table entries + * table entries + * $Revision: 44 $ * - *****************************************************************************/ + ******************************************************************************/ /* * Copyright (C) 2000 R. Byron Moore @@ -27,20 +27,20 @@ #include "acpi.h" #include "amlcode.h" -#include "namesp.h" -#include "interp.h" -#include "tables.h" +#include "acnamesp.h" +#include "acinterp.h" +#include "actables.h" #define _COMPONENT NAMESPACE - MODULE_NAME ("nsobject"); + MODULE_NAME ("nsobject") -/**************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_ns_attach_object * - * PARAMETERS: Handle - Handle of nte + * PARAMETERS: Node - Parent Node * Object - Object to be attached * Type - Type of object, or ACPI_TYPE_ANY if not * known @@ -51,17 +51,16 @@ * * MUTEX: Assumes namespace is locked * - ***************************************************************************/ + ******************************************************************************/ ACPI_STATUS acpi_ns_attach_object ( - ACPI_HANDLE handle, - ACPI_HANDLE object, + ACPI_NAMESPACE_NODE *node, + ACPI_OPERAND_OBJECT *object, OBJECT_TYPE_INTERNAL type) { - ACPI_NAMED_OBJECT *this_entry = (ACPI_NAMED_OBJECT*) handle; - ACPI_OBJECT_INTERNAL *obj_desc; - ACPI_OBJECT_INTERNAL *previous_obj_desc; + ACPI_OPERAND_OBJECT *obj_desc; + ACPI_OPERAND_OBJECT *previous_obj_desc; OBJECT_TYPE_INTERNAL obj_type = ACPI_TYPE_ANY; u8 flags; u16 opcode; @@ -71,17 +70,17 @@ * Parameter validation */ - if (!acpi_gbl_root_object->child_table) { + if (!acpi_gbl_root_node) { /* Name space not initialized */ REPORT_ERROR ("Ns_attach_object: Name space not initialized"); return (AE_NO_NAMESPACE); } - if (!handle) { + if (!node) { /* Invalid handle */ - REPORT_ERROR ("Ns_attach_object: Null name handle"); + REPORT_ERROR ("Ns_attach_object: Null Named_obj handle"); return (AE_BAD_PARAMETER); } @@ -93,7 +92,7 @@ return (AE_BAD_PARAMETER); } - if (!VALID_DESCRIPTOR_TYPE (handle, ACPI_DESC_TYPE_NAMED)) { + if (!VALID_DESCRIPTOR_TYPE (node, ACPI_DESC_TYPE_NAMED)) { /* Not a name handle */ REPORT_ERROR ("Ns_attach_object: Invalid handle"); @@ -102,15 +101,15 @@ /* Check if this object is already attached */ - if (this_entry->object == object) { + if (node->object == object) { return (AE_OK); } - /* Get the current flags field of the NTE */ + /* Get the current flags field of the Node */ - flags = this_entry->flags; - flags &= ~NTE_AML_ATTACHMENT; + flags = node->flags; + flags &= ~ANOBJ_AML_ATTACHMENT; /* If null object, we will just install it */ @@ -121,27 +120,27 @@ } /* - * If the object is an NTE with an attached object, + * If the object is an Node with an attached object, * we will use that (attached) object */ else if (VALID_DESCRIPTOR_TYPE (object, ACPI_DESC_TYPE_NAMED) && - ((ACPI_NAMED_OBJECT*) object)->object) + ((ACPI_NAMESPACE_NODE *) object)->object) { /* * Value passed is a name handle and that name has a * non-null value. Use that name's value and type. */ - obj_desc = ((ACPI_NAMED_OBJECT*) object)->object; - obj_type = ((ACPI_NAMED_OBJECT*) object)->type; + obj_desc = ((ACPI_NAMESPACE_NODE *) object)->object; + obj_type = ((ACPI_NAMESPACE_NODE *) object)->type; /* * Copy appropriate flags */ - if (((ACPI_NAMED_OBJECT*) object)->flags & NTE_AML_ATTACHMENT) { - flags |= NTE_AML_ATTACHMENT; + if (((ACPI_NAMESPACE_NODE *) object)->flags & ANOBJ_AML_ATTACHMENT) { + flags |= ANOBJ_AML_ATTACHMENT; } } @@ -152,7 +151,7 @@ */ else { - obj_desc = (ACPI_OBJECT_INTERNAL *) object; + obj_desc = (ACPI_OPERAND_OBJECT *) object; /* If a valid type (non-ANY) was given, just use it */ @@ -173,10 +172,10 @@ else if (acpi_tb_system_table_pointer (object)) { /* * Object points into the AML stream. - * Set a flag bit in the NTE to indicate this + * Set a flag bit in the Node to indicate this */ - flags |= NTE_AML_ATTACHMENT; + flags |= ANOBJ_AML_ATTACHMENT; /* * The next byte (perhaps the next two bytes) @@ -263,13 +262,13 @@ /* Save the existing object (if any) for deletion later */ - previous_obj_desc = this_entry->object; + previous_obj_desc = node->object; /* Install the object and set the type, flags */ - this_entry->object = obj_desc; - this_entry->type = (u8) obj_type; - this_entry->flags = flags; + node->object = obj_desc; + node->type = (u8) obj_type; + node->flags |= flags; /* @@ -277,86 +276,12 @@ */ if (previous_obj_desc) { - /* One for the attach to the NTE */ - acpi_cm_remove_reference (previous_obj_desc); - /* Now delete */ - acpi_cm_remove_reference (previous_obj_desc); - } + /* One for the attach to the Node */ - return (AE_OK); -} - - -/**************************************************************************** - * - * FUNCTION: Acpi_ns_attach_method - * - * PARAMETERS: Handle - Handle of nte to be set - * Offset - Value to be set - * Length - Length associated with value - * - * DESCRIPTION: Record the given offset and p-code length of the method - * whose handle is passed - * - * MUTEX: Assumes namespace is locked - * - ***************************************************************************/ - -ACPI_STATUS -acpi_ns_attach_method ( - ACPI_HANDLE handle, - u8 *pcode_addr, - u32 pcode_length) -{ - ACPI_OBJECT_INTERNAL *obj_desc; - ACPI_OBJECT_INTERNAL *previous_obj_desc; - ACPI_NAMED_OBJECT *this_entry = (ACPI_NAMED_OBJECT*) handle; - - - /* Parameter validation */ - - if (!acpi_gbl_root_object->child_table) { - /* Name space uninitialized */ - - REPORT_ERROR ("Ns_attach_method: name space uninitialized"); - return (AE_NO_NAMESPACE); - } - - if (!handle) { - /* Null name handle */ - - REPORT_ERROR ("Ns_attach_method: null name handle"); - return (AE_BAD_PARAMETER); - } - - - /* Allocate a method descriptor */ - - obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_METHOD); - if (!obj_desc) { - /* Method allocation failure */ - - REPORT_ERROR ("Ns_attach_method: allocation failure"); - return (AE_NO_MEMORY); - } - - /* Init the method info */ - - obj_desc->method.pcode = pcode_addr; - obj_desc->method.pcode_length = pcode_length; - - /* Update reference count and install */ - - acpi_cm_add_reference (obj_desc); - - previous_obj_desc = this_entry->object; - this_entry->object = obj_desc; + acpi_cm_remove_reference (previous_obj_desc); + /* Now delete */ - /* - * Delete an existing object. Don't try to re-use in case it is shared - */ - if (previous_obj_desc) { acpi_cm_remove_reference (previous_obj_desc); } @@ -364,11 +289,11 @@ } -/**************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_ns_detach_object * - * PARAMETERS: Object - An object whose Value will be deleted + * PARAMETERS: Node - An object whose Value will be deleted * * RETURN: None. * @@ -376,24 +301,23 @@ * Value is an allocated object, it is freed. Otherwise, the * field is simply cleared. * - ***************************************************************************/ + ******************************************************************************/ void acpi_ns_detach_object ( - ACPI_HANDLE object) + ACPI_NAMESPACE_NODE *node) { - ACPI_NAMED_OBJECT *entry = object; - ACPI_OBJECT_INTERNAL *obj_desc; + ACPI_OPERAND_OBJECT *obj_desc; - obj_desc = entry->object; + obj_desc = node->object; if (!obj_desc) { return; } /* Clear the entry in all cases */ - entry->object = NULL; + node->object = NULL; /* Found a valid value */ @@ -412,16 +336,16 @@ } -/**************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_ns_get_attached_object * - * PARAMETERS: Handle - Handle of nte to be examined + * PARAMETERS: Handle - Parent Node to be examined * - * RETURN: Current value of the object field from nte whose handle is - * passed + * RETURN: Current value of the object field from the Node whose + * handle is passed * - ***************************************************************************/ + ******************************************************************************/ void * acpi_ns_get_attached_object ( @@ -435,122 +359,7 @@ return (NULL); } - return (((ACPI_NAMED_OBJECT*) handle)->object); -} - - -/**************************************************************************** - * - * FUNCTION: Acpi_ns_compare_object - * - * PARAMETERS: Obj_handle - A namespace entry - * Level - Current nesting level - * Obj_desc - The value to be compared - * - * DESCRIPTION: A User_function called by Acpi_ns_walk_namespace(). It performs - * a comparison for Acpi_ns_find_attached_object(). The comparison is against - * the value in the value field of the Obj_handle (an NTE). - * If a match is found, the handle is returned, which aborts - * Acpi_ns_walk_namespace. - * - ***************************************************************************/ - -ACPI_STATUS -acpi_ns_compare_object ( - ACPI_HANDLE obj_handle, - u32 level, - void *obj_desc, - void **return_value) -{ - - if (((ACPI_NAMED_OBJECT*) obj_handle)->object == obj_desc) { - if (return_value) { - *return_value = obj_handle; - } - - /* Stop the walk */ - return AE_CTRL_TERMINATE; - } - - /* Not found, continue the walk */ - return AE_OK; -} - - -/**************************************************************************** - * - * FUNCTION: Acpi_ns_find_attached_object - * - * PARAMETERS: *Obj_desc - Value to be found in ptr_val field. - * Start_handle - Root of subtree to be searched, or - * NS_ALL to search the entire namespace - * Max_depth - Maximum depth of search. Use INT_MAX - * for an effectively unlimited depth. - * - * DESCRIPTION: Traverse the name space until finding a name whose Value field - * matches the Obj_desc parameter, and return a handle to that - * name, or (ACPI_HANDLE)0 if none exists. - * if Start_handle is NS_ALL (null) search from the root, - * else it is a handle whose children are to be searched. - * - ***************************************************************************/ - -ACPI_HANDLE -acpi_ns_find_attached_object ( - ACPI_OBJECT_INTERNAL *obj_desc, - ACPI_HANDLE start_handle, - s32 max_depth) -{ - ACPI_HANDLE ret_object; - ACPI_STATUS status; - - - /* Parameter validation */ - - if (!obj_desc) { - return (NULL); - } - - if (0 == max_depth) { - return (NULL); - } - - if (!acpi_gbl_root_object->child_table) { - /* - * If the name space has not been initialized, - * there surely are no matching values. - */ - return (NULL); - } - - if (NS_ALL == start_handle) { - start_handle = acpi_gbl_root_object; - } - - else { - /* - * If base is not the root and has no children, - * there is nothing to search. - */ - return (NULL); - } - - - /* - * Walk namespace until a match is found. - * Either the matching object is returned, or NULL in case - * of no match. - */ - status = acpi_ns_walk_namespace (ACPI_TYPE_ANY, start_handle, - max_depth, NS_WALK_NO_UNLOCK, - acpi_ns_compare_object, - obj_desc, &ret_object); - - if (ACPI_FAILURE (status)) { - ret_object = NULL; - } - - return (ret_object); + return (((ACPI_NAMESPACE_NODE *) handle)->object); } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/namespace/nssearch.c linux/drivers/acpi/namespace/nssearch.c --- v2.4.0-test8/linux/drivers/acpi/namespace/nssearch.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/namespace/nssearch.c Fri Sep 15 14:30:30 2000 @@ -1,9 +1,9 @@ - -/****************************************************************************** +/******************************************************************************* * * Module Name: nssearch - Namespace search + * $Revision: 57 $ * - *****************************************************************************/ + ******************************************************************************/ /* * Copyright (C) 2000 R. Byron Moore @@ -26,192 +26,132 @@ #include "acpi.h" #include "amlcode.h" -#include "interp.h" -#include "namesp.h" +#include "acinterp.h" +#include "acnamesp.h" #define _COMPONENT NAMESPACE - MODULE_NAME ("nssearch"); + MODULE_NAME ("nssearch") -/**************************************************************************** +/******************************************************************************* * - * FUNCTION: Acpi_ns_search_one_scope + * FUNCTION: Acpi_ns_search_node * - * PARAMETERS: *Entry_name - Ascii ACPI name to search for - * *Name_table - Starting table where search will begin + * PARAMETERS: *Target_name - Ascii ACPI name to search for + * *Node - Starting table where search will begin * Type - Object type to match - * **Ret_entry - Where the matched NTE is returned - * *Ret_info - Where info about the search is returned + * **Return_node - Where the matched Named obj is returned * - * RETURN: Status and return information via NS_SEARCH_DATA + * RETURN: Status * * DESCRIPTION: Search a single namespace table. Performs a simple search, * does not add entries or search parents. * - ***************************************************************************/ + * + * Named object lists are built (and subsequently dumped) in the + * order in which the names are encountered during the namespace load; + * + * All namespace searching is linear in this implementation, but + * could be easily modified to support any improved search + * algorithm. However, the linear search was chosen for simplicity + * and because the trees are small and the other interpreter + * execution overhead is relatively high. + * + ******************************************************************************/ ACPI_STATUS -acpi_ns_search_one_scope ( - u32 entry_name, - ACPI_NAME_TABLE *name_table, +acpi_ns_search_node ( + u32 target_name, + ACPI_NAMESPACE_NODE *node, OBJECT_TYPE_INTERNAL type, - ACPI_NAMED_OBJECT **ret_entry, - NS_SEARCH_DATA *ret_info) + ACPI_NAMESPACE_NODE **return_node) { - u32 position; - ACPI_NAME_TABLE *this_table; - ACPI_NAME_TABLE *previous_table = name_table; - ACPI_NAMED_OBJECT *entries; - u8 table_full = TRUE; - ACPI_NAME_TABLE *table_with_empty_slots = NULL; - u32 empty_slot_position = 0; + ACPI_NAMESPACE_NODE *next_node; - /* - * Name tables are built (and subsequently dumped) in the - * order in which the names are encountered during the namespace load; - * - * All namespace searching will be linear; If a table overflows an - * additional segment will be allocated and added (chained). - * - * Start linear search at top of table - */ - position = 0; - this_table = name_table; - entries = this_table->entries; - - - /* Init return data */ - - if (ret_info) { - ret_info->name_table = this_table; - } - /* - * Search entire name table, including all linked appendages + * Search for name in this table, which is to say that we must search + * for the name among the children of this object */ - while (this_table) { - /* - * Search for name in table, starting at Position. Stop - * searching upon examining all entries in the table. - * - */ + next_node = node->child; + while (next_node) { + /* Check for match against the name */ - entries = this_table->entries; - while (position < NS_TABLE_SIZE) { - /* Check for a valid entry */ - - if (!entries[position].name) { - if (table_full) { - /* - * There is room in the table for more - * entries, if necessary - */ - - table_full = FALSE; - table_with_empty_slots = this_table; - empty_slot_position = position; - } - } - - /* Search for name in table */ + if (next_node->name == target_name) { + /* + * Found matching entry. Capture type if + * appropriate before returning the entry. + */ - else if (entries[position].name == entry_name) { - /* - * Found matching entry. Capture type if - * appropriate before returning the entry. - */ - - /* - * The Def_field_defn and Bank_field_defn cases - * are actually looking up the Region in which - * the field will be defined - */ - - if ((INTERNAL_TYPE_DEF_FIELD_DEFN == type) || - (INTERNAL_TYPE_BANK_FIELD_DEFN == type)) - { - type = ACPI_TYPE_REGION; - } - - /* - * Scope, Def_any, and Index_field_defn are bogus - * "types" which do not actually have anything - * to do with the type of the name being looked - * up. For any other value of Type, if the type - * stored in the entry is Any (i.e. unknown), - * save the actual type. - */ - - if (type != INTERNAL_TYPE_SCOPE && - type != INTERNAL_TYPE_DEF_ANY && - type != INTERNAL_TYPE_INDEX_FIELD_DEFN && - entries[position].type == ACPI_TYPE_ANY) - { - entries[position].type = (u8) type; - } + /* + * The Def_field_defn and Bank_field_defn cases + * are actually looking up the Region in which + * the field will be defined + */ - *ret_entry = &entries[position]; - return (AE_OK); + if ((INTERNAL_TYPE_DEF_FIELD_DEFN == type) || + (INTERNAL_TYPE_BANK_FIELD_DEFN == type)) + { + type = ACPI_TYPE_REGION; } + /* + * Scope, Def_any, and Index_field_defn are bogus + * "types" which do not actually have anything + * to do with the type of the name being looked + * up. For any other value of Type, if the type + * stored in the entry is Any (i.e. unknown), + * save the actual type. + */ - /* Didn't match name, move on to the next entry */ + if (type != INTERNAL_TYPE_SCOPE && + type != INTERNAL_TYPE_DEF_ANY && + type != INTERNAL_TYPE_INDEX_FIELD_DEFN && + next_node->type == ACPI_TYPE_ANY) + { + next_node->type = (u8) type; + } - position++; + *return_node = next_node; + return (AE_OK); } /* - * Just examined last slot in this table, move on - * to next appendate. - * All appendages, even to the root NT, contain - * NS_TABLE_SIZE entries. + * The last entry in the list points back to the parent, + * so a flag is used to indicate the end-of-list */ + if (next_node->flags & ANOBJ_END_OF_PEER_LIST) { + /* Searched entire list, we are done */ + + break; + } - previous_table = this_table; - this_table = this_table->next_table; + /* Didn't match name, move on to the next peer object */ - position = 0; + next_node = next_node->peer; } /* Searched entire table, not found */ - if (ret_info) { - /* - * Save info on if/where a slot is available - * (name was not found) - */ - - ret_info->table_full = table_full; - if (table_full) { - ret_info->name_table = previous_table; - } - - else { - ret_info->position = empty_slot_position; - ret_info->name_table = table_with_empty_slots; - } - } - return (AE_NOT_FOUND); } -/**************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_ns_search_parent_tree * - * PARAMETERS: *Entry_name - Ascii ACPI name to search for - * *Name_table - Starting table where search will begin + * PARAMETERS: *Target_name - Ascii ACPI name to search for + * *Node - Starting table where search will begin * Type - Object type to match - * **Ret_entry - Where the matched NTE is returned + * **Return_node - Where the matched Named Obj is returned * * RETURN: Status * @@ -227,274 +167,79 @@ * indicates that the name is not found" (From ACPI Specification, * section 5.3) * - ***************************************************************************/ - + ******************************************************************************/ ACPI_STATUS acpi_ns_search_parent_tree ( - u32 entry_name, - ACPI_NAME_TABLE *name_table, + u32 target_name, + ACPI_NAMESPACE_NODE *node, OBJECT_TYPE_INTERNAL type, - ACPI_NAMED_OBJECT **ret_entry) + ACPI_NAMESPACE_NODE **return_node) { ACPI_STATUS status; - ACPI_NAMED_OBJECT *parent_entry; - ACPI_NAMED_OBJECT *entries; + ACPI_NAMESPACE_NODE *parent_node; - entries = name_table->entries; + parent_node = acpi_ns_get_parent_object (node); /* - * If no parent or type is "local", we won't be searching the - * parent tree. + * If there is no parent (at the root) or type is "local", we won't be + * searching the parent tree. */ - - if (!acpi_ns_local (type) && - name_table->parent_entry) + if ((acpi_ns_local (type)) || + (!parent_node)) { - parent_entry = name_table->parent_entry; - /* - * Search parents until found or we have backed up to - * the root - */ - - while (parent_entry) { - /* Search parent scope */ - /* TBD: [Investigate] Why ACPI_TYPE_ANY? */ - - status = acpi_ns_search_one_scope (entry_name, - parent_entry->child_table, - ACPI_TYPE_ANY, - ret_entry, NULL); - if (status == AE_OK) { - return (status); - } - - /* - * Not found here, go up another level - * (until we reach the root) - */ - - parent_entry = acpi_ns_get_parent_entry (parent_entry); - } - - /* Not found in parent tree */ - } - - - return (AE_NOT_FOUND); -} - - -/**************************************************************************** - * - * FUNCTION: Acpi_ns_create_and_link_new_table - * - * PARAMETERS: *Name_table - The table that is to be "extended" by - * the creation of an appendage table. - * - * RETURN: Status - * - * DESCRIPTION: Allocate a new namespace table, initialize it, and link it - * into the parent table. - * - * NOTE: We are in the first or second pass load mode, want to - * add a new table entry, and the current table is full. - * - ***************************************************************************/ - -ACPI_STATUS -acpi_ns_create_and_link_new_table ( - ACPI_NAME_TABLE *name_table) -{ - ACPI_NAME_TABLE *new_table; - ACPI_NAMED_OBJECT *parent_entry; - ACPI_STATUS status = AE_OK; - - - /* Sanity check on the data structure */ - - if (name_table->next_table) { - /* We should never get here (an appendage already allocated) */ - - return (AE_AML_INTERNAL); - } - - - /* - * We can use the parent entries from the current table - * Since the parent information remains the same. - */ - parent_entry = name_table->parent_entry; - - - /* Allocate and chain an appendage to the filled table */ - - new_table = acpi_ns_allocate_name_table (NS_TABLE_SIZE); - if (!new_table) { - REPORT_ERROR ("Name Table appendage allocation failure"); - return (AE_NO_MEMORY); - } - /* - * Allocation successful. Init the new table. - */ - name_table->next_table = new_table; - acpi_ns_initialize_table (new_table, parent_entry->child_table, - parent_entry); - - return (status); -} - - -/**************************************************************************** - * - * FUNCTION: Acpi_ns_initialize_table - * - * PARAMETERS: New_table - The new table to be initialized - * Parent_table - The parent (owner) scope - * Parent_entry - The NTE for the parent - * - * RETURN: None - * - * DESCRIPTION: Initialize a new namespace table. Simple, but called - * from several places -- code should be kept in one place. - * - ***************************************************************************/ - -void -acpi_ns_initialize_table ( - ACPI_NAME_TABLE *new_table, - ACPI_NAME_TABLE *parent_table, - ACPI_NAMED_OBJECT *parent_entry) -{ - u8 i; - - - new_table->parent_entry = parent_entry; - new_table->parent_table = parent_table; - - - /* Init each named object entry in the table */ - - for (i = 0; i < NS_TABLE_SIZE; i++) { - new_table->entries[i].this_index = i; - new_table->entries[i].data_type = ACPI_DESC_TYPE_NAMED; + return (AE_NOT_FOUND); } -} - - -/**************************************************************************** - * - * FUNCTION: Acpi_ns_initialize_entry - * - * PARAMETERS: Name_table - The containing table for the new NTE - * Position - Position (index) of the new NTE in the table - * Entry_name - ACPI name of the new entry - * Type - ACPI object type of the new entry - * Previous_entry - Link back to the previous entry (can span - * multiple tables) - * - * RETURN: None - * - * DESCRIPTION: Initialize a new entry within a namespace table. - * - ***************************************************************************/ - -void -acpi_ns_initialize_entry ( - ACPI_WALK_STATE *walk_state, - ACPI_NAME_TABLE *name_table, - u32 position, - u32 entry_name, - OBJECT_TYPE_INTERNAL type) -{ - ACPI_NAMED_OBJECT *new_entry; - u16 owner_id = TABLE_ID_DSDT; - ACPI_NAMED_OBJECT *entries; + /* Search the parent tree */ /* - * Get the owner ID from the Walk state - * The owner ID is used to track table deletion and - * deletion of objects created by methods + * Search parents until found the target or we have backed up to + * the root */ - if (walk_state) { - owner_id = walk_state->owner_id; - } - - /* The new entry is given by two parameters */ - - entries = name_table->entries; - new_entry = &entries[position]; - - /* Init the new entry */ - new_entry->data_type = ACPI_DESC_TYPE_NAMED; - new_entry->name = entry_name; - new_entry->owner_id = owner_id; - new_entry->reference_count = 1; + while (parent_node) { + /* Search parent scope */ + /* TBD: [Investigate] Why ACPI_TYPE_ANY? */ + status = acpi_ns_search_node (target_name, parent_node, + ACPI_TYPE_ANY, return_node); - /* - * If adding a name with unknown type, or having to - * add the region in order to define fields in it, we - * have a forward reference. - */ + if (ACPI_SUCCESS (status)) { + return (status); + } - if ((ACPI_TYPE_ANY == type) || - (INTERNAL_TYPE_DEF_FIELD_DEFN == type) || - (INTERNAL_TYPE_BANK_FIELD_DEFN == type)) - { /* - * We don't want to abort here, however! - * We will fill in the actual type when the - * real definition is found later. + * Not found here, go up another level + * (until we reach the root) */ + parent_node = acpi_ns_get_parent_object (parent_node); } - /* - * The Def_field_defn and Bank_field_defn cases are actually - * looking up the Region in which the field will be defined - */ - - if ((INTERNAL_TYPE_DEF_FIELD_DEFN == type) || - (INTERNAL_TYPE_BANK_FIELD_DEFN == type)) - { - type = ACPI_TYPE_REGION; - } - /* - * Scope, Def_any, and Index_field_defn are bogus "types" which do - * not actually have anything to do with the type of the name - * being looked up. Save any other value of Type as the type of - * the entry. - */ + /* Not found in parent tree */ - if ((type != INTERNAL_TYPE_SCOPE) && - (type != INTERNAL_TYPE_DEF_ANY) && - (type != INTERNAL_TYPE_INDEX_FIELD_DEFN)) - { - new_entry->type = (u8) type; - } - - return; + return (AE_NOT_FOUND); } -/**************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_ns_search_and_enter * - * PARAMETERS: Entry_name - Ascii ACPI name to search for (4 chars) - * *Name_table - Starting table where search will begin - * Interpreter_mode - Add names only in MODE_Load_pass_x. Otherwise, - * search only. + * PARAMETERS: Target_name - Ascii ACPI name to search for (4 chars) + * Walk_state - Current state of the walk + * *Node - Starting table where search will begin + * Interpreter_mode - Add names only in MODE_Load_pass_x. + * Otherwise,search only. * Type - Object type to match - * **Ret_entry - Where the matched NTE is returned + * Flags - Flags describing the search restrictions + * **Return_node - Where the Node is returned * * RETURN: Status * @@ -506,51 +251,48 @@ * In IMODE_EXECUTE, search only. * In other modes, search and add if not found. * - ***************************************************************************/ + ******************************************************************************/ ACPI_STATUS acpi_ns_search_and_enter ( - u32 entry_name, + u32 target_name, ACPI_WALK_STATE *walk_state, - ACPI_NAME_TABLE *name_table, + ACPI_NAMESPACE_NODE *node, OPERATING_MODE interpreter_mode, OBJECT_TYPE_INTERNAL type, u32 flags, - ACPI_NAMED_OBJECT **ret_entry) + ACPI_NAMESPACE_NODE **return_node) { - u32 position; /* position in table */ ACPI_STATUS status; - NS_SEARCH_DATA search_info; - ACPI_NAMED_OBJECT *entry; - ACPI_NAMED_OBJECT *entries; + ACPI_NAMESPACE_NODE *new_node; /* Parameter validation */ - if (!name_table || !entry_name || !ret_entry) { - REPORT_ERROR ("Ns_search_and_enter: bad parameter"); + if (!node || !target_name || !return_node) { + REPORT_ERROR ("Ns_search_and_enter: bad (null)parameter"); return (AE_BAD_PARAMETER); } /* Name must consist of printable characters */ - if (!acpi_cm_valid_acpi_name (entry_name)) { + if (!acpi_cm_valid_acpi_name (target_name)) { + REPORT_ERROR ("Ns_search_and_enter: Bad character in ACPI Name"); return (AE_BAD_CHARACTER); } /* Try to find the name in the table specified by the caller */ - *ret_entry = ENTRY_NOT_FOUND; - status = acpi_ns_search_one_scope (entry_name, name_table, - type, ret_entry, &search_info); + *return_node = ENTRY_NOT_FOUND; + status = acpi_ns_search_node (target_name, node, + type, return_node); if (status != AE_NOT_FOUND) { /* * Either found it or there was an error * -- finished either way */ - return (status); } @@ -573,10 +315,9 @@ * to ACPI specification */ - status = acpi_ns_search_parent_tree (entry_name, name_table, - type, ret_entry); - - if (status == AE_OK) { + status = acpi_ns_search_parent_tree (target_name, node, + type, return_node); + if (ACPI_SUCCESS (status)) { return (status); } } @@ -585,61 +326,22 @@ /* * In execute mode, just search, never add names. Exit now. */ - if (interpreter_mode == IMODE_EXECUTE) { return (AE_NOT_FOUND); } - /* - * Extract the pertinent info from the search result struct. - * Name_table and position might now point to an appendage - */ - name_table = search_info.name_table; - position = search_info.position; + /* Create the new named object */ - - /* - * This block handles the case where the existing table is full. - * we must allocate a new table before we can initialize a new entry - */ - - if (search_info.table_full) { - status = acpi_ns_create_and_link_new_table (name_table); - if (status != AE_OK) { - return (status); - } - - /* Point to the first slot in the new table */ - - name_table = name_table->next_table; - position = 0; + new_node = acpi_ns_create_node (target_name); + if (!new_node) { + return (AE_NO_MEMORY); } + /* Install the new object into the parent's list of children */ - /* - * There is room in the table (or we have just allocated a new one.) - * Initialize the new entry - */ - - acpi_ns_initialize_entry (walk_state, name_table, position, - entry_name, type); - - - entries = name_table->entries; - *ret_entry = &entries[position]; - entry = &entries[position]; - - /* - * Increment the reference count(s) of all parents up to - * the root! - */ - - while (acpi_ns_get_parent_entry (entry)) { - entry = acpi_ns_get_parent_entry (entry); - entry->reference_count++; - } - + acpi_ns_install_node (walk_state, node, new_node, type); + *return_node = new_node; return (AE_OK); } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/namespace/nsutils.c linux/drivers/acpi/namespace/nsutils.c --- v2.4.0-test8/linux/drivers/acpi/namespace/nsutils.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/namespace/nsutils.c Fri Sep 15 14:30:30 2000 @@ -1,8 +1,8 @@ - /****************************************************************************** * * Module Name: nsutils - Utilities for accessing ACPI namespace, accessing - * parents and siblings and Scope manipulation + * parents and siblings and Scope manipulation + * $Revision: 69 $ * *****************************************************************************/ @@ -26,13 +26,13 @@ #include "acpi.h" -#include "namesp.h" -#include "interp.h" +#include "acnamesp.h" +#include "acinterp.h" #include "amlcode.h" -#include "tables.h" +#include "actables.h" #define _COMPONENT NAMESPACE - MODULE_NAME ("nsutils"); + MODULE_NAME ("nsutils") /**************************************************************************** @@ -49,7 +49,7 @@ u8 acpi_ns_valid_root_prefix ( - char prefix) + NATIVE_CHAR prefix) { return ((u8) (prefix == '\\')); @@ -70,7 +70,7 @@ u8 acpi_ns_valid_path_separator ( - char sep) + NATIVE_CHAR sep) { return ((u8) (sep == '.')); @@ -81,9 +81,9 @@ * * FUNCTION: Acpi_ns_get_type * - * PARAMETERS: Handle - Handle of nte to be examined + * PARAMETERS: Handle - Parent Node to be examined * - * RETURN: Type field from nte whose handle is passed + * RETURN: Type field from Node whose handle is passed * ***************************************************************************/ @@ -93,13 +93,11 @@ { if (!handle) { - /* Handle invalid */ - REPORT_WARNING ("Ns_get_type: Null handle"); return (ACPI_TYPE_ANY); } - return (((ACPI_NAMED_OBJECT*) handle)->type); + return (((ACPI_NAMESPACE_NODE *) handle)->type); } @@ -114,19 +112,19 @@ * ***************************************************************************/ -s32 +u32 acpi_ns_local ( OBJECT_TYPE_INTERNAL type) { if (!acpi_cm_valid_object_type (type)) { - /* type code out of range */ + /* Type code out of range */ REPORT_WARNING ("Ns_local: Invalid Object Type"); return (NSP_NORMAL); } - return ((s32) acpi_gbl_ns_properties[type] & NSP_LOCAL); + return ((u32) acpi_gbl_ns_properties[type] & NSP_LOCAL); } @@ -147,12 +145,12 @@ ACPI_STATUS acpi_ns_internalize_name ( - char *external_name, - char **converted_name) + NATIVE_CHAR *external_name, + NATIVE_CHAR **converted_name) { - char *result = NULL; - char *internal_name; - ACPI_SIZE num_segments; + NATIVE_CHAR *result = NULL; + NATIVE_CHAR *internal_name; + u32 num_segments; u8 fully_qualified = FALSE; u32 i; @@ -235,7 +233,7 @@ } else { - /* Convert char to uppercase and save it */ + /* Convert s8 to uppercase and save it */ result[i] = (char) TOUPPER (*external_name); external_name++; @@ -273,166 +271,17 @@ /**************************************************************************** * - * FUNCTION: Acpi_ns_externalize_name - * - * PARAMETERS: *Internal_name - Internal representation of name - * **Converted_name - Where to return the resulting - * external representation of name - * - * RETURN: Status - * - * DESCRIPTION: Convert internal name (e.g. 5c 2f 02 5f 50 52 5f 43 50 55 30) - * to its external form (e.g. "\_PR_.CPU0") - * - ****************************************************************************/ - -ACPI_STATUS -acpi_ns_externalize_name ( - u32 internal_name_length, - char *internal_name, - u32 *converted_name_length, - char **converted_name) -{ - u32 prefix_length = 0; - u32 names_index = 0; - u32 names_count = 0; - u32 i = 0; - u32 j = 0; - - if (internal_name_length < 0 || - !internal_name || - !converted_name_length || - !converted_name) - { - return (AE_BAD_PARAMETER); - } - - /* - * Check for a prefix (one '\' | one or more '^'). - */ - switch (internal_name[0]) - { - case '\\': - prefix_length = 1; - break; - - case '^': - for (i = 0; i < internal_name_length; i++) { - if (internal_name[i] != '^') { - prefix_length = i + 1; - } - } - - if (i == internal_name_length) { - prefix_length = i; - } - - break; - } - - /* - * Check for object names. Note that there could be 0-255 of these - * 4-byte elements. - */ - if (prefix_length < internal_name_length) { - switch (internal_name[prefix_length]) - { - - /* 4-byte names */ - - case AML_MULTI_NAME_PREFIX_OP: - names_index = prefix_length + 2; - names_count = (u32) internal_name[prefix_length + 1]; - break; - - - /* two 4-byte names */ - - case AML_DUAL_NAME_PREFIX: - names_index = prefix_length + 1; - names_count = 2; - break; - - - /* Null_name */ - - case 0: - names_index = 0; - names_count = 0; - break; - - - /* one 4-byte name */ - - default: - names_index = prefix_length; - names_count = 1; - break; - } - } - - /* - * Calculate the length of Converted_name, which equals the length - * of the prefix, length of all object names, length of any required - * punctuation ('.') between object names, plus the NULL terminator. - */ - *converted_name_length = prefix_length + (4 * names_count) + - ((names_count > 0) ? (names_count - 1) : 0) + 1; - - /* - * Check to see if we're still in bounds. If not, there's a problem - * with Internal_name (invalid format). - */ - if (*converted_name_length > internal_name_length) { - REPORT_ERROR ("Ns_externalize_name: Invalid internal name.\n"); - return (AE_BAD_PATHNAME); - } - - /* - * Build Converted_name... - */ - - (*converted_name) = acpi_cm_callocate (*converted_name_length); - if (!(*converted_name)) { - return (AE_NO_MEMORY); - } - - j = 0; - - for (i = 0; i < prefix_length; i++) { - (*converted_name)[j++] = internal_name[i]; - } - - if (names_count > 0) { - for (i = 0; i < names_count; i++) { - if (i > 0) { - (*converted_name)[j++] = '.'; - } - - (*converted_name)[j++] = internal_name[names_index++]; - (*converted_name)[j++] = internal_name[names_index++]; - (*converted_name)[j++] = internal_name[names_index++]; - (*converted_name)[j++] = internal_name[names_index++]; - } - } - - return (AE_OK); -} - - -/**************************************************************************** - * * FUNCTION: Acpi_ns_convert_handle_to_entry * - * PARAMETERS: Handle - Handle to be converted to an NTE + * PARAMETERS: Handle - Handle to be converted to an Node * * RETURN: A Name table entry pointer * - * DESCRIPTION: Convert a namespace handle to a real NTE + * DESCRIPTION: Convert a namespace handle to a real Node * ****************************************************************************/ -ACPI_NAMED_OBJECT* +ACPI_NAMESPACE_NODE * acpi_ns_convert_handle_to_entry ( ACPI_HANDLE handle) { @@ -444,21 +293,21 @@ */ if (!handle) { - return NULL; + return (NULL); } if (handle == ACPI_ROOT_OBJECT) { - return acpi_gbl_root_object; + return (acpi_gbl_root_node); } /* We can at least attempt to verify the handle */ if (!VALID_DESCRIPTOR_TYPE (handle, ACPI_DESC_TYPE_NAMED)) { - return NULL; + return (NULL); } - return (ACPI_NAMED_OBJECT*) handle; + return ((ACPI_NAMESPACE_NODE *) handle); } @@ -466,16 +315,17 @@ * * FUNCTION: Acpi_ns_convert_entry_to_handle * - * PARAMETERS: Nte - NTE to be converted to a Handle + * PARAMETERS: Node - Node to be converted to a Handle * * RETURN: An USER ACPI_HANDLE * - * DESCRIPTION: Convert a real NTE to a namespace handle + * DESCRIPTION: Convert a real Node to a namespace handle * ****************************************************************************/ ACPI_HANDLE -acpi_ns_convert_entry_to_handle(ACPI_NAMED_OBJECT*nte) +acpi_ns_convert_entry_to_handle ( + ACPI_NAMESPACE_NODE *node) { @@ -485,21 +335,21 @@ * and keep all pointers within this subsystem! */ - return (ACPI_HANDLE) nte; + return ((ACPI_HANDLE) node); /* --------------------------------------------------- - if (!Nte) { - return NULL; + if (!Node) { + return (NULL); } - if (Nte == Acpi_gbl_Root_object) { - return ACPI_ROOT_OBJECT; + if (Node == Acpi_gbl_Root_node) { + return (ACPI_ROOT_OBJECT); } - return (ACPI_HANDLE) Nte; + return ((ACPI_HANDLE) Node); ------------------------------------------------------*/ } @@ -519,11 +369,11 @@ void acpi_ns_terminate (void) { - ACPI_OBJECT_INTERNAL *obj_desc; - ACPI_NAMED_OBJECT *entry; + ACPI_OPERAND_OBJECT *obj_desc; + ACPI_NAMESPACE_NODE *this_node; - entry = acpi_gbl_root_object; + this_node = acpi_gbl_root_node; /* * 1) Free the entire namespace -- all objects, tables, and stacks @@ -533,22 +383,19 @@ * (additional table descriptors) */ - acpi_ns_delete_namespace_subtree (entry); + acpi_ns_delete_namespace_subtree (this_node); /* Detach any object(s) attached to the root */ - obj_desc = acpi_ns_get_attached_object (entry); + obj_desc = acpi_ns_get_attached_object (this_node); if (obj_desc) { - acpi_ns_detach_object (entry); + acpi_ns_detach_object (this_node); acpi_cm_remove_reference (obj_desc); } - acpi_ns_delete_name_table (entry->child_table); - entry->child_table = NULL; + acpi_ns_delete_children (this_node); - REPORT_SUCCESS ("Entire namespace and objects deleted"); - /* * 2) Now we can delete the ACPI tables */ @@ -570,7 +417,7 @@ * ***************************************************************************/ -s32 +u32 acpi_ns_opens_scope ( OBJECT_TYPE_INTERNAL type) { @@ -582,47 +429,46 @@ return (NSP_NORMAL); } - return (((s32) acpi_gbl_ns_properties[type]) & NSP_NEWSCOPE); + return (((u32) acpi_gbl_ns_properties[type]) & NSP_NEWSCOPE); } /**************************************************************************** * - * FUNCTION: Acpi_ns_get_named_object + * FUNCTION: Acpi_ns_get_node * * PARAMETERS: *Pathname - Name to be found, in external (ASL) format. The * \ (backslash) and ^ (carat) prefixes, and the * . (period) to separate segments are supported. - * In_scope - Root of subtree to be searched, or NS_ALL for the + * Start_node - Root of subtree to be searched, or NS_ALL for the * root of the name space. If Name is fully - * qualified (first char is '\'), the passed value + * qualified (first s8 is '\'), the passed value * of Scope will not be accessed. - * Out_nte - Where the Nte is returned + * Return_node - Where the Node is returned * * DESCRIPTION: Look up a name relative to a given scope and return the - * corresponding NTE. NOTE: Scope can be null. + * corresponding Node. NOTE: Scope can be null. * * MUTEX: Locks namespace * ***************************************************************************/ ACPI_STATUS -acpi_ns_get_named_object ( - char *pathname, - ACPI_NAME_TABLE *in_scope, - ACPI_NAMED_OBJECT **out_nte) +acpi_ns_get_node ( + NATIVE_CHAR *pathname, + ACPI_NAMESPACE_NODE *start_node, + ACPI_NAMESPACE_NODE **return_node) { ACPI_GENERIC_STATE scope_info; ACPI_STATUS status; - ACPI_NAMED_OBJECT *obj_entry = NULL; - char *internal_path = NULL; + NATIVE_CHAR *internal_path = NULL; - scope_info.scope.name_table = in_scope; + scope_info.scope.node = start_node; /* Ensure that the namespace has been initialized */ - if (!acpi_gbl_root_object->child_table) { + if (!acpi_gbl_root_node) { return (AE_NO_NAMESPACE); } @@ -643,13 +489,13 @@ /* NS_ALL means start from the root */ - if (NS_ALL == scope_info.scope.name_table) { - scope_info.scope.name_table = acpi_gbl_root_object->child_table; + if (NS_ALL == scope_info.scope.node) { + scope_info.scope.node = acpi_gbl_root_node; } else { - scope_info.scope.name_table = in_scope; - if (!scope_info.scope.name_table) { + scope_info.scope.node = start_node; + if (!scope_info.scope.node) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } @@ -660,12 +506,8 @@ status = acpi_ns_lookup (&scope_info, internal_path, ACPI_TYPE_ANY, IMODE_EXECUTE, NS_NO_UPSEARCH | NS_DONT_OPEN_SCOPE, - NULL, &obj_entry); - + NULL, return_node); - /* Return what was wanted - the NTE that matches the name */ - - *out_nte = obj_entry; unlock_and_exit: @@ -684,11 +526,11 @@ * * FUNCTION: Acpi_ns_find_parent_name * - * PARAMETERS: *Child_entry - nte whose name is to be found + * PARAMETERS: *Child_node - Named Obj whose name is to be found * * RETURN: The ACPI name * - * DESCRIPTION: Search for the given nte in its parent scope and return the + * DESCRIPTION: Search for the given obj in its parent scope and return the * name segment, or "????" if the parent name can't be found * (which "should not happen"). * @@ -696,18 +538,18 @@ ACPI_NAME acpi_ns_find_parent_name ( - ACPI_NAMED_OBJECT *child_entry) + ACPI_NAMESPACE_NODE *child_node) { - ACPI_NAMED_OBJECT *parent_entry; + ACPI_NAMESPACE_NODE *parent_node; - if (child_entry) { - /* Valid entry. Get the parent Nte */ + if (child_node) { + /* Valid entry. Get the parent Node */ - parent_entry = acpi_ns_get_parent_entry (child_entry); - if (parent_entry) { - if (parent_entry->name) { - return (parent_entry->name); + parent_node = acpi_ns_get_parent_object (child_node); + if (parent_node) { + if (parent_node->name) { + return (parent_node->name); } } @@ -717,92 +559,12 @@ return (ACPI_UNKNOWN_NAME); } -/**************************************************************************** - * - * FUNCTION: Acpi_ns_exist_downstream_sibling - * - * PARAMETERS: *This_entry - pointer to first nte to examine - * - * RETURN: TRUE if sibling is found, FALSE otherwise - * - * DESCRIPTION: Searches remainder of scope being processed to determine - * whether there is a downstream sibling to the current - * object. This function is used to determine what type of - * line drawing character to use when displaying namespace - * trees. - * - ***************************************************************************/ - -u8 -acpi_ns_exist_downstream_sibling ( - ACPI_NAMED_OBJECT *this_entry) -{ - - if (!this_entry) { - return FALSE; - } - - if (this_entry->name) { - return TRUE; - } - - -/* TBD: what did this really do? - if (This_entry->Next_entry) { - return TRUE; - } -*/ - return FALSE; -} - - -/**************************************************************************** - * - * FUNCTION: Acpi_ns_get_owner_table - * - * PARAMETERS: - * - * RETURN: - * - * DESCRIPTION: - * - ***************************************************************************/ - - -ACPI_NAME_TABLE * -acpi_ns_get_owner_table ( - ACPI_NAMED_OBJECT *this_entry) -{ - - /* - * Given an entry in the Name_table->Entries field of a name table, - * we can create a pointer to the beginning of the table as follows: - * - * 1) Starting with the the pointer to the entry, - * 2) Subtract the entry index * size of each entry to get a - * pointer to Entries[0] - * 3) Subtract the size of NAME_TABLE structure to get a pointer - * to the start. - * - * This saves having to put a pointer in every entry that points - * back to the beginning of the table and/or a pointer back to - * the parent. - */ - - return (ACPI_NAME_TABLE *) ((char *) this_entry - - (this_entry->this_index * - sizeof (ACPI_NAMED_OBJECT)) - - (sizeof (ACPI_NAME_TABLE) - - sizeof (ACPI_NAMED_OBJECT))); - -} - /**************************************************************************** * - * FUNCTION: Acpi_ns_get_parent_entry + * FUNCTION: Acpi_ns_get_parent_object * - * PARAMETERS: This_entry - Current table entry + * PARAMETERS: Node - Current table entry * * RETURN: Parent entry of the given entry * @@ -811,76 +573,58 @@ ***************************************************************************/ -ACPI_NAMED_OBJECT * -acpi_ns_get_parent_entry ( - ACPI_NAMED_OBJECT *this_entry) +ACPI_NAMESPACE_NODE * +acpi_ns_get_parent_object ( + ACPI_NAMESPACE_NODE *node) { - ACPI_NAME_TABLE *name_table; - name_table = acpi_ns_get_owner_table (this_entry); - /* - * Now that we have a pointer to the name table, we can just pluck - * the parent + * Walk to the end of this peer list. + * The last entry is marked with a flag and the peer + * pointer is really a pointer back to the parent. + * This saves putting a parent back pointer in each and + * every named object! */ - return (name_table->parent_entry); + while (!(node->flags & ANOBJ_END_OF_PEER_LIST)) { + node = node->peer; + } + + + return (node->peer); } /**************************************************************************** * - * FUNCTION: Acpi_ns_get_next_valid_entry + * FUNCTION: Acpi_ns_get_next_valid_object * - * PARAMETERS: This_entry - Current table entry + * PARAMETERS: Node - Current table entry * * RETURN: Next valid object in the table. NULL if no more valid * objects * * DESCRIPTION: Find the next valid object within a name table. + * Useful for implementing NULL-end-of-list loops. * ***************************************************************************/ -ACPI_NAMED_OBJECT * -acpi_ns_get_next_valid_entry ( - ACPI_NAMED_OBJECT *this_entry) +ACPI_NAMESPACE_NODE * +acpi_ns_get_next_valid_object ( + ACPI_NAMESPACE_NODE *node) { - ACPI_NAME_TABLE *name_table; - u32 index; - - - index = this_entry->this_index + 1; - name_table = acpi_ns_get_owner_table (this_entry); - - - while (name_table) { - if (index >= NS_TABLE_SIZE) { - /* We are at the end of this table */ - name_table = name_table->next_table; - index = 0; - continue; - } - - - /* Is this a valid (occupied) slot? */ - - if (name_table->entries[index].name) { - /* Found a valid entry, all done */ + /* If we are at the end of this peer list, return NULL */ - return (&name_table->entries[index]); - } - - /* Go to the next slot */ - - index++; + if (node->flags & ANOBJ_END_OF_PEER_LIST) { + return NULL; } - /* No more valid entries in this name table */ + /* Otherwise just return the next peer */ - return NULL; + return (node->peer); } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/namespace/nswalk.c linux/drivers/acpi/namespace/nswalk.c --- v2.4.0-test8/linux/drivers/acpi/namespace/nswalk.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/namespace/nswalk.c Fri Sep 15 14:30:30 2000 @@ -1,7 +1,7 @@ - /****************************************************************************** * * Module Name: nswalk - Functions for walking the APCI namespace + * $Revision: 17 $ * *****************************************************************************/ @@ -25,90 +25,85 @@ #include "acpi.h" -#include "interp.h" -#include "namesp.h" +#include "acinterp.h" +#include "acnamesp.h" #define _COMPONENT NAMESPACE - MODULE_NAME ("nswalk"); + MODULE_NAME ("nswalk") /**************************************************************************** * * FUNCTION: Acpi_get_next_object * - * PARAMETERS: Type - Type of object to be searched for - * Parent - Parent object whose children we are getting - * Last_child - Previous child that was found. - * The NEXT child will be returned - * Ret_handle - Where handle to the next object is placed - * - * RETURN: Status - * - * DESCRIPTION: Return the next peer object within the namespace. If Handle is - * valid, Scope is ignored. Otherwise, the first object within - * Scope is returned. + * PARAMETERS: Type - Type of object to be searched for + * Parent - Parent object whose children we are + * getting + * Last_child - Previous child that was found. + * The NEXT child will be returned + * + * RETURN: ACPI_NAMESPACE_NODE - Pointer to the NEXT child or NULL if + * none is found. + * + * DESCRIPTION: Return the next peer object within the namespace. If Handle + * is valid, Scope is ignored. Otherwise, the first object + * within Scope is returned. * - ******************************************************************************/ + ****************************************************************************/ -ACPI_NAMED_OBJECT* +ACPI_NAMESPACE_NODE * acpi_ns_get_next_object ( OBJECT_TYPE_INTERNAL type, - ACPI_NAMED_OBJECT *parent, - ACPI_NAMED_OBJECT *child) + ACPI_NAMESPACE_NODE *parent_node, + ACPI_NAMESPACE_NODE *child_node) { - ACPI_NAMED_OBJECT *this_entry = NULL; + ACPI_NAMESPACE_NODE *next_node = NULL; - if (!child) { + if (!child_node) { /* It's really the parent's _scope_ that we want */ - if (parent->child_table) { - this_entry = parent->child_table->entries; + if (parent_node->child) { + next_node = parent_node->child; } } else { /* Start search at the NEXT object */ - this_entry = acpi_ns_get_next_valid_entry (child); + next_node = acpi_ns_get_next_valid_object (child_node); } /* If any type is OK, we are done */ if (type == ACPI_TYPE_ANY) { - /* Make sure this is valid entry first */ - - if ((!this_entry) || - (!this_entry->name)) - { - return NULL; - } + /* Next_node is NULL if we are at the end-of-list */ - return (this_entry); + return (next_node); } /* Must search for the object -- but within this scope only */ - while (this_entry) { + while (next_node) { /* If type matches, we are done */ - if (this_entry->type == type) { - return (this_entry); + if (next_node->type == type) { + return (next_node); } /* Otherwise, move on to the next object */ - this_entry = acpi_ns_get_next_valid_entry (this_entry); + next_node = acpi_ns_get_next_valid_object (next_node); } /* Not found */ - return NULL; + return (NULL); } @@ -117,7 +112,7 @@ * FUNCTION: Acpi_ns_walk_namespace * * PARAMETERS: Type - ACPI_OBJECT_TYPE to search for - * Start_object - Handle in namespace where search begins + * Start_node - Handle in namespace where search begins * Max_depth - Depth to which search is to reach * Unlock_before_callback- Whether to unlock the NS before invoking * the callback routine @@ -145,7 +140,7 @@ ACPI_STATUS acpi_ns_walk_namespace ( OBJECT_TYPE_INTERNAL type, - ACPI_HANDLE start_object, + ACPI_HANDLE start_node, u32 max_depth, u8 unlock_before_callback, WALK_CALLBACK user_function, @@ -153,25 +148,25 @@ void **return_value) { ACPI_STATUS status; - ACPI_NAMED_OBJECT *child_entry; - ACPI_NAMED_OBJECT *parent_entry; + ACPI_NAMESPACE_NODE *child_node; + ACPI_NAMESPACE_NODE *parent_node; OBJECT_TYPE_INTERNAL child_type; u32 level; - /* Special case for the namespace root object */ + /* Special case for the namespace Root Node */ - if (start_object == ACPI_ROOT_OBJECT) { - start_object = acpi_gbl_root_object; + if (start_node == ACPI_ROOT_OBJECT) { + start_node = acpi_gbl_root_node; } /* Null child means "get first object" */ - parent_entry = start_object; - child_entry = 0; - child_type = ACPI_TYPE_ANY; - level = 1; + parent_node = start_node; + child_node = 0; + child_type = ACPI_TYPE_ANY; + level = 1; /* * Traverse the tree of objects until we bubble back up to where we @@ -186,18 +181,18 @@ */ status = AE_OK; - child_entry = acpi_ns_get_next_object (ACPI_TYPE_ANY, - parent_entry, - child_entry); + child_node = acpi_ns_get_next_object (ACPI_TYPE_ANY, + parent_node, + child_node); - if (child_entry) { + if (child_node) { /* * Found an object, Get the type if we are not * searching for ANY */ if (type != ACPI_TYPE_ANY) { - child_type = child_entry->type; + child_type = child_node->type; } if (child_type == type) { @@ -210,7 +205,7 @@ acpi_cm_release_mutex (ACPI_MTX_NAMESPACE); } - status = user_function (child_entry, level, + status = user_function (child_node, level, context, return_value); if (unlock_before_callback) { @@ -247,15 +242,15 @@ if ((level < max_depth) && (status != AE_CTRL_DEPTH)) { if (acpi_ns_get_next_object (ACPI_TYPE_ANY, - child_entry, 0)) + child_node, 0)) { /* * There is at least one child of this * object, visit the object */ level++; - parent_entry = child_entry; - child_entry = 0; + parent_node = child_node; + child_node = 0; } } } @@ -267,8 +262,8 @@ * the object's parent. */ level--; - child_entry = parent_entry; - parent_entry = acpi_ns_get_parent_entry (parent_entry); + child_node = parent_node; + parent_node = acpi_ns_get_parent_object (parent_node); } } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/namespace/nsxfname.c linux/drivers/acpi/namespace/nsxfname.c --- v2.4.0-test8/linux/drivers/acpi/namespace/nsxfname.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/namespace/nsxfname.c Fri Sep 15 14:30:30 2000 @@ -2,6 +2,7 @@ * * Module Name: nsxfname - Public interfaces to the ACPI subsystem * ACPI Namespace oriented interfaces + * $Revision: 64 $ * *****************************************************************************/ @@ -25,16 +26,16 @@ #include "acpi.h" -#include "interp.h" -#include "namesp.h" +#include "acinterp.h" +#include "acnamesp.h" #include "amlcode.h" -#include "parser.h" -#include "dispatch.h" -#include "events.h" +#include "acparser.h" +#include "acdispat.h" +#include "acevents.h" #define _COMPONENT NAMESPACE - MODULE_NAME ("nsxfname"); + MODULE_NAME ("nsxfname") /****************************************************************************** @@ -64,21 +65,6 @@ } - /* Init the hardware */ - - /* - * TBD: [Restructure] Should this should be moved elsewhere, - * like Acpi_enable! ?? - */ - - /* we need to be able to call this interface repeatedly! */ - /* Does H/W require init before loading the namespace? */ - - status = acpi_cm_hardware_initialize (); - if (ACPI_FAILURE (status)) { - return (status); - } - /* * Load the namespace. The DSDT is required, * but the SSDT and PSDT tables are optional. @@ -131,24 +117,24 @@ ACPI_HANDLE *ret_handle) { ACPI_STATUS status; - ACPI_NAMED_OBJECT *this_entry; - ACPI_NAME_TABLE *scope = NULL; + ACPI_NAMESPACE_NODE *node; + ACPI_NAMESPACE_NODE *prefix_node = NULL; if (!ret_handle || !pathname) { - return AE_BAD_PARAMETER; + return (AE_BAD_PARAMETER); } if (parent) { acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE); - this_entry = acpi_ns_convert_handle_to_entry (parent); - if (!this_entry) { + node = acpi_ns_convert_handle_to_entry (parent); + if (!node) { acpi_cm_release_mutex (ACPI_MTX_NAMESPACE); - return AE_BAD_PARAMETER; + return (AE_BAD_PARAMETER); } - scope = this_entry->child_table; + prefix_node = node->child; acpi_cm_release_mutex (ACPI_MTX_NAMESPACE); } @@ -156,17 +142,20 @@ /* TBD: [Investigate] Check for both forward and backslash?? */ if (STRCMP (pathname, NS_ROOT_PATH) == 0) { - *ret_handle = acpi_ns_convert_entry_to_handle (acpi_gbl_root_object); - return AE_OK; + *ret_handle = acpi_ns_convert_entry_to_handle (acpi_gbl_root_node); + return (AE_OK); } /* - * Find the Nte and convert to the user format + * Find the Node and convert to the user format */ - this_entry = NULL; - status = acpi_ns_get_named_object (pathname, scope, &this_entry); + node = NULL; + status = acpi_ns_get_node (pathname, prefix_node, &node); - *ret_handle = acpi_ns_convert_entry_to_handle (this_entry); + *ret_handle = NULL; + if(ACPI_SUCCESS(status)) { + *ret_handle = acpi_ns_convert_entry_to_handle (node); + } return (status); } @@ -195,13 +184,13 @@ ACPI_BUFFER *ret_path_ptr) { ACPI_STATUS status; - ACPI_NAMED_OBJECT *obj_entry; + ACPI_NAMESPACE_NODE *node; /* Buffer pointer must be valid always */ if (!ret_path_ptr || (name_type > ACPI_NAME_TYPE_MAX)) { - return AE_BAD_PARAMETER; + return (AE_BAD_PARAMETER); } /* Allow length to be zero and ignore the pointer */ @@ -209,7 +198,7 @@ if ((ret_path_ptr->length) && (!ret_path_ptr->pointer)) { - return AE_BAD_PARAMETER; + return (AE_BAD_PARAMETER); } if (name_type == ACPI_FULL_PATHNAME) { @@ -217,17 +206,17 @@ status = acpi_ns_handle_to_pathname (handle, &ret_path_ptr->length, ret_path_ptr->pointer); - return status; + return (status); } /* * Wants the single segment ACPI name. - * Validate handle and convert to an NTE + * Validate handle and convert to an Node */ acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE); - obj_entry = acpi_ns_convert_handle_to_entry (handle); - if (!obj_entry) { + node = acpi_ns_convert_handle_to_entry (handle); + if (!node) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } @@ -240,18 +229,18 @@ goto unlock_and_exit; } - /* Just copy the ACPI name from the NTE and zero terminate it */ + /* Just copy the ACPI name from the Node and zero terminate it */ - STRNCPY (ret_path_ptr->pointer, (char *) &obj_entry->name, + STRNCPY (ret_path_ptr->pointer, (NATIVE_CHAR *) &node->name, ACPI_NAME_SIZE); - ((char *) ret_path_ptr->pointer) [ACPI_NAME_SIZE] = 0; + ((NATIVE_CHAR *) ret_path_ptr->pointer) [ACPI_NAME_SIZE] = 0; status = AE_OK; unlock_and_exit: acpi_cm_release_mutex (ACPI_MTX_NAMESPACE); - return status; + return (status); } @@ -279,27 +268,27 @@ ACPI_STATUS status; u32 device_status = 0; u32 address = 0; - ACPI_NAMED_OBJECT *device_entry; + ACPI_NAMESPACE_NODE *device_node; /* Parameter validation */ if (!device || !info) { - return AE_BAD_PARAMETER; + return (AE_BAD_PARAMETER); } acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE); - device_entry = acpi_ns_convert_handle_to_entry (device); - if (!device_entry) { + device_node = acpi_ns_convert_handle_to_entry (device); + if (!device_node) { acpi_cm_release_mutex (ACPI_MTX_NAMESPACE); - return AE_BAD_PARAMETER; + return (AE_BAD_PARAMETER); } - info->type = device_entry->type; - info->name = device_entry->name; - info->parent = - acpi_ns_convert_entry_to_handle (acpi_ns_get_parent_entry (device_entry)); + info->type = device_node->type; + info->name = device_node->name; + info->parent = acpi_ns_convert_entry_to_handle ( + acpi_ns_get_parent_object (device_node)); acpi_cm_release_mutex (ACPI_MTX_NAMESPACE); @@ -307,17 +296,17 @@ * If not a device, we are all done. */ if (info->type != ACPI_TYPE_DEVICE) { - return AE_OK; + return (AE_OK); } /* Get extra info for ACPI devices */ - info->valid = 0; + info->valid = 0; /* Execute the _HID method and save the result */ - status = acpi_cm_execute_HID (device_entry, &hid); + status = acpi_cm_execute_HID (device_node, &hid); if (ACPI_SUCCESS (status)) { if (hid.type == STRING_PTR_DEVICE_ID) { STRCPY (info->hardware_id, hid.data.string_ptr); @@ -331,7 +320,7 @@ /* Execute the _UID method and save the result */ - status = acpi_cm_execute_UID (device_entry, &uid); + status = acpi_cm_execute_UID (device_node, &uid); if (ACPI_SUCCESS (status)) { if (hid.type == STRING_PTR_DEVICE_ID) { STRCPY (info->unique_id, uid.data.string_ptr); @@ -348,7 +337,7 @@ * _STA is not always present */ - status = acpi_cm_execute_STA (device_entry, &device_status); + status = acpi_cm_execute_STA (device_node, &device_status); if (ACPI_SUCCESS (status)) { info->current_status = device_status; info->valid |= ACPI_VALID_STA; @@ -360,13 +349,13 @@ */ status = acpi_cm_evaluate_numeric_object (METHOD_NAME__ADR, - device_entry, &address); + device_node, &address); if (ACPI_SUCCESS (status)) { info->address = address; info->valid |= ACPI_VALID_ADR; } - return AE_OK; + return (AE_OK); } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/namespace/nsxfobj.c linux/drivers/acpi/namespace/nsxfobj.c --- v2.4.0-test8/linux/drivers/acpi/namespace/nsxfobj.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/namespace/nsxfobj.c Fri Sep 15 14:30:30 2000 @@ -1,10 +1,10 @@ - -/****************************************************************************** +/******************************************************************************* * * Module Name: nsxfobj - Public interfaces to the ACPI subsystem * ACPI Object oriented interfaces + * $Revision: 65 $ * - *****************************************************************************/ + ******************************************************************************/ /* * Copyright (C) 2000 R. Byron Moore @@ -26,15 +26,15 @@ #include "acpi.h" -#include "interp.h" -#include "namesp.h" +#include "acinterp.h" +#include "acnamesp.h" #define _COMPONENT NAMESPACE - MODULE_NAME ("nsxfobj"); + MODULE_NAME ("nsxfobj") -/**************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_evaluate_object * @@ -54,7 +54,7 @@ * parameters if necessary. One of "Handle" or "Pathname" must * be valid (non-null) * - ****************************************************************************/ + ******************************************************************************/ ACPI_STATUS acpi_evaluate_object ( @@ -64,9 +64,9 @@ ACPI_BUFFER *return_buffer) { ACPI_STATUS status; - ACPI_OBJECT_INTERNAL **param_ptr = NULL; - ACPI_OBJECT_INTERNAL *return_obj = NULL; - ACPI_OBJECT_INTERNAL *object_ptr = NULL; + ACPI_OPERAND_OBJECT **param_ptr = NULL; + ACPI_OPERAND_OBJECT *return_obj = NULL; + ACPI_OPERAND_OBJECT *object_ptr = NULL; u32 buffer_space_needed; u32 user_buffer_length; u32 count; @@ -85,12 +85,11 @@ /* * Allocate a new parameter block for the internal objects * Add 1 to count to allow for null terminated internal list - * TBD: [Restructure] merge into single allocation! */ count = param_objects->count; param_length = (count + 1) * sizeof (void *); - object_length = count * sizeof (ACPI_OBJECT_INTERNAL); + object_length = count * sizeof (ACPI_OPERAND_OBJECT); param_ptr = acpi_cm_callocate (param_length + /* Parameter List part */ object_length); /* Actual objects */ @@ -98,7 +97,7 @@ return (AE_NO_MEMORY); } - object_ptr = (ACPI_OBJECT_INTERNAL *) ((u8 *) param_ptr + + object_ptr = (ACPI_OPERAND_OBJECT *) ((u8 *) param_ptr + param_length); /* @@ -169,18 +168,15 @@ * The null pathname case means the handle is for * the actual object to be evaluated */ - status = acpi_ns_evaluate_by_handle (handle, - param_ptr, - &return_obj); + status = acpi_ns_evaluate_by_handle (handle, param_ptr, &return_obj); } else { /* * Both a Handle and a relative Pathname */ - status = acpi_ns_evaluate_relative (handle, pathname, - param_ptr, - &return_obj); + status = acpi_ns_evaluate_relative (handle, pathname, param_ptr, + &return_obj); } } @@ -195,11 +191,9 @@ return_buffer->length = 0; if (return_obj) { - if (VALID_DESCRIPTOR_TYPE (return_obj, - ACPI_DESC_TYPE_NAMED)) - { + if (VALID_DESCRIPTOR_TYPE (return_obj, ACPI_DESC_TYPE_NAMED)) { /* - * If we got an NTE as a return object, + * If we got an Node as a return object, * this means the object we are evaluating * has nothing interesting to return (such * as a mutex, etc.) We return an error @@ -210,7 +204,7 @@ * types at a later date if necessary. */ status = AE_TYPE; - return_obj = NULL; /* No need to delete an NTE */ + return_obj = NULL; /* No need to delete an Node */ } if (ACPI_SUCCESS (status)) { @@ -241,9 +235,8 @@ /* * We have enough space for the object, build it */ - status = - acpi_cm_build_external_object (return_obj, - return_buffer); + status = acpi_cm_build_external_object (return_obj, + return_buffer); return_buffer->length = buffer_space_needed; } } @@ -276,7 +269,7 @@ } -/**************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_get_next_object * @@ -302,15 +295,15 @@ ACPI_HANDLE *ret_handle) { ACPI_STATUS status = AE_OK; - ACPI_NAMED_OBJECT *entry; - ACPI_NAMED_OBJECT *parent_entry = NULL; - ACPI_NAMED_OBJECT *child_entry = NULL; + ACPI_NAMESPACE_NODE *node; + ACPI_NAMESPACE_NODE *parent_node = NULL; + ACPI_NAMESPACE_NODE *child_node = NULL; /* Parameter validation */ if (type > ACPI_TYPE_MAX) { - return AE_BAD_PARAMETER; + return (AE_BAD_PARAMETER); } acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE); @@ -320,8 +313,8 @@ if (!child) { /* Start search at the beginning of the specified scope */ - parent_entry = acpi_ns_convert_handle_to_entry (parent); - if (!parent_entry) { + parent_node = acpi_ns_convert_handle_to_entry (parent); + if (!parent_node) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } @@ -332,8 +325,8 @@ else { /* Convert and validate the handle */ - child_entry = acpi_ns_convert_handle_to_entry (child); - if (!child_entry) { + child_node = acpi_ns_convert_handle_to_entry (child); + if (!child_node) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } @@ -342,26 +335,26 @@ /* Internal function does the real work */ - entry = acpi_ns_get_next_object ((OBJECT_TYPE_INTERNAL) type, - parent_entry, child_entry); - if (!entry) { + node = acpi_ns_get_next_object ((OBJECT_TYPE_INTERNAL) type, + parent_node, child_node); + if (!node) { status = AE_NOT_FOUND; goto unlock_and_exit; } if (ret_handle) { - *ret_handle = acpi_ns_convert_entry_to_handle (entry); + *ret_handle = acpi_ns_convert_entry_to_handle (node); } unlock_and_exit: acpi_cm_release_mutex (ACPI_MTX_NAMESPACE); - return status; + return (status); } -/**************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_get_type * @@ -379,44 +372,43 @@ ACPI_HANDLE handle, ACPI_OBJECT_TYPE *ret_type) { - ACPI_NAMED_OBJECT *object; + ACPI_NAMESPACE_NODE *node; /* Parameter Validation */ if (!ret_type) { - return AE_BAD_PARAMETER; + return (AE_BAD_PARAMETER); } /* - * Special case for the predefined Root Object + * Special case for the predefined Root Node * (return type ANY) */ - if (handle == ACPI_ROOT_OBJECT) { *ret_type = ACPI_TYPE_ANY; - return AE_OK; + return (AE_OK); } acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE); /* Convert and validate the handle */ - object = acpi_ns_convert_handle_to_entry (handle); - if (!object) { + node = acpi_ns_convert_handle_to_entry (handle); + if (!node) { acpi_cm_release_mutex (ACPI_MTX_NAMESPACE); - return AE_BAD_PARAMETER; + return (AE_BAD_PARAMETER); } - *ret_type = object->type; + *ret_type = node->type; acpi_cm_release_mutex (ACPI_MTX_NAMESPACE); - return AE_OK; + return (AE_OK); } -/**************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_get_parent * @@ -435,7 +427,7 @@ ACPI_HANDLE handle, ACPI_HANDLE *ret_handle) { - ACPI_NAMED_OBJECT *object; + ACPI_NAMESPACE_NODE *node; ACPI_STATUS status = AE_OK; @@ -443,13 +435,13 @@ if (!ret_handle) { - return AE_BAD_PARAMETER; + return (AE_BAD_PARAMETER); } - /* Special case for the predefined Root Object (no parent) */ + /* Special case for the predefined Root Node (no parent) */ if (handle == ACPI_ROOT_OBJECT) { - return AE_NULL_ENTRY; + return (AE_NULL_ENTRY); } @@ -457,8 +449,8 @@ /* Convert and validate the handle */ - object = acpi_ns_convert_handle_to_entry (handle); - if (!object) { + node = acpi_ns_convert_handle_to_entry (handle); + if (!node) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } @@ -467,11 +459,11 @@ /* Get the parent entry */ *ret_handle = - acpi_ns_convert_entry_to_handle (acpi_ns_get_parent_entry (object)); + acpi_ns_convert_entry_to_handle (acpi_ns_get_parent_object (node)); /* Return exeption if parent is null */ - if (!acpi_ns_get_parent_entry (object)) { + if (!acpi_ns_get_parent_object (node)) { status = AE_NULL_ENTRY; } @@ -479,11 +471,11 @@ unlock_and_exit: acpi_cm_release_mutex (ACPI_MTX_NAMESPACE); - return AE_OK; + return (status); } -/****************************************************************************** +/******************************************************************************* * * FUNCTION: Acpi_walk_namespace * diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/os.c linux/drivers/acpi/os.c --- v2.4.0-test8/linux/drivers/acpi/os.c Thu Jul 13 09:39:49 2000 +++ linux/drivers/acpi/os.c Fri Sep 22 14:21:17 2000 @@ -24,11 +24,14 @@ #include #include #include +#include #include -#include #include "acpi.h" #include "driver.h" +#define _COMPONENT OS_DEPENDENT + MODULE_NAME ("os") + static int acpi_irq_irq = 0; static OSD_HANDLER acpi_irq_handler = NULL; static void *acpi_irq_context = NULL; @@ -61,7 +64,7 @@ } s32 -acpi_os_printf(const char *fmt,...) +acpi_os_printf(const NATIVE_CHAR *fmt,...) { s32 size; va_list args; @@ -72,11 +75,11 @@ } s32 -acpi_os_vprintf(const char *fmt, va_list args) +acpi_os_vprintf(const NATIVE_CHAR *fmt, va_list args) { static char buffer[512]; int size = vsprintf(buffer, fmt, args); - printk(KERN_DEBUG "ACPI: %s", buffer); + printk("%s", buffer); return size; } @@ -137,7 +140,7 @@ acpi_irq_context = context; if (request_irq(irq, acpi_irq, - SA_INTERRUPT | SA_SHIRQ, + SA_SHIRQ, "acpi", acpi_irq)) { printk(KERN_ERR "ACPI: SCI (IRQ%d) allocation failed\n", irq); @@ -338,7 +341,7 @@ } ACPI_STATUS -acpi_os_breakpoint(char *msg) +acpi_os_breakpoint(NATIVE_CHAR *msg) { acpi_os_printf("breakpoint: %s", msg); return AE_OK; @@ -351,13 +354,13 @@ } void -acpi_os_dbg_assert(void *failure, void *file, u32 line, char *msg) +acpi_os_dbg_assert(void *failure, void *file, u32 line, NATIVE_CHAR *msg) { acpi_os_printf("assert: %s", msg); } u32 -acpi_os_get_line(char *buffer) +acpi_os_get_line(NATIVE_CHAR *buffer) { return 0; } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/parser/Makefile linux/drivers/acpi/parser/Makefile --- v2.4.0-test8/linux/drivers/acpi/parser/Makefile Wed Dec 31 16:00:00 1969 +++ linux/drivers/acpi/parser/Makefile Fri Sep 15 18:21:44 2000 @@ -0,0 +1,28 @@ +# +# Makefile for all Linux ACPI interpreter subdirectories +# + +SUB_DIRS := +MOD_SUB_DIRS := $(SUB_DIRS) +MOD_IN_SUB_DIRS := +ALL_SUB_DIRS := $(SUB_DIRS) + +O_TARGET := ../$(shell basename `pwd`).o +O_OBJS := +M_OBJS := + +ACPI_OBJS := $(patsubst %.c,%.o,$(wildcard *.c)) + +EXTRA_CFLAGS += -I../include + +EXTRA_CFLAGS += $(ACPI_CFLAGS) + +# if the interpreter is used, it overrides arch/i386/kernel/acpi.c +ifeq ($(CONFIG_ACPI_INTERPRETER),y) + O_OBJS := $(ACPI_OBJS) +endif + +include $(TOPDIR)/Rules.make + +clean: + $(RM) *.o diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/parser/psargs.c linux/drivers/acpi/parser/psargs.c --- v2.4.0-test8/linux/drivers/acpi/parser/psargs.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/parser/psargs.c Fri Sep 15 14:30:30 2000 @@ -1,6 +1,7 @@ /****************************************************************************** * * Module Name: psargs - Parse AML opcode arguments + * $Revision: 35 $ * *****************************************************************************/ @@ -24,12 +25,26 @@ #include "acpi.h" -#include "parser.h" +#include "acparser.h" #include "amlcode.h" -#include "namesp.h" +#include "acnamesp.h" #define _COMPONENT PARSER - MODULE_NAME ("psargs"); + MODULE_NAME ("psargs") + + +u32 +acpi_ps_pkg_length_encoding_size ( + u32 first_byte) +{ + + /* + * Bits 6-7 contain the number of bytes + * in the encoded package length (-1) + */ + + return ((first_byte >> 6) + 1); +} /******************************************************************************* @@ -46,14 +61,63 @@ ******************************************************************************/ u32 +xxx_acpi_ps_get_next_package_length ( + ACPI_PARSE_STATE *parser_state) +{ + u32 encoding_length; + u32 package_length = 0; + u8 *aml_ptr = parser_state->aml; + + + encoding_length = acpi_ps_pkg_length_encoding_size ((u32) GET8 (aml_ptr)); + + + switch (encoding_length) + { + case 1: /* 1-byte encoding (bits 0-5) */ + + package_length = ((u32) GET8 (aml_ptr) & 0x3f); + break; + + + case 2: /* 2-byte encoding (next byte + bits 0-3) */ + + package_length = ((((u32) GET8 (aml_ptr + 1)) << 4) | + (((u32) GET8 (aml_ptr)) & 0x0f)); + break; + + + case 3: /* 3-byte encoding (next 2 bytes + bits 0-3) */ + + package_length = ((((u32) GET8 (aml_ptr + 2)) << 12) | + (((u32) GET8 (aml_ptr + 1)) << 4) | + (((u32) GET8 (aml_ptr)) & 0x0f)); + break; + + + case 4: /* 4-byte encoding (next 3 bytes + bits 0-3) */ + + package_length = ((((u32) GET8 (aml_ptr + 3)) << 20) | + (((u32) GET8 (aml_ptr + 2)) << 12) | + (((u32) GET8 (aml_ptr + 1)) << 4) | + (((u32) GET8 (aml_ptr)) & 0x0f)); + break; + } + + parser_state->aml += encoding_length; + + return (package_length); +} + +u32 acpi_ps_get_next_package_length ( ACPI_PARSE_STATE *parser_state) { - s32 encoded_length; - s32 length = 0; + u32 encoded_length; + u32 length = 0; - encoded_length = (s32) GET8 (parser_state->aml); + encoded_length = (u32) GET8 (parser_state->aml); parser_state->aml++; @@ -137,13 +201,13 @@ * ******************************************************************************/ -char * +NATIVE_CHAR * acpi_ps_get_next_namestring ( ACPI_PARSE_STATE *parser_state) { - char *start = (char *) parser_state->aml; - char *end = (char *) parser_state->aml; - s32 length; + u8 *start = parser_state->aml; + u8 *end = parser_state->aml; + u32 length; /* Handle multiple prefix characters */ @@ -181,7 +245,7 @@ /* multiple name segments */ - length = (s32) GET8 (end + 1) * 4; + length = (u32) GET8 (end + 1) * 4; end += 2 + length; break; @@ -197,7 +261,7 @@ parser_state->aml = (u8*) end; - return (start); + return ((NATIVE_CHAR *) start); } @@ -228,14 +292,14 @@ void acpi_ps_get_next_namepath ( ACPI_PARSE_STATE *parser_state, - ACPI_GENERIC_OP *arg, + ACPI_PARSE_OBJECT *arg, u32 *arg_count, u8 method_call) { - char *path; - ACPI_GENERIC_OP *name; - ACPI_GENERIC_OP *op; - ACPI_GENERIC_OP *count; + NATIVE_CHAR *path; + ACPI_PARSE_OBJECT *name_op; + ACPI_PARSE_OBJECT *op; + ACPI_PARSE_OBJECT *count; path = acpi_ps_get_next_namestring (parser_state); @@ -270,18 +334,18 @@ count = acpi_ps_get_arg (op, 0); if (count && count->opcode == AML_BYTE_OP) { - name = acpi_ps_alloc_op (AML_NAMEPATH_OP); - if (name) { + name_op = acpi_ps_alloc_op (AML_NAMEPATH_OP); + if (name_op) { /* Change arg into a METHOD CALL and attach the name */ acpi_ps_init_op (arg, AML_METHODCALL_OP); - name->value.name = path; + name_op->value.name = path; - /* Point METHODCALL/NAME to the METHOD NTE */ + /* Point METHODCALL/NAME to the METHOD Node */ - name->acpi_named_object = op; - acpi_ps_append_arg (arg, name); + name_op->node = (ACPI_NAMESPACE_NODE *) op; + acpi_ps_append_arg (arg, name_op); *arg_count = count->value.integer & METHOD_FLAGS_ARG_COUNT; @@ -320,15 +384,15 @@ void acpi_ps_get_next_namepath ( ACPI_PARSE_STATE *parser_state, - ACPI_GENERIC_OP *arg, + ACPI_PARSE_OBJECT *arg, u32 *arg_count, u8 method_call) { - char *path; - ACPI_GENERIC_OP *name; + NATIVE_CHAR *path; + ACPI_PARSE_OBJECT *name_op; ACPI_STATUS status; - ACPI_NAMED_OBJECT *method = NULL; - ACPI_NAMED_OBJECT *entry; + ACPI_NAMESPACE_NODE *method_node = NULL; + ACPI_NAMESPACE_NODE *node; ACPI_GENERIC_STATE scope_info; @@ -346,10 +410,10 @@ /* * Lookup the name in the internal namespace */ - scope_info.scope.name_table = NULL; - entry = parser_state->start_op->acpi_named_object; - if (entry) { - scope_info.scope.name_table = entry->child_table; + scope_info.scope.node = NULL; + node = parser_state->start_node; + if (node) { + scope_info.scope.node = node; } /* @@ -361,24 +425,24 @@ status = acpi_ns_lookup (&scope_info, path, ACPI_TYPE_ANY, IMODE_EXECUTE, NS_SEARCH_PARENT | NS_DONT_OPEN_SCOPE, NULL, - &entry); + &node); if (ACPI_SUCCESS (status)) { - if (entry->type == ACPI_TYPE_METHOD) { - method = entry; - name = acpi_ps_alloc_op (AML_NAMEPATH_OP); - if (name) { + if (node->type == ACPI_TYPE_METHOD) { + method_node = node; + name_op = acpi_ps_alloc_op (AML_NAMEPATH_OP); + if (name_op) { /* Change arg into a METHOD CALL and attach name to it */ acpi_ps_init_op (arg, AML_METHODCALL_OP); - name->value.name = path; + name_op->value.name = path; - /* Point METHODCALL/NAME to the METHOD NTE */ + /* Point METHODCALL/NAME to the METHOD Node */ - name->acpi_named_object = method; - acpi_ps_append_arg (arg, name); + name_op->node = method_node; + acpi_ps_append_arg (arg, name_op); - *arg_count = ((ACPI_OBJECT_INTERNAL *) method->object)->method.param_count; + *arg_count = ((ACPI_OPERAND_OBJECT *) method_node->object)->method.param_count; } return; @@ -424,8 +488,8 @@ void acpi_ps_get_next_simple_arg ( ACPI_PARSE_STATE *parser_state, - s32 arg_type, - ACPI_GENERIC_OP *arg) + u32 arg_type, + ACPI_PARSE_OBJECT *arg) { @@ -498,13 +562,13 @@ * ******************************************************************************/ -ACPI_GENERIC_OP * +ACPI_PARSE_OBJECT * acpi_ps_get_next_field ( ACPI_PARSE_STATE *parser_state) { ACPI_PTRDIFF aml_offset = parser_state->aml - parser_state->aml_start; - ACPI_GENERIC_OP *field; + ACPI_PARSE_OBJECT *field; u16 opcode; u32 name; @@ -598,16 +662,16 @@ * ******************************************************************************/ -ACPI_GENERIC_OP * +ACPI_PARSE_OBJECT * acpi_ps_get_next_arg ( ACPI_PARSE_STATE *parser_state, - s32 arg_type, + u32 arg_type, u32 *arg_count) { - ACPI_GENERIC_OP *arg = NULL; - ACPI_GENERIC_OP *prev = NULL; - ACPI_GENERIC_OP *field; - s32 subop; + ACPI_PARSE_OBJECT *arg = NULL; + ACPI_PARSE_OBJECT *prev = NULL; + ACPI_PARSE_OBJECT *field; + u32 subop; switch (arg_type) @@ -675,7 +739,7 @@ /* fill in bytelist data */ arg->value.size = (parser_state->pkg_end - parser_state->aml); - acpi_ps_to_bytelist_op (arg)->data = parser_state->aml; + ((ACPI_PARSE2_OBJECT *) arg)->data = parser_state->aml; } /* skip to End of byte data */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/parser/psfind.c linux/drivers/acpi/parser/psfind.c --- v2.4.0-test8/linux/drivers/acpi/parser/psfind.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/acpi/parser/psfind.c Fri Sep 15 14:30:30 2000 @@ -0,0 +1,319 @@ + +/****************************************************************************** + * + * Module Name: psfind - Parse tree search routine + * $Revision: 16 $ + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 R. Byron Moore + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "acpi.h" +#include "acparser.h" +#include "amlcode.h" + +#define _COMPONENT PARSER + MODULE_NAME ("psfind") + + +/******************************************************************************* + * + * FUNCTION: Acpi_ps_get_parent + * + * PARAMETERS: Op - Get the parent of this Op + * + * RETURN: The Parent op. + * + * DESCRIPTION: Get op's parent + * + ******************************************************************************/ + +ACPI_PARSE_OBJECT* +acpi_ps_get_parent ( + ACPI_PARSE_OBJECT *op) +{ + ACPI_PARSE_OBJECT *parent = op; + + + /* Traverse the tree upward (to root if necessary) */ + + while (parent) { + switch (parent->opcode) + { + case AML_SCOPE_OP: + case AML_PACKAGE_OP: + case AML_METHOD_OP: + case AML_DEVICE_OP: + case AML_POWER_RES_OP: + case AML_THERMAL_ZONE_OP: + + return (parent->parent); + } + + parent = parent->parent; + } + + return (parent); +} + + +/******************************************************************************* + * + * FUNCTION: Acpi_ps_find_name + * + * PARAMETERS: Scope - Scope to search + * Name - ACPI name to search for + * Opcode - Opcode to search for + * + * RETURN: Op containing the name + * + * DESCRIPTION: Find name segment from a list of acpi_ops. Searches a single + * scope, no more. + * + ******************************************************************************/ + +ACPI_PARSE_OBJECT * +acpi_ps_find_name ( + ACPI_PARSE_OBJECT *scope, + u32 name, + u32 opcode) +{ + ACPI_PARSE_OBJECT *op; + ACPI_PARSE_OBJECT *field; + + + /* search scope level for matching name segment */ + + op = acpi_ps_get_child (scope); + + while (op) { + + if (acpi_ps_is_field_op (op->opcode)) { + /* Field, search named fields */ + + field = acpi_ps_get_child (op); + while (field) { + if (acpi_ps_is_named_op (field->opcode) && + acpi_ps_get_name (field) == name && + (!opcode || field->opcode == opcode)) + { + return (field); + } + + field = field->next; + } + } + + else if (acpi_ps_is_create_field_op (op->opcode)) { + if (op->opcode == AML_CREATE_FIELD_OP) { + field = acpi_ps_get_arg (op, 3); + } + + else { + /* Create_xXXField, check name */ + + field = acpi_ps_get_arg (op, 2); + } + + if ((field) && + (field->value.string) && + (!STRNCMP (field->value.string, (char *) &name, ACPI_NAME_SIZE))) + { + return (op); + } + } + + else if ((acpi_ps_is_named_op (op->opcode)) && + (acpi_ps_get_name (op) == name) && + (!opcode || op->opcode == opcode)) + { + break; + } + + op = op->next; + } + + return (op); +} + + +/******************************************************************************* + * + * FUNCTION: Acpi_ps_find + * + * PARAMETERS: Scope - Where to begin the search + * Path - ACPI Path to the named object + * Opcode - Opcode associated with the object + * Create - if TRUE, create the object if not found. + * + * RETURN: Op if found, NULL otherwise. + * + * DESCRIPTION: Find object within scope + * + ******************************************************************************/ + +ACPI_PARSE_OBJECT* +acpi_ps_find ( + ACPI_PARSE_OBJECT *scope, + NATIVE_CHAR *path, + u16 opcode, + u32 create) +{ + u32 seg_count; + u32 name; + u32 name_op; + ACPI_PARSE_OBJECT *op = NULL; + u8 unprefixed = TRUE; + + + if (!scope || !path) { + return (NULL); + } + + + acpi_gbl_ps_find_count++; + + + /* Handle all prefixes in the name path */ + + while (acpi_ps_is_prefix_char (GET8 (path))) { + switch (GET8 (path)) + { + + case '\\': + + /* Could just use a global for "root scope" here */ + + while (scope->parent) { + scope = scope->parent; + } + + /* get first object within the scope */ + /* TBD: [Investigate] OR - set next in root scope to point to the same value as arg */ + + /* Scope = Scope->Value.Arg; */ + + break; + + + case '^': + + /* Go up to the next valid scoping Op (method, scope, etc.) */ + + if (acpi_ps_get_parent (scope)) { + scope = acpi_ps_get_parent (scope); + } + + break; + } + + unprefixed = FALSE; + path++; + } + + /* get name segment count */ + + switch (GET8 (path)) + { + case '\0': + seg_count = 0; + + /* Null name case */ + + if (unprefixed) { + op = NULL; + } + else { + op = scope; + } + + + return (op); + break; + + case AML_DUAL_NAME_PREFIX: + seg_count = 2; + path++; + break; + + case AML_MULTI_NAME_PREFIX_OP: + seg_count = GET8 (path + 1); + path += 2; + break; + + default: + seg_count = 1; + break; + } + + /* match each name segment */ + + while (scope && seg_count) { + MOVE_UNALIGNED32_TO_32 (&name, path); + path += 4; + seg_count --; + + if (seg_count) { + name_op = 0; + } + else { + name_op = opcode; + } + + op = acpi_ps_find_name (scope, name, name_op); + + if (!op) { + if (create) { + /* Create a new Scope level */ + + if (seg_count) { + op = acpi_ps_alloc_op (AML_SCOPE_OP); + } + else { + op = acpi_ps_alloc_op (opcode); + } + + if (op) { + acpi_ps_set_name (op, name); + acpi_ps_append_arg (scope, op); + + } + } + + else if (unprefixed) { + /* Search higher scopes for unprefixed name */ + + while (!op && scope->parent) { + scope = scope->parent; + op = acpi_ps_find_name (scope, name, opcode); + + } + } + + } + + unprefixed = FALSE; + scope = op; + } + + return (op); +} + + diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/parser/psopcode.c linux/drivers/acpi/parser/psopcode.c --- v2.4.0-test8/linux/drivers/acpi/parser/psopcode.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/parser/psopcode.c Fri Sep 15 14:30:30 2000 @@ -1,6 +1,7 @@ /****************************************************************************** * * Module Name: psopcode - Parser opcode information table + * $Revision: 20 $ * *****************************************************************************/ @@ -24,12 +25,32 @@ #include "acpi.h" -#include "parser.h" +#include "acparser.h" #include "amlcode.h" #define _COMPONENT PARSER - MODULE_NAME ("psopcode"); + MODULE_NAME ("psopcode") + + +u8 acpi_gbl_aml_short_op_info_index[]; +u8 acpi_gbl_aml_long_op_info_index[]; + +#define _UNK 0x6B +/* + * Reserved ASCII characters. Do not use any of these for + * internal opcodes, since they are used to differentiate + * name strings from AML opcodes + */ +#define _ASC 0x6C +#define _NAM 0x6C +#define _PFX 0x6D +#define _UNKNOWN_OPCODE 0x02 /* An example unknown opcode */ + +#define MAX_EXTENDED_OPCODE 0x87 +#define NUM_EXTENDED_OPCODE MAX_EXTENDED_OPCODE + 1 +#define MAX_INTERNAL_OPCODE +#define NUM_INTERNAL_OPCODE MAX_INTERNAL_OPCODE + 1 /******************************************************************************* @@ -41,27 +62,41 @@ * RETURN: A pointer to the info about the opcode. NULL if the opcode was * not found in the table. * - * DESCRIPTION: Find AML opcode description based on the opcode + * DESCRIPTION: Find AML opcode description based on the opcode. + * NOTE: This procedure must ALWAYS return a valid pointer! * ******************************************************************************/ -ACPI_OP_INFO * +ACPI_OPCODE_INFO * acpi_ps_get_opcode_info ( u16 opcode) { - ACPI_OP_INFO *op; - s32 hash; + ACPI_OPCODE_INFO *op_info; + u8 upper_opcode; + u8 lower_opcode; + + + /* Split the 16-bit opcode into separate bytes */ + + upper_opcode = (u8) (opcode >> 8); + lower_opcode = (u8) opcode; + + /* Default is "unknown opcode" */ + op_info = &acpi_gbl_aml_op_info [_UNK]; - /* compute hash/index into the Acpi_aml_op_index table */ - switch (opcode >> 8) + /* + * Detect normal 8-bit opcode or extended 16-bit opcode + */ + + switch (upper_opcode) { case 0: - /* Simple (8-bit) opcode */ + /* Simple (8-bit) opcode: 0-255, can't index beyond table */ - hash = opcode; + op_info = &acpi_gbl_aml_op_info [acpi_gbl_aml_short_op_info_index [lower_opcode]]; break; @@ -69,38 +104,29 @@ /* Extended (16-bit, prefix+opcode) opcode */ - hash = (opcode + AML_EXTOP_HASH_OFFSET) & 0xff; + if (lower_opcode <= MAX_EXTENDED_OPCODE) { + op_info = &acpi_gbl_aml_op_info [acpi_gbl_aml_long_op_info_index [lower_opcode]]; + } break; case AML_LNOT_OP: /* This case is for the bogus opcodes LNOTEQUAL, LLESSEQUAL, LGREATEREQUAL */ + /* TBD: [Investigate] remove this case? */ - hash = (opcode + AML_LNOT_HASH_OFFSET) & 0xff; break; default: - return NULL; + break; } /* Get the Op info pointer for this opcode */ - op = &acpi_gbl_aml_op_info [(s32) acpi_gbl_aml_op_info_index [hash]]; - - - /* If the returned opcode matches, we have a valid opcode */ - - if (op->opcode == opcode) { - return op; - } - - /* Otherwise, the opcode is an ASCII char or other non-opcode value */ - - return NULL; + return (op_info); } @@ -117,21 +143,19 @@ * ******************************************************************************/ -char * +NATIVE_CHAR * acpi_ps_get_opcode_name ( u16 opcode) { - ACPI_OP_INFO *op; + ACPI_OPCODE_INFO *op; op = acpi_ps_get_opcode_info (opcode); - if (!op) { - return "*ERROR*"; - } + /* Always guaranteed to return a valid pointer */ DEBUG_ONLY_MEMBERS (return op->name); - return "AE_NOT_CONFIGURED"; + return ("AE_NOT_CONFIGURED"); } @@ -153,7 +177,7 @@ * 6-7 (2 bits) = Reserved */ #define AML_NO_ARGS 0 -#define AML_HAS_ARGS OP_INFO_HAS_ARGS +#define AML_HAS_ARGS ACPI_OP_ARGS_MASK /* * All AML opcodes and the parse-time arguments for each. Used by the AML parser Each list is compressed @@ -225,7 +249,7 @@ #define ARGP_IF_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_TERMLIST) #define ARGP_ELSE_OP ARGP_LIST2 (ARGP_PKGLENGTH, ARGP_TERMLIST) #define ARGP_WHILE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_TERMLIST) -#define ARGP_NOOP_CODE ARG_NONE +#define ARGP_NOOP_OP ARG_NONE #define ARGP_RETURN_OP ARGP_LIST1 (ARGP_TERMARG) #define ARGP_BREAK_OP ARG_NONE #define ARGP_BREAK_POINT_OP ARG_NONE @@ -242,9 +266,9 @@ #define ARGP_WAIT_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_TERMARG) #define ARGP_RESET_OP ARGP_LIST1 (ARGP_SUPERNAME) #define ARGP_RELEASE_OP ARGP_LIST1 (ARGP_SUPERNAME) -#define ARGP_FROM_BCDOP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) -#define ARGP_TO_BCDOP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) -#define ARGP_UN_LOAD_OP ARGP_LIST1 (ARGP_SUPERNAME) +#define ARGP_FROM_BCD_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) +#define ARGP_TO_BCD_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) +#define ARGP_UNLOAD_OP ARGP_LIST1 (ARGP_SUPERNAME) #define ARGP_REVISION_OP ARG_NONE #define ARGP_DEBUG_OP ARG_NONE #define ARGP_FATAL_OP ARGP_LIST3 (ARGP_BYTEDATA, ARGP_DWORDDATA, ARGP_TERMARG) @@ -340,7 +364,7 @@ #define ARGI_IF_OP ARGI_INVALID_OPCODE #define ARGI_ELSE_OP ARGI_INVALID_OPCODE #define ARGI_WHILE_OP ARGI_INVALID_OPCODE -#define ARGI_NOOP_CODE ARG_NONE +#define ARGI_NOOP_OP ARG_NONE #define ARGI_RETURN_OP ARGI_INVALID_OPCODE #define ARGI_BREAK_OP ARG_NONE #define ARGI_BREAK_POINT_OP ARG_NONE @@ -357,9 +381,9 @@ #define ARGI_WAIT_OP ARGI_LIST2 (ARGI_EVENT, ARGI_NUMBER) #define ARGI_RESET_OP ARGI_LIST1 (ARGI_EVENT) #define ARGI_RELEASE_OP ARGI_LIST1 (ARGI_MUTEX) -#define ARGI_FROM_BCDOP ARGI_LIST2 (ARGI_NUMBER, ARGI_TARGETREF) -#define ARGI_TO_BCDOP ARGI_LIST2 (ARGI_NUMBER, ARGI_TARGETREF) -#define ARGI_UN_LOAD_OP ARGI_LIST1 (ARGI_DDBHANDLE) +#define ARGI_FROM_BCD_OP ARGI_LIST2 (ARGI_NUMBER, ARGI_TARGETREF) +#define ARGI_TO_BCD_OP ARGI_LIST2 (ARGI_NUMBER, ARGI_TARGETREF) +#define ARGI_UNLOAD_OP ARGI_LIST1 (ARGI_DDBHANDLE) #define ARGI_REVISION_OP ARG_NONE #define ARGI_DEBUG_OP ARG_NONE #define ARGI_FATAL_OP ARGI_LIST3 (ARGI_NUMBER, ARGI_NUMBER, ARGI_NUMBER) @@ -388,157 +412,156 @@ */ -ACPI_OP_INFO acpi_gbl_aml_op_info[] = +ACPI_OPCODE_INFO acpi_gbl_aml_op_info[] = { -/* Opcode Opcode Type Has Arguments? Child Name Parser Args Interpreter Args */ +/* Index Opcode Type Class Has Arguments? Name Parser Args Interpreter Args */ -/* 00 */ OP_INFO_ENTRY (AML_ZERO_OP, OPTYPE_CONSTANT| AML_NO_ARGS| 0, "Zero_op", ARGP_ZERO_OP, ARGI_ZERO_OP), -/* 01 */ OP_INFO_ENTRY (AML_ONE_OP, OPTYPE_CONSTANT| AML_NO_ARGS| 0, "One_op", ARGP_ONE_OP, ARGI_ONE_OP), -/* 02 */ OP_INFO_ENTRY (AML_ALIAS_OP, OPTYPE_NAMED_OBJECT| AML_HAS_ARGS| 0, "Alias", ARGP_ALIAS_OP, ARGI_ALIAS_OP), -/* 03 */ OP_INFO_ENTRY (AML_NAME_OP, OPTYPE_NAMED_OBJECT| AML_HAS_ARGS| 0, "Name", ARGP_NAME_OP, ARGI_NAME_OP), -/* 04 */ OP_INFO_ENTRY (AML_BYTE_OP, OPTYPE_LITERAL| AML_NO_ARGS| 0, "Byte_const", ARGP_BYTE_OP, ARGI_BYTE_OP), -/* 05 */ OP_INFO_ENTRY (AML_WORD_OP, OPTYPE_LITERAL| AML_NO_ARGS| 0, "Word_const", ARGP_WORD_OP, ARGI_WORD_OP), -/* 06 */ OP_INFO_ENTRY (AML_DWORD_OP, OPTYPE_LITERAL| AML_NO_ARGS| 0, "Dword_const", ARGP_DWORD_OP, ARGI_DWORD_OP), -/* 07 */ OP_INFO_ENTRY (AML_STRING_OP, OPTYPE_LITERAL| AML_NO_ARGS| 0, "String", ARGP_STRING_OP, ARGI_STRING_OP), -/* 08 */ OP_INFO_ENTRY (AML_SCOPE_OP, OPTYPE_NAMED_OBJECT| AML_HAS_ARGS| 0, "Scope", ARGP_SCOPE_OP, ARGI_SCOPE_OP), -/* 09 */ OP_INFO_ENTRY (AML_BUFFER_OP, OPTYPE_DATA_TERM| AML_HAS_ARGS| 0, "Buffer", ARGP_BUFFER_OP, ARGI_BUFFER_OP), -/* 0A */ OP_INFO_ENTRY (AML_PACKAGE_OP, OPTYPE_DATA_TERM| AML_HAS_ARGS| 0, "Package", ARGP_PACKAGE_OP, ARGI_PACKAGE_OP), -/* 0B */ OP_INFO_ENTRY (AML_METHOD_OP, OPTYPE_NAMED_OBJECT| AML_HAS_ARGS| 0, "Method", ARGP_METHOD_OP, ARGI_METHOD_OP), -/* 0C */ OP_INFO_ENTRY (AML_LOCAL0, OPTYPE_LOCAL_VARIABLE| AML_NO_ARGS| 0, "Local0", ARGP_LOCAL0, ARGI_LOCAL0), -/* 0D */ OP_INFO_ENTRY (AML_LOCAL1, OPTYPE_LOCAL_VARIABLE| AML_NO_ARGS| 0, "Local1", ARGP_LOCAL1, ARGI_LOCAL1), -/* 0E */ OP_INFO_ENTRY (AML_LOCAL2, OPTYPE_LOCAL_VARIABLE| AML_NO_ARGS| 0, "Local2", ARGP_LOCAL2, ARGI_LOCAL2), -/* 0F */ OP_INFO_ENTRY (AML_LOCAL3, OPTYPE_LOCAL_VARIABLE| AML_NO_ARGS| 0, "Local3", ARGP_LOCAL3, ARGI_LOCAL3), -/* 10 */ OP_INFO_ENTRY (AML_LOCAL4, OPTYPE_LOCAL_VARIABLE| AML_NO_ARGS| 0, "Local4", ARGP_LOCAL4, ARGI_LOCAL4), -/* 11 */ OP_INFO_ENTRY (AML_LOCAL5, OPTYPE_LOCAL_VARIABLE| AML_NO_ARGS| 0, "Local5", ARGP_LOCAL5, ARGI_LOCAL5), -/* 12 */ OP_INFO_ENTRY (AML_LOCAL6, OPTYPE_LOCAL_VARIABLE| AML_NO_ARGS| 0, "Local6", ARGP_LOCAL6, ARGI_LOCAL6), -/* 13 */ OP_INFO_ENTRY (AML_LOCAL7, OPTYPE_LOCAL_VARIABLE| AML_NO_ARGS| 0, "Local7", ARGP_LOCAL7, ARGI_LOCAL7), -/* 14 */ OP_INFO_ENTRY (AML_ARG0, OPTYPE_METHOD_ARGUMENT| AML_NO_ARGS| 0, "Arg0", ARGP_ARG0, ARGI_ARG0), -/* 15 */ OP_INFO_ENTRY (AML_ARG1, OPTYPE_METHOD_ARGUMENT| AML_NO_ARGS| 0, "Arg1", ARGP_ARG1, ARGI_ARG1), -/* 16 */ OP_INFO_ENTRY (AML_ARG2, OPTYPE_METHOD_ARGUMENT| AML_NO_ARGS| 0, "Arg2", ARGP_ARG2, ARGI_ARG2), -/* 17 */ OP_INFO_ENTRY (AML_ARG3, OPTYPE_METHOD_ARGUMENT| AML_NO_ARGS| 0, "Arg3", ARGP_ARG3, ARGI_ARG3), -/* 18 */ OP_INFO_ENTRY (AML_ARG4, OPTYPE_METHOD_ARGUMENT| AML_NO_ARGS| 0, "Arg4", ARGP_ARG4, ARGI_ARG4), -/* 19 */ OP_INFO_ENTRY (AML_ARG5, OPTYPE_METHOD_ARGUMENT| AML_NO_ARGS| 0, "Arg5", ARGP_ARG5, ARGI_ARG5), -/* 1_a */ OP_INFO_ENTRY (AML_ARG6, OPTYPE_METHOD_ARGUMENT| AML_NO_ARGS| 0, "Arg6", ARGP_ARG6, ARGI_ARG6), -/* 1_b */ OP_INFO_ENTRY (AML_STORE_OP, OPTYPE_MONADIC2_r| AML_HAS_ARGS| 0, "Store", ARGP_STORE_OP, ARGI_STORE_OP), -/* 1_c */ OP_INFO_ENTRY (AML_REF_OF_OP, OPTYPE_MONADIC2| AML_HAS_ARGS| 0, "Ref_of", ARGP_REF_OF_OP, ARGI_REF_OF_OP), -/* 1_d */ OP_INFO_ENTRY (AML_ADD_OP, OPTYPE_DYADIC2_r| AML_HAS_ARGS| 0, "Add", ARGP_ADD_OP, ARGI_ADD_OP), -/* 1_e */ OP_INFO_ENTRY (AML_CONCAT_OP, OPTYPE_DYADIC2_r| AML_HAS_ARGS| 0, "Concat", ARGP_CONCAT_OP, ARGI_CONCAT_OP), -/* 1_f */ OP_INFO_ENTRY (AML_SUBTRACT_OP, OPTYPE_DYADIC2_r| AML_HAS_ARGS| 0, "Subtract", ARGP_SUBTRACT_OP, ARGI_SUBTRACT_OP), -/* 20 */ OP_INFO_ENTRY (AML_INCREMENT_OP, OPTYPE_MONADIC2| AML_HAS_ARGS| 0, "Increment", ARGP_INCREMENT_OP, ARGI_INCREMENT_OP), -/* 21 */ OP_INFO_ENTRY (AML_DECREMENT_OP, OPTYPE_MONADIC2| AML_HAS_ARGS| 0, "Decrement", ARGP_DECREMENT_OP, ARGI_DECREMENT_OP), -/* 22 */ OP_INFO_ENTRY (AML_MULTIPLY_OP, OPTYPE_DYADIC2_r| AML_HAS_ARGS| 0, "Multiply", ARGP_MULTIPLY_OP, ARGI_MULTIPLY_OP), -/* 23 */ OP_INFO_ENTRY (AML_DIVIDE_OP, OPTYPE_DYADIC2_r| AML_HAS_ARGS| 0, "Divide", ARGP_DIVIDE_OP, ARGI_DIVIDE_OP), -/* 24 */ OP_INFO_ENTRY (AML_SHIFT_LEFT_OP, OPTYPE_DYADIC2_r| AML_HAS_ARGS| 0, "Shift_left", ARGP_SHIFT_LEFT_OP, ARGI_SHIFT_LEFT_OP), -/* 25 */ OP_INFO_ENTRY (AML_SHIFT_RIGHT_OP, OPTYPE_DYADIC2_r| AML_HAS_ARGS| 0, "Shift_right", ARGP_SHIFT_RIGHT_OP, ARGI_SHIFT_RIGHT_OP), -/* 26 */ OP_INFO_ENTRY (AML_BIT_AND_OP, OPTYPE_DYADIC2_r| AML_HAS_ARGS| 0, "And", ARGP_BIT_AND_OP, ARGI_BIT_AND_OP), -/* 27 */ OP_INFO_ENTRY (AML_BIT_NAND_OP, OPTYPE_DYADIC2_r| AML_HAS_ARGS| 0, "NAnd", ARGP_BIT_NAND_OP, ARGI_BIT_NAND_OP), -/* 28 */ OP_INFO_ENTRY (AML_BIT_OR_OP, OPTYPE_DYADIC2_r| AML_HAS_ARGS| 0, "Or", ARGP_BIT_OR_OP, ARGI_BIT_OR_OP), -/* 29 */ OP_INFO_ENTRY (AML_BIT_NOR_OP, OPTYPE_DYADIC2_r| AML_HAS_ARGS| 0, "NOr", ARGP_BIT_NOR_OP, ARGI_BIT_NOR_OP), -/* 2_a */ OP_INFO_ENTRY (AML_BIT_XOR_OP, OPTYPE_DYADIC2_r| AML_HAS_ARGS| 0, "XOr", ARGP_BIT_XOR_OP, ARGI_BIT_XOR_OP), -/* 2_b */ OP_INFO_ENTRY (AML_BIT_NOT_OP, OPTYPE_MONADIC2_r| AML_HAS_ARGS| 0, "Not", ARGP_BIT_NOT_OP, ARGI_BIT_NOT_OP), -/* 2_c */ OP_INFO_ENTRY (AML_FIND_SET_LEFT_BIT_OP, OPTYPE_MONADIC2_r| AML_HAS_ARGS| 0, "Find_set_left_bit", ARGP_FIND_SET_LEFT_BIT_OP, ARGI_FIND_SET_LEFT_BIT_OP), -/* 2_d */ OP_INFO_ENTRY (AML_FIND_SET_RIGHT_BIT_OP, OPTYPE_MONADIC2_r| AML_HAS_ARGS| 0, "Find_set_right_bit", ARGP_FIND_SET_RIGHT_BIT_OP, ARGI_FIND_SET_RIGHT_BIT_OP), -/* 2_e */ OP_INFO_ENTRY (AML_DEREF_OF_OP, OPTYPE_MONADIC2| AML_HAS_ARGS| 0, "Deref_of", ARGP_DEREF_OF_OP, ARGI_DEREF_OF_OP), -/* 2_f */ OP_INFO_ENTRY (AML_NOTIFY_OP, OPTYPE_DYADIC1| AML_HAS_ARGS| 0, "Notify", ARGP_NOTIFY_OP, ARGI_NOTIFY_OP), -/* 30 */ OP_INFO_ENTRY (AML_SIZE_OF_OP, OPTYPE_MONADIC2| AML_HAS_ARGS| 0, "Size_of", ARGP_SIZE_OF_OP, ARGI_SIZE_OF_OP), -/* 31 */ OP_INFO_ENTRY (AML_INDEX_OP, OPTYPE_INDEX| AML_HAS_ARGS| 0, "Index", ARGP_INDEX_OP, ARGI_INDEX_OP), -/* 32 */ OP_INFO_ENTRY (AML_MATCH_OP, OPTYPE_MATCH| AML_HAS_ARGS| 0, "Match", ARGP_MATCH_OP, ARGI_MATCH_OP), -/* 33 */ OP_INFO_ENTRY (AML_DWORD_FIELD_OP, OPTYPE_CREATE_FIELD| AML_HAS_ARGS| 0, "Create_dWord_field", ARGP_DWORD_FIELD_OP, ARGI_DWORD_FIELD_OP), -/* 34 */ OP_INFO_ENTRY (AML_WORD_FIELD_OP, OPTYPE_CREATE_FIELD| AML_HAS_ARGS| 0, "Create_word_field", ARGP_WORD_FIELD_OP, ARGI_WORD_FIELD_OP), -/* 35 */ OP_INFO_ENTRY (AML_BYTE_FIELD_OP, OPTYPE_CREATE_FIELD| AML_HAS_ARGS| 0, "Create_byte_field", ARGP_BYTE_FIELD_OP, ARGI_BYTE_FIELD_OP), -/* 36 */ OP_INFO_ENTRY (AML_BIT_FIELD_OP, OPTYPE_CREATE_FIELD| AML_HAS_ARGS| 0, "Create_bit_field", ARGP_BIT_FIELD_OP, ARGI_BIT_FIELD_OP), -/* 37 */ OP_INFO_ENTRY (AML_TYPE_OP, OPTYPE_MONADIC2| AML_HAS_ARGS| 0, "Object_type", ARGP_TYPE_OP, ARGI_TYPE_OP), -/* 38 */ OP_INFO_ENTRY (AML_LAND_OP, OPTYPE_DYADIC2| AML_HAS_ARGS| 0, "LAnd", ARGP_LAND_OP, ARGI_LAND_OP), -/* 39 */ OP_INFO_ENTRY (AML_LOR_OP, OPTYPE_DYADIC2| AML_HAS_ARGS| 0, "LOr", ARGP_LOR_OP, ARGI_LOR_OP), -/* 3_a */ OP_INFO_ENTRY (AML_LNOT_OP, OPTYPE_MONADIC2| AML_HAS_ARGS| 0, "LNot", ARGP_LNOT_OP, ARGI_LNOT_OP), -/* 3_b */ OP_INFO_ENTRY (AML_LEQUAL_OP, OPTYPE_DYADIC2| AML_HAS_ARGS| 0, "LEqual", ARGP_LEQUAL_OP, ARGI_LEQUAL_OP), -/* 3_c */ OP_INFO_ENTRY (AML_LGREATER_OP, OPTYPE_DYADIC2| AML_HAS_ARGS| 0, "LGreater", ARGP_LGREATER_OP, ARGI_LGREATER_OP), -/* 3_d */ OP_INFO_ENTRY (AML_LLESS_OP, OPTYPE_DYADIC2| AML_HAS_ARGS| 0, "LLess", ARGP_LLESS_OP, ARGI_LLESS_OP), -/* 3_e */ OP_INFO_ENTRY (AML_IF_OP, OPTYPE_CONTROL| AML_HAS_ARGS| 0, "If", ARGP_IF_OP, ARGI_IF_OP), -/* 3_f */ OP_INFO_ENTRY (AML_ELSE_OP, OPTYPE_CONTROL| AML_HAS_ARGS| 0, "Else", ARGP_ELSE_OP, ARGI_ELSE_OP), -/* 40 */ OP_INFO_ENTRY (AML_WHILE_OP, OPTYPE_CONTROL| AML_HAS_ARGS| 0, "While", ARGP_WHILE_OP, ARGI_WHILE_OP), -/* 41 */ OP_INFO_ENTRY (AML_NOOP_CODE, OPTYPE_CONTROL| AML_NO_ARGS| 0, "Noop", ARGP_NOOP_CODE, ARGI_NOOP_CODE), -/* 42 */ OP_INFO_ENTRY (AML_RETURN_OP, OPTYPE_CONTROL| AML_HAS_ARGS| 0, "Return", ARGP_RETURN_OP, ARGI_RETURN_OP), -/* 43 */ OP_INFO_ENTRY (AML_BREAK_OP, OPTYPE_CONTROL| AML_NO_ARGS| 0, "Break", ARGP_BREAK_OP, ARGI_BREAK_OP), -/* 44 */ OP_INFO_ENTRY (AML_BREAK_POINT_OP, OPTYPE_CONTROL| AML_NO_ARGS| 0, "Break_point", ARGP_BREAK_POINT_OP, ARGI_BREAK_POINT_OP), -/* 45 */ OP_INFO_ENTRY (AML_ONES_OP, OPTYPE_CONSTANT| AML_NO_ARGS| 0, "Ones_op", ARGP_ONES_OP, ARGI_ONES_OP), +/* 00 */ /* AML_ZERO_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CONSTANT| AML_NO_ARGS, "Zero_op", ARGP_ZERO_OP, ARGI_ZERO_OP), +/* 01 */ /* AML_ONE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CONSTANT| AML_NO_ARGS, "One_op", ARGP_ONE_OP, ARGI_ONE_OP), +/* 02 */ /* AML_ALIAS_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_HAS_ARGS, "Alias", ARGP_ALIAS_OP, ARGI_ALIAS_OP), +/* 03 */ /* AML_NAME_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_HAS_ARGS, "Name", ARGP_NAME_OP, ARGI_NAME_OP), +/* 04 */ /* AML_BYTE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_LITERAL| AML_NO_ARGS, "Byte_const", ARGP_BYTE_OP, ARGI_BYTE_OP), +/* 05 */ /* AML_WORD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_LITERAL| AML_NO_ARGS, "Word_const", ARGP_WORD_OP, ARGI_WORD_OP), +/* 06 */ /* AML_DWORD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_LITERAL| AML_NO_ARGS, "Dword_const", ARGP_DWORD_OP, ARGI_DWORD_OP), +/* 07 */ /* AML_STRING_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_LITERAL| AML_NO_ARGS, "String", ARGP_STRING_OP, ARGI_STRING_OP), +/* 08 */ /* AML_SCOPE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_HAS_ARGS, "Scope", ARGP_SCOPE_OP, ARGI_SCOPE_OP), +/* 09 */ /* AML_BUFFER_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DATA_TERM| AML_HAS_ARGS, "Buffer", ARGP_BUFFER_OP, ARGI_BUFFER_OP), +/* 0A */ /* AML_PACKAGE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DATA_TERM| AML_HAS_ARGS, "Package", ARGP_PACKAGE_OP, ARGI_PACKAGE_OP), +/* 0B */ /* AML_METHOD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_HAS_ARGS, "Method", ARGP_METHOD_OP, ARGI_METHOD_OP), +/* 0C */ /* AML_LOCAL0 */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_LOCAL_VARIABLE| AML_NO_ARGS, "Local0", ARGP_LOCAL0, ARGI_LOCAL0), +/* 0D */ /* AML_LOCAL1 */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_LOCAL_VARIABLE| AML_NO_ARGS, "Local1", ARGP_LOCAL1, ARGI_LOCAL1), +/* 0E */ /* AML_LOCAL2 */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_LOCAL_VARIABLE| AML_NO_ARGS, "Local2", ARGP_LOCAL2, ARGI_LOCAL2), +/* 0F */ /* AML_LOCAL3 */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_LOCAL_VARIABLE| AML_NO_ARGS, "Local3", ARGP_LOCAL3, ARGI_LOCAL3), +/* 10 */ /* AML_LOCAL4 */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_LOCAL_VARIABLE| AML_NO_ARGS, "Local4", ARGP_LOCAL4, ARGI_LOCAL4), +/* 11 */ /* AML_LOCAL5 */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_LOCAL_VARIABLE| AML_NO_ARGS, "Local5", ARGP_LOCAL5, ARGI_LOCAL5), +/* 12 */ /* AML_LOCAL6 */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_LOCAL_VARIABLE| AML_NO_ARGS, "Local6", ARGP_LOCAL6, ARGI_LOCAL6), +/* 13 */ /* AML_LOCAL7 */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_LOCAL_VARIABLE| AML_NO_ARGS, "Local7", ARGP_LOCAL7, ARGI_LOCAL7), +/* 14 */ /* AML_ARG0 */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_METHOD_ARGUMENT| AML_NO_ARGS, "Arg0", ARGP_ARG0, ARGI_ARG0), +/* 15 */ /* AML_ARG1 */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_METHOD_ARGUMENT| AML_NO_ARGS, "Arg1", ARGP_ARG1, ARGI_ARG1), +/* 16 */ /* AML_ARG2 */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_METHOD_ARGUMENT| AML_NO_ARGS, "Arg2", ARGP_ARG2, ARGI_ARG2), +/* 17 */ /* AML_ARG3 */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_METHOD_ARGUMENT| AML_NO_ARGS, "Arg3", ARGP_ARG3, ARGI_ARG3), +/* 18 */ /* AML_ARG4 */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_METHOD_ARGUMENT| AML_NO_ARGS, "Arg4", ARGP_ARG4, ARGI_ARG4), +/* 19 */ /* AML_ARG5 */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_METHOD_ARGUMENT| AML_NO_ARGS, "Arg5", ARGP_ARG5, ARGI_ARG5), +/* 1_a */ /* AML_ARG6 */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_METHOD_ARGUMENT| AML_NO_ARGS, "Arg6", ARGP_ARG6, ARGI_ARG6), +/* 1_b */ /* AML_STORE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2_r| AML_HAS_ARGS, "Store", ARGP_STORE_OP, ARGI_STORE_OP), +/* 1_c */ /* AML_REF_OF_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2| AML_HAS_ARGS, "Ref_of", ARGP_REF_OF_OP, ARGI_REF_OF_OP), +/* 1_d */ /* AML_ADD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_r| AML_HAS_ARGS, "Add", ARGP_ADD_OP, ARGI_ADD_OP), +/* 1_e */ /* AML_CONCAT_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_r| AML_HAS_ARGS, "Concat", ARGP_CONCAT_OP, ARGI_CONCAT_OP), +/* 1_f */ /* AML_SUBTRACT_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_r| AML_HAS_ARGS, "Subtract", ARGP_SUBTRACT_OP, ARGI_SUBTRACT_OP), +/* 20 */ /* AML_INCREMENT_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2| AML_HAS_ARGS, "Increment", ARGP_INCREMENT_OP, ARGI_INCREMENT_OP), +/* 21 */ /* AML_DECREMENT_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2| AML_HAS_ARGS, "Decrement", ARGP_DECREMENT_OP, ARGI_DECREMENT_OP), +/* 22 */ /* AML_MULTIPLY_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_r| AML_HAS_ARGS, "Multiply", ARGP_MULTIPLY_OP, ARGI_MULTIPLY_OP), +/* 23 */ /* AML_DIVIDE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_r| AML_HAS_ARGS, "Divide", ARGP_DIVIDE_OP, ARGI_DIVIDE_OP), +/* 24 */ /* AML_SHIFT_LEFT_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_r| AML_HAS_ARGS, "Shift_left", ARGP_SHIFT_LEFT_OP, ARGI_SHIFT_LEFT_OP), +/* 25 */ /* AML_SHIFT_RIGHT_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_r| AML_HAS_ARGS, "Shift_right", ARGP_SHIFT_RIGHT_OP, ARGI_SHIFT_RIGHT_OP), +/* 26 */ /* AML_BIT_AND_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_r| AML_HAS_ARGS, "And", ARGP_BIT_AND_OP, ARGI_BIT_AND_OP), +/* 27 */ /* AML_BIT_NAND_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_r| AML_HAS_ARGS, "NAnd", ARGP_BIT_NAND_OP, ARGI_BIT_NAND_OP), +/* 28 */ /* AML_BIT_OR_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_r| AML_HAS_ARGS, "Or", ARGP_BIT_OR_OP, ARGI_BIT_OR_OP), +/* 29 */ /* AML_BIT_NOR_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_r| AML_HAS_ARGS, "NOr", ARGP_BIT_NOR_OP, ARGI_BIT_NOR_OP), +/* 2_a */ /* AML_BIT_XOR_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_r| AML_HAS_ARGS, "XOr", ARGP_BIT_XOR_OP, ARGI_BIT_XOR_OP), +/* 2_b */ /* AML_BIT_NOT_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2_r| AML_HAS_ARGS, "Not", ARGP_BIT_NOT_OP, ARGI_BIT_NOT_OP), +/* 2_c */ /* AML_FIND_SET_LEFT_BIT_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2_r| AML_HAS_ARGS, "Find_set_left_bit", ARGP_FIND_SET_LEFT_BIT_OP, ARGI_FIND_SET_LEFT_BIT_OP), +/* 2_d */ /* AML_FIND_SET_RIGHT_BIT_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2_r| AML_HAS_ARGS, "Find_set_right_bit", ARGP_FIND_SET_RIGHT_BIT_OP, ARGI_FIND_SET_RIGHT_BIT_OP), +/* 2_e */ /* AML_DEREF_OF_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2| AML_HAS_ARGS, "Deref_of", ARGP_DEREF_OF_OP, ARGI_DEREF_OF_OP), +/* 2_f */ /* AML_NOTIFY_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC1| AML_HAS_ARGS, "Notify", ARGP_NOTIFY_OP, ARGI_NOTIFY_OP), +/* 30 */ /* AML_SIZE_OF_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2| AML_HAS_ARGS, "Size_of", ARGP_SIZE_OF_OP, ARGI_SIZE_OF_OP), +/* 31 */ /* AML_INDEX_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_INDEX| AML_HAS_ARGS, "Index", ARGP_INDEX_OP, ARGI_INDEX_OP), +/* 32 */ /* AML_MATCH_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MATCH| AML_HAS_ARGS, "Match", ARGP_MATCH_OP, ARGI_MATCH_OP), +/* 33 */ /* AML_DWORD_FIELD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CREATE_FIELD| AML_HAS_ARGS, "Create_dWord_field", ARGP_DWORD_FIELD_OP, ARGI_DWORD_FIELD_OP), +/* 34 */ /* AML_WORD_FIELD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CREATE_FIELD| AML_HAS_ARGS, "Create_word_field", ARGP_WORD_FIELD_OP, ARGI_WORD_FIELD_OP), +/* 35 */ /* AML_BYTE_FIELD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CREATE_FIELD| AML_HAS_ARGS, "Create_byte_field", ARGP_BYTE_FIELD_OP, ARGI_BYTE_FIELD_OP), +/* 36 */ /* AML_BIT_FIELD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CREATE_FIELD| AML_HAS_ARGS, "Create_bit_field", ARGP_BIT_FIELD_OP, ARGI_BIT_FIELD_OP), +/* 37 */ /* AML_TYPE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2| AML_HAS_ARGS, "Object_type", ARGP_TYPE_OP, ARGI_TYPE_OP), +/* 38 */ /* AML_LAND_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2| AML_HAS_ARGS, "LAnd", ARGP_LAND_OP, ARGI_LAND_OP), +/* 39 */ /* AML_LOR_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2| AML_HAS_ARGS, "LOr", ARGP_LOR_OP, ARGI_LOR_OP), +/* 3_a */ /* AML_LNOT_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2| AML_HAS_ARGS, "LNot", ARGP_LNOT_OP, ARGI_LNOT_OP), +/* 3_b */ /* AML_LEQUAL_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2| AML_HAS_ARGS, "LEqual", ARGP_LEQUAL_OP, ARGI_LEQUAL_OP), +/* 3_c */ /* AML_LGREATER_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2| AML_HAS_ARGS, "LGreater", ARGP_LGREATER_OP, ARGI_LGREATER_OP), +/* 3_d */ /* AML_LLESS_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2| AML_HAS_ARGS, "LLess", ARGP_LLESS_OP, ARGI_LLESS_OP), +/* 3_e */ /* AML_IF_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CONTROL| AML_HAS_ARGS, "If", ARGP_IF_OP, ARGI_IF_OP), +/* 3_f */ /* AML_ELSE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CONTROL| AML_HAS_ARGS, "Else", ARGP_ELSE_OP, ARGI_ELSE_OP), +/* 40 */ /* AML_WHILE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CONTROL| AML_HAS_ARGS, "While", ARGP_WHILE_OP, ARGI_WHILE_OP), +/* 41 */ /* AML_NOOP_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CONTROL| AML_NO_ARGS, "Noop", ARGP_NOOP_OP, ARGI_NOOP_OP), +/* 42 */ /* AML_RETURN_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CONTROL| AML_HAS_ARGS, "Return", ARGP_RETURN_OP, ARGI_RETURN_OP), +/* 43 */ /* AML_BREAK_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CONTROL| AML_NO_ARGS, "Break", ARGP_BREAK_OP, ARGI_BREAK_OP), +/* 44 */ /* AML_BREAK_POINT_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CONTROL| AML_NO_ARGS, "Break_point", ARGP_BREAK_POINT_OP, ARGI_BREAK_POINT_OP), +/* 45 */ /* AML_ONES_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CONSTANT| AML_NO_ARGS, "Ones_op", ARGP_ONES_OP, ARGI_ONES_OP), /* Prefixed opcodes (Two-byte opcodes with a prefix op) */ -/* 46 */ OP_INFO_ENTRY (AML_MUTEX_OP, OPTYPE_NAMED_OBJECT| AML_HAS_ARGS| 0, "Mutex", ARGP_MUTEX_OP, ARGI_MUTEX_OP), -/* 47 */ OP_INFO_ENTRY (AML_EVENT_OP, OPTYPE_NAMED_OBJECT| AML_NO_ARGS| 0, "Event", ARGP_EVENT_OP, ARGI_EVENT_OP), -/* 48 */ OP_INFO_ENTRY (AML_COND_REF_OF_OP, OPTYPE_MONADIC2_r| AML_HAS_ARGS| 0, "Cond_ref_of", ARGP_COND_REF_OF_OP, ARGI_COND_REF_OF_OP), -/* 49 */ OP_INFO_ENTRY (AML_CREATE_FIELD_OP, OPTYPE_CREATE_FIELD| AML_HAS_ARGS| 0, "Create_field", ARGP_CREATE_FIELD_OP, ARGI_CREATE_FIELD_OP), -/* 4_a */ OP_INFO_ENTRY (AML_LOAD_OP, OPTYPE_RECONFIGURATION| AML_HAS_ARGS| 0, "Load", ARGP_LOAD_OP, ARGI_LOAD_OP), -/* 4_b */ OP_INFO_ENTRY (AML_STALL_OP, OPTYPE_MONADIC1| AML_HAS_ARGS| 0, "Stall", ARGP_STALL_OP, ARGI_STALL_OP), -/* 4_c */ OP_INFO_ENTRY (AML_SLEEP_OP, OPTYPE_MONADIC1| AML_HAS_ARGS| 0, "Sleep", ARGP_SLEEP_OP, ARGI_SLEEP_OP), -/* 4_d */ OP_INFO_ENTRY (AML_ACQUIRE_OP, OPTYPE_DYADIC2_s| AML_HAS_ARGS| 0, "Acquire", ARGP_ACQUIRE_OP, ARGI_ACQUIRE_OP), -/* 4_e */ OP_INFO_ENTRY (AML_SIGNAL_OP, OPTYPE_MONADIC1| AML_HAS_ARGS| 0, "Signal", ARGP_SIGNAL_OP, ARGI_SIGNAL_OP), -/* 4_f */ OP_INFO_ENTRY (AML_WAIT_OP, OPTYPE_DYADIC2_s| AML_HAS_ARGS| 0, "Wait", ARGP_WAIT_OP, ARGI_WAIT_OP), -/* 50 */ OP_INFO_ENTRY (AML_RESET_OP, OPTYPE_MONADIC1| AML_HAS_ARGS| 0, "Reset", ARGP_RESET_OP, ARGI_RESET_OP), -/* 51 */ OP_INFO_ENTRY (AML_RELEASE_OP, OPTYPE_MONADIC1| AML_HAS_ARGS| 0, "Release", ARGP_RELEASE_OP, ARGI_RELEASE_OP), -/* 52 */ OP_INFO_ENTRY (AML_FROM_BCDOP, OPTYPE_MONADIC2_r| AML_HAS_ARGS| 0, "From_bCD", ARGP_FROM_BCDOP, ARGI_FROM_BCDOP), -/* 53 */ OP_INFO_ENTRY (AML_TO_BCDOP, OPTYPE_MONADIC2_r| AML_HAS_ARGS| 0, "To_bCD", ARGP_TO_BCDOP, ARGI_TO_BCDOP), -/* 54 */ OP_INFO_ENTRY (AML_UN_LOAD_OP, OPTYPE_RECONFIGURATION| AML_HAS_ARGS| 0, "Unload", ARGP_UN_LOAD_OP, ARGI_UN_LOAD_OP), -/* 55 */ OP_INFO_ENTRY (AML_REVISION_OP, OPTYPE_CONSTANT| AML_NO_ARGS| 0, "Revision", ARGP_REVISION_OP, ARGI_REVISION_OP), -/* 56 */ OP_INFO_ENTRY (AML_DEBUG_OP, OPTYPE_CONSTANT| AML_NO_ARGS| 0, "Debug", ARGP_DEBUG_OP, ARGI_DEBUG_OP), -/* 57 */ OP_INFO_ENTRY (AML_FATAL_OP, OPTYPE_FATAL| AML_HAS_ARGS| 0, "Fatal", ARGP_FATAL_OP, ARGI_FATAL_OP), -/* 58 */ OP_INFO_ENTRY (AML_REGION_OP, OPTYPE_NAMED_OBJECT| AML_HAS_ARGS| 0, "Op_region", ARGP_REGION_OP, ARGI_REGION_OP), -/* 59 */ OP_INFO_ENTRY (AML_DEF_FIELD_OP, OPTYPE_NAMED_OBJECT| AML_HAS_ARGS| 0, "Field", ARGP_DEF_FIELD_OP, ARGI_DEF_FIELD_OP), -/* 5_a */ OP_INFO_ENTRY (AML_DEVICE_OP, OPTYPE_NAMED_OBJECT| AML_HAS_ARGS| 0, "Device", ARGP_DEVICE_OP, ARGI_DEVICE_OP), -/* 5_b */ OP_INFO_ENTRY (AML_PROCESSOR_OP, OPTYPE_NAMED_OBJECT| AML_HAS_ARGS| 0, "Processor", ARGP_PROCESSOR_OP, ARGI_PROCESSOR_OP), -/* 5_c */ OP_INFO_ENTRY (AML_POWER_RES_OP, OPTYPE_NAMED_OBJECT| AML_HAS_ARGS| 0, "Power_res", ARGP_POWER_RES_OP, ARGI_POWER_RES_OP), -/* 5_d */ OP_INFO_ENTRY (AML_THERMAL_ZONE_OP, OPTYPE_NAMED_OBJECT| AML_HAS_ARGS| 0, "Thermal_zone", ARGP_THERMAL_ZONE_OP, ARGI_THERMAL_ZONE_OP), -/* 5_e */ OP_INFO_ENTRY (AML_INDEX_FIELD_OP, OPTYPE_NAMED_OBJECT| AML_HAS_ARGS| 0, "Index_field", ARGP_INDEX_FIELD_OP, ARGI_INDEX_FIELD_OP), -/* 5_f */ OP_INFO_ENTRY (AML_BANK_FIELD_OP, OPTYPE_NAMED_OBJECT| AML_HAS_ARGS| 0, "Bank_field", ARGP_BANK_FIELD_OP, ARGI_BANK_FIELD_OP), +/* 46 */ /* AML_MUTEX_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_HAS_ARGS, "Mutex", ARGP_MUTEX_OP, ARGI_MUTEX_OP), +/* 47 */ /* AML_EVENT_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_NO_ARGS, "Event", ARGP_EVENT_OP, ARGI_EVENT_OP), +/* 48 */ /* AML_COND_REF_OF_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2_r| AML_HAS_ARGS, "Cond_ref_of", ARGP_COND_REF_OF_OP, ARGI_COND_REF_OF_OP), +/* 49 */ /* AML_CREATE_FIELD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CREATE_FIELD| AML_HAS_ARGS, "Create_field", ARGP_CREATE_FIELD_OP, ARGI_CREATE_FIELD_OP), +/* 4_a */ /* AML_LOAD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_RECONFIGURATION| AML_HAS_ARGS, "Load", ARGP_LOAD_OP, ARGI_LOAD_OP), +/* 4_b */ /* AML_STALL_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC1| AML_HAS_ARGS, "Stall", ARGP_STALL_OP, ARGI_STALL_OP), +/* 4_c */ /* AML_SLEEP_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC1| AML_HAS_ARGS, "Sleep", ARGP_SLEEP_OP, ARGI_SLEEP_OP), +/* 4_d */ /* AML_ACQUIRE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_s| AML_HAS_ARGS, "Acquire", ARGP_ACQUIRE_OP, ARGI_ACQUIRE_OP), +/* 4_e */ /* AML_SIGNAL_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC1| AML_HAS_ARGS, "Signal", ARGP_SIGNAL_OP, ARGI_SIGNAL_OP), +/* 4_f */ /* AML_WAIT_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_DYADIC2_s| AML_HAS_ARGS, "Wait", ARGP_WAIT_OP, ARGI_WAIT_OP), +/* 50 */ /* AML_RESET_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC1| AML_HAS_ARGS, "Reset", ARGP_RESET_OP, ARGI_RESET_OP), +/* 51 */ /* AML_RELEASE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC1| AML_HAS_ARGS, "Release", ARGP_RELEASE_OP, ARGI_RELEASE_OP), +/* 52 */ /* AML_FROM_BCD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2_r| AML_HAS_ARGS, "From_bCD", ARGP_FROM_BCD_OP, ARGI_FROM_BCD_OP), +/* 53 */ /* AML_TO_BCD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_MONADIC2_r| AML_HAS_ARGS, "To_bCD", ARGP_TO_BCD_OP, ARGI_TO_BCD_OP), +/* 54 */ /* AML_UNLOAD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_RECONFIGURATION| AML_HAS_ARGS, "Unload", ARGP_UNLOAD_OP, ARGI_UNLOAD_OP), +/* 55 */ /* AML_REVISION_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CONSTANT| AML_NO_ARGS, "Revision", ARGP_REVISION_OP, ARGI_REVISION_OP), +/* 56 */ /* AML_DEBUG_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_CONSTANT| AML_NO_ARGS, "Debug", ARGP_DEBUG_OP, ARGI_DEBUG_OP), +/* 57 */ /* AML_FATAL_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_FATAL| AML_HAS_ARGS, "Fatal", ARGP_FATAL_OP, ARGI_FATAL_OP), +/* 58 */ /* AML_REGION_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_HAS_ARGS, "Op_region", ARGP_REGION_OP, ARGI_REGION_OP), +/* 59 */ /* AML_DEF_FIELD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_HAS_ARGS, "Field", ARGP_DEF_FIELD_OP, ARGI_DEF_FIELD_OP), +/* 5_a */ /* AML_DEVICE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_HAS_ARGS, "Device", ARGP_DEVICE_OP, ARGI_DEVICE_OP), +/* 5_b */ /* AML_PROCESSOR_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_HAS_ARGS, "Processor", ARGP_PROCESSOR_OP, ARGI_PROCESSOR_OP), +/* 5_c */ /* AML_POWER_RES_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_HAS_ARGS, "Power_res", ARGP_POWER_RES_OP, ARGI_POWER_RES_OP), +/* 5_d */ /* AML_THERMAL_ZONE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_HAS_ARGS, "Thermal_zone", ARGP_THERMAL_ZONE_OP, ARGI_THERMAL_ZONE_OP), +/* 5_e */ /* AML_INDEX_FIELD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_HAS_ARGS, "Index_field", ARGP_INDEX_FIELD_OP, ARGI_INDEX_FIELD_OP), +/* 5_f */ /* AML_BANK_FIELD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_NAMED_OBJECT| AML_HAS_ARGS, "Bank_field", ARGP_BANK_FIELD_OP, ARGI_BANK_FIELD_OP), /* Internal opcodes that map to invalid AML opcodes */ -/* 60 */ OP_INFO_ENTRY (AML_LNOTEQUAL_OP, OPTYPE_BOGUS| AML_HAS_ARGS| 0, "LNot_equal", ARGP_LNOTEQUAL_OP, ARGI_LNOTEQUAL_OP), -/* 61 */ OP_INFO_ENTRY (AML_LLESSEQUAL_OP, OPTYPE_BOGUS| AML_HAS_ARGS| 0, "LLess_equal", ARGP_LLESSEQUAL_OP, ARGI_LLESSEQUAL_OP), -/* 62 */ OP_INFO_ENTRY (AML_LGREATEREQUAL_OP, OPTYPE_BOGUS| AML_HAS_ARGS| 0, "LGreater_equal", ARGP_LGREATEREQUAL_OP, ARGI_LGREATEREQUAL_OP), -/* 63 */ OP_INFO_ENTRY (AML_NAMEPATH_OP, OPTYPE_LITERAL| AML_NO_ARGS| 0, "Name_path", ARGP_NAMEPATH_OP, ARGI_NAMEPATH_OP), -/* 64 */ OP_INFO_ENTRY (AML_METHODCALL_OP, OPTYPE_METHOD_CALL| AML_HAS_ARGS| 0, "Method_call", ARGP_METHODCALL_OP, ARGI_METHODCALL_OP), -/* 65 */ OP_INFO_ENTRY (AML_BYTELIST_OP, OPTYPE_LITERAL| AML_NO_ARGS| 0, "Byte_list", ARGP_BYTELIST_OP, ARGI_BYTELIST_OP), -/* 66 */ OP_INFO_ENTRY (AML_RESERVEDFIELD_OP, OPTYPE_BOGUS| AML_NO_ARGS| 0, "Reserved_field", ARGP_RESERVEDFIELD_OP, ARGI_RESERVEDFIELD_OP), -/* 67 */ OP_INFO_ENTRY (AML_NAMEDFIELD_OP, OPTYPE_BOGUS| AML_NO_ARGS| 0, "Named_field", ARGP_NAMEDFIELD_OP, ARGI_NAMEDFIELD_OP), -/* 68 */ OP_INFO_ENTRY (AML_ACCESSFIELD_OP, OPTYPE_BOGUS| AML_NO_ARGS| 0, "Access_field", ARGP_ACCESSFIELD_OP, ARGI_ACCESSFIELD_OP), -/* 69 */ OP_INFO_ENTRY (AML_STATICSTRING_OP, OPTYPE_BOGUS| AML_NO_ARGS| 0, "Static_string", ARGP_STATICSTRING_OP, ARGI_STATICSTRING_OP), -/* 6_a */ OP_INFO_ENTRY (0, OPTYPE_BOGUS| AML_HAS_ARGS| 0, "UNKNOWN_OP!", ARG_NONE, ARG_NONE), - OP_INFO_ENTRY (0, 0| AML_HAS_ARGS| 0, NULL, ARG_NONE, ARG_NONE) +/* 60 */ /* AML_LNOTEQUAL_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_BOGUS| AML_HAS_ARGS, "LNot_equal", ARGP_LNOTEQUAL_OP, ARGI_LNOTEQUAL_OP), +/* 61 */ /* AML_LLESSEQUAL_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_BOGUS| AML_HAS_ARGS, "LLess_equal", ARGP_LLESSEQUAL_OP, ARGI_LLESSEQUAL_OP), +/* 62 */ /* AML_LGREATEREQUAL_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_BOGUS| AML_HAS_ARGS, "LGreater_equal", ARGP_LGREATEREQUAL_OP, ARGI_LGREATEREQUAL_OP), +/* 63 */ /* AML_NAMEPATH_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_LITERAL| AML_NO_ARGS, "Name_path", ARGP_NAMEPATH_OP, ARGI_NAMEPATH_OP), +/* 64 */ /* AML_METHODCALL_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_METHOD_CALL| AML_HAS_ARGS, "Method_call", ARGP_METHODCALL_OP, ARGI_METHODCALL_OP), +/* 65 */ /* AML_BYTELIST_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_LITERAL| AML_NO_ARGS, "Byte_list", ARGP_BYTELIST_OP, ARGI_BYTELIST_OP), +/* 66 */ /* AML_RESERVEDFIELD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_BOGUS| AML_NO_ARGS, "Reserved_field", ARGP_RESERVEDFIELD_OP, ARGI_RESERVEDFIELD_OP), +/* 67 */ /* AML_NAMEDFIELD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_BOGUS| AML_NO_ARGS, "Named_field", ARGP_NAMEDFIELD_OP, ARGI_NAMEDFIELD_OP), +/* 68 */ /* AML_ACCESSFIELD_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_BOGUS| AML_NO_ARGS, "Access_field", ARGP_ACCESSFIELD_OP, ARGI_ACCESSFIELD_OP), +/* 69 */ /* AML_STATICSTRING_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_BOGUS| AML_NO_ARGS, "Static_string", ARGP_STATICSTRING_OP, ARGI_STATICSTRING_OP), +/* 6_a */ /* AML_RETURN_VALUE_OP */ OP_INFO_ENTRY (ACPI_OP_TYPE_OPCODE | OPTYPE_RETURN| AML_HAS_ARGS, "[Return Value]", ARG_NONE, ARG_NONE), +/* 6_b */ /* UNKNOWN OPCODES */ OP_INFO_ENTRY (ACPI_OP_TYPE_UNKNOWN | OPTYPE_BOGUS| AML_HAS_ARGS, "UNKNOWN_OP!", ARG_NONE, ARG_NONE), +/* 6_c */ /* ASCII CHARACTERS */ OP_INFO_ENTRY (ACPI_OP_TYPE_ASCII | OPTYPE_BOGUS| AML_HAS_ARGS, "ASCII_ONLY!", ARG_NONE, ARG_NONE), +/* 6_d */ /* PREFIX CHARACTERS */ OP_INFO_ENTRY (ACPI_OP_TYPE_PREFIX | OPTYPE_BOGUS| AML_HAS_ARGS, "PREFIX_ONLY!", ARG_NONE, ARG_NONE), }; -#define _UNK 0x6A -#define _UNKNOWN_OPCODE 0x02 /* An example unknown opcode */ - /* * This table is directly indexed by the opcodes, and returns an * index into the table above */ -u8 acpi_gbl_aml_op_info_index[256] = +u8 acpi_gbl_aml_short_op_info_index[256] = { /* 0 1 2 3 4 5 6 7 */ /* 0x00 */ 0x00, 0x01, _UNK, _UNK, _UNK, _UNK, 0x02, _UNK, /* 0x08 */ 0x03, _UNK, 0x04, 0x05, 0x06, 0x07, _UNK, _UNK, -/* 0x10 */ 0x08, 0x09, 0x0a, _UNK, 0x0b, _UNK, _UNK, 0x46, -/* 0x18 */ 0x47, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +/* 0x10 */ 0x08, 0x09, 0x0a, _UNK, 0x0b, _UNK, _UNK, _UNK, +/* 0x18 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, /* 0x20 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, -/* 0x28 */ 0x48, 0x49, _UNK, _UNK, _UNK, 0x63, _UNK, _UNK, -/* 0x30 */ 0x67, 0x66, 0x68, 0x65, 0x69, 0x64, 0x4a, 0x4b, -/* 0x38 */ 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, -/* 0x40 */ 0x54, _UNK, _UNK, _UNK, _UNK, _UNK, 0x55, 0x56, -/* 0x48 */ 0x57, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, -/* 0x50 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, -/* 0x58 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +/* 0x28 */ _UNK, _UNK, _UNK, _UNK, _UNK, 0x63, _PFX, _PFX, +/* 0x30 */ 0x67, 0x66, 0x68, 0x65, 0x69, 0x64, 0x6A, _UNK, +/* 0x38 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +/* 0x40 */ _UNK, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, +/* 0x48 */ _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, +/* 0x50 */ _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, +/* 0x58 */ _ASC, _ASC, _ASC, _UNK, _PFX, _UNK, _PFX, _ASC, /* 0x60 */ 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, /* 0x68 */ 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, _UNK, /* 0x70 */ 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, /* 0x78 */ 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, /* 0x80 */ 0x2b, 0x2c, 0x2d, 0x2e, _UNK, _UNK, 0x2f, 0x30, /* 0x88 */ 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, _UNK, -/* 0x90 */ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x58, 0x59, -/* 0x98 */ 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, _UNK, _UNK, +/* 0x90 */ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, _UNK, _UNK, +/* 0x98 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, /* 0xA0 */ 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x60, 0x61, /* 0xA8 */ 0x62, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, /* 0xB0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, @@ -552,3 +575,32 @@ /* 0xF0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, /* 0xF8 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, 0x45, }; + + +u8 acpi_gbl_aml_long_op_info_index[NUM_EXTENDED_OPCODE] = +{ +/* 0 1 2 3 4 5 6 7 */ +/* 0x00 */ _UNK, 0x46, 0x47, _UNK, _UNK, _UNK, _UNK, _UNK, +/* 0x08 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +/* 0x10 */ _UNK, _UNK, 0x48, 0x49, _UNK, _UNK, _UNK, _UNK, +/* 0x18 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +/* 0x20 */ 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, +/* 0x28 */ 0x52, 0x53, 0x54, _UNK, _UNK, _UNK, _UNK, _UNK, +/* 0x30 */ 0x55, 0x56, 0x57, _UNK, _UNK, _UNK, _UNK, _UNK, +/* 0x38 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +/* 0x40 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +/* 0x48 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +/* 0x50 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +/* 0x58 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +/* 0x60 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +/* 0x68 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +/* 0x70 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +/* 0x78 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +/* 0x80 */ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, +}; + + +/* 0 1 2 3 4 5 6 7 */ +/* 0x00 */ + + diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/parser/psparse.c linux/drivers/acpi/parser/psparse.c --- v2.4.0-test8/linux/drivers/acpi/parser/psparse.c Wed Jul 5 11:23:12 2000 +++ linux/drivers/acpi/parser/psparse.c Fri Sep 15 14:30:30 2000 @@ -1,6 +1,7 @@ /****************************************************************************** * * Module Name: psparse - Parser top level AML parse routines + * $Revision: 51 $ * *****************************************************************************/ @@ -33,14 +34,14 @@ */ #include "acpi.h" -#include "parser.h" -#include "dispatch.h" +#include "acparser.h" +#include "acdispat.h" #include "amlcode.h" -#include "namesp.h" -#include "debugger.h" +#include "acnamesp.h" +#include "acdebug.h" #define _COMPONENT PARSER - MODULE_NAME ("psparse"); + MODULE_NAME ("psparse") u32 acpi_gbl_depth = 0; @@ -65,11 +66,11 @@ ACPI_STATUS acpi_ps_delete_completed_op ( ACPI_WALK_STATE *state, - ACPI_GENERIC_OP *op) + ACPI_PARSE_OBJECT *op) { acpi_ps_free_op (op); - return AE_OK; + return (AE_OK); } @@ -78,7 +79,7 @@ * * FUNCTION: Acpi_ps_delete_parse_tree * - * PARAMETERS: Root - Root of tree (or subtree) to delete + * PARAMETERS: Subtree_root - Root of tree (or subtree) to delete * * RETURN: None * @@ -88,33 +89,54 @@ void acpi_ps_delete_parse_tree ( - ACPI_GENERIC_OP *root) + ACPI_PARSE_OBJECT *subtree_root) { - ACPI_GENERIC_OP *op; - ACPI_WALK_STATE walk_state; + ACPI_WALK_STATE *walk_state; + ACPI_WALK_LIST walk_list; - walk_state.origin = root; - op = root; + if (!subtree_root) { + return; + } - /* TBD: [Restructure] hack for root case */ + /* Create and initialize a new walk list */ - if (op == acpi_gbl_parsed_namespace_root) { - op = acpi_ps_get_child (op); + walk_list.walk_state = NULL; + walk_state = acpi_ds_create_walk_state (TABLE_ID_DSDT, NULL, NULL, &walk_list); + if (!walk_state) { + return; } - /* Save root until last, so that we know when the tree has been walked */ + walk_state->parser_state = NULL; + walk_state->parse_flags = 0; + walk_state->descending_callback = NULL; + walk_state->ascending_callback = NULL; + - walk_state.next_op = op; - walk_state.next_op_info = NEXT_OP_DOWNWARD; + walk_state->origin = subtree_root; + walk_state->next_op = subtree_root; - while (walk_state.next_op) { - acpi_ps_get_next_walk_op (&walk_state, walk_state.next_op, + + /* Head downward in the tree */ + + walk_state->next_op_info = NEXT_OP_DOWNWARD; + + /* Visit all nodes in the subtree */ + + while (walk_state->next_op) { + acpi_ps_get_next_walk_op (walk_state, walk_state->next_op, acpi_ps_delete_completed_op); } + + /* We are done with this walk */ + + acpi_ds_delete_walk_state (walk_state); + + return; } #endif + /******************************************************************************* * * FUNCTION: Acpi_ps_peek_opcode @@ -135,12 +157,12 @@ /* Extended (2-byte) opcode if > 255 */ if (opcode > 0x00FF) { - return 2; + return (2); } /* Otherwise, just a single byte opcode */ - return 1; + return (1); } @@ -194,7 +216,7 @@ /* don't convert bare name to a namepath */ - return opcode; + return (opcode); } @@ -214,7 +236,7 @@ ACPI_PARSE_STATE * acpi_ps_create_state ( u8 *aml, - s32 aml_size) + u32 aml_size) { ACPI_PARSE_STATE *parser_state; @@ -257,88 +279,270 @@ ACPI_STATUS acpi_ps_find_object ( u16 opcode, - ACPI_PARSE_STATE *parser_state, + ACPI_PARSE_OBJECT *op, ACPI_WALK_STATE *walk_state, - ACPI_GENERIC_OP **op) + ACPI_PARSE_OBJECT **out_op) { - char *path; + NATIVE_CHAR *path; + /* We are only interested in opcodes that have an associated name */ + + if (!acpi_ps_is_named_op (opcode)) { + *out_op = op; + return (AE_OK); + } + /* Find the name in the parse tree */ - path = acpi_ps_get_next_namestring (parser_state); + path = acpi_ps_get_next_namestring (walk_state->parser_state); - *op = acpi_ps_find (acpi_ps_get_parent_scope (parser_state), + *out_op = acpi_ps_find (acpi_ps_get_parent_scope (walk_state->parser_state), path, opcode, 1); - if (!(*op)) { - return AE_NOT_FOUND; + if (!(*out_op)) { + return (AE_NOT_FOUND); } - return AE_OK; + return (AE_OK); } + +#endif + + +/******************************************************************************* + * + * FUNCTION: Acpi_ps_complete_this_op + * + * PARAMETERS: Walk_state - Current State + * Op - Op to complete + * + * RETURN: TRUE if Op and subtree was deleted + * + * DESCRIPTION: Perform any cleanup at the completion of an Op. + * + ******************************************************************************/ + +u8 +acpi_ps_complete_this_op ( + ACPI_WALK_STATE *walk_state, + ACPI_PARSE_OBJECT *op) +{ +#ifndef PARSER_ONLY + ACPI_PARSE_OBJECT *prev; + ACPI_PARSE_OBJECT *next; + ACPI_OPCODE_INFO *op_info; + ACPI_OPCODE_INFO *parent_info; + u32 opcode_class; + ACPI_PARSE_OBJECT *replacement_op = NULL; + + + op_info = acpi_ps_get_opcode_info (op->opcode); + opcode_class = ACPI_GET_OP_CLASS (op_info); + + + /* Delete this op and the subtree below it if asked to */ + + if (((walk_state->parse_flags & ACPI_PARSE_TREE_MASK) == ACPI_PARSE_DELETE_TREE) && + (opcode_class != OPTYPE_CONSTANT) && + (opcode_class != OPTYPE_LITERAL) && + (opcode_class != OPTYPE_LOCAL_VARIABLE) && + (opcode_class != OPTYPE_METHOD_ARGUMENT) && + (opcode_class != OPTYPE_DATA_TERM) && + (op->opcode != AML_NAMEPATH_OP)) + { + /* Make sure that we only delete this subtree */ + + if (op->parent) { + /* + * Check if we need to replace the operator and its subtree + * with a return value op + */ + + parent_info = acpi_ps_get_opcode_info (op->parent->opcode); + + switch (ACPI_GET_OP_CLASS (parent_info)) + { + case OPTYPE_CONTROL: /* IF, ELSE, WHILE only */ + case OPTYPE_NAMED_OBJECT: /* Scope, method, etc. */ + break; + + default: + replacement_op = acpi_ps_alloc_op (AML_RETURN_VALUE_OP); + if (!replacement_op) { + return (FALSE); + } + } + + /* We must unlink this op from the parent tree */ + + prev = op->parent->value.arg; + if (prev == op) { + /* This op is the first in the list */ + + if (replacement_op) { + replacement_op->parent = op->parent; + replacement_op->value.arg = NULL; + op->parent->value.arg = replacement_op; + replacement_op->next = op->next; + } + else { + op->parent->value.arg = op->next; + } + } + + /* Search the parent list */ + + else while (prev) { + /* Traverse all siblings in the parent's argument list */ + + next = prev->next; + if (next == op) { + if (replacement_op) { + replacement_op->parent = op->parent; + replacement_op->value.arg = NULL; + prev->next = replacement_op; + replacement_op->next = op->next; + next = NULL; + } + else { + prev->next = op->next; + next = NULL; + } + } + + prev = next; + } + + } + + /* Now we can actually delete the subtree rooted at op */ + + acpi_ps_delete_parse_tree (op); + + return (TRUE); + } + + return (FALSE); + #else + return (FALSE); +#endif +} + + +/******************************************************************************* + * + * FUNCTION: Acpi_ps_next_parse_state + * + * PARAMETERS: Parser_state - Current parser state object + * + * RETURN: + * + * DESCRIPTION: + * + ******************************************************************************/ + ACPI_STATUS -acpi_ps_find_object ( - u16 opcode, - ACPI_PARSE_STATE *parser_state, +acpi_ps_next_parse_state ( ACPI_WALK_STATE *walk_state, - ACPI_GENERIC_OP **out_op) + ACPI_PARSE_OBJECT *op, + ACPI_STATUS callback_status) { - char *path; - ACPI_GENERIC_OP *op; - OBJECT_TYPE_INTERNAL data_type; - ACPI_STATUS status; - ACPI_NAMED_OBJECT *entry = NULL; + ACPI_PARSE_STATE *parser_state = walk_state->parser_state; + ACPI_STATUS status = AE_CTRL_PENDING; - /* - * The full parse tree has already been deleted -- therefore, we are parsing - * a control method. We can lookup the name in the namespace instead of - * the parse tree! - */ + switch (callback_status) + { + case AE_CTRL_TERMINATE: + /* + * A control method was terminated via a RETURN statement. + * The walk of this method is complete. + */ - path = acpi_ps_get_next_namestring (parser_state); + parser_state->aml = parser_state->aml_end; + status = AE_CTRL_TERMINATE; + break; - /* Map the raw opcode into an internal object type */ - data_type = acpi_ds_map_named_opcode_to_data_type (opcode); + case AE_CTRL_PENDING: - /* - * Enter the object into the namespace - * LOAD_PASS1 means Create if not found - */ + /* + * Predicate of a WHILE was true and the loop just completed an + * execution. Go back to the start of the loop and reevaluate the + * predicate. + */ +/* Walk_state->Control_state->Common.State = + CONTROL_PREDICATE_EXECUTING;*/ - status = acpi_ns_lookup (walk_state->scope_info, path, data_type, - IMODE_LOAD_PASS1, - NS_NO_UPSEARCH, walk_state, &entry); - if (ACPI_FAILURE (status)) { - return (status); - } + /* TBD: How to handle a break within a while. */ + /* This code attempts it */ - /* Create a new op */ + parser_state->aml = walk_state->aml_last_while; + break; - op = acpi_ps_alloc_op (opcode); - if (!op) { - return (AE_NO_MEMORY); - } - /* Initialize */ + case AE_CTRL_TRUE: + /* + * Predicate of an IF was true, and we are at the matching ELSE. + * Just close out this package + * + * Parser_state->Aml is modified by the package length procedure + */ + parser_state->aml = (parser_state->aml + + acpi_ps_get_next_package_length (parser_state)) -1; + break; + - ((ACPI_NAMED_OP *)op)->name = entry->name; - op->acpi_named_object = entry; + case AE_CTRL_FALSE: + /* + * Either an IF/WHILE Predicate was false or we encountered a BREAK + * opcode. In both cases, we do not execute the rest of the + * package; We simply close out the parent (finishing the walk of + * this branch of the tree) and continue execution at the parent + * level. + */ - acpi_ps_append_arg (acpi_ps_get_parent_scope (parser_state), op); + parser_state->aml = parser_state->scope->parse_scope.pkg_end; - *out_op = op; + /* In the case of a BREAK, just force a predicate (if any) to FALSE */ + walk_state->control_state->common.value = FALSE; + status = AE_CTRL_END; + break; - return (AE_OK); + + case AE_CTRL_TRANSFER: + + /* + * A method call (invocation) -- transfer control + */ + status = AE_CTRL_TRANSFER; + walk_state->prev_op = op; + walk_state->method_call_op = op; + walk_state->method_call_node = (op->value.arg)->node; + + /* Will return value (if any) be used by the caller? */ + + walk_state->return_used = acpi_ds_is_result_used (op); + break; + + + default: + status = callback_status; + if ((callback_status & AE_CODE_MASK) == AE_CODE_CONTROL) { + status = AE_OK; + } + break; + } + + + return (status); } -#endif /******************************************************************************* @@ -356,26 +560,27 @@ ACPI_STATUS acpi_ps_parse_loop ( - ACPI_PARSE_STATE *parser_state, - ACPI_WALK_STATE *walk_state, - u32 parse_flags) + ACPI_WALK_STATE *walk_state) { ACPI_STATUS status = AE_OK; - ACPI_GENERIC_OP *op = NULL; /* current op */ - ACPI_OP_INFO *op_info; - ACPI_GENERIC_OP *arg = NULL; - ACPI_DEFERRED_OP *deferred_op; + ACPI_PARSE_OBJECT *op = NULL; /* current op */ + ACPI_OPCODE_INFO *op_info; + ACPI_PARSE_OBJECT *arg = NULL; + ACPI_PARSE2_OBJECT *deferred_op; u32 arg_count; /* push for fixed or var args */ u32 arg_types = 0; ACPI_PTRDIFF aml_offset; u16 opcode; - ACPI_GENERIC_OP pre_op; + ACPI_PARSE_OBJECT pre_op; + ACPI_PARSE_STATE *parser_state; -#ifndef PARSER_ONLY - OBJECT_TYPE_INTERNAL data_type; -#endif + parser_state = walk_state->parser_state; + if (walk_state->prev_op) { + op = walk_state->prev_op; + arg_types = walk_state->prev_arg_types; + } /* * Iterative parsing loop, while there is more aml to process: @@ -384,9 +589,8 @@ if (!op) { /* Get the next opcode from the AML stream */ - aml_offset = parser_state->aml - parser_state->aml_start; - opcode = acpi_ps_peek_opcode (parser_state); - op_info = acpi_ps_get_opcode_info (opcode); + aml_offset = parser_state->aml - parser_state->aml_start; + opcode = acpi_ps_peek_opcode (parser_state); /* * First cut to determine what we have found: @@ -395,16 +599,19 @@ * 3) An unknown/invalid opcode */ - if (op_info) { + op_info = acpi_ps_get_opcode_info (opcode); + switch (ACPI_GET_OP_TYPE (op_info)) + { + case ACPI_OP_TYPE_OPCODE: + /* Found opcode info, this is a normal opcode */ parser_state->aml += acpi_ps_get_opcode_size (opcode); arg_types = op_info->parse_args; - } + break; - else if (acpi_ps_is_prefix_char (opcode) || - acpi_ps_is_leading_char (opcode)) - { + case ACPI_OP_TYPE_ASCII: + case ACPI_OP_TYPE_PREFIX: /* * Starts with a valid prefix or ASCII char, this is a name * string. Convert the bare name string to a namepath. @@ -412,9 +619,10 @@ opcode = AML_NAMEPATH_OP; arg_types = ARGP_NAMESTRING; - } + break; + + case ACPI_OP_TYPE_UNKNOWN: - else { /* The opcode is unrecognized. Just skip unknown opcodes */ parser_state->aml += acpi_ps_get_opcode_size (opcode); @@ -441,9 +649,24 @@ INCREMENT_ARG_LIST (arg_types); - status = acpi_ps_find_object (opcode, parser_state, walk_state, &op); - if (ACPI_FAILURE (status)) { - return (AE_NOT_FOUND); + if (walk_state->descending_callback != NULL) { + /* + * Find the object. This will either insert the object into + * the namespace or simply look it up + */ + status = walk_state->descending_callback (opcode, NULL, walk_state, &op); + if (op == NULL) { + continue; + } + status = acpi_ps_next_parse_state (walk_state, op, status); + if (status == AE_CTRL_PENDING) { + status = AE_OK; + goto close_this_op; + } + + if (ACPI_FAILURE (status)) { + goto close_this_op; + } } acpi_ps_append_arg (op, pre_op.value.arg); @@ -451,7 +674,7 @@ if (op->opcode == AML_REGION_OP) { - deferred_op = acpi_ps_to_deferred_op (op); + deferred_op = acpi_ps_to_extended_op (op); if (deferred_op) { /* * Skip parsing of control method or opregion body, @@ -464,13 +687,15 @@ * Body_length is unknown until we parse the body */ - deferred_op->body = parser_state->aml - 6; - deferred_op->body_length = 0; + deferred_op->data = parser_state->aml - 6; + deferred_op->length = 0; } } } else { + + /* Not a named opcode, just allocate Op and append to parent */ op = acpi_ps_alloc_op (opcode); @@ -479,6 +704,23 @@ } acpi_ps_append_arg (acpi_ps_get_parent_scope (parser_state), op); + + if ((walk_state->descending_callback != NULL)) { + /* + * Find the object. This will either insert the object into + * the namespace or simply look it up + */ + status = walk_state->descending_callback (opcode, op, walk_state, &op); + status = acpi_ps_next_parse_state (walk_state, op, status); + if (status == AE_CTRL_PENDING) { + status = AE_OK; + goto close_this_op; + } + + if (ACPI_FAILURE (status)) { + goto close_this_op; + } + } } op->aml_offset = aml_offset; @@ -532,7 +774,7 @@ /* For a method, save the length and address of the body */ if (op->opcode == AML_METHOD_OP) { - deferred_op = acpi_ps_to_deferred_op (op); + deferred_op = acpi_ps_to_extended_op (op); if (deferred_op) { /* * Skip parsing of control method or opregion body, @@ -540,8 +782,8 @@ * to parse them correctly. */ - deferred_op->body = parser_state->aml; - deferred_op->body_length = parser_state->pkg_end - + deferred_op->data = parser_state->aml; + deferred_op->length = parser_state->pkg_end - parser_state->aml; /* @@ -549,8 +791,8 @@ * parsing because the opregion is not a standalone * package (We don't know where the end is). */ - parser_state->aml = parser_state->pkg_end; - arg_count = 0; + parser_state->aml = parser_state->pkg_end; + arg_count = 0; } } @@ -567,7 +809,7 @@ } if (op->opcode == AML_REGION_OP) { - deferred_op = acpi_ps_to_deferred_op (op); + deferred_op = acpi_ps_to_extended_op (op); if (deferred_op) { /* * Skip parsing of control method or opregion body, @@ -578,46 +820,75 @@ * know the length. */ - deferred_op->body_length = parser_state->aml - - deferred_op->body; + deferred_op->length = parser_state->aml - + deferred_op->data; } } + } -#ifndef PARSER_ONLY - data_type = acpi_ds_map_named_opcode_to_data_type (op->opcode); + /* This op complete, notify the dispatcher */ - if (op->opcode == AML_NAME_OP) { - if (op->value.arg) { - data_type = acpi_ds_map_opcode_to_data_type ( - (op->value.arg)->opcode, NULL); - ((ACPI_NAMED_OBJECT*)op->acpi_named_object)->type = - (u8) data_type; - } + if (walk_state->ascending_callback != NULL) { + status = walk_state->ascending_callback (walk_state, op); + status = acpi_ps_next_parse_state (walk_state, op, status); + if (status == AE_CTRL_PENDING) { + status = AE_OK; + goto close_this_op; } + } - /* Pop the scope stack */ - if (acpi_ns_opens_scope (data_type)) { +close_this_op: - acpi_ds_scope_stack_pop (walk_state); - } -#endif + parser_state->scope->parse_scope.arg_count--; + + /* Close this Op (may result in parse subtree deletion) */ + + if (acpi_ps_complete_this_op (walk_state, op)) { + op = NULL; + } + + + if (status == AE_CTRL_END) { + acpi_ps_pop_scope (parser_state, &op, &arg_types); + status = walk_state->ascending_callback (walk_state, op); + status = acpi_ps_next_parse_state (walk_state, op, status); + acpi_ps_complete_this_op (walk_state, op); + op = NULL; + status = AE_OK; } + else if (ACPI_FAILURE (status)) { + if (op == NULL) { + acpi_ps_pop_scope (parser_state, &op, &arg_types); + } + walk_state->prev_op = op; + walk_state->prev_arg_types = arg_types; - parser_state->scope->arg_count--; + /* + * TEMP: + */ + if (status == AE_CTRL_TERMINATE) { + status = AE_OK; - /* Delete op if asked to */ + /* Clean up */ + do + { + if (op) { + acpi_ps_complete_this_op (walk_state, op); + } -#ifndef PARSER_ONLY - if (parse_flags & PARSE_DELETE_TREE) { - acpi_ps_delete_parse_tree (op); + acpi_ps_pop_scope (parser_state, &op, &arg_types); + } while (op); + } + return (status); } -#endif + /* This scope complete? */ + if (acpi_ps_has_completed_scope (parser_state)) { acpi_ps_pop_scope (parser_state, &op, &arg_types); } @@ -625,6 +896,7 @@ else { op = NULL; } + } else { @@ -637,6 +909,54 @@ } /* while Parser_state->Aml */ + /* + * Complete the last Op (if not completed), and clear the scope stack. + * It is easily possible to end an AML "package" with an unbounded number + * of open scopes (such as when several AML blocks are closed with + * sequential closing braces). We want to terminate each one cleanly. + */ + + do + { + if (op) { + if (walk_state->ascending_callback != NULL) { + status = walk_state->ascending_callback (walk_state, op); + status = acpi_ps_next_parse_state (walk_state, op, status); + if (status == AE_CTRL_PENDING) { + status = AE_OK; + goto close_this_op; + } + + if (status == AE_CTRL_TERMINATE) { + status = AE_OK; + + /* Clean up */ + do + { + if (op) { + acpi_ps_complete_this_op (walk_state, op); + } + + acpi_ps_pop_scope (parser_state, &op, &arg_types); + + } while (op); + + return (status); + } + + else if (ACPI_FAILURE (status)) { + acpi_ps_complete_this_op (walk_state, op); + return (status); + } + } + + acpi_ps_complete_this_op (walk_state, op); + } + + acpi_ps_pop_scope (parser_state, &op, &arg_types); + + } while (op); + return (status); } @@ -658,19 +978,28 @@ ACPI_STATUS acpi_ps_parse_aml ( - ACPI_GENERIC_OP *start_scope, + ACPI_PARSE_OBJECT *start_scope, u8 *aml, u32 aml_size, - u32 parse_flags) + u32 parse_flags, + ACPI_NAMESPACE_NODE *method_node, + ACPI_OPERAND_OBJECT **params, + ACPI_OPERAND_OBJECT **caller_return_desc, + ACPI_PARSE_DOWNWARDS descending_callback, + ACPI_PARSE_UPWARDS ascending_callback) { ACPI_STATUS status; ACPI_PARSE_STATE *parser_state; ACPI_WALK_STATE *walk_state; ACPI_WALK_LIST walk_list; - ACPI_NAMED_OBJECT *entry = NULL; + ACPI_NAMESPACE_NODE *node = NULL; + ACPI_WALK_LIST *prev_walk_list = acpi_gbl_current_walk_list; + ACPI_OPERAND_OBJECT *return_desc; + ACPI_OPERAND_OBJECT *mth_desc = NULL; + ACPI_NAMESPACE_NODE *start_node; - /* Initialize parser state and scope */ + /* Create and initialize a new parser state */ parser_state = acpi_ps_create_state (aml, aml_size); if (!parser_state) { @@ -679,36 +1008,166 @@ acpi_ps_init_scope (parser_state, start_scope); + if (method_node) { + mth_desc = acpi_ns_get_attached_object (method_node); + } - /* Initialize a new walk list */ + /* Create and initialize a new walk list */ walk_list.walk_state = NULL; - walk_state = acpi_ds_create_walk_state (TABLE_ID_DSDT, NULL, NULL, &walk_list); + walk_state = acpi_ds_create_walk_state (TABLE_ID_DSDT, parser_state->start_op, mth_desc, &walk_list); if (!walk_state) { status = AE_NO_MEMORY; goto cleanup; } + walk_state->method_node = method_node; + walk_state->parser_state = parser_state; + walk_state->parse_flags = parse_flags; + walk_state->descending_callback = descending_callback; + walk_state->ascending_callback = ascending_callback; + + /* TBD: [Restructure] TEMP until we pass Walk_state to the interpreter + */ + acpi_gbl_current_walk_list = &walk_list; + - /* Setup the current scope */ + if (method_node) { + start_node = method_node; + parser_state->start_node = method_node; + walk_state->walk_type = WALK_METHOD; - entry = parser_state->start_op->acpi_named_object; - if (entry) { - /* Push start scope on scope stack and make it current */ + if (start_node) { + /* Push start scope on scope stack and make it current */ + + status = acpi_ds_scope_stack_push (start_node, ACPI_TYPE_METHOD, walk_state); + if (ACPI_FAILURE (status)) { + return (status); + } - status = acpi_ds_scope_stack_push (entry->child_table, entry->type, - walk_state); - if (ACPI_FAILURE (status)) { - goto cleanup; } + /* Init arguments if this is a control method */ + /* TBD: [Restructure] add walkstate as a param */ + acpi_ds_method_data_init_args (params, MTH_NUM_ARGS, walk_state); } + else { + /* Setup the current scope */ - /* Create the parse tree */ + node = parser_state->start_op->node; + if (node) { + /* Push start scope on scope stack and make it current */ + + status = acpi_ds_scope_stack_push (node, node->type, + walk_state); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + + } + } - status = acpi_ps_parse_loop (parser_state, walk_state, parse_flags); + + status = AE_OK; + + /* + * Execute the walk loop as long as there is a valid Walk State. This + * handles nested control method invocations without recursion. + */ + + while (walk_state) { + if (ACPI_SUCCESS (status)) { + status = acpi_ps_parse_loop (walk_state); + } + + if (status == AE_CTRL_TRANSFER) { + /* + * A method call was detected. + * Transfer control to the called control method + */ + + status = acpi_ds_call_control_method (&walk_list, walk_state, NULL); + + /* + * If the transfer to the new method method call worked, a new walk + * state was created -- get it + */ + + walk_state = acpi_ds_get_current_walk_state (&walk_list); + continue; + } + + else if (status == AE_CTRL_TERMINATE) { + status = AE_OK; + } + + /* We are done with this walk, move on to the parent if any */ + + + walk_state = acpi_ds_pop_walk_state (&walk_list); + + /* Extract return value before we delete Walk_state */ + + return_desc = walk_state->return_desc; + + /* Reset the current scope to the beginning of scope stack */ + + acpi_ds_scope_stack_clear (walk_state); + + /* + * If we just returned from the execution of a control method, + * there's lots of cleanup to do + */ + + if ((walk_state->parse_flags & ACPI_PARSE_MODE_MASK) == ACPI_PARSE_EXECUTE) { + acpi_ds_terminate_control_method (walk_state); + } + + /* Delete this walk state and all linked control states */ + + acpi_ps_cleanup_scope (walk_state->parser_state); + acpi_cm_free (walk_state->parser_state); + acpi_ds_delete_walk_state (walk_state); + + /* Check if we have restarted a preempted walk */ + + walk_state = acpi_ds_get_current_walk_state (&walk_list); + if (walk_state && + ACPI_SUCCESS (status)) + { + /* There is another walk state, restart it */ + + /* + * If the method returned value is not used by the parent, + * The object is deleted + */ + + acpi_ds_restart_control_method (walk_state, return_desc); + } + + /* + * Just completed a 1st-level method, save the final internal return + * value (if any) + */ + + else if (caller_return_desc) { + *caller_return_desc = return_desc; /* NULL if no return value */ + } + + else if (return_desc) { + /* Caller doesn't want it, must delete it */ + + acpi_cm_remove_reference (return_desc); + } + } + + + /* Normal exit */ + + acpi_gbl_current_walk_list = prev_walk_list; + return (status); cleanup: @@ -719,6 +1178,7 @@ acpi_ps_cleanup_scope (parser_state); acpi_cm_free (parser_state); + acpi_gbl_current_walk_list = prev_walk_list; return (status); } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/parser/psscope.c linux/drivers/acpi/parser/psscope.c --- v2.4.0-test8/linux/drivers/acpi/parser/psscope.c Wed Jul 5 11:23:13 2000 +++ linux/drivers/acpi/parser/psscope.c Fri Sep 15 14:30:30 2000 @@ -1,6 +1,7 @@ /****************************************************************************** * * Module Name: psscope - Parser scope stack management routines + * $Revision: 18 $ * *****************************************************************************/ @@ -24,10 +25,10 @@ #include "acpi.h" -#include "parser.h" +#include "acparser.h" #define _COMPONENT PARSER - MODULE_NAME ("psscope"); + MODULE_NAME ("psscope") /******************************************************************************* @@ -42,11 +43,11 @@ * ******************************************************************************/ -ACPI_GENERIC_OP * +ACPI_PARSE_OBJECT * acpi_ps_get_parent_scope ( ACPI_PARSE_STATE *parser_state) { - return parser_state->scope->op; + return (parser_state->scope->parse_scope.op); } @@ -68,8 +69,8 @@ acpi_ps_has_completed_scope ( ACPI_PARSE_STATE *parser_state) { - return (u8) ((parser_state->aml >= parser_state->scope->arg_end || - !parser_state->scope->arg_count)); + return ((u8) ((parser_state->aml >= parser_state->scope->parse_scope.arg_end || + !parser_state->scope->parse_scope.arg_count))); } @@ -78,7 +79,7 @@ * FUNCTION: Acpi_ps_init_scope * * PARAMETERS: Parser_state - Current parser state object - * Root - the root object of this new scope + * Root - the Root Node of this new scope * * RETURN: Status * @@ -89,24 +90,25 @@ ACPI_STATUS acpi_ps_init_scope ( ACPI_PARSE_STATE *parser_state, - ACPI_GENERIC_OP *root) + ACPI_PARSE_OBJECT *root_op) { - ACPI_PARSE_SCOPE *scope; + ACPI_GENERIC_STATE *scope; - scope = acpi_cm_callocate (sizeof (ACPI_PARSE_SCOPE)); + scope = acpi_cm_create_generic_state (); if (!scope) { - return AE_NO_MEMORY; + return (AE_NO_MEMORY); } - scope->op = root; - scope->arg_count = ACPI_VAR_ARGS; - scope->arg_end = parser_state->aml_end; - scope->pkg_end = parser_state->aml_end; - parser_state->scope = scope; - parser_state->start_op = root; + scope->parse_scope.op = root_op; + scope->parse_scope.arg_count = ACPI_VAR_ARGS; + scope->parse_scope.arg_end = parser_state->aml_end; + scope->parse_scope.pkg_end = parser_state->aml_end; - return AE_OK; + parser_state->scope = scope; + parser_state->start_op = root_op; + + return (AE_OK); } @@ -128,49 +130,39 @@ ACPI_STATUS acpi_ps_push_scope ( ACPI_PARSE_STATE *parser_state, - ACPI_GENERIC_OP *op, + ACPI_PARSE_OBJECT *op, u32 remaining_args, u32 arg_count) { - ACPI_PARSE_SCOPE *scope = parser_state->scope_avail; - + ACPI_GENERIC_STATE *scope; - if (scope) { - /* grabbed scope from available list */ - parser_state->scope_avail = scope->parent; + scope = acpi_cm_create_generic_state (); + if (!scope) { + return (AE_NO_MEMORY); } - else { - /* allocate scope from the heap */ - scope = (ACPI_PARSE_SCOPE*) acpi_cm_allocate (sizeof (ACPI_PARSE_SCOPE)); - if (!scope) { - return (AE_NO_MEMORY); - } - } + scope->parse_scope.op = op; + scope->parse_scope.arg_list = remaining_args; + scope->parse_scope.arg_count = arg_count; + scope->parse_scope.pkg_end = parser_state->pkg_end; - /* Always zero out the scope before init */ + /* Push onto scope stack */ - MEMSET (scope, 0, sizeof (*scope)); + acpi_cm_push_generic_state (&parser_state->scope, scope); - scope->op = op; - scope->arg_list = remaining_args; - scope->arg_count = arg_count; - scope->pkg_end = parser_state->pkg_end; - scope->parent = parser_state->scope; - parser_state->scope = scope; if (arg_count == ACPI_VAR_ARGS) { /* multiple arguments */ - scope->arg_end = parser_state->pkg_end; + scope->parse_scope.arg_end = parser_state->pkg_end; } else { /* single argument */ - scope->arg_end = ACPI_MAX_AML; + scope->parse_scope.arg_end = ACPI_MAX_AML; } return (AE_OK); @@ -195,24 +187,28 @@ void acpi_ps_pop_scope ( ACPI_PARSE_STATE *parser_state, - ACPI_GENERIC_OP **op, + ACPI_PARSE_OBJECT **op, u32 *arg_list) { - ACPI_PARSE_SCOPE *scope = parser_state->scope; + ACPI_GENERIC_STATE *scope = parser_state->scope; + + + /* + * Only pop the scope if there is in fact a next scope + */ + if (scope->common.next) { + scope = acpi_cm_pop_generic_state (&parser_state->scope); - if (scope->parent) { /* return to parsing previous op */ - *op = scope->op; - *arg_list = scope->arg_list; - parser_state->pkg_end = scope->pkg_end; - parser_state->scope = scope->parent; + *op = scope->parse_scope.op; + *arg_list = scope->parse_scope.arg_list; + parser_state->pkg_end = scope->parse_scope.pkg_end; - /* add scope to available list */ + /* All done with this scope state structure */ - scope->parent = parser_state->scope_avail; - parser_state->scope_avail = scope; + acpi_cm_delete_generic_state (scope); } else { @@ -222,6 +218,7 @@ *arg_list = 0; } + return; } @@ -243,27 +240,19 @@ acpi_ps_cleanup_scope ( ACPI_PARSE_STATE *parser_state) { - ACPI_PARSE_SCOPE *scope; + ACPI_GENERIC_STATE *scope; if (!parser_state) { return; } - /* destroy available list */ - - while (parser_state->scope_avail) { - scope = parser_state->scope_avail; - parser_state->scope_avail = scope->parent; - acpi_cm_free (scope); - } - /* destroy scope stack */ + /* Delete anything on the scope stack */ while (parser_state->scope) { - scope = parser_state->scope; - parser_state->scope = scope->parent; - acpi_cm_free (scope); + scope = acpi_cm_pop_generic_state (&parser_state->scope); + acpi_cm_delete_generic_state (scope); } return; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/parser/pstree.c linux/drivers/acpi/parser/pstree.c --- v2.4.0-test8/linux/drivers/acpi/parser/pstree.c Wed Jul 5 11:23:13 2000 +++ linux/drivers/acpi/parser/pstree.c Fri Sep 15 14:30:30 2000 @@ -1,6 +1,7 @@ /****************************************************************************** * * Module Name: pstree - Parser op tree manipulation/traversal/search + * $Revision: 23 $ * *****************************************************************************/ @@ -24,11 +25,11 @@ #include "acpi.h" -#include "parser.h" +#include "acparser.h" #include "amlcode.h" #define _COMPONENT PARSER - MODULE_NAME ("pstree"); + MODULE_NAME ("pstree") /******************************************************************************* @@ -44,30 +45,30 @@ * ******************************************************************************/ -ACPI_GENERIC_OP * +ACPI_PARSE_OBJECT * acpi_ps_get_arg ( - ACPI_GENERIC_OP *op, + ACPI_PARSE_OBJECT *op, u32 argn) { - ACPI_GENERIC_OP *arg = NULL; - ACPI_OP_INFO *op_info; + ACPI_PARSE_OBJECT *arg = NULL; + ACPI_OPCODE_INFO *op_info; /* Get the info structure for this opcode */ op_info = acpi_ps_get_opcode_info (op->opcode); - if (!op_info) { - /* Invalid opcode */ + if (ACPI_GET_OP_TYPE (op_info) != ACPI_OP_TYPE_OPCODE) { + /* Invalid opcode or ASCII character */ - return NULL; + return (NULL); } /* Check if this opcode requires argument sub-objects */ - if (!(op_info->flags & OP_INFO_HAS_ARGS)) { + if (!(ACPI_GET_OP_ARGS (op_info))) { /* Has no linked argument objects */ - return NULL; + return (NULL); } /* Get the requested argument object */ @@ -78,7 +79,7 @@ arg = arg->next; } - return arg; + return (arg); } @@ -97,11 +98,11 @@ void acpi_ps_append_arg ( - ACPI_GENERIC_OP *op, - ACPI_GENERIC_OP *arg) + ACPI_PARSE_OBJECT *op, + ACPI_PARSE_OBJECT *arg) { - ACPI_GENERIC_OP *prev_arg; - ACPI_OP_INFO *op_info; + ACPI_PARSE_OBJECT *prev_arg; + ACPI_OPCODE_INFO *op_info; if (!op) { @@ -111,7 +112,7 @@ /* Get the info structure for this opcode */ op_info = acpi_ps_get_opcode_info (op->opcode); - if (!op_info) { + if (ACPI_GET_OP_TYPE (op_info) != ACPI_OP_TYPE_OPCODE) { /* Invalid opcode */ return; @@ -119,7 +120,7 @@ /* Check if this opcode requires argument sub-objects */ - if (!(op_info->flags & OP_INFO_HAS_ARGS)) { + if (!(ACPI_GET_OP_ARGS (op_info))) { /* Has no linked argument objects */ return; @@ -166,11 +167,11 @@ * ******************************************************************************/ -ACPI_GENERIC_OP * +ACPI_PARSE_OBJECT * acpi_ps_get_child ( - ACPI_GENERIC_OP *op) + ACPI_PARSE_OBJECT *op) { - ACPI_GENERIC_OP *child = NULL; + ACPI_PARSE_OBJECT *child = NULL; switch (op->opcode) @@ -211,7 +212,7 @@ } - return child; + return (child); } @@ -229,32 +230,32 @@ * ******************************************************************************/ -ACPI_GENERIC_OP * +ACPI_PARSE_OBJECT * acpi_ps_get_depth_next ( - ACPI_GENERIC_OP *origin, - ACPI_GENERIC_OP *op) + ACPI_PARSE_OBJECT *origin, + ACPI_PARSE_OBJECT *op) { - ACPI_GENERIC_OP *next = NULL; - ACPI_GENERIC_OP *parent; - ACPI_GENERIC_OP *arg; + ACPI_PARSE_OBJECT *next = NULL; + ACPI_PARSE_OBJECT *parent; + ACPI_PARSE_OBJECT *arg; if (!op) { - return NULL; + return (NULL); } /* look for an argument or child */ next = acpi_ps_get_arg (op, 0); if (next) { - return next; + return (next); } /* look for a sibling */ next = op->next; if (next) { - return next; + return (next); } /* look for a sibling of parent */ @@ -270,19 +271,19 @@ if (arg == origin) { /* reached parent of origin, end search */ - return NULL; + return (NULL); } if (parent->next) { /* found sibling of parent */ - return parent->next; + return (parent->next); } op = parent; parent = parent->parent; } - return next; + return (next); } @@ -300,10 +301,10 @@ * ******************************************************************************/ -ACPI_GENERIC_OP * +ACPI_PARSE_OBJECT * acpi_ps_fetch_prefix ( - ACPI_GENERIC_OP *scope, - char **path, + ACPI_PARSE_OBJECT *scope, + NATIVE_CHAR **path, u32 io) { u32 prefix = io ? GET8 (*path):**path; @@ -338,7 +339,7 @@ scope = acpi_ps_get_child (scope); } - return scope; + return (scope); } @@ -349,7 +350,7 @@ * PARAMETERS: Path - A string containing the name segment * io - Direction flag * - * RETURN: The 4-char ASCII ACPI Name as a u32 + * RETURN: The 4-s8 ASCII ACPI Name as a u32 * * DESCRIPTION: Fetch ACPI name segment (dot-delimited) * @@ -357,13 +358,13 @@ u32 acpi_ps_fetch_name ( - char **path, + NATIVE_CHAR **path, u32 io) { u32 name = 0; - char *nm; + NATIVE_CHAR *nm; u32 i; - char ch; + NATIVE_CHAR ch; if (io) { @@ -378,7 +379,7 @@ *path += 1; } - nm = (char*) &name; + nm = (NATIVE_CHAR *) &name; for (i = 0; i < 4; i++) { ch = **path; if (ch && ch != '.') { @@ -393,7 +394,7 @@ } } - return name; + return (name); } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/parser/psutils.c linux/drivers/acpi/parser/psutils.c --- v2.4.0-test8/linux/drivers/acpi/parser/psutils.c Wed Jul 5 11:23:13 2000 +++ linux/drivers/acpi/parser/psutils.c Fri Sep 15 14:30:30 2000 @@ -1,6 +1,7 @@ /****************************************************************************** * * Module Name: psutils - Parser miscellaneous utilities (Parser only) + * $Revision: 29 $ * *****************************************************************************/ @@ -24,17 +25,18 @@ #include "acpi.h" -#include "parser.h" +#include "acparser.h" #include "amlcode.h" #define _COMPONENT PARSER - MODULE_NAME ("psutils"); + MODULE_NAME ("psutils") -#define PARSEOP_GENERIC 1 -#define PARSEOP_NAMED 2 -#define PARSEOP_DEFERRED 3 -#define PARSEOP_BYTELIST 4 +#define PARSEOP_GENERIC 0x01 +#define PARSEOP_NAMED 0x02 +#define PARSEOP_DEFERRED 0x03 +#define PARSEOP_BYTELIST 0x04 +#define PARSEOP_IN_CACHE 0x80 /******************************************************************************* @@ -53,21 +55,19 @@ void acpi_ps_init_op ( - ACPI_GENERIC_OP *op, + ACPI_PARSE_OBJECT *op, u16 opcode) { - ACPI_OP_INFO *aml_op; + ACPI_OPCODE_INFO *aml_op; op->data_type = ACPI_DESC_TYPE_PARSER; op->opcode = opcode; - aml_op = acpi_ps_get_opcode_info (opcode); - if (aml_op) { - DEBUG_ONLY_MEMBERS (STRNCPY (op->op_name, aml_op->name, - sizeof (op->op_name))); - } + + DEBUG_ONLY_MEMBERS (STRNCPY (op->op_name, aml_op->name, + sizeof (op->op_name))); } @@ -85,11 +85,11 @@ * ******************************************************************************/ -ACPI_GENERIC_OP* +ACPI_PARSE_OBJECT* acpi_ps_alloc_op ( u16 opcode) { - ACPI_GENERIC_OP *op = NULL; + ACPI_PARSE_OBJECT *op = NULL; u32 size; u8 flags; @@ -97,24 +97,27 @@ /* Allocate the minimum required size object */ if (acpi_ps_is_deferred_op (opcode)) { - size = sizeof (ACPI_DEFERRED_OP); + size = sizeof (ACPI_PARSE2_OBJECT); flags = PARSEOP_DEFERRED; } else if (acpi_ps_is_named_op (opcode)) { - size = sizeof (ACPI_NAMED_OP); + size = sizeof (ACPI_PARSE2_OBJECT); flags = PARSEOP_NAMED; } else if (acpi_ps_is_bytelist_op (opcode)) { - size = sizeof (ACPI_BYTELIST_OP); + size = sizeof (ACPI_PARSE2_OBJECT); flags = PARSEOP_BYTELIST; } else { - size = sizeof (ACPI_GENERIC_OP); + size = sizeof (ACPI_PARSE_OBJECT); flags = PARSEOP_GENERIC; + } + + if (size == sizeof (ACPI_PARSE_OBJECT)) { /* * The generic op is by far the most common (16 to 1), and therefore * the op cache is implemented with this type. @@ -133,13 +136,44 @@ op = acpi_gbl_parse_cache; acpi_gbl_parse_cache = op->next; + + /* Clear the previously used Op */ + + MEMSET (op, 0, sizeof (ACPI_PARSE_OBJECT)); + + } + acpi_cm_release_mutex (ACPI_MTX_CACHES); + } + + else { + /* + * The generic op is by far the most common (16 to 1), and therefore + * the op cache is implemented with this type. + * + * Check if there is an Op already available in the cache + */ + + acpi_cm_acquire_mutex (ACPI_MTX_CACHES); + acpi_gbl_ext_parse_cache_requests++; + if (acpi_gbl_ext_parse_cache) { + /* Extract an op from the front of the cache list */ + + acpi_gbl_ext_parse_cache_depth--; + acpi_gbl_ext_parse_cache_hits++; + + op = (ACPI_PARSE_OBJECT *) acpi_gbl_ext_parse_cache; + acpi_gbl_ext_parse_cache = (ACPI_PARSE2_OBJECT *) op->next; + + /* Clear the previously used Op */ - MEMSET (op, 0, sizeof (ACPI_GENERIC_OP)); + MEMSET (op, 0, sizeof (ACPI_PARSE2_OBJECT)); + } acpi_cm_release_mutex (ACPI_MTX_CACHES); } + /* Allocate a new Op if necessary */ if (!op) { @@ -152,7 +186,7 @@ op->flags = flags; } - return op; + return (op); } @@ -171,16 +205,22 @@ void acpi_ps_free_op ( - ACPI_GENERIC_OP *op) + ACPI_PARSE_OBJECT *op) { + if (op->flags == PARSEOP_GENERIC) { /* Is the cache full? */ if (acpi_gbl_parse_cache_depth < MAX_PARSE_CACHE_DEPTH) { /* Put a GENERIC_OP back into the cache */ + /* Clear the previously used Op */ + + MEMSET (op, 0, sizeof (ACPI_PARSE_OBJECT)); + op->flags = PARSEOP_IN_CACHE; + acpi_cm_acquire_mutex (ACPI_MTX_CACHES); acpi_gbl_parse_cache_depth++; @@ -192,6 +232,29 @@ } } + else { + /* Is the cache full? */ + + if (acpi_gbl_ext_parse_cache_depth < MAX_EXTPARSE_CACHE_DEPTH) { + /* Put a GENERIC_OP back into the cache */ + + /* Clear the previously used Op */ + + MEMSET (op, 0, sizeof (ACPI_PARSE2_OBJECT)); + op->flags = PARSEOP_IN_CACHE; + + acpi_cm_acquire_mutex (ACPI_MTX_CACHES); + acpi_gbl_ext_parse_cache_depth++; + + op->next = (ACPI_PARSE_OBJECT *) acpi_gbl_ext_parse_cache; + acpi_gbl_ext_parse_cache = (ACPI_PARSE2_OBJECT *) op; + + acpi_cm_release_mutex (ACPI_MTX_CACHES); + return; + } + } + + /* * Not a GENERIC OP, or the cache is full, just free the Op */ @@ -216,7 +279,7 @@ acpi_ps_delete_parse_cache ( void) { - ACPI_GENERIC_OP *next; + ACPI_PARSE_OBJECT *next; /* Traverse the global cache list */ @@ -227,6 +290,18 @@ next = acpi_gbl_parse_cache->next; acpi_cm_free (acpi_gbl_parse_cache); acpi_gbl_parse_cache = next; + acpi_gbl_parse_cache_depth--; + } + + /* Traverse the global cache list */ + + while (acpi_gbl_ext_parse_cache) { + /* Delete one cached state object */ + + next = acpi_gbl_ext_parse_cache->next; + acpi_cm_free (acpi_gbl_ext_parse_cache); + acpi_gbl_ext_parse_cache = (ACPI_PARSE2_OBJECT *) next; + acpi_gbl_ext_parse_cache_depth--; } return; @@ -253,7 +328,7 @@ u8 acpi_ps_is_leading_char ( - s32 c) + u32 c) { return ((u8) (c == '_' || (c >= 'A' && c <= 'Z'))); } @@ -264,7 +339,7 @@ */ u8 acpi_ps_is_prefix_char ( - s32 c) + u32 c) { return ((u8) (c == '\\' || c == '^')); } @@ -329,7 +404,7 @@ * TBD: [Restructure] Need a better way than this brute force approach! */ u8 -acpi_ps_is_named_object_op ( +acpi_ps_is_node_op ( u16 opcode) { return ((u8) @@ -433,38 +508,16 @@ /* - * Cast an acpi_op to an acpi_deferred_op if possible - */ -ACPI_DEFERRED_OP * -acpi_ps_to_deferred_op ( - ACPI_GENERIC_OP *op) -{ - return (acpi_ps_is_deferred_op (op->opcode) - ? ( (ACPI_DEFERRED_OP *) op) : NULL); -} - - -/* - * Cast an acpi_op to an acpi_named_op if possible + * Cast an acpi_op to an acpi_extended_op if possible */ -ACPI_NAMED_OP* -acpi_ps_to_named_op ( - ACPI_GENERIC_OP *op) -{ - return (acpi_ps_is_named_op (op->opcode) - ? ( (ACPI_NAMED_OP *) op) : NULL); -} - -/* - * Cast an acpi_op to an acpi_bytelist_op if possible - */ -ACPI_BYTELIST_OP* -acpi_ps_to_bytelist_op ( - ACPI_GENERIC_OP *op) +/* TBD: This is very inefficient, fix */ +ACPI_PARSE2_OBJECT * +acpi_ps_to_extended_op ( + ACPI_PARSE_OBJECT *op) { - return (acpi_ps_is_bytelist_op (op->opcode) - ? ( (ACPI_BYTELIST_OP*) op) : NULL); + return ((acpi_ps_is_deferred_op (op->opcode) || acpi_ps_is_named_op (op->opcode) || acpi_ps_is_bytelist_op (op->opcode)) + ? ( (ACPI_PARSE2_OBJECT *) op) : NULL); } @@ -473,9 +526,9 @@ */ u32 acpi_ps_get_name ( - ACPI_GENERIC_OP *op) + ACPI_PARSE_OBJECT *op) { - ACPI_NAMED_OP *named = acpi_ps_to_named_op (op); + ACPI_PARSE2_OBJECT *named = acpi_ps_to_extended_op (op); return (named ? named->name : 0); } @@ -486,10 +539,10 @@ */ void acpi_ps_set_name ( - ACPI_GENERIC_OP *op, + ACPI_PARSE_OBJECT *op, u32 name) { - ACPI_NAMED_OP *named = acpi_ps_to_named_op (op); + ACPI_PARSE2_OBJECT *named = acpi_ps_to_extended_op (op); if (named) { named->name = name; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/parser/pswalk.c linux/drivers/acpi/parser/pswalk.c --- v2.4.0-test8/linux/drivers/acpi/parser/pswalk.c Wed Jul 5 11:23:13 2000 +++ linux/drivers/acpi/parser/pswalk.c Fri Sep 15 14:30:30 2000 @@ -1,6 +1,7 @@ /****************************************************************************** * * Module Name: pswalk - Parser routines to walk parsed op tree(s) + * $Revision: 45 $ * *****************************************************************************/ @@ -25,13 +26,13 @@ #include "acpi.h" #include "amlcode.h" -#include "parser.h" -#include "dispatch.h" -#include "namesp.h" -#include "interp.h" +#include "acparser.h" +#include "acdispat.h" +#include "acnamesp.h" +#include "acinterp.h" #define _COMPONENT PARSER - MODULE_NAME ("pswalk"); + MODULE_NAME ("pswalk") /******************************************************************************* @@ -53,12 +54,12 @@ ACPI_STATUS acpi_ps_get_next_walk_op ( ACPI_WALK_STATE *walk_state, - ACPI_GENERIC_OP *op, - INTERPRETER_CALLBACK ascending_callback) + ACPI_PARSE_OBJECT *op, + ACPI_PARSE_UPWARDS ascending_callback) { - ACPI_GENERIC_OP *next; - ACPI_GENERIC_OP *parent; - ACPI_GENERIC_OP *grand_parent; + ACPI_PARSE_OBJECT *next; + ACPI_PARSE_OBJECT *parent; + ACPI_PARSE_OBJECT *grand_parent; ACPI_STATUS status; @@ -146,6 +147,18 @@ default: /* + * If we are back to the starting point, the walk is complete. + */ + if (op == walk_state->origin) { + /* Reached the point of origin, the walk is complete */ + + walk_state->prev_op = op; + walk_state->next_op = NULL; + + return (status); + } + + /* * Check for a sibling to the current op. A sibling means * we are still going "downward" in the tree. */ @@ -166,7 +179,7 @@ * No sibling, but check status. * Abort on error from callback routine */ - if (status != AE_OK) { + if (ACPI_FAILURE (status)) { /* Next op will be the parent */ walk_state->prev_op = op; @@ -302,7 +315,7 @@ * No sibling, check for an error from closing the parent * (Also, AE_PENDING if a method call was encountered) */ - if (status != AE_OK) { + if (ACPI_FAILURE (status)) { walk_state->prev_op = parent; walk_state->next_op = grand_parent; walk_state->next_op_info = NEXT_OP_UPWARD; @@ -347,13 +360,13 @@ ACPI_STATUS acpi_ps_walk_loop ( ACPI_WALK_LIST *walk_list, - ACPI_GENERIC_OP *start_op, - INTERPRETER_CALLBACK descending_callback, - INTERPRETER_CALLBACK ascending_callback) + ACPI_PARSE_OBJECT *start_op, + ACPI_PARSE_DOWNWARDS descending_callback, + ACPI_PARSE_UPWARDS ascending_callback) { ACPI_STATUS status = AE_OK; ACPI_WALK_STATE *walk_state; - ACPI_GENERIC_OP *op = start_op; + ACPI_PARSE_OBJECT *op = start_op; walk_state = acpi_ds_get_current_walk_state (walk_list); @@ -363,7 +376,7 @@ while (op) { if (walk_state->next_op_info != NEXT_OP_UPWARD) { - status = descending_callback (walk_state, op); + status = descending_callback (op->opcode, op, walk_state, NULL); } /* @@ -437,19 +450,19 @@ ACPI_STATUS acpi_ps_walk_parsed_aml ( - ACPI_GENERIC_OP *start_op, - ACPI_GENERIC_OP *end_op, - ACPI_OBJECT_INTERNAL *mth_desc, - ACPI_NAME_TABLE *start_scope, - ACPI_OBJECT_INTERNAL **params, - ACPI_OBJECT_INTERNAL **caller_return_desc, + ACPI_PARSE_OBJECT *start_op, + ACPI_PARSE_OBJECT *end_op, + ACPI_OPERAND_OBJECT *mth_desc, + ACPI_NAMESPACE_NODE *start_node, + ACPI_OPERAND_OBJECT **params, + ACPI_OPERAND_OBJECT **caller_return_desc, ACPI_OWNER_ID owner_id, - INTERPRETER_CALLBACK descending_callback, - INTERPRETER_CALLBACK ascending_callback) + ACPI_PARSE_DOWNWARDS descending_callback, + ACPI_PARSE_UPWARDS ascending_callback) { - ACPI_GENERIC_OP *op; + ACPI_PARSE_OBJECT *op; ACPI_WALK_STATE *walk_state; - ACPI_OBJECT_INTERNAL *return_desc; + ACPI_OPERAND_OBJECT *return_desc; ACPI_STATUS status; ACPI_WALK_LIST walk_list; ACPI_WALK_LIST *prev_walk_list; @@ -458,7 +471,7 @@ /* Parameter Validation */ if (!start_op || !end_op) { - return AE_BAD_PARAMETER; + return (AE_BAD_PARAMETER); } /* Initialize a new walk list */ @@ -475,10 +488,10 @@ prev_walk_list = acpi_gbl_current_walk_list; acpi_gbl_current_walk_list = &walk_list; - if (start_scope) { + if (start_node) { /* Push start scope on scope stack and make it current */ - status = acpi_ds_scope_stack_push (start_scope, ACPI_TYPE_METHOD, walk_state); + status = acpi_ds_scope_stack_push (start_node, ACPI_TYPE_METHOD, walk_state); if (ACPI_FAILURE (status)) { return (status); } @@ -489,7 +502,7 @@ /* Init arguments if this is a control method */ /* TBD: [Restructure] add walkstate as a param */ - acpi_ds_method_data_init_args (params, MTH_NUM_ARGS); + acpi_ds_method_data_init_args (params, MTH_NUM_ARGS, walk_state); } op = start_op; @@ -502,7 +515,7 @@ */ while (walk_state) { - if (status == AE_OK) { + if (ACPI_SUCCESS (status)) { status = acpi_ps_walk_loop (&walk_list, op, descending_callback, ascending_callback); } @@ -526,9 +539,7 @@ * there's lots of cleanup to do */ - if (walk_state->method_desc && - walk_state->method_desc->method.parser_op) - { + if (walk_state->method_desc) { acpi_ds_terminate_control_method (walk_state); } @@ -540,7 +551,7 @@ walk_state = acpi_ds_get_current_walk_state (&walk_list); if (walk_state && - status == AE_OK) + ACPI_SUCCESS (status)) { /* There is another walk state, restart it */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/parser/psxface.c linux/drivers/acpi/parser/psxface.c --- v2.4.0-test8/linux/drivers/acpi/parser/psxface.c Wed Jul 5 11:23:13 2000 +++ linux/drivers/acpi/parser/psxface.c Fri Sep 15 14:30:30 2000 @@ -1,7 +1,7 @@ - /****************************************************************************** * * Module Name: psxface - Parser external interfaces + * $Revision: 36 $ * *****************************************************************************/ @@ -25,18 +25,15 @@ #include "acpi.h" -#include "parser.h" -#include "dispatch.h" -#include "interp.h" +#include "acparser.h" +#include "acdispat.h" +#include "acinterp.h" #include "amlcode.h" -#include "namesp.h" +#include "acnamesp.h" #define _COMPONENT PARSER - MODULE_NAME ("psxface"); - - -char *acpi_gbl_parser_id = "Non-recursive AML Parser"; + MODULE_NAME ("psxface") /***************************************************************************** @@ -57,29 +54,30 @@ ACPI_STATUS acpi_psx_execute ( - ACPI_NAMED_OBJECT *method_entry, - ACPI_OBJECT_INTERNAL **params, - ACPI_OBJECT_INTERNAL **return_obj_desc) + ACPI_NAMESPACE_NODE *method_node, + ACPI_OPERAND_OBJECT **params, + ACPI_OPERAND_OBJECT **return_obj_desc) { ACPI_STATUS status; - ACPI_OBJECT_INTERNAL *obj_desc; + ACPI_OPERAND_OBJECT *obj_desc; u32 i; + ACPI_PARSE_OBJECT *op; - /* Validate the NTE and get the attached object */ + /* Validate the Node and get the attached object */ - if (!method_entry) { + if (!method_node) { return (AE_NULL_ENTRY); } - obj_desc = acpi_ns_get_attached_object (method_entry); + obj_desc = acpi_ns_get_attached_object (method_node); if (!obj_desc) { return (AE_NULL_OBJECT); } - /* Parse method if necessary, wait on concurrency semaphore */ + /* Init for new method, wait on concurrency semaphore */ - status = acpi_ds_begin_method_execution (method_entry, obj_desc); + status = acpi_ds_begin_method_execution (method_node, obj_desc); if (ACPI_FAILURE (status)) { return (status); } @@ -96,15 +94,40 @@ } /* - * Method is parsed and ready to execute - * The walk of the parse tree is where we actually execute the method + * Perform the first pass parse of the method to enter any + * named objects that it creates into the namespace */ - status = acpi_ps_walk_parsed_aml (obj_desc->method.parser_op, - obj_desc->method.parser_op, obj_desc, - method_entry->child_table, params, return_obj_desc, - obj_desc->method.owning_id, acpi_ds_exec_begin_op, - acpi_ds_exec_end_op); + /* Create and init a Root Node */ + + op = acpi_ps_alloc_op (AML_SCOPE_OP); + if (!op) { + return (AE_NO_MEMORY); + } + + status = acpi_ps_parse_aml (op, obj_desc->method.pcode, + obj_desc->method.pcode_length, + ACPI_PARSE_LOAD_PASS1 | ACPI_PARSE_DELETE_TREE, + method_node, params, return_obj_desc, + acpi_ds_load1_begin_op, acpi_ds_load1_end_op); + acpi_ps_delete_parse_tree (op); + + /* Create and init a Root Node */ + + op = acpi_ps_alloc_op (AML_SCOPE_OP); + if (!op) { + return (AE_NO_MEMORY); + } + + /* + * The walk of the parse tree is where we actually execute the method + */ + status = acpi_ps_parse_aml (op, obj_desc->method.pcode, + obj_desc->method.pcode_length, + ACPI_PARSE_EXECUTE | ACPI_PARSE_DELETE_TREE, + method_node, params, return_obj_desc, + acpi_ds_exec_begin_op, acpi_ds_exec_end_op); + acpi_ps_delete_parse_tree (op); if (params) { /* Take away the extra reference that we gave the parameters above */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/resources/Makefile linux/drivers/acpi/resources/Makefile --- v2.4.0-test8/linux/drivers/acpi/resources/Makefile Wed Dec 31 16:00:00 1969 +++ linux/drivers/acpi/resources/Makefile Fri Sep 15 18:21:44 2000 @@ -0,0 +1,28 @@ +# +# Makefile for all Linux ACPI interpreter subdirectories +# + +SUB_DIRS := +MOD_SUB_DIRS := $(SUB_DIRS) +MOD_IN_SUB_DIRS := +ALL_SUB_DIRS := $(SUB_DIRS) + +O_TARGET := ../$(shell basename `pwd`).o +O_OBJS := +M_OBJS := + +ACPI_OBJS := $(patsubst %.c,%.o,$(wildcard *.c)) + +EXTRA_CFLAGS += -I../include + +EXTRA_CFLAGS += $(ACPI_CFLAGS) + +# if the interpreter is used, it overrides arch/i386/kernel/acpi.c +ifeq ($(CONFIG_ACPI_INTERPRETER),y) + O_OBJS := $(ACPI_OBJS) +endif + +include $(TOPDIR)/Rules.make + +clean: + $(RM) *.o diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/resources/rsaddr.c linux/drivers/acpi/resources/rsaddr.c --- v2.4.0-test8/linux/drivers/acpi/resources/rsaddr.c Wed Jul 5 11:23:13 2000 +++ linux/drivers/acpi/resources/rsaddr.c Fri Sep 15 14:30:30 2000 @@ -4,6 +4,7 @@ * Acpi_rs_address16_stream * Acpi_rs_address32_resource * Acpi_rs_address32_stream + * $Revision: 9 $ * *****************************************************************************/ @@ -29,7 +30,7 @@ #include "acpi.h" #define _COMPONENT RESOURCE_MANAGER - MODULE_NAME ("rsaddr"); + MODULE_NAME ("rsaddr") /*************************************************************************** @@ -63,8 +64,8 @@ { u8 *buffer = byte_stream_buffer; RESOURCE *output_struct = (RESOURCE *) * output_buffer; - u16 temp16 = 0; - u8 temp8 = 0; + u16 temp16; + u8 temp8; u32 index; u32 struct_size = sizeof(ADDRESS16_RESOURCE) + RESOURCE_LENGTH_NO_DATA; @@ -75,7 +76,7 @@ */ buffer += 1; - temp16 = *(u16 *)buffer; + MOVE_UNALIGNED16_TO_16 (&temp16, buffer); *bytes_consumed = temp16 + 3; @@ -91,7 +92,7 @@ /* Values 0-2 are valid */ if (temp8 > 2) { - return (AE_ERROR); + return (AE_AML_ERROR); } output_struct->data.address16.resource_type = temp8 & 0x03; @@ -235,6 +236,7 @@ */ temp8 = (u8) (index + 1); struct_size += ROUND_UP_TO_32_bITS (temp8); + output_struct->length = struct_size; } else { output_struct->data.address16.resource_source_index = 0x00; @@ -243,11 +245,6 @@ } /* - * Set the Length parameter - */ - output_struct->length = struct_size; - - /* * Return the final size of the structure */ *structure_size = struct_size; @@ -281,8 +278,8 @@ { u8 *buffer = *output_buffer; u8 *length_field; - u8 temp8 = 0; - u8 *temp_pointer = NULL; + u8 temp8; + NATIVE_CHAR *temp_pointer = NULL; u32 actual_bytes; @@ -389,7 +386,7 @@ *buffer = temp8; buffer += 1; - temp_pointer = buffer; + temp_pointer = (NATIVE_CHAR *) buffer; /* * Copy the string @@ -450,15 +447,21 @@ u8 **output_buffer, u32 *structure_size) { - u8 *buffer = byte_stream_buffer; - RESOURCE *output_struct = (RESOURCE *) * output_buffer; - u16 temp16 = 0; - u8 temp8 = 0; - u32 struct_size = sizeof (ADDRESS32_RESOURCE) + - RESOURCE_LENGTH_NO_DATA; + u8 *buffer; + RESOURCE *output_struct; + u16 temp16; + u8 temp8; + u32 struct_size; u32 index; + buffer = byte_stream_buffer; + + output_struct = (RESOURCE *) *output_buffer; + + struct_size = sizeof (ADDRESS32_RESOURCE) + + RESOURCE_LENGTH_NO_DATA; + /* * Point past the Descriptor to get the number of bytes consumed */ @@ -477,7 +480,7 @@ /* Values 0-2 are valid */ if(temp8 > 2) { - return (AE_ERROR); + return (AE_AML_ERROR); } output_struct->data.address32.resource_type = temp8 & 0x03; @@ -661,11 +664,13 @@ u8 **output_buffer, u32 *bytes_consumed) { - u8 *buffer = *output_buffer; + u8 *buffer; u16 *length_field; - u8 temp8 = 0; - u8 *temp_pointer = NULL; + u8 temp8; + NATIVE_CHAR *temp_pointer; + + buffer = *output_buffer; /* * The descriptor field is static @@ -779,7 +784,7 @@ buffer += 1; - temp_pointer = buffer; + temp_pointer = (NATIVE_CHAR *) buffer; /* * Copy the string diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/resources/rscalc.c linux/drivers/acpi/resources/rscalc.c --- v2.4.0-test8/linux/drivers/acpi/resources/rscalc.c Wed Jul 5 11:23:13 2000 +++ linux/drivers/acpi/resources/rscalc.c Fri Sep 15 14:30:30 2000 @@ -2,6 +2,7 @@ * * Module Name: rscalc - Acpi_rs_calculate_byte_stream_length * Acpi_rs_calculate_list_length + * $Revision: 9 $ * *****************************************************************************/ @@ -27,7 +28,7 @@ #include "acpi.h" #define _COMPONENT RESOURCE_MANAGER - MODULE_NAME ("rscalc"); + MODULE_NAME ("rscalc") /*************************************************************************** @@ -51,9 +52,8 @@ RESOURCE *linked_list, u32 *size_needed) { - ACPI_STATUS status = AE_OK; u32 byte_stream_size_needed = 0; - u32 size_of_this_bit; + u32 segment_size; EXTENDED_IRQ_RESOURCE *ex_irq = NULL; u8 done = FALSE; @@ -64,7 +64,7 @@ * Init the variable that will hold the size to add to the * total. */ - size_of_this_bit = 0; + segment_size = 0; switch (linked_list->id) { @@ -76,7 +76,7 @@ * For an IRQ Resource, Byte 3, although optional, will * always be created - it holds IRQ information. */ - size_of_this_bit = 4; + segment_size = 4; break; case dma: @@ -86,7 +86,7 @@ /* * For this resource the size is static */ - size_of_this_bit = 3; + segment_size = 3; break; case start_dependent_functions: @@ -97,7 +97,7 @@ * For a Start_dependent_functions Resource, Byte 1, * although optional, will always be created. */ - size_of_this_bit = 2; + segment_size = 2; break; case end_dependent_functions: @@ -107,7 +107,7 @@ /* * For this resource the size is static */ - size_of_this_bit = 1; + segment_size = 1; break; case io: @@ -117,7 +117,7 @@ /* * For this resource the size is static */ - size_of_this_bit = 8; + segment_size = 8; break; case fixed_io: @@ -127,7 +127,7 @@ /* * For this resource the size is static */ - size_of_this_bit = 4; + segment_size = 4; break; case vendor_specific: @@ -141,12 +141,12 @@ * Resource data type. */ if(linked_list->data.vendor_specific.length > 7) { - size_of_this_bit = 3; + segment_size = 3; } else { - size_of_this_bit = 1; + segment_size = 1; } - size_of_this_bit += + segment_size += linked_list->data.vendor_specific.length; break; @@ -157,7 +157,7 @@ /* * For this resource the size is static */ - size_of_this_bit = 2; + segment_size = 2; done = TRUE; break; @@ -168,7 +168,7 @@ /* * For this resource the size is static */ - size_of_this_bit = 12; + segment_size = 12; break; case memory32: @@ -178,7 +178,7 @@ /* * For this resource the size is static */ - size_of_this_bit = 20; + segment_size = 20; break; case fixed_memory32: @@ -188,7 +188,7 @@ /* * For this resource the size is static */ - size_of_this_bit = 12; + segment_size = 12; break; case address16: @@ -201,10 +201,10 @@ * the Index + the length of the null terminated * string Resource Source + 1 for the null. */ - size_of_this_bit = 16; + segment_size = 16; if(NULL != linked_list->data.address16.resource_source) { - size_of_this_bit += (1 + + segment_size += (1 + linked_list->data.address16.resource_source_string_length); } break; @@ -219,10 +219,10 @@ * length of the null terminated string Resource Source + * 1 for the null. */ - size_of_this_bit = 26; + segment_size = 26; if(NULL != linked_list->data.address16.resource_source) { - size_of_this_bit += (1 + + segment_size += (1 + linked_list->data.address16.resource_source_string_length); } break; @@ -239,14 +239,14 @@ * Index + the length of the null terminated string * Resource Source + 1 for the null. */ - size_of_this_bit = 9; + segment_size = 9; - size_of_this_bit += + segment_size += (linked_list->data.extended_irq.number_of_interrupts - 1) * 4; if(NULL != ex_irq->resource_source) { - size_of_this_bit += (1 + + segment_size += (1 + linked_list->data.extended_irq.resource_source_string_length); } break; @@ -256,7 +256,7 @@ * If we get here, everything is out of sync, * so exit with an error */ - return (AE_ERROR); + return (AE_AML_ERROR); break; } /* switch (Linked_list->Id) */ @@ -264,7 +264,7 @@ /* * Update the total */ - byte_stream_size_needed += size_of_this_bit; + byte_stream_size_needed += segment_size; /* * Point to the next object @@ -278,7 +278,7 @@ */ *size_needed = byte_stream_size_needed; - return (status); + return (AE_OK); } /* Acpi_rs_calculate_byte_stream_length */ @@ -309,16 +309,16 @@ { u32 buffer_size = 0; u32 bytes_parsed = 0; - u8 resource_type = 0; - u32 structure_size = 0; - u32 bytes_consumed = 0; - u8 *buffer; u8 number_of_interrupts = 0; + u8 number_of_channels = 0; + u8 resource_type; + u32 structure_size; + u32 bytes_consumed; + u8 *buffer; u8 temp8; u16 temp16; u8 index; - u8 number_of_channels = 0; - u8 additional_bytes = 0; + u8 additional_bytes; while (bytes_parsed < byte_stream_buffer_length) { @@ -532,7 +532,7 @@ * If we get here, everything is out of sync, * so exit with an error */ - return (AE_ERROR); + return (AE_AML_ERROR); break; } } @@ -723,7 +723,7 @@ * If we get here, everything is out of sync, * so exit with an error */ - return (AE_ERROR); + return (AE_AML_ERROR); break; } /* switch */ @@ -752,3 +752,116 @@ } /* Acpi_rs_calculate_list_length */ +/*************************************************************************** + * FUNCTION: Acpi_rs_calculate_pci_routing_table_length + * + * PARAMETERS: + * Package_object - Pointer to the package object + * Buffer_size_needed - u32 pointer of the size buffer + * needed to properly return the + * parsed data + * + * RETURN: Status AE_OK + * + * DESCRIPTION: Given a package representing a PCI routing table, this + * calculates the size of the corresponding linked list of + * descriptions. + * + ***************************************************************************/ + +ACPI_STATUS +acpi_rs_calculate_pci_routing_table_length ( + ACPI_OPERAND_OBJECT *package_object, + u32 *buffer_size_needed) +{ + u32 number_of_elements; + u32 temp_size_needed; + ACPI_OPERAND_OBJECT **top_object_list; + u32 index; + + number_of_elements = package_object->package.count; + + /* + * Calculate the size of the return buffer. + * The base size is the number of elements * the sizes of the + * structures. Additional space for the strings is added below. + * The minus one is to subtract the size of the u8 Source[1] + * member because it is added below. + * + * NOTE: The Number_of_elements is incremented by one to add an end + * table structure that is essentially a structure of zeros. + */ + temp_size_needed = (number_of_elements + 1) * + (sizeof (PCI_ROUTING_TABLE) - 1); + + /* + * But each PRT_ENTRY structure has a pointer to a string and + * the size of that string must be found. + */ + top_object_list = package_object->package.elements; + + for (index = 0; index < number_of_elements; index++) { + ACPI_OPERAND_OBJECT *package_element; + ACPI_OPERAND_OBJECT **sub_object_list; + u8 name_found; + u32 table_index; + + /* + * Dereference the sub-package + */ + package_element = *top_object_list; + + /* + * The Sub_object_list will now point to an array of the + * four IRQ elements: Address, Pin, Source and Source_index + */ + sub_object_list = package_element->package.elements; + + /* + * Scan the Irq_table_elements for the Source Name String + */ + name_found = FALSE; + + for (table_index = 0; table_index < 4 && !name_found; table_index++) { + if (ACPI_TYPE_STRING == (*sub_object_list)->common.type) { + name_found = TRUE; + } + + else { + /* + * Look at the next element + */ + sub_object_list++; + } + } + + /* + * Was a String type found? + */ + if (TRUE == name_found) { + /* + * The length String.Length field includes the + * terminating NULL + */ + temp_size_needed += (*sub_object_list)->string.length; + temp_size_needed = ROUND_UP_TO_32_bITS (temp_size_needed); + } + + else { + /* + * If no name was found, then this is a NULL, which is + * translated as a u32 zero. + */ + temp_size_needed += sizeof(u32); + } + + /* + * Point to the next ACPI_OPERAND_OBJECT + */ + top_object_list++; + } + + *buffer_size_needed = temp_size_needed; + + return (AE_OK); +} \ No newline at end of file diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/resources/rscreate.c linux/drivers/acpi/resources/rscreate.c --- v2.4.0-test8/linux/drivers/acpi/resources/rscreate.c Wed Jul 5 11:23:13 2000 +++ linux/drivers/acpi/resources/rscreate.c Fri Sep 15 14:30:30 2000 @@ -3,6 +3,7 @@ * Module Name: rscreate - Acpi_rs_create_resource_list * Acpi_rs_create_pci_routing_table * Acpi_rs_create_byte_stream + * $Revision: 16 $ * *****************************************************************************/ @@ -26,13 +27,14 @@ #include "acpi.h" -#include "resource.h" +#include "acresrc.h" #define _COMPONENT RESOURCE_MANAGER - MODULE_NAME ("rscreate"); + MODULE_NAME ("rscreate") -/*************************************************************************** +/******************************************************************************* + * * FUNCTION: Acpi_rs_create_resource_list * * PARAMETERS: @@ -40,53 +42,40 @@ * Output_buffer - Pointer to the user's buffer * Output_buffer_length - Pointer to the size of Output_buffer * - * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code - * If Output_buffer is not large enough, Output_buffer_length - * indicates how large Output_buffer should be, else it - * indicates how may u8 elements of Output_buffer are - * valid. + * RETURN: Status - AE_OK if okay, else a valid ACPI_STATUS code + * If Output_buffer is not large enough, Output_buffer_length + * indicates how large Output_buffer should be, else it + * indicates how may u8 elements of Output_buffer are valid. * * DESCRIPTION: Takes the byte stream returned from a _CRS, _PRS control method - * execution and parses the stream to create a linked list - * of device resources. + * execution and parses the stream to create a linked list + * of device resources. * - ***************************************************************************/ + ******************************************************************************/ ACPI_STATUS acpi_rs_create_resource_list ( - ACPI_OBJECT_INTERNAL *byte_stream_buffer, + ACPI_OPERAND_OBJECT *byte_stream_buffer, u8 *output_buffer, u32 *output_buffer_length) { - ACPI_STATUS status = AE_UNKNOWN_STATUS; + ACPI_STATUS status; u8 *byte_stream_start = NULL; u32 list_size_needed = 0; u32 byte_stream_buffer_length = 0; /* - * Validate parameters: - * - * 1. If Byte_stream_buffer is NULL after we know that - * Byte_steam_length is not zero, or - * 2. If Output_buffer is NULL and Output_buffer_length - * is not zero - * - * Return an error + * Params already validated, so we don't re-validate here */ - if (!byte_stream_buffer || - (!output_buffer && 0 != *output_buffer_length)) - { - return (AE_BAD_PARAMETER); - } byte_stream_buffer_length = byte_stream_buffer->buffer.length; byte_stream_start = byte_stream_buffer->buffer.pointer; /* * Pass the Byte_stream_buffer into a module that can calculate - * the buffer size needed for the linked list + * the buffer size needed for the linked list */ status = acpi_rs_calculate_list_length (byte_stream_start, byte_stream_buffer_length, @@ -95,13 +84,13 @@ /* * Exit with the error passed back */ - if (AE_OK != status) { + if (ACPI_FAILURE (status)) { return (status); } /* * If the linked list will fit into the available buffer - * call to fill in the list + * call to fill in the list */ if (list_size_needed <= *output_buffer_length) { @@ -117,7 +106,7 @@ /* * Exit with the error passed back */ - if (AE_OK != status) { + if (ACPI_FAILURE (status)) { return (status); } @@ -134,138 +123,53 @@ } -/*************************************************************************** +/******************************************************************************* + * * FUNCTION: Acpi_rs_create_pci_routing_table * * PARAMETERS: - * Package_object - Pointer to an ACPI_OBJECT_INTERNAL + * Package_object - Pointer to an ACPI_OPERAND_OBJECT * package * Output_buffer - Pointer to the user's buffer * Output_buffer_length - Size of Output_buffer * * RETURN: Status AE_OK if okay, else a valid ACPI_STATUS code. * If the Output_buffer is too small, the error will be - * AE_BUFFER_OVERFLOW and Output_buffer_length will point - * to the size buffer needed. + * AE_BUFFER_OVERFLOW and Output_buffer_length will point + * to the size buffer needed. * - * DESCRIPTION: Takes the ACPI_OBJECT_INTERNAL package and creates a - * linked list of PCI interrupt descriptions + * DESCRIPTION: Takes the ACPI_OPERAND_OBJECT package and creates a + * linked list of PCI interrupt descriptions * - ***************************************************************************/ + ******************************************************************************/ ACPI_STATUS acpi_rs_create_pci_routing_table ( - ACPI_OBJECT_INTERNAL *package_object, + ACPI_OPERAND_OBJECT *package_object, u8 *output_buffer, u32 *output_buffer_length) { u8 *buffer = output_buffer; - ACPI_OBJECT_INTERNAL **top_object_list = NULL; - ACPI_OBJECT_INTERNAL **sub_object_list = NULL; - ACPI_OBJECT_INTERNAL *package_element = NULL; + ACPI_OPERAND_OBJECT **top_object_list = NULL; + ACPI_OPERAND_OBJECT **sub_object_list = NULL; + ACPI_OPERAND_OBJECT *package_element = NULL; u32 buffer_size_needed = 0; u32 number_of_elements = 0; u32 index = 0; - u8 table_index = 0; - u8 name_found = FALSE; PCI_ROUTING_TABLE *user_prt = NULL; + ACPI_STATUS status; /* - * Validate parameters: - * - * 1. If Method_return_object is NULL, or - * 2. If Output_buffer is NULL and Output_buffer_length is not zero - * - * Return an error + * Params already validated, so we don't re-validate here */ - if (!package_object || - (!output_buffer && 0 != *output_buffer_length)) - { - return (AE_BAD_PARAMETER); - } - /* - * Calculate the buffer size needed for the routing table. - */ - number_of_elements = package_object->package.count; - - /* - * Properly calculate the size of the return buffer. - * The base size is the number of elements * the sizes of the - * structures. Additional space for the strings is added below. - * The minus one is to subtract the size of the u8 Source[1] - * member because it is added below. - * NOTE: The Number_of_elements is incremented by one to add an end - * table structure that is essentially a structure of zeros. - */ - buffer_size_needed = (number_of_elements + 1) * - (sizeof (PCI_ROUTING_TABLE) - 1); - - /* - * But each PRT_ENTRY structure has a pointer to a string and - * the size of that string must be found. - */ - top_object_list = package_object->package.elements; - - for (index = 0; index < number_of_elements; index++) { - /* - * Dereference the sub-package - */ - package_element = *top_object_list; - - /* - * The Sub_object_list will now point to an array of the - * four IRQ elements: Address, Pin, Source and Source_index - */ - sub_object_list = package_element->package.elements; - - /* - * Scan the Irq_table_elements for the Source Name String - */ - name_found = FALSE; - - for (table_index = 0; table_index < 4 && !name_found; table_index++) { - if (ACPI_TYPE_STRING == (*sub_object_list)->common.type) { - name_found = TRUE; - } - - else { - /* - * Look at the next element - */ - sub_object_list++; - } - } - - /* - * Was a String type found? - */ - if (TRUE == name_found) { - /* - * The length String.Length field includes the - * terminating NULL - */ - buffer_size_needed += ((*sub_object_list)->string.length); - } - - else { - /* - * If no name was found, then this is a NULL, which is - * translated as a u32 zero. - */ - buffer_size_needed += sizeof(u32); - } - - /* - * Point to the next ACPI_OBJECT_INTERNAL - */ - top_object_list++; - } + status = acpi_rs_calculate_pci_routing_table_length(package_object, + &buffer_size_needed); /* * If the data will fit into the available buffer - * call to fill in the list + * call to fill in the list */ if (buffer_size_needed <= *output_buffer_length) { /* @@ -275,34 +179,32 @@ /* * Loop through the ACPI_INTERNAL_OBJECTS - Each object should - * contain a u32 Address, a u8 Pin, a Name and a u8 - * Source_index. + * contain a u32 Address, a u8 Pin, a Name and a u8 + * Source_index. */ top_object_list = package_object->package.elements; number_of_elements = package_object->package.count; - user_prt = (PCI_ROUTING_TABLE *)buffer; + user_prt = (PCI_ROUTING_TABLE *) buffer; for (index = 0; index < number_of_elements; index++) { /* * Point User_prt past this current structure * * NOTE: On the first iteration, User_prt->Length will - * be zero because we zero'ed out the return buffer - * earlier + * be zero because we cleared the return buffer earlier */ buffer += user_prt->length; - - user_prt = (PCI_ROUTING_TABLE *)buffer; + user_prt = (PCI_ROUTING_TABLE *) buffer; /* * Fill in the Length field with the information we - * have at this point. - * The minus one is to subtract the size of the - * u8 Source[1] member because it is added below. + * have at this point. + * The minus one is to subtract the size of the + * u8 Source[1] member because it is added below. */ - user_prt->length = (sizeof(PCI_ROUTING_TABLE) - 1); + user_prt->length = (sizeof (PCI_ROUTING_TABLE) - 1); /* * Dereference the sub-package @@ -311,8 +213,8 @@ /* * The Sub_object_list will now point to an array of - * the four IRQ elements: Address, Pin, Source and - * Source_index + * the four IRQ elements: Address, Pin, Source and + * Source_index */ sub_object_list = package_element->package.elements; @@ -348,27 +250,29 @@ sub_object_list++; if (ACPI_TYPE_STRING == (*sub_object_list)->common.type) { - STRCPY(user_prt->data.source, + STRCPY (user_prt->data.source, (*sub_object_list)->string.pointer); /* * Add to the Length field the length of the string */ user_prt->length += (*sub_object_list)->string.length; + user_prt->length = + ROUND_UP_TO_32_bITS (user_prt->length); } else { /* * If this is a number, then the Source Name - * is NULL, since the entire buffer was zeroed - * out, we can leave this alone. + * is NULL, since the entire buffer was zeroed + * out, we can leave this alone. */ if (ACPI_TYPE_NUMBER == (*sub_object_list)->common.type) { /* * Add to the Length field the length of - * the u32 NULL + * the u32 NULL */ - user_prt->length += sizeof(u32); + user_prt->length += sizeof (u32); } else { @@ -391,7 +295,7 @@ } /* - * Point to the next ACPI_OBJECT_INTERNAL + * Point to the next ACPI_OPERAND_OBJECT */ top_object_list++; } @@ -414,7 +318,8 @@ } -/*************************************************************************** +/******************************************************************************* + * * FUNCTION: Acpi_rs_create_byte_stream * * PARAMETERS: @@ -431,7 +336,7 @@ * creates a bytestream to be used as input for the * _SRS control method. * - ***************************************************************************/ + ******************************************************************************/ ACPI_STATUS acpi_rs_create_byte_stream ( @@ -439,27 +344,15 @@ u8 *output_buffer, u32 *output_buffer_length) { - ACPI_STATUS status = AE_UNKNOWN_STATUS; + ACPI_STATUS status; u32 byte_stream_size_needed = 0; /* - * Validate parameters: + * Params already validated, so we don't re-validate here * - * 1. If Linked_list_buffer is NULL, or - * 2. If Output_buffer is NULL and Output_buffer_length is not zero - * - * Return an error - */ - if (!linked_list_buffer || - (!output_buffer && 0 != *output_buffer_length)) - { - return (AE_BAD_PARAMETER); - } - - /* * Pass the Linked_list_buffer into a module that can calculate - * the buffer size needed for the byte stream. + * the buffer size needed for the byte stream. */ status = acpi_rs_calculate_byte_stream_length (linked_list_buffer, &byte_stream_size_needed); @@ -467,13 +360,13 @@ /* * Exit with the error passed back */ - if (AE_OK != status) { + if (ACPI_FAILURE (status)) { return (status); } /* * If the linked list will fit into the available buffer - * call to fill in the list + * call to fill in the list */ if (byte_stream_size_needed <= *output_buffer_length) { @@ -489,7 +382,7 @@ /* * Exit with the error passed back */ - if (AE_OK != status) { + if (ACPI_FAILURE (status)) { return (status); } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/resources/rsdump.c linux/drivers/acpi/resources/rsdump.c --- v2.4.0-test8/linux/drivers/acpi/resources/rsdump.c Wed Jul 5 11:23:13 2000 +++ linux/drivers/acpi/resources/rsdump.c Fri Sep 15 14:30:30 2000 @@ -1,6 +1,7 @@ /****************************************************************************** * * Module Name: rsdump - Functions do dump out the resource structures. + * $Revision: 10 $ * *****************************************************************************/ @@ -26,7 +27,7 @@ #include "acpi.h" #define _COMPONENT RESOURCE_MANAGER - MODULE_NAME ("rsdump"); + MODULE_NAME ("rsdump") /****************************************************************************** @@ -120,7 +121,7 @@ break; } - acpi_os_printf ("\t\t%s_bus Master\n", + acpi_os_printf ("\t\t%sBus Master\n", BUS_MASTER == dma_data->bus_master ? "" : "Not a "); @@ -802,7 +803,7 @@ acpi_rs_dump_resource_list ( RESOURCE *resource) { - s8 count = 0; + u8 count = 0; u8 done = FALSE; @@ -902,7 +903,7 @@ u8 *route_table) { u8 *buffer = route_table; - s8 count = 0; + u8 count = 0; u8 done = FALSE; PCI_ROUTING_TABLE *prt_element; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/resources/rsio.c linux/drivers/acpi/resources/rsio.c --- v2.4.0-test8/linux/drivers/acpi/resources/rsio.c Wed Jul 5 11:23:13 2000 +++ linux/drivers/acpi/resources/rsio.c Fri Sep 15 14:30:30 2000 @@ -6,6 +6,7 @@ * Acpi_rs_fixed_io_stream * Acpi_rs_dma_resource * Acpi_rs_dma_stream + * $Revision: 7 $ * *****************************************************************************/ @@ -31,7 +32,7 @@ #include "acpi.h" #define _COMPONENT RESOURCE_MANAGER - MODULE_NAME ("rsio"); + MODULE_NAME ("rsio") /*************************************************************************** @@ -90,7 +91,7 @@ * Check Min_base Address */ buffer += 1; - temp16 = *(u16 *)buffer; + MOVE_UNALIGNED16_TO_16 (&temp16, buffer); output_struct->data.io.min_base_address = temp16; @@ -98,7 +99,7 @@ * Check Max_base Address */ buffer += 2; - temp16 = *(u16 *)buffer; + MOVE_UNALIGNED16_TO_16 (&temp16, buffer); output_struct->data.io.max_base_address = temp16; @@ -255,7 +256,7 @@ */ temp16 = (u16) linked_list->data.io.min_base_address; - *(u16 *)buffer = temp16; + MOVE_UNALIGNED16_TO_16 (&temp16, buffer); buffer += 2; @@ -264,7 +265,7 @@ */ temp16 = (u16) linked_list->data.io.max_base_address; - *(u16 *)buffer = temp16; + MOVE_UNALIGNED16_TO_16 (&temp16, buffer); buffer += 2; @@ -336,7 +337,7 @@ */ temp16 = (u16) linked_list->data.fixed_io.base_address; - *(u16 *)buffer = temp16; + MOVE_UNALIGNED16_TO_16 (&temp16, buffer); buffer += 2; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/resources/rsirq.c linux/drivers/acpi/resources/rsirq.c --- v2.4.0-test8/linux/drivers/acpi/resources/rsirq.c Wed Jul 5 11:23:13 2000 +++ linux/drivers/acpi/resources/rsirq.c Fri Sep 15 14:30:30 2000 @@ -4,6 +4,7 @@ * Acpi_rs_irq_stream * Acpi_rs_extended_irq_resource * Acpi_rs_extended_irq_stream + * $Revision: 8 $ * *****************************************************************************/ @@ -29,7 +30,7 @@ #include "acpi.h" #define _COMPONENT RESOURCE_MANAGER - MODULE_NAME ("rsirq"); + MODULE_NAME ("rsirq") /*************************************************************************** @@ -85,7 +86,7 @@ * Point to the 16-bits of Bytes 1 and 2 */ buffer += 1; - temp16 = *(u16 *)buffer; + MOVE_UNALIGNED16_TO_16 (&temp16, buffer); output_struct->data.irq.number_of_interrupts = 0; @@ -226,7 +227,7 @@ temp16 |= 0x1 << temp8; } - *(u16 *)buffer = temp16; + MOVE_UNALIGNED16_TO_16 (&temp16, buffer); buffer += 2; @@ -306,7 +307,7 @@ * Point past the Descriptor to get the number of bytes consumed */ buffer += 1; - temp16 = *(u16 *)buffer; + MOVE_UNALIGNED16_TO_16 (&temp16, buffer); *bytes_consumed = temp16 + 3; output_struct->id = extended_irq; @@ -476,7 +477,7 @@ u16 *length_field; u8 temp8 = 0; u8 index; - u8 *temp_pointer = NULL; + NATIVE_CHAR *temp_pointer = NULL; /* @@ -533,11 +534,10 @@ * Resource Source Index and Resource Source are optional */ if (0 != linked_list->data.extended_irq.resource_source_string_length) { - temp8 = (u8) linked_list->data.extended_irq.resource_source_index; - - *buffer = temp8; + *buffer = (u8) linked_list->data.extended_irq.resource_source_index; buffer += 1; - temp_pointer = buffer; + + temp_pointer = (NATIVE_CHAR *) buffer; /* * Copy the string diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/resources/rslist.c linux/drivers/acpi/resources/rslist.c --- v2.4.0-test8/linux/drivers/acpi/resources/rslist.c Wed Jul 5 11:23:13 2000 +++ linux/drivers/acpi/resources/rslist.c Fri Sep 15 14:30:30 2000 @@ -2,6 +2,7 @@ * * Module Name: rslist - Acpi_rs_byte_stream_to_list * Acpi_list_to_byte_stream + * $Revision: 6 $ * *****************************************************************************/ @@ -25,10 +26,10 @@ #include "acpi.h" -#include "resource.h" +#include "acresrc.h" #define _COMPONENT RESOURCE_MANAGER - MODULE_NAME ("rslist"); + MODULE_NAME ("rslist") /*************************************************************************** @@ -53,7 +54,7 @@ u32 byte_stream_buffer_length, u8 **output_buffer) { - ACPI_STATUS status = AE_UNKNOWN_STATUS; + ACPI_STATUS status; u32 bytes_parsed = 0; u8 resource_type = 0; u32 bytes_consumed = 0; @@ -167,7 +168,7 @@ * If we get here, everything is out of sync, * so exit with an error */ - return (AE_ERROR); + return (AE_AML_ERROR); break; } } @@ -275,11 +276,11 @@ * If we get here, everything is out of sync, * so exit with an error */ - return (AE_ERROR); + return (AE_AML_ERROR); break; } /* switch */ - } /* if(Resource_type & 0x80) */ + } /* end else */ /* * Update the return value and counter @@ -296,14 +297,15 @@ */ *buffer += structure_size; - } /* while (Bytes_parsed < Byte_stream_buffer_length && - FALSE == End_tag_processed) */ + } /* end while */ /* * Check the reason for exiting the while loop */ - if (byte_stream_buffer_length != bytes_parsed || TRUE != end_tag_processed) { - return (AE_ERROR); + if (!(byte_stream_buffer_length == bytes_parsed) || + (TRUE != end_tag_processed)) + { + return (AE_AML_ERROR); } return (AE_OK); @@ -338,7 +340,7 @@ u32 byte_stream_size_needed, u8 **output_buffer) { - ACPI_STATUS status = AE_UNKNOWN_STATUS; + ACPI_STATUS status; u8 *buffer = *output_buffer; u32 bytes_consumed = 0; u8 done = FALSE; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/resources/rsmemory.c linux/drivers/acpi/resources/rsmemory.c --- v2.4.0-test8/linux/drivers/acpi/resources/rsmemory.c Wed Jul 5 11:23:13 2000 +++ linux/drivers/acpi/resources/rsmemory.c Fri Sep 15 14:30:30 2000 @@ -6,6 +6,7 @@ * Acpi_rs_fixed_memory32_resource * Acpi_rs_memory32_range_stream * Acpi_rs_fixed_memory32_stream + * $Revision: 7 $ * *****************************************************************************/ @@ -31,7 +32,7 @@ #include "acpi.h" #define _COMPONENT RESOURCE_MANAGER - MODULE_NAME ("rsmemory"); + MODULE_NAME ("rsmemory") /*************************************************************************** @@ -76,7 +77,7 @@ */ buffer += 1; - temp16 = *(u16 *)buffer; + MOVE_UNALIGNED16_TO_16 (&temp16, buffer); buffer += 2; @@ -96,7 +97,7 @@ /* * Get Min_base_address (Bytes 4-5) */ - temp16 = *(u16 *)buffer; + MOVE_UNALIGNED16_TO_16 (&temp16, buffer); buffer += 2; @@ -105,7 +106,7 @@ /* * Get Max_base_address (Bytes 6-7) */ - temp16 = *(u16 *)buffer; + MOVE_UNALIGNED16_TO_16 (&temp16, buffer); buffer += 2; @@ -114,7 +115,7 @@ /* * Get Alignment (Bytes 8-9) */ - temp16 = *(u16 *)buffer; + MOVE_UNALIGNED16_TO_16 (&temp16, buffer); buffer += 2; @@ -123,7 +124,7 @@ /* * Get Range_length (Bytes 10-11) */ - temp16 = *(u16 *)buffer; + MOVE_UNALIGNED16_TO_16 (&temp16, buffer); output_struct->data.memory24.range_length = temp16; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/resources/rsmisc.c linux/drivers/acpi/resources/rsmisc.c --- v2.4.0-test8/linux/drivers/acpi/resources/rsmisc.c Wed Jul 5 11:23:13 2000 +++ linux/drivers/acpi/resources/rsmisc.c Fri Sep 15 14:30:30 2000 @@ -8,6 +8,7 @@ * Acpi_rs_end_dependent_functions_resource * Acpi_rs_start_dependent_functions_stream * Acpi_rs_end_dependent_functions_stream + * $Revision: 7 $ * *****************************************************************************/ @@ -33,7 +34,7 @@ #include "acpi.h" #define _COMPONENT RESOURCE_MANAGER - MODULE_NAME ("rsmisc"); + MODULE_NAME ("rsmisc") /*************************************************************************** @@ -199,7 +200,7 @@ /* Dereference */ - temp16 = *(u16 *)buffer; + MOVE_UNALIGNED16_TO_16 (&temp16, buffer); /* Calculate bytes consumed */ @@ -304,7 +305,7 @@ temp16 = (u16) linked_list->data.vendor_specific.length; - *(u16 *)buffer = temp16; + MOVE_UNALIGNED16_TO_16 (&temp16, buffer); buffer += 2; } @@ -404,7 +405,7 @@ temp8 & 0x03; if (3 == output_struct->data.start_dependent_functions.compatibility_priority) { - return (AE_ERROR); + return (AE_AML_ERROR); } /* @@ -414,7 +415,7 @@ (temp8 >> 2) & 0x03; if (3 == output_struct->data.start_dependent_functions.performance_robustness) { - return (AE_ERROR); + return (AE_AML_ERROR); } } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/resources/rsutils.c linux/drivers/acpi/resources/rsutils.c --- v2.4.0-test8/linux/drivers/acpi/resources/rsutils.c Wed Jul 5 11:23:13 2000 +++ linux/drivers/acpi/resources/rsutils.c Fri Sep 15 14:30:30 2000 @@ -1,6 +1,7 @@ /****************************************************************************** * * Module Name: rsutils - Utilities for the resource manager + * $Revision: 10 $ * *****************************************************************************/ @@ -24,19 +25,19 @@ #include "acpi.h" -#include "namesp.h" -#include "resource.h" +#include "acnamesp.h" +#include "acresrc.h" #define _COMPONENT RESOURCE_MANAGER - MODULE_NAME ("rsutils"); + MODULE_NAME ("rsutils") /****************************************************************************** * * FUNCTION: Acpi_rs_get_prt_method_data * - * PARAMETERS: Device_handle - a handle to the containing object + * PARAMETERS: Handle - a handle to the containing object * Ret_buffer - a pointer to a buffer structure for the * results * @@ -55,28 +56,20 @@ ACPI_HANDLE handle, ACPI_BUFFER *ret_buffer) { - ACPI_OBJECT_INTERNAL *ret_obj; + ACPI_OPERAND_OBJECT *ret_obj; ACPI_STATUS status; - u32 buffer_space_needed = ret_buffer->length; + u32 buffer_space_needed; - /* - * Must have a valid handle and buffer, So we have to have a handle - * a return buffer structure and if there is a non-zero buffer length - * we also need a valid pointer in the buffer - */ - if ((!handle) || - (!ret_buffer) || - ((!ret_buffer->pointer) && (ret_buffer->length))) - { - return (AE_BAD_PARAMETER); - } + /* already validated params, so we won't repeat here */ + + buffer_space_needed = ret_buffer->length; /* * Execute the method, no parameters */ status = acpi_ns_evaluate_relative (handle, "_PRT", NULL, &ret_obj); - if (status != AE_OK) { + if (ACPI_FAILURE (status)) { return (status); } @@ -128,7 +121,7 @@ * * FUNCTION: Acpi_rs_get_crs_method_data * - * PARAMETERS: Device_handle - a handle to the containing object + * PARAMETERS: Handle - a handle to the containing object * Ret_buffer - a pointer to a buffer structure for the * results * @@ -147,28 +140,18 @@ ACPI_HANDLE handle, ACPI_BUFFER *ret_buffer) { - ACPI_OBJECT_INTERNAL *ret_obj; + ACPI_OPERAND_OBJECT *ret_obj; ACPI_STATUS status; u32 buffer_space_needed = ret_buffer->length; - /* - * Must have a valid handle and buffer, So we have to have a handle - * a return buffer structure and if there is a non-zero buffer length - * we also need a valid pointer in the buffer - */ - if ((!handle) || - (!ret_buffer) || - ((!ret_buffer->pointer) && (ret_buffer->length))) - { - return (AE_BAD_PARAMETER); - } + /* already validated params, so we won't repeat here */ /* * Execute the method, no parameters */ status = acpi_ns_evaluate_relative (handle, "_CRS", NULL, &ret_obj); - if (status != AE_OK) { + if (ACPI_FAILURE (status)) { return (status); } @@ -198,9 +181,7 @@ ret_buffer->pointer, &buffer_space_needed); - if (AE_OK == status) { - acpi_rs_dump_resource_list((RESOURCE *)ret_buffer->pointer); - } + /* * Tell the user how much of the buffer we have used or is needed @@ -223,7 +204,7 @@ * * FUNCTION: Acpi_rs_get_prs_method_data * - * PARAMETERS: Device_handle - a handle to the containing object + * PARAMETERS: Handle - a handle to the containing object * Ret_buffer - a pointer to a buffer structure for the * results * @@ -242,28 +223,18 @@ ACPI_HANDLE handle, ACPI_BUFFER *ret_buffer) { - ACPI_OBJECT_INTERNAL *ret_obj; + ACPI_OPERAND_OBJECT *ret_obj; ACPI_STATUS status; u32 buffer_space_needed = ret_buffer->length; - /* - * Must have a valid handle and buffer, So we have to have a handle - * a return buffer structure and if there is a non-zero buffer length - * we also need a valid pointer in the buffer - */ - if ((!handle) || - (!ret_buffer) || - ((!ret_buffer->pointer) && (ret_buffer->length))) - { - return (AE_BAD_PARAMETER); - } + /* already validated params, so we won't repeat here */ /* * Execute the method, no parameters */ status = acpi_ns_evaluate_relative (handle, "_PRS", NULL, &ret_obj); - if (status != AE_OK) { + if (ACPI_FAILURE (status)) { return (status); } @@ -314,9 +285,7 @@ * * FUNCTION: Acpi_rs_set_srs_method_data * - * PARAMETERS: Device_handle - a handle to the containing object - * *Method_name - Name of method to execute, If NULL, the - * handle is the object to execute + * PARAMETERS: Handle - a handle to the containing object * In_buffer - a pointer to a buffer structure of the * parameter * @@ -335,22 +304,13 @@ ACPI_HANDLE handle, ACPI_BUFFER *in_buffer) { - ACPI_OBJECT_INTERNAL *params[2]; - ACPI_OBJECT_INTERNAL param_obj; + ACPI_OPERAND_OBJECT *params[2]; + ACPI_OPERAND_OBJECT param_obj; ACPI_STATUS status; u8 *byte_stream = NULL; u32 buffer_size_needed = 0; - /* - * Must have a valid handle and buffer - */ - if ((!handle) || - (!in_buffer) || - (!in_buffer->pointer) || - (!in_buffer->length)) - { - return (AE_BAD_PARAMETER); - } + /* already validated params, so we won't repeat here */ /* * The In_buffer parameter will point to a linked list of @@ -390,12 +350,8 @@ byte_stream, &buffer_size_needed); - if(AE_OK != status) { - /* - * Failed the call - */ - acpi_cm_free (byte_stream); - return (status); + if (ACPI_FAILURE (status)) { + goto cleanup; } /* @@ -424,6 +380,9 @@ /* * Clean up and return the status from Acpi_ns_evaluate_relative */ + +cleanup: + acpi_cm_free (byte_stream); return (status); } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/resources/rsxface.c linux/drivers/acpi/resources/rsxface.c --- v2.4.0-test8/linux/drivers/acpi/resources/rsxface.c Wed Jul 5 11:23:13 2000 +++ linux/drivers/acpi/resources/rsxface.c Fri Sep 15 14:30:30 2000 @@ -1,6 +1,7 @@ /****************************************************************************** * * Module Name: rsxface - Public interfaces to the ACPI subsystem + * $Revision: 7 $ * *****************************************************************************/ @@ -24,12 +25,12 @@ #include "acpi.h" -#include "interp.h" -#include "namesp.h" -#include "resource.h" +#include "acinterp.h" +#include "acnamesp.h" +#include "acresrc.h" #define _COMPONENT RESOURCE_MANAGER - MODULE_NAME ("rsxface"); + MODULE_NAME ("rsxface") /****************************************************************************** @@ -37,19 +38,18 @@ * FUNCTION: Acpi_get_irq_routing_table * * PARAMETERS: Device_handle - a handle to the Bus device we are querying - * Out_buffer - a pointer to a buffer to receive the + * Ret_buffer - a pointer to a buffer to receive the * current resources for the device - * Buffer_length - the number of bytes available in the buffer * * RETURN: Status - the status of the call * * DESCRIPTION: This function is called to get the IRQ routing table for a * specific bus. The caller must first acquire a handle for the * desired bus. The routine table is placed in the buffer pointed - * to by the Out_buffer variable parameter. + * to by the Ret_buffer variable parameter. * * If the function fails an appropriate status will be returned - * and the value of Out_buffer is undefined. + * and the value of Ret_buffer is undefined. * * This function attempts to execute the _PRT method contained in * the object indicated by the passed Device_handle. @@ -64,6 +64,19 @@ ACPI_STATUS status; + /* + * Must have a valid handle and buffer, So we have to have a handle + * and a return buffer structure, and if there is a non-zero buffer length + * we also need a valid pointer in the buffer. If it's a zero buffer length, + * we'll be returning the needed buffer size, so keep going. + */ + if ((!device_handle) || + (!ret_buffer) || + ((!ret_buffer->pointer) && (ret_buffer->length))) + { + return (AE_BAD_PARAMETER); + } + status = acpi_rs_get_prt_method_data (device_handle, ret_buffer); return (status); @@ -76,19 +89,18 @@ * * PARAMETERS: Device_handle - a handle to the device object for the * device we are querying - * Out_buffer - a pointer to a buffer to receive the + * Ret_buffer - a pointer to a buffer to receive the * current resources for the device - * Buffer_length - the number of bytes available in the buffer * * RETURN: Status - the status of the call * * DESCRIPTION: This function is called to get the current resources for a * specific device. The caller must first acquire a handle for * the desired device. The resource data is placed in the buffer - * pointed to by the Out_buffer variable parameter. + * pointed to by the Ret_buffer variable parameter. * * If the function fails an appropriate status will be returned - * and the value of Out_buffer is undefined. + * and the value of Ret_buffer is undefined. * * This function attempts to execute the _CRS method contained in * the object indicated by the passed Device_handle. @@ -103,6 +115,19 @@ ACPI_STATUS status; + /* + * Must have a valid handle and buffer, So we have to have a handle + * and a return buffer structure, and if there is a non-zero buffer length + * we also need a valid pointer in the buffer. If it's a zero buffer length, + * we'll be returning the needed buffer size, so keep going. + */ + if ((!device_handle) || + (!ret_buffer) || + ((ret_buffer->length) && (!ret_buffer->pointer))) + { + return (AE_BAD_PARAMETER); + } + status = acpi_rs_get_crs_method_data (device_handle, ret_buffer); return (status); @@ -115,19 +140,18 @@ * * PARAMETERS: Device_handle - a handle to the device object for the * device we are querying - * Out_buffer - a pointer to a buffer to receive the + * Ret_buffer - a pointer to a buffer to receive the * resources for the device - * Buffer_length - the number of bytes available in the buffer - * + * * RETURN: Status - the status of the call * * DESCRIPTION: This function is called to get a list of the possible resources * for a specific device. The caller must first acquire a handle * for the desired device. The resource data is placed in the - * buffer pointed to by the Out_buffer variable. + * buffer pointed to by the Ret_buffer variable. * * If the function fails an appropriate status will be returned - * and the value of Out_buffer is undefined. + * and the value of Ret_buffer is undefined. * ******************************************************************************/ @@ -139,6 +163,19 @@ ACPI_STATUS status; + /* + * Must have a valid handle and buffer, So we have to have a handle + * and a return buffer structure, and if there is a non-zero buffer length + * we also need a valid pointer in the buffer. If it's a zero buffer length, + * we'll be returning the needed buffer size, so keep going. + */ + if ((!device_handle) || + (!ret_buffer) || + ((ret_buffer->length) && (!ret_buffer->pointer))) + { + return (AE_BAD_PARAMETER); + } + status = acpi_rs_get_prs_method_data (device_handle, ret_buffer); return (status); @@ -151,7 +188,7 @@ * * PARAMETERS: Device_handle - a handle to the device object for the * device we are changing the resources of - * Out_buffer - a pointer to a buffer containing the + * In_buffer - a pointer to a buffer containing the * resources to be set for the device * * RETURN: Status - the status of the call @@ -170,6 +207,17 @@ { ACPI_STATUS status; + + /* + * Must have a valid handle and buffer + */ + if ((!device_handle) || + (!in_buffer) || + (!in_buffer->pointer) || + (!in_buffer->length)) + { + return (AE_BAD_PARAMETER); + } status = acpi_rs_set_srs_method_data (device_handle, in_buffer); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/sys.c linux/drivers/acpi/sys.c --- v2.4.0-test8/linux/drivers/acpi/sys.c Thu Jul 13 09:39:49 2000 +++ linux/drivers/acpi/sys.c Fri Sep 15 14:30:30 2000 @@ -24,6 +24,9 @@ #include "acpi.h" #include "driver.h" +#define _COMPONENT OS_DEPENDENT + MODULE_NAME ("sys") + #define ACPI_SLP_TYP(typa, typb) (((int)(typa) << 8) | (int)(typb)) #define ACPI_SLP_TYPA(value) \ ((((value) >> 8) << ACPI_SLP_TYP_SHIFT) & ACPI_SLP_TYP_MASK) diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/table.c linux/drivers/acpi/table.c --- v2.4.0-test8/linux/drivers/acpi/table.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/acpi/table.c Fri Sep 15 14:30:30 2000 @@ -0,0 +1,306 @@ +/* + * tables.c - ACPI tables, chipset, and errata handling + * + * Copyright (C) 2000 Andrew Henroid + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include "acpi.h" +#include "driver.h" + +#define _COMPONENT OS_DEPENDENT + MODULE_NAME ("tables") + +struct acpi_facp acpi_facp; + +#define ACPI_DUMMY_CHECKSUM 9 +#define ACPI_DUMMY_PBLK 51 + +static u8 acpi_dummy_dsdt[] = +{ + 0x44, 0x53, 0x44, 0x54, // "DSDT" + 0x38, 0x00, 0x00, 0x00, // length + 0x01, // revision + 0x00, // checksum + 0x4c, 0x49, 0x4e, 0x55, 0x58, 0x00, // "LINUX" + 0x44, 0x55, 0x4d, 0x4d, 0x59, 0x00, 0x00, 0x00, // "DUMMY" + 0x01, 0x00, 0x00, 0x00, // OEM rev + 0x4c, 0x4e, 0x55, 0x58, // "LNUX" + 0x01, 0x00, 0x00, 0x00, // creator rev + 0x10, // Scope + 0x13, // PkgLength + 0x5c, 0x5f, 0x50, 0x52, 0x5f, // \_PR_ + 0x5b, 0x83, // Processor + 0x0b, // PkgLength + 0x43, 0x50, 0x55, 0x30, // CPU0 + 0x00, // ID + 0x00, 0x00, 0x00, 0x00, // PBLK + 0x06 // PBLK size +}; + +/* + * Calculate and set ACPI table checksum + */ +static void +acpi_set_checksum(u8 *table, int size) +{ + int i, sum = 0; + for (i = 0; i < size; i++) + sum += (int) table[i]; + sum = (0x100 - ((sum - table[ACPI_DUMMY_CHECKSUM]) & 0xff)); + table[ACPI_DUMMY_CHECKSUM] = sum; +} + +/* + * Init PIIX4 device, create a fake FACP + */ +static int +acpi_init_piix4(struct pci_dev *dev) +{ + u32 base, pblk; + u16 cmd; + u8 pmregmisc; + + pci_read_config_word(dev, PCI_COMMAND, &cmd); + if (!(cmd & PCI_COMMAND_IO)) + return -ENODEV; + + pci_read_config_byte(dev, ACPI_PIIX4_PMREGMISC, &pmregmisc); + if (!(pmregmisc & ACPI_PIIX4_PMIOSE)) + return -ENODEV; + + base = pci_resource_start (dev, PCI_BRIDGE_RESOURCES); + if (!base) + return -ENODEV; + + printk(KERN_INFO "ACPI: found \"%s\" at 0x%04x\n", dev->name, base); + + memset(&acpi_facp, 0, sizeof(acpi_facp)); + acpi_facp.hdr.signature = ACPI_FACP_SIG; + acpi_facp.hdr.length = sizeof(acpi_facp); + acpi_facp.int_model = ACPI_PIIX4_INT_MODEL; + acpi_facp.sci_int = ACPI_PIIX4_SCI_INT; + acpi_facp.smi_cmd = ACPI_PIIX4_SMI_CMD; + acpi_facp.acpi_enable = ACPI_PIIX4_ACPI_ENABLE; + acpi_facp.acpi_disable = ACPI_PIIX4_ACPI_DISABLE; + acpi_facp.s4bios_req = ACPI_PIIX4_S4BIOS_REQ; + acpi_facp.pm1a_evt = base + ACPI_PIIX4_PM1_EVT; + acpi_facp.pm1a_cnt = base + ACPI_PIIX4_PM1_CNT; + acpi_facp.pm2_cnt = ACPI_PIIX4_PM2_CNT; + acpi_facp.pm_tmr = base + ACPI_PIIX4_PM_TMR; + acpi_facp.gpe0 = base + ACPI_PIIX4_GPE0; + acpi_facp.pm1_evt_len = ACPI_PIIX4_PM1_EVT_LEN; + acpi_facp.pm1_cnt_len = ACPI_PIIX4_PM1_CNT_LEN; + acpi_facp.pm2_cnt_len = ACPI_PIIX4_PM2_CNT_LEN; + acpi_facp.pm_tm_len = ACPI_PIIX4_PM_TM_LEN; + acpi_facp.gpe0_len = ACPI_PIIX4_GPE0_LEN; + acpi_facp.p_lvl2_lat = (__u16) ACPI_INFINITE_LAT; + acpi_facp.p_lvl3_lat = (__u16) ACPI_INFINITE_LAT; + + acpi_set_checksum((u8*) &acpi_facp, sizeof(acpi_facp)); + acpi_load_table((ACPI_TABLE_HEADER*) &acpi_facp); + + pblk = base + ACPI_PIIX4_P_BLK; + memcpy(acpi_dummy_dsdt + ACPI_DUMMY_PBLK, &pblk, sizeof(pblk)); + acpi_set_checksum(acpi_dummy_dsdt, sizeof(acpi_dummy_dsdt)); + acpi_load_table((ACPI_TABLE_HEADER*) acpi_dummy_dsdt); + + return 0; +} + +/* + * Init VIA ACPI device and create a fake FACP + */ +static int +acpi_init_via(struct pci_dev *dev) +{ + u32 base, pblk; + u8 tmp, irq; + + pci_read_config_byte(dev, 0x41, &tmp); + if (!(tmp & 0x80)) + return -ENODEV; + + base = pci_resource_start(dev, PCI_BRIDGE_RESOURCES); + if (!base) { + base = pci_resource_start(dev, PCI_BASE_ADDRESS_4); + if (!base) + return -ENODEV; + } + + pci_read_config_byte(dev, 0x42, &irq); + + printk(KERN_INFO "ACPI: found \"%s\" at 0x%04x\n", dev->name, base); + + memset(&acpi_facp, 0, sizeof(acpi_facp)); + acpi_facp.hdr.signature = ACPI_FACP_SIG; + acpi_facp.hdr.length = sizeof(acpi_facp); + acpi_facp.int_model = ACPI_VIA_INT_MODEL; + acpi_facp.sci_int = irq; + acpi_facp.smi_cmd = base + ACPI_VIA_SMI_CMD; + acpi_facp.acpi_enable = ACPI_VIA_ACPI_ENABLE; + acpi_facp.acpi_disable = ACPI_VIA_ACPI_DISABLE; + acpi_facp.pm1a_evt = base + ACPI_VIA_PM1_EVT; + acpi_facp.pm1a_cnt = base + ACPI_VIA_PM1_CNT; + acpi_facp.pm_tmr = base + ACPI_VIA_PM_TMR; + acpi_facp.gpe0 = base + ACPI_VIA_GPE0; + + acpi_facp.pm1_evt_len = ACPI_VIA_PM1_EVT_LEN; + acpi_facp.pm1_cnt_len = ACPI_VIA_PM1_CNT_LEN; + acpi_facp.pm_tm_len = ACPI_VIA_PM_TM_LEN; + acpi_facp.gpe0_len = ACPI_VIA_GPE0_LEN; + acpi_facp.p_lvl2_lat = (__u16) ACPI_INFINITE_LAT; + acpi_facp.p_lvl3_lat = (__u16) ACPI_INFINITE_LAT; + + acpi_facp.duty_offset = ACPI_VIA_DUTY_OFFSET; + acpi_facp.duty_width = ACPI_VIA_DUTY_WIDTH; + + acpi_facp.day_alarm = ACPI_VIA_DAY_ALARM; + acpi_facp.mon_alarm = ACPI_VIA_MON_ALARM; + acpi_facp.century = ACPI_VIA_CENTURY; + + acpi_set_checksum((u8*) &acpi_facp, sizeof(acpi_facp)); + acpi_load_table((ACPI_TABLE_HEADER*) &acpi_facp); + + pblk = base + ACPI_VIA_P_BLK; + memcpy(acpi_dummy_dsdt + ACPI_DUMMY_PBLK, &pblk, sizeof(pblk)); + acpi_set_checksum(acpi_dummy_dsdt, sizeof(acpi_dummy_dsdt)); + acpi_load_table((ACPI_TABLE_HEADER*) acpi_dummy_dsdt); + + return 0; +} + +typedef enum +{ + CH_UNKNOWN = 0, + CH_INTEL_PIIX4, + CH_VIA_586, + CH_VIA_686A, +} acpi_chip_t; + +/* indexed by value of each enum in acpi_chip_t */ +const static struct +{ + int (*chip_init)(struct pci_dev *dev); +} acpi_chip_info[] = +{ + {NULL,}, + {acpi_init_piix4}, + {acpi_init_via}, + {acpi_init_via}, +}; + +static struct pci_device_id acpi_pci_tbl[] = +{ + {0x8086, 0x7113, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_INTEL_PIIX4}, + {0x1106, 0x3040, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_VIA_586}, + {0x1106, 0x3057, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_VIA_686A}, + {0,} /* terminate list */ +}; + +static int +acpi_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + return acpi_chip_info[id->driver_data].chip_init(dev); +} + +static struct pci_driver acpi_driver = +{ + name: "acpi", + id_table: acpi_pci_tbl, + probe: acpi_probe, +}; +static int acpi_driver_registered = 0; + +/* + * Locate a known ACPI chipset + */ +static int +acpi_find_chipset(void) +{ + if (pci_register_driver(&acpi_driver) < 1) + return -ENODEV; + acpi_driver_registered = 1; + return 0; +} + +/* + * Fetch the FACP information + */ +static int +acpi_fetch_facp(void) +{ + ACPI_BUFFER buffer; + + memset(&acpi_facp, 0, sizeof(acpi_facp)); + buffer.pointer = &acpi_facp; + buffer.length = sizeof(acpi_facp); + if (!ACPI_SUCCESS(acpi_get_table(ACPI_TABLE_FACP, 1, &buffer))) { + printk(KERN_ERR "ACPI: missing FACP\n"); + return -ENODEV; + } + + if (acpi_facp.p_lvl2_lat + && acpi_facp.p_lvl2_lat <= ACPI_MAX_P_LVL2_LAT) { + acpi_c2_exit_latency + = ACPI_uS_TO_TMR_TICKS(acpi_facp.p_lvl2_lat); + acpi_c2_enter_latency + = ACPI_uS_TO_TMR_TICKS(ACPI_TMR_HZ / 1000); + } + if (acpi_facp.p_lvl3_lat + && acpi_facp.p_lvl3_lat <= ACPI_MAX_P_LVL3_LAT) { + acpi_c3_exit_latency + = ACPI_uS_TO_TMR_TICKS(acpi_facp.p_lvl3_lat); + acpi_c3_enter_latency + = ACPI_uS_TO_TMR_TICKS(acpi_facp.p_lvl3_lat * 5); + } + + return 0; +} + +/* + * Find and load ACPI tables + */ +int +acpi_load_tables(void) +{ + if (ACPI_SUCCESS(acpi_load_firmware_tables())) + { + printk(KERN_INFO "ACPI: support found\n"); + } + else if (acpi_find_chipset()) { + acpi_terminate(); + return -1; + } + + if (acpi_fetch_facp()) { + acpi_terminate(); + return -1; + } + + if (!ACPI_SUCCESS(acpi_load_namespace())) { + printk(KERN_ERR "ACPI: namespace load failed\n"); + acpi_terminate(); + return -1; + } + + return 0; +} diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/tables/Makefile linux/drivers/acpi/tables/Makefile --- v2.4.0-test8/linux/drivers/acpi/tables/Makefile Wed Dec 31 16:00:00 1969 +++ linux/drivers/acpi/tables/Makefile Fri Sep 15 18:21:44 2000 @@ -0,0 +1,28 @@ +# +# Makefile for all Linux ACPI interpreter subdirectories +# + +SUB_DIRS := +MOD_SUB_DIRS := $(SUB_DIRS) +MOD_IN_SUB_DIRS := +ALL_SUB_DIRS := $(SUB_DIRS) + +O_TARGET := ../$(shell basename `pwd`).o +O_OBJS := +M_OBJS := + +ACPI_OBJS := $(patsubst %.c,%.o,$(wildcard *.c)) + +EXTRA_CFLAGS += -I../include + +EXTRA_CFLAGS += $(ACPI_CFLAGS) + +# if the interpreter is used, it overrides arch/i386/kernel/acpi.c +ifeq ($(CONFIG_ACPI_INTERPRETER),y) + O_OBJS := $(ACPI_OBJS) +endif + +include $(TOPDIR)/Rules.make + +clean: + $(RM) *.o diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/tables/tbget.c linux/drivers/acpi/tables/tbget.c --- v2.4.0-test8/linux/drivers/acpi/tables/tbget.c Wed Jul 5 11:23:13 2000 +++ linux/drivers/acpi/tables/tbget.c Fri Sep 15 14:30:30 2000 @@ -1,7 +1,7 @@ - /****************************************************************************** * * Module Name: tbget - ACPI Table get* routines + * $Revision: 22 $ * *****************************************************************************/ @@ -25,12 +25,12 @@ #include "acpi.h" -#include "hardware.h" -#include "tables.h" +#include "achware.h" +#include "actables.h" #define _COMPONENT TABLE_MANAGER - MODULE_NAME ("tbget"); + MODULE_NAME ("tbget") /******************************************************************************* @@ -90,10 +90,15 @@ return (AE_NOT_EXIST); } - /* Walk the list to get the table */ - + /* Walk the list to get the desired table + * Since the if (Instance == 1) check above checked for the + * first table, setting Table_desc equal to the .Next member + * is actually pointing to the second table. Therefore, we + * need to walk from the 2nd table until we reach the Instance + * that the user is looking for and return its table pointer. + */ table_desc = acpi_gbl_acpi_tables[table_type].next; - for (i = 1; i < acpi_gbl_acpi_tables[table_type].count; i++) { + for (i = 2; i < instance; i++) { table_desc = table_desc->next; } @@ -110,8 +115,8 @@ * FUNCTION: Acpi_tb_get_table * * PARAMETERS: Physical_address - Physical address of table to retrieve - * *Buffer_ptr - If == NULL, read data from buffer - * rather than searching memory + * *Buffer_ptr - If Buffer_ptr is valid, read data from + * buffer rather than searching memory * *Table_info - Where the table info is returned * * RETURN: Status @@ -123,7 +128,7 @@ ACPI_STATUS acpi_tb_get_table ( void *physical_address, - char *buffer_ptr, + ACPI_TABLE_HEADER *buffer_ptr, ACPI_TABLE_DESC *table_info) { ACPI_TABLE_HEADER *table_header = NULL; @@ -143,7 +148,7 @@ * Getting data from a buffer, not BIOS tables */ - table_header = (ACPI_TABLE_HEADER *) buffer_ptr; + table_header = buffer_ptr; status = acpi_tb_validate_table_header (table_header); if (ACPI_FAILURE (status)) { /* Table failed verification, map all errors to BAD_DATA */ @@ -160,7 +165,7 @@ /* Copy the entire table (including header) to the local buffer */ - size = (ACPI_SIZE) table_header->length; + size = table_header->length; MEMCPY (full_table, buffer_ptr, size); /* Save allocation type */ @@ -216,7 +221,7 @@ ACPI_STATUS acpi_tb_get_all_tables ( u32 number_of_tables, - char *table_ptr) + ACPI_TABLE_HEADER *table_ptr) { ACPI_STATUS status = AE_OK; u32 index; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/tables/tbinstal.c linux/drivers/acpi/tables/tbinstal.c --- v2.4.0-test8/linux/drivers/acpi/tables/tbinstal.c Wed Jul 5 11:23:13 2000 +++ linux/drivers/acpi/tables/tbinstal.c Fri Sep 15 14:30:30 2000 @@ -1,7 +1,7 @@ - /****************************************************************************** * * Module Name: tbinstal - ACPI table installation and removal + * $Revision: 29 $ * *****************************************************************************/ @@ -25,12 +25,12 @@ #include "acpi.h" -#include "hardware.h" -#include "tables.h" +#include "achware.h" +#include "actables.h" #define _COMPONENT TABLE_MANAGER - MODULE_NAME ("tbinstal"); + MODULE_NAME ("tbinstal") /******************************************************************************* @@ -50,11 +50,9 @@ ACPI_STATUS acpi_tb_install_table ( - char *table_ptr, + ACPI_TABLE_HEADER *table_ptr, ACPI_TABLE_DESC *table_info) { - ACPI_TABLE_TYPE table_type; - ACPI_TABLE_HEADER *table_header; ACPI_STATUS status; @@ -68,11 +66,6 @@ return (status); } - /* Table type is returned by Recognize_table */ - - table_type = table_info->type; - table_header = table_info->pointer; - /* Lock tables while installing */ acpi_cm_acquire_mutex (ACPI_MTX_TABLES); @@ -80,12 +73,9 @@ /* Install the table into the global data structure */ status = acpi_tb_init_table_descriptor (table_info->type, table_info); - if (ACPI_FAILURE (status)) { - return (status); - } acpi_cm_release_mutex (ACPI_MTX_TABLES); - return (AE_OK); + return (status); } @@ -112,7 +102,7 @@ ACPI_STATUS acpi_tb_recognize_table ( - char *table_ptr, + ACPI_TABLE_HEADER *table_ptr, ACPI_TABLE_DESC *table_info) { ACPI_TABLE_HEADER *table_header; @@ -215,9 +205,10 @@ * the table are allowed. This includes SSDT and PSDTs. */ - if (acpi_gbl_acpi_table_data[table_type].flags == ACPI_TABLE_SINGLE) { + if (IS_SINGLE_TABLE (acpi_gbl_acpi_table_data[table_type].flags)) { /* - * Only one table allowed, just update the list head + * Only one table allowed, and a table has alread been installed + * at this location, so return an error. */ if (list_head->pointer) { @@ -249,7 +240,7 @@ /* Update new entry */ table_desc->prev = list_head->prev; - table_desc->next = (ACPI_TABLE_DESC *) list_head; + table_desc->next = list_head; /* Update list head */ @@ -308,7 +299,7 @@ void acpi_tb_delete_acpi_tables (void) { - u32 i; + ACPI_TABLE_TYPE type; /* @@ -316,8 +307,8 @@ * Memory can either be mapped or allocated */ - for (i = 0; i < ACPI_TABLE_MAX; i++) { - acpi_tb_delete_acpi_table (i); + for (type = 0; type < ACPI_TABLE_MAX; type++) { + acpi_tb_delete_acpi_table (type); } } @@ -402,6 +393,46 @@ /******************************************************************************* * + * FUNCTION: Acpi_tb_free_acpi_tables_of_type + * + * PARAMETERS: Table_info - A table info struct + * + * RETURN: None. + * + * DESCRIPTION: Free the memory associated with an internal ACPI table + * Table mutex should be locked. + * + ******************************************************************************/ + +void +acpi_tb_free_acpi_tables_of_type ( + ACPI_TABLE_DESC *list_head) +{ + ACPI_TABLE_DESC *table_desc; + u32 count; + u32 i; + + + /* Get the head of the list */ + + table_desc = list_head; + count = list_head->count; + + /* + * Walk the entire list, deleting both the allocated tables + * and the table descriptors + */ + + for (i = 0; i < count; i++) { + table_desc = acpi_tb_delete_single_table (table_desc); + } + + return; +} + + +/******************************************************************************* + * * FUNCTION: Acpi_tb_delete_single_table * * PARAMETERS: Table_info - A table info struct @@ -488,46 +519,6 @@ return (next_desc); -} - - -/******************************************************************************* - * - * FUNCTION: Acpi_tb_free_acpi_tables_of_type - * - * PARAMETERS: Table_info - A table info struct - * - * RETURN: None. - * - * DESCRIPTION: Free the memory associated with an internal ACPI table - * Table mutex should be locked. - * - ******************************************************************************/ - -void -acpi_tb_free_acpi_tables_of_type ( - ACPI_TABLE_DESC *list_head) -{ - ACPI_TABLE_DESC *table_desc; - u32 count; - u32 i; - - - /* Get the head of the list */ - - table_desc = list_head; - count = list_head->count; - - /* - * Walk the entire list, deleting both the allocated tables - * and the table descriptors - */ - - for (i = 0; i < count; i++) { - table_desc = acpi_tb_delete_single_table (table_desc); - } - - return; } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/tables/tbtable.c linux/drivers/acpi/tables/tbtable.c --- v2.4.0-test8/linux/drivers/acpi/tables/tbtable.c Wed Jul 5 11:23:13 2000 +++ linux/drivers/acpi/tables/tbtable.c Fri Sep 15 14:30:30 2000 @@ -1,7 +1,7 @@ - /****************************************************************************** * * Module Name: tbtable - ACPI tables: FACP, FACS, and RSDP utilities + * $Revision: 24 $ * *****************************************************************************/ @@ -25,12 +25,12 @@ #include "acpi.h" -#include "hardware.h" -#include "tables.h" +#include "achware.h" +#include "actables.h" #define _COMPONENT TABLE_MANAGER - MODULE_NAME ("tbtable"); + MODULE_NAME ("tbtable") /******************************************************************************* @@ -38,7 +38,6 @@ * FUNCTION: Acpi_tb_get_table_rsdt * * PARAMETERS: Number_of_tables - Where the table count is placed - * Table_ptr - Input buffer pointer, optional * * RETURN: Status * @@ -85,15 +84,15 @@ REPORT_ERROR ("Invalid signature where RSDP indicates RSDT should be located"); } + REPORT_ERROR ("Unable to locate RSDT"); + + return (status); } /* Always delete the RSDP mapping */ acpi_tb_delete_acpi_table (ACPI_TABLE_RSDP); - if (ACPI_FAILURE (status)) { - return (status); - } /* Save the table pointers and allocation info */ @@ -109,10 +108,15 @@ status = acpi_tb_verify_table_checksum ((ACPI_TABLE_HEADER *) acpi_gbl_RSDT); - /* Determine the number of tables pointed to by the RSDT */ + /* + * Determine the number of tables pointed to by the RSDT. + * This is defined by the ACPI Specification to be the number of + * pointers contained within the RSDT. The size of the pointers + * is architecture-dependent. + */ - *number_of_tables = (s32) DIV_4 (acpi_gbl_RSDT->header.length - - sizeof (ACPI_TABLE_HEADER)); + *number_of_tables = ((acpi_gbl_RSDT->header.length - + sizeof (ACPI_TABLE_HEADER)) / sizeof (void *)); return (status); @@ -132,13 +136,13 @@ * ******************************************************************************/ -char * +u8 * acpi_tb_scan_memory_for_rsdp ( - char *start_address, + u8 *start_address, u32 length) { u32 offset; - char *mem_rover; + u8 *mem_rover; /* Search from given start addr for the requested length */ @@ -150,19 +154,19 @@ /* The signature and checksum must both be correct */ - if (STRNCMP (mem_rover, RSDP_SIG, sizeof (RSDP_SIG)-1) == 0 && + if (STRNCMP ((NATIVE_CHAR *) mem_rover, RSDP_SIG, sizeof (RSDP_SIG)-1) == 0 && acpi_tb_checksum (mem_rover, sizeof (ROOT_SYSTEM_DESCRIPTOR_POINTER)) == 0) { /* If so, we have found the RSDP */ - return mem_rover; + return (mem_rover); } } /* Searched entire block, no RSDP was found */ - return NULL; + return (NULL); } @@ -189,8 +193,8 @@ acpi_tb_find_rsdp ( ACPI_TABLE_DESC *table_info) { - char *table_ptr; - char *mem_rover; + u8 *table_ptr; + u8 *mem_rover; ACPI_STATUS status = AE_OK; if (acpi_gbl_acpi_init_data.RSDP_physical_address) { @@ -214,9 +218,9 @@ * The signature and checksum must both be correct */ - if (STRNCMP (table_ptr, RSDP_SIG, sizeof (RSDP_SIG)-1) != 0) { + if (STRNCMP ((NATIVE_CHAR *) table_ptr, RSDP_SIG, sizeof (RSDP_SIG)-1) != 0) { /* Nope, BAD Signature */ - + acpi_os_unmap_memory (table_ptr, sizeof (ROOT_SYSTEM_DESCRIPTOR_POINTER)); return (AE_BAD_SIGNATURE); } @@ -226,7 +230,7 @@ sizeof (ROOT_SYSTEM_DESCRIPTOR_POINTER)) != 0) { /* Nope, BAD Checksum */ - + acpi_os_unmap_memory (table_ptr, sizeof (ROOT_SYSTEM_DESCRIPTOR_POINTER)); return (AE_BAD_CHECKSUM); } @@ -309,12 +313,12 @@ } -/******************************************************************************* +/****************************************************************************** * * FUNCTION: Acpi_tb_get_table_facs * - * PARAMETERS: *Buffer_ptr - If == NULL, read data from buffer - * rather than searching memory + * PARAMETERS: *Buffer_ptr - If Buffer_ptr is valid, read data from + * buffer rather than searching memory * *Table_info - Where the table info is returned * * RETURN: Status @@ -324,11 +328,11 @@ * correctly initialized. The value of FACP->Firmware_ctrl * into a far pointer which is returned. * - ******************************************************************************/ + *****************************************************************************/ ACPI_STATUS acpi_tb_get_table_facs ( - char *buffer_ptr, + ACPI_TABLE_HEADER *buffer_ptr, ACPI_TABLE_DESC *table_info) { void *table_ptr = NULL; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/tables/tbutils.c linux/drivers/acpi/tables/tbutils.c --- v2.4.0-test8/linux/drivers/acpi/tables/tbutils.c Wed Jul 5 11:23:13 2000 +++ linux/drivers/acpi/tables/tbutils.c Fri Sep 15 14:30:30 2000 @@ -1,7 +1,7 @@ - /****************************************************************************** * * Module Name: tbutils - Table manipulation utilities + * $Revision: 26 $ * *****************************************************************************/ @@ -25,23 +25,24 @@ #include "acpi.h" -#include "tables.h" -#include "interp.h" +#include "actables.h" +#include "acinterp.h" #define _COMPONENT TABLE_MANAGER - MODULE_NAME ("tbutils"); + MODULE_NAME ("tbutils") /******************************************************************************* * - * FUNCTION: Acpi_tb_system_table_pointer + * FUNCTION: Acpi_tb_handle_to_object * - * PARAMETERS: *Where - Pointer to be examined + * PARAMETERS: Table_id - Id for which the function is searching + * Table_desc - Pointer to return the matching table + * descriptor. * - * RETURN: TRUE if Where is within the AML stream (in one of the ACPI - * system tables such as the DSDT or an SSDT.) - * FALSE otherwise + * RETURN: Search the tables to find one with a matching Table_id and + * return a pointer to that table descriptor. * ******************************************************************************/ @@ -60,7 +61,7 @@ { if (list_head->table_id == table_id) { *table_desc = list_head; - return AE_OK; + return (AE_OK); } list_head = list_head->next; @@ -69,7 +70,7 @@ } - return AE_BAD_PARAMETER; + return (AE_BAD_PARAMETER); } @@ -177,7 +178,7 @@ /* Verify that this is a valid address */ if (!acpi_os_readable (table_header, sizeof (ACPI_TABLE_HEADER))) { - return AE_BAD_ADDRESS; + return (AE_BAD_ADDRESS); } @@ -186,7 +187,7 @@ MOVE_UNALIGNED32_TO_32 (&signature, &table_header->signature); if (!acpi_cm_valid_acpi_name (signature)) { REPORT_WARNING ("Invalid table signature found"); - return AE_BAD_SIGNATURE; + return (AE_BAD_SIGNATURE); } @@ -194,10 +195,10 @@ if (table_header->length < sizeof (ACPI_TABLE_HEADER)) { REPORT_WARNING ("Invalid table header length found"); - return AE_BAD_HEADER; + return (AE_BAD_HEADER); } - return AE_OK; + return (AE_OK); } @@ -236,7 +237,7 @@ status = acpi_os_map_memory (physical_address, sizeof (ACPI_TABLE_HEADER), (void **) &table); if (ACPI_FAILURE (status)) { - return status; + return (status); } /* Extract the full table length before we delete the mapping */ @@ -257,7 +258,7 @@ /* Exit if header invalid */ if (ACPI_FAILURE (status)) { - return status; + return (status); } } @@ -266,13 +267,13 @@ status = acpi_os_map_memory (physical_address, table_size, (void **) &table); if (ACPI_FAILURE (status)) { - return status; + return (status); } *size = table_size; *logical_address = table; - return status; + return (status); } @@ -346,7 +347,7 @@ } } - return sum; + return (sum); } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/tables/tbxface.c linux/drivers/acpi/tables/tbxface.c --- v2.4.0-test8/linux/drivers/acpi/tables/tbxface.c Wed Jul 5 11:23:13 2000 +++ linux/drivers/acpi/tables/tbxface.c Fri Sep 15 14:30:30 2000 @@ -1,8 +1,8 @@ - /****************************************************************************** * * Module Name: tbxface - Public interfaces to the ACPI subsystem * ACPI table oriented interfaces + * $Revision: 24 $ * *****************************************************************************/ @@ -26,13 +26,13 @@ #include "acpi.h" -#include "namesp.h" -#include "interp.h" -#include "tables.h" +#include "acnamesp.h" +#include "acinterp.h" +#include "actables.h" #define _COMPONENT TABLE_MANAGER - MODULE_NAME ("tbxface"); + MODULE_NAME ("tbxface") /******************************************************************************* @@ -57,7 +57,7 @@ /* Get the RSDT first */ status = acpi_tb_get_table_rsdt (&number_of_tables); - if (status != AE_OK) { + if (ACPI_FAILURE (status)) { goto error_exit; } @@ -65,7 +65,7 @@ /* Now get the rest of the tables */ status = acpi_tb_get_all_tables (number_of_tables, NULL); - if (status != AE_OK) { + if (ACPI_FAILURE (status)) { goto error_exit; } @@ -105,12 +105,12 @@ if (!table_ptr) { - return AE_BAD_PARAMETER; + return (AE_BAD_PARAMETER); } /* Copy the table to a local buffer */ - status = acpi_tb_get_table (NULL, ((char *) table_ptr), &table_info); + status = acpi_tb_get_table (NULL, table_ptr, &table_info); if (ACPI_FAILURE (status)) { return (status); } @@ -157,7 +157,12 @@ list_head = &acpi_gbl_acpi_tables[table_type]; do { - /* Delete the entire namespace under this table NTE */ + /* + * Delete all namespace entries owned by this table. Note that these + * entries can appear anywhere in the namespace by virtue of the AML + * "Scope" operator. Thus, we need to track ownership by an ID, not + * simply a position within the hierarchy + */ acpi_ns_delete_namespace_by_owner (list_head->table_id); @@ -205,8 +210,6 @@ ACPI_STATUS status; - status = AE_OK; - if ((instance == 0) || (table_type == ACPI_TABLE_RSDP) || (!out_table_header)) @@ -217,7 +220,7 @@ /* Check the table type and instance */ if ((table_type > ACPI_TABLE_MAX) || - (acpi_gbl_acpi_table_data[table_type].flags == ACPI_TABLE_SINGLE && + (IS_SINGLE_TABLE (acpi_gbl_acpi_table_data[table_type].flags) && instance > 1)) { return (AE_BAD_PARAMETER); @@ -227,7 +230,7 @@ /* Get a pointer to the entire table */ status = acpi_tb_get_table_ptr (table_type, instance, &tbl_ptr); - if (status != AE_OK) { + if (ACPI_FAILURE (status)) { return (status); } @@ -285,8 +288,6 @@ u32 ret_buf_len; - status = AE_OK; - /* * Must have a buffer */ @@ -301,7 +302,7 @@ /* Check the table type and instance */ if ((table_type > ACPI_TABLE_MAX) || - (acpi_gbl_acpi_table_data[table_type].flags == ACPI_TABLE_SINGLE && + (IS_SINGLE_TABLE (acpi_gbl_acpi_table_data[table_type].flags) && instance > 1)) { return (AE_BAD_PARAMETER); @@ -311,12 +312,13 @@ /* Get a pointer to the entire table */ status = acpi_tb_get_table_ptr (table_type, instance, &tbl_ptr); - if (status != AE_OK) { + if (ACPI_FAILURE (status)) { return (status); } /* - * The function will return a NULL pointer if the table is not loaded + * Acpi_tb_get_table_ptr will return a NULL pointer if the + * table is not loaded. */ if (tbl_ptr == NULL) { return (AE_NOT_EXIST); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/acpi/tables.c linux/drivers/acpi/tables.c --- v2.4.0-test8/linux/drivers/acpi/tables.c Thu Jul 13 09:39:49 2000 +++ linux/drivers/acpi/tables.c Wed Dec 31 16:00:00 1969 @@ -1,303 +0,0 @@ -/* - * tables.c - ACPI tables, chipset, and errata handling - * - * Copyright (C) 2000 Andrew Henroid - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include "acpi.h" -#include "driver.h" - -struct acpi_facp acpi_facp; - -#define ACPI_DUMMY_CHECKSUM 9 -#define ACPI_DUMMY_PBLK 51 - -static u8 acpi_dummy_dsdt[] = -{ - 0x44, 0x53, 0x44, 0x54, // "DSDT" - 0x38, 0x00, 0x00, 0x00, // length - 0x01, // revision - 0x00, // checksum - 0x4c, 0x49, 0x4e, 0x55, 0x58, 0x00, // "LINUX" - 0x44, 0x55, 0x4d, 0x4d, 0x59, 0x00, 0x00, 0x00, // "DUMMY" - 0x01, 0x00, 0x00, 0x00, // OEM rev - 0x4c, 0x4e, 0x55, 0x58, // "LNUX" - 0x01, 0x00, 0x00, 0x00, // creator rev - 0x10, // Scope - 0x13, // PkgLength - 0x5c, 0x5f, 0x50, 0x52, 0x5f, // \_PR_ - 0x5b, 0x83, // Processor - 0x0b, // PkgLength - 0x43, 0x50, 0x55, 0x30, // CPU0 - 0x00, // ID - 0x00, 0x00, 0x00, 0x00, // PBLK - 0x06 // PBLK size -}; - -/* - * Calculate and set ACPI table checksum - */ -static void -acpi_set_checksum(u8 *table, int size) -{ - int i, sum = 0; - for (i = 0; i < size; i++) - sum += (int) table[i]; - sum = (0x100 - ((sum - table[ACPI_DUMMY_CHECKSUM]) & 0xff)); - table[ACPI_DUMMY_CHECKSUM] = sum; -} - -/* - * Init PIIX4 device, create a fake FACP - */ -static int -acpi_init_piix4(struct pci_dev *dev) -{ - u32 base, pblk; - u16 cmd; - u8 pmregmisc; - - pci_read_config_word(dev, PCI_COMMAND, &cmd); - if (!(cmd & PCI_COMMAND_IO)) - return -ENODEV; - - pci_read_config_byte(dev, ACPI_PIIX4_PMREGMISC, &pmregmisc); - if (!(pmregmisc & ACPI_PIIX4_PMIOSE)) - return -ENODEV; - - base = pci_resource_start (dev, PCI_BRIDGE_RESOURCES); - if (!base) - return -ENODEV; - - printk(KERN_INFO "ACPI: found \"%s\" at 0x%04x\n", dev->name, base); - - memset(&acpi_facp, 0, sizeof(acpi_facp)); - acpi_facp.hdr.signature = ACPI_FACP_SIG; - acpi_facp.hdr.length = sizeof(acpi_facp); - acpi_facp.int_model = ACPI_PIIX4_INT_MODEL; - acpi_facp.sci_int = ACPI_PIIX4_SCI_INT; - acpi_facp.smi_cmd = ACPI_PIIX4_SMI_CMD; - acpi_facp.acpi_enable = ACPI_PIIX4_ACPI_ENABLE; - acpi_facp.acpi_disable = ACPI_PIIX4_ACPI_DISABLE; - acpi_facp.s4bios_req = ACPI_PIIX4_S4BIOS_REQ; - acpi_facp.pm1a_evt = base + ACPI_PIIX4_PM1_EVT; - acpi_facp.pm1a_cnt = base + ACPI_PIIX4_PM1_CNT; - acpi_facp.pm2_cnt = ACPI_PIIX4_PM2_CNT; - acpi_facp.pm_tmr = base + ACPI_PIIX4_PM_TMR; - acpi_facp.gpe0 = base + ACPI_PIIX4_GPE0; - acpi_facp.pm1_evt_len = ACPI_PIIX4_PM1_EVT_LEN; - acpi_facp.pm1_cnt_len = ACPI_PIIX4_PM1_CNT_LEN; - acpi_facp.pm2_cnt_len = ACPI_PIIX4_PM2_CNT_LEN; - acpi_facp.pm_tm_len = ACPI_PIIX4_PM_TM_LEN; - acpi_facp.gpe0_len = ACPI_PIIX4_GPE0_LEN; - acpi_facp.p_lvl2_lat = (__u16) ACPI_INFINITE_LAT; - acpi_facp.p_lvl3_lat = (__u16) ACPI_INFINITE_LAT; - - acpi_set_checksum((u8*) &acpi_facp, sizeof(acpi_facp)); - acpi_load_table((ACPI_TABLE_HEADER*) &acpi_facp); - - pblk = base + ACPI_PIIX4_P_BLK; - memcpy(acpi_dummy_dsdt + ACPI_DUMMY_PBLK, &pblk, sizeof(pblk)); - acpi_set_checksum(acpi_dummy_dsdt, sizeof(acpi_dummy_dsdt)); - acpi_load_table((ACPI_TABLE_HEADER*) acpi_dummy_dsdt); - - return 0; -} - -/* - * Init VIA ACPI device and create a fake FACP - */ -static int -acpi_init_via(struct pci_dev *dev) -{ - u32 base, pblk; - u8 tmp, irq; - - pci_read_config_byte(dev, 0x41, &tmp); - if (!(tmp & 0x80)) - return -ENODEV; - - base = pci_resource_start(dev, PCI_BRIDGE_RESOURCES); - if (!base) { - base = pci_resource_start(dev, PCI_BASE_ADDRESS_4); - if (!base) - return -ENODEV; - } - - pci_read_config_byte(dev, 0x42, &irq); - - printk(KERN_INFO "ACPI: found \"%s\" at 0x%04x\n", dev->name, base); - - memset(&acpi_facp, 0, sizeof(acpi_facp)); - acpi_facp.hdr.signature = ACPI_FACP_SIG; - acpi_facp.hdr.length = sizeof(acpi_facp); - acpi_facp.int_model = ACPI_VIA_INT_MODEL; - acpi_facp.sci_int = irq; - acpi_facp.smi_cmd = base + ACPI_VIA_SMI_CMD; - acpi_facp.acpi_enable = ACPI_VIA_ACPI_ENABLE; - acpi_facp.acpi_disable = ACPI_VIA_ACPI_DISABLE; - acpi_facp.pm1a_evt = base + ACPI_VIA_PM1_EVT; - acpi_facp.pm1a_cnt = base + ACPI_VIA_PM1_CNT; - acpi_facp.pm_tmr = base + ACPI_VIA_PM_TMR; - acpi_facp.gpe0 = base + ACPI_VIA_GPE0; - - acpi_facp.pm1_evt_len = ACPI_VIA_PM1_EVT_LEN; - acpi_facp.pm1_cnt_len = ACPI_VIA_PM1_CNT_LEN; - acpi_facp.pm_tm_len = ACPI_VIA_PM_TM_LEN; - acpi_facp.gpe0_len = ACPI_VIA_GPE0_LEN; - acpi_facp.p_lvl2_lat = (__u16) ACPI_INFINITE_LAT; - acpi_facp.p_lvl3_lat = (__u16) ACPI_INFINITE_LAT; - - acpi_facp.duty_offset = ACPI_VIA_DUTY_OFFSET; - acpi_facp.duty_width = ACPI_VIA_DUTY_WIDTH; - - acpi_facp.day_alarm = ACPI_VIA_DAY_ALARM; - acpi_facp.mon_alarm = ACPI_VIA_MON_ALARM; - acpi_facp.century = ACPI_VIA_CENTURY; - - acpi_set_checksum((u8*) &acpi_facp, sizeof(acpi_facp)); - acpi_load_table((ACPI_TABLE_HEADER*) &acpi_facp); - - pblk = base + ACPI_VIA_P_BLK; - memcpy(acpi_dummy_dsdt + ACPI_DUMMY_PBLK, &pblk, sizeof(pblk)); - acpi_set_checksum(acpi_dummy_dsdt, sizeof(acpi_dummy_dsdt)); - acpi_load_table((ACPI_TABLE_HEADER*) acpi_dummy_dsdt); - - return 0; -} - -typedef enum -{ - CH_UNKNOWN = 0, - CH_INTEL_PIIX4, - CH_VIA_586, - CH_VIA_686A, -} acpi_chip_t; - -/* indexed by value of each enum in acpi_chip_t */ -const static struct -{ - int (*chip_init)(struct pci_dev *dev); -} acpi_chip_info[] = -{ - {NULL,}, - {acpi_init_piix4}, - {acpi_init_via}, - {acpi_init_via}, -}; - -static struct pci_device_id acpi_pci_tbl[] = -{ - {0x8086, 0x7113, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_INTEL_PIIX4}, - {0x1106, 0x3040, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_VIA_586}, - {0x1106, 0x3057, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_VIA_686A}, - {0,} /* terminate list */ -}; - -static int -acpi_probe(struct pci_dev *dev, const struct pci_device_id *id) -{ - return acpi_chip_info[id->driver_data].chip_init(dev); -} - -static struct pci_driver acpi_driver = -{ - name: "acpi", - id_table: acpi_pci_tbl, - probe: acpi_probe, -}; -static int acpi_driver_registered = 0; - -/* - * Locate a known ACPI chipset - */ -static int -acpi_find_chipset(void) -{ - if (pci_register_driver(&acpi_driver) < 1) - return -ENODEV; - acpi_driver_registered = 1; - return 0; -} - -/* - * Fetch the FACP information - */ -static int -acpi_fetch_facp(void) -{ - ACPI_BUFFER buffer; - - memset(&acpi_facp, 0, sizeof(acpi_facp)); - buffer.pointer = &acpi_facp; - buffer.length = sizeof(acpi_facp); - if (!ACPI_SUCCESS(acpi_get_table(ACPI_TABLE_FACP, 1, &buffer))) { - printk(KERN_ERR "ACPI: missing FACP\n"); - return -ENODEV; - } - - if (acpi_facp.p_lvl2_lat - && acpi_facp.p_lvl2_lat <= ACPI_MAX_P_LVL2_LAT) { - acpi_c2_exit_latency - = ACPI_uS_TO_TMR_TICKS(acpi_facp.p_lvl2_lat); - acpi_c2_enter_latency - = ACPI_uS_TO_TMR_TICKS(ACPI_TMR_HZ / 1000); - } - if (acpi_facp.p_lvl3_lat - && acpi_facp.p_lvl3_lat <= ACPI_MAX_P_LVL3_LAT) { - acpi_c3_exit_latency - = ACPI_uS_TO_TMR_TICKS(acpi_facp.p_lvl3_lat); - acpi_c3_enter_latency - = ACPI_uS_TO_TMR_TICKS(acpi_facp.p_lvl3_lat * 5); - } - - return 0; -} - -/* - * Find and load ACPI tables - */ -int -acpi_load_tables(void) -{ - if (ACPI_SUCCESS(acpi_load_firmware_tables())) - { - printk(KERN_INFO "ACPI: support found\n"); - } - else if (acpi_find_chipset()) { - acpi_terminate(); - return -1; - } - - if (acpi_fetch_facp()) { - acpi_terminate(); - return -1; - } - - if (!ACPI_SUCCESS(acpi_load_namespace())) { - printk(KERN_ERR "ACPI: namespace load failed\n"); - acpi_terminate(); - return -1; - } - - return 0; -} diff -u --recursive --new-file v2.4.0-test8/linux/drivers/block/Config.in linux/drivers/block/Config.in --- v2.4.0-test8/linux/drivers/block/Config.in Tue Jul 25 18:23:48 2000 +++ linux/drivers/block/Config.in Fri Sep 22 17:11:37 2000 @@ -34,25 +34,12 @@ source drivers/block/paride/Config.in fi dep_tristate 'Compaq SMART2 support' CONFIG_BLK_CPQ_DA $CONFIG_PCI +dep_tristate 'Compaq CISS Array support' CONFIG_BLK_CPQ_CISS_DA $CONFIG_PCI dep_tristate 'Mylex DAC960/DAC1100 PCI RAID Controller support' CONFIG_BLK_DEV_DAC960 $CONFIG_PCI tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP dep_tristate 'Network block device support' CONFIG_BLK_DEV_NBD $CONFIG_NET -tristate 'Logical volume manager (LVM) support' CONFIG_BLK_DEV_LVM N -if [ "$CONFIG_BLK_DEV_LVM" != "n" ]; then - bool ' LVM information in proc filesystem' CONFIG_LVM_PROC_FS Y -fi - -tristate 'Multiple devices driver support' CONFIG_BLK_DEV_MD -dep_tristate ' Linear (append) mode' CONFIG_MD_LINEAR $CONFIG_BLK_DEV_MD -dep_tristate ' RAID-0 (striping) mode' CONFIG_MD_RAID0 $CONFIG_BLK_DEV_MD -dep_tristate ' RAID-1 (mirroring) mode' CONFIG_MD_RAID1 $CONFIG_BLK_DEV_MD -dep_tristate ' RAID-4/RAID-5 mode' CONFIG_MD_RAID5 $CONFIG_BLK_DEV_MD -if [ "$CONFIG_MD_LINEAR" = "y" -o "$CONFIG_MD_RAID0" = "y" -o "$CONFIG_MD_RAID1" = "y" -o "$CONFIG_MD_RAID5" = "y" ]; then - bool ' Boot support' CONFIG_MD_BOOT - bool ' Auto Detect support' CONFIG_AUTODETECT_RAID -fi tristate 'RAM disk support' CONFIG_BLK_DEV_RAM if [ "$CONFIG_BLK_DEV_RAM" = "y" -o "$CONFIG_BLK_DEV_RAM" = "m" ]; then int ' Default RAM disk size' CONFIG_BLK_DEV_RAM_SIZE 4096 diff -u --recursive --new-file v2.4.0-test8/linux/drivers/block/Makefile linux/drivers/block/Makefile --- v2.4.0-test8/linux/drivers/block/Makefile Sun Aug 6 11:23:40 2000 +++ linux/drivers/block/Makefile Fri Sep 22 17:11:37 2000 @@ -14,9 +14,7 @@ O_TARGET := block.o -export-objs := ll_rw_blk.o blkpg.o loop.o DAC960.o md.o xor.o -list-multi := lvm-mod.o -lvm-mod-objs := lvm.o lvm-snap.o +export-objs := ll_rw_blk.o blkpg.o loop.o DAC960.o obj-y := ll_rw_blk.o blkpg.o genhd.o elevator.o @@ -33,14 +31,8 @@ obj-$(CONFIG_BLK_DEV_PS2) += ps2esdi.o obj-$(CONFIG_BLK_DEV_XD) += xd.o obj-$(CONFIG_BLK_CPQ_DA) += cpqarray.o +obj-$(CONFIG_BLK_CPQ_CISS_DA) += cciss.o obj-$(CONFIG_BLK_DEV_DAC960) += DAC960.o -obj-$(CONFIG_BLK_DEV_LVM) += lvm-mod.o - -obj-$(CONFIG_BLK_DEV_MD) += md.o -obj-$(CONFIG_MD_LINEAR) += linear.o -obj-$(CONFIG_MD_RAID0) += raid0.o -obj-$(CONFIG_MD_RAID1) += raid1.o -obj-$(CONFIG_MD_RAID5) += raid5.o xor.o obj-$(CONFIG_BLK_DEV_NBD) += nbd.o @@ -71,6 +63,3 @@ MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) include $(TOPDIR)/Rules.make - -lvm-mod.o: $(lvm-mod-objs) - $(LD) -r -o $@ $(lvm-mod-objs) diff -u --recursive --new-file v2.4.0-test8/linux/drivers/block/amiflop.c linux/drivers/block/amiflop.c --- v2.4.0-test8/linux/drivers/block/amiflop.c Tue Jun 20 07:24:52 2000 +++ linux/drivers/block/amiflop.c Sun Oct 1 20:35:15 2000 @@ -140,7 +140,7 @@ /* defaults for 3 1/2" HD-Disks */ static int floppy_sizes[256]={880,880,880,880,720,720,720,720,}; -static int floppy_blocksizes[256]={0,}; +static int floppy_blocksizes[256]; /* hardsector size assumed to be 512 */ static int amiga_read(int), dos_read(int); @@ -151,7 +151,7 @@ }; /* current info on each unit */ -static struct amiga_floppy_struct unit[FD_MAX_UNITS] = {{ 0,}}; +static struct amiga_floppy_struct unit[FD_MAX_UNITS]; static struct timer_list flush_track_timer[FD_MAX_UNITS]; static struct timer_list post_write_timer; @@ -162,15 +162,15 @@ /* Synchronization of FDC access */ /* request loop (trackbuffer) */ static volatile int fdc_busy = -1; -static volatile int fdc_nested = 0; +static volatile int fdc_nested; static DECLARE_WAIT_QUEUE_HEAD(fdc_wait); static DECLARE_WAIT_QUEUE_HEAD(motor_wait); static volatile int selected = -1; /* currently selected drive */ -static int writepending = 0; -static int writefromint = 0; +static int writepending; +static int writefromint; static char *raw_buf; #define RAW_BUF_SIZE 30000 /* size of raw disk data */ @@ -180,7 +180,7 @@ * information to interrupts. They are the data used for the current * request. */ -static volatile char block_flag = 0; +static volatile char block_flag; static DECLARE_WAIT_QUEUE_HEAD(wait_fd_block); /* MS-Dos MFM Coding tables (should go quick and easy) */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/block/cciss.c linux/drivers/block/cciss.c --- v2.4.0-test8/linux/drivers/block/cciss.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/block/cciss.c Wed Sep 27 13:39:23 2000 @@ -0,0 +1,1917 @@ +/* + * Disk Array driver for Compaq SMART2 Controllers + * Copyright 2000 Compaq Computer Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Questions/Comments/Bugfixes to arrays@compaq.com + * + */ + +#include /* CONFIG_PROC_FS */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin)) +#define DRIVER_NAME "Compaq CISS Driver (v 2.4.0)" +#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,4,0) + +/* Embedded module documentation macros - see modules.h */ +MODULE_AUTHOR("Charles M. White III - Compaq Computer Corporation"); +MODULE_DESCRIPTION("Driver for Compaq Smart Array Controller 5300"); + +#include "cciss_cmd.h" +#include "cciss.h" +#include + +#define NR_PRODUCTS (sizeof(products)/sizeof(struct board_type)) + +/* board_id = Subsystem Device ID & Vendor ID + * product = Marketing Name for the board + * access = Address of the struct of function pointers + */ +static struct board_type products[] = { + { 0x40700E11, "Smart Array 5300", &SA5_access }, +}; + +/* How long to wait (in millesconds) for board to go into simple mode */ +#define MAX_CONFIG_WAIT 1000 + +#define READ_AHEAD 128 +#define NR_CMDS 128 /* #commands that can be outstanding */ +#define MAX_CTLR 8 +static int nr_ctlr =0; +static ctlr_info_t *hba[MAX_CTLR] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + +static struct proc_dir_entry *proc_cciss = NULL; + +static void do_cciss_request(int i); +/* + * This is a hack. This driver eats a major number for each controller, and + * sets blkdev[xxx].request_fn to each one of these so the real request + * function knows what controller its working with. + */ +#define DO_CCISS_REQUEST(x) { do_cciss_request(x); } + +static void do_cciss_request0(request_queue_t * q) DO_CCISS_REQUEST(0); +static void do_cciss_request1(request_queue_t * q) DO_CCISS_REQUEST(1); +static void do_cciss_request2(request_queue_t * q) DO_CCISS_REQUEST(2); +static void do_cciss_request3(request_queue_t * q) DO_CCISS_REQUEST(3); +static void do_cciss_request4(request_queue_t * q) DO_CCISS_REQUEST(4); +static void do_cciss_request5(request_queue_t * q) DO_CCISS_REQUEST(5); +static void do_cciss_request6(request_queue_t * q) DO_CCISS_REQUEST(6); +static void do_cciss_request7(request_queue_t * q) DO_CCISS_REQUEST(7); + +static int cciss_open(struct inode *inode, struct file *filep); +static int cciss_release(struct inode *inode, struct file *filep); +static int cciss_ioctl(struct inode *inode, struct file *filep, + unsigned int cmd, unsigned long arg); + +static int revalidate_allvol(kdev_t dev); +static int revalidate_logvol(kdev_t dev, int maxusage); +static int frevalidate_logvol(kdev_t dev); + +static void cciss_getgeometry(int cntl_num); + +static inline void addQ(CommandList_struct **Qptr, CommandList_struct *c); +static void start_io( ctlr_info_t *h); + +#ifdef CONFIG_PROC_FS +static int cciss_proc_get_info(char *buffer, char **start, off_t offset, + int length, int *eof, void *data); +static void cciss_procinit(int i); +#else +static int cciss_proc_get_info(char *buffer, char **start, off_t offset, + int length, int *eof, void *data) {} +static void cciss_procinit(int i) {} +#endif /* CONFIG_PROC_FS */ + +static struct block_device_operations cciss_fops = { + open: cciss_open, + release: cciss_release, + ioctl: cciss_ioctl, + revalidate: frevalidate_logvol, +}; + +/* + * Report information about this controller. + */ +#ifdef CONFIG_PROC_FS +static int cciss_proc_get_info(char *buffer, char **start, off_t offset, + int length, int *eof, void *data) +{ + off_t pos = 0; + off_t len = 0; + int size, i, ctlr; + ctlr_info_t *h = (ctlr_info_t*)data; + drive_info_struct *drv; + + ctlr = h->ctlr; + size = sprintf(buffer, "%s: Compaq %s Controller\n" + " Board ID: %08lx\n" + " Firmware Version: %c%c%c%c\n" + " Memory Address: %08lx\n" + " IRQ: 0x%x\n" + " Logical drives: %d\n" + " Current Q depth: %d\n" + " Current # commands on controller %d\n" + " Max Q depth since init: %d\n" + " Max # commands on controller since init: %d\n" + " Max SG entries since init: %d\n\n", + h->devname, + h->product_name, + (unsigned long)h->board_id, + h->firm_ver[0], h->firm_ver[1], h->firm_ver[2], h->firm_ver[3], + (unsigned long)h->vaddr, + (unsigned int)h->intr, + h->num_luns, + h->Qdepth, h->commands_outstanding, + h->maxQsinceinit, h->max_outstanding, h->maxSG); + + pos += size; len += size; + for(i=0; inum_luns; i++) { + drv = &h->drv[i]; + size = sprintf(buffer+len, "cciss/c%dd%d: blksz=%d nr_blocks=%d\n", + ctlr, i, drv->block_size, drv->nr_blocks); + pos += size; len += size; + } + + size = sprintf(buffer+len, "nr_allocs = %d\nnr_frees = %d\n", + h->nr_allocs, h->nr_frees); + pos += size; len += size; + + *eof = 1; + *start = buffer+offset; + len -= offset; + if (len>length) + len = length; + return len; +} + +/* + * Get us a file in /proc/cciss that says something about each controller. + * Create /proc/cciss if it doesn't exist yet. + */ +static void __init cciss_procinit(int i) +{ + if (proc_cciss == NULL) { + proc_cciss = proc_mkdir("driver/cciss", NULL); + if (!proc_cciss) + return; + } + + create_proc_read_entry(hba[i]->devname, 0, proc_cciss, + cciss_proc_get_info, hba[i]); +} +#endif /* CONFIG_PROC_FS */ + +/* + * For operations that cannot sleep, a command block is allocated at init, + * and managed by cmd_alloc() and cmd_free() using a simple bitmap to track + * which ones are free or in use. For operations that can wait for kmalloc + * to possible sleep, this routine can be called with a NULL pointer. + * cmd_free() MUST be called with a NULL pointer if cmd_alloc was. + */ +static CommandList_struct * cmd_alloc(ctlr_info_t *h) +{ + CommandList_struct *c; + int i; + u64bit temp64; + + if (h == NULL) + { + c = (CommandList_struct *)kmalloc(sizeof(CommandList_struct), + GFP_KERNEL); + if(c==NULL) + return NULL; + memset(c, 0, sizeof(CommandList_struct)); + + c->err_info = (ErrorInfo_struct *)kmalloc( + sizeof(ErrorInfo_struct), GFP_KERNEL); + + if (c->err_info == NULL) + { + kfree(c); + return NULL; + } + memset(c->err_info, 0, sizeof(ErrorInfo_struct)); + } else /* get it out of the controllers pool */ + { + do { + i = find_first_zero_bit(h->cmd_pool_bits, NR_CMDS); + if (i == NR_CMDS) + return NULL; + } while(test_and_set_bit(i%32, h->cmd_pool_bits+(i/32)) != 0); +#ifdef CCISS_DEBUG + printk(KERN_DEBUG "cciss: using command buffer %d\n", i); +#endif + c = h->cmd_pool + i; + memset(c, 0, sizeof(CommandList_struct)); + c->err_info = h->errinfo_pool + i; + memset(c->err_info, 0, sizeof(ErrorInfo_struct)); + h->nr_allocs++; + } + + + temp64.val = (__u64) virt_to_bus(c->err_info); + c->ErrDesc.Addr.lower = temp64.val32.lower; + c->ErrDesc.Addr.upper = temp64.val32.upper; + c->ErrDesc.Len = sizeof(ErrorInfo_struct); + c->busaddr = virt_to_bus(c); + return c; + + +} + +/* + * Frees a command block that was previously allocated with cmd_alloc(). + */ +static void cmd_free(ctlr_info_t *h, CommandList_struct *c) +{ + int i; + + if( h == NULL) + { + kfree(c->err_info); + kfree(c); + } else + { + i = c - h->cmd_pool; + clear_bit(i%32, h->cmd_pool_bits+(i/32)); + h->nr_frees++; + } +} + +/* + * fills in the disk information. + */ +static void cciss_geninit( int ctlr) +{ + drive_info_struct *drv; + int i,j; + + /* Loop through each real device */ + hba[ctlr]->gendisk.nr_real = 0; + for(i=0; i< NWD; i++) + { + drv = &(hba[ctlr]->drv[i]); + if( !(drv->nr_blocks)) + continue; + hba[ctlr]->hd[i << NWD_SHIFT].nr_sects = + hba[ctlr]->sizes[i << NWD_SHIFT] = drv->nr_blocks; + + /* for each partition */ + for(j=0; jblocksizes[(i<hardsizes[ (i<block_size; + } + hba[ctlr]->gendisk.nr_real++; + } +} +/* + * Open. Make sure the device is really there. + */ +static int cciss_open(struct inode *inode, struct file *filep) +{ + int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR; + int dsk = MINOR(inode->i_rdev) >> NWD_SHIFT; + +#ifdef CCISS_DEBUG + printk(KERN_DEBUG "cciss_open %x (%x:%x)\n", inode->i_rdev, ctlr, dsk); +#endif /* CCISS_DEBUG */ + + if (ctlr > MAX_CTLR || hba[ctlr] == NULL) + return -ENXIO; + + if (!suser() && hba[ctlr]->sizes[ MINOR(inode->i_rdev)] == 0) + return -ENXIO; + + /* + * Root is allowed to open raw volume zero even if its not configured + * so array config can still work. I don't think I really like this, + * but I'm already using way to many device nodes to claim another one + * for "raw controller". + */ + if (suser() + && (hba[ctlr]->sizes[MINOR(inode->i_rdev)] == 0) + && (MINOR(inode->i_rdev)!= 0)) + return -ENXIO; + + hba[ctlr]->drv[dsk].usage_count++; + hba[ctlr]->usage_count++; + MOD_INC_USE_COUNT; + return 0; +} +/* + * Close. Sync first. + */ +static int cciss_release(struct inode *inode, struct file *filep) +{ + int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR; + int dsk = MINOR(inode->i_rdev) >> NWD_SHIFT; + +#ifdef CCISS_DEBUG + printk(KERN_DEBUG "cciss_release %x (%x:%x)\n", inode->i_rdev, ctlr, dsk); +#endif /* CCISS_DEBUG */ + + /* fsync_dev(inode->i_rdev); */ + + hba[ctlr]->drv[dsk].usage_count--; + hba[ctlr]->usage_count--; + MOD_DEC_USE_COUNT; + return 0; +} + +/* + * ioctl + */ +static int cciss_ioctl(struct inode *inode, struct file *filep, + unsigned int cmd, unsigned long arg) +{ + int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR; + int dsk = MINOR(inode->i_rdev) >> NWD_SHIFT; + int diskinfo[4]; + struct hd_geometry *geo = (struct hd_geometry *)arg; + +#ifdef CCISS_DEBUG + printk(KERN_DEBUG "cciss_ioctl: Called with cmd=%x %lx\n", cmd, arg); +#endif /* CCISS_DEBUG */ + + switch(cmd) { + case HDIO_GETGEO: + if (hba[ctlr]->drv[dsk].cylinders) { + diskinfo[0] = hba[ctlr]->drv[dsk].heads; + diskinfo[1] = hba[ctlr]->drv[dsk].sectors; + diskinfo[2] = hba[ctlr]->drv[dsk].cylinders; + } else { + diskinfo[0] = 0xff; + diskinfo[1] = 0x3f; + diskinfo[2] = hba[ctlr]->drv[dsk].nr_blocks / (0xff*0x3f); } + put_user(diskinfo[0], &geo->heads); + put_user(diskinfo[1], &geo->sectors); + put_user(diskinfo[2], &geo->cylinders); + put_user(hba[ctlr]->hd[MINOR(inode->i_rdev)].start_sect, &geo->start); + return 0; + case BLKGETSIZE: + if (!arg) return -EINVAL; + put_user(hba[ctlr]->hd[MINOR(inode->i_rdev)].nr_sects, (long*)arg); + return 0; + case BLKRRPART: + return revalidate_logvol(inode->i_rdev, 1); + case BLKFLSBUF: + case BLKROSET: + case BLKROGET: + case BLKRASET: + case BLKRAGET: + case BLKPG: + return( blk_ioctl(inode->i_rdev, cmd, arg)); + case CCISS_GETPCIINFO: + { + cciss_pci_info_struct pciinfo; + + if (!arg) return -EINVAL; + pciinfo.bus = hba[ctlr]->pci_bus; + pciinfo.dev_fn = hba[ctlr]->pci_dev_fn; + pciinfo.board_id = hba[ctlr]->board_id; + if (copy_to_user((void *) arg, &pciinfo, sizeof( cciss_pci_info_struct ))) + return -EFAULT; + return(0); + } + case CCISS_GETINTINFO: + { + cciss_coalint_struct intinfo; + ctlr_info_t *c = hba[ctlr]; + + if (!arg) return -EINVAL; + intinfo.delay = readl(&c->cfgtable->HostWrite.CoalIntDelay); + intinfo.count = readl(&c->cfgtable->HostWrite.CoalIntCount); + if (copy_to_user((void *) arg, &intinfo, sizeof( cciss_coalint_struct ))) + return -EFAULT; + return(0); + } + case CCISS_SETINTINFO: + { + cciss_coalint_struct intinfo; + ctlr_info_t *c = hba[ctlr]; + unsigned long flags; + int i; + + if (!arg) return -EINVAL; + if (!capable(CAP_SYS_ADMIN)) return -EPERM; + if (copy_from_user(&intinfo, (void *) arg, sizeof( cciss_coalint_struct))) + return -EFAULT; + if ( (intinfo.delay == 0 ) && (intinfo.count == 0)) + + { +// printk("cciss_ioctl: delay and count cannot be 0\n"); + return( -EINVAL); + } + spin_lock_irqsave(&io_request_lock, flags); + /* Can only safely update if no commands outstanding */ + if (c->commands_outstanding > 0 ) + { +// printk("cciss_ioctl: cannot change coalasing " +// "%d commands outstanding on controller\n", +// c->commands_outstanding); + spin_unlock_irqrestore(&io_request_lock, flags); + return(-EINVAL); + } + /* Update the field, and then ring the doorbell */ + writel( intinfo.delay, + &(c->cfgtable->HostWrite.CoalIntDelay)); + writel( intinfo.count, + &(c->cfgtable->HostWrite.CoalIntCount)); + writel( CFGTBL_ChangeReq, c->vaddr + SA5_DOORBELL); + + for(i=0;ivaddr + SA5_DOORBELL) + & CFGTBL_ChangeReq)) + break; + /* delay and try again */ + udelay(1000); + } + spin_unlock_irqrestore(&io_request_lock, flags); + if (i >= MAX_CONFIG_WAIT) + return( -EFAULT); + return(0); + } + case CCISS_GETNODENAME: + { + NodeName_type NodeName; + ctlr_info_t *c = hba[ctlr]; + int i; + + if (!arg) return -EINVAL; + for(i=0;i<16;i++) + NodeName[i] = readb(&c->cfgtable->ServerName[i]); + if (copy_to_user((void *) arg, NodeName, sizeof( NodeName_type))) + return -EFAULT; + return(0); + } + case CCISS_SETNODENAME: + { + NodeName_type NodeName; + ctlr_info_t *c = hba[ctlr]; + unsigned long flags; + int i; + + if (!arg) return -EINVAL; + if (!capable(CAP_SYS_ADMIN)) return -EPERM; + + if (copy_from_user(NodeName, (void *) arg, sizeof( NodeName_type))) + return -EFAULT; + + spin_lock_irqsave(&io_request_lock, flags); + + /* Update the field, and then ring the doorbell */ + for(i=0;i<16;i++) + writeb( NodeName[i], &c->cfgtable->ServerName[i]); + + writel( CFGTBL_ChangeReq, c->vaddr + SA5_DOORBELL); + + for(i=0;ivaddr + SA5_DOORBELL) + & CFGTBL_ChangeReq)) + break; + /* delay and try again */ + udelay(1000); + } + spin_unlock_irqrestore(&io_request_lock, flags); + if (i >= MAX_CONFIG_WAIT) + return( -EFAULT); + return(0); + } + + case CCISS_GETHEARTBEAT: + { + Heartbeat_type heartbeat; + ctlr_info_t *c = hba[ctlr]; + + if (!arg) return -EINVAL; + heartbeat = readl(&c->cfgtable->HeartBeat); + if (copy_to_user((void *) arg, &heartbeat, sizeof( Heartbeat_type))) + return -EFAULT; + return(0); + } + case CCISS_GETBUSTYPES: + { + BusTypes_type BusTypes; + ctlr_info_t *c = hba[ctlr]; + + if (!arg) return -EINVAL; + BusTypes = readl(&c->cfgtable->BusTypes); + if (copy_to_user((void *) arg, &BusTypes, sizeof( BusTypes_type) )) + return -EFAULT; + return(0); + } + case CCISS_GETFIRMVER: + { + FirmwareVer_type firmware; + + if (!arg) return -EINVAL; + memcpy(firmware, hba[ctlr]->firm_ver, 4); + + if (copy_to_user((void *) arg, firmware, sizeof( FirmwareVer_type))) + return -EFAULT; + return(0); + } + case CCISS_GETDRIVVER: + { + DriverVer_type DriverVer = DRIVER_VERSION; + + if (!arg) return -EINVAL; + + if (copy_to_user((void *) arg, &DriverVer, sizeof( DriverVer_type) )) + return -EFAULT; + return(0); + } + + case CCISS_REVALIDVOLS: + return( revalidate_allvol(inode->i_rdev)); + + case CCISS_PASSTHRU: + { + IOCTL_Command_struct iocommand; + ctlr_info_t *h = hba[ctlr]; + CommandList_struct *c; + char *buff = NULL; + u64bit temp64; + unsigned long flags; + + if (!arg) return -EINVAL; + + if (!capable(CAP_SYS_RAWIO)) return -EPERM; + + if (copy_from_user(&iocommand, (void *) arg, sizeof( IOCTL_Command_struct) )) + return -EFAULT; + if((iocommand.buf_size < 1) && + (iocommand.Request.Type.Direction != XFER_NONE)) + { + return -EINVAL; + } + /* Check kmalloc limits */ + if(iocommand.buf_size > 128000) + return -EINVAL; + if(iocommand.buf_size > 0) + { + buff = kmalloc(iocommand.buf_size, GFP_KERNEL); + if( buff == NULL) + return -EFAULT; + } + if (iocommand.Request.Type.Direction == XFER_WRITE) + { + /* Copy the data into the buffer we created */ + if (copy_from_user(buff, iocommand.buf, iocommand.buf_size)) + return -EFAULT; + } + if ((c = cmd_alloc(NULL)) == NULL) + { + if(buff!=NULL) + kfree(buff); + return -ENOMEM; + } + // Fill in the command type + c->cmd_type = CMD_IOCTL_PEND; + // Fill in Command Header + c->Header.ReplyQueue = 0; // unused in simple mode + if( iocommand.buf_size > 0) // buffer to fill + { + c->Header.SGList = 1; + c->Header.SGTotal= 1; + } else // no buffers to fill + { + c->Header.SGList = 0; + c->Header.SGTotal= 0; + } + c->Header.LUN = iocommand.LUN_info; + c->Header.Tag.lower = c->busaddr; // use the kernel address the cmd block for tag + + // Fill in Request block + c->Request = iocommand.Request; + + // Fill in the scatter gather information + if (iocommand.buf_size > 0 ) + { + temp64.val = (__u64) virt_to_bus(buff); + c->SG[0].Addr.lower = temp64.val32.lower; + c->SG[0].Addr.upper = temp64.val32.upper; + c->SG[0].Len = iocommand.buf_size; + c->SG[0].Ext = 0; // we are not chaining + } + /* Put the request on the tail of the request queue */ + spin_lock_irqsave(&io_request_lock, flags); + addQ(&h->reqQ, c); + h->Qdepth++; + start_io(h); + spin_unlock_irqrestore(&io_request_lock, flags); + + /* Wait for completion */ + while(c->cmd_type != CMD_IOCTL_DONE) + schedule_timeout(1); + + /* Copy the error information out */ + iocommand.error_info = *(c->err_info); + if ( copy_to_user((void *) arg, &iocommand, sizeof( IOCTL_Command_struct) ) ) + { + cmd_free(NULL, c); + if (buff != NULL) + kfree(buff); + return( -EFAULT); + } + + if (iocommand.Request.Type.Direction == XFER_READ) + { + /* Copy the data out of the buffer we created */ + if (copy_to_user(iocommand.buf, buff, iocommand.buf_size)) + { + cmd_free(NULL, c); + kfree(buff); + } + } + cmd_free(NULL, c); + if (buff != NULL) + kfree(buff); + return(0); + } + + default: + return -EBADRQC; + } + +} + +/* Borrowed and adapted from sd.c */ +static int revalidate_logvol(kdev_t dev, int maxusage) +{ + int ctlr, target; + struct gendisk *gdev; + unsigned long flags; + int max_p; + int start; + int i; + + target = MINOR(dev) >> NWD_SHIFT; + ctlr = MAJOR(dev) - MAJOR_NR; + gdev = &(hba[ctlr]->gendisk); + + spin_lock_irqsave(&io_request_lock, flags); + if (hba[ctlr]->drv[target].usage_count > maxusage) { + spin_unlock_irqrestore(&io_request_lock, flags); + printk(KERN_WARNING "cpqarray: Device busy for " + "revalidation (usage=%d)\n", + hba[ctlr]->drv[target].usage_count); + return -EBUSY; + } + hba[ctlr]->drv[target].usage_count++; + spin_unlock_irqrestore(&io_request_lock, flags); + + max_p = gdev->max_p; + start = target << gdev->minor_shift; + + for(i=max_p; i>=0; i--) { + int minor = start+i; + kdev_t devi = MKDEV(MAJOR_NR + ctlr, minor); + struct super_block *sb = get_super(devi); + sync_dev(devi); + if (sb) invalidate_inodes(sb); + invalidate_buffers(devi); + gdev->part[minor].start_sect = 0; + gdev->part[minor].nr_sects = 0; + + /* reset the blocksize so we can read the partition table */ + blksize_size[MAJOR_NR+ctlr][minor] = 1024; + } + /* setup partitions per disk */ + grok_partitions(gdev, target, MAX_PART, + hba[ctlr]->drv[target].nr_blocks); + hba[ctlr]->drv[target].usage_count--; + return 0; +} + +static int frevalidate_logvol(kdev_t dev) +{ +#ifdef CCISS_DEBUG + printk(KERN_DEBUG "cciss: frevalidate has been called\n"); +#endif /* CCISS_DEBUG */ + return revalidate_logvol(dev, 0); +} + +/* + * revalidate_allvol is for online array config utilities. After a + * utility reconfigures the drives in the array, it can use this function + * (through an ioctl) to make the driver zap any previous disk structs for + * that controller and get new ones. + * + * Right now I'm using the getgeometry() function to do this, but this + * function should probably be finer grained and allow you to revalidate one + * particualar logical volume (instead of all of them on a particular + * controller). + */ +static int revalidate_allvol(kdev_t dev) +{ + int ctlr, i; + unsigned long flags; + + ctlr = MAJOR(dev) - MAJOR_NR; + if (MINOR(dev) != 0) + return -ENXIO; + + spin_lock_irqsave(&io_request_lock, flags); + if (hba[ctlr]->usage_count > 1) { + spin_unlock_irqrestore(&io_request_lock, flags); + printk(KERN_WARNING "cciss: Device busy for volume" + " revalidation (usage=%d)\n", hba[ctlr]->usage_count); + return -EBUSY; + } + spin_unlock_irqrestore(&io_request_lock, flags); + hba[ctlr]->usage_count++; + + /* + * Set the partition and block size structures for all volumes + * on this controller to zero. We will reread all of this data + */ + memset(hba[ctlr]->hd, 0, sizeof(struct hd_struct) * 256); + memset(hba[ctlr]->sizes, 0, sizeof(int) * 256); + memset(hba[ctlr]->blocksizes, 0, sizeof(int) * 256); + memset(hba[ctlr]->hardsizes, 0, sizeof(int) * 256); + memset(hba[ctlr]->drv, 0, sizeof(drive_info_struct) + * CISS_MAX_LUN); + hba[ctlr]->gendisk.nr_real = 0; + + /* + * Tell the array controller not to give us any interupts while + * we check the new geometry. Then turn interrupts back on when + * we're done. + */ + hba[ctlr]->access.set_intr_mask(hba[ctlr], CCISS_INTR_OFF); + cciss_getgeometry(ctlr); + hba[ctlr]->access.set_intr_mask(hba[ctlr], CCISS_INTR_ON); + + cciss_geninit(ctlr); + for(i=0; isizes[ i<usage_count--; + return 0; +} + + + +/* + * Wait polling for a command to complete. + * The memory mapped FIFO is polled for the completion. + * Used only at init time, interrupts disabled. + */ +static unsigned long pollcomplete(int ctlr) +{ + unsigned long done; + int i; + + /* Wait (up to 2 seconds) for a command to complete */ + + for (i = 200000; i > 0; i--) { + done = hba[ctlr]->access.command_completed(hba[ctlr]); + if (done == FIFO_EMPTY) { + udelay(10); /* a short fixed delay */ + } else + return (done); + } + /* Invalid address to tell caller we ran out of time */ + return 1; +} +/* + * Send a command to the controller, and wait for it to complete. + * Only used at init time. + */ +static int sendcmd( + __u8 cmd, + int ctlr, + void *buff, + size_t size, + unsigned int use_unit_num, + unsigned int log_unit, + __u8 page_code ) +{ + CommandList_struct *c; + int i; + unsigned long complete; + ctlr_info_t *info_p= hba[ctlr]; + u64bit temp64; + + c = cmd_alloc(info_p); + if (c == NULL) + { + printk(KERN_WARNING "cciss: unable to get memory"); + return(IO_ERROR); + } + // Fill in Command Header + c->Header.ReplyQueue = 0; // unused in simple mode + if( buff != NULL) // buffer to fill + { + c->Header.SGList = 1; + c->Header.SGTotal= 1; + } else // no buffers to fill + { + c->Header.SGList = 0; + c->Header.SGTotal= 0; + } + c->Header.Tag.lower = c->busaddr; // use the kernel address the cmd block for tag + // Fill in Request block + switch(cmd) + { + case CISS_INQUIRY: + /* If the logical unit number is 0 then, this is going + to controller so It's a physical command + mode = 0 target = 0. + So we have nothing to write. + Otherwise + mode = 1 target = LUNID + */ + if(use_unit_num != 0) + { + c->Header.LUN.LogDev.VolId= + hba[ctlr]->drv[log_unit].LunID; + c->Header.LUN.LogDev.Mode = 1; + } + /* are we trying to read a vital product page */ + if(page_code != 0) + { + c->Request.CDB[1] = 0x01; + c->Request.CDB[2] = page_code; + } + c->Request.CDBLen = 6; + c->Request.Type.Type = TYPE_CMD; // It is a command. + c->Request.Type.Attribute = ATTR_SIMPLE; + c->Request.Type.Direction = XFER_READ; // Read + c->Request.Timeout = 0; // Don't time out + c->Request.CDB[0] = CISS_INQUIRY; + c->Request.CDB[4] = size & 0xFF; + break; + case CISS_REPORT_LOG: + /* Talking to controller so It's a physical command + mode = 00 target = 0. + So we have nothing to write. + */ + c->Request.CDBLen = 12; + c->Request.Type.Type = TYPE_CMD; // It is a command. + c->Request.Type.Attribute = ATTR_SIMPLE; + c->Request.Type.Direction = XFER_READ; // Read + c->Request.Timeout = 0; // Don't time out + c->Request.CDB[0] = CISS_REPORT_LOG; + c->Request.CDB[6] = (size >> 24) & 0xFF; //MSB + c->Request.CDB[7] = (size >> 16) & 0xFF; + c->Request.CDB[8] = (size >> 8) & 0xFF; + c->Request.CDB[9] = size & 0xFF; + break; + + case CCISS_READ_CAPACITY: + c->Header.LUN.LogDev.VolId= + hba[ctlr]->drv[log_unit].LunID; + c->Header.LUN.LogDev.Mode = 1; + c->Request.CDBLen = 10; + c->Request.Type.Type = TYPE_CMD; // It is a command. + c->Request.Type.Attribute = ATTR_SIMPLE; + c->Request.Type.Direction = XFER_READ; // Read + c->Request.Timeout = 0; // Don't time out + c->Request.CDB[0] = CCISS_READ_CAPACITY; + break; + default: + printk(KERN_WARNING + "cciss: Unknown Command 0x%c sent attempted\n", + cmd); + cmd_free(info_p, c); + return(IO_ERROR); + }; + // Fill in the scatter gather information + if (size > 0 ) + { + temp64.val = (__u64) virt_to_bus(buff); + c->SG[0].Addr.lower = temp64.val32.lower; + c->SG[0].Addr.upper = temp64.val32.upper; + c->SG[0].Len = size; + c->SG[0].Ext = 0; // we are not chaining + } + /* + * Disable interrupt + */ +#ifdef CCISS_DEBUG + printk(KERN_DEBUG "cciss: turning intr off\n"); +#endif /* CCISS_DEBUG */ + info_p->access.set_intr_mask(info_p, CCISS_INTR_OFF); + + /* Make sure there is room in the command FIFO */ + /* Actually it should be completely empty at this time. */ + for (i = 200000; i > 0; i--) + { + /* if fifo isn't full go */ + if (!(info_p->access.fifo_full(info_p))) + { + + break; + } + udelay(10); + printk(KERN_WARNING "cciss cciss%d: SendCmd FIFO full," + " waiting!\n", ctlr); + } + /* + * Send the cmd + */ + info_p->access.submit_command(info_p, c); + complete = pollcomplete(ctlr); + +#ifdef CCISS_DEBUG + printk(KERN_DEBUG "cciss: command completed\n"); +#endif /* CCISS_DEBUG */ + + if (complete != 1) { + if ( (complete & CISS_ERROR_BIT) + && (complete & ~CISS_ERROR_BIT) == c->busaddr) + { + /* if data overrun or underun on Report command + ignore it + */ + if (((c->Request.CDB[0] == CISS_REPORT_LOG) || + (c->Request.CDB[0] == CISS_INQUIRY)) && + ((c->err_info->CommandStatus == + CMD_DATA_OVERRUN) || + (c->err_info->CommandStatus == + CMD_DATA_UNDERRUN) + )) + { + complete = c->busaddr; + } else + { + printk(KERN_WARNING "ciss ciss%d: sendcmd" + " Error %x \n", ctlr, + c->err_info->CommandStatus); + printk(KERN_WARNING "ciss ciss%d: sendcmd" + " offensive info\n" + " size %x\n num %x value %x\n", ctlr, + c->err_info->MoreErrInfo.Invalid_Cmd.offense_size, + c->err_info->MoreErrInfo.Invalid_Cmd.offense_num, + c->err_info->MoreErrInfo.Invalid_Cmd.offense_value); + cmd_free(info_p,c); + return(IO_ERROR); + } + } + if (complete != c->busaddr) { + printk( KERN_WARNING "cciss cciss%d: SendCmd " + "Invalid command list address returned! (%lx)\n", + ctlr, complete); + cmd_free(info_p, c); + return (IO_ERROR); + } + } else { + printk( KERN_WARNING + "cciss cciss%d: SendCmd Timeout out, " + "No command list address returned!\n", + ctlr); + cmd_free(info_p, c); + return (IO_ERROR); + } + cmd_free(info_p, c); + return (IO_OK); +} +/* + * Map (physical) PCI mem into (virtual) kernel space + */ +static ulong remap_pci_mem(ulong base, ulong size) +{ + ulong page_base = ((ulong) base) & PAGE_MASK; + ulong page_offs = ((ulong) base) - page_base; + ulong page_remapped = (ulong) ioremap(page_base, page_offs+size); + + return (ulong) (page_remapped ? (page_remapped + page_offs) : 0UL); +} + +/* + * Enqueuing and dequeuing functions for cmdlists. + */ +static inline void addQ(CommandList_struct **Qptr, CommandList_struct *c) +{ + if (*Qptr == NULL) { + *Qptr = c; + c->next = c->prev = c; + } else { + c->prev = (*Qptr)->prev; + c->next = (*Qptr); + (*Qptr)->prev->next = c; + (*Qptr)->prev = c; + } +} + +static inline CommandList_struct *removeQ(CommandList_struct **Qptr, + CommandList_struct *c) +{ + if (c && c->next != c) { + if (*Qptr == c) *Qptr = c->next; + c->prev->next = c->next; + c->next->prev = c->prev; + } else { + *Qptr = NULL; + } + return c; +} + +/* + * Takes jobs of the Q and sends them to the hardware, then puts it on + * the Q to wait for completion. + */ +static void start_io( ctlr_info_t *h) +{ + CommandList_struct *c; + + while(( c = h->reqQ) != NULL ) + { + /* can't do anything if fifo is full */ + if ((h->access.fifo_full(h))) + { + printk(KERN_WARNING "cciss: fifo full \n"); + return; + } + /* Get the frist entry from the Request Q */ + removeQ(&(h->reqQ), c); + h->Qdepth--; + + /* Tell the controller execute command */ + h->access.submit_command(h, c); + + /* Put job onto the completed Q */ + addQ (&(h->cmpQ), c); + } +} + +static inline void complete_buffers( struct buffer_head *bh, int status) +{ + struct buffer_head *xbh; + + while(bh) + { + xbh = bh->b_reqnext; + bh->b_reqnext = NULL; + bh->b_end_io(bh, status); + bh = xbh; + } +} +/* checks the status of the job and calls complete buffers to mark all + * buffers for the completed job. + */ +static inline void complete_command( CommandList_struct *cmd, int timeout) +{ + int status = 1; + + if (timeout) + status = 0; + if(cmd->err_info->CommandStatus != 0) + { /* an error has occured */ + switch(cmd->err_info->CommandStatus) + { + case CMD_TARGET_STATUS: + printk(KERN_WARNING "cciss: cmd %p has " + " completed with errors\n", cmd); + if( cmd->err_info->ScsiStatus) + { + printk(KERN_WARNING "cciss: cmd %p " + "has SCSI Status = %x\n", + cmd, + cmd->err_info->ScsiStatus); + } + + break; + case CMD_DATA_UNDERRUN: + printk(KERN_WARNING "cciss: cmd %p has" + " completed with data underrun " + "reported\n", cmd); + break; + case CMD_DATA_OVERRUN: + printk(KERN_WARNING "cciss: cmd %p has" + " completed with data overrun " + "reported\n", cmd); + break; + case CMD_INVALID: + printk(KERN_WARNING "cciss: cmd %p is " + "reported invalid\n", cmd); + status = 0; + break; + case CMD_PROTOCOL_ERR: + printk(KERN_WARNING "cciss: cmd %p has " + "protocol error \n", cmd); + status = 0; + break; + case CMD_HARDWARE_ERR: + printk(KERN_WARNING "cciss: cmd %p had " + " hardware error\n", cmd); + status = 0; + break; + case CMD_CONNECTION_LOST: + printk(KERN_WARNING "cciss: cmd %p had " + "connection lost\n", cmd); + status=0; + break; + case CMD_ABORTED: + printk(KERN_WARNING "cciss: cmd %p was " + "aborted\n", cmd); + status=0; + break; + case CMD_ABORT_FAILED: + printk(KERN_WARNING "cciss: cmd %p reports " + "abort failed\n", cmd); + status=0; + break; + case CMD_UNSOLICITED_ABORT: + printk(KERN_WARNING "cciss: cmd %p aborted " + "do to an unsolicited abort\n", cmd); + status=0; + break; + case CMD_TIMEOUT: + printk(KERN_WARNING "cciss: cmd %p timedout\n", + cmd); + status=0; + break; + default: + printk(KERN_WARNING "cciss: cmd %p returned " + "unknown status %x\n", cmd, + cmd->err_info->CommandStatus); + status=0; + } + } + complete_buffers(cmd->bh, status); +} +/* + * Get a request and submit it to the controller. + * Currently we do one request at a time. Ideally we would like to send + * everything to the controller on the first call, but there is a danger + * of holding the io_request_lock for to long. + */ +static void do_cciss_request(int ctlr) +{ + ctlr_info_t *h= hba[ctlr]; + CommandList_struct *c; + int log_unit, start_blk, seg, sect; + char *lastdataend; + struct buffer_head *bh; + struct list_head *queue_head; + struct request *creq; + u64bit temp64; + + queue_head = &blk_dev[MAJOR_NR+ctlr].request_queue.queue_head; + if (list_empty(queue_head)) + { + /* nothing to do... */ + start_io(h); + return; + } + creq = blkdev_entry_next_request(queue_head); + if ((creq == NULL) || (creq->rq_status == RQ_INACTIVE)) + { + /* nothing to do... restart processing and return */ + start_io(h); + return; + } + if ((ctlr != (MAJOR(creq->rq_dev)-MAJOR_NR)) || (ctlr > nr_ctlr) + || (h == NULL)) + { +#ifdef CCISS_DEBUG + printk(KERN_WARNING "cciss: doreq cmd of %d, %x at %p\n", + ctlr, creq->rq_dev, creq); +#endif /* CCISS_DEBUG */ + complete_buffers(creq->bh, 0); + start_io(h); + return; + } + if (( c = cmd_alloc(h)) == NULL) + { + start_io(h); + return; + } + c->cmd_type = CMD_RWREQ; + bh = c->bh = creq->bh; + + /* fill in the request */ + log_unit = MINOR(creq->rq_dev) >> NWD_SHIFT; + c->Header.ReplyQueue = 0; // unused in simple mode + c->Header.Tag.lower = c->busaddr; // use the physical address the cmd block for tag + c->Header.LUN.LogDev.VolId= hba[ctlr]->drv[log_unit].LunID; + c->Header.LUN.LogDev.Mode = 1; + c->Request.CDBLen = 10; // 12 byte commands not in FW yet; + c->Request.Type.Type = TYPE_CMD; // It is a command. + c->Request.Type.Attribute = ATTR_SIMPLE; + c->Request.Type.Direction = + (creq->cmd == READ) ? XFER_READ: XFER_WRITE; + c->Request.Timeout = 0; // Don't time out + c->Request.CDB[0] = (creq->cmd == READ) ? CCISS_READ : CCISS_WRITE; + start_blk = hba[ctlr]->hd[MINOR(creq->rq_dev)].start_sect + creq->sector; + if (bh == NULL) + panic("cciss: bh== NULL?"); +#ifdef CCISS_DEBUG + printk(KERN_DEBUG "ciss: sector =%d nr_sectors=%d\n",(int) creq->sector, + (int) creq->nr_sectors); +#endif /* CCISS_DEBUG */ + seg = 0; + lastdataend = NULL; + sect = 0; + while(bh) + { + sect += bh->b_size/512; + if (bh->b_size % 512) + { + printk(KERN_CRIT "cciss: Oh Man. %d+%d, size=%d\n", + (int) creq->sector, sect, (int) bh->b_size); + panic("b_size 512 != 0\n"); + } + if (bh->b_data == lastdataend) + { // tack it on to the last segment + c->SG[seg-1].Len +=bh->b_size; + lastdataend += bh->b_size; + } else + { + c->SG[seg].Len = bh->b_size; + temp64.val = (__u64) virt_to_bus(bh->b_data); + c->SG[seg].Addr.lower = temp64.val32.lower; + c->SG[seg].Addr.upper = temp64.val32.upper; + c->SG[0].Ext = 0; // we are not chaining + lastdataend = bh->b_data + bh->b_size; + if( ++seg == MAXSGENTRIES) + { + break; + } + } + bh = bh->b_reqnext; + } + /* track how many SG entries we are using */ + if( seg > h->maxSG) + h->maxSG = seg; + + /* adjusting the remaining request, if any */ + creq-> sector+= sect; + creq->nr_sectors -= sect; + +#ifdef CCISS_DEBUG + printk(KERN_DEBUG "cciss: Submitting %d sectors in %d segments\n", sect, seg); +#endif /* CCISS_DEBUG */ + + c->Header.SGList = c->Header.SGTotal = seg; + c->Request.CDB[1]= 0; + c->Request.CDB[2]= (start_blk >> 24) & 0xff; //MSB + c->Request.CDB[3]= (start_blk >> 16) & 0xff; + c->Request.CDB[4]= (start_blk >> 8) & 0xff; + c->Request.CDB[5]= start_blk & 0xff; + c->Request.CDB[6]= 0; // (sect >> 24) & 0xff; MSB + // c->Request.CDB[7]= (sect >> 16) & 0xff; + c->Request.CDB[7]= (sect >> 8) & 0xff; + c->Request.CDB[8]= sect & 0xff; + c->Request.CDB[9] = c->Request.CDB[11] = c->Request.CDB[12] = 0; + + /* check to see if we going to complete the entire request */ + /* if so, mark this request as Done and ready the next one */ + if (creq->nr_sectors) + { +#ifdef CCISS_DEBUG + printk(KERN_DEBUG "cciss: More to do on the same request %p %ld\n", + creq, creq->nr_sectors); +#endif /* CCISS_DEBUG */ + + creq->bh = bh->b_reqnext; + bh->b_reqnext = NULL; + } else + { +#ifdef CCISS_DEBUG + printk("cciss: Done with %p, queueing %p\n", creq); +#endif /* CCISS_DEBUG */ + + blkdev_dequeue_request(creq); + end_that_request_last(creq); + } + addQ(&(h->reqQ),c); + h->Qdepth++; + if(h->Qdepth > h->maxQsinceinit) + h->maxQsinceinit = h->Qdepth; + start_io(h); +} + +static void do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + ctlr_info_t *h = dev_id; + CommandList_struct *c; + unsigned long flags; + __u32 a, a1; + + + /* Is this interrupt for us? */ + if ( h->access.intr_pending(h) == 0) + return; + + /* + * If there are completed commands in the completion queue, + * we had better do something about it. + */ + spin_lock_irqsave(&io_request_lock, flags); + while( h->access.intr_pending(h)) + { + while((a = h->access.command_completed(h)) != FIFO_EMPTY) + { + a1 = a; + a &= ~3; + if ((c = h->cmpQ) == NULL) + { + printk(KERN_WARNING "cpqarray: Completion of %08lx ignored\n", (unsigned long)a1); + continue; + } + while(c->busaddr != a) { + c = c->next; + if (c == h->cmpQ) + break; + } + /* + * If we've found the command, take it off the + * completion Q and free it + */ + if (c->busaddr == a) { + removeQ(&h->cmpQ, c); + if (c->cmd_type == CMD_RWREQ) { + complete_command(c, 0); + cmd_free(h, c); + } else if (c->cmd_type == CMD_IOCTL_PEND) { + c->cmd_type = CMD_IOCTL_DONE; + } + continue; + } + } + } + /* + * See if we can queue up some more IO + */ + do_cciss_request(h->ctlr); + spin_unlock_irqrestore(&io_request_lock, flags); +} +/* + * We cannot read the structure directly, for portablity we must use + * the io functions. + * This is for debug only. + */ +#ifdef CCISS_DEBUG +static void print_cfg_table( CfgTable_struct *tb) +{ + int i; + char temp_name[17]; + + printk("Controller Configuration information\n"); + printk("------------------------------------\n"); + for(i=0;i<4;i++) + temp_name[i] = readb(&(tb->Signature[i])); + temp_name[4]='\0'; + printk(" Signature = %s\n", temp_name); + printk(" Spec Number = %d\n", readl(&(tb->SpecValence))); + printk(" Transport methods supported = 0x%x\n", + readl(&(tb-> TransportSupport))); + printk(" Transport methods active = 0x%x\n", + readl(&(tb->TransportActive))); + printk(" Requested transport Method = 0x%x\n", + readl(&(tb->HostWrite.TransportRequest))); + printk(" Coalese Interrupt Delay = 0x%x\n", + readl(&(tb->HostWrite.CoalIntDelay))); + printk(" Coalese Interrupt Count = 0x%x\n", + readl(&(tb->HostWrite.CoalIntCount))); + printk(" Max outstanding commands = 0x%d\n", + readl(&(tb->CmdsOutMax))); + printk(" Bus Types = 0x%x\n", readl(&(tb-> BusTypes))); + for(i=0;i<16;i++) + temp_name[i] = readb(&(tb->ServerName[i])); + temp_name[16] = '\0'; + printk(" Server Name = %s\n", temp_name); + printk(" Heartbeat Counter = 0x%x\n\n\n", + readl(&(tb->HeartBeat))); +} +#endif /* CCISS_DEBUG */ + +static int cciss_pci_init(ctlr_info_t *c, unchar bus, unchar device_fn) +{ + ushort vendor_id, device_id, command; + unchar cache_line_size, latency_timer; + unchar irq, revision; + uint addr[6]; + __u32 board_id; + struct pci_dev *pdev; + + int i; + + pdev = pci_find_slot(bus, device_fn); + vendor_id = pdev->vendor; + device_id = pdev->device; + irq = pdev->irq; + + for(i=0; i<6; i++) + addr[i] = pdev->resource[i].start; + + if (pci_enable_device(pdev)) + return( -1); + + (void) pci_read_config_word(pdev, PCI_COMMAND,&command); + (void) pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); + (void) pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, + &cache_line_size); + (void) pci_read_config_byte(pdev, PCI_LATENCY_TIMER, + &latency_timer); + + (void) pci_read_config_dword(pdev, PCI_SUBSYSTEM_VENDOR_ID, + &board_id); + +#ifdef CCISS_DEBUG + printk("vendor_id = %x\n", vendor_id); + printk("device_id = %x\n", device_id); + printk("command = %x\n", command); + for(i=0; i<6; i++) + printk("addr[%d] = %x\n", i, addr[i]); + printk("revision = %x\n", revision); + printk("irq = %x\n", irq); + printk("cache_line_size = %x\n", cache_line_size); + printk("latency_timer = %x\n", latency_timer); + printk("board_id = %x\n", board_id); +#endif /* CCISS_DEBUG */ + + c->intr = irq; + + /* + * Memory base addr is first addr , the second points to the config + * table + */ + c->paddr = pci_resource_start(pdev, 0); + c->vaddr = remap_pci_mem(c->paddr, 128); + c->cfgtable = (CfgTable_struct *) remap_pci_mem(addr[1], + sizeof(CfgTable_struct)); + c->board_id = board_id; + +#ifdef CCISS_DEBUG + print_cfg_table(c->cfgtable); +#endif /* CCISS_DEBUG */ + for(i=0; iproduct_name = products[i].product_name; + c->access = *(products[i].access); + break; + } + } + if (i == NR_PRODUCTS) { + printk(KERN_WARNING "cciss: Sorry, I don't know how" + " to access the Smart Array controller %08lx\n", + (unsigned long)board_id); + return -1; + } +#ifdef CCISS_DEBUG + printk("Trying to put board into Simple mode\n"); +#endif /* CCISS_DEBUG */ + c->max_commands = readl(&(c->cfgtable->CmdsOutMax)); + /* Update the field, and then ring the doorbell */ + writel( CFGTBL_Trans_Simple, + &(c->cfgtable->HostWrite.TransportRequest)); + writel( CFGTBL_ChangeReq, c->vaddr + SA5_DOORBELL); + + for(i=0;ivaddr + SA5_DOORBELL) & CFGTBL_ChangeReq)) + break; + /* delay and try again */ + udelay(1000); + } + +#ifdef CCISS_DEBUG + printk(KERN_DEBUG "I counter got to %d %x\n", i, readl(c->vaddr + SA5_DOORBELL)); +#endif /* CCISS_DEBUG */ +#ifdef CCISS_DEBUG + print_cfg_table(c->cfgtable); +#endif /* CCISS_DEBUG */ + + if (!(readl(&(c->cfgtable->TransportActive)) & CFGTBL_Trans_Simple)) + { + printk(KERN_WARNING "cciss: unable to get board into" + " simple mode\n"); + return -1; + } + return 0; + +} +/* + * Scans PCI space for any controllers that this driver can control. + */ +static int cciss_pci_detect(void) +{ + + int index; + unchar bus=0, dev_fn=0; + + for(index=0; ; index++) { + if (pcibios_find_device(PCI_VENDOR_ID_COMPAQ, + PCI_DEVICE_ID_COMPAQ_CISS, + index, &bus, &dev_fn)) + break; + printk(KERN_DEBUG "cciss: Device %x has been found at %x %x\n", + PCI_DEVICE_ID_COMPAQ_CISS, bus, dev_fn); + if (index == 1000000) break; + if (nr_ctlr == 8) { + printk(KERN_WARNING "cciss: This driver" + " supports a maximum of 8 controllers.\n"); + break; + } + hba[nr_ctlr] = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL); + if(hba[nr_ctlr]==NULL) + { + printk(KERN_ERR "cciss: out of memory.\n"); + continue; + } + memset(hba[nr_ctlr], 0, sizeof(ctlr_info_t)); + if (cciss_pci_init(hba[nr_ctlr], bus, dev_fn) != 0) + { + kfree(hba[nr_ctlr]); + continue; + } + sprintf(hba[nr_ctlr]->devname, "cciss%d", nr_ctlr); + hba[nr_ctlr]->ctlr = nr_ctlr; + hba[nr_ctlr]->pci_bus = bus; + hba[nr_ctlr]->pci_dev_fn = dev_fn; + nr_ctlr++; + + } + return nr_ctlr; + +} + +/* + * Gets information about the local volumes attached to the controller. + */ +static void cciss_getgeometry(int cntl_num) +{ + ReportLunData_struct *ld_buff; + ReadCapdata_struct *size_buff; + InquiryData_struct *inq_buff; + int return_code; + int i; + int listlength = 0; + int lunid = 0; + int block_size; + int total_size; + + ld_buff = kmalloc(sizeof(ReportLunData_struct), GFP_KERNEL); + if (ld_buff == NULL) + { + printk(KERN_ERR "cciss: out of memory\n"); + return; + } + memset(ld_buff, 0, sizeof(ReportLunData_struct)); + size_buff = kmalloc(sizeof( ReadCapdata_struct), GFP_KERNEL); + if (size_buff == NULL) + { + printk(KERN_ERR "cciss: out of memory\n"); + kfree(ld_buff); + return; + } + inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL); + if (inq_buff == NULL) + { + printk(KERN_ERR "cciss: out of memory\n"); + kfree(ld_buff); + kfree(size_buff); + return; + } + /* Get the firmware version */ + return_code = sendcmd(CISS_INQUIRY, cntl_num, inq_buff, + sizeof(InquiryData_struct), 0, 0 ,0 ); + if (return_code == IO_OK) + { + hba[cntl_num]->firm_ver[0] = inq_buff->data_byte[32]; + hba[cntl_num]->firm_ver[1] = inq_buff->data_byte[33]; + hba[cntl_num]->firm_ver[2] = inq_buff->data_byte[34]; + hba[cntl_num]->firm_ver[3] = inq_buff->data_byte[35]; + } else /* send command failed */ + { + printk(KERN_WARNING "cciss: unable to determine firmware" + " version of controller\n"); + } + /* Get the number of logical volumes */ + return_code = sendcmd(CISS_REPORT_LOG, cntl_num, ld_buff, + sizeof(ReportLunData_struct), 0, 0, 0 ); + + if( return_code == IO_OK) + { +#ifdef CCISS_DEBUG + printk("LUN Data\n--------------------------\n"); +#endif /* CCISS_DEBUG */ + + listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[0])) << 24; + listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[1])) << 16; + listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[2])) << 8; + listlength |= 0xff & (unsigned int)(ld_buff->LUNListLength[3]); + } else /* reading number of logical volumes failed */ + { + printk(KERN_WARNING "cciss: report logical volume" + " command failed\n"); + listlength = 0; + } + hba[cntl_num]->num_luns = listlength / 8; // 8 bytes pre entry + if (hba[cntl_num]->num_luns > CISS_MAX_LUN) + { + printk(KERN_ERR "ciss: only %d number of logical volumes supported\n", + CISS_MAX_LUN); + hba[cntl_num]->num_luns = CISS_MAX_LUN; + } +#ifdef CCISS_DEBUG + printk(KERN_DEBUG "Length = %x %x %x %x = %d\n", ld_buff->LUNListLength[0], + ld_buff->LUNListLength[1], ld_buff->LUNListLength[2], + ld_buff->LUNListLength[3], hba[cntl_num]->num_luns); +#endif /* CCISS_DEBUG */ + for(i=0; i< hba[cntl_num]->num_luns ; i++) + { + lunid = (0xff & (unsigned int)(ld_buff->LUN[i][3])) << 24; + lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][2])) << 16; + lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][1])) << 8; + lunid |= 0xff & (unsigned int)(ld_buff->LUN[i][0]); + hba[cntl_num]->drv[i].LunID = lunid; + +#ifdef CCISS_DEBUG + printk(KERN_DEBUG "LUN[%d]: %x %x %x %x = %x\n", i, + ld_buff->LUN[i][0], ld_buff->LUN[i][1],ld_buff->LUN[i][2], + ld_buff->LUN[i][3], hba[cntl_num]->drv[i].LunID); +#endif /* CCISS_DEBUG */ + + memset(size_buff, 0, sizeof(ReadCapdata_struct)); + return_code = sendcmd(CCISS_READ_CAPACITY, cntl_num, size_buff, + sizeof( ReadCapdata_struct), 1, i, 0 ); + if (return_code == IO_OK) + { + total_size = (0xff & + (unsigned int)(size_buff->total_size[0])) << 24; + total_size |= (0xff & + (unsigned int)(size_buff->total_size[1])) << 16; + total_size |= (0xff & + (unsigned int)(size_buff->total_size[2])) << 8; + total_size |= (0xff & (unsigned int) + (size_buff->total_size[3])); + total_size++; // command returns highest block address + + block_size = (0xff & + (unsigned int)(size_buff->block_size[0])) << 24; + block_size |= (0xff & + (unsigned int)(size_buff->block_size[1])) << 16; + block_size |= (0xff & + (unsigned int)(size_buff->block_size[2])) << 8; + block_size |= (0xff & + (unsigned int)(size_buff->block_size[3])); + } else /* read capacity command failed */ + { + printk(KERN_WARNING "cciss: read capacity failed\n"); + total_size = block_size = 0; + } + printk(" blocks= %d block_size= %d\n", total_size, + block_size); + + /* Execute the command to read the disk geometry */ + memset(inq_buff, 0, sizeof(InquiryData_struct)); + return_code = sendcmd(CISS_INQUIRY, cntl_num, inq_buff, + sizeof(InquiryData_struct), 1, i ,0xC1 ); + if (return_code == IO_OK) + { + if(inq_buff->data_byte[8] == 0xFF) + { + printk(KERN_WARNING "cciss: reading geometry failed, volume does not support reading geometry\n"); + + hba[cntl_num]->drv[i].block_size = block_size; + hba[cntl_num]->drv[i].nr_blocks = total_size; + hba[cntl_num]->drv[i].heads = 255; + hba[cntl_num]->drv[i].sectors = 32; // Sectors per track + hba[cntl_num]->drv[i].cylinders = total_size / 255 / 32; } else + { + + hba[cntl_num]->drv[i].block_size = block_size; + hba[cntl_num]->drv[i].nr_blocks = total_size; + hba[cntl_num]->drv[i].heads = + inq_buff->data_byte[6]; + hba[cntl_num]->drv[i].sectors = + inq_buff->data_byte[7]; + hba[cntl_num]->drv[i].cylinders = + (inq_buff->data_byte[4] & 0xff) << 8; + hba[cntl_num]->drv[i].cylinders += + inq_buff->data_byte[5]; + } + } + else /* Get geometry failed */ + { + printk(KERN_WARNING "cciss: reading geometry failed, continuing with default geometry\n"); + + hba[cntl_num]->drv[i].block_size = block_size; + hba[cntl_num]->drv[i].nr_blocks = total_size; + hba[cntl_num]->drv[i].heads = 255; + hba[cntl_num]->drv[i].sectors = 32; // Sectors per track + hba[cntl_num]->drv[i].cylinders = total_size / 255 / 32; + } + printk(KERN_INFO " heads= %d, sectors= %d, cylinders= %d\n\n", + hba[cntl_num]->drv[i].heads, + hba[cntl_num]->drv[i].sectors, + hba[cntl_num]->drv[i].cylinders); + + } + kfree(ld_buff); + kfree(size_buff); +} + +/* + * This is it. Find all the controllers and register them. I really hate + * stealing all these major device numbers. + * returns the number of block devices registered. + */ +int __init cciss_init(void) +{ + int num_cntlrs_reg = 0; + int i,j; + + void (*request_fns[MAX_CTLR])(request_queue_t *) = { + do_cciss_request0, do_cciss_request1, + do_cciss_request2, do_cciss_request3, + do_cciss_request4, do_cciss_request5, + do_cciss_request6, do_cciss_request7, + }; + + /* detect controllers */ + cciss_pci_detect(); + + if (nr_ctlr == 0) + return(num_cntlrs_reg); + + printk(KERN_INFO DRIVER_NAME "\n"); + printk(KERN_INFO "Found %d controller(s)\n", nr_ctlr); + for(i=0;idevname, &cciss_fops)) + { + printk(KERN_ERR "cciss: Unable to get major number " + "%d for %s\n", MAJOR_NR+i, hba[i]->devname); + continue; + } + /* make sure the board interrupts are off */ + hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_OFF); + if( request_irq(hba[i]->intr, do_cciss_intr, SA_INTERRUPT|SA_SHIRQ, hba[i]->devname, hba[i])) + { + printk(KERN_ERR "ciss: Unable to get irq %d for %s\n", + hba[i]->intr, hba[i]->devname); + unregister_blkdev( MAJOR_NR+i, hba[i]->devname); + continue; + } + num_cntlrs_reg++; + hba[i]->cmd_pool_bits = (__u32*)kmalloc( + ((NR_CMDS+31)/32)*sizeof(__u32), GFP_KERNEL); + hba[i]->cmd_pool = (CommandList_struct *)kmalloc( + NR_CMDS * sizeof(CommandList_struct), + GFP_KERNEL); + hba[i]->errinfo_pool = (ErrorInfo_struct *)kmalloc( + NR_CMDS * sizeof( ErrorInfo_struct), + GFP_KERNEL); + if((hba[i]->cmd_pool_bits == NULL) + || (hba[i]->cmd_pool == NULL) + || (hba[i]->errinfo_pool == NULL)) + { + nr_ctlr = i; + if(hba[i]->cmd_pool_bits) + kfree(hba[i]->cmd_pool_bits); + if(hba[i]->cmd_pool) + kfree(hba[i]->cmd_pool); + if(hba[i]->errinfo_pool) + kfree(hba[i]->errinfo_pool); + free_irq(hba[i]->intr, hba[i]); + unregister_blkdev(MAJOR_NR+i, hba[i]->devname); + num_cntlrs_reg--; + printk( KERN_ERR "cciss: out of memory"); + return(num_cntlrs_reg); + } + + /* command and error info recs zeroed out before + they are used */ + memset(hba[i]->cmd_pool_bits, 0, + ((NR_CMDS+31)/32)*sizeof(__u32)); + +#ifdef CCISS_DEBUG + printk(KERN_DEBUG "Scanning for drives on controller cciss%d\n",i); +#endif /* CCISS_DEBUG */ + + cciss_getgeometry(i); + + /* Turn the interrupts on so we can service requests */ + hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_ON); + + cciss_procinit(i); + + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR+i), + request_fns[i]); + blk_queue_headactive(BLK_DEFAULT_QUEUE(MAJOR_NR+i), 0); + + /* fill in the other Kernel structs */ + blksize_size[MAJOR_NR+i] = hba[i]->blocksizes; + hardsect_size[MAJOR_NR+i] = hba[i]->hardsizes; + read_ahead[MAJOR_NR+i] = READ_AHEAD; + + /* Fill in the gendisk data */ + hba[i]->gendisk.major = MAJOR_NR + i; + hba[i]->gendisk.major_name = "cciss"; + hba[i]->gendisk.minor_shift = NWD_SHIFT; + hba[i]->gendisk.max_p = MAX_PART; + hba[i]->gendisk.part = hba[i]->hd; + hba[i]->gendisk.sizes = hba[i]->sizes; + hba[i]->gendisk.nr_real = hba[i]->num_luns; + + /* Get on the disk list */ + hba[i]->gendisk.next = gendisk_head; + gendisk_head = &(hba[i]->gendisk); + + cciss_geninit(i); + for(j=0; jgendisk), + MKDEV(MAJOR_NR+i, j <<4), + MAX_PART, &cciss_fops, + hba[i]->drv[j].nr_blocks); + } + return(nr_ctlr); +} + +EXPORT_NO_SYMBOLS; + +/* This is a bit of a hack... */ +static int __init init_cciss_module(void) +{ + + if (cciss_init() == 0) /* all the block dev numbers already used */ + return -EIO; /* or no controllers were found */ + return 0; +} + +static void __exit cleanup_cciss_module(void) +{ + int i; + struct gendisk *g; + + for(i=0; iaccess.set_intr_mask(hba[i], CCISS_INTR_OFF); + free_irq(hba[i]->intr, hba[i]); + iounmap((void*)hba[i]->vaddr); + unregister_blkdev(MAJOR_NR+i, hba[i]->devname); + remove_proc_entry(hba[i]->devname, proc_cciss); + + /* remove it from the disk list */ + if (gendisk_head == &(hba[i]->gendisk)) + { + gendisk_head = hba[i]->gendisk.next; + } else + { + for(g=gendisk_head; g ; g=g->next) + { + if(g->next == &(hba[i]->gendisk)) + { + g->next = hba[i]->gendisk.next; + } + } + } + remove_proc_entry("driver/cciss", &proc_root); + kfree(hba[i]->cmd_pool); + kfree(hba[i]->errinfo_pool); + kfree(hba[i]->cmd_pool_bits); + kfree(hba[i]); + } +} + +module_init(init_cciss_module); +module_exit(cleanup_cciss_module); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/block/cciss.h linux/drivers/block/cciss.h --- v2.4.0-test8/linux/drivers/block/cciss.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/block/cciss.h Fri Sep 22 17:11:37 2000 @@ -0,0 +1,201 @@ +#ifndef CCISS_H +#define CCISS_H + +#include + +#include "cciss_cmd.h" + + +#define NWD 16 +#define NWD_SHIFT 4 +#define MAX_PART 16 + +#define IO_OK 0 +#define IO_ERROR 1 + +#define MAJOR_NR COMPAQ_CISS_MAJOR + +struct ctlr_info; +typedef struct ctlr_info ctlr_info_t; + +struct access_method { + void (*submit_command)(ctlr_info_t *h, CommandList_struct *c); + void (*set_intr_mask)(ctlr_info_t *h, unsigned long val); + unsigned long (*fifo_full)(ctlr_info_t *h); + unsigned long (*intr_pending)(ctlr_info_t *h); + unsigned long (*command_completed)(ctlr_info_t *h); +}; +typedef struct _drive_info_struct +{ + __u32 LunID; + int usage_count; + int nr_blocks; + int block_size; + int heads; + int sectors; + int cylinders; +} drive_info_struct; + +struct ctlr_info +{ + int ctlr; + char devname[8]; + char *product_name; + char firm_ver[4]; // Firmware version + unchar pci_bus; + unchar pci_dev_fn; + __u32 board_id; + ulong vaddr; + __u32 paddr; + CfgTable_struct *cfgtable; + int intr; + + int max_commands; + int commands_outstanding; + int max_outstanding; /* Debug */ + int num_luns; + int usage_count; /* number of opens all all minor devices */ + + // information about each logical volume + drive_info_struct drv[CISS_MAX_LUN]; + + struct access_method access; + + /* queue and queue Info */ + CommandList_struct *reqQ; + CommandList_struct *cmpQ; + unsigned int Qdepth; + unsigned int maxQsinceinit; + unsigned int maxSG; + + //* pointers to command and error info pool */ + CommandList_struct *cmd_pool; + ErrorInfo_struct *errinfo_pool; + __u32 *cmd_pool_bits; + int nr_allocs; + int nr_frees; + + // Disk structures we need to pass back + struct gendisk gendisk; + // indexed by minor numbers + struct hd_struct hd[256]; + int sizes[256]; + int blocksizes[256]; + int hardsizes[256]; +}; + +/* Defining the diffent access_menthods */ +/* + * Memory mapped FIFO interface (SMART 53xx cards) + */ +#define SA5_DOORBELL 0x20 +#define SA5_REQUEST_PORT_OFFSET 0x40 +#define SA5_REPLY_INTR_MASK_OFFSET 0x34 +#define SA5_REPLY_PORT_OFFSET 0x44 +#define SA5_INTR_STATUS 0x30 + +#define SA5_INTR_OFF 0x08 +#define SA5_INTR_PENDING 0x08 +#define FIFO_EMPTY 0xffffffff + +#define CISS_ERROR_BIT 0x02 + +#define CCISS_INTR_ON 1 +#define CCISS_INTR_OFF 0 +/* + Send the command to the hardware +*/ +static void SA5_submit_command( ctlr_info_t *h, CommandList_struct *c) +{ +#ifdef CCISS_DEBUG + printk("Sending %x - down to controller\n", c->busaddr ); +#endif /* CCISS_DEBUG */ + writel(c->busaddr, h->vaddr + SA5_REQUEST_PORT_OFFSET); + h->commands_outstanding++; + if ( h->commands_outstanding > h->max_outstanding) + h->max_outstanding = h->commands_outstanding; +} + +/* + * This card is the oposite of the other cards. + * 0 turns interrupts on... + * 0x08 turns them off... + */ +static void SA5_intr_mask(ctlr_info_t *h, unsigned long val) +{ + if (val) + { /* Turn interrupts on */ + writel(0, h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); + } else /* Turn them off */ + { + writel( SA5_INTR_OFF, + h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); + } +} +/* + * Returns true if fifo is full. + * + */ +static unsigned long SA5_fifo_full(ctlr_info_t *h) +{ + if( h->commands_outstanding >= h->max_commands) + return(1); + else + return(0); + +} +/* + * returns value read from hardware. + * returns FIFO_EMPTY if there is nothing to read + */ +static unsigned long SA5_completed(ctlr_info_t *h) +{ + unsigned long register_value + = readl(h->vaddr + SA5_REPLY_PORT_OFFSET); + if(register_value != FIFO_EMPTY) + { + h->commands_outstanding--; +#ifdef CCISS_DEBUG + printk("cciss: Read %lx back from board\n", register_value); +#endif /* CCISS_DEBUG */ + } +#ifdef CCISS_DEBUG + else + { + printk("cciss: FIFO Empty read\n"); + } +#endif + return ( register_value); + +} +/* + * Returns true if an interrupt is pending.. + */ +static unsigned long SA5_intr_pending(ctlr_info_t *h) +{ + unsigned long register_value = + readl(h->vaddr + SA5_INTR_STATUS); +#ifdef CCISS_DEBUG + printk("cciss: intr_pending %lx\n", register_value); +#endif /* CCISS_DEBUG */ + if( register_value & SA5_INTR_PENDING) + return 1; + return 0 ; +} + + +static struct access_method SA5_access = { + SA5_submit_command, + SA5_intr_mask, + SA5_fifo_full, + SA5_intr_pending, + SA5_completed, +}; + +struct board_type { + __u32 board_id; + char *product_name; + struct access_method *access; +}; +#endif /* CCISS_H */ + diff -u --recursive --new-file v2.4.0-test8/linux/drivers/block/cciss_cmd.h linux/drivers/block/cciss_cmd.h --- v2.4.0-test8/linux/drivers/block/cciss_cmd.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/block/cciss_cmd.h Fri Sep 22 17:11:37 2000 @@ -0,0 +1,254 @@ +#ifndef CCISS_CMD_H +#define CCISS_CMD_H +//########################################################################### +//DEFINES +//########################################################################### +#define CISS_VERSION "1.00" + +//general boundary defintions +#define SENSEINFOBYTES 32//note that this value may vary between host implementations +#define MAXSGENTRIES 31 +#define MAXREPLYQS 256 + +//Command Status value +#define CMD_SUCCESS 0x0000 +#define CMD_TARGET_STATUS 0x0001 +#define CMD_DATA_UNDERRUN 0x0002 +#define CMD_DATA_OVERRUN 0x0003 +#define CMD_INVALID 0x0004 +#define CMD_PROTOCOL_ERR 0x0005 +#define CMD_HARDWARE_ERR 0x0006 +#define CMD_CONNECTION_LOST 0x0007 +#define CMD_ABORTED 0x0008 +#define CMD_ABORT_FAILED 0x0009 +#define CMD_UNSOLICITED_ABORT 0x000A +#define CMD_TIMEOUT 0x000B +#define CMD_UNABORTABLE 0x000C + +//transfer direction +#define XFER_NONE 0x00 +#define XFER_WRITE 0x01 +#define XFER_READ 0x02 +#define XFER_RSVD 0x03 + +//task attribute +#define ATTR_UNTAGGED 0x00 +#define ATTR_SIMPLE 0x04 +#define ATTR_HEADOFQUEUE 0x05 +#define ATTR_ORDERED 0x06 +#define ATTR_ACA 0x07 + +//cdb type +#define TYPE_CMD 0x00 +#define TYPE_MSG 0x01 + +//config space register offsets +#define CFG_VENDORID 0x00 +#define CFG_DEVICEID 0x02 +#define CFG_I2OBAR 0x10 +#define CFG_MEM1BAR 0x14 + +//i2o space register offsets +#define I2O_IBDB_SET 0x20 +#define I2O_IBDB_CLEAR 0x70 +#define I2O_INT_STATUS 0x30 +#define I2O_INT_MASK 0x34 +#define I2O_IBPOST_Q 0x40 +#define I2O_OBPOST_Q 0x44 + +//Configuration Table +#define CFGTBL_ChangeReq 0x00000001l +#define CFGTBL_AccCmds 0x00000001l + +#define CFGTBL_Trans_Simple 0x00000002l + +#define CFGTBL_BusType_Ultra2 0x00000001l +#define CFGTBL_BusType_Ultra3 0x00000002l +#define CFGTBL_BusType_Fibre1G 0x00000100l +#define CFGTBL_BusType_Fibre2G 0x00000200l +typedef struct _vals32 +{ + __u32 lower; + __u32 upper; +} vals32; + +typedef union _u64bit +{ + vals32 val32; + __u64 val; +} u64bit; + +// Type defs used in the following structs +#define BYTE __u8 +#define WORD __u16 +#define HWORD __u16 +#define DWORD __u32 +#define QWORD vals32 + +//########################################################################### +//STRUCTURES +//########################################################################### +#define CISS_MAX_LUN 16 +// SCSI-3 Cmmands + +#pragma pack(1) + +#define CISS_INQUIRY 0x12 +//Date returned +typedef struct _InquiryData_struct +{ + BYTE data_byte[36]; +} InquiryData_struct; + +#define CISS_REPORT_LOG 0xc2 /* Report Logical LUNs */ +// Data returned +typedef struct _ReportLUNdata_struct +{ + BYTE LUNListLength[4]; + DWORD reserved; + BYTE LUN[CISS_MAX_LUN][8]; +} ReportLunData_struct; + +#define CCISS_READ_CAPACITY 0x25 /* Read Capacity */ +typedef struct _ReadCapdata_struct +{ + BYTE total_size[4]; // Total size in blocks + BYTE block_size[4]; // Size of blocks in bytes +} ReadCapdata_struct; + +// 12 byte commands not implemented in firmware yet. +// #define CCISS_READ 0xa8 // Read(12) +// #define CCISS_WRITE 0xaa // Write(12) + #define CCISS_READ 0x28 // Read(10) + #define CCISS_WRITE 0x2a // Write(10) + +//Command List Structure +typedef union _SCSI3Addr_struct { + struct { + BYTE Bus:6; + BYTE Mode:2; // b00 + BYTE Dev; + } PeripDev; + struct { + BYTE DevMSB:6; + BYTE Mode:2; // b01 + BYTE DevLSB; + } LogDev; + struct { + BYTE Targ:6; + BYTE Mode:2; // b10 + BYTE Dev:5; + BYTE Bus:3; + } LogUnit; +} SCSI3Addr_struct; + +typedef struct _PhysDevAddr_struct { + DWORD TargetId:24; + DWORD Bus:6; + DWORD Mode:2; + SCSI3Addr_struct Target[2]; //2 level target device addr +} PhysDevAddr_struct; + +typedef struct _LogDevAddr_struct { + DWORD VolId:30; + DWORD Mode:2; + BYTE reserved[4]; +} LogDevAddr_struct; + +typedef union _LUNAddr_struct { + BYTE LunAddrBytes[8]; + SCSI3Addr_struct SCSI3Lun[4]; + PhysDevAddr_struct PhysDev; + LogDevAddr_struct LogDev; +} LUNAddr_struct; + +typedef struct _CommandListHeader_struct { + BYTE ReplyQueue; + BYTE SGList; + HWORD SGTotal; + QWORD Tag; + LUNAddr_struct LUN; +} CommandListHeader_struct; +typedef struct _RequestBlock_struct { + BYTE CDBLen; + struct { + BYTE Type:3; + BYTE Attribute:3; + BYTE Direction:2; + } Type; + HWORD Timeout; + BYTE CDB[16]; +} RequestBlock_struct; +typedef struct _ErrDescriptor_struct { + QWORD Addr; + DWORD Len; +} ErrDescriptor_struct; +typedef struct _SGDescriptor_struct { + QWORD Addr; + DWORD Len; + DWORD Ext; +} SGDescriptor_struct; + +typedef union _MoreErrInfo_struct{ + struct { + BYTE Reserved[3]; + BYTE Type; + DWORD ErrorInfo; + }Common_Info; + struct{ + BYTE Reserved[2]; + BYTE offense_size;//size of offending entry + BYTE offense_num; //byte # of offense 0-base + DWORD offense_value; + }Invalid_Cmd; +}MoreErrInfo_struct; +typedef struct _ErrorInfo_struct { + BYTE ScsiStatus; + BYTE SenseLen; + HWORD CommandStatus; + DWORD ResidualCnt; + MoreErrInfo_struct MoreErrInfo; + BYTE SenseInfo[SENSEINFOBYTES]; +} ErrorInfo_struct; + +/* Command types */ +#define CMD_RWREQ 0x00 +#define CMD_IOCTL_PEND 0x01 +#define CMD_IOCTL_DONE 0x02 + +typedef struct _CommandList_struct { + CommandListHeader_struct Header; + RequestBlock_struct Request; + ErrDescriptor_struct ErrDesc; + SGDescriptor_struct SG[MAXSGENTRIES]; + /* information associated with the command */ + __u32 busaddr; /* physical addres of this record */ + ErrorInfo_struct * err_info; /* pointer to the allocated mem */ + int cmd_type; + struct _CommandList_struct *prev; + struct _CommandList_struct *next; + struct buffer_head * bh; +} CommandList_struct; + +//Configuration Table Structure +typedef struct _HostWrite_struct { + DWORD TransportRequest; + DWORD Reserved; + DWORD CoalIntDelay; + DWORD CoalIntCount; +} HostWrite_struct; + +typedef struct _CfgTable_struct { + BYTE Signature[4]; + DWORD SpecValence; + DWORD TransportSupport; + DWORD TransportActive; + HostWrite_struct HostWrite; + DWORD CmdsOutMax; + DWORD BusTypes; + DWORD Reserved; + BYTE ServerName[16]; + DWORD HeartBeat; +} CfgTable_struct; +#pragma pack() +#endif // CCISS_CMD_H diff -u --recursive --new-file v2.4.0-test8/linux/drivers/block/cpqarray.c linux/drivers/block/cpqarray.c --- v2.4.0-test8/linux/drivers/block/cpqarray.c Thu Jul 6 19:25:21 2000 +++ linux/drivers/block/cpqarray.c Fri Sep 22 14:17:18 2000 @@ -46,6 +46,12 @@ #define DRIVER_NAME "Compaq SMART2 Driver (v 2.4.0)" #define DRIVER_VERSION SMART2_DRIVER_VERSION(2,4,0) + +/* Embedded module documentation macros - see modules.h */ +/* Original author Chris Frantz - Compaq Computer Corporation */ +MODULE_AUTHOR("Compaq Computer Corporation"); +MODULE_DESCRIPTION("Driver for Compaq Smart2 Array Controllers"); + #define MAJOR_NR COMPAQ_SMART2_MAJOR #include #include @@ -85,6 +91,7 @@ { 0x40330E11, "Smart Array 3100ES", &smart2_access }, { 0x40340E11, "Smart Array 221", &smart2_access }, { 0x40400E11, "Integrated Array", &smart4_access }, + { 0x40480E11, "Compaq Raid LC2", &smart4_access }, { 0x40500E11, "Smart Array 4200", &smart4_access }, { 0x40510E11, "Smart Array 4250ES", &smart4_access }, { 0x40580E11, "Smart Array 431", &smart4_access }, @@ -109,8 +116,8 @@ int cpqarray_init(void); static int cpqarray_pci_detect(void); -static int cpqarray_pci_init(ctlr_info_t *c, unchar bus, unchar device_fn); -static ulong remap_pci_mem(ulong base, ulong size); +static int cpqarray_pci_init(ctlr_info_t *c, struct pci_dev *pdev); +static void *remap_pci_mem(ulong base, ulong size); static int cpqarray_eisa_detect(void); static int pollcomplete(int ctlr); static void getgeometry(int ctlr); @@ -328,7 +335,7 @@ for(i=0; iaccess.set_intr_mask(hba[i], 0); free_irq(hba[i]->intr, hba[i]); - iounmap((void*)hba[i]->vaddr); + iounmap(hba[i]->vaddr); unregister_blkdev(MAJOR_NR+i, hba[i]->devname); del_timer(&hba[i]->timer); blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR + i)); @@ -535,8 +542,7 @@ */ static int cpqarray_pci_detect(void) { - int index; - unchar bus=0, dev_fn=0; + struct pci_dev *pdev; #define IDA_BOARD_TYPES 3 static int ida_vendor_id[IDA_BOARD_TYPES] = { PCI_VENDOR_ID_DEC, @@ -547,29 +553,22 @@ /* search for all PCI board types that could be for this driver */ for(brdtype=0; brdtypebus->number, pdev->devfn); if (nr_ctlr == 8) { printk(KERN_WARNING "cpqarray: This driver" " supports a maximum of 8 controllers.\n"); break; } - + /* if it is a PCI_DEVICE_ID_NCR_53C1510, make sure it's the Compaq version of the chip */ if (ida_device_id[brdtype] == PCI_DEVICE_ID_NCR_53C1510) { - unsigned short subvendor=0; - if(pcibios_read_config_word(bus, dev_fn, - PCI_SUBSYSTEM_VENDOR_ID, &subvendor)) - { - printk(KERN_DEBUG "cpqarray: failed to read subvendor\n"); - continue; - } + unsigned short subvendor=pdev->subsystem_vendor; if(subvendor != PCI_VENDOR_ID_COMPAQ) { printk(KERN_DEBUG @@ -584,7 +583,7 @@ continue; } memset(hba[nr_ctlr], 0, sizeof(ctlr_info_t)); - if (cpqarray_pci_init(hba[nr_ctlr], bus, dev_fn) != 0) + if (cpqarray_pci_init(hba[nr_ctlr], pdev) != 0) { kfree(hba[nr_ctlr]); continue; @@ -593,6 +592,8 @@ hba[nr_ctlr]->ctlr = nr_ctlr; nr_ctlr++; + pdev = pci_find_device(ida_vendor_id[brdtype], + ida_device_id[brdtype], pdev); } } @@ -603,24 +604,23 @@ * Find the IO address of the controller, its IRQ and so forth. Fill * in some basic stuff into the ctlr_info_t structure. */ -static int cpqarray_pci_init(ctlr_info_t *c, unchar bus, unchar device_fn) +static int cpqarray_pci_init(ctlr_info_t *c, struct pci_dev *pdev) { ushort vendor_id, device_id, command; unchar cache_line_size, latency_timer; unchar irq, revision; - uint addr[6]; + unsigned long addr[6]; __u32 board_id; - struct pci_dev *pdev; int i; - pdev = pci_find_slot(bus, device_fn); + c->pci_dev = pdev; vendor_id = pdev->vendor; device_id = pdev->device; irq = pdev->irq; for(i=0; i<6; i++) - addr[i] = pdev->resource[i].flags; + addr[i] = pci_resource_start(pdev, i); if (pci_enable_device(pdev)) return -1; @@ -637,7 +637,7 @@ printk("device_id = %x\n", device_id); printk("command = %x\n", command); for(i=0; i<6; i++) - printk("addr[%d] = %x\n", i, addr[i]); + printk("addr[%d] = %lx\n", i, addr[i]); printk("revision = %x\n", revision); printk("irq = %x\n", irq); printk("cache_line_size = %x\n", cache_line_size); @@ -646,17 +646,19 @@ ); c->intr = irq; - c->ioaddr = addr[0] & ~0x1; + c->ioaddr = addr[0]; - /* - * Memory base addr is first addr with the first bit _not_ set - */ + c->paddr = 0; for(i=0; i<6; i++) - if (!(addr[i] & 0x1)) { + if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) { c->paddr = pci_resource_start (pdev, i); break; } + if (!c->paddr) + return -1; c->vaddr = remap_pci_mem(c->paddr, 128); + if (!c->vaddr) + return -1; c->board_id = board_id; for(i=0; iaccess = *(products[j].access); hba[nr_ctlr]->ctlr = nr_ctlr; hba[nr_ctlr]->board_id = board_id; + hba[nr_ctlr]->pci_dev = NULL; /* not PCI */ DBGINFO( printk("i = %d, j = %d\n", i, j); @@ -898,7 +901,7 @@ if (ctlr != MAJOR(creq->rq_dev)-MAJOR_NR || ctlr > nr_ctlr || h == NULL) { - printk("doreq cmd for %d, %x at %p\n", + printk(KERN_WARNING "doreq cmd for %d, %x at %p\n", ctlr, creq->rq_dev, creq); complete_buffers(creq->bh, 0); start_io(h); @@ -1188,6 +1191,20 @@ if (!arg) return -EINVAL; put_user(DRIVER_VERSION, (unsigned long*)arg); return 0; + case IDAGETPCIINFO: + { + + ida_pci_info_struct pciinfo; + + if (!arg) return -EINVAL; + pciinfo.bus = hba[ctlr]->pci_dev->bus->number; + pciinfo.dev_fn = hba[ctlr]->pci_dev->devfn; + pciinfo.board_id = hba[ctlr]->board_id; + if(copy_to_user((void *) arg, &pciinfo, + sizeof( ida_pci_info_struct))) + return -EFAULT; + return(0); + } case BLKFLSBUF: case BLKROSET: @@ -1198,7 +1215,7 @@ return blk_ioctl(inode->i_rdev, cmd, arg); default: - return -EBADRQC; + return -EINVAL; } } @@ -1378,6 +1395,8 @@ ctlr_info_t *info_p = hba[ctlr]; c = cmd_alloc(info_p); + if(!c) + return IO_ERROR; c->ctlr = ctlr; c->hdr.unit = log_unit; c->hdr.prio = 0; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/block/cpqarray.h linux/drivers/block/cpqarray.h --- v2.4.0-test8/linux/drivers/block/cpqarray.h Fri Mar 3 12:54:44 2000 +++ linux/drivers/block/cpqarray.h Fri Sep 22 14:17:18 2000 @@ -87,12 +87,13 @@ int log_drives; int phys_drives; + struct pci_dev *pci_dev; /* NULL if EISA */ __u32 board_id; char *product_name; - __u32 vaddr; - __u32 paddr; - __u32 ioaddr; + void *vaddr; + unsigned long paddr; + unsigned long ioaddr; int intr; int usage_count; drv_info_t drv[NWD]; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/block/floppy.c linux/drivers/block/floppy.c --- v2.4.0-test8/linux/drivers/block/floppy.c Mon Aug 28 21:31:47 2000 +++ linux/drivers/block/floppy.c Sun Oct 1 20:35:15 2000 @@ -168,7 +168,7 @@ * It's been recommended that take about 1/4 of the default speed * in some more extreme cases. */ -static int slow_floppy = 0; +static int slow_floppy; #include #include @@ -203,7 +203,7 @@ void floppy_interrupt(int irq, void *dev_id, struct pt_regs * regs); static int set_dor(int fdc, char mask, char data); static void register_devfs_entries (int drive) __init; -static devfs_handle_t devfs_handle = NULL; +static devfs_handle_t devfs_handle; #define K_64 0x10000 /* 64KB */ @@ -221,7 +221,7 @@ #include -static int irqdma_allocated = 0; +static int irqdma_allocated; #define MAJOR_NR FLOPPY_MAJOR @@ -259,7 +259,7 @@ /* End dma memory related stuff */ -static unsigned long fake_change = 0; +static unsigned long fake_change; static int initialising=1; static inline int TYPE(kdev_t x) { @@ -460,10 +460,7 @@ #define SECTSIZE (_FD_SECTSIZE(*floppy)) /* Auto-detection: Disk type used until the next media change occurs. */ -static struct floppy_struct *current_type[N_DRIVE] = { - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL -}; +static struct floppy_struct *current_type[N_DRIVE]; /* * User-provided type information. current_type points to @@ -472,14 +469,14 @@ static struct floppy_struct user_params[N_DRIVE]; static int floppy_sizes[256]; -static int floppy_blocksizes[256] = { 0, }; +static int floppy_blocksizes[256]; /* * The driver is trying to determine the correct media format * while probing is set. rw_interrupt() clears it after a * successful access. */ -static int probing = 0; +static int probing; /* Synchronization of FDC access. */ #define FD_COMMAND_NONE -1 @@ -487,7 +484,7 @@ #define FD_COMMAND_OKAY 3 static volatile int command_status = FD_COMMAND_NONE; -static unsigned long fdc_busy = 0; +static unsigned long fdc_busy; static DECLARE_WAIT_QUEUE_HEAD(fdc_wait); static DECLARE_WAIT_QUEUE_HEAD(command_done); @@ -558,9 +555,7 @@ #define NEED_1_RECAL -2 #define NEED_2_RECAL -3 -/* */ -static int usage_count = 0; - +static int usage_count; /* buffer related variables */ static int buffer_track = -1; @@ -573,8 +568,8 @@ static int fdc; /* current fdc */ static struct floppy_struct *_floppy = floppy_type; -static unsigned char current_drive = 0; -static long current_count_sectors = 0; +static unsigned char current_drive; +static long current_count_sectors; static unsigned char sector_t; /* sector in track */ static unsigned char in_sector_offset; /* offset within physical sector, * expressed in units of 512 bytes */ @@ -625,7 +620,7 @@ #define OLOGSIZE 20 -static void (*lasthandler)(void) = NULL; +static void (*lasthandler)(void); static unsigned long interruptjiffies; static unsigned long resultjiffies; static int resultsize; @@ -991,8 +986,7 @@ { } -static struct tq_struct floppy_tq = -{ 0, 0, 0, 0 }; +static struct tq_struct floppy_tq; static void schedule_bh( void (*handler)(void*) ) { @@ -1269,7 +1263,7 @@ } /* perpendicular_mode */ static int fifo_depth = 0xa; -static int no_fifo = 0; +static int no_fifo; static int fdc_configure(void) { @@ -2288,6 +2282,7 @@ static void request_done(int uptodate) { int block; + unsigned long flags; probing = 0; reschedule_timeout(MAXTIMEOUT, "request done %d", uptodate); @@ -2306,6 +2301,7 @@ DRS->maxtrack = 1; /* unlock chained buffers */ + spin_lock_irqsave(&io_request_lock, flags); while (current_count_sectors && !QUEUE_EMPTY && current_count_sectors >= CURRENT->current_nr_sectors){ current_count_sectors -= CURRENT->current_nr_sectors; @@ -2313,6 +2309,8 @@ CURRENT->sector += CURRENT->current_nr_sectors; end_request(1); } + spin_unlock_irqrestore(&io_request_lock, flags); + if (current_count_sectors && !QUEUE_EMPTY){ /* "unlock" last subsector */ CURRENT->buffer += current_count_sectors <<9; @@ -2336,7 +2334,9 @@ DRWE->last_error_sector = CURRENT->sector; DRWE->last_error_generation = DRS->generation; } + spin_lock_irqsave(&io_request_lock, flags); end_request(0); + spin_unlock_irqrestore(&io_request_lock, flags); } } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/block/genhd.c linux/drivers/block/genhd.c --- v2.4.0-test8/linux/drivers/block/genhd.c Wed Apr 12 09:38:52 2000 +++ linux/drivers/block/genhd.c Sun Sep 17 23:16:35 2000 @@ -23,7 +23,6 @@ #ifdef CONFIG_BLK_DEV_DAC960 extern void DAC960_Initialize(void); #endif -extern int scsi_dev_init(void); extern int net_dev_init(void); extern void console_map_init(void); extern int soc_probe(void); @@ -49,9 +48,6 @@ #ifdef CONFIG_FC4_SOC /* This has to be done before scsi_dev_init */ soc_probe(); -#endif -#ifdef CONFIG_SCSI - scsi_dev_init(); #endif #ifdef CONFIG_IEEE1394 ieee1394_init(); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/block/ida_ioctl.h linux/drivers/block/ida_ioctl.h --- v2.4.0-test8/linux/drivers/block/ida_ioctl.h Mon Jul 5 19:52:13 1999 +++ linux/drivers/block/ida_ioctl.h Tue Sep 19 08:01:34 2000 @@ -33,7 +33,14 @@ #define IDAGETCTLRSIG 0x29293030 #define IDAREVALIDATEVOLS 0x30303131 #define IDADRIVERVERSION 0x31313232 +#define IDAGETPCIINFO 0x32323333 +typedef struct _ida_pci_info_struct +{ + unsigned char bus; + unsigned char dev_fn; + __u32 board_id; +} ida_pci_info_struct; /* * Normally, the ioctl determines the logical unit for this command by * the major,minor number of the fd passed to ioctl. If you need to send @@ -60,7 +67,7 @@ union ctlr_cmds { drv_info_t drv; - unsigned char buf[512]; + unsigned char buf[1024]; id_ctlr_t id_ctlr; drv_param_t drv_param; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/block/linear.c linux/drivers/block/linear.c --- v2.4.0-test8/linux/drivers/block/linear.c Thu Aug 10 12:35:50 2000 +++ linux/drivers/block/linear.c Wed Dec 31 16:00:00 1969 @@ -1,213 +0,0 @@ -/* - linear.c : Multiple Devices driver for Linux - Copyright (C) 1994-96 Marc ZYNGIER - or - - - Linear mode management functions. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - You should have received a copy of the GNU General Public License - (for example /usr/src/linux/COPYING); if not, write to the Free - Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include - -#include -#include - -#include - -#define MAJOR_NR MD_MAJOR -#define MD_DRIVER -#define MD_PERSONALITY - -static int linear_run (mddev_t *mddev) -{ - linear_conf_t *conf; - struct linear_hash *table; - mdk_rdev_t *rdev; - int size, i, j, nb_zone; - unsigned int curr_offset; - - MOD_INC_USE_COUNT; - - conf = kmalloc (sizeof (*conf), GFP_KERNEL); - if (!conf) - goto out; - mddev->private = conf; - - if (md_check_ordering(mddev)) { - printk("linear: disks are not ordered, aborting!\n"); - goto out; - } - /* - * Find the smallest device. - */ - - conf->smallest = NULL; - curr_offset = 0; - ITERATE_RDEV_ORDERED(mddev,rdev,j) { - dev_info_t *disk = conf->disks + j; - - disk->dev = rdev->dev; - disk->size = rdev->size; - disk->offset = curr_offset; - - curr_offset += disk->size; - - if (!conf->smallest || (disk->size < conf->smallest->size)) - conf->smallest = disk; - } - - nb_zone = conf->nr_zones = - md_size[mdidx(mddev)] / conf->smallest->size + - ((md_size[mdidx(mddev)] % conf->smallest->size) ? 1 : 0); - - conf->hash_table = kmalloc (sizeof (struct linear_hash) * nb_zone, - GFP_KERNEL); - if (!conf->hash_table) - goto out; - - /* - * Here we generate the linear hash table - */ - table = conf->hash_table; - i = 0; - size = 0; - for (j = 0; j < mddev->nb_dev; j++) { - dev_info_t *disk = conf->disks + j; - - if (size < 0) { - table->dev1 = disk; - table++; - } - size += disk->size; - - while (size) { - table->dev0 = disk; - size -= conf->smallest->size; - if (size < 0) - break; - table->dev1 = NULL; - table++; - } - } - table->dev1 = NULL; - - return 0; - -out: - if (conf) - kfree(conf); - MOD_DEC_USE_COUNT; - return 1; -} - -static int linear_stop (mddev_t *mddev) -{ - linear_conf_t *conf = mddev_to_conf(mddev); - - kfree(conf->hash_table); - kfree(conf); - - MOD_DEC_USE_COUNT; - - return 0; -} - -static int linear_make_request (mddev_t *mddev, - int rw, struct buffer_head * bh) -{ - linear_conf_t *conf = mddev_to_conf(mddev); - struct linear_hash *hash; - dev_info_t *tmp_dev; - long block; - - block = bh->b_rsector >> 1; - hash = conf->hash_table + (block / conf->smallest->size); - - if (block >= (hash->dev0->size + hash->dev0->offset)) { - if (!hash->dev1) { - printk ("linear_make_request : hash->dev1==NULL for block %ld\n", - block); - return -1; - } - tmp_dev = hash->dev1; - } else - tmp_dev = hash->dev0; - - if (block >= (tmp_dev->size + tmp_dev->offset) - || block < tmp_dev->offset) { - printk ("linear_make_request: Block %ld out of bounds on dev %s size %ld offset %ld\n", block, kdevname(tmp_dev->dev), tmp_dev->size, tmp_dev->offset); - return -1; - } - bh->b_rdev = tmp_dev->dev; - bh->b_rsector = bh->b_rsector - (tmp_dev->offset << 1); - - return 1; -} - -static int linear_status (char *page, mddev_t *mddev) -{ - int sz = 0; - -#undef MD_DEBUG -#ifdef MD_DEBUG - int j; - linear_conf_t *conf = mddev_to_conf(mddev); - - sz += sprintf(page+sz, " "); - for (j = 0; j < conf->nr_zones; j++) - { - sz += sprintf(page+sz, "[%s", - partition_name(conf->hash_table[j].dev0->dev)); - - if (conf->hash_table[j].dev1) - sz += sprintf(page+sz, "/%s] ", - partition_name(conf->hash_table[j].dev1->dev)); - else - sz += sprintf(page+sz, "] "); - } - sz += sprintf(page+sz, "\n"); -#endif - sz += sprintf(page+sz, " %dk rounding", mddev->param.chunk_size/1024); - return sz; -} - - -static mdk_personality_t linear_personality= -{ - name: "linear", - make_request: linear_make_request, - run: linear_run, - stop: linear_stop, - status: linear_status, -}; - -#ifndef MODULE - -void md__init linear_init (void) -{ - register_md_personality (LINEAR, &linear_personality); -} - -#else - -int init_module (void) -{ - return (register_md_personality (LINEAR, &linear_personality)); -} - -void cleanup_module (void) -{ - unregister_md_personality (LINEAR); -} - -#endif - diff -u --recursive --new-file v2.4.0-test8/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c --- v2.4.0-test8/linux/drivers/block/ll_rw_blk.c Mon Aug 14 08:26:34 2000 +++ linux/drivers/block/ll_rw_blk.c Fri Sep 22 17:11:37 2000 @@ -600,6 +600,8 @@ major = MAJOR(req->rq_dev); if (major >= COMPAQ_SMART2_MAJOR+0 && major <= COMPAQ_SMART2_MAJOR+7) (q->request_fn)(q); + if (major >= COMPAQ_CISS_MAJOR+0 && major <= COMPAQ_CISS_MAJOR+7) + (q->request_fn)(q); if (major >= DAC960_MAJOR+0 && major <= DAC960_MAJOR+7) (q->request_fn)(q); } @@ -1128,9 +1130,6 @@ #ifdef CONFIG_SJCD sjcd_init(); #endif CONFIG_SJCD -#ifdef CONFIG_BLK_DEV_MD - md_init(); -#endif CONFIG_BLK_DEV_MD #ifdef CONFIG_APBLOCK ap_init(); #endif diff -u --recursive --new-file v2.4.0-test8/linux/drivers/block/loop.c linux/drivers/block/loop.c --- v2.4.0-test8/linux/drivers/block/loop.c Tue Sep 5 14:07:30 2000 +++ linux/drivers/block/loop.c Tue Sep 19 08:31:35 2000 @@ -584,6 +584,8 @@ type = info.lo_encrypt_type; if (type >= MAX_LO_CRYPT || xfer_funcs[type] == NULL) return -EINVAL; + if (type == LO_CRYPT_XOR && info.lo_encrypt_key_size == 0) + return -EINVAL; err = loop_release_xfer(lo); if (!err) err = loop_init_xfer(lo, type, &info); @@ -793,7 +795,6 @@ max_loop = 8; } - printk(KERN_INFO "loop: registered device at major %d\n", MAJOR_NR); printk(KERN_INFO "loop: enabling %d loop devices\n", max_loop); loop_dev = kmalloc (max_loop * sizeof(struct loop_device), GFP_KERNEL); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/block/lvm-snap.c linux/drivers/block/lvm-snap.c --- v2.4.0-test8/linux/drivers/block/lvm-snap.c Mon Aug 7 21:01:35 2000 +++ linux/drivers/block/lvm-snap.c Wed Dec 31 16:00:00 1969 @@ -1,434 +0,0 @@ -/* - * kernel/lvm-snap.c - * - * Copyright (C) 2000 Andrea Arcangeli SuSE - * - * LVM snapshot driver is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * LVM driver is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - */ - -#include -#include -#include -#include -#include -#include -#include - - -static char *lvm_snap_version __attribute__ ((unused)) = "LVM 0.8final (15/02/2000)\n"; - -extern const char *const lvm_name; -extern int lvm_blocksizes[]; - -void lvm_snapshot_release(lv_t *); - -#define hashfn(dev,block,mask,chunk_size) \ - ((HASHDEV(dev)^((block)/(chunk_size))) & (mask)) - -static inline lv_block_exception_t * -lvm_find_exception_table(kdev_t org_dev, unsigned long org_start, lv_t * lv) -{ - struct list_head * hash_table = lv->lv_snapshot_hash_table, * next; - unsigned long mask = lv->lv_snapshot_hash_mask; - int chunk_size = lv->lv_chunk_size; - lv_block_exception_t * ret; - int i = 0; - - hash_table = &hash_table[hashfn(org_dev, org_start, mask, chunk_size)]; - ret = NULL; - for (next = hash_table->next; next != hash_table; next = next->next) - { - lv_block_exception_t * exception; - - exception = list_entry(next, lv_block_exception_t, hash); - if (exception->rsector_org == org_start && - exception->rdev_org == org_dev) - { - if (i) - { - /* fun, isn't it? :) */ - list_del(next); - list_add(next, hash_table); - } - ret = exception; - break; - } - i++; - } - return ret; -} - -static inline void lvm_hash_link(lv_block_exception_t * exception, - kdev_t org_dev, unsigned long org_start, - lv_t * lv) -{ - struct list_head * hash_table = lv->lv_snapshot_hash_table; - unsigned long mask = lv->lv_snapshot_hash_mask; - int chunk_size = lv->lv_chunk_size; - - hash_table = &hash_table[hashfn(org_dev, org_start, mask, chunk_size)]; - list_add(&exception->hash, hash_table); -} - -int lvm_snapshot_remap_block(kdev_t * org_dev, unsigned long * org_sector, - unsigned long pe_start, lv_t * lv) -{ - int ret; - unsigned long pe_off, pe_adjustment, __org_start; - kdev_t __org_dev; - int chunk_size = lv->lv_chunk_size; - lv_block_exception_t * exception; - - pe_off = pe_start % chunk_size; - pe_adjustment = (*org_sector-pe_off) % chunk_size; - __org_start = *org_sector - pe_adjustment; - __org_dev = *org_dev; - - ret = 0; - exception = lvm_find_exception_table(__org_dev, __org_start, lv); - if (exception) - { - *org_dev = exception->rdev_new; - *org_sector = exception->rsector_new + pe_adjustment; - ret = 1; - } - return ret; -} - -static void lvm_drop_snapshot(lv_t * lv_snap, const char * reason) -{ - kdev_t last_dev; - int i; - - /* no exception storage space available for this snapshot - or error on this snapshot --> release it */ - invalidate_buffers(lv_snap->lv_dev); - - for (i = last_dev = 0; i < lv_snap->lv_remap_ptr; i++) { - if ( lv_snap->lv_block_exception[i].rdev_new != last_dev) { - last_dev = lv_snap->lv_block_exception[i].rdev_new; - invalidate_buffers(last_dev); - } - } - - lvm_snapshot_release(lv_snap); - - printk(KERN_INFO - "%s -- giving up to snapshot %s on %s due %s\n", - lvm_name, lv_snap->lv_snapshot_org->lv_name, lv_snap->lv_name, - reason); -} - -static inline void lvm_snapshot_prepare_blocks(unsigned long * blocks, - unsigned long start, - int nr_sectors, - int blocksize) -{ - int i, sectors_per_block, nr_blocks; - - sectors_per_block = blocksize >> 9; - nr_blocks = nr_sectors / sectors_per_block; - start /= sectors_per_block; - - for (i = 0; i < nr_blocks; i++) - blocks[i] = start++; -} - -static inline int get_blksize(kdev_t dev) -{ - int correct_size = BLOCK_SIZE, i, major; - - major = MAJOR(dev); - if (blksize_size[major]) - { - i = blksize_size[major][MINOR(dev)]; - if (i) - correct_size = i; - } - return correct_size; -} - -#ifdef DEBUG_SNAPSHOT -static inline void invalidate_snap_cache(unsigned long start, unsigned long nr, - kdev_t dev) -{ - struct buffer_head * bh; - int sectors_per_block, i, blksize, minor; - - minor = MINOR(dev); - blksize = lvm_blocksizes[minor]; - sectors_per_block = blksize >> 9; - nr /= sectors_per_block; - start /= sectors_per_block; - - for (i = 0; i < nr; i++) - { - bh = get_hash_table(dev, start++, blksize); - if (bh) - bforget(bh); - } -} -#endif - -/* - * copy on write handler for one snapshot logical volume - * - * read the original blocks and store it/them on the new one(s). - * if there is no exception storage space free any longer --> release snapshot. - * - * this routine gets called for each _first_ write to a physical chunk. - */ -int lvm_snapshot_COW(kdev_t org_phys_dev, - unsigned long org_phys_sector, - unsigned long org_pe_start, - unsigned long org_virt_sector, - lv_t * lv_snap) -{ - const char * reason; - unsigned long org_start, snap_start, snap_phys_dev, virt_start, pe_off; - int idx = lv_snap->lv_remap_ptr, chunk_size = lv_snap->lv_chunk_size; - struct kiobuf * iobuf; - unsigned long blocks[KIO_MAX_SECTORS]; - int blksize_snap, blksize_org, min_blksize, max_blksize; - int max_sectors, nr_sectors; - - /* check if we are out of snapshot space */ - if (idx >= lv_snap->lv_remap_end) - goto fail_out_of_space; - - /* calculate physical boundaries of source chunk */ - pe_off = org_pe_start % chunk_size; - org_start = org_phys_sector - ((org_phys_sector-pe_off) % chunk_size); - virt_start = org_virt_sector - (org_phys_sector - org_start); - - /* calculate physical boundaries of destination chunk */ - snap_phys_dev = lv_snap->lv_block_exception[idx].rdev_new; - snap_start = lv_snap->lv_block_exception[idx].rsector_new; - -#ifdef DEBUG_SNAPSHOT - printk(KERN_INFO - "%s -- COW: " - "org %02d:%02d faulting %lu start %lu, " - "snap %02d:%02d start %lu, " - "size %d, pe_start %lu pe_off %lu, virt_sec %lu\n", - lvm_name, - MAJOR(org_phys_dev), MINOR(org_phys_dev), org_phys_sector, - org_start, - MAJOR(snap_phys_dev), MINOR(snap_phys_dev), snap_start, - chunk_size, - org_pe_start, pe_off, - org_virt_sector); -#endif - - iobuf = lv_snap->lv_iobuf; - - blksize_org = get_blksize(org_phys_dev); - blksize_snap = get_blksize(snap_phys_dev); - max_blksize = max(blksize_org, blksize_snap); - min_blksize = min(blksize_org, blksize_snap); - max_sectors = KIO_MAX_SECTORS * (min_blksize>>9); - - if (chunk_size % (max_blksize>>9)) - goto fail_blksize; - - while (chunk_size) - { - nr_sectors = min(chunk_size, max_sectors); - chunk_size -= nr_sectors; - - iobuf->length = nr_sectors << 9; - - lvm_snapshot_prepare_blocks(blocks, org_start, - nr_sectors, blksize_org); - if (brw_kiovec(READ, 1, &iobuf, org_phys_dev, - blocks, blksize_org) != (nr_sectors<<9)) - goto fail_raw_read; - - lvm_snapshot_prepare_blocks(blocks, snap_start, - nr_sectors, blksize_snap); - if (brw_kiovec(WRITE, 1, &iobuf, snap_phys_dev, - blocks, blksize_snap) != (nr_sectors<<9)) - goto fail_raw_write; - } - -#ifdef DEBUG_SNAPSHOT - /* invalidate the logcial snapshot buffer cache */ - invalidate_snap_cache(virt_start, lv_snap->lv_chunk_size, - lv_snap->lv_dev); -#endif - - /* the original chunk is now stored on the snapshot volume - so update the execption table */ - lv_snap->lv_block_exception[idx].rdev_org = org_phys_dev; - lv_snap->lv_block_exception[idx].rsector_org = org_start; - lvm_hash_link(lv_snap->lv_block_exception + idx, - org_phys_dev, org_start, lv_snap); - lv_snap->lv_remap_ptr = idx + 1; - return 1; - - /* slow path */ - out: - lvm_drop_snapshot(lv_snap, reason); - return -1; - - fail_out_of_space: - reason = "out of space"; - goto out; - fail_raw_read: - reason = "read error"; - goto out; - fail_raw_write: - reason = "write error"; - goto out; - fail_blksize: - reason = "blocksize error"; - goto out; -} - -static int lvm_snapshot_alloc_iobuf_pages(struct kiobuf * iobuf, int sectors) -{ - int bytes, nr_pages, err, i; - - bytes = sectors << 9; - nr_pages = (bytes + ~PAGE_MASK) >> PAGE_SHIFT; - err = expand_kiobuf(iobuf, nr_pages); - if (err) - goto out; - - err = -ENOMEM; - iobuf->locked = 1; - iobuf->nr_pages = 0; - for (i = 0; i < nr_pages; i++) - { - struct page * page; - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,27) - page = alloc_page(GFP_KERNEL); - if (!page) - goto out; -#else - { - unsigned long addr = __get_free_page(GFP_USER); - if (!addr) - goto out; - iobuf->pagelist[i] = addr; - page = virt_to_page(addr); - } -#endif - - iobuf->maplist[i] = page; - /* the only point to lock the page here is to be allowed - to share unmap_kiobuf() in the fail-path */ -#ifndef LockPage -#define LockPage(map) set_bit(PG_locked, &(map)->flags) -#endif - LockPage(page); - iobuf->nr_pages++; - } - iobuf->offset = 0; - - err = 0; - out: - return err; -} - -static int calc_max_buckets(void) -{ - unsigned long mem; - - mem = num_physpages << PAGE_SHIFT; - mem /= 100; - mem *= 2; - mem /= sizeof(struct list_head); - - return mem; -} - -static int lvm_snapshot_alloc_hash_table(lv_t * lv) -{ - int err; - unsigned long buckets, max_buckets, size; - struct list_head * hash; - - buckets = lv->lv_remap_end; - max_buckets = calc_max_buckets(); - buckets = min(buckets, max_buckets); - while (buckets & (buckets-1)) - buckets &= (buckets-1); - - size = buckets * sizeof(struct list_head); - - err = -ENOMEM; - hash = vmalloc(size); - lv->lv_snapshot_hash_table = hash; - - if (!hash) - goto out; - - lv->lv_snapshot_hash_mask = buckets-1; - while (buckets--) - INIT_LIST_HEAD(hash+buckets); - err = 0; - out: - return err; -} - -int lvm_snapshot_alloc(lv_t * lv_snap) -{ - int err, blocksize, max_sectors; - - err = alloc_kiovec(1, &lv_snap->lv_iobuf); - if (err) - goto out; - - blocksize = lvm_blocksizes[MINOR(lv_snap->lv_dev)]; - max_sectors = KIO_MAX_SECTORS << (PAGE_SHIFT-9); - - err = lvm_snapshot_alloc_iobuf_pages(lv_snap->lv_iobuf, max_sectors); - if (err) - goto out_free_kiovec; - - err = lvm_snapshot_alloc_hash_table(lv_snap); - if (err) - goto out_free_kiovec; - out: - return err; - - out_free_kiovec: - unmap_kiobuf(lv_snap->lv_iobuf); - free_kiovec(1, &lv_snap->lv_iobuf); - goto out; -} - -void lvm_snapshot_release(lv_t * lv) -{ - if (lv->lv_block_exception) - { - vfree(lv->lv_block_exception); - lv->lv_block_exception = NULL; - } - if (lv->lv_snapshot_hash_table) - { - vfree(lv->lv_snapshot_hash_table); - lv->lv_snapshot_hash_table = NULL; - } - if (lv->lv_iobuf) - { - free_kiovec(1, &lv->lv_iobuf); - lv->lv_iobuf = NULL; - } -} diff -u --recursive --new-file v2.4.0-test8/linux/drivers/block/lvm.c linux/drivers/block/lvm.c --- v2.4.0-test8/linux/drivers/block/lvm.c Tue Sep 5 13:56:57 2000 +++ linux/drivers/block/lvm.c Wed Dec 31 16:00:00 1969 @@ -1,2569 +0,0 @@ -/* - * kernel/lvm.c - * - * Copyright (C) 1997 - 2000 Heinz Mauelshagen, Germany - * - * February-November 1997 - * April-May,July-August,November 1998 - * January-March,May,July,September,October 1999 - * January,February 2000 - * - * - * LVM driver is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * LVM driver is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - */ - -/* - * Changelog - * - * 09/11/1997 - added chr ioctls VG_STATUS_GET_COUNT - * and VG_STATUS_GET_NAMELIST - * 18/01/1998 - change lvm_chr_open/close lock handling - * 30/04/1998 - changed LV_STATUS ioctl to LV_STATUS_BYNAME and - * - added LV_STATUS_BYINDEX ioctl - * - used lvm_status_byname_req_t and - * lvm_status_byindex_req_t vars - * 04/05/1998 - added multiple device support - * 08/05/1998 - added support to set/clear extendable flag in volume group - * 09/05/1998 - changed output of lvm_proc_get_info() because of - * support for free (eg. longer) logical volume names - * 12/05/1998 - added spin_locks (thanks to Pascal van Dam - * ) - * 25/05/1998 - fixed handling of locked PEs in lvm_map() and lvm_chr_ioctl() - * 26/05/1998 - reactivated verify_area by access_ok - * 07/06/1998 - used vmalloc/vfree instead of kmalloc/kfree to go - * beyond 128/256 KB max allocation limit per call - * - #ifdef blocked spin_lock calls to avoid compile errors - * with 2.0.x - * 11/06/1998 - another enhancement to spinlock code in lvm_chr_open() - * and use of LVM_VERSION_CODE instead of my own macros - * (thanks to Michael Marxmeier ) - * 07/07/1998 - added statistics in lvm_map() - * 08/07/1998 - saved statistics in lvm_do_lv_extend_reduce() - * 25/07/1998 - used __initfunc macro - * 02/08/1998 - changes for official char/block major numbers - * 07/08/1998 - avoided init_module() and cleanup_module() to be static - * 30/08/1998 - changed VG lv_open counter from sum of LV lv_open counters - * to sum of LVs open (no matter how often each is) - * 01/09/1998 - fixed lvm_gendisk.part[] index error - * 07/09/1998 - added copying of lv_current_pe-array - * in LV_STATUS_BYINDEX ioctl - * 17/11/1998 - added KERN_* levels to printk - * 13/01/1999 - fixed LV index bug in lvm_do_lv_create() which hit lvrename - * 07/02/1999 - fixed spinlock handling bug in case of LVM_RESET - * by moving spinlock code from lvm_chr_open() - * to lvm_chr_ioctl() - * - added LVM_LOCK_LVM ioctl to lvm_chr_ioctl() - * - allowed LVM_RESET and retrieval commands to go ahead; - * only other update ioctls are blocked now - * - fixed pv->pe to NULL for pv_status - * - using lv_req structure in lvm_chr_ioctl() now - * - fixed NULL ptr reference bug in lvm_do_lv_extend_reduce() - * caused by uncontiguous PV array in lvm_chr_ioctl(VG_REDUCE) - * 09/02/1999 - changed BLKRASET and BLKRAGET in lvm_chr_ioctl() to - * handle lgoical volume private read ahead sector - * - implemented LV read_ahead handling with lvm_blk_read() - * and lvm_blk_write() - * 10/02/1999 - implemented 2.[12].* support function lvm_hd_name() - * to be used in drivers/block/genhd.c by disk_name() - * 12/02/1999 - fixed index bug in lvm_blk_ioctl(), HDIO_GETGEO - * - enhanced gendisk insert/remove handling - * 16/02/1999 - changed to dynamic block minor number allocation to - * have as much as 99 volume groups with 256 logical volumes - * as the grand total; this allows having 1 volume group with - * up to 256 logical volumes in it - * 21/02/1999 - added LV open count information to proc filesystem - * - substituted redundant LVM_RESET code by calls - * to lvm_do_vg_remove() - * 22/02/1999 - used schedule_timeout() to be more responsive - * in case of lvm_do_vg_remove() with lots of logical volumes - * 19/03/1999 - fixed NULL pointer bug in module_init/lvm_init - * 17/05/1999 - used DECLARE_WAIT_QUEUE_HEAD macro (>2.3.0) - * - enhanced lvm_hd_name support - * 03/07/1999 - avoided use of KERNEL_VERSION macro based ifdefs and - * memcpy_tofs/memcpy_fromfs macro redefinitions - * 06/07/1999 - corrected reads/writes statistic counter copy in case - * of striped logical volume - * 28/07/1999 - implemented snapshot logical volumes - * - lvm_chr_ioctl - * - LV_STATUS_BYINDEX - * - LV_STATUS_BYNAME - * - lvm_do_lv_create - * - lvm_do_lv_remove - * - lvm_map - * - new lvm_snapshot_remap_block - * - new lvm_snapshot_remap_new_block - * 08/10/1999 - implemented support for multiple snapshots per - * original logical volume - * 12/10/1999 - support for 2.3.19 - * 11/11/1999 - support for 2.3.28 - * 21/11/1999 - changed lvm_map() interface to buffer_head based - * 19/12/1999 - support for 2.3.33 - * 01/01/2000 - changed locking concept in lvm_map(), - * lvm_do_vg_create() and lvm_do_lv_remove() - * 15/01/2000 - fixed PV_FLUSH bug in lvm_chr_ioctl() - * 24/01/2000 - ported to 2.3.40 including Alan Cox's pointer changes etc. - * 29/01/2000 - used kmalloc/kfree again for all small structures - * 20/01/2000 - cleaned up lvm_chr_ioctl by moving code - * to seperated functions - * - avoided "/dev/" in proc filesystem output - * - avoided inline strings functions lvm_strlen etc. - * 14/02/2000 - support for 2.3.43 - * - integrated Andrea Arcangeli's snapshot code - * - */ - - -static char *lvm_version = "LVM version 0.8final by Heinz Mauelshagen (15/02/2000)\n"; -static char *lvm_short_version = "version 0.8final (15/02/2000)"; - -#define MAJOR_NR LVM_BLK_MAJOR -#define DEVICE_OFF(device) - -#include -#include - -#ifdef MODVERSIONS -#undef MODULE -#define MODULE -#include -#endif - -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_KERNELD -#include -#endif - -#define LOCAL_END_REQUEST - -#include -#include - -#include -#include - -#define LVM_CORRECT_READ_AHEAD(a) \ - (((a) < LVM_MIN_READ_AHEAD || (a) > LVM_MAX_READ_AHEAD) \ - ? LVM_MAX_READ_AHEAD : (a)) - -#ifndef WRITEA -# define WRITEA WRITE -#endif - -/* - * External function prototypes - */ -#ifdef MODULE -int init_module(void); -void cleanup_module(void); -#else -extern int lvm_init(void); -#endif - -static void lvm_dummy_device_request(request_queue_t *); -#define DEVICE_REQUEST lvm_dummy_device_request - -static int lvm_make_request_fn(request_queue_t *, int, struct buffer_head*); -static void lvm_plug_device_noop(request_queue_t *, kdev_t); - -static int lvm_blk_ioctl(struct inode *, struct file *, uint, ulong); -static int lvm_blk_open(struct inode *, struct file *); - -static int lvm_chr_open(struct inode *, struct file *); - -static int lvm_chr_close(struct inode *, struct file *); -static int lvm_blk_close(struct inode *, struct file *); - -static int lvm_chr_ioctl(struct inode *, struct file *, uint, ulong); - -#if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS -static int lvm_proc_get_info(char *, char **, off_t, int); -static int (*lvm_proc_get_info_ptr) (char *, char **, off_t, int) = -&lvm_proc_get_info; -#endif - -#ifdef LVM_HD_NAME -void lvm_hd_name(char *, int); -#endif -/* End external function prototypes */ - - -/* - * Internal function prototypes - */ -static void lvm_init_vars(void); - -/* external snapshot calls */ -int lvm_snapshot_remap_block(kdev_t *, ulong *, ulong, lv_t *); -int lvm_snapshot_COW(kdev_t, ulong, ulong, ulong, lv_t *); -int lvm_snapshot_alloc(lv_t *); -void lvm_snapshot_release(lv_t *); - -#ifdef LVM_HD_NAME -extern void (*lvm_hd_name_ptr) (char *, int); -#endif -static int lvm_map(struct buffer_head *, int); -static int lvm_do_lock_lvm(void); -static int lvm_do_le_remap(vg_t *, void *); -static int lvm_do_pe_lock_unlock(vg_t *r, void *); -static int lvm_do_vg_create(int, void *); -static int lvm_do_vg_extend(vg_t *, void *); -static int lvm_do_vg_reduce(vg_t *, void *); -static int lvm_do_vg_remove(int); -static int lvm_do_lv_create(int, char *, lv_t *); -static int lvm_do_lv_remove(int, char *, int); -static int lvm_do_lv_extend_reduce(int, char *, lv_t *); -static int lvm_do_lv_status_byname(vg_t *r, void *); -static int lvm_do_lv_status_byindex(vg_t *, void *arg); -static int lvm_do_pv_change(vg_t*, void*); -static int lvm_do_pv_status(vg_t *, void *); -static void lvm_geninit(struct gendisk *); -#ifdef LVM_GET_INODE -static struct inode *lvm_get_inode(int); -void lvm_clear_inode(struct inode *); -#endif -/* END Internal function prototypes */ - - -/* volume group descriptor area pointers */ -static vg_t *vg[ABS_MAX_VG]; -static pv_t *pvp = NULL; -static lv_t *lvp = NULL; -static pe_t *pep = NULL; -static pe_t *pep1 = NULL; - - -/* map from block minor number to VG and LV numbers */ -typedef struct { - int vg_number; - int lv_number; -} vg_lv_map_t; -static vg_lv_map_t vg_lv_map[ABS_MAX_LV]; - - -/* Request structures (lvm_chr_ioctl()) */ -static pv_change_req_t pv_change_req; -static pv_flush_req_t pv_flush_req; -static pv_status_req_t pv_status_req; -static pe_lock_req_t pe_lock_req; -static le_remap_req_t le_remap_req; -static lv_req_t lv_req; - -#ifdef LVM_TOTAL_RESET -static int lvm_reset_spindown = 0; -#endif - -static char pv_name[NAME_LEN]; -/* static char rootvg[NAME_LEN] = { 0, }; */ -static uint lv_open = 0; -const char *const lvm_name = LVM_NAME; -static int lock = 0; -static int loadtime = 0; -static uint vg_count = 0; -static long lvm_chr_open_count = 0; -static ushort lvm_iop_version = LVM_DRIVER_IOP_VERSION; -static DECLARE_WAIT_QUEUE_HEAD(lvm_snapshot_wait); -static DECLARE_WAIT_QUEUE_HEAD(lvm_wait); -static DECLARE_WAIT_QUEUE_HEAD(lvm_map_wait); - -static spinlock_t lvm_lock = SPIN_LOCK_UNLOCKED; - -static devfs_handle_t lvm_devfs_handle; -static devfs_handle_t vg_devfs_handle[MAX_VG]; -static devfs_handle_t ch_devfs_handle[MAX_VG]; -static devfs_handle_t lv_devfs_handle[MAX_LV]; - -static struct file_operations lvm_chr_fops = -{ - owner: THIS_MODULE, - open: lvm_chr_open, - release: lvm_chr_close, - ioctl: lvm_chr_ioctl, -}; - -static struct block_device_operations lvm_blk_dops = -{ - open: lvm_blk_open, - release: lvm_blk_close, - ioctl: lvm_blk_ioctl -}; - -/* gendisk structures */ -static struct hd_struct lvm_hd_struct[MAX_LV]; -static int lvm_blocksizes[MAX_LV] = -{0,}; -static int lvm_size[MAX_LV] = -{0,}; -static struct gendisk lvm_gendisk = -{ - MAJOR_NR, /* major # */ - LVM_NAME, /* name of major */ - 0, /* number of times minor is shifted - to get real minor */ - 1, /* maximum partitions per device */ - lvm_hd_struct, /* partition table */ - lvm_size, /* device size in blocks, copied - to block_size[] */ - MAX_LV, /* number or real devices */ - NULL, /* internal */ - NULL, /* pointer to next gendisk struct (internal) */ -}; - - -#ifdef MODULE -/* - * Module initialization... - */ -int init_module(void) -#else -/* - * Driver initialization... - */ -#ifdef __initfunc -__initfunc(int lvm_init(void)) -#else -int __init lvm_init(void) -#endif -#endif /* #ifdef MODULE */ -{ - struct gendisk *gendisk_ptr = NULL; - - if (register_chrdev(LVM_CHAR_MAJOR, lvm_name, &lvm_chr_fops) < 0) { - printk(KERN_ERR "%s -- register_chrdev failed\n", lvm_name); - return -EIO; - } - if (register_blkdev(MAJOR_NR, lvm_name, &lvm_blk_dops) < 0) { - printk("%s -- register_blkdev failed\n", lvm_name); - if (unregister_chrdev(LVM_CHAR_MAJOR, lvm_name) < 0) - printk(KERN_ERR "%s -- unregister_chrdev failed\n", lvm_name); - return -EIO; - } - - lvm_devfs_handle = devfs_register( - 0 , "lvm", 0, 0, LVM_CHAR_MAJOR, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, - &lvm_chr_fops, NULL); - -#if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS - create_proc_info_entry(LVM_NAME, S_IFREG | S_IRUGO, - &proc_root, lvm_proc_get_info_ptr); -#endif - - lvm_init_vars(); - lvm_geninit(&lvm_gendisk); - - /* insert our gendisk at the corresponding major */ - if (gendisk_head != NULL) { - gendisk_ptr = gendisk_head; - while (gendisk_ptr->next != NULL && - gendisk_ptr->major > lvm_gendisk.major) { - gendisk_ptr = gendisk_ptr->next; - } - lvm_gendisk.next = gendisk_ptr->next; - gendisk_ptr->next = &lvm_gendisk; - } else { - gendisk_head = &lvm_gendisk; - lvm_gendisk.next = NULL; - } - -#ifdef LVM_HD_NAME - /* reference from drivers/block/genhd.c */ - lvm_hd_name_ptr = lvm_hd_name; -#endif - - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); - blk_queue_make_request(BLK_DEFAULT_QUEUE(MAJOR_NR), lvm_make_request_fn); - blk_queue_pluggable(BLK_DEFAULT_QUEUE(MAJOR_NR), lvm_plug_device_noop); - /* optional read root VGDA */ -/* - if ( *rootvg != 0) vg_read_with_pv_and_lv ( rootvg, &vg); -*/ - - printk(KERN_INFO - "%s%s -- " -#ifdef MODULE - "Module" -#else - "Driver" -#endif - " successfully initialized\n", - lvm_version, lvm_name); - - return 0; -} /* init_module() / lvm_init() */ - - -#ifdef MODULE -/* - * Module cleanup... - */ -void cleanup_module(void) -{ - struct gendisk *gendisk_ptr = NULL, *gendisk_ptr_prev = NULL; - - devfs_unregister (lvm_devfs_handle); - - if (unregister_chrdev(LVM_CHAR_MAJOR, lvm_name) < 0) { - printk(KERN_ERR "%s -- unregister_chrdev failed\n", lvm_name); - } - if (unregister_blkdev(MAJOR_NR, lvm_name) < 0) { - printk(KERN_ERR "%s -- unregister_blkdev failed\n", lvm_name); - } - blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); - - gendisk_ptr = gendisk_ptr_prev = gendisk_head; - while (gendisk_ptr != NULL) { - if (gendisk_ptr == &lvm_gendisk) - break; - gendisk_ptr_prev = gendisk_ptr; - gendisk_ptr = gendisk_ptr->next; - } - /* delete our gendisk from chain */ - if (gendisk_ptr == &lvm_gendisk) - gendisk_ptr_prev->next = gendisk_ptr->next; - - blk_size[MAJOR_NR] = NULL; - blksize_size[MAJOR_NR] = NULL; - -#if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS - remove_proc_entry(LVM_NAME, &proc_root); -#endif - -#ifdef LVM_HD_NAME - /* reference from linux/drivers/block/genhd.c */ - lvm_hd_name_ptr = NULL; -#endif - - printk(KERN_INFO "%s -- Module successfully deactivated\n", lvm_name); - - return; -} /* void cleanup_module() */ -#endif /* #ifdef MODULE */ - - -/* - * support function to initialize lvm variables - */ -#ifdef __initfunc -__initfunc(void lvm_init_vars(void)) -#else -void __init lvm_init_vars(void) -#endif -{ - int v; - - loadtime = CURRENT_TIME; - - pe_lock_req.lock = UNLOCK_PE; - pe_lock_req.data.lv_dev = \ - pe_lock_req.data.pv_dev = \ - pe_lock_req.data.pv_offset = 0; - - /* Initialize VG pointers */ - for (v = 0; v < ABS_MAX_VG; v++) vg[v] = NULL; - - /* Initialize LV -> VG association */ - for (v = 0; v < ABS_MAX_LV; v++) { - /* index ABS_MAX_VG never used for real VG */ - vg_lv_map[v].vg_number = ABS_MAX_VG; - vg_lv_map[v].lv_number = -1; - } - - return; -} /* lvm_init_vars() */ - - -/******************************************************************** - * - * Character device functions - * - ********************************************************************/ - -/* - * character device open routine - */ -static int lvm_chr_open(struct inode *inode, - struct file *file) -{ - int minor = MINOR(inode->i_rdev); - -#ifdef DEBUG - printk(KERN_DEBUG - "%s -- lvm_chr_open MINOR: %d VG#: %d mode: 0x%X lock: %d\n", - lvm_name, minor, VG_CHR(minor), file->f_mode, lock); -#endif - - /* super user validation */ - if (!capable(CAP_SYS_ADMIN)) return -EACCES; - - /* Group special file open */ - if (VG_CHR(minor) > MAX_VG) return -ENXIO; - - lvm_chr_open_count++; - return 0; -} /* lvm_chr_open() */ - - -/* - * character device i/o-control routine - * - * Only one changing process can do changing ioctl at one time, - * others will block. - * - */ -static int lvm_chr_ioctl(struct inode *inode, struct file *file, - uint command, ulong a) -{ - int minor = MINOR(inode->i_rdev); - uint extendable, l, v; - void *arg = (void *) a; - lv_t lv; - vg_t* vg_ptr = vg[VG_CHR(minor)]; - - /* otherwise cc will complain about unused variables */ - (void) lvm_lock; - - -#ifdef DEBUG_IOCTL - printk(KERN_DEBUG - "%s -- lvm_chr_ioctl: command: 0x%X MINOR: %d " - "VG#: %d mode: 0x%X\n", - lvm_name, command, minor, VG_CHR(minor), file->f_mode); -#endif - -#ifdef LVM_TOTAL_RESET - if (lvm_reset_spindown > 0) return -EACCES; -#endif - - /* Main command switch */ - switch (command) { - case LVM_LOCK_LVM: - /* lock the LVM */ - return lvm_do_lock_lvm(); - - case LVM_GET_IOP_VERSION: - /* check lvm version to ensure driver/tools+lib - interoperability */ - if (copy_to_user(arg, &lvm_iop_version, sizeof(ushort)) != 0) - return -EFAULT; - return 0; - -#ifdef LVM_TOTAL_RESET - case LVM_RESET: - /* lock reset function */ - lvm_reset_spindown = 1; - for (v = 0; v < ABS_MAX_VG; v++) { - if (vg[v] != NULL) lvm_do_vg_remove(v); - } - -#ifdef MODULE - while (GET_USE_COUNT(&__this_module) < 1) - MOD_INC_USE_COUNT; - while (GET_USE_COUNT(&__this_module) > 1) - MOD_DEC_USE_COUNT; -#endif /* MODULE */ - lock = 0; /* release lock */ - wake_up_interruptible(&lvm_wait); - return 0; -#endif /* LVM_TOTAL_RESET */ - - - case LE_REMAP: - /* remap a logical extent (after moving the physical extent) */ - return lvm_do_le_remap(vg_ptr,arg); - - case PE_LOCK_UNLOCK: - /* lock/unlock i/o to a physical extent to move it to another - physical volume (move's done in user space's pvmove) */ - return lvm_do_pe_lock_unlock(vg_ptr,arg); - - case VG_CREATE: - /* create a VGDA */ - return lvm_do_vg_create(minor, arg); - - case VG_REMOVE: - /* remove an inactive VGDA */ - return lvm_do_vg_remove(minor); - - case VG_EXTEND: - /* extend a volume group */ - return lvm_do_vg_extend(vg_ptr,arg); - - case VG_REDUCE: - /* reduce a volume group */ - return lvm_do_vg_reduce(vg_ptr,arg); - - - case VG_SET_EXTENDABLE: - /* set/clear extendability flag of volume group */ - if (vg_ptr == NULL) return -ENXIO; - if (copy_from_user(&extendable, arg, sizeof(extendable)) != 0) - return -EFAULT; - - if (extendable == VG_EXTENDABLE || - extendable == ~VG_EXTENDABLE) { - if (extendable == VG_EXTENDABLE) - vg_ptr->vg_status |= VG_EXTENDABLE; - else - vg_ptr->vg_status &= ~VG_EXTENDABLE; - } else return -EINVAL; - return 0; - - - case VG_STATUS: - /* get volume group data (only the vg_t struct) */ - if (vg_ptr == NULL) return -ENXIO; - if (copy_to_user(arg, vg_ptr, sizeof(vg_t)) != 0) - return -EFAULT; - return 0; - - - case VG_STATUS_GET_COUNT: - /* get volume group count */ - if (copy_to_user(arg, &vg_count, sizeof(vg_count)) != 0) - return -EFAULT; - return 0; - - - case VG_STATUS_GET_NAMELIST: - /* get volume group count */ - for (l = v = 0; v < ABS_MAX_VG; v++) { - if (vg[v] != NULL) { - if (copy_to_user(arg + l++ * NAME_LEN, - vg[v]->vg_name, - NAME_LEN) != 0) - return -EFAULT; - } - } - return 0; - - - case LV_CREATE: - case LV_REMOVE: - case LV_EXTEND: - case LV_REDUCE: - /* create, remove, extend or reduce a logical volume */ - if (vg_ptr == NULL) return -ENXIO; - if (copy_from_user(&lv_req, arg, sizeof(lv_req)) != 0) - return -EFAULT; - - if (command != LV_REMOVE) { - if (copy_from_user(&lv, lv_req.lv, sizeof(lv_t)) != 0) - return -EFAULT; - } - switch (command) { - case LV_CREATE: - return lvm_do_lv_create(minor, lv_req.lv_name, &lv); - - case LV_REMOVE: - return lvm_do_lv_remove(minor, lv_req.lv_name, -1); - - case LV_EXTEND: - case LV_REDUCE: - return lvm_do_lv_extend_reduce(minor, lv_req.lv_name, &lv); - } - - - case LV_STATUS_BYNAME: - /* get status of a logical volume by name */ - return lvm_do_lv_status_byname(vg_ptr,arg); - - case LV_STATUS_BYINDEX: - /* get status of a logical volume by index */ - return lvm_do_lv_status_byindex(vg_ptr,arg); - - case PV_CHANGE: - /* change a physical volume */ - return lvm_do_pv_change(vg_ptr,arg); - - case PV_STATUS: - /* get physical volume data (pv_t structure only) */ - return lvm_do_pv_status(vg_ptr,arg); - - case PV_FLUSH: - /* physical volume buffer flush/invalidate */ - if (copy_from_user(&pv_flush_req, arg, - sizeof(pv_flush_req)) != 0) - return -EFAULT; - - for ( v = 0; v < ABS_MAX_VG; v++) { - unsigned int p; - if ( vg[v] == NULL) continue; - for ( p = 0; p < vg[v]->pv_max; p++) { - if ( vg[v]->pv[p] != NULL && - strcmp ( vg[v]->pv[p]->pv_name, - pv_flush_req.pv_name) == 0) { - fsync_dev ( vg[v]->pv[p]->pv_dev); - invalidate_buffers ( vg[v]->pv[p]->pv_dev); - return 0; - } - } - } - return 0; - - default: - printk(KERN_WARNING - "%s -- lvm_chr_ioctl: unknown command %x\n", - lvm_name, command); - return -EINVAL; - } - - return 0; -} /* lvm_chr_ioctl */ - - -/* - * character device close routine - */ -static int lvm_chr_close(struct inode *inode, struct file *file) -{ -#ifdef DEBUG - int minor = MINOR(inode->i_rdev); - printk(KERN_DEBUG - "%s -- lvm_chr_close VG#: %d\n", lvm_name, VG_CHR(minor)); -#endif - - lock_kernel(); -#ifdef LVM_TOTAL_RESET - if (lvm_reset_spindown > 0) { - lvm_reset_spindown = 0; - lvm_chr_open_count = 1; - } -#endif - - if (lvm_chr_open_count > 0) lvm_chr_open_count--; - if (lock == current->pid) { - lock = 0; /* release lock */ - wake_up_interruptible(&lvm_wait); - } - unlock_kernel(); - - return 0; -} /* lvm_chr_close() */ - - - -/******************************************************************** - * - * Block device functions - * - ********************************************************************/ - -/* - * block device open routine - */ -static int lvm_blk_open(struct inode *inode, struct file *file) -{ - int minor = MINOR(inode->i_rdev); - lv_t *lv_ptr; - vg_t *vg_ptr = vg[VG_BLK(minor)]; - -#ifdef DEBUG_LVM_BLK_OPEN - printk(KERN_DEBUG - "%s -- lvm_blk_open MINOR: %d VG#: %d LV#: %d mode: 0x%X\n", - lvm_name, minor, VG_BLK(minor), LV_BLK(minor), file->f_mode); -#endif - -#ifdef LVM_TOTAL_RESET - if (lvm_reset_spindown > 0) - return -EPERM; -#endif - - if (vg_ptr != NULL && - (vg_ptr->vg_status & VG_ACTIVE) && - (lv_ptr = vg_ptr->lv[LV_BLK(minor)]) != NULL && - LV_BLK(minor) >= 0 && - LV_BLK(minor) < vg_ptr->lv_max) { - - /* Check parallel LV spindown (LV remove) */ - if (lv_ptr->lv_status & LV_SPINDOWN) return -EPERM; - - /* Check inactive LV and open for read/write */ - if (file->f_mode & O_RDWR) { - if (!(lv_ptr->lv_status & LV_ACTIVE)) return -EPERM; - if (!(lv_ptr->lv_access & LV_WRITE)) return -EACCES; - } - - /* be sure to increment VG counter */ - if (lv_ptr->lv_open == 0) vg_ptr->lv_open++; - lv_ptr->lv_open++; - - MOD_INC_USE_COUNT; - -#ifdef DEBUG_LVM_BLK_OPEN - printk(KERN_DEBUG - "%s -- lvm_blk_open MINOR: %d VG#: %d LV#: %d size: %d\n", - lvm_name, minor, VG_BLK(minor), LV_BLK(minor), - lv_ptr->lv_size); -#endif - - return 0; - } - return -ENXIO; -} /* lvm_blk_open() */ - - -/* - * block device i/o-control routine - */ -static int lvm_blk_ioctl(struct inode *inode, struct file *file, - uint command, ulong a) -{ - int minor = MINOR(inode->i_rdev); - vg_t *vg_ptr = vg[VG_BLK(minor)]; - lv_t *lv_ptr = vg_ptr->lv[LV_BLK(minor)]; - void *arg = (void *) a; - struct hd_geometry *hd = (struct hd_geometry *) a; - -#ifdef DEBUG_IOCTL - printk(KERN_DEBUG - "%s -- lvm_blk_ioctl MINOR: %d command: 0x%X arg: %X " - "VG#: %dl LV#: %d\n", - lvm_name, minor, command, (ulong) arg, - VG_BLK(minor), LV_BLK(minor)); -#endif - - switch (command) { - case BLKGETSIZE: - /* return device size */ -#ifdef DEBUG_IOCTL - printk(KERN_DEBUG - "%s -- lvm_blk_ioctl -- BLKGETSIZE: %u\n", - lvm_name, lv_ptr->lv_size); -#endif - if (put_user(lv_ptr->lv_size, (long *)arg)) - return -EFAULT; - break; - - - case BLKFLSBUF: - /* flush buffer cache */ - if (!capable(CAP_SYS_ADMIN)) return -EACCES; - -#ifdef DEBUG_IOCTL - printk(KERN_DEBUG - "%s -- lvm_blk_ioctl -- BLKFLSBUF\n", lvm_name); -#endif - fsync_dev(inode->i_rdev); - invalidate_buffers(inode->i_rdev); - break; - - - case BLKRASET: - /* set read ahead for block device */ - if (!capable(CAP_SYS_ADMIN)) return -EACCES; - -#ifdef DEBUG_IOCTL - printk(KERN_DEBUG - "%s -- lvm_blk_ioctl -- BLKRASET: %d sectors for %02X:%02X\n", - lvm_name, (long) arg, MAJOR(inode->i_rdev), minor); -#endif - if ((long) arg < LVM_MIN_READ_AHEAD || - (long) arg > LVM_MAX_READ_AHEAD) - return -EINVAL; - read_ahead[MAJOR_NR] = lv_ptr->lv_read_ahead = (long) arg; - break; - - - case BLKRAGET: - /* get current read ahead setting */ -#ifdef DEBUG_IOCTL - printk(KERN_DEBUG - "%s -- lvm_blk_ioctl -- BLKRAGET\n", lvm_name); -#endif - if (put_user(lv_ptr->lv_read_ahead, (long *)arg)) - return -EFAULT; - break; - - - case HDIO_GETGEO: - /* get disk geometry */ -#ifdef DEBUG_IOCTL - printk(KERN_DEBUG - "%s -- lvm_blk_ioctl -- HDIO_GETGEO\n", lvm_name); -#endif - if (hd == NULL) - return -EINVAL; - { - unsigned char heads = 64; - unsigned char sectors = 32; - long start = 0; - short cylinders = lv_ptr->lv_size / heads / sectors; - - if (copy_to_user((char *) &hd->heads, &heads, - sizeof(heads)) != 0 || - copy_to_user((char *) &hd->sectors, §ors, - sizeof(sectors)) != 0 || - copy_to_user((short *) &hd->cylinders, - &cylinders, sizeof(cylinders)) != 0 || - copy_to_user((long *) &hd->start, &start, - sizeof(start)) != 0) - return -EFAULT; - } - -#ifdef DEBUG_IOCTL - printk(KERN_DEBUG - "%s -- lvm_blk_ioctl -- cylinders: %d\n", - lvm_name, lv_ptr->lv_size / heads / sectors); -#endif - break; - - - case LV_SET_ACCESS: - /* set access flags of a logical volume */ - if (!capable(CAP_SYS_ADMIN)) return -EACCES; - lv_ptr->lv_access = (ulong) arg; - break; - - - case LV_SET_STATUS: - /* set status flags of a logical volume */ - if (!capable(CAP_SYS_ADMIN)) return -EACCES; - if (!((ulong) arg & LV_ACTIVE) && lv_ptr->lv_open > 1) - return -EPERM; - lv_ptr->lv_status = (ulong) arg; - break; - - - case LV_SET_ALLOCATION: - /* set allocation flags of a logical volume */ - if (!capable(CAP_SYS_ADMIN)) return -EACCES; - lv_ptr->lv_allocation = (ulong) arg; - break; - - - default: - printk(KERN_WARNING - "%s -- lvm_blk_ioctl: unknown command %d\n", - lvm_name, command); - return -EINVAL; - } - - return 0; -} /* lvm_blk_ioctl() */ - - -/* - * block device close routine - */ -static int lvm_blk_close(struct inode *inode, struct file *file) -{ - int minor = MINOR(inode->i_rdev); - vg_t *vg_ptr = vg[VG_BLK(minor)]; - lv_t *lv_ptr = vg_ptr->lv[LV_BLK(minor)]; - -#ifdef DEBUG - printk(KERN_DEBUG - "%s -- lvm_blk_close MINOR: %d VG#: %d LV#: %d\n", - lvm_name, minor, VG_BLK(minor), LV_BLK(minor)); -#endif - - sync_dev(inode->i_rdev); - if (lv_ptr->lv_open == 1) vg_ptr->lv_open--; - lv_ptr->lv_open--; - - MOD_DEC_USE_COUNT; - - return 0; -} /* lvm_blk_close() */ - - -#if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS -/* - * Support function /proc-Filesystem - */ -#define LVM_PROC_BUF ( i == 0 ? dummy_buf : &buf[sz]) - -static int lvm_proc_get_info(char *page, char **start, off_t pos, int count) -{ - int c, i, l, p, v, vg_counter, pv_counter, lv_counter, lv_open_counter, - lv_open_total, pe_t_bytes, lv_block_exception_t_bytes, seconds; - static off_t sz; - off_t sz_last; - char allocation_flag, inactive_flag, rw_flag, stripes_flag; - char *lv_name, *pv_name; - static char *buf = NULL; - static char dummy_buf[160]; /* sized for 2 lines */ - vg_t *vg_ptr; - lv_t *lv_ptr; - pv_t *pv_ptr; - - -#ifdef DEBUG_LVM_PROC_GET_INFO - printk(KERN_DEBUG - "%s - lvm_proc_get_info CALLED pos: %lu count: %d whence: %d\n", - lvm_name, pos, count, whence); -#endif - - if (pos == 0 || buf == NULL) { - sz_last = vg_counter = pv_counter = lv_counter = lv_open_counter = \ - lv_open_total = pe_t_bytes = lv_block_exception_t_bytes = 0; - - /* search for activity */ - for (v = 0; v < ABS_MAX_VG; v++) { - if ((vg_ptr = vg[v]) != NULL) { - vg_counter++; - pv_counter += vg_ptr->pv_cur; - lv_counter += vg_ptr->lv_cur; - if (vg_ptr->lv_cur > 0) { - for (l = 0; l < vg[v]->lv_max; l++) { - if ((lv_ptr = vg_ptr->lv[l]) != NULL) { - pe_t_bytes += lv_ptr->lv_allocated_le; - if (lv_ptr->lv_block_exception != NULL) - lv_block_exception_t_bytes += lv_ptr->lv_remap_end; - if (lv_ptr->lv_open > 0) { - lv_open_counter++; - lv_open_total += lv_ptr->lv_open; - } - } - } - } - } - } - pe_t_bytes *= sizeof(pe_t); - lv_block_exception_t_bytes *= sizeof(lv_block_exception_t); - - if (buf != NULL) { -#ifdef DEBUG_KFREE - printk(KERN_DEBUG - "%s -- kfree %d\n", lvm_name, __LINE__); -#endif - kfree(buf); - buf = NULL; - } - /* 2 times: first to get size to allocate buffer, - 2nd to fill the malloced buffer */ - for (i = 0; i < 2; i++) { - sz = 0; - sz += sprintf(LVM_PROC_BUF, - "LVM " -#ifdef MODULE - "module" -#else - "driver" -#endif - " %s\n\n" - "Total: %d VG%s %d PV%s %d LV%s ", - lvm_short_version, - vg_counter, vg_counter == 1 ? "" : "s", - pv_counter, pv_counter == 1 ? "" : "s", - lv_counter, lv_counter == 1 ? "" : "s"); - sz += sprintf(LVM_PROC_BUF, - "(%d LV%s open", - lv_open_counter, - lv_open_counter == 1 ? "" : "s"); - if (lv_open_total > 0) - sz += sprintf(LVM_PROC_BUF, - " %d times)\n", - lv_open_total); - else - sz += sprintf(LVM_PROC_BUF, ")"); - sz += sprintf(LVM_PROC_BUF, - "\nGlobal: %lu bytes malloced IOP version: %d ", - vg_counter * sizeof(vg_t) + - pv_counter * sizeof(pv_t) + - lv_counter * sizeof(lv_t) + - pe_t_bytes + lv_block_exception_t_bytes + sz_last, - lvm_iop_version); - - seconds = CURRENT_TIME - loadtime; - if (seconds < 0) - loadtime = CURRENT_TIME + seconds; - if (seconds / 86400 > 0) { - sz += sprintf(LVM_PROC_BUF, "%d day%s ", - seconds / 86400, - seconds / 86400 == 0 || - seconds / 86400 > 1 ? "s" : ""); - } - sz += sprintf(LVM_PROC_BUF, "%d:%02d:%02d active\n", - (seconds % 86400) / 3600, - (seconds % 3600) / 60, - seconds % 60); - - if (vg_counter > 0) { - for (v = 0; v < ABS_MAX_VG; v++) { - /* volume group */ - if ((vg_ptr = vg[v]) != NULL) { - inactive_flag = ' '; - if (!(vg_ptr->vg_status & VG_ACTIVE)) inactive_flag = 'I'; - sz += sprintf(LVM_PROC_BUF, - "\nVG: %c%s [%d PV, %d LV/%d open] " - " PE Size: %d KB\n" - " Usage [KB/PE]: %d /%d total " - "%d /%d used %d /%d free", - inactive_flag, - vg_ptr->vg_name, - vg_ptr->pv_cur, - vg_ptr->lv_cur, - vg_ptr->lv_open, - vg_ptr->pe_size >> 1, - vg_ptr->pe_size * vg_ptr->pe_total >> 1, - vg_ptr->pe_total, - vg_ptr->pe_allocated * vg_ptr->pe_size >> 1, - vg_ptr->pe_allocated, - (vg_ptr->pe_total - vg_ptr->pe_allocated) * - vg_ptr->pe_size >> 1, - vg_ptr->pe_total - vg_ptr->pe_allocated); - - /* physical volumes */ - sz += sprintf(LVM_PROC_BUF, - "\n PV%s ", - vg_ptr->pv_cur == 1 ? ": " : "s:"); - c = 0; - for (p = 0; p < vg_ptr->pv_max; p++) { - if ((pv_ptr = vg_ptr->pv[p]) != NULL) { - inactive_flag = 'A'; - if (!(pv_ptr->pv_status & PV_ACTIVE)) - inactive_flag = 'I'; - allocation_flag = 'A'; - if (!(pv_ptr->pv_allocatable & PV_ALLOCATABLE)) - allocation_flag = 'N'; - pv_name = strchr(pv_ptr->pv_name+1,'/'); - if ( pv_name == 0) pv_name = pv_ptr->pv_name; - else pv_name++; - sz += sprintf(LVM_PROC_BUF, - "[%c%c] %-21s %8d /%-6d " - "%8d /%-6d %8d /%-6d", - inactive_flag, - allocation_flag, - pv_name, - pv_ptr->pe_total * - pv_ptr->pe_size >> 1, - pv_ptr->pe_total, - pv_ptr->pe_allocated * - pv_ptr->pe_size >> 1, - pv_ptr->pe_allocated, - (pv_ptr->pe_total - - pv_ptr->pe_allocated) * - pv_ptr->pe_size >> 1, - pv_ptr->pe_total - - pv_ptr->pe_allocated); - c++; - if (c < vg_ptr->pv_cur) - sz += sprintf(LVM_PROC_BUF, - "\n "); - } - } - - /* logical volumes */ - sz += sprintf(LVM_PROC_BUF, - "\n LV%s ", - vg_ptr->lv_cur == 1 ? ": " : "s:"); - c = 0; - for (l = 0; l < vg[v]->lv_max; l++) { - if ((lv_ptr = vg_ptr->lv[l]) != NULL) { - inactive_flag = 'A'; - if (!(lv_ptr->lv_status & LV_ACTIVE)) - inactive_flag = 'I'; - rw_flag = 'R'; - if (lv_ptr->lv_access & LV_WRITE) - rw_flag = 'W'; - allocation_flag = 'D'; - if (lv_ptr->lv_allocation & LV_CONTIGUOUS) - allocation_flag = 'C'; - stripes_flag = 'L'; - if (lv_ptr->lv_stripes > 1) - stripes_flag = 'S'; - sz += sprintf(LVM_PROC_BUF, - "[%c%c%c%c", - inactive_flag, - rw_flag, - allocation_flag, - stripes_flag); - if (lv_ptr->lv_stripes > 1) - sz += sprintf(LVM_PROC_BUF, "%-2d", - lv_ptr->lv_stripes); - else - sz += sprintf(LVM_PROC_BUF, " "); - lv_name = strrchr(lv_ptr->lv_name, '/'); - if ( lv_name == 0) lv_name = lv_ptr->lv_name; - else lv_name++; - sz += sprintf(LVM_PROC_BUF, "] %-25s", lv_name); - if (strlen(lv_name) > 25) - sz += sprintf(LVM_PROC_BUF, - "\n "); - sz += sprintf(LVM_PROC_BUF, "%9d /%-6d ", - lv_ptr->lv_size >> 1, - lv_ptr->lv_size / vg[v]->pe_size); - - if (lv_ptr->lv_open == 0) - sz += sprintf(LVM_PROC_BUF, "close"); - else - sz += sprintf(LVM_PROC_BUF, "%dx open", - lv_ptr->lv_open); - c++; - if (c < vg_ptr->lv_cur) - sz += sprintf(LVM_PROC_BUF, - "\n "); - } - } - if (vg_ptr->lv_cur == 0) sz += sprintf(LVM_PROC_BUF, "none"); - sz += sprintf(LVM_PROC_BUF, "\n"); - } - } - } - if (buf == NULL) { - if ((buf = vmalloc(sz)) == NULL) { - sz = 0; - return sprintf(page, "%s - vmalloc error at line %d\n", - lvm_name, __LINE__); - } - } - sz_last = sz; - } - } - if (pos > sz - 1) { - vfree(buf); - buf = NULL; - return 0; - } - *start = &buf[pos]; - if (sz - pos < count) - return sz - pos; - else - return count; -} /* lvm_proc_get_info() */ -#endif /* #if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS */ - - -/* - * block device support function for /usr/src/linux/drivers/block/ll_rw_blk.c - * (see init_module/lvm_init) - */ -static int lvm_map(struct buffer_head *bh, int rw) -{ - int minor = MINOR(bh->b_rdev); - ulong index; - ulong pe_start; - ulong size = bh->b_size >> 9; - ulong rsector_tmp = bh->b_rsector; - ulong rsector_sav; - kdev_t rdev_tmp = bh->b_rdev; - kdev_t rdev_sav; - lv_t *lv = vg[VG_BLK(minor)]->lv[LV_BLK(minor)]; - - - if (!(lv->lv_status & LV_ACTIVE)) { - printk(KERN_ALERT - "%s - lvm_map: ll_rw_blk for inactive LV %s\n", - lvm_name, lv->lv_name); - goto error; - } -/* - if ( lv->lv_access & LV_SNAPSHOT) - printk ( "%s -- %02d:%02d block: %lu rw: %d\n", lvm_name, MAJOR ( bh->b_dev), MINOR ( bh->b_dev), bh->b_blocknr, rw); - */ - - /* take care of snapshot chunk writes before - check for writable logical volume */ - if ((lv->lv_access & LV_SNAPSHOT) && - MAJOR(bh->b_rdev) != 0 && - MAJOR(bh->b_rdev) != MAJOR_NR && - (rw == WRITEA || rw == WRITE)) - { - printk ( "%s -- doing snapshot write for %02d:%02d[%02d:%02d] b_blocknr: %lu b_rsector: %lu\n", lvm_name, MAJOR ( bh->b_dev), MINOR ( bh->b_dev), MAJOR ( bh->b_rdev), MINOR ( bh->b_rdev), bh->b_blocknr, bh->b_rsector); - goto error; - } - - if ((rw == WRITE || rw == WRITEA) && - !(lv->lv_access & LV_WRITE)) { - printk(KERN_CRIT - "%s - lvm_map: ll_rw_blk write for readonly LV %s\n", - lvm_name, lv->lv_name); - goto error; - } -#ifdef DEBUG_MAP - printk(KERN_DEBUG - "%s - lvm_map minor:%d *rdev: %02d:%02d *rsector: %lu " - "size:%lu\n", - lvm_name, minor, - MAJOR(rdev_tmp), - MINOR(rdev_tmp), - rsector_tmp, size); -#endif - - if (rsector_tmp + size > lv->lv_size) { - printk(KERN_ALERT - "%s - lvm_map *rsector: %lu or size: %lu wrong for" - " minor: %2d\n", lvm_name, rsector_tmp, size, minor); - goto error; - } - rsector_sav = rsector_tmp; - rdev_sav = rdev_tmp; - -lvm_second_remap: - /* linear mapping */ - if (lv->lv_stripes < 2) { - /* get the index */ - index = rsector_tmp / vg[VG_BLK(minor)]->pe_size; - pe_start = lv->lv_current_pe[index].pe; - rsector_tmp = lv->lv_current_pe[index].pe + - (rsector_tmp % vg[VG_BLK(minor)]->pe_size); - rdev_tmp = lv->lv_current_pe[index].dev; - -#ifdef DEBUG_MAP - printk(KERN_DEBUG - "lv_current_pe[%ld].pe: %ld rdev: %02d:%02d rsector:%ld\n", - index, - lv->lv_current_pe[index].pe, - MAJOR(rdev_tmp), - MINOR(rdev_tmp), - rsector_tmp); -#endif - - /* striped mapping */ - } else { - ulong stripe_index; - ulong stripe_length; - - stripe_length = vg[VG_BLK(minor)]->pe_size * lv->lv_stripes; - stripe_index = (rsector_tmp % stripe_length) / lv->lv_stripesize; - index = rsector_tmp / stripe_length + - (stripe_index % lv->lv_stripes) * - (lv->lv_allocated_le / lv->lv_stripes); - pe_start = lv->lv_current_pe[index].pe; - rsector_tmp = lv->lv_current_pe[index].pe + - (rsector_tmp % stripe_length) - - (stripe_index % lv->lv_stripes) * lv->lv_stripesize - - stripe_index / lv->lv_stripes * - (lv->lv_stripes - 1) * lv->lv_stripesize; - rdev_tmp = lv->lv_current_pe[index].dev; - } - -#ifdef DEBUG_MAP - printk(KERN_DEBUG - "lv_current_pe[%ld].pe: %ld rdev: %02d:%02d rsector:%ld\n" - "stripe_length: %ld stripe_index: %ld\n", - index, - lv->lv_current_pe[index].pe, - MAJOR(rdev_tmp), - MINOR(rdev_tmp), - rsector_tmp, - stripe_length, - stripe_index); -#endif - - /* handle physical extents on the move */ - if (pe_lock_req.lock == LOCK_PE) { - if (rdev_tmp == pe_lock_req.data.pv_dev && - rsector_tmp >= pe_lock_req.data.pv_offset && - rsector_tmp < (pe_lock_req.data.pv_offset + - vg[VG_BLK(minor)]->pe_size)) { - sleep_on(&lvm_map_wait); - rsector_tmp = rsector_sav; - rdev_tmp = rdev_sav; - goto lvm_second_remap; - } - } - /* statistic */ - if (rw == WRITE || rw == WRITEA) - lv->lv_current_pe[index].writes++; - else - lv->lv_current_pe[index].reads++; - - /* snapshot volume exception handling on physical device address base */ - if (lv->lv_access & (LV_SNAPSHOT | LV_SNAPSHOT_ORG)) { - /* original logical volume */ - if (lv->lv_access & LV_SNAPSHOT_ORG) { - if (rw == WRITE || rw == WRITEA) - { - lv_t *lv_ptr; - - /* start with first snapshot and loop thrugh all of them */ - for (lv_ptr = lv->lv_snapshot_next; - lv_ptr != NULL; - lv_ptr = lv_ptr->lv_snapshot_next) { - down(&lv->lv_snapshot_org->lv_snapshot_sem); - /* do we still have exception storage for this snapshot free? */ - if (lv_ptr->lv_block_exception != NULL) { - rdev_sav = rdev_tmp; - rsector_sav = rsector_tmp; - if (!lvm_snapshot_remap_block(&rdev_tmp, - &rsector_tmp, - pe_start, - lv_ptr)) { - /* create a new mapping */ - lvm_snapshot_COW(rdev_tmp, - rsector_tmp, - pe_start, - rsector_sav, - lv_ptr); - } - rdev_tmp = rdev_sav; - rsector_tmp = rsector_sav; - } - up(&lv->lv_snapshot_org->lv_snapshot_sem); - } - } - } else { - /* remap snapshot logical volume */ - down(&lv->lv_snapshot_sem); - if (lv->lv_block_exception != NULL) - lvm_snapshot_remap_block(&rdev_tmp, &rsector_tmp, pe_start, lv); - up(&lv->lv_snapshot_sem); - } - } - bh->b_rdev = rdev_tmp; - bh->b_rsector = rsector_tmp; - - return 1; - - error: - buffer_IO_error(bh); - return -1; -} /* lvm_map() */ - - -/* - * internal support functions - */ - -#ifdef LVM_HD_NAME -/* - * generate "hard disk" name - */ -void lvm_hd_name(char *buf, int minor) -{ - int len = 0; - lv_t *lv_ptr; - - if (vg[VG_BLK(minor)] == NULL || - (lv_ptr = vg[VG_BLK(minor)]->lv[LV_BLK(minor)]) == NULL) - return; - len = strlen(lv_ptr->lv_name) - 5; - memcpy(buf, &lv_ptr->lv_name[5], len); - buf[len] = 0; - return; -} -#endif - - -/* - * this one never should be called... - */ -static void lvm_dummy_device_request(request_queue_t * t) -{ - printk(KERN_EMERG - "%s -- oops, got lvm request for %02d:%02d [sector: %lu]\n", - lvm_name, - MAJOR(CURRENT->rq_dev), - MINOR(CURRENT->rq_dev), - CURRENT->sector); - return; -} - - -/* - * make request function - */ -static int lvm_make_request_fn(request_queue_t *q, int rw, struct buffer_head *bh) -{ - lvm_map(bh, rw); - return 1; -} - -/* - * plug device function is a noop because plugging has to happen - * in the queue of the physical blockdevice to allow the - * elevator to do a better job. - */ -static void lvm_plug_device_noop(request_queue_t *q, kdev_t dev) { } - -/******************************************************************** - * - * Character device support functions - * - ********************************************************************/ -/* - * character device support function logical volume manager lock - */ -static int lvm_do_lock_lvm(void) -{ -lock_try_again: - spin_lock(&lvm_lock); - if (lock != 0 && lock != current->pid) { -#ifdef DEBUG_IOCTL - printk(KERN_INFO "lvm_do_lock_lvm: %s is locked by pid %d ...\n", - lvm_name, lock); -#endif - spin_unlock(&lvm_lock); - interruptible_sleep_on(&lvm_wait); - if (current->sigpending != 0) - return -EINTR; -#ifdef LVM_TOTAL_RESET - if (lvm_reset_spindown > 0) - return -EACCES; -#endif - goto lock_try_again; - } - lock = current->pid; - spin_unlock(&lvm_lock); - return 0; -} /* lvm_do_lock_lvm */ - - -/* - * character device support function lock/unlock physical extend - */ -static int lvm_do_pe_lock_unlock(vg_t *vg_ptr, void *arg) -{ - uint p; - - if (vg_ptr == NULL) return -ENXIO; - if (copy_from_user(&pe_lock_req, arg, - sizeof(pe_lock_req_t)) != 0) return -EFAULT; - - switch (pe_lock_req.lock) { - case LOCK_PE: - for (p = 0; p < vg_ptr->pv_max; p++) { - if (vg_ptr->pv[p] != NULL && - pe_lock_req.data.pv_dev == - vg_ptr->pv[p]->pv_dev) - break; - } - if (p == vg_ptr->pv_max) return -ENXIO; - - pe_lock_req.lock = UNLOCK_PE; - fsync_dev(pe_lock_req.data.lv_dev); - pe_lock_req.lock = LOCK_PE; - break; - - case UNLOCK_PE: - pe_lock_req.lock = UNLOCK_PE; - pe_lock_req.data.lv_dev = \ - pe_lock_req.data.pv_dev = \ - pe_lock_req.data.pv_offset = 0; - wake_up(&lvm_map_wait); - break; - - default: - return -EINVAL; - } - return 0; -} - - -/* - * character device support function logical extend remap - */ -static int lvm_do_le_remap(vg_t *vg_ptr, void *arg) -{ - uint l, le; - lv_t *lv_ptr; - - if (vg_ptr == NULL) return -ENXIO; - if (copy_from_user(&le_remap_req, arg, - sizeof(le_remap_req_t)) != 0) - return -EFAULT; - - for (l = 0; l < vg_ptr->lv_max; l++) { - lv_ptr = vg_ptr->lv[l]; - if (lv_ptr != NULL && - strcmp(lv_ptr->lv_name, - le_remap_req.lv_name) == 0) { - for (le = 0; le < lv_ptr->lv_allocated_le; - le++) { - if (lv_ptr->lv_current_pe[le].dev == - le_remap_req.old_dev && - lv_ptr->lv_current_pe[le].pe == - le_remap_req.old_pe) { - lv_ptr->lv_current_pe[le].dev = - le_remap_req.new_dev; - lv_ptr->lv_current_pe[le].pe = - le_remap_req.new_pe; - return 0; - } - } - return -EINVAL; - } - } - return -ENXIO; -} /* lvm_do_le_remap() */ - - -/* - * character device support function VGDA create - */ -int lvm_do_vg_create(int minor, void *arg) -{ - int snaporg_minor = 0; - ulong l, p; - lv_t lv; - vg_t *vg_ptr; - pv_t *pv_ptr; - lv_t *lv_ptr; - - if (vg[VG_CHR(minor)] != NULL) return -EPERM; - - if ((vg_ptr = kmalloc(sizeof(vg_t),GFP_KERNEL)) == NULL) { - printk(KERN_CRIT - "%s -- VG_CREATE: kmalloc error VG at line %d\n", - lvm_name, __LINE__); - return -ENOMEM; - } - /* get the volume group structure */ - if (copy_from_user(vg_ptr, arg, sizeof(vg_t)) != 0) { - kfree(vg_ptr); - return -EFAULT; - } - - vg_devfs_handle[vg_ptr->vg_number] = devfs_mk_dir(0, vg_ptr->vg_name, NULL); - ch_devfs_handle[vg_ptr->vg_number] = devfs_register( - vg_devfs_handle[vg_ptr->vg_number] , "group", - DEVFS_FL_DEFAULT, LVM_CHAR_MAJOR, vg_ptr->vg_number, - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, - &lvm_chr_fops, NULL); - - /* we are not that active so far... */ - vg_ptr->vg_status &= ~VG_ACTIVE; - vg[VG_CHR(minor)] = vg_ptr; - - vg[VG_CHR(minor)]->pe_allocated = 0; - if (vg_ptr->pv_max > ABS_MAX_PV) { - printk(KERN_WARNING - "%s -- Can't activate VG: ABS_MAX_PV too small\n", - lvm_name); - kfree(vg_ptr); - vg[VG_CHR(minor)] = NULL; - return -EPERM; - } - if (vg_ptr->lv_max > ABS_MAX_LV) { - printk(KERN_WARNING - "%s -- Can't activate VG: ABS_MAX_LV too small for %u\n", - lvm_name, vg_ptr->lv_max); - kfree(vg_ptr); - vg_ptr = NULL; - return -EPERM; - } - /* get the physical volume structures */ - vg_ptr->pv_act = vg_ptr->pv_cur = 0; - for (p = 0; p < vg_ptr->pv_max; p++) { - /* user space address */ - if ((pvp = vg_ptr->pv[p]) != NULL) { - pv_ptr = vg_ptr->pv[p] = kmalloc(sizeof(pv_t),GFP_KERNEL); - if (pv_ptr == NULL) { - printk(KERN_CRIT - "%s -- VG_CREATE: kmalloc error PV at line %d\n", - lvm_name, __LINE__); - lvm_do_vg_remove(minor); - return -ENOMEM; - } - if (copy_from_user(pv_ptr, pvp, sizeof(pv_t)) != 0) { - lvm_do_vg_remove(minor); - return -EFAULT; - } - /* We don't need the PE list - in kernel space as with LVs pe_t list (see below) */ - pv_ptr->pe = NULL; - pv_ptr->pe_allocated = 0; - pv_ptr->pv_status = PV_ACTIVE; - vg_ptr->pv_act++; - vg_ptr->pv_cur++; - -#ifdef LVM_GET_INODE - /* insert a dummy inode for fs_may_mount */ - pv_ptr->inode = lvm_get_inode(pv_ptr->pv_dev); -#endif - } - } - - /* get the logical volume structures */ - vg_ptr->lv_cur = 0; - for (l = 0; l < vg_ptr->lv_max; l++) { - /* user space address */ - if ((lvp = vg_ptr->lv[l]) != NULL) { - if (copy_from_user(&lv, lvp, sizeof(lv_t)) != 0) { - lvm_do_vg_remove(minor); - return -EFAULT; - } - vg_ptr->lv[l] = NULL; - if (lvm_do_lv_create(minor, lv.lv_name, &lv) != 0) { - lvm_do_vg_remove(minor); - return -EFAULT; - } - } - } - - /* Second path to correct snapshot logical volumes which are not - in place during first path above */ - for (l = 0; l < vg_ptr->lv_max; l++) { - if ((lv_ptr = vg_ptr->lv[l]) != NULL && - vg_ptr->lv[l]->lv_access & LV_SNAPSHOT) { - snaporg_minor = lv_ptr->lv_snapshot_minor; - if (vg_ptr->lv[LV_BLK(snaporg_minor)] != NULL) { - /* get pointer to original logical volume */ - lv_ptr = vg_ptr->lv[l]->lv_snapshot_org = - vg_ptr->lv[LV_BLK(snaporg_minor)]; - - /* set necessary fields of original logical volume */ - lv_ptr->lv_access |= LV_SNAPSHOT_ORG; - lv_ptr->lv_snapshot_minor = 0; - lv_ptr->lv_snapshot_org = lv_ptr; - lv_ptr->lv_snapshot_prev = NULL; - - /* find last snapshot logical volume in the chain */ - while (lv_ptr->lv_snapshot_next != NULL) - lv_ptr = lv_ptr->lv_snapshot_next; - - /* set back pointer to this last one in our new logical volume */ - vg_ptr->lv[l]->lv_snapshot_prev = lv_ptr; - - /* last logical volume now points to our new snapshot volume */ - lv_ptr->lv_snapshot_next = vg_ptr->lv[l]; - - /* now point to the new one */ - lv_ptr = lv_ptr->lv_snapshot_next; - - /* set necessary fields of new snapshot logical volume */ - lv_ptr->lv_snapshot_next = NULL; - lv_ptr->lv_current_pe = - vg_ptr->lv[LV_BLK(snaporg_minor)]->lv_current_pe; - lv_ptr->lv_allocated_le = - vg_ptr->lv[LV_BLK(snaporg_minor)]->lv_allocated_le; - lv_ptr->lv_current_le = - vg_ptr->lv[LV_BLK(snaporg_minor)]->lv_current_le; - lv_ptr->lv_size = - vg_ptr->lv[LV_BLK(snaporg_minor)]->lv_size; - } - } - } - - vg_count++; - - /* let's go active */ - vg_ptr->vg_status |= VG_ACTIVE; - - MOD_INC_USE_COUNT; - - return 0; -} /* lvm_do_vg_create() */ - - -/* - * character device support function VGDA extend - */ -static int lvm_do_vg_extend(vg_t *vg_ptr, void *arg) -{ - uint p; - pv_t *pv_ptr; - - if (vg_ptr == NULL) return -ENXIO; - if (vg_ptr->pv_cur < vg_ptr->pv_max) { - for (p = 0; p < vg_ptr->pv_max; p++) { - if (vg_ptr->pv[p] == NULL) { - if ((pv_ptr = vg_ptr->pv[p] = kmalloc(sizeof(pv_t),GFP_KERNEL)) == NULL) { - printk(KERN_CRIT - "%s -- VG_EXTEND: kmalloc error PV at line %d\n", - lvm_name, __LINE__); - return -ENOMEM; - } - if (copy_from_user(pv_ptr, arg, sizeof(pv_t)) != 0) { - kfree(pv_ptr); - vg_ptr->pv[p] = NULL; - return -EFAULT; - } - - pv_ptr->pv_status = PV_ACTIVE; - /* We don't need the PE list - in kernel space like LVs pe_t list */ - pv_ptr->pe = NULL; - vg_ptr->pv_cur++; - vg_ptr->pv_act++; - vg_ptr->pe_total += - pv_ptr->pe_total; -#ifdef LVM_GET_INODE - /* insert a dummy inode for fs_may_mount */ - pv_ptr->inode = lvm_get_inode(pv_ptr->pv_dev); -#endif - return 0; - } - } - } -return -EPERM; -} /* lvm_do_vg_extend() */ - - -/* - * character device support function VGDA reduce - */ -static int lvm_do_vg_reduce(vg_t *vg_ptr, void *arg) -{ - uint p; - pv_t *pv_ptr; - - if (vg_ptr == NULL) return -ENXIO; - if (copy_from_user(pv_name, arg, sizeof(pv_name)) != 0) - return -EFAULT; - - for (p = 0; p < vg_ptr->pv_max; p++) { - pv_ptr = vg_ptr->pv[p]; - if (pv_ptr != NULL && - strcmp(pv_ptr->pv_name, - pv_name) == 0) { - if (pv_ptr->lv_cur > 0) return -EPERM; - vg_ptr->pe_total -= - pv_ptr->pe_total; - vg_ptr->pv_cur--; - vg_ptr->pv_act--; -#ifdef LVM_GET_INODE - lvm_clear_inode(pv_ptr->inode); -#endif - kfree(pv_ptr); - /* Make PV pointer array contiguous */ - for (; p < vg_ptr->pv_max - 1; p++) - vg_ptr->pv[p] = vg_ptr->pv[p + 1]; - vg_ptr->pv[p + 1] = NULL; - return 0; - } - } - return -ENXIO; -} /* lvm_do_vg_reduce */ - - -/* - * character device support function VGDA remove - */ -static int lvm_do_vg_remove(int minor) -{ - int i; - vg_t *vg_ptr = vg[VG_CHR(minor)]; - pv_t *pv_ptr; - - if (vg_ptr == NULL) return -ENXIO; - -#ifdef LVM_TOTAL_RESET - if (vg_ptr->lv_open > 0 && lvm_reset_spindown == 0) -#else - if (vg_ptr->lv_open > 0) -#endif - return -EPERM; - - /* let's go inactive */ - vg_ptr->vg_status &= ~VG_ACTIVE; - - devfs_unregister (ch_devfs_handle[vg_ptr->vg_number]); - devfs_unregister (vg_devfs_handle[vg_ptr->vg_number]); - - /* free LVs */ - /* first free snapshot logical volumes */ - for (i = 0; i < vg_ptr->lv_max; i++) { - if (vg_ptr->lv[i] != NULL && - vg_ptr->lv[i]->lv_access & LV_SNAPSHOT) { - lvm_do_lv_remove(minor, NULL, i); - current->state = TASK_UNINTERRUPTIBLE; - schedule_timeout(1); - } - } - /* then free the rest of the LVs */ - for (i = 0; i < vg_ptr->lv_max; i++) { - if (vg_ptr->lv[i] != NULL) { - lvm_do_lv_remove(minor, NULL, i); - current->state = TASK_UNINTERRUPTIBLE; - schedule_timeout(1); - } - } - - /* free PVs */ - for (i = 0; i < vg_ptr->pv_max; i++) { - if ((pv_ptr = vg_ptr->pv[i]) != NULL) { -#ifdef DEBUG_KFREE - printk(KERN_DEBUG - "%s -- kfree %d\n", lvm_name, __LINE__); -#endif -#ifdef LVM_GET_INODE - lvm_clear_inode(pv_ptr->inode); -#endif - kfree(pv_ptr); - vg[VG_CHR(minor)]->pv[i] = NULL; - } - } - -#ifdef DEBUG_KFREE - printk(KERN_DEBUG "%s -- kfree %d\n", lvm_name, __LINE__); -#endif - kfree(vg_ptr); - vg[VG_CHR(minor)] = NULL; - - vg_count--; - - MOD_DEC_USE_COUNT; - - return 0; -} /* lvm_do_vg_remove() */ - - -/* - * character device support function logical volume create - */ -static int lvm_do_lv_create(int minor, char *lv_name, lv_t *lv) -{ - int l, le, l_new, p, size; - ulong lv_status_save; - char *lv_tmp, *lv_buf; - lv_block_exception_t *lvbe = lv->lv_block_exception; - vg_t *vg_ptr = vg[VG_CHR(minor)]; - lv_t *lv_ptr = NULL; - - if ((pep = lv->lv_current_pe) == NULL) return -EINVAL; - if (lv->lv_chunk_size > LVM_SNAPSHOT_MAX_CHUNK) - return -EINVAL; - - for (l = 0; l < vg_ptr->lv_max; l++) { - if (vg_ptr->lv[l] != NULL && - strcmp(vg_ptr->lv[l]->lv_name, lv_name) == 0) - return -EEXIST; - } - - /* in case of lv_remove(), lv_create() pair; for eg. lvrename does this */ - l_new = -1; - if (vg_ptr->lv[lv->lv_number] == NULL) - l_new = lv->lv_number; - else { - for (l = 0; l < vg_ptr->lv_max; l++) { - if (vg_ptr->lv[l] == NULL) - if (l_new == -1) l_new = l; - } - } - if (l_new == -1) return -EPERM; - else l = l_new; - - if ((lv_ptr = kmalloc(sizeof(lv_t),GFP_KERNEL)) == NULL) {; - printk(KERN_CRIT "%s -- LV_CREATE: kmalloc error LV at line %d\n", - lvm_name, __LINE__); - return -ENOMEM; - } - /* copy preloaded LV */ - memcpy((char *) lv_ptr, (char *) lv, sizeof(lv_t)); - - lv_status_save = lv_ptr->lv_status; - lv_ptr->lv_status &= ~LV_ACTIVE; - lv_ptr->lv_snapshot_org = \ - lv_ptr->lv_snapshot_prev = \ - lv_ptr->lv_snapshot_next = NULL; - lv_ptr->lv_block_exception = NULL; - init_MUTEX(&lv_ptr->lv_snapshot_sem); - vg_ptr->lv[l] = lv_ptr; - - /* get the PE structures from user space if this - is no snapshot logical volume */ - if (!(lv_ptr->lv_access & LV_SNAPSHOT)) { - size = lv_ptr->lv_allocated_le * sizeof(pe_t); - if ((lv_ptr->lv_current_pe = vmalloc(size)) == NULL) { - printk(KERN_CRIT - "%s -- LV_CREATE: vmalloc error LV_CURRENT_PE of %d Byte " - "at line %d\n", - lvm_name, size, __LINE__); -#ifdef DEBUG_KFREE - printk(KERN_DEBUG "%s -- kfree %d\n", lvm_name, __LINE__); -#endif - kfree(lv_ptr); - vg[VG_CHR(minor)]->lv[l] = NULL; - return -ENOMEM; - } - if (copy_from_user(lv_ptr->lv_current_pe, pep, size)) { - vfree(lv_ptr->lv_current_pe); - kfree(lv_ptr); - vg_ptr->lv[l] = NULL; - return -EFAULT; - } - /* correct the PE count in PVs */ - for (le = 0; le < lv_ptr->lv_allocated_le; le++) { - vg_ptr->pe_allocated++; - for (p = 0; p < vg_ptr->pv_cur; p++) { - if (vg_ptr->pv[p]->pv_dev == - lv_ptr->lv_current_pe[le].dev) - vg_ptr->pv[p]->pe_allocated++; - } - } - } else { - /* Get snapshot exception data and block list */ - if (lvbe != NULL) { - lv_ptr->lv_snapshot_org = - vg_ptr->lv[LV_BLK(lv_ptr->lv_snapshot_minor)]; - if (lv_ptr->lv_snapshot_org != NULL) { - size = lv_ptr->lv_remap_end * sizeof(lv_block_exception_t); - if ((lv_ptr->lv_block_exception = vmalloc(size)) == NULL) { - printk(KERN_CRIT - "%s -- lvm_do_lv_create: vmalloc error LV_BLOCK_EXCEPTION " - "of %d byte at line %d\n", - lvm_name, size, __LINE__); -#ifdef DEBUG_KFREE - printk(KERN_DEBUG "%s -- kfree %d\n", lvm_name, __LINE__); -#endif - kfree(lv_ptr); - vg_ptr->lv[l] = NULL; - return -ENOMEM; - } - if (copy_from_user(lv_ptr->lv_block_exception, lvbe, size)) { - vfree(lv_ptr->lv_block_exception); - kfree(lv_ptr); - vg[VG_CHR(minor)]->lv[l] = NULL; - return -EFAULT; - } - /* get pointer to original logical volume */ - lv_ptr = lv_ptr->lv_snapshot_org; - - lv_ptr->lv_snapshot_minor = 0; - lv_ptr->lv_snapshot_org = lv_ptr; - lv_ptr->lv_snapshot_prev = NULL; - /* walk thrugh the snapshot list */ - while (lv_ptr->lv_snapshot_next != NULL) - lv_ptr = lv_ptr->lv_snapshot_next; - /* now lv_ptr points to the last existing snapshot in the chain */ - vg_ptr->lv[l]->lv_snapshot_prev = lv_ptr; - /* our new one now back points to the previous last in the chain */ - lv_ptr = vg_ptr->lv[l]; - /* now lv_ptr points to our new last snapshot logical volume */ - lv_ptr->lv_snapshot_org = lv_ptr->lv_snapshot_prev->lv_snapshot_org; - lv_ptr->lv_snapshot_next = NULL; - lv_ptr->lv_current_pe = lv_ptr->lv_snapshot_org->lv_current_pe; - lv_ptr->lv_allocated_le = lv_ptr->lv_snapshot_org->lv_allocated_le; - lv_ptr->lv_current_le = lv_ptr->lv_snapshot_org->lv_current_le; - lv_ptr->lv_size = lv_ptr->lv_snapshot_org->lv_size; - lv_ptr->lv_stripes = lv_ptr->lv_snapshot_org->lv_stripes; - lv_ptr->lv_stripesize = lv_ptr->lv_snapshot_org->lv_stripesize; - { - int err = lvm_snapshot_alloc(lv_ptr); - if (err) - { - vfree(lv_ptr->lv_block_exception); - kfree(lv_ptr); - vg[VG_CHR(minor)]->lv[l] = NULL; - return err; - } - } - } else { - vfree(lv_ptr->lv_block_exception); - kfree(lv_ptr); - vg_ptr->lv[l] = NULL; - return -EFAULT; - } - } else { - kfree(vg_ptr->lv[l]); - vg_ptr->lv[l] = NULL; - return -EINVAL; - } - } /* if ( vg[VG_CHR(minor)]->lv[l]->lv_access & LV_SNAPSHOT) */ - - lv_ptr = vg_ptr->lv[l]; - lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].start_sect = 0; - lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].nr_sects = lv_ptr->lv_size; - lvm_size[MINOR(lv_ptr->lv_dev)] = lv_ptr->lv_size >> 1; - vg_lv_map[MINOR(lv_ptr->lv_dev)].vg_number = vg_ptr->vg_number; - vg_lv_map[MINOR(lv_ptr->lv_dev)].lv_number = lv_ptr->lv_number; - read_ahead[MAJOR_NR] = lv_ptr->lv_read_ahead = LVM_CORRECT_READ_AHEAD(lv_ptr->lv_read_ahead); - vg_ptr->lv_cur++; - lv_ptr->lv_status = lv_status_save; - - strtok(lv->lv_name, "/"); /* /dev */ - - while((lv_tmp = strtok(NULL, "/")) != NULL) - lv_buf = lv_tmp; - - lv_devfs_handle[lv->lv_number] = devfs_register( - vg_devfs_handle[vg_ptr->vg_number], lv_buf, - DEVFS_FL_DEFAULT, LVM_BLK_MAJOR, lv->lv_number, - S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP, - &lvm_blk_dops, NULL); - - /* optionally add our new snapshot LV */ - if (lv_ptr->lv_access & LV_SNAPSHOT) { - /* sync the original logical volume */ - fsync_dev(lv_ptr->lv_snapshot_org->lv_dev); - /* put ourselve into the chain */ - lv_ptr->lv_snapshot_prev->lv_snapshot_next = lv_ptr; - lv_ptr->lv_snapshot_org->lv_access |= LV_SNAPSHOT_ORG; - } - return 0; -} /* lvm_do_lv_create() */ - - -/* - * character device support function logical volume remove - */ -static int lvm_do_lv_remove(int minor, char *lv_name, int l) -{ - uint le, p; - vg_t *vg_ptr = vg[VG_CHR(minor)]; - lv_t *lv_ptr; - - if (l == -1) { - for (l = 0; l < vg_ptr->lv_max; l++) { - if (vg_ptr->lv[l] != NULL && - strcmp(vg_ptr->lv[l]->lv_name, lv_name) == 0) { - break; - } - } - } - if (l == vg_ptr->lv_max) return -ENXIO; - - lv_ptr = vg_ptr->lv[l]; -#ifdef LVM_TOTAL_RESET - if (lv_ptr->lv_open > 0 && lvm_reset_spindown == 0) -#else - if (lv_ptr->lv_open > 0) -#endif - return -EBUSY; - - /* check for deletion of snapshot source while - snapshot volume still exists */ - if ((lv_ptr->lv_access & LV_SNAPSHOT_ORG) && - lv_ptr->lv_snapshot_next != NULL) - return -EPERM; - - lv_ptr->lv_status |= LV_SPINDOWN; - - /* sync the buffers */ - fsync_dev(lv_ptr->lv_dev); - - lv_ptr->lv_status &= ~LV_ACTIVE; - - /* invalidate the buffers */ - invalidate_buffers(lv_ptr->lv_dev); - - /* reset generic hd */ - lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].start_sect = -1; - lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].nr_sects = 0; - lvm_size[MINOR(lv_ptr->lv_dev)] = 0; - - /* reset VG/LV mapping */ - vg_lv_map[MINOR(lv_ptr->lv_dev)].vg_number = ABS_MAX_VG; - vg_lv_map[MINOR(lv_ptr->lv_dev)].lv_number = -1; - - /* correct the PE count in PVs if this is no snapshot logical volume */ - if (!(lv_ptr->lv_access & LV_SNAPSHOT)) { - /* only if this is no snapshot logical volume because - we share the lv_current_pe[] structs with the - original logical volume */ - for (le = 0; le < lv_ptr->lv_allocated_le; le++) { - vg_ptr->pe_allocated--; - for (p = 0; p < vg_ptr->pv_cur; p++) { - if (vg_ptr->pv[p]->pv_dev == - lv_ptr->lv_current_pe[le].dev) - vg_ptr->pv[p]->pe_allocated--; - } - } - vfree(lv_ptr->lv_current_pe); - /* LV_SNAPSHOT */ - } else { - /* remove this snapshot logical volume from the chain */ - lv_ptr->lv_snapshot_prev->lv_snapshot_next = lv_ptr->lv_snapshot_next; - if (lv_ptr->lv_snapshot_next != NULL) { - lv_ptr->lv_snapshot_next->lv_snapshot_prev = - lv_ptr->lv_snapshot_prev; - } - /* no more snapshots? */ - if (lv_ptr->lv_snapshot_org->lv_snapshot_next == NULL) - lv_ptr->lv_snapshot_org->lv_access &= ~LV_SNAPSHOT_ORG; - lvm_snapshot_release(lv_ptr); - } - - devfs_unregister(lv_devfs_handle[lv_ptr->lv_number]); - -#ifdef DEBUG_KFREE - printk(KERN_DEBUG "%s -- kfree %d\n", lvm_name, __LINE__); -#endif - kfree(lv_ptr); - vg_ptr->lv[l] = NULL; - vg_ptr->lv_cur--; - return 0; -} /* lvm_do_lv_remove() */ - - -/* - * character device support function logical volume extend / reduce - */ -static int lvm_do_lv_extend_reduce(int minor, char *lv_name, lv_t *lv) -{ - int l, le, p, size, old_allocated_le; - uint32_t end, lv_status_save; - vg_t *vg_ptr = vg[VG_CHR(minor)]; - lv_t *lv_ptr; - pe_t *pe; - - if ((pep = lv->lv_current_pe) == NULL) return -EINVAL; - - for (l = 0; l < vg_ptr->lv_max; l++) { - if (vg_ptr->lv[l] != NULL && - strcmp(vg_ptr->lv[l]->lv_name, lv_name) == 0) - break; - } - if (l == vg_ptr->lv_max) return -ENXIO; - lv_ptr = vg_ptr->lv[l]; - - /* check for active snapshot */ - if (lv->lv_access & (LV_SNAPSHOT | LV_SNAPSHOT_ORG)) return -EPERM; - - if ((pe = vmalloc(size = lv->lv_current_le * sizeof(pe_t))) == NULL) { - printk(KERN_CRIT - "%s -- lvm_do_lv_extend_reduce: vmalloc error LV_CURRENT_PE " - "of %d Byte at line %d\n", - lvm_name, size, __LINE__); - return -ENOMEM; - } - /* get the PE structures from user space */ - if (copy_from_user(pe, pep, size)) { - vfree(pe); - return -EFAULT; - } - -#ifdef DEBUG - printk(KERN_DEBUG - "%s -- fsync_dev and " - "invalidate_buffers for %s [%s] in %s\n", - lvm_name, lv_ptr->lv_name, - kdevname(lv_ptr->lv_dev), - vg_ptr->vg_name); -#endif - - lv_ptr->lv_status |= LV_SPINDOWN; - fsync_dev(lv_ptr->lv_dev); - lv_ptr->lv_status &= ~LV_ACTIVE; - invalidate_buffers(lv_ptr->lv_dev); - - /* reduce allocation counters on PV(s) */ - for (le = 0; le < lv_ptr->lv_allocated_le; le++) { - vg_ptr->pe_allocated--; - for (p = 0; p < vg_ptr->pv_cur; p++) { - if (vg_ptr->pv[p]->pv_dev == - lv_ptr->lv_current_pe[le].dev) { - vg_ptr->pv[p]->pe_allocated--; - break; - } - } - } - - - /* save pointer to "old" lv/pe pointer array */ - pep1 = lv_ptr->lv_current_pe; - end = lv_ptr->lv_current_le; - - /* save open counter */ - lv_open = lv_ptr->lv_open; - - /* save # of old allocated logical extents */ - old_allocated_le = lv_ptr->lv_allocated_le; - - /* copy preloaded LV */ - lv_status_save = lv->lv_status; - lv->lv_status |= LV_SPINDOWN; - lv->lv_status &= ~LV_ACTIVE; - memcpy((char *) lv_ptr, (char *) lv, sizeof(lv_t)); - lv_ptr->lv_current_pe = pe; - lv_ptr->lv_open = lv_open; - - /* save availiable i/o statistic data */ - /* linear logical volume */ - if (lv_ptr->lv_stripes < 2) { - /* Check what last LE shall be used */ - if (end > lv_ptr->lv_current_le) end = lv_ptr->lv_current_le; - for (le = 0; le < end; le++) { - lv_ptr->lv_current_pe[le].reads = pep1[le].reads; - lv_ptr->lv_current_pe[le].writes = pep1[le].writes; - } - /* striped logical volume */ - } else { - uint i, j, source, dest, end, old_stripe_size, new_stripe_size; - - old_stripe_size = old_allocated_le / lv_ptr->lv_stripes; - new_stripe_size = lv_ptr->lv_allocated_le / lv_ptr->lv_stripes; - end = old_stripe_size; - if (end > new_stripe_size) end = new_stripe_size; - for (i = source = dest = 0; - i < lv_ptr->lv_stripes; i++) { - for (j = 0; j < end; j++) { - lv_ptr->lv_current_pe[dest + j].reads = - pep1[source + j].reads; - lv_ptr->lv_current_pe[dest + j].writes = - pep1[source + j].writes; - } - source += old_stripe_size; - dest += new_stripe_size; - } - } - vfree(pep1); - pep1 = NULL; - - - /* extend the PE count in PVs */ - for (le = 0; le < lv_ptr->lv_allocated_le; le++) { - vg_ptr->pe_allocated++; - for (p = 0; p < vg_ptr->pv_cur; p++) { - if (vg_ptr->pv[p]->pv_dev == - vg_ptr->lv[l]->lv_current_pe[le].dev) { - vg_ptr->pv[p]->pe_allocated++; - break; - } - } - } - - lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].start_sect = 0; - lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].nr_sects = lv_ptr->lv_size; - lvm_size[MINOR(lv_ptr->lv_dev)] = lv_ptr->lv_size >> 1; - /* vg_lv_map array doesn't have to be changed here */ - - read_ahead[MAJOR_NR] = lv_ptr->lv_read_ahead = LVM_CORRECT_READ_AHEAD(lv_ptr->lv_read_ahead); - lv_ptr->lv_status = lv_status_save; - - return 0; -} /* lvm_do_lv_extend_reduce() */ - - -/* - * character device support function logical volume status by name - */ -static int lvm_do_lv_status_byname(vg_t *vg_ptr, void *arg) -{ - uint l; - ulong size; - lv_t lv; - lv_t *lv_ptr; - lv_status_byname_req_t lv_status_byname_req; - - if (vg_ptr == NULL) return -ENXIO; - if (copy_from_user(&lv_status_byname_req, arg, - sizeof(lv_status_byname_req_t)) != 0) - return -EFAULT; - - if (lv_status_byname_req.lv == NULL) return -EINVAL; - if (copy_from_user(&lv, lv_status_byname_req.lv, - sizeof(lv_t)) != 0) - return -EFAULT; - - for (l = 0; l < vg_ptr->lv_max; l++) { - lv_ptr = vg_ptr->lv[l]; - if (lv_ptr != NULL && - strcmp(lv_ptr->lv_name, - lv_status_byname_req.lv_name) == 0) { - if (copy_to_user(lv_status_byname_req.lv, - lv_ptr, - sizeof(lv_t)) != 0) - return -EFAULT; - - if (lv.lv_current_pe != NULL) { - size = lv_ptr->lv_allocated_le * - sizeof(pe_t); - if (copy_to_user(lv.lv_current_pe, - lv_ptr->lv_current_pe, - size) != 0) - return -EFAULT; - } - return 0; - } - } - return -ENXIO; -} /* lvm_do_lv_status_byname() */ - - -/* - * character device support function logical volume status by index - */ -static int lvm_do_lv_status_byindex(vg_t *vg_ptr,void *arg) -{ - ulong size; - lv_t lv; - lv_t *lv_ptr; - lv_status_byindex_req_t lv_status_byindex_req; - - if (vg_ptr == NULL) return -ENXIO; - if (copy_from_user(&lv_status_byindex_req, arg, - sizeof(lv_status_byindex_req)) != 0) - return -EFAULT; - - if ((lvp = lv_status_byindex_req.lv) == NULL) - return -EINVAL; - if ( ( lv_ptr = vg_ptr->lv[lv_status_byindex_req.lv_index]) == NULL) - return -ENXIO; - - if (copy_from_user(&lv, lvp, sizeof(lv_t)) != 0) - return -EFAULT; - - if (copy_to_user(lvp, lv_ptr, sizeof(lv_t)) != 0) - return -EFAULT; - - if (lv.lv_current_pe != NULL) { - size = lv_ptr->lv_allocated_le * sizeof(pe_t); - if (copy_to_user(lv.lv_current_pe, - lv_ptr->lv_current_pe, - size) != 0) - return -EFAULT; - } - return 0; -} /* lvm_do_lv_status_byindex() */ - - -/* - * character device support function physical volume change - */ -static int lvm_do_pv_change(vg_t *vg_ptr, void *arg) -{ - uint p; - pv_t *pv_ptr; -#ifdef LVM_GET_INODE - struct inode *inode_sav; -#endif - - if (vg_ptr == NULL) return -ENXIO; - if (copy_from_user(&pv_change_req, arg, - sizeof(pv_change_req)) != 0) - return -EFAULT; - - for (p = 0; p < vg_ptr->pv_max; p++) { - pv_ptr = vg_ptr->pv[p]; - if (pv_ptr != NULL && - strcmp(pv_ptr->pv_name, - pv_change_req.pv_name) == 0) { -#ifdef LVM_GET_INODE - inode_sav = pv_ptr->inode; -#endif - if (copy_from_user(pv_ptr, - pv_change_req.pv, - sizeof(pv_t)) != 0) - return -EFAULT; - - /* We don't need the PE list - in kernel space as with LVs pe_t list */ - pv_ptr->pe = NULL; -#ifdef LVM_GET_INODE - pv_ptr->inode = inode_sav; -#endif - return 0; - } - } - return -ENXIO; -} /* lvm_do_pv_change() */ - -/* - * character device support function get physical volume status - */ -static int lvm_do_pv_status(vg_t *vg_ptr, void *arg) -{ - uint p; - pv_t *pv_ptr; - - if (vg_ptr == NULL) return -ENXIO; - if (copy_from_user(&pv_status_req, arg, - sizeof(pv_status_req)) != 0) - return -EFAULT; - - for (p = 0; p < vg_ptr->pv_max; p++) { - pv_ptr = vg_ptr->pv[p]; - if (pv_ptr != NULL && - strcmp(pv_ptr->pv_name, - pv_status_req.pv_name) == 0) { - if (copy_to_user(pv_status_req.pv, - pv_ptr, - sizeof(pv_t)) != 0) - return -EFAULT; - return 0; - } - } - return -ENXIO; -} /* lvm_do_pv_status() */ - - -/* - * support function initialize gendisk variables - */ -#ifdef __initfunc -__initfunc(void lvm_geninit(struct gendisk *lvm_gdisk)) -#else -void __init - lvm_geninit(struct gendisk *lvm_gdisk) -#endif -{ - int i = 0; - -#ifdef DEBUG_GENDISK - printk(KERN_DEBUG "%s -- lvm_gendisk\n", lvm_name); -#endif - - for (i = 0; i < MAX_LV; i++) { - lvm_gendisk.part[i].start_sect = -1; /* avoid partition check */ - lvm_size[i] = lvm_gendisk.part[i].nr_sects = 0; - lvm_blocksizes[i] = BLOCK_SIZE; - } - - blksize_size[MAJOR_NR] = lvm_blocksizes; - blk_size[MAJOR_NR] = lvm_size; - - return; -} /* lvm_gen_init() */ - - -#ifdef LVM_GET_INODE -/* - * support function to get an empty inode - * - * Gets an empty inode to be inserted into the inode hash, - * so that a physical volume can't be mounted. - * This is analog to drivers/block/md.c - * - * Is this the real thing? - * - * No, it's bollocks. md.c tries to do a bit different thing that might - * _somewhat_ work eons ago. Neither does any good these days. mount() couldn't - * care less for icache (it cares only for ->s_root->d_count and if we want - * loopback mounts even that will stop). BTW, with the form used here mount() - * would have to scan the _whole_ icache to detect the attempt - how on the - * Earth could it guess the i_ino of your dummy inode? Official line on the - * exclusion between mount()/swapon()/open()/etc. is Just Don't Do It(tm). - * If you can convince Linus that it's worth changing - fine, then you'll need - * to do blkdev_get()/blkdev_put(). Until then... - */ -struct inode *lvm_get_inode(int dev) -{ - struct inode *inode_this = NULL; - - /* Lock the device by inserting a dummy inode. */ - inode_this = get_empty_inode(); - inode_this->i_dev = dev; - insert_inode_hash(inode_this); - return inode_this; -} - - -/* - * support function to clear an inode - * - */ -void lvm_clear_inode(struct inode *inode) -{ -#ifdef I_FREEING - inode->i_state |= I_FREEING; -#endif - clear_inode(inode); - return; -} -#endif /* #ifdef LVM_GET_INODE */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/block/md.c linux/drivers/block/md.c --- v2.4.0-test8/linux/drivers/block/md.c Tue Sep 5 14:07:30 2000 +++ linux/drivers/block/md.c Wed Dec 31 16:00:00 1969 @@ -1,3867 +0,0 @@ -/* - md.c : Multiple Devices driver for Linux - Copyright (C) 1998, 1999, 2000 Ingo Molnar - - completely rewritten, based on the MD driver code from Marc Zyngier - - Changes: - - - RAID-1/RAID-5 extensions by Miguel de Icaza, Gadi Oxman, Ingo Molnar - - boot support for linear and striped mode by Harald Hoyer - - kerneld support by Boris Tobotras - - kmod support by: Cyrus Durgin - - RAID0 bugfixes: Mark Anthony Lisher - - Devfs support by Richard Gooch - - - lots of fixes and improvements to the RAID1/RAID5 and generic - RAID code (such as request based resynchronization): - - Neil Brown . - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - You should have received a copy of the GNU General Public License - (for example /usr/src/linux/COPYING); if not, write to the Free - Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include - -#ifdef CONFIG_KMOD -#include -#endif - -#define __KERNEL_SYSCALLS__ -#include - -#include - -extern asmlinkage int sys_sched_yield(void); -extern asmlinkage long sys_setsid(void); - -#define MAJOR_NR MD_MAJOR -#define MD_DRIVER - -#include - -#define DEBUG 0 -#if DEBUG -# define dprintk(x...) printk(x) -#else -# define dprintk(x...) do { } while(0) -#endif - -static mdk_personality_t *pers[MAX_PERSONALITY] = {NULL, }; - -/* - * Current RAID-1,4,5 parallel reconstruction 'guaranteed speed limit' - * is 100 KB/sec, so the extra system load does not show up that much. - * Increase it if you want to have more _guaranteed_ speed. Note that - * the RAID driver will use the maximum available bandwith if the IO - * subsystem is idle. There is also an 'absolute maximum' reconstruction - * speed limit - in case reconstruction slows down your system despite - * idle IO detection. - * - * you can change it via /proc/sys/dev/raid/speed_limit_min and _max. - */ - -static int sysctl_speed_limit_min = 100; -static int sysctl_speed_limit_max = 100000; - -static struct ctl_table_header *raid_table_header; - -static ctl_table raid_table[] = { - {DEV_RAID_SPEED_LIMIT_MIN, "speed_limit_min", - &sysctl_speed_limit_min, sizeof(int), 0644, NULL, &proc_dointvec}, - {DEV_RAID_SPEED_LIMIT_MAX, "speed_limit_max", - &sysctl_speed_limit_max, sizeof(int), 0644, NULL, &proc_dointvec}, - {0} -}; - -static ctl_table raid_dir_table[] = { - {DEV_RAID, "raid", NULL, 0, 0555, raid_table}, - {0} -}; - -static ctl_table raid_root_table[] = { - {CTL_DEV, "dev", NULL, 0, 0555, raid_dir_table}, - {0} -}; - -/* - * these have to be allocated separately because external - * subsystems want to have a pre-defined structure - */ -struct hd_struct md_hd_struct[MAX_MD_DEVS]; -static int md_blocksizes[MAX_MD_DEVS]; -static int md_hardsect_sizes[MAX_MD_DEVS]; -static int md_maxreadahead[MAX_MD_DEVS]; -static mdk_thread_t *md_recovery_thread = NULL; - -int md_size[MAX_MD_DEVS] = {0, }; - -extern struct block_device_operations md_fops; -static devfs_handle_t devfs_handle = NULL; - -static struct gendisk md_gendisk= -{ - major: MD_MAJOR, - major_name: "md", - minor_shift: 0, - max_p: 1, - part: md_hd_struct, - sizes: md_size, - nr_real: MAX_MD_DEVS, - real_devices: NULL, - next: NULL, - fops: &md_fops, -}; - -/* - * Enables to iterate over all existing md arrays - */ -static MD_LIST_HEAD(all_mddevs); - -/* - * The mapping between kdev and mddev is not necessary a simple - * one! Eg. HSM uses several sub-devices to implement Logical - * Volumes. All these sub-devices map to the same mddev. - */ -dev_mapping_t mddev_map [MAX_MD_DEVS] = { {NULL, 0}, }; - -void add_mddev_mapping (mddev_t * mddev, kdev_t dev, void *data) -{ - unsigned int minor = MINOR(dev); - - if (MAJOR(dev) != MD_MAJOR) { - MD_BUG(); - return; - } - if (mddev_map[minor].mddev != NULL) { - MD_BUG(); - return; - } - mddev_map[minor].mddev = mddev; - mddev_map[minor].data = data; -} - -void del_mddev_mapping (mddev_t * mddev, kdev_t dev) -{ - unsigned int minor = MINOR(dev); - - if (MAJOR(dev) != MD_MAJOR) { - MD_BUG(); - return; - } - if (mddev_map[minor].mddev != mddev) { - MD_BUG(); - return; - } - mddev_map[minor].mddev = NULL; - mddev_map[minor].data = NULL; -} - -static int md_make_request (request_queue_t *q, int rw, struct buffer_head * bh) -{ - mddev_t *mddev = kdev_to_mddev(bh->b_rdev); - - if (mddev && mddev->pers) - return mddev->pers->make_request(mddev, rw, bh); - else { - buffer_IO_error(bh); - return -1; - } -} - -static mddev_t * alloc_mddev (kdev_t dev) -{ - mddev_t *mddev; - - if (MAJOR(dev) != MD_MAJOR) { - MD_BUG(); - return 0; - } - mddev = (mddev_t *) kmalloc(sizeof(*mddev), GFP_KERNEL); - if (!mddev) - return NULL; - - memset(mddev, 0, sizeof(*mddev)); - - mddev->__minor = MINOR(dev); - init_MUTEX(&mddev->reconfig_sem); - init_MUTEX(&mddev->recovery_sem); - init_MUTEX(&mddev->resync_sem); - MD_INIT_LIST_HEAD(&mddev->disks); - MD_INIT_LIST_HEAD(&mddev->all_mddevs); - - /* - * The 'base' mddev is the one with data NULL. - * personalities can create additional mddevs - * if necessary. - */ - add_mddev_mapping(mddev, dev, 0); - md_list_add(&mddev->all_mddevs, &all_mddevs); - - MOD_INC_USE_COUNT; - - return mddev; -} - -struct gendisk * find_gendisk (kdev_t dev) -{ - struct gendisk *tmp = gendisk_head; - - while (tmp != NULL) { - if (tmp->major == MAJOR(dev)) - return (tmp); - tmp = tmp->next; - } - return (NULL); -} - -mdk_rdev_t * find_rdev_nr(mddev_t *mddev, int nr) -{ - mdk_rdev_t * rdev; - struct md_list_head *tmp; - - ITERATE_RDEV(mddev,rdev,tmp) { - if (rdev->desc_nr == nr) - return rdev; - } - return NULL; -} - -mdk_rdev_t * find_rdev(mddev_t * mddev, kdev_t dev) -{ - struct md_list_head *tmp; - mdk_rdev_t *rdev; - - ITERATE_RDEV(mddev,rdev,tmp) { - if (rdev->dev == dev) - return rdev; - } - return NULL; -} - -static MD_LIST_HEAD(device_names); - -char * partition_name (kdev_t dev) -{ - struct gendisk *hd; - static char nomem [] = ""; - dev_name_t *dname; - struct md_list_head *tmp = device_names.next; - - while (tmp != &device_names) { - dname = md_list_entry(tmp, dev_name_t, list); - if (dname->dev == dev) - return dname->name; - tmp = tmp->next; - } - - dname = (dev_name_t *) kmalloc(sizeof(*dname), GFP_KERNEL); - - if (!dname) - return nomem; - /* - * ok, add this new device name to the list - */ - hd = find_gendisk (dev); - dname->name = NULL; - if (hd) - dname->name = disk_name (hd, MINOR(dev), dname->namebuf); - if (!dname->name) { - sprintf (dname->namebuf, "[dev %s]", kdevname(dev)); - dname->name = dname->namebuf; - } - - dname->dev = dev; - MD_INIT_LIST_HEAD(&dname->list); - md_list_add(&dname->list, &device_names); - - return dname->name; -} - -static unsigned int calc_dev_sboffset (kdev_t dev, mddev_t *mddev, - int persistent) -{ - unsigned int size = 0; - - if (blk_size[MAJOR(dev)]) - size = blk_size[MAJOR(dev)][MINOR(dev)]; - if (persistent) - size = MD_NEW_SIZE_BLOCKS(size); - return size; -} - -static unsigned int calc_dev_size (kdev_t dev, mddev_t *mddev, int persistent) -{ - unsigned int size; - - size = calc_dev_sboffset(dev, mddev, persistent); - if (!mddev->sb) { - MD_BUG(); - return size; - } - if (mddev->sb->chunk_size) - size &= ~(mddev->sb->chunk_size/1024 - 1); - return size; -} - -static unsigned int zoned_raid_size (mddev_t *mddev) -{ - unsigned int mask; - mdk_rdev_t * rdev; - struct md_list_head *tmp; - - if (!mddev->sb) { - MD_BUG(); - return -EINVAL; - } - /* - * do size and offset calculations. - */ - mask = ~(mddev->sb->chunk_size/1024 - 1); - - ITERATE_RDEV(mddev,rdev,tmp) { - rdev->size &= mask; - md_size[mdidx(mddev)] += rdev->size; - } - return 0; -} - -/* - * We check wether all devices are numbered from 0 to nb_dev-1. The - * order is guaranteed even after device name changes. - * - * Some personalities (raid0, linear) use this. Personalities that - * provide data have to be able to deal with loss of individual - * disks, so they do their checking themselves. - */ -int md_check_ordering (mddev_t *mddev) -{ - int i, c; - mdk_rdev_t *rdev; - struct md_list_head *tmp; - - /* - * First, all devices must be fully functional - */ - ITERATE_RDEV(mddev,rdev,tmp) { - if (rdev->faulty) { - printk("md: md%d's device %s faulty, aborting.\n", - mdidx(mddev), partition_name(rdev->dev)); - goto abort; - } - } - - c = 0; - ITERATE_RDEV(mddev,rdev,tmp) { - c++; - } - if (c != mddev->nb_dev) { - MD_BUG(); - goto abort; - } - if (mddev->nb_dev != mddev->sb->raid_disks) { - printk("md: md%d, array needs %d disks, has %d, aborting.\n", - mdidx(mddev), mddev->sb->raid_disks, mddev->nb_dev); - goto abort; - } - /* - * Now the numbering check - */ - for (i = 0; i < mddev->nb_dev; i++) { - c = 0; - ITERATE_RDEV(mddev,rdev,tmp) { - if (rdev->desc_nr == i) - c++; - } - if (!c) { - printk("md: md%d, missing disk #%d, aborting.\n", - mdidx(mddev), i); - goto abort; - } - if (c > 1) { - printk("md: md%d, too many disks #%d, aborting.\n", - mdidx(mddev), i); - goto abort; - } - } - return 0; -abort: - return 1; -} - -static void remove_descriptor (mdp_disk_t *disk, mdp_super_t *sb) -{ - if (disk_active(disk)) { - sb->working_disks--; - } else { - if (disk_spare(disk)) { - sb->spare_disks--; - sb->working_disks--; - } else { - sb->failed_disks--; - } - } - sb->nr_disks--; - disk->major = 0; - disk->minor = 0; - mark_disk_removed(disk); -} - -#define BAD_MAGIC KERN_ERR \ -"md: invalid raid superblock magic on %s\n" - -#define BAD_MINOR KERN_ERR \ -"md: %s: invalid raid minor (%x)\n" - -#define OUT_OF_MEM KERN_ALERT \ -"md: out of memory.\n" - -#define NO_SB KERN_ERR \ -"md: disabled device %s, could not read superblock.\n" - -#define BAD_CSUM KERN_WARNING \ -"md: invalid superblock checksum on %s\n" - -static int alloc_array_sb (mddev_t * mddev) -{ - if (mddev->sb) { - MD_BUG(); - return 0; - } - - mddev->sb = (mdp_super_t *) __get_free_page (GFP_KERNEL); - if (!mddev->sb) - return -ENOMEM; - md_clear_page(mddev->sb); - return 0; -} - -static int alloc_disk_sb (mdk_rdev_t * rdev) -{ - if (rdev->sb) - MD_BUG(); - - rdev->sb = (mdp_super_t *) __get_free_page(GFP_KERNEL); - if (!rdev->sb) { - printk (OUT_OF_MEM); - return -EINVAL; - } - md_clear_page(rdev->sb); - - return 0; -} - -static void free_disk_sb (mdk_rdev_t * rdev) -{ - if (rdev->sb) { - free_page((unsigned long) rdev->sb); - rdev->sb = NULL; - rdev->sb_offset = 0; - rdev->size = 0; - } else { - if (!rdev->faulty) - MD_BUG(); - } -} - -static void mark_rdev_faulty (mdk_rdev_t * rdev) -{ - if (!rdev) { - MD_BUG(); - return; - } - free_disk_sb(rdev); - rdev->faulty = 1; -} - -static int read_disk_sb (mdk_rdev_t * rdev) -{ - int ret = -EINVAL; - struct buffer_head *bh = NULL; - kdev_t dev = rdev->dev; - mdp_super_t *sb; - unsigned long sb_offset; - - if (!rdev->sb) { - MD_BUG(); - goto abort; - } - - /* - * Calculate the position of the superblock, - * it's at the end of the disk - */ - sb_offset = calc_dev_sboffset(rdev->dev, rdev->mddev, 1); - rdev->sb_offset = sb_offset; - printk("(read) %s's sb offset: %ld", partition_name(dev), sb_offset); - fsync_dev(dev); - set_blocksize (dev, MD_SB_BYTES); - bh = bread (dev, sb_offset / MD_SB_BLOCKS, MD_SB_BYTES); - - if (bh) { - sb = (mdp_super_t *) bh->b_data; - memcpy (rdev->sb, sb, MD_SB_BYTES); - } else { - printk (NO_SB,partition_name(rdev->dev)); - goto abort; - } - printk(" [events: %08lx]\n", (unsigned long)rdev->sb->events_lo); - ret = 0; -abort: - if (bh) - brelse (bh); - return ret; -} - -static unsigned int calc_sb_csum (mdp_super_t * sb) -{ - unsigned int disk_csum, csum; - - disk_csum = sb->sb_csum; - sb->sb_csum = 0; - csum = csum_partial((void *)sb, MD_SB_BYTES, 0); - sb->sb_csum = disk_csum; - return csum; -} - -/* - * Check one RAID superblock for generic plausibility - */ - -static int check_disk_sb (mdk_rdev_t * rdev) -{ - mdp_super_t *sb; - int ret = -EINVAL; - - sb = rdev->sb; - if (!sb) { - MD_BUG(); - goto abort; - } - - if (sb->md_magic != MD_SB_MAGIC) { - printk (BAD_MAGIC, partition_name(rdev->dev)); - goto abort; - } - - if (sb->md_minor >= MAX_MD_DEVS) { - printk (BAD_MINOR, partition_name(rdev->dev), - sb->md_minor); - goto abort; - } - - if (calc_sb_csum(sb) != sb->sb_csum) - printk(BAD_CSUM, partition_name(rdev->dev)); - ret = 0; -abort: - return ret; -} - -static kdev_t dev_unit(kdev_t dev) -{ - unsigned int mask; - struct gendisk *hd = find_gendisk(dev); - - if (!hd) - return 0; - mask = ~((1 << hd->minor_shift) - 1); - - return MKDEV(MAJOR(dev), MINOR(dev) & mask); -} - -static mdk_rdev_t * match_dev_unit(mddev_t *mddev, kdev_t dev) -{ - struct md_list_head *tmp; - mdk_rdev_t *rdev; - - ITERATE_RDEV(mddev,rdev,tmp) - if (dev_unit(rdev->dev) == dev_unit(dev)) - return rdev; - - return NULL; -} - -static int match_mddev_units(mddev_t *mddev1, mddev_t *mddev2) -{ - struct md_list_head *tmp; - mdk_rdev_t *rdev; - - ITERATE_RDEV(mddev1,rdev,tmp) - if (match_dev_unit(mddev2, rdev->dev)) - return 1; - - return 0; -} - -static MD_LIST_HEAD(all_raid_disks); -static MD_LIST_HEAD(pending_raid_disks); - -static void bind_rdev_to_array (mdk_rdev_t * rdev, mddev_t * mddev) -{ - mdk_rdev_t *same_pdev; - - if (rdev->mddev) { - MD_BUG(); - return; - } - same_pdev = match_dev_unit(mddev, rdev->dev); - if (same_pdev) - printk( KERN_WARNING -"md%d: WARNING: %s appears to be on the same physical disk as %s. True\n" -" protection against single-disk failure might be compromised.\n", - mdidx(mddev), partition_name(rdev->dev), - partition_name(same_pdev->dev)); - - md_list_add(&rdev->same_set, &mddev->disks); - rdev->mddev = mddev; - mddev->nb_dev++; - printk("bind<%s,%d>\n", partition_name(rdev->dev), mddev->nb_dev); -} - -static void unbind_rdev_from_array (mdk_rdev_t * rdev) -{ - if (!rdev->mddev) { - MD_BUG(); - return; - } - md_list_del(&rdev->same_set); - MD_INIT_LIST_HEAD(&rdev->same_set); - rdev->mddev->nb_dev--; - printk("unbind<%s,%d>\n", partition_name(rdev->dev), - rdev->mddev->nb_dev); - rdev->mddev = NULL; -} - -/* - * prevent the device from being mounted, repartitioned or - * otherwise reused by a RAID array (or any other kernel - * subsystem), by opening the device. [simply getting an - * inode is not enough, the SCSI module usage code needs - * an explicit open() on the device] - */ -static int lock_rdev (mdk_rdev_t *rdev) -{ - int err = 0; - - /* - * First insert a dummy inode. - */ - if (rdev->inode) - MD_BUG(); - rdev->inode = get_empty_inode(); - if (!rdev->inode) - return -ENOMEM; - /* - * we dont care about any other fields - */ - rdev->inode->i_dev = rdev->inode->i_rdev = rdev->dev; - insert_inode_hash(rdev->inode); - - memset(&rdev->filp, 0, sizeof(rdev->filp)); - rdev->filp.f_mode = 3; /* read write */ - return err; -} - -static void unlock_rdev (mdk_rdev_t *rdev) -{ - if (!rdev->inode) - MD_BUG(); - iput(rdev->inode); - rdev->inode = NULL; -} - -static void export_rdev (mdk_rdev_t * rdev) -{ - printk("export_rdev(%s)\n",partition_name(rdev->dev)); - if (rdev->mddev) - MD_BUG(); - unlock_rdev(rdev); - free_disk_sb(rdev); - md_list_del(&rdev->all); - MD_INIT_LIST_HEAD(&rdev->all); - if (rdev->pending.next != &rdev->pending) { - printk("(%s was pending)\n",partition_name(rdev->dev)); - md_list_del(&rdev->pending); - MD_INIT_LIST_HEAD(&rdev->pending); - } - rdev->dev = 0; - rdev->faulty = 0; - kfree(rdev); -} - -static void kick_rdev_from_array (mdk_rdev_t * rdev) -{ - unbind_rdev_from_array(rdev); - export_rdev(rdev); -} - -static void export_array (mddev_t *mddev) -{ - struct md_list_head *tmp; - mdk_rdev_t *rdev; - mdp_super_t *sb = mddev->sb; - - if (mddev->sb) { - mddev->sb = NULL; - free_page((unsigned long) sb); - } - - ITERATE_RDEV(mddev,rdev,tmp) { - if (!rdev->mddev) { - MD_BUG(); - continue; - } - kick_rdev_from_array(rdev); - } - if (mddev->nb_dev) - MD_BUG(); -} - -static void free_mddev (mddev_t *mddev) -{ - if (!mddev) { - MD_BUG(); - return; - } - - export_array(mddev); - md_size[mdidx(mddev)] = 0; - md_hd_struct[mdidx(mddev)].nr_sects = 0; - - /* - * Make sure nobody else is using this mddev - * (careful, we rely on the global kernel lock here) - */ - while (md_atomic_read(&mddev->resync_sem.count) != 1) - schedule(); - while (md_atomic_read(&mddev->recovery_sem.count) != 1) - schedule(); - - del_mddev_mapping(mddev, MKDEV(MD_MAJOR, mdidx(mddev))); - md_list_del(&mddev->all_mddevs); - MD_INIT_LIST_HEAD(&mddev->all_mddevs); - kfree(mddev); - MOD_DEC_USE_COUNT; -} - -#undef BAD_CSUM -#undef BAD_MAGIC -#undef OUT_OF_MEM -#undef NO_SB - -static void print_desc(mdp_disk_t *desc) -{ - printk(" DISK\n", desc->number, - partition_name(MKDEV(desc->major,desc->minor)), - desc->major,desc->minor,desc->raid_disk,desc->state); -} - -static void print_sb(mdp_super_t *sb) -{ - int i; - - printk(" SB: (V:%d.%d.%d) ID:<%08x.%08x.%08x.%08x> CT:%08x\n", - sb->major_version, sb->minor_version, sb->patch_version, - sb->set_uuid0, sb->set_uuid1, sb->set_uuid2, sb->set_uuid3, - sb->ctime); - printk(" L%d S%08d ND:%d RD:%d md%d LO:%d CS:%d\n", sb->level, - sb->size, sb->nr_disks, sb->raid_disks, sb->md_minor, - sb->layout, sb->chunk_size); - printk(" UT:%08x ST:%d AD:%d WD:%d FD:%d SD:%d CSUM:%08x E:%08lx\n", - sb->utime, sb->state, sb->active_disks, sb->working_disks, - sb->failed_disks, sb->spare_disks, - sb->sb_csum, (unsigned long)sb->events_lo); - - for (i = 0; i < MD_SB_DISKS; i++) { - mdp_disk_t *desc; - - desc = sb->disks + i; - printk(" D %2d: ", i); - print_desc(desc); - } - printk(" THIS: "); - print_desc(&sb->this_disk); - -} - -static void print_rdev(mdk_rdev_t *rdev) -{ - printk(" rdev %s: O:%s, SZ:%08ld F:%d DN:%d ", - partition_name(rdev->dev), partition_name(rdev->old_dev), - rdev->size, rdev->faulty, rdev->desc_nr); - if (rdev->sb) { - printk("rdev superblock:\n"); - print_sb(rdev->sb); - } else - printk("no rdev superblock!\n"); -} - -void md_print_devices (void) -{ - struct md_list_head *tmp, *tmp2; - mdk_rdev_t *rdev; - mddev_t *mddev; - - printk("\n"); - printk(" **********************************\n"); - printk(" * *\n"); - printk(" **********************************\n"); - ITERATE_MDDEV(mddev,tmp) { - printk("md%d: ", mdidx(mddev)); - - ITERATE_RDEV(mddev,rdev,tmp2) - printk("<%s>", partition_name(rdev->dev)); - - if (mddev->sb) { - printk(" array superblock:\n"); - print_sb(mddev->sb); - } else - printk(" no array superblock.\n"); - - ITERATE_RDEV(mddev,rdev,tmp2) - print_rdev(rdev); - } - printk(" **********************************\n"); - printk("\n"); -} - -static int sb_equal ( mdp_super_t *sb1, mdp_super_t *sb2) -{ - int ret; - mdp_super_t *tmp1, *tmp2; - - tmp1 = kmalloc(sizeof(*tmp1),GFP_KERNEL); - tmp2 = kmalloc(sizeof(*tmp2),GFP_KERNEL); - - if (!tmp1 || !tmp2) { - ret = 0; - goto abort; - } - - *tmp1 = *sb1; - *tmp2 = *sb2; - - /* - * nr_disks is not constant - */ - tmp1->nr_disks = 0; - tmp2->nr_disks = 0; - - if (memcmp(tmp1, tmp2, MD_SB_GENERIC_CONSTANT_WORDS * 4)) - ret = 0; - else - ret = 1; - -abort: - if (tmp1) - kfree(tmp1); - if (tmp2) - kfree(tmp2); - - return ret; -} - -static int uuid_equal(mdk_rdev_t *rdev1, mdk_rdev_t *rdev2) -{ - if ( (rdev1->sb->set_uuid0 == rdev2->sb->set_uuid0) && - (rdev1->sb->set_uuid1 == rdev2->sb->set_uuid1) && - (rdev1->sb->set_uuid2 == rdev2->sb->set_uuid2) && - (rdev1->sb->set_uuid3 == rdev2->sb->set_uuid3)) - - return 1; - - return 0; -} - -static mdk_rdev_t * find_rdev_all (kdev_t dev) -{ - struct md_list_head *tmp; - mdk_rdev_t *rdev; - - tmp = all_raid_disks.next; - while (tmp != &all_raid_disks) { - rdev = md_list_entry(tmp, mdk_rdev_t, all); - if (rdev->dev == dev) - return rdev; - tmp = tmp->next; - } - return NULL; -} - -#define GETBLK_FAILED KERN_ERR \ -"md: getblk failed for device %s\n" - -static int write_disk_sb(mdk_rdev_t * rdev) -{ - struct buffer_head *bh; - kdev_t dev; - unsigned long sb_offset, size; - mdp_super_t *sb; - - if (!rdev->sb) { - MD_BUG(); - return -1; - } - if (rdev->faulty) { - MD_BUG(); - return -1; - } - if (rdev->sb->md_magic != MD_SB_MAGIC) { - MD_BUG(); - return -1; - } - - dev = rdev->dev; - sb_offset = calc_dev_sboffset(dev, rdev->mddev, 1); - if (rdev->sb_offset != sb_offset) { - printk("%s's sb offset has changed from %ld to %ld, skipping\n", partition_name(dev), rdev->sb_offset, sb_offset); - goto skip; - } - /* - * If the disk went offline meanwhile and it's just a spare, then - * it's size has changed to zero silently, and the MD code does - * not yet know that it's faulty. - */ - size = calc_dev_size(dev, rdev->mddev, 1); - if (size != rdev->size) { - printk("%s's size has changed from %ld to %ld since import, skipping\n", partition_name(dev), rdev->size, size); - goto skip; - } - - printk("(write) %s's sb offset: %ld\n", partition_name(dev), sb_offset); - fsync_dev(dev); - set_blocksize(dev, MD_SB_BYTES); - bh = getblk(dev, sb_offset / MD_SB_BLOCKS, MD_SB_BYTES); - if (!bh) { - printk(GETBLK_FAILED, partition_name(dev)); - return 1; - } - memset(bh->b_data,0,bh->b_size); - sb = (mdp_super_t *) bh->b_data; - memcpy(sb, rdev->sb, MD_SB_BYTES); - - mark_buffer_uptodate(bh, 1); - mark_buffer_dirty(bh); - ll_rw_block(WRITE, 1, &bh); - wait_on_buffer(bh); - brelse(bh); - fsync_dev(dev); -skip: - return 0; -} -#undef GETBLK_FAILED - -static void set_this_disk(mddev_t *mddev, mdk_rdev_t *rdev) -{ - int i, ok = 0; - mdp_disk_t *desc; - - for (i = 0; i < MD_SB_DISKS; i++) { - desc = mddev->sb->disks + i; -#if 0 - if (disk_faulty(desc)) { - if (MKDEV(desc->major,desc->minor) == rdev->dev) - ok = 1; - continue; - } -#endif - if (MKDEV(desc->major,desc->minor) == rdev->dev) { - rdev->sb->this_disk = *desc; - rdev->desc_nr = desc->number; - ok = 1; - break; - } - } - - if (!ok) { - MD_BUG(); - } -} - -static int sync_sbs(mddev_t * mddev) -{ - mdk_rdev_t *rdev; - mdp_super_t *sb; - struct md_list_head *tmp; - - ITERATE_RDEV(mddev,rdev,tmp) { - if (rdev->faulty) - continue; - sb = rdev->sb; - *sb = *mddev->sb; - set_this_disk(mddev, rdev); - sb->sb_csum = calc_sb_csum(sb); - } - return 0; -} - -int md_update_sb(mddev_t * mddev) -{ - int first, err, count = 100; - struct md_list_head *tmp; - mdk_rdev_t *rdev; - -repeat: - mddev->sb->utime = CURRENT_TIME; - if ((++mddev->sb->events_lo)==0) - ++mddev->sb->events_hi; - - if ((mddev->sb->events_lo|mddev->sb->events_hi)==0) { - /* - * oops, this 64-bit counter should never wrap. - * Either we are in around ~1 trillion A.C., assuming - * 1 reboot per second, or we have a bug: - */ - MD_BUG(); - mddev->sb->events_lo = mddev->sb->events_hi = 0xffffffff; - } - sync_sbs(mddev); - - /* - * do not write anything to disk if using - * nonpersistent superblocks - */ - if (mddev->sb->not_persistent) - return 0; - - printk(KERN_INFO "md: updating md%d RAID superblock on device\n", - mdidx(mddev)); - - first = 1; - err = 0; - ITERATE_RDEV(mddev,rdev,tmp) { - if (!first) { - first = 0; - printk(", "); - } - if (rdev->faulty) - printk("(skipping faulty "); - printk("%s ", partition_name(rdev->dev)); - if (!rdev->faulty) { - printk("[events: %08lx]", - (unsigned long)rdev->sb->events_lo); - err += write_disk_sb(rdev); - } else - printk(")\n"); - } - printk(".\n"); - if (err) { - printk("errors occured during superblock update, repeating\n"); - if (--count) - goto repeat; - printk("excessive errors occured during superblock update, exiting\n"); - } - return 0; -} - -/* - * Import a device. If 'on_disk', then sanity check the superblock - * - * mark the device faulty if: - * - * - the device is nonexistent (zero size) - * - the device has no valid superblock - * - * a faulty rdev _never_ has rdev->sb set. - */ -static int md_import_device (kdev_t newdev, int on_disk) -{ - int err; - mdk_rdev_t *rdev; - unsigned int size; - - if (find_rdev_all(newdev)) - return -EEXIST; - - rdev = (mdk_rdev_t *) kmalloc(sizeof(*rdev), GFP_KERNEL); - if (!rdev) { - printk("could not alloc mem for %s!\n", partition_name(newdev)); - return -ENOMEM; - } - memset(rdev, 0, sizeof(*rdev)); - - if (get_super(newdev)) { - printk("md: can not import %s, has active inodes!\n", - partition_name(newdev)); - err = -EBUSY; - goto abort_free; - } - - if ((err = alloc_disk_sb(rdev))) - goto abort_free; - - rdev->dev = newdev; - if (lock_rdev(rdev)) { - printk("md: could not lock %s, zero-size? Marking faulty.\n", - partition_name(newdev)); - err = -EINVAL; - goto abort_free; - } - rdev->desc_nr = -1; - rdev->faulty = 0; - - size = 0; - if (blk_size[MAJOR(newdev)]) - size = blk_size[MAJOR(newdev)][MINOR(newdev)]; - if (!size) { - printk("md: %s has zero size, marking faulty!\n", - partition_name(newdev)); - err = -EINVAL; - goto abort_free; - } - - if (on_disk) { - if ((err = read_disk_sb(rdev))) { - printk("md: could not read %s's sb, not importing!\n", - partition_name(newdev)); - goto abort_free; - } - if ((err = check_disk_sb(rdev))) { - printk("md: %s has invalid sb, not importing!\n", - partition_name(newdev)); - goto abort_free; - } - - rdev->old_dev = MKDEV(rdev->sb->this_disk.major, - rdev->sb->this_disk.minor); - rdev->desc_nr = rdev->sb->this_disk.number; - } - md_list_add(&rdev->all, &all_raid_disks); - MD_INIT_LIST_HEAD(&rdev->pending); - - if (rdev->faulty && rdev->sb) - free_disk_sb(rdev); - return 0; - -abort_free: - if (rdev->sb) { - if (rdev->inode) - unlock_rdev(rdev); - free_disk_sb(rdev); - } - kfree(rdev); - return err; -} - -/* - * Check a full RAID array for plausibility - */ - -#define INCONSISTENT KERN_ERR \ -"md: fatal superblock inconsistency in %s -- removing from array\n" - -#define OUT_OF_DATE KERN_ERR \ -"md: superblock update time inconsistency -- using the most recent one\n" - -#define OLD_VERSION KERN_ALERT \ -"md: md%d: unsupported raid array version %d.%d.%d\n" - -#define NOT_CLEAN_IGNORE KERN_ERR \ -"md: md%d: raid array is not clean -- starting background reconstruction\n" - -#define UNKNOWN_LEVEL KERN_ERR \ -"md: md%d: unsupported raid level %d\n" - -static int analyze_sbs (mddev_t * mddev) -{ - int out_of_date = 0, i; - struct md_list_head *tmp, *tmp2; - mdk_rdev_t *rdev, *rdev2, *freshest; - mdp_super_t *sb; - - /* - * Verify the RAID superblock on each real device - */ - ITERATE_RDEV(mddev,rdev,tmp) { - if (rdev->faulty) { - MD_BUG(); - goto abort; - } - if (!rdev->sb) { - MD_BUG(); - goto abort; - } - if (check_disk_sb(rdev)) - goto abort; - } - - /* - * The superblock constant part has to be the same - * for all disks in the array. - */ - sb = NULL; - - ITERATE_RDEV(mddev,rdev,tmp) { - if (!sb) { - sb = rdev->sb; - continue; - } - if (!sb_equal(sb, rdev->sb)) { - printk (INCONSISTENT, partition_name(rdev->dev)); - kick_rdev_from_array(rdev); - continue; - } - } - - /* - * OK, we have all disks and the array is ready to run. Let's - * find the freshest superblock, that one will be the superblock - * that represents the whole array. - */ - if (!mddev->sb) - if (alloc_array_sb(mddev)) - goto abort; - sb = mddev->sb; - freshest = NULL; - - ITERATE_RDEV(mddev,rdev,tmp) { - __u64 ev1, ev2; - /* - * if the checksum is invalid, use the superblock - * only as a last resort. (decrease it's age by - * one event) - */ - if (calc_sb_csum(rdev->sb) != rdev->sb->sb_csum) { - if (rdev->sb->events_lo || rdev->sb->events_hi) - if ((rdev->sb->events_lo--)==0) - rdev->sb->events_hi--; - } - - printk("%s's event counter: %08lx\n", partition_name(rdev->dev), - (unsigned long)rdev->sb->events_lo); - if (!freshest) { - freshest = rdev; - continue; - } - /* - * Find the newest superblock version - */ - ev1 = md_event(rdev->sb); - ev2 = md_event(freshest->sb); - if (ev1 != ev2) { - out_of_date = 1; - if (ev1 > ev2) - freshest = rdev; - } - } - if (out_of_date) { - printk(OUT_OF_DATE); - printk("freshest: %s\n", partition_name(freshest->dev)); - } - memcpy (sb, freshest->sb, sizeof(*sb)); - - /* - * at this point we have picked the 'best' superblock - * from all available superblocks. - * now we validate this superblock and kick out possibly - * failed disks. - */ - ITERATE_RDEV(mddev,rdev,tmp) { - /* - * Kick all non-fresh devices faulty - */ - __u64 ev1, ev2; - ev1 = md_event(rdev->sb); - ev2 = md_event(sb); - ++ev1; - if (ev1 < ev2) { - printk("md: kicking non-fresh %s from array!\n", - partition_name(rdev->dev)); - kick_rdev_from_array(rdev); - continue; - } - } - - /* - * Fix up changed device names ... but only if this disk has a - * recent update time. Use faulty checksum ones too. - */ - ITERATE_RDEV(mddev,rdev,tmp) { - __u64 ev1, ev2, ev3; - if (rdev->faulty) { /* REMOVEME */ - MD_BUG(); - goto abort; - } - ev1 = md_event(rdev->sb); - ev2 = md_event(sb); - ev3 = ev2; - --ev3; - if ((rdev->dev != rdev->old_dev) && - ((ev1 == ev2) || (ev1 == ev3))) { - mdp_disk_t *desc; - - printk("md: device name has changed from %s to %s since last import!\n", partition_name(rdev->old_dev), partition_name(rdev->dev)); - if (rdev->desc_nr == -1) { - MD_BUG(); - goto abort; - } - desc = &sb->disks[rdev->desc_nr]; - if (rdev->old_dev != MKDEV(desc->major, desc->minor)) { - MD_BUG(); - goto abort; - } - desc->major = MAJOR(rdev->dev); - desc->minor = MINOR(rdev->dev); - desc = &rdev->sb->this_disk; - desc->major = MAJOR(rdev->dev); - desc->minor = MINOR(rdev->dev); - } - } - - /* - * Remove unavailable and faulty devices ... - * - * note that if an array becomes completely unrunnable due to - * missing devices, we do not write the superblock back, so the - * administrator has a chance to fix things up. The removal thus - * only happens if it's nonfatal to the contents of the array. - */ - for (i = 0; i < MD_SB_DISKS; i++) { - int found; - mdp_disk_t *desc; - kdev_t dev; - - desc = sb->disks + i; - dev = MKDEV(desc->major, desc->minor); - - /* - * We kick faulty devices/descriptors immediately. - */ - if (disk_faulty(desc)) { - found = 0; - ITERATE_RDEV(mddev,rdev,tmp) { - if (rdev->desc_nr != desc->number) - continue; - printk("md%d: kicking faulty %s!\n", - mdidx(mddev),partition_name(rdev->dev)); - kick_rdev_from_array(rdev); - found = 1; - break; - } - if (!found) { - if (dev == MKDEV(0,0)) - continue; - printk("md%d: removing former faulty %s!\n", - mdidx(mddev), partition_name(dev)); - } - remove_descriptor(desc, sb); - continue; - } - - if (dev == MKDEV(0,0)) - continue; - /* - * Is this device present in the rdev ring? - */ - found = 0; - ITERATE_RDEV(mddev,rdev,tmp) { - if (rdev->desc_nr == desc->number) { - found = 1; - break; - } - } - if (found) - continue; - - printk("md%d: former device %s is unavailable, removing from array!\n", mdidx(mddev), partition_name(dev)); - remove_descriptor(desc, sb); - } - - /* - * Double check wether all devices mentioned in the - * superblock are in the rdev ring. - */ - for (i = 0; i < MD_SB_DISKS; i++) { - mdp_disk_t *desc; - kdev_t dev; - - desc = sb->disks + i; - dev = MKDEV(desc->major, desc->minor); - - if (dev == MKDEV(0,0)) - continue; - - if (disk_faulty(desc)) { - MD_BUG(); - goto abort; - } - - rdev = find_rdev(mddev, dev); - if (!rdev) { - MD_BUG(); - goto abort; - } - } - - /* - * Do a final reality check. - */ - ITERATE_RDEV(mddev,rdev,tmp) { - if (rdev->desc_nr == -1) { - MD_BUG(); - goto abort; - } - /* - * is the desc_nr unique? - */ - ITERATE_RDEV(mddev,rdev2,tmp2) { - if ((rdev2 != rdev) && - (rdev2->desc_nr == rdev->desc_nr)) { - MD_BUG(); - goto abort; - } - } - /* - * is the device unique? - */ - ITERATE_RDEV(mddev,rdev2,tmp2) { - if ((rdev2 != rdev) && - (rdev2->dev == rdev->dev)) { - MD_BUG(); - goto abort; - } - } - } - - /* - * Check if we can support this RAID array - */ - if (sb->major_version != MD_MAJOR_VERSION || - sb->minor_version > MD_MINOR_VERSION) { - - printk (OLD_VERSION, mdidx(mddev), sb->major_version, - sb->minor_version, sb->patch_version); - goto abort; - } - - if ((sb->state != (1 << MD_SB_CLEAN)) && ((sb->level == 1) || - (sb->level == 4) || (sb->level == 5))) - printk (NOT_CLEAN_IGNORE, mdidx(mddev)); - - return 0; -abort: - return 1; -} - -#undef INCONSISTENT -#undef OUT_OF_DATE -#undef OLD_VERSION -#undef OLD_LEVEL - -static int device_size_calculation (mddev_t * mddev) -{ - int data_disks = 0, persistent; - unsigned int readahead; - mdp_super_t *sb = mddev->sb; - struct md_list_head *tmp; - mdk_rdev_t *rdev; - - /* - * Do device size calculation. Bail out if too small. - * (we have to do this after having validated chunk_size, - * because device size has to be modulo chunk_size) - */ - persistent = !mddev->sb->not_persistent; - ITERATE_RDEV(mddev,rdev,tmp) { - if (rdev->faulty) - continue; - if (rdev->size) { - MD_BUG(); - continue; - } - rdev->size = calc_dev_size(rdev->dev, mddev, persistent); - if (rdev->size < sb->chunk_size / 1024) { - printk (KERN_WARNING - "Dev %s smaller than chunk_size: %ldk < %dk\n", - partition_name(rdev->dev), - rdev->size, sb->chunk_size / 1024); - return -EINVAL; - } - } - - switch (sb->level) { - case -3: - data_disks = 1; - break; - case -2: - data_disks = 1; - break; - case -1: - zoned_raid_size(mddev); - data_disks = 1; - break; - case 0: - zoned_raid_size(mddev); - data_disks = sb->raid_disks; - break; - case 1: - data_disks = 1; - break; - case 4: - case 5: - data_disks = sb->raid_disks-1; - break; - default: - printk (UNKNOWN_LEVEL, mdidx(mddev), sb->level); - goto abort; - } - if (!md_size[mdidx(mddev)]) - md_size[mdidx(mddev)] = sb->size * data_disks; - - readahead = MD_READAHEAD; - if ((sb->level == 0) || (sb->level == 4) || (sb->level == 5)) { - readahead = (mddev->sb->chunk_size>>PAGE_SHIFT) * 4 * data_disks; - if (readahead < data_disks * (MAX_SECTORS>>(PAGE_SHIFT-9))*2) - readahead = data_disks * (MAX_SECTORS>>(PAGE_SHIFT-9))*2; - } else { - if (sb->level == -3) - readahead = 0; - } - md_maxreadahead[mdidx(mddev)] = readahead; - - printk(KERN_INFO "md%d: max total readahead window set to %ldk\n", - mdidx(mddev), readahead*(PAGE_SIZE/1024)); - - printk(KERN_INFO - "md%d: %d data-disks, max readahead per data-disk: %ldk\n", - mdidx(mddev), data_disks, readahead/data_disks*(PAGE_SIZE/1024)); - return 0; -abort: - return 1; -} - - -#define TOO_BIG_CHUNKSIZE KERN_ERR \ -"too big chunk_size: %d > %d\n" - -#define TOO_SMALL_CHUNKSIZE KERN_ERR \ -"too small chunk_size: %d < %ld\n" - -#define BAD_CHUNKSIZE KERN_ERR \ -"no chunksize specified, see 'man raidtab'\n" - -static int do_md_run (mddev_t * mddev) -{ - int pnum, err; - int chunk_size; - struct md_list_head *tmp; - mdk_rdev_t *rdev; - - - if (!mddev->nb_dev) { - MD_BUG(); - return -EINVAL; - } - - if (mddev->pers) - return -EBUSY; - - /* - * Resize disks to align partitions size on a given - * chunk size. - */ - md_size[mdidx(mddev)] = 0; - - /* - * Analyze all RAID superblock(s) - */ - if (analyze_sbs(mddev)) { - MD_BUG(); - return -EINVAL; - } - - chunk_size = mddev->sb->chunk_size; - pnum = level_to_pers(mddev->sb->level); - - mddev->param.chunk_size = chunk_size; - mddev->param.personality = pnum; - - if (chunk_size > MAX_CHUNK_SIZE) { - printk(TOO_BIG_CHUNKSIZE, chunk_size, MAX_CHUNK_SIZE); - return -EINVAL; - } - /* - * chunk-size has to be a power of 2 and multiples of PAGE_SIZE - */ - if ( (1 << ffz(~chunk_size)) != chunk_size) { - MD_BUG(); - return -EINVAL; - } - if (chunk_size < PAGE_SIZE) { - printk(TOO_SMALL_CHUNKSIZE, chunk_size, PAGE_SIZE); - return -EINVAL; - } - - if (pnum >= MAX_PERSONALITY) { - MD_BUG(); - return -EINVAL; - } - - if ((pnum != RAID1) && (pnum != LINEAR) && !chunk_size) { - /* - * 'default chunksize' in the old md code used to - * be PAGE_SIZE, baaad. - * we abort here to be on the safe side. We dont - * want to continue the bad practice. - */ - printk(BAD_CHUNKSIZE); - return -EINVAL; - } - - if (!pers[pnum]) - { -#ifdef CONFIG_KMOD - char module_name[80]; - sprintf (module_name, "md-personality-%d", pnum); - request_module (module_name); - if (!pers[pnum]) -#endif - return -EINVAL; - } - - if (device_size_calculation(mddev)) - return -EINVAL; - - /* - * Drop all container device buffers, from now on - * the only valid external interface is through the md - * device. - * Also find largest hardsector size - */ - md_hardsect_sizes[mdidx(mddev)] = 512; - ITERATE_RDEV(mddev,rdev,tmp) { - if (rdev->faulty) - continue; - fsync_dev(rdev->dev); - invalidate_buffers(rdev->dev); - if (get_hardsect_size(rdev->dev) - > md_hardsect_sizes[mdidx(mddev)]) - md_hardsect_sizes[mdidx(mddev)] = - get_hardsect_size(rdev->dev); - } - md_blocksizes[mdidx(mddev)] = 1024; - if (md_blocksizes[mdidx(mddev)] < md_hardsect_sizes[mdidx(mddev)]) - md_blocksizes[mdidx(mddev)] = md_hardsect_sizes[mdidx(mddev)]; - mddev->pers = pers[pnum]; - - err = mddev->pers->run(mddev); - if (err) { - printk("pers->run() failed ...\n"); - mddev->pers = NULL; - return -EINVAL; - } - - mddev->sb->state &= ~(1 << MD_SB_CLEAN); - md_update_sb(mddev); - - /* - * md_size has units of 1K blocks, which are - * twice as large as sectors. - */ - md_hd_struct[mdidx(mddev)].start_sect = 0; - md_hd_struct[mdidx(mddev)].nr_sects = md_size[mdidx(mddev)] << 1; - - read_ahead[MD_MAJOR] = 1024; - return (0); -} - -#undef TOO_BIG_CHUNKSIZE -#undef BAD_CHUNKSIZE - -#define OUT(x) do { err = (x); goto out; } while (0) - -static int restart_array (mddev_t *mddev) -{ - int err = 0; - - /* - * Complain if it has no devices - */ - if (!mddev->nb_dev) - OUT(-ENXIO); - - if (mddev->pers) { - if (!mddev->ro) - OUT(-EBUSY); - - mddev->ro = 0; - set_device_ro(mddev_to_kdev(mddev), 0); - - printk (KERN_INFO - "md%d switched to read-write mode.\n", mdidx(mddev)); - /* - * Kick recovery or resync if necessary - */ - md_recover_arrays(); - if (mddev->pers->restart_resync) - mddev->pers->restart_resync(mddev); - } else - err = -EINVAL; - -out: - return err; -} - -#define STILL_MOUNTED KERN_WARNING \ -"md: md%d still mounted.\n" - -static int do_md_stop (mddev_t * mddev, int ro) -{ - int err = 0, resync_interrupted = 0; - kdev_t dev = mddev_to_kdev(mddev); - - if (!ro && get_super(dev)) { - printk (STILL_MOUNTED, mdidx(mddev)); - OUT(-EBUSY); - } - - if (mddev->pers) { - /* - * It is safe to call stop here, it only frees private - * data. Also, it tells us if a device is unstoppable - * (eg. resyncing is in progress) - */ - if (mddev->pers->stop_resync) - if (mddev->pers->stop_resync(mddev)) - resync_interrupted = 1; - - if (mddev->recovery_running) - md_interrupt_thread(md_recovery_thread); - - /* - * This synchronizes with signal delivery to the - * resync or reconstruction thread. It also nicely - * hangs the process if some reconstruction has not - * finished. - */ - down(&mddev->recovery_sem); - up(&mddev->recovery_sem); - - /* - * sync and invalidate buffers because we cannot kill the - * main thread with valid IO transfers still around. - * the kernel lock protects us from new requests being - * added after invalidate_buffers(). - */ - fsync_dev (mddev_to_kdev(mddev)); - fsync_dev (dev); - invalidate_buffers (dev); - - if (ro) { - if (mddev->ro) - OUT(-ENXIO); - mddev->ro = 1; - } else { - if (mddev->ro) - set_device_ro(dev, 0); - if (mddev->pers->stop(mddev)) { - if (mddev->ro) - set_device_ro(dev, 1); - OUT(-EBUSY); - } - if (mddev->ro) - mddev->ro = 0; - } - if (mddev->sb) { - /* - * mark it clean only if there was no resync - * interrupted. - */ - if (!mddev->recovery_running && !resync_interrupted) { - printk("marking sb clean...\n"); - mddev->sb->state |= 1 << MD_SB_CLEAN; - } - md_update_sb(mddev); - } - if (ro) - set_device_ro(dev, 1); - } - - /* - * Free resources if final stop - */ - if (!ro) { - printk (KERN_INFO "md%d stopped.\n", mdidx(mddev)); - free_mddev(mddev); - - } else - printk (KERN_INFO - "md%d switched to read-only mode.\n", mdidx(mddev)); -out: - return err; -} - -#undef OUT - -/* - * We have to safely support old arrays too. - */ -int detect_old_array (mdp_super_t *sb) -{ - if (sb->major_version > 0) - return 0; - if (sb->minor_version >= 90) - return 0; - - return -EINVAL; -} - - -static void autorun_array (mddev_t *mddev) -{ - mdk_rdev_t *rdev; - struct md_list_head *tmp; - int err; - - if (mddev->disks.prev == &mddev->disks) { - MD_BUG(); - return; - } - - printk("running: "); - - ITERATE_RDEV(mddev,rdev,tmp) { - printk("<%s>", partition_name(rdev->dev)); - } - printk("\nnow!\n"); - - err = do_md_run (mddev); - if (err) { - printk("do_md_run() returned %d\n", err); - /* - * prevent the writeback of an unrunnable array - */ - mddev->sb_dirty = 0; - do_md_stop (mddev, 0); - } -} - -/* - * lets try to run arrays based on all disks that have arrived - * until now. (those are in the ->pending list) - * - * the method: pick the first pending disk, collect all disks with - * the same UUID, remove all from the pending list and put them into - * the 'same_array' list. Then order this list based on superblock - * update time (freshest comes first), kick out 'old' disks and - * compare superblocks. If everything's fine then run it. - */ -static void autorun_devices (void) -{ - struct md_list_head candidates; - struct md_list_head *tmp; - mdk_rdev_t *rdev0, *rdev; - mddev_t *mddev; - kdev_t md_kdev; - - - printk("autorun ...\n"); - while (pending_raid_disks.next != &pending_raid_disks) { - rdev0 = md_list_entry(pending_raid_disks.next, - mdk_rdev_t, pending); - - printk("considering %s ...\n", partition_name(rdev0->dev)); - MD_INIT_LIST_HEAD(&candidates); - ITERATE_RDEV_PENDING(rdev,tmp) { - if (uuid_equal(rdev0, rdev)) { - if (!sb_equal(rdev0->sb, rdev->sb)) { - printk("%s has same UUID as %s, but superblocks differ ...\n", partition_name(rdev->dev), partition_name(rdev0->dev)); - continue; - } - printk(" adding %s ...\n", partition_name(rdev->dev)); - md_list_del(&rdev->pending); - md_list_add(&rdev->pending, &candidates); - } - } - /* - * now we have a set of devices, with all of them having - * mostly sane superblocks. It's time to allocate the - * mddev. - */ - md_kdev = MKDEV(MD_MAJOR, rdev0->sb->md_minor); - mddev = kdev_to_mddev(md_kdev); - if (mddev) { - printk("md%d already running, cannot run %s\n", - mdidx(mddev), partition_name(rdev0->dev)); - ITERATE_RDEV_GENERIC(candidates,pending,rdev,tmp) - export_rdev(rdev); - continue; - } - mddev = alloc_mddev(md_kdev); - printk("created md%d\n", mdidx(mddev)); - ITERATE_RDEV_GENERIC(candidates,pending,rdev,tmp) { - bind_rdev_to_array(rdev, mddev); - md_list_del(&rdev->pending); - MD_INIT_LIST_HEAD(&rdev->pending); - } - autorun_array(mddev); - } - printk("... autorun DONE.\n"); -} - -/* - * import RAID devices based on one partition - * if possible, the array gets run as well. - */ - -#define BAD_VERSION KERN_ERR \ -"md: %s has RAID superblock version 0.%d, autodetect needs v0.90 or higher\n" - -#define OUT_OF_MEM KERN_ALERT \ -"md: out of memory.\n" - -#define NO_DEVICE KERN_ERR \ -"md: disabled device %s\n" - -#define AUTOADD_FAILED KERN_ERR \ -"md: auto-adding devices to md%d FAILED (error %d).\n" - -#define AUTOADD_FAILED_USED KERN_ERR \ -"md: cannot auto-add device %s to md%d, already used.\n" - -#define AUTORUN_FAILED KERN_ERR \ -"md: auto-running md%d FAILED (error %d).\n" - -#define MDDEV_BUSY KERN_ERR \ -"md: cannot auto-add to md%d, already running.\n" - -#define AUTOADDING KERN_INFO \ -"md: auto-adding devices to md%d, based on %s's superblock.\n" - -#define AUTORUNNING KERN_INFO \ -"md: auto-running md%d.\n" - -static int autostart_array (kdev_t startdev) -{ - int err = -EINVAL, i; - mdp_super_t *sb = NULL; - mdk_rdev_t *start_rdev = NULL, *rdev; - - if (md_import_device(startdev, 1)) { - printk("could not import %s!\n", partition_name(startdev)); - goto abort; - } - - start_rdev = find_rdev_all(startdev); - if (!start_rdev) { - MD_BUG(); - goto abort; - } - if (start_rdev->faulty) { - printk("can not autostart based on faulty %s!\n", - partition_name(startdev)); - goto abort; - } - md_list_add(&start_rdev->pending, &pending_raid_disks); - - sb = start_rdev->sb; - - err = detect_old_array(sb); - if (err) { - printk("array version is too old to be autostarted, use raidtools 0.90 mkraid --upgrade\nto upgrade the array without data loss!\n"); - goto abort; - } - - for (i = 0; i < MD_SB_DISKS; i++) { - mdp_disk_t *desc; - kdev_t dev; - - desc = sb->disks + i; - dev = MKDEV(desc->major, desc->minor); - - if (dev == MKDEV(0,0)) - continue; - if (dev == startdev) - continue; - if (md_import_device(dev, 1)) { - printk("could not import %s, trying to run array nevertheless.\n", partition_name(dev)); - continue; - } - rdev = find_rdev_all(dev); - if (!rdev) { - MD_BUG(); - goto abort; - } - md_list_add(&rdev->pending, &pending_raid_disks); - } - - /* - * possibly return codes - */ - autorun_devices(); - return 0; - -abort: - if (start_rdev) - export_rdev(start_rdev); - return err; -} - -#undef BAD_VERSION -#undef OUT_OF_MEM -#undef NO_DEVICE -#undef AUTOADD_FAILED_USED -#undef AUTOADD_FAILED -#undef AUTORUN_FAILED -#undef AUTOADDING -#undef AUTORUNNING - -struct { - int set; - int noautodetect; - -} raid_setup_args md__initdata = { 0, 0 }; - -void md_setup_drive(void) md__init; - -/* - * Searches all registered partitions for autorun RAID arrays - * at boot time. - */ -#ifdef CONFIG_AUTODETECT_RAID -static int detected_devices[128] md__initdata; -static int dev_cnt=0; -void md_autodetect_dev(kdev_t dev) -{ - if (dev_cnt >= 0 && dev_cnt < 127) - detected_devices[dev_cnt++] = dev; -} -#endif - -void md__init md_run_setup(void) -{ -#ifdef CONFIG_AUTODETECT_RAID - mdk_rdev_t *rdev; - int i; - - if (raid_setup_args.noautodetect) - printk(KERN_INFO "skipping autodetection of RAID arrays\n"); - else { - - printk(KERN_INFO "autodetecting RAID arrays\n"); - - for (i=0; ifaulty) { - MD_BUG(); - continue; - } - md_list_add(&rdev->pending, &pending_raid_disks); - } - - autorun_devices(); - } - - dev_cnt = -1; /* make sure further calls to md_autodetect_dev are ignored */ -#endif -#ifdef CONFIG_MD_BOOT - md_setup_drive(); -#endif - -} - -static int get_version (void * arg) -{ - mdu_version_t ver; - - ver.major = MD_MAJOR_VERSION; - ver.minor = MD_MINOR_VERSION; - ver.patchlevel = MD_PATCHLEVEL_VERSION; - - if (md_copy_to_user(arg, &ver, sizeof(ver))) - return -EFAULT; - - return 0; -} - -#define SET_FROM_SB(x) info.x = mddev->sb->x -static int get_array_info (mddev_t * mddev, void * arg) -{ - mdu_array_info_t info; - - if (!mddev->sb) - return -EINVAL; - - SET_FROM_SB(major_version); - SET_FROM_SB(minor_version); - SET_FROM_SB(patch_version); - SET_FROM_SB(ctime); - SET_FROM_SB(level); - SET_FROM_SB(size); - SET_FROM_SB(nr_disks); - SET_FROM_SB(raid_disks); - SET_FROM_SB(md_minor); - SET_FROM_SB(not_persistent); - - SET_FROM_SB(utime); - SET_FROM_SB(state); - SET_FROM_SB(active_disks); - SET_FROM_SB(working_disks); - SET_FROM_SB(failed_disks); - SET_FROM_SB(spare_disks); - - SET_FROM_SB(layout); - SET_FROM_SB(chunk_size); - - if (md_copy_to_user(arg, &info, sizeof(info))) - return -EFAULT; - - return 0; -} -#undef SET_FROM_SB - -#define SET_FROM_SB(x) info.x = mddev->sb->disks[nr].x -static int get_disk_info (mddev_t * mddev, void * arg) -{ - mdu_disk_info_t info; - unsigned int nr; - - if (!mddev->sb) - return -EINVAL; - - if (md_copy_from_user(&info, arg, sizeof(info))) - return -EFAULT; - - nr = info.number; - if (nr >= mddev->sb->nr_disks) - return -EINVAL; - - SET_FROM_SB(major); - SET_FROM_SB(minor); - SET_FROM_SB(raid_disk); - SET_FROM_SB(state); - - if (md_copy_to_user(arg, &info, sizeof(info))) - return -EFAULT; - - return 0; -} -#undef SET_FROM_SB - -#define SET_SB(x) mddev->sb->disks[nr].x = info->x - -static int add_new_disk (mddev_t * mddev, mdu_disk_info_t *info) -{ - int err, size, persistent; - mdk_rdev_t *rdev; - unsigned int nr; - kdev_t dev; - dev = MKDEV(info->major,info->minor); - - if (find_rdev_all(dev)) { - printk("device %s already used in a RAID array!\n", - partition_name(dev)); - return -EBUSY; - } - if (!mddev->sb) { - /* expecting a device which has a superblock */ - err = md_import_device(dev, 1); - if (err) { - printk("md error, md_import_device returned %d\n", err); - return -EINVAL; - } - rdev = find_rdev_all(dev); - if (!rdev) { - MD_BUG(); - return -EINVAL; - } - if (mddev->nb_dev) { - mdk_rdev_t *rdev0 = md_list_entry(mddev->disks.next, - mdk_rdev_t, same_set); - if (!uuid_equal(rdev0, rdev)) { - printk("md: %s has different UUID to %s\n", partition_name(rdev->dev), partition_name(rdev0->dev)); - export_rdev(rdev); - return -EINVAL; - } - if (!sb_equal(rdev0->sb, rdev->sb)) { - printk("md: %s has same UUID but different superblock to %s\n", partition_name(rdev->dev), partition_name(rdev0->dev)); - export_rdev(rdev); - return -EINVAL; - } - } - bind_rdev_to_array(rdev, mddev); - return 0; - } - - nr = info->number; - if (nr >= mddev->sb->nr_disks) - return -EINVAL; - - SET_SB(number); - SET_SB(major); - SET_SB(minor); - SET_SB(raid_disk); - SET_SB(state); - - if ((info->state & (1<old_dev = dev; - rdev->desc_nr = info->number; - - bind_rdev_to_array(rdev, mddev); - - persistent = !mddev->sb->not_persistent; - if (!persistent) - printk("nonpersistent superblock ...\n"); - if (!mddev->sb->chunk_size) - printk("no chunksize?\n"); - - size = calc_dev_size(dev, mddev, persistent); - rdev->sb_offset = calc_dev_sboffset(dev, mddev, persistent); - - if (!mddev->sb->size || (mddev->sb->size > size)) - mddev->sb->size = size; - } - - /* - * sync all other superblocks with the main superblock - */ - sync_sbs(mddev); - - return 0; -} -#undef SET_SB - -static int hot_remove_disk (mddev_t * mddev, kdev_t dev) -{ - int err; - mdk_rdev_t *rdev; - mdp_disk_t *disk; - - if (!mddev->pers) - return -ENODEV; - - printk("trying to remove %s from md%d ... \n", - partition_name(dev), mdidx(mddev)); - - if (!mddev->pers->diskop) { - printk("md%d: personality does not support diskops!\n", - mdidx(mddev)); - return -EINVAL; - } - - rdev = find_rdev(mddev, dev); - if (!rdev) - return -ENXIO; - - if (rdev->desc_nr == -1) { - MD_BUG(); - return -EINVAL; - } - disk = &mddev->sb->disks[rdev->desc_nr]; - if (disk_active(disk)) - goto busy; - if (disk_removed(disk)) { - MD_BUG(); - return -EINVAL; - } - - err = mddev->pers->diskop(mddev, &disk, DISKOP_HOT_REMOVE_DISK); - if (err == -EBUSY) - goto busy; - if (err) { - MD_BUG(); - return -EINVAL; - } - - remove_descriptor(disk, mddev->sb); - kick_rdev_from_array(rdev); - mddev->sb_dirty = 1; - md_update_sb(mddev); - - return 0; -busy: - printk("cannot remove active disk %s from md%d ... \n", - partition_name(dev), mdidx(mddev)); - return -EBUSY; -} - -static int hot_add_disk (mddev_t * mddev, kdev_t dev) -{ - int i, err, persistent; - unsigned int size; - mdk_rdev_t *rdev; - mdp_disk_t *disk; - - if (!mddev->pers) - return -ENODEV; - - printk("trying to hot-add %s to md%d ... \n", - partition_name(dev), mdidx(mddev)); - - if (!mddev->pers->diskop) { - printk("md%d: personality does not support diskops!\n", - mdidx(mddev)); - return -EINVAL; - } - - persistent = !mddev->sb->not_persistent; - size = calc_dev_size(dev, mddev, persistent); - - if (size < mddev->sb->size) { - printk("md%d: disk size %d blocks < array size %d\n", - mdidx(mddev), size, mddev->sb->size); - return -ENOSPC; - } - - rdev = find_rdev(mddev, dev); - if (rdev) - return -EBUSY; - - err = md_import_device (dev, 0); - if (err) { - printk("md: error, md_import_device() returned %d\n", err); - return -EINVAL; - } - rdev = find_rdev_all(dev); - if (!rdev) { - MD_BUG(); - return -EINVAL; - } - if (rdev->faulty) { - printk("md: can not hot-add faulty %s disk to md%d!\n", - partition_name(dev), mdidx(mddev)); - err = -EINVAL; - goto abort_export; - } - bind_rdev_to_array(rdev, mddev); - - /* - * The rest should better be atomic, we can have disk failures - * noticed in interrupt contexts ... - */ - rdev->old_dev = dev; - rdev->size = size; - rdev->sb_offset = calc_dev_sboffset(dev, mddev, persistent); - - disk = mddev->sb->disks + mddev->sb->raid_disks; - for (i = mddev->sb->raid_disks; i < MD_SB_DISKS; i++) { - disk = mddev->sb->disks + i; - - if (!disk->major && !disk->minor) - break; - if (disk_removed(disk)) - break; - } - if (i == MD_SB_DISKS) { - printk("md%d: can not hot-add to full array!\n", mdidx(mddev)); - err = -EBUSY; - goto abort_unbind_export; - } - - if (disk_removed(disk)) { - /* - * reuse slot - */ - if (disk->number != i) { - MD_BUG(); - err = -EINVAL; - goto abort_unbind_export; - } - } else { - disk->number = i; - } - - disk->raid_disk = disk->number; - disk->major = MAJOR(dev); - disk->minor = MINOR(dev); - - if (mddev->pers->diskop(mddev, &disk, DISKOP_HOT_ADD_DISK)) { - MD_BUG(); - err = -EINVAL; - goto abort_unbind_export; - } - - mark_disk_spare(disk); - mddev->sb->nr_disks++; - mddev->sb->spare_disks++; - mddev->sb->working_disks++; - - mddev->sb_dirty = 1; - - md_update_sb(mddev); - - /* - * Kick recovery, maybe this spare has to be added to the - * array immediately. - */ - md_recover_arrays(); - - return 0; - -abort_unbind_export: - unbind_rdev_from_array(rdev); - -abort_export: - export_rdev(rdev); - return err; -} - -#define SET_SB(x) mddev->sb->x = info->x -static int set_array_info (mddev_t * mddev, mdu_array_info_t *info) -{ - - if (alloc_array_sb(mddev)) - return -ENOMEM; - - mddev->sb->major_version = MD_MAJOR_VERSION; - mddev->sb->minor_version = MD_MINOR_VERSION; - mddev->sb->patch_version = MD_PATCHLEVEL_VERSION; - mddev->sb->ctime = CURRENT_TIME; - - SET_SB(level); - SET_SB(size); - SET_SB(nr_disks); - SET_SB(raid_disks); - SET_SB(md_minor); - SET_SB(not_persistent); - - SET_SB(state); - SET_SB(active_disks); - SET_SB(working_disks); - SET_SB(failed_disks); - SET_SB(spare_disks); - - SET_SB(layout); - SET_SB(chunk_size); - - mddev->sb->md_magic = MD_SB_MAGIC; - - /* - * Generate a 128 bit UUID - */ - get_random_bytes(&mddev->sb->set_uuid0, 4); - get_random_bytes(&mddev->sb->set_uuid1, 4); - get_random_bytes(&mddev->sb->set_uuid2, 4); - get_random_bytes(&mddev->sb->set_uuid3, 4); - - return 0; -} -#undef SET_SB - -static int set_disk_info (mddev_t * mddev, void * arg) -{ - printk("not yet"); - return -EINVAL; -} - -static int clear_array (mddev_t * mddev) -{ - printk("not yet"); - return -EINVAL; -} - -static int write_raid_info (mddev_t * mddev) -{ - printk("not yet"); - return -EINVAL; -} - -static int protect_array (mddev_t * mddev) -{ - printk("not yet"); - return -EINVAL; -} - -static int unprotect_array (mddev_t * mddev) -{ - printk("not yet"); - return -EINVAL; -} - -static int set_disk_faulty (mddev_t *mddev, kdev_t dev) -{ - int ret; - - fsync_dev(mddev_to_kdev(mddev)); - ret = md_error(mddev_to_kdev(mddev), dev); - return ret; -} - -static int md_ioctl (struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - unsigned int minor; - int err = 0; - struct hd_geometry *loc = (struct hd_geometry *) arg; - mddev_t *mddev = NULL; - kdev_t dev; - - if (!md_capable_admin()) - return -EACCES; - - dev = inode->i_rdev; - minor = MINOR(dev); - if (minor >= MAX_MD_DEVS) - return -EINVAL; - - /* - * Commands dealing with the RAID driver but not any - * particular array: - */ - switch (cmd) - { - case RAID_VERSION: - err = get_version((void *)arg); - goto done; - - case PRINT_RAID_DEBUG: - err = 0; - md_print_devices(); - goto done_unlock; - - case BLKGETSIZE: /* Return device size */ - if (!arg) { - err = -EINVAL; - goto abort; - } - err = md_put_user(md_hd_struct[minor].nr_sects, - (long *) arg); - goto done; - - case BLKFLSBUF: - fsync_dev(dev); - invalidate_buffers(dev); - goto done; - - case BLKRASET: - if (arg > 0xff) { - err = -EINVAL; - goto abort; - } - read_ahead[MAJOR(dev)] = arg; - goto done; - - case BLKRAGET: - if (!arg) { - err = -EINVAL; - goto abort; - } - err = md_put_user (read_ahead[ - MAJOR(dev)], (long *) arg); - goto done; - default: - } - - /* - * Commands creating/starting a new array: - */ - - mddev = kdev_to_mddev(dev); - - switch (cmd) - { - case SET_ARRAY_INFO: - case START_ARRAY: - if (mddev) { - printk("array md%d already exists!\n", - mdidx(mddev)); - err = -EEXIST; - goto abort; - } - default: - } - switch (cmd) - { - case SET_ARRAY_INFO: - mddev = alloc_mddev(dev); - if (!mddev) { - err = -ENOMEM; - goto abort; - } - /* - * alloc_mddev() should possibly self-lock. - */ - err = lock_mddev(mddev); - if (err) { - printk("ioctl, reason %d, cmd %d\n", err, cmd); - goto abort; - } - - if (mddev->sb) { - printk("array md%d already has a superblock!\n", - mdidx(mddev)); - err = -EBUSY; - goto abort_unlock; - } - if (arg) { - mdu_array_info_t info; - if (md_copy_from_user(&info, (void*)arg, sizeof(info))) { - err = -EFAULT; - goto abort_unlock; - } - err = set_array_info(mddev, &info); - if (err) { - printk("couldnt set array info. %d\n", err); - goto abort_unlock; - } - } - goto done_unlock; - - case START_ARRAY: - /* - * possibly make it lock the array ... - */ - err = autostart_array((kdev_t)arg); - if (err) { - printk("autostart %s failed!\n", - partition_name((kdev_t)arg)); - goto abort; - } - goto done; - - default: - } - - /* - * Commands querying/configuring an existing array: - */ - - if (!mddev) { - err = -ENODEV; - goto abort; - } - err = lock_mddev(mddev); - if (err) { - printk("ioctl lock interrupted, reason %d, cmd %d\n",err, cmd); - goto abort; - } - /* if we don't have a superblock yet, only ADD_NEW_DISK or STOP_ARRAY is allowed */ - if (!mddev->sb && cmd != ADD_NEW_DISK && cmd != STOP_ARRAY && cmd != RUN_ARRAY) { - err = -ENODEV; - goto abort_unlock; - } - - /* - * Commands even a read-only array can execute: - */ - switch (cmd) - { - case GET_ARRAY_INFO: - err = get_array_info(mddev, (void *)arg); - goto done_unlock; - - case GET_DISK_INFO: - err = get_disk_info(mddev, (void *)arg); - goto done_unlock; - - case RESTART_ARRAY_RW: - err = restart_array(mddev); - goto done_unlock; - - case STOP_ARRAY: - if (!(err = do_md_stop (mddev, 0))) - mddev = NULL; - goto done_unlock; - - case STOP_ARRAY_RO: - err = do_md_stop (mddev, 1); - goto done_unlock; - - /* - * We have a problem here : there is no easy way to give a CHS - * virtual geometry. We currently pretend that we have a 2 heads - * 4 sectors (with a BIG number of cylinders...). This drives - * dosfs just mad... ;-) - */ - case HDIO_GETGEO: - if (!loc) { - err = -EINVAL; - goto abort_unlock; - } - err = md_put_user (2, (char *) &loc->heads); - if (err) - goto abort_unlock; - err = md_put_user (4, (char *) &loc->sectors); - if (err) - goto abort_unlock; - err = md_put_user (md_hd_struct[mdidx(mddev)].nr_sects/8, - (short *) &loc->cylinders); - if (err) - goto abort_unlock; - err = md_put_user (md_hd_struct[minor].start_sect, - (long *) &loc->start); - goto done_unlock; - } - - /* - * The remaining ioctls are changing the state of the - * superblock, so we do not allow read-only arrays - * here: - */ - if (mddev->ro) { - err = -EROFS; - goto abort_unlock; - } - - switch (cmd) - { - case CLEAR_ARRAY: - err = clear_array(mddev); - goto done_unlock; - - case ADD_NEW_DISK: - { - mdu_disk_info_t info; - if (md_copy_from_user(&info, (void*)arg, sizeof(info))) - err = -EFAULT; - else - err = add_new_disk(mddev, &info); - goto done_unlock; - } - case HOT_REMOVE_DISK: - err = hot_remove_disk(mddev, (kdev_t)arg); - goto done_unlock; - - case HOT_ADD_DISK: - err = hot_add_disk(mddev, (kdev_t)arg); - goto done_unlock; - - case SET_DISK_INFO: - err = set_disk_info(mddev, (void *)arg); - goto done_unlock; - - case WRITE_RAID_INFO: - err = write_raid_info(mddev); - goto done_unlock; - - case UNPROTECT_ARRAY: - err = unprotect_array(mddev); - goto done_unlock; - - case PROTECT_ARRAY: - err = protect_array(mddev); - goto done_unlock; - - case SET_DISK_FAULTY: - err = set_disk_faulty(mddev, (kdev_t)arg); - goto done_unlock; - - case RUN_ARRAY: - { -/* The data is never used.... - mdu_param_t param; - err = md_copy_from_user(¶m, (mdu_param_t *)arg, - sizeof(param)); - if (err) - goto abort_unlock; -*/ - err = do_md_run (mddev); - /* - * we have to clean up the mess if - * the array cannot be run for some - * reason ... - */ - if (err) { - mddev->sb_dirty = 0; - if (!do_md_stop (mddev, 0)) - mddev = NULL; - } - goto done_unlock; - } - - default: - printk(KERN_WARNING "%s(pid %d) used obsolete MD ioctl, upgrade your software to use new ictls.\n", current->comm, current->pid); - err = -EINVAL; - goto abort_unlock; - } - -done_unlock: -abort_unlock: - if (mddev) - unlock_mddev(mddev); - - return err; -done: - if (err) - printk("huh12?\n"); -abort: - return err; -} - -static int md_open (struct inode *inode, struct file *file) -{ - /* - * Always succeed - */ - return (0); -} - -static struct block_device_operations md_fops= -{ - open: md_open, - ioctl: md_ioctl, -}; - - -int md_thread(void * arg) -{ - mdk_thread_t *thread = arg; - - md_lock_kernel(); - exit_mm(current); - exit_files(current); - exit_fs(current); - - /* - * Detach thread - */ - daemonize(); - sprintf(current->comm, thread->name); - md_init_signals(); - md_flush_signals(); - thread->tsk = current; - - /* - * md_thread is a 'system-thread', it's priority should be very - * high. We avoid resource deadlocks individually in each - * raid personality. (RAID5 does preallocation) We also use RR and - * the very same RT priority as kswapd, thus we will never get - * into a priority inversion deadlock. - * - * we definitely have to have equal or higher priority than - * bdflush, otherwise bdflush will deadlock if there are too - * many dirty RAID5 blocks. - */ - current->policy = SCHED_OTHER; - current->nice = -20; -// md_unlock_kernel(); - - up(thread->sem); - - for (;;) { - DECLARE_WAITQUEUE(wait, current); - - add_wait_queue(&thread->wqueue, &wait); - set_task_state(current, TASK_INTERRUPTIBLE); - if (!test_bit(THREAD_WAKEUP, &thread->flags)) { - dprintk("thread %p went to sleep.\n", thread); - schedule(); - dprintk("thread %p woke up.\n", thread); - } - current->state = TASK_RUNNING; - remove_wait_queue(&thread->wqueue, &wait); - clear_bit(THREAD_WAKEUP, &thread->flags); - - if (thread->run) { - thread->run(thread->data); - run_task_queue(&tq_disk); - } else - break; - if (md_signal_pending(current)) { - printk("%8s(%d) flushing signals.\n", current->comm, - current->pid); - md_flush_signals(); - } - } - up(thread->sem); - return 0; -} - -void md_wakeup_thread(mdk_thread_t *thread) -{ - dprintk("waking up MD thread %p.\n", thread); - set_bit(THREAD_WAKEUP, &thread->flags); - wake_up(&thread->wqueue); -} - -mdk_thread_t *md_register_thread (void (*run) (void *), - void *data, const char *name) -{ - mdk_thread_t *thread; - int ret; - DECLARE_MUTEX_LOCKED(sem); - - thread = (mdk_thread_t *) kmalloc - (sizeof(mdk_thread_t), GFP_KERNEL); - if (!thread) - return NULL; - - memset(thread, 0, sizeof(mdk_thread_t)); - md_init_waitqueue_head(&thread->wqueue); - - thread->sem = &sem; - thread->run = run; - thread->data = data; - thread->name = name; - ret = kernel_thread(md_thread, thread, 0); - if (ret < 0) { - kfree(thread); - return NULL; - } - down(&sem); - return thread; -} - -void md_interrupt_thread (mdk_thread_t *thread) -{ - if (!thread->tsk) { - MD_BUG(); - return; - } - printk("interrupting MD-thread pid %d\n", thread->tsk->pid); - send_sig(SIGKILL, thread->tsk, 1); -} - -void md_unregister_thread (mdk_thread_t *thread) -{ - DECLARE_MUTEX_LOCKED(sem); - - thread->sem = &sem; - thread->run = NULL; - thread->name = NULL; - if (!thread->tsk) { - MD_BUG(); - return; - } - md_interrupt_thread(thread); - down(&sem); -} - -void md_recover_arrays (void) -{ - if (!md_recovery_thread) { - MD_BUG(); - return; - } - md_wakeup_thread(md_recovery_thread); -} - - -int md_error (kdev_t dev, kdev_t rdev) -{ - mddev_t *mddev; - mdk_rdev_t * rrdev; - int rc; - - mddev = kdev_to_mddev(dev); -/* printk("md_error dev:(%d:%d), rdev:(%d:%d), (caller: %p,%p,%p,%p).\n",MAJOR(dev),MINOR(dev),MAJOR(rdev),MINOR(rdev), __builtin_return_address(0),__builtin_return_address(1),__builtin_return_address(2),__builtin_return_address(3)); - */ - if (!mddev) { - MD_BUG(); - return 0; - } - rrdev = find_rdev(mddev, rdev); - mark_rdev_faulty(rrdev); - /* - * if recovery was running, stop it now. - */ - if (mddev->pers->stop_resync) - mddev->pers->stop_resync(mddev); - if (mddev->recovery_running) - md_interrupt_thread(md_recovery_thread); - if (mddev->pers->error_handler) { - rc = mddev->pers->error_handler(mddev, rdev); - md_recover_arrays(); - return rc; - } - return 0; -} - -static int status_unused (char * page) -{ - int sz = 0, i = 0; - mdk_rdev_t *rdev; - struct md_list_head *tmp; - - sz += sprintf(page + sz, "unused devices: "); - - ITERATE_RDEV_ALL(rdev,tmp) { - if (!rdev->same_set.next && !rdev->same_set.prev) { - /* - * The device is not yet used by any array. - */ - i++; - sz += sprintf(page + sz, "%s ", - partition_name(rdev->dev)); - } - } - if (!i) - sz += sprintf(page + sz, ""); - - sz += sprintf(page + sz, "\n"); - return sz; -} - - -static int status_resync (char * page, mddev_t * mddev) -{ - int sz = 0; - unsigned long max_blocks, resync, res, dt, db, rt; - - resync = mddev->curr_resync - atomic_read(&mddev->recovery_active); - max_blocks = mddev->sb->size; - - /* - * Should not happen. - */ - if (!max_blocks) { - MD_BUG(); - return 0; - } - res = (resync/1024)*1000/(max_blocks/1024 + 1); - { - int i, x = res/50, y = 20-x; - sz += sprintf(page + sz, "["); - for (i = 0; i < x; i++) - sz += sprintf(page + sz, "="); - sz += sprintf(page + sz, ">"); - for (i = 0; i < y; i++) - sz += sprintf(page + sz, "."); - sz += sprintf(page + sz, "] "); - } - if (!mddev->recovery_running) - /* - * true resync - */ - sz += sprintf(page + sz, " resync =%3lu.%lu%% (%lu/%lu)", - res/10, res % 10, resync, max_blocks); - else - /* - * recovery ... - */ - sz += sprintf(page + sz, " recovery =%3lu.%lu%% (%lu/%lu)", - res/10, res % 10, resync, max_blocks); - - /* - * We do not want to overflow, so the order of operands and - * the * 100 / 100 trick are important. We do a +1 to be - * safe against division by zero. We only estimate anyway. - * - * dt: time from mark until now - * db: blocks written from mark until now - * rt: remaining time - */ - dt = ((jiffies - mddev->resync_mark) / HZ); - if (!dt) dt++; - db = resync - mddev->resync_mark_cnt; - rt = (dt * ((max_blocks-resync) / (db/100+1)))/100; - - sz += sprintf(page + sz, " finish=%lu.%lumin", rt / 60, (rt % 60)/6); - - sz += sprintf(page + sz, " speed=%ldK/sec", db/dt); - - return sz; -} - -static int md_status_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - int sz = 0, j, size; - struct md_list_head *tmp, *tmp2; - mdk_rdev_t *rdev; - mddev_t *mddev; - - sz += sprintf(page + sz, "Personalities : "); - for (j = 0; j < MAX_PERSONALITY; j++) - if (pers[j]) - sz += sprintf(page+sz, "[%s] ", pers[j]->name); - - sz += sprintf(page+sz, "\n"); - - - sz += sprintf(page+sz, "read_ahead "); - if (read_ahead[MD_MAJOR] == INT_MAX) - sz += sprintf(page+sz, "not set\n"); - else - sz += sprintf(page+sz, "%d sectors\n", read_ahead[MD_MAJOR]); - - ITERATE_MDDEV(mddev,tmp) { - sz += sprintf(page + sz, "md%d : %sactive", mdidx(mddev), - mddev->pers ? "" : "in"); - if (mddev->pers) { - if (mddev->ro) - sz += sprintf(page + sz, " (read-only)"); - sz += sprintf(page + sz, " %s", mddev->pers->name); - } - - size = 0; - ITERATE_RDEV(mddev,rdev,tmp2) { - sz += sprintf(page + sz, " %s[%d]", - partition_name(rdev->dev), rdev->desc_nr); - if (rdev->faulty) { - sz += sprintf(page + sz, "(F)"); - continue; - } - size += rdev->size; - } - - if (mddev->nb_dev) { - if (mddev->pers) - sz += sprintf(page + sz, "\n %d blocks", - md_size[mdidx(mddev)]); - else - sz += sprintf(page + sz, "\n %d blocks", size); - } - - if (!mddev->pers) { - sz += sprintf(page+sz, "\n"); - continue; - } - - sz += mddev->pers->status (page+sz, mddev); - - sz += sprintf(page+sz, "\n "); - if (mddev->curr_resync) { - sz += status_resync (page+sz, mddev); - } else { - if (md_atomic_read(&mddev->resync_sem.count) != 1) - sz += sprintf(page + sz, " resync=DELAYED"); - } - sz += sprintf(page + sz, "\n"); - } - sz += status_unused (page + sz); - - return sz; -} - -int register_md_personality (int pnum, mdk_personality_t *p) -{ - if (pnum >= MAX_PERSONALITY) - return -EINVAL; - - if (pers[pnum]) - return -EBUSY; - - pers[pnum] = p; - printk(KERN_INFO "%s personality registered\n", p->name); - return 0; -} - -int unregister_md_personality (int pnum) -{ - if (pnum >= MAX_PERSONALITY) - return -EINVAL; - - printk(KERN_INFO "%s personality unregistered\n", pers[pnum]->name); - pers[pnum] = NULL; - return 0; -} - -static mdp_disk_t *get_spare(mddev_t *mddev) -{ - mdp_super_t *sb = mddev->sb; - mdp_disk_t *disk; - mdk_rdev_t *rdev; - struct md_list_head *tmp; - - ITERATE_RDEV(mddev,rdev,tmp) { - if (rdev->faulty) - continue; - if (!rdev->sb) { - MD_BUG(); - continue; - } - disk = &sb->disks[rdev->desc_nr]; - if (disk_faulty(disk)) { - MD_BUG(); - continue; - } - if (disk_active(disk)) - continue; - return disk; - } - return NULL; -} - -static unsigned int sync_io[DK_MAX_MAJOR][DK_MAX_DISK]; -void md_sync_acct(kdev_t dev, unsigned long nr_sectors) -{ - unsigned int major = MAJOR(dev); - unsigned int index; - - index = disk_index(dev); - if ((index >= DK_MAX_DISK) || (major >= DK_MAX_MAJOR)) - return; - - sync_io[major][index] += nr_sectors; -} - -static int is_mddev_idle (mddev_t *mddev) -{ - mdk_rdev_t * rdev; - struct md_list_head *tmp; - int idle; - unsigned long curr_events; - - idle = 1; - ITERATE_RDEV(mddev,rdev,tmp) { - int major = MAJOR(rdev->dev); - int idx = disk_index(rdev->dev); - - if ((idx >= DK_MAX_DISK) || (major >= DK_MAX_MAJOR)) - continue; - - curr_events = kstat.dk_drive_rblk[major][idx] + - kstat.dk_drive_wblk[major][idx] ; - curr_events -= sync_io[major][idx]; -// printk("events(major: %d, idx: %d): %ld\n", major, idx, curr_events); - if (curr_events != rdev->last_events) { -// printk("!I(%ld)", curr_events - rdev->last_events); - rdev->last_events = curr_events; - idle = 0; - } - } - return idle; -} - -MD_DECLARE_WAIT_QUEUE_HEAD(resync_wait); - -void md_done_sync(mddev_t *mddev, int blocks, int ok) -{ - /* another "blocks" (1K) blocks have been synced */ - atomic_sub(blocks, &mddev->recovery_active); - wake_up(&mddev->recovery_wait); - if (!ok) { - // stop recovery, signal do_sync .... - } -} - -#define SYNC_MARKS 10 -#define SYNC_MARK_STEP (3*HZ) -int md_do_sync(mddev_t *mddev, mdp_disk_t *spare) -{ - mddev_t *mddev2; - unsigned int max_blocks, currspeed, - j, window, err, serialize; - kdev_t read_disk = mddev_to_kdev(mddev); - unsigned long mark[SYNC_MARKS]; - unsigned long mark_cnt[SYNC_MARKS]; - int last_mark,m; - struct md_list_head *tmp; - unsigned long last_check; - - - err = down_interruptible(&mddev->resync_sem); - if (err) - goto out_nolock; - -recheck: - serialize = 0; - ITERATE_MDDEV(mddev2,tmp) { - if (mddev2 == mddev) - continue; - if (mddev2->curr_resync && match_mddev_units(mddev,mddev2)) { - printk(KERN_INFO "md: serializing resync, md%d has overlapping physical units with md%d!\n", mdidx(mddev), mdidx(mddev2)); - serialize = 1; - break; - } - } - if (serialize) { - interruptible_sleep_on(&resync_wait); - if (md_signal_pending(current)) { - md_flush_signals(); - err = -EINTR; - goto out; - } - goto recheck; - } - - mddev->curr_resync = 1; - - max_blocks = mddev->sb->size; - - printk(KERN_INFO "md: syncing RAID array md%d\n", mdidx(mddev)); - printk(KERN_INFO "md: minimum _guaranteed_ reconstruction speed: %d KB/sec/disc.\n", - sysctl_speed_limit_min); - printk(KERN_INFO "md: using maximum available idle IO bandwith (but not more than %d KB/sec) for reconstruction.\n", sysctl_speed_limit_max); - - /* - * Resync has low priority. - */ - current->nice = 19; - - is_mddev_idle(mddev); /* this also initializes IO event counters */ - for (m = 0; m < SYNC_MARKS; m++) { - mark[m] = jiffies; - mark_cnt[m] = 0; - } - last_mark = 0; - mddev->resync_mark = mark[last_mark]; - mddev->resync_mark_cnt = mark_cnt[last_mark]; - - /* - * Tune reconstruction: - */ - window = MAX_READAHEAD*(PAGE_SIZE/1024); - printk(KERN_INFO "md: using %dk window, over a total of %d blocks.\n",window,max_blocks); - - atomic_set(&mddev->recovery_active, 0); - init_waitqueue_head(&mddev->recovery_wait); - last_check = 0; - for (j = 0; j < max_blocks;) { - int blocks; - - blocks = mddev->pers->sync_request(mddev, j); - - if (blocks < 0) { - err = blocks; - goto out; - } - atomic_add(blocks, &mddev->recovery_active); - j += blocks; - mddev->curr_resync = j; - - if (last_check + window > j) - continue; - - run_task_queue(&tq_disk); //?? - - if (jiffies >= mark[last_mark] + SYNC_MARK_STEP ) { - /* step marks */ - int next = (last_mark+1) % SYNC_MARKS; - - mddev->resync_mark = mark[next]; - mddev->resync_mark_cnt = mark_cnt[next]; - mark[next] = jiffies; - mark_cnt[next] = j - atomic_read(&mddev->recovery_active); - last_mark = next; - } - - - if (md_signal_pending(current)) { - /* - * got a signal, exit. - */ - mddev->curr_resync = 0; - printk("md_do_sync() got signal ... exiting\n"); - md_flush_signals(); - err = -EINTR; - goto out; - } - - /* - * this loop exits only if either when we are slower than - * the 'hard' speed limit, or the system was IO-idle for - * a jiffy. - * the system might be non-idle CPU-wise, but we only care - * about not overloading the IO subsystem. (things like an - * e2fsck being done on the RAID array should execute fast) - */ -repeat: - if (md_need_resched(current)) - schedule(); - - currspeed = (j-mddev->resync_mark_cnt)/((jiffies-mddev->resync_mark)/HZ +1) +1; - - if (currspeed > sysctl_speed_limit_min) { - current->nice = 19; - - if ((currspeed > sysctl_speed_limit_max) || - !is_mddev_idle(mddev)) { - current->state = TASK_INTERRUPTIBLE; - md_schedule_timeout(HZ/4); - if (!md_signal_pending(current)) - goto repeat; - } - } else - current->nice = -20; - } - fsync_dev(read_disk); - printk(KERN_INFO "md: md%d: sync done.\n",mdidx(mddev)); - err = 0; - /* - * this also signals 'finished resyncing' to md_stop - */ -out: - wait_event(mddev->recovery_wait, atomic_read(&mddev->recovery_active)==0); - up(&mddev->resync_sem); -out_nolock: - mddev->curr_resync = 0; - wake_up(&resync_wait); - return err; -} - - -/* - * This is a kernel thread which syncs a spare disk with the active array - * - * the amount of foolproofing might seem to be a tad excessive, but an - * early (not so error-safe) version of raid1syncd synced the first 0.5 gigs - * of my root partition with the first 0.5 gigs of my /home partition ... so - * i'm a bit nervous ;) - */ -void md_do_recovery (void *data) -{ - int err; - mddev_t *mddev; - mdp_super_t *sb; - mdp_disk_t *spare; - struct md_list_head *tmp; - - printk(KERN_INFO "md: recovery thread got woken up ...\n"); -restart: - ITERATE_MDDEV(mddev,tmp) { - sb = mddev->sb; - if (!sb) - continue; - if (mddev->recovery_running) - continue; - if (sb->active_disks == sb->raid_disks) - continue; - if (!sb->spare_disks) { - printk(KERN_ERR "md%d: no spare disk to reconstruct array! -- continuing in degraded mode\n", mdidx(mddev)); - continue; - } - /* - * now here we get the spare and resync it. - */ - if ((spare = get_spare(mddev)) == NULL) - continue; - printk(KERN_INFO "md%d: resyncing spare disk %s to replace failed disk\n", mdidx(mddev), partition_name(MKDEV(spare->major,spare->minor))); - if (!mddev->pers->diskop) - continue; - if (mddev->pers->diskop(mddev, &spare, DISKOP_SPARE_WRITE)) - continue; - down(&mddev->recovery_sem); - mddev->recovery_running = 1; - err = md_do_sync(mddev, spare); - if (err == -EIO) { - printk(KERN_INFO "md%d: spare disk %s failed, skipping to next spare.\n", mdidx(mddev), partition_name(MKDEV(spare->major,spare->minor))); - if (!disk_faulty(spare)) { - mddev->pers->diskop(mddev,&spare,DISKOP_SPARE_INACTIVE); - mark_disk_faulty(spare); - mark_disk_nonsync(spare); - mark_disk_inactive(spare); - sb->spare_disks--; - sb->working_disks--; - sb->failed_disks++; - } - } else - if (disk_faulty(spare)) - mddev->pers->diskop(mddev, &spare, - DISKOP_SPARE_INACTIVE); - if (err == -EINTR || err == -ENOMEM) { - /* - * Recovery got interrupted, or ran out of mem ... - * signal back that we have finished using the array. - */ - mddev->pers->diskop(mddev, &spare, - DISKOP_SPARE_INACTIVE); - up(&mddev->recovery_sem); - mddev->recovery_running = 0; - continue; - } else { - mddev->recovery_running = 0; - up(&mddev->recovery_sem); - } - if (!disk_faulty(spare)) { - /* - * the SPARE_ACTIVE diskop possibly changes the - * pointer too - */ - mddev->pers->diskop(mddev, &spare, DISKOP_SPARE_ACTIVE); - mark_disk_sync(spare); - mark_disk_active(spare); - sb->active_disks++; - sb->spare_disks--; - } - mddev->sb_dirty = 1; - md_update_sb(mddev); - goto restart; - } - printk(KERN_INFO "md: recovery thread finished ...\n"); - -} - -int md_notify_reboot(struct notifier_block *this, - unsigned long code, void *x) -{ - struct md_list_head *tmp; - mddev_t *mddev; - - if ((code == MD_SYS_DOWN) || (code == MD_SYS_HALT) - || (code == MD_SYS_POWER_OFF)) { - - printk(KERN_INFO "stopping all md devices.\n"); - - ITERATE_MDDEV(mddev,tmp) - do_md_stop (mddev, 1); - /* - * certain more exotic SCSI devices are known to be - * volatile wrt too early system reboots. While the - * right place to handle this issue is the given - * driver, we do want to have a safe RAID driver ... - */ - md_mdelay(1000*1); - } - return NOTIFY_DONE; -} - -struct notifier_block md_notifier = { - md_notify_reboot, - NULL, - 0 -}; -#ifndef MODULE -static int md__init raid_setup(char *str) -{ - int len, pos; - - len = strlen(str) + 1; - pos = 0; - - while (pos < len) { - char *comma = strchr(str+pos, ','); - int wlen; - if (comma) - wlen = (comma-str)-pos; - else wlen = (len-1)-pos; - - if (strncmp(str, "noautodetect", wlen) == 0) - raid_setup_args.noautodetect = 1; - pos += wlen+1; - } - raid_setup_args.set = 1; - return 1; -} -__setup("raid=", raid_setup); -#endif -static void md_geninit (void) -{ - int i; - - for(i = 0; i < MAX_MD_DEVS; i++) { - md_blocksizes[i] = 1024; - md_size[i] = 0; - md_hardsect_sizes[i] = 512; - md_maxreadahead[i] = MD_READAHEAD; - register_disk(&md_gendisk, MKDEV(MAJOR_NR,i), 1, &md_fops, 0); - } - blksize_size[MAJOR_NR] = md_blocksizes; - blk_size[MAJOR_NR] = md_size; - max_readahead[MAJOR_NR] = md_maxreadahead; - hardsect_size[MAJOR_NR] = md_hardsect_sizes; - - printk("md.c: sizeof(mdp_super_t) = %d\n", (int)sizeof(mdp_super_t)); - -#ifdef CONFIG_PROC_FS - create_proc_read_entry("mdstat", 0, NULL, md_status_read_proc, NULL); -#endif -} -void hsm_init (void); -void translucent_init (void); -void linear_init (void); -void raid0_init (void); -void raid1_init (void); -void raid5_init (void); - -int md__init md_init (void) -{ - static char * name = "mdrecoveryd"; - - printk (KERN_INFO "md driver %d.%d.%d MAX_MD_DEVS=%d, MAX_REAL=%d\n", - MD_MAJOR_VERSION, MD_MINOR_VERSION, - MD_PATCHLEVEL_VERSION, MAX_MD_DEVS, MAX_REAL); - - if (devfs_register_blkdev (MAJOR_NR, "md", &md_fops)) - { - printk (KERN_ALERT "Unable to get major %d for md\n", MAJOR_NR); - return (-1); - } - devfs_handle = devfs_mk_dir (NULL, "md", NULL); - devfs_register_series (devfs_handle, "%u",MAX_MD_DEVS,DEVFS_FL_DEFAULT, - MAJOR_NR, 0, S_IFBLK | S_IRUSR | S_IWUSR, - &md_fops, NULL); - - /* forward all md request to md_make_request */ - blk_queue_make_request(BLK_DEFAULT_QUEUE(MAJOR_NR), md_make_request); - - - read_ahead[MAJOR_NR] = INT_MAX; - md_gendisk.next = gendisk_head; - - gendisk_head = &md_gendisk; - - md_recovery_thread = md_register_thread(md_do_recovery, NULL, name); - if (!md_recovery_thread) - printk(KERN_ALERT "bug: couldn't allocate md_recovery_thread\n"); - - md_register_reboot_notifier(&md_notifier); - raid_table_header = register_sysctl_table(raid_root_table, 1); - -#ifdef CONFIG_MD_LINEAR - linear_init (); -#endif -#ifdef CONFIG_MD_RAID0 - raid0_init (); -#endif -#ifdef CONFIG_MD_RAID1 - raid1_init (); -#endif -#ifdef CONFIG_MD_RAID5 - raid5_init (); -#endif - md_geninit(); - return (0); -} - -#ifdef CONFIG_MD_BOOT -#define MAX_MD_BOOT_DEVS 8 -struct { - unsigned long set; - int pers[MAX_MD_BOOT_DEVS]; - int chunk[MAX_MD_BOOT_DEVS]; - kdev_t devices[MAX_MD_BOOT_DEVS][MAX_REAL]; -} md_setup_args md__initdata; - -/* - * Parse the command-line parameters given our kernel, but do not - * actually try to invoke the MD device now; that is handled by - * md_setup_drive after the low-level disk drivers have initialised. - * - * 27/11/1999: Fixed to work correctly with the 2.3 kernel (which - * assigns the task of parsing integer arguments to the - * invoked program now). Added ability to initialise all - * the MD devices (by specifying multiple "md=" lines) - * instead of just one. -- KTK - * 18May2000: Added support for persistant-superblock arrays: - * md=n,0,factor,fault,device-list uses RAID0 for device n - * md=n,-1,factor,fault,device-list uses LINEAR for device n - * md=n,device-list reads a RAID superblock from the devices - * elements in device-list are read by name_to_kdev_t so can be - * a hex number or something like /dev/hda1 /dev/sdb - */ -extern kdev_t name_to_kdev_t(char *line) md__init; -static int md__init md_setup(char *str) -{ - int minor, level, factor, fault, i=0; - kdev_t device; - char *devnames, *pername = ""; - - if(get_option(&str, &minor) != 2) { /* MD Number */ - printk("md: Too few arguments supplied to md=.\n"); - return 0; - } - if (minor >= MAX_MD_BOOT_DEVS) { - printk ("md: Minor device number too high.\n"); - return 0; - } else if (md_setup_args.set & (1 << minor)) { - printk ("md: Warning - md=%d,... has been specified twice;\n" - " will discard the first definition.\n", minor); - } - switch(get_option(&str, &level)) { /* RAID Personality */ - case 2: /* could be 0 or -1.. */ - if (level == 0 || level == -1) { - if (get_option(&str, &factor) != 2 || /* Chunk Size */ - get_option(&str, &fault) != 2) { - printk("md: Too few arguments supplied to md=.\n"); - return 0; - } - md_setup_args.pers[minor] = level; - md_setup_args.chunk[minor] = 1 << (factor+12); - switch(level) { - case -1: - level = LINEAR; - pername = "linear"; - break; - case 0: - level = RAID0; - pername = "raid0"; - break; - default: - printk ("md: The kernel has not been configured for raid%d" - " support!\n", level); - return 0; - } - md_setup_args.pers[minor] = level; - break; - } - /* FALL THROUGH */ - case 1: /* the first device is numeric */ - md_setup_args.devices[minor][i++] = level; - /* FALL THROUGH */ - case 0: - md_setup_args.pers[minor] = 0; - pername="super-block"; - } - devnames = str; - for (; isb->nr_disks++; - mddev->sb->raid_disks++; - mddev->sb->active_disks++; - mddev->sb->working_disks++; - err = add_new_disk (mddev, &dinfo); - } - } else { - /* persistent */ - for (i = 0; (dev = md_setup_args.devices[minor][i]); i++) { - dinfo.major = MAJOR(dev); - dinfo.minor = MINOR(dev); - add_new_disk (mddev, &dinfo); - } - } - if (!err) - err = do_md_run(mddev); - if (err) { - mddev->sb_dirty = 0; - do_md_stop(mddev, 0); - printk("md: starting md%d failed\n", minor); - } - } -} - -__setup("md=", md_setup); -#endif - -#ifdef MODULE -int init_module (void) -{ - return md_init(); -} - -static void free_device_names(void) -{ - while (device_names.next != &device_names) { - struct list_head *tmp = device_names.next; - list_del(tmp); - kfree(tmp); - } -} - - -void cleanup_module (void) -{ - struct gendisk **gendisk_ptr; - - md_unregister_thread(md_recovery_thread); - devfs_unregister(devfs_handle); - - devfs_unregister_blkdev(MAJOR_NR,"md"); - unregister_reboot_notifier(&md_notifier); - unregister_sysctl_table(raid_table_header); -#ifdef CONFIG_PROC_FS - remove_proc_entry("mdstat", NULL); -#endif - - gendisk_ptr = &gendisk_head; - while (*gendisk_ptr) { - if (*gendisk_ptr == &md_gendisk) { - *gendisk_ptr = md_gendisk.next; - break; - } - gendisk_ptr = & (*gendisk_ptr)->next; - } - blk_dev[MAJOR_NR].queue = NULL; - blksize_size[MAJOR_NR] = NULL; - blk_size[MAJOR_NR] = NULL; - max_readahead[MAJOR_NR] = NULL; - hardsect_size[MAJOR_NR] = NULL; - - free_device_names(); - -} -#endif - -MD_EXPORT_SYMBOL(md_size); -MD_EXPORT_SYMBOL(register_md_personality); -MD_EXPORT_SYMBOL(unregister_md_personality); -MD_EXPORT_SYMBOL(partition_name); -MD_EXPORT_SYMBOL(md_error); -MD_EXPORT_SYMBOL(md_do_sync); -MD_EXPORT_SYMBOL(md_sync_acct); -MD_EXPORT_SYMBOL(md_done_sync); -MD_EXPORT_SYMBOL(md_recover_arrays); -MD_EXPORT_SYMBOL(md_register_thread); -MD_EXPORT_SYMBOL(md_unregister_thread); -MD_EXPORT_SYMBOL(md_update_sb); -MD_EXPORT_SYMBOL(md_wakeup_thread); -MD_EXPORT_SYMBOL(md_print_devices); -MD_EXPORT_SYMBOL(find_rdev_nr); -MD_EXPORT_SYMBOL(md_interrupt_thread); -MD_EXPORT_SYMBOL(mddev_map); -MD_EXPORT_SYMBOL(md_check_ordering); - diff -u --recursive --new-file v2.4.0-test8/linux/drivers/block/paride/paride.h linux/drivers/block/paride/paride.h --- v2.4.0-test8/linux/drivers/block/paride/paride.h Wed May 12 13:27:37 1999 +++ linux/drivers/block/paride/paride.h Fri Sep 22 14:21:16 2000 @@ -1,3 +1,6 @@ +#ifndef __DRIVERS_PARIDE_H__ +#define __DRIVERS_PARIDE_H__ + /* paride.h (c) 1997-8 Grant R. Guenther Under the terms of the GPL. @@ -161,4 +164,5 @@ extern int pi_register( PIP * ); extern void pi_unregister ( PIP * ); +#endif /* __DRIVERS_PARIDE_H__ */ /* end of paride.h */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/block/raid0.c linux/drivers/block/raid0.c --- v2.4.0-test8/linux/drivers/block/raid0.c Thu Aug 10 12:35:50 2000 +++ linux/drivers/block/raid0.c Wed Dec 31 16:00:00 1969 @@ -1,356 +0,0 @@ -/* - raid0.c : Multiple Devices driver for Linux - Copyright (C) 1994-96 Marc ZYNGIER - or - - Copyright (C) 1999, 2000 Ingo Molnar, Red Hat - - - RAID-0 management functions. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - You should have received a copy of the GNU General Public License - (for example /usr/src/linux/COPYING); if not, write to the Free - Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include - -#define MAJOR_NR MD_MAJOR -#define MD_DRIVER -#define MD_PERSONALITY - -static int create_strip_zones (mddev_t *mddev) -{ - int i, c, j, j1, j2; - unsigned long current_offset, curr_zone_offset; - raid0_conf_t *conf = mddev_to_conf(mddev); - mdk_rdev_t *smallest, *rdev1, *rdev2, *rdev; - - /* - * The number of 'same size groups' - */ - conf->nr_strip_zones = 0; - - ITERATE_RDEV_ORDERED(mddev,rdev1,j1) { - printk("raid0: looking at %s\n", partition_name(rdev1->dev)); - c = 0; - ITERATE_RDEV_ORDERED(mddev,rdev2,j2) { - printk("raid0: comparing %s(%ld) with %s(%ld)\n", partition_name(rdev1->dev), rdev1->size, partition_name(rdev2->dev), rdev2->size); - if (rdev2 == rdev1) { - printk("raid0: END\n"); - break; - } - if (rdev2->size == rdev1->size) - { - /* - * Not unique, dont count it as a new - * group - */ - printk("raid0: EQUAL\n"); - c = 1; - break; - } - printk("raid0: NOT EQUAL\n"); - } - if (!c) { - printk("raid0: ==> UNIQUE\n"); - conf->nr_strip_zones++; - printk("raid0: %d zones\n", conf->nr_strip_zones); - } - } - printk("raid0: FINAL %d zones\n", conf->nr_strip_zones); - - conf->strip_zone = vmalloc(sizeof(struct strip_zone)* - conf->nr_strip_zones); - if (!conf->strip_zone) - return 1; - - - conf->smallest = NULL; - current_offset = 0; - curr_zone_offset = 0; - - for (i = 0; i < conf->nr_strip_zones; i++) - { - struct strip_zone *zone = conf->strip_zone + i; - - printk("zone %d\n", i); - zone->dev_offset = current_offset; - smallest = NULL; - c = 0; - - ITERATE_RDEV_ORDERED(mddev,rdev,j) { - - printk(" checking %s ...", partition_name(rdev->dev)); - if (rdev->size > current_offset) - { - printk(" contained as device %d\n", c); - zone->dev[c] = rdev; - c++; - if (!smallest || (rdev->size size)) { - smallest = rdev; - printk(" (%ld) is smallest!.\n", rdev->size); - } - } else - printk(" nope.\n"); - } - - zone->nb_dev = c; - zone->size = (smallest->size - current_offset) * c; - printk(" zone->nb_dev: %d, size: %ld\n",zone->nb_dev,zone->size); - - if (!conf->smallest || (zone->size < conf->smallest->size)) - conf->smallest = zone; - - zone->zone_offset = curr_zone_offset; - curr_zone_offset += zone->size; - - current_offset = smallest->size; - printk("current zone offset: %ld\n", current_offset); - } - printk("done.\n"); - return 0; -} - -static int raid0_run (mddev_t *mddev) -{ - unsigned long cur=0, i=0, size, zone0_size, nb_zone; - raid0_conf_t *conf; - - MOD_INC_USE_COUNT; - - conf = vmalloc(sizeof (raid0_conf_t)); - if (!conf) - goto out; - mddev->private = (void *)conf; - - if (md_check_ordering(mddev)) { - printk("raid0: disks are not ordered, aborting!\n"); - goto out_free_conf; - } - - if (create_strip_zones (mddev)) - goto out_free_conf; - - printk("raid0 : md_size is %d blocks.\n", md_size[mdidx(mddev)]); - printk("raid0 : conf->smallest->size is %ld blocks.\n", conf->smallest->size); - nb_zone = md_size[mdidx(mddev)]/conf->smallest->size + - (md_size[mdidx(mddev)] % conf->smallest->size ? 1 : 0); - printk("raid0 : nb_zone is %ld.\n", nb_zone); - conf->nr_zones = nb_zone; - - printk("raid0 : Allocating %ld bytes for hash.\n", - nb_zone*sizeof(struct raid0_hash)); - - conf->hash_table = vmalloc (sizeof (struct raid0_hash)*nb_zone); - if (!conf->hash_table) - goto out_free_zone_conf; - size = conf->strip_zone[cur].size; - - i = 0; - while (cur < conf->nr_strip_zones) { - conf->hash_table[i].zone0 = conf->strip_zone + cur; - - /* - * If we completely fill the slot - */ - if (size >= conf->smallest->size) { - conf->hash_table[i++].zone1 = NULL; - size -= conf->smallest->size; - - if (!size) { - if (++cur == conf->nr_strip_zones) - continue; - size = conf->strip_zone[cur].size; - } - continue; - } - if (++cur == conf->nr_strip_zones) { - /* - * Last dev, set unit1 as NULL - */ - conf->hash_table[i].zone1=NULL; - continue; - } - - /* - * Here we use a 2nd dev to fill the slot - */ - zone0_size = size; - size = conf->strip_zone[cur].size; - conf->hash_table[i++].zone1 = conf->strip_zone + cur; - size -= (conf->smallest->size - zone0_size); - } - return 0; - -out_free_zone_conf: - vfree(conf->strip_zone); - conf->strip_zone = NULL; - -out_free_conf: - vfree(conf); - mddev->private = NULL; -out: - MOD_DEC_USE_COUNT; - return 1; -} - -static int raid0_stop (mddev_t *mddev) -{ - raid0_conf_t *conf = mddev_to_conf(mddev); - - vfree (conf->hash_table); - conf->hash_table = NULL; - vfree (conf->strip_zone); - conf->strip_zone = NULL; - vfree (conf); - mddev->private = NULL; - - MOD_DEC_USE_COUNT; - return 0; -} - -/* - * FIXME - We assume some things here : - * - requested buffers NEVER bigger than chunk size, - * - requested buffers NEVER cross stripes limits. - * Of course, those facts may not be valid anymore (and surely won't...) - * Hey guys, there's some work out there ;-) - */ -static int raid0_make_request (mddev_t *mddev, - int rw, struct buffer_head * bh) -{ - unsigned int sect_in_chunk, chunksize_bits, chunk_size; - raid0_conf_t *conf = mddev_to_conf(mddev); - struct raid0_hash *hash; - struct strip_zone *zone; - mdk_rdev_t *tmp_dev; - unsigned long chunk, block, rsect; - - chunk_size = mddev->param.chunk_size >> 10; - chunksize_bits = ffz(~chunk_size); - block = bh->b_rsector >> 1; - hash = conf->hash_table + block / conf->smallest->size; - - /* Sanity check */ - if (chunk_size < (block % chunk_size) + (bh->b_size >> 10)) - goto bad_map; - - if (!hash) - goto bad_hash; - - if (!hash->zone0) - goto bad_zone0; - - if (block >= (hash->zone0->size + hash->zone0->zone_offset)) { - if (!hash->zone1) - goto bad_zone1; - zone = hash->zone1; - } else - zone = hash->zone0; - - sect_in_chunk = bh->b_rsector & ((chunk_size<<1) -1); - chunk = (block - zone->zone_offset) / (zone->nb_dev << chunksize_bits); - tmp_dev = zone->dev[(block >> chunksize_bits) % zone->nb_dev]; - rsect = (((chunk << chunksize_bits) + zone->dev_offset)<<1) - + sect_in_chunk; - - /* - * The new BH_Lock semantics in ll_rw_blk.c guarantee that this - * is the only IO operation happening on this bh. - */ - bh->b_rdev = tmp_dev->dev; - bh->b_rsector = rsect; - - /* - * Let the main block layer submit the IO and resolve recursion: - */ - return 1; - -bad_map: - printk ("raid0_make_request bug: can't convert block across chunks or bigger than %dk %ld %d\n", chunk_size, bh->b_rsector, bh->b_size >> 10); - return -1; -bad_hash: - printk("raid0_make_request bug: hash==NULL for block %ld\n", block); - return -1; -bad_zone0: - printk ("raid0_make_request bug: hash->zone0==NULL for block %ld\n", block); - return -1; -bad_zone1: - printk ("raid0_make_request bug: hash->zone1==NULL for block %ld\n", block); - return -1; -} - -static int raid0_status (char *page, mddev_t *mddev) -{ - int sz = 0; -#undef MD_DEBUG -#ifdef MD_DEBUG - int j, k; - raid0_conf_t *conf = mddev_to_conf(mddev); - - sz += sprintf(page + sz, " "); - for (j = 0; j < conf->nr_zones; j++) { - sz += sprintf(page + sz, "[z%d", - conf->hash_table[j].zone0 - conf->strip_zone); - if (conf->hash_table[j].zone1) - sz += sprintf(page+sz, "/z%d] ", - conf->hash_table[j].zone1 - conf->strip_zone); - else - sz += sprintf(page+sz, "] "); - } - - sz += sprintf(page + sz, "\n"); - - for (j = 0; j < conf->nr_strip_zones; j++) { - sz += sprintf(page + sz, " z%d=[", j); - for (k = 0; k < conf->strip_zone[j].nb_dev; k++) - sz += sprintf (page+sz, "%s/", partition_name( - conf->strip_zone[j].dev[k]->dev)); - sz--; - sz += sprintf (page+sz, "] zo=%d do=%d s=%d\n", - conf->strip_zone[j].zone_offset, - conf->strip_zone[j].dev_offset, - conf->strip_zone[j].size); - } -#endif - sz += sprintf(page + sz, " %dk chunks", mddev->param.chunk_size/1024); - return sz; -} - -static mdk_personality_t raid0_personality= -{ - name: "raid0", - make_request: raid0_make_request, - run: raid0_run, - stop: raid0_stop, - status: raid0_status, -}; - -#ifndef MODULE - -void raid0_init (void) -{ - register_md_personality (RAID0, &raid0_personality); -} - -#else - -int init_module (void) -{ - return (register_md_personality (RAID0, &raid0_personality)); -} - -void cleanup_module (void) -{ - unregister_md_personality (RAID0); -} - -#endif - diff -u --recursive --new-file v2.4.0-test8/linux/drivers/block/raid1.c linux/drivers/block/raid1.c --- v2.4.0-test8/linux/drivers/block/raid1.c Mon Aug 14 08:26:34 2000 +++ linux/drivers/block/raid1.c Wed Dec 31 16:00:00 1969 @@ -1,1897 +0,0 @@ -/* - * raid1.c : Multiple Devices driver for Linux - * - * Copyright (C) 1999, 2000 Ingo Molnar, Red Hat - * - * Copyright (C) 1996, 1997, 1998 Ingo Molnar, Miguel de Icaza, Gadi Oxman - * - * RAID-1 management functions. - * - * Better read-balancing code written by Mika Kuoppala , 2000 - * - * Fixes to reconstruction by Jakob Østergaard" - * Various fixes by Neil Brown - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * You should have received a copy of the GNU General Public License - * (for example /usr/src/linux/COPYING); if not, write to the Free - * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include - -#define MAJOR_NR MD_MAJOR -#define MD_DRIVER -#define MD_PERSONALITY - -#define MAX_WORK_PER_DISK 128 - -/* - * The following can be used to debug the driver - */ -#define RAID1_DEBUG 0 - -#if RAID1_DEBUG -#define PRINTK(x...) printk(x) -#define inline -#define __inline__ -#else -#define PRINTK(x...) do { } while (0) -#endif - - -static mdk_personality_t raid1_personality; -static md_spinlock_t retry_list_lock = MD_SPIN_LOCK_UNLOCKED; -struct raid1_bh *raid1_retry_list = NULL, **raid1_retry_tail; - -static struct buffer_head *raid1_alloc_bh(raid1_conf_t *conf, int cnt) -{ - /* return a linked list of "cnt" struct buffer_heads. - * don't take any off the free list unless we know we can - * get all we need, otherwise we could deadlock - */ - struct buffer_head *bh=NULL; - - while(cnt) { - struct buffer_head *t; - md_spin_lock_irq(&conf->device_lock); - if (conf->freebh_cnt >= cnt) - while (cnt) { - t = conf->freebh; - conf->freebh = t->b_next; - t->b_next = bh; - bh = t; - t->b_state = 0; - conf->freebh_cnt--; - cnt--; - } - md_spin_unlock_irq(&conf->device_lock); - if (cnt == 0) - break; - t = (struct buffer_head *)kmalloc(sizeof(struct buffer_head), GFP_BUFFER); - if (t) { - memset(t, 0, sizeof(*t)); - t->b_next = bh; - bh = t; - cnt--; - } else { - PRINTK("waiting for %d bh\n", cnt); - wait_event(conf->wait_buffer, conf->freebh_cnt >= cnt); - } - } - return bh; -} - -static inline void raid1_free_bh(raid1_conf_t *conf, struct buffer_head *bh) -{ - md_spin_lock_irq(&conf->device_lock); - while (bh) { - struct buffer_head *t = bh; - bh=bh->b_next; - if (t->b_pprev == NULL) - kfree(t); - else { - t->b_next= conf->freebh; - conf->freebh = t; - conf->freebh_cnt++; - } - } - md_spin_unlock_irq(&conf->device_lock); - wake_up(&conf->wait_buffer); -} - -static int raid1_grow_bh(raid1_conf_t *conf, int cnt) -{ - /* allocate cnt buffer_heads, possibly less if kalloc fails */ - int i = 0; - - while (i < cnt) { - struct buffer_head *bh; - bh = kmalloc(sizeof(*bh), GFP_KERNEL); - if (!bh) break; - memset(bh, 0, sizeof(*bh)); - - md_spin_lock_irq(&conf->device_lock); - bh->b_pprev = &conf->freebh; - bh->b_next = conf->freebh; - conf->freebh = bh; - conf->freebh_cnt++; - md_spin_unlock_irq(&conf->device_lock); - - i++; - } - return i; -} - -static int raid1_shrink_bh(raid1_conf_t *conf, int cnt) -{ - /* discard cnt buffer_heads, if we can find them */ - int i = 0; - - md_spin_lock_irq(&conf->device_lock); - while ((i < cnt) && conf->freebh) { - struct buffer_head *bh = conf->freebh; - conf->freebh = bh->b_next; - kfree(bh); - i++; - conf->freebh_cnt--; - } - md_spin_unlock_irq(&conf->device_lock); - return i; -} - - -static struct raid1_bh *raid1_alloc_r1bh(raid1_conf_t *conf) -{ - struct raid1_bh *r1_bh = NULL; - - do { - md_spin_lock_irq(&conf->device_lock); - if (conf->freer1) { - r1_bh = conf->freer1; - conf->freer1 = r1_bh->next_r1; - r1_bh->next_r1 = NULL; - r1_bh->state = 0; - r1_bh->bh_req.b_state = 0; - } - md_spin_unlock_irq(&conf->device_lock); - if (r1_bh) - return r1_bh; - r1_bh = (struct raid1_bh *) kmalloc(sizeof(struct raid1_bh), - GFP_BUFFER); - if (r1_bh) { - memset(r1_bh, 0, sizeof(*r1_bh)); - return r1_bh; - } - wait_event(conf->wait_buffer, conf->freer1); - } while (1); -} - -static inline void raid1_free_r1bh(struct raid1_bh *r1_bh) -{ - struct buffer_head *bh = r1_bh->mirror_bh_list; - raid1_conf_t *conf = mddev_to_conf(r1_bh->mddev); - - r1_bh->mirror_bh_list = NULL; - - if (test_bit(R1BH_PreAlloc, &r1_bh->state)) { - md_spin_lock_irq(&conf->device_lock); - r1_bh->next_r1 = conf->freer1; - conf->freer1 = r1_bh; - md_spin_unlock_irq(&conf->device_lock); - } else { - kfree(r1_bh); - } - raid1_free_bh(conf, bh); -} - -static int raid1_grow_r1bh (raid1_conf_t *conf, int cnt) -{ - int i = 0; - - while (i < cnt) { - struct raid1_bh *r1_bh; - r1_bh = (struct raid1_bh*)kmalloc(sizeof(*r1_bh), GFP_KERNEL); - if (!r1_bh) - break; - memset(r1_bh, 0, sizeof(*r1_bh)); - - md_spin_lock_irq(&conf->device_lock); - set_bit(R1BH_PreAlloc, &r1_bh->state); - r1_bh->next_r1 = conf->freer1; - conf->freer1 = r1_bh; - md_spin_unlock_irq(&conf->device_lock); - - i++; - } - return i; -} - -static void raid1_shrink_r1bh(raid1_conf_t *conf) -{ - md_spin_lock_irq(&conf->device_lock); - while (conf->freer1) { - struct raid1_bh *r1_bh = conf->freer1; - conf->freer1 = r1_bh->next_r1; - kfree(r1_bh); - } - md_spin_unlock_irq(&conf->device_lock); -} - - - -static inline void raid1_free_buf(struct raid1_bh *r1_bh) -{ - struct buffer_head *bh = r1_bh->mirror_bh_list; - raid1_conf_t *conf = mddev_to_conf(r1_bh->mddev); - r1_bh->mirror_bh_list = NULL; - - md_spin_lock_irq(&conf->device_lock); - r1_bh->next_r1 = conf->freebuf; - conf->freebuf = r1_bh; - md_spin_unlock_irq(&conf->device_lock); - raid1_free_bh(conf, bh); -} - -static struct raid1_bh *raid1_alloc_buf(raid1_conf_t *conf) -{ - struct raid1_bh *r1_bh; - - md_spin_lock_irq(&conf->device_lock); - wait_event_lock_irq(conf->wait_buffer, conf->freebuf, conf->device_lock); - r1_bh = conf->freebuf; - conf->freebuf = r1_bh->next_r1; - r1_bh->next_r1= NULL; - md_spin_unlock_irq(&conf->device_lock); - - return r1_bh; -} - -static int raid1_grow_buffers (raid1_conf_t *conf, int cnt) -{ - int i = 0; - - md_spin_lock_irq(&conf->device_lock); - while (i < cnt) { - struct raid1_bh *r1_bh; - struct page *page; - - page = alloc_page(GFP_KERNEL); - if (!page) - break; - - r1_bh = (struct raid1_bh *) kmalloc(sizeof(*r1_bh), GFP_KERNEL); - if (!r1_bh) { - __free_page(page); - break; - } - memset(r1_bh, 0, sizeof(*r1_bh)); - r1_bh->bh_req.b_page = page; - r1_bh->bh_req.b_data = page_address(page); - r1_bh->next_r1 = conf->freebuf; - conf->freebuf = r1_bh; - i++; - } - md_spin_unlock_irq(&conf->device_lock); - return i; -} - -static void raid1_shrink_buffers (raid1_conf_t *conf) -{ - md_spin_lock_irq(&conf->device_lock); - while (conf->freebuf) { - struct raid1_bh *r1_bh = conf->freebuf; - conf->freebuf = r1_bh->next_r1; - __free_page(r1_bh->bh_req.b_page); - kfree(r1_bh); - } - md_spin_unlock_irq(&conf->device_lock); -} - -static int raid1_map (mddev_t *mddev, kdev_t *rdev, unsigned long size) -{ - raid1_conf_t *conf = mddev_to_conf(mddev); - int i, disks = MD_SB_DISKS; - - /* - * Later we do read balancing on the read side - * now we use the first available disk. - */ - - for (i = 0; i < disks; i++) { - if (conf->mirrors[i].operational) { - *rdev = conf->mirrors[i].dev; - return (0); - } - } - - printk (KERN_ERR "raid1_map(): huh, no more operational devices?\n"); - return (-1); -} - -static void raid1_reschedule_retry (struct raid1_bh *r1_bh) -{ - unsigned long flags; - mddev_t *mddev = r1_bh->mddev; - raid1_conf_t *conf = mddev_to_conf(mddev); - - md_spin_lock_irqsave(&retry_list_lock, flags); - if (raid1_retry_list == NULL) - raid1_retry_tail = &raid1_retry_list; - *raid1_retry_tail = r1_bh; - raid1_retry_tail = &r1_bh->next_r1; - r1_bh->next_r1 = NULL; - md_spin_unlock_irqrestore(&retry_list_lock, flags); - md_wakeup_thread(conf->thread); -} - - -static void inline io_request_done(unsigned long sector, raid1_conf_t *conf, int phase) -{ - unsigned long flags; - spin_lock_irqsave(&conf->segment_lock, flags); - if (sector < conf->start_active) - conf->cnt_done--; - else if (sector >= conf->start_future && conf->phase == phase) - conf->cnt_future--; - else if (!--conf->cnt_pending) - wake_up(&conf->wait_ready); - - spin_unlock_irqrestore(&conf->segment_lock, flags); -} - -static void inline sync_request_done (unsigned long sector, raid1_conf_t *conf) -{ - unsigned long flags; - spin_lock_irqsave(&conf->segment_lock, flags); - if (sector >= conf->start_ready) - --conf->cnt_ready; - else if (sector >= conf->start_active) { - if (!--conf->cnt_active) { - conf->start_active = conf->start_ready; - wake_up(&conf->wait_done); - } - } - spin_unlock_irqrestore(&conf->segment_lock, flags); -} - -/* - * raid1_end_bh_io() is called when we have finished servicing a mirrored - * operation and are ready to return a success/failure code to the buffer - * cache layer. - */ -static void raid1_end_bh_io (struct raid1_bh *r1_bh, int uptodate) -{ - struct buffer_head *bh = r1_bh->master_bh; - - io_request_done(bh->b_rsector, mddev_to_conf(r1_bh->mddev), - test_bit(R1BH_SyncPhase, &r1_bh->state)); - - bh->b_end_io(bh, uptodate); - raid1_free_r1bh(r1_bh); -} -void raid1_end_request (struct buffer_head *bh, int uptodate) -{ - struct raid1_bh * r1_bh = (struct raid1_bh *)(bh->b_private); - - /* - * this branch is our 'one mirror IO has finished' event handler: - */ - if (!uptodate) - md_error (mddev_to_kdev(r1_bh->mddev), bh->b_dev); - else - /* - * Set R1BH_Uptodate in our master buffer_head, so that - * we will return a good error code for to the higher - * levels even if IO on some other mirrored buffer fails. - * - * The 'master' represents the complex operation to - * user-side. So if something waits for IO, then it will - * wait for the 'master' buffer_head. - */ - set_bit (R1BH_Uptodate, &r1_bh->state); - - /* - * We split up the read and write side, imho they are - * conceptually different. - */ - - if ( (r1_bh->cmd == READ) || (r1_bh->cmd == READA) ) { - /* - * we have only one buffer_head on the read side - */ - - if (uptodate) { - raid1_end_bh_io(r1_bh, uptodate); - return; - } - /* - * oops, read error: - */ - printk(KERN_ERR "raid1: %s: rescheduling block %lu\n", - partition_name(bh->b_dev), bh->b_blocknr); - raid1_reschedule_retry(r1_bh); - return; - } - - /* - * WRITE: - * - * Let's see if all mirrored write operations have finished - * already. - */ - - if (atomic_dec_and_test(&r1_bh->remaining)) - raid1_end_bh_io(r1_bh, test_bit(R1BH_Uptodate, &r1_bh->state)); -} - -/* - * This routine returns the disk from which the requested read should - * be done. It bookkeeps the last read position for every disk - * in array and when new read requests come, the disk which last - * position is nearest to the request, is chosen. - * - * TODO: now if there are 2 mirrors in the same 2 devices, performance - * degrades dramatically because position is mirror, not device based. - * This should be changed to be device based. Also atomic sequential - * reads should be somehow balanced. - */ - -static int raid1_read_balance (raid1_conf_t *conf, struct buffer_head *bh) -{ - int new_disk = conf->last_used; - const int sectors = bh->b_size >> 9; - const unsigned long this_sector = bh->b_rsector; - int disk = new_disk; - unsigned long new_distance; - unsigned long current_distance; - - /* - * Check if it is sane at all to balance - */ - - if (conf->resync_mirrors) - goto rb_out; - - if (conf->working_disks < 2) { - int i = 0; - - while( !conf->mirrors[new_disk].operational && - (i < MD_SB_DISKS) ) { - new_disk = conf->mirrors[new_disk].next; - i++; - } - - if (i >= MD_SB_DISKS) { - /* - * This means no working disk was found - * Nothing much to do, lets not change anything - * and hope for the best... - */ - - new_disk = conf->last_used; - } - - goto rb_out; - } - - /* - * Don't touch anything for sequential reads. - */ - - if (this_sector == conf->mirrors[new_disk].head_position) - goto rb_out; - - /* - * If reads have been done only on a single disk - * for a time, lets give another disk a change. - * This is for kicking those idling disks so that - * they would find work near some hotspot. - */ - - if (conf->sect_count >= conf->mirrors[new_disk].sect_limit) { - conf->sect_count = 0; - - while( new_disk != conf->mirrors[new_disk].next ) { - if ((conf->mirrors[new_disk].write_only) || - (!conf->mirrors[new_disk].operational) ) - continue; - - new_disk = conf->mirrors[new_disk].next; - break; - } - - goto rb_out; - } - - current_distance = abs(this_sector - - conf->mirrors[disk].head_position); - - /* Find the disk which is closest */ - - while( conf->mirrors[disk].next != conf->last_used ) { - disk = conf->mirrors[disk].next; - - if ((conf->mirrors[disk].write_only) || - (!conf->mirrors[disk].operational)) - continue; - - new_distance = abs(this_sector - - conf->mirrors[disk].head_position); - - if (new_distance < current_distance) { - conf->sect_count = 0; - current_distance = new_distance; - new_disk = disk; - } - } - -rb_out: - conf->mirrors[new_disk].head_position = this_sector + sectors; - - conf->last_used = new_disk; - conf->sect_count += sectors; - - return new_disk; -} - -static int raid1_make_request (mddev_t *mddev, int rw, - struct buffer_head * bh) -{ - raid1_conf_t *conf = mddev_to_conf(mddev); - struct buffer_head *bh_req, *bhl; - struct raid1_bh * r1_bh; - int disks = MD_SB_DISKS; - int i, sum_bhs = 0, sectors; - struct mirror_info *mirror; - - if (!buffer_locked(bh)) - BUG(); - -/* - * make_request() can abort the operation when READA is being - * used and no empty request is available. - * - * Currently, just replace the command with READ/WRITE. - */ - if (rw == READA) - rw = READ; - - r1_bh = raid1_alloc_r1bh (conf); - - spin_lock_irq(&conf->segment_lock); - wait_event_lock_irq(conf->wait_done, - bh->b_rsector < conf->start_active || - bh->b_rsector >= conf->start_future, - conf->segment_lock); - if (bh->b_rsector < conf->start_active) - conf->cnt_done++; - else { - conf->cnt_future++; - if (conf->phase) - set_bit(R1BH_SyncPhase, &r1_bh->state); - } - spin_unlock_irq(&conf->segment_lock); - - /* - * i think the read and write branch should be separated completely, - * since we want to do read balancing on the read side for example. - * Alternative implementations? :) --mingo - */ - - r1_bh->master_bh = bh; - r1_bh->mddev = mddev; - r1_bh->cmd = rw; - - sectors = bh->b_size >> 9; - if (rw == READ) { - /* - * read balancing logic: - */ - mirror = conf->mirrors + raid1_read_balance(conf, bh); - - bh_req = &r1_bh->bh_req; - memcpy(bh_req, bh, sizeof(*bh)); - bh_req->b_blocknr = bh->b_rsector * sectors; - bh_req->b_dev = mirror->dev; - bh_req->b_rdev = mirror->dev; - /* bh_req->b_rsector = bh->n_rsector; */ - bh_req->b_end_io = raid1_end_request; - bh_req->b_private = r1_bh; - generic_make_request (rw, bh_req); - return 0; - } - - /* - * WRITE: - */ - - bhl = raid1_alloc_bh(conf, conf->raid_disks); - for (i = 0; i < disks; i++) { - struct buffer_head *mbh; - if (!conf->mirrors[i].operational) - continue; - - /* - * We should use a private pool (size depending on NR_REQUEST), - * to avoid writes filling up the memory with bhs - * - * Such pools are much faster than kmalloc anyways (so we waste - * almost nothing by not using the master bh when writing and - * win alot of cleanness) but for now we are cool enough. --mingo - * - * It's safe to sleep here, buffer heads cannot be used in a shared - * manner in the write branch. Look how we lock the buffer at the - * beginning of this function to grok the difference ;) - */ - mbh = bhl; - if (mbh == NULL) { - MD_BUG(); - break; - } - bhl = mbh->b_next; - mbh->b_next = NULL; - mbh->b_this_page = (struct buffer_head *)1; - - /* - * prepare mirrored mbh (fields ordered for max mem throughput): - */ - mbh->b_blocknr = bh->b_rsector * sectors; - mbh->b_dev = conf->mirrors[i].dev; - mbh->b_rdev = conf->mirrors[i].dev; - mbh->b_rsector = bh->b_rsector; - mbh->b_state = (1<b_count, 1); - mbh->b_size = bh->b_size; - mbh->b_page = bh->b_page; - mbh->b_data = bh->b_data; - mbh->b_list = BUF_LOCKED; - mbh->b_end_io = raid1_end_request; - mbh->b_private = r1_bh; - - mbh->b_next = r1_bh->mirror_bh_list; - r1_bh->mirror_bh_list = mbh; - sum_bhs++; - } - if (bhl) raid1_free_bh(conf,bhl); - md_atomic_set(&r1_bh->remaining, sum_bhs); - - /* - * We have to be a bit careful about the semaphore above, thats - * why we start the requests separately. Since kmalloc() could - * fail, sleep and make_request() can sleep too, this is the - * safer solution. Imagine, end_request decreasing the semaphore - * before we could have set it up ... We could play tricks with - * the semaphore (presetting it and correcting at the end if - * sum_bhs is not 'n' but we have to do end_request by hand if - * all requests finish until we had a chance to set up the - * semaphore correctly ... lots of races). - */ - bh = r1_bh->mirror_bh_list; - while(bh) { - struct buffer_head *bh2 = bh; - bh = bh->b_next; - generic_make_request(rw, bh2); - } - return (0); -} - -static int raid1_status (char *page, mddev_t *mddev) -{ - raid1_conf_t *conf = mddev_to_conf(mddev); - int sz = 0, i; - - sz += sprintf (page+sz, " [%d/%d] [", conf->raid_disks, - conf->working_disks); - for (i = 0; i < conf->raid_disks; i++) - sz += sprintf (page+sz, "%s", - conf->mirrors[i].operational ? "U" : "_"); - sz += sprintf (page+sz, "]"); - return sz; -} - -static void unlink_disk (raid1_conf_t *conf, int target) -{ - int disks = MD_SB_DISKS; - int i; - - for (i = 0; i < disks; i++) - if (conf->mirrors[i].next == target) - conf->mirrors[i].next = conf->mirrors[target].next; -} - -#define LAST_DISK KERN_ALERT \ -"raid1: only one disk left and IO error.\n" - -#define NO_SPARE_DISK KERN_ALERT \ -"raid1: no spare disk left, degrading mirror level by one.\n" - -#define DISK_FAILED KERN_ALERT \ -"raid1: Disk failure on %s, disabling device. \n" \ -" Operation continuing on %d devices\n" - -#define START_SYNCING KERN_ALERT \ -"raid1: start syncing spare disk.\n" - -#define ALREADY_SYNCING KERN_INFO \ -"raid1: syncing already in progress.\n" - -static void mark_disk_bad (mddev_t *mddev, int failed) -{ - raid1_conf_t *conf = mddev_to_conf(mddev); - struct mirror_info *mirror = conf->mirrors+failed; - mdp_super_t *sb = mddev->sb; - - mirror->operational = 0; - unlink_disk(conf, failed); - mark_disk_faulty(sb->disks+mirror->number); - mark_disk_nonsync(sb->disks+mirror->number); - mark_disk_inactive(sb->disks+mirror->number); - sb->active_disks--; - sb->working_disks--; - sb->failed_disks++; - mddev->sb_dirty = 1; - md_wakeup_thread(conf->thread); - conf->working_disks--; - printk (DISK_FAILED, partition_name (mirror->dev), - conf->working_disks); -} - -static int raid1_error (mddev_t *mddev, kdev_t dev) -{ - raid1_conf_t *conf = mddev_to_conf(mddev); - struct mirror_info * mirrors = conf->mirrors; - int disks = MD_SB_DISKS; - int i; - - if (conf->working_disks == 1) { - /* - * Uh oh, we can do nothing if this is our last disk, but - * first check if this is a queued request for a device - * which has just failed. - */ - for (i = 0; i < disks; i++) { - if (mirrors[i].dev==dev && !mirrors[i].operational) - return 0; - } - printk (LAST_DISK); - } else { - /* - * Mark disk as unusable - */ - for (i = 0; i < disks; i++) { - if (mirrors[i].dev==dev && mirrors[i].operational) { - mark_disk_bad(mddev, i); - break; - } - } - } - return 0; -} - -#undef LAST_DISK -#undef NO_SPARE_DISK -#undef DISK_FAILED -#undef START_SYNCING - -/* - * Insert the spare disk into the drive-ring - */ -static void link_disk(raid1_conf_t *conf, struct mirror_info *mirror) -{ - int j, next; - int disks = MD_SB_DISKS; - struct mirror_info *p = conf->mirrors; - - for (j = 0; j < disks; j++, p++) - if (p->operational && !p->write_only) { - next = p->next; - p->next = mirror->raid_disk; - mirror->next = next; - return; - } - - printk("raid1: bug: no read-operational devices\n"); -} - -static void print_raid1_conf (raid1_conf_t *conf) -{ - int i; - struct mirror_info *tmp; - - printk("RAID1 conf printout:\n"); - if (!conf) { - printk("(conf==NULL)\n"); - return; - } - printk(" --- wd:%d rd:%d nd:%d\n", conf->working_disks, - conf->raid_disks, conf->nr_disks); - - for (i = 0; i < MD_SB_DISKS; i++) { - tmp = conf->mirrors + i; - printk(" disk %d, s:%d, o:%d, n:%d rd:%d us:%d dev:%s\n", - i, tmp->spare,tmp->operational, - tmp->number,tmp->raid_disk,tmp->used_slot, - partition_name(tmp->dev)); - } -} - -static int raid1_diskop(mddev_t *mddev, mdp_disk_t **d, int state) -{ - int err = 0; - int i, failed_disk=-1, spare_disk=-1, removed_disk=-1, added_disk=-1; - raid1_conf_t *conf = mddev->private; - struct mirror_info *tmp, *sdisk, *fdisk, *rdisk, *adisk; - mdp_super_t *sb = mddev->sb; - mdp_disk_t *failed_desc, *spare_desc, *added_desc; - - print_raid1_conf(conf); - md_spin_lock_irq(&conf->device_lock); - /* - * find the disk ... - */ - switch (state) { - - case DISKOP_SPARE_ACTIVE: - - /* - * Find the failed disk within the RAID1 configuration ... - * (this can only be in the first conf->working_disks part) - */ - for (i = 0; i < conf->raid_disks; i++) { - tmp = conf->mirrors + i; - if ((!tmp->operational && !tmp->spare) || - !tmp->used_slot) { - failed_disk = i; - break; - } - } - /* - * When we activate a spare disk we _must_ have a disk in - * the lower (active) part of the array to replace. - */ - if ((failed_disk == -1) || (failed_disk >= conf->raid_disks)) { - MD_BUG(); - err = 1; - goto abort; - } - /* fall through */ - - case DISKOP_SPARE_WRITE: - case DISKOP_SPARE_INACTIVE: - - /* - * Find the spare disk ... (can only be in the 'high' - * area of the array) - */ - for (i = conf->raid_disks; i < MD_SB_DISKS; i++) { - tmp = conf->mirrors + i; - if (tmp->spare && tmp->number == (*d)->number) { - spare_disk = i; - break; - } - } - if (spare_disk == -1) { - MD_BUG(); - err = 1; - goto abort; - } - break; - - case DISKOP_HOT_REMOVE_DISK: - - for (i = 0; i < MD_SB_DISKS; i++) { - tmp = conf->mirrors + i; - if (tmp->used_slot && (tmp->number == (*d)->number)) { - if (tmp->operational) { - err = -EBUSY; - goto abort; - } - removed_disk = i; - break; - } - } - if (removed_disk == -1) { - MD_BUG(); - err = 1; - goto abort; - } - break; - - case DISKOP_HOT_ADD_DISK: - - for (i = conf->raid_disks; i < MD_SB_DISKS; i++) { - tmp = conf->mirrors + i; - if (!tmp->used_slot) { - added_disk = i; - break; - } - } - if (added_disk == -1) { - MD_BUG(); - err = 1; - goto abort; - } - break; - } - - switch (state) { - /* - * Switch the spare disk to write-only mode: - */ - case DISKOP_SPARE_WRITE: - sdisk = conf->mirrors + spare_disk; - sdisk->operational = 1; - sdisk->write_only = 1; - break; - /* - * Deactivate a spare disk: - */ - case DISKOP_SPARE_INACTIVE: - sdisk = conf->mirrors + spare_disk; - sdisk->operational = 0; - sdisk->write_only = 0; - break; - /* - * Activate (mark read-write) the (now sync) spare disk, - * which means we switch it's 'raid position' (->raid_disk) - * with the failed disk. (only the first 'conf->nr_disks' - * slots are used for 'real' disks and we must preserve this - * property) - */ - case DISKOP_SPARE_ACTIVE: - - sdisk = conf->mirrors + spare_disk; - fdisk = conf->mirrors + failed_disk; - - spare_desc = &sb->disks[sdisk->number]; - failed_desc = &sb->disks[fdisk->number]; - - if (spare_desc != *d) { - MD_BUG(); - err = 1; - goto abort; - } - - if (spare_desc->raid_disk != sdisk->raid_disk) { - MD_BUG(); - err = 1; - goto abort; - } - - if (sdisk->raid_disk != spare_disk) { - MD_BUG(); - err = 1; - goto abort; - } - - if (failed_desc->raid_disk != fdisk->raid_disk) { - MD_BUG(); - err = 1; - goto abort; - } - - if (fdisk->raid_disk != failed_disk) { - MD_BUG(); - err = 1; - goto abort; - } - - /* - * do the switch finally - */ - xchg_values(*spare_desc, *failed_desc); - xchg_values(*fdisk, *sdisk); - - /* - * (careful, 'failed' and 'spare' are switched from now on) - * - * we want to preserve linear numbering and we want to - * give the proper raid_disk number to the now activated - * disk. (this means we switch back these values) - */ - - xchg_values(spare_desc->raid_disk, failed_desc->raid_disk); - xchg_values(sdisk->raid_disk, fdisk->raid_disk); - xchg_values(spare_desc->number, failed_desc->number); - xchg_values(sdisk->number, fdisk->number); - - *d = failed_desc; - - if (sdisk->dev == MKDEV(0,0)) - sdisk->used_slot = 0; - /* - * this really activates the spare. - */ - fdisk->spare = 0; - fdisk->write_only = 0; - link_disk(conf, fdisk); - - /* - * if we activate a spare, we definitely replace a - * non-operational disk slot in the 'low' area of - * the disk array. - */ - - conf->working_disks++; - - break; - - case DISKOP_HOT_REMOVE_DISK: - rdisk = conf->mirrors + removed_disk; - - if (rdisk->spare && (removed_disk < conf->raid_disks)) { - MD_BUG(); - err = 1; - goto abort; - } - rdisk->dev = MKDEV(0,0); - rdisk->used_slot = 0; - conf->nr_disks--; - break; - - case DISKOP_HOT_ADD_DISK: - adisk = conf->mirrors + added_disk; - added_desc = *d; - - if (added_disk != added_desc->number) { - MD_BUG(); - err = 1; - goto abort; - } - - adisk->number = added_desc->number; - adisk->raid_disk = added_desc->raid_disk; - adisk->dev = MKDEV(added_desc->major,added_desc->minor); - - adisk->operational = 0; - adisk->write_only = 0; - adisk->spare = 1; - adisk->used_slot = 1; - adisk->head_position = 0; - conf->nr_disks++; - - break; - - default: - MD_BUG(); - err = 1; - goto abort; - } -abort: - md_spin_unlock_irq(&conf->device_lock); - if (state == DISKOP_SPARE_ACTIVE || state == DISKOP_SPARE_INACTIVE) - /* should move to "END_REBUILD" when such exists */ - raid1_shrink_buffers(conf); - - print_raid1_conf(conf); - return err; -} - - -#define IO_ERROR KERN_ALERT \ -"raid1: %s: unrecoverable I/O read error for block %lu\n" - -#define REDIRECT_SECTOR KERN_ERR \ -"raid1: %s: redirecting sector %lu to another mirror\n" - -/* - * This is a kernel thread which: - * - * 1. Retries failed read operations on working mirrors. - * 2. Updates the raid superblock when problems encounter. - * 3. Performs writes following reads for array syncronising. - */ -static void end_sync_write(struct buffer_head *bh, int uptodate); -static void end_sync_read(struct buffer_head *bh, int uptodate); - -static void raid1d (void *data) -{ - struct raid1_bh *r1_bh; - struct buffer_head *bh; - unsigned long flags; - mddev_t *mddev; - kdev_t dev; - - - for (;;) { - md_spin_lock_irqsave(&retry_list_lock, flags); - r1_bh = raid1_retry_list; - if (!r1_bh) - break; - raid1_retry_list = r1_bh->next_r1; - md_spin_unlock_irqrestore(&retry_list_lock, flags); - - mddev = r1_bh->mddev; - if (mddev->sb_dirty) { - printk(KERN_INFO "dirty sb detected, updating.\n"); - mddev->sb_dirty = 0; - md_update_sb(mddev); - } - bh = &r1_bh->bh_req; - switch(r1_bh->cmd) { - case SPECIAL: - /* have to allocate lots of bh structures and - * schedule writes - */ - if (test_bit(R1BH_Uptodate, &r1_bh->state)) { - int i, sum_bhs = 0; - int disks = MD_SB_DISKS; - struct buffer_head *bhl, *mbh; - raid1_conf_t *conf; - int sectors = bh->b_size >> 9; - - conf = mddev_to_conf(mddev); - bhl = raid1_alloc_bh(conf, conf->raid_disks); /* don't really need this many */ - for (i = 0; i < disks ; i++) { - if (!conf->mirrors[i].operational) - continue; - if (i==conf->last_used) - /* we read from here, no need to write */ - continue; - if (i < conf->raid_disks - && !conf->resync_mirrors) - /* don't need to write this, - * we are just rebuilding */ - continue; - mbh = bhl; - if (!mbh) { - MD_BUG(); - break; - } - bhl = mbh->b_next; - mbh->b_this_page = (struct buffer_head *)1; - - - /* - * prepare mirrored bh (fields ordered for max mem throughput): - */ - mbh->b_blocknr = bh->b_blocknr; - mbh->b_dev = conf->mirrors[i].dev; - mbh->b_rdev = conf->mirrors[i].dev; - mbh->b_rsector = bh->b_blocknr * sectors; - mbh->b_state = (1<b_count, 1); - mbh->b_size = bh->b_size; - mbh->b_page = bh->b_page; - mbh->b_data = bh->b_data; - mbh->b_list = BUF_LOCKED; - mbh->b_end_io = end_sync_write; - mbh->b_private = r1_bh; - - mbh->b_next = r1_bh->mirror_bh_list; - r1_bh->mirror_bh_list = mbh; - - sum_bhs++; - } - md_atomic_set(&r1_bh->remaining, sum_bhs); - if (bhl) raid1_free_bh(conf, bhl); - mbh = r1_bh->mirror_bh_list; - while (mbh) { - struct buffer_head *bh1 = mbh; - mbh = mbh->b_next; - generic_make_request(WRITE, bh1); - md_sync_acct(bh1->b_rdev, bh1->b_size/512); - } - } else { - dev = bh->b_dev; - raid1_map (mddev, &bh->b_dev, bh->b_size >> 9); - if (bh->b_dev == dev) { - printk (IO_ERROR, partition_name(bh->b_dev), bh->b_blocknr); - md_done_sync(mddev, bh->b_size>>10, 0); - } else { - printk (REDIRECT_SECTOR, - partition_name(bh->b_dev), bh->b_blocknr); - bh->b_rdev = bh->b_dev; - generic_make_request(READ, bh); - } - } - - break; - case READ: - case READA: - dev = bh->b_dev; - - raid1_map (mddev, &bh->b_dev, bh->b_size >> 9); - if (bh->b_dev == dev) { - printk (IO_ERROR, partition_name(bh->b_dev), bh->b_blocknr); - raid1_end_bh_io(r1_bh, 0); - } else { - printk (REDIRECT_SECTOR, - partition_name(bh->b_dev), bh->b_blocknr); - bh->b_rdev = bh->b_dev; - generic_make_request (r1_bh->cmd, bh); - } - break; - } - } - md_spin_unlock_irqrestore(&retry_list_lock, flags); -} -#undef IO_ERROR -#undef REDIRECT_SECTOR - -/* - * Private kernel thread to reconstruct mirrors after an unclean - * shutdown. - */ -static void raid1syncd (void *data) -{ - raid1_conf_t *conf = data; - mddev_t *mddev = conf->mddev; - - if (!conf->resync_mirrors) - return; - if (conf->resync_mirrors == 2) - return; - down(&mddev->recovery_sem); - if (!md_do_sync(mddev, NULL)) { - /* - * Only if everything went Ok. - */ - conf->resync_mirrors = 0; - } - - /* If reconstruction was interrupted, we need to close the "active" and "pending" - * holes. - * we know that there are no active rebuild requests, os cnt_active == cnt_ready ==0 - */ - /* this is really needed when recovery stops too... */ - spin_lock_irq(&conf->segment_lock); - conf->start_active = conf->start_pending; - conf->start_ready = conf->start_pending; - wait_event_lock_irq(conf->wait_ready, !conf->cnt_pending, conf->segment_lock); - conf->start_active =conf->start_ready = conf->start_pending = conf->start_future; - conf->start_future = mddev->sb->size+1; - conf->cnt_pending = conf->cnt_future; - conf->cnt_future = 0; - conf->phase = conf->phase ^1; - wait_event_lock_irq(conf->wait_ready, !conf->cnt_pending, conf->segment_lock); - conf->start_active = conf->start_ready = conf->start_pending = conf->start_future = 0; - conf->phase = 0; - conf->cnt_future = conf->cnt_done;; - conf->cnt_done = 0; - spin_unlock_irq(&conf->segment_lock); - wake_up(&conf->wait_done); - - up(&mddev->recovery_sem); - raid1_shrink_buffers(conf); -} - -/* - * perform a "sync" on one "block" - * - * We need to make sure that no normal I/O request - particularly write - * requests - conflict with active sync requests. - * This is achieved by conceptually dividing the device space into a - * number of sections: - * DONE: 0 .. a-1 These blocks are in-sync - * ACTIVE: a.. b-1 These blocks may have active sync requests, but - * no normal IO requests - * READY: b .. c-1 These blocks have no normal IO requests - sync - * request may be happening - * PENDING: c .. d-1 These blocks may have IO requests, but no new - * ones will be added - * FUTURE: d .. end These blocks are not to be considered yet. IO may - * be happening, but not sync - * - * We keep a - * phase which flips (0 or 1) each time d moves and - * a count of: - * z = active io requests in FUTURE since d moved - marked with - * current phase - * y = active io requests in FUTURE before d moved, or PENDING - - * marked with previous phase - * x = active sync requests in READY - * w = active sync requests in ACTIVE - * v = active io requests in DONE - * - * Normally, a=b=c=d=0 and z= active io requests - * or a=b=c=d=END and v= active io requests - * Allowed changes to a,b,c,d: - * A: c==d && y==0 -> d+=window, y=z, z=0, phase=!phase - * B: y==0 -> c=d - * C: b=c, w+=x, x=0 - * D: w==0 -> a=b - * E: a==b==c==d==end -> a=b=c=d=0, z=v, v=0 - * - * At start of sync we apply A. - * When y reaches 0, we apply B then A then being sync requests - * When sync point reaches c-1, we wait for y==0, and W==0, and - * then apply apply B then A then D then C. - * Finally, we apply E - * - * The sync request simply issues a "read" against a working drive - * This is marked so that on completion the raid1d thread is woken to - * issue suitable write requests - */ - -static int raid1_sync_request (mddev_t *mddev, unsigned long block_nr) -{ - raid1_conf_t *conf = mddev_to_conf(mddev); - struct mirror_info *mirror; - struct raid1_bh *r1_bh; - struct buffer_head *bh; - int bsize; - - spin_lock_irq(&conf->segment_lock); - if (!block_nr) { - /* initialize ...*/ - int buffs; - conf->start_active = 0; - conf->start_ready = 0; - conf->start_pending = 0; - conf->start_future = 0; - conf->phase = 0; - /* we want enough buffers to hold twice the window of 128*/ - buffs = 128 *2 / (PAGE_SIZE>>9); - buffs = raid1_grow_buffers(conf, buffs); - if (buffs < 2) - goto nomem; - - conf->window = buffs*(PAGE_SIZE>>9)/2; - conf->cnt_future += conf->cnt_done+conf->cnt_pending; - conf->cnt_done = conf->cnt_pending = 0; - if (conf->cnt_ready || conf->cnt_active) - MD_BUG(); - } - while ((block_nr<<1) >= conf->start_pending) { - PRINTK("wait .. sect=%lu start_active=%d ready=%d pending=%d future=%d, cnt_done=%d active=%d ready=%d pending=%d future=%d\n", - block_nr<<1, conf->start_active, conf->start_ready, conf->start_pending, conf->start_future, - conf->cnt_done, conf->cnt_active, conf->cnt_ready, conf->cnt_pending, conf->cnt_future); - wait_event_lock_irq(conf->wait_done, - !conf->cnt_active, - conf->segment_lock); - wait_event_lock_irq(conf->wait_ready, - !conf->cnt_pending, - conf->segment_lock); - conf->start_active = conf->start_ready; - conf->start_ready = conf->start_pending; - conf->start_pending = conf->start_future; - conf->start_future = conf->start_future+conf->window; - // Note: falling off the end is not a problem - conf->phase = conf->phase ^1; - conf->cnt_active = conf->cnt_ready; - conf->cnt_ready = 0; - conf->cnt_pending = conf->cnt_future; - conf->cnt_future = 0; - wake_up(&conf->wait_done); - } - conf->cnt_ready++; - spin_unlock_irq(&conf->segment_lock); - - - /* If reconstructing, and >1 working disc, - * could dedicate one to rebuild and others to - * service read requests .. - */ - mirror = conf->mirrors+conf->last_used; - - r1_bh = raid1_alloc_buf (conf); - r1_bh->master_bh = NULL; - r1_bh->mddev = mddev; - r1_bh->cmd = SPECIAL; - bh = &r1_bh->bh_req; - - bh->b_blocknr = block_nr; - bsize = 1024; - while (!(bh->b_blocknr & 1) && bsize < PAGE_SIZE - && (bh->b_blocknr+2)*(bsize>>10) < mddev->sb->size) { - bh->b_blocknr >>= 1; - bsize <<= 1; - } - bh->b_size = bsize; - bh->b_list = BUF_LOCKED; - bh->b_dev = mirror->dev; - bh->b_rdev = mirror->dev; - bh->b_state = (1<b_page) - BUG(); - if (!bh->b_data) - BUG(); - if (bh->b_data != page_address(bh->b_page)) - BUG(); - bh->b_end_io = end_sync_read; - bh->b_private = r1_bh; - bh->b_rsector = block_nr<<1; - init_waitqueue_head(&bh->b_wait); - - generic_make_request(READ, bh); - md_sync_acct(bh->b_rdev, bh->b_size/512); - - return (bsize >> 10); - -nomem: - raid1_shrink_buffers(conf); - spin_unlock_irq(&conf->segment_lock); - return -ENOMEM; -} - -static void end_sync_read(struct buffer_head *bh, int uptodate) -{ - struct raid1_bh * r1_bh = (struct raid1_bh *)(bh->b_private); - - /* we have read a block, now it needs to be re-written, - * or re-read if the read failed. - * We don't do much here, just schedule handling by raid1d - */ - if (!uptodate) - md_error (mddev_to_kdev(r1_bh->mddev), bh->b_dev); - else - set_bit(R1BH_Uptodate, &r1_bh->state); - raid1_reschedule_retry(r1_bh); -} - -static void end_sync_write(struct buffer_head *bh, int uptodate) -{ - struct raid1_bh * r1_bh = (struct raid1_bh *)(bh->b_private); - - if (!uptodate) - md_error (mddev_to_kdev(r1_bh->mddev), bh->b_dev); - if (atomic_dec_and_test(&r1_bh->remaining)) { - mddev_t *mddev = r1_bh->mddev; - unsigned long sect = bh->b_blocknr * (bh->b_size>>9); - int size = bh->b_size; - raid1_free_buf(r1_bh); - sync_request_done(sect, mddev_to_conf(mddev)); - md_done_sync(mddev,size>>10, uptodate); - } -} - -/* - * This will catch the scenario in which one of the mirrors was - * mounted as a normal device rather than as a part of a raid set. - * - * check_consistency is very personality-dependent, eg. RAID5 cannot - * do this check, it uses another method. - */ -static int __check_consistency (mddev_t *mddev, int row) -{ - raid1_conf_t *conf = mddev_to_conf(mddev); - int disks = MD_SB_DISKS; - kdev_t dev; - struct buffer_head *bh = NULL; - int i, rc = 0; - char *buffer = NULL; - - for (i = 0; i < disks; i++) { - printk("(checking disk %d)\n",i); - if (!conf->mirrors[i].operational) - continue; - printk("(really checking disk %d)\n",i); - dev = conf->mirrors[i].dev; - set_blocksize(dev, 4096); - if ((bh = bread(dev, row / 4, 4096)) == NULL) - break; - if (!buffer) { - buffer = (char *) __get_free_page(GFP_KERNEL); - if (!buffer) - break; - memcpy(buffer, bh->b_data, 4096); - } else if (memcmp(buffer, bh->b_data, 4096)) { - rc = 1; - break; - } - bforget(bh); - fsync_dev(dev); - invalidate_buffers(dev); - bh = NULL; - } - if (buffer) - free_page((unsigned long) buffer); - if (bh) { - dev = bh->b_dev; - bforget(bh); - fsync_dev(dev); - invalidate_buffers(dev); - } - return rc; -} - -static int check_consistency (mddev_t *mddev) -{ - if (__check_consistency(mddev, 0)) -/* - * we do not do this currently, as it's perfectly possible to - * have an inconsistent array when it's freshly created. Only - * newly written data has to be consistent. - */ - return 0; - - return 0; -} - -#define INVALID_LEVEL KERN_WARNING \ -"raid1: md%d: raid level not set to mirroring (%d)\n" - -#define NO_SB KERN_ERR \ -"raid1: disabled mirror %s (couldn't access raid superblock)\n" - -#define ERRORS KERN_ERR \ -"raid1: disabled mirror %s (errors detected)\n" - -#define NOT_IN_SYNC KERN_ERR \ -"raid1: disabled mirror %s (not in sync)\n" - -#define INCONSISTENT KERN_ERR \ -"raid1: disabled mirror %s (inconsistent descriptor)\n" - -#define ALREADY_RUNNING KERN_ERR \ -"raid1: disabled mirror %s (mirror %d already operational)\n" - -#define OPERATIONAL KERN_INFO \ -"raid1: device %s operational as mirror %d\n" - -#define MEM_ERROR KERN_ERR \ -"raid1: couldn't allocate memory for md%d\n" - -#define SPARE KERN_INFO \ -"raid1: spare disk %s\n" - -#define NONE_OPERATIONAL KERN_ERR \ -"raid1: no operational mirrors for md%d\n" - -#define RUNNING_CKRAID KERN_ERR \ -"raid1: detected mirror differences -- running resync\n" - -#define ARRAY_IS_ACTIVE KERN_INFO \ -"raid1: raid set md%d active with %d out of %d mirrors\n" - -#define THREAD_ERROR KERN_ERR \ -"raid1: couldn't allocate thread for md%d\n" - -#define START_RESYNC KERN_WARNING \ -"raid1: raid set md%d not clean; reconstructing mirrors\n" - -static int raid1_run (mddev_t *mddev) -{ - raid1_conf_t *conf; - int i, j, disk_idx; - struct mirror_info *disk; - mdp_super_t *sb = mddev->sb; - mdp_disk_t *descriptor; - mdk_rdev_t *rdev; - struct md_list_head *tmp; - int start_recovery = 0; - - MOD_INC_USE_COUNT; - - if (sb->level != 1) { - printk(INVALID_LEVEL, mdidx(mddev), sb->level); - goto out; - } - /* - * copy the already verified devices into our private RAID1 - * bookkeeping area. [whatever we allocate in raid1_run(), - * should be freed in raid1_stop()] - */ - - conf = kmalloc(sizeof(raid1_conf_t), GFP_KERNEL); - mddev->private = conf; - if (!conf) { - printk(MEM_ERROR, mdidx(mddev)); - goto out; - } - memset(conf, 0, sizeof(*conf)); - - ITERATE_RDEV(mddev,rdev,tmp) { - if (rdev->faulty) { - printk(ERRORS, partition_name(rdev->dev)); - } else { - if (!rdev->sb) { - MD_BUG(); - continue; - } - } - if (rdev->desc_nr == -1) { - MD_BUG(); - continue; - } - descriptor = &sb->disks[rdev->desc_nr]; - disk_idx = descriptor->raid_disk; - disk = conf->mirrors + disk_idx; - - if (disk_faulty(descriptor)) { - disk->number = descriptor->number; - disk->raid_disk = disk_idx; - disk->dev = rdev->dev; - disk->sect_limit = MAX_WORK_PER_DISK; - disk->operational = 0; - disk->write_only = 0; - disk->spare = 0; - disk->used_slot = 1; - disk->head_position = 0; - continue; - } - if (disk_active(descriptor)) { - if (!disk_sync(descriptor)) { - printk(NOT_IN_SYNC, - partition_name(rdev->dev)); - continue; - } - if ((descriptor->number > MD_SB_DISKS) || - (disk_idx > sb->raid_disks)) { - - printk(INCONSISTENT, - partition_name(rdev->dev)); - continue; - } - if (disk->operational) { - printk(ALREADY_RUNNING, - partition_name(rdev->dev), - disk_idx); - continue; - } - printk(OPERATIONAL, partition_name(rdev->dev), - disk_idx); - disk->number = descriptor->number; - disk->raid_disk = disk_idx; - disk->dev = rdev->dev; - disk->sect_limit = MAX_WORK_PER_DISK; - disk->operational = 1; - disk->write_only = 0; - disk->spare = 0; - disk->used_slot = 1; - disk->head_position = 0; - conf->working_disks++; - } else { - /* - * Must be a spare disk .. - */ - printk(SPARE, partition_name(rdev->dev)); - disk->number = descriptor->number; - disk->raid_disk = disk_idx; - disk->dev = rdev->dev; - disk->sect_limit = MAX_WORK_PER_DISK; - disk->operational = 0; - disk->write_only = 0; - disk->spare = 1; - disk->used_slot = 1; - disk->head_position = 0; - } - } - conf->raid_disks = sb->raid_disks; - conf->nr_disks = sb->nr_disks; - conf->mddev = mddev; - conf->device_lock = MD_SPIN_LOCK_UNLOCKED; - - conf->segment_lock = MD_SPIN_LOCK_UNLOCKED; - init_waitqueue_head(&conf->wait_buffer); - init_waitqueue_head(&conf->wait_done); - init_waitqueue_head(&conf->wait_ready); - - if (!conf->working_disks) { - printk(NONE_OPERATIONAL, mdidx(mddev)); - goto out_free_conf; - } - - - /* pre-allocate some buffer_head structures. - * As a minimum, 1 r1bh and raid_disks buffer_heads - * would probably get us by in tight memory situations, - * but a few more is probably a good idea. - * For now, try 16 r1bh and 16*raid_disks bufferheads - * This will allow at least 16 concurrent reads or writes - * even if kmalloc starts failing - */ - if (raid1_grow_r1bh(conf, 16) < 16 || - raid1_grow_bh(conf, 16*conf->raid_disks)< 16*conf->raid_disks) { - printk(MEM_ERROR, mdidx(mddev)); - goto out_free_conf; - } - - for (i = 0; i < MD_SB_DISKS; i++) { - - descriptor = sb->disks+i; - disk_idx = descriptor->raid_disk; - disk = conf->mirrors + disk_idx; - - if (disk_faulty(descriptor) && (disk_idx < conf->raid_disks) && - !disk->used_slot) { - - disk->number = descriptor->number; - disk->raid_disk = disk_idx; - disk->dev = MKDEV(0,0); - - disk->operational = 0; - disk->write_only = 0; - disk->spare = 0; - disk->used_slot = 1; - disk->head_position = 0; - } - } - - /* - * find the first working one and use it as a starting point - * to read balancing. - */ - for (j = 0; !conf->mirrors[j].operational; j++) - /* nothing */; - conf->last_used = j; - - /* - * initialize the 'working disks' list. - */ - for (i = conf->raid_disks - 1; i >= 0; i--) { - if (conf->mirrors[i].operational) { - conf->mirrors[i].next = j; - j = i; - } - } - - if (conf->working_disks != sb->raid_disks) { - printk(KERN_ALERT "raid1: md%d, not all disks are operational -- trying to recover array\n", mdidx(mddev)); - start_recovery = 1; - } - - if (!start_recovery && (sb->state & (1 << MD_SB_CLEAN))) { - /* - * we do sanity checks even if the device says - * it's clean ... - */ - if (check_consistency(mddev)) { - printk(RUNNING_CKRAID); - sb->state &= ~(1 << MD_SB_CLEAN); - } - } - - { - const char * name = "raid1d"; - - conf->thread = md_register_thread(raid1d, conf, name); - if (!conf->thread) { - printk(THREAD_ERROR, mdidx(mddev)); - goto out_free_conf; - } - } - - if (!start_recovery && !(sb->state & (1 << MD_SB_CLEAN))) { - const char * name = "raid1syncd"; - - conf->resync_thread = md_register_thread(raid1syncd, conf,name); - if (!conf->resync_thread) { - printk(THREAD_ERROR, mdidx(mddev)); - goto out_free_conf; - } - - printk(START_RESYNC, mdidx(mddev)); - conf->resync_mirrors = 1; - md_wakeup_thread(conf->resync_thread); - } - - /* - * Regenerate the "device is in sync with the raid set" bit for - * each device. - */ - for (i = 0; i < MD_SB_DISKS; i++) { - mark_disk_nonsync(sb->disks+i); - for (j = 0; j < sb->raid_disks; j++) { - if (!conf->mirrors[j].operational) - continue; - if (sb->disks[i].number == conf->mirrors[j].number) - mark_disk_sync(sb->disks+i); - } - } - sb->active_disks = conf->working_disks; - - if (start_recovery) - md_recover_arrays(); - - - printk(ARRAY_IS_ACTIVE, mdidx(mddev), sb->active_disks, sb->raid_disks); - /* - * Ok, everything is just fine now - */ - return 0; - -out_free_conf: - raid1_shrink_r1bh(conf); - raid1_shrink_bh(conf, conf->freebh_cnt); - raid1_shrink_buffers(conf); - kfree(conf); - mddev->private = NULL; -out: - MOD_DEC_USE_COUNT; - return -EIO; -} - -#undef INVALID_LEVEL -#undef NO_SB -#undef ERRORS -#undef NOT_IN_SYNC -#undef INCONSISTENT -#undef ALREADY_RUNNING -#undef OPERATIONAL -#undef SPARE -#undef NONE_OPERATIONAL -#undef RUNNING_CKRAID -#undef ARRAY_IS_ACTIVE - -static int raid1_stop_resync (mddev_t *mddev) -{ - raid1_conf_t *conf = mddev_to_conf(mddev); - - if (conf->resync_thread) { - if (conf->resync_mirrors) { - conf->resync_mirrors = 2; - md_interrupt_thread(conf->resync_thread); - - printk(KERN_INFO "raid1: mirror resync was not fully finished, restarting next time.\n"); - return 1; - } - return 0; - } - return 0; -} - -static int raid1_restart_resync (mddev_t *mddev) -{ - raid1_conf_t *conf = mddev_to_conf(mddev); - - if (conf->resync_mirrors) { - if (!conf->resync_thread) { - MD_BUG(); - return 0; - } - conf->resync_mirrors = 1; - md_wakeup_thread(conf->resync_thread); - return 1; - } - return 0; -} - -static int raid1_stop (mddev_t *mddev) -{ - raid1_conf_t *conf = mddev_to_conf(mddev); - - md_unregister_thread(conf->thread); - if (conf->resync_thread) - md_unregister_thread(conf->resync_thread); - raid1_shrink_r1bh(conf); - raid1_shrink_bh(conf, conf->freebh_cnt); - raid1_shrink_buffers(conf); - kfree(conf); - mddev->private = NULL; - MOD_DEC_USE_COUNT; - return 0; -} - -static mdk_personality_t raid1_personality= -{ - name: "raid1", - make_request: raid1_make_request, - run: raid1_run, - stop: raid1_stop, - status: raid1_status, - error_handler: raid1_error, - diskop: raid1_diskop, - stop_resync: raid1_stop_resync, - restart_resync: raid1_restart_resync, - sync_request: raid1_sync_request -}; - -int raid1_init (void) -{ - return register_md_personality (RAID1, &raid1_personality); -} - -#ifdef MODULE -int init_module (void) -{ - return raid1_init(); -} - -void cleanup_module (void) -{ - unregister_md_personality (RAID1); -} -#endif diff -u --recursive --new-file v2.4.0-test8/linux/drivers/block/raid5.c linux/drivers/block/raid5.c --- v2.4.0-test8/linux/drivers/block/raid5.c Mon Aug 14 08:26:34 2000 +++ linux/drivers/block/raid5.c Wed Dec 31 16:00:00 1969 @@ -1,2371 +0,0 @@ -/* - * raid5.c : Multiple Devices driver for Linux - * Copyright (C) 1996, 1997 Ingo Molnar, Miguel de Icaza, Gadi Oxman - * Copyright (C) 1999, 2000 Ingo Molnar - * - * RAID-5 management functions. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * You should have received a copy of the GNU General Public License - * (for example /usr/src/linux/COPYING); if not, write to the Free - * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - - -#include -#include -#include -#include -#include -#include -#include - -static mdk_personality_t raid5_personality; - -/* - * Stripe cache - */ - -#define NR_STRIPES 128 -#define HASH_PAGES 1 -#define HASH_PAGES_ORDER 0 -#define NR_HASH (HASH_PAGES * PAGE_SIZE / sizeof(struct stripe_head *)) -#define HASH_MASK (NR_HASH - 1) -#define stripe_hash(conf, sect, size) ((conf)->stripe_hashtbl[((sect) / (size >> 9)) & HASH_MASK]) - -/* - * The following can be used to debug the driver - */ -#define RAID5_DEBUG 0 -#define RAID5_PARANOIA 1 -#if RAID5_PARANOIA && CONFIG_SMP -# define CHECK_DEVLOCK() if (!spin_is_locked(&conf->device_lock)) BUG() -# define CHECK_SHLOCK(sh) if (!stripe_locked(sh)) BUG() -#else -# define CHECK_DEVLOCK() -# define CHECK_SHLOCK(unused) -#endif - -#if RAID5_DEBUG -#define PRINTK(x...) printk(x) -#define inline -#define __inline__ -#else -#define PRINTK(x...) do { } while (0) -#endif - -static void print_raid5_conf (raid5_conf_t *conf); - -static inline int stripe_locked(struct stripe_head *sh) -{ - return test_bit(STRIPE_LOCKED, &sh->state); -} - -static void __unlock_stripe(struct stripe_head *sh) -{ - if (!md_test_and_clear_bit(STRIPE_LOCKED, &sh->state)) - BUG(); - PRINTK("unlocking stripe %lu\n", sh->sector); - wake_up(&sh->wait); -} - -static void finish_unlock_stripe(struct stripe_head *sh) -{ - raid5_conf_t *conf = sh->raid_conf; - sh->cmd = STRIPE_NONE; - sh->phase = PHASE_COMPLETE; - atomic_dec(&conf->nr_pending_stripes); - atomic_inc(&conf->nr_cached_stripes); - __unlock_stripe(sh); - atomic_dec(&sh->count); - wake_up(&conf->wait_for_stripe); -} - -static void remove_hash(raid5_conf_t *conf, struct stripe_head *sh) -{ - PRINTK("remove_hash(), stripe %lu\n", sh->sector); - - CHECK_DEVLOCK(); - CHECK_SHLOCK(sh); - if (sh->hash_pprev) { - if (sh->hash_next) - sh->hash_next->hash_pprev = sh->hash_pprev; - *sh->hash_pprev = sh->hash_next; - sh->hash_pprev = NULL; - atomic_dec(&conf->nr_hashed_stripes); - } -} - -static void lock_get_bh (struct buffer_head *bh) -{ - while (md_test_and_set_bit(BH_Lock, &bh->b_state)) - __wait_on_buffer(bh); - atomic_inc(&bh->b_count); -} - -static __inline__ void insert_hash(raid5_conf_t *conf, struct stripe_head *sh) -{ - struct stripe_head **shp = &stripe_hash(conf, sh->sector, sh->size); - - PRINTK("insert_hash(), stripe %lu, nr_hashed_stripes %d\n", - sh->sector, atomic_read(&conf->nr_hashed_stripes)); - - CHECK_DEVLOCK(); - CHECK_SHLOCK(sh); - if ((sh->hash_next = *shp) != NULL) - (*shp)->hash_pprev = &sh->hash_next; - *shp = sh; - sh->hash_pprev = shp; - atomic_inc(&conf->nr_hashed_stripes); -} - -static struct buffer_head *get_free_buffer(struct stripe_head *sh, int b_size) -{ - struct buffer_head *bh; - unsigned long flags; - - CHECK_SHLOCK(sh); - md_spin_lock_irqsave(&sh->stripe_lock, flags); - bh = sh->buffer_pool; - if (!bh) - goto out_unlock; - sh->buffer_pool = bh->b_next; - bh->b_size = b_size; - if (atomic_read(&bh->b_count)) - BUG(); -out_unlock: - md_spin_unlock_irqrestore(&sh->stripe_lock, flags); - - return bh; -} - -static struct buffer_head *get_free_bh(struct stripe_head *sh) -{ - struct buffer_head *bh; - unsigned long flags; - - CHECK_SHLOCK(sh); - md_spin_lock_irqsave(&sh->stripe_lock, flags); - bh = sh->bh_pool; - if (!bh) - goto out_unlock; - sh->bh_pool = bh->b_next; - if (atomic_read(&bh->b_count)) - BUG(); -out_unlock: - md_spin_unlock_irqrestore(&sh->stripe_lock, flags); - - return bh; -} - -static void put_free_buffer(struct stripe_head *sh, struct buffer_head *bh) -{ - unsigned long flags; - - if (atomic_read(&bh->b_count)) - BUG(); - CHECK_SHLOCK(sh); - md_spin_lock_irqsave(&sh->stripe_lock, flags); - bh->b_next = sh->buffer_pool; - sh->buffer_pool = bh; - md_spin_unlock_irqrestore(&sh->stripe_lock, flags); -} - -static void put_free_bh(struct stripe_head *sh, struct buffer_head *bh) -{ - unsigned long flags; - - if (atomic_read(&bh->b_count)) - BUG(); - CHECK_SHLOCK(sh); - md_spin_lock_irqsave(&sh->stripe_lock, flags); - bh->b_next = sh->bh_pool; - sh->bh_pool = bh; - md_spin_unlock_irqrestore(&sh->stripe_lock, flags); -} - -static struct stripe_head *get_free_stripe(raid5_conf_t *conf) -{ - struct stripe_head *sh; - - md_spin_lock_irq(&conf->device_lock); - sh = conf->free_sh_list; - if (!sh) - goto out; - conf->free_sh_list = sh->free_next; - atomic_dec(&conf->nr_free_sh); - if (!atomic_read(&conf->nr_free_sh) && conf->free_sh_list) - BUG(); - if (sh->hash_pprev || md_atomic_read(&sh->nr_pending) || - atomic_read(&sh->count)) - BUG(); -out: - md_spin_unlock_irq(&conf->device_lock); - return sh; -} - -static void __put_free_stripe (raid5_conf_t *conf, struct stripe_head *sh) -{ - if (atomic_read(&sh->count) != 0) - BUG(); - CHECK_DEVLOCK(); - CHECK_SHLOCK(sh); - clear_bit(STRIPE_LOCKED, &sh->state); - sh->free_next = conf->free_sh_list; - conf->free_sh_list = sh; - atomic_inc(&conf->nr_free_sh); -} - -static void shrink_buffers(struct stripe_head *sh, int num) -{ - struct buffer_head *bh; - - while (num--) { - bh = get_free_buffer(sh, -1); - if (!bh) - return; - free_page((unsigned long) bh->b_data); - kfree(bh); - } -} - -static void shrink_bh(struct stripe_head *sh, int num) -{ - struct buffer_head *bh; - - while (num--) { - bh = get_free_bh(sh); - if (!bh) - return; - kfree(bh); - } -} - -static int grow_raid5_buffers(struct stripe_head *sh, int num, int b_size, int priority) -{ - struct buffer_head *bh; - - while (num--) { - struct page *page; - bh = kmalloc(sizeof(struct buffer_head), priority); - if (!bh) - return 1; - memset(bh, 0, sizeof (struct buffer_head)); - init_waitqueue_head(&bh->b_wait); - page = alloc_page(priority); - bh->b_data = page_address(page); - if (!bh->b_data) { - kfree(bh); - return 1; - } - bh->b_size = b_size; - atomic_set(&bh->b_count, 0); - bh->b_page = page; - put_free_buffer(sh, bh); - } - return 0; -} - -static int grow_bh(struct stripe_head *sh, int num, int priority) -{ - struct buffer_head *bh; - - while (num--) { - bh = kmalloc(sizeof(struct buffer_head), priority); - if (!bh) - return 1; - memset(bh, 0, sizeof (struct buffer_head)); - init_waitqueue_head(&bh->b_wait); - put_free_bh(sh, bh); - } - return 0; -} - -static void raid5_free_buffer(struct stripe_head *sh, struct buffer_head *bh) -{ - put_free_buffer(sh, bh); -} - -static void raid5_free_bh(struct stripe_head *sh, struct buffer_head *bh) -{ - put_free_bh(sh, bh); -} - -static void raid5_free_old_bh(struct stripe_head *sh, int i) -{ - CHECK_SHLOCK(sh); - if (!sh->bh_old[i]) - BUG(); - raid5_free_buffer(sh, sh->bh_old[i]); - sh->bh_old[i] = NULL; -} - -static void raid5_update_old_bh(struct stripe_head *sh, int i) -{ - CHECK_SHLOCK(sh); - PRINTK("stripe %lu, idx %d, updating cache copy\n", sh->sector, i); - if (!sh->bh_copy[i]) - BUG(); - if (sh->bh_old[i]) - raid5_free_old_bh(sh, i); - sh->bh_old[i] = sh->bh_copy[i]; - sh->bh_copy[i] = NULL; -} - -static void free_stripe(struct stripe_head *sh) -{ - raid5_conf_t *conf = sh->raid_conf; - int disks = conf->raid_disks, j; - - if (atomic_read(&sh->count) != 0) - BUG(); - CHECK_DEVLOCK(); - CHECK_SHLOCK(sh); - PRINTK("free_stripe called, stripe %lu\n", sh->sector); - if (sh->phase != PHASE_COMPLETE || atomic_read(&sh->count)) { - PRINTK("raid5: free_stripe(), sector %lu, phase %d, count %d\n", sh->sector, sh->phase, atomic_read(&sh->count)); - return; - } - for (j = 0; j < disks; j++) { - if (sh->bh_old[j]) - raid5_free_old_bh(sh, j); - if (sh->bh_new[j] || sh->bh_copy[j]) - BUG(); - } - remove_hash(conf, sh); - __put_free_stripe(conf, sh); -} - -static int shrink_stripe_cache(raid5_conf_t *conf, int nr) -{ - struct stripe_head *sh; - int i, count = 0; - - PRINTK("shrink_stripe_cache called, %d/%d, clock %d\n", nr, atomic_read(&conf->nr_hashed_stripes), conf->clock); - md_spin_lock_irq(&conf->device_lock); - for (i = 0; i < NR_HASH; i++) { - sh = conf->stripe_hashtbl[(i + conf->clock) & HASH_MASK]; - for (; sh; sh = sh->hash_next) { - if (sh->phase != PHASE_COMPLETE) - continue; - if (atomic_read(&sh->count)) - continue; - /* - * Try to lock this stripe: - */ - if (md_test_and_set_bit(STRIPE_LOCKED, &sh->state)) - continue; - free_stripe(sh); - if (++count == nr) { - conf->clock = (i + conf->clock) & HASH_MASK; - goto out; - } - } - } -out: - md_spin_unlock_irq(&conf->device_lock); - PRINTK("shrink completed, nr_hashed_stripes %d, nr_pending_strips %d\n", - atomic_read(&conf->nr_hashed_stripes), - atomic_read(&conf->nr_pending_stripes)); - return count; -} - -void __wait_lock_stripe(struct stripe_head *sh) -{ - MD_DECLARE_WAITQUEUE(wait, current); - - PRINTK("wait_lock_stripe %lu\n", sh->sector); - if (!atomic_read(&sh->count)) - BUG(); - add_wait_queue(&sh->wait, &wait); -repeat: - set_current_state(TASK_UNINTERRUPTIBLE); - if (md_test_and_set_bit(STRIPE_LOCKED, &sh->state)) { - schedule(); - goto repeat; - } - PRINTK("wait_lock_stripe %lu done\n", sh->sector); - remove_wait_queue(&sh->wait, &wait); - current->state = TASK_RUNNING; -} - -static struct stripe_head *__find_stripe(raid5_conf_t *conf, unsigned long sector, int size) -{ - struct stripe_head *sh; - - PRINTK("__find_stripe, sector %lu\n", sector); - for (sh = stripe_hash(conf, sector, size); sh; sh = sh->hash_next) { - if (sh->sector == sector && sh->raid_conf == conf) { - if (sh->size != size) - BUG(); - return sh; - } - } - PRINTK("__stripe %lu not in cache\n", sector); - return NULL; -} - -static inline struct stripe_head *alloc_stripe(raid5_conf_t *conf, unsigned long sector, int size) -{ - struct stripe_head *sh; - struct buffer_head *buffer_pool, *bh_pool; - MD_DECLARE_WAITQUEUE(wait, current); - - PRINTK("alloc_stripe called\n"); - - - while ((sh = get_free_stripe(conf)) == NULL) { - int cnt; - add_wait_queue(&conf->wait_for_stripe, &wait); - set_current_state(TASK_UNINTERRUPTIBLE); - cnt = shrink_stripe_cache(conf, conf->max_nr_stripes / 8); - sh = get_free_stripe(conf); - if (!sh && cnt < (conf->max_nr_stripes/8)) { - md_wakeup_thread(conf->thread); - PRINTK("waiting for some stripes to complete - %d %d\n", cnt, conf->max_nr_stripes/8); - schedule(); - } - remove_wait_queue(&conf->wait_for_stripe, &wait); - current->state = TASK_RUNNING; - if (sh) - break; - } - - buffer_pool = sh->buffer_pool; - bh_pool = sh->bh_pool; - memset(sh, 0, sizeof(*sh)); - sh->stripe_lock = MD_SPIN_LOCK_UNLOCKED; - md_init_waitqueue_head(&sh->wait); - sh->buffer_pool = buffer_pool; - sh->bh_pool = bh_pool; - sh->phase = PHASE_COMPLETE; - sh->cmd = STRIPE_NONE; - sh->raid_conf = conf; - sh->sector = sector; - sh->size = size; - atomic_inc(&conf->nr_cached_stripes); - - return sh; -} - -static struct stripe_head *get_lock_stripe(raid5_conf_t *conf, unsigned long sector, int size) -{ - struct stripe_head *sh, *new = NULL; - - PRINTK("get_stripe, sector %lu\n", sector); - - /* - * Do this in set_blocksize()! - */ - if (conf->buffer_size != size) { - PRINTK("switching size, %d --> %d\n", conf->buffer_size, size); - shrink_stripe_cache(conf, conf->max_nr_stripes); - conf->buffer_size = size; - } - -repeat: - md_spin_lock_irq(&conf->device_lock); - sh = __find_stripe(conf, sector, size); - if (!sh) { - if (!new) { - md_spin_unlock_irq(&conf->device_lock); - new = alloc_stripe(conf, sector, size); - goto repeat; - } - sh = new; - new = NULL; - if (md_test_and_set_bit(STRIPE_LOCKED, &sh->state)) - BUG(); - insert_hash(conf, sh); - atomic_inc(&sh->count); - md_spin_unlock_irq(&conf->device_lock); - } else { - atomic_inc(&sh->count); - if (new) { - if (md_test_and_set_bit(STRIPE_LOCKED, &new->state)) - BUG(); - __put_free_stripe(conf, new); - } - md_spin_unlock_irq(&conf->device_lock); - PRINTK("get_stripe, waiting, sector %lu\n", sector); - if (md_test_and_set_bit(STRIPE_LOCKED, &sh->state)) - __wait_lock_stripe(sh); - } - return sh; -} - -static int grow_stripes(raid5_conf_t *conf, int num, int priority) -{ - struct stripe_head *sh; - - while (num--) { - sh = kmalloc(sizeof(struct stripe_head), priority); - if (!sh) - return 1; - memset(sh, 0, sizeof(*sh)); - sh->raid_conf = conf; - sh->stripe_lock = MD_SPIN_LOCK_UNLOCKED; - md_init_waitqueue_head(&sh->wait); - - if (md_test_and_set_bit(STRIPE_LOCKED, &sh->state)) - BUG(); - if (grow_raid5_buffers(sh, 2 * conf->raid_disks, PAGE_SIZE, priority)) { - shrink_buffers(sh, 2 * conf->raid_disks); - kfree(sh); - return 1; - } - if (grow_bh(sh, conf->raid_disks, priority)) { - shrink_buffers(sh, 2 * conf->raid_disks); - shrink_bh(sh, conf->raid_disks); - kfree(sh); - return 1; - } - md_spin_lock_irq(&conf->device_lock); - __put_free_stripe(conf, sh); - atomic_inc(&conf->nr_stripes); - md_spin_unlock_irq(&conf->device_lock); - } - return 0; -} - -static void shrink_stripes(raid5_conf_t *conf, int num) -{ - struct stripe_head *sh; - - while (num--) { - sh = get_free_stripe(conf); - if (!sh) - break; - if (md_test_and_set_bit(STRIPE_LOCKED, &sh->state)) - BUG(); - shrink_buffers(sh, conf->raid_disks * 2); - shrink_bh(sh, conf->raid_disks); - kfree(sh); - atomic_dec(&conf->nr_stripes); - } -} - - -static struct buffer_head *raid5_alloc_buffer(struct stripe_head *sh, int b_size) -{ - struct buffer_head *bh; - - bh = get_free_buffer(sh, b_size); - if (!bh) - BUG(); - return bh; -} - -static struct buffer_head *raid5_alloc_bh(struct stripe_head *sh) -{ - struct buffer_head *bh; - - bh = get_free_bh(sh); - if (!bh) - BUG(); - return bh; -} - -static void raid5_end_buffer_io (struct stripe_head *sh, int i, int uptodate) -{ - struct buffer_head *bh = sh->bh_new[i]; - - PRINTK("raid5_end_buffer_io %lu, uptodate: %d.\n", bh->b_blocknr, uptodate); - sh->bh_new[i] = NULL; - raid5_free_bh(sh, sh->bh_req[i]); - sh->bh_req[i] = NULL; - PRINTK("calling %p->end_io: %p.\n", bh, bh->b_end_io); - bh->b_end_io(bh, uptodate); - if (!uptodate) - printk(KERN_ALERT "raid5: %s: unrecoverable I/O error for " - "block %lu\n", - partition_name(mddev_to_kdev(sh->raid_conf->mddev)), - bh->b_blocknr); -} - -static inline void raid5_mark_buffer_uptodate (struct buffer_head *bh, int uptodate) -{ - if (uptodate) - set_bit(BH_Uptodate, &bh->b_state); - else - clear_bit(BH_Uptodate, &bh->b_state); -} - -static void raid5_end_request (struct buffer_head * bh, int uptodate) -{ - struct stripe_head *sh = bh->b_private; - raid5_conf_t *conf = sh->raid_conf; - int disks = conf->raid_disks, i; - unsigned long flags; - - PRINTK("end_request %lu, nr_pending %d, uptodate: %d, (caller: %p,%p,%p,%p).\n", sh->sector, atomic_read(&sh->nr_pending), uptodate, __builtin_return_address(0),__builtin_return_address(1),__builtin_return_address(2), __builtin_return_address(3)); - md_spin_lock_irqsave(&sh->stripe_lock, flags); - raid5_mark_buffer_uptodate(bh, uptodate); - if (!uptodate) - md_error(mddev_to_kdev(conf->mddev), bh->b_dev); - if (conf->failed_disks) { - for (i = 0; i < disks; i++) { - if (conf->disks[i].operational) - continue; - if (bh != sh->bh_old[i] && bh != sh->bh_req[i] && bh != sh->bh_copy[i]) - continue; - if (bh->b_dev != conf->disks[i].dev) - continue; - set_bit(STRIPE_ERROR, &sh->state); - } - } - md_spin_unlock_irqrestore(&sh->stripe_lock, flags); - - if (atomic_dec_and_test(&sh->nr_pending)) { - atomic_inc(&conf->nr_handle); - md_wakeup_thread(conf->thread); - } -} - -static void raid5_build_block (struct stripe_head *sh, struct buffer_head *bh, int i) -{ - raid5_conf_t *conf = sh->raid_conf; - char *b_data; - struct page *b_page; - unsigned long block = sh->sector / (sh->size >> 9); - - b_data = bh->b_data; - b_page = bh->b_page; - memset (bh, 0, sizeof (struct buffer_head)); - init_waitqueue_head(&bh->b_wait); - init_buffer(bh, raid5_end_request, sh); - bh->b_dev = conf->disks[i].dev; - bh->b_blocknr = block; - - bh->b_data = b_data; - bh->b_page = b_page; - - bh->b_rdev = conf->disks[i].dev; - bh->b_rsector = sh->sector; - - bh->b_state = (1 << BH_Req) | (1 << BH_Mapped); - bh->b_size = sh->size; - bh->b_list = BUF_LOCKED; -} - -static int raid5_error (mddev_t *mddev, kdev_t dev) -{ - raid5_conf_t *conf = (raid5_conf_t *) mddev->private; - mdp_super_t *sb = mddev->sb; - struct disk_info *disk; - int i; - - PRINTK("raid5_error called\n"); - conf->resync_parity = 0; - for (i = 0, disk = conf->disks; i < conf->raid_disks; i++, disk++) { - if (disk->dev == dev && disk->operational) { - disk->operational = 0; - mark_disk_faulty(sb->disks+disk->number); - mark_disk_nonsync(sb->disks+disk->number); - mark_disk_inactive(sb->disks+disk->number); - sb->active_disks--; - sb->working_disks--; - sb->failed_disks++; - mddev->sb_dirty = 1; - conf->working_disks--; - conf->failed_disks++; - md_wakeup_thread(conf->thread); - printk (KERN_ALERT - "raid5: Disk failure on %s, disabling device." - " Operation continuing on %d devices\n", - partition_name (dev), conf->working_disks); - return 0; - } - } - /* - * handle errors in spares (during reconstruction) - */ - if (conf->spare) { - disk = conf->spare; - if (disk->dev == dev) { - printk (KERN_ALERT - "raid5: Disk failure on spare %s\n", - partition_name (dev)); - if (!conf->spare->operational) { - MD_BUG(); - return -EIO; - } - disk->operational = 0; - disk->write_only = 0; - conf->spare = NULL; - mark_disk_faulty(sb->disks+disk->number); - mark_disk_nonsync(sb->disks+disk->number); - mark_disk_inactive(sb->disks+disk->number); - sb->spare_disks--; - sb->working_disks--; - sb->failed_disks++; - - return 0; - } - } - MD_BUG(); - return -EIO; -} - -/* - * Input: a 'big' sector number, - * Output: index of the data and parity disk, and the sector # in them. - */ -static unsigned long raid5_compute_sector(unsigned long r_sector, unsigned int raid_disks, - unsigned int data_disks, unsigned int * dd_idx, - unsigned int * pd_idx, raid5_conf_t *conf) -{ - unsigned long stripe; - unsigned long chunk_number; - unsigned int chunk_offset; - unsigned long new_sector; - int sectors_per_chunk = conf->chunk_size >> 9; - - /* First compute the information on this sector */ - - /* - * Compute the chunk number and the sector offset inside the chunk - */ - chunk_number = r_sector / sectors_per_chunk; - chunk_offset = r_sector % sectors_per_chunk; - - /* - * Compute the stripe number - */ - stripe = chunk_number / data_disks; - - /* - * Compute the data disk and parity disk indexes inside the stripe - */ - *dd_idx = chunk_number % data_disks; - - /* - * Select the parity disk based on the user selected algorithm. - */ - if (conf->level == 4) - *pd_idx = data_disks; - else switch (conf->algorithm) { - case ALGORITHM_LEFT_ASYMMETRIC: - *pd_idx = data_disks - stripe % raid_disks; - if (*dd_idx >= *pd_idx) - (*dd_idx)++; - break; - case ALGORITHM_RIGHT_ASYMMETRIC: - *pd_idx = stripe % raid_disks; - if (*dd_idx >= *pd_idx) - (*dd_idx)++; - break; - case ALGORITHM_LEFT_SYMMETRIC: - *pd_idx = data_disks - stripe % raid_disks; - *dd_idx = (*pd_idx + 1 + *dd_idx) % raid_disks; - break; - case ALGORITHM_RIGHT_SYMMETRIC: - *pd_idx = stripe % raid_disks; - *dd_idx = (*pd_idx + 1 + *dd_idx) % raid_disks; - break; - default: - printk ("raid5: unsupported algorithm %d\n", conf->algorithm); - } - - /* - * Finally, compute the new sector number - */ - new_sector = stripe * sectors_per_chunk + chunk_offset; - return new_sector; -} - -static unsigned long compute_blocknr(struct stripe_head *sh, int i) -{ - raid5_conf_t *conf = sh->raid_conf; - int raid_disks = conf->raid_disks, data_disks = raid_disks - 1; - unsigned long new_sector = sh->sector, check; - int sectors_per_chunk = conf->chunk_size >> 9; - unsigned long stripe = new_sector / sectors_per_chunk; - int chunk_offset = new_sector % sectors_per_chunk; - int chunk_number, dummy1, dummy2, dd_idx = i; - unsigned long r_sector, blocknr; - - switch (conf->algorithm) { - case ALGORITHM_LEFT_ASYMMETRIC: - case ALGORITHM_RIGHT_ASYMMETRIC: - if (i > sh->pd_idx) - i--; - break; - case ALGORITHM_LEFT_SYMMETRIC: - case ALGORITHM_RIGHT_SYMMETRIC: - if (i < sh->pd_idx) - i += raid_disks; - i -= (sh->pd_idx + 1); - break; - default: - printk ("raid5: unsupported algorithm %d\n", conf->algorithm); - } - - chunk_number = stripe * data_disks + i; - r_sector = chunk_number * sectors_per_chunk + chunk_offset; - blocknr = r_sector / (sh->size >> 9); - - check = raid5_compute_sector (r_sector, raid_disks, data_disks, &dummy1, &dummy2, conf); - if (check != sh->sector || dummy1 != dd_idx || dummy2 != sh->pd_idx) { - printk("compute_blocknr: map not correct\n"); - return 0; - } - return blocknr; -} - -static void compute_block(struct stripe_head *sh, int dd_idx) -{ - raid5_conf_t *conf = sh->raid_conf; - int i, count, disks = conf->raid_disks; - struct buffer_head *bh_ptr[MAX_XOR_BLOCKS]; - - PRINTK("compute_block, stripe %lu, idx %d\n", sh->sector, dd_idx); - - if (sh->bh_old[dd_idx] == NULL) - sh->bh_old[dd_idx] = raid5_alloc_buffer(sh, sh->size); - raid5_build_block(sh, sh->bh_old[dd_idx], dd_idx); - - memset(sh->bh_old[dd_idx]->b_data, 0, sh->size); - bh_ptr[0] = sh->bh_old[dd_idx]; - count = 1; - for (i = 0; i < disks; i++) { - if (i == dd_idx) - continue; - if (sh->bh_old[i]) { - bh_ptr[count++] = sh->bh_old[i]; - } else { - printk("compute_block() %d, stripe %lu, %d not present\n", dd_idx, sh->sector, i); - } - if (count == MAX_XOR_BLOCKS) { - xor_block(count, &bh_ptr[0]); - count = 1; - } - } - if (count != 1) - xor_block(count, &bh_ptr[0]); - raid5_mark_buffer_uptodate(sh->bh_old[dd_idx], 1); -} - -static void compute_parity(struct stripe_head *sh, int method) -{ - raid5_conf_t *conf = sh->raid_conf; - int i, pd_idx = sh->pd_idx, disks = conf->raid_disks, count; - struct buffer_head *bh_ptr[MAX_XOR_BLOCKS]; - - PRINTK("compute_parity, stripe %lu, method %d\n", sh->sector, method); - for (i = 0; i < disks; i++) { - if (i == pd_idx || !sh->bh_new[i]) - continue; - if (!sh->bh_copy[i]) - sh->bh_copy[i] = raid5_alloc_buffer(sh, sh->size); - raid5_build_block(sh, sh->bh_copy[i], i); - atomic_set_buffer_dirty(sh->bh_copy[i]); - memcpy(sh->bh_copy[i]->b_data, sh->bh_new[i]->b_data, sh->size); - } - if (sh->bh_copy[pd_idx] == NULL) { - sh->bh_copy[pd_idx] = raid5_alloc_buffer(sh, sh->size); - atomic_set_buffer_dirty(sh->bh_copy[pd_idx]); - } - raid5_build_block(sh, sh->bh_copy[pd_idx], sh->pd_idx); - - if (method == RECONSTRUCT_WRITE) { - memset(sh->bh_copy[pd_idx]->b_data, 0, sh->size); - bh_ptr[0] = sh->bh_copy[pd_idx]; - count = 1; - for (i = 0; i < disks; i++) { - if (i == sh->pd_idx) - continue; - if (sh->bh_new[i]) { - bh_ptr[count++] = sh->bh_copy[i]; - } else if (sh->bh_old[i]) { - bh_ptr[count++] = sh->bh_old[i]; - } - if (count == MAX_XOR_BLOCKS) { - xor_block(count, &bh_ptr[0]); - count = 1; - } - } - if (count != 1) { - xor_block(count, &bh_ptr[0]); - } - } else if (method == READ_MODIFY_WRITE) { - memcpy(sh->bh_copy[pd_idx]->b_data, sh->bh_old[pd_idx]->b_data, sh->size); - bh_ptr[0] = sh->bh_copy[pd_idx]; - count = 1; - for (i = 0; i < disks; i++) { - if (i == sh->pd_idx) - continue; - if (sh->bh_new[i] && sh->bh_old[i]) { - bh_ptr[count++] = sh->bh_copy[i]; - bh_ptr[count++] = sh->bh_old[i]; - } - if (count >= (MAX_XOR_BLOCKS - 1)) { - xor_block(count, &bh_ptr[0]); - count = 1; - } - } - if (count != 1) { - xor_block(count, &bh_ptr[0]); - } - } - raid5_mark_buffer_uptodate(sh->bh_copy[pd_idx], 1); -} - -static void add_stripe_bh (struct stripe_head *sh, struct buffer_head *bh, int dd_idx, int rw) -{ - raid5_conf_t *conf = sh->raid_conf; - struct buffer_head *bh_req; - - PRINTK("adding bh b#%lu to stripe s#%lu\n", bh->b_blocknr, sh->sector); - CHECK_SHLOCK(sh); - if (sh->bh_new[dd_idx]) - BUG(); - - bh_req = raid5_alloc_bh(sh); - raid5_build_block(sh, bh_req, dd_idx); - bh_req->b_data = bh->b_data; - bh_req->b_page = bh->b_page; - - md_spin_lock_irq(&conf->device_lock); - if (sh->phase == PHASE_COMPLETE && sh->cmd == STRIPE_NONE) { - PRINTK("stripe s#%lu => PHASE_BEGIN (%s)\n", sh->sector, rw == READ ? "read" : "write"); - sh->phase = PHASE_BEGIN; - sh->cmd = (rw == READ) ? STRIPE_READ : STRIPE_WRITE; - atomic_inc(&conf->nr_pending_stripes); - atomic_inc(&conf->nr_handle); - PRINTK("# of pending stripes: %u, # of handle: %u\n", atomic_read(&conf->nr_pending_stripes), atomic_read(&conf->nr_handle)); - } - sh->bh_new[dd_idx] = bh; - sh->bh_req[dd_idx] = bh_req; - sh->cmd_new[dd_idx] = rw; - sh->new[dd_idx] = 1; - md_spin_unlock_irq(&conf->device_lock); - - PRINTK("added bh b#%lu to stripe s#%lu, disk %d.\n", bh->b_blocknr, sh->sector, dd_idx); -} - -static void complete_stripe(struct stripe_head *sh) -{ - raid5_conf_t *conf = sh->raid_conf; - int disks = conf->raid_disks; - int i, new = 0; - - PRINTK("complete_stripe %lu\n", sh->sector); - for (i = 0; i < disks; i++) { - if (sh->cmd == STRIPE_SYNC && sh->bh_copy[i]) - raid5_update_old_bh(sh, i); - if (sh->cmd == STRIPE_WRITE && i == sh->pd_idx) - raid5_update_old_bh(sh, i); - if (sh->bh_new[i]) { - PRINTK("stripe %lu finishes new bh, sh->new == %d\n", sh->sector, sh->new[i]); - if (!sh->new[i]) { -#if 0 - if (sh->cmd == STRIPE_WRITE) { - if (memcmp(sh->bh_new[i]->b_data, sh->bh_copy[i]->b_data, sh->size)) { - printk("copy differs, %s, sector %lu ", - test_bit(BH_Dirty, &sh->bh_new[i]->b_state) ? "dirty" : "clean", - sh->sector); - } else if (test_bit(BH_Dirty, &sh->bh_new[i]->b_state)) - printk("sector %lu dirty\n", sh->sector); - } -#endif - if (sh->cmd == STRIPE_WRITE) - raid5_update_old_bh(sh, i); - raid5_end_buffer_io(sh, i, 1); - continue; - } else - new++; - } - if (new && sh->cmd == STRIPE_WRITE) - printk("raid5: bug, completed STRIPE_WRITE with new == %d\n", new); - } - if (sh->cmd == STRIPE_SYNC) - md_done_sync(conf->mddev, (sh->size>>10) - sh->sync_redone,1); - if (!new) - finish_unlock_stripe(sh); - else { - PRINTK("stripe %lu, new == %d\n", sh->sector, new); - sh->phase = PHASE_BEGIN; - } -} - - -static void handle_stripe_write (mddev_t *mddev , raid5_conf_t *conf, - struct stripe_head *sh, int nr_write, int * operational, int disks, - int parity, int parity_failed, int nr_cache, int nr_cache_other, - int nr_failed_other, int nr_cache_overwrite, int nr_failed_overwrite) -{ - int i; - unsigned int block; - struct buffer_head *bh; - int method1 = INT_MAX, method2 = INT_MAX; - - /* - * Attempt to add entries :-) - */ - if (nr_write != disks - 1) { - for (i = 0; i < disks; i++) { - if (i == sh->pd_idx) - continue; - if (sh->bh_new[i]) - continue; - block = (int) compute_blocknr(sh, i); - bh = get_hash_table(mddev_to_kdev(mddev), block, sh->size); - if (!bh) - continue; - if (buffer_dirty(bh) && !md_test_and_set_bit(BH_Lock, &bh->b_state)) { - PRINTK("Whee.. sector %lu, index %d (%d) found in the buffer cache!\n", sh->sector, i, block); - add_stripe_bh(sh, bh, i, WRITE); - sh->new[i] = 0; - nr_write++; - if (sh->bh_old[i]) { - nr_cache_overwrite++; - nr_cache_other--; - } else - if (!operational[i]) { - nr_failed_overwrite++; - nr_failed_other--; - } - } - atomic_dec(&bh->b_count); - } - } - PRINTK("handle_stripe() -- begin writing, stripe %lu\n", sh->sector); - /* - * Writing, need to update parity buffer. - * - * Compute the number of I/O requests in the "reconstruct - * write" and "read modify write" methods. - */ - if (!nr_failed_other) - method1 = (disks - 1) - (nr_write + nr_cache_other); - if (!nr_failed_overwrite && !parity_failed) - method2 = nr_write - nr_cache_overwrite + (1 - parity); - - if (method1 == INT_MAX && method2 == INT_MAX) - BUG(); - PRINTK("handle_stripe(), sector %lu, nr_write %d, method1 %d, method2 %d\n", sh->sector, nr_write, method1, method2); - - if (!method1 || !method2) { - sh->phase = PHASE_WRITE; - compute_parity(sh, method1 <= method2 ? RECONSTRUCT_WRITE : READ_MODIFY_WRITE); - - for (i = 0; i < disks; i++) { - if (!operational[i] && !conf->spare && !conf->resync_parity) - continue; - bh = sh->bh_copy[i]; - if (i != sh->pd_idx && ((bh == NULL) ^ (sh->bh_new[i] == NULL))) - printk("raid5: bug: bh == %p, bh_new[%d] == %p\n", bh, i, sh->bh_new[i]); - if (i == sh->pd_idx && !bh) - printk("raid5: bug: bh == NULL, i == pd_idx == %d\n", i); - if (bh) { - PRINTK("making request for buffer %d\n", i); - lock_get_bh(bh); - if (!operational[i] && !conf->resync_parity) { - PRINTK("writing spare %d\n", i); - atomic_inc(&sh->nr_pending); - bh->b_dev = bh->b_rdev = conf->spare->dev; - generic_make_request(WRITE, bh); - } else { - atomic_inc(&sh->nr_pending); - bh->b_dev = bh->b_rdev = conf->disks[i].dev; - generic_make_request(WRITE, bh); - } - atomic_dec(&bh->b_count); - } - } - PRINTK("handle_stripe() %lu, writing back %d buffers\n", sh->sector, md_atomic_read(&sh->nr_pending)); - return; - } - - if (method1 < method2) { - sh->write_method = RECONSTRUCT_WRITE; - for (i = 0; i < disks; i++) { - if (i == sh->pd_idx) - continue; - if (sh->bh_new[i] || sh->bh_old[i]) - continue; - sh->bh_old[i] = raid5_alloc_buffer(sh, sh->size); - raid5_build_block(sh, sh->bh_old[i], i); - } - } else { - sh->write_method = READ_MODIFY_WRITE; - for (i = 0; i < disks; i++) { - if (sh->bh_old[i]) - continue; - if (!sh->bh_new[i] && i != sh->pd_idx) - continue; - sh->bh_old[i] = raid5_alloc_buffer(sh, sh->size); - raid5_build_block(sh, sh->bh_old[i], i); - } - } - sh->phase = PHASE_READ_OLD; - for (i = 0; i < disks; i++) { - if (!sh->bh_old[i]) - continue; - if (test_bit(BH_Uptodate, &sh->bh_old[i]->b_state)) - continue; - lock_get_bh(sh->bh_old[i]); - atomic_inc(&sh->nr_pending); - sh->bh_old[i]->b_dev = sh->bh_old[i]->b_rdev = conf->disks[i].dev; - generic_make_request(READ, sh->bh_old[i]); - atomic_dec(&sh->bh_old[i]->b_count); - } - PRINTK("handle_stripe() %lu, reading %d old buffers\n", sh->sector, md_atomic_read(&sh->nr_pending)); -} - -/* - * Reading - */ -static void handle_stripe_read (mddev_t *mddev , raid5_conf_t *conf, - struct stripe_head *sh, int nr_read, int * operational, int disks, - int parity, int parity_failed, int nr_cache, int nr_cache_other, - int nr_failed_other, int nr_cache_overwrite, int nr_failed_overwrite) -{ - int i; - int method1 = INT_MAX; - - method1 = nr_read - nr_cache_overwrite; - - PRINTK("handle_stripe(), sector %lu, nr_read %d, nr_cache %d, method1 %d\n", sh->sector, nr_read, nr_cache, method1); - - if (!method1 || (method1 == 1 && nr_cache == disks - 1)) { - PRINTK("read %lu completed from cache\n", sh->sector); - for (i = 0; i < disks; i++) { - if (!sh->bh_new[i]) - continue; - if (!sh->bh_old[i]) - compute_block(sh, i); - memcpy(sh->bh_new[i]->b_data, sh->bh_old[i]->b_data, sh->size); - } - complete_stripe(sh); - return; - } - if (nr_failed_overwrite) { - sh->phase = PHASE_READ_OLD; - for (i = 0; i < disks; i++) { - if (sh->bh_old[i]) - continue; - if (!operational[i]) - continue; - sh->bh_old[i] = raid5_alloc_buffer(sh, sh->size); - raid5_build_block(sh, sh->bh_old[i], i); - lock_get_bh(sh->bh_old[i]); - atomic_inc(&sh->nr_pending); - sh->bh_old[i]->b_dev = sh->bh_old[i]->b_rdev = conf->disks[i].dev; - generic_make_request(READ, sh->bh_old[i]); - atomic_dec(&sh->bh_old[i]->b_count); - } - PRINTK("handle_stripe() %lu, phase READ_OLD, pending %d buffers\n", sh->sector, md_atomic_read(&sh->nr_pending)); - return; - } - sh->phase = PHASE_READ; - for (i = 0; i < disks; i++) { - if (!sh->bh_new[i]) - continue; - if (sh->bh_old[i]) { - memcpy(sh->bh_new[i]->b_data, sh->bh_old[i]->b_data, sh->size); - continue; - } -#if RAID5_PARANOIA - if (sh->bh_req[i] == NULL || test_bit(BH_Lock, &sh->bh_req[i]->b_state)) { - int j; - printk("req %d is NULL! or locked \n", i); - for (j=0; jbh_new[j], sh->bh_old[j], sh->bh_req[j], - sh->new[j], sh->cmd_new[j]); - } - - } -#endif - lock_get_bh(sh->bh_req[i]); - atomic_inc(&sh->nr_pending); - sh->bh_req[i]->b_dev = sh->bh_req[i]->b_rdev = conf->disks[i].dev; - generic_make_request(READ, sh->bh_req[i]); - atomic_dec(&sh->bh_req[i]->b_count); - } - PRINTK("handle_stripe() %lu, phase READ, pending %d\n", sh->sector, md_atomic_read(&sh->nr_pending)); -} - -/* - * Syncing - */ -static void handle_stripe_sync (mddev_t *mddev , raid5_conf_t *conf, - struct stripe_head *sh, int * operational, int disks, - int parity, int parity_failed, int nr_cache, int nr_cache_other, - int nr_failed_other, int nr_cache_overwrite, int nr_failed_overwrite) -{ - struct buffer_head *bh; - int i, pd_idx; - - /* firstly, we want to have data from all non-failed drives - * in bh_old - */ - PRINTK("handle_stripe_sync: sec=%lu disks=%d nr_cache=%d\n", sh->sector, disks, nr_cache); - if ((nr_cache < disks-1) || ((nr_cache == disks-1) && !(parity_failed+nr_failed_other+nr_failed_overwrite)) - ) { - sh->phase = PHASE_READ_OLD; - for (i = 0; i < disks; i++) { - if (sh->bh_old[i]) - continue; - if (!conf->disks[i].operational) - continue; - - bh = raid5_alloc_buffer(sh, sh->size); - sh->bh_old[i] = bh; - raid5_build_block(sh, bh, i); - lock_get_bh(bh); - atomic_inc(&sh->nr_pending); - bh->b_dev = bh->b_rdev = conf->disks[i].dev; - generic_make_request(READ, bh); - md_sync_acct(bh->b_rdev, bh->b_size/512); - atomic_dec(&sh->bh_old[i]->b_count); - } - PRINTK("handle_stripe_sync() %lu, phase READ_OLD, pending %d buffers\n", sh->sector, md_atomic_read(&sh->nr_pending)); - - return; - } - /* now, if there is a failed drive, rebuild and write to spare */ - if (nr_cache == disks-1) { - sh->phase = PHASE_WRITE; - /* we can generate the missing block, which will be on the failed drive */ - for (i=0; ispare) { - bh = sh->bh_copy[i]; - if (bh) { - memcpy(bh->b_data, sh->bh_old[i]->b_data, sh->size); - set_bit(BH_Uptodate, &bh->b_state); - } else { - bh = sh->bh_old[i]; - sh->bh_old[i] = NULL; - sh->bh_copy[i] = bh; - } - atomic_inc(&sh->nr_pending); - lock_get_bh(bh); - bh->b_dev = bh->b_rdev = conf->spare->dev; - generic_make_request(WRITE, bh); - md_sync_acct(bh->b_rdev, bh->b_size/512); - atomic_dec(&bh->b_count); - PRINTK("handle_stripe_sync() %lu, phase WRITE, pending %d buffers\n", sh->sector, md_atomic_read(&sh->nr_pending)); - } - break; - } - return; - } - - /* nr_cache == disks: - * check parity and compute/write if needed - */ - - compute_parity(sh, RECONSTRUCT_WRITE); - pd_idx = sh->pd_idx; - if (!memcmp(sh->bh_copy[pd_idx]->b_data, sh->bh_old[pd_idx]->b_data, sh->size)) { - /* the parity is correct - Yay! */ - complete_stripe(sh); - } else { - sh->phase = PHASE_WRITE; - bh = sh->bh_copy[pd_idx]; - atomic_set_buffer_dirty(bh); - lock_get_bh(bh); - atomic_inc(&sh->nr_pending); - bh->b_dev = bh->b_rdev = conf->disks[pd_idx].dev; - generic_make_request(WRITE, bh); - md_sync_acct(bh->b_rdev, bh->b_size/512); - atomic_dec(&bh->b_count); - PRINTK("handle_stripe_sync() %lu phase WRITE, pending %d buffers\n", - sh->sector, md_atomic_read(&sh->nr_pending)); - } -} - -/* - * handle_stripe() is our main logic routine. Note that: - * - * 1. lock_stripe() should be used whenever we can't accept additonal - * buffers, either during short sleeping in handle_stripe() or - * during io operations. - * - * 2. We should be careful to set sh->nr_pending whenever we sleep, - * to prevent re-entry of handle_stripe() for the same sh. - * - * 3. conf->failed_disks and disk->operational can be changed - * from an interrupt. This complicates things a bit, but it allows - * us to stop issuing requests for a failed drive as soon as possible. - */ -static void handle_stripe(struct stripe_head *sh) -{ - raid5_conf_t *conf = sh->raid_conf; - mddev_t *mddev = conf->mddev; - int disks = conf->raid_disks; - int i, nr_read = 0, nr_write = 0, parity = 0; - int nr_cache = 0, nr_cache_other = 0, nr_cache_overwrite = 0; - int nr_failed_other = 0, nr_failed_overwrite = 0, parity_failed = 0; - int operational[MD_SB_DISKS], failed_disks = conf->failed_disks; - - PRINTK("handle_stripe(), stripe %lu\n", sh->sector); - if (!stripe_locked(sh)) - BUG(); - if (md_atomic_read(&sh->nr_pending)) - BUG(); - if (sh->phase == PHASE_COMPLETE) - BUG(); - - atomic_dec(&conf->nr_handle); - - if (md_test_and_clear_bit(STRIPE_ERROR, &sh->state)) { - printk("raid5: restarting stripe %lu\n", sh->sector); - sh->phase = PHASE_BEGIN; - } - - if ((sh->cmd == STRIPE_WRITE && sh->phase == PHASE_WRITE) || - (sh->cmd == STRIPE_READ && sh->phase == PHASE_READ) || - (sh->cmd == STRIPE_SYNC && sh->phase == PHASE_WRITE) - ) { - /* - * Completed - */ - complete_stripe(sh); - if (sh->phase == PHASE_COMPLETE) - return; - } - - md_spin_lock_irq(&conf->device_lock); - for (i = 0; i < disks; i++) { - operational[i] = conf->disks[i].operational; - if (i == sh->pd_idx && conf->resync_parity) - operational[i] = 0; - } - failed_disks = conf->failed_disks; - md_spin_unlock_irq(&conf->device_lock); - - /* - * Make this one more graceful? - */ - if (failed_disks > 1) { - for (i = 0; i < disks; i++) { - if (sh->bh_new[i]) { - raid5_end_buffer_io(sh, i, 0); - continue; - } - } - if (sh->cmd == STRIPE_SYNC) - md_done_sync(conf->mddev, (sh->size>>10) - sh->sync_redone,1); - finish_unlock_stripe(sh); - return; - } - - PRINTK("=== stripe index START ===\n"); - for (i = 0; i < disks; i++) { - PRINTK("disk %d, ", i); - if (sh->bh_old[i]) { - nr_cache++; - PRINTK(" (old cached, %d)", nr_cache); - } - if (i == sh->pd_idx) { - PRINTK(" PARITY."); - if (sh->bh_old[i]) { - PRINTK(" CACHED."); - parity = 1; - } else { - PRINTK(" UNCACHED."); - if (!operational[i]) { - PRINTK(" FAILED."); - parity_failed = 1; - } - } - PRINTK("\n"); - continue; - } - if (!sh->bh_new[i]) { - PRINTK(" (no new data block) "); - if (sh->bh_old[i]) { - PRINTK(" (but old block cached) "); - nr_cache_other++; - } else { - if (!operational[i]) { - PRINTK(" (because failed disk) "); - nr_failed_other++; - } else - PRINTK(" (no old block either) "); - } - PRINTK("\n"); - continue; - } - sh->new[i] = 0; - if (sh->cmd_new[i] == READ) { - nr_read++; - PRINTK(" (new READ %d)", nr_read); - } - if (sh->cmd_new[i] == WRITE) { - nr_write++; - PRINTK(" (new WRITE %d)", nr_write); - } - if (sh->bh_old[i]) { - nr_cache_overwrite++; - PRINTK(" (overwriting old %d)", nr_cache_overwrite); - } else { - if (!operational[i]) { - nr_failed_overwrite++; - PRINTK(" (overwriting failed %d)", nr_failed_overwrite); - } - } - PRINTK("\n"); - } - PRINTK("=== stripe index END ===\n"); - - if (nr_write && nr_read) - BUG(); - - if (nr_write) - handle_stripe_write( - mddev, conf, sh, nr_write, operational, disks, - parity, parity_failed, nr_cache, nr_cache_other, - nr_failed_other, nr_cache_overwrite, - nr_failed_overwrite - ); - else if (nr_read) - handle_stripe_read( - mddev, conf, sh, nr_read, operational, disks, - parity, parity_failed, nr_cache, nr_cache_other, - nr_failed_other, nr_cache_overwrite, - nr_failed_overwrite - ); - else if (sh->cmd == STRIPE_SYNC) - handle_stripe_sync( - mddev, conf, sh, operational, disks, - parity, parity_failed, nr_cache, nr_cache_other, - nr_failed_other, nr_cache_overwrite, nr_failed_overwrite - ); -} - - -static int raid5_make_request (mddev_t *mddev, int rw, struct buffer_head * bh) -{ - raid5_conf_t *conf = (raid5_conf_t *) mddev->private; - const unsigned int raid_disks = conf->raid_disks; - const unsigned int data_disks = raid_disks - 1; - unsigned int dd_idx, pd_idx; - unsigned long new_sector; - - struct stripe_head *sh; - - if (rw == READA) - rw = READ; - - new_sector = raid5_compute_sector(bh->b_rsector, - raid_disks, data_disks, &dd_idx, &pd_idx, conf); - - PRINTK("raid5_make_request, sector %lu\n", new_sector); - sh = get_lock_stripe(conf, new_sector, bh->b_size); -#if 0 - if ((rw == READ && sh->cmd == STRIPE_WRITE) || (rw == WRITE && sh->cmd == STRIPE_READ)) { - PRINTK("raid5: lock contention, rw == %d, sh->cmd == %d\n", rw, sh->cmd); - lock_stripe(sh); - if (!md_atomic_read(&sh->nr_pending)) - handle_stripe(sh); - goto repeat; - } -#endif - sh->pd_idx = pd_idx; - if (sh->phase != PHASE_COMPLETE && sh->phase != PHASE_BEGIN) - PRINTK("stripe %lu catching the bus!\n", sh->sector); - if (sh->bh_new[dd_idx]) - BUG(); - add_stripe_bh(sh, bh, dd_idx, rw); - - md_wakeup_thread(conf->thread); - return 0; -} - -/* - * Determine correct block size for this device. - */ -unsigned int device_bsize (kdev_t dev) -{ - unsigned int i, correct_size; - - correct_size = BLOCK_SIZE; - if (blksize_size[MAJOR(dev)]) { - i = blksize_size[MAJOR(dev)][MINOR(dev)]; - if (i) - correct_size = i; - } - - return correct_size; -} - -static int raid5_sync_request (mddev_t *mddev, unsigned long block_nr) -{ - raid5_conf_t *conf = (raid5_conf_t *) mddev->private; - struct stripe_head *sh; - int sectors_per_chunk = conf->chunk_size >> 9; - unsigned long stripe = (block_nr<<2)/sectors_per_chunk; - int chunk_offset = (block_nr<<2) % sectors_per_chunk; - int dd_idx, pd_idx; - unsigned long first_sector; - int raid_disks = conf->raid_disks; - int data_disks = raid_disks-1; - int redone = 0; - int bufsize; - - if (!conf->buffer_size) - conf->buffer_size = /* device_bsize(mddev_to_kdev(mddev))*/ PAGE_SIZE; - bufsize = conf->buffer_size; - /* Hmm... race on buffer_size ?? */ - redone = block_nr% (bufsize>>10); - block_nr -= redone; - sh = get_lock_stripe(conf, block_nr<<1, bufsize); - first_sector = raid5_compute_sector(stripe*data_disks*sectors_per_chunk - + chunk_offset, raid_disks, data_disks, &dd_idx, &pd_idx, conf); - sh->pd_idx = pd_idx; - sh->cmd = STRIPE_SYNC; - sh->phase = PHASE_BEGIN; - sh->sync_redone = redone; - atomic_inc(&conf->nr_pending_stripes); - atomic_inc(&conf->nr_handle); - md_wakeup_thread(conf->thread); - return (bufsize>>10)-redone; -} - -/* - * This is our raid5 kernel thread. - * - * We scan the hash table for stripes which can be handled now. - * During the scan, completed stripes are saved for us by the interrupt - * handler, so that they will not have to wait for our next wakeup. - */ -static void raid5d (void *data) -{ - struct stripe_head *sh; - raid5_conf_t *conf = data; - mddev_t *mddev = conf->mddev; - int i, handled; - - PRINTK("+++ raid5d active\n"); - - handled = 0; - md_spin_lock_irq(&conf->device_lock); - clear_bit(THREAD_WAKEUP, &conf->thread->flags); -repeat_pass: - if (mddev->sb_dirty) { - md_spin_unlock_irq(&conf->device_lock); - mddev->sb_dirty = 0; - md_update_sb(mddev); - md_spin_lock_irq(&conf->device_lock); - } - for (i = 0; i < NR_HASH; i++) { -repeat: - sh = conf->stripe_hashtbl[i]; - for (; sh; sh = sh->hash_next) { - if (sh->raid_conf != conf) - continue; - if (sh->phase == PHASE_COMPLETE) - continue; - if (md_atomic_read(&sh->nr_pending)) - continue; - md_spin_unlock_irq(&conf->device_lock); - if (!atomic_read(&sh->count)) - BUG(); - - handled++; - handle_stripe(sh); - md_spin_lock_irq(&conf->device_lock); - goto repeat; - } - } - if (conf) { - PRINTK("%d stripes handled, nr_handle %d\n", handled, md_atomic_read(&conf->nr_handle)); - if (test_and_clear_bit(THREAD_WAKEUP, &conf->thread->flags) && - md_atomic_read(&conf->nr_handle)) - goto repeat_pass; - } - md_spin_unlock_irq(&conf->device_lock); - - PRINTK("--- raid5d inactive\n"); -} - -/* - * Private kernel thread for parity reconstruction after an unclean - * shutdown. Reconstruction on spare drives in case of a failed drive - * is done by the generic mdsyncd. - */ -static void raid5syncd (void *data) -{ - raid5_conf_t *conf = data; - mddev_t *mddev = conf->mddev; - - if (!conf->resync_parity) - return; - if (conf->resync_parity == 2) - return; - down(&mddev->recovery_sem); - if (md_do_sync(mddev,NULL)) { - up(&mddev->recovery_sem); - printk("raid5: resync aborted!\n"); - return; - } - conf->resync_parity = 0; - up(&mddev->recovery_sem); - printk("raid5: resync finished.\n"); -} - -static int __check_consistency (mddev_t *mddev, int row) -{ - raid5_conf_t *conf = mddev->private; - kdev_t dev; - struct buffer_head *bh[MD_SB_DISKS], *tmp = NULL; - int i, ret = 0, nr = 0, count; - struct buffer_head *bh_ptr[MAX_XOR_BLOCKS]; - - if (conf->working_disks != conf->raid_disks) - goto out; - tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); - tmp->b_size = 4096; - tmp->b_page = alloc_page(GFP_KERNEL); - tmp->b_data = page_address(tmp->b_page); - if (!tmp->b_data) - goto out; - md_clear_page(tmp->b_data); - memset(bh, 0, MD_SB_DISKS * sizeof(struct buffer_head *)); - for (i = 0; i < conf->raid_disks; i++) { - dev = conf->disks[i].dev; - set_blocksize(dev, 4096); - bh[i] = bread(dev, row / 4, 4096); - if (!bh[i]) - break; - nr++; - } - if (nr == conf->raid_disks) { - bh_ptr[0] = tmp; - count = 1; - for (i = 1; i < nr; i++) { - bh_ptr[count++] = bh[i]; - if (count == MAX_XOR_BLOCKS) { - xor_block(count, &bh_ptr[0]); - count = 1; - } - } - if (count != 1) { - xor_block(count, &bh_ptr[0]); - } - if (memcmp(tmp->b_data, bh[0]->b_data, 4096)) - ret = 1; - } - for (i = 0; i < conf->raid_disks; i++) { - dev = conf->disks[i].dev; - if (bh[i]) { - bforget(bh[i]); - bh[i] = NULL; - } - fsync_dev(dev); - invalidate_buffers(dev); - } - free_page((unsigned long) tmp->b_data); -out: - if (tmp) - kfree(tmp); - return ret; -} - -static int check_consistency (mddev_t *mddev) -{ - if (__check_consistency(mddev, 0)) -/* - * We are not checking this currently, as it's legitimate to have - * an inconsistent array, at creation time. - */ - return 0; - - return 0; -} - -static int raid5_run (mddev_t *mddev) -{ - raid5_conf_t *conf; - int i, j, raid_disk, memory; - mdp_super_t *sb = mddev->sb; - mdp_disk_t *desc; - mdk_rdev_t *rdev; - struct disk_info *disk; - struct md_list_head *tmp; - int start_recovery = 0; - - MOD_INC_USE_COUNT; - - if (sb->level != 5 && sb->level != 4) { - printk("raid5: md%d: raid level not set to 4/5 (%d)\n", mdidx(mddev), sb->level); - MOD_DEC_USE_COUNT; - return -EIO; - } - - mddev->private = kmalloc (sizeof (raid5_conf_t), GFP_KERNEL); - if ((conf = mddev->private) == NULL) - goto abort; - memset (conf, 0, sizeof (*conf)); - conf->mddev = mddev; - - if ((conf->stripe_hashtbl = (struct stripe_head **) md__get_free_pages(GFP_ATOMIC, HASH_PAGES_ORDER)) == NULL) - goto abort; - memset(conf->stripe_hashtbl, 0, HASH_PAGES * PAGE_SIZE); - - conf->device_lock = MD_SPIN_LOCK_UNLOCKED; - md_init_waitqueue_head(&conf->wait_for_stripe); - PRINTK("raid5_run(md%d) called.\n", mdidx(mddev)); - - ITERATE_RDEV(mddev,rdev,tmp) { - /* - * This is important -- we are using the descriptor on - * the disk only to get a pointer to the descriptor on - * the main superblock, which might be more recent. - */ - desc = sb->disks + rdev->desc_nr; - raid_disk = desc->raid_disk; - disk = conf->disks + raid_disk; - - if (disk_faulty(desc)) { - printk(KERN_ERR "raid5: disabled device %s (errors detected)\n", partition_name(rdev->dev)); - if (!rdev->faulty) { - MD_BUG(); - goto abort; - } - disk->number = desc->number; - disk->raid_disk = raid_disk; - disk->dev = rdev->dev; - - disk->operational = 0; - disk->write_only = 0; - disk->spare = 0; - disk->used_slot = 1; - continue; - } - if (disk_active(desc)) { - if (!disk_sync(desc)) { - printk(KERN_ERR "raid5: disabled device %s (not in sync)\n", partition_name(rdev->dev)); - MD_BUG(); - goto abort; - } - if (raid_disk > sb->raid_disks) { - printk(KERN_ERR "raid5: disabled device %s (inconsistent descriptor)\n", partition_name(rdev->dev)); - continue; - } - if (disk->operational) { - printk(KERN_ERR "raid5: disabled device %s (device %d already operational)\n", partition_name(rdev->dev), raid_disk); - continue; - } - printk(KERN_INFO "raid5: device %s operational as raid disk %d\n", partition_name(rdev->dev), raid_disk); - - disk->number = desc->number; - disk->raid_disk = raid_disk; - disk->dev = rdev->dev; - disk->operational = 1; - disk->used_slot = 1; - - conf->working_disks++; - } else { - /* - * Must be a spare disk .. - */ - printk(KERN_INFO "raid5: spare disk %s\n", partition_name(rdev->dev)); - disk->number = desc->number; - disk->raid_disk = raid_disk; - disk->dev = rdev->dev; - - disk->operational = 0; - disk->write_only = 0; - disk->spare = 1; - disk->used_slot = 1; - } - } - - for (i = 0; i < MD_SB_DISKS; i++) { - desc = sb->disks + i; - raid_disk = desc->raid_disk; - disk = conf->disks + raid_disk; - - if (disk_faulty(desc) && (raid_disk < sb->raid_disks) && - !conf->disks[raid_disk].used_slot) { - - disk->number = desc->number; - disk->raid_disk = raid_disk; - disk->dev = MKDEV(0,0); - - disk->operational = 0; - disk->write_only = 0; - disk->spare = 0; - disk->used_slot = 1; - } - } - - conf->raid_disks = sb->raid_disks; - /* - * 0 for a fully functional array, 1 for a degraded array. - */ - conf->failed_disks = conf->raid_disks - conf->working_disks; - conf->mddev = mddev; - conf->chunk_size = sb->chunk_size; - conf->level = sb->level; - conf->algorithm = sb->layout; - conf->max_nr_stripes = NR_STRIPES; - -#if 0 - for (i = 0; i < conf->raid_disks; i++) { - if (!conf->disks[i].used_slot) { - MD_BUG(); - goto abort; - } - } -#endif - if (!conf->chunk_size || conf->chunk_size % 4) { - printk(KERN_ERR "raid5: invalid chunk size %d for md%d\n", conf->chunk_size, mdidx(mddev)); - goto abort; - } - if (conf->algorithm > ALGORITHM_RIGHT_SYMMETRIC) { - printk(KERN_ERR "raid5: unsupported parity algorithm %d for md%d\n", conf->algorithm, mdidx(mddev)); - goto abort; - } - if (conf->failed_disks > 1) { - printk(KERN_ERR "raid5: not enough operational devices for md%d (%d/%d failed)\n", mdidx(mddev), conf->failed_disks, conf->raid_disks); - goto abort; - } - - if (conf->working_disks != sb->raid_disks) { - printk(KERN_ALERT "raid5: md%d, not all disks are operational -- trying to recover array\n", mdidx(mddev)); - start_recovery = 1; - } - - if (!start_recovery && (sb->state & (1 << MD_SB_CLEAN)) && - check_consistency(mddev)) { - printk(KERN_ERR "raid5: detected raid-5 superblock xor inconsistency -- running resync\n"); - sb->state &= ~(1 << MD_SB_CLEAN); - } - - { - const char * name = "raid5d"; - - conf->thread = md_register_thread(raid5d, conf, name); - if (!conf->thread) { - printk(KERN_ERR "raid5: couldn't allocate thread for md%d\n", mdidx(mddev)); - goto abort; - } - } - - memory = conf->max_nr_stripes * (sizeof(struct stripe_head) + - conf->raid_disks * (sizeof(struct buffer_head) + - 2 * (sizeof(struct buffer_head) + PAGE_SIZE))) / 1024; - if (grow_stripes(conf, conf->max_nr_stripes, GFP_KERNEL)) { - printk(KERN_ERR "raid5: couldn't allocate %dkB for buffers\n", memory); - shrink_stripes(conf, conf->max_nr_stripes); - goto abort; - } else - printk(KERN_INFO "raid5: allocated %dkB for md%d\n", memory, mdidx(mddev)); - - /* - * Regenerate the "device is in sync with the raid set" bit for - * each device. - */ - for (i = 0; i < MD_SB_DISKS ; i++) { - mark_disk_nonsync(sb->disks + i); - for (j = 0; j < sb->raid_disks; j++) { - if (!conf->disks[j].operational) - continue; - if (sb->disks[i].number == conf->disks[j].number) - mark_disk_sync(sb->disks + i); - } - } - sb->active_disks = conf->working_disks; - - if (sb->active_disks == sb->raid_disks) - printk("raid5: raid level %d set md%d active with %d out of %d devices, algorithm %d\n", conf->level, mdidx(mddev), sb->active_disks, sb->raid_disks, conf->algorithm); - else - printk(KERN_ALERT "raid5: raid level %d set md%d active with %d out of %d devices, algorithm %d\n", conf->level, mdidx(mddev), sb->active_disks, sb->raid_disks, conf->algorithm); - - if (!start_recovery && !(sb->state & (1 << MD_SB_CLEAN))) { - const char * name = "raid5syncd"; - - conf->resync_thread = md_register_thread(raid5syncd, conf,name); - if (!conf->resync_thread) { - printk(KERN_ERR "raid5: couldn't allocate thread for md%d\n", mdidx(mddev)); - goto abort; - } - - printk("raid5: raid set md%d not clean; reconstructing parity\n", mdidx(mddev)); - conf->resync_parity = 1; - md_wakeup_thread(conf->resync_thread); - } - - print_raid5_conf(conf); - if (start_recovery) - md_recover_arrays(); - print_raid5_conf(conf); - - /* Ok, everything is just fine now */ - return (0); -abort: - if (conf) { - print_raid5_conf(conf); - if (conf->stripe_hashtbl) - free_pages((unsigned long) conf->stripe_hashtbl, - HASH_PAGES_ORDER); - kfree(conf); - } - mddev->private = NULL; - printk(KERN_ALERT "raid5: failed to run raid set md%d\n", mdidx(mddev)); - MOD_DEC_USE_COUNT; - return -EIO; -} - -static int raid5_stop_resync (mddev_t *mddev) -{ - raid5_conf_t *conf = mddev_to_conf(mddev); - mdk_thread_t *thread = conf->resync_thread; - - if (thread) { - if (conf->resync_parity) { - conf->resync_parity = 2; - md_interrupt_thread(thread); - printk(KERN_INFO "raid5: parity resync was not fully finished, restarting next time.\n"); - return 1; - } - return 0; - } - return 0; -} - -static int raid5_restart_resync (mddev_t *mddev) -{ - raid5_conf_t *conf = mddev_to_conf(mddev); - - if (conf->resync_parity) { - if (!conf->resync_thread) { - MD_BUG(); - return 0; - } - printk("raid5: waking up raid5resync.\n"); - conf->resync_parity = 1; - md_wakeup_thread(conf->resync_thread); - return 1; - } else - printk("raid5: no restart-resync needed.\n"); - return 0; -} - - -static int raid5_stop (mddev_t *mddev) -{ - raid5_conf_t *conf = (raid5_conf_t *) mddev->private; - - shrink_stripe_cache(conf, conf->max_nr_stripes); - shrink_stripes(conf, conf->max_nr_stripes); - md_unregister_thread(conf->thread); - if (conf->resync_thread) - md_unregister_thread(conf->resync_thread); - free_pages((unsigned long) conf->stripe_hashtbl, HASH_PAGES_ORDER); - kfree(conf); - mddev->private = NULL; - MOD_DEC_USE_COUNT; - return 0; -} - -#if RAID5_DEBUG -static void print_sh (struct stripe_head *sh) -{ - int i; - - printk("sh %lu, phase %d, size %d, pd_idx %d, state %ld, cmd %d.\n", sh->sector, sh->phase, sh->size, sh->pd_idx, sh->state, sh->cmd); - printk("sh %lu, write_method %d, nr_pending %d, count %d.\n", sh->sector, sh->write_method, atomic_read(&sh->nr_pending), atomic_read(&sh->count)); - printk("sh %lu, ", sh->sector); - for (i = 0; i < MD_SB_DISKS; i++) { - if (sh->bh_old[i]) - printk("(old%d: %p) ", i, sh->bh_old[i]); - if (sh->bh_new[i]) - printk("(new%d: %p) ", i, sh->bh_new[i]); - if (sh->bh_copy[i]) - printk("(copy%d: %p) ", i, sh->bh_copy[i]); - if (sh->bh_req[i]) - printk("(req%d: %p) ", i, sh->bh_req[i]); - } - printk("\n"); - for (i = 0; i < MD_SB_DISKS; i++) - printk("%d(%d/%d) ", i, sh->cmd_new[i], sh->new[i]); - printk("\n"); -} - -static void printall (raid5_conf_t *conf) -{ - struct stripe_head *sh; - int i; - - md_spin_lock_irq(&conf->device_lock); - for (i = 0; i < NR_HASH; i++) { - sh = conf->stripe_hashtbl[i]; - for (; sh; sh = sh->hash_next) { - if (sh->raid_conf != conf) - continue; - print_sh(sh); - } - } - md_spin_unlock_irq(&conf->device_lock); - - PRINTK("--- raid5d inactive\n"); -} -#endif - -static int raid5_status (char *page, mddev_t *mddev) -{ - raid5_conf_t *conf = (raid5_conf_t *) mddev->private; - mdp_super_t *sb = mddev->sb; - int sz = 0, i; - - sz += sprintf (page+sz, " level %d, %dk chunk, algorithm %d", sb->level, sb->chunk_size >> 10, sb->layout); - sz += sprintf (page+sz, " [%d/%d] [", conf->raid_disks, conf->working_disks); - for (i = 0; i < conf->raid_disks; i++) - sz += sprintf (page+sz, "%s", conf->disks[i].operational ? "U" : "_"); - sz += sprintf (page+sz, "]"); -#if RAID5_DEBUG -#define D(x) \ - sz += sprintf (page+sz, "<"#x":%d>", atomic_read(&conf->x)) - D(nr_handle); - D(nr_stripes); - D(nr_hashed_stripes); - D(nr_locked_stripes); - D(nr_pending_stripes); - D(nr_cached_stripes); - D(nr_free_sh); - printall(conf); -#endif - return sz; -} - -static void print_raid5_conf (raid5_conf_t *conf) -{ - int i; - struct disk_info *tmp; - - printk("RAID5 conf printout:\n"); - if (!conf) { - printk("(conf==NULL)\n"); - return; - } - printk(" --- rd:%d wd:%d fd:%d\n", conf->raid_disks, - conf->working_disks, conf->failed_disks); - - for (i = 0; i < MD_SB_DISKS; i++) { - tmp = conf->disks + i; - printk(" disk %d, s:%d, o:%d, n:%d rd:%d us:%d dev:%s\n", - i, tmp->spare,tmp->operational, - tmp->number,tmp->raid_disk,tmp->used_slot, - partition_name(tmp->dev)); - } -} - -static int raid5_diskop(mddev_t *mddev, mdp_disk_t **d, int state) -{ - int err = 0; - int i, failed_disk=-1, spare_disk=-1, removed_disk=-1, added_disk=-1; - raid5_conf_t *conf = mddev->private; - struct disk_info *tmp, *sdisk, *fdisk, *rdisk, *adisk; - mdp_super_t *sb = mddev->sb; - mdp_disk_t *failed_desc, *spare_desc, *added_desc; - - print_raid5_conf(conf); - md_spin_lock_irq(&conf->device_lock); - /* - * find the disk ... - */ - switch (state) { - - case DISKOP_SPARE_ACTIVE: - - /* - * Find the failed disk within the RAID5 configuration ... - * (this can only be in the first conf->raid_disks part) - */ - for (i = 0; i < conf->raid_disks; i++) { - tmp = conf->disks + i; - if ((!tmp->operational && !tmp->spare) || - !tmp->used_slot) { - failed_disk = i; - break; - } - } - /* - * When we activate a spare disk we _must_ have a disk in - * the lower (active) part of the array to replace. - */ - if ((failed_disk == -1) || (failed_disk >= conf->raid_disks)) { - MD_BUG(); - err = 1; - goto abort; - } - /* fall through */ - - case DISKOP_SPARE_WRITE: - case DISKOP_SPARE_INACTIVE: - - /* - * Find the spare disk ... (can only be in the 'high' - * area of the array) - */ - for (i = conf->raid_disks; i < MD_SB_DISKS; i++) { - tmp = conf->disks + i; - if (tmp->spare && tmp->number == (*d)->number) { - spare_disk = i; - break; - } - } - if (spare_disk == -1) { - MD_BUG(); - err = 1; - goto abort; - } - break; - - case DISKOP_HOT_REMOVE_DISK: - - for (i = 0; i < MD_SB_DISKS; i++) { - tmp = conf->disks + i; - if (tmp->used_slot && (tmp->number == (*d)->number)) { - if (tmp->operational) { - err = -EBUSY; - goto abort; - } - removed_disk = i; - break; - } - } - if (removed_disk == -1) { - MD_BUG(); - err = 1; - goto abort; - } - break; - - case DISKOP_HOT_ADD_DISK: - - for (i = conf->raid_disks; i < MD_SB_DISKS; i++) { - tmp = conf->disks + i; - if (!tmp->used_slot) { - added_disk = i; - break; - } - } - if (added_disk == -1) { - MD_BUG(); - err = 1; - goto abort; - } - break; - } - - switch (state) { - /* - * Switch the spare disk to write-only mode: - */ - case DISKOP_SPARE_WRITE: - if (conf->spare) { - MD_BUG(); - err = 1; - goto abort; - } - sdisk = conf->disks + spare_disk; - sdisk->operational = 1; - sdisk->write_only = 1; - conf->spare = sdisk; - break; - /* - * Deactivate a spare disk: - */ - case DISKOP_SPARE_INACTIVE: - sdisk = conf->disks + spare_disk; - sdisk->operational = 0; - sdisk->write_only = 0; - /* - * Was the spare being resynced? - */ - if (conf->spare == sdisk) - conf->spare = NULL; - break; - /* - * Activate (mark read-write) the (now sync) spare disk, - * which means we switch it's 'raid position' (->raid_disk) - * with the failed disk. (only the first 'conf->raid_disks' - * slots are used for 'real' disks and we must preserve this - * property) - */ - case DISKOP_SPARE_ACTIVE: - if (!conf->spare) { - MD_BUG(); - err = 1; - goto abort; - } - sdisk = conf->disks + spare_disk; - fdisk = conf->disks + failed_disk; - - spare_desc = &sb->disks[sdisk->number]; - failed_desc = &sb->disks[fdisk->number]; - - if (spare_desc != *d) { - MD_BUG(); - err = 1; - goto abort; - } - - if (spare_desc->raid_disk != sdisk->raid_disk) { - MD_BUG(); - err = 1; - goto abort; - } - - if (sdisk->raid_disk != spare_disk) { - MD_BUG(); - err = 1; - goto abort; - } - - if (failed_desc->raid_disk != fdisk->raid_disk) { - MD_BUG(); - err = 1; - goto abort; - } - - if (fdisk->raid_disk != failed_disk) { - MD_BUG(); - err = 1; - goto abort; - } - - /* - * do the switch finally - */ - xchg_values(*spare_desc, *failed_desc); - xchg_values(*fdisk, *sdisk); - - /* - * (careful, 'failed' and 'spare' are switched from now on) - * - * we want to preserve linear numbering and we want to - * give the proper raid_disk number to the now activated - * disk. (this means we switch back these values) - */ - - xchg_values(spare_desc->raid_disk, failed_desc->raid_disk); - xchg_values(sdisk->raid_disk, fdisk->raid_disk); - xchg_values(spare_desc->number, failed_desc->number); - xchg_values(sdisk->number, fdisk->number); - - *d = failed_desc; - - if (sdisk->dev == MKDEV(0,0)) - sdisk->used_slot = 0; - - /* - * this really activates the spare. - */ - fdisk->spare = 0; - fdisk->write_only = 0; - - /* - * if we activate a spare, we definitely replace a - * non-operational disk slot in the 'low' area of - * the disk array. - */ - conf->failed_disks--; - conf->working_disks++; - conf->spare = NULL; - - break; - - case DISKOP_HOT_REMOVE_DISK: - rdisk = conf->disks + removed_disk; - - if (rdisk->spare && (removed_disk < conf->raid_disks)) { - MD_BUG(); - err = 1; - goto abort; - } - rdisk->dev = MKDEV(0,0); - rdisk->used_slot = 0; - - break; - - case DISKOP_HOT_ADD_DISK: - adisk = conf->disks + added_disk; - added_desc = *d; - - if (added_disk != added_desc->number) { - MD_BUG(); - err = 1; - goto abort; - } - - adisk->number = added_desc->number; - adisk->raid_disk = added_desc->raid_disk; - adisk->dev = MKDEV(added_desc->major,added_desc->minor); - - adisk->operational = 0; - adisk->write_only = 0; - adisk->spare = 1; - adisk->used_slot = 1; - - - break; - - default: - MD_BUG(); - err = 1; - goto abort; - } -abort: - md_spin_unlock_irq(&conf->device_lock); - print_raid5_conf(conf); - return err; -} - -static mdk_personality_t raid5_personality= -{ - name: "raid5", - make_request: raid5_make_request, - run: raid5_run, - stop: raid5_stop, - status: raid5_status, - error_handler: raid5_error, - diskop: raid5_diskop, - stop_resync: raid5_stop_resync, - restart_resync: raid5_restart_resync, - sync_request: raid5_sync_request -}; - -int raid5_init (void) -{ - int err; - - err = register_md_personality (RAID5, &raid5_personality); - if (err) - return err; - - /* - * pick a XOR routine, runtime. - */ - calibrate_xor_block(); - - return 0; -} - -#ifdef MODULE -int init_module (void) -{ - return raid5_init(); -} - -void cleanup_module (void) -{ - unregister_md_personality (RAID5); -} -#endif diff -u --recursive --new-file v2.4.0-test8/linux/drivers/block/swim3.c linux/drivers/block/swim3.c --- v2.4.0-test8/linux/drivers/block/swim3.c Tue Jun 20 07:24:52 2000 +++ linux/drivers/block/swim3.c Tue Sep 19 08:31:53 2000 @@ -16,6 +16,7 @@ * handle GCR disks */ +#include #include #include #include @@ -245,6 +246,13 @@ static int floppy_revalidate(kdev_t dev); static int swim3_add_device(struct device_node *swims); int swim3_init(void); + +#ifndef CONFIG_PMAC_PBOOK +static inline int check_media_bay(struct device_node *which_bay, int what) +{ + return 1; +} +#endif static void swim3_select(struct floppy_state *fs, int sel) { diff -u --recursive --new-file v2.4.0-test8/linux/drivers/block/xd.c linux/drivers/block/xd.c --- v2.4.0-test8/linux/drivers/block/xd.c Thu Jun 29 18:25:49 2000 +++ linux/drivers/block/xd.c Mon Oct 2 14:22:40 2000 @@ -116,7 +116,7 @@ }; static struct hd_struct xd_struct[XD_MAXDRIVES << 6]; -static int xd_sizes[XD_MAXDRIVES << 6], xd_access[XD_MAXDRIVES] = { 0, 0 }; +static int xd_sizes[XD_MAXDRIVES << 6], xd_access[XD_MAXDRIVES]; static int xd_blocksizes[XD_MAXDRIVES << 6]; extern struct block_device_operations xd_fops; @@ -141,12 +141,12 @@ static DECLARE_WAIT_QUEUE_HEAD(xd_wait_int); static DECLARE_WAIT_QUEUE_HEAD(xd_wait_open); static u_char xd_valid[XD_MAXDRIVES] = { 0,0 }; -static u_char xd_drives = 0, xd_irq = 5, xd_dma = 3, xd_maxsectors; -static u_char xd_override __initdata = 0, xd_type = 0; +static u_char xd_drives, xd_irq = 5, xd_dma = 3, xd_maxsectors; +static u_char xd_override __initdata, xd_type __initdata; static u_short xd_iobase = 0x320; -static int xd_geo[XD_MAXDRIVES*3] __initdata = { 0,0,0,0,0,0 }; +static int xd_geo[XD_MAXDRIVES*3] __initdata; -static volatile int xdc_busy = 0; +static volatile int xdc_busy; static DECLARE_WAIT_QUEUE_HEAD(xdc_wait); static struct timer_list xd_timer, xd_watchdog_int; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/block/xor.c linux/drivers/block/xor.c --- v2.4.0-test8/linux/drivers/block/xor.c Mon Aug 28 21:21:57 2000 +++ linux/drivers/block/xor.c Wed Dec 31 16:00:00 1969 @@ -1,2728 +0,0 @@ -/* - * xor.c : Multiple Devices driver for Linux - * - * Copyright (C) 1996, 1997, 1998, 1999 Ingo Molnar, Matti Aarnio, Jakub Jelinek - * - * - * optimized RAID-5 checksumming functions. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * You should have received a copy of the GNU General Public License - * (for example /usr/src/linux/COPYING); if not, write to the Free - * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#include -#define BH_TRACE 0 -#include -#include -#ifdef __sparc_v9__ -#include -#include -#include -#endif - -/* - * we use the 'XOR function template' to register multiple xor - * functions runtime. The kernel measures their speed upon bootup - * and decides which one to use. (compile-time registration is - * not enough as certain CPU features like MMX can only be detected - * runtime) - * - * this architecture makes it pretty easy to add new routines - * that are faster on certain CPUs, without killing other CPU's - * 'native' routine. Although the current routines are belived - * to be the physically fastest ones on all CPUs tested, but - * feel free to prove me wrong and add yet another routine =B-) - * --mingo - */ - -#define MAX_XOR_BLOCKS 5 - -#define XOR_ARGS (unsigned int count, struct buffer_head **bh_ptr) - -typedef void (*xor_block_t) XOR_ARGS; -xor_block_t xor_block = NULL; - -#ifndef __sparc_v9__ - -struct xor_block_template; - -struct xor_block_template { - char * name; - xor_block_t xor_block; - int speed; - struct xor_block_template * next; -}; - -struct xor_block_template * xor_functions = NULL; - -#define XORBLOCK_TEMPLATE(x) \ -static void xor_block_##x XOR_ARGS; \ -static struct xor_block_template t_xor_block_##x = \ - { #x, xor_block_##x, 0, NULL }; \ -static void xor_block_##x XOR_ARGS - -#ifdef __i386__ - -#ifdef CONFIG_X86_XMM -/* - * Cache avoiding checksumming functions utilizing KNI instructions - * Copyright (C) 1999 Zach Brown (with obvious credit due Ingo) - */ - -XORBLOCK_TEMPLATE(pIII_kni) -{ - char xmm_save[16*4]; - int cr0; - int lines = (bh_ptr[0]->b_size>>8); - - __asm__ __volatile__ ( - "movl %%cr0,%0 ;\n\t" - "clts ;\n\t" - "movups %%xmm0,(%1) ;\n\t" - "movups %%xmm1,0x10(%1) ;\n\t" - "movups %%xmm2,0x20(%1) ;\n\t" - "movups %%xmm3,0x30(%1) ;\n\t" - : "=r" (cr0) - : "r" (xmm_save) - : "memory" ); - -#define OFFS(x) "8*("#x"*2)" -#define PF0(x) \ - " prefetcht0 "OFFS(x)"(%1) ;\n" -#define LD(x,y) \ - " movaps "OFFS(x)"(%1), %%xmm"#y" ;\n" -#define ST(x,y) \ - " movaps %%xmm"#y", "OFFS(x)"(%1) ;\n" -#define PF1(x) \ - " prefetchnta "OFFS(x)"(%2) ;\n" -#define PF2(x) \ - " prefetchnta "OFFS(x)"(%3) ;\n" -#define PF3(x) \ - " prefetchnta "OFFS(x)"(%4) ;\n" -#define PF4(x) \ - " prefetchnta "OFFS(x)"(%5) ;\n" -#define PF5(x) \ - " prefetchnta "OFFS(x)"(%6) ;\n" -#define XO1(x,y) \ - " xorps "OFFS(x)"(%2), %%xmm"#y" ;\n" -#define XO2(x,y) \ - " xorps "OFFS(x)"(%3), %%xmm"#y" ;\n" -#define XO3(x,y) \ - " xorps "OFFS(x)"(%4), %%xmm"#y" ;\n" -#define XO4(x,y) \ - " xorps "OFFS(x)"(%5), %%xmm"#y" ;\n" -#define XO5(x,y) \ - " xorps "OFFS(x)"(%6), %%xmm"#y" ;\n" - - switch(count) { - case 2: - __asm__ __volatile__ ( -#undef BLOCK -#define BLOCK(i) \ - LD(i,0) \ - LD(i+1,1) \ - PF1(i) \ - PF1(i+2) \ - LD(i+2,2) \ - LD(i+3,3) \ - PF0(i+4) \ - PF0(i+6) \ - XO1(i,0) \ - XO1(i+1,1) \ - XO1(i+2,2) \ - XO1(i+3,3) \ - ST(i,0) \ - ST(i+1,1) \ - ST(i+2,2) \ - ST(i+3,3) \ - - - PF0(0) - PF0(2) - - " .align 32,0x90 ;\n" - " 1: ;\n" - - BLOCK(0) - BLOCK(4) - BLOCK(8) - BLOCK(12) - - " addl $256, %1 ;\n" - " addl $256, %2 ;\n" - " decl %0 ;\n" - " jnz 1b ;\n" - - : - : "r" (lines), - "r" (bh_ptr[0]->b_data), - "r" (bh_ptr[1]->b_data) - : "memory" ); - break; - case 3: - __asm__ __volatile__ ( -#undef BLOCK -#define BLOCK(i) \ - PF1(i) \ - PF1(i+2) \ - LD(i,0) \ - LD(i+1,1) \ - LD(i+2,2) \ - LD(i+3,3) \ - PF2(i) \ - PF2(i+2) \ - PF0(i+4) \ - PF0(i+6) \ - XO1(i,0) \ - XO1(i+1,1) \ - XO1(i+2,2) \ - XO1(i+3,3) \ - XO2(i,0) \ - XO2(i+1,1) \ - XO2(i+2,2) \ - XO2(i+3,3) \ - ST(i,0) \ - ST(i+1,1) \ - ST(i+2,2) \ - ST(i+3,3) \ - - - PF0(0) - PF0(2) - - " .align 32,0x90 ;\n" - " 1: ;\n" - - BLOCK(0) - BLOCK(4) - BLOCK(8) - BLOCK(12) - - " addl $256, %1 ;\n" - " addl $256, %2 ;\n" - " addl $256, %3 ;\n" - " decl %0 ;\n" - " jnz 1b ;\n" - : - : "r" (lines), - "r" (bh_ptr[0]->b_data), - "r" (bh_ptr[1]->b_data), - "r" (bh_ptr[2]->b_data) - : "memory" ); - break; - case 4: - __asm__ __volatile__ ( -#undef BLOCK -#define BLOCK(i) \ - PF1(i) \ - PF1(i+2) \ - LD(i,0) \ - LD(i+1,1) \ - LD(i+2,2) \ - LD(i+3,3) \ - PF2(i) \ - PF2(i+2) \ - XO1(i,0) \ - XO1(i+1,1) \ - XO1(i+2,2) \ - XO1(i+3,3) \ - PF3(i) \ - PF3(i+2) \ - PF0(i+4) \ - PF0(i+6) \ - XO2(i,0) \ - XO2(i+1,1) \ - XO2(i+2,2) \ - XO2(i+3,3) \ - XO3(i,0) \ - XO3(i+1,1) \ - XO3(i+2,2) \ - XO3(i+3,3) \ - ST(i,0) \ - ST(i+1,1) \ - ST(i+2,2) \ - ST(i+3,3) \ - - - PF0(0) - PF0(2) - - " .align 32,0x90 ;\n" - " 1: ;\n" - - BLOCK(0) - BLOCK(4) - BLOCK(8) - BLOCK(12) - - " addl $256, %1 ;\n" - " addl $256, %2 ;\n" - " addl $256, %3 ;\n" - " addl $256, %4 ;\n" - " decl %0 ;\n" - " jnz 1b ;\n" - - : - : "r" (lines), - "r" (bh_ptr[0]->b_data), - "r" (bh_ptr[1]->b_data), - "r" (bh_ptr[2]->b_data), - "r" (bh_ptr[3]->b_data) - : "memory" ); - break; - case 5: - __asm__ __volatile__ ( -#undef BLOCK -#define BLOCK(i) \ - PF1(i) \ - PF1(i+2) \ - LD(i,0) \ - LD(i+1,1) \ - LD(i+2,2) \ - LD(i+3,3) \ - PF2(i) \ - PF2(i+2) \ - XO1(i,0) \ - XO1(i+1,1) \ - XO1(i+2,2) \ - XO1(i+3,3) \ - PF3(i) \ - PF3(i+2) \ - XO2(i,0) \ - XO2(i+1,1) \ - XO2(i+2,2) \ - XO2(i+3,3) \ - PF4(i) \ - PF4(i+2) \ - PF0(i+4) \ - PF0(i+6) \ - XO3(i,0) \ - XO3(i+1,1) \ - XO3(i+2,2) \ - XO3(i+3,3) \ - XO4(i,0) \ - XO4(i+1,1) \ - XO4(i+2,2) \ - XO4(i+3,3) \ - ST(i,0) \ - ST(i+1,1) \ - ST(i+2,2) \ - ST(i+3,3) \ - - - PF0(0) - PF0(2) - - " .align 32,0x90 ;\n" - " 1: ;\n" - - BLOCK(0) - BLOCK(4) - BLOCK(8) - BLOCK(12) - - " addl $256, %1 ;\n" - " addl $256, %2 ;\n" - " addl $256, %3 ;\n" - " addl $256, %4 ;\n" - " addl $256, %5 ;\n" - " decl %0 ;\n" - " jnz 1b ;\n" - - : - : "r" (lines), - "r" (bh_ptr[0]->b_data), - "r" (bh_ptr[1]->b_data), - "r" (bh_ptr[2]->b_data), - "r" (bh_ptr[3]->b_data), - "r" (bh_ptr[4]->b_data) - : "memory"); - break; - } - - __asm__ __volatile__ ( - "sfence ;\n\t" - "movups (%1),%%xmm0 ;\n\t" - "movups 0x10(%1),%%xmm1 ;\n\t" - "movups 0x20(%1),%%xmm2 ;\n\t" - "movups 0x30(%1),%%xmm3 ;\n\t" - "movl %0,%%cr0 ;\n\t" - : - : "r" (cr0), "r" (xmm_save) - : "memory" ); -} - -#undef OFFS -#undef LD -#undef ST -#undef PF0 -#undef PF1 -#undef PF2 -#undef PF3 -#undef PF4 -#undef PF5 -#undef XO1 -#undef XO2 -#undef XO3 -#undef XO4 -#undef XO5 -#undef BLOCK - -#endif /* CONFIG_X86_XMM */ - -/* - * high-speed RAID5 checksumming functions utilizing MMX instructions - * Copyright (C) 1998 Ingo Molnar - */ -XORBLOCK_TEMPLATE(pII_mmx) -{ - char fpu_save[108]; - int lines = (bh_ptr[0]->b_size>>7); - - if (!(current->flags & PF_USEDFPU)) - __asm__ __volatile__ ( " clts;\n"); - - __asm__ __volatile__ ( " fsave %0; fwait\n"::"m"(fpu_save[0]) ); - -#define LD(x,y) \ - " movq 8*("#x")(%1), %%mm"#y" ;\n" -#define ST(x,y) \ - " movq %%mm"#y", 8*("#x")(%1) ;\n" -#define XO1(x,y) \ - " pxor 8*("#x")(%2), %%mm"#y" ;\n" -#define XO2(x,y) \ - " pxor 8*("#x")(%3), %%mm"#y" ;\n" -#define XO3(x,y) \ - " pxor 8*("#x")(%4), %%mm"#y" ;\n" -#define XO4(x,y) \ - " pxor 8*("#x")(%5), %%mm"#y" ;\n" - - switch(count) { - case 2: - __asm__ __volatile__ ( -#undef BLOCK -#define BLOCK(i) \ - LD(i,0) \ - LD(i+1,1) \ - LD(i+2,2) \ - LD(i+3,3) \ - XO1(i,0) \ - ST(i,0) \ - XO1(i+1,1) \ - ST(i+1,1) \ - XO1(i+2,2) \ - ST(i+2,2) \ - XO1(i+3,3) \ - ST(i+3,3) - - " .align 32,0x90 ;\n" - " 1: ;\n" - - BLOCK(0) - BLOCK(4) - BLOCK(8) - BLOCK(12) - - " addl $128, %1 ;\n" - " addl $128, %2 ;\n" - " decl %0 ;\n" - " jnz 1b ;\n" - : - : "r" (lines), - "r" (bh_ptr[0]->b_data), - "r" (bh_ptr[1]->b_data) - : "memory"); - break; - case 3: - __asm__ __volatile__ ( -#undef BLOCK -#define BLOCK(i) \ - LD(i,0) \ - LD(i+1,1) \ - LD(i+2,2) \ - LD(i+3,3) \ - XO1(i,0) \ - XO1(i+1,1) \ - XO1(i+2,2) \ - XO1(i+3,3) \ - XO2(i,0) \ - ST(i,0) \ - XO2(i+1,1) \ - ST(i+1,1) \ - XO2(i+2,2) \ - ST(i+2,2) \ - XO2(i+3,3) \ - ST(i+3,3) - - " .align 32,0x90 ;\n" - " 1: ;\n" - - BLOCK(0) - BLOCK(4) - BLOCK(8) - BLOCK(12) - - " addl $128, %1 ;\n" - " addl $128, %2 ;\n" - " addl $128, %3 ;\n" - " decl %0 ;\n" - " jnz 1b ;\n" - : - : "r" (lines), - "r" (bh_ptr[0]->b_data), - "r" (bh_ptr[1]->b_data), - "r" (bh_ptr[2]->b_data) - : "memory"); - break; - case 4: - __asm__ __volatile__ ( -#undef BLOCK -#define BLOCK(i) \ - LD(i,0) \ - LD(i+1,1) \ - LD(i+2,2) \ - LD(i+3,3) \ - XO1(i,0) \ - XO1(i+1,1) \ - XO1(i+2,2) \ - XO1(i+3,3) \ - XO2(i,0) \ - XO2(i+1,1) \ - XO2(i+2,2) \ - XO2(i+3,3) \ - XO3(i,0) \ - ST(i,0) \ - XO3(i+1,1) \ - ST(i+1,1) \ - XO3(i+2,2) \ - ST(i+2,2) \ - XO3(i+3,3) \ - ST(i+3,3) - - " .align 32,0x90 ;\n" - " 1: ;\n" - - BLOCK(0) - BLOCK(4) - BLOCK(8) - BLOCK(12) - - " addl $128, %1 ;\n" - " addl $128, %2 ;\n" - " addl $128, %3 ;\n" - " addl $128, %4 ;\n" - " decl %0 ;\n" - " jnz 1b ;\n" - : - : "r" (lines), - "r" (bh_ptr[0]->b_data), - "r" (bh_ptr[1]->b_data), - "r" (bh_ptr[2]->b_data), - "r" (bh_ptr[3]->b_data) - : "memory"); - break; - case 5: - __asm__ __volatile__ ( -#undef BLOCK -#define BLOCK(i) \ - LD(i,0) \ - LD(i+1,1) \ - LD(i+2,2) \ - LD(i+3,3) \ - XO1(i,0) \ - XO1(i+1,1) \ - XO1(i+2,2) \ - XO1(i+3,3) \ - XO2(i,0) \ - XO2(i+1,1) \ - XO2(i+2,2) \ - XO2(i+3,3) \ - XO3(i,0) \ - XO3(i+1,1) \ - XO3(i+2,2) \ - XO3(i+3,3) \ - XO4(i,0) \ - ST(i,0) \ - XO4(i+1,1) \ - ST(i+1,1) \ - XO4(i+2,2) \ - ST(i+2,2) \ - XO4(i+3,3) \ - ST(i+3,3) - - " .align 32,0x90 ;\n" - " 1: ;\n" - - BLOCK(0) - BLOCK(4) - BLOCK(8) - BLOCK(12) - - " addl $128, %1 ;\n" - " addl $128, %2 ;\n" - " addl $128, %3 ;\n" - " addl $128, %4 ;\n" - " addl $128, %5 ;\n" - " decl %0 ;\n" - " jnz 1b ;\n" - : - : "g" (lines), - "r" (bh_ptr[0]->b_data), - "r" (bh_ptr[1]->b_data), - "r" (bh_ptr[2]->b_data), - "r" (bh_ptr[3]->b_data), - "r" (bh_ptr[4]->b_data) - : "memory"); - break; - } - - __asm__ __volatile__ ( " frstor %0;\n"::"m"(fpu_save[0]) ); - - if (!(current->flags & PF_USEDFPU)) - stts(); -} - -#undef LD -#undef XO1 -#undef XO2 -#undef XO3 -#undef XO4 -#undef ST -#undef BLOCK - -XORBLOCK_TEMPLATE(p5_mmx) -{ - char fpu_save[108]; - int lines = (bh_ptr[0]->b_size>>6); - - if (!(current->flags & PF_USEDFPU)) - __asm__ __volatile__ ( " clts;\n"); - - __asm__ __volatile__ ( " fsave %0; fwait\n"::"m"(fpu_save[0]) ); - - switch(count) { - case 2: - __asm__ __volatile__ ( - - " .align 32,0x90 ;\n" - " 1: ;\n" - " movq (%1), %%mm0 ;\n" - " movq 8(%1), %%mm1 ;\n" - " pxor (%2), %%mm0 ;\n" - " movq 16(%1), %%mm2 ;\n" - " movq %%mm0, (%1) ;\n" - " pxor 8(%2), %%mm1 ;\n" - " movq 24(%1), %%mm3 ;\n" - " movq %%mm1, 8(%1) ;\n" - " pxor 16(%2), %%mm2 ;\n" - " movq 32(%1), %%mm4 ;\n" - " movq %%mm2, 16(%1) ;\n" - " pxor 24(%2), %%mm3 ;\n" - " movq 40(%1), %%mm5 ;\n" - " movq %%mm3, 24(%1) ;\n" - " pxor 32(%2), %%mm4 ;\n" - " movq 48(%1), %%mm6 ;\n" - " movq %%mm4, 32(%1) ;\n" - " pxor 40(%2), %%mm5 ;\n" - " movq 56(%1), %%mm7 ;\n" - " movq %%mm5, 40(%1) ;\n" - " pxor 48(%2), %%mm6 ;\n" - " pxor 56(%2), %%mm7 ;\n" - " movq %%mm6, 48(%1) ;\n" - " movq %%mm7, 56(%1) ;\n" - - " addl $64, %1 ;\n" - " addl $64, %2 ;\n" - " decl %0 ;\n" - " jnz 1b ;\n" - - : - : "r" (lines), - "r" (bh_ptr[0]->b_data), - "r" (bh_ptr[1]->b_data) - : "memory" ); - break; - case 3: - __asm__ __volatile__ ( - - " .align 32,0x90 ;\n" - " 1: ;\n" - " movq (%1), %%mm0 ;\n" - " movq 8(%1), %%mm1 ;\n" - " pxor (%2), %%mm0 ;\n" - " movq 16(%1), %%mm2 ;\n" - " pxor 8(%2), %%mm1 ;\n" - " pxor (%3), %%mm0 ;\n" - " pxor 16(%2), %%mm2 ;\n" - " movq %%mm0, (%1) ;\n" - " pxor 8(%3), %%mm1 ;\n" - " pxor 16(%3), %%mm2 ;\n" - " movq 24(%1), %%mm3 ;\n" - " movq %%mm1, 8(%1) ;\n" - " movq 32(%1), %%mm4 ;\n" - " movq 40(%1), %%mm5 ;\n" - " pxor 24(%2), %%mm3 ;\n" - " movq %%mm2, 16(%1) ;\n" - " pxor 32(%2), %%mm4 ;\n" - " pxor 24(%3), %%mm3 ;\n" - " pxor 40(%2), %%mm5 ;\n" - " movq %%mm3, 24(%1) ;\n" - " pxor 32(%3), %%mm4 ;\n" - " pxor 40(%3), %%mm5 ;\n" - " movq 48(%1), %%mm6 ;\n" - " movq %%mm4, 32(%1) ;\n" - " movq 56(%1), %%mm7 ;\n" - " pxor 48(%2), %%mm6 ;\n" - " movq %%mm5, 40(%1) ;\n" - " pxor 56(%2), %%mm7 ;\n" - " pxor 48(%3), %%mm6 ;\n" - " pxor 56(%3), %%mm7 ;\n" - " movq %%mm6, 48(%1) ;\n" - " movq %%mm7, 56(%1) ;\n" - - " addl $64, %1 ;\n" - " addl $64, %2 ;\n" - " addl $64, %3 ;\n" - " decl %0 ;\n" - " jnz 1b ;\n" - - : - : "r" (lines), - "r" (bh_ptr[0]->b_data), - "r" (bh_ptr[1]->b_data), - "r" (bh_ptr[2]->b_data) - : "memory" ); - break; - case 4: - __asm__ __volatile__ ( - - " .align 32,0x90 ;\n" - " 1: ;\n" - " movq (%1), %%mm0 ;\n" - " movq 8(%1), %%mm1 ;\n" - " pxor (%2), %%mm0 ;\n" - " movq 16(%1), %%mm2 ;\n" - " pxor 8(%2), %%mm1 ;\n" - " pxor (%3), %%mm0 ;\n" - " pxor 16(%2), %%mm2 ;\n" - " pxor 8(%3), %%mm1 ;\n" - " pxor (%4), %%mm0 ;\n" - " movq 24(%1), %%mm3 ;\n" - " pxor 16(%3), %%mm2 ;\n" - " pxor 8(%4), %%mm1 ;\n" - " movq %%mm0, (%1) ;\n" - " movq 32(%1), %%mm4 ;\n" - " pxor 24(%2), %%mm3 ;\n" - " pxor 16(%4), %%mm2 ;\n" - " movq %%mm1, 8(%1) ;\n" - " movq 40(%1), %%mm5 ;\n" - " pxor 32(%2), %%mm4 ;\n" - " pxor 24(%3), %%mm3 ;\n" - " movq %%mm2, 16(%1) ;\n" - " pxor 40(%2), %%mm5 ;\n" - " pxor 32(%3), %%mm4 ;\n" - " pxor 24(%4), %%mm3 ;\n" - " movq %%mm3, 24(%1) ;\n" - " movq 56(%1), %%mm7 ;\n" - " movq 48(%1), %%mm6 ;\n" - " pxor 40(%3), %%mm5 ;\n" - " pxor 32(%4), %%mm4 ;\n" - " pxor 48(%2), %%mm6 ;\n" - " movq %%mm4, 32(%1) ;\n" - " pxor 56(%2), %%mm7 ;\n" - " pxor 40(%4), %%mm5 ;\n" - " pxor 48(%3), %%mm6 ;\n" - " pxor 56(%3), %%mm7 ;\n" - " movq %%mm5, 40(%1) ;\n" - " pxor 48(%4), %%mm6 ;\n" - " pxor 56(%4), %%mm7 ;\n" - " movq %%mm6, 48(%1) ;\n" - " movq %%mm7, 56(%1) ;\n" - - " addl $64, %1 ;\n" - " addl $64, %2 ;\n" - " addl $64, %3 ;\n" - " addl $64, %4 ;\n" - " decl %0 ;\n" - " jnz 1b ;\n" - - : - : "r" (lines), - "r" (bh_ptr[0]->b_data), - "r" (bh_ptr[1]->b_data), - "r" (bh_ptr[2]->b_data), - "r" (bh_ptr[3]->b_data) - : "memory" ); - break; - case 5: - __asm__ __volatile__ ( - - " .align 32,0x90 ;\n" - " 1: ;\n" - " movq (%1), %%mm0 ;\n" - " movq 8(%1), %%mm1 ;\n" - " pxor (%2), %%mm0 ;\n" - " pxor 8(%2), %%mm1 ;\n" - " movq 16(%1), %%mm2 ;\n" - " pxor (%3), %%mm0 ;\n" - " pxor 8(%3), %%mm1 ;\n" - " pxor 16(%2), %%mm2 ;\n" - " pxor (%4), %%mm0 ;\n" - " pxor 8(%4), %%mm1 ;\n" - " pxor 16(%3), %%mm2 ;\n" - " movq 24(%1), %%mm3 ;\n" - " pxor (%5), %%mm0 ;\n" - " pxor 8(%5), %%mm1 ;\n" - " movq %%mm0, (%1) ;\n" - " pxor 16(%4), %%mm2 ;\n" - " pxor 24(%2), %%mm3 ;\n" - " movq %%mm1, 8(%1) ;\n" - " pxor 16(%5), %%mm2 ;\n" - " pxor 24(%3), %%mm3 ;\n" - " movq 32(%1), %%mm4 ;\n" - " movq %%mm2, 16(%1) ;\n" - " pxor 24(%4), %%mm3 ;\n" - " pxor 32(%2), %%mm4 ;\n" - " movq 40(%1), %%mm5 ;\n" - " pxor 24(%5), %%mm3 ;\n" - " pxor 32(%3), %%mm4 ;\n" - " pxor 40(%2), %%mm5 ;\n" - " movq %%mm3, 24(%1) ;\n" - " pxor 32(%4), %%mm4 ;\n" - " pxor 40(%3), %%mm5 ;\n" - " movq 48(%1), %%mm6 ;\n" - " movq 56(%1), %%mm7 ;\n" - " pxor 32(%5), %%mm4 ;\n" - " pxor 40(%4), %%mm5 ;\n" - " pxor 48(%2), %%mm6 ;\n" - " pxor 56(%2), %%mm7 ;\n" - " movq %%mm4, 32(%1) ;\n" - " pxor 48(%3), %%mm6 ;\n" - " pxor 56(%3), %%mm7 ;\n" - " pxor 40(%5), %%mm5 ;\n" - " pxor 48(%4), %%mm6 ;\n" - " pxor 56(%4), %%mm7 ;\n" - " movq %%mm5, 40(%1) ;\n" - " pxor 48(%5), %%mm6 ;\n" - " pxor 56(%5), %%mm7 ;\n" - " movq %%mm6, 48(%1) ;\n" - " movq %%mm7, 56(%1) ;\n" - - " addl $64, %1 ;\n" - " addl $64, %2 ;\n" - " addl $64, %3 ;\n" - " addl $64, %4 ;\n" - " addl $64, %5 ;\n" - " decl %0 ;\n" - " jnz 1b ;\n" - - : - : "g" (lines), - "r" (bh_ptr[0]->b_data), - "r" (bh_ptr[1]->b_data), - "r" (bh_ptr[2]->b_data), - "r" (bh_ptr[3]->b_data), - "r" (bh_ptr[4]->b_data) - : "memory" ); - break; - } - - __asm__ __volatile__ ( " frstor %0;\n"::"m"(fpu_save[0]) ); - - if (!(current->flags & PF_USEDFPU)) - stts(); -} -#endif /* __i386__ */ -#endif /* !__sparc_v9__ */ - -#ifdef __sparc_v9__ -/* - * High speed xor_block operation for RAID4/5 utilizing the - * UltraSparc Visual Instruction Set. - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * - * Requirements: - * !(((long)dest | (long)sourceN) & (64 - 1)) && - * !(len & 127) && len >= 256 - * - * It is done in pure assembly, as otherwise gcc makes it - * a non-leaf function, which is not what we want. - * Also, we don't measure the speeds as on other architectures, - * as the measuring routine does not take into account cold caches - * and the fact that xor_block_VIS bypasses the caches. - * xor_block_32regs might be 5% faster for count 2 if caches are hot - * and things just right (for count 3 VIS is about as fast as 32regs for - * hot caches and for count 4 and 5 VIS is faster by good margin always), - * but I think it is better not to pollute the caches. - * Actually, if I'd just fight for speed for hot caches, I could - * write a hybrid VIS/integer routine, which would do always two - * 64B blocks in VIS and two in IEUs, but I really care more about - * caches. - */ -extern void *VISenter(void); -extern void xor_block_VIS XOR_ARGS; - -void __xor_block_VIS(void) -{ -__asm__ (" - .globl xor_block_VIS -xor_block_VIS: - ldx [%%o1 + 0], %%o4 - ldx [%%o1 + 8], %%o3 - ldx [%%o4 + %1], %%g5 - ldx [%%o4 + %0], %%o4 - ldx [%%o3 + %0], %%o3 - rd %%fprs, %%o5 - andcc %%o5, %2, %%g0 - be,pt %%icc, 297f - sethi %%hi(%5), %%g1 - jmpl %%g1 + %%lo(%5), %%g7 - add %%g7, 8, %%g7 -297: wr %%g0, %4, %%fprs - membar #LoadStore|#StoreLoad|#StoreStore - sub %%g5, 64, %%g5 - ldda [%%o4] %3, %%f0 - ldda [%%o3] %3, %%f16 - cmp %%o0, 4 - bgeu,pt %%xcc, 10f - cmp %%o0, 3 - be,pn %%xcc, 13f - mov -64, %%g1 - sub %%g5, 64, %%g5 - rd %%asi, %%g1 - wr %%g0, %3, %%asi - -2: ldda [%%o4 + 64] %%asi, %%f32 - fxor %%f0, %%f16, %%f16 - fxor %%f2, %%f18, %%f18 - fxor %%f4, %%f20, %%f20 - fxor %%f6, %%f22, %%f22 - fxor %%f8, %%f24, %%f24 - fxor %%f10, %%f26, %%f26 - fxor %%f12, %%f28, %%f28 - fxor %%f14, %%f30, %%f30 - stda %%f16, [%%o4] %3 - ldda [%%o3 + 64] %%asi, %%f48 - ldda [%%o4 + 128] %%asi, %%f0 - fxor %%f32, %%f48, %%f48 - fxor %%f34, %%f50, %%f50 - add %%o4, 128, %%o4 - fxor %%f36, %%f52, %%f52 - add %%o3, 128, %%o3 - fxor %%f38, %%f54, %%f54 - subcc %%g5, 128, %%g5 - fxor %%f40, %%f56, %%f56 - fxor %%f42, %%f58, %%f58 - fxor %%f44, %%f60, %%f60 - fxor %%f46, %%f62, %%f62 - stda %%f48, [%%o4 - 64] %%asi - bne,pt %%xcc, 2b - ldda [%%o3] %3, %%f16 - - ldda [%%o4 + 64] %%asi, %%f32 - fxor %%f0, %%f16, %%f16 - fxor %%f2, %%f18, %%f18 - fxor %%f4, %%f20, %%f20 - fxor %%f6, %%f22, %%f22 - fxor %%f8, %%f24, %%f24 - fxor %%f10, %%f26, %%f26 - fxor %%f12, %%f28, %%f28 - fxor %%f14, %%f30, %%f30 - stda %%f16, [%%o4] %3 - ldda [%%o3 + 64] %%asi, %%f48 - membar #Sync - fxor %%f32, %%f48, %%f48 - fxor %%f34, %%f50, %%f50 - fxor %%f36, %%f52, %%f52 - fxor %%f38, %%f54, %%f54 - fxor %%f40, %%f56, %%f56 - fxor %%f42, %%f58, %%f58 - fxor %%f44, %%f60, %%f60 - fxor %%f46, %%f62, %%f62 - stda %%f48, [%%o4 + 64] %%asi - membar #Sync|#StoreStore|#StoreLoad - wr %%g0, 0, %%fprs - retl - wr %%g1, %%g0, %%asi - -13: ldx [%%o1 + 16], %%o2 - ldx [%%o2 + %0], %%o2 - -3: ldda [%%o2] %3, %%f32 - fxor %%f0, %%f16, %%f48 - fxor %%f2, %%f18, %%f50 - add %%o4, 64, %%o4 - fxor %%f4, %%f20, %%f52 - fxor %%f6, %%f22, %%f54 - add %%o3, 64, %%o3 - fxor %%f8, %%f24, %%f56 - fxor %%f10, %%f26, %%f58 - fxor %%f12, %%f28, %%f60 - fxor %%f14, %%f30, %%f62 - ldda [%%o4] %3, %%f0 - fxor %%f48, %%f32, %%f48 - fxor %%f50, %%f34, %%f50 - fxor %%f52, %%f36, %%f52 - fxor %%f54, %%f38, %%f54 - add %%o2, 64, %%o2 - fxor %%f56, %%f40, %%f56 - fxor %%f58, %%f42, %%f58 - subcc %%g5, 64, %%g5 - fxor %%f60, %%f44, %%f60 - fxor %%f62, %%f46, %%f62 - stda %%f48, [%%o4 + %%g1] %3 - bne,pt %%xcc, 3b - ldda [%%o3] %3, %%f16 - - ldda [%%o2] %3, %%f32 - fxor %%f0, %%f16, %%f48 - fxor %%f2, %%f18, %%f50 - fxor %%f4, %%f20, %%f52 - fxor %%f6, %%f22, %%f54 - fxor %%f8, %%f24, %%f56 - fxor %%f10, %%f26, %%f58 - fxor %%f12, %%f28, %%f60 - fxor %%f14, %%f30, %%f62 - membar #Sync - fxor %%f48, %%f32, %%f48 - fxor %%f50, %%f34, %%f50 - fxor %%f52, %%f36, %%f52 - fxor %%f54, %%f38, %%f54 - fxor %%f56, %%f40, %%f56 - fxor %%f58, %%f42, %%f58 - fxor %%f60, %%f44, %%f60 - fxor %%f62, %%f46, %%f62 - stda %%f48, [%%o4] %3 - membar #Sync|#StoreStore|#StoreLoad - retl - wr %%g0, 0, %%fprs - -10: cmp %%o0, 5 - be,pt %%xcc, 15f - mov -64, %%g1 - -14: ldx [%%o1 + 16], %%o2 - ldx [%%o1 + 24], %%o0 - ldx [%%o2 + %0], %%o2 - ldx [%%o0 + %0], %%o0 - -4: ldda [%%o2] %3, %%f32 - fxor %%f0, %%f16, %%f16 - fxor %%f2, %%f18, %%f18 - add %%o4, 64, %%o4 - fxor %%f4, %%f20, %%f20 - fxor %%f6, %%f22, %%f22 - add %%o3, 64, %%o3 - fxor %%f8, %%f24, %%f24 - fxor %%f10, %%f26, %%f26 - fxor %%f12, %%f28, %%f28 - fxor %%f14, %%f30, %%f30 - ldda [%%o0] %3, %%f48 - fxor %%f16, %%f32, %%f32 - fxor %%f18, %%f34, %%f34 - fxor %%f20, %%f36, %%f36 - fxor %%f22, %%f38, %%f38 - add %%o2, 64, %%o2 - fxor %%f24, %%f40, %%f40 - fxor %%f26, %%f42, %%f42 - fxor %%f28, %%f44, %%f44 - fxor %%f30, %%f46, %%f46 - ldda [%%o4] %3, %%f0 - fxor %%f32, %%f48, %%f48 - fxor %%f34, %%f50, %%f50 - fxor %%f36, %%f52, %%f52 - add %%o0, 64, %%o0 - fxor %%f38, %%f54, %%f54 - fxor %%f40, %%f56, %%f56 - fxor %%f42, %%f58, %%f58 - subcc %%g5, 64, %%g5 - fxor %%f44, %%f60, %%f60 - fxor %%f46, %%f62, %%f62 - stda %%f48, [%%o4 + %%g1] %3 - bne,pt %%xcc, 4b - ldda [%%o3] %3, %%f16 - - ldda [%%o2] %3, %%f32 - fxor %%f0, %%f16, %%f16 - fxor %%f2, %%f18, %%f18 - fxor %%f4, %%f20, %%f20 - fxor %%f6, %%f22, %%f22 - fxor %%f8, %%f24, %%f24 - fxor %%f10, %%f26, %%f26 - fxor %%f12, %%f28, %%f28 - fxor %%f14, %%f30, %%f30 - ldda [%%o0] %3, %%f48 - fxor %%f16, %%f32, %%f32 - fxor %%f18, %%f34, %%f34 - fxor %%f20, %%f36, %%f36 - fxor %%f22, %%f38, %%f38 - fxor %%f24, %%f40, %%f40 - fxor %%f26, %%f42, %%f42 - fxor %%f28, %%f44, %%f44 - fxor %%f30, %%f46, %%f46 - membar #Sync - fxor %%f32, %%f48, %%f48 - fxor %%f34, %%f50, %%f50 - fxor %%f36, %%f52, %%f52 - fxor %%f38, %%f54, %%f54 - fxor %%f40, %%f56, %%f56 - fxor %%f42, %%f58, %%f58 - fxor %%f44, %%f60, %%f60 - fxor %%f46, %%f62, %%f62 - stda %%f48, [%%o4] %3 - membar #Sync|#StoreStore|#StoreLoad - retl - wr %%g0, 0, %%fprs - -15: ldx [%%o1 + 16], %%o2 - ldx [%%o1 + 24], %%o0 - ldx [%%o1 + 32], %%o1 - ldx [%%o2 + %0], %%o2 - ldx [%%o0 + %0], %%o0 - ldx [%%o1 + %0], %%o1 - -5: ldda [%%o2] %3, %%f32 - fxor %%f0, %%f16, %%f48 - fxor %%f2, %%f18, %%f50 - add %%o4, 64, %%o4 - fxor %%f4, %%f20, %%f52 - fxor %%f6, %%f22, %%f54 - add %%o3, 64, %%o3 - fxor %%f8, %%f24, %%f56 - fxor %%f10, %%f26, %%f58 - fxor %%f12, %%f28, %%f60 - fxor %%f14, %%f30, %%f62 - ldda [%%o0] %3, %%f16 - fxor %%f48, %%f32, %%f48 - fxor %%f50, %%f34, %%f50 - fxor %%f52, %%f36, %%f52 - fxor %%f54, %%f38, %%f54 - add %%o2, 64, %%o2 - fxor %%f56, %%f40, %%f56 - fxor %%f58, %%f42, %%f58 - fxor %%f60, %%f44, %%f60 - fxor %%f62, %%f46, %%f62 - ldda [%%o1] %3, %%f32 - fxor %%f48, %%f16, %%f48 - fxor %%f50, %%f18, %%f50 - add %%o0, 64, %%o0 - fxor %%f52, %%f20, %%f52 - fxor %%f54, %%f22, %%f54 - add %%o1, 64, %%o1 - fxor %%f56, %%f24, %%f56 - fxor %%f58, %%f26, %%f58 - fxor %%f60, %%f28, %%f60 - fxor %%f62, %%f30, %%f62 - ldda [%%o4] %3, %%f0 - fxor %%f48, %%f32, %%f48 - fxor %%f50, %%f34, %%f50 - fxor %%f52, %%f36, %%f52 - fxor %%f54, %%f38, %%f54 - fxor %%f56, %%f40, %%f56 - fxor %%f58, %%f42, %%f58 - subcc %%g5, 64, %%g5 - fxor %%f60, %%f44, %%f60 - fxor %%f62, %%f46, %%f62 - stda %%f48, [%%o4 + %%g1] %3 - bne,pt %%xcc, 5b - ldda [%%o3] %3, %%f16 - - ldda [%%o2] %3, %%f32 - fxor %%f0, %%f16, %%f48 - fxor %%f2, %%f18, %%f50 - fxor %%f4, %%f20, %%f52 - fxor %%f6, %%f22, %%f54 - fxor %%f8, %%f24, %%f56 - fxor %%f10, %%f26, %%f58 - fxor %%f12, %%f28, %%f60 - fxor %%f14, %%f30, %%f62 - ldda [%%o0] %3, %%f16 - fxor %%f48, %%f32, %%f48 - fxor %%f50, %%f34, %%f50 - fxor %%f52, %%f36, %%f52 - fxor %%f54, %%f38, %%f54 - fxor %%f56, %%f40, %%f56 - fxor %%f58, %%f42, %%f58 - fxor %%f60, %%f44, %%f60 - fxor %%f62, %%f46, %%f62 - ldda [%%o1] %3, %%f32 - fxor %%f48, %%f16, %%f48 - fxor %%f50, %%f18, %%f50 - fxor %%f52, %%f20, %%f52 - fxor %%f54, %%f22, %%f54 - fxor %%f56, %%f24, %%f56 - fxor %%f58, %%f26, %%f58 - fxor %%f60, %%f28, %%f60 - fxor %%f62, %%f30, %%f62 - membar #Sync - fxor %%f48, %%f32, %%f48 - fxor %%f50, %%f34, %%f50 - fxor %%f52, %%f36, %%f52 - fxor %%f54, %%f38, %%f54 - fxor %%f56, %%f40, %%f56 - fxor %%f58, %%f42, %%f58 - fxor %%f60, %%f44, %%f60 - fxor %%f62, %%f46, %%f62 - stda %%f48, [%%o4] %3 - membar #Sync|#StoreStore|#StoreLoad - retl - wr %%g0, 0, %%fprs - " : : - "i" (&((struct buffer_head *)0)->b_data), - "i" (&((struct buffer_head *)0)->b_size), - "i" (FPRS_FEF|FPRS_DU), "i" (ASI_BLK_P), - "i" (FPRS_FEF), "i" (VISenter)); -} -#endif /* __sparc_v9__ */ - -#if defined(__sparc__) && !defined(__sparc_v9__) -/* - * High speed xor_block operation for RAID4/5 utilizing the - * ldd/std SPARC instructions. - * - * Copyright (C) 1999 Jakub Jelinek (jj@ultra.linux.cz) - * - */ - -XORBLOCK_TEMPLATE(SPARC) -{ - int size = bh_ptr[0]->b_size; - int lines = size / (sizeof (long)) / 8, i; - long *destp = (long *) bh_ptr[0]->b_data; - long *source1 = (long *) bh_ptr[1]->b_data; - long *source2, *source3, *source4; - - switch (count) { - case 2: - for (i = lines; i > 0; i--) { - __asm__ __volatile__(" - ldd [%0 + 0x00], %%g2 - ldd [%0 + 0x08], %%g4 - ldd [%0 + 0x10], %%o0 - ldd [%0 + 0x18], %%o2 - ldd [%1 + 0x00], %%o4 - ldd [%1 + 0x08], %%l0 - ldd [%1 + 0x10], %%l2 - ldd [%1 + 0x18], %%l4 - xor %%g2, %%o4, %%g2 - xor %%g3, %%o5, %%g3 - xor %%g4, %%l0, %%g4 - xor %%g5, %%l1, %%g5 - xor %%o0, %%l2, %%o0 - xor %%o1, %%l3, %%o1 - xor %%o2, %%l4, %%o2 - xor %%o3, %%l5, %%o3 - std %%g2, [%0 + 0x00] - std %%g4, [%0 + 0x08] - std %%o0, [%0 + 0x10] - std %%o2, [%0 + 0x18] - " : : "r" (destp), "r" (source1) : "g2", "g3", "g4", "g5", "o0", - "o1", "o2", "o3", "o4", "o5", "l0", "l1", "l2", "l3", "l4", "l5"); - destp += 8; - source1 += 8; - } - break; - case 3: - source2 = (long *) bh_ptr[2]->b_data; - for (i = lines; i > 0; i--) { - __asm__ __volatile__(" - ldd [%0 + 0x00], %%g2 - ldd [%0 + 0x08], %%g4 - ldd [%0 + 0x10], %%o0 - ldd [%0 + 0x18], %%o2 - ldd [%1 + 0x00], %%o4 - ldd [%1 + 0x08], %%l0 - ldd [%1 + 0x10], %%l2 - ldd [%1 + 0x18], %%l4 - xor %%g2, %%o4, %%g2 - xor %%g3, %%o5, %%g3 - ldd [%2 + 0x00], %%o4 - xor %%g4, %%l0, %%g4 - xor %%g5, %%l1, %%g5 - ldd [%2 + 0x08], %%l0 - xor %%o0, %%l2, %%o0 - xor %%o1, %%l3, %%o1 - ldd [%2 + 0x10], %%l2 - xor %%o2, %%l4, %%o2 - xor %%o3, %%l5, %%o3 - ldd [%2 + 0x18], %%l4 - xor %%g2, %%o4, %%g2 - xor %%g3, %%o5, %%g3 - xor %%g4, %%l0, %%g4 - xor %%g5, %%l1, %%g5 - xor %%o0, %%l2, %%o0 - xor %%o1, %%l3, %%o1 - xor %%o2, %%l4, %%o2 - xor %%o3, %%l5, %%o3 - std %%g2, [%0 + 0x00] - std %%g4, [%0 + 0x08] - std %%o0, [%0 + 0x10] - std %%o2, [%0 + 0x18] - " : : "r" (destp), "r" (source1), "r" (source2) - : "g2", "g3", "g4", "g5", "o0", "o1", "o2", "o3", "o4", "o5", - "l0", "l1", "l2", "l3", "l4", "l5"); - destp += 8; - source1 += 8; - source2 += 8; - } - break; - case 4: - source2 = (long *) bh_ptr[2]->b_data; - source3 = (long *) bh_ptr[3]->b_data; - for (i = lines; i > 0; i--) { - __asm__ __volatile__(" - ldd [%0 + 0x00], %%g2 - ldd [%0 + 0x08], %%g4 - ldd [%0 + 0x10], %%o0 - ldd [%0 + 0x18], %%o2 - ldd [%1 + 0x00], %%o4 - ldd [%1 + 0x08], %%l0 - ldd [%1 + 0x10], %%l2 - ldd [%1 + 0x18], %%l4 - xor %%g2, %%o4, %%g2 - xor %%g3, %%o5, %%g3 - ldd [%2 + 0x00], %%o4 - xor %%g4, %%l0, %%g4 - xor %%g5, %%l1, %%g5 - ldd [%2 + 0x08], %%l0 - xor %%o0, %%l2, %%o0 - xor %%o1, %%l3, %%o1 - ldd [%2 + 0x10], %%l2 - xor %%o2, %%l4, %%o2 - xor %%o3, %%l5, %%o3 - ldd [%2 + 0x18], %%l4 - xor %%g2, %%o4, %%g2 - xor %%g3, %%o5, %%g3 - ldd [%3 + 0x00], %%o4 - xor %%g4, %%l0, %%g4 - xor %%g5, %%l1, %%g5 - ldd [%3 + 0x08], %%l0 - xor %%o0, %%l2, %%o0 - xor %%o1, %%l3, %%o1 - ldd [%3 + 0x10], %%l2 - xor %%o2, %%l4, %%o2 - xor %%o3, %%l5, %%o3 - ldd [%3 + 0x18], %%l4 - xor %%g2, %%o4, %%g2 - xor %%g3, %%o5, %%g3 - xor %%g4, %%l0, %%g4 - xor %%g5, %%l1, %%g5 - xor %%o0, %%l2, %%o0 - xor %%o1, %%l3, %%o1 - xor %%o2, %%l4, %%o2 - xor %%o3, %%l5, %%o3 - std %%g2, [%0 + 0x00] - std %%g4, [%0 + 0x08] - std %%o0, [%0 + 0x10] - std %%o2, [%0 + 0x18] - " : : "r" (destp), "r" (source1), "r" (source2), "r" (source3) - : "g2", "g3", "g4", "g5", "o0", "o1", "o2", "o3", "o4", "o5", - "l0", "l1", "l2", "l3", "l4", "l5"); - destp += 8; - source1 += 8; - source2 += 8; - source3 += 8; - } - break; - case 5: - source2 = (long *) bh_ptr[2]->b_data; - source3 = (long *) bh_ptr[3]->b_data; - source4 = (long *) bh_ptr[4]->b_data; - for (i = lines; i > 0; i--) { - __asm__ __volatile__(" - ldd [%0 + 0x00], %%g2 - ldd [%0 + 0x08], %%g4 - ldd [%0 + 0x10], %%o0 - ldd [%0 + 0x18], %%o2 - ldd [%1 + 0x00], %%o4 - ldd [%1 + 0x08], %%l0 - ldd [%1 + 0x10], %%l2 - ldd [%1 + 0x18], %%l4 - xor %%g2, %%o4, %%g2 - xor %%g3, %%o5, %%g3 - ldd [%2 + 0x00], %%o4 - xor %%g4, %%l0, %%g4 - xor %%g5, %%l1, %%g5 - ldd [%2 + 0x08], %%l0 - xor %%o0, %%l2, %%o0 - xor %%o1, %%l3, %%o1 - ldd [%2 + 0x10], %%l2 - xor %%o2, %%l4, %%o2 - xor %%o3, %%l5, %%o3 - ldd [%2 + 0x18], %%l4 - xor %%g2, %%o4, %%g2 - xor %%g3, %%o5, %%g3 - ldd [%3 + 0x00], %%o4 - xor %%g4, %%l0, %%g4 - xor %%g5, %%l1, %%g5 - ldd [%3 + 0x08], %%l0 - xor %%o0, %%l2, %%o0 - xor %%o1, %%l3, %%o1 - ldd [%3 + 0x10], %%l2 - xor %%o2, %%l4, %%o2 - xor %%o3, %%l5, %%o3 - ldd [%3 + 0x18], %%l4 - xor %%g2, %%o4, %%g2 - xor %%g3, %%o5, %%g3 - ldd [%4 + 0x00], %%o4 - xor %%g4, %%l0, %%g4 - xor %%g5, %%l1, %%g5 - ldd [%4 + 0x08], %%l0 - xor %%o0, %%l2, %%o0 - xor %%o1, %%l3, %%o1 - ldd [%4 + 0x10], %%l2 - xor %%o2, %%l4, %%o2 - xor %%o3, %%l5, %%o3 - ldd [%4 + 0x18], %%l4 - xor %%g2, %%o4, %%g2 - xor %%g3, %%o5, %%g3 - xor %%g4, %%l0, %%g4 - xor %%g5, %%l1, %%g5 - xor %%o0, %%l2, %%o0 - xor %%o1, %%l3, %%o1 - xor %%o2, %%l4, %%o2 - xor %%o3, %%l5, %%o3 - std %%g2, [%0 + 0x00] - std %%g4, [%0 + 0x08] - std %%o0, [%0 + 0x10] - std %%o2, [%0 + 0x18] - " : : "r" (destp), "r" (source1), "r" (source2), "r" (source3), "r" (source4) - : "g2", "g3", "g4", "g5", "o0", "o1", "o2", "o3", "o4", "o5", - "l0", "l1", "l2", "l3", "l4", "l5"); - destp += 8; - source1 += 8; - source2 += 8; - source3 += 8; - source4 += 8; - } - break; - } -} -#endif /* __sparc_v[78]__ */ - -#ifdef __alpha__ -/* - * High speed xor_block operation for RAID4/5 pipelined for Alpha EV5. - * There is a second version using EV6 prefetch instructions. - * - * Copyright (C) 2000 Richard Henderson (rth@redhat.com) - */ - -XORBLOCK_TEMPLATE(alpha) -{ - long lines = bh_ptr[0]->b_size / sizeof (long) / 8; - long *d = (long *) bh_ptr[0]->b_data; - long *s1 = (long *) bh_ptr[1]->b_data; - long *s2, *s3, *s4; - - if (count == 2) goto two_blocks; - - s2 = (long *) bh_ptr[2]->b_data; - if (count == 3) goto three_blocks; - - s3 = (long *) bh_ptr[3]->b_data; - if (count == 4) goto four_blocks; - - s4 = (long *) bh_ptr[4]->b_data; - goto five_blocks; - -two_blocks: -asm volatile (" - .align 4 -2: - ldq $0,0(%0) - ldq $1,0(%1) - ldq $2,8(%0) - ldq $3,8(%1) - - ldq $4,16(%0) - ldq $5,16(%1) - ldq $6,24(%0) - ldq $7,24(%1) - - ldq $16,32(%0) - ldq $17,32(%1) - ldq $18,40(%0) - ldq $19,40(%1) - - ldq $20,48(%0) - ldq $21,48(%1) - ldq $22,56(%0) - xor $0,$1,$0 # 7 cycles from $1 load - - ldq $23,56(%1) - xor $2,$3,$2 - stq $0,0(%0) - xor $4,$5,$4 - - stq $2,8(%0) - xor $6,$7,$6 - stq $4,16(%0) - xor $16,$17,$16 - - stq $6,24(%0) - xor $18,$19,$18 - stq $16,32(%0) - xor $20,$21,$20 - - stq $18,40(%0) - xor $22,$23,$22 - stq $20,48(%0) - subq %2,1,%2 - - stq $22,56(%0) - addq %0,64,%0 - addq %1,64,%1 - bgt %2,2b" - : "=r"(d), "=r"(s1), "=r"(lines) - : "0"(d), "1"(s1), "2"(lines) - : "memory", "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", - "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23"); - return; - -three_blocks: -asm volatile (" - .align 4 -3: - ldq $0,0(%0) - ldq $1,0(%1) - ldq $2,0(%2) - ldq $3,8(%0) - - ldq $4,8(%1) - ldq $6,16(%0) - ldq $7,16(%1) - ldq $17,24(%0) - - ldq $18,24(%1) - ldq $20,32(%0) - ldq $21,32(%1) - ldq $5,8(%2) - - ldq $16,16(%2) - ldq $19,24(%2) - ldq $22,32(%2) - nop - - xor $0,$1,$1 # 8 cycles from $0 load - xor $3,$4,$4 # 6 cycles from $4 load - xor $6,$7,$7 # 6 cycles from $7 load - xor $17,$18,$18 # 5 cycles from $18 load - - xor $1,$2,$2 # 9 cycles from $2 load - xor $20,$21,$21 # 5 cycles from $21 load - stq $2,0(%0) - xor $4,$5,$5 # 6 cycles from $5 load - - stq $5,8(%0) - xor $7,$16,$16 # 7 cycles from $16 load - stq $16,16(%0) - xor $18,$19,$19 # 7 cycles from $19 load - - stq $19,24(%0) - xor $21,$22,$22 # 7 cycles from $22 load - stq $22,32(%0) - nop - - ldq $0,40(%0) - ldq $1,40(%1) - ldq $3,48(%0) - ldq $4,48(%1) - - ldq $6,56(%0) - ldq $7,56(%1) - ldq $2,40(%2) - ldq $5,48(%2) - - ldq $16,56(%2) - xor $0,$1,$1 # 4 cycles from $1 load - xor $3,$4,$4 # 5 cycles from $4 load - xor $6,$7,$7 # 5 cycles from $7 load - - xor $1,$2,$2 # 4 cycles from $2 load - xor $4,$5,$5 # 5 cycles from $5 load - stq $2,40(%0) - xor $7,$16,$16 # 4 cycles from $16 load - - stq $5,48(%0) - subq %3,1,%3 - stq $16,56(%0) - addq %2,64,%2 - - addq %1,64,%1 - addq %0,64,%0 - bgt %3,3b" - : "=r"(d), "=r"(s1), "=r"(s2), "=r"(lines) - : "0"(d), "1"(s1), "2"(s2), "3"(lines) - : "memory", "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", - "$16", "$17", "$18", "$19", "$20", "$21", "$22"); - return; - -four_blocks: -asm volatile (" - .align 4 -4: - ldq $0,0(%0) - ldq $1,0(%1) - ldq $2,0(%2) - ldq $3,0(%3) - - ldq $4,8(%0) - ldq $5,8(%1) - ldq $6,8(%2) - ldq $7,8(%3) - - ldq $16,16(%0) - ldq $17,16(%1) - ldq $18,16(%2) - ldq $19,16(%3) - - ldq $20,24(%0) - xor $0,$1,$1 # 6 cycles from $1 load - ldq $21,24(%1) - xor $2,$3,$3 # 6 cycles from $3 load - - ldq $0,24(%2) - xor $1,$3,$3 - ldq $1,24(%3) - xor $4,$5,$5 # 7 cycles from $5 load - - stq $3,0(%0) - xor $6,$7,$7 - xor $16,$17,$17 # 7 cycles from $17 load - xor $5,$7,$7 - - stq $7,8(%0) - xor $18,$19,$19 # 7 cycles from $19 load - ldq $2,32(%0) - xor $17,$19,$19 - - ldq $3,32(%1) - ldq $4,32(%2) - ldq $5,32(%3) - xor $20,$21,$21 # 8 cycles from $21 load - - ldq $6,40(%0) - ldq $7,40(%1) - ldq $16,40(%2) - ldq $17,40(%3) - - stq $19,16(%0) - xor $0,$1,$1 # 9 cycles from $1 load - xor $2,$3,$3 # 5 cycles from $3 load - xor $21,$1,$1 - - ldq $18,48(%0) - xor $4,$5,$5 # 5 cycles from $5 load - ldq $19,48(%1) - xor $3,$5,$5 - - ldq $20,48(%2) - ldq $21,48(%3) - ldq $0,56(%0) - ldq $1,56(%1) - - ldq $2,56(%2) - xor $6,$7,$7 # 8 cycles from $6 load - ldq $3,56(%3) - xor $16,$17,$17 # 8 cycles from $17 load - - xor $7,$17,$17 - xor $18,$19,$19 # 5 cycles from $19 load - xor $20,$21,$21 # 5 cycles from $21 load - xor $19,$21,$21 - - stq $1,24(%0) - xor $0,$1,$1 # 5 cycles from $1 load - stq $5,32(%0) - xor $2,$3,$3 # 4 cycles from $3 load - - stq $17,40(%0) - xor $1,$3,$3 - stq $21,48(%0) - subq %4,1,%4 - - stq $3,56(%0) - addq %3,64,%3 - addq %2,64,%2 - addq %1,64,%1 - - addq %0,64,%0 - bgt %4,4b" - : "=r"(d), "=r"(s1), "=r"(s2), "=r"(s3), "=r"(lines) - : "0"(d), "1"(s1), "2"(s2), "3"(s3), "4"(lines) - : "memory", "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", - "$16", "$17", "$18", "$19", "$20", "$21"); - return; - -five_blocks: -asm volatile (" - ldq %0,0(%6) - ldq %1,8(%6) - ldq %2,16(%6) - ldq %3,24(%6) - ldq %4,32(%6) - ldq %0,%7(%0) - ldq %1,%7(%1) - ldq %2,%7(%2) - ldq %3,%7(%3) - ldq %4,%7(%4) - .align 4 -5: - ldq $0,0(%0) - ldq $1,0(%1) - ldq $2,0(%2) - ldq $3,0(%3) - - ldq $4,0(%4) - ldq $5,8(%0) - ldq $6,8(%1) - ldq $7,8(%2) - - ldq $16,8(%3) - ldq $17,8(%4) - ldq $18,16(%0) - ldq $19,16(%1) - - ldq $20,16(%2) - xor $0,$1,$1 # 6 cycles from $1 load - ldq $21,16(%3) - xor $2,$3,$3 # 6 cycles from $3 load - - ldq $0,16(%4) - xor $1,$3,$3 - ldq $1,24(%0) - xor $3,$4,$4 # 7 cycles from $4 load - - stq $4,0(%0) - xor $5,$6,$6 # 7 cycles from $6 load - xor $7,$16,$16 # 7 cycles from $16 load - xor $6,$17,$17 # 7 cycles from $17 load - - ldq $2,24(%1) - xor $16,$17,$17 - ldq $3,24(%2) - xor $18,$19,$19 # 8 cycles from $19 load - - stq $17,8(%0) - xor $19,$20,$20 # 8 cycles from $20 load - ldq $4,24(%3) - xor $21,$0,$0 # 7 cycles from $0 load - - ldq $5,24(%4) - xor $20,$0,$0 - ldq $6,32(%0) - ldq $7,32(%1) - - stq $0,16(%0) - xor $1,$2,$2 # 6 cycles from $2 load - ldq $16,32(%2) - xor $3,$4,$4 # 4 cycles from $4 load - - ldq $17,32(%3) - xor $2,$4,$4 - ldq $18,32(%4) - ldq $19,40(%0) - - ldq $20,40(%1) - ldq $21,40(%2) - ldq $0,40(%3) - xor $4,$5,$5 # 7 cycles from $5 load - - stq $5,24(%0) - xor $6,$7,$7 # 7 cycles from $7 load - ldq $1,40(%4) - ldq $2,48(%0) - - ldq $3,48(%1) - xor $7,$16,$16 # 7 cycles from $16 load - ldq $4,48(%2) - xor $17,$18,$18 # 6 cycles from $18 load - - ldq $5,48(%3) - xor $16,$18,$18 - ldq $6,48(%4) - xor $19,$20,$20 # 7 cycles from $20 load - - stq $18,32(%0) - xor $20,$21,$21 # 8 cycles from $21 load - ldq $7,56(%0) - xor $0,$1,$1 # 6 cycles from $1 load - - ldq $16,56(%1) - ldq $17,56(%2) - ldq $18,56(%3) - ldq $19,56(%4) - - xor $21,$1,$1 - xor $2,$3,$3 # 9 cycles from $3 load - xor $3,$4,$4 # 9 cycles from $4 load - xor $5,$6,$6 # 8 cycles from $6 load - - unop - xor $4,$6,$6 - xor $7,$16,$16 # 7 cycles from $16 load - xor $17,$18,$18 # 6 cycles from $18 load - - stq $6,48(%0) - xor $16,$18,$18 - subq %5,1,%5 - xor $18,$19,$19 # 8 cycles from $19 load - - stq $19,56(%0) - addq %4,64,%4 - addq %3,64,%3 - addq %2,64,%2 - - addq %1,64,%1 - addq %0,64,%0 - bgt %5,5b" - : "=&r"(d), "=&r"(s1), "=&r"(s2), "=&r"(s3), "=r"(s4), "=r"(lines) - /* ARG! We've run out of asm arguments! We've got to reload - all those pointers we just loaded. */ - : "r"(bh_ptr), "i" (&((struct buffer_head *)0)->b_data), "5"(lines) - : "memory", "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", - "$16", "$17", "$18", "$19", "$20", "$21"); - return; -} - -#define prefetch(base, ofs) \ - asm("ldq $31,%2(%0)" : "=r"(base) : "0"(base), "i"(ofs)) - -XORBLOCK_TEMPLATE(alpha_prefetch) -{ - long lines = bh_ptr[0]->b_size / sizeof (long) / 8; - long *d = (long *) bh_ptr[0]->b_data; - long *s1 = (long *) bh_ptr[1]->b_data; - long *s2, *s3, *s4; - long p; - - p = count == 2; - prefetch(d, 0); - prefetch(s1, 0); - prefetch(d, 64); - prefetch(s1, 64); - prefetch(d, 128); - prefetch(s1, 128); - prefetch(d, 192); - prefetch(s1, 192); - if (p) goto two_blocks; - - s2 = (long *) bh_ptr[2]->b_data; - p = count == 3; - prefetch(s2, 0); - prefetch(s2, 64); - prefetch(s2, 128); - prefetch(s2, 192); - if (p) goto three_blocks; - - s3 = (long *) bh_ptr[3]->b_data; - p = count == 4; - prefetch(s3, 0); - prefetch(s3, 64); - prefetch(s3, 128); - prefetch(s3, 192); - if (p) goto four_blocks; - - s4 = (long *) bh_ptr[4]->b_data; - prefetch(s4, 0); - prefetch(s4, 64); - prefetch(s4, 128); - prefetch(s4, 192); - goto five_blocks; - -two_blocks: -asm volatile (" - .align 4 -2: - ldq $0,0(%0) - ldq $1,0(%1) - ldq $2,8(%0) - ldq $3,8(%1) - - ldq $4,16(%0) - ldq $5,16(%1) - ldq $6,24(%0) - ldq $7,24(%1) - - ldq $16,32(%0) - ldq $17,32(%1) - ldq $18,40(%0) - ldq $19,40(%1) - - ldq $20,48(%0) - ldq $21,48(%1) - ldq $22,56(%0) - ldq $23,56(%1) - - ldq $31,256(%0) - xor $0,$1,$0 # 8 cycles from $1 load - ldq $31,256(%1) - xor $2,$3,$2 - - stq $0,0(%0) - xor $4,$5,$4 - stq $2,8(%0) - xor $6,$7,$6 - - stq $4,16(%0) - xor $16,$17,$16 - stq $6,24(%0) - xor $18,$19,$18 - - stq $16,32(%0) - xor $20,$21,$20 - stq $18,40(%0) - xor $22,$23,$22 - - stq $20,48(%0) - subq %2,1,%2 - stq $22,56(%0) - addq %0,64,%0 - - addq %1,64,%1 - bgt %2,2b" - : "=r"(d), "=r"(s1), "=r"(lines) - : "0"(d), "1"(s1), "2"(lines) - : "memory", "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", - "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23"); - return; - -three_blocks: -asm volatile (" - .align 4 -3: - ldq $0,0(%0) - ldq $1,0(%1) - ldq $2,0(%2) - ldq $3,8(%0) - - ldq $4,8(%1) - ldq $6,16(%0) - ldq $7,16(%1) - ldq $17,24(%0) - - ldq $18,24(%1) - ldq $20,32(%0) - ldq $21,32(%1) - ldq $5,8(%2) - - ldq $16,16(%2) - ldq $19,24(%2) - ldq $22,32(%2) - nop - - xor $0,$1,$1 # 8 cycles from $0 load - xor $3,$4,$4 # 7 cycles from $4 load - xor $6,$7,$7 # 6 cycles from $7 load - xor $17,$18,$18 # 5 cycles from $18 load - - xor $1,$2,$2 # 9 cycles from $2 load - xor $20,$21,$21 # 5 cycles from $21 load - stq $2,0(%0) - xor $4,$5,$5 # 6 cycles from $5 load - - stq $5,8(%0) - xor $7,$16,$16 # 7 cycles from $16 load - stq $16,16(%0) - xor $18,$19,$19 # 7 cycles from $19 load - - stq $19,24(%0) - xor $21,$22,$22 # 7 cycles from $22 load - stq $22,32(%0) - nop - - ldq $0,40(%0) - ldq $1,40(%1) - ldq $3,48(%0) - ldq $4,48(%1) - - ldq $6,56(%0) - ldq $7,56(%1) - ldq $2,40(%2) - ldq $5,48(%2) - - ldq $16,56(%2) - ldq $31,256(%0) - ldq $31,256(%1) - ldq $31,256(%2) - - xor $0,$1,$1 # 6 cycles from $1 load - xor $3,$4,$4 # 5 cycles from $4 load - xor $6,$7,$7 # 5 cycles from $7 load - xor $1,$2,$2 # 4 cycles from $2 load - - xor $4,$5,$5 # 5 cycles from $5 load - xor $7,$16,$16 # 4 cycles from $16 load - stq $2,40(%0) - subq %3,1,%3 - - stq $5,48(%0) - addq %2,64,%2 - stq $16,56(%0) - addq %1,64,%1 - - addq %0,64,%0 - bgt %3,3b" - : "=r"(d), "=r"(s1), "=r"(s2), "=r"(lines) - : "0"(d), "1"(s1), "2"(s2), "3"(lines) - : "memory", "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", - "$16", "$17", "$18", "$19", "$20", "$21", "$22"); - return; - -four_blocks: -asm volatile (" - .align 4 -4: - ldq $0,0(%0) - ldq $1,0(%1) - ldq $2,0(%2) - ldq $3,0(%3) - - ldq $4,8(%0) - ldq $5,8(%1) - ldq $6,8(%2) - ldq $7,8(%3) - - ldq $16,16(%0) - ldq $17,16(%1) - ldq $18,16(%2) - ldq $19,16(%3) - - ldq $20,24(%0) - xor $0,$1,$1 # 6 cycles from $1 load - ldq $21,24(%1) - xor $2,$3,$3 # 6 cycles from $3 load - - ldq $0,24(%2) - xor $1,$3,$3 - ldq $1,24(%3) - xor $4,$5,$5 # 7 cycles from $5 load - - stq $3,0(%0) - xor $6,$7,$7 - xor $16,$17,$17 # 7 cycles from $17 load - xor $5,$7,$7 - - stq $7,8(%0) - xor $18,$19,$19 # 7 cycles from $19 load - ldq $2,32(%0) - xor $17,$19,$19 - - ldq $3,32(%1) - ldq $4,32(%2) - ldq $5,32(%3) - xor $20,$21,$21 # 8 cycles from $21 load - - ldq $6,40(%0) - ldq $7,40(%1) - ldq $16,40(%2) - ldq $17,40(%3) - - stq $19,16(%0) - xor $0,$1,$1 # 9 cycles from $1 load - xor $2,$3,$3 # 5 cycles from $3 load - xor $21,$1,$1 - - ldq $18,48(%0) - xor $4,$5,$5 # 5 cycles from $5 load - ldq $19,48(%1) - xor $3,$5,$5 - - ldq $20,48(%2) - ldq $21,48(%3) - ldq $0,56(%0) - ldq $1,56(%1) - - ldq $2,56(%2) - xor $6,$7,$7 # 8 cycles from $6 load - ldq $3,56(%3) - xor $16,$17,$17 # 8 cycles from $17 load - - ldq $31,256(%0) - xor $7,$17,$17 - ldq $31,256(%1) - xor $18,$19,$19 # 6 cycles from $19 load - - ldq $31,256(%2) - xor $20,$21,$21 # 6 cycles from $21 load - ldq $31,256(%3) - xor $19,$21,$21 - - stq $1,24(%0) - xor $0,$1,$1 # 7 cycles from $1 load - stq $5,32(%0) - xor $2,$3,$3 # 6 cycles from $3 load - - stq $17,40(%0) - xor $1,$3,$3 - stq $21,48(%0) - subq %4,1,%4 - - stq $3,56(%0) - addq %3,64,%3 - addq %2,64,%2 - addq %1,64,%1 - - addq %0,64,%0 - bgt %4,4b" - : "=r"(d), "=r"(s1), "=r"(s2), "=r"(s3), "=r"(lines) - : "0"(d), "1"(s1), "2"(s2), "3"(s3), "4"(lines) - : "memory", "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", - "$16", "$17", "$18", "$19", "$20", "$21"); - return; - -five_blocks: -asm volatile (" - ldq %0,0(%6) - ldq %1,8(%6) - ldq %2,16(%6) - ldq %3,24(%6) - ldq %4,32(%6) - ldq %0,%7(%0) - ldq %1,%7(%1) - ldq %2,%7(%2) - ldq %3,%7(%3) - ldq %4,%7(%4) - .align 4 -5: - ldq $0,0(%0) - ldq $1,0(%1) - ldq $2,0(%2) - ldq $3,0(%3) - - ldq $4,0(%4) - ldq $5,8(%0) - ldq $6,8(%1) - ldq $7,8(%2) - - ldq $16,8(%3) - ldq $17,8(%4) - ldq $18,16(%0) - ldq $19,16(%1) - - ldq $20,16(%2) - xor $0,$1,$1 # 6 cycles from $1 load - ldq $21,16(%3) - xor $2,$3,$3 # 6 cycles from $3 load - - ldq $0,16(%4) - xor $1,$3,$3 - ldq $1,24(%0) - xor $3,$4,$4 # 7 cycles from $4 load - - stq $4,0(%0) - xor $5,$6,$6 # 7 cycles from $6 load - xor $7,$16,$16 # 7 cycles from $16 load - xor $6,$17,$17 # 7 cycles from $17 load - - ldq $2,24(%1) - xor $16,$17,$17 - ldq $3,24(%2) - xor $18,$19,$19 # 8 cycles from $19 load - - stq $17,8(%0) - xor $19,$20,$20 # 8 cycles from $20 load - ldq $4,24(%3) - xor $21,$0,$0 # 7 cycles from $0 load - - ldq $5,24(%4) - xor $20,$0,$0 - ldq $6,32(%0) - ldq $7,32(%1) - - stq $0,16(%0) - xor $1,$2,$2 # 6 cycles from $2 load - ldq $16,32(%2) - xor $3,$4,$4 # 4 cycles from $4 load - - ldq $17,32(%3) - xor $2,$4,$4 - ldq $18,32(%4) - ldq $19,40(%0) - - ldq $20,40(%1) - ldq $21,40(%2) - ldq $0,40(%3) - xor $4,$5,$5 # 7 cycles from $5 load - - stq $5,24(%0) - xor $6,$7,$7 # 7 cycles from $7 load - ldq $1,40(%4) - ldq $2,48(%0) - - ldq $3,48(%1) - xor $7,$16,$16 # 7 cycles from $16 load - ldq $4,48(%2) - xor $17,$18,$18 # 6 cycles from $18 load - - ldq $5,48(%3) - xor $16,$18,$18 - ldq $6,48(%4) - xor $19,$20,$20 # 7 cycles from $20 load - - stq $18,32(%0) - xor $20,$21,$21 # 8 cycles from $21 load - ldq $7,56(%0) - xor $0,$1,$1 # 6 cycles from $1 load - - ldq $16,56(%1) - ldq $17,56(%2) - ldq $18,56(%3) - ldq $19,56(%4) - - ldq $31,256(%0) - xor $21,$1,$1 - ldq $31,256(%1) - xor $2,$3,$3 # 9 cycles from $3 load - - ldq $31,256(%2) - xor $3,$4,$4 # 9 cycles from $4 load - ldq $31,256(%3) - xor $5,$6,$6 # 8 cycles from $6 load - - ldq $31,256(%4) - xor $4,$6,$6 - xor $7,$16,$16 # 7 cycles from $16 load - xor $17,$18,$18 # 6 cycles from $18 load - - stq $6,48(%0) - xor $16,$18,$18 - subq %5,1,%5 - xor $18,$19,$19 # 8 cycles from $19 load - - stq $19,56(%0) - addq %4,64,%4 - addq %3,64,%3 - addq %2,64,%2 - - addq %1,64,%1 - addq %0,64,%0 - bgt %5,5b" - : "=&r"(d), "=&r"(s1), "=&r"(s2), "=&r"(s3), "=r"(s4), "=r"(lines) - /* ARG! We've run out of asm arguments! We've got to reload - all those pointers we just loaded. */ - : "r"(bh_ptr), "i" (&((struct buffer_head *)0)->b_data), "5"(lines) - : "memory", "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", - "$16", "$17", "$18", "$19", "$20", "$21"); - return; -} - -#undef prefetch - -#endif /* __alpha__ */ - -#ifndef __sparc_v9__ - -/* - * this one works reasonably on any x86 CPU - * (send me an assembly version for inclusion if you can make it faster) - * - * this one is just as fast as written in pure assembly on x86. - * the reason for this separate version is that the - * fast open-coded xor routine "32reg" produces suboptimal code - * on x86, due to lack of registers. - */ -XORBLOCK_TEMPLATE(8regs) -{ - int len = bh_ptr[0]->b_size; - long *destp = (long *) bh_ptr[0]->b_data; - long *source1, *source2, *source3, *source4; - long lines = len / (sizeof (long)) / 8, i; - - switch(count) { - case 2: - source1 = (long *) bh_ptr[1]->b_data; - for (i = lines; i > 0; i--) { - *(destp + 0) ^= *(source1 + 0); - *(destp + 1) ^= *(source1 + 1); - *(destp + 2) ^= *(source1 + 2); - *(destp + 3) ^= *(source1 + 3); - *(destp + 4) ^= *(source1 + 4); - *(destp + 5) ^= *(source1 + 5); - *(destp + 6) ^= *(source1 + 6); - *(destp + 7) ^= *(source1 + 7); - source1 += 8; - destp += 8; - } - break; - case 3: - source2 = (long *) bh_ptr[2]->b_data; - source1 = (long *) bh_ptr[1]->b_data; - for (i = lines; i > 0; i--) { - *(destp + 0) ^= *(source1 + 0); - *(destp + 0) ^= *(source2 + 0); - *(destp + 1) ^= *(source1 + 1); - *(destp + 1) ^= *(source2 + 1); - *(destp + 2) ^= *(source1 + 2); - *(destp + 2) ^= *(source2 + 2); - *(destp + 3) ^= *(source1 + 3); - *(destp + 3) ^= *(source2 + 3); - *(destp + 4) ^= *(source1 + 4); - *(destp + 4) ^= *(source2 + 4); - *(destp + 5) ^= *(source1 + 5); - *(destp + 5) ^= *(source2 + 5); - *(destp + 6) ^= *(source1 + 6); - *(destp + 6) ^= *(source2 + 6); - *(destp + 7) ^= *(source1 + 7); - *(destp + 7) ^= *(source2 + 7); - source1 += 8; - source2 += 8; - destp += 8; - } - break; - case 4: - source3 = (long *) bh_ptr[3]->b_data; - source2 = (long *) bh_ptr[2]->b_data; - source1 = (long *) bh_ptr[1]->b_data; - for (i = lines; i > 0; i--) { - *(destp + 0) ^= *(source1 + 0); - *(destp + 0) ^= *(source2 + 0); - *(destp + 0) ^= *(source3 + 0); - *(destp + 1) ^= *(source1 + 1); - *(destp + 1) ^= *(source2 + 1); - *(destp + 1) ^= *(source3 + 1); - *(destp + 2) ^= *(source1 + 2); - *(destp + 2) ^= *(source2 + 2); - *(destp + 2) ^= *(source3 + 2); - *(destp + 3) ^= *(source1 + 3); - *(destp + 3) ^= *(source2 + 3); - *(destp + 3) ^= *(source3 + 3); - *(destp + 4) ^= *(source1 + 4); - *(destp + 4) ^= *(source2 + 4); - *(destp + 4) ^= *(source3 + 4); - *(destp + 5) ^= *(source1 + 5); - *(destp + 5) ^= *(source2 + 5); - *(destp + 5) ^= *(source3 + 5); - *(destp + 6) ^= *(source1 + 6); - *(destp + 6) ^= *(source2 + 6); - *(destp + 6) ^= *(source3 + 6); - *(destp + 7) ^= *(source1 + 7); - *(destp + 7) ^= *(source2 + 7); - *(destp + 7) ^= *(source3 + 7); - source1 += 8; - source2 += 8; - source3 += 8; - destp += 8; - } - break; - case 5: - source4 = (long *) bh_ptr[4]->b_data; - source3 = (long *) bh_ptr[3]->b_data; - source2 = (long *) bh_ptr[2]->b_data; - source1 = (long *) bh_ptr[1]->b_data; - for (i = lines; i > 0; i--) { - *(destp + 0) ^= *(source1 + 0); - *(destp + 0) ^= *(source2 + 0); - *(destp + 0) ^= *(source3 + 0); - *(destp + 0) ^= *(source4 + 0); - *(destp + 1) ^= *(source1 + 1); - *(destp + 1) ^= *(source2 + 1); - *(destp + 1) ^= *(source3 + 1); - *(destp + 1) ^= *(source4 + 1); - *(destp + 2) ^= *(source1 + 2); - *(destp + 2) ^= *(source2 + 2); - *(destp + 2) ^= *(source3 + 2); - *(destp + 2) ^= *(source4 + 2); - *(destp + 3) ^= *(source1 + 3); - *(destp + 3) ^= *(source2 + 3); - *(destp + 3) ^= *(source3 + 3); - *(destp + 3) ^= *(source4 + 3); - *(destp + 4) ^= *(source1 + 4); - *(destp + 4) ^= *(source2 + 4); - *(destp + 4) ^= *(source3 + 4); - *(destp + 4) ^= *(source4 + 4); - *(destp + 5) ^= *(source1 + 5); - *(destp + 5) ^= *(source2 + 5); - *(destp + 5) ^= *(source3 + 5); - *(destp + 5) ^= *(source4 + 5); - *(destp + 6) ^= *(source1 + 6); - *(destp + 6) ^= *(source2 + 6); - *(destp + 6) ^= *(source3 + 6); - *(destp + 6) ^= *(source4 + 6); - *(destp + 7) ^= *(source1 + 7); - *(destp + 7) ^= *(source2 + 7); - *(destp + 7) ^= *(source3 + 7); - *(destp + 7) ^= *(source4 + 7); - source1 += 8; - source2 += 8; - source3 += 8; - source4 += 8; - destp += 8; - } - break; - } -} - -/* - * platform independent RAID5 checksum calculation, this should - * be very fast on any platform that has a decent amount of - * registers. (32 or more) - */ -XORBLOCK_TEMPLATE(32regs) -{ - int size = bh_ptr[0]->b_size; - int lines = size / (sizeof (long)) / 8, i; - long *destp = (long *) bh_ptr[0]->b_data; - long *source1, *source2, *source3, *source4; - - /* LOTS of registers available... - We do explicite loop-unrolling here for code which - favours RISC machines. In fact this is almoast direct - RISC assembly on Alpha and SPARC :-) */ - - - switch(count) { - case 2: - source1 = (long *) bh_ptr[1]->b_data; - for (i = lines; i > 0; i--) { - register long d0, d1, d2, d3, d4, d5, d6, d7; - d0 = destp[0]; /* Pull the stuff into registers */ - d1 = destp[1]; /* ... in bursts, if possible. */ - d2 = destp[2]; - d3 = destp[3]; - d4 = destp[4]; - d5 = destp[5]; - d6 = destp[6]; - d7 = destp[7]; - d0 ^= source1[0]; - d1 ^= source1[1]; - d2 ^= source1[2]; - d3 ^= source1[3]; - d4 ^= source1[4]; - d5 ^= source1[5]; - d6 ^= source1[6]; - d7 ^= source1[7]; - destp[0] = d0; /* Store the result (in burts) */ - destp[1] = d1; - destp[2] = d2; - destp[3] = d3; - destp[4] = d4; /* Store the result (in burts) */ - destp[5] = d5; - destp[6] = d6; - destp[7] = d7; - source1 += 8; - destp += 8; - } - break; - case 3: - source2 = (long *) bh_ptr[2]->b_data; - source1 = (long *) bh_ptr[1]->b_data; - for (i = lines; i > 0; i--) { - register long d0, d1, d2, d3, d4, d5, d6, d7; - d0 = destp[0]; /* Pull the stuff into registers */ - d1 = destp[1]; /* ... in bursts, if possible. */ - d2 = destp[2]; - d3 = destp[3]; - d4 = destp[4]; - d5 = destp[5]; - d6 = destp[6]; - d7 = destp[7]; - d0 ^= source1[0]; - d1 ^= source1[1]; - d2 ^= source1[2]; - d3 ^= source1[3]; - d4 ^= source1[4]; - d5 ^= source1[5]; - d6 ^= source1[6]; - d7 ^= source1[7]; - d0 ^= source2[0]; - d1 ^= source2[1]; - d2 ^= source2[2]; - d3 ^= source2[3]; - d4 ^= source2[4]; - d5 ^= source2[5]; - d6 ^= source2[6]; - d7 ^= source2[7]; - destp[0] = d0; /* Store the result (in burts) */ - destp[1] = d1; - destp[2] = d2; - destp[3] = d3; - destp[4] = d4; /* Store the result (in burts) */ - destp[5] = d5; - destp[6] = d6; - destp[7] = d7; - source1 += 8; - source2 += 8; - destp += 8; - } - break; - case 4: - source3 = (long *) bh_ptr[3]->b_data; - source2 = (long *) bh_ptr[2]->b_data; - source1 = (long *) bh_ptr[1]->b_data; - for (i = lines; i > 0; i--) { - register long d0, d1, d2, d3, d4, d5, d6, d7; - d0 = destp[0]; /* Pull the stuff into registers */ - d1 = destp[1]; /* ... in bursts, if possible. */ - d2 = destp[2]; - d3 = destp[3]; - d4 = destp[4]; - d5 = destp[5]; - d6 = destp[6]; - d7 = destp[7]; - d0 ^= source1[0]; - d1 ^= source1[1]; - d2 ^= source1[2]; - d3 ^= source1[3]; - d4 ^= source1[4]; - d5 ^= source1[5]; - d6 ^= source1[6]; - d7 ^= source1[7]; - d0 ^= source2[0]; - d1 ^= source2[1]; - d2 ^= source2[2]; - d3 ^= source2[3]; - d4 ^= source2[4]; - d5 ^= source2[5]; - d6 ^= source2[6]; - d7 ^= source2[7]; - d0 ^= source3[0]; - d1 ^= source3[1]; - d2 ^= source3[2]; - d3 ^= source3[3]; - d4 ^= source3[4]; - d5 ^= source3[5]; - d6 ^= source3[6]; - d7 ^= source3[7]; - destp[0] = d0; /* Store the result (in burts) */ - destp[1] = d1; - destp[2] = d2; - destp[3] = d3; - destp[4] = d4; /* Store the result (in burts) */ - destp[5] = d5; - destp[6] = d6; - destp[7] = d7; - source1 += 8; - source2 += 8; - source3 += 8; - destp += 8; - } - break; - case 5: - source4 = (long *) bh_ptr[4]->b_data; - source3 = (long *) bh_ptr[3]->b_data; - source2 = (long *) bh_ptr[2]->b_data; - source1 = (long *) bh_ptr[1]->b_data; - for (i = lines; i > 0; i--) { - register long d0, d1, d2, d3, d4, d5, d6, d7; - d0 = destp[0]; /* Pull the stuff into registers */ - d1 = destp[1]; /* ... in bursts, if possible. */ - d2 = destp[2]; - d3 = destp[3]; - d4 = destp[4]; - d5 = destp[5]; - d6 = destp[6]; - d7 = destp[7]; - d0 ^= source1[0]; - d1 ^= source1[1]; - d2 ^= source1[2]; - d3 ^= source1[3]; - d4 ^= source1[4]; - d5 ^= source1[5]; - d6 ^= source1[6]; - d7 ^= source1[7]; - d0 ^= source2[0]; - d1 ^= source2[1]; - d2 ^= source2[2]; - d3 ^= source2[3]; - d4 ^= source2[4]; - d5 ^= source2[5]; - d6 ^= source2[6]; - d7 ^= source2[7]; - d0 ^= source3[0]; - d1 ^= source3[1]; - d2 ^= source3[2]; - d3 ^= source3[3]; - d4 ^= source3[4]; - d5 ^= source3[5]; - d6 ^= source3[6]; - d7 ^= source3[7]; - d0 ^= source4[0]; - d1 ^= source4[1]; - d2 ^= source4[2]; - d3 ^= source4[3]; - d4 ^= source4[4]; - d5 ^= source4[5]; - d6 ^= source4[6]; - d7 ^= source4[7]; - destp[0] = d0; /* Store the result (in burts) */ - destp[1] = d1; - destp[2] = d2; - destp[3] = d3; - destp[4] = d4; /* Store the result (in burts) */ - destp[5] = d5; - destp[6] = d6; - destp[7] = d7; - source1 += 8; - source2 += 8; - source3 += 8; - source4 += 8; - destp += 8; - } - break; - } -} - -/* - * (the -6*32 shift factor colors the cache) - */ -#define SIZE (PAGE_SIZE-6*32) - -static void xor_speed ( struct xor_block_template * func, - struct buffer_head *b1, struct buffer_head *b2) -{ - int speed; - unsigned long now; - int i, count, max; - struct buffer_head *bh_ptr[6]; - - func->next = xor_functions; - xor_functions = func; - bh_ptr[0] = b1; - bh_ptr[1] = b2; - - /* - * count the number of XORs done during a whole jiffy. - * calculate the speed of checksumming from this. - * (we use a 2-page allocation to have guaranteed - * color L1-cache layout) - */ - max = 0; - for (i = 0; i < 5; i++) { - now = jiffies; - count = 0; - while (jiffies == now) { - mb(); - func->xor_block(2,bh_ptr); - mb(); - count++; - mb(); - } - if (count > max) - max = count; - } - - speed = max * (HZ*SIZE/1024); - func->speed = speed; - - printk( " %-10s: %5d.%03d MB/sec\n", func->name, - speed / 1000, speed % 1000); -} - -static inline void pick_fastest_function(void) -{ - struct xor_block_template *f, *fastest; - - fastest = xor_functions; - for (f = fastest; f; f = f->next) { - if (f->speed > fastest->speed) - fastest = f; - } -#ifdef CONFIG_X86_XMM - if (cpu_has_xmm) { - /* we force the use of the KNI xor block because it - can write around l2. we may also be able - to load into the l1 only depending on how - the cpu deals with a load to a line that is - being prefetched. - */ - fastest = &t_xor_block_pIII_kni; - } -#endif -#ifdef __alpha__ - if (implver() == IMPLVER_EV6) { - /* Force the use of alpha_prefetch if EV6, as it - is significantly faster in the cold cache case. */ - fastest = &t_xor_block_alpha_prefetch; - } -#endif - xor_block = fastest->xor_block; - printk( "using fastest function: %s (%d.%03d MB/sec)\n", fastest->name, - fastest->speed / 1000, fastest->speed % 1000); -} - -static struct buffer_head b1, b2; - -void calibrate_xor_block(void) -{ - if (xor_block) - return; - memset(&b1,0,sizeof(b1)); - b2 = b1; - - b1.b_data = (char *) md__get_free_pages(GFP_KERNEL,2); - if (!b1.b_data) { - pick_fastest_function(); - return; - } - b2.b_data = b1.b_data + 2*PAGE_SIZE + SIZE; - - b1.b_size = SIZE; - - printk(KERN_INFO "raid5: measuring checksumming speed\n"); - - sti(); /* should be safe */ - -#if defined(__sparc__) && !defined(__sparc_v9__) - printk(KERN_INFO "raid5: trying high-speed SPARC checksum routine\n"); - xor_speed(&t_xor_block_SPARC,&b1,&b2); -#endif - -#ifdef CONFIG_X86_XMM - if (cpu_has_xmm) { - printk(KERN_INFO - "raid5: KNI detected, trying cache-avoiding KNI checksum routine\n"); - xor_speed(&t_xor_block_pIII_kni,&b1,&b2); - } -#endif /* CONFIG_X86_XMM */ - -#ifdef __i386__ - if (md_cpu_has_mmx()) { - printk(KERN_INFO - "raid5: MMX detected, trying high-speed MMX checksum routines\n"); - xor_speed(&t_xor_block_pII_mmx,&b1,&b2); - xor_speed(&t_xor_block_p5_mmx,&b1,&b2); - } -#endif /* __i386__ */ - -#ifdef __alpha__ - xor_speed(&t_xor_block_alpha,&b1,&b2); - xor_speed(&t_xor_block_alpha_prefetch,&b1,&b2); -#endif - - xor_speed(&t_xor_block_8regs,&b1,&b2); - xor_speed(&t_xor_block_32regs,&b1,&b2); - - free_pages((unsigned long)b1.b_data,2); - pick_fastest_function(); -} - -#else /* __sparc_v9__ */ - -void calibrate_xor_block(void) -{ - if (xor_block) - return; - printk(KERN_INFO "raid5: using high-speed VIS checksum routine\n"); - xor_block = xor_block_VIS; -} - -#endif /* __sparc_v9__ */ - -MD_EXPORT_SYMBOL(xor_block); -MD_EXPORT_SYMBOL(calibrate_xor_block); - -#ifdef MODULE -int init_module(void) -{ - calibrate_xor_block(); - return 0; -} -#endif diff -u --recursive --new-file v2.4.0-test8/linux/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c --- v2.4.0-test8/linux/drivers/cdrom/cdrom.c Tue Sep 5 13:46:15 2000 +++ linux/drivers/cdrom/cdrom.c Mon Sep 25 17:05:01 2000 @@ -1118,6 +1118,7 @@ cdinfo(CD_DVD, "entering DVD_LU_SEND_RPC_STATE\n"); setup_report_key(&cgc, 0, 8); memset(&rpc_state, 0, sizeof(rpc_state_t)); + cgc.buffer = (char *) &rpc_state; if ((ret = cdo->generic_packet(cdi, &cgc))) return ret; @@ -2571,8 +2572,9 @@ return; cdrom_sysctl_header = register_sysctl_table(cdrom_root_table, 1); +#ifdef CONFIG_PROC_FS cdrom_root_table->child->de->owner = THIS_MODULE; - +#endif /* CONFIG_PROC_FS */ /* set the defaults */ cdrom_sysctl_settings.autoclose = autoclose; cdrom_sysctl_settings.autoeject = autoeject; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/cdrom/mcd.c linux/drivers/cdrom/mcd.c --- v2.4.0-test8/linux/drivers/cdrom/mcd.c Wed Jul 26 09:09:39 2000 +++ linux/drivers/cdrom/mcd.c Sun Sep 17 09:45:06 2000 @@ -275,7 +275,7 @@ static int statusCmd(void) { - int st, retry; + int st = -1, retry; for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) { @@ -297,7 +297,7 @@ static int mcdPlay(struct mcd_Play_msf *arg) { - int retry, st; + int retry, st = -1; for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) { diff -u --recursive --new-file v2.4.0-test8/linux/drivers/cdrom/sonycd535.c linux/drivers/cdrom/sonycd535.c --- v2.4.0-test8/linux/drivers/cdrom/sonycd535.c Tue Jul 18 16:09:27 2000 +++ linux/drivers/cdrom/sonycd535.c Sun Oct 1 20:35:15 2000 @@ -217,16 +217,16 @@ static unsigned short read_status_reg; static unsigned short data_reg; -static int initialized = 0; /* Has the drive been initialized? */ +static int initialized; /* Has the drive been initialized? */ static int sony_disc_changed = 1; /* Has the disk been changed since the last check? */ -static int sony_toc_read = 0; /* Has the table of contents been +static int sony_toc_read; /* Has the table of contents been read? */ static unsigned int sony_buffer_size; /* Size in bytes of the read-ahead buffer. */ static unsigned int sony_buffer_sectors; /* Size (in 2048 byte records) of the read-ahead buffer. */ -static unsigned int sony_usage = 0; /* How many processes have the +static unsigned int sony_usage; /* How many processes have the drive open. */ static int sony_first_block = -1; /* First OS block (512 byte) in @@ -242,7 +242,7 @@ static Byte **sony_buffer; /* Points to the pointers to the sector buffers */ -static int sony_inuse = 0; /* is the drive in use? Only one +static int sony_inuse; /* is the drive in use? Only one open at a time allowed */ /* @@ -260,8 +260,8 @@ * I just kept the CDU-31A driver behavior rather than using the PAUSE * command on the CDU-535. */ -static Byte cur_pos_msf[3] = {0, 0, 0}; -static Byte final_pos_msf[3] = {0, 0, 0}; +static Byte cur_pos_msf[3]; +static Byte final_pos_msf[3]; /* What IRQ is the drive using? 0 if none. */ static int sony535_irq_used = CDU535_INTERRUPT; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/Config.in linux/drivers/char/Config.in --- v2.4.0-test8/linux/drivers/char/Config.in Tue Aug 22 11:29:02 2000 +++ linux/drivers/char/Config.in Sun Oct 1 20:33:28 2000 @@ -16,7 +16,7 @@ tristate ' Dual serial port support' CONFIG_DUALSP_SERIAL fi fi -bool 'Extended dumb serial driver options' CONFIG_SERIAL_EXTENDED +dep_bool 'Extended dumb serial driver options' CONFIG_SERIAL_EXTENDED $CONFIG_SERIAL if [ "$CONFIG_SERIAL_EXTENDED" = "y" ]; then bool ' Support more than 4 serial ports' CONFIG_SERIAL_MANY_PORTS bool ' Support for sharing serial interrupts' CONFIG_SERIAL_SHARE_IRQ @@ -90,8 +90,8 @@ dep_tristate ' ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE $CONFIG_BUSMOUSE dep_tristate ' Logitech busmouse support' CONFIG_LOGIBUSMOUSE $CONFIG_BUSMOUSE dep_tristate ' Microsoft busmouse support' CONFIG_MS_BUSMOUSE $CONFIG_BUSMOUSE - if [ "$CONFIG_ADB" = "y" ]; then - dep_tristate ' Apple Desktop Bus mouse support' CONFIG_ADBMOUSE $CONFIG_BUSMOUSE + if [ "$CONFIG_ADB" = "y" -a "$CONFIG_ADB_KEYBOARD" = "y" ]; then + dep_tristate ' Apple Desktop Bus mouse support (old driver)' CONFIG_ADBMOUSE $CONFIG_BUSMOUSE fi fi @@ -122,6 +122,7 @@ bool 'Watchdog Timer Support' CONFIG_WATCHDOG if [ "$CONFIG_WATCHDOG" != "n" ]; then bool ' Disable watchdog shutdown on close' CONFIG_WATCHDOG_NOWAYOUT + tristate ' Software Watchdog' CONFIG_SOFT_WATCHDOG tristate ' WDT Watchdog timer' CONFIG_WDT tristate ' WDT PCI Watchdog timer' CONFIG_WDTPCI if [ "$CONFIG_WDT" != "n" ]; then @@ -130,7 +131,6 @@ bool ' Fan Tachometer' CONFIG_WDT_501_FAN fi fi - tristate ' Software Watchdog' CONFIG_SOFT_WATCHDOG tristate ' Berkshire Products PC Watchdog' CONFIG_PCWATCHDOG tristate ' Acquire SBC Watchdog Timer' CONFIG_ACQUIRE_WDT tristate ' SBC-60XX Watchdog Timer' CONFIG_60XX_WDT diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/Makefile linux/drivers/char/Makefile --- v2.4.0-test8/linux/drivers/char/Makefile Tue Aug 22 11:41:14 2000 +++ linux/drivers/char/Makefile Sun Oct 1 19:45:29 2000 @@ -101,6 +101,8 @@ obj-$(CONFIG_VT) += vt.o vc_screen.o consolemap.o consolemap_deftbl.o $(CONSOLE) selection.o obj-$(CONFIG_SERIAL) += $(SERIAL) obj-$(CONFIG_SERIAL_21285) += serial_21285.o +obj-$(CONFIG_SERIAL_SA1100) += serial_sa1100.o +obj-$(CONFIG_SERIAL_AMBA) += serial_amba.o ifndef CONFIG_SUN_KEYBOARD obj-$(CONFIG_VT) += keyboard.o $(KEYMAP) $(KEYBD) @@ -158,26 +160,16 @@ obj-$(CONFIG_APPLICOM) += applicom.o obj-$(CONFIG_MS_BUSMOUSE) += msbusmouse.o obj-$(CONFIG_82C710_MOUSE) += qpmouse.o -obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o -obj-$(CONFIG_PCWATCHDOG) += pcwd.o -obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o -obj-$(CONFIG_MIXCOMWD) += mixcomwd.o -obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o obj-$(CONFIG_AMIGAMOUSE) += amigamouse.o obj-$(CONFIG_ATARIMOUSE) += atarimouse.o obj-$(CONFIG_ADBMOUSE) += adbmouse.o obj-$(CONFIG_PC110_PAD) += pc110pad.o -obj-$(CONFIG_WDT) += wdt.o -obj-$(CONFIG_WDTPCI) += wdt_pci.o obj-$(CONFIG_RTC) += rtc.o obj-$(CONFIG_EFI_RTC) += efirtc.o ifeq ($(CONFIG_PPC),) obj-$(CONFIG_NVRAM) += nvram.o endif - -obj-$(CONFIG_21285_WATCHDOG) += wdt285.o -obj-$(CONFIG_977_WATCHDOG) += wdt977.o -obj-$(CONFIG_I810_TCO) += i810-tco.o +obj-$(CONFIG_TOSHIBA) += toshiba.o obj-$(CONFIG_DS1620) += ds1620.o obj-$(CONFIG_INTEL_RNG) += i810_rng.o @@ -227,6 +219,23 @@ MOD_SUB_DIRS += agp endif endif + +# Only one watchdog can succeed. We probe the hardware watchdog +# drivers first, then the softdog driver. This means if your hardware +# watchdog dies or is 'borrowed' for some reason the software watchdog +# still gives you some cover. + +obj-$(CONFIG_PCWATCHDOG) += pcwd.o +obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o +obj-$(CONFIG_MIXCOMWD) += mixcomwd.o +obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o +obj-$(CONFIG_WDT) += wdt.o +obj-$(CONFIG_WDTPCI) += wdt_pci.o +obj-$(CONFIG_21285_WATCHDOG) += wdt285.o +obj-$(CONFIG_977_WATCHDOG) += wdt977.o +obj-$(CONFIG_I810_TCO) += i810-tco.o +obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o + # Extract lists of the multi-part drivers. # The 'int-*' lists are the intermediate files used to build the multi's. diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/acquirewdt.c linux/drivers/char/acquirewdt.c --- v2.4.0-test8/linux/drivers/char/acquirewdt.c Wed Jul 12 21:58:42 2000 +++ linux/drivers/char/acquirewdt.c Sun Oct 1 19:45:29 2000 @@ -204,21 +204,7 @@ 0 }; -#ifdef MODULE - -#define acq_init init_module - -void cleanup_module(void) -{ - misc_deregister(&acq_miscdev); - unregister_reboot_notifier(&acq_notifier); - release_region(WDT_STOP,1); - release_region(WDT_START,1); -} - -#endif - -int __init acq_init(void) +static int __init acq_init(void) { printk("WDT driver for Acquire single board computer initialising.\n"); @@ -229,4 +215,14 @@ register_reboot_notifier(&acq_notifier); return 0; } + +static void __exit acq_exit(void) +{ + misc_deregister(&acq_miscdev); + unregister_reboot_notifier(&acq_notifier); + release_region(WDT_STOP,1); + release_region(WDT_START,1); +} +module_init(acq_init); +module_exit(acq_exit); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/drm/dma.c linux/drivers/char/drm/dma.c --- v2.4.0-test8/linux/drivers/char/drm/dma.c Tue Aug 29 14:09:15 2000 +++ linux/drivers/char/drm/dma.c Sun Oct 1 19:59:59 2000 @@ -397,10 +397,10 @@ atomic_inc(&q->use_count); if (atomic_read(&q->block_write)) { - current->state = TASK_INTERRUPTIBLE; add_wait_queue(&q->write_queue, &entry); atomic_inc(&q->block_count); for (;;) { + current->state = TASK_INTERRUPTIBLE; if (!atomic_read(&q->block_write)) break; schedule(); if (signal_pending(current)) { diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/drm/drm.h linux/drivers/char/drm/drm.h --- v2.4.0-test8/linux/drivers/char/drm/drm.h Fri Jul 21 12:56:44 2000 +++ linux/drivers/char/drm/drm.h Sun Oct 1 19:59:59 2000 @@ -35,7 +35,13 @@ #ifndef _DRM_H_ #define _DRM_H_ +#if defined(__linux__) #include /* For _IO* macros */ +#define DRM_IOCTL_NR(n) _IOC_NR(n) +#elif defined(__FreeBSD__) +#include +#define DRM_IOCTL_NR(n) ((n) & 0xff) +#endif #define DRM_PROC_DEVICES "/proc/devices" #define DRM_PROC_MISC "/proc/misc" @@ -289,7 +295,6 @@ } drm_agp_info_t; #define DRM_IOCTL_BASE 'd' -#define DRM_IOCTL_NR(n) _IOC_NR(n) #define DRM_IO(nr) _IO(DRM_IOCTL_BASE,nr) #define DRM_IOR(nr,size) _IOR(DRM_IOCTL_BASE,nr,size) #define DRM_IOW(nr,size) _IOW(DRM_IOCTL_BASE,nr,size) diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/drm/drmP.h linux/drivers/char/drm/drmP.h --- v2.4.0-test8/linux/drivers/char/drm/drmP.h Fri Sep 8 12:52:45 2000 +++ linux/drivers/char/drm/drmP.h Mon Oct 2 12:07:56 2000 @@ -33,6 +33,12 @@ #define _DRM_P_H_ #ifdef __KERNEL__ +#ifdef __alpha__ +/* add include of current.h so that "current" is defined + * before static inline funcs in wait.h. Doing this so we + * can build the DRM (part of PI DRI). 4/21/2000 S + B */ +#include +#endif /* __alpha__ */ #include #include #include @@ -47,6 +53,9 @@ #include #include /* For (un)lock_kernel */ #include +#ifdef __alpha__ +#include /* For pte_wrprotect */ +#endif #include #include #include @@ -147,6 +156,71 @@ #ifndef __HAVE_ARCH_CMPXCHG /* Include this here so that driver can be used with older kernels. */ +#if defined(__alpha__) +static __inline__ unsigned long +__cmpxchg_u32(volatile int *m, int old, int new) +{ + unsigned long prev, cmp; + + __asm__ __volatile__( + "1: ldl_l %0,%2\n" + " cmpeq %0,%3,%1\n" + " beq %1,2f\n" + " mov %4,%1\n" + " stl_c %1,%2\n" + " beq %1,3f\n" + "2: mb\n" + ".subsection 2\n" + "3: br 1b\n" + ".previous" + : "=&r"(prev), "=&r"(cmp), "=m"(*m) + : "r"((long) old), "r"(new), "m"(*m)); + + return prev; +} + +static __inline__ unsigned long +__cmpxchg_u64(volatile long *m, unsigned long old, unsigned long new) +{ + unsigned long prev, cmp; + + __asm__ __volatile__( + "1: ldq_l %0,%2\n" + " cmpeq %0,%3,%1\n" + " beq %1,2f\n" + " mov %4,%1\n" + " stq_c %1,%2\n" + " beq %1,3f\n" + "2: mb\n" + ".subsection 2\n" + "3: br 1b\n" + ".previous" + : "=&r"(prev), "=&r"(cmp), "=m"(*m) + : "r"((long) old), "r"(new), "m"(*m)); + + return prev; +} + +static __inline__ unsigned long +__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size) +{ + switch (size) { + case 4: + return __cmpxchg_u32(ptr, old, new); + case 8: + return __cmpxchg_u64(ptr, old, new); + } + return old; +} +#define cmpxchg(ptr,o,n) \ + ({ \ + __typeof__(*(ptr)) _o_ = (o); \ + __typeof__(*(ptr)) _n_ = (n); \ + (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_, \ + (unsigned long)_n_, sizeof(*(ptr))); \ + }) + +#elif __i386__ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size) { @@ -177,6 +251,7 @@ #define cmpxchg(ptr,o,n) \ ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o), \ (unsigned long)(n),sizeof(*(ptr)))) +#endif /* i386 & alpha */ #endif /* Macros to make printk easier */ @@ -355,6 +430,7 @@ struct drm_file *next; struct drm_file *prev; struct drm_device *dev; + int remove_auth_on_close; } drm_file_t; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/drm/gamma_dma.c linux/drivers/char/drm/gamma_dma.c --- v2.4.0-test8/linux/drivers/char/drm/gamma_dma.c Tue Aug 29 21:09:10 2000 +++ linux/drivers/char/drm/gamma_dma.c Sun Oct 1 19:59:59 2000 @@ -542,10 +542,9 @@ if (d->flags & _DRM_DMA_BLOCK) { DRM_DEBUG("%d waiting\n", current->pid); - current->state = TASK_INTERRUPTIBLE; for (;;) { - if (!last_buf->waiting - && !last_buf->pending) + current->state = TASK_INTERRUPTIBLE; + if (!last_buf->waiting && !last_buf->pending) break; /* finished */ schedule(); if (signal_pending(current)) { @@ -778,6 +777,7 @@ } add_wait_queue(&dev->lock.lock_queue, &entry); for (;;) { + current->state = TASK_INTERRUPTIBLE; if (!dev->lock.hw_lock) { /* Device has been unregistered */ ret = -EINTR; @@ -794,7 +794,6 @@ /* Contention */ atomic_inc(&dev->total_sleeps); - current->state = TASK_INTERRUPTIBLE; schedule(); if (signal_pending(current)) { ret = -ERESTARTSYS; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/drm/gamma_drv.c linux/drivers/char/drm/gamma_drv.c --- v2.4.0-test8/linux/drivers/char/drm/gamma_drv.c Tue Aug 29 21:09:10 2000 +++ linux/drivers/char/drm/gamma_drv.c Fri Sep 15 14:24:55 2000 @@ -11,11 +11,11 @@ * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL @@ -23,7 +23,7 @@ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. - * + * * Authors: * Rickard E. (Rik) Faith * @@ -42,7 +42,7 @@ #define GAMMA_NAME "gamma" #define GAMMA_DESC "3dlabs GMX 2000" -#define GAMMA_DATE "20000719" +#define GAMMA_DATE "20000910" #define GAMMA_MAJOR 1 #define GAMMA_MINOR 0 #define GAMMA_PATCHLEVEL 0 @@ -87,7 +87,7 @@ [DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)] = { drm_infobufs, 1, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)] = { drm_mapbufs, 1, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)] = { drm_freebufs, 1, 0 }, - + [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = { drm_addctx, 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = { drm_rmctx, 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = { drm_modctx, 1, 1 }, @@ -120,7 +120,7 @@ * passed via the boot-loader (e.g., LILO). It calls the insmod option * routine, drm_parse_options. */ - + static int __init gamma_options(char *str) { @@ -134,7 +134,7 @@ static int gamma_setup(drm_device_t *dev) { int i; - + atomic_set(&dev->ioctl_count, 0); atomic_set(&dev->vma_count, 0); dev->buf_use = 0; @@ -179,22 +179,22 @@ #endif dev->ctx_start = 0; dev->lck_start = 0; - + dev->buf_rp = dev->buf; dev->buf_wp = dev->buf; dev->buf_end = dev->buf + DRM_BSZ; dev->buf_async = NULL; init_waitqueue_head(&dev->buf_readers); init_waitqueue_head(&dev->buf_writers); - + DRM_DEBUG("\n"); - + /* The kernel's context could be created here, but is now created in drm_dma_enqueue. This is more resource-efficient for hardware that does not do DMA, but may mean that drm_select_queue fails between the time the interrupt is initialized and the time the queues are initialized. */ - + return 0; } @@ -209,15 +209,15 @@ DRM_DEBUG("\n"); if (dev->irq) gamma_irq_uninstall(dev); - + down(&dev->struct_sem); del_timer(&dev->timer); - + if (dev->devname) { drm_free(dev->devname, strlen(dev->devname)+1, DRM_MEM_DRIVER); dev->devname = NULL; } - + if (dev->unique) { drm_free(dev->unique, strlen(dev->unique)+1, DRM_MEM_DRIVER); dev->unique = NULL; @@ -231,7 +231,7 @@ } dev->magiclist[i].head = dev->magiclist[i].tail = NULL; } - + /* Clear vma list (only built for debugging) */ if (dev->vmalist) { for (vma = dev->vmalist; vma; vma = vma_next) { @@ -240,7 +240,7 @@ } dev->vmalist = NULL; } - + /* Clear map area and mtrr information */ if (dev->maplist) { for (i = 0; i < dev->map_count; i++) { @@ -278,7 +278,7 @@ dev->maplist = NULL; dev->map_count = 0; } - + if (dev->queuelist) { for (i = 0; i < dev->queue_count; i++) { drm_waitlist_destroy(&dev->queuelist[i]->waitlist); @@ -304,7 +304,7 @@ wake_up_interruptible(&dev->lock.lock_queue); } up(&dev->struct_sem); - + return 0; } @@ -349,7 +349,7 @@ memset((void *)dev, 0, sizeof(*dev)); dev->count_lock = SPIN_LOCK_UNLOCKED; sema_init(&dev->struct_sem, 1); - + #ifdef MODULE drm_parse_options(gamma); #endif @@ -374,7 +374,7 @@ GAMMA_DATE, gamma_misc.minor, devices); - + return 0; } @@ -385,7 +385,7 @@ drm_device_t *dev = &gamma_device; DRM_DEBUG("\n"); - + drm_proc_cleanup(); if (misc_deregister(&gamma_misc)) { DRM_ERROR("Cannot unload module\n"); @@ -438,7 +438,7 @@ { drm_device_t *dev = &gamma_device; int retcode = 0; - + DRM_DEBUG("open_count = %d\n", dev->open_count); if (!(retcode = drm_open_helper(inode, filp, dev))) { #if LINUX_VERSION_CODE < 0x020333 @@ -505,7 +505,7 @@ atomic_inc(&dev->ioctl_count); atomic_inc(&dev->total_ioctl); ++priv->ioctl_count; - + DRM_DEBUG("pid = %d, cmd = 0x%02x, nr = 0x%02x, dev 0x%x, auth = %d\n", current->pid, cmd, nr, dev->device, priv->authenticated); @@ -525,7 +525,7 @@ retcode = (func)(inode, filp, cmd, arg); } } - + atomic_dec(&dev->ioctl_count); return retcode; } @@ -540,7 +540,7 @@ if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock))) return -EFAULT; - + if (lock.context == DRM_KERNEL_CONTEXT) { DRM_ERROR("Process %d using kernel context %d\n", current->pid, lock.context); @@ -565,7 +565,7 @@ atomic_inc(&dev->histo.lhld[drm_histogram_slot(get_cycles() - dev->lck_start)]); #endif - + unblock_all_signals(); return 0; } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/drm/i810_dma.c linux/drivers/char/drm/i810_dma.c --- v2.4.0-test8/linux/drivers/char/drm/i810_dma.c Tue Aug 29 21:09:10 2000 +++ linux/drivers/char/drm/i810_dma.c Sun Oct 1 19:59:59 2000 @@ -252,16 +252,15 @@ buf = i810_freelist_get(dev); if (!buf) { retcode = -ENOMEM; - DRM_DEBUG("%s retcode %d\n", __FUNCTION__, retcode); - goto out_get_buf; + DRM_DEBUG("retcode=%d\n", retcode); + return retcode; } retcode = i810_map_buffer(buf, filp); if(retcode) { i810_freelist_put(dev, buf); - DRM_DEBUG("mapbuf failed in %s retcode %d\n", - __FUNCTION__, retcode); - goto out_get_buf; + DRM_DEBUG("mapbuf failed, retcode %d\n", retcode); + return retcode; } buf->pid = priv->pid; buf_priv = buf->dev_private; @@ -270,7 +269,6 @@ d->request_size = buf->total; d->virtual = buf_priv->virtual; -out_get_buf: return retcode; } @@ -1069,11 +1067,11 @@ return; } atomic_set(&dev_priv->flush_done, 0); - current->state = TASK_INTERRUPTIBLE; add_wait_queue(&dev_priv->flush_queue, &entry); end = jiffies + (HZ*3); for (;;) { + current->state = TASK_INTERRUPTIBLE; i810_dma_quiescent_emit(dev); if (atomic_read(&dev_priv->flush_done) == 1) break; if((signed)(end - jiffies) <= 0) { @@ -1104,10 +1102,10 @@ return 0; } atomic_set(&dev_priv->flush_done, 0); - current->state = TASK_INTERRUPTIBLE; add_wait_queue(&dev_priv->flush_queue, &entry); end = jiffies + (HZ*3); for (;;) { + current->state = TASK_INTERRUPTIBLE; i810_dma_emit_flush(dev); if (atomic_read(&dev_priv->flush_done) == 1) break; if((signed)(end - jiffies) <= 0) { @@ -1201,6 +1199,7 @@ if (!ret) { add_wait_queue(&dev->lock.lock_queue, &entry); for (;;) { + current->state = TASK_INTERRUPTIBLE; if (!dev->lock.hw_lock) { /* Device has been unregistered */ ret = -EINTR; @@ -1216,7 +1215,6 @@ /* Contention */ atomic_inc(&dev->total_sleeps); - current->state = TASK_INTERRUPTIBLE; DRM_DEBUG("Calling lock schedule\n"); schedule(); if (signal_pending(current)) { diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/drm/i810_drv.c linux/drivers/char/drm/i810_drv.c --- v2.4.0-test8/linux/drivers/char/drm/i810_drv.c Tue Sep 5 13:51:30 2000 +++ linux/drivers/char/drm/i810_drv.c Sun Oct 1 20:00:00 2000 @@ -1,6 +1,6 @@ /* i810_drv.c -- I810 driver -*- linux-c -*- * Created: Mon Dec 13 01:56:22 1999 by jhartmann@precisioninsight.com - * + * * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. * All Rights Reserved. @@ -11,11 +11,11 @@ * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL @@ -35,7 +35,7 @@ #define I810_NAME "i810" #define I810_DESC "Intel I810" -#define I810_DATE "20000719" +#define I810_DATE "20000928" #define I810_MAJOR 1 #define I810_MINOR 1 #define I810_PATCHLEVEL 0 @@ -143,7 +143,7 @@ static int i810_setup(drm_device_t *dev) { int i; - + atomic_set(&dev->ioctl_count, 0); atomic_set(&dev->vma_count, 0); dev->buf_use = 0; @@ -188,22 +188,22 @@ #endif dev->ctx_start = 0; dev->lck_start = 0; - + dev->buf_rp = dev->buf; dev->buf_wp = dev->buf; dev->buf_end = dev->buf + DRM_BSZ; dev->buf_async = NULL; init_waitqueue_head(&dev->buf_readers); init_waitqueue_head(&dev->buf_writers); - + DRM_DEBUG("\n"); - + /* The kernel's context could be created here, but is now created in drm_dma_enqueue. This is more resource-efficient for hardware that does not do DMA, but may mean that drm_select_queue fails between the time the interrupt is initialized and the time the queues are initialized. */ - + return 0; } @@ -218,15 +218,15 @@ DRM_DEBUG("\n"); if (dev->irq) i810_irq_uninstall(dev); - + down(&dev->struct_sem); del_timer(&dev->timer); - + if (dev->devname) { drm_free(dev->devname, strlen(dev->devname)+1, DRM_MEM_DRIVER); dev->devname = NULL; } - + if (dev->unique) { drm_free(dev->unique, strlen(dev->unique)+1, DRM_MEM_DRIVER); dev->unique = NULL; @@ -244,7 +244,7 @@ if (dev->agp) { drm_agp_mem_t *entry; drm_agp_mem_t *nexte; - + /* Remove AGP resources, but leave dev->agp intact until r128_cleanup is called. */ for (entry = dev->agp->memory; entry; entry = nexte) { @@ -254,10 +254,10 @@ drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS); } dev->agp->memory = NULL; - + if (dev->agp->acquired && drm_agp.release) (*drm_agp.release)(); - + dev->agp->acquired = 0; dev->agp->enabled = 0; } @@ -269,7 +269,7 @@ } dev->vmalist = NULL; } - + /* Clear map area and mtrr information */ if (dev->maplist) { for (i = 0; i < dev->map_count; i++) { @@ -305,7 +305,7 @@ dev->maplist = NULL; dev->map_count = 0; } - + if (dev->queuelist) { for (i = 0; i < dev->queue_count; i++) { drm_waitlist_destroy(&dev->queuelist[i]->waitlist); @@ -331,7 +331,7 @@ wake_up_interruptible(&dev->lock.lock_queue); } up(&dev->struct_sem); - + return 0; } @@ -348,7 +348,7 @@ memset((void *)dev, 0, sizeof(*dev)); dev->count_lock = SPIN_LOCK_UNLOCKED; sema_init(&dev->struct_sem, 1); - + #ifdef MODULE drm_parse_options(i810); #endif @@ -402,7 +402,7 @@ drm_device_t *dev = &i810_device; DRM_DEBUG("\n"); - + drm_proc_cleanup(); if (misc_deregister(&i810_misc)) { DRM_ERROR("Cannot unload module\n"); @@ -461,7 +461,7 @@ { drm_device_t *dev = &i810_device; int retcode = 0; - + DRM_DEBUG("open_count = %d\n", dev->open_count); if (!(retcode = drm_open_helper(inode, filp, dev))) { #if LINUX_VERSION_CODE < 0x020333 @@ -498,7 +498,7 @@ drm_lock_free(dev, &dev->lock.hw_lock->lock, _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); - + /* FIXME: may require heavy-handed reset of hardware at this point, possibly processed via a callback to the X @@ -508,6 +508,7 @@ DECLARE_WAITQUEUE(entry, current); add_wait_queue(&dev->lock.lock_queue, &entry); for (;;) { + current->state = TASK_INTERRUPTIBLE; if (!dev->lock.hw_lock) { /* Device has been unregistered */ retcode = -EINTR; @@ -519,10 +520,9 @@ dev->lock.lock_time = jiffies; atomic_inc(&dev->total_locks); break; /* Got lock */ - } + } /* Contention */ atomic_inc(&dev->total_sleeps); - current->state = TASK_INTERRUPTIBLE; schedule(); if (signal_pending(current)) { retcode = -ERESTARTSYS; @@ -545,7 +545,7 @@ if (priv->next) priv->next->prev = priv->prev; else dev->file_last = priv->prev; up(&dev->struct_sem); - + drm_free(priv, sizeof(*priv), DRM_MEM_FILES); #if LINUX_VERSION_CODE < 0x020333 MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */ @@ -585,7 +585,7 @@ atomic_inc(&dev->ioctl_count); atomic_inc(&dev->total_ioctl); ++priv->ioctl_count; - + DRM_DEBUG("pid = %d, cmd = 0x%02x, nr = 0x%02x, dev 0x%x, auth = %d\n", current->pid, cmd, nr, dev->device, priv->authenticated); @@ -605,7 +605,7 @@ retcode = (func)(inode, filp, cmd, arg); } } - + atomic_dec(&dev->ioctl_count); return retcode; } @@ -619,7 +619,7 @@ if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock))) return -EFAULT; - + if (lock.context == DRM_KERNEL_CONTEXT) { DRM_ERROR("Process %d using kernel context %d\n", current->pid, lock.context); @@ -643,7 +643,7 @@ atomic_inc(&dev->histo.lhld[drm_histogram_slot(get_cycles() - dev->lck_start)]); #endif - + unblock_all_signals(); return 0; } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/drm/lists.c linux/drivers/char/drm/lists.c --- v2.4.0-test8/linux/drivers/char/drm/lists.c Mon Aug 21 08:08:12 2000 +++ linux/drivers/char/drm/lists.c Sun Oct 1 20:00:00 2000 @@ -34,7 +34,6 @@ int drm_waitlist_create(drm_waitlist_t *bl, int count) { - DRM_DEBUG("%d\n", count); if (bl->count) return -EINVAL; bl->count = count; @@ -50,7 +49,6 @@ int drm_waitlist_destroy(drm_waitlist_t *bl) { - DRM_DEBUG("\n"); if (bl->rp != bl->wp) return -EINVAL; if (bl->bufs) drm_free(bl->bufs, (bl->count + 2) * sizeof(*bl->bufs), @@ -69,8 +67,6 @@ unsigned long flags; left = DRM_LEFTCOUNT(bl); - DRM_DEBUG("put %d (%d left, rp = %p, wp = %p)\n", - buf->idx, left, bl->rp, bl->wp); if (!left) { DRM_ERROR("Overflow while adding buffer %d from pid %d\n", buf->idx, buf->pid); @@ -103,13 +99,11 @@ if (++bl->rp >= bl->end) bl->rp = bl->bufs; spin_unlock_irqrestore(&bl->read_lock, flags); - DRM_DEBUG("get %d\n", buf->idx); return buf; } int drm_freelist_create(drm_freelist_t *bl, int count) { - DRM_DEBUG("\n"); atomic_set(&bl->count, 0); bl->next = NULL; init_waitqueue_head(&bl->waiting); @@ -123,7 +117,6 @@ int drm_freelist_destroy(drm_freelist_t *bl) { - DRM_DEBUG("\n"); atomic_set(&bl->count, 0); bl->next = NULL; return 0; @@ -142,9 +135,6 @@ DRM_ERROR("Freed buffer %d: w%d, p%d, l%d\n", buf->idx, buf->waiting, buf->pending, buf->list); } - DRM_DEBUG("%d, count = %d, wfh = %d, w%d, p%d\n", - buf->idx, atomic_read(&bl->count), atomic_read(&bl->wfh), - buf->waiting, buf->pending); if (!bl) return 1; #if DRM_DMA_HISTOGRAM buf->time_freed = get_cycles(); @@ -190,9 +180,6 @@ atomic_dec(&bl->count); buf->next = NULL; buf->list = DRM_LIST_NONE; - DRM_DEBUG("%d, count = %d, wfh = %d, w%d, p%d\n", - buf->idx, atomic_read(&bl->count), atomic_read(&bl->wfh), - buf->waiting, buf->pending); if (buf->waiting || buf->pending) { DRM_ERROR("Free buffer %d: w%d, p%d, l%d\n", buf->idx, buf->waiting, buf->pending, buf->list); @@ -212,13 +199,10 @@ if (atomic_read(&bl->count) <= bl->low_mark) /* Became low */ atomic_set(&bl->wfh, 1); if (atomic_read(&bl->wfh)) { - DRM_DEBUG("Block = %d, count = %d, wfh = %d\n", - block, atomic_read(&bl->count), - atomic_read(&bl->wfh)); if (block) { add_wait_queue(&bl->waiting, &entry); - current->state = TASK_INTERRUPTIBLE; for (;;) { + current->state = TASK_INTERRUPTIBLE; if (!atomic_read(&bl->wfh) && (buf = drm_freelist_try(bl))) break; schedule(); @@ -230,7 +214,5 @@ return buf; } - DRM_DEBUG("Count = %d, wfh = %d\n", - atomic_read(&bl->count), atomic_read(&bl->wfh)); return drm_freelist_try(bl); } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/drm/lock.c linux/drivers/char/drm/lock.c --- v2.4.0-test8/linux/drivers/char/drm/lock.c Tue Aug 29 14:09:15 2000 +++ linux/drivers/char/drm/lock.c Sun Oct 1 20:00:00 2000 @@ -50,7 +50,6 @@ { unsigned int old, new, prev; - DRM_DEBUG("%d attempts\n", context); do { old = *lock; if (old & _DRM_LOCK_HELD) new = old | _DRM_LOCK_CONT; @@ -68,11 +67,8 @@ } if (new == (context | _DRM_LOCK_HELD)) { /* Have lock */ - DRM_DEBUG("%d\n", context); return 1; } - DRM_DEBUG("%d unable to get lock held by %d\n", - context, _DRM_LOCKING_CONTEXT(old)); return 0; } @@ -89,7 +85,6 @@ new = context | _DRM_LOCK_HELD; prev = cmpxchg(lock, old, new); } while (prev != old); - DRM_DEBUG("%d => %d\n", _DRM_LOCKING_CONTEXT(old), context); return 1; } @@ -99,7 +94,6 @@ unsigned int old, new, prev; pid_t pid = dev->lock.pid; - DRM_DEBUG("%d\n", context); dev->lock.pid = 0; do { old = *lock; @@ -128,10 +122,10 @@ atomic_inc(&q->use_count); if (atomic_read(&q->use_count) > 1) { atomic_inc(&q->block_write); - current->state = TASK_INTERRUPTIBLE; add_wait_queue(&q->flush_queue, &entry); atomic_inc(&q->block_count); for (;;) { + current->state = TASK_INTERRUPTIBLE; if (!DRM_BUFCOUNT(&q->waitlist)) break; schedule(); if (signal_pending(current)) { diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/drm/mga_bufs.c linux/drivers/char/drm/mga_bufs.c --- v2.4.0-test8/linux/drivers/char/drm/mga_bufs.c Tue Aug 29 14:09:15 2000 +++ linux/drivers/char/drm/mga_bufs.c Sun Oct 1 20:00:00 2000 @@ -66,7 +66,7 @@ order = drm_order(request.size); size = 1 << order; agp_offset = request.agp_start; - alignment = (request.flags & _DRM_PAGE_ALIGN) ? PAGE_ALIGN(size) :size; + alignment = (request.flags & _DRM_PAGE_ALIGN) ? PAGE_ALIGN(size):size; page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; total = PAGE_SIZE << page_order; byte_count = 0; @@ -119,8 +119,6 @@ buf->order = order; buf->used = 0; - DRM_DEBUG("offset : %ld\n", offset); - buf->offset = offset; /* Hrm */ buf->bus_address = dev->agp->base + agp_offset + offset; buf->address = (void *)(agp_offset + offset + dev->agp->base); @@ -130,7 +128,8 @@ init_waitqueue_head(&buf->dma_wait); buf->pid = 0; - buf->dev_private = drm_alloc(sizeof(drm_mga_buf_priv_t), DRM_MEM_BUFS); + buf->dev_private = drm_alloc(sizeof(drm_mga_buf_priv_t), + DRM_MEM_BUFS); buf->dev_priv_size = sizeof(drm_mga_buf_priv_t); #if DRM_DMA_HISTOGRAM @@ -142,9 +141,6 @@ offset = offset + alignment; entry->buf_count++; byte_count += PAGE_SIZE << page_order; - - DRM_DEBUG("buffer %d @ %p\n", - entry->buf_count, buf->address); } dma->buflist = drm_realloc(dma->buflist, @@ -234,7 +230,7 @@ if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return -EINVAL; if (dev->queue_count) return -EBUSY; /* Not while in use */ - alignment = (request.flags & _DRM_PAGE_ALIGN) ? PAGE_ALIGN(size) :size; + alignment = (request.flags & _DRM_PAGE_ALIGN) ? PAGE_ALIGN(size):size; page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0; total = PAGE_SIZE << page_order; @@ -402,8 +398,6 @@ if (dma->bufs[i].buf_count) ++count; } - DRM_DEBUG("count = %d\n", count); - if (request.count >= count) { for (i = 0, count = 0; i < DRM_MAX_ORDER+1; i++) { if (dma->bufs[i].buf_count) { @@ -426,13 +420,6 @@ sizeof(dma->bufs[0] .freelist.high_mark))) return -EFAULT; - - DRM_DEBUG("%d %d %d %d %d\n", - i, - dma->bufs[i].buf_count, - dma->bufs[i].buf_size, - dma->bufs[i].freelist.low_mark, - dma->bufs[i].freelist.high_mark); ++count; } } @@ -459,13 +446,9 @@ if (!dma) return -EINVAL; - if (copy_from_user(&request, - (drm_buf_desc_t *)arg, - sizeof(request))) + if (copy_from_user(&request, (drm_buf_desc_t *)arg, sizeof(request))) return -EFAULT; - DRM_DEBUG("%d, %d, %d\n", - request.size, request.low_mark, request.high_mark); order = drm_order(request.size); if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return -EINVAL; entry = &dma->bufs[order]; @@ -499,7 +482,6 @@ sizeof(request))) return -EFAULT; - DRM_DEBUG("%d\n", request.count); for (i = 0; i < request.count; i++) { if (copy_from_user(&idx, &request.list[i], @@ -537,12 +519,9 @@ if (!dma) return -EINVAL; - DRM_DEBUG("\n"); - spin_lock(&dev->count_lock); if (atomic_read(&dev->buf_alloc)) { spin_unlock(&dev->count_lock); - DRM_DEBUG("Busy\n"); return -EBUSY; } ++dev->buf_use; /* Can't allocate more after this call */ @@ -553,9 +532,6 @@ sizeof(request))) return -EFAULT; - DRM_DEBUG("mga_mapbufs\n"); - DRM_DEBUG("dma->flags : %x\n", dma->flags); - if (request.count >= dma->buf_count) { if(dma->flags & _DRM_DMA_USE_AGP) { drm_mga_private_t *dev_priv = dev->dev_private; @@ -563,7 +539,6 @@ map = dev->maplist[dev_priv->buffer_map_idx]; if (!map) { - DRM_DEBUG("map is null\n"); retcode = -EINVAL; goto done; } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/drm/mga_context.c linux/drivers/char/drm/mga_context.c --- v2.4.0-test8/linux/drivers/char/drm/mga_context.c Tue Aug 29 14:09:15 2000 +++ linux/drivers/char/drm/mga_context.c Sun Oct 1 20:00:00 2000 @@ -35,9 +35,7 @@ static int mga_alloc_queue(drm_device_t *dev) { - int temp = drm_ctxbitmap_next(dev); - DRM_DEBUG("mga_alloc_queue: %d\n", temp); - return temp; + return drm_ctxbitmap_next(dev); } int mga_context_switch(drm_device_t *dev, int old, int new) @@ -102,7 +100,6 @@ drm_ctx_t ctx; int i; - DRM_DEBUG("%d\n", DRM_RESERVED_CONTEXTS); if (copy_from_user(&res, (drm_ctx_res_t *)arg, sizeof(res))) return -EFAULT; if (res.count >= DRM_RESERVED_CONTEXTS) { @@ -135,8 +132,6 @@ ctx.handle = mga_alloc_queue(dev); } if (ctx.handle == -1) { - DRM_DEBUG("Not enough free contexts.\n"); - /* Should this return -EBUSY instead? */ return -ENOMEM; } DRM_DEBUG("%d\n", ctx.handle); @@ -204,6 +199,8 @@ if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) return -EFAULT; DRM_DEBUG("%d\n", ctx.handle); + if(ctx.handle == DRM_KERNEL_CONTEXT+1) priv->remove_auth_on_close = 1; + if(ctx.handle != DRM_KERNEL_CONTEXT) { drm_ctxbitmap_free(dev, ctx.handle); } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/drm/mga_dma.c linux/drivers/char/drm/mga_dma.c --- v2.4.0-test8/linux/drivers/char/drm/mga_dma.c Tue Aug 29 21:09:10 2000 +++ linux/drivers/char/drm/mga_dma.c Sun Oct 1 20:00:00 2000 @@ -11,11 +11,11 @@ * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL @@ -51,53 +51,30 @@ static unsigned long mga_alloc_page(drm_device_t *dev) { unsigned long address; - - DRM_DEBUG("%s\n", __FUNCTION__); + address = __get_free_page(GFP_KERNEL); if(address == 0UL) { return 0; } atomic_inc(&virt_to_page(address)->count); - set_bit(PG_locked, &virt_to_page(address)->flags); - + set_bit(PG_reserved, &virt_to_page(address)->flags); + return address; } static void mga_free_page(drm_device_t *dev, unsigned long page) { - DRM_DEBUG("%s\n", __FUNCTION__); - - if(page == 0UL) { - return; - } + if(!page) return; atomic_dec(&virt_to_page(page)->count); - clear_bit(PG_locked, &virt_to_page(page)->flags); - wake_up(&virt_to_page(page)->wait); + clear_bit(PG_reserved, &virt_to_page(page)->flags); free_page(page); return; } static void mga_delay(void) { - return; -} - -#ifdef __i386__ -void mga_flush_write_combine(void) -{ - int xchangeDummy; - DRM_DEBUG("%s\n", __FUNCTION__); - - __asm__ volatile(" push %%eax ; xchg %%eax, %0 ; pop %%eax" : : "m" (xchangeDummy)); - __asm__ volatile(" push %%eax ; push %%ebx ; push %%ecx ; push %%edx ;" - " movl $0,%%eax ; cpuid ; pop %%edx ; pop %%ecx ; pop %%ebx ;" - " pop %%eax" : /* no outputs */ : /* no inputs */ ); -} -#else -void mga_flush_write_combine(void) -{ + return; } -#endif /* These are two age tags that will never be sent to * the hardware */ @@ -113,13 +90,11 @@ drm_mga_freelist_t *item; int i; - DRM_DEBUG("%s\n", __FUNCTION__); - dev_priv->head = drm_alloc(sizeof(drm_mga_freelist_t), DRM_MEM_DRIVER); if(dev_priv->head == NULL) return -ENOMEM; memset(dev_priv->head, 0, sizeof(drm_mga_freelist_t)); dev_priv->head->age = MGA_BUF_USED; - + for (i = 0; i < dma->buf_count; i++) { buf = dma->buflist[ i ]; buf_priv = buf->dev_private; @@ -139,7 +114,7 @@ buf_priv->dispatched = 0; dev_priv->head->next = item; } - + return 0; } @@ -149,15 +124,13 @@ drm_mga_freelist_t *item; drm_mga_freelist_t *prev; - DRM_DEBUG("%s\n", __FUNCTION__); - item = dev_priv->head; while(item) { prev = item; item = item->next; drm_free(prev, sizeof(drm_mga_freelist_t), DRM_MEM_DRIVER); } - + dev_priv->head = dev_priv->tail = NULL; } @@ -170,19 +143,21 @@ unsigned long end; int i; - DRM_DEBUG("%s\n", __FUNCTION__); + DRM_DEBUG("dispatch_status = 0x%02x\n", dev_priv->dispatch_status); end = jiffies + (HZ*3); while(1) { - if(!test_and_set_bit(MGA_IN_DISPATCH, + if(!test_and_set_bit(MGA_IN_DISPATCH, &dev_priv->dispatch_status)) { break; } if((signed)(end - jiffies) <= 0) { - DRM_ERROR("irqs: %d wanted %d\n", - atomic_read(&dev->total_irq), + DRM_ERROR("irqs: %d wanted %d\n", + atomic_read(&dev->total_irq), atomic_read(&dma->total_lost)); - DRM_ERROR("lockup\n"); - goto out_nolock; + DRM_ERROR("lockup: dispatch_status = 0x%02x," + " jiffies = %lu, end = %lu\n", + dev_priv->dispatch_status, jiffies, end); + return; } for (i = 0 ; i < 2000 ; i++) mga_delay(); } @@ -190,19 +165,20 @@ DRM_DEBUG("quiescent status : %x\n", MGA_READ(MGAREG_STATUS)); while((MGA_READ(MGAREG_STATUS) & 0x00030001) != 0x00020000) { if((signed)(end - jiffies) <= 0) { - DRM_ERROR("irqs: %d wanted %d\n", - atomic_read(&dev->total_irq), + DRM_ERROR("irqs: %d wanted %d\n", + atomic_read(&dev->total_irq), atomic_read(&dma->total_lost)); - DRM_ERROR("lockup\n"); - goto out_status; + DRM_ERROR("lockup\n"); + clear_bit(MGA_IN_DISPATCH, &dev_priv->dispatch_status); + return; } - for (i = 0 ; i < 2000 ; i++) mga_delay(); + for (i = 0 ; i < 2000 ; i++) mga_delay(); } sarea_priv->dirty |= MGA_DMA_FLUSH; -out_status: clear_bit(MGA_IN_DISPATCH, &dev_priv->dispatch_status); -out_nolock: + DRM_DEBUG("exit, dispatch_status = 0x%02x\n", + dev_priv->dispatch_status); } static void mga_reset_freelist(drm_device_t *dev) @@ -220,44 +196,44 @@ } /* Least recently used : - * These operations are not atomic b/c they are protected by the + * These operations are not atomic b/c they are protected by the * hardware lock */ drm_buf_t *mga_freelist_get(drm_device_t *dev) { DECLARE_WAITQUEUE(entry, current); - drm_mga_private_t *dev_priv = + drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; drm_mga_freelist_t *prev; drm_mga_freelist_t *next; static int failed = 0; + int return_null = 0; - DRM_DEBUG("%s : tail->age : %d last_prim_age : %d\n", __FUNCTION__, - dev_priv->tail->age, dev_priv->last_prim_age); - if(failed >= 1000 && dev_priv->tail->age >= dev_priv->last_prim_age) { - DRM_DEBUG("I'm waiting on the freelist!!! %d\n", - dev_priv->last_prim_age); - set_bit(MGA_IN_GETBUF, &dev_priv->dispatch_status); - current->state = TASK_INTERRUPTIBLE; + DRM_DEBUG("Waiting on freelist," + " tail->age = %d, last_prim_age= %d\n", + dev_priv->tail->age, + dev_priv->last_prim_age); add_wait_queue(&dev_priv->buf_queue, &entry); + set_bit(MGA_IN_GETBUF, &dev_priv->dispatch_status); for (;;) { + current->state = TASK_INTERRUPTIBLE; mga_dma_schedule(dev, 0); - if(!test_bit(MGA_IN_GETBUF, - &dev_priv->dispatch_status)) + if(dev_priv->tail->age < dev_priv->last_prim_age) break; atomic_inc(&dev->total_sleeps); schedule(); if (signal_pending(current)) { - clear_bit(MGA_IN_GETBUF, - &dev_priv->dispatch_status); - goto failed_getbuf; + ++return_null; + break; } } - current->state = TASK_RUNNING; + clear_bit(MGA_IN_GETBUF, &dev_priv->dispatch_status); + current->state = TASK_RUNNING; remove_wait_queue(&dev_priv->buf_queue, &entry); + if (return_null) return NULL; } - + if(dev_priv->tail->age < dev_priv->last_prim_age) { prev = dev_priv->tail->prev; next = dev_priv->tail; @@ -269,22 +245,19 @@ return next->buf; } -failed_getbuf: failed++; return NULL; } int mga_freelist_put(drm_device_t *dev, drm_buf_t *buf) { - drm_mga_private_t *dev_priv = + drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; drm_mga_buf_priv_t *buf_priv = buf->dev_private; drm_mga_freelist_t *prev; drm_mga_freelist_t *head; drm_mga_freelist_t *next; - DRM_DEBUG("%s\n", __FUNCTION__); - if(buf_priv->my_freelist->age == MGA_BUF_USED) { /* Discarded buffer, put it on the tail */ next = buf_priv->my_freelist; @@ -294,7 +267,6 @@ next->prev = prev; next->next = NULL; dev_priv->tail = next; - DRM_DEBUG("Discarded\n"); } else { /* Normally aged buffer, put it on the head + 1, * as the real head is a sentinal element @@ -307,7 +279,7 @@ next->prev = head; next->next = prev; } - + return 0; } @@ -318,42 +290,41 @@ int i, temp, size_of_buf; int offset = init->reserved_map_agpstart; - DRM_DEBUG("%s\n", __FUNCTION__); - dev_priv->primary_size = ((init->primary_size + PAGE_SIZE - 1) / + dev_priv->primary_size = ((init->primary_size + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE; size_of_buf = dev_priv->primary_size / MGA_NUM_PRIM_BUFS; dev_priv->warp_ucode_size = init->warp_ucode_size; - dev_priv->prim_bufs = drm_alloc(sizeof(drm_mga_prim_buf_t *) * - (MGA_NUM_PRIM_BUFS + 1), + dev_priv->prim_bufs = drm_alloc(sizeof(drm_mga_prim_buf_t *) * + (MGA_NUM_PRIM_BUFS + 1), DRM_MEM_DRIVER); if(dev_priv->prim_bufs == NULL) { DRM_ERROR("Unable to allocate memory for prim_buf\n"); return -ENOMEM; } - memset(dev_priv->prim_bufs, + memset(dev_priv->prim_bufs, 0, sizeof(drm_mga_prim_buf_t *) * (MGA_NUM_PRIM_BUFS + 1)); - + temp = init->warp_ucode_size + dev_priv->primary_size; temp = ((temp + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE; - - dev_priv->ioremap = drm_ioremap(dev->agp->base + offset, + + dev_priv->ioremap = drm_ioremap(dev->agp->base + offset, temp); if(dev_priv->ioremap == NULL) { - DRM_DEBUG("Ioremap failed\n"); + DRM_ERROR("Ioremap failed\n"); return -ENOMEM; } init_waitqueue_head(&dev_priv->wait_queue); - + for(i = 0; i < MGA_NUM_PRIM_BUFS; i++) { - prim_buffer = drm_alloc(sizeof(drm_mga_prim_buf_t), + prim_buffer = drm_alloc(sizeof(drm_mga_prim_buf_t), DRM_MEM_DRIVER); if(prim_buffer == NULL) return -ENOMEM; memset(prim_buffer, 0, sizeof(drm_mga_prim_buf_t)); prim_buffer->phys_head = offset + dev->agp->base; - prim_buffer->current_dma_ptr = - prim_buffer->head = - (u32 *) (dev_priv->ioremap + - offset - + prim_buffer->current_dma_ptr = + prim_buffer->head = + (u32 *) (dev_priv->ioremap + + offset - init->reserved_map_agpstart); prim_buffer->num_dwords = 0; prim_buffer->max_dwords = size_of_buf / sizeof(u32); @@ -365,11 +336,11 @@ dev_priv->prim_bufs[i] = prim_buffer; } dev_priv->current_prim_idx = 0; - dev_priv->next_prim = - dev_priv->last_prim = + dev_priv->next_prim = + dev_priv->last_prim = dev_priv->current_prim = dev_priv->prim_bufs[0]; - dev_priv->next_prim_age = 2; + dev_priv->next_prim_age = 2; dev_priv->last_prim_age = 1; set_bit(MGA_BUF_IN_USE, &dev_priv->current_prim->buffer_status); return 0; @@ -386,13 +357,12 @@ int next_idx; PRIMLOCALS; - DRM_DEBUG("%s\n", __FUNCTION__); dev_priv->last_prim = prim; - + /* We never check for overflow, b/c there is always room */ PRIMPTR(prim); if(num_dwords <= 0) { - DRM_DEBUG("num_dwords == 0 when dispatched\n"); + DRM_ERROR("num_dwords == 0 when dispatched\n"); goto out_prim_wait; } PRIMOUTREG( MGAREG_DMAPAD, 0); @@ -403,32 +373,28 @@ end = jiffies + (HZ*3); if(sarea_priv->dirty & MGA_DMA_FLUSH) { - DRM_DEBUG("Dma top flush\n"); while((MGA_READ(MGAREG_STATUS) & 0x00030001) != 0x00020000) { if((signed)(end - jiffies) <= 0) { - DRM_ERROR("irqs: %d wanted %d\n", - atomic_read(&dev->total_irq), + DRM_ERROR("irqs: %d wanted %d\n", + atomic_read(&dev->total_irq), atomic_read(&dma->total_lost)); - DRM_ERROR("lockup in fire primary " - "(Dma Top Flush)\n"); + DRM_ERROR("lockup (flush)\n"); goto out_prim_wait; } - + for (i = 0 ; i < 4096 ; i++) mga_delay(); } sarea_priv->dirty &= ~(MGA_DMA_FLUSH); } else { - DRM_DEBUG("Status wait\n"); while((MGA_READ(MGAREG_STATUS) & 0x00020001) != 0x00020000) { if((signed)(end - jiffies) <= 0) { - DRM_ERROR("irqs: %d wanted %d\n", - atomic_read(&dev->total_irq), + DRM_ERROR("irqs: %d wanted %d\n", + atomic_read(&dev->total_irq), atomic_read(&dma->total_lost)); - DRM_ERROR("lockup in fire primary " - "(Status Wait)\n"); + DRM_ERROR("lockup (wait)\n"); goto out_prim_wait; } - + for (i = 0 ; i < 4096 ; i++) mga_delay(); } } @@ -439,9 +405,9 @@ MGA_WRITE(MGAREG_PRIMEND, (phys_head + num_dwords * 4) | use_agp); prim->num_dwords = 0; sarea_priv->last_enqueue = prim->prim_age; - + next_idx = prim->idx + 1; - if(next_idx >= MGA_NUM_PRIM_BUFS) + if(next_idx >= MGA_NUM_PRIM_BUFS) next_idx = 0; dev_priv->next_prim = dev_priv->prim_bufs[next_idx]; @@ -464,28 +430,26 @@ drm_device_dma_t *dma = dev->dma; int next_prim_idx; int ret = 0; - + /* This needs to reset the primary buffer if available, * we should collect stats on how many times it bites * it's tail */ - DRM_DEBUG("%s\n", __FUNCTION__); - + next_prim_idx = dev_priv->current_prim_idx + 1; if(next_prim_idx >= MGA_NUM_PRIM_BUFS) next_prim_idx = 0; prim_buffer = dev_priv->prim_bufs[next_prim_idx]; set_bit(MGA_IN_WAIT, &dev_priv->dispatch_status); - + /* In use is cleared in interrupt handler */ - + if(test_and_set_bit(MGA_BUF_IN_USE, &prim_buffer->buffer_status)) { add_wait_queue(&dev_priv->wait_queue, &entry); - current->state = TASK_INTERRUPTIBLE; - for (;;) { + current->state = TASK_INTERRUPTIBLE; mga_dma_schedule(dev, 0); - if(!test_and_set_bit(MGA_BUF_IN_USE, - &prim_buffer->buffer_status)) + if(!test_and_set_bit(MGA_BUF_IN_USE, + &prim_buffer->buffer_status)) break; atomic_inc(&dev->total_sleeps); atomic_inc(&dma->total_missed_sched); @@ -495,7 +459,7 @@ break; } } - current->state = TASK_RUNNING; + current->state = TASK_RUNNING; remove_wait_queue(&dev_priv->wait_queue, &entry); if(ret) return ret; } @@ -507,10 +471,10 @@ prim_buffer->sec_used = 0; prim_buffer->prim_age = dev_priv->next_prim_age++; if(prim_buffer->prim_age == 0 || prim_buffer->prim_age == 0xffffffff) { - mga_flush_queue(dev); - mga_dma_quiescent(dev); - mga_reset_freelist(dev); - prim_buffer->prim_age = (dev_priv->next_prim_age += 2); + mga_flush_queue(dev); + mga_dma_quiescent(dev); + mga_reset_freelist(dev); + prim_buffer->prim_age = (dev_priv->next_prim_age += 2); } /* Reset all buffer status stuff */ @@ -527,88 +491,72 @@ static inline int mga_decide_to_fire(drm_device_t *dev) { drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; - drm_device_dma_t *dma = dev->dma; - - DRM_DEBUG("%s\n", __FUNCTION__); if(test_bit(MGA_BUF_FORCE_FIRE, &dev_priv->next_prim->buffer_status)) { - atomic_inc(&dma->total_prio); return 1; } if (test_bit(MGA_IN_GETBUF, &dev_priv->dispatch_status) && dev_priv->next_prim->num_dwords) { - atomic_inc(&dma->total_prio); return 1; } if (test_bit(MGA_IN_FLUSH, &dev_priv->dispatch_status) && dev_priv->next_prim->num_dwords) { - atomic_inc(&dma->total_prio); return 1; } - + if(atomic_read(&dev_priv->pending_bufs) <= MGA_NUM_PRIM_BUFS - 1) { - if(test_bit(MGA_BUF_SWAP_PENDING, + if(test_bit(MGA_BUF_SWAP_PENDING, &dev_priv->next_prim->buffer_status)) { - atomic_inc(&dma->total_dmas); return 1; } } if(atomic_read(&dev_priv->pending_bufs) <= MGA_NUM_PRIM_BUFS / 2) { if(dev_priv->next_prim->sec_used >= MGA_DMA_BUF_NR / 8) { - atomic_inc(&dma->total_hit); return 1; } } if(atomic_read(&dev_priv->pending_bufs) >= MGA_NUM_PRIM_BUFS / 2) { if(dev_priv->next_prim->sec_used >= MGA_DMA_BUF_NR / 4) { - atomic_inc(&dma->total_missed_free); return 1; } } - atomic_inc(&dma->total_tried); return 0; } int mga_dma_schedule(drm_device_t *dev, int locked) { drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; - drm_device_dma_t *dma = dev->dma; - int retval = 0; + int retval = 0; - if (test_and_set_bit(0, &dev->dma_flag)) { - atomic_inc(&dma->total_missed_dma); + if (!dev_priv) return -EBUSY; + + if (test_and_set_bit(0, &dev->dma_flag)) { retval = -EBUSY; goto sch_out_wakeup; } - - DRM_DEBUG("%s\n", __FUNCTION__); - if(test_bit(MGA_IN_FLUSH, &dev_priv->dispatch_status) || + if(test_bit(MGA_IN_FLUSH, &dev_priv->dispatch_status) || test_bit(MGA_IN_WAIT, &dev_priv->dispatch_status) || test_bit(MGA_IN_GETBUF, &dev_priv->dispatch_status)) { locked = 1; } - - if (!locked && + + if (!locked && !drm_lock_take(&dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT)) { - atomic_inc(&dma->total_missed_lock); clear_bit(0, &dev->dma_flag); - DRM_DEBUG("Not locked\n"); retval = -EBUSY; goto sch_out_wakeup; } - DRM_DEBUG("I'm locked\n"); if(!test_and_set_bit(MGA_IN_DISPATCH, &dev_priv->dispatch_status)) { /* Fire dma buffer */ if(mga_decide_to_fire(dev)) { - DRM_DEBUG("idx :%d\n", dev_priv->next_prim->idx); - clear_bit(MGA_BUF_FORCE_FIRE, + clear_bit(MGA_BUF_FORCE_FIRE, &dev_priv->next_prim->buffer_status); if(dev_priv->current_prim == dev_priv->next_prim) { /* Schedule overflow for a later time */ @@ -619,10 +567,8 @@ } else { clear_bit(MGA_IN_DISPATCH, &dev_priv->dispatch_status); } - } else { - DRM_DEBUG("I can't get the dispatch lock\n"); } - + if (!locked) { if (drm_lock_free(dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT)) { @@ -630,6 +576,8 @@ } } + clear_bit(0, &dev->dma_flag); + sch_out_wakeup: if(test_bit(MGA_IN_FLUSH, &dev_priv->dispatch_status) && atomic_read(&dev_priv->pending_bufs) == 0) { @@ -638,18 +586,10 @@ wake_up_interruptible(&dev_priv->flush_queue); } - if(test_bit(MGA_IN_GETBUF, &dev_priv->dispatch_status) && - dev_priv->tail->age < dev_priv->last_prim_age) { - clear_bit(MGA_IN_GETBUF, &dev_priv->dispatch_status); - DRM_DEBUG("Waking up buf queue\n"); + if(test_bit(MGA_IN_GETBUF, &dev_priv->dispatch_status) + && dev_priv->tail->age < dev_priv->last_prim_age) wake_up_interruptible(&dev_priv->buf_queue); - } else if (test_bit(MGA_IN_GETBUF, &dev_priv->dispatch_status)) { - DRM_DEBUG("Not waking buf_queue on %d %d\n", - atomic_read(&dev->total_irq), - dev_priv->last_prim_age); - } - clear_bit(0, &dev->dma_flag); return retval; } @@ -659,41 +599,40 @@ drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; drm_mga_prim_buf_t *last_prim_buffer; - DRM_DEBUG("%s\n", __FUNCTION__); atomic_inc(&dev->total_irq); if((MGA_READ(MGAREG_STATUS) & 0x00000001) != 0x00000001) return; MGA_WRITE(MGAREG_ICLEAR, 0x00000001); last_prim_buffer = dev_priv->last_prim; last_prim_buffer->num_dwords = 0; last_prim_buffer->sec_used = 0; - dev_priv->sarea_priv->last_dispatch = + dev_priv->sarea_priv->last_dispatch = dev_priv->last_prim_age = last_prim_buffer->prim_age; clear_bit(MGA_BUF_IN_USE, &last_prim_buffer->buffer_status); - wake_up_interruptible(&dev_priv->wait_queue); clear_bit(MGA_BUF_SWAP_PENDING, &last_prim_buffer->buffer_status); clear_bit(MGA_IN_DISPATCH, &dev_priv->dispatch_status); atomic_dec(&dev_priv->pending_bufs); queue_task(&dev->tq, &tq_immediate); mark_bh(IMMEDIATE_BH); + wake_up_interruptible(&dev_priv->wait_queue); } static void mga_dma_task_queue(void *device) { - DRM_DEBUG("%s\n", __FUNCTION__); mga_dma_schedule((drm_device_t *)device, 0); } int mga_dma_cleanup(drm_device_t *dev) { - DRM_DEBUG("%s\n", __FUNCTION__); - if(dev->dev_private) { - drm_mga_private_t *dev_priv = + drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; - + + if (dev->irq) mga_flush_queue(dev); + mga_dma_quiescent(dev); + if(dev_priv->ioremap) { - int temp = (dev_priv->warp_ucode_size + - dev_priv->primary_size + + int temp = (dev_priv->warp_ucode_size + + dev_priv->primary_size + PAGE_SIZE - 1) / PAGE_SIZE * PAGE_SIZE; drm_ioremapfree((void *) dev_priv->ioremap, temp); @@ -714,7 +653,7 @@ } } drm_free(dev_priv->prim_bufs, sizeof(void *) * - (MGA_NUM_PRIM_BUFS + 1), + (MGA_NUM_PRIM_BUFS + 1), DRM_MEM_DRIVER); } if(dev_priv->head != NULL) { @@ -722,7 +661,7 @@ } - drm_free(dev->dev_private, sizeof(drm_mga_private_t), + drm_free(dev->dev_private, sizeof(drm_mga_private_t), DRM_MEM_DRIVER); dev->dev_private = NULL; } @@ -733,9 +672,6 @@ static int mga_dma_initialize(drm_device_t *dev, drm_mga_init_t *init) { drm_mga_private_t *dev_priv; drm_map_t *sarea_map = NULL; - int i; - - DRM_DEBUG("%s\n", __FUNCTION__); dev_priv = drm_alloc(sizeof(drm_mga_private_t), DRM_MEM_DRIVER); if(dev_priv == NULL) return -ENOMEM; @@ -746,15 +682,14 @@ if((init->reserved_map_idx >= dev->map_count) || (init->buffer_map_idx >= dev->map_count)) { mga_dma_cleanup(dev); - DRM_DEBUG("reserved_map or buffer_map are invalid\n"); return -EINVAL; } - + dev_priv->reserved_map_idx = init->reserved_map_idx; dev_priv->buffer_map_idx = init->buffer_map_idx; sarea_map = dev->maplist[0]; - dev_priv->sarea_priv = (drm_mga_sarea_t *) - ((u8 *)sarea_map->handle + + dev_priv->sarea_priv = (drm_mga_sarea_t *) + ((u8 *)sarea_map->handle + init->sarea_priv_offset); /* Scale primary size to the next page */ @@ -772,23 +707,17 @@ init_waitqueue_head(&dev_priv->flush_queue); init_waitqueue_head(&dev_priv->buf_queue); dev_priv->WarpPipe = 0xff000000; + dev_priv->vertexsize = 0; - DRM_DEBUG("chipset: %d ucode_size: %d backOffset: %x depthOffset: %x\n", - dev_priv->chipset, dev_priv->warp_ucode_size, + DRM_DEBUG("chipset=%d ucode_size=%d backOffset=%x depthOffset=%x\n", + dev_priv->chipset, dev_priv->warp_ucode_size, dev_priv->backOffset, dev_priv->depthOffset); DRM_DEBUG("cpp: %d sgram: %d stride: %d maccess: %x\n", - dev_priv->cpp, dev_priv->sgram, dev_priv->stride, + dev_priv->cpp, dev_priv->sgram, dev_priv->stride, dev_priv->mAccess); - - memcpy(&dev_priv->WarpIndex, &init->WarpIndex, - sizeof(drm_mga_warp_index_t) * MGA_MAX_WARP_PIPES); - for (i = 0 ; i < MGA_MAX_WARP_PIPES ; i++) - DRM_DEBUG("warp pipe %d: installed: %d phys: %lx size: %x\n", - i, - dev_priv->WarpIndex[i].installed, - dev_priv->WarpIndex[i].phys_addr, - dev_priv->WarpIndex[i].size); + memcpy(&dev_priv->WarpIndex, &init->WarpIndex, + sizeof(drm_mga_warp_index_t) * MGA_MAX_WARP_PIPES); if(mga_init_primary_bufs(dev, init) != 0) { DRM_ERROR("Can not initialize primary buffers\n"); @@ -802,7 +731,7 @@ return -ENOMEM; } - dev_priv->status_page = + dev_priv->status_page = ioremap_nocache(virt_to_bus((void *)dev_priv->real_status_page), PAGE_SIZE); @@ -813,15 +742,15 @@ } /* Write status page when secend or softrap occurs */ - MGA_WRITE(MGAREG_PRIMPTR, + MGA_WRITE(MGAREG_PRIMPTR, virt_to_bus((void *)dev_priv->real_status_page) | 0x00000003); - + /* Private is now filled in, initialize the hardware */ { PRIMLOCALS; PRIMGETPTR( dev_priv ); - + PRIMOUTREG(MGAREG_DMAPAD, 0); PRIMOUTREG(MGAREG_DMAPAD, 0); PRIMOUTREG(MGAREG_DWGSYNC, 0x0100); @@ -829,13 +758,13 @@ /* Poll for the first buffer to insure that * the status register will be correct */ - + mga_flush_write_combine(); MGA_WRITE(MGAREG_PRIMADDRESS, phys_head | TT_GENERAL); - MGA_WRITE(MGAREG_PRIMEND, ((phys_head + num_dwords * 4) | + MGA_WRITE(MGAREG_PRIMEND, ((phys_head + num_dwords * 4) | PDEA_pagpxfer_enable)); - + while(MGA_READ(MGAREG_DWGSYNC) != 0x0100) ; } @@ -853,12 +782,10 @@ drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; drm_mga_init_t init; - - DRM_DEBUG("%s\n", __FUNCTION__); if (copy_from_user(&init, (drm_mga_init_t *)arg, sizeof(init))) return -EFAULT; - + switch(init.func) { case MGA_INIT_DMA: return mga_dma_initialize(dev, &init); @@ -874,7 +801,7 @@ int retcode; if (!irq) return -EINVAL; - + down(&dev->struct_sem); if (dev->irq) { up(&dev->struct_sem); @@ -882,7 +809,7 @@ } dev->irq = irq; up(&dev->struct_sem); - + DRM_DEBUG("install irq handler %d\n", irq); dev->context_flag = 0; @@ -923,7 +850,7 @@ irq = dev->irq; dev->irq = 0; up(&dev->struct_sem); - + if (!irq) return -EINVAL; DRM_DEBUG("remove irq handler %d\n", irq); MGA_WRITE(MGAREG_ICLEAR, 0x00000001); @@ -938,12 +865,10 @@ drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; drm_control_t ctl; - + if (copy_from_user(&ctl, (drm_control_t *)arg, sizeof(ctl))) return -EFAULT; - DRM_DEBUG("%s\n", __FUNCTION__); - switch (ctl.func) { case DRM_INST_HANDLER: return mga_irq_install(dev, ctl.irq); @@ -960,31 +885,29 @@ drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; int ret = 0; - DRM_DEBUG("%s\n", __FUNCTION__); + if(!dev_priv) return 0; - if(dev_priv == NULL) { - return 0; - } - if(dev_priv->next_prim->num_dwords != 0) { - current->state = TASK_INTERRUPTIBLE; add_wait_queue(&dev_priv->flush_queue, &entry); + if (test_bit(MGA_IN_FLUSH, &dev_priv->dispatch_status)) + DRM_ERROR("Incorrect mga_flush_queue logic\n"); set_bit(MGA_IN_FLUSH, &dev_priv->dispatch_status); mga_dma_schedule(dev, 0); for (;;) { - if (!test_bit(MGA_IN_FLUSH, - &dev_priv->dispatch_status)) + current->state = TASK_INTERRUPTIBLE; + if (!test_bit(MGA_IN_FLUSH, + &dev_priv->dispatch_status)) break; atomic_inc(&dev->total_sleeps); schedule(); if (signal_pending(current)) { ret = -EINTR; /* Can't restart */ - clear_bit(MGA_IN_FLUSH, + clear_bit(MGA_IN_FLUSH, &dev_priv->dispatch_status); break; } } - current->state = TASK_RUNNING; + current->state = TASK_RUNNING; remove_wait_queue(&dev_priv->flush_queue, &entry); } return ret; @@ -1000,18 +923,19 @@ if(dev->dev_private == NULL) return; if(dma->buflist == NULL) return; - DRM_DEBUG("%s\n", __FUNCTION__); + DRM_DEBUG("buf_count=%d\n", dma->buf_count); + mga_flush_queue(dev); for (i = 0; i < dma->buf_count; i++) { drm_buf_t *buf = dma->buflist[ i ]; drm_mga_buf_priv_t *buf_priv = buf->dev_private; - /* Only buffers that need to get reclaimed ever - * get set to free + /* Only buffers that need to get reclaimed ever + * get set to free */ if (buf->pid == pid && buf_priv) { - if(buf_priv->my_freelist->age == MGA_BUF_USED) + if(buf_priv->my_freelist->age == MGA_BUF_USED) buf_priv->my_freelist->age = MGA_BUF_FREE; } } @@ -1026,7 +950,6 @@ int ret = 0; drm_lock_t lock; - DRM_DEBUG("%s\n", __FUNCTION__); if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock))) return -EFAULT; @@ -1035,21 +958,16 @@ current->pid, lock.context); return -EINVAL; } - - DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n", - lock.context, current->pid, dev->lock.hw_lock->lock, - lock.flags); - if (lock.context < 0) { - return -EINVAL; - } - + if (lock.context < 0) return -EINVAL; + /* Only one queue: */ if (!ret) { add_wait_queue(&dev->lock.lock_queue, &entry); for (;;) { + current->state = TASK_INTERRUPTIBLE; if (!dev->lock.hw_lock) { /* Device has been unregistered */ ret = -EINTR; @@ -1062,10 +980,9 @@ atomic_inc(&dev->total_locks); break; /* Got lock */ } - + /* Contention */ atomic_inc(&dev->total_sleeps); - current->state = TASK_INTERRUPTIBLE; schedule(); if (signal_pending(current)) { ret = -ERESTARTSYS; @@ -1075,7 +992,7 @@ current->state = TASK_RUNNING; remove_wait_queue(&dev->lock.lock_queue, &entry); } - + if (!ret) { sigemptyset(&dev->sigmask); sigaddset(&dev->sigmask, SIGSTOP); @@ -1092,12 +1009,13 @@ mga_dma_quiescent(dev); } } - - DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock"); + + if (ret) DRM_DEBUG("%d %s\n", lock.context, + ret ? "interrupted" : "has lock"); return ret; } - -int mga_flush_ioctl(struct inode *inode, struct file *filp, + +int mga_flush_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { drm_file_t *priv = filp->private_data; @@ -1105,12 +1023,11 @@ drm_lock_t lock; drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; - DRM_DEBUG("%s\n", __FUNCTION__); if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock))) return -EFAULT; if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { - DRM_ERROR("mga_flush_ioctl called without lock held\n"); + DRM_ERROR("lock not held\n"); return -EINVAL; } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/drm/mga_drm.h linux/drivers/char/drm/mga_drm.h --- v2.4.0-test8/linux/drivers/char/drm/mga_drm.h Fri Jul 21 12:56:44 2000 +++ linux/drivers/char/drm/mga_drm.h Fri Sep 15 14:24:55 2000 @@ -73,17 +73,19 @@ /* 3d state excluding texture units: */ -#define MGA_CTXREG_DSTORG 0 /* validated */ -#define MGA_CTXREG_MACCESS 1 -#define MGA_CTXREG_PLNWT 2 -#define MGA_CTXREG_DWGCTL 3 -#define MGA_CTXREG_ALPHACTRL 4 -#define MGA_CTXREG_FOGCOLOR 5 -#define MGA_CTXREG_WFLAG 6 -#define MGA_CTXREG_TDUAL0 7 -#define MGA_CTXREG_TDUAL1 8 -#define MGA_CTXREG_FCOL 9 -#define MGA_CTX_SETUP_SIZE 10 +#define MGA_CTXREG_DSTORG 0 /* validated */ +#define MGA_CTXREG_MACCESS 1 +#define MGA_CTXREG_PLNWT 2 +#define MGA_CTXREG_DWGCTL 3 +#define MGA_CTXREG_ALPHACTRL 4 +#define MGA_CTXREG_FOGCOLOR 5 +#define MGA_CTXREG_WFLAG 6 +#define MGA_CTXREG_TDUAL0 7 +#define MGA_CTXREG_TDUAL1 8 +#define MGA_CTXREG_FCOL 9 +#define MGA_CTXREG_STENCIL 10 +#define MGA_CTXREG_STENCILCTL 11 +#define MGA_CTX_SETUP_SIZE 12 /* 2d state */ @@ -233,6 +235,7 @@ /* Mechanism to validate card state. */ int ctxOwner; + int vertexsize; } drm_mga_sarea_t; /* Device specific ioctls: @@ -241,6 +244,8 @@ unsigned int clear_color; unsigned int clear_depth; unsigned int flags; + unsigned int clear_depth_mask; + unsigned int clear_color_mask; } drm_mga_clear_t; typedef struct _drm_mga_swap { diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/drm/mga_drv.c linux/drivers/char/drm/mga_drv.c --- v2.4.0-test8/linux/drivers/char/drm/mga_drv.c Tue Aug 29 21:09:10 2000 +++ linux/drivers/char/drm/mga_drv.c Sun Oct 1 20:00:00 2000 @@ -1,6 +1,6 @@ /* mga_drv.c -- Matrox g200/g400 driver -*- linux-c -*- * Created: Mon Dec 13 01:56:22 1999 by jhartmann@precisioninsight.com - * + * * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. * All Rights Reserved. @@ -11,11 +11,11 @@ * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL @@ -35,11 +35,11 @@ #include "mga_drv.h" #define MGA_NAME "mga" -#define MGA_DESC "Matrox g200/g400" -#define MGA_DATE "20000719" -#define MGA_MAJOR 1 +#define MGA_DESC "Matrox G200/G400" +#define MGA_DATE "20000928" +#define MGA_MAJOR 2 #define MGA_MINOR 0 -#define MGA_PATCHLEVEL 0 +#define MGA_PATCHLEVEL 1 static drm_device_t mga_device; drm_ctx_t mga_res_ctx; @@ -123,7 +123,7 @@ #endif MODULE_AUTHOR("VA Linux Systems, Inc."); -MODULE_DESCRIPTION("Matrox g200/g400"); +MODULE_DESCRIPTION("Matrox G200/G400"); MODULE_PARM(mga, "s"); #ifndef MODULE @@ -144,7 +144,7 @@ static int mga_setup(drm_device_t *dev) { int i; - + atomic_set(&dev->ioctl_count, 0); atomic_set(&dev->vma_count, 0); dev->buf_use = 0; @@ -187,22 +187,22 @@ dev->ctx_start = 0; dev->lck_start = 0; - + dev->buf_rp = dev->buf; dev->buf_wp = dev->buf; dev->buf_end = dev->buf + DRM_BSZ; dev->buf_async = NULL; init_waitqueue_head(&dev->buf_readers); init_waitqueue_head(&dev->buf_writers); - + DRM_DEBUG("\n"); - + /* The kernel's context could be created here, but is now created in drm_dma_enqueue. This is more resource-efficient for hardware that does not do DMA, but may mean that drm_select_queue fails between the time the interrupt is initialized and the time the queues are initialized. */ - + return 0; } @@ -216,16 +216,17 @@ DRM_DEBUG("\n"); + if (dev->dev_private) mga_dma_cleanup(dev); if (dev->irq) mga_irq_uninstall(dev); - + down(&dev->struct_sem); del_timer(&dev->timer); - + if (dev->devname) { drm_free(dev->devname, strlen(dev->devname)+1, DRM_MEM_DRIVER); dev->devname = NULL; } - + if (dev->unique) { drm_free(dev->unique, strlen(dev->unique)+1, DRM_MEM_DRIVER); dev->unique = NULL; @@ -243,7 +244,7 @@ if (dev->agp) { drm_agp_mem_t *entry; drm_agp_mem_t *nexte; - + /* Remove AGP resources, but leave dev->agp intact until cleanup is called. */ for (entry = dev->agp->memory; entry; entry = nexte) { @@ -253,10 +254,10 @@ drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS); } dev->agp->memory = NULL; - + if (dev->agp->acquired && drm_agp.release) (*drm_agp.release)(); - + dev->agp->acquired = 0; dev->agp->enabled = 0; } @@ -268,7 +269,7 @@ } dev->vmalist = NULL; } - + /* Clear map area and mtrr information */ if (dev->maplist) { for (i = 0; i < dev->map_count; i++) { @@ -304,7 +305,7 @@ dev->maplist = NULL; dev->map_count = 0; } - + if (dev->queuelist) { for (i = 0; i < dev->queue_count; i++) { drm_waitlist_destroy(&dev->queuelist[i]->waitlist); @@ -330,7 +331,7 @@ wake_up_interruptible(&dev->lock.lock_queue); } up(&dev->struct_sem); - + return 0; } @@ -347,11 +348,10 @@ memset((void *)dev, 0, sizeof(*dev)); dev->count_lock = SPIN_LOCK_UNLOCKED; sema_init(&dev->struct_sem, 1); - + #ifdef MODULE drm_parse_options(mga); #endif - DRM_DEBUG("doing misc_register\n"); if ((retcode = misc_register(&mga_misc))) { DRM_ERROR("Cannot register \"%s\"\n", MGA_NAME); return retcode; @@ -359,11 +359,8 @@ dev->device = MKDEV(MISC_MAJOR, mga_misc.minor); dev->name = MGA_NAME; - DRM_DEBUG("doing mem init\n"); drm_mem_init(); - DRM_DEBUG("doing proc init\n"); drm_proc_init(dev); - DRM_DEBUG("doing agp init\n"); dev->agp = drm_agp_init(); if(dev->agp == NULL) { DRM_INFO("The mga drm module requires the agpgart module" @@ -380,7 +377,6 @@ MTRR_TYPE_WRCOMB, 1); #endif - DRM_DEBUG("doing ctxbitmap init\n"); if((retcode = drm_ctxbitmap_init(dev))) { DRM_ERROR("Cannot allocate memory for context bitmap.\n"); drm_proc_cleanup(); @@ -407,7 +403,7 @@ drm_device_t *dev = &mga_device; DRM_DEBUG("\n"); - + drm_proc_cleanup(); if (misc_deregister(&mga_misc)) { DRM_ERROR("Cannot unload module\n"); @@ -415,11 +411,10 @@ DRM_INFO("Module unloaded\n"); } drm_ctxbitmap_cleanup(dev); - mga_dma_cleanup(dev); #ifdef CONFIG_MTRR if(dev->agp && dev->agp->agp_mtrr) { int retval; - retval = mtrr_del(dev->agp->agp_mtrr, + retval = mtrr_del(dev->agp->agp_mtrr, dev->agp->agp_info.aper_base, dev->agp->agp_info.aper_size * 1024*1024); DRM_DEBUG("mtrr_del = %d\n", retval); @@ -477,7 +472,7 @@ { drm_device_t *dev = &mga_device; int retcode = 0; - + DRM_DEBUG("open_count = %d\n", dev->open_count); if (!(retcode = drm_open_helper(inode, filp, dev))) { #if LINUX_VERSION_CODE < 0x020333 @@ -508,22 +503,27 @@ if (dev->lock.hw_lock && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) && dev->lock.pid == current->pid) { mga_reclaim_buffers(dev, priv->pid); - DRM_ERROR("Process %d dead, freeing lock for context %d\n", - current->pid, - _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); + DRM_INFO("Process %d dead (ctx %d, d_s = 0x%02x)\n", + current->pid, + _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock), + dev->dev_private ? + ((drm_mga_private_t *)dev->dev_private) + ->dispatch_status + : 0); + + if (dev->dev_private) + ((drm_mga_private_t *)dev->dev_private) + ->dispatch_status &= MGA_IN_DISPATCH; + drm_lock_free(dev, &dev->lock.hw_lock->lock, _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); - - /* FIXME: may require heavy-handed reset of - hardware at this point, possibly - processed via a callback to the X - server. */ } else if (dev->lock.hw_lock) { /* The lock is required to reclaim buffers */ DECLARE_WAITQUEUE(entry, current); add_wait_queue(&dev->lock.lock_queue, &entry); for (;;) { + current->state = TASK_INTERRUPTIBLE; if (!dev->lock.hw_lock) { /* Device has been unregistered */ retcode = -EINTR; @@ -535,10 +535,9 @@ dev->lock.lock_time = jiffies; atomic_inc(&dev->total_locks); break; /* Got lock */ - } + } /* Contention */ atomic_inc(&dev->total_sleeps); - current->state = TASK_INTERRUPTIBLE; schedule(); if (signal_pending(current)) { retcode = -ERESTARTSYS; @@ -549,6 +548,9 @@ remove_wait_queue(&dev->lock.lock_queue, &entry); if(!retcode) { mga_reclaim_buffers(dev, priv->pid); + if (dev->dev_private) + ((drm_mga_private_t *)dev->dev_private) + ->dispatch_status &= MGA_IN_DISPATCH; drm_lock_free(dev, &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT); } @@ -556,12 +558,19 @@ drm_fasync(-1, filp, 0); down(&dev->struct_sem); + if (priv->remove_auth_on_close == 1) { + drm_file_t *temp = dev->file_first; + while(temp) { + temp->authenticated = 0; + temp = temp->next; + } + } if (priv->prev) priv->prev->next = priv->next; else dev->file_first = priv->next; if (priv->next) priv->next->prev = priv->prev; else dev->file_last = priv->prev; up(&dev->struct_sem); - + drm_free(priv, sizeof(*priv), DRM_MEM_FILES); #if LINUX_VERSION_CODE < 0x020333 MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */ @@ -602,9 +611,6 @@ atomic_inc(&dev->ioctl_count); atomic_inc(&dev->total_ioctl); ++priv->ioctl_count; - - DRM_DEBUG("pid = %d, cmd = 0x%02x, nr = 0x%02x, dev 0x%x, auth = %d\n", - current->pid, cmd, nr, dev->device, priv->authenticated); if (nr >= MGA_IOCTL_COUNT) { retcode = -EINVAL; @@ -613,7 +619,10 @@ func = ioctl->func; if (!func) { - DRM_DEBUG("no function\n"); + DRM_DEBUG("no function: pid = %d, cmd = 0x%02x," + " nr = 0x%02x, dev 0x%x, auth = %d\n", + current->pid, cmd, nr, dev->device, + priv->authenticated); retcode = -EINVAL; } else if ((ioctl->root_only && !capable(CAP_SYS_ADMIN)) || (ioctl->auth_needed && !priv->authenticated)) { @@ -622,7 +631,7 @@ retcode = (func)(inode, filp, cmd, arg); } } - + atomic_dec(&dev->ioctl_count); return retcode; } @@ -636,16 +645,13 @@ if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock))) return -EFAULT; - + if (lock.context == DRM_KERNEL_CONTEXT) { DRM_ERROR("Process %d using kernel context %d\n", current->pid, lock.context); return -EINVAL; } - DRM_DEBUG("%d frees lock (%d holds)\n", - lock.context, - _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)); atomic_inc(&dev->total_unlocks); if (_DRM_LOCK_IS_CONT(dev->lock.hw_lock->lock)) atomic_inc(&dev->total_contends); @@ -653,9 +659,7 @@ mga_dma_schedule(dev, 1); if (drm_lock_free(dev, &dev->lock.hw_lock->lock, - DRM_KERNEL_CONTEXT)) { - DRM_ERROR("\n"); - } + DRM_KERNEL_CONTEXT)) DRM_ERROR("\n"); unblock_all_signals(); return 0; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/drm/mga_drv.h linux/drivers/char/drm/mga_drv.h --- v2.4.0-test8/linux/drivers/char/drm/mga_drv.h Tue Aug 29 21:09:10 2000 +++ linux/drivers/char/drm/mga_drv.h Sun Oct 1 20:00:00 2000 @@ -11,11 +11,11 @@ * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL @@ -50,7 +50,7 @@ } drm_mga_prim_buf_t; typedef struct _drm_mga_freelist { - unsigned int age; + __volatile__ unsigned int age; drm_buf_t *buf; struct _drm_mga_freelist *next; struct _drm_mga_freelist *prev; @@ -82,6 +82,7 @@ int use_agp; drm_mga_warp_index_t WarpIndex[MGA_MAX_G400_PIPES]; unsigned int WarpPipe; + unsigned int vertexsize; atomic_t pending_bufs; void *status_page; unsigned long real_status_page; @@ -97,7 +98,7 @@ wait_queue_head_t wait_queue; /* Processes waiting until interrupt */ wait_queue_head_t buf_queue; /* Processes waiting for a free buf */ /* Some validated register values: - */ + */ u32 mAccess; } drm_mga_private_t; @@ -128,7 +129,6 @@ extern int mga_dma_cleanup(drm_device_t *dev); extern int mga_flush_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); -extern void mga_flush_write_combine(void); extern unsigned int mga_create_sync_tag(drm_device_t *dev); extern drm_buf_t *mga_freelist_get(drm_device_t *dev); extern int mga_freelist_put(drm_device_t *dev, drm_buf_t *buf); @@ -137,9 +137,9 @@ /* mga_bufs.c */ -extern int mga_addbufs(struct inode *inode, struct file *filp, +extern int mga_addbufs(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); -extern int mga_infobufs(struct inode *inode, struct file *filp, +extern int mga_infobufs(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); extern int mga_markbufs(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); @@ -179,6 +179,7 @@ extern int mga_context_switch(drm_device_t *dev, int old, int new); extern int mga_context_switch_complete(drm_device_t *dev, int new); +#define mga_flush_write_combine() mb() typedef enum { TT_GENERAL, @@ -201,7 +202,7 @@ #define ISREG0(r) (r >= DWGREG0 && r <= DWGREG0_END) #define ADRINDEX0(r) (u8)((r - DWGREG0) >> 2) #define ADRINDEX1(r) (u8)(((r - DWGREG1) >> 2) | 0x80) -#define ADRINDEX(r) (ISREG0(r) ? ADRINDEX0(r) : ADRINDEX1(r)) +#define ADRINDEX(r) (ISREG0(r) ? ADRINDEX0(r) : ADRINDEX1(r)) #define MGA_VERBOSE 0 #define MGA_NUM_PRIM_BUFS 8 @@ -212,13 +213,12 @@ #define PRIM_OVERFLOW(dev, dev_priv, length) do { \ drm_mga_prim_buf_t *tmp_buf = \ dev_priv->prim_bufs[dev_priv->current_prim_idx]; \ - if( test_bit(MGA_BUF_NEEDS_OVERFLOW, \ - &tmp_buf->buffer_status)) { \ + if( test_bit(MGA_BUF_NEEDS_OVERFLOW, &tmp_buf->buffer_status)) { \ mga_advance_primary(dev); \ mga_dma_schedule(dev, 1); \ tmp_buf = dev_priv->prim_bufs[dev_priv->current_prim_idx]; \ } else if( tmp_buf->max_dwords - tmp_buf->num_dwords < length || \ - tmp_buf->sec_used > MGA_DMA_BUF_NR/2) { \ + tmp_buf->sec_used > MGA_DMA_BUF_NR/2) { \ set_bit(MGA_BUF_FORCE_FIRE, &tmp_buf->buffer_status); \ mga_advance_primary(dev); \ mga_dma_schedule(dev, 1); \ @@ -295,7 +295,7 @@ num_dwords + 1 + outcount, ADRINDEX(reg), val); \ if( ++outcount == 4) { \ outcount = 0; \ - dma_ptr[0] = *(u32 *)tempIndex; \ + dma_ptr[0] = *(unsigned long *)tempIndex; \ dma_ptr+=5; \ num_dwords += 5; \ } \ @@ -377,6 +377,72 @@ #define MGAREG_YTOP 0x1c98 #define MGAREG_ZORG 0x1c0c +/* Warp registers */ +#define MGAREG_WR0 0x2d00 +#define MGAREG_WR1 0x2d04 +#define MGAREG_WR2 0x2d08 +#define MGAREG_WR3 0x2d0c +#define MGAREG_WR4 0x2d10 +#define MGAREG_WR5 0x2d14 +#define MGAREG_WR6 0x2d18 +#define MGAREG_WR7 0x2d1c +#define MGAREG_WR8 0x2d20 +#define MGAREG_WR9 0x2d24 +#define MGAREG_WR10 0x2d28 +#define MGAREG_WR11 0x2d2c +#define MGAREG_WR12 0x2d30 +#define MGAREG_WR13 0x2d34 +#define MGAREG_WR14 0x2d38 +#define MGAREG_WR15 0x2d3c +#define MGAREG_WR16 0x2d40 +#define MGAREG_WR17 0x2d44 +#define MGAREG_WR18 0x2d48 +#define MGAREG_WR19 0x2d4c +#define MGAREG_WR20 0x2d50 +#define MGAREG_WR21 0x2d54 +#define MGAREG_WR22 0x2d58 +#define MGAREG_WR23 0x2d5c +#define MGAREG_WR24 0x2d60 +#define MGAREG_WR25 0x2d64 +#define MGAREG_WR26 0x2d68 +#define MGAREG_WR27 0x2d6c +#define MGAREG_WR28 0x2d70 +#define MGAREG_WR29 0x2d74 +#define MGAREG_WR30 0x2d78 +#define MGAREG_WR31 0x2d7c +#define MGAREG_WR32 0x2d80 +#define MGAREG_WR33 0x2d84 +#define MGAREG_WR34 0x2d88 +#define MGAREG_WR35 0x2d8c +#define MGAREG_WR36 0x2d90 +#define MGAREG_WR37 0x2d94 +#define MGAREG_WR38 0x2d98 +#define MGAREG_WR39 0x2d9c +#define MGAREG_WR40 0x2da0 +#define MGAREG_WR41 0x2da4 +#define MGAREG_WR42 0x2da8 +#define MGAREG_WR43 0x2dac +#define MGAREG_WR44 0x2db0 +#define MGAREG_WR45 0x2db4 +#define MGAREG_WR46 0x2db8 +#define MGAREG_WR47 0x2dbc +#define MGAREG_WR48 0x2dc0 +#define MGAREG_WR49 0x2dc4 +#define MGAREG_WR50 0x2dc8 +#define MGAREG_WR51 0x2dcc +#define MGAREG_WR52 0x2dd0 +#define MGAREG_WR53 0x2dd4 +#define MGAREG_WR54 0x2dd8 +#define MGAREG_WR55 0x2ddc +#define MGAREG_WR56 0x2de0 +#define MGAREG_WR57 0x2de4 +#define MGAREG_WR58 0x2de8 +#define MGAREG_WR59 0x2dec +#define MGAREG_WR60 0x2df0 +#define MGAREG_WR61 0x2df4 +#define MGAREG_WR62 0x2df8 +#define MGAREG_WR63 0x2dfc + #define PDEA_pagpxfer_enable 0x2 #define WIA_wmode_suspend 0x0 @@ -396,8 +462,8 @@ #define DC_atype_zi 0x30 #define DC_atype_blk 0x40 #define DC_atype_i 0x70 -#define DC_linear_xy 0x0 -#define DC_linear_linear 0x80 +#define DC_linear_xy 0x0 +#define DC_linear_linear 0x80 #define DC_zmode_nozcmp 0x0 #define DC_zmode_ze 0x200 #define DC_zmode_zne 0x300 @@ -405,16 +471,16 @@ #define DC_zmode_zlte 0x500 #define DC_zmode_zgt 0x600 #define DC_zmode_zgte 0x700 -#define DC_solid_disable 0x0 -#define DC_solid_enable 0x800 -#define DC_arzero_disable 0x0 -#define DC_arzero_enable 0x1000 -#define DC_sgnzero_disable 0x0 -#define DC_sgnzero_enable 0x2000 -#define DC_shftzero_disable 0x0 -#define DC_shftzero_enable 0x4000 -#define DC_bop_SHIFT 16 -#define DC_trans_SHIFT 20 +#define DC_solid_disable 0x0 +#define DC_solid_enable 0x800 +#define DC_arzero_disable 0x0 +#define DC_arzero_enable 0x1000 +#define DC_sgnzero_disable 0x0 +#define DC_sgnzero_enable 0x2000 +#define DC_shftzero_disable 0x0 +#define DC_shftzero_enable 0x4000 +#define DC_bop_SHIFT 16 +#define DC_trans_SHIFT 20 #define DC_bltmod_bmonolef 0x0 #define DC_bltmod_bmonowf 0x8000000 #define DC_bltmod_bplan 0x2000000 @@ -423,21 +489,22 @@ #define DC_bltmod_bu32rgb 0xe000000 #define DC_bltmod_bu24bgr 0x16000000 #define DC_bltmod_bu24rgb 0x1e000000 -#define DC_pattern_disable 0x0 -#define DC_pattern_enable 0x20000000 -#define DC_transc_disable 0x0 -#define DC_transc_enable 0x40000000 -#define DC_clipdis_disable 0x0 -#define DC_clipdis_enable 0x80000000 +#define DC_pattern_disable 0x0 +#define DC_pattern_enable 0x20000000 +#define DC_transc_disable 0x0 +#define DC_transc_enable 0x40000000 +#define DC_clipdis_disable 0x0 +#define DC_clipdis_enable 0x80000000 -#define SETADD_mode_vertlist 0x0 + +#define SETADD_mode_vertlist 0x0 #define MGA_CLEAR_CMD (DC_opcod_trap | DC_arzero_enable | \ DC_sgnzero_enable | DC_shftzero_enable | \ (0xC << DC_bop_SHIFT) | DC_clipdis_enable | \ DC_solid_enable | DC_transc_enable) - + #define MGA_COPY_CMD (DC_opcod_bitblt | DC_atype_rpl | DC_linear_xy | \ DC_solid_disable | DC_arzero_disable | \ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/drm/mga_state.c linux/drivers/char/drm/mga_state.c --- v2.4.0-test8/linux/drivers/char/drm/mga_state.c Tue Aug 29 21:09:10 2000 +++ linux/drivers/char/drm/mga_state.c Sun Oct 1 20:00:00 2000 @@ -11,11 +11,11 @@ * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL @@ -38,13 +38,13 @@ * change these values */ -#define MGAEMITCLIP_SIZE 10 -#define MGAEMITCTX_SIZE 15 -#define MGAG200EMITTEX_SIZE 20 -#define MGAG400EMITTEX0_SIZE 30 -#define MGAG400EMITTEX1_SIZE 25 -#define MGAG400EMITPIPE_SIZE 50 -#define MGAG200EMITPIPE_SIZE 15 +#define MGAEMITCLIP_SIZE 10 +#define MGAEMITCTX_SIZE 20 +#define MGAG200EMITTEX_SIZE 20 +#define MGAG400EMITTEX0_SIZE 30 +#define MGAG400EMITTEX1_SIZE 25 +#define MGAG400EMITPIPE_SIZE 50 +#define MGAG200EMITPIPE_SIZE 15 #define MAX_STATE_SIZE ((MGAEMITCLIP_SIZE * MGA_NR_SAREA_CLIPRECTS) + \ MGAEMITCTX_SIZE + MGAG400EMITTEX0_SIZE + \ @@ -56,24 +56,24 @@ drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; unsigned int *regs = sarea_priv->ContextState; PRIMLOCALS; - DRM_DEBUG("%s\n", __FUNCTION__); /* This takes 10 dwords */ PRIMGETPTR(dev_priv); - /* Force reset of dwgctl (eliminates clip disable) */ + /* Force reset of dwgctl on G400 (eliminates clip disable bit) */ + if (dev_priv->chipset == MGA_CARD_TYPE_G400) { #if 0 - PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_DWGSYNC, 0); - PRIMOUTREG(MGAREG_DWGSYNC, 0); - PRIMOUTREG(MGAREG_DWGCTL, regs[MGA_CTXREG_DWGCTL]); + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_DWGSYNC, 0); + PRIMOUTREG(MGAREG_DWGSYNC, 0); + PRIMOUTREG(MGAREG_DWGCTL, regs[MGA_CTXREG_DWGCTL]); #else - PRIMOUTREG(MGAREG_DWGCTL, regs[MGA_CTXREG_DWGCTL]); - PRIMOUTREG(MGAREG_LEN + MGAREG_MGA_EXEC, 0x80000000); - PRIMOUTREG(MGAREG_DWGCTL, regs[MGA_CTXREG_DWGCTL]); - PRIMOUTREG(MGAREG_LEN + MGAREG_MGA_EXEC, 0x80000000); + PRIMOUTREG(MGAREG_DWGCTL, regs[MGA_CTXREG_DWGCTL]); + PRIMOUTREG(MGAREG_LEN + MGAREG_MGA_EXEC, 0x80000000); + PRIMOUTREG(MGAREG_DWGCTL, regs[MGA_CTXREG_DWGCTL]); + PRIMOUTREG(MGAREG_LEN + MGAREG_MGA_EXEC, 0x80000000); #endif - + } PRIMOUTREG(MGAREG_DMAPAD, 0); PRIMOUTREG(MGAREG_CXBNDRY, ((box->x2) << 16) | (box->x1)); PRIMOUTREG(MGAREG_YTOP, box->y1 * dev_priv->stride / dev_priv->cpp); @@ -87,9 +87,8 @@ drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; unsigned int *regs = sarea_priv->ContextState; PRIMLOCALS; - DRM_DEBUG("%s\n", __FUNCTION__); - /* This takes a max of 15 dwords */ + /* This takes a max of 20 dwords */ PRIMGETPTR(dev_priv); PRIMOUTREG(MGAREG_DSTORG, regs[MGA_CTXREG_DSTORG]); @@ -107,6 +106,11 @@ PRIMOUTREG(MGAREG_TDUALSTAGE0, regs[MGA_CTXREG_TDUAL0]); PRIMOUTREG(MGAREG_TDUALSTAGE1, regs[MGA_CTXREG_TDUAL1]); PRIMOUTREG(MGAREG_FCOL, regs[MGA_CTXREG_FCOL]); + + PRIMOUTREG(MGAREG_STENCIL, regs[MGA_CTXREG_STENCIL]); + PRIMOUTREG(MGAREG_STENCILCTL, regs[MGA_CTXREG_STENCILCTL]); + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_DMAPAD, 0); } else { PRIMOUTREG(MGAREG_FCOL, regs[MGA_CTXREG_FCOL]); PRIMOUTREG(MGAREG_DMAPAD, 0); @@ -122,7 +126,6 @@ drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; unsigned int *regs = sarea_priv->TexState[0]; PRIMLOCALS; - DRM_DEBUG("%s\n", __FUNCTION__); PRIMGETPTR(dev_priv); @@ -141,9 +144,9 @@ PRIMOUTREG(MGAREG_TEXORG4, regs[MGA_TEXREG_ORG4]); PRIMOUTREG(MGAREG_TEXWIDTH, regs[MGA_TEXREG_WIDTH]); PRIMOUTREG(MGAREG_TEXHEIGHT, regs[MGA_TEXREG_HEIGHT]); - PRIMOUTREG(0x2d00 + 24 * 4, regs[MGA_TEXREG_WIDTH]); + PRIMOUTREG(MGAREG_WR24, regs[MGA_TEXREG_WIDTH]); - PRIMOUTREG(0x2d00 + 34 * 4, regs[MGA_TEXREG_HEIGHT]); + PRIMOUTREG(MGAREG_WR34, regs[MGA_TEXREG_HEIGHT]); PRIMOUTREG(MGAREG_TEXTRANS, 0xffff); PRIMOUTREG(MGAREG_TEXTRANSHIGH, 0xffff); PRIMOUTREG(MGAREG_DMAPAD, 0); @@ -151,17 +154,17 @@ PRIMADVANCE(dev_priv); } +#define TMC_dualtex_enable 0x80 + static void mgaG400EmitTex0(drm_mga_private_t * dev_priv) { drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; unsigned int *regs = sarea_priv->TexState[0]; - int multitex = sarea_priv->WarpPipe & MGA_T2; PRIMLOCALS; - DRM_DEBUG("%s\n", __FUNCTION__); PRIMGETPTR(dev_priv); - /* This takes a max of 30 dwords */ + /* This takes 30 dwords */ PRIMOUTREG(MGAREG_TEXCTL2, regs[MGA_TEXREG_CTL2] | 0x00008000); PRIMOUTREG(MGAREG_TEXCTL, regs[MGA_TEXREG_CTL]); @@ -176,22 +179,20 @@ PRIMOUTREG(MGAREG_TEXORG4, regs[MGA_TEXREG_ORG4]); PRIMOUTREG(MGAREG_TEXWIDTH, regs[MGA_TEXREG_WIDTH]); PRIMOUTREG(MGAREG_TEXHEIGHT, regs[MGA_TEXREG_HEIGHT]); - PRIMOUTREG(0x2d00 + 49 * 4, 0); + PRIMOUTREG(MGAREG_WR49, 0); - PRIMOUTREG(0x2d00 + 57 * 4, 0); - PRIMOUTREG(0x2d00 + 53 * 4, 0); - PRIMOUTREG(0x2d00 + 61 * 4, 0); + PRIMOUTREG(MGAREG_WR57, 0); + PRIMOUTREG(MGAREG_WR53, 0); + PRIMOUTREG(MGAREG_WR61, 0); + PRIMOUTREG(MGAREG_WR52, 0x40); + + PRIMOUTREG(MGAREG_WR60, 0x40); + PRIMOUTREG(MGAREG_WR54, regs[MGA_TEXREG_WIDTH] | 0x40); + PRIMOUTREG(MGAREG_WR62, regs[MGA_TEXREG_HEIGHT] | 0x40); PRIMOUTREG(MGAREG_DMAPAD, 0); - if (!multitex) { - PRIMOUTREG(0x2d00 + 52 * 4, 0x40); - PRIMOUTREG(0x2d00 + 60 * 4, 0x40); - PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_DMAPAD, 0); - } - - PRIMOUTREG(0x2d00 + 54 * 4, regs[MGA_TEXREG_WIDTH] | 0x40); - PRIMOUTREG(0x2d00 + 62 * 4, regs[MGA_TEXREG_HEIGHT] | 0x40); + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_DMAPAD, 0); PRIMOUTREG(MGAREG_TEXTRANS, 0xffff); PRIMOUTREG(MGAREG_TEXTRANSHIGH, 0xffff); @@ -205,7 +206,6 @@ drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; unsigned int *regs = sarea_priv->TexState[1]; PRIMLOCALS; - DRM_DEBUG("%s\n", __FUNCTION__); PRIMGETPTR(dev_priv); @@ -225,14 +225,14 @@ PRIMOUTREG(MGAREG_TEXORG4, regs[MGA_TEXREG_ORG4]); PRIMOUTREG(MGAREG_TEXWIDTH, regs[MGA_TEXREG_WIDTH]); PRIMOUTREG(MGAREG_TEXHEIGHT, regs[MGA_TEXREG_HEIGHT]); - PRIMOUTREG(0x2d00 + 49 * 4, 0); + PRIMOUTREG(MGAREG_WR49, 0); - PRIMOUTREG(0x2d00 + 57 * 4, 0); - PRIMOUTREG(0x2d00 + 53 * 4, 0); - PRIMOUTREG(0x2d00 + 61 * 4, 0); - PRIMOUTREG(0x2d00 + 52 * 4, regs[MGA_TEXREG_WIDTH] | 0x40); + PRIMOUTREG(MGAREG_WR57, 0); + PRIMOUTREG(MGAREG_WR53, 0); + PRIMOUTREG(MGAREG_WR61, 0); + PRIMOUTREG(MGAREG_WR52, regs[MGA_TEXREG_WIDTH] | 0x40); - PRIMOUTREG(0x2d00 + 60 * 4, regs[MGA_TEXREG_HEIGHT] | 0x40); + PRIMOUTREG(MGAREG_WR60, regs[MGA_TEXREG_HEIGHT] | 0x40); PRIMOUTREG(MGAREG_TEXTRANS, 0xffff); PRIMOUTREG(MGAREG_TEXTRANSHIGH, 0xffff); PRIMOUTREG(MGAREG_TEXCTL2, regs[MGA_TEXREG_CTL2] | 0x00008000); @@ -240,13 +240,16 @@ PRIMADVANCE(dev_priv); } +#define MAGIC_FPARAM_HEX_VALUE 0x46480000 +/* This is the hex value of 12800.0f which is a magic value we must + * set in wr56. + */ + static void mgaG400EmitPipe(drm_mga_private_t * dev_priv) { drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; unsigned int pipe = sarea_priv->WarpPipe; - float fParam = 12800.0f; PRIMLOCALS; - DRM_DEBUG("%s\n", __FUNCTION__); PRIMGETPTR(dev_priv); @@ -278,14 +281,14 @@ PRIMOUTREG(MGAREG_DWGCTL, MGA_FLUSH_CMD); PRIMOUTREG(MGAREG_LEN + MGAREG_MGA_EXEC, 1); - PRIMOUTREG(MGAREG_DMAPAD, 0); PRIMOUTREG(MGAREG_DWGSYNC, 0x7000); - PRIMOUTREG(MGAREG_DMAPAD, 0); - - PRIMOUTREG(MGAREG_TEXCTL2, 0 | 0x00008000); + PRIMOUTREG(MGAREG_TEXCTL2, 0x00008000); PRIMOUTREG(MGAREG_LEN + MGAREG_MGA_EXEC, 0); + PRIMOUTREG(MGAREG_TEXCTL2, 0x80 | 0x00008000); PRIMOUTREG(MGAREG_LEN + MGAREG_MGA_EXEC, 0); + PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_DMAPAD, 0); } PRIMOUTREG(MGAREG_WVRTXSZ, 0x00001807); @@ -301,18 +304,18 @@ PRIMOUTREG(MGAREG_WFLAG, 0); PRIMOUTREG(MGAREG_WFLAG1, 0); - PRIMOUTREG(0x2d00 + 56 * 4, *((u32 *) (&fParam))); + PRIMOUTREG(MGAREG_WR56, MAGIC_FPARAM_HEX_VALUE); PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(0x2d00 + 49 * 4, 0); /* Tex stage 0 */ - PRIMOUTREG(0x2d00 + 57 * 4, 0); /* Tex stage 0 */ - PRIMOUTREG(0x2d00 + 53 * 4, 0); /* Tex stage 1 */ - PRIMOUTREG(0x2d00 + 61 * 4, 0); /* Tex stage 1 */ - - PRIMOUTREG(0x2d00 + 54 * 4, 0x40); /* Tex stage 0 : w */ - PRIMOUTREG(0x2d00 + 62 * 4, 0x40); /* Tex stage 0 : h */ - PRIMOUTREG(0x2d00 + 52 * 4, 0x40); /* Tex stage 1 : w */ - PRIMOUTREG(0x2d00 + 60 * 4, 0x40); /* Tex stage 1 : h */ + PRIMOUTREG(MGAREG_WR49, 0); /* Tex stage 0 */ + PRIMOUTREG(MGAREG_WR57, 0); /* Tex stage 0 */ + PRIMOUTREG(MGAREG_WR53, 0); /* Tex stage 1 */ + PRIMOUTREG(MGAREG_WR61, 0); /* Tex stage 1 */ + + PRIMOUTREG(MGAREG_WR54, 0x40); /* Tex stage 0 : w */ + PRIMOUTREG(MGAREG_WR62, 0x40); /* Tex stage 0 : h */ + PRIMOUTREG(MGAREG_WR52, 0x40); /* Tex stage 1 : w */ + PRIMOUTREG(MGAREG_WR60, 0x40); /* Tex stage 1 : h */ /* Dma pading required due to hw bug */ PRIMOUTREG(MGAREG_DMAPAD, 0xffffffff); @@ -329,7 +332,6 @@ drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; unsigned int pipe = sarea_priv->WarpPipe; PRIMLOCALS; - DRM_DEBUG("%s\n", __FUNCTION__); PRIMGETPTR(dev_priv); @@ -338,12 +340,12 @@ PRIMOUTREG(MGAREG_WIADDR, WIA_wmode_suspend); PRIMOUTREG(MGAREG_WVRTXSZ, 7); PRIMOUTREG(MGAREG_WFLAG, 0); - PRIMOUTREG(0x2d00 + 24 * 4, 0); /* tex w/h */ + PRIMOUTREG(MGAREG_WR24, 0); /* tex w/h */ - PRIMOUTREG(0x2d00 + 25 * 4, 0x100); - PRIMOUTREG(0x2d00 + 34 * 4, 0); /* tex w/h */ - PRIMOUTREG(0x2d00 + 42 * 4, 0xFFFF); - PRIMOUTREG(0x2d00 + 60 * 4, 0xFFFF); + PRIMOUTREG(MGAREG_WR25, 0x100); + PRIMOUTREG(MGAREG_WR34, 0); /* tex w/h */ + PRIMOUTREG(MGAREG_WR42, 0xFFFF); + PRIMOUTREG(MGAREG_WR60, 0xFFFF); /* Dma pading required due to hw bug */ PRIMOUTREG(MGAREG_DMAPAD, 0xffffffff); @@ -360,7 +362,6 @@ { drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; unsigned int dirty = sarea_priv->dirty; - DRM_DEBUG("%s\n", __FUNCTION__); if (dev_priv->chipset == MGA_CARD_TYPE_G400) { int multitex = sarea_priv->WarpPipe & MGA_T2; @@ -402,7 +403,6 @@ } } - /* Disallow all write destinations except the front and backbuffer. */ static int mgaVerifyContext(drm_mga_private_t * dev_priv) @@ -410,8 +410,6 @@ drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; unsigned int *regs = sarea_priv->ContextState; - DRM_DEBUG("%s\n", __FUNCTION__); - if (regs[MGA_CTXREG_DSTORG] != dev_priv->frontOffset && regs[MGA_CTXREG_DSTORG] != dev_priv->backOffset) { DRM_DEBUG("BAD DSTORG: %x (front %x, back %x)\n\n", @@ -430,8 +428,6 @@ { drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; - DRM_DEBUG("%s\n", __FUNCTION__); - if ((sarea_priv->TexState[unit][MGA_TEXREG_ORG] & 0x3) == 0x1) { DRM_DEBUG("BAD TEXREG_ORG: %x, unit %d\n", sarea_priv->TexState[unit][MGA_TEXREG_ORG], @@ -449,8 +445,6 @@ unsigned int dirty = sarea_priv->dirty; int rv = 0; - DRM_DEBUG("%s\n", __FUNCTION__); - if (sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS) sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS; @@ -478,8 +472,6 @@ unsigned long bus_address, unsigned int dstOrg, int length) { - DRM_DEBUG("%s\n", __FUNCTION__); - if (dstOrg < dev_priv->textureOffset || dstOrg + length > (dev_priv->textureOffset + dev_priv->textureSize)) { @@ -502,7 +494,6 @@ int use_agp = PDEA_pagpxfer_enable | 0x00000001; u16 y2; PRIMLOCALS; - DRM_DEBUG("%s\n", __FUNCTION__); y2 = length / 64; @@ -510,7 +501,6 @@ PRIMOUTREG(MGAREG_DSTORG, destOrg); PRIMOUTREG(MGAREG_MACCESS, 0x00000000); - DRM_DEBUG("srcorg : %lx\n", bus_address | use_agp); PRIMOUTREG(MGAREG_SRCORG, (u32) bus_address | use_agp); PRIMOUTREG(MGAREG_AR5, 64); @@ -524,10 +514,10 @@ PRIMOUTREG(MGAREG_FXBNDRY, (63 << 16)); PRIMOUTREG(MGAREG_YDSTLEN + MGAREG_MGA_EXEC, y2); + PRIMOUTREG(MGAREG_DMAPAD, 0); PRIMOUTREG(MGAREG_SRCORG, 0); PRIMOUTREG(MGAREG_PITCH, dev_priv->stride / dev_priv->cpp); - PRIMOUTREG(MGAREG_DMAPAD, 0); - PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_DWGSYNC, 0x7000); PRIMADVANCE(dev_priv); } @@ -541,34 +531,22 @@ int use_agp = PDEA_pagpxfer_enable; int i = 0; PRIMLOCALS; - DRM_DEBUG("%s\n", __FUNCTION__); - - DRM_DEBUG("dispatch vertex %d addr 0x%lx, " - "length 0x%x nbox %d dirty %x\n", - buf->idx, address, length, - sarea_priv->nbox, sarea_priv->dirty); - - DRM_DEBUG("used : %d, total : %d\n", buf->used, buf->total); if (buf->used) { /* WARNING: if you change any of the state functions verify - * these numbers (Overestimating this doesn't hurt). + * these numbers (Overestimating this doesn't hurt). */ buf_priv->dispatched = 1; PRIM_OVERFLOW(dev, dev_priv, (MAX_STATE_SIZE + (5 * MGA_NR_SAREA_CLIPRECTS))); mgaEmitState(dev_priv); + +#if 0 + length = dev_priv->vertexsize * 3 * 4; +#endif + do { if (i < sarea_priv->nbox) { - DRM_DEBUG("idx %d Emit box %d/%d:" - "%d,%d - %d,%d\n", - buf->idx, - i, sarea_priv->nbox, - sarea_priv->boxes[i].x1, - sarea_priv->boxes[i].y1, - sarea_priv->boxes[i].x2, - sarea_priv->boxes[i].y2); - mgaEmitClipRect(dev_priv, &sarea_priv->boxes[i]); } @@ -605,16 +583,10 @@ int use_agp = PDEA_pagpxfer_enable; int i = 0; PRIMLOCALS; - DRM_DEBUG("%s\n", __FUNCTION__); - - DRM_DEBUG("dispatch indices %d addr 0x%x, " - "start 0x%x end 0x%x nbox %d dirty %x\n", - buf->idx, address, start, end, - sarea_priv->nbox, sarea_priv->dirty); if (start != end) { /* WARNING: if you change any of the state functions verify - * these numbers (Overestimating this doesn't hurt). + * these numbers (Overestimating this doesn't hurt). */ buf_priv->dispatched = 1; PRIM_OVERFLOW(dev, dev_priv, @@ -623,15 +595,6 @@ do { if (i < sarea_priv->nbox) { - DRM_DEBUG("idx %d Emit box %d/%d:" - "%d,%d - %d,%d\n", - buf->idx, - i, sarea_priv->nbox, - sarea_priv->boxes[i].x1, - sarea_priv->boxes[i].y1, - sarea_priv->boxes[i].x2, - sarea_priv->boxes[i].y2); - mgaEmitClipRect(dev_priv, &sarea_priv->boxes[i]); } @@ -644,6 +607,7 @@ SETADD_mode_vertlist)); PRIMOUTREG(MGAREG_SETUPEND, ((address + end) | use_agp)); +/* ((address + start + 12) | use_agp)); */ PRIMADVANCE(dev_priv); } while (++i < sarea_priv->nbox); } @@ -658,7 +622,9 @@ static void mga_dma_dispatch_clear(drm_device_t * dev, int flags, unsigned int clear_color, - unsigned int clear_zval) + unsigned int clear_zval, + unsigned int clear_colormask, + unsigned int clear_depthmask) { drm_mga_private_t *dev_priv = dev->dev_private; drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; @@ -668,7 +634,6 @@ unsigned int cmd; int i; PRIMLOCALS; - DRM_DEBUG("%s\n", __FUNCTION__); if (dev_priv->sgram) cmd = MGA_CLEAR_CMD | DC_atype_blk; @@ -680,14 +645,9 @@ for (i = 0; i < nbox; i++) { unsigned int height = pbox[i].y2 - pbox[i].y1; - DRM_DEBUG("dispatch clear %d,%d-%d,%d flags %x!\n", - pbox[i].x1, pbox[i].y1, pbox[i].x2, - pbox[i].y2, flags); - if (flags & MGA_FRONT) { - DRM_DEBUG("clear front\n"); - PRIMOUTREG(MGAREG_DMAPAD, 0); PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_PLNWT, clear_colormask); PRIMOUTREG(MGAREG_YDSTLEN, (pbox[i].y1 << 16) | height); PRIMOUTREG(MGAREG_FXBNDRY, @@ -700,9 +660,8 @@ } if (flags & MGA_BACK) { - DRM_DEBUG("clear back\n"); - PRIMOUTREG(MGAREG_DMAPAD, 0); PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_PLNWT, clear_colormask); PRIMOUTREG(MGAREG_YDSTLEN, (pbox[i].y1 << 16) | height); PRIMOUTREG(MGAREG_FXBNDRY, @@ -715,9 +674,8 @@ } if (flags & MGA_DEPTH) { - DRM_DEBUG("clear depth\n"); - PRIMOUTREG(MGAREG_DMAPAD, 0); PRIMOUTREG(MGAREG_DMAPAD, 0); + PRIMOUTREG(MGAREG_PLNWT, clear_depthmask); PRIMOUTREG(MGAREG_YDSTLEN, (pbox[i].y1 << 16) | height); PRIMOUTREG(MGAREG_FXBNDRY, @@ -749,7 +707,6 @@ int pixel_stride = dev_priv->stride / dev_priv->cpp; PRIMLOCALS; - DRM_DEBUG("%s\n", __FUNCTION__); PRIM_OVERFLOW(dev, dev_priv, (MGA_NR_SAREA_CLIPRECTS * 5) + 20); @@ -772,9 +729,6 @@ unsigned int h = pbox[i].y2 - pbox[i].y1; unsigned int start = pbox[i].y1 * pixel_stride; - DRM_DEBUG("dispatch swap %d,%d-%d,%d!\n", - pbox[i].x1, pbox[i].y1, pbox[i].x2, pbox[i].y2); - PRIMOUTREG(MGAREG_AR0, start + pbox[i].x2 - 1); PRIMOUTREG(MGAREG_AR3, start + pbox[i].x1); PRIMOUTREG(MGAREG_FXBNDRY, @@ -804,7 +758,6 @@ if (copy_from_user(&clear, (drm_mga_clear_t *) arg, sizeof(clear))) return -EFAULT; - DRM_DEBUG("%s\n", __FUNCTION__); if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { DRM_ERROR("mga_clear_bufs called without lock held\n"); @@ -818,7 +771,10 @@ */ dev_priv->sarea_priv->dirty |= MGA_UPLOAD_CTX; mga_dma_dispatch_clear(dev, clear.flags, - clear.clear_color, clear.clear_depth); + clear.clear_color, + clear.clear_depth, + clear.clear_color_mask, + clear.clear_depth_mask); PRIMUPDATE(dev_priv); mga_flush_write_combine(); mga_dma_schedule(dev, 1); @@ -833,7 +789,6 @@ drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; - DRM_DEBUG("%s\n", __FUNCTION__); if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { DRM_ERROR("mga_swap_bufs called without lock held\n"); @@ -868,9 +823,7 @@ drm_mga_buf_priv_t *buf_priv; drm_mga_iload_t iload; unsigned long bus_address; - DRM_DEBUG("%s\n", __FUNCTION__); - DRM_DEBUG("Starting Iload\n"); if (copy_from_user(&iload, (drm_mga_iload_t *) arg, sizeof(iload))) return -EFAULT; @@ -882,8 +835,6 @@ buf = dma->buflist[iload.idx]; buf_priv = buf->dev_private; bus_address = buf->bus_address; - DRM_DEBUG("bus_address %lx, length %d, destorg : %x\n", - bus_address, iload.length, iload.destOrg); if (mgaVerifyIload(dev_priv, bus_address, iload.destOrg, iload.length)) { @@ -914,7 +865,6 @@ drm_buf_t *buf; drm_mga_buf_priv_t *buf_priv; drm_mga_vertex_t vertex; - DRM_DEBUG("%s\n", __FUNCTION__); if (copy_from_user(&vertex, (drm_mga_vertex_t *) arg, sizeof(vertex))) return -EFAULT; @@ -924,8 +874,6 @@ return -EINVAL; } - DRM_DEBUG("mga_vertex\n"); - buf = dma->buflist[vertex.idx]; buf_priv = buf->dev_private; @@ -939,7 +887,6 @@ buf_priv->dispatched = 0; mga_freelist_put(dev, buf); } - DRM_DEBUG("bad state\n"); return -EINVAL; } @@ -963,9 +910,9 @@ drm_buf_t *buf; drm_mga_buf_priv_t *buf_priv; drm_mga_indices_t indices; - DRM_DEBUG("%s\n", __FUNCTION__); - if (copy_from_user(&indices, (drm_mga_indices_t *) arg, sizeof(indices))) + if (copy_from_user(&indices, + (drm_mga_indices_t *)arg, sizeof(indices))) return -EFAULT; if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { @@ -973,8 +920,6 @@ return -EINVAL; } - DRM_DEBUG("mga_indices\n"); - buf = dma->buflist[indices.idx]; buf_priv = buf->dev_private; @@ -1004,7 +949,6 @@ { int i; drm_buf_t *buf; - DRM_DEBUG("%s\n", __FUNCTION__); for (i = d->granted_count; i < d->request_count; i++) { buf = mga_freelist_get(dev); @@ -1012,8 +956,9 @@ break; buf->pid = current->pid; if (copy_to_user(&d->request_indices[i], - &buf->idx, sizeof(buf->idx)) || - copy_to_user(&d->request_sizes[i], + &buf->idx, sizeof(buf->idx))) + return -EFAULT; + if (copy_to_user(&d->request_sizes[i], &buf->total, sizeof(buf->total))) return -EFAULT; ++d->granted_count; @@ -1029,12 +974,9 @@ drm_device_dma_t *dma = dev->dma; int retcode = 0; drm_dma_t d; - DRM_DEBUG("%s\n", __FUNCTION__); if (copy_from_user(&d, (drm_dma_t *) arg, sizeof(d))) return -EFAULT; - DRM_DEBUG("%d %d: %d send, %d req\n", - current->pid, d.context, d.send_count, d.request_count); if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { DRM_ERROR("mga_dma called without lock held\n"); @@ -1065,8 +1007,6 @@ retcode = mga_dma_get_buffers(dev, &d); } - DRM_DEBUG("%d returning, granted = %d\n", - current->pid, d.granted_count); if (copy_to_user((drm_dma_t *) arg, &d, sizeof(d))) return -EFAULT; return retcode; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/drm/r128_dma.c linux/drivers/char/drm/r128_dma.c --- v2.4.0-test8/linux/drivers/char/drm/r128_dma.c Tue Aug 29 21:09:10 2000 +++ linux/drivers/char/drm/r128_dma.c Fri Sep 15 14:24:55 2000 @@ -68,30 +68,8 @@ return R128_READ(R128_CLOCK_CNTL_DATA); } -#ifdef __i386__ -static void r128_flush_write_combine(void) -{ - int xchangeDummy; +#define r128_flush_write_combine() mb() - __asm__ volatile("push %%eax ;" - "xchg %%eax, %0 ;" - "pop %%eax" : : "m" (xchangeDummy)); - __asm__ volatile("push %%eax ;" - "push %%ebx ;" - "push %%ecx ;" - "push %%edx ;" - "movl $0,%%eax ;" - "cpuid ;" - "pop %%edx ;" - "pop %%ecx ;" - "pop %%ebx ;" - "pop %%eax" : /* no outputs */ : /* no inputs */ ); -} -#else -static void r128_flush_write_combine(void) -{ -} -#endif static void r128_status(drm_device_t *dev) { diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/drm/r128_drv.c linux/drivers/char/drm/r128_drv.c --- v2.4.0-test8/linux/drivers/char/drm/r128_drv.c Tue Aug 29 14:09:15 2000 +++ linux/drivers/char/drm/r128_drv.c Sun Oct 1 20:00:00 2000 @@ -35,7 +35,7 @@ #define R128_NAME "r128" #define R128_DESC "ATI Rage 128" -#define R128_DATE "20000719" +#define R128_DATE "20000928" #define R128_MAJOR 1 #define R128_MINOR 0 #define R128_PATCHLEVEL 0 @@ -467,7 +467,7 @@ } spin_unlock(&dev->count_lock); } - + return retcode; } @@ -501,7 +501,7 @@ } spin_unlock(&dev->count_lock); } - + unlock_kernel(); return retcode; } @@ -602,6 +602,7 @@ #endif add_wait_queue(&dev->lock.lock_queue, &entry); for (;;) { + current->state = TASK_INTERRUPTIBLE; if (!dev->lock.hw_lock) { /* Device has been unregistered */ ret = -EINTR; @@ -617,7 +618,6 @@ /* Contention */ atomic_inc(&dev->total_sleeps); - current->state = TASK_INTERRUPTIBLE; #if 1 current->policy |= SCHED_YIELD; #endif diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/drm/r128_drv.h linux/drivers/char/drm/r128_drv.h --- v2.4.0-test8/linux/drivers/char/drm/r128_drv.h Thu Jul 27 15:05:40 2000 +++ linux/drivers/char/drm/r128_drv.h Sun Oct 1 20:00:00 2000 @@ -11,11 +11,11 @@ * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL @@ -23,7 +23,7 @@ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. - * + * * Authors: Rickard E. (Rik) Faith * Kevin E. Martin * diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/drm/tdfx_drv.c linux/drivers/char/drm/tdfx_drv.c --- v2.4.0-test8/linux/drivers/char/drm/tdfx_drv.c Tue Aug 29 21:09:10 2000 +++ linux/drivers/char/drm/tdfx_drv.c Sun Oct 1 20:00:00 2000 @@ -1,4 +1,4 @@ -/* tdfx.c -- tdfx driver -*- linux-c -*- +/* tdfx_drv.c -- tdfx driver -*- linux-c -*- * Created: Thu Oct 7 10:38:32 1999 by faith@precisioninsight.com * * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. @@ -11,11 +11,11 @@ * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL @@ -23,7 +23,7 @@ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. - * + * * Authors: * Rickard E. (Rik) Faith * Daryll Strauss @@ -36,7 +36,7 @@ #define TDFX_NAME "tdfx" #define TDFX_DESC "3dfx Banshee/Voodoo3+" -#define TDFX_DATE "20000719" +#define TDFX_DATE "20000928" #define TDFX_MAJOR 1 #define TDFX_MINOR 0 #define TDFX_PATCHLEVEL 0 @@ -76,7 +76,7 @@ [DRM_IOCTL_NR(DRM_IOCTL_UNBLOCK)] = { drm_unblock, 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_AUTH_MAGIC)] = { drm_authmagic, 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)] = { drm_addmap, 1, 1 }, - + [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = { tdfx_addctx, 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = { tdfx_rmctx, 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = { tdfx_modctx, 1, 1 }, @@ -128,7 +128,7 @@ static int tdfx_setup(drm_device_t *dev) { int i; - + atomic_set(&dev->ioctl_count, 0); atomic_set(&dev->vma_count, 0); dev->buf_use = 0; @@ -170,7 +170,7 @@ dev->ctx_start = 0; dev->lck_start = 0; - + dev->buf_rp = dev->buf; dev->buf_wp = dev->buf; dev->buf_end = dev->buf + DRM_BSZ; @@ -179,15 +179,15 @@ init_waitqueue_head(&dev->buf_writers); tdfx_res_ctx.handle=-1; - + DRM_DEBUG("\n"); - + /* The kernel's context could be created here, but is now created in drm_dma_enqueue. This is more resource-efficient for hardware that does not do DMA, but may mean that drm_select_queue fails between the time the interrupt is initialized and the time the queues are initialized. */ - + return 0; } @@ -203,12 +203,12 @@ down(&dev->struct_sem); del_timer(&dev->timer); - + if (dev->devname) { drm_free(dev->devname, strlen(dev->devname)+1, DRM_MEM_DRIVER); dev->devname = NULL; } - + if (dev->unique) { drm_free(dev->unique, strlen(dev->unique)+1, DRM_MEM_DRIVER); dev->unique = NULL; @@ -227,7 +227,7 @@ if (dev->agp) { drm_agp_mem_t *temp; drm_agp_mem_t *temp_next; - + temp = dev->agp->memory; while(temp != NULL) { temp_next = temp->next; @@ -246,7 +246,7 @@ } dev->vmalist = NULL; } - + /* Clear map area and mtrr information */ if (dev->maplist) { for (i = 0; i < dev->map_count; i++) { @@ -284,14 +284,14 @@ dev->maplist = NULL; dev->map_count = 0; } - + if (dev->lock.hw_lock) { dev->lock.hw_lock = NULL; /* SHM removed */ dev->lock.pid = 0; wake_up_interruptible(&dev->lock.lock_queue); } up(&dev->struct_sem); - + return 0; } @@ -308,7 +308,7 @@ memset((void *)dev, 0, sizeof(*dev)); dev->count_lock = SPIN_LOCK_UNLOCKED; sema_init(&dev->struct_sem, 1); - + #ifdef MODULE drm_parse_options(tdfx); #endif @@ -340,7 +340,7 @@ TDFX_PATCHLEVEL, TDFX_DATE, tdfx_misc.minor); - + return 0; } @@ -351,7 +351,7 @@ drm_device_t *dev = &tdfx_device; DRM_DEBUG("\n"); - + drm_proc_cleanup(); if (misc_deregister(&tdfx_misc)) { DRM_ERROR("Cannot unload module\n"); @@ -412,7 +412,7 @@ { drm_device_t *dev = &tdfx_device; int retcode = 0; - + DRM_DEBUG("open_count = %d\n", dev->open_count); if (!(retcode = drm_open_helper(inode, filp, dev))) { #if LINUX_VERSION_CODE < 0x020333 @@ -480,7 +480,7 @@ atomic_inc(&dev->ioctl_count); atomic_inc(&dev->total_ioctl); ++priv->ioctl_count; - + DRM_DEBUG("pid = %d, cmd = 0x%02x, nr = 0x%02x, dev 0x%x, auth = %d\n", current->pid, cmd, nr, dev->device, priv->authenticated); @@ -500,7 +500,7 @@ retcode = (func)(inode, filp, cmd, arg); } } - + atomic_dec(&dev->ioctl_count); return retcode; } @@ -538,7 +538,7 @@ if (lock.context < 0 || lock.context >= dev->queue_count) return -EINVAL; #endif - + if (!ret) { #if 0 if (_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock) @@ -550,7 +550,7 @@ /* Can't take lock if we just had it and there is contention. */ DRM_DEBUG("%d (pid %d) delayed j=%d dev=%d jiffies=%d\n", - lock.context, current->pid, j, + lock.context, current->pid, j, dev->lock.lock_time, jiffies); current->state = TASK_INTERRUPTIBLE; current->policy |= SCHED_YIELD; @@ -561,6 +561,7 @@ #endif add_wait_queue(&dev->lock.lock_queue, &entry); for (;;) { + current->state = TASK_INTERRUPTIBLE; if (!dev->lock.hw_lock) { /* Device has been unregistered */ ret = -EINTR; @@ -573,10 +574,9 @@ atomic_inc(&dev->total_locks); break; /* Got lock */ } - + /* Contention */ atomic_inc(&dev->total_sleeps); - current->state = TASK_INTERRUPTIBLE; #if 1 current->policy |= SCHED_YIELD; #endif @@ -648,7 +648,7 @@ #if DRM_DMA_HISTOGRAM atomic_inc(&dev->histo.lacq[drm_histogram_slot(get_cycles() - start)]); #endif - + return ret; } @@ -662,7 +662,7 @@ if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock))) return -EFAULT; - + if (lock.context == DRM_KERNEL_CONTEXT) { DRM_ERROR("Process %d using kernel context %d\n", current->pid, lock.context); @@ -690,7 +690,7 @@ current->priority = DEF_PRIORITY; } #endif - + unblock_all_signals(); return 0; } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/drm/vm.c linux/drivers/char/drm/vm.c --- v2.4.0-test8/linux/drivers/char/drm/vm.c Fri Aug 11 19:14:46 2000 +++ linux/drivers/char/drm/vm.c Sun Oct 1 20:00:00 2000 @@ -67,8 +67,6 @@ int write_access) #endif { - DRM_DEBUG("0x%08lx, %d\n", address, write_access); - return NOPAGE_SIGBUS; /* Disallow mremap */ } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/efirtc.c linux/drivers/char/efirtc.c --- v2.4.0-test8/linux/drivers/char/efirtc.c Fri Aug 11 19:09:06 2000 +++ linux/drivers/char/efirtc.c Mon Sep 18 14:57:01 2000 @@ -249,7 +249,7 @@ convert_from_efi_time(&eft, &wtime); - return copy_to_user((void *)&ewp->time, &wtime, sizeof(struct rtc_time)); + return copy_to_user((void *)&ewp->time, &wtime, sizeof(struct rtc_time)) ? -EFAULT : 0; } return -EINVAL; } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/ftape/lowlevel/ftape-calibr.c linux/drivers/char/ftape/lowlevel/ftape-calibr.c --- v2.4.0-test8/linux/drivers/char/ftape/lowlevel/ftape-calibr.c Tue Nov 25 14:45:27 1997 +++ linux/drivers/char/ftape/lowlevel/ftape-calibr.c Fri Sep 22 14:21:16 2000 @@ -183,7 +183,7 @@ } #elif defined(__alpha__) #if CONFIG_FT_ALPHA_CLOCK == 0 -#error You must define and set CONFIG_FT_ALPHA_CLOCK in the Makefile ! +#error You must define and set CONFIG_FT_ALPHA_CLOCK in 'make config' ! #endif extern struct hwrpb_struct *hwrpb; TRACE_FUN(ft_t_any); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/hp600_keyb.c linux/drivers/char/hp600_keyb.c --- v2.4.0-test8/linux/drivers/char/hp600_keyb.c Wed Aug 9 13:59:04 2000 +++ linux/drivers/char/hp600_keyb.c Fri Sep 22 14:21:17 2000 @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include "scan_keyb.h" diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/i810-tco.c linux/drivers/char/i810-tco.c --- v2.4.0-test8/linux/drivers/char/i810-tco.c Fri Aug 11 17:56:40 2000 +++ linux/drivers/char/i810-tco.c Sun Oct 1 19:45:29 2000 @@ -301,10 +301,9 @@ tco_timer_settimer ((unsigned char) i810_margin); tco_timer_reload (); - /* FIXME: no floating point math */ printk (KERN_INFO "i810 TCO timer: V0.02, timer margin: %d sec (0x%04x)\n", - (int) (i810_margin * 0.6), TCOBASE); + (int) (i810_margin * 6 / 10), TCOBASE); return 0; } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/i810_rng.c linux/drivers/char/i810_rng.c --- v2.4.0-test8/linux/drivers/char/i810_rng.c Wed Jul 12 21:58:42 2000 +++ linux/drivers/char/i810_rng.c Mon Oct 2 12:00:16 2000 @@ -119,13 +119,6 @@ * The timer and the character device may be used simultaneously, if desired. - * FIXME: Currently only one open() of the character device is allowed. - If another user tries to open() the device, they will get an - -EBUSY error. Instead, this really should either support - multiple simultaneous users of the character device (not hard), - or simply block open() until the current user of the chrdev - calls close(). - * FIXME: support poll() * FIXME: should we be crazy and support mmap()? @@ -138,11 +131,16 @@ This will slow things down but guarantee that bad data is never passed upstream. + * Since the RNG is accessed from a timer as well as normal + kernel code, but not from interrupts, we use spin_lock_bh + in regular code, and spin_lock in the timer function, to + serialize access to the RNG hardware area. + ---------------------------------------------------------- Change history: - 0.6.2: + Version 0.6.2: * Clean up spinlocks. Since we don't have any interrupts to worry about, but we do have a timer to worry about, we use spin_lock_bh everywhere except the timer function @@ -152,6 +150,20 @@ * New timer interval sysctl * Clean up sysctl names + Version 0.9.0: + * Don't register a pci_driver, because we are really + using PCI bridge vendor/device ids, and someone + may want to register a driver for the bridge. (bug fix) + * Don't let the usage count go negative (bug fix) + * Clean up spinlocks (bug fix) + * Enable PCI device, if necessary (bug fix) + * iounmap on module unload (bug fix) + * If RNG chrdev is already in use when open(2) is called, + sleep until it is available. + * Remove redundant globals rng_allocated, rng_use_count + * Convert numeric globals to unsigned + * Module unload cleanup + */ @@ -166,6 +178,7 @@ #include #include #include +#include #include #include @@ -174,7 +187,7 @@ /* * core module and version information */ -#define RNG_VERSION "0.6.2" +#define RNG_VERSION "0.9.0" #define RNG_MODULE_NAME "i810_rng" #define RNG_DRIVER_NAME RNG_MODULE_NAME " hardware driver " RNG_VERSION #define PFX RNG_MODULE_NAME ": " @@ -253,22 +266,24 @@ * various RNG status variables. they are globals * as we only support a single RNG device */ -static int rng_allocated; /* is someone using the RNG region? */ static int rng_hw_enabled; /* is the RNG h/w enabled? */ static int rng_timer_enabled; /* is the RNG timer enabled? */ -static int rng_use_count; /* number of times RNG has been enabled */ static int rng_trusted; /* does FIPS trust out data? */ static int rng_enabled_sysctl; /* sysctl for enabling/disabling RNG */ -static int rng_entropy = 8; /* number of entropy bits we submit to /dev/random */ -static int rng_entropy_sysctl; /* sysctl for changing entropy bits */ -static int rng_interval_sysctl; /* sysctl for changing timer interval */ +static unsigned int rng_entropy = 8; /* number of entropy bits we submit to /dev/random */ +static unsigned int rng_entropy_sysctl; /* sysctl for changing entropy bits */ +static unsigned int rng_interval_sysctl; /* sysctl for changing timer interval */ static int rng_have_mem_region; /* did we grab RNG region via request_mem_region? */ -static int rng_fips_counter; /* size of internal FIPS test data pool */ -static int rng_timer_len = RNG_DEF_TIMER_LEN; /* timer interval, in jiffies */ +static unsigned int rng_fips_counter; /* size of internal FIPS test data pool */ +static unsigned int rng_timer_len = RNG_DEF_TIMER_LEN; /* timer interval, in jiffies */ static void *rng_mem; /* token to our ioremap'd RNG register area */ static spinlock_t rng_lock = SPIN_LOCK_UNLOCKED; /* hardware lock */ static struct timer_list rng_timer; /* kernel timer for RNG hardware reads and tests */ -static int rng_open; /* boolean, 0 (false) if chrdev is closed, 1 (true) if open */ +static struct pci_dev *rng_pdev; /* Firmware Hub PCI device found during PCI probe */ +static struct semaphore rng_open_sem; /* Semaphore for serializing rng_open/release */ +static wait_queue_head_t rng_open_wait; /* Wait queue for serializing open/release */ +static int rng_open_mode; /* Open mode (we only allow reads) */ + /* * inlined helper functions for accessing RNG registers @@ -320,6 +335,8 @@ /* gimme some thermal noise, baby */ rng_data = rng_data_read (); + spin_unlock (&rng_lock); + /* * if RNG has been verified in the past, add * data just read to the /dev/random pool, @@ -333,6 +350,8 @@ rng_fips_test_store (rng_data); if (rng_fips_counter > RNG_FIPS_TEST_THRESHOLD) rng_run_fips_test (); + } else { + spin_unlock (&rng_lock); } /* run the timer again, if enabled */ @@ -340,9 +359,6 @@ rng_timer.expires = jiffies + rng_timer_len; add_timer (&rng_timer); } - - spin_unlock (&rng_lock); - } @@ -351,8 +367,8 @@ */ static int rng_enable (int enable) { - int rc = 0; - u8 hw_status; + int rc = 0, action = 0; + u8 hw_status, new_status; DPRINTK ("ENTER\n"); @@ -362,28 +378,36 @@ if (enable) { rng_hw_enabled = 1; - rng_use_count++; MOD_INC_USE_COUNT; } else { - rng_use_count--; - if (rng_use_count == 0) +#ifndef __alpha__ + if (GET_USE_COUNT (THIS_MODULE) > 0) + MOD_DEC_USE_COUNT; + if (GET_USE_COUNT (THIS_MODULE) == 0) rng_hw_enabled = 0; - MOD_DEC_USE_COUNT; +#endif } if (rng_hw_enabled && ((hw_status & RNG_ENABLED) == 0)) { rng_hwstatus_set (hw_status | RNG_ENABLED); - printk (KERN_INFO PFX "RNG h/w enabled\n"); + action = 1; } else if (!rng_hw_enabled && (hw_status & RNG_ENABLED)) { rng_hwstatus_set (hw_status & ~RNG_ENABLED); - printk (KERN_INFO PFX "RNG h/w disabled\n"); + action = 2; } + new_status = rng_hwstatus (); + spin_unlock_bh (&rng_lock); - if ((!!enable) != (!!(rng_hwstatus () & RNG_ENABLED))) { + if (action == 1) + printk (KERN_INFO PFX "RNG h/w enabled\n"); + else if (action == 2) + printk (KERN_INFO PFX "RNG h/w disabled\n"); + + if ((!!enable) != (!!(new_status & RNG_ENABLED))) { printk (KERN_ERR PFX "Unable to %sable the RNG\n", enable ? "en" : "dis"); rc = -EIO; @@ -406,15 +430,14 @@ DPRINTK ("ENTER\n"); spin_lock_bh (&rng_lock); - rng_enabled_sysctl = enabled_save = rng_timer_enabled; + spin_unlock_bh (&rng_lock); rc = proc_dointvec (table, write, filp, buffer, lenp); - if (rc) { - spin_unlock_bh (&rng_lock); + if (rc) return rc; - } + spin_lock_bh (&rng_lock); if (enabled_save != rng_enabled_sysctl) { rng_timer_enabled = rng_enabled_sysctl; spin_unlock_bh (&rng_lock); @@ -591,53 +614,49 @@ int rc = -EINVAL; if ((filp->f_mode & FMODE_READ) == 0) - goto err_out; + goto err_out_ret; if (filp->f_mode & FMODE_WRITE) - goto err_out; + goto err_out_ret; - spin_lock_bh (&rng_lock); - - /* only allow one open of this device, exit with -EBUSY if already open */ - /* FIXME: we should sleep on a semaphore here, unless O_NONBLOCK */ - if (rng_open) { - spin_unlock_bh (&rng_lock); - rc = -EBUSY; - goto err_out; + /* wait for device to become free */ + down (&rng_open_sem); + while (rng_open_mode & filp->f_mode) { + if (filp->f_flags & O_NONBLOCK) { + up (&rng_open_sem); + return -EWOULDBLOCK; + } + up (&rng_open_sem); + interruptible_sleep_on (&rng_open_wait); + if (signal_pending (current)) + return -ERESTARTSYS; + down (&rng_open_sem); } - rng_open = 1; - - spin_unlock_bh (&rng_lock); - - if (rng_enable(1) != 0) { - spin_lock_bh (&rng_lock); - rng_open = 0; - spin_unlock_bh (&rng_lock); + if (rng_enable (1)) { rc = -EIO; goto err_out; } + rng_open_mode |= filp->f_mode & (FMODE_READ | FMODE_WRITE); + up (&rng_open_sem); return 0; err_out: + up (&rng_open_sem); +err_out_ret: return rc; } static int rng_dev_release (struct inode *inode, struct file *filp) { + down(&rng_open_sem); - lock_kernel(); - if (rng_enable(0) != 0) { - unlock_kernel(); - return -EIO; - } - - spin_lock_bh (&rng_lock); - rng_open = 0; - spin_unlock_bh (&rng_lock); - unlock_kernel(); + rng_enable(0); + rng_open_mode &= (~filp->f_mode) & (FMODE_READ|FMODE_WRITE); + up (&rng_open_sem); + wake_up (&rng_open_wait); return 0; } @@ -705,19 +724,15 @@ /* * rng_init_one - look for and attempt to init a single RNG */ -static int __init rng_init_one (struct pci_dev *dev, - const struct pci_device_id *id) +static int __init rng_init_one (struct pci_dev *dev) { int rc; u8 hw_status; DPRINTK ("ENTER\n"); - if (rng_allocated) { - printk (KERN_ERR PFX "this driver only supports one RNG\n"); - DPRINTK ("EXIT, returning -EBUSY\n"); - return -EBUSY; - } + if (pci_enable_device (dev)) + return -EIO; /* XXX currently fails, investigate who has our mem region */ if (request_mem_region (RNG_ADDR, RNG_ADDR_LEN, RNG_MODULE_NAME)) @@ -728,7 +743,7 @@ printk (KERN_ERR PFX "cannot ioremap RNG Memory\n"); DPRINTK ("EXIT, returning -EBUSY\n"); rc = -EBUSY; - goto err_out; + goto err_out_free_res; } /* Check for Intel 82802 */ @@ -737,11 +752,9 @@ printk (KERN_ERR PFX "RNG not detected\n"); DPRINTK ("EXIT, returning -ENODEV\n"); rc = -ENODEV; - goto err_out; + goto err_out_free_map; } - rng_allocated = 1; - if (rng_entropy < 0 || rng_entropy > RNG_MAX_ENTROPY) rng_entropy = RNG_MAX_ENTROPY; @@ -749,10 +762,11 @@ init_timer (&rng_timer); rng_timer.function = rng_timer_tick; + /* turn RNG h/w off, if it's on */ rc = rng_enable (0); if (rc) { printk (KERN_ERR PFX "cannot disable RNG, aborting\n"); - goto err_out; + goto err_out_free_map; } /* add sysctls */ @@ -761,9 +775,9 @@ DPRINTK ("EXIT, returning 0\n"); return 0; -err_out: - if (rng_mem) - iounmap (rng_mem); +err_out_free_map: + iounmap (rng_mem); +err_out_free_res: if (rng_have_mem_region) release_mem_region (RNG_ADDR, RNG_ADDR_LEN); return rc; @@ -772,6 +786,11 @@ /* * Data for PCI driver interface + * + * This data only exists for exporting the supported + * PCI ids via MODULE_DEVICE_TABLE. We do not actually + * register a pci_driver, because someone else might one day + * want to register another driver on the same PCI id. */ const static struct pci_device_id rng_pci_tbl[] __initdata = { { 0x8086, 0x2418, PCI_ANY_ID, PCI_ANY_ID, }, @@ -780,11 +799,6 @@ }; MODULE_DEVICE_TABLE (pci, rng_pci_tbl); -static struct pci_driver rng_driver = { - name: RNG_MODULE_NAME, - id_table: rng_pci_tbl, - probe: rng_init_one, -}; MODULE_AUTHOR("Jeff Garzik, Matt Sottek"); MODULE_DESCRIPTION("Intel i8xx chipset Random Number Generator (RNG) driver"); @@ -813,23 +827,36 @@ static int __init rng_init (void) { int rc; + struct pci_dev *pdev; DPRINTK ("ENTER\n"); - if (pci_register_driver (&rng_driver) < 1) { - DPRINTK ("EXIT, returning -ENODEV\n"); + init_MUTEX (&rng_open_sem); + init_waitqueue_head (&rng_open_wait); + + pdev = pci_find_device (0x8086, 0x2418, NULL); + if (!pdev) + pdev = pci_find_device (0x8086, 0x2428, NULL); + if (!pdev) return -ENODEV; - } + + rc = rng_init_one (pdev); + if (rc) + return rc; rc = misc_register (&rng_miscdev); if (rc) { - pci_unregister_driver (&rng_driver); + iounmap (rng_mem); + if (rng_have_mem_region) + release_mem_region (RNG_ADDR, RNG_ADDR_LEN); DPRINTK ("EXIT, returning %d\n", rc); return rc; } printk (KERN_INFO RNG_DRIVER_NAME " loaded\n"); + rng_pdev = pdev; + DPRINTK ("EXIT, returning 0\n"); return 0; } @@ -842,17 +869,16 @@ { DPRINTK ("ENTER\n"); - del_timer_sync (&rng_timer); + assert (rng_timer_enabled == 0); + assert (rng_hw_enabled == 0); + + misc_deregister (&rng_miscdev); rng_sysctl (0); - pci_unregister_driver (&rng_driver); + iounmap (rng_mem); if (rng_have_mem_region) release_mem_region (RNG_ADDR, RNG_ADDR_LEN); - - rng_hwstatus_set (rng_hwstatus() & ~RNG_ENABLED); - - misc_deregister (&rng_miscdev); DPRINTK ("EXIT\n"); } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/joystick/pcigame.c linux/drivers/char/joystick/pcigame.c --- v2.4.0-test8/linux/drivers/char/joystick/pcigame.c Wed Jun 21 08:22:21 2000 +++ linux/drivers/char/joystick/pcigame.c Fri Sep 22 14:21:17 2000 @@ -40,8 +40,8 @@ #include #include #include -#include #include +#include #include #define PCI_VENDOR_ID_AUREAL 0x12eb diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/lp.c linux/drivers/char/lp.c --- v2.4.0-test8/linux/drivers/char/lp.c Tue Jul 18 15:59:05 2000 +++ linux/drivers/char/lp.c Sat Sep 23 21:10:30 2000 @@ -712,11 +712,12 @@ if (parport_nr[0] == LP_PARPORT_AUTO && port->probe_info[0].class != PARPORT_CLASS_PRINTER) return; - + if (lp_count == LP_NO) { + printk("lp: ignoring parallel port (max. %d)\n",LP_NO); + return; + } if (!lp_register(lp_count, port)) - if (++lp_count == LP_NO) - break; - + lp_count++; break; default: diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/mem.c linux/drivers/char/mem.c --- v2.4.0-test8/linux/drivers/char/mem.c Wed Jun 21 22:31:01 2000 +++ linux/drivers/char/mem.c Mon Sep 25 15:26:56 2000 @@ -28,12 +28,6 @@ #ifdef CONFIG_I2C extern int i2c_init_all(void); #endif -#ifdef CONFIG_SOUND -void soundcore_init(void); -#ifdef CONFIG_SOUND_OSS -void soundcard_init(void); -#endif -#endif #ifdef CONFIG_SPARCAUDIO extern int sparcaudio_init(void); #endif @@ -55,9 +49,6 @@ #if defined(CONFIG_ADB) extern void adbdev_init(void); #endif -#ifdef CONFIG_PHONE -extern void telephony_init(void); -#endif static ssize_t do_write_mem(struct file * file, void *p, unsigned long realp, const char * buf, size_t count, loff_t *ppos) @@ -258,25 +249,27 @@ count -= read; } - kbuf = (char *)__get_free_page(GFP_KERNEL); - if (!kbuf) - return -ENOMEM; - while (count > 0) { - int len = count; - - if (len > PAGE_SIZE) - len = PAGE_SIZE; - len = vread(kbuf, (char *)p, len); - if (len && copy_to_user(buf, kbuf, len)) { - free_page((unsigned long)kbuf); - return -EFAULT; + if (count > 0) { + kbuf = (char *)__get_free_page(GFP_KERNEL); + if (!kbuf) + return -ENOMEM; + while (count > 0) { + int len = count; + + if (len > PAGE_SIZE) + len = PAGE_SIZE; + len = vread(kbuf, (char *)p, len); + if (len && copy_to_user(buf, kbuf, len)) { + free_page((unsigned long)kbuf); + return -EFAULT; + } + count -= len; + buf += len; + virtr += len; + p += len; } - count -= len; - buf += len; - virtr += len; - p += len; + free_page((unsigned long)kbuf); } - free_page((unsigned long)kbuf); *ppos = p; return virtr + read; } @@ -642,15 +635,6 @@ lp_m68k_init(); #endif misc_init(); -#ifdef CONFIG_SOUND - soundcore_init(); -#ifdef CONFIG_SOUND_OSS - soundcard_init(); -#endif -#endif -#ifdef CONFIG_SPARCAUDIO - sparcaudio_init(); -#endif #if CONFIG_QIC02_TAPE qic02_tape_init(); #endif @@ -666,8 +650,5 @@ #ifdef CONFIG_VIDEO_DEV videodev_init(); #endif -#ifdef CONFIG_PHONE - telephony_init(); -#endif return 0; } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/misc.c linux/drivers/char/misc.c --- v2.4.0-test8/linux/drivers/char/misc.c Mon Jul 24 17:04:12 2000 +++ linux/drivers/char/misc.c Sun Oct 1 19:45:29 2000 @@ -70,8 +70,6 @@ extern void gfx_register(void); #endif extern void streamable_init(void); -extern void watchdog_init(void); -extern void pcwatchdog_init(void); extern int rtc_sun_init(void); /* Combines MK48T02 and MK48T08 */ extern int rtc_DP8570A_init(void); extern int rtc_MK48T08_init(void); @@ -81,6 +79,7 @@ extern int pc110pad_init(void); extern int pmu_device_init(void); extern int qpmouse_init(void); +extern int tosh_init(void); static int misc_read_proc(char *buf, char **start, off_t offset, int len, int *eof, void *private) @@ -254,18 +253,6 @@ #ifdef CONFIG_PC110_PAD pc110pad_init(); #endif -/* - * Only one watchdog can succeed. We probe the pcwatchdog first, - * then the wdt cards and finally the software watchdog which always - * works. This means if your hardware watchdog dies or is 'borrowed' - * for some reason the software watchdog still gives you some cover. - */ -#ifdef CONFIG_PCWATCHDOG - pcwatchdog_init(); -#endif -#ifdef CONFIG_SOFT_WATCHDOG - watchdog_init(); -#endif #ifdef CONFIG_MVME16x rtc_MK48T08_init(); #endif @@ -298,6 +285,9 @@ #endif #ifdef CONFIG_SGI streamable_init (); +#endif +#ifdef CONFIG_TOSHIBA + tosh_init(); #endif if (devfs_register_chrdev(MISC_MAJOR,"misc",&misc_fops)) { printk("unable to get major %d for misc devices\n", diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/mixcomwd.c linux/drivers/char/mixcomwd.c --- v2.4.0-test8/linux/drivers/char/mixcomwd.c Wed Jul 12 21:58:42 2000 +++ linux/drivers/char/mixcomwd.c Sun Oct 1 19:45:29 2000 @@ -216,9 +216,10 @@ return 1; } -void __init mixcomwd_init(void) +static int __init mixcomwd_init(void) { int i; + int ret; int found=0; for (i = 0; !found && mixcomwd_ioports[i] != 0; i++) { @@ -238,23 +239,21 @@ if (!found) { printk("mixcomwd: No card detected, or port not available.\n"); - return; + return -ENODEV; } request_region(watchdog_port,1,"MixCOM watchdog"); - misc_register(&mixcomwd_miscdev); + ret = misc_register(&mixcomwd_miscdev); + if (ret) + return ret; + printk(KERN_INFO "MixCOM watchdog driver v%s, watchdog port at 0x%3x\n",VERSION,watchdog_port); -} -#ifdef MODULE -int init_module(void) -{ - mixcomwd_init(); return 0; -} +} -void cleanup_module(void) +static void __exit mixcomwd_exit(void) { #ifndef CONFIG_WATCHDOG_NOWAYOUT if(mixcomwd_timer_alive) { @@ -267,4 +266,6 @@ release_region(watchdog_port,1); misc_deregister(&mixcomwd_miscdev); } -#endif + +module_init(mixcomwd_init); +module_exit(mixcomwd_exit); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/nvram.c linux/drivers/char/nvram.c --- v2.4.0-test8/linux/drivers/char/nvram.c Sat Aug 26 16:24:58 2000 +++ linux/drivers/char/nvram.c Mon Sep 11 08:41:07 2000 @@ -109,7 +109,7 @@ extern spinlock_t rtc_lock; -static int nvram_open_cnt = 0; /* #times opened */ +static int nvram_open_cnt; /* #times opened */ static int nvram_open_mode; /* special open modes */ #define NVRAM_WRITE 1 /* opened for writing (exclusive) */ #define NVRAM_EXCL 2 /* opened with O_EXCL */ @@ -415,14 +415,29 @@ static int __init nvram_init(void) { + int ret; + /* First test whether the driver should init at all */ if (!CHECK_DRIVER_INIT()) return( -ENXIO ); - printk(KERN_INFO "Non-volatile memory driver v%s\n", NVRAM_VERSION ); - misc_register( &nvram_dev ); - create_proc_read_entry("driver/nvram",0,0,nvram_read_proc,NULL); - return( 0 ); + ret = misc_register( &nvram_dev ); + if (ret) { + printk(KERN_ERR "nvram: can't misc_register on minor=%d\n", NVRAM_MINOR); + goto out; + } + if (!create_proc_read_entry("driver/nvram",0,0,nvram_read_proc,NULL)) { + printk(KERN_ERR "nvram: can't create /proc/driver/nvram\n"); + ret = -ENOMEM; + goto outmisc; + } + ret = 0; + printk(KERN_INFO "Non-volatile memory driver v" NVRAM_VERSION "\n"); +out: + return( ret ); +outmisc: + misc_deregister( &nvram_dev ); + goto out; } static void __exit nvram_cleanup_module (void) diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/nwflash.c linux/drivers/char/nwflash.c --- v2.4.0-test8/linux/drivers/char/nwflash.c Sun Aug 13 09:54:15 2000 +++ linux/drivers/char/nwflash.c Mon Sep 18 15:15:22 2000 @@ -1,6 +1,9 @@ /* * Flash memory interface rev.5 driver for the Intel * Flash chips used on the NetWinder. + * + * 20/08/2000 RMK use __ioremap to map flash into virtual memory + * make a few more places use "volatile" */ #include @@ -15,7 +18,7 @@ #include #include -#include +#include #include #include #include @@ -33,7 +36,7 @@ #define MSTATIC #endif -#define NWFLASH_VERSION "6.2" +#define NWFLASH_VERSION "6.3" MSTATIC void kick_open(void); MSTATIC int get_flash_id(void); @@ -54,6 +57,7 @@ static int gbWriteEnable; static int gbWriteBase64Enable; +static volatile unsigned char *FLASH_BASE; MSTATIC int gbFlashSize = KFLASH_SIZE; extern spinlock_t gpio_lock; @@ -93,25 +97,25 @@ */ kick_open(); c2 = inb(0x80); - *(unsigned char *) (FLASH_BASE + 0x8000) = 0x90; + *(volatile unsigned char *) (FLASH_BASE + 0x8000) = 0x90; udelay(15); - c1 = *(unsigned char *) FLASH_BASE; + c1 = *(volatile unsigned char *) FLASH_BASE; c2 = inb(0x80); /* * on 4 Meg flash the second byte is actually at offset 2... */ if (c1 == 0xB0) - c2 = *(unsigned char *) (FLASH_BASE + 2); + c2 = *(volatile unsigned char *) (FLASH_BASE + 2); else - c2 = *(unsigned char *) (FLASH_BASE + 1); + c2 = *(volatile unsigned char *) (FLASH_BASE + 1); c2 += (c1 << 8); /* * set it back to read mode */ - *(unsigned char *) (FLASH_BASE + 0x8000) = 0xFF; + *(volatile unsigned char *) (FLASH_BASE + 0x8000) = 0xFF; if (c2 == KFLASH_ID4) gbFlashSize = KFLASH_SIZE4; @@ -177,14 +181,9 @@ if (count > gbFlashSize - p) count = gbFlashSize - p; - /* - * flash virtual address - */ - p += FLASH_BASE; - read = 0; - if (copy_to_user(buf, (void *) p, count)) + if (copy_to_user(buf, (void *)(FLASH_BASE + p), count)) return -EFAULT; read += count; file->f_pos += read; @@ -193,15 +192,15 @@ static ssize_t flash_write(struct file *file, const char *buf, size_t count, loff_t * ppos) { + struct inode *inode = file->f_dentry->d_inode; unsigned long p = file->f_pos; int written; int nBlock, temp, rc; int i, j; - if (flashdebug) - printk("Flash_dev: flash_write: offset=0x%X, buffer=0x%X, count=0x%X.\n", - (unsigned int) p, (unsigned int) buf, count); + printk("flash_write: offset=0x%lX, buffer=0x%p, count=0x%X.\n", + p, buf, count); if (!gbWriteEnable) return -EINVAL; @@ -209,20 +208,25 @@ if (p < 64 * 1024 && (!gbWriteBase64Enable)) return -EINVAL; - if (count < 0) - return -EINVAL; - /* - * if write size to big - error! + * if byte count is -ve or to big - error! */ - if (count > gbFlashSize - p) + if (count < 0 || count > gbFlashSize - p) return -EINVAL; - if (verify_area(VERIFY_READ, buf, count)) return -EFAULT; + /* + * We now should lock around writes. Really, we shouldn't + * allow the flash to be opened more than once in write + * mode though (note that you can't stop two processes having + * it open even then). --rmk + */ + if (down_interruptible(&inode->i_sem)) + return -ERESTARTSYS; + written = 0; leds_event(led_claim); @@ -310,6 +314,8 @@ */ leds_event(led_release); + up(&inode->i_sem); + return written; } @@ -586,7 +592,7 @@ if (time_before(jiffies, timeout)) { if (flashdebug) printk("FlashWrite: Retrying write (addr=0x%X)...\n", - (unsigned int) pWritePtr - FLASH_BASE); + pWritePtr - FLASH_BASE); /* * no LED == waiting @@ -604,7 +610,7 @@ goto WriteRetry; } else { printk("Timeout in flash write! (addr=0x%X) Aborting...\n", - (unsigned int) pWritePtr - FLASH_BASE); + pWritePtr - FLASH_BASE); /* * return error -2 */ @@ -666,6 +672,10 @@ if (machine_is_netwinder()) { int id; + FLASH_BASE = __ioremap(DC21285_FLASH, KFLASH_SIZE4, 0); + if (!FLASH_BASE) + goto out; + id = get_flash_id(); printk("Flash ROM driver v.%s, flash device ID 0x%04X, size %d Mb.\n", NWFLASH_VERSION, id, gbFlashSize / (1024 * 1024)); @@ -674,13 +684,14 @@ ret = 0; } - +out: return ret; } MSTATIC void __exit nwflash_exit(void) { misc_deregister(&flash_miscdev); + iounmap((void *)FLASH_BASE); } EXPORT_NO_SYMBOLS; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/pcwd.c linux/drivers/char/pcwd.c --- v2.4.0-test8/linux/drivers/char/pcwd.c Wed Jul 12 21:58:42 2000 +++ linux/drivers/char/pcwd.c Sun Oct 1 19:45:29 2000 @@ -564,11 +564,7 @@ &pcwd_fops }; -#ifdef MODULE -int init_module(void) -#else -int __init pcwatchdog_init(void) -#endif +static int __init pcwatchdog_init(void) { int i, found = 0; spin_lock_init(&io_lock); @@ -644,8 +640,7 @@ return 0; } -#ifdef MODULE -void cleanup_module(void) +static void __exit pcwatchdog_exit(void) { /* Disable the board */ if (revision == PCWD_REVISION_C) { @@ -658,4 +653,6 @@ release_region(current_readport, (revision == PCWD_REVISION_A) ? 2 : 4); } -#endif + +module_init(pcwatchdog_init); +module_exit(pcwatchdog_exit); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/ppdev.c linux/drivers/char/ppdev.c --- v2.4.0-test8/linux/drivers/char/ppdev.c Wed Jul 12 21:58:42 2000 +++ linux/drivers/char/ppdev.c Wed Sep 27 13:53:52 2000 @@ -39,7 +39,13 @@ * read/write read or write in current IEEE 1284 protocol * select wait for interrupt (in readfds) * + * Changes: * Added SETTIME/GETTIME ioctl, Fred Barnes 1999. + * + * Arnaldo Carvalho de Melo 2000/08/25 + * - On error, copy_from_user and copy_to_user do not return -EFAULT, + * They return the positive number of bytes *not* copied due to address + * space errors. */ #include @@ -179,7 +185,7 @@ wrote = parport_write (pp->pdev->port, kbuffer, n); - if (wrote < 0) { + if (wrote <= 0) { if (!bytes_written) bytes_written = wrote; break; @@ -369,19 +375,19 @@ case PPRSTATUS: reg = parport_read_status (port); - return copy_to_user ((unsigned char *) arg, ®, - sizeof (reg)); - + if (copy_to_user ((unsigned char *) arg, ®, sizeof (reg))) + return -EFAULT; + return 0; case PPRDATA: reg = parport_read_data (port); - return copy_to_user ((unsigned char *) arg, ®, - sizeof (reg)); - + if (copy_to_user ((unsigned char *) arg, ®, sizeof (reg))) + return -EFAULT; + return 0; case PPRCONTROL: reg = parport_read_control (port); - return copy_to_user ((unsigned char *) arg, ®, - sizeof (reg)); - + if (copy_to_user ((unsigned char *) arg, ®, sizeof (reg))) + return -EFAULT; + return 0; case PPYIELD: parport_yield_blocking (pp->pdev); return 0; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/qpmouse.c linux/drivers/char/qpmouse.c --- v2.4.0-test8/linux/drivers/char/qpmouse.c Wed Jul 12 21:58:42 2000 +++ linux/drivers/char/qpmouse.c Tue Sep 19 08:01:34 2000 @@ -344,9 +344,14 @@ printk(KERN_INFO "82C710 type pointing device detected -- driver installed.\n"); /* printk("82C710 address = %x (should be 0x310)\n", qp_data); */ + queue = (struct qp_queue *) kmalloc(sizeof(*queue), GFP_KERNEL); + if(queue==NULL) + { + printk(KERN_ERR "qpmouse: no queue memory.\n"); + return -ENOMEM; + } qp_present = 1; misc_register(&qp_mouse); - queue = (struct qp_queue *) kmalloc(sizeof(*queue), GFP_KERNEL); memset(queue, 0, sizeof(*queue)); queue->head = queue->tail = 0; init_waitqueue_head(&queue->proc_list); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/raw.c linux/drivers/char/raw.c --- v2.4.0-test8/linux/drivers/char/raw.c Wed Jul 12 21:58:42 2000 +++ linux/drivers/char/raw.c Sun Oct 1 20:35:15 2000 @@ -19,10 +19,10 @@ #define dprintk(x...) -static struct block_device *raw_device_bindings[256] = {}; -static int raw_device_inuse[256] = {}; -static int raw_device_sector_size[256] = {}; -static int raw_device_sector_bits[256] = {}; +static struct block_device *raw_device_bindings[256]; +static int raw_device_inuse[256]; +static int raw_device_sector_size[256]; +static int raw_device_sector_bits[256]; static ssize_t rw_raw_dev(int rw, struct file *, char *, size_t, loff_t *); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/rtc.c linux/drivers/char/rtc.c --- v2.4.0-test8/linux/drivers/char/rtc.c Wed Jul 19 11:27:45 2000 +++ linux/drivers/char/rtc.c Fri Sep 22 14:09:00 2000 @@ -693,7 +693,7 @@ if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) BCD_TO_BIN(year); /* This should never happen... */ - if (year > 20 && year < 48) { + if (year >= 20 && year < 48) { epoch = 1980; guess = "ARC console"; } else if (year >= 48 && year < 70) { diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/sbc60xxwdt.c linux/drivers/char/sbc60xxwdt.c --- v2.4.0-test8/linux/drivers/char/sbc60xxwdt.c Wed Jul 12 21:58:42 2000 +++ linux/drivers/char/sbc60xxwdt.c Sun Oct 1 19:45:29 2000 @@ -338,4 +338,4 @@ } module_init(sbc60xxwdt_init); -module_exit(sbc60xxwdt_unload) +module_exit(sbc60xxwdt_unload); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/serial.c linux/drivers/char/serial.c --- v2.4.0-test8/linux/drivers/char/serial.c Thu Sep 7 08:40:58 2000 +++ linux/drivers/char/serial.c Thu Sep 21 13:23:16 2000 @@ -331,6 +331,10 @@ #define IS_PCI_REGION_IOPORT(dev, r) (pci_resource_flags((dev), (r)) & \ IORESOURCE_IO) #endif +#ifndef IS_PCI_REGION_IOMEM +#define IS_PCI_REGION_IOMEM(dev, r) (pci_resource_flags((dev), (r)) & \ + IORESOURCE_MEM) +#endif #ifndef PCI_IRQ_RESOURCE #define PCI_IRQ_RESOURCE(dev, r) ((dev)->irq_resource[r].start) #endif @@ -4185,7 +4189,7 @@ * This is the configuration table for all of the PCI serial boards * which we support. */ -static struct pci_board pci_boards[] __initdata = { +static struct pci_board pci_boards[] __devinitdata = { /* * Vendor ID, Device ID, * Subvendor ID, Subdevice ID, @@ -4606,9 +4610,9 @@ num_port++; if (first_port == -1) first_port = i; - } else { - num_iomem++; } + if (IS_PCI_REGION_IOMEM(dev, i)) + num_iomem++; } /* diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/serial_amba.c linux/drivers/char/serial_amba.c --- v2.4.0-test8/linux/drivers/char/serial_amba.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/serial_amba.c Mon Sep 18 15:15:22 2000 @@ -0,0 +1,2030 @@ +/* + * linux/drivers/char/serial_amba.c + * + * Driver for AMBA serial ports + * + * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. + * + * Copyright 1999 ARM Limited + * Copyright (C) 2000 Deep Blue Solutions Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * This is a generic driver for ARM AMBA-type serial ports. They + * have a lot of 16550-like features, but are not register compatable. + * Note that although they do have CTS, DCD and DSR inputs, they do + * not have an RI input, nor do they have DTR or RTS outputs. If + * required, these have to be supplied via some other means (eg, GPIO) + * and hooked into this driver. + * + * This could very easily become a generic serial driver for dumb UARTs + * (eg, {82,16x}50, 21285, SA1100). + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#define SERIAL_AMBA_NAME "ttyAM" +#define SERIAL_AMBA_MAJOR 204 +#define SERIAL_AMBA_MINOR 16 +#define SERIAL_AMBA_NR 2 + +#define CALLOUT_AMBA_NAME "cuaam" +#define CALLOUT_AMBA_MAJOR 205 +#define CALLOUT_AMBA_MINOR 16 +#define CALLOUT_AMBA_NR SERIAL_AMBA_NR + +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +#define DEBUG 0 +#define DEBUG_LEDS 0 + +#if DEBUG_LEDS +extern int get_leds(void); +extern int set_leds(int); +#endif + +/* + * Access routines for the AMBA UARTs + */ +#define UART_GET_INT_STATUS(p) IO_READ((p)->uart_base + AMBA_UARTIIR) +#define UART_GET_FR(p) IO_READ((p)->uart_base + AMBA_UARTFR) +#define UART_GET_CHAR(p) IO_READ((p)->uart_base + AMBA_UARTDR) +#define UART_PUT_CHAR(p, c) IO_WRITE((p)->uart_base + AMBA_UARTDR, (c)) +#define UART_GET_RSR(p) IO_READ((p)->uart_base + AMBA_UARTRSR) +#define UART_GET_CR(p) IO_READ((p)->uart_base + AMBA_UARTCR) +#define UART_PUT_CR(p,c) IO_WRITE((p)->uart_base + AMBA_UARTCR, (c)) +#define UART_GET_LCRL(p) IO_READ((p)->uart_base + AMBA_UARTLCR_L) +#define UART_PUT_LCRL(p,c) IO_WRITE((p)->uart_base + AMBA_UARTLCR_L, (c)) +#define UART_GET_LCRM(p) IO_READ((p)->uart_base + AMBA_UARTLCR_M) +#define UART_PUT_LCRM(p,c) IO_WRITE((p)->uart_base + AMBA_UARTLCR_M, (c)) +#define UART_GET_LCRH(p) IO_READ((p)->uart_base + AMBA_UARTLCR_H) +#define UART_PUT_LCRH(p,c) IO_WRITE((p)->uart_base + AMBA_UARTLCR_H, (c)) +#define UART_RX_DATA(s) (((s) & AMBA_UARTFR_RXFE) == 0) +#define UART_TX_READY(s) (((s) & AMBA_UARTFR_TXFF) == 0) +#define UART_TX_EMPTY(p) ((UART_GET_FR(p) & AMBA_UARTFR_TMSK) == 0) + +#define AMBA_UARTRSR_ANY (AMBA_UARTRSR_OE|AMBA_UARTRSR_BE|AMBA_UARTRSR_PE|AMBA_UARTRSR_FE) +#define AMBA_UARTFR_MODEM_ANY (AMBA_UARTFR_DCD|AMBA_UARTFR_DSR|AMBA_UARTFR_CTS) + +/* + * Things needed by tty driver + */ +static struct tty_driver ambanormal_driver, ambacallout_driver; +static int ambauart_refcount; +static struct tty_struct *ambauart_table[SERIAL_AMBA_NR]; +static struct termios *ambauart_termios[SERIAL_AMBA_NR]; +static struct termios *ambauart_termios_locked[SERIAL_AMBA_NR]; + +#if defined(CONFIG_SERIAL_AMBA_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +/* + * Things needed internally to this driver + */ + +/* + * tmp_buf is used as a temporary buffer by serial_write. We need to + * lock it in case the copy_from_user blocks while swapping in a page, + * and some other program tries to do a serial write at the same time. + * Since the lock will only come under contention when the system is + * swapping and available memory is low, it makes sense to share one + * buffer across all the serial ports, since it significantly saves + * memory if large numbers of serial ports are open. + */ +static u_char *tmp_buf; +static DECLARE_MUTEX(tmp_buf_sem); + +#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8) + +/* number of characters left in xmit buffer before we ask for more */ +#define WAKEUP_CHARS 256 +#define AMBA_ISR_PASS_LIMIT 256 + +#define EVT_WRITE_WAKEUP 0 + +struct amba_icount { + __u32 cts; + __u32 dsr; + __u32 rng; + __u32 dcd; + __u32 rx; + __u32 tx; + __u32 frame; + __u32 overrun; + __u32 parity; + __u32 brk; + __u32 buf_overrun; +}; + +/* + * Static information about the port + */ +struct amba_port { + unsigned int uart_base; + unsigned int irq; + unsigned int uartclk; + unsigned int fifosize; + unsigned int tiocm_support; + void (*set_mctrl)(struct amba_port *, u_int mctrl); +}; + +/* + * This is the state information which is persistent across opens + */ +struct amba_state { + struct amba_icount icount; + unsigned int line; + unsigned int close_delay; + unsigned int closing_wait; + unsigned int custom_divisor; + unsigned int flags; + struct termios normal_termios; + struct termios callout_termios; + + int count; + struct amba_info *info; +}; + +#define AMBA_XMIT_SIZE 1024 +/* + * This is the state information which is only valid when the port is open. + */ +struct amba_info { + struct amba_port *port; + struct amba_state *state; + struct tty_struct *tty; + unsigned char x_char; + unsigned char old_status; + unsigned char read_status_mask; + unsigned char ignore_status_mask; + struct circ_buf xmit; + unsigned int flags; +#ifdef SUPPORT_SYSRQ + unsigned long sysrq; +#endif + + unsigned int event; + unsigned int timeout; + unsigned int lcr_h; + unsigned int mctrl; + int blocked_open; + pid_t session; + pid_t pgrp; + + struct tasklet_struct tlet; + + wait_queue_head_t open_wait; + wait_queue_head_t close_wait; + wait_queue_head_t delta_msr_wait; +}; + +#ifdef CONFIG_SERIAL_AMBA_CONSOLE +static struct console ambauart_cons; +#endif +static void ambauart_change_speed(struct amba_info *info, struct termios *old_termios); +static void ambauart_wait_until_sent(struct tty_struct *tty, int timeout); + +#if 1 //def CONFIG_SERIAL_INTEGRATOR +static void amba_set_mctrl_null(struct amba_port *port, u_int mctrl) +{ +} + +static struct amba_port amba_ports[SERIAL_AMBA_NR] = { + { + uart_base: IO_ADDRESS(INTEGRATOR_UART0_BASE), + irq: IRQ_UARTINT0, + uartclk: 14745600, + fifosize: 8, + set_mctrl: amba_set_mctrl_null, + }, + { + uart_base: IO_ADDRESS(INTEGRATOR_UART1_BASE), + irq: IRQ_UARTINT1, + uartclk: 14745600, + fifosize: 8, + set_mctrl: amba_set_mctrl_null, + } +}; +#endif + +static struct amba_state amba_state[SERIAL_AMBA_NR]; + +static void ambauart_enable_rx_interrupt(struct amba_info *info) +{ + unsigned int cr; + + cr = UART_GET_CR(info->port); + cr |= AMBA_UARTCR_RIE | AMBA_UARTCR_RTIE; + UART_PUT_CR(info->port, cr); +} + +static void ambauart_disable_rx_interrupt(struct amba_info *info) +{ + unsigned int cr; + + cr = UART_GET_CR(info->port); + cr &= ~(AMBA_UARTCR_RIE | AMBA_UARTCR_RTIE); + UART_PUT_CR(info->port, cr); +} + +static void ambauart_enable_tx_interrupt(struct amba_info *info) +{ + unsigned int cr; + + cr = UART_GET_CR(info->port); + cr |= AMBA_UARTCR_TIE; + UART_PUT_CR(info->port, cr); +} + +static void ambauart_disable_tx_interrupt(struct amba_info *info) +{ + unsigned int cr; + + cr = UART_GET_CR(info->port); + cr &= ~AMBA_UARTCR_TIE; + UART_PUT_CR(info->port, cr); +} + +static void ambauart_stop(struct tty_struct *tty) +{ + struct amba_info *info = tty->driver_data; + unsigned long flags; + + save_flags(flags); cli(); + ambauart_disable_tx_interrupt(info); + restore_flags(flags); +} + +static void ambauart_start(struct tty_struct *tty) +{ + struct amba_info *info = tty->driver_data; + unsigned long flags; + + save_flags(flags); cli(); + if (info->xmit.head != info->xmit.tail + && info->xmit.buf) + ambauart_enable_tx_interrupt(info); + restore_flags(flags); +} + + +/* + * This routine is used by the interrupt handler to schedule + * processing in the software interrupt portion of the driver. + */ +static void ambauart_event(struct amba_info *info, int event) +{ + info->event |= 1 << event; + tasklet_schedule(&info->tlet); +} + +static void +#ifdef SUPPORT_SYSRQ +ambauart_rx_chars(struct amba_info *info, struct pt_regs *regs) +#else +ambauart_rx_chars(struct amba_info *info) +#endif +{ + struct tty_struct *tty = info->tty; + unsigned int status, ch, rsr, flg, ignored = 0; + struct amba_icount *icount = &info->state->icount; + struct amba_port *port = info->port; + + status = UART_GET_FR(port); + while (UART_RX_DATA(status)) { + ch = UART_GET_CHAR(port); + + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + goto ignore_char; + icount->rx++; + + flg = TTY_NORMAL; + + /* + * Note that the error handling code is + * out of the main execution path + */ + rsr = UART_GET_RSR(port); + if (rsr & AMBA_UARTRSR_ANY) + goto handle_error; +#ifdef SUPPORT_SYSRQ + if (info->sysrq) { + if (ch && time_before(jiffies, info->sysrq)) { + handle_sysrq(ch, regs, NULL, NULL); + info->sysrq = 0; + goto ignore_char; + } + info->sysrq = 0; + } +#endif + error_return: + *tty->flip.flag_buf_ptr++ = flg; + *tty->flip.char_buf_ptr++ = ch; + tty->flip.count++; + ignore_char: + status = UART_GET_FR(port); + } +out: + tty_flip_buffer_push(tty); + return; + +handle_error: + if (rsr & AMBA_UARTRSR_BE) { + rsr &= ~(AMBA_UARTRSR_FE | AMBA_UARTRSR_PE); + icount->brk++; + +#ifdef SUPPORT_SYSRQ + if (info->state->line == ambauart_cons.index) { + if (!info->sysrq) { + info->sysrq = jiffies + HZ*5; + goto ignore_char; + } + } +#endif + } else if (rsr & AMBA_UARTRSR_PE) + icount->parity++; + else if (rsr & AMBA_UARTRSR_FE) + icount->frame++; + if (rsr & AMBA_UARTRSR_OE) + icount->overrun++; + + if (rsr & info->ignore_status_mask) { + if (++ignored > 100) + goto out; + goto ignore_char; + } + rsr &= info->read_status_mask; + + if (rsr & AMBA_UARTRSR_BE) + flg = TTY_BREAK; + else if (rsr & AMBA_UARTRSR_PE) + flg = TTY_PARITY; + else if (rsr & AMBA_UARTRSR_FE) + flg = TTY_FRAME; + + if (rsr & AMBA_UARTRSR_OE) { + /* + * CHECK: does overrun affect the current character? + * ASSUMPTION: it does not. + */ + *tty->flip.flag_buf_ptr++ = flg; + *tty->flip.char_buf_ptr++ = ch; + tty->flip.count++; + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + goto ignore_char; + ch = 0; + flg = TTY_OVERRUN; + } +#ifdef SUPPORT_SYSRQ + info->sysrq = 0; +#endif + goto error_return; +} + +static void ambauart_tx_chars(struct amba_info *info) +{ + struct amba_port *port = info->port; + int count; + + if (info->x_char) { + UART_PUT_CHAR(port, info->x_char); + info->state->icount.tx++; + info->x_char = 0; + return; + } + if (info->xmit.head == info->xmit.tail + || info->tty->stopped + || info->tty->hw_stopped) { + ambauart_disable_tx_interrupt(info); + return; + } + + count = port->fifosize; + do { + UART_PUT_CHAR(port, info->xmit.buf[info->xmit.tail]); + info->xmit.tail = (info->xmit.tail + 1) & (AMBA_XMIT_SIZE - 1); + info->state->icount.tx++; + if (info->xmit.head == info->xmit.tail) + break; + } while (--count > 0); + + if (CIRC_CNT(info->xmit.head, + info->xmit.tail, + AMBA_XMIT_SIZE) < WAKEUP_CHARS) + ambauart_event(info, EVT_WRITE_WAKEUP); + + if (info->xmit.head == info->xmit.tail) { + ambauart_disable_tx_interrupt(info); + } +} + +static void ambauart_modem_status(struct amba_info *info) +{ + unsigned int status, delta; + struct amba_icount *icount = &info->state->icount; + + status = UART_GET_FR(info->port) & AMBA_UARTFR_MODEM_ANY; + + delta = status ^ info->old_status; + info->old_status = status; + + if (!delta) + return; + + if (delta & AMBA_UARTFR_DCD) { + icount->dcd++; +#ifdef CONFIG_HARD_PPS + if ((info->flags & ASYNC_HARDPPS_CD) && + (status & AMBA_UARTFR_DCD) + hardpps(); +#endif + if (info->flags & ASYNC_CHECK_CD) { + if (status & AMBA_UARTFR_DCD) + wake_up_interruptible(&info->open_wait); + else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) && + (info->flags & ASYNC_CALLOUT_NOHUP))) { + if (info->tty) + tty_hangup(info->tty); + } + } + } + + if (delta & AMBA_UARTFR_DSR) + icount->dsr++; + + if (delta & AMBA_UARTFR_CTS) { + icount->cts++; + + if (info->flags & ASYNC_CTS_FLOW) { + status &= AMBA_UARTFR_CTS; + + if (info->tty->hw_stopped) { + if (status) { + info->tty->hw_stopped = 0; + ambauart_enable_tx_interrupt(info); + ambauart_event(info, EVT_WRITE_WAKEUP); + } + } else { + if (!status) { + info->tty->hw_stopped = 1; + ambauart_disable_tx_interrupt(info); + } + } + } + } + wake_up_interruptible(&info->delta_msr_wait); + +} + +static void ambauart_int(int irq, void *dev_id, struct pt_regs *regs) +{ + struct amba_info *info = dev_id; + unsigned int status, pass_counter = 0; + +#if DEBUG_LEDS + // tell the world + set_leds(get_leds() | RED_LED); +#endif + + status = UART_GET_INT_STATUS(info->port); + do { + /* + * FIXME: what about clearing the interrupts? + */ + + if (status & (AMBA_UARTIIR_RTIS | AMBA_UARTIIR_RIS)) +#ifdef SUPPORT_SYSRQ + ambauart_rx_chars(info, regs); +#else + ambauart_rx_chars(info); +#endif + if (status & AMBA_UARTIIR_TIS) + ambauart_tx_chars(info); + if (status & AMBA_UARTIIR_MIS) + ambauart_modem_status(info); + if (pass_counter++ > AMBA_ISR_PASS_LIMIT) + break; + + status = UART_GET_INT_STATUS(info->port); + } while (status & (AMBA_UARTIIR_RTIS | AMBA_UARTIIR_RIS | AMBA_UARTIIR_TIS)); + +#if DEBUG_LEDS + // tell the world + set_leds(get_leds() & ~RED_LED); +#endif +} + +static void ambauart_tasklet_action(unsigned long data) +{ + struct amba_info *info = (struct amba_info *)data; + struct tty_struct *tty; + + tty = info->tty; + if (!tty || !test_and_clear_bit(EVT_WRITE_WAKEUP, &info->event)) + return; + + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + wake_up_interruptible(&tty->write_wait); +} + +static int ambauart_startup(struct amba_info *info) +{ + unsigned long flags; + unsigned long page; + int retval = 0; + + page = get_zeroed_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + + save_flags(flags); cli(); + + if (info->flags & ASYNC_INITIALIZED) { + free_page(page); + goto errout; + } + + if (info->xmit.buf) + free_page(page); + else + info->xmit.buf = (unsigned char *) page; + + /* + * Allocate the IRQ + */ + retval = request_irq(info->port->irq, ambauart_int, 0, "amba", info); + if (retval) { + if (capable(CAP_SYS_ADMIN)) { + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + retval = 0; + } + goto errout; + } + + info->mctrl = 0; + if (info->tty->termios->c_cflag & CBAUD) + info->mctrl = TIOCM_RTS | TIOCM_DTR; + info->port->set_mctrl(info->port, info->mctrl); + + /* + * initialise the old status of the modem signals + */ + info->old_status = UART_GET_FR(info->port) & AMBA_UARTFR_MODEM_ANY; + + /* + * Finally, enable interrupts + */ + ambauart_enable_rx_interrupt(info); + + if (info->tty) + clear_bit(TTY_IO_ERROR, &info->tty->flags); + info->xmit.head = info->xmit.tail = 0; + + /* + * Set up the tty->alt_speed kludge + */ + if (info->tty) { + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + info->tty->alt_speed = 57600; + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + info->tty->alt_speed = 115200; + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + info->tty->alt_speed = 230400; + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + info->tty->alt_speed = 460800; + } + + /* + * and set the speed of the serial port + */ + ambauart_change_speed(info, 0); + + info->flags |= ASYNC_INITIALIZED; + restore_flags(flags); + return 0; + +errout: + restore_flags(flags); + return retval; +} + +/* + * This routine will shutdown a serial port; interrupts are disabled, and + * DTR is dropped if the hangup on close termio flag is on. + */ +static void ambauart_shutdown(struct amba_info *info) +{ + unsigned long flags; + + if (!(info->flags & ASYNC_INITIALIZED)) + return; + + save_flags(flags); cli(); /* Disable interrupts */ + + /* + * clear delta_msr_wait queue to avoid mem leaks: we may free the irq + * here so the queue might never be woken up + */ + wake_up_interruptible(&info->delta_msr_wait); + + /* + * Free the IRQ + */ + free_irq(info->port->irq, info); + + if (info->xmit.buf) { + unsigned long pg = (unsigned long) info->xmit.buf; + info->xmit.buf = NULL; + free_page(pg); + } + + /* + * disable all interrupts, disable the port + */ + UART_PUT_CR(info->port, 0); + + /* disable break condition and fifos */ + UART_PUT_LCRH(info->port, UART_GET_LCRH(info->port) & + ~(AMBA_UARTLCR_H_BRK | AMBA_UARTLCR_H_FEN)); + + if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) + info->mctrl &= ~(TIOCM_DTR|TIOCM_RTS); + info->port->set_mctrl(info->port, info->mctrl); + + /* kill off our tasklet */ + tasklet_kill(&info->tlet); + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + + info->flags &= ~ASYNC_INITIALIZED; + restore_flags(flags); +} + +static void ambauart_change_speed(struct amba_info *info, struct termios *old_termios) +{ + unsigned int lcr_h, baud, quot, cflag, old_cr, bits; + unsigned long flags; + + if (!info->tty || !info->tty->termios) + return; + + cflag = info->tty->termios->c_cflag; + +#if DEBUG + printk("ambauart_set_cflag(0x%x) called\n", cflag); +#endif + /* byte size and parity */ + switch (cflag & CSIZE) { + case CS5: lcr_h = AMBA_UARTLCR_H_WLEN_5; bits = 7; break; + case CS6: lcr_h = AMBA_UARTLCR_H_WLEN_6; bits = 8; break; + case CS7: lcr_h = AMBA_UARTLCR_H_WLEN_7; bits = 9; break; + default: lcr_h = AMBA_UARTLCR_H_WLEN_8; bits = 10; break; // CS8 + } + if (cflag & CSTOPB) { + lcr_h |= AMBA_UARTLCR_H_STP2; + bits ++; + } + if (cflag & PARENB) { + lcr_h |= AMBA_UARTLCR_H_PEN; + bits++; + if (!(cflag & PARODD)) + lcr_h |= AMBA_UARTLCR_H_EPS; + } + if (info->port->fifosize > 1) + lcr_h |= AMBA_UARTLCR_H_FEN; + + do { + /* Determine divisor based on baud rate */ + baud = tty_get_baud_rate(info->tty); + if (!baud) + baud = 9600; + + if (baud == 38400 && + ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) + quot = info->state->custom_divisor; + else + quot = (info->port->uartclk / (16 * baud)) - 1; + + if (!quot && old_termios) { + info->tty->termios->c_cflag &= ~CBAUD; + info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD); + old_termios = NULL; + } + } while (quot == 0 && old_termios); + + /* As a last resort, if the quotient is zero, default to 9600 bps */ + if (!quot) + quot = (info->port->uartclk / (16 * 9600)) - 1; + + info->timeout = (info->port->fifosize * HZ * bits * quot) / + (info->port->uartclk / 16); + info->timeout += HZ/50; /* Add .02 seconds of slop */ + + if (cflag & CRTSCTS) + info->flags |= ASYNC_CTS_FLOW; + else + info->flags &= ~ASYNC_CTS_FLOW; + if (cflag & CLOCAL) + info->flags &= ~ASYNC_CHECK_CD; + else + info->flags |= ASYNC_CHECK_CD; + + /* + * Set up parity check flag + */ +#define RELEVENT_IFLAG(iflag) ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) + + info->read_status_mask = AMBA_UARTRSR_OE; + if (I_INPCK(info->tty)) + info->read_status_mask |= AMBA_UARTRSR_FE | AMBA_UARTRSR_PE; + if (I_BRKINT(info->tty) || I_PARMRK(info->tty)) + info->read_status_mask |= AMBA_UARTRSR_BE; + + /* + * Characters to ignore + */ + info->ignore_status_mask = 0; + if (I_IGNPAR(info->tty)) + info->ignore_status_mask |= AMBA_UARTRSR_FE | AMBA_UARTRSR_PE; + if (I_IGNBRK(info->tty)) { + info->ignore_status_mask |= AMBA_UARTRSR_BE; + /* + * If we're ignoring parity and break indicators, + * ignore overruns to (for real raw support). + */ + if (I_IGNPAR(info->tty)) + info->ignore_status_mask |= AMBA_UARTRSR_OE; + } + + /* first, disable everything */ + save_flags(flags); cli(); + old_cr = UART_GET_CR(info->port) &= ~AMBA_UARTCR_MSIE; + + if ((info->flags & ASYNC_HARDPPS_CD) || + (cflag & CRTSCTS) || + !(cflag & CLOCAL)) + old_cr |= AMBA_UARTCR_MSIE; + + UART_PUT_CR(info->port, 0); + restore_flags(flags); + + /* Set baud rate */ + UART_PUT_LCRM(info->port, ((quot & 0xf00) >> 8)); + UART_PUT_LCRL(info->port, (quot & 0xff)); + + /* + * ----------v----------v----------v----------v----- + * NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L + * ----------^----------^----------^----------^----- + */ + UART_PUT_LCRH(info->port, lcr_h); + UART_PUT_CR(info->port, old_cr); +} + +static void ambauart_put_char(struct tty_struct *tty, u_char ch) +{ + struct amba_info *info = tty->driver_data; + unsigned long flags; + + if (!tty || !info->xmit.buf) + return; + + save_flags(flags); cli(); + if (CIRC_SPACE(info->xmit.head, info->xmit.tail, AMBA_XMIT_SIZE) != 0) { + info->xmit.buf[info->xmit.head] = ch; + info->xmit.head = (info->xmit.head + 1) & (AMBA_XMIT_SIZE - 1); + } + restore_flags(flags); +} + +static void ambauart_flush_chars(struct tty_struct *tty) +{ + struct amba_info *info = tty->driver_data; + unsigned long flags; + + if (info->xmit.head == info->xmit.tail + || tty->stopped + || tty->hw_stopped + || !info->xmit.buf) + return; + + save_flags(flags); cli(); + ambauart_enable_tx_interrupt(info); + restore_flags(flags); +} + +static int ambauart_write(struct tty_struct *tty, int from_user, + const u_char * buf, int count) +{ + struct amba_info *info = tty->driver_data; + unsigned long flags; + int c, ret = 0; + + if (!tty || !info->xmit.buf || !tmp_buf) + return 0; + + save_flags(flags); + if (from_user) { + down(&tmp_buf_sem); + while (1) { + int c1; + c = CIRC_SPACE_TO_END(info->xmit.head, + info->xmit.tail, + AMBA_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, + AMBA_XMIT_SIZE); + if (c1 < c) + c = c1; + memcpy(info->xmit.buf + info->xmit.head, tmp_buf, c); + info->xmit.head = (info->xmit.head + c) & + (AMBA_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, + AMBA_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) & + (AMBA_XMIT_SIZE - 1); + buf += c; + count -= c; + ret += c; + } + restore_flags(flags); + } + if (info->xmit.head != info->xmit.tail + && !tty->stopped + && !tty->hw_stopped) + ambauart_enable_tx_interrupt(info); + return ret; +} + +static int ambauart_write_room(struct tty_struct *tty) +{ + struct amba_info *info = tty->driver_data; + + return CIRC_SPACE(info->xmit.head, info->xmit.tail, AMBA_XMIT_SIZE); +} + +static int ambauart_chars_in_buffer(struct tty_struct *tty) +{ + struct amba_info *info = tty->driver_data; + + return CIRC_CNT(info->xmit.head, info->xmit.tail, AMBA_XMIT_SIZE); +} + +static void ambauart_flush_buffer(struct tty_struct *tty) +{ + struct amba_info *info = tty->driver_data; + unsigned long flags; + +#if DEBUG + printk("ambauart_flush_buffer(%d) called\n", + MINOR(tty->device) - tty->driver.minor_start); +#endif + 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 + */ +static void ambauart_send_xchar(struct tty_struct *tty, char ch) +{ + struct amba_info *info = tty->driver_data; + + info->x_char = ch; + if (ch) + ambauart_enable_tx_interrupt(info); +} + +static void ambauart_throttle(struct tty_struct *tty) +{ + struct amba_info *info = tty->driver_data; + unsigned long flags; + + if (I_IXOFF(tty)) + ambauart_send_xchar(tty, STOP_CHAR(tty)); + + if (tty->termios->c_cflag & CRTSCTS) { + save_flags(flags); cli(); + info->mctrl &= ~TIOCM_RTS; + info->port->set_mctrl(info->port, info->mctrl); + restore_flags(flags); + } +} + +static void ambauart_unthrottle(struct tty_struct *tty) +{ + struct amba_info *info = (struct amba_info *) tty->driver_data; + unsigned long flags; + + if (I_IXOFF(tty)) { + if (info->x_char) + info->x_char = 0; + else + ambauart_send_xchar(tty, START_CHAR(tty)); + } + + if (tty->termios->c_cflag & CRTSCTS) { + save_flags(flags); cli(); + info->mctrl |= TIOCM_RTS; + info->port->set_mctrl(info->port, info->mctrl); + restore_flags(flags); + } +} + +static int get_serial_info(struct amba_info *info, struct serial_struct *retinfo) +{ + struct amba_state *state = info->state; + struct amba_port *port = info->port; + struct serial_struct tmp; + + memset(&tmp, 0, sizeof(tmp)); + tmp.type = 0; + tmp.line = state->line; + tmp.port = port->uart_base; + if (HIGH_BITS_OFFSET) + tmp.port_high = port->uart_base >> HIGH_BITS_OFFSET; + tmp.irq = port->irq; + tmp.flags = 0; + tmp.xmit_fifo_size = port->fifosize; + tmp.baud_base = port->uartclk / 16; + tmp.close_delay = state->close_delay; + tmp.closing_wait = state->closing_wait; + tmp.custom_divisor = state->custom_divisor; + + if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) + return -EFAULT; + return 0; +} + +static int set_serial_info(struct amba_info *info, + struct serial_struct *newinfo) +{ + struct serial_struct new_serial; + struct amba_state *state, old_state; + struct amba_port *port; + unsigned long new_port; + unsigned int i, change_irq, change_port; + int retval = 0; + + if (copy_from_user(&new_serial, newinfo, sizeof(new_serial))) + return -EFAULT; + + state = info->state; + old_state = *state; + port = info->port; + + new_port = new_serial.port; + if (HIGH_BITS_OFFSET) + new_port += (unsigned long) new_serial.port_high << HIGH_BITS_OFFSET; + + change_irq = new_serial.irq != port->irq; + change_port = new_port != port->uart_base; + + if (!capable(CAP_SYS_ADMIN)) { + if (change_irq || change_port || + (new_serial.baud_base != port->uartclk / 16) || + (new_serial.close_delay != state->close_delay) || + (new_serial.xmit_fifo_size != port->fifosize) || + ((new_serial.flags & ~ASYNC_USR_MASK) != + (state->flags & ~ASYNC_USR_MASK))) + return -EPERM; + state->flags = ((state->flags & ~ASYNC_USR_MASK) | + (new_serial.flags & ASYNC_USR_MASK)); + info->flags = ((info->flags & ~ASYNC_USR_MASK) | + (new_serial.flags & ASYNC_USR_MASK)); + state->custom_divisor = new_serial.custom_divisor; + goto check_and_exit; + } + + if ((new_serial.irq >= NR_IRQS) || (new_serial.irq < 0) || + (new_serial.baud_base < 9600)) + return -EINVAL; + + if (new_serial.type && change_port) { + for (i = 0; i < SERIAL_AMBA_NR; i++) + if ((port != amba_ports + i) && + amba_ports[i].uart_base != new_port) + return -EADDRINUSE; + } + + if ((change_port || change_irq) && (state->count > 1)) + return -EBUSY; + + /* + * OK, past this point, all the error checking has been done. + * At this point, we start making changes..... + */ + port->uartclk = new_serial.baud_base * 16; + state->flags = ((state->flags & ~ASYNC_FLAGS) | + (new_serial.flags & ASYNC_FLAGS)); + info->flags = ((state->flags & ~ASYNC_INTERNAL_FLAGS) | + (info->flags & ASYNC_INTERNAL_FLAGS)); + state->custom_divisor = new_serial.custom_divisor; + state->close_delay = new_serial.close_delay * HZ / 100; + state->closing_wait = new_serial.closing_wait * HZ / 100; + info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; + port->fifosize = new_serial.xmit_fifo_size; + + if (change_port || change_irq) { + /* + * We need to shutdown the serial port at the old + * port/irq combination. + */ + ambauart_shutdown(info); + port->irq = new_serial.irq; + port->uart_base = new_port; + } + +check_and_exit: + if (!port->uart_base) + return 0; + if (info->flags & ASYNC_INITIALIZED) { + if ((old_state.flags & ASYNC_SPD_MASK) != + (state->flags & ASYNC_SPD_MASK) || + (old_state.custom_divisor != state->custom_divisor)) { + if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + info->tty->alt_speed = 57600; + if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + info->tty->alt_speed = 115200; + if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + info->tty->alt_speed = 230400; + if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + info->tty->alt_speed = 460800; + ambauart_change_speed(info, NULL); + } + } else + retval = ambauart_startup(info); + return retval; +} + + +/* + * get_lsr_info - get line status register info + */ +static int get_lsr_info(struct amba_info *info, unsigned int *value) +{ + unsigned int result, status; + unsigned long flags; + + save_flags(flags); cli(); + status = UART_GET_FR(info->port); + restore_flags(flags); + result = status & AMBA_UARTFR_BUSY ? TIOCSER_TEMT : 0; + + /* + * If we're about to load something into the transmit + * register, we'll pretend the transmitter isn't empty to + * avoid a race condition (depending on when the transmit + * interrupt happens). + */ + if (info->x_char || + ((CIRC_CNT(info->xmit.head, info->xmit.tail, + AMBA_XMIT_SIZE) > 0) && + !info->tty->stopped && !info->tty->hw_stopped)) + result &= TIOCSER_TEMT; + + return put_user(result, value); +} + +static int get_modem_info(struct amba_info *info, unsigned int *value) +{ + unsigned int result = info->mctrl; + unsigned int status; + + status = UART_GET_FR(info->port); + if (status & AMBA_UARTFR_DCD) + result |= TIOCM_CAR; + if (status & AMBA_UARTFR_DSR) + result |= TIOCM_DSR; + if (status & AMBA_UARTFR_CTS) + result |= TIOCM_CTS; + + return put_user(result, value); +} + +static int set_modem_info(struct amba_info *info, unsigned int cmd, + unsigned int *value) +{ + unsigned int arg, old; + unsigned long flags; + + if (get_user(arg, value)) + return -EFAULT; + + old = info->mctrl; + switch (cmd) { + case TIOCMBIS: + info->mctrl |= arg; + break; + + case TIOCMBIC: + info->mctrl &= ~arg; + break; + + case TIOCMSET: + info->mctrl = arg; + break; + + default: + return -EINVAL; + } + save_flags(flags); cli(); + if (old != info->mctrl) + info->port->set_mctrl(info->port, info->mctrl); + restore_flags(flags); + return 0; +} + +static void ambauart_break_ctl(struct tty_struct *tty, int break_state) +{ + struct amba_info *info = tty->driver_data; + unsigned long flags; + unsigned int lcr_h; + + save_flags(flags); cli(); + lcr_h = UART_GET_LCRH(info->port); + if (break_state == -1) + lcr_h |= AMBA_UARTLCR_H_BRK; + else + lcr_h &= ~AMBA_UARTLCR_H_BRK; + UART_PUT_LCRH(info->port, lcr_h); + restore_flags(flags); +} + +static int ambauart_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct amba_info *info = tty->driver_data; + struct amba_icount cprev, cnow; + struct serial_icounter_struct icount; + unsigned long flags; + + if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && + (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) && + (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { + if (tty->flags & (1 << TTY_IO_ERROR)) + return -EIO; + } + + switch (cmd) { + case TIOCMGET: + return get_modem_info(info, (unsigned int *)arg); + case TIOCMBIS: + case TIOCMBIC: + case TIOCMSET: + return set_modem_info(info, cmd, (unsigned int *)arg); + 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); + /* + * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change + * - mask passed in arg for lines of interest + * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) + * Caller should use TIOCGICOUNT to see which one it was + */ + case TIOCMIWAIT: + save_flags(flags); cli(); + /* note the counters on entry */ + cprev = info->state->icount; + /* Force modem status interrupts on */ + UART_PUT_CR(info->port, UART_GET_CR(info->port) | AMBA_UARTCR_MSIE); + restore_flags(flags); + while (1) { + interruptible_sleep_on(&info->delta_msr_wait); + /* see if a signal did it */ + if (signal_pending(current)) + return -ERESTARTSYS; + save_flags(flags); cli(); + cnow = info->state->icount; /* atomic copy */ + restore_flags(flags); + if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && + cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) + return -EIO; /* no change => error */ + if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || + ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || + ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || + ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) { + return 0; + } + cprev = cnow; + } + /* NOTREACHED */ + + /* + * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) + * Return: write counters to the user passed counter struct + * NB: both 1->0 and 0->1 transitions are counted except for + * RI where only 0->1 is counted. + */ + case TIOCGICOUNT: + save_flags(flags); cli(); + cnow = info->state->icount; + restore_flags(flags); + icount.cts = cnow.cts; + icount.dsr = cnow.dsr; + icount.rng = cnow.rng; + icount.dcd = cnow.dcd; + icount.rx = cnow.rx; + icount.tx = cnow.tx; + icount.frame = cnow.frame; + icount.overrun = cnow.overrun; + icount.parity = cnow.parity; + icount.brk = cnow.brk; + icount.buf_overrun = cnow.buf_overrun; + + return copy_to_user((void *)arg, &icount, sizeof(icount)) + ? -EFAULT : 0; + + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static void ambauart_set_termios(struct tty_struct *tty, struct termios *old_termios) +{ + struct amba_info *info = tty->driver_data; + unsigned long flags; + unsigned int cflag = tty->termios->c_cflag; + + if ((cflag ^ old_termios->c_cflag) == 0 && + RELEVENT_IFLAG(tty->termios->c_iflag ^ old_termios->c_iflag) == 0) + return; + + ambauart_change_speed(info, old_termios); + + /* Handle transition to B0 status */ + if ((old_termios->c_cflag & CBAUD) && + !(cflag & CBAUD)) { + save_flags(flags); cli(); + info->mctrl &= ~(TIOCM_RTS | TIOCM_DTR); + info->port->set_mctrl(info->port, info->mctrl); + restore_flags(flags); + } + + /* Handle transition away from B0 status */ + if (!(old_termios->c_cflag & CBAUD) && + (cflag & CBAUD)) { + save_flags(flags); cli(); + info->mctrl |= TIOCM_DTR; + if (!(cflag & CRTSCTS) || + !test_bit(TTY_THROTTLED, &tty->flags)) + info->mctrl |= TIOCM_RTS; + info->port->set_mctrl(info->port, info->mctrl); + restore_flags(flags); + } + + /* Handle turning off CRTSCTS */ + if ((old_termios->c_cflag & CRTSCTS) && + !(cflag & CRTSCTS)) { + tty->hw_stopped = 0; + ambauart_start(tty); + } + +#if 0 + /* + * No need to wake up processes in open wait, since they + * sample the CLOCAL flag once, and don't recheck it. + * XXX It's not clear whether the current behavior is correct + * or not. Hence, this may change..... + */ + if (!(old_termios->c_cflag & CLOCAL) && + (tty->termios->c_cflag & CLOCAL)) + wake_up_interruptible(&info->open_wait); +#endif +} + +static void ambauart_close(struct tty_struct *tty, struct file *filp) +{ + struct amba_info *info = tty->driver_data; + struct amba_state *state; + unsigned long flags; + + if (!info) + return; + + state = info->state; + +#if DEBUG + printk("ambauart_close() called\n"); +#endif + + save_flags(flags); cli(); + + if (tty_hung_up_p(filp)) { + MOD_DEC_USE_COUNT; + restore_flags(flags); + return; + } + + if ((tty->count == 1) && (state->count != 1)) { + /* + * Uh, oh. tty->count is 1, which means that the tty + * structure will be freed. state->count should always + * be one in these conditions. If it's greater than + * one, we've got real problems, since it means the + * serial port won't be shutdown. + */ + printk("ambauart_close: bad serial port count; tty->count is 1, " + "state->count is %d\n", state->count); + state->count = 1; + } + if (--state->count < 0) { + printk("rs_close: bad serial port count for %s%d: %d\n", + tty->driver.name, info->state->line, state->count); + state->count = 0; + } + if (state->count) { + MOD_DEC_USE_COUNT; + restore_flags(flags); + return; + } + info->flags |= ASYNC_CLOSING; + restore_flags(flags); + /* + * Save the termios structure, since this port may have + * separate termios for callout and dialin. + */ + if (info->flags & ASYNC_NORMAL_ACTIVE) + info->state->normal_termios = *tty->termios; + if (info->flags & ASYNC_CALLOUT_ACTIVE) + info->state->callout_termios = *tty->termios; + /* + * Now we wait for the transmit buffer to clear; and we notify + * the line discipline to only process XON/XOFF characters. + */ + tty->closing = 1; + if (info->state->closing_wait != ASYNC_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, info->state->closing_wait); + /* + * At this point, we stop accepting input. To do this, we + * disable the receive line status interrupts. + */ + if (info->flags & ASYNC_INITIALIZED) { + ambauart_disable_rx_interrupt(info); + /* + * Before we drop DTR, make sure the UART transmitter + * has completely drained; this is especially + * important if there is a transmit FIFO! + */ + ambauart_wait_until_sent(tty, info->timeout); + } + ambauart_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 = NULL; + if (info->blocked_open) { + if (info->state->close_delay) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(info->state->close_delay); + } + wake_up_interruptible(&info->open_wait); + } + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| + ASYNC_CLOSING); + wake_up_interruptible(&info->close_wait); + MOD_DEC_USE_COUNT; +} + +static void ambauart_wait_until_sent(struct tty_struct *tty, int timeout) +{ + struct amba_info *info = (struct amba_info *) tty->driver_data; + unsigned long char_time, expire; + unsigned int status; + + if (info->port->fifosize == 0) + return; + + /* + * Set the check interval to be 1/5 of the estimated time to + * send a single character, and make it at least 1. The check + * interval should also be less than the timeout. + * + * Note: we have to use pretty tight timings here to satisfy + * the NIST-PCTS. + */ + char_time = (info->timeout - HZ/50) / info->port->fifosize; + char_time = char_time / 5; + if (char_time == 0) + char_time = 1; + if (timeout && timeout < char_time) + char_time = timeout; + /* + * If the transmitter hasn't cleared in twice the approximate + * amount of time to send the entire FIFO, it probably won't + * ever clear. This assumes the UART isn't doing flow + * control, which is currently the case. Hence, if it ever + * takes longer than info->timeout, this is probably due to a + * UART bug of some kind. So, we clamp the timeout parameter at + * 2*info->timeout. + */ + if (!timeout || timeout > 2 * info->timeout) + timeout = 2 * info->timeout; + + expire = jiffies + timeout; +#if DEBUG + printk("ambauart_wait_until_sent(%d), jiff=%lu, expire=%lu...\n", + MINOR(tty->device) - tty->driver.minor_start, jiffies, + expire); +#endif + while (UART_GET_FR(info->port) & AMBA_UARTFR_BUSY) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(char_time); + if (signal_pending(current)) + break; + if (timeout && time_after(jiffies, expire)) + break; + status = UART_GET_FR(info->port); + } + set_current_state(TASK_RUNNING); +} + +static void ambauart_hangup(struct tty_struct *tty) +{ + struct amba_info *info = tty->driver_data; + struct amba_state *state = info->state; + + ambauart_flush_buffer(tty); + if (info->flags & ASYNC_CLOSING) + return; + ambauart_shutdown(info); + info->event = 0; + state->count = 0; + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); + info->tty = NULL; + wake_up_interruptible(&info->open_wait); +} + +static int block_til_ready(struct tty_struct *tty, struct file *filp, + struct amba_info *info) +{ + DECLARE_WAITQUEUE(wait, current); + struct amba_state *state = info->state; + unsigned long flags; + int do_clocal = 0, extra_count = 0, retval; + + /* + * 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); + return (info->flags & ASYNC_HUP_NOTIFY) ? + -EAGAIN : -ERESTARTSYS; + } + + /* + * If this is a callout device, then just make sure the normal + * device isn't being used. + */ + if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) { + if (info->flags & ASYNC_NORMAL_ACTIVE) + return -EBUSY; + if ((info->flags & ASYNC_CALLOUT_ACTIVE) && + (info->flags & ASYNC_SESSION_LOCKOUT) && + (info->session != current->session)) + return -EBUSY; + if ((info->flags & ASYNC_CALLOUT_ACTIVE) && + (info->flags & ASYNC_PGRP_LOCKOUT) && + (info->pgrp != current->pgrp)) + return -EBUSY; + info->flags |= ASYNC_CALLOUT_ACTIVE; + return 0; + } + + /* + * If non-blocking mode is set, or the port is not enabled, + * then make the check up front and then exit. + */ + if ((filp->f_flags & O_NONBLOCK) || + (tty->flags & (1 << TTY_IO_ERROR))) { + if (info->flags & ASYNC_CALLOUT_ACTIVE) + return -EBUSY; + info->flags |= ASYNC_NORMAL_ACTIVE; + return 0; + } + + if (info->flags & ASYNC_CALLOUT_ACTIVE) { + if (state->normal_termios.c_cflag & CLOCAL) + do_clocal = 1; + } else { + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; + } + + /* + * Block waiting for the carrier detect and the line to become + * free (i.e., not in use by the callout). While we are in + * this loop, state->count is dropped by one, so that + * rs_close() knows when to free things. We restore it upon + * exit, either normal or abnormal. + */ + retval = 0; + add_wait_queue(&info->open_wait, &wait); + save_flags(flags); cli(); + if (!tty_hung_up_p(filp)) { + extra_count = 1; + state->count--; + } + restore_flags(flags); + info->blocked_open++; + while (1) { + save_flags(flags); cli(); + if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && + (tty->termios->c_cflag & CBAUD)) { + info->mctrl = TIOCM_DTR | TIOCM_RTS; + info->port->set_mctrl(info->port, info->mctrl); + } + restore_flags(flags); + set_current_state(TASK_INTERRUPTIBLE); + if (tty_hung_up_p(filp) || + !(info->flags & ASYNC_INITIALIZED)) { + if (info->flags & ASYNC_HUP_NOTIFY) + retval = -EAGAIN; + else + retval = -ERESTARTSYS; + break; + } + if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && + !(info->flags & ASYNC_CLOSING) && + (do_clocal || (UART_GET_FR(info->port) & AMBA_UARTFR_DCD))) + break; + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } + schedule(); + } + set_current_state(TASK_RUNNING); + remove_wait_queue(&info->open_wait, &wait); + if (extra_count) + state->count++; + info->blocked_open--; + if (retval) + return retval; + info->flags |= ASYNC_NORMAL_ACTIVE; + return 0; +} + +static struct amba_info *ambauart_get(int line) +{ + struct amba_info *info; + struct amba_state *state = amba_state + line; + + state->count++; + if (state->info) + return state->info; + info = kmalloc(sizeof(struct amba_info), GFP_KERNEL); + if (info) { + memset(info, 0, sizeof(struct amba_info)); + init_waitqueue_head(&info->open_wait); + init_waitqueue_head(&info->close_wait); + init_waitqueue_head(&info->delta_msr_wait); + info->flags = state->flags; + info->state = state; + info->port = amba_ports + line; + tasklet_init(&info->tlet, ambauart_tasklet_action, + (unsigned long)info); + } + if (state->info) { + kfree(info); + return state->info; + } + state->info = info; + return info; +} + +static int ambauart_open(struct tty_struct *tty, struct file *filp) +{ + struct amba_info *info; + int retval, line = MINOR(tty->device) - tty->driver.minor_start; + +#if DEBUG + printk("ambauart_open(%d) called\n", line); +#endif + + // is this a line that we've got? + MOD_INC_USE_COUNT; + if (line >= SERIAL_AMBA_NR) { + MOD_DEC_USE_COUNT; + return -ENODEV; + } + + info = ambauart_get(line); + if (!info) + return -ENOMEM; + + tty->driver_data = info; + info->tty = tty; + info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; + + /* + * Make sure we have the temporary buffer allocated + */ + if (!tmp_buf) { + unsigned long page = get_zeroed_page(GFP_KERNEL); + if (tmp_buf) + free_page(page); + else if (!page) { + MOD_DEC_USE_COUNT; + return -ENOMEM; + } + tmp_buf = (u_char *)page; + } + + /* + * If the port is in 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); + MOD_DEC_USE_COUNT; + return -EAGAIN; + } + + /* + * Start up the serial port + */ + retval = ambauart_startup(info); + if (retval) { + MOD_DEC_USE_COUNT; + return retval; + } + + retval = block_til_ready(tty, filp, info); + if (retval) { + MOD_DEC_USE_COUNT; + return retval; + } + + if ((info->state->count == 1) && + (info->flags & ASYNC_SPLIT_TERMIOS)) { + if (tty->driver.subtype == SERIAL_TYPE_NORMAL) + *tty->termios = info->state->normal_termios; + else + *tty->termios = info->state->callout_termios; + } +#ifdef CONFIG_SERIAL_AMBA_CONSOLE + if (ambauart_cons.cflag && ambauart_cons.index == line) { + tty->termios->c_cflag = ambauart_cons.cflag; + ambauart_cons.cflag = 0; + } +#endif + ambauart_change_speed(info, NULL); + info->session = current->session; + info->pgrp = current->pgrp; + return 0; +} + +int __init ambauart_init(void) +{ + int i; + + ambanormal_driver.magic = TTY_DRIVER_MAGIC; + ambanormal_driver.driver_name = "serial_amba"; + ambanormal_driver.name = SERIAL_AMBA_NAME; + ambanormal_driver.major = SERIAL_AMBA_MAJOR; + ambanormal_driver.minor_start = SERIAL_AMBA_MINOR; + ambanormal_driver.num = SERIAL_AMBA_NR; + ambanormal_driver.type = TTY_DRIVER_TYPE_SERIAL; + ambanormal_driver.subtype = SERIAL_TYPE_NORMAL; + ambanormal_driver.init_termios = tty_std_termios; + ambanormal_driver.init_termios.c_cflag = B38400 | CS8 | CREAD | HUPCL | CLOCAL; + ambanormal_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS; + ambanormal_driver.refcount = &ambauart_refcount; + ambanormal_driver.table = ambauart_table; + ambanormal_driver.termios = ambauart_termios; + ambanormal_driver.termios_locked = ambauart_termios_locked; + + ambanormal_driver.open = ambauart_open; + ambanormal_driver.close = ambauart_close; + ambanormal_driver.write = ambauart_write; + ambanormal_driver.put_char = ambauart_put_char; + ambanormal_driver.flush_chars = ambauart_flush_chars; + ambanormal_driver.write_room = ambauart_write_room; + ambanormal_driver.chars_in_buffer = ambauart_chars_in_buffer; + ambanormal_driver.flush_buffer = ambauart_flush_buffer; + ambanormal_driver.ioctl = ambauart_ioctl; + ambanormal_driver.throttle = ambauart_throttle; + ambanormal_driver.unthrottle = ambauart_unthrottle; + ambanormal_driver.send_xchar = ambauart_send_xchar; + ambanormal_driver.set_termios = ambauart_set_termios; + ambanormal_driver.stop = ambauart_stop; + ambanormal_driver.start = ambauart_start; + ambanormal_driver.hangup = ambauart_hangup; + ambanormal_driver.break_ctl = ambauart_break_ctl; + ambanormal_driver.wait_until_sent = ambauart_wait_until_sent; + ambanormal_driver.read_proc = NULL; + + /* + * The callout device is just like the normal device except for + * the major number and the subtype code. + */ + ambacallout_driver = ambanormal_driver; + ambacallout_driver.name = CALLOUT_AMBA_NAME; + ambacallout_driver.major = CALLOUT_AMBA_MAJOR; + ambacallout_driver.subtype = SERIAL_TYPE_CALLOUT; + ambacallout_driver.read_proc = NULL; + ambacallout_driver.proc_entry = NULL; + + if (tty_register_driver(&ambanormal_driver)) + panic("Couldn't register AMBA serial driver\n"); + if (tty_register_driver(&ambacallout_driver)) + panic("Couldn't register AMBA callout driver\n"); + + for (i = 0; i < SERIAL_AMBA_NR; i++) { + struct amba_state *state = amba_state + i; + state->line = i; + state->close_delay = 5 * HZ / 10; + state->closing_wait = 30 * HZ; + state->callout_termios = ambacallout_driver.init_termios; + state->normal_termios = ambanormal_driver.init_termios; + } + + return 0; +} + +__initcall(ambauart_init); + +#ifdef CONFIG_SERIAL_AMBA_CONSOLE +/************** console driver *****************/ + +/* + * This code is currently never used; console->read is never called. + * Therefore, although we have an implementation, we don't use it. + * FIXME: the "const char *s" should be fixed to "char *s" some day. + * (when the definition in include/linux/console.h is also fixed) + */ +#ifdef used_and_not_const_char_pointer +static int ambauart_console_read(struct console *co, const char *s, u_int count) +{ + struct amba_port *port = &amba_ports[co->index]; + unsigned int status; + char *w; + int c; +#if DEBUG + printk("ambauart_console_read() called\n"); +#endif + + c = 0; + w = s; + while (c < count) { + status = UART_GET_FR(port); + if (UART_RX_DATA(status)) { + *w++ = UART_GET_CHAR(port); + c++; + } else { + // nothing more to get, return + return c; + } + } + // return the count + return c; +} +#endif + +/* + * Print a string to the serial port trying not to disturb + * any possible real use of the port... + * + * The console_lock must be held when we get here. + */ +static void ambauart_console_write(struct console *co, const char *s, u_int count) +{ + struct amba_port *port = &amba_ports[co->index]; + unsigned int status, old_cr; + int i; + + /* + * First save the CR then disable the interrupts + */ + old_cr = UART_GET_CR(port); + UART_PUT_CR(port, AMBA_UARTCR_UARTEN); + + /* + * Now, do each character + */ + for (i = 0; i < count; i++) { + do { + status = UART_GET_FR(port); + } while (!UART_TX_READY(status)); + UART_PUT_CHAR(port, s[i]); + if (s[i] == '\n') { + do { + status = UART_GET_FR(port); + } while (!UART_TX_READY(status)); + UART_PUT_CHAR(port, '\r'); + } + } + + /* + * Finally, wait for transmitter to become empty + * and restore the TCR + */ + do { + status = UART_GET_FR(port); + } while (status & AMBA_UARTFR_BUSY); + UART_PUT_CR(port, old_cr); +} + +/* + * Receive character from the serial port + */ +static int ambauart_console_wait_key(struct console *co) +{ + struct amba_port *port = &amba_ports[co->index]; + unsigned int status; + int c; + + do { + status = UART_GET_FR(port); + } while (!UART_RX_DATA(status)); + c = UART_GET_CHAR(port); + return c; +} + +static kdev_t ambauart_console_device(struct console *c) +{ + return MKDEV(SERIAL_AMBA_MAJOR, SERIAL_AMBA_MINOR + c->index); +} + +static int __init ambauart_console_setup(struct console *co, char *options) +{ + struct amba_port *port; + int baud = 38400; + int bits = 8; + int parity = 'n'; + u_int cflag = CREAD | HUPCL | CLOCAL; + u_int lcr_h, quot; + + if (co->index >= SERIAL_AMBA_NR) + co->index = 0; + + port = &amba_ports[co->index]; + + if (options) { + char *s = options; + baud = simple_strtoul(s, NULL, 10); + while (*s >= '0' && *s <= '9') + s++; + if (*s) parity = *s++; + if (*s) bits = *s - '0'; + } + + /* + * Now construct a cflag setting. + */ + switch (baud) { + case 1200: cflag |= B1200; break; + case 2400: cflag |= B2400; break; + case 4800: cflag |= B4800; break; + default: cflag |= B9600; baud = 9600; break; + case 19200: cflag |= B19200; break; + case 38400: cflag |= B38400; break; + case 57600: cflag |= B57600; break; + case 115200: cflag |= B115200; break; + } + switch (bits) { + case 7: cflag |= CS7; lcr_h = AMBA_UARTLCR_H_WLEN_7; break; + default: cflag |= CS8; lcr_h = AMBA_UARTLCR_H_WLEN_8; break; + } + switch (parity) { + case 'o': + case 'O': cflag |= PARODD; lcr_h |= AMBA_UARTLCR_H_PEN; break; + case 'e': + case 'E': cflag |= PARENB; lcr_h |= AMBA_UARTLCR_H_PEN | + AMBA_UARTLCR_H_EPS; break; + } + + co->cflag = cflag; + + if (port->fifosize > 1) + lcr_h |= AMBA_UARTLCR_H_FEN; + + quot = (port->uartclk / (16 * baud)) - 1; + + UART_PUT_LCRL(port, (quot & 0xff)); + UART_PUT_LCRM(port, (quot >> 8)); + UART_PUT_LCRH(port, lcr_h); + + /* we will enable the port as we need it */ + UART_PUT_CR(port, 0); + + return 0; +} + +static struct console ambauart_cons = +{ + name: SERIAL_AMBA_NAME, + write: ambauart_console_write, +#ifdef used_and_not_const_char_pointer + read: ambauart_console_read, +#endif + device: ambauart_console_device, + wait_key: ambauart_console_wait_key, + unblank: NULL, + setup: ambauart_console_setup, + flags: CON_PRINTBUFFER, + index: -1, +}; + +void __init ambauart_console_init(void) +{ + register_console(&ambauart_cons); +} + +#endif /* CONFIG_SERIAL_AMBA_CONSOLE */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/sh-sci.c linux/drivers/char/sh-sci.c --- v2.4.0-test8/linux/drivers/char/sh-sci.c Wed Aug 9 13:59:04 2000 +++ linux/drivers/char/sh-sci.c Mon Oct 2 11:57:34 2000 @@ -90,6 +90,8 @@ MODULE_PARM(sci_debug, "i"); #endif +#define dprintk(x...) do { if (sci_debug) printk(x); } while(0) + static void put_char(struct sci_port *port, char c) { unsigned long flags; @@ -329,6 +331,9 @@ case 38400: t = BPS_38400; break; + case 57600: + t = BPS_57600; + break; default: printk(KERN_INFO "sci: unsupported baud rate: %d, using 115200 instead.\n", baud); case 115200: @@ -341,6 +346,8 @@ if(t >= 256) { sci_out(port, SCSMR, (sci_in(port, SCSMR) & ~3) | 1); t >>= 2; + } else { + sci_out(port, SCSMR, sci_in(port, SCSMR) & ~3); } sci_out(port, SCBRR, t); udelay((1000000+(baud-1)) / baud); /* Wait one bit interval */ @@ -374,10 +381,9 @@ if (cflag & CSTOPB) smr_val |= 0x08; sci_out(port, SCSMR, smr_val); + sci_set_baud(port, baud); port->init_pins(port, cflag); - - sci_set_baud(port, baud); sci_out(port, SCSCR, SCSCR_INIT(port)); } @@ -528,13 +534,28 @@ if (count == 0) break; - for (i=0; iflip.char_buf_ptr[i] = sci_in(port, SCxRDR); + if (port->type == PORT_SCI) { + tty->flip.char_buf_ptr[0] = sci_in(port, SCxRDR); + tty->flip.flag_buf_ptr[0] = TTY_NORMAL; + } else { + for (i=0; iflip.char_buf_ptr[i] = sci_in(port, SCxRDR); + status = sci_in(port, SCxSR); + if (status&SCxSR_FER(port)) { + tty->flip.flag_buf_ptr[i] = TTY_FRAME; + dprintk("sci: frame error\n"); + } else if (status&SCxSR_PER(port)) { + tty->flip.flag_buf_ptr[i] = TTY_PARITY; + dprintk("sci: parity error\n"); + } else { + tty->flip.flag_buf_ptr[i] = TTY_NORMAL; + } + } + } + sci_in(port, SCxSR); /* dummy read */ sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); - memset(tty->flip.flag_buf_ptr, TTY_NORMAL, count); - /* Update the kernel buffer end */ tty->flip.count += count; tty->flip.char_buf_ptr += count; @@ -549,6 +570,82 @@ tty_flip_buffer_push(tty); } +static inline int sci_handle_errors(struct sci_port *port) +{ + int copied = 0; + unsigned short status = sci_in(port, SCxSR); + struct tty_struct *tty = port->gs.tty; + + if (status&SCxSR_ORER(port) && tty->flip.countflip.flag_buf_ptr++ = TTY_OVERRUN; + dprintk("sci: overrun error\n"); + } + + if (status&SCxSR_FER(port) && tty->flip.countflip.flag_buf_ptr++ = TTY_BREAK; + dprintk("sci: BREAK detected\n"); + } + else { + /* frame error */ + copied++; + *tty->flip.flag_buf_ptr++ = TTY_FRAME; + dprintk("sci: frame error\n"); + } + } + + if (status&SCxSR_PER(port) && tty->flip.countflip.flag_buf_ptr++ = TTY_PARITY; + dprintk("sci: parity error\n"); + } + + if (copied) { + tty->flip.count += copied; + tty_flip_buffer_push(tty); + } + + return copied; +} + +static inline int sci_handle_breaks(struct sci_port *port) +{ + int copied = 0; + unsigned short status = sci_in(port, SCxSR); + struct tty_struct *tty = port->gs.tty; + + if (status&SCxSR_BRK(port) && tty->flip.countflip.flag_buf_ptr++ = TTY_BREAK; + dprintk("sci: BREAK detected\n"); + } + +#if defined(CONFIG_CPU_SUBTYPE_SH7750) + /* XXX: Handle SCIF overrun error */ + if (port->type == PORT_SCIF && (ctrl_inw(SCLSR2) & SCIF_ORER) != 0) { + ctrl_outw(0, SCLSR2); + if(tty->flip.countflip.flag_buf_ptr++ = TTY_OVERRUN; + dprintk("sci: overrun error\n"); + } + } +#endif + + if (copied) { + tty->flip.count += copied; + tty_flip_buffer_push(tty); + } + + return copied; +} + static void sci_rx_interrupt(int irq, void *ptr, struct pt_regs *regs) { struct sci_port *port = ptr; @@ -577,13 +674,31 @@ struct sci_port *port = ptr; /* Handle errors */ - if (sci_in(port, SCxSR) & SCxSR_ERRORS(port)) - sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port)); + if (port->type == PORT_SCI) { + if(sci_handle_errors(port)) { + /* discard character in rx buffer */ + sci_in(port, SCxSR); + sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); + } + } + else + sci_rx_interrupt(irq, ptr, regs); + + sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port)); /* Kick the transmission */ sci_tx_interrupt(irq, ptr, regs); } +static void sci_br_interrupt(int irq, void *ptr, struct pt_regs *regs) +{ + struct sci_port *port = ptr; + + /* Handle BREAKs */ + sci_handle_breaks(port); + sci_out(port, SCxSR, SCxSR_BREAK_CLEAR(port)); +} + static void do_softint(void *private_) { struct sci_port *port = (struct sci_port *) private_; @@ -983,8 +1098,9 @@ { struct sci_port *port; int i, j; - void (*handlers[3])(int irq, void *ptr, struct pt_regs *regs) = { - sci_er_interrupt, sci_rx_interrupt, sci_tx_interrupt + void (*handlers[4])(int irq, void *ptr, struct pt_regs *regs) = { + sci_er_interrupt, sci_rx_interrupt, sci_tx_interrupt, + sci_br_interrupt, }; printk("SuperH SCI(F) driver initialized\n"); @@ -993,7 +1109,8 @@ port = &sci_ports[j]; printk("ttySC%d at 0x%08x is a %s\n", j, port->base, (port->type == PORT_SCI) ? "SCI" : "SCIF"); - for (i=0; i<3; i++) { + for (i=0; i<4; i++) { + if (!port->irqs[i]) continue; if (request_irq(port->irqs[i], handlers[i], SA_INTERRUPT, "sci", port)) { printk(KERN_ERR "sci: Cannot allocate irq.\n"); @@ -1001,7 +1118,6 @@ } } } - /* XXX: How about BRI interrupt?? */ sci_init_drivers(); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/sh-sci.h linux/drivers/char/sh-sci.h --- v2.4.0-test8/linux/drivers/char/sh-sci.h Wed Aug 9 13:59:04 2000 +++ linux/drivers/char/sh-sci.h Mon Oct 2 11:57:34 2000 @@ -20,11 +20,11 @@ #define SCIx_RXI_IRQ 1 #define SCIx_TXI_IRQ 2 -/* ERI, RXI, TXI, */ -#define SCI_IRQS { 23, 24, 25 } -#define SH3_SCIF_IRQS { 56, 57, 59 } -#define SH3_IRDA_IRQS { 52, 53, 55 } -#define SH4_SCIF_IRQS { 40, 41, 43 } +/* ERI, RXI, TXI, BRI */ +#define SCI_IRQS { 23, 24, 25, 0 } +#define SH3_SCIF_IRQS { 56, 57, 59, 58 } +#define SH3_IRDA_IRQS { 52, 53, 55, 54 } +#define SH4_SCIF_IRQS { 40, 41, 43, 42 } #if defined(CONFIG_CPU_SUBTYPE_SH7708) # define SCI_NPORTS 1 @@ -54,6 +54,7 @@ # define SCSPTR1 0xffe0001c /* 8 bit SCI */ # define SCSPTR2 0xFFE80020 /* 16 bit SCIF */ # define SCLSR2 0xFFE80024 /* 16 bit SCIF */ +# define SCIF_ORER 0x0001 /* overrun error bit */ # define SCSCR_INIT(port) (((port)->type == PORT_SCI) ? \ 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ : \ 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ ) @@ -102,25 +103,40 @@ # define SCxSR_ERRORS(port) SCI_ERRORS # define SCxSR_RDxF(port) SCI_RDRF # define SCxSR_TDxE(port) SCI_TDRE +# define SCxSR_ORER(port) SCI_ORER +# define SCxSR_FER(port) SCI_FER +# define SCxSR_PER(port) SCI_PER +# define SCxSR_BRK(port) 0x00 # define SCxSR_RDxF_CLEAR(port) 0xbc # define SCxSR_ERROR_CLEAR(port) 0xc4 # define SCxSR_TDxE_CLEAR(port) 0x78 +# define SCxSR_BREAK_CLEAR(port) 0xc4 #elif defined(SCIF_ONLY) # define SCxSR_TEND(port) SCIF_TEND # define SCxSR_ERRORS(port) SCIF_ERRORS # define SCxSR_RDxF(port) SCIF_RDF # define SCxSR_TDxE(port) SCIF_TDFE +# define SCxSR_ORER(port) 0x0000 +# define SCxSR_FER(port) SCIF_FER +# define SCxSR_PER(port) SCIF_PER +# define SCxSR_BRK(port) SCIF_BRK # define SCxSR_RDxF_CLEAR(port) 0x00fc -# define SCxSR_ERROR_CLEAR(port) 0x0063 +# define SCxSR_ERROR_CLEAR(port) 0x0073 # define SCxSR_TDxE_CLEAR(port) 0x00df +# define SCxSR_BREAK_CLEAR(port) 0x00e3 #else # define SCxSR_TEND(port) (((port)->type == PORT_SCI) ? SCI_TEND : SCIF_TEND) # define SCxSR_ERRORS(port) (((port)->type == PORT_SCI) ? SCI_ERRORS : SCIF_ERRORS) # define SCxSR_RDxF(port) (((port)->type == PORT_SCI) ? SCI_RDRF : SCIF_RDF) # define SCxSR_TDxE(port) (((port)->type == PORT_SCI) ? SCI_TDRE : SCIF_TDFE) +# define SCxSR_ORER(port) (((port)->type == PORT_SCI) ? SCI_ORER : 0x0000) +# define SCxSR_FER(port) (((port)->type == PORT_SCI) ? SCI_FER : SCIF_FER) +# define SCxSR_PER(port) (((port)->type == PORT_SCI) ? SCI_PER : SCIF_PER) +# define SCxSR_BRK(port) (((port)->type == PORT_SCI) ? 0x00 : SCIF_BRK) # define SCxSR_RDxF_CLEAR(port) (((port)->type == PORT_SCI) ? 0xbc : 0x00fc) -# define SCxSR_ERROR_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x0063) +# define SCxSR_ERROR_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x0073) # define SCxSR_TDxE_CLEAR(port) (((port)->type == PORT_SCI) ? 0x78 : 0x00df) +# define SCxSR_BREAK_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x00e3) #endif /* SCFCR */ @@ -169,7 +185,7 @@ struct gs_port gs; int type; unsigned int base; - unsigned char irqs[3]; /* ERI, RXI, TXI */ + unsigned char irqs[4]; /* ERI, RXI, TXI, BRI */ void (*init_pins)(struct sci_port* port, unsigned int cflag); unsigned int old_cflag; struct async_icount icount; @@ -248,6 +264,34 @@ #define sci_in(port, reg) sci_##reg##_in(port) #define sci_out(port, reg, value) sci_##reg##_out(port, value) +#if defined(CONFIG_CPU_SUBTYPE_SH7708) +static inline int sci_rxd_in(struct sci_port *port) +{ + if (port->base == 0xfffffe80) + return ctrl_inb(SCSPTR)&0x01 ? 1 : 0; /* SCI */ + return 1; +} +#elif defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) +static inline int sci_rxd_in(struct sci_port *port) +{ + if (port->base == 0xfffffe80) + return ctrl_inb(SCPDR)&0x01 ? 1 : 0; /* SCI */ + if (port->base == 0xa4000150) + return ctrl_inb(SCPDR)&0x10 ? 1 : 0; /* SCIF */ + if (port->base == 0xa4000140) + return ctrl_inb(SCPDR)&0x04 ? 1 : 0; /* IRDA */ + return 1; +} +#elif defined(CONFIG_CPU_SUBTYPE_SH7750) +static inline int sci_rxd_in(struct sci_port *port) +{ + if (port->base == 0xffe00000) + return ctrl_inb(SCSPTR1)&0x01 ? 1 : 0; /* SCI */ + if (port->base == 0xffe80000) + return ctrl_inw(SCSPTR2)&0x0001 ? 1 : 0; /* SCIF */ + return 1; +} +#endif /* * Values for the BitRate Register (SCBRR) @@ -289,5 +333,6 @@ #define BPS_9600 SCBRR_VALUE(9600) #define BPS_19200 SCBRR_VALUE(19200) #define BPS_38400 SCBRR_VALUE(38400) +#define BPS_57600 SCBRR_VALUE(57600) #define BPS_115200 SCBRR_VALUE(115200) diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/softdog.c linux/drivers/char/softdog.c --- v2.4.0-test8/linux/drivers/char/softdog.c Wed Jul 12 21:58:42 2000 +++ linux/drivers/char/softdog.c Sun Oct 1 19:45:29 2000 @@ -53,7 +53,11 @@ * Our timer */ -struct timer_list watchdog_ticktock; +static void watchdog_fire(unsigned long); + +static struct timer_list watchdog_ticktock = { + function: watchdog_fire, +}; static int timer_alive = 0; @@ -164,23 +168,24 @@ &softdog_fops }; -void __init watchdog_init(void) +static int __init watchdog_init(void) { - misc_register(&softdog_miscdev); - init_timer(&watchdog_ticktock); - watchdog_ticktock.function=watchdog_fire; + int ret; + + ret = misc_register(&softdog_miscdev); + + if (ret) + return ret; + printk("Software Watchdog Timer: 0.05, timer margin: %d sec\n", soft_margin); -} -#ifdef MODULE -int init_module(void) -{ - watchdog_init(); return 0; -} +} -void cleanup_module(void) +static void __exit watchdog_exit(void) { misc_deregister(&softdog_miscdev); } -#endif + +module_init(watchdog_init); +module_exit(watchdog_exit); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/toshiba.c linux/drivers/char/toshiba.c --- v2.4.0-test8/linux/drivers/char/toshiba.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/toshiba.c Wed Sep 27 13:53:56 2000 @@ -0,0 +1,522 @@ +/* toshiba.c -- Linux driver for accessing the SMM on Toshiba laptops + * + * Copyright (c) 1996-2000 Jonathan A. Buzzard (jonathan@buzzard.org.uk) + * + * Valuable assistance and patches from: + * Tom May + * Rob Napier + * + * Fn status port numbers for machine ID's courtesy of + * 0xfc08: Garth Berry + * 0xfc11: Spencer Olson + * 0xfc13: Claudius Frankewitz + * 0xfc15: Tom May + * 0xfc17: Dave Konrad + * 0xfc1a: George Betzos + * 0xfc1d: Arthur Liu + * + * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING + * + * This code is covered by the GNU GPL and you are free to make any + * changes you wish to it under the terms of the license. However the + * code has the potential to render your computer and/or someone else's + * unusable. Please proceed with care when modifying the code. + * + * Note: Unfortunately the laptop hardware can close the System Configuration + * Interface on it's own accord. It is therefore necessary for *all* + * programs using this driver to be aware that *any* SCI call can fail at + * *any* time. It is up to any program to be aware of this eventuality + * and take appropriate steps. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * The information used to write this driver has been obtained by reverse + * engineering the software supplied by Toshiba for their portable computers in + * strict accordance with the European Council Directive 92/250/EEC on the legal + * protection of computer programs, and it's implementation into English Law by + * the Copyright (Computer Programs) Regulations 1992 (S.I. 1992 No.3233). + * + */ + +#define TOSH_VERSION "1.7 22/6/2000" +#define TOSH_DEBUG 0 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define TOSH_MINOR_DEV 181 + +static int tosh_id = 0x0000; +static int tosh_bios = 0x0000; +static int tosh_date = 0x0000; +static int tosh_sci = 0x0000; +static int tosh_fan = 0; + +static int tosh_fn = 0; + +MODULE_PARM(tosh_fn, "i"); + + +static int tosh_get_info(char *, char **, off_t, int); +static int tosh_ioctl(struct inode *, struct file *, unsigned int, + unsigned long); + + +static struct file_operations tosh_fops = { + owner: THIS_MODULE, + ioctl: tosh_ioctl, +}; + +static struct miscdevice tosh_device = { + TOSH_MINOR_DEV, + "toshiba", + &tosh_fops +}; + +/* + * Read the Fn key status + */ +static int tosh_fn_status(void) +{ + unsigned char scan; + unsigned long flags; + + if (tosh_fn!=0) { + scan = inb(tosh_fn); + } else { + save_flags(flags); + cli(); + outb(0x8e, 0xe4); + scan = inb(0xe5); + restore_flags(flags); + } + + return (int) scan; +} + + +/* + * At some point we need to emulate setting the HDD auto off times for + * the new laptops. We can do this by calling the ide_ioctl on /dev/hda. + * The values we need for the various times are + * + * Disabled 0x00 + * 1 minute 0x0c + * 3 minutes 0x24 + * 5 minutes 0x3c + * 10 minutes 0x78 + * 15 minutes 0xb4 + * 20 minutes 0xf0 + * 30 minutes 0xf1 + * + */ +/*static int tosh_emulate_hdd(SMMRegisters *regs) +{ + return 0; +}*/ + + +/* + * For the Portage 610CT and the Tecra 700CS/700CDT emulate the HCI fan function + */ +static int tosh_emulate_fan(SMMRegisters *regs) +{ + unsigned long eax,ecx,flags; + unsigned char al; + + eax = regs->eax & 0xff00; + ecx = regs->ecx & 0xffff; + + /* Portage 610CT */ + + if (tosh_id==0xfccb) { + if (eax==0xfe00) { + /* fan status */ + save_flags(flags); + cli(); + outb(0xbe, 0xe4); + al = inb(0xe5); + restore_flags(flags); + regs->eax = 0x00; + regs->ecx = (unsigned int) (al & 0x01); + } + if ((eax==0xff00) && (ecx==0x0000)) { + /* fan off */ + save_flags(flags); + cli(); + outb(0xbe, 0xe4); + al = inb(0xe5); + outb(0xbe, 0xe4); + outb (al | 0x01, 0xe5); + restore_flags(flags); + regs->eax = 0x00; + regs->ecx = 0x00; + } + if ((eax==0xff00) && (ecx==0x0001)) { + /* fan on */ + save_flags(flags); + cli(); + outb(0xbe, 0xe4); + al = inb(0xe5); + outb(0xbe, 0xe4); + outb(al & 0xfe, 0xe5); + restore_flags(flags); + regs->eax = 0x00; + regs->ecx = 0x01; + } + } + + /* Tecra 700CS/CDT */ + + if (tosh_id==0xfccc) { + if (eax==0xfe00) { + /* fan status */ + save_flags(flags); + cli(); + outb(0xe0, 0xe4); + al = inb(0xe5); + restore_flags(flags); + regs->eax = 0x00; + regs->ecx = al & 0x01; + } + if ((eax==0xff00) && (ecx==0x0000)) { + /* fan off */ + save_flags(flags); + cli(); + outb(0xe0, 0xe4); + al = inb(0xe5); + outw(0xe0 | ((al & 0xfe) << 8), 0xe4); + restore_flags(flags); + regs->eax = 0x00; + regs->ecx = 0x00; + } + if ((eax==0xff00) && (ecx==0x0001)) { + /* fan on */ + save_flags(flags); + cli(); + outb(0xe0, 0xe4); + al = inb(0xe5); + outw(0xe0 | ((al | 0x01) << 8), 0xe4); + restore_flags(flags); + regs->eax = 0x00; + regs->ecx = 0x01; + } + } + + return 0; +} + + +/* + * Put the laptop into System Management Mode + */ +static int tosh_smm(SMMRegisters *regs) +{ + int eax; + + asm ("# load the values into the registers\n\t" \ + "pushl %%eax\n\t" \ + "movl 0(%%eax),%%edx\n\t" \ + "push %%edx\n\t" \ + "movl 4(%%eax),%%ebx\n\t" \ + "movl 8(%%eax),%%ecx\n\t" \ + "movl 12(%%eax),%%edx\n\t" \ + "movl 16(%%eax),%%esi\n\t" \ + "movl 20(%%eax),%%edi\n\t" \ + "popl %%eax\n\t" \ + "# call the System Management mode\n\t" \ + "inb $0xb2,%%al\n\t" + "# fill out the memory with the values in the registers\n\t" \ + "xchgl %%eax,(%%esp)\n\t" + "movl %%ebx,4(%%eax)\n\t" \ + "movl %%ecx,8(%%eax)\n\t" \ + "movl %%edx,12(%%eax)\n\t" \ + "movl %%esi,16(%%eax)\n\t" \ + "movl %%edi,20(%%eax)\n\t" \ + "popl %%edx\n\t" \ + "movl %%edx,0(%%eax)\n\t" \ + "# setup the return value to the carry flag\n\t" \ + "lahf\n\t" \ + "shrl $8,%%eax\n\t" \ + "andl $1,%%eax\n" \ + : "=a" (eax) + : "a" (regs) + : "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory"); + + return eax; +} + + +static int tosh_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, + unsigned long arg) +{ + SMMRegisters regs; + unsigned short ax,bx; + int err; + + if (!arg) + return -EINVAL; + + if(copy_from_user(®s, (SMMRegisters *) arg, sizeof(SMMRegisters))) + return -EFAULT; + + switch (cmd) { + case TOSH_SMM: + ax = regs.eax & 0xff00; + bx = regs.ebx & 0xffff; + /* block HCI calls to read/write memory & PCI devices */ + if (((ax==0xff00) || (ax==0xfe00)) && (bx>0x0069)) + return -EINVAL; + + /* do we need to emulate the fan ? */ + if (tosh_fan==1) { + if (((ax==0xf300) || (ax==0xf400)) && (bx==0x0004)) { + err = tosh_emulate_fan(®s); + break; + } + } + err = tosh_smm(®s); + break; + default: + return -EINVAL; + } + + if(copy_to_user((SMMRegisters *) arg, ®s, sizeof(SMMRegisters))) + return -EFAULT; + + return (err==0) ? 0:-EINVAL; +} + + +/* + * Print the information for /proc/toshiba + */ +int tosh_get_info(char *buffer, char **start, off_t fpos, int length) +{ + char *temp; + int key; + + temp = buffer; + key = tosh_fn_status(); + + /* Arguments + 0) Linux driver version (this will change if format changes) + 1) Machine ID + 2) SCI version + 3) BIOS version (major, minor) + 4) BIOS date (in SCI date format) + 5) Fn Key status + */ + + temp += sprintf(temp, "1.1 0x%04x %d.%d %d.%d 0x%04x 0x%02x\n", + tosh_id, + (tosh_sci & 0xff00)>>8, + tosh_sci & 0xff, + (tosh_bios & 0xff00)>>8, + tosh_bios & 0xff, + tosh_date, + key); + + return temp-buffer; +} + + +/* + * Determine which port to use for the Fn key status + */ +static void tosh_set_fn_port(void) +{ + switch (tosh_id) { + case 0xfc11: case 0xfc13: case 0xfc15: case 0xfc1a: + tosh_fn = 0x62; + break; + case 0xfc08: case 0xfc17: case 0xfc1d: case 0xfcd1: + case 0xfce0: case 0xfce2: + tosh_fn = 0x68; + break; + default: + tosh_fn = 0x00; + break; + } + + return; +} + + +/* + * Get the machine identification number of the current model + */ +static int tosh_get_machine_id(void) +{ + int id; + SMMRegisters regs; + unsigned short bx,cx; + unsigned long address; + + id = (0x100*(int) isa_readb(0xffffe))+((int) isa_readb(0xffffa)); + + /* do we have a SCTTable machine identication number on our hands */ + + if (id==0xfc2f) { + + /* start by getting a pointer into the BIOS */ + + regs.eax = 0xc000; + regs.ebx = 0x0000; + regs.ecx = 0x0000; + tosh_smm(®s); + bx = (unsigned short) (regs.ebx & 0xffff); + + /* At this point in the Toshiba routines under MS Windows + the bx register holds 0xe6f5. However my code is producing + a different value! For the time being I will just fudge the + value. This has been verified on a Satellite Pro 430CDT, + Tecra 750CDT, Tecra 780DVD and Satellite 310CDT. */ +#if TOSH_DEBUG + printk("toshiba: debugging ID ebx=0x%04x\n", regs.ebx); +#endif + bx = 0xe6f5; + + /* now twiddle with our pointer a bit */ + + address = 0x000f0000+bx; + cx = isa_readw(address); + address = 0x000f0009+bx+cx; + cx = isa_readw(address); + address = 0x000f000a+cx; + cx = isa_readw(address); + + /* now construct our machine identification number */ + + id = ((cx & 0xff)<<8)+((cx & 0xff00)>>8); + } + + return id; +} + + +/* + * Probe for the presence of a Toshiba laptop + * + * returns and non-zero if unable to detect the presence of a Toshiba + * laptop, otherwise zero and determines the Machine ID, BIOS version and + * date, and SCI version. + */ +int tosh_probe(void) +{ + int major,minor,day,year,month,flag; + SMMRegisters regs; + + /* call the Toshiba SCI support check routine */ + + regs.eax = 0xf0f0; + regs.ebx = 0x0000; + regs.ecx = 0x0000; + flag = tosh_smm(®s); + + /* if this is not a Toshiba laptop carry flag is set and ah=0x86 */ + + if ((flag==1) || ((regs.eax & 0xff00)==0x8600)) { + printk("toshiba: not a supported Toshiba laptop\n"); + return -ENODEV; + } + + /* if we get this far then we are running on a Toshiba (probably)! */ + + tosh_sci = regs.edx & 0xffff; + + /* next get the machine ID of the current laptop */ + + tosh_id = tosh_get_machine_id(); + + /* get the BIOS version */ + + major = isa_readb(0xfe009)-'0'; + minor = ((isa_readb(0xfe00b)-'0')*10)+(isa_readb(0xfe00c)-'0'); + tosh_bios = (major*0x100)+minor; + + /* get the BIOS date */ + + day = ((isa_readb(0xffff5)-'0')*10)+(isa_readb(0xffff6)-'0'); + month = ((isa_readb(0xffff8)-'0')*10)+(isa_readb(0xffff9)-'0'); + year = ((isa_readb(0xffffb)-'0')*10)+(isa_readb(0xffffc)-'0'); + tosh_date = (((year-90) & 0x1f)<<10) | ((month & 0xf)<<6) + | ((day & 0x1f)<<1); + + + /* in theory we should check the ports we are going to use for the + fn key detection (and the fan on the Portage 610/Tecra700), and + then request them to stop other drivers using them. However as + the keyboard driver grabs 0x60-0x6f and the pic driver grabs + 0xa0-0xbf we can't. We just have to live dangerously and use the + ports anyway, oh boy! */ + + + /* do we need to emulate the fan? */ + + if ((tosh_id==0xfccb) || (tosh_id==0xfccc)) + tosh_fan = 1; + + return 0; +} + +int __init tosh_init(void) +{ + /* are we running on a Toshiba laptop */ + + if (tosh_probe()!=0) + return -EIO; + + printk(KERN_INFO "Toshiba System Managment Mode driver v" + TOSH_VERSION"\n"); + + /* set the port to use for Fn status if not specified as a parameter */ + + if (tosh_fn==0x00) + tosh_set_fn_port(); + + /* register the device file */ + + misc_register(&tosh_device); + + /* register the proc entry */ + create_proc_info_entry("toshiba", 0, NULL, tosh_get_info); + return 0; +} + +#ifdef MODULE +int init_module(void) +{ + return tosh_init(); +} + +void cleanup_module(void) +{ + /* remove the proc entry */ + remove_proc_entry("toshiba", NULL); + + /* unregister the device file */ + misc_deregister(&tosh_device); +} +#endif diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c --- v2.4.0-test8/linux/drivers/char/tty_io.c Sat Aug 12 19:48:04 2000 +++ linux/drivers/char/tty_io.c Mon Sep 18 15:15:22 2000 @@ -2202,6 +2202,9 @@ #ifdef CONFIG_SERIAL_SA1100_CONSOLE sa1100_rs_console_init(); #endif +#ifdef CONFIG_SERIAL_AMBA_CONSOLE + ambauart_console_init(); +#endif } static struct tty_driver dev_tty_driver, dev_syscons_driver; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/wdt.c linux/drivers/char/wdt.c --- v2.4.0-test8/linux/drivers/char/wdt.c Fri Jul 14 16:08:11 2000 +++ linux/drivers/char/wdt.c Sun Oct 1 19:45:29 2000 @@ -26,6 +26,7 @@ * Alan Cox : Cleaned up copy/user stuff * Tim Hockin : Added insmod parameters, comment cleanup * Parameterized timeout + * Tigran Aivazian : Restructured wdt_init() to handle failures */ #include @@ -49,7 +50,7 @@ #include #include -static int wdt_is_open=0; +static int wdt_is_open; /* * You must set these - there is no sane way to probe for this board. @@ -458,10 +459,6 @@ 0 }; -#ifdef MODULE - -#define wdt_init init_module - /** * cleanup_module: * @@ -472,7 +469,7 @@ * module in 60 seconds or reboot. */ -void cleanup_module(void) +static void __exit wdt_exit(void) { misc_deregister(&wdt_miscdev); #ifdef CONFIG_WDT_501 @@ -483,8 +480,6 @@ free_irq(irq, NULL); } -#endif - /** * wdt_init: * @@ -493,20 +488,58 @@ * The open() function will actually kick the board off. */ -int __init wdt_init(void) +static int __init wdt_init(void) { - printk(KERN_INFO "WDT500/501-P driver 0.07 at %X (Interrupt %d)\n", io,irq); - if(request_irq(irq, wdt_interrupt, SA_INTERRUPT, "wdt501p", &wdt_miscdev)) - { - printk(KERN_ERR "IRQ %d is not free.\n", irq); - return -EIO; + int ret; + + ret = misc_register(&wdt_miscdev); + if (ret) { + printk(KERN_ERR "wdt: can't misc_register on minor=%d\n", WATCHDOG_MINOR); + goto out; } - misc_register(&wdt_miscdev); -#ifdef CONFIG_WDT_501 - misc_register(&temp_miscdev); -#endif - request_region(io, 8, "wdt501p"); - register_reboot_notifier(&wdt_notifier); - return 0; + ret = request_irq(irq, wdt_interrupt, SA_INTERRUPT, "wdt501p", NULL); + if(ret) { + printk(KERN_ERR "wdt: IRQ %d is not free.\n", irq); + goto outmisc; + } + if (!request_region(io, 8, "wdt501p")) { + printk(KERN_ERR "wdt: IO %X is not free.\n", io); + ret = -EBUSY; + goto outirq; + } + ret = register_reboot_notifier(&wdt_notifier); + if(ret) { + printk(KERN_ERR "wdt: can't register reboot notifier (err=%d)\n", ret); + goto outreg; + } + +#ifdef CONFIG_WDT_501 + ret = misc_register(&temp_miscdev); + if (ret) { + printk(KERN_ERR "wdt: can't misc_register (temp) on minor=%d\n", TEMP_MINOR); + goto outrbt; + } +#endif + + ret = 0; + printk(KERN_INFO "WDT500/501-P driver 0.07 at %X (Interrupt %d)\n", io, irq); +out: + return ret; + +#ifdef CONFIG_WDT_501 +outrbt: + unregister_reboot_notifier(&wdt_notifier); +#endif + +outreg: + release_region(io,8); +outirq: + free_irq(irq, NULL); +outmisc: + misc_deregister(&wdt_miscdev); + goto out; } + +module_init(wdt_init); +module_exit(wdt_exit); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/wdt285.c linux/drivers/char/wdt285.c --- v2.4.0-test8/linux/drivers/char/wdt285.c Sun Aug 13 09:54:15 2000 +++ linux/drivers/char/wdt285.c Mon Sep 18 15:15:22 2000 @@ -6,8 +6,7 @@ * * SoftDog 0.05: A Software Watchdog Device * - * (c) Copyright 1996 Alan Cox , All Rights Reserved. - * http://www.cymru.net + * (c) Copyright 1996 Alan Cox , All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -32,7 +31,7 @@ #include #include #include -#include +#include /* * Define this to stop the watchdog actually rebooting the machine. diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/wdt977.c linux/drivers/char/wdt977.c --- v2.4.0-test8/linux/drivers/char/wdt977.c Wed Jul 12 21:58:42 2000 +++ linux/drivers/char/wdt977.c Mon Sep 18 15:15:22 2000 @@ -24,6 +24,7 @@ #include #include +#include #define WATCHDOG_MINOR 130 diff -u --recursive --new-file v2.4.0-test8/linux/drivers/char/wdt_pci.c linux/drivers/char/wdt_pci.c --- v2.4.0-test8/linux/drivers/char/wdt_pci.c Wed Jul 12 21:58:42 2000 +++ linux/drivers/char/wdt_pci.c Sun Oct 1 19:45:29 2000 @@ -29,6 +29,7 @@ * JP Nollmann : Added support for PCI wdt501p * Alan Cox : Split ISA and PCI cards into two drivers * Jeff Garzik : PCI cleanups + * Tigran Aivazian : Restructured wdtpci_init_one() to handle failures */ #include @@ -70,7 +71,7 @@ #define PCI_DEVICE_ID_WDG_CSM 0x22c0 #endif -static int wdt_is_open=0; +static int wdt_is_open; /* * You must set these - there is no sane way to probe for this board. @@ -273,7 +274,7 @@ * @ptr: offset (no seek allowed) * * Read reports the temperature in degrees Fahrenheit. The API is in - * farenheit. It was designed by an imperial measurement luddite. + * fahrenheit. It was designed by an imperial measurement luddite. */ static ssize_t wdtpci_read(struct file *file, char *buf, size_t count, loff_t *ptr) @@ -499,6 +500,7 @@ const struct pci_device_id *ent) { static int dev_count = 0; + int ret = -EIO; dev_count++; if (dev_count > 1) { @@ -513,33 +515,53 @@ "(Interrupt %d)\n", io, irq); if (pci_enable_device (dev)) - goto err_out; + goto out; if (request_region (io, 16, "wdt-pci") == NULL) { printk (KERN_ERR PFX "I/O %d is not free.\n", io); - goto err_out; + goto out; } if (request_irq (irq, wdtpci_interrupt, SA_INTERRUPT | SA_SHIRQ, "wdt-pci", &wdtpci_miscdev)) { printk (KERN_ERR PFX "IRQ %d is not free.\n", irq); - goto err_out_free_res; + goto out_reg; } - misc_register (&wdtpci_miscdev); + ret = misc_register (&wdtpci_miscdev); + if (ret) { + printk (KERN_ERR PFX "can't misc_register on minor=%d\n", WATCHDOG_MINOR); + goto out_irq; + } + ret = register_reboot_notifier (&wdtpci_notifier); + if (ret) { + printk (KERN_ERR PFX "can't misc_register on minor=%d\n", WATCHDOG_MINOR); + goto out_misc; + } #ifdef CONFIG_WDT_501 - misc_register (&temp_miscdev); + ret = misc_register (&temp_miscdev); + if (ret) { + printk (KERN_ERR PFX "can't misc_register (temp) on minor=%d\n", TEMP_MINOR); + goto out_rbt; + } #endif - register_reboot_notifier (&wdtpci_notifier); + ret = 0; +out: + return ret; - return 0; - -err_out_free_res: +#ifdef CONFIG_WDT_501 +out_rbt: + unregister_reboot_notifier(&wdtpci_notifier); +#endif +out_misc: + misc_deregister(&wdtpci_miscdev); +out_irq: + free_irq(irq, &wdtpci_miscdev); +out_reg: release_region (io, 16); -err_out: - return -EIO; + goto out; } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/i2c/i2c-algo-bit.c linux/drivers/i2c/i2c-algo-bit.c --- v2.4.0-test8/linux/drivers/i2c/i2c-algo-bit.c Tue Jul 25 18:10:42 2000 +++ linux/drivers/i2c/i2c-algo-bit.c Sun Oct 1 20:35:16 2000 @@ -62,9 +62,9 @@ /* module parameters: */ -static int i2c_debug=0; -static int bit_test=0; /* see if the line-setting functions work */ -static int bit_scan=0; /* have a look at what's hanging 'round */ +static int i2c_debug; +static int bit_test; /* see if the line-setting functions work */ +static int bit_scan; /* have a look at what's hanging 'round */ /* --- setting states on the bus with the right timing: --------------- */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/i2c/i2c-core.c linux/drivers/i2c/i2c-core.c --- v2.4.0-test8/linux/drivers/i2c/i2c-core.c Tue Jul 25 18:10:42 2000 +++ linux/drivers/i2c/i2c-core.c Sun Oct 1 20:35:16 2000 @@ -105,7 +105,7 @@ }; #endif -static int i2cproc_initialized = 0; +static int i2cproc_initialized; #else /* undef CONFIG_PROC_FS */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/i2o/i2o_proc.c linux/drivers/i2o/i2o_proc.c --- v2.4.0-test8/linux/drivers/i2o/i2o_proc.c Wed Apr 12 09:38:53 2000 +++ linux/drivers/i2o/i2o_proc.c Sun Sep 17 09:45:06 2000 @@ -3319,7 +3319,7 @@ return 0; } -static int destroy_i2o_procfs(void) +static int __exit destroy_i2o_procfs(void) { struct i2o_controller *pctrl = NULL; int i; @@ -3342,10 +3342,6 @@ return 0; } -#ifdef MODULE -#define i2o_proc_init init_module -#endif - int __init i2o_proc_init(void) { if (i2o_install_handler(&i2o_proc_handler) < 0) @@ -3360,14 +3356,17 @@ return 0; } -#ifdef MODULE - MODULE_AUTHOR("Deepak Saxena"); MODULE_DESCRIPTION("I2O procfs Handler"); -void cleanup_module(void) +static void __exit i2o_proc_exit(void) { destroy_i2o_procfs(); i2o_remove_handler(&i2o_proc_handler); } + +#ifdef MODULE +module_init(i2o_proc_init); #endif +module_exit(i2o_proc_exit); + diff -u --recursive --new-file v2.4.0-test8/linux/drivers/ide/icside.c linux/drivers/ide/icside.c --- v2.4.0-test8/linux/drivers/ide/icside.c Tue Jun 20 07:52:36 2000 +++ linux/drivers/ide/icside.c Mon Sep 18 15:15:22 2000 @@ -255,43 +255,7 @@ static int icside_build_dmatable(ide_drive_t *drive, int reading) { - dmasg_t *ide_sg = (dmasg_t *)HWIF(drive)->dmatable_cpu; - unsigned int count = 0; - int i; - struct scatterlist *sg; - - HWIF(drive)->sg_nents = i = ide_build_sglist(HWIF(drive), HWGROUP(drive)->rq); - - sg = HWIF(drive)->sg_table; - while (i && sg_dma_len(sg)) { - u32 cur_addr; - u32 cur_len; - - cur_addr = sg_dma_address(sg); - cur_len = sg_dma_len(sg); - - if (count >= (TABLE_SIZE / sizeof(dmasg_t))) { - printk("%s: DMA table too small\n", - drive->name); - pci_unmap_sg(NULL, - HWIF(drive)->sg_table, - HWIF(drive)->sg_nents, - HWIF(drive)->sg_dma_direction); - return 0; - } else { - ide_sg[count].address = cur_addr; - ide_sg[count].length = cur_len; - } - - count++; - sg++; - i--; - } - - if (!count) - printk("%s: empty DMA table?\n", drive->name); - - return count; + return HWIF(drive)->sg_nents = ide_build_sglist(HWIF(drive), HWGROUP(drive)->rq); } /* Teardown mappings after DMA has completed. */ @@ -435,7 +399,7 @@ */ set_dma_speed(hwif->hw.dma, drive->drive_data); - set_dma_sg(hwif->hw.dma, (dmasg_t *)hwif->dmatable_cpu, count); + set_dma_sg(hwif->hw.dma, HWIF(drive)->sg_table, count); set_dma_mode(hwif->hw.dma, reading ? DMA_MODE_READ : DMA_MODE_WRITE); @@ -465,31 +429,6 @@ } } -static void *icside_alloc_dmatable(void) -{ - static unsigned long dmatable; - static unsigned int leftover; - unsigned long table; - - if (leftover < TABLE_SIZE) { -#if PAGE_SIZE == TABLE_SIZE * 2 - dmatable = __get_free_pages(GFP_KERNEL, 1); - leftover = PAGE_SIZE; -#else - dmatable = kmalloc(TABLE_SIZE, GFP_KERNEL); - leftover = TABLE_SIZE; -#endif - } - - table = dmatable; - if (table) { - dmatable += TABLE_SIZE; - leftover -= TABLE_SIZE; - } - - return (void *)table; -} - static int icside_setup_dma(ide_hwif_t *hwif, int autodma) { @@ -500,14 +439,8 @@ if (!hwif->sg_table) goto failed; - hwif->dmatable_cpu = icside_alloc_dmatable(); - - if (!hwif->dmatable_cpu) { - kfree(hwif->sg_table); - hwif->sg_table = NULL; - goto failed; - } - + hwif->dmatable_cpu = NULL; + hwif->dmatable_dma = 0; hwif->speedproc = icside_set_speed; hwif->dmaproc = icside_dmaproc; hwif->autodma = autodma; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/ide/ide-pci.c linux/drivers/ide/ide-pci.c --- v2.4.0-test8/linux/drivers/ide/ide-pci.c Thu Jul 27 16:40:57 2000 +++ linux/drivers/ide/ide-pci.c Mon Oct 2 11:49:25 2000 @@ -493,6 +493,7 @@ byte tmp = 0; ide_hwif_t *hwif, *mate = NULL; unsigned int class_rev; + int pci_class_ide; #ifdef CONFIG_IDEDMA_AUTO autodma = 1; @@ -538,7 +539,8 @@ * Can we trust the reported IRQ? */ pciirq = dev->irq; - if ((dev->class & ~(0xfa)) != ((PCI_CLASS_STORAGE_IDE << 8) | 5)) { + pci_class_ide = ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE); + if (!pci_class_ide) { printk("%s: not 100%% native mode: will probe irqs later\n", d->name); /* * This allows offboard ide-pci cards the enable a BIOS, @@ -548,11 +550,17 @@ */ pciirq = (d->init_chipset) ? d->init_chipset(dev, d->name) : ide_special_settings(dev, d->name); } else if (tried_config) { - printk("%s: will probe irqs later\n", d->name); + printk(KERN_INFO "%s: will probe irqs later\n", d->name); pciirq = 0; } else if (!pciirq) { - printk("%s: bad irq (%d): will probe later\n", d->name, pciirq); - pciirq = 0; + if (pci_class_ide) { + /* this is the normal path for most IDE devices */ + if (d->init_chipset) + pciirq = d->init_chipset(dev, d->name); + else + printk(KERN_INFO "%s standard IDE storage device detected\n", d->name); + } else + printk(KERN_WARNING "%s: bad irq (0): will probe later\n", d->name); } else { if (d->init_chipset) (void) d->init_chipset(dev, d->name); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/ide/ide-proc.c linux/drivers/ide/ide-proc.c --- v2.4.0-test8/linux/drivers/ide/ide-proc.c Thu Apr 13 22:54:26 2000 +++ linux/drivers/ide/ide-proc.c Mon Sep 18 14:57:01 2000 @@ -159,7 +159,7 @@ unsigned long startn = 0, n, flags; const char *start = NULL, *msg = NULL; - if (!capable(CAP_SYS_ADMIN)) + if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) return -EACCES; /* * Skip over leading whitespace diff -u --recursive --new-file v2.4.0-test8/linux/drivers/ide/ide.c linux/drivers/ide/ide.c --- v2.4.0-test8/linux/drivers/ide/ide.c Tue Sep 5 13:08:42 2000 +++ linux/drivers/ide/ide.c Mon Sep 11 08:42:57 2000 @@ -1082,7 +1082,7 @@ { byte *args = rq->buffer; if (args && rq->cmd == IDE_DRIVE_TASK) { - + byte sel; #ifdef DEBUG printk("%s: DRIVE_TASK_CMD data=x%02x cmd=0x%02x fr=0x%02x ns=0x%02x sc=0x%02x lcyl=0x%02x hcyl=0x%02x sel=0x%02x\n", drive->name, args[0], args[1], args[2], args[3], args[4], args[5], args[6]); @@ -1091,7 +1091,10 @@ OUT_BYTE(args[3], IDE_SECTOR_REG); OUT_BYTE(args[4], IDE_LCYL_REG); OUT_BYTE(args[5], IDE_HCYL_REG); - OUT_BYTE(args[6], IDE_SELECT_REG); + sel = (args[6] & ~0x10); + if (drive->select.b.unit) + sel |= 0x10; + OUT_BYTE(sel, IDE_SELECT_REG); ide_cmd(drive, args[0], args[2], &drive_cmd_intr); return ide_started; } else if (args) { diff -u --recursive --new-file v2.4.0-test8/linux/drivers/ide/via82cxxx.c linux/drivers/ide/via82cxxx.c --- v2.4.0-test8/linux/drivers/ide/via82cxxx.c Wed Sep 6 08:07:56 2000 +++ linux/drivers/ide/via82cxxx.c Mon Oct 2 11:55:04 2000 @@ -1,5 +1,5 @@ /* - * $Id: via82cxxx.c,v 2.1 2000/08/29 01:34:60 vojtech Exp $ + * $Id: via82cxxx.c,v 2.1d 2000/10/01 10:01:00 vojtech Exp $ * * Copyright (c) 2000 Vojtech Pavlik * @@ -97,7 +97,6 @@ { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, XFER_UDMA_2 }, { "vt82c586a", PCI_DEVICE_ID_VIA_82C586_0, XFER_UDMA_2 }, { "vt82c586", PCI_DEVICE_ID_VIA_82C586_0, XFER_MW_DMA_2 }, - { "Unknown SouthBridge", 0, XFER_UDMA_4 }, { "Unknown SouthBridge", 0, XFER_UDMA_2 }, }; @@ -140,8 +139,8 @@ { XFER_MW_DMA_1, "MDMA1", 45, 80, 50, 150, 0 }, { XFER_MW_DMA_0, "MDMA0", 60, 215, 215, 480, 0 }, - { XFER_SW_DMA_0, "SDMA0", 60, 120, 120, 240, 0 }, - { XFER_SW_DMA_0, "SDMA0", 90, 240, 240, 480, 0 }, + { XFER_SW_DMA_2, "SDMA2", 60, 120, 120, 240, 0 }, + { XFER_SW_DMA_1, "SDMA1", 90, 240, 240, 480, 0 }, { XFER_SW_DMA_0, "SDMA0",120, 480, 480, 960, 0 }, { XFER_PIO_5, "PIO5", 20, 50, 30, 100, 0 }, @@ -193,7 +192,7 @@ via_print("----------VIA BusMastering IDE Configuration----------------"); - via_print("Driver Version: 2.1"); + via_print("Driver Version: 2.1d"); pci_read_config_byte(isa_dev, PCI_REVISION_ID, &t); via_print("South Bridge: VIA %s rev %#x", via_isa_bridges[via_config].name, t); @@ -213,9 +212,6 @@ via_print("FIFO Output Data 1/2 Clock Advance: %s", (t & 16) ? "on" : "off" ); via_print("BM IDE Status Register Read Retry: %s", (t & 8) ? "on" : "off" ); - pci_read_config_byte(dev, VIA_MISC_2, &t); - sprintf(p, "Interrupt Steering Swap: %s", (t & 64) ? "on" : "off"); - pci_read_config_byte(dev, VIA_MISC_3, &t); via_print("Max DRDY Pulse Width: %s%s", via_control3[(t & 0x03)], (t & 0x03) ? "PCI clocks" : ""); @@ -337,15 +333,13 @@ * UDMA cycle */ - if (via_timing[i].udma) { - t = 0xe8; - if (via_isa_bridges[via_config].speed >= XFER_UDMA_4) - t |= FIT(ENOUGH(via_timing[i].udma, T >> 1) - 2, 0, 7); - else - t |= FIT(ENOUGH(via_timing[i].udma, T ) - 2, 0, 3); - } else t = 0x0b; + switch(via_isa_bridges[via_config].speed) { + case XFER_UDMA_2: t = via_timing[i].udma ? (0xe0 | (FIT(via_timing[i].udma, 2, 5) - 2)) : 0x03; break; + case XFER_UDMA_4: t = via_timing[i].udma ? (0xe8 | (FIT(via_timing[i].udma, 2, 9) - 2)) : 0x0f; break; + } - via_write_config_byte(dev, VIA_UDMA_TIMING + (3 - drive->dn), t); + if (via_isa_bridges[via_config].speed != XFER_MW_DMA_2) + via_write_config_byte(dev, VIA_UDMA_TIMING + (3 - drive->dn), t); /* * Drive init @@ -511,6 +505,11 @@ if (t < 0x20) via_config++; /* vt82c586 */ } + if (via_isa_bridges[via_config].id == PCI_DEVICE_ID_VIA_82C596) { + pci_read_config_byte(isa, PCI_REVISION_ID, &t); + if (t < 0x10) via_config++; /* vt82c596a */ + } + /* * Check UDMA66 mode set by BIOS. */ @@ -530,13 +529,8 @@ /* * Set UDMA66 double clock bits. */ - - pci_write_config_dword(dev, VIA_UDMA_TIMING, u | 0x80008); - pci_read_config_dword(dev, VIA_UDMA_TIMING, &u); - - if ((via_isa_bridges[via_config].id == PCI_DEVICE_ID_VIA_82C596 || !isa) - && (u & 0x80008) != 0x80008) - via_config++; /* vt82c596a / Unknown UDMA33 */ + if (via_isa_bridges[via_config].speed == XFER_UDMA_4) + pci_write_config_dword(dev, VIA_UDMA_TIMING, u | 0x80008); /* * Set up FIFO, flush, prefetch and post-writes. @@ -594,7 +588,7 @@ unsigned int __init ata66_via82cxxx(ide_hwif_t *hwif) { - return ((via_enabled && via_ata66) >> hwif->channel) & 1; + return ((via_enabled & via_ata66) >> hwif->channel) & 1; } void __init ide_init_via82cxxx(ide_hwif_t *hwif) diff -u --recursive --new-file v2.4.0-test8/linux/drivers/ieee1394/hosts.c linux/drivers/ieee1394/hosts.c --- v2.4.0-test8/linux/drivers/ieee1394/hosts.c Wed Jul 5 13:03:56 2000 +++ linux/drivers/ieee1394/hosts.c Sun Oct 1 19:53:07 2000 @@ -61,8 +61,9 @@ struct hpsb_host_template *tmpl; struct hpsb_host *h; int retval = 0; + unsigned long flags; - spin_lock(&templates_lock); + spin_lock_irqsave(&templates_lock, flags); for (tmpl = templates; (tmpl != NULL) && !retval; tmpl = tmpl->next) { for (h = tmpl->hosts; h != NULL; h = h->next) { @@ -74,7 +75,7 @@ } } - spin_unlock(&templates_lock); + spin_unlock_irqrestore(&templates_lock, flags); return retval; } @@ -99,11 +100,11 @@ } memset(h, 0, sizeof(struct hpsb_host) + hd_size); - h->tlabel_count = 64; INIT_LIST_HEAD(&h->pending_packets); spin_lock_init(&h->pending_pkt_lock); + + sema_init(&h->tlabel_count, 64); spin_lock_init(&h->tlabel_lock); - init_waitqueue_head(&h->tlabel_wait); h->timeout_tq.routine = (void (*)(void*))abort_timedouts; h->timeout_tq.data = h; @@ -154,10 +155,7 @@ host->initialized = 1; highlevel_add_host(host); - reset_host_bus(host); - - //kernel_thread(hpsb_host_thread, host, - // CLONE_FS | CLONE_FILES | CLONE_SIGHAND); + hpsb_reset_bus(host); } } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/ieee1394/hosts.h linux/drivers/ieee1394/hosts.h --- v2.4.0-test8/linux/drivers/ieee1394/hosts.h Sun Feb 20 20:32:50 2000 +++ linux/drivers/ieee1394/hosts.h Sun Oct 1 19:53:07 2000 @@ -4,6 +4,7 @@ #include #include +#include #include "ieee1394_types.h" #include "csr.h" @@ -22,9 +23,8 @@ /* A bitmask where a set bit means that this tlabel is in use. * FIXME - should be handled per node instead of per bus. */ u32 tlabel_pool[2]; - int tlabel_count; + struct semaphore tlabel_count; spinlock_t tlabel_lock; - wait_queue_head_t tlabel_wait; int reset_retries; quadlet_t *topology_map; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/ieee1394/ieee1394_core.c linux/drivers/ieee1394/ieee1394_core.c --- v2.4.0-test8/linux/drivers/ieee1394/ieee1394_core.c Wed Jul 5 13:03:56 2000 +++ linux/drivers/ieee1394/ieee1394_core.c Sun Oct 1 19:53:07 2000 @@ -127,30 +127,37 @@ } -void reset_host_bus(struct hpsb_host *host) +int hpsb_reset_bus(struct hpsb_host *host) { if (!host->initialized) { - return; + return 1; } - hpsb_bus_reset(host); - host->template->devctl(host, RESET_BUS, 0); + if (!hpsb_bus_reset(host)) { + host->template->devctl(host, RESET_BUS, 0); + return 0; + } else { + return 1; + } } -void hpsb_bus_reset(struct hpsb_host *host) +int hpsb_bus_reset(struct hpsb_host *host) { - if (!host->in_bus_reset) { - abort_requests(host); - host->in_bus_reset = 1; - host->irm_id = -1; - host->busmgr_id = -1; - host->node_count = 0; - host->selfid_count = 0; - } else { + if (host->in_bus_reset) { HPSB_NOTICE(__FUNCTION__ " called while bus reset already in progress"); + return 1; } + + abort_requests(host); + host->in_bus_reset = 1; + host->irm_id = -1; + host->busmgr_id = -1; + host->node_count = 0; + host->selfid_count = 0; + + return 0; } @@ -311,7 +318,7 @@ if (host->reset_retries++ < 20) { /* selfid stage did not complete without error */ HPSB_NOTICE("error in SelfID stage - resetting"); - reset_host_bus(host); + hpsb_reset_bus(host); return; } else { HPSB_NOTICE("stopping out-of-control reset loop"); @@ -332,6 +339,7 @@ host->reset_retries = 0; inc_hpsb_generation(); + if (isroot) host->template->devctl(host, ACT_CYCLE_MASTER, 1); highlevel_host_reset(host); } @@ -374,7 +382,7 @@ * * The packet is sent through the host specified in the packet->host field. * Before sending, the packet's transmit speed is automatically determined using - * the local speed map. + * the local speed map when it is an async, non-broadcast packet. * * Possibilities for failure are that host is either not initialized, in bus * reset, the packet's generation number doesn't match the current generation @@ -392,8 +400,12 @@ } packet->state = queued; - packet->speed_code = host->speed_map[(host->node_id & NODE_MASK) * 64 - + (packet->node_id & NODE_MASK)]; + + if (packet->type == async && packet->node_id != ALL_NODES) { + packet->speed_code = + host->speed_map[(host->node_id & NODE_MASK) * 64 + + (packet->node_id & NODE_MASK)]; + } #ifdef CONFIG_IEEE1394_VERBOSEDEBUG switch (packet->speed_code) { diff -u --recursive --new-file v2.4.0-test8/linux/drivers/ieee1394/ieee1394_core.h linux/drivers/ieee1394/ieee1394_core.h --- v2.4.0-test8/linux/drivers/ieee1394/ieee1394_core.h Wed Jul 5 13:03:56 2000 +++ linux/drivers/ieee1394/ieee1394_core.h Sun Oct 1 19:53:07 2000 @@ -73,7 +73,6 @@ }; -void reset_host_bus(struct hpsb_host *host); void abort_timedouts(struct hpsb_host *host); void abort_requests(struct hpsb_host *host); @@ -106,6 +105,9 @@ */ int hpsb_send_packet(struct hpsb_packet *packet); +/* Initiate bus reset on the given host. Returns 1 if bus reset already in + * progress, 0 otherwise. */ +int hpsb_reset_bus(struct hpsb_host *host); /* * The following functions are exported for host driver module usage. All of @@ -114,8 +116,9 @@ * them directly. */ -/* Notify a bus reset to the core. */ -void hpsb_bus_reset(struct hpsb_host *host); +/* Notify a bus reset to the core. Returns 1 if bus reset already in progress, + * 0 otherwise. */ +int hpsb_bus_reset(struct hpsb_host *host); /* * Hand over received selfid packet to the core. Complement check (second diff -u --recursive --new-file v2.4.0-test8/linux/drivers/ieee1394/ieee1394_syms.c linux/drivers/ieee1394/ieee1394_syms.c --- v2.4.0-test8/linux/drivers/ieee1394/ieee1394_syms.c Wed Jul 5 13:03:56 2000 +++ linux/drivers/ieee1394/ieee1394_syms.c Sun Oct 1 19:53:07 2000 @@ -17,7 +17,6 @@ #include "hosts.h" #include "ieee1394_core.h" #include "ieee1394_transactions.h" -/* #include "events.h" */ #include "highlevel.h" #include "guid.h" @@ -30,6 +29,7 @@ EXPORT_SYMBOL(alloc_hpsb_packet); EXPORT_SYMBOL(free_hpsb_packet); EXPORT_SYMBOL(hpsb_send_packet); +EXPORT_SYMBOL(hpsb_reset_bus); EXPORT_SYMBOL(hpsb_bus_reset); EXPORT_SYMBOL(hpsb_selfid_received); EXPORT_SYMBOL(hpsb_selfid_complete); @@ -39,6 +39,16 @@ EXPORT_SYMBOL(get_tlabel); EXPORT_SYMBOL(free_tlabel); +EXPORT_SYMBOL(fill_async_readquad); +EXPORT_SYMBOL(fill_async_readquad_resp); +EXPORT_SYMBOL(fill_async_readblock); +EXPORT_SYMBOL(fill_async_readblock_resp); +EXPORT_SYMBOL(fill_async_writequad); +EXPORT_SYMBOL(fill_async_writeblock); +EXPORT_SYMBOL(fill_async_write_resp); +EXPORT_SYMBOL(fill_async_lock); +EXPORT_SYMBOL(fill_async_lock_resp); +EXPORT_SYMBOL(fill_iso_packet); EXPORT_SYMBOL(hpsb_make_readqpacket); EXPORT_SYMBOL(hpsb_make_readbpacket); EXPORT_SYMBOL(hpsb_make_writeqpacket); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/ieee1394/ieee1394_transactions.c linux/drivers/ieee1394/ieee1394_transactions.c --- v2.4.0-test8/linux/drivers/ieee1394/ieee1394_transactions.c Wed Jul 5 13:03:56 2000 +++ linux/drivers/ieee1394/ieee1394_transactions.c Sun Oct 1 19:53:07 2000 @@ -155,56 +155,29 @@ * Return value: The allocated transaction label or -1 if there was no free * tlabel and @wait is false. */ -static int __get_tlabel(struct hpsb_host *host, nodeid_t nodeid) +int get_tlabel(struct hpsb_host *host, nodeid_t nodeid, int wait) { int tlabel; + unsigned long flags; - if (host->tlabel_count) { - host->tlabel_count--; - - if (host->tlabel_pool[0] != ~0) { - tlabel = ffz(host->tlabel_pool[0]); - host->tlabel_pool[0] |= 1 << tlabel; - } else { - tlabel = ffz(host->tlabel_pool[1]); - host->tlabel_pool[1] |= 1 << tlabel; - tlabel += 32; - } - return tlabel; + if (wait) { + down(&host->tlabel_count); + } else { + if (down_trylock(&host->tlabel_count)) return -1; } - return -1; -} - -int get_tlabel(struct hpsb_host *host, nodeid_t nodeid, int wait) -{ - unsigned long flags; - int tlabel; - wait_queue_t wq; spin_lock_irqsave(&host->tlabel_lock, flags); - tlabel = __get_tlabel(host, nodeid); - if (tlabel != -1 || !wait) { - spin_unlock_irqrestore(&host->tlabel_lock, flags); - return tlabel; - } - - init_waitqueue_entry(&wq, current); - add_wait_queue(&host->tlabel_wait, &wq); - - for (;;) { - set_current_state(TASK_UNINTERRUPTIBLE); - tlabel = __get_tlabel(host, nodeid); - if (tlabel != -1) break; - - spin_unlock_irqrestore(&host->tlabel_lock, flags); - schedule(); - spin_lock_irqsave(&host->tlabel_lock, flags); + if (host->tlabel_pool[0] != ~0) { + tlabel = ffz(host->tlabel_pool[0]); + host->tlabel_pool[0] |= 1 << tlabel; + } else { + tlabel = ffz(host->tlabel_pool[1]); + host->tlabel_pool[1] |= 1 << tlabel; + tlabel += 32; } spin_unlock_irqrestore(&host->tlabel_lock, flags); - set_current_state(TASK_RUNNING); - remove_wait_queue(&host->tlabel_wait, &wq); return tlabel; } @@ -233,11 +206,9 @@ host->tlabel_pool[1] &= ~(1 << (tlabel-32)); } - host->tlabel_count++; - spin_unlock_irqrestore(&host->tlabel_lock, flags); - wake_up(&host->tlabel_wait); + up(&host->tlabel_count); } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/ieee1394/ieee1394_types.h linux/drivers/ieee1394/ieee1394_types.h --- v2.4.0-test8/linux/drivers/ieee1394/ieee1394_types.h Wed Jul 5 13:03:56 2000 +++ linux/drivers/ieee1394/ieee1394_types.h Sun Oct 1 19:53:07 2000 @@ -53,7 +53,7 @@ return order; } - +#include #include inline static int pci_enable_device(struct pci_dev *dev) { @@ -114,7 +114,7 @@ BUG(); } -struct scatterlist {}; +#include extern inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction) { diff -u --recursive --new-file v2.4.0-test8/linux/drivers/ieee1394/ohci1394.c linux/drivers/ieee1394/ohci1394.c --- v2.4.0-test8/linux/drivers/ieee1394/ohci1394.c Wed Jul 5 13:03:56 2000 +++ linux/drivers/ieee1394/ohci1394.c Sun Oct 1 19:53:07 2000 @@ -56,6 +56,8 @@ * . Apple PowerBook detection * Daniel Kobras * . Reset the board properly before leaving + misc cleanups + * Leon van Stuivenberg + * . Bug fixes */ #include @@ -253,7 +255,7 @@ return -1; } - size = ((self_id_count&0x0000EFFC)>>2) - 1; + size = ((self_id_count&0x00001FFC)>>2) - 1; q++; while (size > 0) { @@ -652,6 +654,15 @@ * FIXME: check that the packet data buffer * do not cross a page boundary */ + if (cross_bound((unsigned long)packet->data, + packet->data_size)>0) { + /* FIXME: do something about it */ + PRINT(KERN_ERR, ohci->id, __FUNCTION__ + ": packet data addr: %p size %d bytes " + "cross page boundary", + packet->data, packet->data_size); + } + d->prg_cpu[idx]->end.address = pci_map_single(ohci->dev, packet->data, packet->data_size, PCI_DMA_TODEVICE); @@ -734,7 +745,7 @@ unsigned char tcode; unsigned long flags; - if (packet->data_size >= ohci->max_packet_size) { + if (packet->data_size > ohci->max_packet_size) { PRINT(KERN_ERR, ohci->id, "transmit packet size = %d too big", packet->data_size); @@ -803,11 +814,11 @@ u32 nodeId = reg_read(ohci, OHCI1394_NodeID); if ((nodeId & (1<<30)) && (nodeId & 0x3f)) { /* - * enable cycleTimer cycleMaster cycleSource + * enable cycleTimer, cycleMaster */ DBGMSG(ohci->id, "Cycle master enabled"); reg_write(ohci, OHCI1394_LinkControlSet, - 0x00700000); + 0x00300000); } } else { /* disable cycleTimer, cycleMaster, cycleSource */ @@ -830,61 +841,67 @@ break; case ISO_LISTEN_CHANNEL: + { + int *isochannels, offset= OHCI1394_IRMultiChanMaskLoSet; + unsigned int channel= (unsigned int)arg; + unsigned int channelbit= channel; + u32 setMask= 0x00000001; + + /* save people from themselves */ + if (channel > 63) + break; + + if (channel > 31) { + isochannels= &(((int*)&ohci->IR_channel_usage)[0]); + channelbit-= 32; + offset= OHCI1394_IRMultiChanMaskHiSet; + } + else + isochannels= &(((int*)&ohci->IR_channel_usage)[1]); - spin_lock_irqsave(&ohci->IR_channel_lock, flags); + while(channelbit--) setMask= setMask << 1; - if (!test_and_set_bit(arg, &ohci->IR_channel_usage)) { - DBGMSG(ohci->id, - "listening enabled on channel %d", arg); - - if (arg > 31) { - u32 setMask= 0x00000001; - arg-= 32; - while(arg--) setMask= setMask << 1; - reg_write(ohci, OHCI1394_IRMultiChanMaskHiSet, - setMask); - } else { - u32 setMask= 0x00000001; - while(arg--) setMask= setMask << 1; - reg_write(ohci, OHCI1394_IRMultiChanMaskLoSet, - setMask); - } + spin_lock_irqsave(&ohci->IR_channel_lock, flags); - } + if (!test_and_set_bit(channelbit, isochannels)) + reg_write(ohci, offset, setMask); spin_unlock_irqrestore(&ohci->IR_channel_lock, flags); + DBGMSG(ohci->id, "listening enabled on channel %u", channel); break; - + } case ISO_UNLISTEN_CHANNEL: + { + int *isochannels, offset= OHCI1394_IRMultiChanMaskLoClear; + unsigned int channel= (unsigned int)arg; + unsigned int channelbit= channel; + u32 clearMask= 0x00000001; + + /* save people from themselves */ + if (channel > 63) + break; + + if (channel > 31) { + isochannels= &(((int*)&ohci->IR_channel_usage)[0]); + channelbit-= 32; + offset= OHCI1394_IRMultiChanMaskHiClear; + } + else + isochannels= &(((int*)&ohci->IR_channel_usage)[1]); - spin_lock_irqsave(&ohci->IR_channel_lock, flags); + while(channelbit--) clearMask= clearMask << 1; - if (test_and_clear_bit(arg, &ohci->IR_channel_usage)) { - DBGMSG(ohci->id, - "listening disabled on iso channel %d", arg); - - if (arg > 31) { - u32 clearMask= 0x00000001; - arg-= 32; - while(arg--) clearMask= clearMask << 1; - reg_write(ohci, - OHCI1394_IRMultiChanMaskHiClear, - clearMask); - } else { - u32 clearMask= 0x00000001; - while(arg--) clearMask= clearMask << 1; - reg_write(ohci, - OHCI1394_IRMultiChanMaskLoClear, - clearMask); - } + spin_lock_irqsave(&ohci->IR_channel_lock, flags); - } + if (!test_and_clear_bit(channelbit, isochannels)) + reg_write(ohci, offset, clearMask); spin_unlock_irqrestore(&ohci->IR_channel_lock, flags); + DBGMSG(ohci->id, "listening disabled on channel %u", channel); break; - + } default: - PRINT_G(KERN_ERR, "ohci_devctl cmd %d not implemented yet\n", + PRINT_G(KERN_ERR, "ohci_devctl cmd %d not implemented yet", cmd); break; } @@ -904,6 +921,7 @@ { struct ti_ohci *ohci; unsigned long flags; + struct hpsb_packet *nextpacket; if (d==NULL) { PRINT_G(KERN_ERR, "dma_trm_reset called with NULL arg"); @@ -919,8 +937,9 @@ PRINT(KERN_INFO, ohci->id, "AT dma reset ctx=%d, aborting transmission", d->ctx); + nextpacket = d->fifo_first->xnext; hpsb_packet_sent(ohci->host, d->fifo_first, ACKX_ABORTED); - d->fifo_first = d->fifo_first->xnext; + d->fifo_first = nextpacket; } d->fifo_first = d->fifo_last = NULL; @@ -929,9 +948,10 @@ PRINT(KERN_INFO, ohci->id, "AT dma reset ctx=%d, aborting transmission", d->ctx); + nextpacket = d->pending_first->xnext; hpsb_packet_sent(ohci->host, d->pending_first, ACKX_ABORTED); - d->pending_first = d->pending_first->xnext; + d->pending_first = nextpacket; } d->pending_first = d->pending_last = NULL; @@ -1072,6 +1092,20 @@ } if (event & OHCI1394_selfIDComplete) { if (host->in_bus_reset) { + /* + * Begin Fix (JSG): Check to make sure our + * node id is valid + */ + node_id = reg_read(ohci, OHCI1394_NodeID); + if (!(node_id & 0x80000000)) { + mdelay(1); /* phy is upset - + * this happens once in + * a while on hot-plugs... + * give it a ms to recover + */ + } + /* End Fix (JSG) */ + node_id = reg_read(ohci, OHCI1394_NodeID); if (node_id & 0x80000000) { /* NodeID valid */ phyid = node_id & 0x0000003f; @@ -1346,9 +1380,10 @@ { struct dma_trm_ctx *d = (struct dma_trm_ctx*)data; struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci); - struct hpsb_packet *packet; + struct hpsb_packet *packet, *nextpacket; unsigned long flags; u32 ack; + size_t datasize; spin_lock_irqsave(&d->lock, flags); @@ -1363,7 +1398,8 @@ while (d->fifo_first) { packet = d->fifo_first; - if (packet->data_size) + datasize = d->fifo_first->data_size; + if (datasize) ack = d->prg_cpu[d->sent_ind]->end.status>>16; else ack = d->prg_cpu[d->sent_ind]->begin.status>>16; @@ -1372,20 +1408,40 @@ /* this packet hasn't been sent yet*/ break; - DBGMSG(ohci->id, - "Packet sent to node %d ack=0x%X spd=%d ctx=%d", - (packet->header[0]>>16)&0x3f, ack&0x1f, (ack>>5)&0x3, - d->ctx); +#ifdef OHCI1394_DEBUG + if (datasize) + DBGMSG(ohci->id, + "Packet sent to node %d tcode=0x%X tLabel=" + "0x%02X ack=0x%X spd=%d dataLength=%d ctx=%d", + (d->prg_cpu[d->sent_ind]->data[1]>>16)&0x3f, + (d->prg_cpu[d->sent_ind]->data[0]>>4)&0xf, + (d->prg_cpu[d->sent_ind]->data[0]>>10)&0x3f, + ack&0x1f, (ack>>5)&0x3, + d->prg_cpu[d->sent_ind]->data[3]>>16, + d->ctx); + else + DBGMSG(ohci->id, + "Packet sent to node %d tcode=0x%X tLabel=" + "0x%02X ack=0x%X spd=%d data=0x%08X ctx=%d", + (d->prg_cpu[d->sent_ind]->data[1]>>16)&0x3f, + (d->prg_cpu[d->sent_ind]->data[0]>>4)&0xf, + (d->prg_cpu[d->sent_ind]->data[0]>>10)&0x3f, + ack&0x1f, (ack>>5)&0x3, + d->prg_cpu[d->sent_ind]->data[3], + d->ctx); +#endif + + nextpacket = packet->xnext; hpsb_packet_sent(ohci->host, packet, ack&0xf); - if (packet->data_size) + if (datasize) pci_unmap_single(ohci->dev, d->prg_cpu[d->sent_ind]->end.address, - packet->data_size, PCI_DMA_TODEVICE); + datasize, PCI_DMA_TODEVICE); d->sent_ind = (d->sent_ind+1)%d->num_desc; d->free_prgs++; - d->fifo_first = d->fifo_first->xnext; + d->fifo_first = nextpacket; } if (d->fifo_first==NULL) d->fifo_last=NULL; @@ -1687,22 +1743,36 @@ FAIL("failed to allocate buffer config rom"); } - DBGMSG(ohci->id, "The 1st byte at offset 0x404 is: 0x%02x", - *((char *)ohci->csr_config_rom_cpu+4)); - /* * self-id dma buffer allocation * FIXME: some early chips may need 8KB alignment for the - * selfid buffer + * selfid buffer... if you have problems a temporary fic + * is to allocate 8192 bytes instead of 2048 */ ohci->selfid_buf_cpu = pci_alloc_consistent(ohci->dev, 2048, &ohci->selfid_buf_bus); if (ohci->selfid_buf_cpu == NULL) { FAIL("failed to allocate DMA buffer for self-id packets"); } - if ((unsigned long)ohci->selfid_buf_cpu & 0xfff) + if ((unsigned long)ohci->selfid_buf_cpu & 0x1fff) PRINT(KERN_INFO, ohci->id, "Selfid buffer %p not aligned on " - "8Kb boundary", ohci->selfid_buf_cpu); + "8Kb boundary... may cause pb on some CXD3222 chip", + ohci->selfid_buf_cpu); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,13) + ohci->registers = ioremap_nocache(dev->base_address[0], + OHCI1394_REGISTER_SIZE); +#else + ohci->registers = ioremap_nocache(dev->resource[0].start, + OHCI1394_REGISTER_SIZE); +#endif + + if (ohci->registers == NULL) { + FAIL("failed to remap registers - card not accessible"); + } + + PRINT(KERN_INFO, ohci->id, "remapped memory spaces reg 0x%p", + ohci->registers); ohci->ar_req_context = alloc_dma_rcv_ctx(ohci, 0, AR_REQ_NUM_DESC, @@ -1711,7 +1781,9 @@ OHCI1394_AsReqRcvContextControlClear, OHCI1394_AsReqRcvCommandPtr); - if (ohci->ar_req_context == NULL) return 1; + if (ohci->ar_req_context == NULL) { + FAIL("failed to allocate AR Req context"); + } ohci->ar_resp_context = alloc_dma_rcv_ctx(ohci, 1, AR_RESP_NUM_DESC, @@ -1758,21 +1830,6 @@ ohci->IR_channel_usage= 0x0000000000000000; spin_lock_init(&ohci->IR_channel_lock); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,13) - ohci->registers = ioremap_nocache(dev->base_address[0], - OHCI1394_REGISTER_SIZE); -#else - ohci->registers = ioremap_nocache(dev->resource[0].start, - OHCI1394_REGISTER_SIZE); -#endif - - if (ohci->registers == NULL) { - FAIL("failed to remap registers - card not accessible"); - } - - PRINT(KERN_INFO, ohci->id, "remapped memory spaces reg 0x%p", - ohci->registers); - if (!request_irq(dev->irq, ohci_irq_handler, SA_SHIRQ, OHCI1394_DRIVER_NAME, ohci)) { PRINT(KERN_INFO, ohci->id, "allocated interrupt %d", dev->irq); @@ -1782,6 +1839,9 @@ ohci_init_config_rom(ohci); + DBGMSG(ohci->id, "The 1st byte at offset 0x404 is: 0x%02x", + *((char *)ohci->csr_config_rom_cpu+4)); + return 0; #undef FAIL } @@ -2116,7 +2176,7 @@ create_proc_read_entry ("ohci1394", 0, NULL, ohci1394_read_proc, NULL); #else if (proc_register(&proc_root, &ohci_proc_entry)) { - PRINT_G(KERN_ERR, "unable to register proc file\n"); + PRINT_G(KERN_ERR, "unable to register proc file"); return -EIO; } #endif @@ -2290,7 +2350,7 @@ #endif #endif - PRINT_G(KERN_INFO, "removed " OHCI1394_DRIVER_NAME " module\n"); + PRINT_G(KERN_INFO, "removed " OHCI1394_DRIVER_NAME " module"); } int init_module(void) @@ -2298,7 +2358,7 @@ memset(cards, 0, MAX_OHCI1394_CARDS * sizeof (struct ti_ohci)); if (hpsb_register_lowlevel(get_ohci_template())) { - PRINT_G(KERN_ERR, "registering failed\n"); + PRINT_G(KERN_ERR, "registering failed"); return -ENXIO; } return 0; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/ieee1394/ohci1394.h linux/drivers/ieee1394/ohci1394.h --- v2.4.0-test8/linux/drivers/ieee1394/ohci1394.h Wed Jul 5 13:03:56 2000 +++ linux/drivers/ieee1394/ohci1394.h Sun Oct 1 19:53:07 2000 @@ -91,16 +91,16 @@ #define OHCI1394_MAX_SELF_ID_ERRORS 16 #define AR_REQ_NUM_DESC 4 /* number of AR req descriptors */ -#define AR_REQ_BUF_SIZE 4096 /* size of AR req buffers */ -#define AR_REQ_SPLIT_BUF_SIZE 4096 /* split packet buffer */ +#define AR_REQ_BUF_SIZE PAGE_SIZE /* size of AR req buffers */ +#define AR_REQ_SPLIT_BUF_SIZE PAGE_SIZE /* split packet buffer */ #define AR_RESP_NUM_DESC 4 /* number of AR resp descriptors */ -#define AR_RESP_BUF_SIZE 4096 /* size of AR resp buffers */ -#define AR_RESP_SPLIT_BUF_SIZE 4096 /* split packet buffer */ +#define AR_RESP_BUF_SIZE PAGE_SIZE /* size of AR resp buffers */ +#define AR_RESP_SPLIT_BUF_SIZE PAGE_SIZE /* split packet buffer */ #define IR_NUM_DESC 16 /* number of IR descriptors */ -#define IR_BUF_SIZE 4096 /* 6480 bytes/buffer */ -#define IR_SPLIT_BUF_SIZE 4096 /* split packet buffer */ +#define IR_BUF_SIZE PAGE_SIZE /* 4096 bytes/buffer */ +#define IR_SPLIT_BUF_SIZE PAGE_SIZE /* split packet buffer */ #define AT_REQ_NUM_DESC 32 /* number of AT req descriptors */ #define AT_RESP_NUM_DESC 32 /* number of AT resp descriptors */ @@ -112,10 +112,17 @@ u32 status; }; +/* + * FIXME: + * It is important that a single at_dma_prg does not cross a page boundary + * The proper way to do it would be to do the check dynamically as the + * programs are inserted into the AT fifo. + */ struct at_dma_prg { struct dma_cmd begin; quadlet_t data[4]; struct dma_cmd end; + quadlet_t pad[4]; /* FIXME: quick hack for memory alignment */ }; /* DMA receive context */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/ieee1394/pcilynx.c linux/drivers/ieee1394/pcilynx.c --- v2.4.0-test8/linux/drivers/ieee1394/pcilynx.c Fri Jul 21 19:51:56 2000 +++ linux/drivers/ieee1394/pcilynx.c Sun Oct 1 19:53:07 2000 @@ -18,16 +18,6 @@ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* - * Lynx DMA usage: - * - * 0 is used for Lynx local bus transfers - * 1 is async/selfid receive - * 2 is iso receive - * 3 is async transmit - */ - - #include #include #include @@ -63,8 +53,8 @@ #define PRINT_GD(level, fmt, args...) printk(level "pcilynx: " fmt "\n" , ## args) #define PRINTD(level, card, fmt, args...) printk(level "pcilynx%d: " fmt "\n" , card , ## args) #else -#define PRINT_GD(level, fmt, args...) -#define PRINTD(level, card, fmt, args...) +#define PRINT_GD(level, fmt, args...) do {} while (0) +#define PRINTD(level, card, fmt, args...) do {} while (0) #endif static struct ti_lynx cards[MAX_PCILYNX_CARDS]; @@ -177,8 +167,8 @@ spin_lock_irqsave(&lynx->phy_reg_lock, flags); + reg_write(lynx, LINK_PHY, LINK_PHY_READ | LINK_PHY_ADDR(addr)); do { - reg_write(lynx, LINK_PHY, LINK_PHY_READ | LINK_PHY_ADDR(addr)); retval = reg_read(lynx, LINK_PHY); if (i > 10000) { @@ -309,12 +299,11 @@ lsid = 0x80400000 | ((phyreg[0] & 0xfc) << 22); lsid |= (phyreg[1] & 0x3f) << 16; /* gap count */ lsid |= (phyreg[2] & 0xc0) << 8; /* max speed */ - /* lsid |= (phyreg[6] & 0x01) << 11; *//* contender (phy dependent) */ - lsid |= 1 << 11; /* set contender (hack) */ + lsid |= (phyreg[6] & 0x01) << 11; /* contender (phy dependent) */ + /* lsid |= 1 << 11; *//* set contender (hack) */ lsid |= (phyreg[6] & 0x10) >> 3; /* initiated reset */ - //for (i = 0; i < (phyreg[2] & 0xf); i++) { /* ports */ - for (i = 0; i < (phyreg[2] & 0x1f); i++) { /* ports */ + for (i = 0; i < (phyreg[2] & 0xf); i++) { /* ports */ if (phyreg[3 + i] & 0x4) { lsid |= (((phyreg[3 + i] & 0x8) | 0x10) >> 3) << (6 - i*2); @@ -380,47 +369,63 @@ hpsb_selfid_received(host, lsid); } + if (isroot) reg_set_bits(lynx, LINK_CONTROL, LINK_CONTROL_CYCMASTER); + hpsb_selfid_complete(host, phyid, isroot); } -/* This must be called with the async.queue_lock held. */ -static void send_next_async(struct ti_lynx *lynx) +/* This must be called with the respective queue_lock held. */ +static void send_next(struct ti_lynx *lynx, int what) { struct ti_pcl pcl; - struct hpsb_packet *packet = lynx->async.queue; + struct lynx_send_data *d; + struct hpsb_packet *packet; + + d = (what == iso ? &lynx->iso_send : &lynx->async); + packet = d->queue; - lynx->async.header_dma = pci_map_single(lynx->dev, packet->header, - packet->header_size, - PCI_DMA_TODEVICE); + d->header_dma = pci_map_single(lynx->dev, packet->header, + packet->header_size, PCI_DMA_TODEVICE); if (packet->data_size) { - lynx->async.data_dma = pci_map_single(lynx->dev, packet->data, - packet->data_size, - PCI_DMA_TODEVICE); + d->data_dma = pci_map_single(lynx->dev, packet->data, + packet->data_size, + PCI_DMA_TODEVICE); } else { - lynx->async.data_dma = 0; + d->data_dma = 0; } pcl.next = PCL_NEXT_INVALID; pcl.async_error_next = PCL_NEXT_INVALID; #ifdef __BIG_ENDIAN - pcl.buffer[0].control = PCL_CMD_XMT | packet->speed_code << 14 - | packet->header_size; + pcl.buffer[0].control = packet->speed_code << 14 | packet->header_size; #else - pcl.buffer[0].control = PCL_CMD_XMT | packet->speed_code << 14 - | packet->header_size | PCL_BIGENDIAN; + pcl.buffer[0].control = packet->speed_code << 14 | packet->header_size + | PCL_BIGENDIAN; #endif - pcl.buffer[0].pointer = lynx->async.header_dma; + pcl.buffer[0].pointer = d->header_dma; pcl.buffer[1].control = PCL_LAST_BUFF | packet->data_size; - pcl.buffer[1].pointer = lynx->async.data_dma; + pcl.buffer[1].pointer = d->data_dma; + + switch (packet->type) { + case async: + pcl.buffer[0].control |= PCL_CMD_XMT; + break; + case iso: + pcl.buffer[0].control |= PCL_CMD_XMT | PCL_ISOMODE; + break; + case raw: + pcl.buffer[0].control |= PCL_CMD_UNFXMT; + break; + } if (!packet->data_be) { pcl.buffer[1].control |= PCL_BIGENDIAN; } - put_pcl(lynx, lynx->async.pcl, &pcl); - run_pcl(lynx, lynx->async.pcl_start, 3); + put_pcl(lynx, d->pcl, &pcl); + run_pcl(lynx, d->pcl_start, d->channel); } @@ -475,6 +480,10 @@ pcl.async_error_next = pcl_bus(lynx, lynx->async.pcl); put_pcl(lynx, lynx->async.pcl_start, &pcl); + pcl.next = pcl_bus(lynx, lynx->iso_send.pcl); + pcl.async_error_next = PCL_NEXT_INVALID; + put_pcl(lynx, lynx->iso_send.pcl_start, &pcl); + pcl.next = PCL_NEXT_INVALID; pcl.async_error_next = PCL_NEXT_INVALID; pcl.buffer[0].control = PCL_CMD_RCV | 4; @@ -499,15 +508,18 @@ } put_pcl(lynx, lynx->iso_rcv.pcl_start, &pcl); - /* 85 bytes for each FIFO - FIXME - optimize or make configurable */ - /* reg_write(lynx, FIFO_SIZES, 0x00555555); */ - reg_write(lynx, FIFO_SIZES, 0x002020c0); + /* FIFO sizes from left to right: ITF=48 ATF=48 GRF=160 */ + reg_write(lynx, FIFO_SIZES, 0x003030a0); /* 20 byte threshold before triggering PCI transfer */ reg_write(lynx, DMA_GLOBAL_REGISTER, 0x2<<24); - /* 69 byte threshold on both send FIFOs before transmitting */ - reg_write(lynx, FIFO_XMIT_THRESHOLD, 0x4545); + /* threshold on both send FIFOs before transmitting: + FIFO size - cache line size - 1 */ + i = reg_read(lynx, PCI_LATENCY_CACHELINE) & 0xff; + i = 0x30 - i - 1; + reg_write(lynx, FIFO_XMIT_THRESHOLD, (i << 8) | i); reg_set_bits(lynx, PCI_INT_ENABLE, PCI_INT_1394); + reg_write(lynx, LINK_INT_ENABLE, LINK_INT_PHY_TIMEOUT | LINK_INT_PHY_REG_RCVD | LINK_INT_PHY_BUSRESET | LINK_INT_ISO_STUCK | LINK_INT_ASYNC_STUCK @@ -515,15 +527,15 @@ | LINK_INT_GRF_OVERFLOW | LINK_INT_ITF_UNDERFLOW | LINK_INT_ATF_UNDERFLOW); - reg_write(lynx, DMA1_WORD0_CMP_VALUE, 0); - reg_write(lynx, DMA1_WORD0_CMP_ENABLE, 0xa<<4); - reg_write(lynx, DMA1_WORD1_CMP_VALUE, 0); - reg_write(lynx, DMA1_WORD1_CMP_ENABLE, DMA_WORD1_CMP_MATCH_NODE_BCAST - | DMA_WORD1_CMP_MATCH_BROADCAST | DMA_WORD1_CMP_MATCH_LOCAL - | DMA_WORD1_CMP_MATCH_BUS_BCAST | DMA_WORD1_CMP_ENABLE_SELF_ID - | DMA_WORD1_CMP_ENABLE_MASTER); + reg_write(lynx, DMA_WORD0_CMP_VALUE(CHANNEL_ASYNC_RCV), 0); + reg_write(lynx, DMA_WORD0_CMP_ENABLE(CHANNEL_ASYNC_RCV), 0xa<<4); + reg_write(lynx, DMA_WORD1_CMP_VALUE(CHANNEL_ASYNC_RCV), 0); + reg_write(lynx, DMA_WORD1_CMP_ENABLE(CHANNEL_ASYNC_RCV), + DMA_WORD1_CMP_MATCH_NODE_BCAST | DMA_WORD1_CMP_MATCH_BROADCAST + | DMA_WORD1_CMP_MATCH_LOCAL | DMA_WORD1_CMP_MATCH_BUS_BCAST + | DMA_WORD1_CMP_ENABLE_SELF_ID | DMA_WORD1_CMP_ENABLE_MASTER); - run_pcl(lynx, lynx->rcv_pcl_start, 1); + run_pcl(lynx, lynx->rcv_pcl_start, CHANNEL_ASYNC_RCV); reg_write(lynx, DMA_WORD0_CMP_VALUE(CHANNEL_ISO_RCV), 0); reg_write(lynx, DMA_WORD0_CMP_ENABLE(CHANNEL_ISO_RCV), 0x9<<4); @@ -536,7 +548,7 @@ | LINK_CONTROL_TX_ISO_EN | LINK_CONTROL_RX_ISO_EN | LINK_CONTROL_TX_ASYNC_EN | LINK_CONTROL_RX_ASYNC_EN | LINK_CONTROL_RESET_TX | LINK_CONTROL_RESET_RX - | LINK_CONTROL_CYCSOURCE | LINK_CONTROL_CYCTIMEREN); + | LINK_CONTROL_CYCTIMEREN); /* attempt to enable contender bit -FIXME- would this work elsewhere? */ reg_set_bits(lynx, GPIO_CTRL_A, 0x1); @@ -559,14 +571,10 @@ } } - -/* - * FIXME - does not support iso/raw transmits yet and will choke on them. - */ static int lynx_transmit(struct hpsb_host *host, struct hpsb_packet *packet) { struct ti_lynx *lynx = host->hostdata; - struct hpsb_packet *p; + struct lynx_send_data *d; unsigned long flags; if (packet->data_size >= 4096) { @@ -575,27 +583,38 @@ return 0; } + switch (packet->type) { + case async: + case raw: + d = &lynx->async; + break; + case iso: + d = &lynx->iso_send; + break; + default: + PRINT(KERN_ERR, lynx->id, "invalid packet type %d", + packet->type); + return 0; + } + packet->xnext = NULL; if (packet->tcode == TCODE_WRITEQ || packet->tcode == TCODE_READQ_RESPONSE) { cpu_to_be32s(&packet->header[3]); } - spin_lock_irqsave(&lynx->async.queue_lock, flags); + spin_lock_irqsave(&d->queue_lock, flags); - if (lynx->async.queue == NULL) { - lynx->async.queue = packet; - send_next_async(lynx); + if (d->queue == NULL) { + d->queue = packet; + d->queue_last = packet; + send_next(lynx, packet->type); } else { - p = lynx->async.queue; - while (p->xnext != NULL) { - p = p->xnext; - } - - p->xnext = packet; + d->queue_last->xnext = packet; + d->queue_last = packet; } - spin_unlock_irqrestore(&lynx->async.queue_lock, flags); + spin_unlock_irqrestore(&d->queue_lock, flags); return 1; } @@ -652,7 +671,7 @@ case CANCEL_REQUESTS: spin_lock_irqsave(&lynx->async.queue_lock, flags); - reg_write(lynx, DMA3_CHAN_CTRL, 0); + reg_write(lynx, DMA_CHAN_CTRL(CHANNEL_ASYNC_SEND), 0); packet = lynx->async.queue; lynx->async.queue = NULL; @@ -718,18 +737,19 @@ static int mem_open(struct inode*, struct file*); static int mem_release(struct inode*, struct file*); static unsigned int aux_poll(struct file*, struct poll_table_struct*); +static loff_t mem_llseek(struct file*, loff_t, int); static ssize_t mem_read (struct file*, char*, size_t, loff_t*); static ssize_t mem_write(struct file*, const char*, size_t, loff_t*); static struct file_operations aux_ops = { OWNER_THIS_MODULE - /* FIXME: should have custom llseek with bounds checking */ - read: mem_read, - write: mem_write, - poll: aux_poll, - open: mem_open, - release: mem_release, + read: mem_read, + write: mem_write, + poll: aux_poll, + llseek: mem_llseek, + open: mem_open, + release: mem_release, }; @@ -745,7 +765,7 @@ static int mem_open(struct inode *inode, struct file *file) { int cid = MINOR(inode->i_rdev); - enum { rom, aux, ram } type; + enum { t_rom, t_aux, t_ram } type; struct memdata *md; V22_COMPAT_MOD_INC_USE_COUNT; @@ -760,14 +780,14 @@ V22_COMPAT_MOD_DEC_USE_COUNT; return -ENXIO; } - type = aux; + type = t_aux; } else if (cid < PCILYNX_MINOR_RAM_START) { cid -= PCILYNX_MINOR_ROM_START; if (cid >= num_of_cards || !cards[cid].local_rom) { V22_COMPAT_MOD_DEC_USE_COUNT; return -ENXIO; } - type = rom; + type = t_rom; } else { /* WARNING: Know what you are doing when opening RAM. * It is currently used inside the driver! */ @@ -776,10 +796,10 @@ V22_COMPAT_MOD_DEC_USE_COUNT; return -ENXIO; } - type = ram; + type = t_ram; } - md = (struct memdata *)vmalloc(sizeof(struct memdata)); + md = (struct memdata *)kmalloc(sizeof(struct memdata), SLAB_KERNEL); if (md == NULL) { V22_COMPAT_MOD_DEC_USE_COUNT; return -ENOMEM; @@ -789,13 +809,13 @@ md->cid = cid; switch (type) { - case rom: + case t_rom: md->type = rom; break; - case ram: + case t_ram: md->type = ram; break; - case aux: + case t_aux: atomic_set(&md->aux_intr_last_seen, atomic_read(&cards[cid].aux_intr_seen)); md->type = aux; @@ -811,7 +831,7 @@ { struct memdata *md = (struct memdata *)file->private_data; - vfree(md); + kfree(md); V22_COMPAT_MOD_DEC_USE_COUNT; return 0; @@ -839,6 +859,29 @@ return mask; } +loff_t mem_llseek(struct file *file, loff_t offs, int orig) +{ + loff_t newoffs; + + switch (orig) { + case 0: + newoffs = offs; + break; + case 1: + newoffs = offs + file->f_pos; + break; + case 2: + newoffs = PCILYNX_MAX_MEMORY + 1 + offs; + break; + default: + return -EINVAL; + } + + if (newoffs < 0 || newoffs > PCILYNX_MAX_MEMORY + 1) return -EINVAL; + + file->f_pos = newoffs; + return newoffs; +} /* * do not DMA if count is too small because this will have a serious impact @@ -857,8 +900,6 @@ int i; DECLARE_WAITQUEUE(wait, current); - //printk("buf 0x%08x %x count %d offset %d\n", physbuf, physbuf % 3, count, offset); - count &= ~3; count = MIN(count, 53196); retval = count; @@ -868,17 +909,7 @@ PRINT(KERN_WARNING, md->lynx->id, "DMA ALREADY ACTIVE!"); } - switch (md->type) { - case rom: - reg_write(md->lynx, LBUS_ADDR, LBUS_ADDR_SEL_ROM | offset); - break; - case ram: - reg_write(md->lynx, LBUS_ADDR, LBUS_ADDR_SEL_RAM | offset); - break; - case aux: - reg_write(md->lynx, LBUS_ADDR, LBUS_ADDR_SEL_AUX | offset); - break; - } + reg_write(md->lynx, LBUS_ADDR, md->type | offset); pcl = edit_pcl(md->lynx, md->lynx->dmem_pcl, &pcltmp); pcl->buffer[0].control = PCL_CMD_LBUS_TO_PCI | MIN(count, 4092); @@ -933,7 +964,7 @@ if ((off + count) > PCILYNX_MAX_MEMORY + 1) { count = PCILYNX_MAX_MEMORY + 1 - off; } - if (count <= 0) { + if (count == 0) { return 0; } @@ -1041,12 +1072,17 @@ { struct ti_lynx *lynx = (struct ti_lynx *)dev_id; struct hpsb_host *host = lynx->host; - u32 intmask = reg_read(lynx, PCI_INT_STATUS); - u32 linkint = reg_read(lynx, LINK_INT_STATUS); + u32 intmask; + u32 linkint; + + linkint = reg_read(lynx, LINK_INT_STATUS); + intmask = reg_read(lynx, PCI_INT_STATUS); + + PRINTD(KERN_DEBUG, lynx->id, "interrupt: 0x%08x / 0x%08x", intmask, + linkint); - reg_write(lynx, PCI_INT_STATUS, intmask); reg_write(lynx, LINK_INT_STATUS, linkint); - //printk("-%d- one interrupt: 0x%08x / 0x%08x\n", lynx->id, intmask, linkint); + reg_write(lynx, PCI_INT_STATUS, intmask); #ifdef CONFIG_IEEE1394_PCILYNX_PORTS if (intmask & PCI_INT_AUX_INT) { @@ -1054,7 +1090,7 @@ wake_up_interruptible(&lynx->aux_intr_wait); } - if (intmask & PCI_INT_DMA0_HLT) { + if (intmask & PCI_INT_DMA_HLT(CHANNEL_LOCALBUS)) { wake_up_interruptible(&lynx->mem_dma_intr_wait); } #endif @@ -1125,14 +1161,13 @@ mark_bh(IMMEDIATE_BH); } - if (intmask & PCI_INT_DMA3_HLT) { - /* async send DMA completed */ + if (intmask & PCI_INT_DMA_HLT(CHANNEL_ASYNC_SEND)) { u32 ack; struct hpsb_packet *packet; spin_lock(&lynx->async.queue_lock); - ack = reg_read(lynx, DMA3_CHAN_STAT); + ack = reg_read(lynx, DMA_CHAN_STAT(CHANNEL_ASYNC_SEND)); packet = lynx->async.queue; lynx->async.queue = packet->xnext; @@ -1144,7 +1179,7 @@ } if (lynx->async.queue != NULL) { - send_next_async(lynx); + send_next(lynx, async); } spin_unlock(&lynx->async.queue_lock); @@ -1160,9 +1195,33 @@ hpsb_packet_sent(host, packet, ack); } - if (intmask & (PCI_INT_DMA1_HLT | PCI_INT_DMA1_PCL)) { + if (intmask & PCI_INT_DMA_HLT(CHANNEL_ISO_SEND)) { + struct hpsb_packet *packet; + + spin_lock(&lynx->iso_send.queue_lock); + + packet = lynx->iso_send.queue; + lynx->iso_send.queue = packet->xnext; + + pci_unmap_single(lynx->dev, lynx->iso_send.header_dma, + packet->header_size, PCI_DMA_TODEVICE); + if (packet->data_size) { + pci_unmap_single(lynx->dev, lynx->iso_send.data_dma, + packet->data_size, PCI_DMA_TODEVICE); + } + + if (lynx->iso_send.queue != NULL) { + send_next(lynx, iso); + } + + spin_unlock(&lynx->iso_send.queue_lock); + + hpsb_packet_sent(host, packet, ACK_COMPLETE); + } + + if (intmask & PCI_INT_DMA_HLT(CHANNEL_ASYNC_RCV)) { /* general receive DMA completed */ - int stat = reg_read(lynx, DMA1_CHAN_STAT); + int stat = reg_read(lynx, DMA_CHAN_STAT(CHANNEL_ASYNC_RCV)); PRINTD(KERN_DEBUG, lynx->id, "received packet size %d", stat & 0x1fff); @@ -1182,7 +1241,7 @@ hpsb_packet_received(host, q_data, stat & 0x1fff, 0); } - run_pcl(lynx, lynx->rcv_pcl_start, 1); + run_pcl(lynx, lynx->rcv_pcl_start, CHANNEL_ASYNC_RCV); } } @@ -1263,14 +1322,6 @@ } pci_set_master(dev); - if (!request_irq(dev->irq, lynx_irq_handler, SA_SHIRQ, - PCILYNX_DRIVER_NAME, lynx)) { - PRINT(KERN_INFO, lynx->id, "allocated interrupt %d", dev->irq); - lynx->state = have_intr; - } else { - FAIL("failed to allocate shared interrupt %d", dev->irq); - } - #ifndef CONFIG_IEEE1394_PCILYNX_LOCALRAM lynx->pcl_mem = pci_alloc_consistent(dev, LOCALRAM_SIZE, &lynx->pcl_mem_dma); @@ -1329,6 +1380,16 @@ } #endif + reg_write(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET); + + if (!request_irq(dev->irq, lynx_irq_handler, SA_SHIRQ, + PCILYNX_DRIVER_NAME, lynx)) { + PRINT(KERN_INFO, lynx->id, "allocated interrupt %d", dev->irq); + lynx->state = have_intr; + } else { + FAIL("failed to allocate shared interrupt %d", dev->irq); + } + /* alloc_pcl return values are not checked, it is expected that the * provided PCL space is sufficient for the initial allocations */ #ifdef CONFIG_IEEE1394_PCILYNX_PORTS @@ -1342,6 +1403,8 @@ lynx->rcv_pcl_start = alloc_pcl(lynx); lynx->async.pcl = alloc_pcl(lynx); lynx->async.pcl_start = alloc_pcl(lynx); + lynx->iso_send.pcl = alloc_pcl(lynx); + lynx->iso_send.pcl_start = alloc_pcl(lynx); for (i = 0; i < NUM_ISORCV_PCL; i++) { lynx->iso_rcv.pcl[i] = alloc_pcl(lynx); @@ -1362,6 +1425,11 @@ lynx->iso_rcv.tq.routine = (void (*)(void*))iso_rcv_bh; lynx->iso_rcv.tq.data = lynx; lynx->iso_rcv.lock = SPIN_LOCK_UNLOCKED; + + lynx->async.queue_lock = SPIN_LOCK_UNLOCKED; + lynx->async.channel = CHANNEL_ASYNC_SEND; + lynx->iso_send.queue_lock = SPIN_LOCK_UNLOCKED; + lynx->iso_send.channel = CHANNEL_ISO_SEND; PRINT(KERN_INFO, lynx->id, "remapped memory spaces reg 0x%p, rom 0x%p, " "ram 0x%p, aux 0x%p", lynx->registers, lynx->local_rom, @@ -1388,6 +1456,8 @@ int i; switch (lynx->state) { + case have_intr: + free_irq(lynx->dev->irq, lynx); case have_iomappings: reg_write(lynx, PCI_INT_ENABLE, 0); reg_write(lynx, MISC_CONTROL, MISC_CONTROL_SWRESET); @@ -1410,13 +1480,11 @@ pci_free_consistent(lynx->dev, 65536, lynx->mem_dma_buffer, lynx->mem_dma_buffer_dma); #endif - case have_pcl_mem: + case have_pcl_mem: #ifndef CONFIG_IEEE1394_PCILYNX_LOCALRAM pci_free_consistent(lynx->dev, LOCALRAM_SIZE, lynx->pcl_mem, lynx->pcl_mem_dma); #endif - case have_intr: - free_irq(lynx->dev->irq, lynx); case clear: /* do nothing - already freed */ } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/ieee1394/pcilynx.h linux/drivers/ieee1394/pcilynx.h --- v2.4.0-test8/linux/drivers/ieee1394/pcilynx.h Wed Jul 5 13:03:56 2000 +++ linux/drivers/ieee1394/pcilynx.h Sun Oct 1 19:53:07 2000 @@ -19,11 +19,11 @@ #define ISORCV_PER_PAGE (PAGE_SIZE / MAX_ISORCV_SIZE) #define ISORCV_PAGES (NUM_ISORCV_PCL / ISORCV_PER_PAGE) -/* only iso rcv and localbus use these definitions so far */ #define CHANNEL_LOCALBUS 0 #define CHANNEL_ASYNC_RCV 1 #define CHANNEL_ISO_RCV 2 #define CHANNEL_ASYNC_SEND 3 +#define CHANNEL_ISO_SEND 4 typedef int pcl_t; @@ -88,12 +88,13 @@ dma_addr_t rcv_page_dma; int rcv_active; - struct { + struct lynx_send_data { pcl_t pcl_start, pcl; - struct hpsb_packet *queue; + struct hpsb_packet *queue, *queue_last; spinlock_t queue_lock; dma_addr_t header_dma, data_dma; - } async; + int channel; + } async, iso_send; struct { pcl_t pcl[NUM_ISORCV_PCL]; @@ -113,7 +114,8 @@ struct ti_lynx *lynx; int cid; atomic_t aux_intr_last_seen; - enum { rom, aux, ram } type; + /* enum values are the same as LBUS_ADDR_SEL_* values below */ + enum { rom = 0x10000, aux = 0x20000, ram = 0 } type; }; @@ -147,6 +149,8 @@ /* chip register definitions follow */ +#define PCI_LATENCY_CACHELINE 0x0c + #define MISC_CONTROL 0x40 #define MISC_CONTROL_SWRESET (1<<0) @@ -495,6 +499,7 @@ #define PCL_LAST_CMD (PCL_LAST_BUFF) #define PCL_WAITSTAT (1<<17) #define PCL_BIGENDIAN (1<<16) +#define PCL_ISOMODE (1<<12) #define _(x) (__constant_cpu_to_be32(x)) diff -u --recursive --new-file v2.4.0-test8/linux/drivers/ieee1394/raw1394.c linux/drivers/ieee1394/raw1394.c --- v2.4.0-test8/linux/drivers/ieee1394/raw1394.c Wed Jul 12 21:58:42 2000 +++ linux/drivers/ieee1394/raw1394.c Sun Oct 1 19:53:07 2000 @@ -33,6 +33,15 @@ #include "raw1394.h" +#if BITS_PER_LONG == 64 +#define int2ptr(x) ((void *)x) +#define ptr2int(x) ((u64)x) +#else +#define int2ptr(x) ((void *)(u32)x) +#define ptr2int(x) ((u64)(u32)x) +#endif + + static devfs_handle_t devfs_handle = NULL; LIST_HEAD(host_info_list); @@ -204,8 +213,13 @@ req->file_info = fi; req->req.type = RAW1394_REQ_BUS_RESET; req->req.generation = get_hpsb_generation(); - req->req.misc = (host->node_id << 16) + req->req.misc = (host->node_id << 16) | host->node_count; + if (fi->protocol_version > 3) { + req->req.misc |= ((host->irm_id + & NODE_MASK) << 8); + } + queue_complete_req(req); } @@ -268,7 +282,7 @@ req->req.type = RAW1394_REQ_ISO_RECEIVE; req->req.generation = get_hpsb_generation(); req->req.misc = 0; - req->req.recvb = (u64)fi->iso_buffer; + req->req.recvb = ptr2int(fi->iso_buffer); req->req.length = MIN(length, fi->iso_buffer_length); list_add_tail(&req->list, &reqs); @@ -337,7 +351,7 @@ req->req.type = RAW1394_REQ_FCP_REQUEST; req->req.generation = get_hpsb_generation(); req->req.misc = nodeid | (direction << 16); - req->req.recvb = (u64)fi->fcp_buffer; + req->req.recvb = ptr2int(fi->fcp_buffer); req->req.length = length; list_add_tail(&req->list, &reqs); @@ -387,7 +401,7 @@ req = list_entry(lh, struct pending_request, list); if (req->req.length) { - if (copy_to_user((void *)req->req.recvb, req->data, + if (copy_to_user(int2ptr(req->req.recvb), req->data, req->req.length)) { req->req.error = RAW1394_ERROR_MEMFAULT; } @@ -402,11 +416,16 @@ static int state_opened(struct file_info *fi, struct pending_request *req) { if (req->req.type == RAW1394_REQ_INITIALIZE) { - if (req->req.misc == RAW1394_KERNELAPI_VERSION) { + switch (req->req.misc) { + case RAW1394_KERNELAPI_VERSION: + case 3: fi->state = initialized; + fi->protocol_version = req->req.misc; req->req.error = RAW1394_ERROR_NONE; req->req.generation = get_hpsb_generation(); - } else { + break; + + default: req->req.error = RAW1394_ERROR_COMPAT; req->req.misc = RAW1394_KERNELAPI_VERSION; } @@ -488,6 +507,10 @@ req->req.error = RAW1394_ERROR_NONE; req->req.misc = (fi->host->node_id << 16) | fi->host->node_count; + if (fi->protocol_version > 3) { + req->req.misc |= + (fi->host->irm_id & NODE_MASK) << 8; + } } else { req->req.error = RAW1394_ERROR_INVALID_ARG; } @@ -519,7 +542,7 @@ } else { fi->listen_channels |= 1ULL << channel; hpsb_listen_channel(hl_handle, fi->host, channel); - fi->iso_buffer = (void *)req->req.recvb; + fi->iso_buffer = int2ptr(req->req.recvb); fi->iso_buffer_length = req->req.length; } } else { @@ -545,7 +568,7 @@ if (fi->fcp_buffer) { req->req.error = RAW1394_ERROR_ALREADY; } else { - fi->fcp_buffer = (u8 *)req->req.recvb; + fi->fcp_buffer = (u8 *)int2ptr(req->req.recvb); } } else { if (!fi->fcp_buffer) { @@ -575,7 +598,7 @@ break; case RAW1394_REQ_ASYNC_WRITE: - if (copy_from_user(req->data, (void *)req->req.sendb, + if (copy_from_user(req->data, int2ptr(req->req.sendb), req->req.length)) { req->req.error = RAW1394_ERROR_MEMFAULT; break; @@ -600,7 +623,7 @@ } } - if (copy_from_user(req->data, (void *)req->req.sendb, + if (copy_from_user(req->data, int2ptr(req->req.sendb), req->req.length)) { req->req.error = RAW1394_ERROR_MEMFAULT; break; @@ -658,7 +681,7 @@ if (req->req.length == 4) { quadlet_t x; - if (copy_from_user(&x, (void *)req->req.sendb, 4)) { + if (copy_from_user(&x, int2ptr(req->req.sendb), 4)) { req->req.error = RAW1394_ERROR_MEMFAULT; } @@ -670,7 +693,7 @@ req->req.length); if (!packet) return -ENOMEM; - if (copy_from_user(packet->data, (void *)req->req.sendb, + if (copy_from_user(packet->data, int2ptr(req->req.sendb), req->req.length)) { req->req.error = RAW1394_ERROR_MEMFAULT; } @@ -696,7 +719,7 @@ req->req.misc); if (!packet) return -ENOMEM; - if (copy_from_user(packet->data, (void *)req->req.sendb, + if (copy_from_user(packet->data, int2ptr(req->req.sendb), req->req.length)) { req->req.error = RAW1394_ERROR_MEMFAULT; break; @@ -735,12 +758,52 @@ return sizeof(struct raw1394_request); } +static int handle_iso_send(struct file_info *fi, struct pending_request *req, + int channel) +{ + struct hpsb_packet *packet; + + packet = alloc_hpsb_packet(req->req.length); + if (!packet) return -ENOMEM; + req->packet = packet; + + fill_iso_packet(packet, req->req.length, channel & 0x3f, + (req->req.misc >> 16) & 0x3, req->req.misc & 0xf); + packet->type = iso; + packet->speed_code = req->req.address & 0x3; + packet->host = fi->host; + + if (copy_from_user(packet->data, int2ptr(req->req.sendb), + req->req.length)) { + req->req.error = RAW1394_ERROR_MEMFAULT; + req->req.length = 0; + queue_complete_req(req); + return sizeof(struct raw1394_request); + } + + req->tq.data = req; + req->tq.routine = (void (*)(void*))queue_complete_req; + req->req.length = 0; + queue_task(&req->tq, &packet->complete_tq); + + if (!hpsb_send_packet(packet)) { + req->req.error = RAW1394_ERROR_SEND_ERROR; + queue_complete_req(req); + } + + return sizeof(struct raw1394_request); +} + static int state_connected(struct file_info *fi, struct pending_request *req) { int node = req->req.address >> 48; req->req.error = RAW1394_ERROR_NONE; + if (req->req.type == RAW1394_REQ_ISO_SEND) { + return handle_iso_send(fi, req, node); + } + if (req->req.generation != get_hpsb_generation()) { req->req.error = RAW1394_ERROR_GENERATION; req->req.generation = get_hpsb_generation(); @@ -749,14 +812,18 @@ return sizeof(struct raw1394_request); } - if (req->req.type == RAW1394_REQ_ISO_LISTEN) { + switch (req->req.type) { + case RAW1394_REQ_ISO_LISTEN: handle_iso_listen(fi, req); return sizeof(struct raw1394_request); - } - if (req->req.type == RAW1394_REQ_FCP_LISTEN) { + case RAW1394_REQ_FCP_LISTEN: handle_fcp_listen(fi, req); return sizeof(struct raw1394_request); + + case RAW1394_REQ_RESET_BUS: + hpsb_reset_bus(fi->host); + return sizeof(struct raw1394_request); } if (req->req.length == 0) { @@ -870,7 +937,7 @@ struct pending_request *req; int done = 0, i; - lock_kernel(); + lock_kernel(); for (i = 0; i < 64; i++) { if (fi->listen_channels & (1ULL << i)) { hpsb_unlisten_channel(hl_handle, fi->host, i); @@ -915,7 +982,7 @@ kfree(fi); V22_COMPAT_MOD_DEC_USE_COUNT; - unlock_kernel(); + unlock_kernel(); return 0; } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/ieee1394/raw1394.h linux/drivers/ieee1394/raw1394.h --- v2.4.0-test8/linux/drivers/ieee1394/raw1394.h Wed Jul 5 13:03:56 2000 +++ linux/drivers/ieee1394/raw1394.h Sun Oct 1 19:53:07 2000 @@ -4,7 +4,7 @@ #define RAW1394_DEVICE_MAJOR 171 #define RAW1394_DEVICE_NAME "raw1394" -#define RAW1394_KERNELAPI_VERSION 3 +#define RAW1394_KERNELAPI_VERSION 4 /* state: opened */ #define RAW1394_REQ_INITIALIZE 1 @@ -18,9 +18,11 @@ #define RAW1394_REQ_ASYNC_WRITE 101 #define RAW1394_REQ_LOCK 102 #define RAW1394_REQ_LOCK64 103 +#define RAW1394_REQ_ISO_SEND 104 #define RAW1394_REQ_ISO_LISTEN 200 #define RAW1394_REQ_FCP_LISTEN 201 +#define RAW1394_REQ_RESET_BUS 202 /* kernel to user */ #define RAW1394_REQ_BUS_RESET 10000 @@ -79,6 +81,7 @@ struct list_head list; enum { opened, initialized, connected } state; + unsigned int protocol_version; struct hpsb_host *host; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/ieee1394/video1394.c linux/drivers/ieee1394/video1394.c --- v2.4.0-test8/linux/drivers/ieee1394/video1394.c Mon Aug 7 21:01:36 2000 +++ linux/drivers/ieee1394/video1394.c Sun Oct 1 19:53:07 2000 @@ -57,6 +57,10 @@ #define ISO_RECEIVE 0 #define ISO_TRANSMIT 1 +#ifndef virt_to_page +#define virt_to_page(x) MAP_NR(x) +#endif + struct it_dma_prg { struct dma_cmd begin; quadlet_t data[4]; @@ -84,6 +88,7 @@ int cmdPtr; int ctxMatch; wait_queue_head_t waitq; + spinlock_t lock; }; struct video_card { @@ -144,7 +149,7 @@ */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) -#define page_address(x) ((void *) (x)) +#define page_address(x) (x) #endif /* Given PGD from the address space's page table, return the kernel @@ -163,7 +168,7 @@ pte = *ptep; if(pte_present(pte)) { ret = (unsigned long) page_address(pte_page(pte)); - ret |= (adr & (PAGE_SIZE - 1)); + ret |= (adr & (PAGE_SIZE - 1)); } } } @@ -212,7 +217,7 @@ void * mem; unsigned long adr, page; - mem=vmalloc(size); + mem=vmalloc_32(size); if (mem) { memset(mem, 0, size); /* Clear the ram out, @@ -374,7 +379,7 @@ d->packet_size = packet_size; - if (PAGE_SIZE % packet_size || packet_size>2048) { + if (PAGE_SIZE % packet_size || packet_size>4096) { PRINT(KERN_ERR, ohci->id, "Packet size %d not yet supported\n", packet_size); @@ -413,6 +418,8 @@ } memset(d->buffer_status, 0, d->num_desc * sizeof(unsigned int)); + spin_lock_init(&d->lock); + PRINT(KERN_INFO, ohci->id, "Iso %s DMA: %d buffers " "of size %d allocated for a frame size %d, each with %d prgs", (type==ISO_RECEIVE) ? "receive" : "transmit", @@ -531,12 +538,14 @@ return -EFAULT; } + spin_lock(&d->lock); for (i=0;inum_desc;i++) { if (d->ir_prg[i][d->nb_cmd-1].status & 0xFFFF0000) { reset_ir_status(d, i); d->buffer_status[i] = VIDEO1394_BUFFER_READY; } } + spin_unlock(&d->lock); if (waitqueue_active(&d->waitq)) wake_up_interruptible(&d->waitq); return 0; } @@ -551,12 +560,14 @@ return -EFAULT; } + spin_lock(&d->lock); for (i=0;inum_desc;i++) { if (d->it_prg[i][d->nb_cmd-1].end.status & 0xFFFF0000) { d->it_prg[i][d->nb_cmd-1].end.status = 0; d->buffer_status[i] = VIDEO1394_BUFFER_READY; } } + spin_unlock(&d->lock); if (waitqueue_active(&d->waitq)) wake_up_interruptible(&d->waitq); return 0; } @@ -664,6 +675,7 @@ { struct video_card *video = &video_cards[MINOR(inode->i_rdev)]; struct ti_ohci *ohci= video->ohci; + unsigned long flags; switch(cmd) { @@ -832,9 +844,12 @@ return -EFAULT; } - if (d->buffer_status[v.buffer]!=VIDEO1394_BUFFER_FREE) { + spin_lock_irqsave(&d->lock,flags); + + if (d->buffer_status[v.buffer]==VIDEO1394_BUFFER_QUEUED) { PRINT(KERN_ERR, ohci->id, "buffer %d is already used",v.buffer); + spin_unlock_irqrestore(&d->lock,flags); return -EFAULT; } @@ -849,6 +864,8 @@ d->ir_prg[d->last_buffer][d->nb_cmd-1].branchAddress = 0; + spin_unlock_irqrestore(&d->lock,flags); + if (!(reg_read(ohci, d->ctrlSet) & 0x8000)) { DBGMSG(ohci->id, "Starting iso DMA ctx=%d",d->ctx); @@ -890,16 +907,26 @@ return -EFAULT; } + /* + * I change the way it works so that it returns + * the last received frame. + */ + spin_lock_irqsave(&d->lock, flags); switch(d->buffer_status[v.buffer]) { case VIDEO1394_BUFFER_READY: d->buffer_status[v.buffer]=VIDEO1394_BUFFER_FREE; - return 0; + break; case VIDEO1394_BUFFER_QUEUED: #if 1 while(d->buffer_status[v.buffer]!= VIDEO1394_BUFFER_READY) { + spin_unlock_irqrestore(&d->lock, flags); interruptible_sleep_on(&d->waitq); - if(signal_pending(current)) return -EINTR; + spin_lock_irqsave(&d->lock, flags); + if(signal_pending(current)) { + spin_unlock_irqrestore(&d->lock,flags); + return -EINTR; + } } #else if (wait_event_interruptible(d->waitq, @@ -909,12 +936,30 @@ return -EINTR; #endif d->buffer_status[v.buffer]=VIDEO1394_BUFFER_FREE; - return 0; + break; default: PRINT(KERN_ERR, ohci->id, "buffer %d is not queued",v.buffer); + spin_unlock_irqrestore(&d->lock, flags); return -EFAULT; } + + /* + * Look ahead to see how many more buffers have been received + */ + i=0; + while (d->buffer_status[(v.buffer+1)%d->num_desc]== + VIDEO1394_BUFFER_READY) { + v.buffer=(v.buffer+1)%d->num_desc; + i++; + } + spin_unlock_irqrestore(&d->lock, flags); + + v.buffer=i; + if(copy_to_user((void *)arg, &v, sizeof(v))) + return -EFAULT; + + return 0; } case VIDEO1394_TALK_QUEUE_BUFFER: { @@ -935,9 +980,12 @@ return -EFAULT; } + spin_lock_irqsave(&d->lock,flags); + if (d->buffer_status[v.buffer]!=VIDEO1394_BUFFER_FREE) { PRINT(KERN_ERR, ohci->id, "buffer %d is already used",v.buffer); + spin_unlock_irqrestore(&d->lock,flags); return -EFAULT; } @@ -957,6 +1005,8 @@ d->last_buffer = v.buffer; d->it_prg[d->last_buffer][d->nb_cmd-1].end.branchAddress = 0; + + spin_unlock_irqrestore(&d->lock,flags); if (!(reg_read(ohci, d->ctrlSet) & 0x8000)) { diff -u --recursive --new-file v2.4.0-test8/linux/drivers/ieee1394/video1394.h linux/drivers/ieee1394/video1394.h --- v2.4.0-test8/linux/drivers/ieee1394/video1394.h Wed Jul 5 13:03:56 2000 +++ linux/drivers/ieee1394/video1394.h Sun Oct 1 19:53:07 2000 @@ -22,7 +22,7 @@ #define VIDEO1394_DRIVER_NAME "video1394" -#define VIDEO1394_MAX_SIZE 0x400000 +#define VIDEO1394_MAX_SIZE 0x4000000 enum { VIDEO1394_BUFFER_FREE = 0, diff -u --recursive --new-file v2.4.0-test8/linux/drivers/isdn/avmb1/b1.c linux/drivers/isdn/avmb1/b1.c --- v2.4.0-test8/linux/drivers/isdn/avmb1/b1.c Mon Aug 21 07:49:02 2000 +++ linux/drivers/isdn/avmb1/b1.c Mon Sep 18 15:02:02 2000 @@ -517,7 +517,7 @@ struct sk_buff *skb; unsigned ApplId; - unsigned MsgLen; + signed MsgLen; unsigned DataB3Len; unsigned NCCI; unsigned WindowSize; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/isdn/avmb1/b1dma.c linux/drivers/isdn/avmb1/b1dma.c --- v2.4.0-test8/linux/drivers/isdn/avmb1/b1dma.c Mon Aug 21 07:49:02 2000 +++ linux/drivers/isdn/avmb1/b1dma.c Mon Sep 18 15:02:02 2000 @@ -475,7 +475,8 @@ struct capi_ctr *ctrl = cinfo->capi_ctrl; struct sk_buff *skb; void *p = dma->recvbuf+4; - __u32 ApplId, MsgLen, DataB3Len, NCCI, WindowSize; + __u32 ApplId, DataB3Len, NCCI, WindowSize; + __s32 MsgLen; __u8 b1cmd = _get_byte(&p); #ifdef CONFIG_B1DMA_DEBUG diff -u --recursive --new-file v2.4.0-test8/linux/drivers/isdn/avmb1/c4.c linux/drivers/isdn/avmb1/c4.c --- v2.4.0-test8/linux/drivers/isdn/avmb1/c4.c Mon Aug 21 07:49:02 2000 +++ linux/drivers/isdn/avmb1/c4.c Mon Sep 18 15:02:02 2000 @@ -572,7 +572,8 @@ avmctrl_info *cinfo; struct sk_buff *skb; void *p = dma->recvbuf; - __u32 ApplId, MsgLen, DataB3Len, NCCI, WindowSize; + __u32 ApplId, DataB3Len, NCCI, WindowSize; + __s32 MsgLen; __u8 b1cmd = _get_byte(&p); __u32 cidx; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/isdn/avmb1/capi.c linux/drivers/isdn/avmb1/capi.c --- v2.4.0-test8/linux/drivers/isdn/avmb1/capi.c Mon Aug 21 07:49:02 2000 +++ linux/drivers/isdn/avmb1/capi.c Sun Sep 17 09:45:05 2000 @@ -212,6 +212,7 @@ #include #include #include +#include #include "capiutil.h" #include "capicmd.h" #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE @@ -1930,7 +1931,7 @@ { "capi/capi20ncci", 0 , proc_capincci_read_proc }, }; -static void proc_init(void) +static void __init proc_init(void) { int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]); int i; @@ -1942,7 +1943,7 @@ } } -static void proc_exit(void) +static void __exit proc_exit(void) { int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]); int i; @@ -1981,7 +1982,7 @@ #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ } -static int alloc_init(void) +static int __init alloc_init(void) { capidev_cachep = kmem_cache_create("capi20_dev", sizeof(struct capidev), @@ -2052,10 +2053,6 @@ } } -#ifdef MODULE -#define capi_init init_module -#endif - static struct capi_interface_user cuser = { "capi20", lower_callback, @@ -2063,7 +2060,7 @@ static char rev[10]; -int capi_init(void) +int __init capi_init(void) { char *p; @@ -2152,8 +2149,7 @@ return 0; } -#ifdef MODULE -void cleanup_module(void) +static void __exit capi_exit(void) { #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE unsigned int j; @@ -2177,4 +2173,8 @@ printk(KERN_NOTICE "capi: Rev%s: unloaded\n", rev); } +#ifdef MODULE +module_init(capi_init); #endif +module_exit(capi_exit); + diff -u --recursive --new-file v2.4.0-test8/linux/drivers/isdn/avmb1/capidrv.c linux/drivers/isdn/avmb1/capidrv.c --- v2.4.0-test8/linux/drivers/isdn/avmb1/capidrv.c Mon Aug 21 07:49:02 2000 +++ linux/drivers/isdn/avmb1/capidrv.c Sun Sep 17 09:45:05 2000 @@ -200,6 +200,7 @@ #include #include #include +#include #include #include "capiutil.h" @@ -2436,7 +2437,7 @@ { "capi/capidrv", 0 , proc_capidrv_read_proc }, }; -static void proc_init(void) +static void __init proc_init(void) { int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]); int i; @@ -2448,7 +2449,7 @@ } } -static void proc_exit(void) +static void __exit proc_exit(void) { int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]); int i; @@ -2467,11 +2468,7 @@ lower_callback }; -#ifdef MODULE -#define capidrv_init init_module -#endif - -int capidrv_init(void) +int __init capidrv_init(void) { struct capi_register_params rparam; capi_profile profile; @@ -2531,8 +2528,7 @@ return 0; } -#ifdef MODULE -void cleanup_module(void) +static void __exit capidrv_exit(void) { char rev[10]; char *p; @@ -2554,4 +2550,8 @@ printk(KERN_NOTICE "capidrv: Rev%s: unloaded\n", rev); } +#ifdef MODULE +module_init(capidrv_init); #endif +module_exit(capidrv_exit); + diff -u --recursive --new-file v2.4.0-test8/linux/drivers/isdn/avmb1/t1isa.c linux/drivers/isdn/avmb1/t1isa.c --- v2.4.0-test8/linux/drivers/isdn/avmb1/t1isa.c Mon Aug 21 07:49:02 2000 +++ linux/drivers/isdn/avmb1/t1isa.c Mon Sep 18 15:02:02 2000 @@ -200,7 +200,7 @@ struct sk_buff *skb; unsigned ApplId; - unsigned MsgLen; + signed MsgLen; unsigned DataB3Len; unsigned NCCI; unsigned WindowSize; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/isdn/eicon/Divas_mod.c linux/drivers/isdn/eicon/Divas_mod.c --- v2.4.0-test8/linux/drivers/isdn/eicon/Divas_mod.c Mon Aug 14 13:09:07 2000 +++ linux/drivers/isdn/eicon/Divas_mod.c Wed Sep 27 13:45:40 2000 @@ -42,11 +42,13 @@ #ifdef MODULE #include "idi.h" -void EtdM_DIDD_Write(DESCRIPTOR *, int); -EXPORT_SYMBOL_NOVERS(EtdM_DIDD_Read); -EXPORT_SYMBOL_NOVERS(EtdM_DIDD_Write); +void DIVA_DIDD_Write(DESCRIPTOR *, int); +EXPORT_SYMBOL_NOVERS(DIVA_DIDD_Read); +EXPORT_SYMBOL_NOVERS(DIVA_DIDD_Write); EXPORT_SYMBOL_NOVERS(DivasPrintf); #define Divas_init init_module +#else +#define Divas_init eicon_init #endif extern char *file_check(void); @@ -58,7 +60,7 @@ { printk(KERN_DEBUG "DIVA Server Driver - initialising\n"); - printk(KERN_DEBUG "DIVA Server Driver - Version 2.0.12 (%s)\n",file_check()); + printk(KERN_DEBUG "DIVA Server Driver - Version 2.0.15 (%s)\n",file_check()); #if !defined(CONFIG_PCI) @@ -164,9 +166,5 @@ MOD_DEC_USE_COUNT; } -#else -Divas_setup(char *str, int *ints) -{ -} #endif diff -u --recursive --new-file v2.4.0-test8/linux/drivers/isdn/eicon/common.c linux/drivers/isdn/eicon/common.c --- v2.4.0-test8/linux/drivers/isdn/eicon/common.c Sun Aug 13 10:05:32 2000 +++ linux/drivers/isdn/eicon/common.c Wed Sep 27 13:45:40 2000 @@ -81,29 +81,33 @@ dia_config_t *DivasConfig(card_t *, dia_config_t *); static -DESCRIPTOR DIDD_Table[16]; -static -int DIDD_Length = 0; +DESCRIPTOR DIDD_Table[32]; -void EtdM_DIDD_Read( DESCRIPTOR *table, int *tablelength ) +void DIVA_DIDD_Read( DESCRIPTOR *table, int tablelength ) { - int table_size = sizeof(DIDD_Table); + bzero(table, tablelength); + + if (tablelength > sizeof(DIDD_Table)) + tablelength = sizeof(DIDD_Table); - bcopy((caddr_t)DIDD_Table, (caddr_t)table, table_size); + if(tablelength % sizeof(DESCRIPTOR)) { + tablelength /= sizeof(DESCRIPTOR); + tablelength *= sizeof(DESCRIPTOR); + } - *tablelength = DIDD_Length; + if (tablelength > 0) + bcopy((caddr_t)DIDD_Table, (caddr_t)table, tablelength); return; } static -void EtdM_DIDD_Write(DESCRIPTOR *table, int tablelength) +void DIVA_DIDD_Write(DESCRIPTOR *table, int tablelength) { - int table_size = sizeof(DIDD_Table); - - bcopy((caddr_t)table, (caddr_t)DIDD_Table, table_size); + if (tablelength > sizeof(DIDD_Table)) + tablelength = sizeof(DIDD_Table); - DIDD_Length = tablelength; + bcopy((caddr_t)table, (caddr_t)DIDD_Table, tablelength); return; } @@ -111,19 +115,16 @@ static void init_idi_tab(void) { - int length = 0; + DESCRIPTOR d[32]; - DESCRIPTOR d[16]; + bzero(d, sizeof(d)); - EtdM_DIDD_Read(d, &length); - - d[length].type = IDI_DIMAINT; /* identify the DIMAINT entry */ - d[length].channels = 0; /* zero channels associated with dimaint*/ - d[length].features = 0; /* no features associated with dimaint */ - d[length].request = (IDI_CALL) DivasPrintf; - length++; + d[0].type = IDI_DIMAINT; /* identify the DIMAINT entry */ + d[0].channels = 0; /* zero channels associated with dimaint*/ + d[0].features = 0; /* no features associated with dimaint */ + d[0].request = (IDI_CALL) DivasPrintf; - EtdM_DIDD_Write(d, length); + DIVA_DIDD_Write(d, sizeof(d)); return; } @@ -663,7 +664,7 @@ static int idi_register(card_t *card, byte channels) { - DESCRIPTOR d[16]; + DESCRIPTOR d[32]; int length, num_entities; DPRINTF(("divas: registering card with IDI")); @@ -680,9 +681,12 @@ bzero(card->e_tbl, sizeof(E_INFO) * num_entities); card->e_max = num_entities; - EtdM_DIDD_Read(d, &length); + DIVA_DIDD_Read(d, sizeof(d)); + + for(length=0; length < DIM(d); length++) + if (d[length].type == 0) break; - if (length == DIM(d)) + if (length >= DIM(d)) { KDPRINTF((KERN_WARNING "Divas: IDI register failed - table full")); return -1; @@ -692,18 +696,18 @@ { case DIA_CARD_TYPE_DIVA_SERVER: d[length].type = IDI_ADAPTER_PR; - d[length].serial = card->serial_no; + /* d[length].serial = card->serial_no; */ break; case DIA_CARD_TYPE_DIVA_SERVER_B: d[length].type = IDI_ADAPTER_MAESTRA; - d[length].serial = card->serial_no; + /* d[length].serial = card->serial_no; */ break; // 4BRI is treated as 4 BRI adapters case DIA_CARD_TYPE_DIVA_SERVER_Q: d[length].type = IDI_ADAPTER_MAESTRA; - d[length].serial = card->cfg.serial; + /* d[length].serial = card->cfg.serial; */ } d[length].features = 0; @@ -727,7 +731,7 @@ length++; - EtdM_DIDD_Write(d, length); + DIVA_DIDD_Write(d, sizeof(d)); return 0; } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/isdn/eicon/eicon_mod.c linux/drivers/isdn/eicon/eicon_mod.c --- v2.4.0-test8/linux/drivers/isdn/eicon/eicon_mod.c Sun Aug 13 10:05:32 2000 +++ linux/drivers/isdn/eicon/eicon_mod.c Wed Sep 27 13:45:40 2000 @@ -1,4 +1,4 @@ -/* $Id: eicon_mod.c,v 1.35 2000/08/12 18:00:47 armin Exp $ +/* $Id: eicon_mod.c,v 1.37 2000/09/02 11:16:47 armin Exp $ * * ISDN lowlevel-module for Eicon active cards. * @@ -32,7 +32,7 @@ #define DRIVERNAME "Eicon active ISDN driver" #define DRIVERRELEASE "2.0" -#define DRIVERPATCH ".14" +#define DRIVERPATCH ".15" #include @@ -55,7 +55,7 @@ static eicon_card *cards = (eicon_card *) NULL; /* glob. var , contains start of card-list */ -static char *eicon_revision = "$Revision: 1.35 $"; +static char *eicon_revision = "$Revision: 1.37 $"; extern char *eicon_pci_revision; extern char *eicon_isa_revision; @@ -78,8 +78,7 @@ spinlock_t eicon_lock; -DESCRIPTOR idi_d[16]; -int idi_dlength; +DESCRIPTOR idi_d[32]; /* Parameters to be set by insmod */ #ifdef CONFIG_ISDN_DRV_EICON_ISA @@ -210,6 +209,7 @@ #ifdef CONFIG_PCI #ifdef CONFIG_ISDN_DRV_EICON_PCI dia_start_t dstart; + int idi_length = 0; #endif #endif isdn_ctrl cmd; @@ -399,8 +399,15 @@ (unsigned long) a); if (((c->arg - EICON_IOCTL_DIA_OFFSET)==DIA_IOCTL_START) && (!ret)) { if (card->type != EICON_CTYPE_MAESTRAQ) { - EtdM_DIDD_Read(idi_d, &idi_dlength); - card->d = &idi_d[idi_dlength - 1]; + DIVA_DIDD_Read(idi_d, sizeof(idi_d)); + for(idi_length = 0; idi_length < 32; idi_length++) { + if (idi_d[idi_length].type == 0) break; + } + if ((idi_length < 1) || (idi_length >= 32)) { + eicon_log(card, 1, "eicon: invalid idi table length.\n"); + break; + } + card->d = &idi_d[idi_length - 1]; card->flags |= EICON_FLAGS_LOADED; card->flags |= EICON_FLAGS_RUNNING; eicon_pci_init_conf(card); @@ -414,19 +421,25 @@ cmd.driver = card->myid; cmd.arg = 0; card->interface.statcallb(&cmd); - eicon_log(card, 1, "Eicon: %s started, %d channels (feat. 0x%x, SerNo. %d)\n", + eicon_log(card, 1, "Eicon: %s started, %d channels (feat. 0x%x)\n", (card->type == EICON_CTYPE_MAESTRA) ? "BRI" : "PRI", - card->d->channels, card->d->features, card->d->serial); + card->d->channels, card->d->features); } else { int i; - EtdM_DIDD_Read(idi_d, &idi_dlength); + DIVA_DIDD_Read(idi_d, sizeof(idi_d)); + for(idi_length = 0; idi_length < 32; idi_length++) + if (idi_d[idi_length].type == 0) break; + if ((idi_length < 1) || (idi_length >= 32)) { + eicon_log(card, 1, "eicon: invalid idi table length.\n"); + break; + } for(i = 3; i >= 0; i--) { if (!(card = eicon_findnpcicard(dstart.card_id - i))) return -EINVAL; card->flags |= EICON_FLAGS_LOADED; card->flags |= EICON_FLAGS_RUNNING; - card->d = &idi_d[idi_dlength - (i+1)]; + card->d = &idi_d[idi_length - (i+1)]; eicon_pci_init_conf(card); if (card->d->channels > 1) { cmd.command = ISDN_STAT_ADDCH; @@ -438,8 +451,8 @@ cmd.driver = card->myid; cmd.arg = 0; card->interface.statcallb(&cmd); - eicon_log(card, 1, "Eicon: %d/4BRI started, %d channels (feat. 0x%x, SerNo. %d)\n", - 4-i, card->d->channels, card->d->features, card->d->serial); + eicon_log(card, 1, "Eicon: %d/4BRI started, %d channels (feat. 0x%x)\n", + 4-i, card->d->channels, card->d->features); } } } @@ -1392,9 +1405,9 @@ } #ifdef CONFIG_ISDN_DRV_EICON_PCI -void EtdM_DIDD_Write(DESCRIPTOR *, int); -EXPORT_SYMBOL_NOVERS(EtdM_DIDD_Read); -EXPORT_SYMBOL_NOVERS(EtdM_DIDD_Write); +void DIVA_DIDD_Write(DESCRIPTOR *, int); +EXPORT_SYMBOL_NOVERS(DIVA_DIDD_Read); +EXPORT_SYMBOL_NOVERS(DIVA_DIDD_Write); EXPORT_SYMBOL_NOVERS(DivasPrintf); #else int DivasCardNext; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/isdn/eicon/idi.h linux/drivers/isdn/eicon/idi.h --- v2.4.0-test8/linux/drivers/isdn/eicon/idi.h Sun Aug 13 10:05:32 2000 +++ linux/drivers/isdn/eicon/idi.h Wed Sep 27 13:45:40 2000 @@ -112,11 +112,11 @@ byte type; byte channels; word features; - dword serial; + /* dword serial; */ IDI_CALL request; } DESCRIPTOR; -extern void EtdM_DIDD_Read(DESCRIPTOR *, int *); +extern void DIVA_DIDD_Read(DESCRIPTOR *, int); /* descriptor type field coding */ #define IDI_ADAPTER_S 1 diff -u --recursive --new-file v2.4.0-test8/linux/drivers/isdn/eicon/md5sums.asc linux/drivers/isdn/eicon/md5sums.asc --- v2.4.0-test8/linux/drivers/isdn/eicon/md5sums.asc Sun Aug 13 10:05:32 2000 +++ linux/drivers/isdn/eicon/md5sums.asc Wed Sep 27 13:45:40 2000 @@ -3,7 +3,7 @@ # For changes and modifications in these files please # read ../../../Documentation/isdn/README.eicon # -9b0e381d4558af3a6eba66843e1ee5d9 common.c +34bfe8d08d337a97c699ac8326f1d9b6 common.c dbb92cba52db31ff8325a252b3f595c3 idi.c 15687687ef82f099966ed42772001cd3 bri.c c3e3b720c3351b66635bd548195e29e8 pri.c diff -u --recursive --new-file v2.4.0-test8/linux/drivers/isdn/hisax/hfc_pci.c linux/drivers/isdn/hisax/hfc_pci.c --- v2.4.0-test8/linux/drivers/isdn/hisax/hfc_pci.c Mon Aug 21 07:49:03 2000 +++ linux/drivers/isdn/hisax/hfc_pci.c Tue Sep 19 08:01:34 2000 @@ -1686,6 +1686,7 @@ printk(KERN_WARNING "HFC-PCI: No PCI card found\n"); return (0); } +#ifdef notdef if (((int) cs->hw.hfcpci.pci_io & (PAGE_SIZE - 1))) { printk(KERN_WARNING "HFC-PCI shared mem address will be corrected\n"); pcibios_write_config_word(cs->hw.hfcpci.pci_bus, @@ -1719,6 +1720,7 @@ } dev_hfcpci->resource[1].start = (int) cs->hw.hfcpci.pci_io; } +#endif if (!cs->hw.hfcpci.pci_io) { printk(KERN_WARNING "HFC-PCI: No IO-Mem for PCI card found\n"); return (0); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/macintosh/Makefile linux/drivers/macintosh/Makefile --- v2.4.0-test8/linux/drivers/macintosh/Makefile Sat May 20 12:07:56 2000 +++ linux/drivers/macintosh/Makefile Sun Sep 17 09:48:05 2000 @@ -9,76 +9,67 @@ # parent makes.. # -SUB_DIRS := -MOD_SUB_DIRS := $(SUB_DIRS) +# Subdirs. -O_TARGET := macintosh.o -O_OBJS := -M_OBJS := +SUB_DIRS := +MOD_SUB_DIRS := $(SUB_DIRS) +MOD_IN_SUB_DIRS := $(SUB_DIRS) +ALL_SUB_DIRS := $(SUB_DIRS) -ifeq ($(CONFIG_PMAC_PBOOK),y) - O_OBJS += mediabay.o -else - ifeq ($(CONFIG_MAC_FLOPPY),y) - O_OBJS += mediabay.o - endif -endif +# The target object and module list name. -ifeq ($(CONFIG_MAC_SERIAL),y) - O_OBJS += macserial.o -else - ifeq ($(CONFIG_MAC_SERIAL),m) - M_OBJS += macserial.o - endif -endif +O_TARGET := macintosh.o +M_OBJS := +O_OBJS := +MOD_LIST_NAME := MACINTOSH_MODULES -ifeq ($(CONFIG_NVRAM),y) - O_OBJS += nvram.o -else - ifeq ($(CONFIG_NVRAM),m) - M_OBJS += nvram.o - endif -endif +# Objects that export symbols. -ifdef CONFIG_ADB - OX_OBJS := adb.o -endif +export-objs := adb.o rtc.o mac_hid.o -ifdef CONFIG_ADB_KEYBOARD - O_OBJS += mac_keyb.o -endif +# Object file lists. -ifdef CONFIG_ADB_MACII - O_OBJS += via-macii.o -endif +obj-y := +obj-m := +obj-n := +obj- := -ifdef CONFIG_ADB_MACIISI - O_OBJS += via-maciisi.o -endif +# Each configuration option enables a list of files. -ifdef CONFIG_ADB_CUDA - O_OBJS += via-cuda.o +ifeq ($(CONFIG_PMAC_PBOOK),y) + obj-y += mediabay.o endif -ifdef CONFIG_ADB_IOP - O_OBJS += adb-iop.o -endif +obj-$(CONFIG_MAC_SERIAL) += macserial.o +obj-$(CONFIG_NVRAM) += nvram.o +obj-$(CONFIG_MAC_HID) += mac_hid.o +obj-$(CONFIG_INPUT_ADBHID) += adbhid.o +obj-$(CONFIG_PPC_RTC) += rtc.o -ifdef CONFIG_ADB_PMU - O_OBJS += via-pmu.o -endif +obj-$(CONFIG_ADB_PMU) += via-pmu.o +obj-$(CONFIG_ADB_CUDA) += via-cuda.o -ifdef CONFIG_ADB_PMU68K - O_OBJS += via-pmu68k.o -endif +obj-$(CONFIG_ADB) += adb.o +obj-$(CONFIG_ADB_KEYBOARD) += mac_keyb.o +obj-$(CONFIG_ADB_MACII) += via-macii.o +obj-$(CONFIG_ADB_MACIISI) += via-maciisi.o +obj-$(CONFIG_ADB_IOP) += adb-iop.o +obj-$(CONFIG_ADB_PMU68K) += via-pmu68k.o +obj-$(CONFIG_ADB_MACIO) += macio-adb.o -ifdef CONFIG_ADB_MACIO - O_OBJS += macio-adb.o -endif +# Files that are both resident and modular: remove from modular. + +obj-m := $(filter-out $(obj-y), $(obj-m)) +int-m := $(filter-out $(int-y), $(int-m)) + +# Translate to Rules.make lists. + +O_OBJS := $(sort $(filter-out $(export-objs), $(obj-y))) +OX_OBJS := $(sort $(filter $(export-objs), $(obj-y))) +M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) +MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) + +# The global Rules.make. include $(TOPDIR)/Rules.make -# Integrated in mac_keyb.c -# mackeymap.map is retained for historical reasons -#mackeymap.c: mackeymap.map -# loadkeys --mktable mackeymap.map > mackeymap.c diff -u --recursive --new-file v2.4.0-test8/linux/drivers/macintosh/adb.c linux/drivers/macintosh/adb.c --- v2.4.0-test8/linux/drivers/macintosh/adb.c Wed Jul 12 21:58:42 2000 +++ linux/drivers/macintosh/adb.c Sun Sep 17 09:48:05 2000 @@ -393,6 +393,15 @@ return ids->nids; } +int +adb_unregister(int index) +{ + if (!adb_handler[index].handler) + return -ENODEV; + adb_handler[index].handler = 0; + return 0; +} + void adb_input(unsigned char *buf, int nb, struct pt_regs *regs, int autopoll) { diff -u --recursive --new-file v2.4.0-test8/linux/drivers/macintosh/adbhid.c linux/drivers/macintosh/adbhid.c --- v2.4.0-test8/linux/drivers/macintosh/adbhid.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/macintosh/adbhid.c Sun Sep 17 09:48:05 2000 @@ -0,0 +1,875 @@ +/* + * drivers/input/adbhid.c + * + * ADB HID driver for Power Macintosh computers. + * + * Adapted from drivers/macintosh/mac_keyb.c by Franz Sirl + * (see that file for its authors and contributors). + * + * Copyright (C) 2000 Franz Sirl. + * + * Adapted to ADB changes and support for more devices by + * Benjamin Herrenschmidt. Adapted from code in MkLinux + * and reworked. + * + * Supported devices: + * + * - Standard 1 button mouse + * - All standard Apple Extended protocol (handler ID 4) + * - mouseman and trackman mice & trackballs + * - PowerBook Trackpad (default setup: enable tapping) + * - MicroSpeed mouse & trackball (needs testing) + * - CH Products Trackball Pro (needs testing) + * - Contour Design (Contour Mouse) + * - Hunter digital (NoHandsMouse) + * - Kensignton TurboMouse 5 (needs testing) + * - Mouse Systems A3 mice and trackballs + * - MacAlly 2-buttons mouse (needs testing) + * + * To do: + * + * Improve Kensington support. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#ifdef CONFIG_PMAC_BACKLIGHT +#include +#endif + +MODULE_AUTHOR("Franz Sirl "); + +#define KEYB_KEYREG 0 /* register # for key up/down data */ +#define KEYB_LEDREG 2 /* register # for leds on ADB keyboard */ +#define MOUSE_DATAREG 0 /* reg# for movement/button codes from mouse */ + +static int adb_message_handler(struct notifier_block *, unsigned long, void *); +static struct notifier_block adbhid_adb_notifier = { + notifier_call: adb_message_handler, +}; + +unsigned char adb_to_linux_keycodes[128] = { + 30, 31, 32, 33, 35, 34, 44, 45, 46, 47, 86, 48, 16, 17, 18, 19, + 21, 20, 2, 3, 4, 5, 7, 6, 13, 10, 8, 12, 9, 11, 27, 24, + 22, 26, 23, 25, 28, 38, 36, 40, 37, 39, 43, 51, 53, 49, 50, 52, + 15, 57, 41, 14, 96, 1, 29,125, 42, 58, 56,105,106,108,103, 0, + 0, 83, 0, 55, 0, 78, 0, 69, 0, 0, 0, 98, 96, 0, 74, 0, + 0,117, 82, 79, 80, 81, 75, 76, 77, 71, 0, 72, 73,183,181,124, + 63, 64, 65, 61, 66, 67,191, 87,190, 99, 0, 70, 0, 68,101, 88, + 0,119,110,102,104,111, 62,107, 60,109, 59, 54,100, 97,116,116 +}; + +struct adbhid { + struct input_dev input; + int id; + int default_id; + int original_handler_id; + int current_handler_id; + int mouse_kind; + unsigned char *keycode; + char name[64]; +}; + +static struct adbhid *adbhid[16] = { 0 }; + +static void adbhid_probe(void); + +static void adbhid_input_keycode(int, int, int); +static void leds_done(struct adb_request *); + +static void init_trackpad(int id); +static void init_trackball(int id); +static void init_turbomouse(int id); +static void init_microspeed(int id); +static void init_ms_a3(int id); + +static struct adb_ids keyboard_ids; +static struct adb_ids mouse_ids; +static struct adb_ids buttons_ids; + +/* Kind of keyboard, see Apple technote 1152 */ +#define ADB_KEYBOARD_UNKNOWN 0 +#define ADB_KEYBOARD_ANSI 0x0100 +#define ADB_KEYBOARD_ISO 0x0200 +#define ADB_KEYBOARD_JIS 0x0300 + +/* Kind of mouse */ +#define ADBMOUSE_STANDARD_100 0 /* Standard 100cpi mouse (handler 1) */ +#define ADBMOUSE_STANDARD_200 1 /* Standard 200cpi mouse (handler 2) */ +#define ADBMOUSE_EXTENDED 2 /* Apple Extended mouse (handler 4) */ +#define ADBMOUSE_TRACKBALL 3 /* TrackBall (handler 4) */ +#define ADBMOUSE_TRACKPAD 4 /* Apple's PowerBook trackpad (handler 4) */ +#define ADBMOUSE_TURBOMOUSE5 5 /* Turbomouse 5 (previously req. mousehack) */ +#define ADBMOUSE_MICROSPEED 6 /* Microspeed mouse (&trackball ?), MacPoint */ +#define ADBMOUSE_TRACKBALLPRO 7 /* Trackball Pro (special buttons) */ +#define ADBMOUSE_MS_A3 8 /* Mouse systems A3 trackball (handler 3) */ +#define ADBMOUSE_MACALLY2 9 /* MacAlly 2-button mouse */ + +static void +adbhid_keyboard_input(unsigned char *data, int nb, struct pt_regs *regs, int apoll) +{ + int id = (data[0] >> 4) & 0x0f; + + if (!adbhid[id]) { + printk(KERN_ERR "ADB HID on ID %d not yet registered, packet %#02x, %#02x, %#02x, %#02x\n", + id, data[0], data[1], data[2], data[3]); + return; + } + + /* first check this is from register 0 */ + if (nb != 3 || (data[0] & 3) != KEYB_KEYREG) + return; /* ignore it */ + kbd_pt_regs = regs; + adbhid_input_keycode(id, data[1], 0); + if (!(data[2] == 0xff || (data[2] == 0x7f && data[1] == 0x7f))) + adbhid_input_keycode(id, data[2], 0); +} + +static void +adbhid_input_keycode(int id, int keycode, int repeat) +{ + int up_flag; + + up_flag = (keycode & 0x80); + keycode &= 0x7f; + + switch (keycode) { + case 0x39: /* Generate down/up events for CapsLock everytime. */ + input_report_key(&adbhid[id]->input, KEY_CAPSLOCK, 1); + input_report_key(&adbhid[id]->input, KEY_CAPSLOCK, 0); + return; + case 0x3f: /* ignore Powerbook Fn key */ + return; + } + + if (adbhid[id]->keycode[keycode]) + input_report_key(&adbhid[id]->input, + adbhid[id]->keycode[keycode], !up_flag); + else + printk(KERN_INFO "Unhandled ADB key (scancode %#02x) %s.\n", keycode, + up_flag ? "released" : "pressed"); +} + +static void +adbhid_mouse_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll) +{ + int id = (data[0] >> 4) & 0x0f; + + if (!adbhid[id]) { + printk(KERN_ERR "ADB HID on ID %d not yet registered\n", id); + return; + } + + /* + Handler 1 -- 100cpi original Apple mouse protocol. + Handler 2 -- 200cpi original Apple mouse protocol. + + For Apple's standard one-button mouse protocol the data array will + contain the following values: + + BITS COMMENTS + data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd. + data[1] = bxxx xxxx First button and x-axis motion. + data[2] = byyy yyyy Second button and y-axis motion. + + Handler 4 -- Apple Extended mouse protocol. + + For Apple's 3-button mouse protocol the data array will contain the + following values: + + BITS COMMENTS + data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd. + data[1] = bxxx xxxx Left button and x-axis motion. + data[2] = byyy yyyy Second button and y-axis motion. + data[3] = byyy bxxx Third button and fourth button. Y is additional + high bits of y-axis motion. XY is additional + high bits of x-axis motion. + + MacAlly 2-button mouse protocol. + + For MacAlly 2-button mouse protocol the data array will contain the + following values: + + BITS COMMENTS + data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd. + data[1] = bxxx xxxx Left button and x-axis motion. + data[2] = byyy yyyy Right button and y-axis motion. + data[3] = ???? ???? unknown + data[4] = ???? ???? unknown + + */ + + /* If it's a trackpad, we alias the second button to the first. + NOTE: Apple sends an ADB flush command to the trackpad when + the first (the real) button is released. We could do + this here using async flush requests. + */ + switch (adbhid[id]->mouse_kind) + { + case ADBMOUSE_TRACKPAD: + data[1] = (data[1] & 0x7f) | ((data[1] & data[2]) & 0x80); + data[2] = data[2] | 0x80; + break; + case ADBMOUSE_MICROSPEED: + data[1] = (data[1] & 0x7f) | ((data[3] & 0x01) << 7); + data[2] = (data[2] & 0x7f) | ((data[3] & 0x02) << 6); + data[3] = (data[3] & 0x77) | ((data[3] & 0x04) << 5) + | (data[3] & 0x08); + break; + case ADBMOUSE_TRACKBALLPRO: + data[1] = (data[1] & 0x7f) | (((data[3] & 0x04) << 5) + & ((data[3] & 0x08) << 4)); + data[2] = (data[2] & 0x7f) | ((data[3] & 0x01) << 7); + data[3] = (data[3] & 0x77) | ((data[3] & 0x02) << 6); + break; + case ADBMOUSE_MS_A3: + data[1] = (data[1] & 0x7f) | ((data[3] & 0x01) << 7); + data[2] = (data[2] & 0x7f) | ((data[3] & 0x02) << 6); + data[3] = ((data[3] & 0x04) << 5); + break; + case ADBMOUSE_MACALLY2: + data[3] = (data[2] & 0x80) ? 0x80 : 0x00; + data[2] |= 0x80; /* Right button is mapped as button 3 */ + nb=4; + break; + } + + input_report_key(&adbhid[id]->input, BTN_LEFT, !((data[1] >> 7) & 1)); + input_report_key(&adbhid[id]->input, BTN_MIDDLE, !((data[2] >> 7) & 1)); + + if (nb >= 4) + input_report_key(&adbhid[id]->input, BTN_RIGHT, !((data[3] >> 7) & 1)); + + input_report_rel(&adbhid[id]->input, REL_X, + ((data[2]&0x7f) < 64 ? (data[2]&0x7f) : (data[2]&0x7f)-128 )); + input_report_rel(&adbhid[id]->input, REL_Y, + ((data[1]&0x7f) < 64 ? (data[1]&0x7f) : (data[1]&0x7f)-128 )); +} + +static void +adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll) +{ + int id = (data[0] >> 4) & 0x0f; + + if (!adbhid[id]) { + printk(KERN_ERR "ADB HID on ID %d not yet registered\n", id); + return; + } + + switch (adbhid[id]->original_handler_id) { + default: + case 0x02: /* Adjustable keyboard button device */ + printk(KERN_INFO "Unhandled ADB_MISC event %02x, %02x, %02x, %02x\n", + data[0], data[1], data[2], data[3]); + break; + case 0x1f: /* Powerbook button device */ + { +#ifdef CONFIG_PMAC_BACKLIGHT + int backlight = get_backlight_level(); + + /* + * XXX: Where is the contrast control for the passive? + * -- Cort + */ + + switch (data[1]) { + case 0x8: /* mute */ + break; + + case 0x7: /* contrast decrease */ + break; + + case 0x6: /* contrast increase */ + break; + + case 0xa: /* brightness decrease */ + if (backlight < 0) + break; + if (backlight > BACKLIGHT_OFF) + set_backlight_level(backlight-1); + else + set_backlight_level(BACKLIGHT_OFF); + break; + + case 0x9: /* brightness increase */ + if (backlight < 0) + break; + if (backlight < BACKLIGHT_MAX) + set_backlight_level(backlight+1); + else + set_backlight_level(BACKLIGHT_MAX); + break; + } +#endif /* CONFIG_PMAC_BACKLIGHT */ + } + break; + } +} + +static struct adb_request led_request; +static int leds_pending[16]; +static int pending_devs[16]; +static int pending_led_start=0; +static int pending_led_end=0; + +static void real_leds(unsigned char leds, int device) +{ + if (led_request.complete) { + adb_request(&led_request, leds_done, 0, 3, + ADB_WRITEREG(device, KEYB_LEDREG), 0xff, + ~leds); + } else { + if (!(leds_pending[device] & 0x100)) { + pending_devs[pending_led_end] = device; + pending_led_end++; + pending_led_end = (pending_led_end < 16) ? pending_led_end : 0; + } + leds_pending[device] = leds | 0x100; + } +} + +/* + * Event callback from the input module. Events that change the state of + * the hardware are processed here. + */ +static int adbhid_kbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) +{ + struct adbhid *adbhid = dev->private; + unsigned char leds; + + switch (type) { + case EV_LED: + leds = (test_bit(LED_SCROLLL, dev->led) ? 4 : 0) + | (test_bit(LED_NUML, dev->led) ? 1 : 0) + | (test_bit(LED_CAPSL, dev->led) ? 2 : 0); + real_leds(leds, adbhid->id); + return 0; + } + + return -1; +} + +static void leds_done(struct adb_request *req) +{ + int leds,device; + + if (pending_led_start != pending_led_end) { + device = pending_devs[pending_led_start]; + leds = leds_pending[device] & 0xff; + leds_pending[device] = 0; + pending_led_start++; + pending_led_start = (pending_led_start < 16) ? pending_led_start : 0; + real_leds(leds,device); + } + +} + +static int +adb_message_handler(struct notifier_block *this, unsigned long code, void *x) +{ + unsigned long flags; + + switch (code) { + case ADB_MSG_PRE_RESET: + case ADB_MSG_POWERDOWN: + /* Stop the repeat timer. Autopoll is already off at this point */ + save_flags(flags); + cli(); + { + int i; + for (i = 1; i < 16; i++) { + if (adbhid[i]) + del_timer(&adbhid[i]->input.timer); + } + } + restore_flags(flags); + + /* Stop pending led requests */ + while(!led_request.complete) + adb_poll(); + break; + + case ADB_MSG_POST_RESET: + adbhid_probe(); + break; + } + return NOTIFY_DONE; +} + +static void +adbhid_input_register(int id, int default_id, int original_handler_id, + int current_handler_id, int mouse_kind) +{ + int i; + + if (adbhid[id]) { + printk(KERN_ERR "Trying to reregister ADB HID on ID %d\n", id); + return; + } + + if (!(adbhid[id] = kmalloc(sizeof(struct adbhid), GFP_KERNEL))) + return; + + memset(adbhid[id], 0, sizeof(struct adbhid)); + + adbhid[id]->id = default_id; + adbhid[id]->original_handler_id = original_handler_id; + adbhid[id]->current_handler_id = current_handler_id; + adbhid[id]->mouse_kind = mouse_kind; + adbhid[id]->input.private = adbhid[id]; + adbhid[id]->input.name = adbhid[id]->name; + adbhid[id]->input.idbus = BUS_ADB; + adbhid[id]->input.idvendor = 0x0001; + adbhid[id]->input.idproduct = (id << 12) | (default_id << 8) | original_handler_id; + adbhid[id]->input.idversion = 0x0100; + + switch (default_id) { + case ADB_KEYBOARD: + if (!(adbhid[id]->keycode = kmalloc(sizeof(adb_to_linux_keycodes), GFP_KERNEL))) { + kfree(adbhid[id]); + return; + } + + sprintf(adbhid[id]->name, "ADB keyboard on ID %d:%d.%02x", + id, default_id, original_handler_id); + + memcpy(adbhid[id]->keycode, adb_to_linux_keycodes, sizeof(adb_to_linux_keycodes)); + + printk(KERN_INFO "Detected ADB keyboard, type "); + switch (original_handler_id) { + default: + printk(".\n"); + adbhid[id]->input.idversion = ADB_KEYBOARD_UNKNOWN; + break; + + case 0x01: case 0x02: case 0x03: case 0x06: case 0x08: + case 0x0C: case 0x10: case 0x18: case 0x1B: case 0x1C: + case 0xC0: case 0xC3: case 0xC6: + printk("ANSI.\n"); + adbhid[id]->input.idversion = ADB_KEYBOARD_ANSI; + break; + + case 0x04: case 0x05: case 0x07: case 0x09: case 0x0D: + case 0x11: case 0x14: case 0x19: case 0x1D: case 0xC1: + case 0xC4: case 0xC7: + printk("ISO, swapping keys.\n"); + adbhid[id]->input.idversion = ADB_KEYBOARD_ISO; + i = adbhid[id]->keycode[10]; + adbhid[id]->keycode[10] = adbhid[id]->keycode[50]; + adbhid[id]->keycode[50] = i; + break; + + case 0x12: case 0x15: case 0x16: case 0x17: case 0x1A: + case 0x1E: case 0xC2: case 0xC5: case 0xC8: case 0xC9: + printk("JIS.\n"); + adbhid[id]->input.idversion = ADB_KEYBOARD_JIS; + break; + } + + for (i = 0; i < 128; i++) + if (adbhid[id]->keycode[i]) + set_bit(adbhid[id]->keycode[i], adbhid[id]->input.keybit); + + adbhid[id]->input.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP); + adbhid[id]->input.ledbit[0] = BIT(LED_SCROLLL) | BIT(LED_CAPSL) | BIT(LED_NUML); + adbhid[id]->input.event = adbhid_kbd_event; + adbhid[id]->input.keycodemax = 127; + adbhid[id]->input.keycodesize = 1; + break; + + case ADB_MOUSE: + sprintf(adbhid[id]->name, "ADB mouse on ID %d:%d.%02x", + id, default_id, original_handler_id); + + adbhid[id]->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + adbhid[id]->input.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); + adbhid[id]->input.relbit[0] = BIT(REL_X) | BIT(REL_Y); + break; + + case ADB_MISC: + switch (original_handler_id) { + case 0x02: /* Adjustable keyboard button device */ + sprintf(adbhid[id]->name, "ADB adjustable keyboard buttons on ID %d:%d.%02x", + id, default_id, original_handler_id); + break; + case 0x1f: /* Powerbook button device */ + sprintf(adbhid[id]->name, "ADB Powerbook buttons on ID %d:%d.%02x", + id, default_id, original_handler_id); + break; + } + if (adbhid[id]->name[0]) + break; + /* else fall through */ + + default: + printk(KERN_INFO "Trying to register unknown ADB device to input layer.\n"); + kfree(adbhid[id]); + return; + } + + adbhid[id]->input.keycode = adbhid[id]->keycode; + + input_register_device(&adbhid[id]->input); + + printk(KERN_INFO "input%d: ADB HID on ID %d:%d.%02x\n", + adbhid[id]->input.number, id, default_id, original_handler_id); + + if (default_id == ADB_KEYBOARD) { + /* HACK WARNING!! This should go away as soon there is an utility + * to control that for event devices. + */ + adbhid[id]->input.rep[REP_DELAY] = HZ/2; /* input layer default: HZ/4 */ + adbhid[id]->input.rep[REP_PERIOD] = HZ/15; /* input layer default: HZ/33 */ + } +} + +static void adbhid_input_unregister(int id) +{ + input_unregister_device(&adbhid[id]->input); + if (adbhid[id]->keycode) + kfree(adbhid[id]->keycode); + kfree(adbhid[id]); + adbhid[id] = 0; +} + + +static void +adbhid_probe(void) +{ + struct adb_request req; + int i, default_id, org_handler_id, cur_handler_id; + + for (i = 1; i < 16; i++) { + if (adbhid[i]) + adbhid_input_unregister(i); + } + + adb_register(ADB_MOUSE, 0, &mouse_ids, adbhid_mouse_input); + adb_register(ADB_KEYBOARD, 0, &keyboard_ids, adbhid_keyboard_input); + adb_register(ADB_MISC, 0, &buttons_ids, adbhid_buttons_input); + + for (i = 0; i < keyboard_ids.nids; i++) { + int id = keyboard_ids.id[i]; + + adb_get_infos(id, &default_id, &org_handler_id); + + /* turn off all leds */ + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id, KEYB_LEDREG), 0xff, 0xff); + + /* Enable full feature set of the keyboard + ->get it to send separate codes for left and right shift, + control, option keys */ +#if 0 /* handler 5 doesn't send separate codes for R modifiers */ + if (adb_try_handler_change(id, 5)) + printk("ADB keyboard at %d, handler set to 5\n", id); + else +#endif + if (adb_try_handler_change(id, 3)) + printk("ADB keyboard at %d, handler set to 3\n", id); + else + printk("ADB keyboard at %d, handler 1\n", id); + + adb_get_infos(id, &default_id, &cur_handler_id); + adbhid_input_register(id, default_id, org_handler_id, cur_handler_id, 0); + } + + for (i = 0; i < buttons_ids.nids; i++) { + int id = buttons_ids.id[i]; + + adb_get_infos(id, &default_id, &org_handler_id); + adbhid_input_register(id, default_id, org_handler_id, org_handler_id, 0); + } + + /* Try to switch all mice to handler 4, or 2 for three-button + mode and full resolution. */ + for (i = 0; i < mouse_ids.nids; i++) { + int id = mouse_ids.id[i]; + int mouse_kind; + + adb_get_infos(id, &default_id, &org_handler_id); + + if (adb_try_handler_change(id, 4)) { + printk("ADB mouse at %d, handler set to 4", id); + mouse_kind = ADBMOUSE_EXTENDED; + } + else if (adb_try_handler_change(id, 0x2F)) { + printk("ADB mouse at %d, handler set to 0x2F", id); + mouse_kind = ADBMOUSE_MICROSPEED; + } + else if (adb_try_handler_change(id, 0x42)) { + printk("ADB mouse at %d, handler set to 0x42", id); + mouse_kind = ADBMOUSE_TRACKBALLPRO; + } + else if (adb_try_handler_change(id, 0x66)) { + printk("ADB mouse at %d, handler set to 0x66", id); + mouse_kind = ADBMOUSE_MICROSPEED; + } + else if (adb_try_handler_change(id, 0x5F)) { + printk("ADB mouse at %d, handler set to 0x5F", id); + mouse_kind = ADBMOUSE_MICROSPEED; + } + else if (adb_try_handler_change(id, 3)) { + printk("ADB mouse at %d, handler set to 3", id); + mouse_kind = ADBMOUSE_MS_A3; + } + else if (adb_try_handler_change(id, 2)) { + printk("ADB mouse at %d, handler set to 2", id); + mouse_kind = ADBMOUSE_STANDARD_200; + } + else { + printk("ADB mouse at %d, handler 1", id); + mouse_kind = ADBMOUSE_STANDARD_100; + } + + if ((mouse_kind == ADBMOUSE_TRACKBALLPRO) + || (mouse_kind == ADBMOUSE_MICROSPEED)) { + init_microspeed(id); + } else if (mouse_kind == ADBMOUSE_MS_A3) { + init_ms_a3(id); + } else if (mouse_kind == ADBMOUSE_EXTENDED) { + /* + * Register 1 is usually used for device + * identification. Here, we try to identify + * a known device and call the appropriate + * init function. + */ + adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1, + ADB_READREG(id, 1)); + + if ((req.reply_len) && + (req.reply[1] == 0x9a) && ((req.reply[2] == 0x21) + || (req.reply[2] == 0x20))) { + mouse_kind = ADBMOUSE_TRACKBALL; + init_trackball(id); + } + else if ((req.reply_len >= 4) && + (req.reply[1] == 0x74) && (req.reply[2] == 0x70) && + (req.reply[3] == 0x61) && (req.reply[4] == 0x64)) { + mouse_kind = ADBMOUSE_TRACKPAD; + init_trackpad(id); + } + else if ((req.reply_len >= 4) && + (req.reply[1] == 0x4b) && (req.reply[2] == 0x4d) && + (req.reply[3] == 0x4c) && (req.reply[4] == 0x31)) { + mouse_kind = ADBMOUSE_TURBOMOUSE5; + init_turbomouse(id); + } + else if ((req.reply_len == 9) && + (req.reply[1] == 0x4b) && (req.reply[2] == 0x4f) && + (req.reply[3] == 0x49) && (req.reply[4] == 0x54)) { + if (adb_try_handler_change(id, 0x42)) { + printk("\nADB MacAlly 2-button mouse at %d, handler set to 0x42", id); + mouse_kind = ADBMOUSE_MACALLY2; + } + } + } + printk("\n"); + + adb_get_infos(id, &default_id, &cur_handler_id); + adbhid_input_register(id, default_id, org_handler_id, + cur_handler_id, mouse_kind); + } +} + +static void +init_trackpad(int id) +{ + struct adb_request req; + unsigned char r1_buffer[8]; + + printk(" (trackpad)"); + + adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1, + ADB_READREG(id,1)); + if (req.reply_len < 8) + printk("bad length for reg. 1\n"); + else + { + memcpy(r1_buffer, &req.reply[1], 8); + adb_request(&req, NULL, ADBREQ_SYNC, 9, + ADB_WRITEREG(id,1), + r1_buffer[0], + r1_buffer[1], + r1_buffer[2], + r1_buffer[3], + r1_buffer[4], + r1_buffer[5], + 0x0d, /*r1_buffer[6],*/ + r1_buffer[7]); + + adb_request(&req, NULL, ADBREQ_SYNC, 9, + ADB_WRITEREG(id,2), + 0x99, + 0x94, + 0x19, + 0xff, + 0xb2, + 0x8a, + 0x1b, + 0x50); + + adb_request(&req, NULL, ADBREQ_SYNC, 9, + ADB_WRITEREG(id,1), + r1_buffer[0], + r1_buffer[1], + r1_buffer[2], + r1_buffer[3], + r1_buffer[4], + r1_buffer[5], + 0x03, /*r1_buffer[6],*/ + r1_buffer[7]); + } +} + +static void +init_trackball(int id) +{ + struct adb_request req; + + printk(" (trackman/mouseman)"); + + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id,1), 00,0x81); + + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id,1), 01,0x81); + + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id,1), 02,0x81); + + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id,1), 03,0x38); + + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id,1), 00,0x81); + + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id,1), 01,0x81); + + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id,1), 02,0x81); + + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id,1), 03,0x38); +} + +static void +init_turbomouse(int id) +{ + struct adb_request req; + + printk(" (TurboMouse 5)"); + + adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id)); + + adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(3)); + + adb_request(&req, NULL, ADBREQ_SYNC, 9, + ADB_WRITEREG(3,2), + 0xe7, + 0x8c, + 0, + 0, + 0, + 0xff, + 0xff, + 0x94); + + adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(3)); + + adb_request(&req, NULL, ADBREQ_SYNC, 9, + ADB_WRITEREG(3,2), + 0xa5, + 0x14, + 0, + 0, + 0x69, + 0xff, + 0xff, + 0x27); +} + +static void +init_microspeed(int id) +{ + struct adb_request req; + + printk(" (Microspeed/MacPoint or compatible)"); + + adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id)); + + /* This will initialize mice using the Microspeed, MacPoint and + other compatible firmware. Bit 12 enables extended protocol. + + Register 1 Listen (4 Bytes) + 0 - 3 Button is mouse (set also for double clicking!!!) + 4 - 7 Button is locking (affects change speed also) + 8 - 11 Button changes speed + 12 1 = Extended mouse mode, 0 = normal mouse mode + 13 - 15 unused 0 + 16 - 23 normal speed + 24 - 31 changed speed + + Register 1 talk holds version and product identification information. + Register 1 Talk (4 Bytes): + 0 - 7 Product code + 8 - 23 undefined, reserved + 24 - 31 Version number + + Speed 0 is max. 1 to 255 set speed in increments of 1/256 of max. + */ + adb_request(&req, NULL, ADBREQ_SYNC, 5, + ADB_WRITEREG(id,1), + 0x20, /* alt speed = 0x20 (rather slow) */ + 0x00, /* norm speed = 0x00 (fastest) */ + 0x10, /* extended protocol, no speed change */ + 0x07); /* all buttons enabled as mouse buttons, no locking */ + + + adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id)); +} + +static void +init_ms_a3(int id) +{ + struct adb_request req; + + printk(" (Mouse Systems A3 Mouse, or compatible)"); + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id, 0x2), + 0x00, + 0x07); + + adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id)); +} + +static int __init adbhid_init(void) +{ + if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) ) + return 0; + + led_request.complete = 1; + + adbhid_probe(); + + notifier_chain_register(&adb_client_list, &adbhid_adb_notifier); + + return 0; +} + +static void __exit adbhid_exit(void) +{ +} + +module_init(adbhid_init); +module_exit(adbhid_exit); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/macintosh/mac_hid.c linux/drivers/macintosh/mac_hid.c --- v2.4.0-test8/linux/drivers/macintosh/mac_hid.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/macintosh/mac_hid.c Sun Sep 17 09:48:05 2000 @@ -0,0 +1,492 @@ +/* + * drivers/macintosh/mac_hid.c + * + * HID support stuff for Macintosh computers. + * + * Copyright (C) 2000 Franz Sirl. + * + * Stuff inside CONFIG_MAC_ADBKEYCODES should go away during 2.5 when all + * major distributions are using the Linux keycodes. + * Stuff inside CONFIG_MAC_EMUMOUSEBTN should really be moved to userspace. + */ + +#include +#include +#include +#include +#include + +#ifdef CONFIG_MAC_ADBKEYCODES +#include +#include +#include +#endif + +#ifdef CONFIG_MAC_ADBKEYCODES +/* Simple translation table for the SysRq keys */ + +#ifdef CONFIG_MAGIC_SYSRQ +unsigned char mac_hid_kbd_sysrq_xlate[128] = + "asdfhgzxcv\000bqwer" /* 0x00 - 0x0f */ + "yt123465=97-80o]" /* 0x10 - 0x1f */ + "u[ip\rlj'k;\\,/nm." /* 0x20 - 0x2f */ + "\t `\177\000\033\000\000\000\000\000\000\000\000\000\000" + /* 0x30 - 0x3f */ + "\000\000\000*\000+\000\000\000\000\000/\r\000-\000" + /* 0x40 - 0x4f */ + "\000\0000123456789\000\000\000" /* 0x50 - 0x5f */ + "\205\206\207\203\210\211\000\213\000\215\000\000\000\000\000\212\000\214"; + /* 0x60 - 0x6f */ +extern unsigned char pckbd_sysrq_xlate[128]; +#endif + +static u_short macplain_map[NR_KEYS] = { + 0xfb61, 0xfb73, 0xfb64, 0xfb66, 0xfb68, 0xfb67, 0xfb7a, 0xfb78, + 0xfb63, 0xfb76, 0xf200, 0xfb62, 0xfb71, 0xfb77, 0xfb65, 0xfb72, + 0xfb79, 0xfb74, 0xf031, 0xf032, 0xf033, 0xf034, 0xf036, 0xf035, + 0xf03d, 0xf039, 0xf037, 0xf02d, 0xf038, 0xf030, 0xf05d, 0xfb6f, + 0xfb75, 0xf05b, 0xfb69, 0xfb70, 0xf201, 0xfb6c, 0xfb6a, 0xf027, + 0xfb6b, 0xf03b, 0xf05c, 0xf02c, 0xf02f, 0xfb6e, 0xfb6d, 0xf02e, + 0xf009, 0xf020, 0xf060, 0xf07f, 0xf200, 0xf01b, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, + 0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, + 0xf104, 0xf105, 0xf106, 0xf102, 0xf107, 0xf108, 0xf200, 0xf10a, + 0xf200, 0xf10c, 0xf200, 0xf209, 0xf200, 0xf109, 0xf200, 0xf10b, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf103, 0xf117, + 0xf101, 0xf119, 0xf100, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200, +}; + +static u_short macshift_map[NR_KEYS] = { + 0xfb41, 0xfb53, 0xfb44, 0xfb46, 0xfb48, 0xfb47, 0xfb5a, 0xfb58, + 0xfb43, 0xfb56, 0xf200, 0xfb42, 0xfb51, 0xfb57, 0xfb45, 0xfb52, + 0xfb59, 0xfb54, 0xf021, 0xf040, 0xf023, 0xf024, 0xf05e, 0xf025, + 0xf02b, 0xf028, 0xf026, 0xf05f, 0xf02a, 0xf029, 0xf07d, 0xfb4f, + 0xfb55, 0xf07b, 0xfb49, 0xfb50, 0xf201, 0xfb4c, 0xfb4a, 0xf022, + 0xfb4b, 0xf03a, 0xf07c, 0xf03c, 0xf03f, 0xfb4e, 0xfb4d, 0xf03e, + 0xf009, 0xf020, 0xf07e, 0xf07f, 0xf200, 0xf01b, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, + 0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, + 0xf10e, 0xf10f, 0xf110, 0xf10c, 0xf111, 0xf112, 0xf200, 0xf10a, + 0xf200, 0xf10c, 0xf200, 0xf203, 0xf200, 0xf113, 0xf200, 0xf10b, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf20b, 0xf116, 0xf10d, 0xf117, + 0xf10b, 0xf20a, 0xf10a, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200, +}; + +static u_short macaltgr_map[NR_KEYS] = { + 0xf914, 0xfb73, 0xf917, 0xf919, 0xfb68, 0xfb67, 0xfb7a, 0xfb78, + 0xf916, 0xfb76, 0xf200, 0xf915, 0xfb71, 0xfb77, 0xf918, 0xfb72, + 0xfb79, 0xfb74, 0xf200, 0xf040, 0xf200, 0xf024, 0xf200, 0xf200, + 0xf200, 0xf05d, 0xf07b, 0xf05c, 0xf05b, 0xf07d, 0xf07e, 0xfb6f, + 0xfb75, 0xf200, 0xfb69, 0xfb70, 0xf201, 0xfb6c, 0xfb6a, 0xf200, + 0xfb6b, 0xf200, 0xf200, 0xf200, 0xf200, 0xfb6e, 0xfb6d, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf90a, 0xf90b, 0xf90c, 0xf90d, 0xf90e, 0xf90f, + 0xf910, 0xf911, 0xf200, 0xf912, 0xf913, 0xf200, 0xf200, 0xf200, + 0xf510, 0xf511, 0xf512, 0xf50e, 0xf513, 0xf514, 0xf200, 0xf516, + 0xf200, 0xf10c, 0xf200, 0xf202, 0xf200, 0xf515, 0xf200, 0xf517, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf50f, 0xf117, + 0xf50d, 0xf119, 0xf50c, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200, +}; + +static u_short macctrl_map[NR_KEYS] = { + 0xf001, 0xf013, 0xf004, 0xf006, 0xf008, 0xf007, 0xf01a, 0xf018, + 0xf003, 0xf016, 0xf200, 0xf002, 0xf011, 0xf017, 0xf005, 0xf012, + 0xf019, 0xf014, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01e, 0xf01d, + 0xf200, 0xf200, 0xf01f, 0xf01f, 0xf07f, 0xf200, 0xf01d, 0xf00f, + 0xf015, 0xf01b, 0xf009, 0xf010, 0xf201, 0xf00c, 0xf00a, 0xf007, + 0xf00b, 0xf200, 0xf01c, 0xf200, 0xf07f, 0xf00e, 0xf00d, 0xf20e, + 0xf200, 0xf000, 0xf000, 0xf008, 0xf200, 0xf200, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, + 0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, + 0xf104, 0xf105, 0xf106, 0xf102, 0xf107, 0xf108, 0xf200, 0xf10a, + 0xf200, 0xf10c, 0xf200, 0xf204, 0xf200, 0xf109, 0xf200, 0xf10b, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf103, 0xf117, + 0xf101, 0xf119, 0xf100, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200, +}; + +static u_short macshift_ctrl_map[NR_KEYS] = { + 0xf001, 0xf013, 0xf004, 0xf006, 0xf008, 0xf007, 0xf01a, 0xf018, + 0xf003, 0xf016, 0xf200, 0xf002, 0xf011, 0xf017, 0xf005, 0xf012, + 0xf019, 0xf014, 0xf200, 0xf000, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf200, 0xf200, 0xf00f, + 0xf015, 0xf200, 0xf009, 0xf010, 0xf201, 0xf00c, 0xf00a, 0xf200, + 0xf00b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf00e, 0xf00d, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, + 0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf10c, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf200, 0xf117, + 0xf200, 0xf119, 0xf200, 0xf700, 0xf701, 0xf702, 0xf200, 0xf20c, +}; + +static u_short macalt_map[NR_KEYS] = { + 0xf861, 0xf873, 0xf864, 0xf866, 0xf868, 0xf867, 0xf87a, 0xf878, + 0xf863, 0xf876, 0xf200, 0xf862, 0xf871, 0xf877, 0xf865, 0xf872, + 0xf879, 0xf874, 0xf831, 0xf832, 0xf833, 0xf834, 0xf836, 0xf835, + 0xf83d, 0xf839, 0xf837, 0xf82d, 0xf838, 0xf830, 0xf85d, 0xf86f, + 0xf875, 0xf85b, 0xf869, 0xf870, 0xf80d, 0xf86c, 0xf86a, 0xf827, + 0xf86b, 0xf83b, 0xf85c, 0xf82c, 0xf82f, 0xf86e, 0xf86d, 0xf82e, + 0xf809, 0xf820, 0xf860, 0xf87f, 0xf200, 0xf81b, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf210, 0xf211, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf900, 0xf901, 0xf902, 0xf903, 0xf904, 0xf905, + 0xf906, 0xf907, 0xf200, 0xf908, 0xf909, 0xf200, 0xf200, 0xf200, + 0xf504, 0xf505, 0xf506, 0xf502, 0xf507, 0xf508, 0xf200, 0xf50a, + 0xf200, 0xf10c, 0xf200, 0xf209, 0xf200, 0xf509, 0xf200, 0xf50b, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf503, 0xf117, + 0xf501, 0xf119, 0xf500, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200, +}; + +static u_short macctrl_alt_map[NR_KEYS] = { + 0xf801, 0xf813, 0xf804, 0xf806, 0xf808, 0xf807, 0xf81a, 0xf818, + 0xf803, 0xf816, 0xf200, 0xf802, 0xf811, 0xf817, 0xf805, 0xf812, + 0xf819, 0xf814, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf80f, + 0xf815, 0xf200, 0xf809, 0xf810, 0xf201, 0xf80c, 0xf80a, 0xf200, + 0xf80b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf80e, 0xf80d, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, + 0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, + 0xf504, 0xf505, 0xf506, 0xf502, 0xf507, 0xf508, 0xf200, 0xf50a, + 0xf200, 0xf10c, 0xf200, 0xf200, 0xf200, 0xf509, 0xf200, 0xf50b, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf503, 0xf117, + 0xf501, 0xf119, 0xf500, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200, +}; + +static unsigned short *mac_key_maps_save[MAX_NR_KEYMAPS] = { + macplain_map, macshift_map, macaltgr_map, 0, + macctrl_map, macshift_ctrl_map, 0, 0, + macalt_map, 0, 0, 0, + macctrl_alt_map, 0 +}; + +static unsigned short *pc_key_maps_save[MAX_NR_KEYMAPS]; + +int mac_hid_kbd_translate(unsigned char keycode, unsigned char *keycodep, + char raw_mode); +static int mac_hid_sysctl_keycodes(ctl_table *ctl, int write, struct file * filp, + void *buffer, size_t *lenp); +char mac_hid_kbd_unexpected_up(unsigned char keycode); + +static int keyboard_lock_keycodes = 0; +int keyboard_sends_linux_keycodes = 0; +#else +int keyboard_sends_linux_keycodes = 1; +#endif + + +static unsigned char e0_keys[128] = { + 0, 0, 0, KEY_KPCOMMA, 0, KEY_INTL3, 0, 0, /* 0x00-0x07 */ + 0, 0, 0, 0, KEY_LANG1, KEY_LANG2, 0, 0, /* 0x08-0x0f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10-0x17 */ + 0, 0, 0, 0, KEY_KPENTER, KEY_RIGHTCTRL, 0, 0, /* 0x18-0x1f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20-0x27 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x28-0x2f */ + 0, 0, 0, 0, 0, KEY_KPSLASH, 0, KEY_SYSRQ, /* 0x30-0x37 */ + KEY_RIGHTALT, 0, 0, 0, 0, 0, 0, 0, /* 0x38-0x3f */ + 0, 0, 0, 0, 0, 0, 0, KEY_HOME, /* 0x40-0x47 */ + KEY_UP, KEY_PAGEUP, 0, KEY_LEFT, 0, KEY_RIGHT, 0, KEY_END, /* 0x48-0x4f */ + KEY_DOWN, KEY_PAGEDOWN, KEY_INSERT, KEY_DELETE, 0, 0, 0, 0, /* 0x50-0x57 */ + 0, 0, 0, KEY_LEFTMETA, KEY_RIGHTMETA, KEY_COMPOSE, 0, 0, /* 0x58-0x5f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */ + 0, 0, 0, 0, 0, 0, 0, KEY_MACRO, /* 0x68-0x6f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x77 */ + 0, 0, 0, 0, 0, 0, 0, 0 /* 0x78-0x7f */ +}; + +#ifdef CONFIG_MAC_EMUMOUSEBTN +static struct input_dev emumousebtn; +static void emumousebtn_input_register(void); +static int mouse_emulate_buttons = 0; +static int mouse_button2_keycode = KEY_RIGHTCTRL; /* right control key */ +static int mouse_button3_keycode = KEY_RIGHTALT; /* right option key */ +static int mouse_last_keycode = 0; +#endif + +extern void pckbd_init_hw(void); + +#if defined CONFIG_SYSCTL && (defined(CONFIG_MAC_ADBKEYCODES) || defined(CONFIG_MAC_EMUMOUSEBTN)) +/* file(s) in /proc/sys/dev/mac_hid */ +ctl_table mac_hid_files[] = +{ +#ifdef CONFIG_MAC_ADBKEYCODES + { + DEV_MAC_HID_KEYBOARD_SENDS_LINUX_KEYCODES, + "keyboard_sends_linux_keycodes", &keyboard_sends_linux_keycodes, sizeof(int), + 0644, NULL, &mac_hid_sysctl_keycodes + }, + { + DEV_MAC_HID_KEYBOARD_LOCK_KEYCODES, + "keyboard_lock_keycodes", &keyboard_lock_keycodes, sizeof(int), + 0644, NULL, &proc_dointvec + }, +#endif +#ifdef CONFIG_MAC_EMUMOUSEBTN + { + DEV_MAC_HID_MOUSE_BUTTON_EMULATION, + "mouse_button_emulation", &mouse_emulate_buttons, sizeof(int), + 0644, NULL, &proc_dointvec + }, + { + DEV_MAC_HID_MOUSE_BUTTON2_KEYCODE, + "mouse_button2_keycode", &mouse_button2_keycode, sizeof(int), + 0644, NULL, &proc_dointvec + }, + { + DEV_MAC_HID_MOUSE_BUTTON3_KEYCODE, + "mouse_button3_keycode", &mouse_button3_keycode, sizeof(int), + 0644, NULL, &proc_dointvec + }, +#endif + { 0 } +}; + +/* dir in /proc/sys/dev */ +ctl_table mac_hid_dir[] = +{ + { DEV_MAC_HID, "mac_hid", NULL, 0, 0555, mac_hid_files }, + { 0 } +}; + +/* /proc/sys/dev itself, in case that is not there yet */ +ctl_table mac_hid_root_dir[] = +{ + { CTL_DEV, "dev", NULL, 0, 0555, mac_hid_dir }, + { 0 } +}; + +static struct ctl_table_header *mac_hid_sysctl_header; + +#ifdef CONFIG_MAC_ADBKEYCODES +static +int mac_hid_sysctl_keycodes(ctl_table *ctl, int write, struct file * filp, + void *buffer, size_t *lenp) +{ + int val = keyboard_sends_linux_keycodes; + int ret = 0; + + if (!write + || (write && !keyboard_lock_keycodes)) + ret = proc_dointvec(ctl, write, filp, buffer, lenp); + + if (write + && keyboard_sends_linux_keycodes != val) { + if (!keyboard_sends_linux_keycodes) { +#ifdef CONFIG_MAGIC_SYSRQ + ppc_md.ppc_kbd_sysrq_xlate = mac_hid_kbd_sysrq_xlate; + SYSRQ_KEY = 0x69; +#endif + memcpy(pc_key_maps_save, key_maps, sizeof(key_maps)); + memcpy(key_maps, mac_key_maps_save, sizeof(key_maps)); + } else { +#ifdef CONFIG_MAGIC_SYSRQ + ppc_md.ppc_kbd_sysrq_xlate = pckbd_sysrq_xlate; + SYSRQ_KEY = 0x54; +#endif + memcpy(mac_key_maps_save, key_maps, sizeof(key_maps)); + memcpy(key_maps, pc_key_maps_save, sizeof(key_maps)); + } + } + + return ret; +} +#endif +#endif /* endif CONFIG_SYSCTL */ + +int mac_hid_kbd_translate(unsigned char scancode, unsigned char *keycode, + char raw_mode) +{ +#ifdef CONFIG_MAC_ADBKEYCODES + if (!keyboard_sends_linux_keycodes) { + if (!raw_mode) { + /* + * Convert R-shift/control/option to L version. + */ + switch (scancode) { + case 0x7b: scancode = 0x38; break; /* R-shift */ + case 0x7c: scancode = 0x3a; break; /* R-option */ + case 0x7d: scancode = 0x36; break; /* R-control */ + } + } + *keycode = scancode; + return 1; + } else +#endif + { + /* This code was copied from char/pc_keyb.c and will be + * superflous when the input layer is fully integrated. + * We don't need the high_keys handling, so this part + * has been removed. + */ + static int prev_scancode = 0; + + /* special prefix scancodes.. */ + if (scancode == 0xe0 || scancode == 0xe1) { + prev_scancode = scancode; + return 0; + } + + scancode &= 0x7f; + + if (prev_scancode) { + if (prev_scancode != 0xe0) { + if (prev_scancode == 0xe1 && scancode == 0x1d) { + prev_scancode = 0x100; + return 0; + } else if (prev_scancode == 0x100 && scancode == 0x45) { + *keycode = KEY_PAUSE; + prev_scancode = 0; + } else { + if (!raw_mode) + printk(KERN_INFO "keyboard: unknown e1 escape sequence\n"); + prev_scancode = 0; + return 0; + } + } else { + prev_scancode = 0; + if (scancode == 0x2a || scancode == 0x36) + return 0; + } + if (e0_keys[scancode]) + *keycode = e0_keys[scancode]; + else { + if (!raw_mode) + printk(KERN_INFO "keyboard: unknown scancode e0 %02x\n", + scancode); + return 0; + } + } else { + switch (scancode) { + case 91: scancode = KEY_LINEFEED; break; + case 92: scancode = KEY_KPEQUAL; break; + case 125: scancode = KEY_INTL1; break; + } + *keycode = scancode; + } + return 1; + } +} + +char mac_hid_kbd_unexpected_up(unsigned char keycode) +{ + if (keyboard_sends_linux_keycodes && keycode == KEY_F13) + return 0; + else + return 0x80; +} + +#ifdef CONFIG_MAC_ADBKEYCODES +int mac_hid_keyboard_sends_linux_keycodes(void) +{ + return keyboard_sends_linux_keycodes; +} + +static int __init mac_hid_setup(char *str) +{ + int ints[2]; + + str = get_options(str, ARRAY_SIZE(ints), ints); + if (ints[0] == 1) { + keyboard_sends_linux_keycodes = ints[1] != 0; + keyboard_lock_keycodes = 1; + } + return 1; +} + +__setup("keyboard_sends_linux_keycodes=", mac_hid_setup); + +#endif + +#ifdef CONFIG_MAC_EMUMOUSEBTN +int mac_hid_mouse_emulate_buttons(int caller, unsigned int keycode, int down) +{ + switch (caller) { + case 1: + /* Called from keybdev.c */ + if (mouse_emulate_buttons + && (keycode == mouse_button2_keycode + || keycode == mouse_button3_keycode)) { + if (mouse_emulate_buttons == 1) { + input_report_key(&emumousebtn, + keycode == mouse_button2_keycode ? BTN_MIDDLE : BTN_RIGHT, + down); + return 1; + } + mouse_last_keycode = down ? keycode : 0; + } + break; + case 2: + /* Called from mousedev.c */ + if (mouse_emulate_buttons == 2 && keycode == 0) { + if (mouse_last_keycode == mouse_button2_keycode) + return 1; /* map to middle button */ + if (mouse_last_keycode == mouse_button3_keycode) + return 2; /* map to right button */ + } + return keycode; /* keep button */ + } + return 0; +} + +static void emumousebtn_input_register(void) +{ + emumousebtn.name = "Macintosh mouse button emulation"; + + emumousebtn.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + emumousebtn.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); + emumousebtn.relbit[0] = BIT(REL_X) | BIT(REL_Y); + + emumousebtn.idbus = BUS_ADB; + emumousebtn.idvendor = 0x0001; + emumousebtn.idproduct = 0x0001; + emumousebtn.idversion = 0x0100; + + input_register_device(&emumousebtn); + + printk(KERN_INFO "input%d: Macintosh mouse button emulation\n", emumousebtn.number); +} +#endif + +void __init mac_hid_init_hw(void) +{ + +#ifdef CONFIG_MAC_ADBKEYCODES + memcpy(pc_key_maps_save, key_maps, sizeof(key_maps)); + + if (!keyboard_sends_linux_keycodes) + memcpy(key_maps, mac_key_maps_save, sizeof(key_maps)); +#endif + +#ifdef CONFIG_MAC_EMUMOUSEBTN + emumousebtn_input_register(); +#endif + +#if CONFIG_PPC + if (_machine != _MACH_Pmac) + pckbd_init_hw(); +#endif + +#if defined(CONFIG_SYSCTL) && (defined(CONFIG_MAC_ADBKEYCODES) || defined(CONFIG_MAC_EMUMOUSEBTN)) + mac_hid_sysctl_header = register_sysctl_table(mac_hid_root_dir, 1); +#endif /* CONFIG_SYSCTL */ +} diff -u --recursive --new-file v2.4.0-test8/linux/drivers/macintosh/mac_keyb.c linux/drivers/macintosh/mac_keyb.c --- v2.4.0-test8/linux/drivers/macintosh/mac_keyb.c Tue Jun 20 13:58:42 2000 +++ linux/drivers/macintosh/mac_keyb.c Sun Sep 17 09:48:05 2000 @@ -51,6 +51,10 @@ #include #include +#ifdef CONFIG_PMAC_BACKLIGHT +#include +#endif + #define KEYB_KEYREG 0 /* register # for key up/down data */ #define KEYB_LEDREG 2 /* register # for leds on ADB keyboard */ #define MOUSE_DATAREG 0 /* reg# for movement/button codes from mouse */ @@ -585,68 +589,50 @@ } #endif /* CONFIG_ADBMOUSE */ -/* XXX Needs to get rid of this, see comments in pmu.c */ -extern int backlight_level; - static void buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll) { -#ifdef CONFIG_ADB_PMU +#ifdef CONFIG_PMAC_BACKLIGHT + int backlight = get_backlight_level(); + /* * XXX: Where is the contrast control for the passive? * -- Cort */ /* Ignore data from register other than 0 */ -#if 0 - if ((adb_hardware != ADB_VIAPMU) || (data[0] & 0x3) || (nb < 2)) -#else if ((data[0] & 0x3) || (nb < 2)) -#endif return; - switch (data[1]&0xf ) - { - /* mute */ - case 0x8: - /* down event */ - if ( data[1] == (data[1]&0xf) ) { - } - break; - /* contrast decrease */ - case 0x7: - /* down event */ - if ( data[1] == (data[1]&0xf) ) { - } - break; - /* contrast increase */ - case 0x6: - /* down event */ - if ( data[1] == (data[1]&0xf) ) { - } - break; - /* brightness decrease */ - case 0xa: - /* down event */ - if ( data[1] == (data[1]&0xf) ) { - if (backlight_level > 2) - pmu_set_brightness(backlight_level-2); - else - pmu_set_brightness(0); - } + switch (data[1]) { + case 0x8: /* mute */ + break; + + case 0x7: /* contrast decrease */ + break; + + case 0x6: /* contrast increase */ + break; + + case 0xa: /* brightness decrease */ + if (backlight < 0) break; - /* brightness increase */ - case 0x9: - /* down event */ - if ( data[1] == (data[1]&0xf) ) { - if (backlight_level < 0x1e) - pmu_set_brightness(backlight_level+2); - else - pmu_set_brightness(0x1f); - } + if (backlight > BACKLIGHT_OFF) + set_backlight_level(backlight-1); + else + set_backlight_level(BACKLIGHT_OFF); + break; + + case 0x9: /* brightness increase */ + if (backlight < 0) break; + if (backlight < BACKLIGHT_MAX) + set_backlight_level(backlight+1); + else + set_backlight_level(BACKLIGHT_MAX); + break; } -#endif /* CONFIG_ADB_PMU */ +#endif /* CONFIG_PMAC_BACKLIGHT */ } /* Map led flags as defined in kbd_kern.h to bits for Apple keyboard. */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/macintosh/macio-adb.c linux/drivers/macintosh/macio-adb.c --- v2.4.0-test8/linux/drivers/macintosh/macio-adb.c Thu Oct 7 10:17:09 1999 +++ linux/drivers/macintosh/macio-adb.c Sun Sep 17 09:48:05 2000 @@ -122,6 +122,8 @@ out_8(&adb->autopoll.r, APE); out_8(&adb->intr_enb.r, DFB | TAG); + printk("adb: mac-io driver 1.0 for unified ADB\n"); + return 0; } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/macintosh/macserial.c linux/drivers/macintosh/macserial.c --- v2.4.0-test8/linux/drivers/macintosh/macserial.c Sat May 20 12:07:56 2000 +++ linux/drivers/macintosh/macserial.c Sun Sep 17 09:48:05 2000 @@ -2291,7 +2291,7 @@ zss->irq = ch->intrs[0].line; zss->has_dma = 0; #if !defined(CONFIG_KGDB) && defined(SUPPORT_SERIAL_DMA) - if (ch->n_addrs == 3 && ch->n_intrs == 3) + if (ch->n_addrs >= 3 && ch->n_intrs == 3) zss->has_dma = 1; #endif zss->dma_initted = 0; @@ -2643,9 +2643,6 @@ * ------------------------------------------------------------ */ #ifdef CONFIG_SERIAL_CONSOLE -#ifdef CONFIG_SERIAL -#error Cannot build serial console with macserial and serial drivers -#endif /* * Print a string to the serial port trying not to disturb @@ -2719,7 +2716,7 @@ */ static int __init serial_console_setup(struct console *co, char *options) { - struct mac_serial *info = zs_soft + co->index; + struct mac_serial *info; int baud = 38400; int bits = 8; int parity = 'n'; @@ -2735,6 +2732,11 @@ if (zs_chain == 0) return -1; + /* Do we have the device asked for? */ + if (co->index >= zs_channels_found) + return -1; + info = zs_soft + co->index; + set_scc_power(info, 1); /* Reset the channel */ @@ -2904,7 +2906,7 @@ /* * Register console. */ -void __init serial_console_init(void) +void __init mac_scc_console_init(void) { register_console(&sercons); } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/macintosh/mediabay.c linux/drivers/macintosh/mediabay.c --- v2.4.0-test8/linux/drivers/macintosh/mediabay.c Sat May 20 12:07:56 2000 +++ linux/drivers/macintosh/mediabay.c Sun Sep 17 09:48:05 2000 @@ -472,8 +472,11 @@ } else if (MB_IDE_READY(i)) { bay->timer = 0; bay->state = mb_up; - if (bay->cd_index < 0) + if (bay->cd_index < 0) { + pmu_suspend(); bay->cd_index = ide_register(bay->cd_base, 0, bay->cd_irq); + pmu_resume(); + } if (bay->cd_index == -1) { /* We eventually do a retry */ bay->cd_retry++; @@ -605,7 +608,9 @@ only if it did not change. Note those bozo timings, they seem to help the 3400 get it right. */ - mdelay(MB_STABLE_DELAY); + /* Force MB power to 0 */ + set_mb_power(i, 0); + mdelay(MB_POWER_DELAY); if (!bay->pismo) out_8(&bay->addr->contents, 0x70); mdelay(MB_STABLE_DELAY); @@ -615,7 +620,9 @@ bay->last_value = bay->content_id; bay->value_count = MS_TO_HZ(MB_STABLE_DELAY); bay->timer = MS_TO_HZ(MB_POWER_DELAY); +#ifdef CONFIG_BLK_DEV_IDE bay->cd_retry = 0; +#endif do { mdelay(1000/HZ); media_bay_step(i); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/macintosh/nvram.c linux/drivers/macintosh/nvram.c --- v2.4.0-test8/linux/drivers/macintosh/nvram.c Tue Jun 20 13:58:42 2000 +++ linux/drivers/macintosh/nvram.c Sun Sep 17 09:48:05 2000 @@ -14,6 +14,7 @@ #include #include #include +#include #define NVRAM_SIZE 8192 @@ -70,11 +71,36 @@ return p - buf; } +static int nvram_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + switch(cmd) { + case PMAC_NVRAM_GET_OFFSET: + { + int part, offset; + if (copy_from_user(&part,(void*)arg,sizeof(part))!=0) + return -EFAULT; + if (part < pmac_nvram_OF || part > pmac_nvram_NR) + return -EINVAL; + offset = pmac_get_partition(part); + if (copy_to_user((void*)arg,&offset,sizeof(offset))!=0) + return -EFAULT; + break; + } + + default: + return -EINVAL; + } + + return 0; +} + struct file_operations nvram_fops = { owner: THIS_MODULE, llseek: nvram_llseek, read: read_nvram, write: write_nvram, + ioctl: nvram_ioctl, }; static struct miscdevice nvram_dev = { diff -u --recursive --new-file v2.4.0-test8/linux/drivers/macintosh/rtc.c linux/drivers/macintosh/rtc.c --- v2.4.0-test8/linux/drivers/macintosh/rtc.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/macintosh/rtc.c Tue Sep 19 08:31:53 2000 @@ -0,0 +1,157 @@ +/* + * Linux/PowerPC Real Time Clock Driver + * + * heavily based on: + * Linux/SPARC Real Time Clock Driver + * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu) + * + * This is a little driver that lets a user-level program access + * the PPC clocks chip. It is no use unless you + * use the modified clock utility. + * + * Get the modified clock utility from: + * ftp://vger.rutgers.edu/pub/linux/Sparc/userland/clock.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static int rtc_busy = 0; + +/* Retrieve the current date and time from the real time clock. */ +void get_rtc_time(struct rtc_time *t) +{ + unsigned long nowtime; + + nowtime = (ppc_md.get_rtc_time)(); + + to_tm(nowtime, t); + + t->tm_year -= 1900; + t->tm_mon -= 1; + t->tm_wday -= 1; +} + +/* Set the current date and time in the real time clock. */ +void set_rtc_time(struct rtc_time *t) +{ + unsigned long nowtime; + + printk(KERN_INFO "rtc.c:set_rtc_time: %04d-%02d-%02d %02d:%02d:%02d.\n", t->tm_year+1900, t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); + + nowtime = mktime(t->tm_year+1900, t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); + + printk(KERN_INFO "rtc.c:set_rtc_time: set rtc time to %ld seconds.\n", nowtime); + + (ppc_md.set_rtc_time)(nowtime); +} + +static loff_t rtc_lseek(struct file *file, loff_t offset, int origin) +{ + return -ESPIPE; +} + +static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct rtc_time rtc_tm; + + switch (cmd) + { + case RTC_RD_TIME: + if (ppc_md.get_rtc_time) + { + get_rtc_time(&rtc_tm); + + if (copy_to_user((struct rtc_time*)arg, &rtc_tm, sizeof(struct rtc_time))) + return -EFAULT; + + return 0; + } + else + return -EINVAL; + + case RTC_SET_TIME: + if (!capable(CAP_SYS_TIME)) + return -EPERM; + + if (ppc_md.set_rtc_time) + { + if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time))) + return -EFAULT; + + set_rtc_time(&rtc_tm); + + return 0; + } + else + return -EINVAL; + + default: + return -EINVAL; + } +} + +static int rtc_open(struct inode *inode, struct file *file) +{ + if (rtc_busy) + return -EBUSY; + + rtc_busy = 1; + + MOD_INC_USE_COUNT; + + return 0; +} + +static int rtc_release(struct inode *inode, struct file *file) +{ + MOD_DEC_USE_COUNT; + rtc_busy = 0; + return 0; +} + +static struct file_operations rtc_fops = { + owner: THIS_MODULE, + llseek: rtc_lseek, + ioctl: rtc_ioctl, + open: rtc_open, + release: rtc_release +}; + +static struct miscdevice rtc_dev = { RTC_MINOR, "rtc", &rtc_fops }; + +EXPORT_NO_SYMBOLS; + +static int __init rtc_init(void) +{ + int error; + + error = misc_register(&rtc_dev); + if (error) { + printk(KERN_ERR "rtc: unable to get misc minor\n"); + return error; + } + + return 0; +} + +static void __exit rtc_exit(void) +{ + misc_deregister(&rtc_dev); +} + +module_init(rtc_init); +module_exit(rtc_exit); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/macintosh/via-cuda.c linux/drivers/macintosh/via-cuda.c --- v2.4.0-test8/linux/drivers/macintosh/via-cuda.c Fri Nov 12 04:29:47 1999 +++ linux/drivers/macintosh/via-cuda.c Sun Sep 17 09:48:05 2000 @@ -94,39 +94,48 @@ #endif static int cuda_fully_inited = 0; +#ifdef CONFIG_ADB static int cuda_probe(void); static int cuda_init(void); +static int cuda_send_request(struct adb_request *req, int sync); +static int cuda_adb_autopoll(int devs); +static int cuda_reset_adb_bus(void); +#endif /* CONFIG_ADB */ + static int cuda_init_via(void); static void cuda_start(void); static void cuda_interrupt(int irq, void *arg, struct pt_regs *regs); static void cuda_input(unsigned char *buf, int nb, struct pt_regs *regs); -static int cuda_send_request(struct adb_request *req, int sync); -static int cuda_adb_autopoll(int devs); void cuda_poll(void); -static int cuda_reset_adb_bus(void); static int cuda_write(struct adb_request *req); int cuda_request(struct adb_request *req, void (*done)(struct adb_request *), int nbytes, ...); +#ifdef CONFIG_ADB struct adb_driver via_cuda_driver = { "CUDA", cuda_probe, cuda_init, cuda_send_request, - /*cuda_write,*/ cuda_adb_autopoll, cuda_poll, cuda_reset_adb_bus }; +#endif /* CONFIG_ADB */ #ifdef CONFIG_PPC -void -find_via_cuda() +int +find_via_cuda(void) { + int err; + struct adb_request req; + + if (vias != 0) + return 1; vias = find_devices("via-cuda"); if (vias == 0) - return; + return 0; if (vias->next != 0) printk(KERN_WARNING "Warning: only using 1st via-cuda\n"); @@ -146,15 +155,54 @@ printk(KERN_ERR "via-cuda: expecting 1 address (%d) and 1 interrupt (%d)\n", vias->n_addrs, vias->n_intrs); if (vias->n_addrs < 1 || vias->n_intrs < 1) - return; + return 0; } via = (volatile unsigned char *) ioremap(vias->addrs->address, 0x2000); cuda_state = idle; sys_ctrler = SYS_CTRLER_CUDA; + + err = cuda_init_via(); + if (err) { + printk(KERN_ERR "cuda_init_via() failed\n"); + via = NULL; + return 0; + } + + /* Clear and enable interrupts, but only on PPC. On 68K it's done */ + /* for us by the the main VIA driver in arch/m68k/mac/via.c */ + +#ifndef CONFIG_MAC + via[IFR] = 0x7f; eieio(); /* clear interrupts by writing 1s */ + via[IER] = IER_SET|SR_INT; eieio(); /* enable interrupt from SR */ +#endif + + /* enable autopoll */ + cuda_request(&req, NULL, 3, CUDA_PACKET, CUDA_AUTOPOLL, 1); + while (!req.complete) + cuda_poll(); + + return 1; } #endif /* CONFIG_PPC */ +int via_cuda_start(void) +{ + if (via == NULL) + return -ENODEV; + + if (request_irq(CUDA_IRQ, cuda_interrupt, 0, "ADB", cuda_interrupt)) { + printk(KERN_ERR "cuda_init: can't get irq %d\n", CUDA_IRQ); + return -EAGAIN; + } + + printk("Macintosh CUDA driver v0.5 for Unified ADB.\n"); + + cuda_fully_inited = 1; + return 0; +} + +#ifdef CONFIG_ADB static int cuda_probe() { @@ -172,46 +220,24 @@ static int cuda_init(void) { - int err; - if (via == NULL) return -ENODEV; - - err = cuda_init_via(); - if (err) { - printk(KERN_ERR "cuda_probe: init_via() failed\n"); - via = NULL; - return err; - } - - /* Clear and enable interrupts, but only on PPC. On 68K it's done */ - /* for us by the the main VIA driver in arch/m68k/mac/via.c */ - -#ifndef CONFIG_MAC - via[IFR] = 0x7f; eieio(); /* clear interrupts by writing 1s */ - via[IER] = IER_SET|SR_INT; eieio(); /* enable interrupt from SR */ +#ifndef CONFIG_PPC + return via_cuda_start(); #endif - - if (request_irq(CUDA_IRQ, cuda_interrupt, 0, "ADB", cuda_interrupt)) { - printk(KERN_ERR "cuda_init: can't get irq %d\n", CUDA_IRQ); - return -EAGAIN; - } - - printk("adb: CUDA driver v0.5 for Unified ADB.\n"); - - cuda_fully_inited = 1; return 0; } +#endif /* CONFIG_ADB */ -#define WAIT_FOR(cond, what) \ - do { \ - for (x = 1000; !(cond); --x) { \ - if (x == 0) { \ - printk("Timeout waiting for " what); \ - return -ENXIO; \ - } \ +#define WAIT_FOR(cond, what) \ + do { \ + for (x = 1000; !(cond); --x) { \ + if (x == 0) { \ + printk("Timeout waiting for " what "\n"); \ + return -ENXIO; \ + } \ udelay(100); \ - } \ + } \ } while (0) static int @@ -255,6 +281,7 @@ return 0; } +#ifdef CONFIG_ADB /* Send an ADB command */ static int cuda_send_request(struct adb_request *req, int sync) @@ -309,7 +336,7 @@ cuda_poll(); return 0; } - +#endif /* CONFIG_ADB */ /* Construct and send a cuda request */ int cuda_request(struct adb_request *req, void (*done)(struct adb_request *), @@ -534,7 +561,18 @@ switch (buf[0]) { case ADB_PACKET: +#ifdef CONFIG_XMON + if (nb == 5 && buf[2] == 0x2c) { + extern int xmon_wants_key, xmon_adb_keycode; + if (xmon_wants_key) { + xmon_adb_keycode = buf[3]; + return; + } + } +#endif /* CONFIG_XMON */ +#ifdef CONFIG_ADB adb_input(buf+2, nb-2, regs, buf[1] & 0x40); +#endif /* CONFIG_ADB */ break; default: diff -u --recursive --new-file v2.4.0-test8/linux/drivers/macintosh/via-pmu.c linux/drivers/macintosh/via-pmu.c --- v2.4.0-test8/linux/drivers/macintosh/via-pmu.c Wed Jul 12 21:58:42 2000 +++ linux/drivers/macintosh/via-pmu.c Sun Sep 17 09:48:05 2000 @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -39,10 +40,16 @@ #include #include #include +#include #include #include #include -#include +#ifdef CONFIG_PMAC_BACKLIGHT +#include +#endif + +/* Some compile options */ +#undef SUSPEND_USES_PMU /* Misc minor number allocated for /dev/pmu */ #define PMU_MINOR 154 @@ -84,7 +91,7 @@ #define CB2_INT 0x08 #define CB1_INT 0x10 /* transition on CB1 input */ -static enum pmu_state { +static volatile enum pmu_state { idle, sending, intack, @@ -95,7 +102,7 @@ static struct adb_request *current_req; static struct adb_request *last_req; static struct adb_request *req_awaiting_reply; -static unsigned char interrupt_data[32]; +static unsigned char interrupt_data[256]; /* Made bigger: I've been told that might happen */ static unsigned char *reply_ptr; static int data_index; static int data_len; @@ -106,22 +113,27 @@ static struct device_node *vias; static int pmu_kind = PMU_UNKNOWN; static int pmu_fully_inited = 0; -static int pmu_has_adb, pmu_has_backlight; +static int pmu_has_adb; static unsigned char *gpio_reg = NULL; -static int gpio_irq; +static int gpio_irq = -1; +static volatile int pmu_suspended = 0; +static spinlock_t pmu_lock; int asleep; struct notifier_block *sleep_notifier_list; +#ifdef CONFIG_ADB static int pmu_probe(void); static int pmu_init(void); +static int pmu_send_request(struct adb_request *req, int sync); +static int pmu_adb_autopoll(int devs); +static int pmu_adb_reset_bus(void); +#endif /* CONFIG_ADB */ + static int init_pmu(void); static int pmu_queue_request(struct adb_request *req); static void pmu_start(void); static void via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs); -static int pmu_send_request(struct adb_request *req, int sync); -static int pmu_adb_autopoll(int devs); -static int pmu_adb_reset_bus(void); static void send_byte(int x); static void recv_byte(void); static void pmu_sr_intr(struct pt_regs *regs); @@ -130,20 +142,25 @@ struct pt_regs *regs); static void set_volume(int level); static void gpio1_interrupt(int irq, void *arg, struct pt_regs *regs); +#ifdef CONFIG_PMAC_BACKLIGHT +static int pmu_set_backlight_level(int level, void* data); +static int pmu_set_backlight_enable(int on, int level, void* data); +#endif /* CONFIG_PMAC_BACKLIGHT */ #ifdef CONFIG_PMAC_PBOOK static void pmu_pass_intr(unsigned char *data, int len); #endif +#ifdef CONFIG_ADB struct adb_driver via_pmu_driver = { "PMU", pmu_probe, pmu_init, pmu_send_request, - /*pmu_queue_request,*/ pmu_adb_autopoll, pmu_poll, pmu_adb_reset_bus }; +#endif /* CONFIG_ADB */ extern void low_sleep_handler(void); extern void sleep_save_intrs(int); @@ -206,6 +223,13 @@ "Core99" }; +#ifdef CONFIG_PMAC_BACKLIGHT +static struct backlight_controller pmu_backlight_controller = { + pmu_set_backlight_enable, + pmu_set_backlight_level +}; +#endif /* CONFIG_PMAC_BACKLIGHT */ + int __openfirmware find_via_pmu() { @@ -216,17 +240,6 @@ return 0; if (vias->next != 0) printk(KERN_WARNING "Warning: only using 1st via-pmu\n"); -#if 0 - { int i; - - printk("find_via_pmu: node = %p, addrs =", vias->node); - for (i = 0; i < vias->n_addrs; ++i) - printk(" %x(%x)", vias->addrs[i].address, vias->addrs[i].size); - printk(", intrs ="); - for (i = 0; i < vias->n_intrs; ++i) - printk(" %x", vias->intrs[i].line); - printk("\n"); } -#endif if (vias->n_addrs < 1 || vias->n_intrs < 1) { printk(KERN_ERR "via-pmu: %d addresses, %d interrupts!\n", @@ -235,8 +248,9 @@ return 0; } + spin_lock_init(&pmu_lock); + pmu_has_adb = 1; - pmu_has_backlight = 1; if (vias->parent->name && ((strcmp(vias->parent->name, "ohare") == 0) || device_is_compatible(vias->parent, "ohare"))) @@ -246,9 +260,18 @@ else if (device_is_compatible(vias->parent, "heathrow")) pmu_kind = PMU_HEATHROW_BASED; else if (device_is_compatible(vias->parent, "Keylargo")) { + struct device_node *gpio, *gpiop; + pmu_kind = PMU_KEYLARGO_BASED; pmu_has_adb = (find_type_devices("adb") != NULL); - pmu_has_backlight = (find_type_devices("backlight") != NULL); + + gpiop = find_devices("gpio"); + if (gpiop && gpiop->n_addrs) { + gpio_reg = ioremap(gpiop->addrs->address, 0x10); + gpio = find_devices("extint-gpio1"); + if (gpio && gpio->parent == gpiop && gpio->n_intrs) + gpio_irq = gpio->intrs[0].line; + } } else pmu_kind = PMU_UNKNOWN; @@ -266,10 +289,13 @@ printk(KERN_INFO "PMU driver initialized for %s\n", pbook_type[pmu_kind]); + sys_ctrler = SYS_CTRLER_PMU; + return 1; } +#ifdef CONFIG_ADB static int __openfirmware pmu_probe() { @@ -280,9 +306,10 @@ pmu_init(void) { if (vias == NULL) - return -ENXIO; + return -ENODEV; return 0; } +#endif /* CONFIG_ADB */ /* * We can't wait until pmu_init gets called, that happens too late. @@ -291,10 +318,10 @@ * turned us off. * This is called from arch/ppc/kernel/pmac_setup.c:pmac_init2(). */ -void via_pmu_start(void) +int via_pmu_start(void) { if (vias == NULL) - return; + return -ENODEV; bright_req_1.complete = 1; bright_req_2.complete = 1; @@ -304,24 +331,12 @@ (void *)0)) { printk(KERN_ERR "VIA-PMU: can't get irq %d\n", vias->intrs[0].line); - return; + return -EAGAIN; } - if (pmu_kind == PMU_KEYLARGO_BASED) { - struct device_node *gpio, *gpiop; - - gpiop = find_devices("gpio"); - if (gpiop && gpiop->n_addrs) { - gpio_reg = ioremap(gpiop->addrs->address, 0x10); - gpio = find_devices("extint-gpio1"); - if (gpio && gpio->parent == gpiop && gpio->n_intrs) { - gpio_irq = gpio->intrs[0].line; - if (request_irq(gpio_irq, gpio1_interrupt, 0, - "GPIO1/ADB", (void *)0)) - printk(KERN_ERR "pmu: can't get irq %d (GPIO1)\n", - gpio->intrs[0].line); - } - } + if (pmu_kind == PMU_KEYLARGO_BASED && gpio_irq != -1) { + if (request_irq(gpio_irq, gpio1_interrupt, 0, "GPIO1/ADB", (void *)0)) + printk(KERN_ERR "pmu: can't get irq %d (GPIO1)\n", gpio_irq); } /* Enable interrupts */ @@ -329,8 +344,24 @@ pmu_fully_inited = 1; +#ifdef CONFIG_PMAC_BACKLIGHT /* Enable backlight */ - pmu_enable_backlight(1); + register_backlight_controller(&pmu_backlight_controller, NULL, "pmu"); +#endif /* CONFIG_PMAC_BACKLIGHT */ + + /* Make sure PMU settle down before continuing. This is _very_ important + * since the IDE probe may shut interrupts down for quite a bit of time. If + * a PMU communication is pending while this happens, the PMU may timeout + * Not that on Core99 machines, the PMU keeps sending us environement + * messages, we should find a way to either fix IDE or make it call + * pmu_suspend() before masking interrupts. This can also happens while + * scolling with some fbdevs. + */ + do { + pmu_poll(); + } while (pmu_state != idle); + + return 0; } static int __openfirmware @@ -342,7 +373,7 @@ out_8(&via[B], via[B] | TREQ); /* negate TREQ */ out_8(&via[DIRB], (via[DIRB] | TREQ) & ~TACK); /* TACK in, TREQ out */ - pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0xff); + pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0xfc); timeout = 100000; while (!req.complete) { if (--timeout < 0) { @@ -367,6 +398,13 @@ udelay(10); } + /* Tell PMU we are ready. Which PMU support this ? */ + if (pmu_kind == PMU_KEYLARGO_BASED) { + pmu_request(&req, NULL, 2, PMU_SYSTEM_READY, 2); + while (!req.complete) + pmu_poll(); + } + return 1; } @@ -376,6 +414,7 @@ return pmu_kind; } +#ifdef CONFIG_ADB /* Send an ADB command */ static int __openfirmware pmu_send_request(struct adb_request *req, int sync) @@ -513,6 +552,7 @@ return 0; } +#endif /* CONFIG_ADB */ /* Construct and send a pmu request */ int __openfirmware @@ -568,8 +608,8 @@ req->next = 0; req->sent = 0; req->complete = 0; - save_flags(flags); cli(); + spin_lock_irqsave(&pmu_lock, flags); if (current_req != 0) { last_req->next = req; last_req = req; @@ -579,11 +619,27 @@ if (pmu_state == idle) pmu_start(); } + spin_unlock_irqrestore(&pmu_lock, flags); - restore_flags(flags); return 0; } +static void __openfirmware +wait_for_ack(void) +{ + /* Sightly increased the delay, I had one occurence of the message + * reported + */ + int timeout = 4000; + while ((in_8(&via[B]) & TACK) == 0) { + if (--timeout < 0) { + printk(KERN_ERR "PMU not responding (!ack)\n"); + return; + } + udelay(10); + } +} + /* New PMU seems to be very sensitive to those timings, so we make sure * PCI is flushed immediately */ static void __openfirmware @@ -613,57 +669,126 @@ static void __openfirmware pmu_start() { - unsigned long flags; struct adb_request *req; /* assert pmu_state == idle */ /* get the packet to send */ - save_flags(flags); cli(); req = current_req; if (req == 0 || pmu_state != idle - || (req->reply_expected && req_awaiting_reply)) - goto out; + || (/*req->reply_expected && */req_awaiting_reply)) + return; pmu_state = sending; data_index = 1; data_len = pmu_data_len[req->data[0]][0]; + /* Sounds safer to make sure ACK is high before writing. This helped + * kill a problem with ADB and some iBooks + */ + wait_for_ack(); /* set the shift register to shift out and send a byte */ - ++disable_poll; send_byte(req->data[0]); - --disable_poll; - -out: - restore_flags(flags); } void __openfirmware pmu_poll() { - unsigned long flags; - + if (!via) + return; if (disable_poll) return; - save_flags(flags); - cli(); - if ((via[IFR] & (SR_INT | CB1_INT)) || - (gpio_reg && (in_8(gpio_reg + 0x9) & 0x02) == 0)) + /* Kicks ADB read when PMU is suspended */ + if (pmu_suspended) + adb_int_pending = 1; + do { + via_pmu_interrupt(0, 0, 0); + } while (pmu_suspended && (adb_int_pending || pmu_state != idle + || req_awaiting_reply)); +} + +/* This function loops until the PMU is idle and prevents it from + * anwsering to ADB interrupts. pmu_request can still be called. + * This is done to avoid spurrious shutdowns when we know we'll have + * interrupts switched off for a long time + */ +void __openfirmware +pmu_suspend(void) +{ + unsigned long flags; +#ifdef SUSPEND_USES_PMU + struct adb_request *req; +#endif + if (!via) + return; + + spin_lock_irqsave(&pmu_lock, flags); + pmu_suspended++; + if (pmu_suspended > 1) { + spin_unlock_irqrestore(&pmu_lock, flags); + return; + } + + do { + spin_unlock(&pmu_lock); via_pmu_interrupt(0, 0, 0); - restore_flags(flags); + spin_lock(&pmu_lock); + if (!adb_int_pending && pmu_state == idle && !req_awaiting_reply) { +#ifdef SUSPEND_USES_PMU + pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0); + spin_unlock_irqrestore(&pmu_lock, flags); + while(!req.complete) + pmu_poll(); +#else /* SUSPEND_USES_PMU */ + if (gpio_irq >= 0) + disable_irq(gpio_irq); + out_8(&via[IER], CB1_INT | IER_CLR); + spin_unlock_irqrestore(&pmu_lock, flags); +#endif /* SUSPEND_USES_PMU */ + break; + } + } while (1); +} + +void __openfirmware +pmu_resume(void) +{ + unsigned long flags; + + if (!via || (pmu_suspended < 1)) + return; + + spin_lock_irqsave(&pmu_lock, flags); + pmu_suspended--; + if (pmu_suspended > 0) { + spin_unlock_irqrestore(&pmu_lock, flags); + return; + } + adb_int_pending = 1; +#ifdef SUSPEND_USES_PMU + pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0xfc); + spin_unlock_irqrestore(&pmu_lock, flags); + while(!req.complete) + pmu_poll(); +#else /* SUSPEND_USES_PMU */ + if (gpio_irq >= 0) + enable_irq(gpio_irq); + out_8(&via[IER], CB1_INT | IER_SET); + spin_unlock_irqrestore(&pmu_lock, flags); + pmu_poll(); +#endif /* SUSPEND_USES_PMU */ } static void __openfirmware via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs) { + unsigned long flags; int intr; int nloop = 0; - unsigned long flags; - /* Currently, we use brute-force cli() for syncing with GPIO - * interrupt. I'll make this smarter later, along with some - * spinlocks for SMP */ - save_flags(flags);cli(); + /* This is a bit brutal, we can probably do better */ + spin_lock_irqsave(&pmu_lock, flags); ++disable_poll; + while ((intr = in_8(&via[IFR])) != 0) { if (++nloop > 1000) { printk(KERN_DEBUG "PMU: stuck in intr loop, " @@ -681,25 +806,38 @@ out_8(&via[IFR], intr); } } - if (gpio_reg && (in_8(gpio_reg + 0x9) & 0x02) == 0) + /* This is not necessary except if synchronous ADB requests are done + * with interrupts off, which should not happen. Since I'm not sure + * this "wiring" will remain, I'm commenting it out for now. Please do + * not remove. -- BenH. + */ +#if 0 + if (gpio_reg && !pmu_suspended && (in_8(gpio_reg + 0x9) & 0x02) == 0) adb_int_pending = 1; +#endif if (pmu_state == idle) { if (adb_int_pending) { pmu_state = intack; + /* Sounds safer to make sure ACK is high before writing. + * This helped kill a problem with ADB and some iBooks + */ + wait_for_ack(); send_byte(PMU_INT_ACK); adb_int_pending = 0; } else if (current_req) { pmu_start(); } } + --disable_poll; - restore_flags(flags); + spin_unlock_irqrestore(&pmu_lock, flags); } static void __openfirmware gpio1_interrupt(int irq, void *arg, struct pt_regs *regs) { + adb_int_pending = 1; via_pmu_interrupt(0, 0, 0); } @@ -707,7 +845,7 @@ pmu_sr_intr(struct pt_regs *regs) { struct adb_request *req; - int bite, timeout; + int bite; if (via[B] & TREQ) { printk(KERN_ERR "PMU: spurious SR intr (%x)\n", via[B]); @@ -720,26 +858,16 @@ if (via[B] & TACK) { while ((in_8(&via[B]) & TACK) != 0) ; -#if 0 - printk(KERN_ERR "PMU: sr_intr but ack still high! (%x)\n", - via[B]); -#endif } /* reset TREQ and wait for TACK to go high */ out_8(&via[B], in_8(&via[B]) | TREQ); - timeout = 3200; - while ((in_8(&via[B]) & TACK) == 0) { - if (--timeout < 0) { - printk(KERN_ERR "PMU not responding (!ack)\n"); - return; - } - udelay(10); - } + wait_for_ack(); /* if reading grab the byte, and reset the interrupt */ if (pmu_state == reading || pmu_state == reading_intr) bite = in_8(&via[SR]); + out_8(&via[IFR], SR_INT); switch (pmu_state) { @@ -761,8 +889,11 @@ current_req = req->next; if (req->reply_expected) req_awaiting_reply = req; - else + else { + spin_unlock(&pmu_lock); pmu_done(req); + spin_lock(&pmu_lock); + } } else { pmu_state = reading; data_index = 0; @@ -795,12 +926,16 @@ } if (pmu_state == reading_intr) { + spin_unlock(&pmu_lock); pmu_handle_data(interrupt_data, data_index, regs); + spin_lock(&pmu_lock); } else { req = current_req; current_req = req->next; req->reply_len += data_index; + spin_unlock(&pmu_lock); pmu_done(req); + spin_lock(&pmu_lock); } pmu_state = idle; @@ -826,6 +961,7 @@ { asleep = 0; if (len < 1) { +// xmon_printk("empty ADB\n"); adb_int_pending = 0; return; } @@ -854,6 +990,7 @@ } } #endif /* CONFIG_XMON */ +#ifdef CONFIG_ADB /* * XXX On the [23]400 the PMU gives us an up * event for keycodes 0x74 or 0x75 when the PC @@ -864,10 +1001,13 @@ && data[1] == 0x2c && data[3] == 0xff && (data[2] & ~1) == 0xf4)) adb_input(data+1, len-1, regs, 1); +#endif /* CONFIG_ADB */ } } else if (data[0] == 0x08 && len == 3) { /* sound/brightness buttons pressed */ - pmu_set_brightness(data[1] >> 3); +#ifdef CONFIG_PMAC_BACKLIGHT + set_backlight_level(data[1] >> 4); +#endif set_volume(data[2]); } else { #ifdef CONFIG_PMAC_PBOOK @@ -876,53 +1016,23 @@ } } -int backlight_level = -1; -int backlight_enabled = 0; - -#define LEVEL_TO_BRIGHT(lev) ((lev) < 1? 0x7f: 0x4a - ((lev) << 1)) - -void __openfirmware -pmu_enable_backlight(int on) +#ifdef CONFIG_PMAC_BACKLIGHT +static int backlight_to_bright[] = { + 0x7f, 0x46, 0x42, 0x3e, 0x3a, 0x36, 0x32, 0x2e, + 0x2a, 0x26, 0x22, 0x1e, 0x1a, 0x16, 0x12, 0x0e +}; + +static int __openfirmware +pmu_set_backlight_enable(int on, int level, void* data) { struct adb_request req; + + if (vias == NULL) + return -ENODEV; - if ((vias == NULL) || !pmu_has_backlight) - return; - - /* first call: get current backlight value */ - if (on && backlight_level < 0) { - switch (pmu_kind) { - case PMU_OHARE_BASED: - pmu_request(&req, NULL, 2, 0xd9, 0); - while (!req.complete) - pmu_poll(); - backlight_level = req.reply[1] >> 3; - break; - case PMU_HEATHROW_BASED: - /* We cannot use nvram_read_byte here (not yet initialized) */ - pmu_request(&req, NULL, 3, PMU_READ_NVRAM, 0x14, 0xe); - while (!req.complete) - pmu_poll(); - backlight_level = req.reply[1]; - printk(KERN_DEBUG "pmu: nvram returned bright: %d\n", backlight_level); - break; - case PMU_PADDINGTON_BASED: - case PMU_KEYLARGO_BASED: - /* the G3 PB 1999 has a backlight node - and chrp-structured nvram */ - /* XXX should read macos's "blkt" property in nvram - for this node. For now this ensures that the - backlight doesn't go off as soon as linux boots. */ - backlight_level = 20; - break; - default: - backlight_enabled = 0; - return; - } - } if (on) { pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT, - LEVEL_TO_BRIGHT(backlight_level)); + backlight_to_bright[level]); while (!req.complete) pmu_poll(); } @@ -930,35 +1040,28 @@ PMU_POW_BACKLIGHT | (on ? PMU_POW_ON : PMU_POW_OFF)); while (!req.complete) pmu_poll(); - backlight_enabled = on; + + return 0; } -void __openfirmware -pmu_set_brightness(int level) +static int __openfirmware +pmu_set_backlight_level(int level, void* data) { - int bright; + if (vias == NULL) + return -ENODEV; - if ((vias == NULL) || !pmu_has_backlight) - return ; + if (!bright_req_1.complete) + return -EAGAIN; + pmu_request(&bright_req_1, NULL, 2, PMU_BACKLIGHT_BRIGHT, + backlight_to_bright[level]); + if (!bright_req_2.complete) + return -EAGAIN; + pmu_request(&bright_req_2, NULL, 2, PMU_POWER_CTRL, PMU_POW_BACKLIGHT + | (level > BACKLIGHT_OFF ? PMU_POW_ON : PMU_POW_OFF)); - backlight_level = level; - bright = LEVEL_TO_BRIGHT(level); - if (!backlight_enabled) - return; - if (bright_req_1.complete) - pmu_request(&bright_req_1, NULL, 2, PMU_BACKLIGHT_BRIGHT, - bright); - if (bright_req_2.complete) - pmu_request(&bright_req_2, NULL, 2, PMU_POWER_CTRL, - PMU_POW_BACKLIGHT | (bright < 0x7f ? PMU_POW_ON : PMU_POW_OFF)); - - /* XXX nvram address is hard-coded and looks ok on wallstreet, please - test on your machine. Note that newer MacOS system software may break - the nvram layout. */ - if ((pmu_kind == PMU_HEATHROW_BASED) && bright_req_3.complete) - pmu_request(&bright_req_3, NULL, 4, PMU_WRITE_NVRAM, - 0x14, 0xe, level); + return 0; } +#endif /* CONFIG_PMAC_BACKLIGHT */ void __openfirmware pmu_enable_irled(int on) @@ -967,6 +1070,8 @@ if (vias == NULL) return ; + if (pmu_kind == PMU_KEYLARGO_BASED) + return ; pmu_request(&req, NULL, 2, PMU_POWER_CTRL, PMU_POW_IRLED | (on ? PMU_POW_ON : PMU_POW_OFF)); @@ -1201,17 +1306,9 @@ { int ret; unsigned long save_l2cr; - unsigned long save_fcr; unsigned long wait; unsigned short pmcr1; - struct adb_request sleep_req; - struct device_node *macio; - unsigned long macio_base = 0; - - macio = find_devices("mac-io"); - if (macio != 0 && macio->n_addrs > 0) - macio_base = (unsigned long) - ioremap(macio->addrs[0].address, 0x40); + struct adb_request req; /* Notify device drivers */ ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, PBOOK_SLEEP_REJECT); @@ -1245,14 +1342,13 @@ /* Make sure the decrementer won't interrupt us */ asm volatile("mtdec %0" : : "r" (0x7fffffff)); + feature_prepare_for_sleep(); + /* For 750, save backside cache setting and disable it */ save_l2cr = _get_L2CR(); /* (returns 0 if not 750) */ if (save_l2cr) _set_L2CR(0); - if (macio_base != 0) - save_fcr = in_le32(FEATURE_CTRL(macio_base)); - if (current->thread.regs && (current->thread.regs->msr & MSR_FP) != 0) giveup_fpu(current); @@ -1263,17 +1359,14 @@ grackle_pcibios_write_config_word(0, 0, 0x70, pmcr1); /* Ask the PMU to put us to sleep */ - pmu_request(&sleep_req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T'); - while (!sleep_req.complete) + pmu_request(&req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T'); + while (!req.complete) pmu_poll(); cli(); while (pmu_state != idle) pmu_poll(); - /* clear IOBUS enable */ - out_le32(FEATURE_CTRL(macio_base), save_fcr & ~HRW_IOBUS_ENABLE); - /* Call low-level ASM sleep handler */ low_sleep_handler(); @@ -1282,15 +1375,14 @@ pmcr1 &= ~(GRACKLE_PM|GRACKLE_DOZE|GRACKLE_SLEEP|GRACKLE_NAP); grackle_pcibios_write_config_word(0, 0, 0x70, pmcr1); - /* reenable IOBUS */ - out_le32(FEATURE_CTRL(macio_base), save_fcr | HRW_IOBUS_ENABLE); - /* Make sure the PMU is idle */ while (pmu_state != idle) pmu_poll(); sti(); + feature_wake_up(); + /* The PGD is only a placeholder until Dan finds a way to make * this work properly on the 8xx processors. It is only used on * 8xx processors, it is ignored here. @@ -1304,6 +1396,116 @@ /* reenable interrupts */ sleep_restore_intrs(); + /* Tell PMU we are ready */ + pmu_request(&req, NULL, 2, PMU_SYSTEM_READY, 2); + while (!req.complete) + pmu_poll(); + + /* Notify drivers */ + mdelay(10); + broadcast_wake(); + + return 0; +} + +/* Not finished yet */ +int __openfirmware powerbook_sleep_Core99(void) +{ + int ret; + unsigned long save_l2cr; + unsigned long wait; + struct adb_request req; + + /* Notify device drivers */ + ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, PBOOK_SLEEP_REJECT); + if (ret != PBOOK_SLEEP_OK) { + printk("pmu: sleep rejected\n"); + return -EBUSY; + } + + /* Sync the disks. */ + /* XXX It would be nice to have some way to ensure that + * nobody is dirtying any new buffers while we wait. + * BenH: Moved to _after_ sleep request and changed video + * drivers to vmalloc() during sleep request. This way, all + * vmalloc's are done before actual sleep of block drivers */ + fsync_dev(0); + + /* Sleep can fail now. May not be very robust but useful for debugging */ + ret = broadcast_sleep(PBOOK_SLEEP_NOW, PBOOK_WAKE); + if (ret != PBOOK_SLEEP_OK) { + printk("pmu: sleep failed\n"); + return -EBUSY; + } + + /* Give the disks a little time to actually finish writing */ + for (wait = jiffies + (HZ/4); time_before(jiffies, wait); ) + mb(); + + /* Tell PMU what events will wake us up */ + pmu_request(&req, NULL, 4, PMU_POWER_EVENTS, PMU_PWR_CLR_WAKEUP_EVENTS, + 0xff, 0xff); + while (!req.complete) + pmu_poll(); + pmu_request(&req, NULL, 4, PMU_POWER_EVENTS, PMU_PWR_SET_WAKEUP_EVENTS, + 0, PMU_PWR_WAKEUP_KEY | PMU_PWR_WAKEUP_LID_OPEN); + while (!req.complete) + pmu_poll(); + + /* Disable all interrupts except pmu */ + sleep_save_intrs(vias->intrs[0].line); + + /* Make sure the decrementer won't interrupt us */ + asm volatile("mtdec %0" : : "r" (0x7fffffff)); + + /* Save the state of PCI config space for some slots */ + pbook_pci_save(); + + feature_prepare_for_sleep(); + + /* For 750, save backside cache setting and disable it */ + save_l2cr = _get_L2CR(); /* (returns 0 if not 750) */ + if (save_l2cr) + _set_L2CR(0); + + if (current->thread.regs && (current->thread.regs->msr & MSR_FP) != 0) + giveup_fpu(current); + + /* Ask the PMU to put us to sleep */ + pmu_request(&req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T'); + while (!req.complete) + mb(); + + cli(); + while (pmu_state != idle) + pmu_poll(); + + /* Call low-level ASM sleep handler */ + low_sleep_handler(); + + /* Make sure the PMU is idle */ + while (pmu_state != idle) + pmu_poll(); + + sti(); + + feature_wake_up(); + pbook_pci_restore(); + + set_context(current->mm->context, current->mm->pgd); + + /* Restore L2 cache */ + if (save_l2cr) + _set_L2CR(save_l2cr | 0x200000); /* set invalidate bit */ + + /* reenable interrupts */ + sleep_restore_intrs(); + + /* Tell PMU we are ready */ + pmu_request(&req, NULL, 2, PMU_SYSTEM_READY, 2); + while (!req.complete) + pmu_poll(); + /* Notify drivers */ mdelay(10); broadcast_wake(); @@ -1557,7 +1759,6 @@ u_int cmd, u_long arg) { int error; - __u32 value; switch (cmd) { case PMU_IOC_SLEEP: @@ -1569,21 +1770,33 @@ case PMU_PADDINGTON_BASED: error = powerbook_sleep_G3(); break; +#if 0 /* Not ready yet */ + case PMU_KEYLARGO_BASED: + error = powerbook_sleep_Core99(); + break; +#endif default: error = -ENOSYS; } return error; +#ifdef CONFIG_PMAC_BACKLIGHT + /* Backlight should have its own device or go via + * the fbdev + */ case PMU_IOC_GET_BACKLIGHT: - if (!pmu_has_backlight) - return -ENOSYS; - return put_user(backlight_level, (__u32 *)arg); + error = get_backlight_level(); + if (error < 0) + return error; + return put_user(error, (__u32 *)arg); case PMU_IOC_SET_BACKLIGHT: - if (!pmu_has_backlight) - return -ENOSYS; + { + __u32 value; error = get_user(value, (__u32 *)arg); if (!error) - pmu_set_brightness(value); + error = set_backlight_level(value); return error; + } +#endif /* CONFIG_PMAC_BACKLIGHT */ case PMU_IOC_GET_MODEL: return put_user(pmu_kind, (__u32 *)arg); case PMU_IOC_HAS_ADB: diff -u --recursive --new-file v2.4.0-test8/linux/drivers/md/Config.in linux/drivers/md/Config.in --- v2.4.0-test8/linux/drivers/md/Config.in Wed Dec 31 16:00:00 1969 +++ linux/drivers/md/Config.in Mon Oct 2 12:00:07 2000 @@ -0,0 +1,22 @@ +# +# Block device driver configuration +# +mainmenu_option next_comment +comment 'Multi-device support (RAID and LVM)' + +bool 'Multiple devices driver support (RAID and LVM)' CONFIG_MD + +dep_tristate ' RAID support' CONFIG_BLK_DEV_MD $CONFIG_MD +dep_tristate ' Linear (append) mode' CONFIG_MD_LINEAR $CONFIG_BLK_DEV_MD +dep_tristate ' RAID-0 (striping) mode' CONFIG_MD_RAID0 $CONFIG_BLK_DEV_MD +dep_tristate ' RAID-1 (mirroring) mode' CONFIG_MD_RAID1 $CONFIG_BLK_DEV_MD +dep_tristate ' RAID-4/RAID-5 mode' CONFIG_MD_RAID5 $CONFIG_BLK_DEV_MD +if [ "$CONFIG_MD_LINEAR" = "y" -o "$CONFIG_MD_RAID0" = "y" -o "$CONFIG_MD_RAID1" = "y" -o "$CONFIG_MD_RAID5" = "y" ]; then + bool ' Boot support' CONFIG_MD_BOOT + bool ' Auto Detect support' CONFIG_AUTODETECT_RAID +fi + +dep_tristate ' Logical volume manager (LVM) support' CONFIG_BLK_DEV_LVM $CONFIG_MD +dep_mbool ' LVM information in proc filesystem' CONFIG_LVM_PROC_FS $CONFIG_BLK_DEV_LVM + +endmenu diff -u --recursive --new-file v2.4.0-test8/linux/drivers/md/Makefile linux/drivers/md/Makefile --- v2.4.0-test8/linux/drivers/md/Makefile Wed Dec 31 16:00:00 1969 +++ linux/drivers/md/Makefile Tue Sep 19 11:05:19 2000 @@ -0,0 +1,35 @@ +# +# Makefile for the kernel software RAID and LVM drivers. +# + +O_TARGET := mddev.o +SUB_DIRS := +ALL_SUB_DIRS := +MOD_SUB_DIRS := + +export-objs := md.o xor.o +list-multi := lvm-mod.o +lvm-mod-objs := lvm.o lvm-snap.o + +obj-y := +obj-m := +obj-n := +obj- := + +obj-$(CONFIG_BLK_DEV_MD) += md.o +obj-$(CONFIG_MD_LINEAR) += linear.o +obj-$(CONFIG_MD_RAID0) += raid0.o +obj-$(CONFIG_MD_RAID1) += raid1.o +obj-$(CONFIG_MD_RAID5) += raid5.o xor.o +obj-$(CONFIG_BLK_DEV_LVM) += lvm-mod.o + +# 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 + +lvm-mod.o: $(lvm-mod-objs) + $(LD) -r -o $@ $(lvm-mod-objs) diff -u --recursive --new-file v2.4.0-test8/linux/drivers/md/linear.c linux/drivers/md/linear.c --- v2.4.0-test8/linux/drivers/md/linear.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/md/linear.c Thu Aug 10 12:35:50 2000 @@ -0,0 +1,213 @@ +/* + linear.c : Multiple Devices driver for Linux + Copyright (C) 1994-96 Marc ZYNGIER + or + + + Linear mode management functions. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + You should have received a copy of the GNU General Public License + (for example /usr/src/linux/COPYING); if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include + +#include +#include + +#include + +#define MAJOR_NR MD_MAJOR +#define MD_DRIVER +#define MD_PERSONALITY + +static int linear_run (mddev_t *mddev) +{ + linear_conf_t *conf; + struct linear_hash *table; + mdk_rdev_t *rdev; + int size, i, j, nb_zone; + unsigned int curr_offset; + + MOD_INC_USE_COUNT; + + conf = kmalloc (sizeof (*conf), GFP_KERNEL); + if (!conf) + goto out; + mddev->private = conf; + + if (md_check_ordering(mddev)) { + printk("linear: disks are not ordered, aborting!\n"); + goto out; + } + /* + * Find the smallest device. + */ + + conf->smallest = NULL; + curr_offset = 0; + ITERATE_RDEV_ORDERED(mddev,rdev,j) { + dev_info_t *disk = conf->disks + j; + + disk->dev = rdev->dev; + disk->size = rdev->size; + disk->offset = curr_offset; + + curr_offset += disk->size; + + if (!conf->smallest || (disk->size < conf->smallest->size)) + conf->smallest = disk; + } + + nb_zone = conf->nr_zones = + md_size[mdidx(mddev)] / conf->smallest->size + + ((md_size[mdidx(mddev)] % conf->smallest->size) ? 1 : 0); + + conf->hash_table = kmalloc (sizeof (struct linear_hash) * nb_zone, + GFP_KERNEL); + if (!conf->hash_table) + goto out; + + /* + * Here we generate the linear hash table + */ + table = conf->hash_table; + i = 0; + size = 0; + for (j = 0; j < mddev->nb_dev; j++) { + dev_info_t *disk = conf->disks + j; + + if (size < 0) { + table->dev1 = disk; + table++; + } + size += disk->size; + + while (size) { + table->dev0 = disk; + size -= conf->smallest->size; + if (size < 0) + break; + table->dev1 = NULL; + table++; + } + } + table->dev1 = NULL; + + return 0; + +out: + if (conf) + kfree(conf); + MOD_DEC_USE_COUNT; + return 1; +} + +static int linear_stop (mddev_t *mddev) +{ + linear_conf_t *conf = mddev_to_conf(mddev); + + kfree(conf->hash_table); + kfree(conf); + + MOD_DEC_USE_COUNT; + + return 0; +} + +static int linear_make_request (mddev_t *mddev, + int rw, struct buffer_head * bh) +{ + linear_conf_t *conf = mddev_to_conf(mddev); + struct linear_hash *hash; + dev_info_t *tmp_dev; + long block; + + block = bh->b_rsector >> 1; + hash = conf->hash_table + (block / conf->smallest->size); + + if (block >= (hash->dev0->size + hash->dev0->offset)) { + if (!hash->dev1) { + printk ("linear_make_request : hash->dev1==NULL for block %ld\n", + block); + return -1; + } + tmp_dev = hash->dev1; + } else + tmp_dev = hash->dev0; + + if (block >= (tmp_dev->size + tmp_dev->offset) + || block < tmp_dev->offset) { + printk ("linear_make_request: Block %ld out of bounds on dev %s size %ld offset %ld\n", block, kdevname(tmp_dev->dev), tmp_dev->size, tmp_dev->offset); + return -1; + } + bh->b_rdev = tmp_dev->dev; + bh->b_rsector = bh->b_rsector - (tmp_dev->offset << 1); + + return 1; +} + +static int linear_status (char *page, mddev_t *mddev) +{ + int sz = 0; + +#undef MD_DEBUG +#ifdef MD_DEBUG + int j; + linear_conf_t *conf = mddev_to_conf(mddev); + + sz += sprintf(page+sz, " "); + for (j = 0; j < conf->nr_zones; j++) + { + sz += sprintf(page+sz, "[%s", + partition_name(conf->hash_table[j].dev0->dev)); + + if (conf->hash_table[j].dev1) + sz += sprintf(page+sz, "/%s] ", + partition_name(conf->hash_table[j].dev1->dev)); + else + sz += sprintf(page+sz, "] "); + } + sz += sprintf(page+sz, "\n"); +#endif + sz += sprintf(page+sz, " %dk rounding", mddev->param.chunk_size/1024); + return sz; +} + + +static mdk_personality_t linear_personality= +{ + name: "linear", + make_request: linear_make_request, + run: linear_run, + stop: linear_stop, + status: linear_status, +}; + +#ifndef MODULE + +void md__init linear_init (void) +{ + register_md_personality (LINEAR, &linear_personality); +} + +#else + +int init_module (void) +{ + return (register_md_personality (LINEAR, &linear_personality)); +} + +void cleanup_module (void) +{ + unregister_md_personality (LINEAR); +} + +#endif + diff -u --recursive --new-file v2.4.0-test8/linux/drivers/md/lvm-snap.c linux/drivers/md/lvm-snap.c --- v2.4.0-test8/linux/drivers/md/lvm-snap.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/md/lvm-snap.c Sun Sep 17 09:51:57 2000 @@ -0,0 +1,436 @@ +/* + * kernel/lvm-snap.c + * + * Copyright (C) 2000 Andrea Arcangeli SuSE + * + * LVM snapshot driver is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * LVM driver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include + + +static char *lvm_snap_version __attribute__ ((unused)) = "LVM 0.8final (15/02/2000)\n"; + +extern const char *const lvm_name; +extern int lvm_blocksizes[]; + +void lvm_snapshot_release(lv_t *); + +#define hashfn(dev,block,mask,chunk_size) \ + ((HASHDEV(dev)^((block)/(chunk_size))) & (mask)) + +static inline lv_block_exception_t * +lvm_find_exception_table(kdev_t org_dev, unsigned long org_start, lv_t * lv) +{ + struct list_head * hash_table = lv->lv_snapshot_hash_table, * next; + unsigned long mask = lv->lv_snapshot_hash_mask; + int chunk_size = lv->lv_chunk_size; + lv_block_exception_t * ret; + int i = 0; + + hash_table = &hash_table[hashfn(org_dev, org_start, mask, chunk_size)]; + ret = NULL; + for (next = hash_table->next; next != hash_table; next = next->next) + { + lv_block_exception_t * exception; + + exception = list_entry(next, lv_block_exception_t, hash); + if (exception->rsector_org == org_start && + exception->rdev_org == org_dev) + { + if (i) + { + /* fun, isn't it? :) */ + list_del(next); + list_add(next, hash_table); + } + ret = exception; + break; + } + i++; + } + return ret; +} + +static inline void lvm_hash_link(lv_block_exception_t * exception, + kdev_t org_dev, unsigned long org_start, + lv_t * lv) +{ + struct list_head * hash_table = lv->lv_snapshot_hash_table; + unsigned long mask = lv->lv_snapshot_hash_mask; + int chunk_size = lv->lv_chunk_size; + + hash_table = &hash_table[hashfn(org_dev, org_start, mask, chunk_size)]; + list_add(&exception->hash, hash_table); +} + +int lvm_snapshot_remap_block(kdev_t * org_dev, unsigned long * org_sector, + unsigned long pe_start, lv_t * lv) +{ + int ret; + unsigned long pe_off, pe_adjustment, __org_start; + kdev_t __org_dev; + int chunk_size = lv->lv_chunk_size; + lv_block_exception_t * exception; + + pe_off = pe_start % chunk_size; + pe_adjustment = (*org_sector-pe_off) % chunk_size; + __org_start = *org_sector - pe_adjustment; + __org_dev = *org_dev; + + ret = 0; + exception = lvm_find_exception_table(__org_dev, __org_start, lv); + if (exception) + { + *org_dev = exception->rdev_new; + *org_sector = exception->rsector_new + pe_adjustment; + ret = 1; + } + return ret; +} + +static void lvm_drop_snapshot(lv_t * lv_snap, const char * reason) +{ + kdev_t last_dev; + int i; + + /* no exception storage space available for this snapshot + or error on this snapshot --> release it */ + invalidate_buffers(lv_snap->lv_dev); + + last_dev = 0; + for (i = 0; i < lv_snap->lv_remap_ptr; i++) { + if ( lv_snap->lv_block_exception[i].rdev_new != last_dev) { + last_dev = lv_snap->lv_block_exception[i].rdev_new; + invalidate_buffers(last_dev); + } + } + + lvm_snapshot_release(lv_snap); + + printk(KERN_INFO + "%s -- giving up to snapshot %s on %s due %s\n", + lvm_name, lv_snap->lv_snapshot_org->lv_name, lv_snap->lv_name, + reason); +} + +static inline void lvm_snapshot_prepare_blocks(unsigned long * blocks, + unsigned long start, + int nr_sectors, + int blocksize) +{ + int i, sectors_per_block, nr_blocks; + + sectors_per_block = blocksize >> 9; + nr_blocks = nr_sectors / sectors_per_block; + start /= sectors_per_block; + + for (i = 0; i < nr_blocks; i++) + blocks[i] = start++; +} + +static inline int get_blksize(kdev_t dev) +{ + int correct_size = BLOCK_SIZE, i, major; + + major = MAJOR(dev); + if (blksize_size[major]) + { + i = blksize_size[major][MINOR(dev)]; + if (i) + correct_size = i; + } + return correct_size; +} + +#ifdef DEBUG_SNAPSHOT +static inline void invalidate_snap_cache(unsigned long start, unsigned long nr, + kdev_t dev) +{ + struct buffer_head * bh; + int sectors_per_block, i, blksize, minor; + + minor = MINOR(dev); + blksize = lvm_blocksizes[minor]; + sectors_per_block = blksize >> 9; + nr /= sectors_per_block; + start /= sectors_per_block; + + for (i = 0; i < nr; i++) + { + bh = get_hash_table(dev, start++, blksize); + if (bh) + bforget(bh); + } +} +#endif + +/* + * copy on write handler for one snapshot logical volume + * + * read the original blocks and store it/them on the new one(s). + * if there is no exception storage space free any longer --> release snapshot. + * + * this routine gets called for each _first_ write to a physical chunk. + */ +int lvm_snapshot_COW(kdev_t org_phys_dev, + unsigned long org_phys_sector, + unsigned long org_pe_start, + unsigned long org_virt_sector, + lv_t * lv_snap) +{ + const char * reason; + unsigned long org_start, snap_start, virt_start, pe_off; + int idx = lv_snap->lv_remap_ptr, chunk_size = lv_snap->lv_chunk_size; + kdev_t snap_phys_dev; + struct kiobuf * iobuf; + unsigned long blocks[KIO_MAX_SECTORS]; + int blksize_snap, blksize_org, min_blksize, max_blksize; + int max_sectors, nr_sectors; + + /* check if we are out of snapshot space */ + if (idx >= lv_snap->lv_remap_end) + goto fail_out_of_space; + + /* calculate physical boundaries of source chunk */ + pe_off = org_pe_start % chunk_size; + org_start = org_phys_sector - ((org_phys_sector-pe_off) % chunk_size); + virt_start = org_virt_sector - (org_phys_sector - org_start); + + /* calculate physical boundaries of destination chunk */ + snap_phys_dev = lv_snap->lv_block_exception[idx].rdev_new; + snap_start = lv_snap->lv_block_exception[idx].rsector_new; + +#ifdef DEBUG_SNAPSHOT + printk(KERN_INFO + "%s -- COW: " + "org %02d:%02d faulting %lu start %lu, " + "snap %02d:%02d start %lu, " + "size %d, pe_start %lu pe_off %lu, virt_sec %lu\n", + lvm_name, + MAJOR(org_phys_dev), MINOR(org_phys_dev), org_phys_sector, + org_start, + MAJOR(snap_phys_dev), MINOR(snap_phys_dev), snap_start, + chunk_size, + org_pe_start, pe_off, + org_virt_sector); +#endif + + iobuf = lv_snap->lv_iobuf; + + blksize_org = get_blksize(org_phys_dev); + blksize_snap = get_blksize(snap_phys_dev); + max_blksize = max(blksize_org, blksize_snap); + min_blksize = min(blksize_org, blksize_snap); + max_sectors = KIO_MAX_SECTORS * (min_blksize>>9); + + if (chunk_size % (max_blksize>>9)) + goto fail_blksize; + + while (chunk_size) + { + nr_sectors = min(chunk_size, max_sectors); + chunk_size -= nr_sectors; + + iobuf->length = nr_sectors << 9; + + lvm_snapshot_prepare_blocks(blocks, org_start, + nr_sectors, blksize_org); + if (brw_kiovec(READ, 1, &iobuf, org_phys_dev, + blocks, blksize_org) != (nr_sectors<<9)) + goto fail_raw_read; + + lvm_snapshot_prepare_blocks(blocks, snap_start, + nr_sectors, blksize_snap); + if (brw_kiovec(WRITE, 1, &iobuf, snap_phys_dev, + blocks, blksize_snap) != (nr_sectors<<9)) + goto fail_raw_write; + } + +#ifdef DEBUG_SNAPSHOT + /* invalidate the logcial snapshot buffer cache */ + invalidate_snap_cache(virt_start, lv_snap->lv_chunk_size, + lv_snap->lv_dev); +#endif + + /* the original chunk is now stored on the snapshot volume + so update the execption table */ + lv_snap->lv_block_exception[idx].rdev_org = org_phys_dev; + lv_snap->lv_block_exception[idx].rsector_org = org_start; + lvm_hash_link(lv_snap->lv_block_exception + idx, + org_phys_dev, org_start, lv_snap); + lv_snap->lv_remap_ptr = idx + 1; + return 1; + + /* slow path */ + out: + lvm_drop_snapshot(lv_snap, reason); + return -1; + + fail_out_of_space: + reason = "out of space"; + goto out; + fail_raw_read: + reason = "read error"; + goto out; + fail_raw_write: + reason = "write error"; + goto out; + fail_blksize: + reason = "blocksize error"; + goto out; +} + +static int lvm_snapshot_alloc_iobuf_pages(struct kiobuf * iobuf, int sectors) +{ + int bytes, nr_pages, err, i; + + bytes = sectors << 9; + nr_pages = (bytes + ~PAGE_MASK) >> PAGE_SHIFT; + err = expand_kiobuf(iobuf, nr_pages); + if (err) + goto out; + + err = -ENOMEM; + iobuf->locked = 1; + iobuf->nr_pages = 0; + for (i = 0; i < nr_pages; i++) + { + struct page * page; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,27) + page = alloc_page(GFP_KERNEL); + if (!page) + goto out; +#else + { + unsigned long addr = __get_free_page(GFP_USER); + if (!addr) + goto out; + iobuf->pagelist[i] = addr; + page = virt_to_page(addr); + } +#endif + + iobuf->maplist[i] = page; + /* the only point to lock the page here is to be allowed + to share unmap_kiobuf() in the fail-path */ +#ifndef LockPage +#define LockPage(map) set_bit(PG_locked, &(map)->flags) +#endif + LockPage(page); + iobuf->nr_pages++; + } + iobuf->offset = 0; + + err = 0; + out: + return err; +} + +static int calc_max_buckets(void) +{ + unsigned long mem; + + mem = num_physpages << PAGE_SHIFT; + mem /= 100; + mem *= 2; + mem /= sizeof(struct list_head); + + return mem; +} + +static int lvm_snapshot_alloc_hash_table(lv_t * lv) +{ + int err; + unsigned long buckets, max_buckets, size; + struct list_head * hash; + + buckets = lv->lv_remap_end; + max_buckets = calc_max_buckets(); + buckets = min(buckets, max_buckets); + while (buckets & (buckets-1)) + buckets &= (buckets-1); + + size = buckets * sizeof(struct list_head); + + err = -ENOMEM; + hash = vmalloc(size); + lv->lv_snapshot_hash_table = hash; + + if (!hash) + goto out; + + lv->lv_snapshot_hash_mask = buckets-1; + while (buckets--) + INIT_LIST_HEAD(hash+buckets); + err = 0; + out: + return err; +} + +int lvm_snapshot_alloc(lv_t * lv_snap) +{ + int err, blocksize, max_sectors; + + err = alloc_kiovec(1, &lv_snap->lv_iobuf); + if (err) + goto out; + + blocksize = lvm_blocksizes[MINOR(lv_snap->lv_dev)]; + max_sectors = KIO_MAX_SECTORS << (PAGE_SHIFT-9); + + err = lvm_snapshot_alloc_iobuf_pages(lv_snap->lv_iobuf, max_sectors); + if (err) + goto out_free_kiovec; + + err = lvm_snapshot_alloc_hash_table(lv_snap); + if (err) + goto out_free_kiovec; + out: + return err; + + out_free_kiovec: + unmap_kiobuf(lv_snap->lv_iobuf); + free_kiovec(1, &lv_snap->lv_iobuf); + goto out; +} + +void lvm_snapshot_release(lv_t * lv) +{ + if (lv->lv_block_exception) + { + vfree(lv->lv_block_exception); + lv->lv_block_exception = NULL; + } + if (lv->lv_snapshot_hash_table) + { + vfree(lv->lv_snapshot_hash_table); + lv->lv_snapshot_hash_table = NULL; + } + if (lv->lv_iobuf) + { + free_kiovec(1, &lv->lv_iobuf); + lv->lv_iobuf = NULL; + } +} diff -u --recursive --new-file v2.4.0-test8/linux/drivers/md/lvm.c linux/drivers/md/lvm.c --- v2.4.0-test8/linux/drivers/md/lvm.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/md/lvm.c Sun Sep 17 09:51:57 2000 @@ -0,0 +1,2567 @@ +/* + * kernel/lvm.c + * + * Copyright (C) 1997 - 2000 Heinz Mauelshagen, Germany + * + * February-November 1997 + * April-May,July-August,November 1998 + * January-March,May,July,September,October 1999 + * January,February 2000 + * + * + * LVM driver is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * LVM driver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +/* + * Changelog + * + * 09/11/1997 - added chr ioctls VG_STATUS_GET_COUNT + * and VG_STATUS_GET_NAMELIST + * 18/01/1998 - change lvm_chr_open/close lock handling + * 30/04/1998 - changed LV_STATUS ioctl to LV_STATUS_BYNAME and + * - added LV_STATUS_BYINDEX ioctl + * - used lvm_status_byname_req_t and + * lvm_status_byindex_req_t vars + * 04/05/1998 - added multiple device support + * 08/05/1998 - added support to set/clear extendable flag in volume group + * 09/05/1998 - changed output of lvm_proc_get_info() because of + * support for free (eg. longer) logical volume names + * 12/05/1998 - added spin_locks (thanks to Pascal van Dam + * ) + * 25/05/1998 - fixed handling of locked PEs in lvm_map() and lvm_chr_ioctl() + * 26/05/1998 - reactivated verify_area by access_ok + * 07/06/1998 - used vmalloc/vfree instead of kmalloc/kfree to go + * beyond 128/256 KB max allocation limit per call + * - #ifdef blocked spin_lock calls to avoid compile errors + * with 2.0.x + * 11/06/1998 - another enhancement to spinlock code in lvm_chr_open() + * and use of LVM_VERSION_CODE instead of my own macros + * (thanks to Michael Marxmeier ) + * 07/07/1998 - added statistics in lvm_map() + * 08/07/1998 - saved statistics in lvm_do_lv_extend_reduce() + * 25/07/1998 - used __initfunc macro + * 02/08/1998 - changes for official char/block major numbers + * 07/08/1998 - avoided init_module() and cleanup_module() to be static + * 30/08/1998 - changed VG lv_open counter from sum of LV lv_open counters + * to sum of LVs open (no matter how often each is) + * 01/09/1998 - fixed lvm_gendisk.part[] index error + * 07/09/1998 - added copying of lv_current_pe-array + * in LV_STATUS_BYINDEX ioctl + * 17/11/1998 - added KERN_* levels to printk + * 13/01/1999 - fixed LV index bug in lvm_do_lv_create() which hit lvrename + * 07/02/1999 - fixed spinlock handling bug in case of LVM_RESET + * by moving spinlock code from lvm_chr_open() + * to lvm_chr_ioctl() + * - added LVM_LOCK_LVM ioctl to lvm_chr_ioctl() + * - allowed LVM_RESET and retrieval commands to go ahead; + * only other update ioctls are blocked now + * - fixed pv->pe to NULL for pv_status + * - using lv_req structure in lvm_chr_ioctl() now + * - fixed NULL ptr reference bug in lvm_do_lv_extend_reduce() + * caused by uncontiguous PV array in lvm_chr_ioctl(VG_REDUCE) + * 09/02/1999 - changed BLKRASET and BLKRAGET in lvm_chr_ioctl() to + * handle lgoical volume private read ahead sector + * - implemented LV read_ahead handling with lvm_blk_read() + * and lvm_blk_write() + * 10/02/1999 - implemented 2.[12].* support function lvm_hd_name() + * to be used in drivers/block/genhd.c by disk_name() + * 12/02/1999 - fixed index bug in lvm_blk_ioctl(), HDIO_GETGEO + * - enhanced gendisk insert/remove handling + * 16/02/1999 - changed to dynamic block minor number allocation to + * have as much as 99 volume groups with 256 logical volumes + * as the grand total; this allows having 1 volume group with + * up to 256 logical volumes in it + * 21/02/1999 - added LV open count information to proc filesystem + * - substituted redundant LVM_RESET code by calls + * to lvm_do_vg_remove() + * 22/02/1999 - used schedule_timeout() to be more responsive + * in case of lvm_do_vg_remove() with lots of logical volumes + * 19/03/1999 - fixed NULL pointer bug in module_init/lvm_init + * 17/05/1999 - used DECLARE_WAIT_QUEUE_HEAD macro (>2.3.0) + * - enhanced lvm_hd_name support + * 03/07/1999 - avoided use of KERNEL_VERSION macro based ifdefs and + * memcpy_tofs/memcpy_fromfs macro redefinitions + * 06/07/1999 - corrected reads/writes statistic counter copy in case + * of striped logical volume + * 28/07/1999 - implemented snapshot logical volumes + * - lvm_chr_ioctl + * - LV_STATUS_BYINDEX + * - LV_STATUS_BYNAME + * - lvm_do_lv_create + * - lvm_do_lv_remove + * - lvm_map + * - new lvm_snapshot_remap_block + * - new lvm_snapshot_remap_new_block + * 08/10/1999 - implemented support for multiple snapshots per + * original logical volume + * 12/10/1999 - support for 2.3.19 + * 11/11/1999 - support for 2.3.28 + * 21/11/1999 - changed lvm_map() interface to buffer_head based + * 19/12/1999 - support for 2.3.33 + * 01/01/2000 - changed locking concept in lvm_map(), + * lvm_do_vg_create() and lvm_do_lv_remove() + * 15/01/2000 - fixed PV_FLUSH bug in lvm_chr_ioctl() + * 24/01/2000 - ported to 2.3.40 including Alan Cox's pointer changes etc. + * 29/01/2000 - used kmalloc/kfree again for all small structures + * 20/01/2000 - cleaned up lvm_chr_ioctl by moving code + * to seperated functions + * - avoided "/dev/" in proc filesystem output + * - avoided inline strings functions lvm_strlen etc. + * 14/02/2000 - support for 2.3.43 + * - integrated Andrea Arcangeli's snapshot code + * + */ + + +static char *lvm_version = "LVM version 0.8final by Heinz Mauelshagen (15/02/2000)\n"; +static char *lvm_short_version = "version 0.8final (15/02/2000)"; + +#define MAJOR_NR LVM_BLK_MAJOR +#define DEVICE_OFF(device) + +#include +#include + +#ifdef MODVERSIONS +#undef MODULE +#define MODULE +#include +#endif + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_KERNELD +#include +#endif + +#define LOCAL_END_REQUEST + +#include +#include + +#include +#include + +#define LVM_CORRECT_READ_AHEAD(a) \ + (((a) < LVM_MIN_READ_AHEAD || (a) > LVM_MAX_READ_AHEAD) \ + ? LVM_MAX_READ_AHEAD : (a)) + +#ifndef WRITEA +# define WRITEA WRITE +#endif + +/* + * External function prototypes + */ +#ifdef MODULE +int init_module(void); +void cleanup_module(void); +#else +extern int lvm_init(void); +#endif + +static void lvm_dummy_device_request(request_queue_t *); +#define DEVICE_REQUEST lvm_dummy_device_request + +static int lvm_make_request_fn(request_queue_t *, int, struct buffer_head*); +static void lvm_plug_device_noop(request_queue_t *, kdev_t); + +static int lvm_blk_ioctl(struct inode *, struct file *, uint, ulong); +static int lvm_blk_open(struct inode *, struct file *); + +static int lvm_chr_open(struct inode *, struct file *); + +static int lvm_chr_close(struct inode *, struct file *); +static int lvm_blk_close(struct inode *, struct file *); + +static int lvm_chr_ioctl(struct inode *, struct file *, uint, ulong); + +#if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS +static int lvm_proc_get_info(char *, char **, off_t, int); +static int (*lvm_proc_get_info_ptr) (char *, char **, off_t, int) = +&lvm_proc_get_info; +#endif + +#ifdef LVM_HD_NAME +void lvm_hd_name(char *, int); +#endif +/* End external function prototypes */ + + +/* + * Internal function prototypes + */ +static void lvm_init_vars(void); + +/* external snapshot calls */ +int lvm_snapshot_remap_block(kdev_t *, ulong *, ulong, lv_t *); +int lvm_snapshot_COW(kdev_t, ulong, ulong, ulong, lv_t *); +int lvm_snapshot_alloc(lv_t *); +void lvm_snapshot_release(lv_t *); + +#ifdef LVM_HD_NAME +extern void (*lvm_hd_name_ptr) (char *, int); +#endif +static int lvm_map(struct buffer_head *, int); +static int lvm_do_lock_lvm(void); +static int lvm_do_le_remap(vg_t *, void *); +static int lvm_do_pe_lock_unlock(vg_t *r, void *); +static int lvm_do_vg_create(int, void *); +static int lvm_do_vg_extend(vg_t *, void *); +static int lvm_do_vg_reduce(vg_t *, void *); +static int lvm_do_vg_remove(int); +static int lvm_do_lv_create(int, char *, lv_t *); +static int lvm_do_lv_remove(int, char *, int); +static int lvm_do_lv_extend_reduce(int, char *, lv_t *); +static int lvm_do_lv_status_byname(vg_t *r, void *); +static int lvm_do_lv_status_byindex(vg_t *, void *arg); +static int lvm_do_pv_change(vg_t*, void*); +static int lvm_do_pv_status(vg_t *, void *); +static void lvm_geninit(struct gendisk *); +#ifdef LVM_GET_INODE +static struct inode *lvm_get_inode(kdev_t); +void lvm_clear_inode(struct inode *); +#endif +/* END Internal function prototypes */ + + +/* volume group descriptor area pointers */ +static vg_t *vg[ABS_MAX_VG]; +static pv_t *pvp = NULL; +static lv_t *lvp = NULL; +static pe_t *pep = NULL; +static pe_t *pep1 = NULL; + + +/* map from block minor number to VG and LV numbers */ +typedef struct { + int vg_number; + int lv_number; +} vg_lv_map_t; +static vg_lv_map_t vg_lv_map[ABS_MAX_LV]; + + +/* Request structures (lvm_chr_ioctl()) */ +static pv_change_req_t pv_change_req; +static pv_flush_req_t pv_flush_req; +static pv_status_req_t pv_status_req; +static pe_lock_req_t pe_lock_req; +static le_remap_req_t le_remap_req; +static lv_req_t lv_req; + +#ifdef LVM_TOTAL_RESET +static int lvm_reset_spindown = 0; +#endif + +static char pv_name[NAME_LEN]; +/* static char rootvg[NAME_LEN] = { 0, }; */ +static uint lv_open = 0; +const char *const lvm_name = LVM_NAME; +static int lock = 0; +static int loadtime = 0; +static uint vg_count = 0; +static long lvm_chr_open_count = 0; +static ushort lvm_iop_version = LVM_DRIVER_IOP_VERSION; +static DECLARE_WAIT_QUEUE_HEAD(lvm_snapshot_wait); +static DECLARE_WAIT_QUEUE_HEAD(lvm_wait); +static DECLARE_WAIT_QUEUE_HEAD(lvm_map_wait); + +static spinlock_t lvm_lock = SPIN_LOCK_UNLOCKED; + +static devfs_handle_t lvm_devfs_handle; +static devfs_handle_t vg_devfs_handle[MAX_VG]; +static devfs_handle_t ch_devfs_handle[MAX_VG]; +static devfs_handle_t lv_devfs_handle[MAX_LV]; + +static struct file_operations lvm_chr_fops = +{ + owner: THIS_MODULE, + open: lvm_chr_open, + release: lvm_chr_close, + ioctl: lvm_chr_ioctl, +}; + +static struct block_device_operations lvm_blk_dops = +{ + open: lvm_blk_open, + release: lvm_blk_close, + ioctl: lvm_blk_ioctl +}; + +/* gendisk structures */ +static struct hd_struct lvm_hd_struct[MAX_LV]; +static int lvm_blocksizes[MAX_LV] = +{0,}; +static int lvm_size[MAX_LV] = +{0,}; +static struct gendisk lvm_gendisk = +{ + MAJOR_NR, /* major # */ + LVM_NAME, /* name of major */ + 0, /* number of times minor is shifted + to get real minor */ + 1, /* maximum partitions per device */ + lvm_hd_struct, /* partition table */ + lvm_size, /* device size in blocks, copied + to block_size[] */ + MAX_LV, /* number or real devices */ + NULL, /* internal */ + NULL, /* pointer to next gendisk struct (internal) */ +}; + + +#ifdef MODULE +/* + * Module initialization... + */ +int init_module(void) +#else +/* + * Driver initialization... + */ +#ifdef __initfunc +__initfunc(int lvm_init(void)) +#else +int __init lvm_init(void) +#endif +#endif /* #ifdef MODULE */ +{ + struct gendisk *gendisk_ptr = NULL; + + if (register_chrdev(LVM_CHAR_MAJOR, lvm_name, &lvm_chr_fops) < 0) { + printk(KERN_ERR "%s -- register_chrdev failed\n", lvm_name); + return -EIO; + } + if (register_blkdev(MAJOR_NR, lvm_name, &lvm_blk_dops) < 0) { + printk("%s -- register_blkdev failed\n", lvm_name); + if (unregister_chrdev(LVM_CHAR_MAJOR, lvm_name) < 0) + printk(KERN_ERR "%s -- unregister_chrdev failed\n", lvm_name); + return -EIO; + } + + lvm_devfs_handle = devfs_register( + 0 , "lvm", 0, 0, LVM_CHAR_MAJOR, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, + &lvm_chr_fops, NULL); + +#if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS + create_proc_info_entry(LVM_NAME, S_IFREG | S_IRUGO, + &proc_root, lvm_proc_get_info_ptr); +#endif + + lvm_init_vars(); + lvm_geninit(&lvm_gendisk); + + /* insert our gendisk at the corresponding major */ + if (gendisk_head != NULL) { + gendisk_ptr = gendisk_head; + while (gendisk_ptr->next != NULL && + gendisk_ptr->major > lvm_gendisk.major) { + gendisk_ptr = gendisk_ptr->next; + } + lvm_gendisk.next = gendisk_ptr->next; + gendisk_ptr->next = &lvm_gendisk; + } else { + gendisk_head = &lvm_gendisk; + lvm_gendisk.next = NULL; + } + +#ifdef LVM_HD_NAME + /* reference from drivers/block/genhd.c */ + lvm_hd_name_ptr = lvm_hd_name; +#endif + + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); + blk_queue_make_request(BLK_DEFAULT_QUEUE(MAJOR_NR), lvm_make_request_fn); + blk_queue_pluggable(BLK_DEFAULT_QUEUE(MAJOR_NR), lvm_plug_device_noop); + /* optional read root VGDA */ +/* + if ( *rootvg != 0) vg_read_with_pv_and_lv ( rootvg, &vg); +*/ + + printk(KERN_INFO + "%s%s -- " +#ifdef MODULE + "Module" +#else + "Driver" +#endif + " successfully initialized\n", + lvm_version, lvm_name); + + return 0; +} /* init_module() / lvm_init() */ + + +#ifdef MODULE +/* + * Module cleanup... + */ +void cleanup_module(void) +{ + struct gendisk *gendisk_ptr = NULL, *gendisk_ptr_prev = NULL; + + devfs_unregister (lvm_devfs_handle); + + if (unregister_chrdev(LVM_CHAR_MAJOR, lvm_name) < 0) { + printk(KERN_ERR "%s -- unregister_chrdev failed\n", lvm_name); + } + if (unregister_blkdev(MAJOR_NR, lvm_name) < 0) { + printk(KERN_ERR "%s -- unregister_blkdev failed\n", lvm_name); + } + blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); + + gendisk_ptr = gendisk_ptr_prev = gendisk_head; + while (gendisk_ptr != NULL) { + if (gendisk_ptr == &lvm_gendisk) + break; + gendisk_ptr_prev = gendisk_ptr; + gendisk_ptr = gendisk_ptr->next; + } + /* delete our gendisk from chain */ + if (gendisk_ptr == &lvm_gendisk) + gendisk_ptr_prev->next = gendisk_ptr->next; + + blk_size[MAJOR_NR] = NULL; + blksize_size[MAJOR_NR] = NULL; + +#if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS + remove_proc_entry(LVM_NAME, &proc_root); +#endif + +#ifdef LVM_HD_NAME + /* reference from linux/drivers/block/genhd.c */ + lvm_hd_name_ptr = NULL; +#endif + + printk(KERN_INFO "%s -- Module successfully deactivated\n", lvm_name); + + return; +} /* void cleanup_module() */ +#endif /* #ifdef MODULE */ + + +/* + * support function to initialize lvm variables + */ +#ifdef __initfunc +__initfunc(void lvm_init_vars(void)) +#else +void __init lvm_init_vars(void) +#endif +{ + int v; + + loadtime = CURRENT_TIME; + + pe_lock_req.lock = UNLOCK_PE; + pe_lock_req.data.lv_dev = pe_lock_req.data.pv_dev = 0; + pe_lock_req.data.pv_offset = 0; + + /* Initialize VG pointers */ + for (v = 0; v < ABS_MAX_VG; v++) vg[v] = NULL; + + /* Initialize LV -> VG association */ + for (v = 0; v < ABS_MAX_LV; v++) { + /* index ABS_MAX_VG never used for real VG */ + vg_lv_map[v].vg_number = ABS_MAX_VG; + vg_lv_map[v].lv_number = -1; + } + + return; +} /* lvm_init_vars() */ + + +/******************************************************************** + * + * Character device functions + * + ********************************************************************/ + +/* + * character device open routine + */ +static int lvm_chr_open(struct inode *inode, + struct file *file) +{ + int minor = MINOR(inode->i_rdev); + +#ifdef DEBUG + printk(KERN_DEBUG + "%s -- lvm_chr_open MINOR: %d VG#: %d mode: 0x%X lock: %d\n", + lvm_name, minor, VG_CHR(minor), file->f_mode, lock); +#endif + + /* super user validation */ + if (!capable(CAP_SYS_ADMIN)) return -EACCES; + + /* Group special file open */ + if (VG_CHR(minor) > MAX_VG) return -ENXIO; + + lvm_chr_open_count++; + return 0; +} /* lvm_chr_open() */ + + +/* + * character device i/o-control routine + * + * Only one changing process can do changing ioctl at one time, + * others will block. + * + */ +static int lvm_chr_ioctl(struct inode *inode, struct file *file, + uint command, ulong a) +{ + int minor = MINOR(inode->i_rdev); + uint extendable, l, v; + void *arg = (void *) a; + lv_t lv; + vg_t* vg_ptr = vg[VG_CHR(minor)]; + + /* otherwise cc will complain about unused variables */ + (void) lvm_lock; + + +#ifdef DEBUG_IOCTL + printk(KERN_DEBUG + "%s -- lvm_chr_ioctl: command: 0x%X MINOR: %d " + "VG#: %d mode: 0x%X\n", + lvm_name, command, minor, VG_CHR(minor), file->f_mode); +#endif + +#ifdef LVM_TOTAL_RESET + if (lvm_reset_spindown > 0) return -EACCES; +#endif + + /* Main command switch */ + switch (command) { + case LVM_LOCK_LVM: + /* lock the LVM */ + return lvm_do_lock_lvm(); + + case LVM_GET_IOP_VERSION: + /* check lvm version to ensure driver/tools+lib + interoperability */ + if (copy_to_user(arg, &lvm_iop_version, sizeof(ushort)) != 0) + return -EFAULT; + return 0; + +#ifdef LVM_TOTAL_RESET + case LVM_RESET: + /* lock reset function */ + lvm_reset_spindown = 1; + for (v = 0; v < ABS_MAX_VG; v++) { + if (vg[v] != NULL) lvm_do_vg_remove(v); + } + +#ifdef MODULE + while (GET_USE_COUNT(&__this_module) < 1) + MOD_INC_USE_COUNT; + while (GET_USE_COUNT(&__this_module) > 1) + MOD_DEC_USE_COUNT; +#endif /* MODULE */ + lock = 0; /* release lock */ + wake_up_interruptible(&lvm_wait); + return 0; +#endif /* LVM_TOTAL_RESET */ + + + case LE_REMAP: + /* remap a logical extent (after moving the physical extent) */ + return lvm_do_le_remap(vg_ptr,arg); + + case PE_LOCK_UNLOCK: + /* lock/unlock i/o to a physical extent to move it to another + physical volume (move's done in user space's pvmove) */ + return lvm_do_pe_lock_unlock(vg_ptr,arg); + + case VG_CREATE: + /* create a VGDA */ + return lvm_do_vg_create(minor, arg); + + case VG_REMOVE: + /* remove an inactive VGDA */ + return lvm_do_vg_remove(minor); + + case VG_EXTEND: + /* extend a volume group */ + return lvm_do_vg_extend(vg_ptr,arg); + + case VG_REDUCE: + /* reduce a volume group */ + return lvm_do_vg_reduce(vg_ptr,arg); + + + case VG_SET_EXTENDABLE: + /* set/clear extendability flag of volume group */ + if (vg_ptr == NULL) return -ENXIO; + if (copy_from_user(&extendable, arg, sizeof(extendable)) != 0) + return -EFAULT; + + if (extendable == VG_EXTENDABLE || + extendable == ~VG_EXTENDABLE) { + if (extendable == VG_EXTENDABLE) + vg_ptr->vg_status |= VG_EXTENDABLE; + else + vg_ptr->vg_status &= ~VG_EXTENDABLE; + } else return -EINVAL; + return 0; + + + case VG_STATUS: + /* get volume group data (only the vg_t struct) */ + if (vg_ptr == NULL) return -ENXIO; + if (copy_to_user(arg, vg_ptr, sizeof(vg_t)) != 0) + return -EFAULT; + return 0; + + + case VG_STATUS_GET_COUNT: + /* get volume group count */ + if (copy_to_user(arg, &vg_count, sizeof(vg_count)) != 0) + return -EFAULT; + return 0; + + + case VG_STATUS_GET_NAMELIST: + /* get volume group count */ + for (l = v = 0; v < ABS_MAX_VG; v++) { + if (vg[v] != NULL) { + if (copy_to_user(arg + l++ * NAME_LEN, + vg[v]->vg_name, + NAME_LEN) != 0) + return -EFAULT; + } + } + return 0; + + + case LV_CREATE: + case LV_REMOVE: + case LV_EXTEND: + case LV_REDUCE: + /* create, remove, extend or reduce a logical volume */ + if (vg_ptr == NULL) return -ENXIO; + if (copy_from_user(&lv_req, arg, sizeof(lv_req)) != 0) + return -EFAULT; + + if (command != LV_REMOVE) { + if (copy_from_user(&lv, lv_req.lv, sizeof(lv_t)) != 0) + return -EFAULT; + } + switch (command) { + case LV_CREATE: + return lvm_do_lv_create(minor, lv_req.lv_name, &lv); + + case LV_REMOVE: + return lvm_do_lv_remove(minor, lv_req.lv_name, -1); + + case LV_EXTEND: + case LV_REDUCE: + return lvm_do_lv_extend_reduce(minor, lv_req.lv_name, &lv); + } + + + case LV_STATUS_BYNAME: + /* get status of a logical volume by name */ + return lvm_do_lv_status_byname(vg_ptr,arg); + + case LV_STATUS_BYINDEX: + /* get status of a logical volume by index */ + return lvm_do_lv_status_byindex(vg_ptr,arg); + + case PV_CHANGE: + /* change a physical volume */ + return lvm_do_pv_change(vg_ptr,arg); + + case PV_STATUS: + /* get physical volume data (pv_t structure only) */ + return lvm_do_pv_status(vg_ptr,arg); + + case PV_FLUSH: + /* physical volume buffer flush/invalidate */ + if (copy_from_user(&pv_flush_req, arg, + sizeof(pv_flush_req)) != 0) + return -EFAULT; + + for ( v = 0; v < ABS_MAX_VG; v++) { + unsigned int p; + if ( vg[v] == NULL) continue; + for ( p = 0; p < vg[v]->pv_max; p++) { + if ( vg[v]->pv[p] != NULL && + strcmp ( vg[v]->pv[p]->pv_name, + pv_flush_req.pv_name) == 0) { + fsync_dev ( vg[v]->pv[p]->pv_dev); + invalidate_buffers ( vg[v]->pv[p]->pv_dev); + return 0; + } + } + } + return 0; + + default: + printk(KERN_WARNING + "%s -- lvm_chr_ioctl: unknown command %x\n", + lvm_name, command); + return -EINVAL; + } + + return 0; +} /* lvm_chr_ioctl */ + + +/* + * character device close routine + */ +static int lvm_chr_close(struct inode *inode, struct file *file) +{ +#ifdef DEBUG + int minor = MINOR(inode->i_rdev); + printk(KERN_DEBUG + "%s -- lvm_chr_close VG#: %d\n", lvm_name, VG_CHR(minor)); +#endif + + lock_kernel(); +#ifdef LVM_TOTAL_RESET + if (lvm_reset_spindown > 0) { + lvm_reset_spindown = 0; + lvm_chr_open_count = 1; + } +#endif + + if (lvm_chr_open_count > 0) lvm_chr_open_count--; + if (lock == current->pid) { + lock = 0; /* release lock */ + wake_up_interruptible(&lvm_wait); + } + unlock_kernel(); + + return 0; +} /* lvm_chr_close() */ + + + +/******************************************************************** + * + * Block device functions + * + ********************************************************************/ + +/* + * block device open routine + */ +static int lvm_blk_open(struct inode *inode, struct file *file) +{ + int minor = MINOR(inode->i_rdev); + lv_t *lv_ptr; + vg_t *vg_ptr = vg[VG_BLK(minor)]; + +#ifdef DEBUG_LVM_BLK_OPEN + printk(KERN_DEBUG + "%s -- lvm_blk_open MINOR: %d VG#: %d LV#: %d mode: 0x%X\n", + lvm_name, minor, VG_BLK(minor), LV_BLK(minor), file->f_mode); +#endif + +#ifdef LVM_TOTAL_RESET + if (lvm_reset_spindown > 0) + return -EPERM; +#endif + + if (vg_ptr != NULL && + (vg_ptr->vg_status & VG_ACTIVE) && + (lv_ptr = vg_ptr->lv[LV_BLK(minor)]) != NULL && + LV_BLK(minor) >= 0 && + LV_BLK(minor) < vg_ptr->lv_max) { + + /* Check parallel LV spindown (LV remove) */ + if (lv_ptr->lv_status & LV_SPINDOWN) return -EPERM; + + /* Check inactive LV and open for read/write */ + if (file->f_mode & O_RDWR) { + if (!(lv_ptr->lv_status & LV_ACTIVE)) return -EPERM; + if (!(lv_ptr->lv_access & LV_WRITE)) return -EACCES; + } + + /* be sure to increment VG counter */ + if (lv_ptr->lv_open == 0) vg_ptr->lv_open++; + lv_ptr->lv_open++; + + MOD_INC_USE_COUNT; + +#ifdef DEBUG_LVM_BLK_OPEN + printk(KERN_DEBUG + "%s -- lvm_blk_open MINOR: %d VG#: %d LV#: %d size: %d\n", + lvm_name, minor, VG_BLK(minor), LV_BLK(minor), + lv_ptr->lv_size); +#endif + + return 0; + } + return -ENXIO; +} /* lvm_blk_open() */ + + +/* + * block device i/o-control routine + */ +static int lvm_blk_ioctl(struct inode *inode, struct file *file, + uint command, ulong a) +{ + int minor = MINOR(inode->i_rdev); + vg_t *vg_ptr = vg[VG_BLK(minor)]; + lv_t *lv_ptr = vg_ptr->lv[LV_BLK(minor)]; + void *arg = (void *) a; + struct hd_geometry *hd = (struct hd_geometry *) a; + +#ifdef DEBUG_IOCTL + printk(KERN_DEBUG + "%s -- lvm_blk_ioctl MINOR: %d command: 0x%X arg: %X " + "VG#: %dl LV#: %d\n", + lvm_name, minor, command, (ulong) arg, + VG_BLK(minor), LV_BLK(minor)); +#endif + + switch (command) { + case BLKGETSIZE: + /* return device size */ +#ifdef DEBUG_IOCTL + printk(KERN_DEBUG + "%s -- lvm_blk_ioctl -- BLKGETSIZE: %u\n", + lvm_name, lv_ptr->lv_size); +#endif + if (put_user(lv_ptr->lv_size, (long *)arg)) + return -EFAULT; + break; + + + case BLKFLSBUF: + /* flush buffer cache */ + if (!capable(CAP_SYS_ADMIN)) return -EACCES; + +#ifdef DEBUG_IOCTL + printk(KERN_DEBUG + "%s -- lvm_blk_ioctl -- BLKFLSBUF\n", lvm_name); +#endif + fsync_dev(inode->i_rdev); + invalidate_buffers(inode->i_rdev); + break; + + + case BLKRASET: + /* set read ahead for block device */ + if (!capable(CAP_SYS_ADMIN)) return -EACCES; + +#ifdef DEBUG_IOCTL + printk(KERN_DEBUG + "%s -- lvm_blk_ioctl -- BLKRASET: %d sectors for %02X:%02X\n", + lvm_name, (long) arg, MAJOR(inode->i_rdev), minor); +#endif + if ((long) arg < LVM_MIN_READ_AHEAD || + (long) arg > LVM_MAX_READ_AHEAD) + return -EINVAL; + read_ahead[MAJOR_NR] = lv_ptr->lv_read_ahead = (long) arg; + break; + + + case BLKRAGET: + /* get current read ahead setting */ +#ifdef DEBUG_IOCTL + printk(KERN_DEBUG + "%s -- lvm_blk_ioctl -- BLKRAGET\n", lvm_name); +#endif + if (put_user(lv_ptr->lv_read_ahead, (long *)arg)) + return -EFAULT; + break; + + + case HDIO_GETGEO: + /* get disk geometry */ +#ifdef DEBUG_IOCTL + printk(KERN_DEBUG + "%s -- lvm_blk_ioctl -- HDIO_GETGEO\n", lvm_name); +#endif + if (hd == NULL) + return -EINVAL; + { + unsigned char heads = 64; + unsigned char sectors = 32; + long start = 0; + short cylinders = lv_ptr->lv_size / heads / sectors; + + if (copy_to_user((char *) &hd->heads, &heads, + sizeof(heads)) != 0 || + copy_to_user((char *) &hd->sectors, §ors, + sizeof(sectors)) != 0 || + copy_to_user((short *) &hd->cylinders, + &cylinders, sizeof(cylinders)) != 0 || + copy_to_user((long *) &hd->start, &start, + sizeof(start)) != 0) + return -EFAULT; + } + +#ifdef DEBUG_IOCTL + printk(KERN_DEBUG + "%s -- lvm_blk_ioctl -- cylinders: %d\n", + lvm_name, lv_ptr->lv_size / heads / sectors); +#endif + break; + + + case LV_SET_ACCESS: + /* set access flags of a logical volume */ + if (!capable(CAP_SYS_ADMIN)) return -EACCES; + lv_ptr->lv_access = (ulong) arg; + break; + + + case LV_SET_STATUS: + /* set status flags of a logical volume */ + if (!capable(CAP_SYS_ADMIN)) return -EACCES; + if (!((ulong) arg & LV_ACTIVE) && lv_ptr->lv_open > 1) + return -EPERM; + lv_ptr->lv_status = (ulong) arg; + break; + + + case LV_SET_ALLOCATION: + /* set allocation flags of a logical volume */ + if (!capable(CAP_SYS_ADMIN)) return -EACCES; + lv_ptr->lv_allocation = (ulong) arg; + break; + + + default: + printk(KERN_WARNING + "%s -- lvm_blk_ioctl: unknown command %d\n", + lvm_name, command); + return -EINVAL; + } + + return 0; +} /* lvm_blk_ioctl() */ + + +/* + * block device close routine + */ +static int lvm_blk_close(struct inode *inode, struct file *file) +{ + int minor = MINOR(inode->i_rdev); + vg_t *vg_ptr = vg[VG_BLK(minor)]; + lv_t *lv_ptr = vg_ptr->lv[LV_BLK(minor)]; + +#ifdef DEBUG + printk(KERN_DEBUG + "%s -- lvm_blk_close MINOR: %d VG#: %d LV#: %d\n", + lvm_name, minor, VG_BLK(minor), LV_BLK(minor)); +#endif + + sync_dev(inode->i_rdev); + if (lv_ptr->lv_open == 1) vg_ptr->lv_open--; + lv_ptr->lv_open--; + + MOD_DEC_USE_COUNT; + + return 0; +} /* lvm_blk_close() */ + + +#if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS +/* + * Support function /proc-Filesystem + */ +#define LVM_PROC_BUF ( i == 0 ? dummy_buf : &buf[sz]) + +static int lvm_proc_get_info(char *page, char **start, off_t pos, int count) +{ + int c, i, l, p, v, vg_counter, pv_counter, lv_counter, lv_open_counter, + lv_open_total, pe_t_bytes, lv_block_exception_t_bytes, seconds; + static off_t sz; + off_t sz_last; + char allocation_flag, inactive_flag, rw_flag, stripes_flag; + char *lv_name, *pv_name; + static char *buf = NULL; + static char dummy_buf[160]; /* sized for 2 lines */ + vg_t *vg_ptr; + lv_t *lv_ptr; + pv_t *pv_ptr; + + +#ifdef DEBUG_LVM_PROC_GET_INFO + printk(KERN_DEBUG + "%s - lvm_proc_get_info CALLED pos: %lu count: %d whence: %d\n", + lvm_name, pos, count, whence); +#endif + + if (pos == 0 || buf == NULL) { + sz_last = vg_counter = pv_counter = lv_counter = lv_open_counter = \ + lv_open_total = pe_t_bytes = lv_block_exception_t_bytes = 0; + + /* search for activity */ + for (v = 0; v < ABS_MAX_VG; v++) { + if ((vg_ptr = vg[v]) != NULL) { + vg_counter++; + pv_counter += vg_ptr->pv_cur; + lv_counter += vg_ptr->lv_cur; + if (vg_ptr->lv_cur > 0) { + for (l = 0; l < vg[v]->lv_max; l++) { + if ((lv_ptr = vg_ptr->lv[l]) != NULL) { + pe_t_bytes += lv_ptr->lv_allocated_le; + if (lv_ptr->lv_block_exception != NULL) + lv_block_exception_t_bytes += lv_ptr->lv_remap_end; + if (lv_ptr->lv_open > 0) { + lv_open_counter++; + lv_open_total += lv_ptr->lv_open; + } + } + } + } + } + } + pe_t_bytes *= sizeof(pe_t); + lv_block_exception_t_bytes *= sizeof(lv_block_exception_t); + + if (buf != NULL) { +#ifdef DEBUG_KFREE + printk(KERN_DEBUG + "%s -- kfree %d\n", lvm_name, __LINE__); +#endif + kfree(buf); + buf = NULL; + } + /* 2 times: first to get size to allocate buffer, + 2nd to fill the malloced buffer */ + for (i = 0; i < 2; i++) { + sz = 0; + sz += sprintf(LVM_PROC_BUF, + "LVM " +#ifdef MODULE + "module" +#else + "driver" +#endif + " %s\n\n" + "Total: %d VG%s %d PV%s %d LV%s ", + lvm_short_version, + vg_counter, vg_counter == 1 ? "" : "s", + pv_counter, pv_counter == 1 ? "" : "s", + lv_counter, lv_counter == 1 ? "" : "s"); + sz += sprintf(LVM_PROC_BUF, + "(%d LV%s open", + lv_open_counter, + lv_open_counter == 1 ? "" : "s"); + if (lv_open_total > 0) + sz += sprintf(LVM_PROC_BUF, + " %d times)\n", + lv_open_total); + else + sz += sprintf(LVM_PROC_BUF, ")"); + sz += sprintf(LVM_PROC_BUF, + "\nGlobal: %lu bytes malloced IOP version: %d ", + vg_counter * sizeof(vg_t) + + pv_counter * sizeof(pv_t) + + lv_counter * sizeof(lv_t) + + pe_t_bytes + lv_block_exception_t_bytes + sz_last, + lvm_iop_version); + + seconds = CURRENT_TIME - loadtime; + if (seconds < 0) + loadtime = CURRENT_TIME + seconds; + if (seconds / 86400 > 0) { + sz += sprintf(LVM_PROC_BUF, "%d day%s ", + seconds / 86400, + seconds / 86400 == 0 || + seconds / 86400 > 1 ? "s" : ""); + } + sz += sprintf(LVM_PROC_BUF, "%d:%02d:%02d active\n", + (seconds % 86400) / 3600, + (seconds % 3600) / 60, + seconds % 60); + + if (vg_counter > 0) { + for (v = 0; v < ABS_MAX_VG; v++) { + /* volume group */ + if ((vg_ptr = vg[v]) != NULL) { + inactive_flag = ' '; + if (!(vg_ptr->vg_status & VG_ACTIVE)) inactive_flag = 'I'; + sz += sprintf(LVM_PROC_BUF, + "\nVG: %c%s [%d PV, %d LV/%d open] " + " PE Size: %d KB\n" + " Usage [KB/PE]: %d /%d total " + "%d /%d used %d /%d free", + inactive_flag, + vg_ptr->vg_name, + vg_ptr->pv_cur, + vg_ptr->lv_cur, + vg_ptr->lv_open, + vg_ptr->pe_size >> 1, + vg_ptr->pe_size * vg_ptr->pe_total >> 1, + vg_ptr->pe_total, + vg_ptr->pe_allocated * vg_ptr->pe_size >> 1, + vg_ptr->pe_allocated, + (vg_ptr->pe_total - vg_ptr->pe_allocated) * + vg_ptr->pe_size >> 1, + vg_ptr->pe_total - vg_ptr->pe_allocated); + + /* physical volumes */ + sz += sprintf(LVM_PROC_BUF, + "\n PV%s ", + vg_ptr->pv_cur == 1 ? ": " : "s:"); + c = 0; + for (p = 0; p < vg_ptr->pv_max; p++) { + if ((pv_ptr = vg_ptr->pv[p]) != NULL) { + inactive_flag = 'A'; + if (!(pv_ptr->pv_status & PV_ACTIVE)) + inactive_flag = 'I'; + allocation_flag = 'A'; + if (!(pv_ptr->pv_allocatable & PV_ALLOCATABLE)) + allocation_flag = 'N'; + pv_name = strchr(pv_ptr->pv_name+1,'/'); + if ( pv_name == 0) pv_name = pv_ptr->pv_name; + else pv_name++; + sz += sprintf(LVM_PROC_BUF, + "[%c%c] %-21s %8d /%-6d " + "%8d /%-6d %8d /%-6d", + inactive_flag, + allocation_flag, + pv_name, + pv_ptr->pe_total * + pv_ptr->pe_size >> 1, + pv_ptr->pe_total, + pv_ptr->pe_allocated * + pv_ptr->pe_size >> 1, + pv_ptr->pe_allocated, + (pv_ptr->pe_total - + pv_ptr->pe_allocated) * + pv_ptr->pe_size >> 1, + pv_ptr->pe_total - + pv_ptr->pe_allocated); + c++; + if (c < vg_ptr->pv_cur) + sz += sprintf(LVM_PROC_BUF, + "\n "); + } + } + + /* logical volumes */ + sz += sprintf(LVM_PROC_BUF, + "\n LV%s ", + vg_ptr->lv_cur == 1 ? ": " : "s:"); + c = 0; + for (l = 0; l < vg[v]->lv_max; l++) { + if ((lv_ptr = vg_ptr->lv[l]) != NULL) { + inactive_flag = 'A'; + if (!(lv_ptr->lv_status & LV_ACTIVE)) + inactive_flag = 'I'; + rw_flag = 'R'; + if (lv_ptr->lv_access & LV_WRITE) + rw_flag = 'W'; + allocation_flag = 'D'; + if (lv_ptr->lv_allocation & LV_CONTIGUOUS) + allocation_flag = 'C'; + stripes_flag = 'L'; + if (lv_ptr->lv_stripes > 1) + stripes_flag = 'S'; + sz += sprintf(LVM_PROC_BUF, + "[%c%c%c%c", + inactive_flag, + rw_flag, + allocation_flag, + stripes_flag); + if (lv_ptr->lv_stripes > 1) + sz += sprintf(LVM_PROC_BUF, "%-2d", + lv_ptr->lv_stripes); + else + sz += sprintf(LVM_PROC_BUF, " "); + lv_name = strrchr(lv_ptr->lv_name, '/'); + if ( lv_name == 0) lv_name = lv_ptr->lv_name; + else lv_name++; + sz += sprintf(LVM_PROC_BUF, "] %-25s", lv_name); + if (strlen(lv_name) > 25) + sz += sprintf(LVM_PROC_BUF, + "\n "); + sz += sprintf(LVM_PROC_BUF, "%9d /%-6d ", + lv_ptr->lv_size >> 1, + lv_ptr->lv_size / vg[v]->pe_size); + + if (lv_ptr->lv_open == 0) + sz += sprintf(LVM_PROC_BUF, "close"); + else + sz += sprintf(LVM_PROC_BUF, "%dx open", + lv_ptr->lv_open); + c++; + if (c < vg_ptr->lv_cur) + sz += sprintf(LVM_PROC_BUF, + "\n "); + } + } + if (vg_ptr->lv_cur == 0) sz += sprintf(LVM_PROC_BUF, "none"); + sz += sprintf(LVM_PROC_BUF, "\n"); + } + } + } + if (buf == NULL) { + if ((buf = vmalloc(sz)) == NULL) { + sz = 0; + return sprintf(page, "%s - vmalloc error at line %d\n", + lvm_name, __LINE__); + } + } + sz_last = sz; + } + } + if (pos > sz - 1) { + vfree(buf); + buf = NULL; + return 0; + } + *start = &buf[pos]; + if (sz - pos < count) + return sz - pos; + else + return count; +} /* lvm_proc_get_info() */ +#endif /* #if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS */ + + +/* + * block device support function for /usr/src/linux/drivers/block/ll_rw_blk.c + * (see init_module/lvm_init) + */ +static int lvm_map(struct buffer_head *bh, int rw) +{ + int minor = MINOR(bh->b_rdev); + ulong index; + ulong pe_start; + ulong size = bh->b_size >> 9; + ulong rsector_tmp = bh->b_rsector; + ulong rsector_sav; + kdev_t rdev_tmp = bh->b_rdev; + kdev_t rdev_sav; + lv_t *lv = vg[VG_BLK(minor)]->lv[LV_BLK(minor)]; + + + if (!(lv->lv_status & LV_ACTIVE)) { + printk(KERN_ALERT + "%s - lvm_map: ll_rw_blk for inactive LV %s\n", + lvm_name, lv->lv_name); + goto error; + } +/* + if ( lv->lv_access & LV_SNAPSHOT) + printk ( "%s -- %02d:%02d block: %lu rw: %d\n", lvm_name, MAJOR ( bh->b_dev), MINOR ( bh->b_dev), bh->b_blocknr, rw); + */ + + /* take care of snapshot chunk writes before + check for writable logical volume */ + if ((lv->lv_access & LV_SNAPSHOT) && + MAJOR(bh->b_rdev) != 0 && + MAJOR(bh->b_rdev) != MAJOR_NR && + (rw == WRITEA || rw == WRITE)) + { + printk ( "%s -- doing snapshot write for %02d:%02d[%02d:%02d] b_blocknr: %lu b_rsector: %lu\n", lvm_name, MAJOR ( bh->b_dev), MINOR ( bh->b_dev), MAJOR ( bh->b_rdev), MINOR ( bh->b_rdev), bh->b_blocknr, bh->b_rsector); + goto error; + } + + if ((rw == WRITE || rw == WRITEA) && + !(lv->lv_access & LV_WRITE)) { + printk(KERN_CRIT + "%s - lvm_map: ll_rw_blk write for readonly LV %s\n", + lvm_name, lv->lv_name); + goto error; + } +#ifdef DEBUG_MAP + printk(KERN_DEBUG + "%s - lvm_map minor:%d *rdev: %02d:%02d *rsector: %lu " + "size:%lu\n", + lvm_name, minor, + MAJOR(rdev_tmp), + MINOR(rdev_tmp), + rsector_tmp, size); +#endif + + if (rsector_tmp + size > lv->lv_size) { + printk(KERN_ALERT + "%s - lvm_map *rsector: %lu or size: %lu wrong for" + " minor: %2d\n", lvm_name, rsector_tmp, size, minor); + goto error; + } + rsector_sav = rsector_tmp; + rdev_sav = rdev_tmp; + +lvm_second_remap: + /* linear mapping */ + if (lv->lv_stripes < 2) { + /* get the index */ + index = rsector_tmp / vg[VG_BLK(minor)]->pe_size; + pe_start = lv->lv_current_pe[index].pe; + rsector_tmp = lv->lv_current_pe[index].pe + + (rsector_tmp % vg[VG_BLK(minor)]->pe_size); + rdev_tmp = lv->lv_current_pe[index].dev; + +#ifdef DEBUG_MAP + printk(KERN_DEBUG + "lv_current_pe[%ld].pe: %ld rdev: %02d:%02d rsector:%ld\n", + index, + lv->lv_current_pe[index].pe, + MAJOR(rdev_tmp), + MINOR(rdev_tmp), + rsector_tmp); +#endif + + /* striped mapping */ + } else { + ulong stripe_index; + ulong stripe_length; + + stripe_length = vg[VG_BLK(minor)]->pe_size * lv->lv_stripes; + stripe_index = (rsector_tmp % stripe_length) / lv->lv_stripesize; + index = rsector_tmp / stripe_length + + (stripe_index % lv->lv_stripes) * + (lv->lv_allocated_le / lv->lv_stripes); + pe_start = lv->lv_current_pe[index].pe; + rsector_tmp = lv->lv_current_pe[index].pe + + (rsector_tmp % stripe_length) - + (stripe_index % lv->lv_stripes) * lv->lv_stripesize - + stripe_index / lv->lv_stripes * + (lv->lv_stripes - 1) * lv->lv_stripesize; + rdev_tmp = lv->lv_current_pe[index].dev; + } + +#ifdef DEBUG_MAP + printk(KERN_DEBUG + "lv_current_pe[%ld].pe: %ld rdev: %02d:%02d rsector:%ld\n" + "stripe_length: %ld stripe_index: %ld\n", + index, + lv->lv_current_pe[index].pe, + MAJOR(rdev_tmp), + MINOR(rdev_tmp), + rsector_tmp, + stripe_length, + stripe_index); +#endif + + /* handle physical extents on the move */ + if (pe_lock_req.lock == LOCK_PE) { + if (rdev_tmp == pe_lock_req.data.pv_dev && + rsector_tmp >= pe_lock_req.data.pv_offset && + rsector_tmp < (pe_lock_req.data.pv_offset + + vg[VG_BLK(minor)]->pe_size)) { + sleep_on(&lvm_map_wait); + rsector_tmp = rsector_sav; + rdev_tmp = rdev_sav; + goto lvm_second_remap; + } + } + /* statistic */ + if (rw == WRITE || rw == WRITEA) + lv->lv_current_pe[index].writes++; + else + lv->lv_current_pe[index].reads++; + + /* snapshot volume exception handling on physical device address base */ + if (lv->lv_access & (LV_SNAPSHOT | LV_SNAPSHOT_ORG)) { + /* original logical volume */ + if (lv->lv_access & LV_SNAPSHOT_ORG) { + if (rw == WRITE || rw == WRITEA) + { + lv_t *lv_ptr; + + /* start with first snapshot and loop thrugh all of them */ + for (lv_ptr = lv->lv_snapshot_next; + lv_ptr != NULL; + lv_ptr = lv_ptr->lv_snapshot_next) { + down(&lv->lv_snapshot_org->lv_snapshot_sem); + /* do we still have exception storage for this snapshot free? */ + if (lv_ptr->lv_block_exception != NULL) { + rdev_sav = rdev_tmp; + rsector_sav = rsector_tmp; + if (!lvm_snapshot_remap_block(&rdev_tmp, + &rsector_tmp, + pe_start, + lv_ptr)) { + /* create a new mapping */ + lvm_snapshot_COW(rdev_tmp, + rsector_tmp, + pe_start, + rsector_sav, + lv_ptr); + } + rdev_tmp = rdev_sav; + rsector_tmp = rsector_sav; + } + up(&lv->lv_snapshot_org->lv_snapshot_sem); + } + } + } else { + /* remap snapshot logical volume */ + down(&lv->lv_snapshot_sem); + if (lv->lv_block_exception != NULL) + lvm_snapshot_remap_block(&rdev_tmp, &rsector_tmp, pe_start, lv); + up(&lv->lv_snapshot_sem); + } + } + bh->b_rdev = rdev_tmp; + bh->b_rsector = rsector_tmp; + + return 1; + + error: + buffer_IO_error(bh); + return -1; +} /* lvm_map() */ + + +/* + * internal support functions + */ + +#ifdef LVM_HD_NAME +/* + * generate "hard disk" name + */ +void lvm_hd_name(char *buf, int minor) +{ + int len = 0; + lv_t *lv_ptr; + + if (vg[VG_BLK(minor)] == NULL || + (lv_ptr = vg[VG_BLK(minor)]->lv[LV_BLK(minor)]) == NULL) + return; + len = strlen(lv_ptr->lv_name) - 5; + memcpy(buf, &lv_ptr->lv_name[5], len); + buf[len] = 0; + return; +} +#endif + + +/* + * this one never should be called... + */ +static void lvm_dummy_device_request(request_queue_t * t) +{ + printk(KERN_EMERG + "%s -- oops, got lvm request for %02d:%02d [sector: %lu]\n", + lvm_name, + MAJOR(CURRENT->rq_dev), + MINOR(CURRENT->rq_dev), + CURRENT->sector); + return; +} + + +/* + * make request function + */ +static int lvm_make_request_fn(request_queue_t *q, int rw, struct buffer_head *bh) +{ + lvm_map(bh, rw); + return 1; +} + +/* + * plug device function is a noop because plugging has to happen + * in the queue of the physical blockdevice to allow the + * elevator to do a better job. + */ +static void lvm_plug_device_noop(request_queue_t *q, kdev_t dev) { } + +/******************************************************************** + * + * Character device support functions + * + ********************************************************************/ +/* + * character device support function logical volume manager lock + */ +static int lvm_do_lock_lvm(void) +{ +lock_try_again: + spin_lock(&lvm_lock); + if (lock != 0 && lock != current->pid) { +#ifdef DEBUG_IOCTL + printk(KERN_INFO "lvm_do_lock_lvm: %s is locked by pid %d ...\n", + lvm_name, lock); +#endif + spin_unlock(&lvm_lock); + interruptible_sleep_on(&lvm_wait); + if (current->sigpending != 0) + return -EINTR; +#ifdef LVM_TOTAL_RESET + if (lvm_reset_spindown > 0) + return -EACCES; +#endif + goto lock_try_again; + } + lock = current->pid; + spin_unlock(&lvm_lock); + return 0; +} /* lvm_do_lock_lvm */ + + +/* + * character device support function lock/unlock physical extend + */ +static int lvm_do_pe_lock_unlock(vg_t *vg_ptr, void *arg) +{ + uint p; + + if (vg_ptr == NULL) return -ENXIO; + if (copy_from_user(&pe_lock_req, arg, + sizeof(pe_lock_req_t)) != 0) return -EFAULT; + + switch (pe_lock_req.lock) { + case LOCK_PE: + for (p = 0; p < vg_ptr->pv_max; p++) { + if (vg_ptr->pv[p] != NULL && + pe_lock_req.data.pv_dev == + vg_ptr->pv[p]->pv_dev) + break; + } + if (p == vg_ptr->pv_max) return -ENXIO; + + pe_lock_req.lock = UNLOCK_PE; + fsync_dev(pe_lock_req.data.lv_dev); + pe_lock_req.lock = LOCK_PE; + break; + + case UNLOCK_PE: + pe_lock_req.lock = UNLOCK_PE; + pe_lock_req.data.lv_dev = pe_lock_req.data.pv_dev = 0; + pe_lock_req.data.pv_offset = 0; + wake_up(&lvm_map_wait); + break; + + default: + return -EINVAL; + } + return 0; +} + + +/* + * character device support function logical extend remap + */ +static int lvm_do_le_remap(vg_t *vg_ptr, void *arg) +{ + uint l, le; + lv_t *lv_ptr; + + if (vg_ptr == NULL) return -ENXIO; + if (copy_from_user(&le_remap_req, arg, + sizeof(le_remap_req_t)) != 0) + return -EFAULT; + + for (l = 0; l < vg_ptr->lv_max; l++) { + lv_ptr = vg_ptr->lv[l]; + if (lv_ptr != NULL && + strcmp(lv_ptr->lv_name, + le_remap_req.lv_name) == 0) { + for (le = 0; le < lv_ptr->lv_allocated_le; + le++) { + if (lv_ptr->lv_current_pe[le].dev == + le_remap_req.old_dev && + lv_ptr->lv_current_pe[le].pe == + le_remap_req.old_pe) { + lv_ptr->lv_current_pe[le].dev = + le_remap_req.new_dev; + lv_ptr->lv_current_pe[le].pe = + le_remap_req.new_pe; + return 0; + } + } + return -EINVAL; + } + } + return -ENXIO; +} /* lvm_do_le_remap() */ + + +/* + * character device support function VGDA create + */ +int lvm_do_vg_create(int minor, void *arg) +{ + int snaporg_minor = 0; + ulong l, p; + lv_t lv; + vg_t *vg_ptr; + pv_t *pv_ptr; + lv_t *lv_ptr; + + if (vg[VG_CHR(minor)] != NULL) return -EPERM; + + if ((vg_ptr = kmalloc(sizeof(vg_t),GFP_KERNEL)) == NULL) { + printk(KERN_CRIT + "%s -- VG_CREATE: kmalloc error VG at line %d\n", + lvm_name, __LINE__); + return -ENOMEM; + } + /* get the volume group structure */ + if (copy_from_user(vg_ptr, arg, sizeof(vg_t)) != 0) { + kfree(vg_ptr); + return -EFAULT; + } + + vg_devfs_handle[vg_ptr->vg_number] = devfs_mk_dir(0, vg_ptr->vg_name, NULL); + ch_devfs_handle[vg_ptr->vg_number] = devfs_register( + vg_devfs_handle[vg_ptr->vg_number] , "group", + DEVFS_FL_DEFAULT, LVM_CHAR_MAJOR, vg_ptr->vg_number, + S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, + &lvm_chr_fops, NULL); + + /* we are not that active so far... */ + vg_ptr->vg_status &= ~VG_ACTIVE; + vg[VG_CHR(minor)] = vg_ptr; + + vg[VG_CHR(minor)]->pe_allocated = 0; + if (vg_ptr->pv_max > ABS_MAX_PV) { + printk(KERN_WARNING + "%s -- Can't activate VG: ABS_MAX_PV too small\n", + lvm_name); + kfree(vg_ptr); + vg[VG_CHR(minor)] = NULL; + return -EPERM; + } + if (vg_ptr->lv_max > ABS_MAX_LV) { + printk(KERN_WARNING + "%s -- Can't activate VG: ABS_MAX_LV too small for %u\n", + lvm_name, vg_ptr->lv_max); + kfree(vg_ptr); + vg_ptr = NULL; + return -EPERM; + } + /* get the physical volume structures */ + vg_ptr->pv_act = vg_ptr->pv_cur = 0; + for (p = 0; p < vg_ptr->pv_max; p++) { + /* user space address */ + if ((pvp = vg_ptr->pv[p]) != NULL) { + pv_ptr = vg_ptr->pv[p] = kmalloc(sizeof(pv_t),GFP_KERNEL); + if (pv_ptr == NULL) { + printk(KERN_CRIT + "%s -- VG_CREATE: kmalloc error PV at line %d\n", + lvm_name, __LINE__); + lvm_do_vg_remove(minor); + return -ENOMEM; + } + if (copy_from_user(pv_ptr, pvp, sizeof(pv_t)) != 0) { + lvm_do_vg_remove(minor); + return -EFAULT; + } + /* We don't need the PE list + in kernel space as with LVs pe_t list (see below) */ + pv_ptr->pe = NULL; + pv_ptr->pe_allocated = 0; + pv_ptr->pv_status = PV_ACTIVE; + vg_ptr->pv_act++; + vg_ptr->pv_cur++; + +#ifdef LVM_GET_INODE + /* insert a dummy inode for fs_may_mount */ + pv_ptr->inode = lvm_get_inode(pv_ptr->pv_dev); +#endif + } + } + + /* get the logical volume structures */ + vg_ptr->lv_cur = 0; + for (l = 0; l < vg_ptr->lv_max; l++) { + /* user space address */ + if ((lvp = vg_ptr->lv[l]) != NULL) { + if (copy_from_user(&lv, lvp, sizeof(lv_t)) != 0) { + lvm_do_vg_remove(minor); + return -EFAULT; + } + vg_ptr->lv[l] = NULL; + if (lvm_do_lv_create(minor, lv.lv_name, &lv) != 0) { + lvm_do_vg_remove(minor); + return -EFAULT; + } + } + } + + /* Second path to correct snapshot logical volumes which are not + in place during first path above */ + for (l = 0; l < vg_ptr->lv_max; l++) { + if ((lv_ptr = vg_ptr->lv[l]) != NULL && + vg_ptr->lv[l]->lv_access & LV_SNAPSHOT) { + snaporg_minor = lv_ptr->lv_snapshot_minor; + if (vg_ptr->lv[LV_BLK(snaporg_minor)] != NULL) { + /* get pointer to original logical volume */ + lv_ptr = vg_ptr->lv[l]->lv_snapshot_org = + vg_ptr->lv[LV_BLK(snaporg_minor)]; + + /* set necessary fields of original logical volume */ + lv_ptr->lv_access |= LV_SNAPSHOT_ORG; + lv_ptr->lv_snapshot_minor = 0; + lv_ptr->lv_snapshot_org = lv_ptr; + lv_ptr->lv_snapshot_prev = NULL; + + /* find last snapshot logical volume in the chain */ + while (lv_ptr->lv_snapshot_next != NULL) + lv_ptr = lv_ptr->lv_snapshot_next; + + /* set back pointer to this last one in our new logical volume */ + vg_ptr->lv[l]->lv_snapshot_prev = lv_ptr; + + /* last logical volume now points to our new snapshot volume */ + lv_ptr->lv_snapshot_next = vg_ptr->lv[l]; + + /* now point to the new one */ + lv_ptr = lv_ptr->lv_snapshot_next; + + /* set necessary fields of new snapshot logical volume */ + lv_ptr->lv_snapshot_next = NULL; + lv_ptr->lv_current_pe = + vg_ptr->lv[LV_BLK(snaporg_minor)]->lv_current_pe; + lv_ptr->lv_allocated_le = + vg_ptr->lv[LV_BLK(snaporg_minor)]->lv_allocated_le; + lv_ptr->lv_current_le = + vg_ptr->lv[LV_BLK(snaporg_minor)]->lv_current_le; + lv_ptr->lv_size = + vg_ptr->lv[LV_BLK(snaporg_minor)]->lv_size; + } + } + } + + vg_count++; + + /* let's go active */ + vg_ptr->vg_status |= VG_ACTIVE; + + MOD_INC_USE_COUNT; + + return 0; +} /* lvm_do_vg_create() */ + + +/* + * character device support function VGDA extend + */ +static int lvm_do_vg_extend(vg_t *vg_ptr, void *arg) +{ + uint p; + pv_t *pv_ptr; + + if (vg_ptr == NULL) return -ENXIO; + if (vg_ptr->pv_cur < vg_ptr->pv_max) { + for (p = 0; p < vg_ptr->pv_max; p++) { + if (vg_ptr->pv[p] == NULL) { + if ((pv_ptr = vg_ptr->pv[p] = kmalloc(sizeof(pv_t),GFP_KERNEL)) == NULL) { + printk(KERN_CRIT + "%s -- VG_EXTEND: kmalloc error PV at line %d\n", + lvm_name, __LINE__); + return -ENOMEM; + } + if (copy_from_user(pv_ptr, arg, sizeof(pv_t)) != 0) { + kfree(pv_ptr); + vg_ptr->pv[p] = NULL; + return -EFAULT; + } + + pv_ptr->pv_status = PV_ACTIVE; + /* We don't need the PE list + in kernel space like LVs pe_t list */ + pv_ptr->pe = NULL; + vg_ptr->pv_cur++; + vg_ptr->pv_act++; + vg_ptr->pe_total += + pv_ptr->pe_total; +#ifdef LVM_GET_INODE + /* insert a dummy inode for fs_may_mount */ + pv_ptr->inode = lvm_get_inode(pv_ptr->pv_dev); +#endif + return 0; + } + } + } +return -EPERM; +} /* lvm_do_vg_extend() */ + + +/* + * character device support function VGDA reduce + */ +static int lvm_do_vg_reduce(vg_t *vg_ptr, void *arg) +{ + uint p; + pv_t *pv_ptr; + + if (vg_ptr == NULL) return -ENXIO; + if (copy_from_user(pv_name, arg, sizeof(pv_name)) != 0) + return -EFAULT; + + for (p = 0; p < vg_ptr->pv_max; p++) { + pv_ptr = vg_ptr->pv[p]; + if (pv_ptr != NULL && + strcmp(pv_ptr->pv_name, + pv_name) == 0) { + if (pv_ptr->lv_cur > 0) return -EPERM; + vg_ptr->pe_total -= + pv_ptr->pe_total; + vg_ptr->pv_cur--; + vg_ptr->pv_act--; +#ifdef LVM_GET_INODE + lvm_clear_inode(pv_ptr->inode); +#endif + kfree(pv_ptr); + /* Make PV pointer array contiguous */ + for (; p < vg_ptr->pv_max - 1; p++) + vg_ptr->pv[p] = vg_ptr->pv[p + 1]; + vg_ptr->pv[p + 1] = NULL; + return 0; + } + } + return -ENXIO; +} /* lvm_do_vg_reduce */ + + +/* + * character device support function VGDA remove + */ +static int lvm_do_vg_remove(int minor) +{ + int i; + vg_t *vg_ptr = vg[VG_CHR(minor)]; + pv_t *pv_ptr; + + if (vg_ptr == NULL) return -ENXIO; + +#ifdef LVM_TOTAL_RESET + if (vg_ptr->lv_open > 0 && lvm_reset_spindown == 0) +#else + if (vg_ptr->lv_open > 0) +#endif + return -EPERM; + + /* let's go inactive */ + vg_ptr->vg_status &= ~VG_ACTIVE; + + devfs_unregister (ch_devfs_handle[vg_ptr->vg_number]); + devfs_unregister (vg_devfs_handle[vg_ptr->vg_number]); + + /* free LVs */ + /* first free snapshot logical volumes */ + for (i = 0; i < vg_ptr->lv_max; i++) { + if (vg_ptr->lv[i] != NULL && + vg_ptr->lv[i]->lv_access & LV_SNAPSHOT) { + lvm_do_lv_remove(minor, NULL, i); + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(1); + } + } + /* then free the rest of the LVs */ + for (i = 0; i < vg_ptr->lv_max; i++) { + if (vg_ptr->lv[i] != NULL) { + lvm_do_lv_remove(minor, NULL, i); + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(1); + } + } + + /* free PVs */ + for (i = 0; i < vg_ptr->pv_max; i++) { + if ((pv_ptr = vg_ptr->pv[i]) != NULL) { +#ifdef DEBUG_KFREE + printk(KERN_DEBUG + "%s -- kfree %d\n", lvm_name, __LINE__); +#endif +#ifdef LVM_GET_INODE + lvm_clear_inode(pv_ptr->inode); +#endif + kfree(pv_ptr); + vg[VG_CHR(minor)]->pv[i] = NULL; + } + } + +#ifdef DEBUG_KFREE + printk(KERN_DEBUG "%s -- kfree %d\n", lvm_name, __LINE__); +#endif + kfree(vg_ptr); + vg[VG_CHR(minor)] = NULL; + + vg_count--; + + MOD_DEC_USE_COUNT; + + return 0; +} /* lvm_do_vg_remove() */ + + +/* + * character device support function logical volume create + */ +static int lvm_do_lv_create(int minor, char *lv_name, lv_t *lv) +{ + int l, le, l_new, p, size; + ulong lv_status_save; + char *lv_tmp, *lv_buf; + lv_block_exception_t *lvbe = lv->lv_block_exception; + vg_t *vg_ptr = vg[VG_CHR(minor)]; + lv_t *lv_ptr = NULL; + + if ((pep = lv->lv_current_pe) == NULL) return -EINVAL; + if (lv->lv_chunk_size > LVM_SNAPSHOT_MAX_CHUNK) + return -EINVAL; + + for (l = 0; l < vg_ptr->lv_max; l++) { + if (vg_ptr->lv[l] != NULL && + strcmp(vg_ptr->lv[l]->lv_name, lv_name) == 0) + return -EEXIST; + } + + /* in case of lv_remove(), lv_create() pair; for eg. lvrename does this */ + l_new = -1; + if (vg_ptr->lv[lv->lv_number] == NULL) + l_new = lv->lv_number; + else { + for (l = 0; l < vg_ptr->lv_max; l++) { + if (vg_ptr->lv[l] == NULL) + if (l_new == -1) l_new = l; + } + } + if (l_new == -1) return -EPERM; + else l = l_new; + + if ((lv_ptr = kmalloc(sizeof(lv_t),GFP_KERNEL)) == NULL) {; + printk(KERN_CRIT "%s -- LV_CREATE: kmalloc error LV at line %d\n", + lvm_name, __LINE__); + return -ENOMEM; + } + /* copy preloaded LV */ + memcpy((char *) lv_ptr, (char *) lv, sizeof(lv_t)); + + lv_status_save = lv_ptr->lv_status; + lv_ptr->lv_status &= ~LV_ACTIVE; + lv_ptr->lv_snapshot_org = \ + lv_ptr->lv_snapshot_prev = \ + lv_ptr->lv_snapshot_next = NULL; + lv_ptr->lv_block_exception = NULL; + init_MUTEX(&lv_ptr->lv_snapshot_sem); + vg_ptr->lv[l] = lv_ptr; + + /* get the PE structures from user space if this + is no snapshot logical volume */ + if (!(lv_ptr->lv_access & LV_SNAPSHOT)) { + size = lv_ptr->lv_allocated_le * sizeof(pe_t); + if ((lv_ptr->lv_current_pe = vmalloc(size)) == NULL) { + printk(KERN_CRIT + "%s -- LV_CREATE: vmalloc error LV_CURRENT_PE of %d Byte " + "at line %d\n", + lvm_name, size, __LINE__); +#ifdef DEBUG_KFREE + printk(KERN_DEBUG "%s -- kfree %d\n", lvm_name, __LINE__); +#endif + kfree(lv_ptr); + vg[VG_CHR(minor)]->lv[l] = NULL; + return -ENOMEM; + } + if (copy_from_user(lv_ptr->lv_current_pe, pep, size)) { + vfree(lv_ptr->lv_current_pe); + kfree(lv_ptr); + vg_ptr->lv[l] = NULL; + return -EFAULT; + } + /* correct the PE count in PVs */ + for (le = 0; le < lv_ptr->lv_allocated_le; le++) { + vg_ptr->pe_allocated++; + for (p = 0; p < vg_ptr->pv_cur; p++) { + if (vg_ptr->pv[p]->pv_dev == + lv_ptr->lv_current_pe[le].dev) + vg_ptr->pv[p]->pe_allocated++; + } + } + } else { + /* Get snapshot exception data and block list */ + if (lvbe != NULL) { + lv_ptr->lv_snapshot_org = + vg_ptr->lv[LV_BLK(lv_ptr->lv_snapshot_minor)]; + if (lv_ptr->lv_snapshot_org != NULL) { + size = lv_ptr->lv_remap_end * sizeof(lv_block_exception_t); + if ((lv_ptr->lv_block_exception = vmalloc(size)) == NULL) { + printk(KERN_CRIT + "%s -- lvm_do_lv_create: vmalloc error LV_BLOCK_EXCEPTION " + "of %d byte at line %d\n", + lvm_name, size, __LINE__); +#ifdef DEBUG_KFREE + printk(KERN_DEBUG "%s -- kfree %d\n", lvm_name, __LINE__); +#endif + kfree(lv_ptr); + vg_ptr->lv[l] = NULL; + return -ENOMEM; + } + if (copy_from_user(lv_ptr->lv_block_exception, lvbe, size)) { + vfree(lv_ptr->lv_block_exception); + kfree(lv_ptr); + vg[VG_CHR(minor)]->lv[l] = NULL; + return -EFAULT; + } + /* get pointer to original logical volume */ + lv_ptr = lv_ptr->lv_snapshot_org; + + lv_ptr->lv_snapshot_minor = 0; + lv_ptr->lv_snapshot_org = lv_ptr; + lv_ptr->lv_snapshot_prev = NULL; + /* walk thrugh the snapshot list */ + while (lv_ptr->lv_snapshot_next != NULL) + lv_ptr = lv_ptr->lv_snapshot_next; + /* now lv_ptr points to the last existing snapshot in the chain */ + vg_ptr->lv[l]->lv_snapshot_prev = lv_ptr; + /* our new one now back points to the previous last in the chain */ + lv_ptr = vg_ptr->lv[l]; + /* now lv_ptr points to our new last snapshot logical volume */ + lv_ptr->lv_snapshot_org = lv_ptr->lv_snapshot_prev->lv_snapshot_org; + lv_ptr->lv_snapshot_next = NULL; + lv_ptr->lv_current_pe = lv_ptr->lv_snapshot_org->lv_current_pe; + lv_ptr->lv_allocated_le = lv_ptr->lv_snapshot_org->lv_allocated_le; + lv_ptr->lv_current_le = lv_ptr->lv_snapshot_org->lv_current_le; + lv_ptr->lv_size = lv_ptr->lv_snapshot_org->lv_size; + lv_ptr->lv_stripes = lv_ptr->lv_snapshot_org->lv_stripes; + lv_ptr->lv_stripesize = lv_ptr->lv_snapshot_org->lv_stripesize; + { + int err = lvm_snapshot_alloc(lv_ptr); + if (err) + { + vfree(lv_ptr->lv_block_exception); + kfree(lv_ptr); + vg[VG_CHR(minor)]->lv[l] = NULL; + return err; + } + } + } else { + vfree(lv_ptr->lv_block_exception); + kfree(lv_ptr); + vg_ptr->lv[l] = NULL; + return -EFAULT; + } + } else { + kfree(vg_ptr->lv[l]); + vg_ptr->lv[l] = NULL; + return -EINVAL; + } + } /* if ( vg[VG_CHR(minor)]->lv[l]->lv_access & LV_SNAPSHOT) */ + + lv_ptr = vg_ptr->lv[l]; + lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].start_sect = 0; + lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].nr_sects = lv_ptr->lv_size; + lvm_size[MINOR(lv_ptr->lv_dev)] = lv_ptr->lv_size >> 1; + vg_lv_map[MINOR(lv_ptr->lv_dev)].vg_number = vg_ptr->vg_number; + vg_lv_map[MINOR(lv_ptr->lv_dev)].lv_number = lv_ptr->lv_number; + read_ahead[MAJOR_NR] = lv_ptr->lv_read_ahead = LVM_CORRECT_READ_AHEAD(lv_ptr->lv_read_ahead); + vg_ptr->lv_cur++; + lv_ptr->lv_status = lv_status_save; + + strtok(lv->lv_name, "/"); /* /dev */ + + while((lv_tmp = strtok(NULL, "/")) != NULL) + lv_buf = lv_tmp; + + lv_devfs_handle[lv->lv_number] = devfs_register( + vg_devfs_handle[vg_ptr->vg_number], lv_buf, + DEVFS_FL_DEFAULT, LVM_BLK_MAJOR, lv->lv_number, + S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP, + &lvm_blk_dops, NULL); + + /* optionally add our new snapshot LV */ + if (lv_ptr->lv_access & LV_SNAPSHOT) { + /* sync the original logical volume */ + fsync_dev(lv_ptr->lv_snapshot_org->lv_dev); + /* put ourselve into the chain */ + lv_ptr->lv_snapshot_prev->lv_snapshot_next = lv_ptr; + lv_ptr->lv_snapshot_org->lv_access |= LV_SNAPSHOT_ORG; + } + return 0; +} /* lvm_do_lv_create() */ + + +/* + * character device support function logical volume remove + */ +static int lvm_do_lv_remove(int minor, char *lv_name, int l) +{ + uint le, p; + vg_t *vg_ptr = vg[VG_CHR(minor)]; + lv_t *lv_ptr; + + if (l == -1) { + for (l = 0; l < vg_ptr->lv_max; l++) { + if (vg_ptr->lv[l] != NULL && + strcmp(vg_ptr->lv[l]->lv_name, lv_name) == 0) { + break; + } + } + } + if (l == vg_ptr->lv_max) return -ENXIO; + + lv_ptr = vg_ptr->lv[l]; +#ifdef LVM_TOTAL_RESET + if (lv_ptr->lv_open > 0 && lvm_reset_spindown == 0) +#else + if (lv_ptr->lv_open > 0) +#endif + return -EBUSY; + + /* check for deletion of snapshot source while + snapshot volume still exists */ + if ((lv_ptr->lv_access & LV_SNAPSHOT_ORG) && + lv_ptr->lv_snapshot_next != NULL) + return -EPERM; + + lv_ptr->lv_status |= LV_SPINDOWN; + + /* sync the buffers */ + fsync_dev(lv_ptr->lv_dev); + + lv_ptr->lv_status &= ~LV_ACTIVE; + + /* invalidate the buffers */ + invalidate_buffers(lv_ptr->lv_dev); + + /* reset generic hd */ + lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].start_sect = -1; + lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].nr_sects = 0; + lvm_size[MINOR(lv_ptr->lv_dev)] = 0; + + /* reset VG/LV mapping */ + vg_lv_map[MINOR(lv_ptr->lv_dev)].vg_number = ABS_MAX_VG; + vg_lv_map[MINOR(lv_ptr->lv_dev)].lv_number = -1; + + /* correct the PE count in PVs if this is no snapshot logical volume */ + if (!(lv_ptr->lv_access & LV_SNAPSHOT)) { + /* only if this is no snapshot logical volume because + we share the lv_current_pe[] structs with the + original logical volume */ + for (le = 0; le < lv_ptr->lv_allocated_le; le++) { + vg_ptr->pe_allocated--; + for (p = 0; p < vg_ptr->pv_cur; p++) { + if (vg_ptr->pv[p]->pv_dev == + lv_ptr->lv_current_pe[le].dev) + vg_ptr->pv[p]->pe_allocated--; + } + } + vfree(lv_ptr->lv_current_pe); + /* LV_SNAPSHOT */ + } else { + /* remove this snapshot logical volume from the chain */ + lv_ptr->lv_snapshot_prev->lv_snapshot_next = lv_ptr->lv_snapshot_next; + if (lv_ptr->lv_snapshot_next != NULL) { + lv_ptr->lv_snapshot_next->lv_snapshot_prev = + lv_ptr->lv_snapshot_prev; + } + /* no more snapshots? */ + if (lv_ptr->lv_snapshot_org->lv_snapshot_next == NULL) + lv_ptr->lv_snapshot_org->lv_access &= ~LV_SNAPSHOT_ORG; + lvm_snapshot_release(lv_ptr); + } + + devfs_unregister(lv_devfs_handle[lv_ptr->lv_number]); + +#ifdef DEBUG_KFREE + printk(KERN_DEBUG "%s -- kfree %d\n", lvm_name, __LINE__); +#endif + kfree(lv_ptr); + vg_ptr->lv[l] = NULL; + vg_ptr->lv_cur--; + return 0; +} /* lvm_do_lv_remove() */ + + +/* + * character device support function logical volume extend / reduce + */ +static int lvm_do_lv_extend_reduce(int minor, char *lv_name, lv_t *lv) +{ + int l, le, p, size, old_allocated_le; + uint32_t end, lv_status_save; + vg_t *vg_ptr = vg[VG_CHR(minor)]; + lv_t *lv_ptr; + pe_t *pe; + + if ((pep = lv->lv_current_pe) == NULL) return -EINVAL; + + for (l = 0; l < vg_ptr->lv_max; l++) { + if (vg_ptr->lv[l] != NULL && + strcmp(vg_ptr->lv[l]->lv_name, lv_name) == 0) + break; + } + if (l == vg_ptr->lv_max) return -ENXIO; + lv_ptr = vg_ptr->lv[l]; + + /* check for active snapshot */ + if (lv->lv_access & (LV_SNAPSHOT | LV_SNAPSHOT_ORG)) return -EPERM; + + if ((pe = vmalloc(size = lv->lv_current_le * sizeof(pe_t))) == NULL) { + printk(KERN_CRIT + "%s -- lvm_do_lv_extend_reduce: vmalloc error LV_CURRENT_PE " + "of %d Byte at line %d\n", + lvm_name, size, __LINE__); + return -ENOMEM; + } + /* get the PE structures from user space */ + if (copy_from_user(pe, pep, size)) { + vfree(pe); + return -EFAULT; + } + +#ifdef DEBUG + printk(KERN_DEBUG + "%s -- fsync_dev and " + "invalidate_buffers for %s [%s] in %s\n", + lvm_name, lv_ptr->lv_name, + kdevname(lv_ptr->lv_dev), + vg_ptr->vg_name); +#endif + + lv_ptr->lv_status |= LV_SPINDOWN; + fsync_dev(lv_ptr->lv_dev); + lv_ptr->lv_status &= ~LV_ACTIVE; + invalidate_buffers(lv_ptr->lv_dev); + + /* reduce allocation counters on PV(s) */ + for (le = 0; le < lv_ptr->lv_allocated_le; le++) { + vg_ptr->pe_allocated--; + for (p = 0; p < vg_ptr->pv_cur; p++) { + if (vg_ptr->pv[p]->pv_dev == + lv_ptr->lv_current_pe[le].dev) { + vg_ptr->pv[p]->pe_allocated--; + break; + } + } + } + + + /* save pointer to "old" lv/pe pointer array */ + pep1 = lv_ptr->lv_current_pe; + end = lv_ptr->lv_current_le; + + /* save open counter */ + lv_open = lv_ptr->lv_open; + + /* save # of old allocated logical extents */ + old_allocated_le = lv_ptr->lv_allocated_le; + + /* copy preloaded LV */ + lv_status_save = lv->lv_status; + lv->lv_status |= LV_SPINDOWN; + lv->lv_status &= ~LV_ACTIVE; + memcpy((char *) lv_ptr, (char *) lv, sizeof(lv_t)); + lv_ptr->lv_current_pe = pe; + lv_ptr->lv_open = lv_open; + + /* save availiable i/o statistic data */ + /* linear logical volume */ + if (lv_ptr->lv_stripes < 2) { + /* Check what last LE shall be used */ + if (end > lv_ptr->lv_current_le) end = lv_ptr->lv_current_le; + for (le = 0; le < end; le++) { + lv_ptr->lv_current_pe[le].reads = pep1[le].reads; + lv_ptr->lv_current_pe[le].writes = pep1[le].writes; + } + /* striped logical volume */ + } else { + uint i, j, source, dest, end, old_stripe_size, new_stripe_size; + + old_stripe_size = old_allocated_le / lv_ptr->lv_stripes; + new_stripe_size = lv_ptr->lv_allocated_le / lv_ptr->lv_stripes; + end = old_stripe_size; + if (end > new_stripe_size) end = new_stripe_size; + for (i = source = dest = 0; + i < lv_ptr->lv_stripes; i++) { + for (j = 0; j < end; j++) { + lv_ptr->lv_current_pe[dest + j].reads = + pep1[source + j].reads; + lv_ptr->lv_current_pe[dest + j].writes = + pep1[source + j].writes; + } + source += old_stripe_size; + dest += new_stripe_size; + } + } + vfree(pep1); + pep1 = NULL; + + + /* extend the PE count in PVs */ + for (le = 0; le < lv_ptr->lv_allocated_le; le++) { + vg_ptr->pe_allocated++; + for (p = 0; p < vg_ptr->pv_cur; p++) { + if (vg_ptr->pv[p]->pv_dev == + vg_ptr->lv[l]->lv_current_pe[le].dev) { + vg_ptr->pv[p]->pe_allocated++; + break; + } + } + } + + lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].start_sect = 0; + lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].nr_sects = lv_ptr->lv_size; + lvm_size[MINOR(lv_ptr->lv_dev)] = lv_ptr->lv_size >> 1; + /* vg_lv_map array doesn't have to be changed here */ + + read_ahead[MAJOR_NR] = lv_ptr->lv_read_ahead = LVM_CORRECT_READ_AHEAD(lv_ptr->lv_read_ahead); + lv_ptr->lv_status = lv_status_save; + + return 0; +} /* lvm_do_lv_extend_reduce() */ + + +/* + * character device support function logical volume status by name + */ +static int lvm_do_lv_status_byname(vg_t *vg_ptr, void *arg) +{ + uint l; + ulong size; + lv_t lv; + lv_t *lv_ptr; + lv_status_byname_req_t lv_status_byname_req; + + if (vg_ptr == NULL) return -ENXIO; + if (copy_from_user(&lv_status_byname_req, arg, + sizeof(lv_status_byname_req_t)) != 0) + return -EFAULT; + + if (lv_status_byname_req.lv == NULL) return -EINVAL; + if (copy_from_user(&lv, lv_status_byname_req.lv, + sizeof(lv_t)) != 0) + return -EFAULT; + + for (l = 0; l < vg_ptr->lv_max; l++) { + lv_ptr = vg_ptr->lv[l]; + if (lv_ptr != NULL && + strcmp(lv_ptr->lv_name, + lv_status_byname_req.lv_name) == 0) { + if (copy_to_user(lv_status_byname_req.lv, + lv_ptr, + sizeof(lv_t)) != 0) + return -EFAULT; + + if (lv.lv_current_pe != NULL) { + size = lv_ptr->lv_allocated_le * + sizeof(pe_t); + if (copy_to_user(lv.lv_current_pe, + lv_ptr->lv_current_pe, + size) != 0) + return -EFAULT; + } + return 0; + } + } + return -ENXIO; +} /* lvm_do_lv_status_byname() */ + + +/* + * character device support function logical volume status by index + */ +static int lvm_do_lv_status_byindex(vg_t *vg_ptr,void *arg) +{ + ulong size; + lv_t lv; + lv_t *lv_ptr; + lv_status_byindex_req_t lv_status_byindex_req; + + if (vg_ptr == NULL) return -ENXIO; + if (copy_from_user(&lv_status_byindex_req, arg, + sizeof(lv_status_byindex_req)) != 0) + return -EFAULT; + + if ((lvp = lv_status_byindex_req.lv) == NULL) + return -EINVAL; + if ( ( lv_ptr = vg_ptr->lv[lv_status_byindex_req.lv_index]) == NULL) + return -ENXIO; + + if (copy_from_user(&lv, lvp, sizeof(lv_t)) != 0) + return -EFAULT; + + if (copy_to_user(lvp, lv_ptr, sizeof(lv_t)) != 0) + return -EFAULT; + + if (lv.lv_current_pe != NULL) { + size = lv_ptr->lv_allocated_le * sizeof(pe_t); + if (copy_to_user(lv.lv_current_pe, + lv_ptr->lv_current_pe, + size) != 0) + return -EFAULT; + } + return 0; +} /* lvm_do_lv_status_byindex() */ + + +/* + * character device support function physical volume change + */ +static int lvm_do_pv_change(vg_t *vg_ptr, void *arg) +{ + uint p; + pv_t *pv_ptr; +#ifdef LVM_GET_INODE + struct inode *inode_sav; +#endif + + if (vg_ptr == NULL) return -ENXIO; + if (copy_from_user(&pv_change_req, arg, + sizeof(pv_change_req)) != 0) + return -EFAULT; + + for (p = 0; p < vg_ptr->pv_max; p++) { + pv_ptr = vg_ptr->pv[p]; + if (pv_ptr != NULL && + strcmp(pv_ptr->pv_name, + pv_change_req.pv_name) == 0) { +#ifdef LVM_GET_INODE + inode_sav = pv_ptr->inode; +#endif + if (copy_from_user(pv_ptr, + pv_change_req.pv, + sizeof(pv_t)) != 0) + return -EFAULT; + + /* We don't need the PE list + in kernel space as with LVs pe_t list */ + pv_ptr->pe = NULL; +#ifdef LVM_GET_INODE + pv_ptr->inode = inode_sav; +#endif + return 0; + } + } + return -ENXIO; +} /* lvm_do_pv_change() */ + +/* + * character device support function get physical volume status + */ +static int lvm_do_pv_status(vg_t *vg_ptr, void *arg) +{ + uint p; + pv_t *pv_ptr; + + if (vg_ptr == NULL) return -ENXIO; + if (copy_from_user(&pv_status_req, arg, + sizeof(pv_status_req)) != 0) + return -EFAULT; + + for (p = 0; p < vg_ptr->pv_max; p++) { + pv_ptr = vg_ptr->pv[p]; + if (pv_ptr != NULL && + strcmp(pv_ptr->pv_name, + pv_status_req.pv_name) == 0) { + if (copy_to_user(pv_status_req.pv, + pv_ptr, + sizeof(pv_t)) != 0) + return -EFAULT; + return 0; + } + } + return -ENXIO; +} /* lvm_do_pv_status() */ + + +/* + * support function initialize gendisk variables + */ +#ifdef __initfunc +__initfunc(void lvm_geninit(struct gendisk *lvm_gdisk)) +#else +void __init + lvm_geninit(struct gendisk *lvm_gdisk) +#endif +{ + int i = 0; + +#ifdef DEBUG_GENDISK + printk(KERN_DEBUG "%s -- lvm_gendisk\n", lvm_name); +#endif + + for (i = 0; i < MAX_LV; i++) { + lvm_gendisk.part[i].start_sect = -1; /* avoid partition check */ + lvm_size[i] = lvm_gendisk.part[i].nr_sects = 0; + lvm_blocksizes[i] = BLOCK_SIZE; + } + + blksize_size[MAJOR_NR] = lvm_blocksizes; + blk_size[MAJOR_NR] = lvm_size; + + return; +} /* lvm_gen_init() */ + + +#ifdef LVM_GET_INODE +/* + * support function to get an empty inode + * + * Gets an empty inode to be inserted into the inode hash, + * so that a physical volume can't be mounted. + * This is analog to drivers/block/md.c + * + * Is this the real thing? + * + * No, it's bollocks. md.c tries to do a bit different thing that might + * _somewhat_ work eons ago. Neither does any good these days. mount() couldn't + * care less for icache (it cares only for ->s_root->d_count and if we want + * loopback mounts even that will stop). BTW, with the form used here mount() + * would have to scan the _whole_ icache to detect the attempt - how on the + * Earth could it guess the i_ino of your dummy inode? Official line on the + * exclusion between mount()/swapon()/open()/etc. is Just Don't Do It(tm). + * If you can convince Linus that it's worth changing - fine, then you'll need + * to do blkdev_get()/blkdev_put(). Until then... + */ +struct inode *lvm_get_inode(kdev_t dev) +{ + struct inode *inode_this = NULL; + + /* Lock the device by inserting a dummy inode. */ + inode_this = get_empty_inode(); + inode_this->i_dev = dev; + insert_inode_hash(inode_this); + return inode_this; +} + + +/* + * support function to clear an inode + * + */ +void lvm_clear_inode(struct inode *inode) +{ +#ifdef I_FREEING + inode->i_state |= I_FREEING; +#endif + clear_inode(inode); + return; +} +#endif /* #ifdef LVM_GET_INODE */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/md/md.c linux/drivers/md/md.c --- v2.4.0-test8/linux/drivers/md/md.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/md/md.c Wed Sep 27 13:55:04 2000 @@ -0,0 +1,3878 @@ +/* + md.c : Multiple Devices driver for Linux + Copyright (C) 1998, 1999, 2000 Ingo Molnar + + completely rewritten, based on the MD driver code from Marc Zyngier + + Changes: + + - RAID-1/RAID-5 extensions by Miguel de Icaza, Gadi Oxman, Ingo Molnar + - boot support for linear and striped mode by Harald Hoyer + - kerneld support by Boris Tobotras + - kmod support by: Cyrus Durgin + - RAID0 bugfixes: Mark Anthony Lisher + - Devfs support by Richard Gooch + + - lots of fixes and improvements to the RAID1/RAID5 and generic + RAID code (such as request based resynchronization): + + Neil Brown . + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + You should have received a copy of the GNU General Public License + (for example /usr/src/linux/COPYING); if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include + +#include + +#ifdef CONFIG_KMOD +#include +#endif + +#define __KERNEL_SYSCALLS__ +#include + +#include + +extern asmlinkage int sys_sched_yield(void); +extern asmlinkage long sys_setsid(void); + +#define MAJOR_NR MD_MAJOR +#define MD_DRIVER + +#include + +#define DEBUG 0 +#if DEBUG +# define dprintk(x...) printk(x) +#else +# define dprintk(x...) do { } while(0) +#endif + +static mdk_personality_t *pers[MAX_PERSONALITY] = {NULL, }; + +/* + * Current RAID-1,4,5 parallel reconstruction 'guaranteed speed limit' + * is 100 KB/sec, so the extra system load does not show up that much. + * Increase it if you want to have more _guaranteed_ speed. Note that + * the RAID driver will use the maximum available bandwith if the IO + * subsystem is idle. There is also an 'absolute maximum' reconstruction + * speed limit - in case reconstruction slows down your system despite + * idle IO detection. + * + * you can change it via /proc/sys/dev/raid/speed_limit_min and _max. + */ + +static int sysctl_speed_limit_min = 100; +static int sysctl_speed_limit_max = 100000; + +static struct ctl_table_header *raid_table_header; + +static ctl_table raid_table[] = { + {DEV_RAID_SPEED_LIMIT_MIN, "speed_limit_min", + &sysctl_speed_limit_min, sizeof(int), 0644, NULL, &proc_dointvec}, + {DEV_RAID_SPEED_LIMIT_MAX, "speed_limit_max", + &sysctl_speed_limit_max, sizeof(int), 0644, NULL, &proc_dointvec}, + {0} +}; + +static ctl_table raid_dir_table[] = { + {DEV_RAID, "raid", NULL, 0, 0555, raid_table}, + {0} +}; + +static ctl_table raid_root_table[] = { + {CTL_DEV, "dev", NULL, 0, 0555, raid_dir_table}, + {0} +}; + +/* + * these have to be allocated separately because external + * subsystems want to have a pre-defined structure + */ +struct hd_struct md_hd_struct[MAX_MD_DEVS]; +static int md_blocksizes[MAX_MD_DEVS]; +static int md_hardsect_sizes[MAX_MD_DEVS]; +static int md_maxreadahead[MAX_MD_DEVS]; +static mdk_thread_t *md_recovery_thread = NULL; + +int md_size[MAX_MD_DEVS] = {0, }; + +extern struct block_device_operations md_fops; +static devfs_handle_t devfs_handle = NULL; + +static struct gendisk md_gendisk= +{ + major: MD_MAJOR, + major_name: "md", + minor_shift: 0, + max_p: 1, + part: md_hd_struct, + sizes: md_size, + nr_real: MAX_MD_DEVS, + real_devices: NULL, + next: NULL, + fops: &md_fops, +}; + +/* + * Enables to iterate over all existing md arrays + */ +static MD_LIST_HEAD(all_mddevs); + +/* + * The mapping between kdev and mddev is not necessary a simple + * one! Eg. HSM uses several sub-devices to implement Logical + * Volumes. All these sub-devices map to the same mddev. + */ +dev_mapping_t mddev_map [MAX_MD_DEVS] = { {NULL, 0}, }; + +void add_mddev_mapping (mddev_t * mddev, kdev_t dev, void *data) +{ + unsigned int minor = MINOR(dev); + + if (MAJOR(dev) != MD_MAJOR) { + MD_BUG(); + return; + } + if (mddev_map[minor].mddev != NULL) { + MD_BUG(); + return; + } + mddev_map[minor].mddev = mddev; + mddev_map[minor].data = data; +} + +void del_mddev_mapping (mddev_t * mddev, kdev_t dev) +{ + unsigned int minor = MINOR(dev); + + if (MAJOR(dev) != MD_MAJOR) { + MD_BUG(); + return; + } + if (mddev_map[minor].mddev != mddev) { + MD_BUG(); + return; + } + mddev_map[minor].mddev = NULL; + mddev_map[minor].data = NULL; +} + +static int md_make_request (request_queue_t *q, int rw, struct buffer_head * bh) +{ + mddev_t *mddev = kdev_to_mddev(bh->b_rdev); + + if (mddev && mddev->pers) + return mddev->pers->make_request(mddev, rw, bh); + else { + buffer_IO_error(bh); + return -1; + } +} + +static mddev_t * alloc_mddev (kdev_t dev) +{ + mddev_t *mddev; + + if (MAJOR(dev) != MD_MAJOR) { + MD_BUG(); + return 0; + } + mddev = (mddev_t *) kmalloc(sizeof(*mddev), GFP_KERNEL); + if (!mddev) + return NULL; + + memset(mddev, 0, sizeof(*mddev)); + + mddev->__minor = MINOR(dev); + init_MUTEX(&mddev->reconfig_sem); + init_MUTEX(&mddev->recovery_sem); + init_MUTEX(&mddev->resync_sem); + MD_INIT_LIST_HEAD(&mddev->disks); + MD_INIT_LIST_HEAD(&mddev->all_mddevs); + + /* + * The 'base' mddev is the one with data NULL. + * personalities can create additional mddevs + * if necessary. + */ + add_mddev_mapping(mddev, dev, 0); + md_list_add(&mddev->all_mddevs, &all_mddevs); + + MOD_INC_USE_COUNT; + + return mddev; +} + +struct gendisk * find_gendisk (kdev_t dev) +{ + struct gendisk *tmp = gendisk_head; + + while (tmp != NULL) { + if (tmp->major == MAJOR(dev)) + return (tmp); + tmp = tmp->next; + } + return (NULL); +} + +mdk_rdev_t * find_rdev_nr(mddev_t *mddev, int nr) +{ + mdk_rdev_t * rdev; + struct md_list_head *tmp; + + ITERATE_RDEV(mddev,rdev,tmp) { + if (rdev->desc_nr == nr) + return rdev; + } + return NULL; +} + +mdk_rdev_t * find_rdev(mddev_t * mddev, kdev_t dev) +{ + struct md_list_head *tmp; + mdk_rdev_t *rdev; + + ITERATE_RDEV(mddev,rdev,tmp) { + if (rdev->dev == dev) + return rdev; + } + return NULL; +} + +static MD_LIST_HEAD(device_names); + +char * partition_name (kdev_t dev) +{ + struct gendisk *hd; + static char nomem [] = ""; + dev_name_t *dname; + struct md_list_head *tmp = device_names.next; + + while (tmp != &device_names) { + dname = md_list_entry(tmp, dev_name_t, list); + if (dname->dev == dev) + return dname->name; + tmp = tmp->next; + } + + dname = (dev_name_t *) kmalloc(sizeof(*dname), GFP_KERNEL); + + if (!dname) + return nomem; + /* + * ok, add this new device name to the list + */ + hd = find_gendisk (dev); + dname->name = NULL; + if (hd) + dname->name = disk_name (hd, MINOR(dev), dname->namebuf); + if (!dname->name) { + sprintf (dname->namebuf, "[dev %s]", kdevname(dev)); + dname->name = dname->namebuf; + } + + dname->dev = dev; + MD_INIT_LIST_HEAD(&dname->list); + md_list_add(&dname->list, &device_names); + + return dname->name; +} + +static unsigned int calc_dev_sboffset (kdev_t dev, mddev_t *mddev, + int persistent) +{ + unsigned int size = 0; + + if (blk_size[MAJOR(dev)]) + size = blk_size[MAJOR(dev)][MINOR(dev)]; + if (persistent) + size = MD_NEW_SIZE_BLOCKS(size); + return size; +} + +static unsigned int calc_dev_size (kdev_t dev, mddev_t *mddev, int persistent) +{ + unsigned int size; + + size = calc_dev_sboffset(dev, mddev, persistent); + if (!mddev->sb) { + MD_BUG(); + return size; + } + if (mddev->sb->chunk_size) + size &= ~(mddev->sb->chunk_size/1024 - 1); + return size; +} + +static unsigned int zoned_raid_size (mddev_t *mddev) +{ + unsigned int mask; + mdk_rdev_t * rdev; + struct md_list_head *tmp; + + if (!mddev->sb) { + MD_BUG(); + return -EINVAL; + } + /* + * do size and offset calculations. + */ + mask = ~(mddev->sb->chunk_size/1024 - 1); + + ITERATE_RDEV(mddev,rdev,tmp) { + rdev->size &= mask; + md_size[mdidx(mddev)] += rdev->size; + } + return 0; +} + +/* + * We check wether all devices are numbered from 0 to nb_dev-1. The + * order is guaranteed even after device name changes. + * + * Some personalities (raid0, linear) use this. Personalities that + * provide data have to be able to deal with loss of individual + * disks, so they do their checking themselves. + */ +int md_check_ordering (mddev_t *mddev) +{ + int i, c; + mdk_rdev_t *rdev; + struct md_list_head *tmp; + + /* + * First, all devices must be fully functional + */ + ITERATE_RDEV(mddev,rdev,tmp) { + if (rdev->faulty) { + printk("md: md%d's device %s faulty, aborting.\n", + mdidx(mddev), partition_name(rdev->dev)); + goto abort; + } + } + + c = 0; + ITERATE_RDEV(mddev,rdev,tmp) { + c++; + } + if (c != mddev->nb_dev) { + MD_BUG(); + goto abort; + } + if (mddev->nb_dev != mddev->sb->raid_disks) { + printk("md: md%d, array needs %d disks, has %d, aborting.\n", + mdidx(mddev), mddev->sb->raid_disks, mddev->nb_dev); + goto abort; + } + /* + * Now the numbering check + */ + for (i = 0; i < mddev->nb_dev; i++) { + c = 0; + ITERATE_RDEV(mddev,rdev,tmp) { + if (rdev->desc_nr == i) + c++; + } + if (!c) { + printk("md: md%d, missing disk #%d, aborting.\n", + mdidx(mddev), i); + goto abort; + } + if (c > 1) { + printk("md: md%d, too many disks #%d, aborting.\n", + mdidx(mddev), i); + goto abort; + } + } + return 0; +abort: + return 1; +} + +static void remove_descriptor (mdp_disk_t *disk, mdp_super_t *sb) +{ + if (disk_active(disk)) { + sb->working_disks--; + } else { + if (disk_spare(disk)) { + sb->spare_disks--; + sb->working_disks--; + } else { + sb->failed_disks--; + } + } + sb->nr_disks--; + disk->major = 0; + disk->minor = 0; + mark_disk_removed(disk); +} + +#define BAD_MAGIC KERN_ERR \ +"md: invalid raid superblock magic on %s\n" + +#define BAD_MINOR KERN_ERR \ +"md: %s: invalid raid minor (%x)\n" + +#define OUT_OF_MEM KERN_ALERT \ +"md: out of memory.\n" + +#define NO_SB KERN_ERR \ +"md: disabled device %s, could not read superblock.\n" + +#define BAD_CSUM KERN_WARNING \ +"md: invalid superblock checksum on %s\n" + +static int alloc_array_sb (mddev_t * mddev) +{ + if (mddev->sb) { + MD_BUG(); + return 0; + } + + mddev->sb = (mdp_super_t *) __get_free_page (GFP_KERNEL); + if (!mddev->sb) + return -ENOMEM; + md_clear_page(mddev->sb); + return 0; +} + +static int alloc_disk_sb (mdk_rdev_t * rdev) +{ + if (rdev->sb) + MD_BUG(); + + rdev->sb = (mdp_super_t *) __get_free_page(GFP_KERNEL); + if (!rdev->sb) { + printk (OUT_OF_MEM); + return -EINVAL; + } + md_clear_page(rdev->sb); + + return 0; +} + +static void free_disk_sb (mdk_rdev_t * rdev) +{ + if (rdev->sb) { + free_page((unsigned long) rdev->sb); + rdev->sb = NULL; + rdev->sb_offset = 0; + rdev->size = 0; + } else { + if (!rdev->faulty) + MD_BUG(); + } +} + +static void mark_rdev_faulty (mdk_rdev_t * rdev) +{ + if (!rdev) { + MD_BUG(); + return; + } + free_disk_sb(rdev); + rdev->faulty = 1; +} + +static int read_disk_sb (mdk_rdev_t * rdev) +{ + int ret = -EINVAL; + struct buffer_head *bh = NULL; + kdev_t dev = rdev->dev; + mdp_super_t *sb; + unsigned long sb_offset; + + if (!rdev->sb) { + MD_BUG(); + goto abort; + } + + /* + * Calculate the position of the superblock, + * it's at the end of the disk + */ + sb_offset = calc_dev_sboffset(rdev->dev, rdev->mddev, 1); + rdev->sb_offset = sb_offset; + printk("(read) %s's sb offset: %ld", partition_name(dev), sb_offset); + fsync_dev(dev); + set_blocksize (dev, MD_SB_BYTES); + bh = bread (dev, sb_offset / MD_SB_BLOCKS, MD_SB_BYTES); + + if (bh) { + sb = (mdp_super_t *) bh->b_data; + memcpy (rdev->sb, sb, MD_SB_BYTES); + } else { + printk (NO_SB,partition_name(rdev->dev)); + goto abort; + } + printk(" [events: %08lx]\n", (unsigned long)rdev->sb->events_lo); + ret = 0; +abort: + if (bh) + brelse (bh); + return ret; +} + +static unsigned int calc_sb_csum (mdp_super_t * sb) +{ + unsigned int disk_csum, csum; + + disk_csum = sb->sb_csum; + sb->sb_csum = 0; + csum = csum_partial((void *)sb, MD_SB_BYTES, 0); + sb->sb_csum = disk_csum; + return csum; +} + +/* + * Check one RAID superblock for generic plausibility + */ + +static int check_disk_sb (mdk_rdev_t * rdev) +{ + mdp_super_t *sb; + int ret = -EINVAL; + + sb = rdev->sb; + if (!sb) { + MD_BUG(); + goto abort; + } + + if (sb->md_magic != MD_SB_MAGIC) { + printk (BAD_MAGIC, partition_name(rdev->dev)); + goto abort; + } + + if (sb->md_minor >= MAX_MD_DEVS) { + printk (BAD_MINOR, partition_name(rdev->dev), + sb->md_minor); + goto abort; + } + + if (calc_sb_csum(sb) != sb->sb_csum) + printk(BAD_CSUM, partition_name(rdev->dev)); + ret = 0; +abort: + return ret; +} + +static kdev_t dev_unit(kdev_t dev) +{ + unsigned int mask; + struct gendisk *hd = find_gendisk(dev); + + if (!hd) + return 0; + mask = ~((1 << hd->minor_shift) - 1); + + return MKDEV(MAJOR(dev), MINOR(dev) & mask); +} + +static mdk_rdev_t * match_dev_unit(mddev_t *mddev, kdev_t dev) +{ + struct md_list_head *tmp; + mdk_rdev_t *rdev; + + ITERATE_RDEV(mddev,rdev,tmp) + if (dev_unit(rdev->dev) == dev_unit(dev)) + return rdev; + + return NULL; +} + +static int match_mddev_units(mddev_t *mddev1, mddev_t *mddev2) +{ + struct md_list_head *tmp; + mdk_rdev_t *rdev; + + ITERATE_RDEV(mddev1,rdev,tmp) + if (match_dev_unit(mddev2, rdev->dev)) + return 1; + + return 0; +} + +static MD_LIST_HEAD(all_raid_disks); +static MD_LIST_HEAD(pending_raid_disks); + +static void bind_rdev_to_array (mdk_rdev_t * rdev, mddev_t * mddev) +{ + mdk_rdev_t *same_pdev; + + if (rdev->mddev) { + MD_BUG(); + return; + } + same_pdev = match_dev_unit(mddev, rdev->dev); + if (same_pdev) + printk( KERN_WARNING +"md%d: WARNING: %s appears to be on the same physical disk as %s. True\n" +" protection against single-disk failure might be compromised.\n", + mdidx(mddev), partition_name(rdev->dev), + partition_name(same_pdev->dev)); + + md_list_add(&rdev->same_set, &mddev->disks); + rdev->mddev = mddev; + mddev->nb_dev++; + printk("bind<%s,%d>\n", partition_name(rdev->dev), mddev->nb_dev); +} + +static void unbind_rdev_from_array (mdk_rdev_t * rdev) +{ + if (!rdev->mddev) { + MD_BUG(); + return; + } + md_list_del(&rdev->same_set); + MD_INIT_LIST_HEAD(&rdev->same_set); + rdev->mddev->nb_dev--; + printk("unbind<%s,%d>\n", partition_name(rdev->dev), + rdev->mddev->nb_dev); + rdev->mddev = NULL; +} + +/* + * prevent the device from being mounted, repartitioned or + * otherwise reused by a RAID array (or any other kernel + * subsystem), by opening the device. [simply getting an + * inode is not enough, the SCSI module usage code needs + * an explicit open() on the device] + */ +static int lock_rdev (mdk_rdev_t *rdev) +{ + int err = 0; + + /* + * First insert a dummy inode. + */ + if (rdev->inode) + MD_BUG(); + rdev->inode = get_empty_inode(); + if (!rdev->inode) + return -ENOMEM; + /* + * we dont care about any other fields + */ + rdev->inode->i_dev = rdev->inode->i_rdev = rdev->dev; + insert_inode_hash(rdev->inode); + + memset(&rdev->filp, 0, sizeof(rdev->filp)); + rdev->filp.f_mode = 3; /* read write */ + return err; +} + +static void unlock_rdev (mdk_rdev_t *rdev) +{ + if (!rdev->inode) + MD_BUG(); + iput(rdev->inode); + rdev->inode = NULL; +} + +static void export_rdev (mdk_rdev_t * rdev) +{ + printk("export_rdev(%s)\n",partition_name(rdev->dev)); + if (rdev->mddev) + MD_BUG(); + unlock_rdev(rdev); + free_disk_sb(rdev); + md_list_del(&rdev->all); + MD_INIT_LIST_HEAD(&rdev->all); + if (rdev->pending.next != &rdev->pending) { + printk("(%s was pending)\n",partition_name(rdev->dev)); + md_list_del(&rdev->pending); + MD_INIT_LIST_HEAD(&rdev->pending); + } + rdev->dev = 0; + rdev->faulty = 0; + kfree(rdev); +} + +static void kick_rdev_from_array (mdk_rdev_t * rdev) +{ + unbind_rdev_from_array(rdev); + export_rdev(rdev); +} + +static void export_array (mddev_t *mddev) +{ + struct md_list_head *tmp; + mdk_rdev_t *rdev; + mdp_super_t *sb = mddev->sb; + + if (mddev->sb) { + mddev->sb = NULL; + free_page((unsigned long) sb); + } + + ITERATE_RDEV(mddev,rdev,tmp) { + if (!rdev->mddev) { + MD_BUG(); + continue; + } + kick_rdev_from_array(rdev); + } + if (mddev->nb_dev) + MD_BUG(); +} + +static void free_mddev (mddev_t *mddev) +{ + if (!mddev) { + MD_BUG(); + return; + } + + export_array(mddev); + md_size[mdidx(mddev)] = 0; + md_hd_struct[mdidx(mddev)].nr_sects = 0; + + /* + * Make sure nobody else is using this mddev + * (careful, we rely on the global kernel lock here) + */ + while (md_atomic_read(&mddev->resync_sem.count) != 1) + schedule(); + while (md_atomic_read(&mddev->recovery_sem.count) != 1) + schedule(); + + del_mddev_mapping(mddev, MKDEV(MD_MAJOR, mdidx(mddev))); + md_list_del(&mddev->all_mddevs); + MD_INIT_LIST_HEAD(&mddev->all_mddevs); + kfree(mddev); + MOD_DEC_USE_COUNT; +} + +#undef BAD_CSUM +#undef BAD_MAGIC +#undef OUT_OF_MEM +#undef NO_SB + +static void print_desc(mdp_disk_t *desc) +{ + printk(" DISK\n", desc->number, + partition_name(MKDEV(desc->major,desc->minor)), + desc->major,desc->minor,desc->raid_disk,desc->state); +} + +static void print_sb(mdp_super_t *sb) +{ + int i; + + printk(" SB: (V:%d.%d.%d) ID:<%08x.%08x.%08x.%08x> CT:%08x\n", + sb->major_version, sb->minor_version, sb->patch_version, + sb->set_uuid0, sb->set_uuid1, sb->set_uuid2, sb->set_uuid3, + sb->ctime); + printk(" L%d S%08d ND:%d RD:%d md%d LO:%d CS:%d\n", sb->level, + sb->size, sb->nr_disks, sb->raid_disks, sb->md_minor, + sb->layout, sb->chunk_size); + printk(" UT:%08x ST:%d AD:%d WD:%d FD:%d SD:%d CSUM:%08x E:%08lx\n", + sb->utime, sb->state, sb->active_disks, sb->working_disks, + sb->failed_disks, sb->spare_disks, + sb->sb_csum, (unsigned long)sb->events_lo); + + for (i = 0; i < MD_SB_DISKS; i++) { + mdp_disk_t *desc; + + desc = sb->disks + i; + printk(" D %2d: ", i); + print_desc(desc); + } + printk(" THIS: "); + print_desc(&sb->this_disk); + +} + +static void print_rdev(mdk_rdev_t *rdev) +{ + printk(" rdev %s: O:%s, SZ:%08ld F:%d DN:%d ", + partition_name(rdev->dev), partition_name(rdev->old_dev), + rdev->size, rdev->faulty, rdev->desc_nr); + if (rdev->sb) { + printk("rdev superblock:\n"); + print_sb(rdev->sb); + } else + printk("no rdev superblock!\n"); +} + +void md_print_devices (void) +{ + struct md_list_head *tmp, *tmp2; + mdk_rdev_t *rdev; + mddev_t *mddev; + + printk("\n"); + printk(" **********************************\n"); + printk(" * *\n"); + printk(" **********************************\n"); + ITERATE_MDDEV(mddev,tmp) { + printk("md%d: ", mdidx(mddev)); + + ITERATE_RDEV(mddev,rdev,tmp2) + printk("<%s>", partition_name(rdev->dev)); + + if (mddev->sb) { + printk(" array superblock:\n"); + print_sb(mddev->sb); + } else + printk(" no array superblock.\n"); + + ITERATE_RDEV(mddev,rdev,tmp2) + print_rdev(rdev); + } + printk(" **********************************\n"); + printk("\n"); +} + +static int sb_equal ( mdp_super_t *sb1, mdp_super_t *sb2) +{ + int ret; + mdp_super_t *tmp1, *tmp2; + + tmp1 = kmalloc(sizeof(*tmp1),GFP_KERNEL); + tmp2 = kmalloc(sizeof(*tmp2),GFP_KERNEL); + + if (!tmp1 || !tmp2) { + ret = 0; + goto abort; + } + + *tmp1 = *sb1; + *tmp2 = *sb2; + + /* + * nr_disks is not constant + */ + tmp1->nr_disks = 0; + tmp2->nr_disks = 0; + + if (memcmp(tmp1, tmp2, MD_SB_GENERIC_CONSTANT_WORDS * 4)) + ret = 0; + else + ret = 1; + +abort: + if (tmp1) + kfree(tmp1); + if (tmp2) + kfree(tmp2); + + return ret; +} + +static int uuid_equal(mdk_rdev_t *rdev1, mdk_rdev_t *rdev2) +{ + if ( (rdev1->sb->set_uuid0 == rdev2->sb->set_uuid0) && + (rdev1->sb->set_uuid1 == rdev2->sb->set_uuid1) && + (rdev1->sb->set_uuid2 == rdev2->sb->set_uuid2) && + (rdev1->sb->set_uuid3 == rdev2->sb->set_uuid3)) + + return 1; + + return 0; +} + +static mdk_rdev_t * find_rdev_all (kdev_t dev) +{ + struct md_list_head *tmp; + mdk_rdev_t *rdev; + + tmp = all_raid_disks.next; + while (tmp != &all_raid_disks) { + rdev = md_list_entry(tmp, mdk_rdev_t, all); + if (rdev->dev == dev) + return rdev; + tmp = tmp->next; + } + return NULL; +} + +#define GETBLK_FAILED KERN_ERR \ +"md: getblk failed for device %s\n" + +static int write_disk_sb(mdk_rdev_t * rdev) +{ + struct buffer_head *bh; + kdev_t dev; + unsigned long sb_offset, size; + mdp_super_t *sb; + + if (!rdev->sb) { + MD_BUG(); + return -1; + } + if (rdev->faulty) { + MD_BUG(); + return -1; + } + if (rdev->sb->md_magic != MD_SB_MAGIC) { + MD_BUG(); + return -1; + } + + dev = rdev->dev; + sb_offset = calc_dev_sboffset(dev, rdev->mddev, 1); + if (rdev->sb_offset != sb_offset) { + printk("%s's sb offset has changed from %ld to %ld, skipping\n", partition_name(dev), rdev->sb_offset, sb_offset); + goto skip; + } + /* + * If the disk went offline meanwhile and it's just a spare, then + * it's size has changed to zero silently, and the MD code does + * not yet know that it's faulty. + */ + size = calc_dev_size(dev, rdev->mddev, 1); + if (size != rdev->size) { + printk("%s's size has changed from %ld to %ld since import, skipping\n", partition_name(dev), rdev->size, size); + goto skip; + } + + printk("(write) %s's sb offset: %ld\n", partition_name(dev), sb_offset); + fsync_dev(dev); + set_blocksize(dev, MD_SB_BYTES); + bh = getblk(dev, sb_offset / MD_SB_BLOCKS, MD_SB_BYTES); + if (!bh) { + printk(GETBLK_FAILED, partition_name(dev)); + return 1; + } + memset(bh->b_data,0,bh->b_size); + sb = (mdp_super_t *) bh->b_data; + memcpy(sb, rdev->sb, MD_SB_BYTES); + + mark_buffer_uptodate(bh, 1); + mark_buffer_dirty(bh); + ll_rw_block(WRITE, 1, &bh); + wait_on_buffer(bh); + brelse(bh); + fsync_dev(dev); +skip: + return 0; +} +#undef GETBLK_FAILED + +static void set_this_disk(mddev_t *mddev, mdk_rdev_t *rdev) +{ + int i, ok = 0; + mdp_disk_t *desc; + + for (i = 0; i < MD_SB_DISKS; i++) { + desc = mddev->sb->disks + i; +#if 0 + if (disk_faulty(desc)) { + if (MKDEV(desc->major,desc->minor) == rdev->dev) + ok = 1; + continue; + } +#endif + if (MKDEV(desc->major,desc->minor) == rdev->dev) { + rdev->sb->this_disk = *desc; + rdev->desc_nr = desc->number; + ok = 1; + break; + } + } + + if (!ok) { + MD_BUG(); + } +} + +static int sync_sbs(mddev_t * mddev) +{ + mdk_rdev_t *rdev; + mdp_super_t *sb; + struct md_list_head *tmp; + + ITERATE_RDEV(mddev,rdev,tmp) { + if (rdev->faulty) + continue; + sb = rdev->sb; + *sb = *mddev->sb; + set_this_disk(mddev, rdev); + sb->sb_csum = calc_sb_csum(sb); + } + return 0; +} + +int md_update_sb(mddev_t * mddev) +{ + int first, err, count = 100; + struct md_list_head *tmp; + mdk_rdev_t *rdev; + +repeat: + mddev->sb->utime = CURRENT_TIME; + if ((++mddev->sb->events_lo)==0) + ++mddev->sb->events_hi; + + if ((mddev->sb->events_lo|mddev->sb->events_hi)==0) { + /* + * oops, this 64-bit counter should never wrap. + * Either we are in around ~1 trillion A.C., assuming + * 1 reboot per second, or we have a bug: + */ + MD_BUG(); + mddev->sb->events_lo = mddev->sb->events_hi = 0xffffffff; + } + sync_sbs(mddev); + + /* + * do not write anything to disk if using + * nonpersistent superblocks + */ + if (mddev->sb->not_persistent) + return 0; + + printk(KERN_INFO "md: updating md%d RAID superblock on device\n", + mdidx(mddev)); + + first = 1; + err = 0; + ITERATE_RDEV(mddev,rdev,tmp) { + if (!first) { + first = 0; + printk(", "); + } + if (rdev->faulty) + printk("(skipping faulty "); + printk("%s ", partition_name(rdev->dev)); + if (!rdev->faulty) { + printk("[events: %08lx]", + (unsigned long)rdev->sb->events_lo); + err += write_disk_sb(rdev); + } else + printk(")\n"); + } + printk(".\n"); + if (err) { + printk("errors occured during superblock update, repeating\n"); + if (--count) + goto repeat; + printk("excessive errors occured during superblock update, exiting\n"); + } + return 0; +} + +/* + * Import a device. If 'on_disk', then sanity check the superblock + * + * mark the device faulty if: + * + * - the device is nonexistent (zero size) + * - the device has no valid superblock + * + * a faulty rdev _never_ has rdev->sb set. + */ +static int md_import_device (kdev_t newdev, int on_disk) +{ + int err; + mdk_rdev_t *rdev; + unsigned int size; + + if (find_rdev_all(newdev)) + return -EEXIST; + + rdev = (mdk_rdev_t *) kmalloc(sizeof(*rdev), GFP_KERNEL); + if (!rdev) { + printk("could not alloc mem for %s!\n", partition_name(newdev)); + return -ENOMEM; + } + memset(rdev, 0, sizeof(*rdev)); + + if (get_super(newdev)) { + printk("md: can not import %s, has active inodes!\n", + partition_name(newdev)); + err = -EBUSY; + goto abort_free; + } + + if ((err = alloc_disk_sb(rdev))) + goto abort_free; + + rdev->dev = newdev; + if (lock_rdev(rdev)) { + printk("md: could not lock %s, zero-size? Marking faulty.\n", + partition_name(newdev)); + err = -EINVAL; + goto abort_free; + } + rdev->desc_nr = -1; + rdev->faulty = 0; + + size = 0; + if (blk_size[MAJOR(newdev)]) + size = blk_size[MAJOR(newdev)][MINOR(newdev)]; + if (!size) { + printk("md: %s has zero size, marking faulty!\n", + partition_name(newdev)); + err = -EINVAL; + goto abort_free; + } + + if (on_disk) { + if ((err = read_disk_sb(rdev))) { + printk("md: could not read %s's sb, not importing!\n", + partition_name(newdev)); + goto abort_free; + } + if ((err = check_disk_sb(rdev))) { + printk("md: %s has invalid sb, not importing!\n", + partition_name(newdev)); + goto abort_free; + } + + rdev->old_dev = MKDEV(rdev->sb->this_disk.major, + rdev->sb->this_disk.minor); + rdev->desc_nr = rdev->sb->this_disk.number; + } + md_list_add(&rdev->all, &all_raid_disks); + MD_INIT_LIST_HEAD(&rdev->pending); + + if (rdev->faulty && rdev->sb) + free_disk_sb(rdev); + return 0; + +abort_free: + if (rdev->sb) { + if (rdev->inode) + unlock_rdev(rdev); + free_disk_sb(rdev); + } + kfree(rdev); + return err; +} + +/* + * Check a full RAID array for plausibility + */ + +#define INCONSISTENT KERN_ERR \ +"md: fatal superblock inconsistency in %s -- removing from array\n" + +#define OUT_OF_DATE KERN_ERR \ +"md: superblock update time inconsistency -- using the most recent one\n" + +#define OLD_VERSION KERN_ALERT \ +"md: md%d: unsupported raid array version %d.%d.%d\n" + +#define NOT_CLEAN_IGNORE KERN_ERR \ +"md: md%d: raid array is not clean -- starting background reconstruction\n" + +#define UNKNOWN_LEVEL KERN_ERR \ +"md: md%d: unsupported raid level %d\n" + +static int analyze_sbs (mddev_t * mddev) +{ + int out_of_date = 0, i; + struct md_list_head *tmp, *tmp2; + mdk_rdev_t *rdev, *rdev2, *freshest; + mdp_super_t *sb; + + /* + * Verify the RAID superblock on each real device + */ + ITERATE_RDEV(mddev,rdev,tmp) { + if (rdev->faulty) { + MD_BUG(); + goto abort; + } + if (!rdev->sb) { + MD_BUG(); + goto abort; + } + if (check_disk_sb(rdev)) + goto abort; + } + + /* + * The superblock constant part has to be the same + * for all disks in the array. + */ + sb = NULL; + + ITERATE_RDEV(mddev,rdev,tmp) { + if (!sb) { + sb = rdev->sb; + continue; + } + if (!sb_equal(sb, rdev->sb)) { + printk (INCONSISTENT, partition_name(rdev->dev)); + kick_rdev_from_array(rdev); + continue; + } + } + + /* + * OK, we have all disks and the array is ready to run. Let's + * find the freshest superblock, that one will be the superblock + * that represents the whole array. + */ + if (!mddev->sb) + if (alloc_array_sb(mddev)) + goto abort; + sb = mddev->sb; + freshest = NULL; + + ITERATE_RDEV(mddev,rdev,tmp) { + __u64 ev1, ev2; + /* + * if the checksum is invalid, use the superblock + * only as a last resort. (decrease it's age by + * one event) + */ + if (calc_sb_csum(rdev->sb) != rdev->sb->sb_csum) { + if (rdev->sb->events_lo || rdev->sb->events_hi) + if ((rdev->sb->events_lo--)==0) + rdev->sb->events_hi--; + } + + printk("%s's event counter: %08lx\n", partition_name(rdev->dev), + (unsigned long)rdev->sb->events_lo); + if (!freshest) { + freshest = rdev; + continue; + } + /* + * Find the newest superblock version + */ + ev1 = md_event(rdev->sb); + ev2 = md_event(freshest->sb); + if (ev1 != ev2) { + out_of_date = 1; + if (ev1 > ev2) + freshest = rdev; + } + } + if (out_of_date) { + printk(OUT_OF_DATE); + printk("freshest: %s\n", partition_name(freshest->dev)); + } + memcpy (sb, freshest->sb, sizeof(*sb)); + + /* + * at this point we have picked the 'best' superblock + * from all available superblocks. + * now we validate this superblock and kick out possibly + * failed disks. + */ + ITERATE_RDEV(mddev,rdev,tmp) { + /* + * Kick all non-fresh devices faulty + */ + __u64 ev1, ev2; + ev1 = md_event(rdev->sb); + ev2 = md_event(sb); + ++ev1; + if (ev1 < ev2) { + printk("md: kicking non-fresh %s from array!\n", + partition_name(rdev->dev)); + kick_rdev_from_array(rdev); + continue; + } + } + + /* + * Fix up changed device names ... but only if this disk has a + * recent update time. Use faulty checksum ones too. + */ + ITERATE_RDEV(mddev,rdev,tmp) { + __u64 ev1, ev2, ev3; + if (rdev->faulty) { /* REMOVEME */ + MD_BUG(); + goto abort; + } + ev1 = md_event(rdev->sb); + ev2 = md_event(sb); + ev3 = ev2; + --ev3; + if ((rdev->dev != rdev->old_dev) && + ((ev1 == ev2) || (ev1 == ev3))) { + mdp_disk_t *desc; + + printk("md: device name has changed from %s to %s since last import!\n", partition_name(rdev->old_dev), partition_name(rdev->dev)); + if (rdev->desc_nr == -1) { + MD_BUG(); + goto abort; + } + desc = &sb->disks[rdev->desc_nr]; + if (rdev->old_dev != MKDEV(desc->major, desc->minor)) { + MD_BUG(); + goto abort; + } + desc->major = MAJOR(rdev->dev); + desc->minor = MINOR(rdev->dev); + desc = &rdev->sb->this_disk; + desc->major = MAJOR(rdev->dev); + desc->minor = MINOR(rdev->dev); + } + } + + /* + * Remove unavailable and faulty devices ... + * + * note that if an array becomes completely unrunnable due to + * missing devices, we do not write the superblock back, so the + * administrator has a chance to fix things up. The removal thus + * only happens if it's nonfatal to the contents of the array. + */ + for (i = 0; i < MD_SB_DISKS; i++) { + int found; + mdp_disk_t *desc; + kdev_t dev; + + desc = sb->disks + i; + dev = MKDEV(desc->major, desc->minor); + + /* + * We kick faulty devices/descriptors immediately. + */ + if (disk_faulty(desc)) { + found = 0; + ITERATE_RDEV(mddev,rdev,tmp) { + if (rdev->desc_nr != desc->number) + continue; + printk("md%d: kicking faulty %s!\n", + mdidx(mddev),partition_name(rdev->dev)); + kick_rdev_from_array(rdev); + found = 1; + break; + } + if (!found) { + if (dev == MKDEV(0,0)) + continue; + printk("md%d: removing former faulty %s!\n", + mdidx(mddev), partition_name(dev)); + } + remove_descriptor(desc, sb); + continue; + } + + if (dev == MKDEV(0,0)) + continue; + /* + * Is this device present in the rdev ring? + */ + found = 0; + ITERATE_RDEV(mddev,rdev,tmp) { + if (rdev->desc_nr == desc->number) { + found = 1; + break; + } + } + if (found) + continue; + + printk("md%d: former device %s is unavailable, removing from array!\n", mdidx(mddev), partition_name(dev)); + remove_descriptor(desc, sb); + } + + /* + * Double check wether all devices mentioned in the + * superblock are in the rdev ring. + */ + for (i = 0; i < MD_SB_DISKS; i++) { + mdp_disk_t *desc; + kdev_t dev; + + desc = sb->disks + i; + dev = MKDEV(desc->major, desc->minor); + + if (dev == MKDEV(0,0)) + continue; + + if (disk_faulty(desc)) { + MD_BUG(); + goto abort; + } + + rdev = find_rdev(mddev, dev); + if (!rdev) { + MD_BUG(); + goto abort; + } + } + + /* + * Do a final reality check. + */ + ITERATE_RDEV(mddev,rdev,tmp) { + if (rdev->desc_nr == -1) { + MD_BUG(); + goto abort; + } + /* + * is the desc_nr unique? + */ + ITERATE_RDEV(mddev,rdev2,tmp2) { + if ((rdev2 != rdev) && + (rdev2->desc_nr == rdev->desc_nr)) { + MD_BUG(); + goto abort; + } + } + /* + * is the device unique? + */ + ITERATE_RDEV(mddev,rdev2,tmp2) { + if ((rdev2 != rdev) && + (rdev2->dev == rdev->dev)) { + MD_BUG(); + goto abort; + } + } + } + + /* + * Check if we can support this RAID array + */ + if (sb->major_version != MD_MAJOR_VERSION || + sb->minor_version > MD_MINOR_VERSION) { + + printk (OLD_VERSION, mdidx(mddev), sb->major_version, + sb->minor_version, sb->patch_version); + goto abort; + } + + if ((sb->state != (1 << MD_SB_CLEAN)) && ((sb->level == 1) || + (sb->level == 4) || (sb->level == 5))) + printk (NOT_CLEAN_IGNORE, mdidx(mddev)); + + return 0; +abort: + return 1; +} + +#undef INCONSISTENT +#undef OUT_OF_DATE +#undef OLD_VERSION +#undef OLD_LEVEL + +static int device_size_calculation (mddev_t * mddev) +{ + int data_disks = 0, persistent; + unsigned int readahead; + mdp_super_t *sb = mddev->sb; + struct md_list_head *tmp; + mdk_rdev_t *rdev; + + /* + * Do device size calculation. Bail out if too small. + * (we have to do this after having validated chunk_size, + * because device size has to be modulo chunk_size) + */ + persistent = !mddev->sb->not_persistent; + ITERATE_RDEV(mddev,rdev,tmp) { + if (rdev->faulty) + continue; + if (rdev->size) { + MD_BUG(); + continue; + } + rdev->size = calc_dev_size(rdev->dev, mddev, persistent); + if (rdev->size < sb->chunk_size / 1024) { + printk (KERN_WARNING + "Dev %s smaller than chunk_size: %ldk < %dk\n", + partition_name(rdev->dev), + rdev->size, sb->chunk_size / 1024); + return -EINVAL; + } + } + + switch (sb->level) { + case -3: + data_disks = 1; + break; + case -2: + data_disks = 1; + break; + case -1: + zoned_raid_size(mddev); + data_disks = 1; + break; + case 0: + zoned_raid_size(mddev); + data_disks = sb->raid_disks; + break; + case 1: + data_disks = 1; + break; + case 4: + case 5: + data_disks = sb->raid_disks-1; + break; + default: + printk (UNKNOWN_LEVEL, mdidx(mddev), sb->level); + goto abort; + } + if (!md_size[mdidx(mddev)]) + md_size[mdidx(mddev)] = sb->size * data_disks; + + readahead = MD_READAHEAD; + if ((sb->level == 0) || (sb->level == 4) || (sb->level == 5)) { + readahead = (mddev->sb->chunk_size>>PAGE_SHIFT) * 4 * data_disks; + if (readahead < data_disks * (MAX_SECTORS>>(PAGE_SHIFT-9))*2) + readahead = data_disks * (MAX_SECTORS>>(PAGE_SHIFT-9))*2; + } else { + if (sb->level == -3) + readahead = 0; + } + md_maxreadahead[mdidx(mddev)] = readahead; + + printk(KERN_INFO "md%d: max total readahead window set to %ldk\n", + mdidx(mddev), readahead*(PAGE_SIZE/1024)); + + printk(KERN_INFO + "md%d: %d data-disks, max readahead per data-disk: %ldk\n", + mdidx(mddev), data_disks, readahead/data_disks*(PAGE_SIZE/1024)); + return 0; +abort: + return 1; +} + + +#define TOO_BIG_CHUNKSIZE KERN_ERR \ +"too big chunk_size: %d > %d\n" + +#define TOO_SMALL_CHUNKSIZE KERN_ERR \ +"too small chunk_size: %d < %ld\n" + +#define BAD_CHUNKSIZE KERN_ERR \ +"no chunksize specified, see 'man raidtab'\n" + +static int do_md_run (mddev_t * mddev) +{ + int pnum, err; + int chunk_size; + struct md_list_head *tmp; + mdk_rdev_t *rdev; + + + if (!mddev->nb_dev) { + MD_BUG(); + return -EINVAL; + } + + if (mddev->pers) + return -EBUSY; + + /* + * Resize disks to align partitions size on a given + * chunk size. + */ + md_size[mdidx(mddev)] = 0; + + /* + * Analyze all RAID superblock(s) + */ + if (analyze_sbs(mddev)) { + MD_BUG(); + return -EINVAL; + } + + chunk_size = mddev->sb->chunk_size; + pnum = level_to_pers(mddev->sb->level); + + mddev->param.chunk_size = chunk_size; + mddev->param.personality = pnum; + + if (chunk_size > MAX_CHUNK_SIZE) { + printk(TOO_BIG_CHUNKSIZE, chunk_size, MAX_CHUNK_SIZE); + return -EINVAL; + } + /* + * chunk-size has to be a power of 2 and multiples of PAGE_SIZE + */ + if ( (1 << ffz(~chunk_size)) != chunk_size) { + MD_BUG(); + return -EINVAL; + } + if (chunk_size < PAGE_SIZE) { + printk(TOO_SMALL_CHUNKSIZE, chunk_size, PAGE_SIZE); + return -EINVAL; + } + + if (pnum >= MAX_PERSONALITY) { + MD_BUG(); + return -EINVAL; + } + + if ((pnum != RAID1) && (pnum != LINEAR) && !chunk_size) { + /* + * 'default chunksize' in the old md code used to + * be PAGE_SIZE, baaad. + * we abort here to be on the safe side. We dont + * want to continue the bad practice. + */ + printk(BAD_CHUNKSIZE); + return -EINVAL; + } + + if (!pers[pnum]) + { +#ifdef CONFIG_KMOD + char module_name[80]; + sprintf (module_name, "md-personality-%d", pnum); + request_module (module_name); + if (!pers[pnum]) +#endif + return -EINVAL; + } + + if (device_size_calculation(mddev)) + return -EINVAL; + + /* + * Drop all container device buffers, from now on + * the only valid external interface is through the md + * device. + * Also find largest hardsector size + */ + md_hardsect_sizes[mdidx(mddev)] = 512; + ITERATE_RDEV(mddev,rdev,tmp) { + if (rdev->faulty) + continue; + fsync_dev(rdev->dev); + invalidate_buffers(rdev->dev); + if (get_hardsect_size(rdev->dev) + > md_hardsect_sizes[mdidx(mddev)]) + md_hardsect_sizes[mdidx(mddev)] = + get_hardsect_size(rdev->dev); + } + md_blocksizes[mdidx(mddev)] = 1024; + if (md_blocksizes[mdidx(mddev)] < md_hardsect_sizes[mdidx(mddev)]) + md_blocksizes[mdidx(mddev)] = md_hardsect_sizes[mdidx(mddev)]; + mddev->pers = pers[pnum]; + + err = mddev->pers->run(mddev); + if (err) { + printk("pers->run() failed ...\n"); + mddev->pers = NULL; + return -EINVAL; + } + + mddev->sb->state &= ~(1 << MD_SB_CLEAN); + md_update_sb(mddev); + + /* + * md_size has units of 1K blocks, which are + * twice as large as sectors. + */ + md_hd_struct[mdidx(mddev)].start_sect = 0; + md_hd_struct[mdidx(mddev)].nr_sects = md_size[mdidx(mddev)] << 1; + + read_ahead[MD_MAJOR] = 1024; + return (0); +} + +#undef TOO_BIG_CHUNKSIZE +#undef BAD_CHUNKSIZE + +#define OUT(x) do { err = (x); goto out; } while (0) + +static int restart_array (mddev_t *mddev) +{ + int err = 0; + + /* + * Complain if it has no devices + */ + if (!mddev->nb_dev) + OUT(-ENXIO); + + if (mddev->pers) { + if (!mddev->ro) + OUT(-EBUSY); + + mddev->ro = 0; + set_device_ro(mddev_to_kdev(mddev), 0); + + printk (KERN_INFO + "md%d switched to read-write mode.\n", mdidx(mddev)); + /* + * Kick recovery or resync if necessary + */ + md_recover_arrays(); + if (mddev->pers->restart_resync) + mddev->pers->restart_resync(mddev); + } else + err = -EINVAL; + +out: + return err; +} + +#define STILL_MOUNTED KERN_WARNING \ +"md: md%d still mounted.\n" + +static int do_md_stop (mddev_t * mddev, int ro) +{ + int err = 0, resync_interrupted = 0; + kdev_t dev = mddev_to_kdev(mddev); + + if (!ro && get_super(dev)) { + printk (STILL_MOUNTED, mdidx(mddev)); + OUT(-EBUSY); + } + + if (mddev->pers) { + /* + * It is safe to call stop here, it only frees private + * data. Also, it tells us if a device is unstoppable + * (eg. resyncing is in progress) + */ + if (mddev->pers->stop_resync) + if (mddev->pers->stop_resync(mddev)) + resync_interrupted = 1; + + if (mddev->recovery_running) + md_interrupt_thread(md_recovery_thread); + + /* + * This synchronizes with signal delivery to the + * resync or reconstruction thread. It also nicely + * hangs the process if some reconstruction has not + * finished. + */ + down(&mddev->recovery_sem); + up(&mddev->recovery_sem); + + /* + * sync and invalidate buffers because we cannot kill the + * main thread with valid IO transfers still around. + * the kernel lock protects us from new requests being + * added after invalidate_buffers(). + */ + fsync_dev (mddev_to_kdev(mddev)); + fsync_dev (dev); + invalidate_buffers (dev); + + if (ro) { + if (mddev->ro) + OUT(-ENXIO); + mddev->ro = 1; + } else { + if (mddev->ro) + set_device_ro(dev, 0); + if (mddev->pers->stop(mddev)) { + if (mddev->ro) + set_device_ro(dev, 1); + OUT(-EBUSY); + } + if (mddev->ro) + mddev->ro = 0; + } + if (mddev->sb) { + /* + * mark it clean only if there was no resync + * interrupted. + */ + if (!mddev->recovery_running && !resync_interrupted) { + printk("marking sb clean...\n"); + mddev->sb->state |= 1 << MD_SB_CLEAN; + } + md_update_sb(mddev); + } + if (ro) + set_device_ro(dev, 1); + } + + /* + * Free resources if final stop + */ + if (!ro) { + printk (KERN_INFO "md%d stopped.\n", mdidx(mddev)); + free_mddev(mddev); + + } else + printk (KERN_INFO + "md%d switched to read-only mode.\n", mdidx(mddev)); +out: + return err; +} + +#undef OUT + +/* + * We have to safely support old arrays too. + */ +int detect_old_array (mdp_super_t *sb) +{ + if (sb->major_version > 0) + return 0; + if (sb->minor_version >= 90) + return 0; + + return -EINVAL; +} + + +static void autorun_array (mddev_t *mddev) +{ + mdk_rdev_t *rdev; + struct md_list_head *tmp; + int err; + + if (mddev->disks.prev == &mddev->disks) { + MD_BUG(); + return; + } + + printk("running: "); + + ITERATE_RDEV(mddev,rdev,tmp) { + printk("<%s>", partition_name(rdev->dev)); + } + printk("\nnow!\n"); + + err = do_md_run (mddev); + if (err) { + printk("do_md_run() returned %d\n", err); + /* + * prevent the writeback of an unrunnable array + */ + mddev->sb_dirty = 0; + do_md_stop (mddev, 0); + } +} + +/* + * lets try to run arrays based on all disks that have arrived + * until now. (those are in the ->pending list) + * + * the method: pick the first pending disk, collect all disks with + * the same UUID, remove all from the pending list and put them into + * the 'same_array' list. Then order this list based on superblock + * update time (freshest comes first), kick out 'old' disks and + * compare superblocks. If everything's fine then run it. + */ +static void autorun_devices (void) +{ + struct md_list_head candidates; + struct md_list_head *tmp; + mdk_rdev_t *rdev0, *rdev; + mddev_t *mddev; + kdev_t md_kdev; + + + printk("autorun ...\n"); + while (pending_raid_disks.next != &pending_raid_disks) { + rdev0 = md_list_entry(pending_raid_disks.next, + mdk_rdev_t, pending); + + printk("considering %s ...\n", partition_name(rdev0->dev)); + MD_INIT_LIST_HEAD(&candidates); + ITERATE_RDEV_PENDING(rdev,tmp) { + if (uuid_equal(rdev0, rdev)) { + if (!sb_equal(rdev0->sb, rdev->sb)) { + printk("%s has same UUID as %s, but superblocks differ ...\n", partition_name(rdev->dev), partition_name(rdev0->dev)); + continue; + } + printk(" adding %s ...\n", partition_name(rdev->dev)); + md_list_del(&rdev->pending); + md_list_add(&rdev->pending, &candidates); + } + } + /* + * now we have a set of devices, with all of them having + * mostly sane superblocks. It's time to allocate the + * mddev. + */ + md_kdev = MKDEV(MD_MAJOR, rdev0->sb->md_minor); + mddev = kdev_to_mddev(md_kdev); + if (mddev) { + printk("md%d already running, cannot run %s\n", + mdidx(mddev), partition_name(rdev0->dev)); + ITERATE_RDEV_GENERIC(candidates,pending,rdev,tmp) + export_rdev(rdev); + continue; + } + mddev = alloc_mddev(md_kdev); + printk("created md%d\n", mdidx(mddev)); + ITERATE_RDEV_GENERIC(candidates,pending,rdev,tmp) { + bind_rdev_to_array(rdev, mddev); + md_list_del(&rdev->pending); + MD_INIT_LIST_HEAD(&rdev->pending); + } + autorun_array(mddev); + } + printk("... autorun DONE.\n"); +} + +/* + * import RAID devices based on one partition + * if possible, the array gets run as well. + */ + +#define BAD_VERSION KERN_ERR \ +"md: %s has RAID superblock version 0.%d, autodetect needs v0.90 or higher\n" + +#define OUT_OF_MEM KERN_ALERT \ +"md: out of memory.\n" + +#define NO_DEVICE KERN_ERR \ +"md: disabled device %s\n" + +#define AUTOADD_FAILED KERN_ERR \ +"md: auto-adding devices to md%d FAILED (error %d).\n" + +#define AUTOADD_FAILED_USED KERN_ERR \ +"md: cannot auto-add device %s to md%d, already used.\n" + +#define AUTORUN_FAILED KERN_ERR \ +"md: auto-running md%d FAILED (error %d).\n" + +#define MDDEV_BUSY KERN_ERR \ +"md: cannot auto-add to md%d, already running.\n" + +#define AUTOADDING KERN_INFO \ +"md: auto-adding devices to md%d, based on %s's superblock.\n" + +#define AUTORUNNING KERN_INFO \ +"md: auto-running md%d.\n" + +static int autostart_array (kdev_t startdev) +{ + int err = -EINVAL, i; + mdp_super_t *sb = NULL; + mdk_rdev_t *start_rdev = NULL, *rdev; + + if (md_import_device(startdev, 1)) { + printk("could not import %s!\n", partition_name(startdev)); + goto abort; + } + + start_rdev = find_rdev_all(startdev); + if (!start_rdev) { + MD_BUG(); + goto abort; + } + if (start_rdev->faulty) { + printk("can not autostart based on faulty %s!\n", + partition_name(startdev)); + goto abort; + } + md_list_add(&start_rdev->pending, &pending_raid_disks); + + sb = start_rdev->sb; + + err = detect_old_array(sb); + if (err) { + printk("array version is too old to be autostarted, use raidtools 0.90 mkraid --upgrade\nto upgrade the array without data loss!\n"); + goto abort; + } + + for (i = 0; i < MD_SB_DISKS; i++) { + mdp_disk_t *desc; + kdev_t dev; + + desc = sb->disks + i; + dev = MKDEV(desc->major, desc->minor); + + if (dev == MKDEV(0,0)) + continue; + if (dev == startdev) + continue; + if (md_import_device(dev, 1)) { + printk("could not import %s, trying to run array nevertheless.\n", partition_name(dev)); + continue; + } + rdev = find_rdev_all(dev); + if (!rdev) { + MD_BUG(); + goto abort; + } + md_list_add(&rdev->pending, &pending_raid_disks); + } + + /* + * possibly return codes + */ + autorun_devices(); + return 0; + +abort: + if (start_rdev) + export_rdev(start_rdev); + return err; +} + +#undef BAD_VERSION +#undef OUT_OF_MEM +#undef NO_DEVICE +#undef AUTOADD_FAILED_USED +#undef AUTOADD_FAILED +#undef AUTORUN_FAILED +#undef AUTOADDING +#undef AUTORUNNING + +struct { + int set; + int noautodetect; + +} raid_setup_args md__initdata = { 0, 0 }; + +void md_setup_drive(void) md__init; + +/* + * Searches all registered partitions for autorun RAID arrays + * at boot time. + */ +#ifdef CONFIG_AUTODETECT_RAID +static int detected_devices[128] md__initdata; +static int dev_cnt=0; +void md_autodetect_dev(kdev_t dev) +{ + if (dev_cnt >= 0 && dev_cnt < 127) + detected_devices[dev_cnt++] = dev; +} +#endif + +int md__init md_run_setup(void) +{ +#ifdef CONFIG_AUTODETECT_RAID + mdk_rdev_t *rdev; + int i; + + if (raid_setup_args.noautodetect) + printk(KERN_INFO "skipping autodetection of RAID arrays\n"); + else { + + printk(KERN_INFO "autodetecting RAID arrays\n"); + + for (i=0; ifaulty) { + MD_BUG(); + continue; + } + md_list_add(&rdev->pending, &pending_raid_disks); + } + + autorun_devices(); + } + + dev_cnt = -1; /* make sure further calls to md_autodetect_dev are ignored */ +#endif +#ifdef CONFIG_MD_BOOT + md_setup_drive(); +#endif + return 0; +} + +static int get_version (void * arg) +{ + mdu_version_t ver; + + ver.major = MD_MAJOR_VERSION; + ver.minor = MD_MINOR_VERSION; + ver.patchlevel = MD_PATCHLEVEL_VERSION; + + if (md_copy_to_user(arg, &ver, sizeof(ver))) + return -EFAULT; + + return 0; +} + +#define SET_FROM_SB(x) info.x = mddev->sb->x +static int get_array_info (mddev_t * mddev, void * arg) +{ + mdu_array_info_t info; + + if (!mddev->sb) + return -EINVAL; + + SET_FROM_SB(major_version); + SET_FROM_SB(minor_version); + SET_FROM_SB(patch_version); + SET_FROM_SB(ctime); + SET_FROM_SB(level); + SET_FROM_SB(size); + SET_FROM_SB(nr_disks); + SET_FROM_SB(raid_disks); + SET_FROM_SB(md_minor); + SET_FROM_SB(not_persistent); + + SET_FROM_SB(utime); + SET_FROM_SB(state); + SET_FROM_SB(active_disks); + SET_FROM_SB(working_disks); + SET_FROM_SB(failed_disks); + SET_FROM_SB(spare_disks); + + SET_FROM_SB(layout); + SET_FROM_SB(chunk_size); + + if (md_copy_to_user(arg, &info, sizeof(info))) + return -EFAULT; + + return 0; +} +#undef SET_FROM_SB + +#define SET_FROM_SB(x) info.x = mddev->sb->disks[nr].x +static int get_disk_info (mddev_t * mddev, void * arg) +{ + mdu_disk_info_t info; + unsigned int nr; + + if (!mddev->sb) + return -EINVAL; + + if (md_copy_from_user(&info, arg, sizeof(info))) + return -EFAULT; + + nr = info.number; + if (nr >= mddev->sb->nr_disks) + return -EINVAL; + + SET_FROM_SB(major); + SET_FROM_SB(minor); + SET_FROM_SB(raid_disk); + SET_FROM_SB(state); + + if (md_copy_to_user(arg, &info, sizeof(info))) + return -EFAULT; + + return 0; +} +#undef SET_FROM_SB + +#define SET_SB(x) mddev->sb->disks[nr].x = info->x + +static int add_new_disk (mddev_t * mddev, mdu_disk_info_t *info) +{ + int err, size, persistent; + mdk_rdev_t *rdev; + unsigned int nr; + kdev_t dev; + dev = MKDEV(info->major,info->minor); + + if (find_rdev_all(dev)) { + printk("device %s already used in a RAID array!\n", + partition_name(dev)); + return -EBUSY; + } + if (!mddev->sb) { + /* expecting a device which has a superblock */ + err = md_import_device(dev, 1); + if (err) { + printk("md error, md_import_device returned %d\n", err); + return -EINVAL; + } + rdev = find_rdev_all(dev); + if (!rdev) { + MD_BUG(); + return -EINVAL; + } + if (mddev->nb_dev) { + mdk_rdev_t *rdev0 = md_list_entry(mddev->disks.next, + mdk_rdev_t, same_set); + if (!uuid_equal(rdev0, rdev)) { + printk("md: %s has different UUID to %s\n", partition_name(rdev->dev), partition_name(rdev0->dev)); + export_rdev(rdev); + return -EINVAL; + } + if (!sb_equal(rdev0->sb, rdev->sb)) { + printk("md: %s has same UUID but different superblock to %s\n", partition_name(rdev->dev), partition_name(rdev0->dev)); + export_rdev(rdev); + return -EINVAL; + } + } + bind_rdev_to_array(rdev, mddev); + return 0; + } + + nr = info->number; + if (nr >= mddev->sb->nr_disks) + return -EINVAL; + + SET_SB(number); + SET_SB(major); + SET_SB(minor); + SET_SB(raid_disk); + SET_SB(state); + + if ((info->state & (1<old_dev = dev; + rdev->desc_nr = info->number; + + bind_rdev_to_array(rdev, mddev); + + persistent = !mddev->sb->not_persistent; + if (!persistent) + printk("nonpersistent superblock ...\n"); + if (!mddev->sb->chunk_size) + printk("no chunksize?\n"); + + size = calc_dev_size(dev, mddev, persistent); + rdev->sb_offset = calc_dev_sboffset(dev, mddev, persistent); + + if (!mddev->sb->size || (mddev->sb->size > size)) + mddev->sb->size = size; + } + + /* + * sync all other superblocks with the main superblock + */ + sync_sbs(mddev); + + return 0; +} +#undef SET_SB + +static int hot_remove_disk (mddev_t * mddev, kdev_t dev) +{ + int err; + mdk_rdev_t *rdev; + mdp_disk_t *disk; + + if (!mddev->pers) + return -ENODEV; + + printk("trying to remove %s from md%d ... \n", + partition_name(dev), mdidx(mddev)); + + if (!mddev->pers->diskop) { + printk("md%d: personality does not support diskops!\n", + mdidx(mddev)); + return -EINVAL; + } + + rdev = find_rdev(mddev, dev); + if (!rdev) + return -ENXIO; + + if (rdev->desc_nr == -1) { + MD_BUG(); + return -EINVAL; + } + disk = &mddev->sb->disks[rdev->desc_nr]; + if (disk_active(disk)) + goto busy; + if (disk_removed(disk)) { + MD_BUG(); + return -EINVAL; + } + + err = mddev->pers->diskop(mddev, &disk, DISKOP_HOT_REMOVE_DISK); + if (err == -EBUSY) + goto busy; + if (err) { + MD_BUG(); + return -EINVAL; + } + + remove_descriptor(disk, mddev->sb); + kick_rdev_from_array(rdev); + mddev->sb_dirty = 1; + md_update_sb(mddev); + + return 0; +busy: + printk("cannot remove active disk %s from md%d ... \n", + partition_name(dev), mdidx(mddev)); + return -EBUSY; +} + +static int hot_add_disk (mddev_t * mddev, kdev_t dev) +{ + int i, err, persistent; + unsigned int size; + mdk_rdev_t *rdev; + mdp_disk_t *disk; + + if (!mddev->pers) + return -ENODEV; + + printk("trying to hot-add %s to md%d ... \n", + partition_name(dev), mdidx(mddev)); + + if (!mddev->pers->diskop) { + printk("md%d: personality does not support diskops!\n", + mdidx(mddev)); + return -EINVAL; + } + + persistent = !mddev->sb->not_persistent; + size = calc_dev_size(dev, mddev, persistent); + + if (size < mddev->sb->size) { + printk("md%d: disk size %d blocks < array size %d\n", + mdidx(mddev), size, mddev->sb->size); + return -ENOSPC; + } + + rdev = find_rdev(mddev, dev); + if (rdev) + return -EBUSY; + + err = md_import_device (dev, 0); + if (err) { + printk("md: error, md_import_device() returned %d\n", err); + return -EINVAL; + } + rdev = find_rdev_all(dev); + if (!rdev) { + MD_BUG(); + return -EINVAL; + } + if (rdev->faulty) { + printk("md: can not hot-add faulty %s disk to md%d!\n", + partition_name(dev), mdidx(mddev)); + err = -EINVAL; + goto abort_export; + } + bind_rdev_to_array(rdev, mddev); + + /* + * The rest should better be atomic, we can have disk failures + * noticed in interrupt contexts ... + */ + rdev->old_dev = dev; + rdev->size = size; + rdev->sb_offset = calc_dev_sboffset(dev, mddev, persistent); + + disk = mddev->sb->disks + mddev->sb->raid_disks; + for (i = mddev->sb->raid_disks; i < MD_SB_DISKS; i++) { + disk = mddev->sb->disks + i; + + if (!disk->major && !disk->minor) + break; + if (disk_removed(disk)) + break; + } + if (i == MD_SB_DISKS) { + printk("md%d: can not hot-add to full array!\n", mdidx(mddev)); + err = -EBUSY; + goto abort_unbind_export; + } + + if (disk_removed(disk)) { + /* + * reuse slot + */ + if (disk->number != i) { + MD_BUG(); + err = -EINVAL; + goto abort_unbind_export; + } + } else { + disk->number = i; + } + + disk->raid_disk = disk->number; + disk->major = MAJOR(dev); + disk->minor = MINOR(dev); + + if (mddev->pers->diskop(mddev, &disk, DISKOP_HOT_ADD_DISK)) { + MD_BUG(); + err = -EINVAL; + goto abort_unbind_export; + } + + mark_disk_spare(disk); + mddev->sb->nr_disks++; + mddev->sb->spare_disks++; + mddev->sb->working_disks++; + + mddev->sb_dirty = 1; + + md_update_sb(mddev); + + /* + * Kick recovery, maybe this spare has to be added to the + * array immediately. + */ + md_recover_arrays(); + + return 0; + +abort_unbind_export: + unbind_rdev_from_array(rdev); + +abort_export: + export_rdev(rdev); + return err; +} + +#define SET_SB(x) mddev->sb->x = info->x +static int set_array_info (mddev_t * mddev, mdu_array_info_t *info) +{ + + if (alloc_array_sb(mddev)) + return -ENOMEM; + + mddev->sb->major_version = MD_MAJOR_VERSION; + mddev->sb->minor_version = MD_MINOR_VERSION; + mddev->sb->patch_version = MD_PATCHLEVEL_VERSION; + mddev->sb->ctime = CURRENT_TIME; + + SET_SB(level); + SET_SB(size); + SET_SB(nr_disks); + SET_SB(raid_disks); + SET_SB(md_minor); + SET_SB(not_persistent); + + SET_SB(state); + SET_SB(active_disks); + SET_SB(working_disks); + SET_SB(failed_disks); + SET_SB(spare_disks); + + SET_SB(layout); + SET_SB(chunk_size); + + mddev->sb->md_magic = MD_SB_MAGIC; + + /* + * Generate a 128 bit UUID + */ + get_random_bytes(&mddev->sb->set_uuid0, 4); + get_random_bytes(&mddev->sb->set_uuid1, 4); + get_random_bytes(&mddev->sb->set_uuid2, 4); + get_random_bytes(&mddev->sb->set_uuid3, 4); + + return 0; +} +#undef SET_SB + +static int set_disk_info (mddev_t * mddev, void * arg) +{ + printk("not yet"); + return -EINVAL; +} + +static int clear_array (mddev_t * mddev) +{ + printk("not yet"); + return -EINVAL; +} + +static int write_raid_info (mddev_t * mddev) +{ + printk("not yet"); + return -EINVAL; +} + +static int protect_array (mddev_t * mddev) +{ + printk("not yet"); + return -EINVAL; +} + +static int unprotect_array (mddev_t * mddev) +{ + printk("not yet"); + return -EINVAL; +} + +static int set_disk_faulty (mddev_t *mddev, kdev_t dev) +{ + int ret; + + fsync_dev(mddev_to_kdev(mddev)); + ret = md_error(mddev_to_kdev(mddev), dev); + return ret; +} + +static int md_ioctl (struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + unsigned int minor; + int err = 0; + struct hd_geometry *loc = (struct hd_geometry *) arg; + mddev_t *mddev = NULL; + kdev_t dev; + + if (!md_capable_admin()) + return -EACCES; + + dev = inode->i_rdev; + minor = MINOR(dev); + if (minor >= MAX_MD_DEVS) + return -EINVAL; + + /* + * Commands dealing with the RAID driver but not any + * particular array: + */ + switch (cmd) + { + case RAID_VERSION: + err = get_version((void *)arg); + goto done; + + case PRINT_RAID_DEBUG: + err = 0; + md_print_devices(); + goto done_unlock; + + case BLKGETSIZE: /* Return device size */ + if (!arg) { + err = -EINVAL; + goto abort; + } + err = md_put_user(md_hd_struct[minor].nr_sects, + (long *) arg); + goto done; + + case BLKFLSBUF: + fsync_dev(dev); + invalidate_buffers(dev); + goto done; + + case BLKRASET: + if (arg > 0xff) { + err = -EINVAL; + goto abort; + } + read_ahead[MAJOR(dev)] = arg; + goto done; + + case BLKRAGET: + if (!arg) { + err = -EINVAL; + goto abort; + } + err = md_put_user (read_ahead[ + MAJOR(dev)], (long *) arg); + goto done; + default: + } + + /* + * Commands creating/starting a new array: + */ + + mddev = kdev_to_mddev(dev); + + switch (cmd) + { + case SET_ARRAY_INFO: + case START_ARRAY: + if (mddev) { + printk("array md%d already exists!\n", + mdidx(mddev)); + err = -EEXIST; + goto abort; + } + default: + } + switch (cmd) + { + case SET_ARRAY_INFO: + mddev = alloc_mddev(dev); + if (!mddev) { + err = -ENOMEM; + goto abort; + } + /* + * alloc_mddev() should possibly self-lock. + */ + err = lock_mddev(mddev); + if (err) { + printk("ioctl, reason %d, cmd %d\n", err, cmd); + goto abort; + } + + if (mddev->sb) { + printk("array md%d already has a superblock!\n", + mdidx(mddev)); + err = -EBUSY; + goto abort_unlock; + } + if (arg) { + mdu_array_info_t info; + if (md_copy_from_user(&info, (void*)arg, sizeof(info))) { + err = -EFAULT; + goto abort_unlock; + } + err = set_array_info(mddev, &info); + if (err) { + printk("couldnt set array info. %d\n", err); + goto abort_unlock; + } + } + goto done_unlock; + + case START_ARRAY: + /* + * possibly make it lock the array ... + */ + err = autostart_array((kdev_t)arg); + if (err) { + printk("autostart %s failed!\n", + partition_name((kdev_t)arg)); + goto abort; + } + goto done; + + default: + } + + /* + * Commands querying/configuring an existing array: + */ + + if (!mddev) { + err = -ENODEV; + goto abort; + } + err = lock_mddev(mddev); + if (err) { + printk("ioctl lock interrupted, reason %d, cmd %d\n",err, cmd); + goto abort; + } + /* if we don't have a superblock yet, only ADD_NEW_DISK or STOP_ARRAY is allowed */ + if (!mddev->sb && cmd != ADD_NEW_DISK && cmd != STOP_ARRAY && cmd != RUN_ARRAY) { + err = -ENODEV; + goto abort_unlock; + } + + /* + * Commands even a read-only array can execute: + */ + switch (cmd) + { + case GET_ARRAY_INFO: + err = get_array_info(mddev, (void *)arg); + goto done_unlock; + + case GET_DISK_INFO: + err = get_disk_info(mddev, (void *)arg); + goto done_unlock; + + case RESTART_ARRAY_RW: + err = restart_array(mddev); + goto done_unlock; + + case STOP_ARRAY: + if (!(err = do_md_stop (mddev, 0))) + mddev = NULL; + goto done_unlock; + + case STOP_ARRAY_RO: + err = do_md_stop (mddev, 1); + goto done_unlock; + + /* + * We have a problem here : there is no easy way to give a CHS + * virtual geometry. We currently pretend that we have a 2 heads + * 4 sectors (with a BIG number of cylinders...). This drives + * dosfs just mad... ;-) + */ + case HDIO_GETGEO: + if (!loc) { + err = -EINVAL; + goto abort_unlock; + } + err = md_put_user (2, (char *) &loc->heads); + if (err) + goto abort_unlock; + err = md_put_user (4, (char *) &loc->sectors); + if (err) + goto abort_unlock; + err = md_put_user (md_hd_struct[mdidx(mddev)].nr_sects/8, + (short *) &loc->cylinders); + if (err) + goto abort_unlock; + err = md_put_user (md_hd_struct[minor].start_sect, + (long *) &loc->start); + goto done_unlock; + } + + /* + * The remaining ioctls are changing the state of the + * superblock, so we do not allow read-only arrays + * here: + */ + if (mddev->ro) { + err = -EROFS; + goto abort_unlock; + } + + switch (cmd) + { + case CLEAR_ARRAY: + err = clear_array(mddev); + goto done_unlock; + + case ADD_NEW_DISK: + { + mdu_disk_info_t info; + if (md_copy_from_user(&info, (void*)arg, sizeof(info))) + err = -EFAULT; + else + err = add_new_disk(mddev, &info); + goto done_unlock; + } + case HOT_REMOVE_DISK: + err = hot_remove_disk(mddev, (kdev_t)arg); + goto done_unlock; + + case HOT_ADD_DISK: + err = hot_add_disk(mddev, (kdev_t)arg); + goto done_unlock; + + case SET_DISK_INFO: + err = set_disk_info(mddev, (void *)arg); + goto done_unlock; + + case WRITE_RAID_INFO: + err = write_raid_info(mddev); + goto done_unlock; + + case UNPROTECT_ARRAY: + err = unprotect_array(mddev); + goto done_unlock; + + case PROTECT_ARRAY: + err = protect_array(mddev); + goto done_unlock; + + case SET_DISK_FAULTY: + err = set_disk_faulty(mddev, (kdev_t)arg); + goto done_unlock; + + case RUN_ARRAY: + { +/* The data is never used.... + mdu_param_t param; + err = md_copy_from_user(¶m, (mdu_param_t *)arg, + sizeof(param)); + if (err) + goto abort_unlock; +*/ + err = do_md_run (mddev); + /* + * we have to clean up the mess if + * the array cannot be run for some + * reason ... + */ + if (err) { + mddev->sb_dirty = 0; + if (!do_md_stop (mddev, 0)) + mddev = NULL; + } + goto done_unlock; + } + + default: + printk(KERN_WARNING "%s(pid %d) used obsolete MD ioctl, upgrade your software to use new ictls.\n", current->comm, current->pid); + err = -EINVAL; + goto abort_unlock; + } + +done_unlock: +abort_unlock: + if (mddev) + unlock_mddev(mddev); + + return err; +done: + if (err) + printk("huh12?\n"); +abort: + return err; +} + +static int md_open (struct inode *inode, struct file *file) +{ + /* + * Always succeed + */ + return (0); +} + +static struct block_device_operations md_fops= +{ + open: md_open, + ioctl: md_ioctl, +}; + + +int md_thread(void * arg) +{ + mdk_thread_t *thread = arg; + + md_lock_kernel(); + exit_mm(current); + exit_files(current); + exit_fs(current); + + /* + * Detach thread + */ + daemonize(); + sprintf(current->comm, thread->name); + md_init_signals(); + md_flush_signals(); + thread->tsk = current; + + /* + * md_thread is a 'system-thread', it's priority should be very + * high. We avoid resource deadlocks individually in each + * raid personality. (RAID5 does preallocation) We also use RR and + * the very same RT priority as kswapd, thus we will never get + * into a priority inversion deadlock. + * + * we definitely have to have equal or higher priority than + * bdflush, otherwise bdflush will deadlock if there are too + * many dirty RAID5 blocks. + */ + current->policy = SCHED_OTHER; + current->nice = -20; +// md_unlock_kernel(); + + up(thread->sem); + + for (;;) { + DECLARE_WAITQUEUE(wait, current); + + add_wait_queue(&thread->wqueue, &wait); + set_task_state(current, TASK_INTERRUPTIBLE); + if (!test_bit(THREAD_WAKEUP, &thread->flags)) { + dprintk("thread %p went to sleep.\n", thread); + schedule(); + dprintk("thread %p woke up.\n", thread); + } + current->state = TASK_RUNNING; + remove_wait_queue(&thread->wqueue, &wait); + clear_bit(THREAD_WAKEUP, &thread->flags); + + if (thread->run) { + thread->run(thread->data); + run_task_queue(&tq_disk); + } else + break; + if (md_signal_pending(current)) { + printk("%8s(%d) flushing signals.\n", current->comm, + current->pid); + md_flush_signals(); + } + } + up(thread->sem); + return 0; +} + +void md_wakeup_thread(mdk_thread_t *thread) +{ + dprintk("waking up MD thread %p.\n", thread); + set_bit(THREAD_WAKEUP, &thread->flags); + wake_up(&thread->wqueue); +} + +mdk_thread_t *md_register_thread (void (*run) (void *), + void *data, const char *name) +{ + mdk_thread_t *thread; + int ret; + DECLARE_MUTEX_LOCKED(sem); + + thread = (mdk_thread_t *) kmalloc + (sizeof(mdk_thread_t), GFP_KERNEL); + if (!thread) + return NULL; + + memset(thread, 0, sizeof(mdk_thread_t)); + md_init_waitqueue_head(&thread->wqueue); + + thread->sem = &sem; + thread->run = run; + thread->data = data; + thread->name = name; + ret = kernel_thread(md_thread, thread, 0); + if (ret < 0) { + kfree(thread); + return NULL; + } + down(&sem); + return thread; +} + +void md_interrupt_thread (mdk_thread_t *thread) +{ + if (!thread->tsk) { + MD_BUG(); + return; + } + printk("interrupting MD-thread pid %d\n", thread->tsk->pid); + send_sig(SIGKILL, thread->tsk, 1); +} + +void md_unregister_thread (mdk_thread_t *thread) +{ + DECLARE_MUTEX_LOCKED(sem); + + thread->sem = &sem; + thread->run = NULL; + thread->name = NULL; + if (!thread->tsk) { + MD_BUG(); + return; + } + md_interrupt_thread(thread); + down(&sem); +} + +void md_recover_arrays (void) +{ + if (!md_recovery_thread) { + MD_BUG(); + return; + } + md_wakeup_thread(md_recovery_thread); +} + + +int md_error (kdev_t dev, kdev_t rdev) +{ + mddev_t *mddev; + mdk_rdev_t * rrdev; + int rc; + + mddev = kdev_to_mddev(dev); +/* printk("md_error dev:(%d:%d), rdev:(%d:%d), (caller: %p,%p,%p,%p).\n",MAJOR(dev),MINOR(dev),MAJOR(rdev),MINOR(rdev), __builtin_return_address(0),__builtin_return_address(1),__builtin_return_address(2),__builtin_return_address(3)); + */ + if (!mddev) { + MD_BUG(); + return 0; + } + rrdev = find_rdev(mddev, rdev); + mark_rdev_faulty(rrdev); + /* + * if recovery was running, stop it now. + */ + if (mddev->pers->stop_resync) + mddev->pers->stop_resync(mddev); + if (mddev->recovery_running) + md_interrupt_thread(md_recovery_thread); + if (mddev->pers->error_handler) { + rc = mddev->pers->error_handler(mddev, rdev); + md_recover_arrays(); + return rc; + } + return 0; +} + +static int status_unused (char * page) +{ + int sz = 0, i = 0; + mdk_rdev_t *rdev; + struct md_list_head *tmp; + + sz += sprintf(page + sz, "unused devices: "); + + ITERATE_RDEV_ALL(rdev,tmp) { + if (!rdev->same_set.next && !rdev->same_set.prev) { + /* + * The device is not yet used by any array. + */ + i++; + sz += sprintf(page + sz, "%s ", + partition_name(rdev->dev)); + } + } + if (!i) + sz += sprintf(page + sz, ""); + + sz += sprintf(page + sz, "\n"); + return sz; +} + + +static int status_resync (char * page, mddev_t * mddev) +{ + int sz = 0; + unsigned long max_blocks, resync, res, dt, db, rt; + + resync = mddev->curr_resync - atomic_read(&mddev->recovery_active); + max_blocks = mddev->sb->size; + + /* + * Should not happen. + */ + if (!max_blocks) { + MD_BUG(); + return 0; + } + res = (resync/1024)*1000/(max_blocks/1024 + 1); + { + int i, x = res/50, y = 20-x; + sz += sprintf(page + sz, "["); + for (i = 0; i < x; i++) + sz += sprintf(page + sz, "="); + sz += sprintf(page + sz, ">"); + for (i = 0; i < y; i++) + sz += sprintf(page + sz, "."); + sz += sprintf(page + sz, "] "); + } + if (!mddev->recovery_running) + /* + * true resync + */ + sz += sprintf(page + sz, " resync =%3lu.%lu%% (%lu/%lu)", + res/10, res % 10, resync, max_blocks); + else + /* + * recovery ... + */ + sz += sprintf(page + sz, " recovery =%3lu.%lu%% (%lu/%lu)", + res/10, res % 10, resync, max_blocks); + + /* + * We do not want to overflow, so the order of operands and + * the * 100 / 100 trick are important. We do a +1 to be + * safe against division by zero. We only estimate anyway. + * + * dt: time from mark until now + * db: blocks written from mark until now + * rt: remaining time + */ + dt = ((jiffies - mddev->resync_mark) / HZ); + if (!dt) dt++; + db = resync - mddev->resync_mark_cnt; + rt = (dt * ((max_blocks-resync) / (db/100+1)))/100; + + sz += sprintf(page + sz, " finish=%lu.%lumin", rt / 60, (rt % 60)/6); + + sz += sprintf(page + sz, " speed=%ldK/sec", db/dt); + + return sz; +} + +static int md_status_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int sz = 0, j, size; + struct md_list_head *tmp, *tmp2; + mdk_rdev_t *rdev; + mddev_t *mddev; + + sz += sprintf(page + sz, "Personalities : "); + for (j = 0; j < MAX_PERSONALITY; j++) + if (pers[j]) + sz += sprintf(page+sz, "[%s] ", pers[j]->name); + + sz += sprintf(page+sz, "\n"); + + + sz += sprintf(page+sz, "read_ahead "); + if (read_ahead[MD_MAJOR] == INT_MAX) + sz += sprintf(page+sz, "not set\n"); + else + sz += sprintf(page+sz, "%d sectors\n", read_ahead[MD_MAJOR]); + + ITERATE_MDDEV(mddev,tmp) { + sz += sprintf(page + sz, "md%d : %sactive", mdidx(mddev), + mddev->pers ? "" : "in"); + if (mddev->pers) { + if (mddev->ro) + sz += sprintf(page + sz, " (read-only)"); + sz += sprintf(page + sz, " %s", mddev->pers->name); + } + + size = 0; + ITERATE_RDEV(mddev,rdev,tmp2) { + sz += sprintf(page + sz, " %s[%d]", + partition_name(rdev->dev), rdev->desc_nr); + if (rdev->faulty) { + sz += sprintf(page + sz, "(F)"); + continue; + } + size += rdev->size; + } + + if (mddev->nb_dev) { + if (mddev->pers) + sz += sprintf(page + sz, "\n %d blocks", + md_size[mdidx(mddev)]); + else + sz += sprintf(page + sz, "\n %d blocks", size); + } + + if (!mddev->pers) { + sz += sprintf(page+sz, "\n"); + continue; + } + + sz += mddev->pers->status (page+sz, mddev); + + sz += sprintf(page+sz, "\n "); + if (mddev->curr_resync) { + sz += status_resync (page+sz, mddev); + } else { + if (md_atomic_read(&mddev->resync_sem.count) != 1) + sz += sprintf(page + sz, " resync=DELAYED"); + } + sz += sprintf(page + sz, "\n"); + } + sz += status_unused (page + sz); + + return sz; +} + +int register_md_personality (int pnum, mdk_personality_t *p) +{ + if (pnum >= MAX_PERSONALITY) + return -EINVAL; + + if (pers[pnum]) + return -EBUSY; + + pers[pnum] = p; + printk(KERN_INFO "%s personality registered\n", p->name); + return 0; +} + +int unregister_md_personality (int pnum) +{ + if (pnum >= MAX_PERSONALITY) + return -EINVAL; + + printk(KERN_INFO "%s personality unregistered\n", pers[pnum]->name); + pers[pnum] = NULL; + return 0; +} + +static mdp_disk_t *get_spare(mddev_t *mddev) +{ + mdp_super_t *sb = mddev->sb; + mdp_disk_t *disk; + mdk_rdev_t *rdev; + struct md_list_head *tmp; + + ITERATE_RDEV(mddev,rdev,tmp) { + if (rdev->faulty) + continue; + if (!rdev->sb) { + MD_BUG(); + continue; + } + disk = &sb->disks[rdev->desc_nr]; + if (disk_faulty(disk)) { + MD_BUG(); + continue; + } + if (disk_active(disk)) + continue; + return disk; + } + return NULL; +} + +static unsigned int sync_io[DK_MAX_MAJOR][DK_MAX_DISK]; +void md_sync_acct(kdev_t dev, unsigned long nr_sectors) +{ + unsigned int major = MAJOR(dev); + unsigned int index; + + index = disk_index(dev); + if ((index >= DK_MAX_DISK) || (major >= DK_MAX_MAJOR)) + return; + + sync_io[major][index] += nr_sectors; +} + +static int is_mddev_idle (mddev_t *mddev) +{ + mdk_rdev_t * rdev; + struct md_list_head *tmp; + int idle; + unsigned long curr_events; + + idle = 1; + ITERATE_RDEV(mddev,rdev,tmp) { + int major = MAJOR(rdev->dev); + int idx = disk_index(rdev->dev); + + if ((idx >= DK_MAX_DISK) || (major >= DK_MAX_MAJOR)) + continue; + + curr_events = kstat.dk_drive_rblk[major][idx] + + kstat.dk_drive_wblk[major][idx] ; + curr_events -= sync_io[major][idx]; +// printk("events(major: %d, idx: %d): %ld\n", major, idx, curr_events); + if (curr_events != rdev->last_events) { +// printk("!I(%ld)", curr_events - rdev->last_events); + rdev->last_events = curr_events; + idle = 0; + } + } + return idle; +} + +MD_DECLARE_WAIT_QUEUE_HEAD(resync_wait); + +void md_done_sync(mddev_t *mddev, int blocks, int ok) +{ + /* another "blocks" (1K) blocks have been synced */ + atomic_sub(blocks, &mddev->recovery_active); + wake_up(&mddev->recovery_wait); + if (!ok) { + // stop recovery, signal do_sync .... + } +} + +#define SYNC_MARKS 10 +#define SYNC_MARK_STEP (3*HZ) +int md_do_sync(mddev_t *mddev, mdp_disk_t *spare) +{ + mddev_t *mddev2; + unsigned int max_blocks, currspeed, + j, window, err, serialize; + kdev_t read_disk = mddev_to_kdev(mddev); + unsigned long mark[SYNC_MARKS]; + unsigned long mark_cnt[SYNC_MARKS]; + int last_mark,m; + struct md_list_head *tmp; + unsigned long last_check; + + + err = down_interruptible(&mddev->resync_sem); + if (err) + goto out_nolock; + +recheck: + serialize = 0; + ITERATE_MDDEV(mddev2,tmp) { + if (mddev2 == mddev) + continue; + if (mddev2->curr_resync && match_mddev_units(mddev,mddev2)) { + printk(KERN_INFO "md: serializing resync, md%d has overlapping physical units with md%d!\n", mdidx(mddev), mdidx(mddev2)); + serialize = 1; + break; + } + } + if (serialize) { + interruptible_sleep_on(&resync_wait); + if (md_signal_pending(current)) { + md_flush_signals(); + err = -EINTR; + goto out; + } + goto recheck; + } + + mddev->curr_resync = 1; + + max_blocks = mddev->sb->size; + + printk(KERN_INFO "md: syncing RAID array md%d\n", mdidx(mddev)); + printk(KERN_INFO "md: minimum _guaranteed_ reconstruction speed: %d KB/sec/disc.\n", + sysctl_speed_limit_min); + printk(KERN_INFO "md: using maximum available idle IO bandwith (but not more than %d KB/sec) for reconstruction.\n", sysctl_speed_limit_max); + + /* + * Resync has low priority. + */ + current->nice = 19; + + is_mddev_idle(mddev); /* this also initializes IO event counters */ + for (m = 0; m < SYNC_MARKS; m++) { + mark[m] = jiffies; + mark_cnt[m] = 0; + } + last_mark = 0; + mddev->resync_mark = mark[last_mark]; + mddev->resync_mark_cnt = mark_cnt[last_mark]; + + /* + * Tune reconstruction: + */ + window = MAX_READAHEAD*(PAGE_SIZE/1024); + printk(KERN_INFO "md: using %dk window, over a total of %d blocks.\n",window,max_blocks); + + atomic_set(&mddev->recovery_active, 0); + init_waitqueue_head(&mddev->recovery_wait); + last_check = 0; + for (j = 0; j < max_blocks;) { + int blocks; + + blocks = mddev->pers->sync_request(mddev, j); + + if (blocks < 0) { + err = blocks; + goto out; + } + atomic_add(blocks, &mddev->recovery_active); + j += blocks; + mddev->curr_resync = j; + + if (last_check + window > j) + continue; + + run_task_queue(&tq_disk); //?? + + if (jiffies >= mark[last_mark] + SYNC_MARK_STEP ) { + /* step marks */ + int next = (last_mark+1) % SYNC_MARKS; + + mddev->resync_mark = mark[next]; + mddev->resync_mark_cnt = mark_cnt[next]; + mark[next] = jiffies; + mark_cnt[next] = j - atomic_read(&mddev->recovery_active); + last_mark = next; + } + + + if (md_signal_pending(current)) { + /* + * got a signal, exit. + */ + mddev->curr_resync = 0; + printk("md_do_sync() got signal ... exiting\n"); + md_flush_signals(); + err = -EINTR; + goto out; + } + + /* + * this loop exits only if either when we are slower than + * the 'hard' speed limit, or the system was IO-idle for + * a jiffy. + * the system might be non-idle CPU-wise, but we only care + * about not overloading the IO subsystem. (things like an + * e2fsck being done on the RAID array should execute fast) + */ +repeat: + if (md_need_resched(current)) + schedule(); + + currspeed = (j-mddev->resync_mark_cnt)/((jiffies-mddev->resync_mark)/HZ +1) +1; + + if (currspeed > sysctl_speed_limit_min) { + current->nice = 19; + + if ((currspeed > sysctl_speed_limit_max) || + !is_mddev_idle(mddev)) { + current->state = TASK_INTERRUPTIBLE; + md_schedule_timeout(HZ/4); + if (!md_signal_pending(current)) + goto repeat; + } + } else + current->nice = -20; + } + fsync_dev(read_disk); + printk(KERN_INFO "md: md%d: sync done.\n",mdidx(mddev)); + err = 0; + /* + * this also signals 'finished resyncing' to md_stop + */ +out: + wait_event(mddev->recovery_wait, atomic_read(&mddev->recovery_active)==0); + up(&mddev->resync_sem); +out_nolock: + mddev->curr_resync = 0; + wake_up(&resync_wait); + return err; +} + + +/* + * This is a kernel thread which syncs a spare disk with the active array + * + * the amount of foolproofing might seem to be a tad excessive, but an + * early (not so error-safe) version of raid1syncd synced the first 0.5 gigs + * of my root partition with the first 0.5 gigs of my /home partition ... so + * i'm a bit nervous ;) + */ +void md_do_recovery (void *data) +{ + int err; + mddev_t *mddev; + mdp_super_t *sb; + mdp_disk_t *spare; + struct md_list_head *tmp; + + printk(KERN_INFO "md: recovery thread got woken up ...\n"); +restart: + ITERATE_MDDEV(mddev,tmp) { + sb = mddev->sb; + if (!sb) + continue; + if (mddev->recovery_running) + continue; + if (sb->active_disks == sb->raid_disks) + continue; + if (!sb->spare_disks) { + printk(KERN_ERR "md%d: no spare disk to reconstruct array! -- continuing in degraded mode\n", mdidx(mddev)); + continue; + } + /* + * now here we get the spare and resync it. + */ + if ((spare = get_spare(mddev)) == NULL) + continue; + printk(KERN_INFO "md%d: resyncing spare disk %s to replace failed disk\n", mdidx(mddev), partition_name(MKDEV(spare->major,spare->minor))); + if (!mddev->pers->diskop) + continue; + if (mddev->pers->diskop(mddev, &spare, DISKOP_SPARE_WRITE)) + continue; + down(&mddev->recovery_sem); + mddev->recovery_running = 1; + err = md_do_sync(mddev, spare); + if (err == -EIO) { + printk(KERN_INFO "md%d: spare disk %s failed, skipping to next spare.\n", mdidx(mddev), partition_name(MKDEV(spare->major,spare->minor))); + if (!disk_faulty(spare)) { + mddev->pers->diskop(mddev,&spare,DISKOP_SPARE_INACTIVE); + mark_disk_faulty(spare); + mark_disk_nonsync(spare); + mark_disk_inactive(spare); + sb->spare_disks--; + sb->working_disks--; + sb->failed_disks++; + } + } else + if (disk_faulty(spare)) + mddev->pers->diskop(mddev, &spare, + DISKOP_SPARE_INACTIVE); + if (err == -EINTR || err == -ENOMEM) { + /* + * Recovery got interrupted, or ran out of mem ... + * signal back that we have finished using the array. + */ + mddev->pers->diskop(mddev, &spare, + DISKOP_SPARE_INACTIVE); + up(&mddev->recovery_sem); + mddev->recovery_running = 0; + continue; + } else { + mddev->recovery_running = 0; + up(&mddev->recovery_sem); + } + if (!disk_faulty(spare)) { + /* + * the SPARE_ACTIVE diskop possibly changes the + * pointer too + */ + mddev->pers->diskop(mddev, &spare, DISKOP_SPARE_ACTIVE); + mark_disk_sync(spare); + mark_disk_active(spare); + sb->active_disks++; + sb->spare_disks--; + } + mddev->sb_dirty = 1; + md_update_sb(mddev); + goto restart; + } + printk(KERN_INFO "md: recovery thread finished ...\n"); + +} + +int md_notify_reboot(struct notifier_block *this, + unsigned long code, void *x) +{ + struct md_list_head *tmp; + mddev_t *mddev; + + if ((code == MD_SYS_DOWN) || (code == MD_SYS_HALT) + || (code == MD_SYS_POWER_OFF)) { + + printk(KERN_INFO "stopping all md devices.\n"); + + ITERATE_MDDEV(mddev,tmp) + do_md_stop (mddev, 1); + /* + * certain more exotic SCSI devices are known to be + * volatile wrt too early system reboots. While the + * right place to handle this issue is the given + * driver, we do want to have a safe RAID driver ... + */ + md_mdelay(1000*1); + } + return NOTIFY_DONE; +} + +struct notifier_block md_notifier = { + md_notify_reboot, + NULL, + 0 +}; +#ifndef MODULE +static int md__init raid_setup(char *str) +{ + int len, pos; + + len = strlen(str) + 1; + pos = 0; + + while (pos < len) { + char *comma = strchr(str+pos, ','); + int wlen; + if (comma) + wlen = (comma-str)-pos; + else wlen = (len-1)-pos; + + if (strncmp(str, "noautodetect", wlen) == 0) + raid_setup_args.noautodetect = 1; + pos += wlen+1; + } + raid_setup_args.set = 1; + return 1; +} +__setup("raid=", raid_setup); +#endif +static void md_geninit (void) +{ + int i; + + for(i = 0; i < MAX_MD_DEVS; i++) { + md_blocksizes[i] = 1024; + md_size[i] = 0; + md_hardsect_sizes[i] = 512; + md_maxreadahead[i] = MD_READAHEAD; + register_disk(&md_gendisk, MKDEV(MAJOR_NR,i), 1, &md_fops, 0); + } + blksize_size[MAJOR_NR] = md_blocksizes; + blk_size[MAJOR_NR] = md_size; + max_readahead[MAJOR_NR] = md_maxreadahead; + hardsect_size[MAJOR_NR] = md_hardsect_sizes; + + printk("md.c: sizeof(mdp_super_t) = %d\n", (int)sizeof(mdp_super_t)); + +#ifdef CONFIG_PROC_FS + create_proc_read_entry("mdstat", 0, NULL, md_status_read_proc, NULL); +#endif +} +void hsm_init (void); +void translucent_init (void); +void linear_init (void); +void raid0_init (void); +void raid1_init (void); +void raid5_init (void); + +int md__init md_init (void) +{ + static char * name = "mdrecoveryd"; + + printk (KERN_INFO "md driver %d.%d.%d MAX_MD_DEVS=%d, MAX_REAL=%d\n", + MD_MAJOR_VERSION, MD_MINOR_VERSION, + MD_PATCHLEVEL_VERSION, MAX_MD_DEVS, MAX_REAL); + + if (devfs_register_blkdev (MAJOR_NR, "md", &md_fops)) + { + printk (KERN_ALERT "Unable to get major %d for md\n", MAJOR_NR); + return (-1); + } + devfs_handle = devfs_mk_dir (NULL, "md", NULL); + devfs_register_series (devfs_handle, "%u",MAX_MD_DEVS,DEVFS_FL_DEFAULT, + MAJOR_NR, 0, S_IFBLK | S_IRUSR | S_IWUSR, + &md_fops, NULL); + + /* forward all md request to md_make_request */ + blk_queue_make_request(BLK_DEFAULT_QUEUE(MAJOR_NR), md_make_request); + + + read_ahead[MAJOR_NR] = INT_MAX; + md_gendisk.next = gendisk_head; + + gendisk_head = &md_gendisk; + + md_recovery_thread = md_register_thread(md_do_recovery, NULL, name); + if (!md_recovery_thread) + printk(KERN_ALERT "bug: couldn't allocate md_recovery_thread\n"); + + md_register_reboot_notifier(&md_notifier); + raid_table_header = register_sysctl_table(raid_root_table, 1); + +#ifdef CONFIG_MD_LINEAR + linear_init (); +#endif +#ifdef CONFIG_MD_RAID0 + raid0_init (); +#endif +#ifdef CONFIG_MD_RAID1 + raid1_init (); +#endif +#ifdef CONFIG_MD_RAID5 + raid5_init (); +#endif + md_geninit(); + return (0); +} + +#ifdef CONFIG_MD_BOOT +#define MAX_MD_BOOT_DEVS 8 +struct { + unsigned long set; + int pers[MAX_MD_BOOT_DEVS]; + int chunk[MAX_MD_BOOT_DEVS]; + kdev_t devices[MAX_MD_BOOT_DEVS][MAX_REAL]; +} md_setup_args md__initdata; + +/* + * Parse the command-line parameters given our kernel, but do not + * actually try to invoke the MD device now; that is handled by + * md_setup_drive after the low-level disk drivers have initialised. + * + * 27/11/1999: Fixed to work correctly with the 2.3 kernel (which + * assigns the task of parsing integer arguments to the + * invoked program now). Added ability to initialise all + * the MD devices (by specifying multiple "md=" lines) + * instead of just one. -- KTK + * 18May2000: Added support for persistant-superblock arrays: + * md=n,0,factor,fault,device-list uses RAID0 for device n + * md=n,-1,factor,fault,device-list uses LINEAR for device n + * md=n,device-list reads a RAID superblock from the devices + * elements in device-list are read by name_to_kdev_t so can be + * a hex number or something like /dev/hda1 /dev/sdb + */ +extern kdev_t name_to_kdev_t(char *line) md__init; +static int md__init md_setup(char *str) +{ + int minor, level, factor, fault, i=0; + kdev_t device; + char *devnames, *pername = ""; + + if(get_option(&str, &minor) != 2) { /* MD Number */ + printk("md: Too few arguments supplied to md=.\n"); + return 0; + } + if (minor >= MAX_MD_BOOT_DEVS) { + printk ("md: Minor device number too high.\n"); + return 0; + } else if (md_setup_args.set & (1 << minor)) { + printk ("md: Warning - md=%d,... has been specified twice;\n" + " will discard the first definition.\n", minor); + } + switch(get_option(&str, &level)) { /* RAID Personality */ + case 2: /* could be 0 or -1.. */ + if (level == 0 || level == -1) { + if (get_option(&str, &factor) != 2 || /* Chunk Size */ + get_option(&str, &fault) != 2) { + printk("md: Too few arguments supplied to md=.\n"); + return 0; + } + md_setup_args.pers[minor] = level; + md_setup_args.chunk[minor] = 1 << (factor+12); + switch(level) { + case -1: + level = LINEAR; + pername = "linear"; + break; + case 0: + level = RAID0; + pername = "raid0"; + break; + default: + printk ("md: The kernel has not been configured for raid%d" + " support!\n", level); + return 0; + } + md_setup_args.pers[minor] = level; + break; + } + /* FALL THROUGH */ + case 1: /* the first device is numeric */ + md_setup_args.devices[minor][i++] = level; + /* FALL THROUGH */ + case 0: + md_setup_args.pers[minor] = 0; + pername="super-block"; + } + devnames = str; + for (; isb->nr_disks++; + mddev->sb->raid_disks++; + mddev->sb->active_disks++; + mddev->sb->working_disks++; + err = add_new_disk (mddev, &dinfo); + } + } else { + /* persistent */ + for (i = 0; (dev = md_setup_args.devices[minor][i]); i++) { + dinfo.major = MAJOR(dev); + dinfo.minor = MINOR(dev); + add_new_disk (mddev, &dinfo); + } + } + if (!err) + err = do_md_run(mddev); + if (err) { + mddev->sb_dirty = 0; + do_md_stop(mddev, 0); + printk("md: starting md%d failed\n", minor); + } + } +} + +__setup("md=", md_setup); +#endif + +#ifdef MODULE +int init_module (void) +{ + return md_init(); +} + +static void free_device_names(void) +{ + while (device_names.next != &device_names) { + struct list_head *tmp = device_names.next; + list_del(tmp); + kfree(tmp); + } +} + + +void cleanup_module (void) +{ + struct gendisk **gendisk_ptr; + + md_unregister_thread(md_recovery_thread); + devfs_unregister(devfs_handle); + + devfs_unregister_blkdev(MAJOR_NR,"md"); + unregister_reboot_notifier(&md_notifier); + unregister_sysctl_table(raid_table_header); +#ifdef CONFIG_PROC_FS + remove_proc_entry("mdstat", NULL); +#endif + + gendisk_ptr = &gendisk_head; + while (*gendisk_ptr) { + if (*gendisk_ptr == &md_gendisk) { + *gendisk_ptr = md_gendisk.next; + break; + } + gendisk_ptr = & (*gendisk_ptr)->next; + } + blk_dev[MAJOR_NR].queue = NULL; + blksize_size[MAJOR_NR] = NULL; + blk_size[MAJOR_NR] = NULL; + max_readahead[MAJOR_NR] = NULL; + hardsect_size[MAJOR_NR] = NULL; + + free_device_names(); + +} +#endif + +__initcall(md_init); +#ifdef CONFIG_AUTODETECT_RAID +__initcall(md_run_setup); +#endif + +MD_EXPORT_SYMBOL(md_size); +MD_EXPORT_SYMBOL(register_md_personality); +MD_EXPORT_SYMBOL(unregister_md_personality); +MD_EXPORT_SYMBOL(partition_name); +MD_EXPORT_SYMBOL(md_error); +MD_EXPORT_SYMBOL(md_do_sync); +MD_EXPORT_SYMBOL(md_sync_acct); +MD_EXPORT_SYMBOL(md_done_sync); +MD_EXPORT_SYMBOL(md_recover_arrays); +MD_EXPORT_SYMBOL(md_register_thread); +MD_EXPORT_SYMBOL(md_unregister_thread); +MD_EXPORT_SYMBOL(md_update_sb); +MD_EXPORT_SYMBOL(md_wakeup_thread); +MD_EXPORT_SYMBOL(md_print_devices); +MD_EXPORT_SYMBOL(find_rdev_nr); +MD_EXPORT_SYMBOL(md_interrupt_thread); +MD_EXPORT_SYMBOL(mddev_map); +MD_EXPORT_SYMBOL(md_check_ordering); + diff -u --recursive --new-file v2.4.0-test8/linux/drivers/md/raid0.c linux/drivers/md/raid0.c --- v2.4.0-test8/linux/drivers/md/raid0.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/md/raid0.c Thu Aug 10 12:35:50 2000 @@ -0,0 +1,356 @@ +/* + raid0.c : Multiple Devices driver for Linux + Copyright (C) 1994-96 Marc ZYNGIER + or + + Copyright (C) 1999, 2000 Ingo Molnar, Red Hat + + + RAID-0 management functions. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + You should have received a copy of the GNU General Public License + (for example /usr/src/linux/COPYING); if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include + +#define MAJOR_NR MD_MAJOR +#define MD_DRIVER +#define MD_PERSONALITY + +static int create_strip_zones (mddev_t *mddev) +{ + int i, c, j, j1, j2; + unsigned long current_offset, curr_zone_offset; + raid0_conf_t *conf = mddev_to_conf(mddev); + mdk_rdev_t *smallest, *rdev1, *rdev2, *rdev; + + /* + * The number of 'same size groups' + */ + conf->nr_strip_zones = 0; + + ITERATE_RDEV_ORDERED(mddev,rdev1,j1) { + printk("raid0: looking at %s\n", partition_name(rdev1->dev)); + c = 0; + ITERATE_RDEV_ORDERED(mddev,rdev2,j2) { + printk("raid0: comparing %s(%ld) with %s(%ld)\n", partition_name(rdev1->dev), rdev1->size, partition_name(rdev2->dev), rdev2->size); + if (rdev2 == rdev1) { + printk("raid0: END\n"); + break; + } + if (rdev2->size == rdev1->size) + { + /* + * Not unique, dont count it as a new + * group + */ + printk("raid0: EQUAL\n"); + c = 1; + break; + } + printk("raid0: NOT EQUAL\n"); + } + if (!c) { + printk("raid0: ==> UNIQUE\n"); + conf->nr_strip_zones++; + printk("raid0: %d zones\n", conf->nr_strip_zones); + } + } + printk("raid0: FINAL %d zones\n", conf->nr_strip_zones); + + conf->strip_zone = vmalloc(sizeof(struct strip_zone)* + conf->nr_strip_zones); + if (!conf->strip_zone) + return 1; + + + conf->smallest = NULL; + current_offset = 0; + curr_zone_offset = 0; + + for (i = 0; i < conf->nr_strip_zones; i++) + { + struct strip_zone *zone = conf->strip_zone + i; + + printk("zone %d\n", i); + zone->dev_offset = current_offset; + smallest = NULL; + c = 0; + + ITERATE_RDEV_ORDERED(mddev,rdev,j) { + + printk(" checking %s ...", partition_name(rdev->dev)); + if (rdev->size > current_offset) + { + printk(" contained as device %d\n", c); + zone->dev[c] = rdev; + c++; + if (!smallest || (rdev->size size)) { + smallest = rdev; + printk(" (%ld) is smallest!.\n", rdev->size); + } + } else + printk(" nope.\n"); + } + + zone->nb_dev = c; + zone->size = (smallest->size - current_offset) * c; + printk(" zone->nb_dev: %d, size: %ld\n",zone->nb_dev,zone->size); + + if (!conf->smallest || (zone->size < conf->smallest->size)) + conf->smallest = zone; + + zone->zone_offset = curr_zone_offset; + curr_zone_offset += zone->size; + + current_offset = smallest->size; + printk("current zone offset: %ld\n", current_offset); + } + printk("done.\n"); + return 0; +} + +static int raid0_run (mddev_t *mddev) +{ + unsigned long cur=0, i=0, size, zone0_size, nb_zone; + raid0_conf_t *conf; + + MOD_INC_USE_COUNT; + + conf = vmalloc(sizeof (raid0_conf_t)); + if (!conf) + goto out; + mddev->private = (void *)conf; + + if (md_check_ordering(mddev)) { + printk("raid0: disks are not ordered, aborting!\n"); + goto out_free_conf; + } + + if (create_strip_zones (mddev)) + goto out_free_conf; + + printk("raid0 : md_size is %d blocks.\n", md_size[mdidx(mddev)]); + printk("raid0 : conf->smallest->size is %ld blocks.\n", conf->smallest->size); + nb_zone = md_size[mdidx(mddev)]/conf->smallest->size + + (md_size[mdidx(mddev)] % conf->smallest->size ? 1 : 0); + printk("raid0 : nb_zone is %ld.\n", nb_zone); + conf->nr_zones = nb_zone; + + printk("raid0 : Allocating %ld bytes for hash.\n", + nb_zone*sizeof(struct raid0_hash)); + + conf->hash_table = vmalloc (sizeof (struct raid0_hash)*nb_zone); + if (!conf->hash_table) + goto out_free_zone_conf; + size = conf->strip_zone[cur].size; + + i = 0; + while (cur < conf->nr_strip_zones) { + conf->hash_table[i].zone0 = conf->strip_zone + cur; + + /* + * If we completely fill the slot + */ + if (size >= conf->smallest->size) { + conf->hash_table[i++].zone1 = NULL; + size -= conf->smallest->size; + + if (!size) { + if (++cur == conf->nr_strip_zones) + continue; + size = conf->strip_zone[cur].size; + } + continue; + } + if (++cur == conf->nr_strip_zones) { + /* + * Last dev, set unit1 as NULL + */ + conf->hash_table[i].zone1=NULL; + continue; + } + + /* + * Here we use a 2nd dev to fill the slot + */ + zone0_size = size; + size = conf->strip_zone[cur].size; + conf->hash_table[i++].zone1 = conf->strip_zone + cur; + size -= (conf->smallest->size - zone0_size); + } + return 0; + +out_free_zone_conf: + vfree(conf->strip_zone); + conf->strip_zone = NULL; + +out_free_conf: + vfree(conf); + mddev->private = NULL; +out: + MOD_DEC_USE_COUNT; + return 1; +} + +static int raid0_stop (mddev_t *mddev) +{ + raid0_conf_t *conf = mddev_to_conf(mddev); + + vfree (conf->hash_table); + conf->hash_table = NULL; + vfree (conf->strip_zone); + conf->strip_zone = NULL; + vfree (conf); + mddev->private = NULL; + + MOD_DEC_USE_COUNT; + return 0; +} + +/* + * FIXME - We assume some things here : + * - requested buffers NEVER bigger than chunk size, + * - requested buffers NEVER cross stripes limits. + * Of course, those facts may not be valid anymore (and surely won't...) + * Hey guys, there's some work out there ;-) + */ +static int raid0_make_request (mddev_t *mddev, + int rw, struct buffer_head * bh) +{ + unsigned int sect_in_chunk, chunksize_bits, chunk_size; + raid0_conf_t *conf = mddev_to_conf(mddev); + struct raid0_hash *hash; + struct strip_zone *zone; + mdk_rdev_t *tmp_dev; + unsigned long chunk, block, rsect; + + chunk_size = mddev->param.chunk_size >> 10; + chunksize_bits = ffz(~chunk_size); + block = bh->b_rsector >> 1; + hash = conf->hash_table + block / conf->smallest->size; + + /* Sanity check */ + if (chunk_size < (block % chunk_size) + (bh->b_size >> 10)) + goto bad_map; + + if (!hash) + goto bad_hash; + + if (!hash->zone0) + goto bad_zone0; + + if (block >= (hash->zone0->size + hash->zone0->zone_offset)) { + if (!hash->zone1) + goto bad_zone1; + zone = hash->zone1; + } else + zone = hash->zone0; + + sect_in_chunk = bh->b_rsector & ((chunk_size<<1) -1); + chunk = (block - zone->zone_offset) / (zone->nb_dev << chunksize_bits); + tmp_dev = zone->dev[(block >> chunksize_bits) % zone->nb_dev]; + rsect = (((chunk << chunksize_bits) + zone->dev_offset)<<1) + + sect_in_chunk; + + /* + * The new BH_Lock semantics in ll_rw_blk.c guarantee that this + * is the only IO operation happening on this bh. + */ + bh->b_rdev = tmp_dev->dev; + bh->b_rsector = rsect; + + /* + * Let the main block layer submit the IO and resolve recursion: + */ + return 1; + +bad_map: + printk ("raid0_make_request bug: can't convert block across chunks or bigger than %dk %ld %d\n", chunk_size, bh->b_rsector, bh->b_size >> 10); + return -1; +bad_hash: + printk("raid0_make_request bug: hash==NULL for block %ld\n", block); + return -1; +bad_zone0: + printk ("raid0_make_request bug: hash->zone0==NULL for block %ld\n", block); + return -1; +bad_zone1: + printk ("raid0_make_request bug: hash->zone1==NULL for block %ld\n", block); + return -1; +} + +static int raid0_status (char *page, mddev_t *mddev) +{ + int sz = 0; +#undef MD_DEBUG +#ifdef MD_DEBUG + int j, k; + raid0_conf_t *conf = mddev_to_conf(mddev); + + sz += sprintf(page + sz, " "); + for (j = 0; j < conf->nr_zones; j++) { + sz += sprintf(page + sz, "[z%d", + conf->hash_table[j].zone0 - conf->strip_zone); + if (conf->hash_table[j].zone1) + sz += sprintf(page+sz, "/z%d] ", + conf->hash_table[j].zone1 - conf->strip_zone); + else + sz += sprintf(page+sz, "] "); + } + + sz += sprintf(page + sz, "\n"); + + for (j = 0; j < conf->nr_strip_zones; j++) { + sz += sprintf(page + sz, " z%d=[", j); + for (k = 0; k < conf->strip_zone[j].nb_dev; k++) + sz += sprintf (page+sz, "%s/", partition_name( + conf->strip_zone[j].dev[k]->dev)); + sz--; + sz += sprintf (page+sz, "] zo=%d do=%d s=%d\n", + conf->strip_zone[j].zone_offset, + conf->strip_zone[j].dev_offset, + conf->strip_zone[j].size); + } +#endif + sz += sprintf(page + sz, " %dk chunks", mddev->param.chunk_size/1024); + return sz; +} + +static mdk_personality_t raid0_personality= +{ + name: "raid0", + make_request: raid0_make_request, + run: raid0_run, + stop: raid0_stop, + status: raid0_status, +}; + +#ifndef MODULE + +void raid0_init (void) +{ + register_md_personality (RAID0, &raid0_personality); +} + +#else + +int init_module (void) +{ + return (register_md_personality (RAID0, &raid0_personality)); +} + +void cleanup_module (void) +{ + unregister_md_personality (RAID0); +} + +#endif + diff -u --recursive --new-file v2.4.0-test8/linux/drivers/md/raid1.c linux/drivers/md/raid1.c --- v2.4.0-test8/linux/drivers/md/raid1.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/md/raid1.c Mon Aug 14 08:26:34 2000 @@ -0,0 +1,1897 @@ +/* + * raid1.c : Multiple Devices driver for Linux + * + * Copyright (C) 1999, 2000 Ingo Molnar, Red Hat + * + * Copyright (C) 1996, 1997, 1998 Ingo Molnar, Miguel de Icaza, Gadi Oxman + * + * RAID-1 management functions. + * + * Better read-balancing code written by Mika Kuoppala , 2000 + * + * Fixes to reconstruction by Jakob Østergaard" + * Various fixes by Neil Brown + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * You should have received a copy of the GNU General Public License + * (for example /usr/src/linux/COPYING); if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include + +#define MAJOR_NR MD_MAJOR +#define MD_DRIVER +#define MD_PERSONALITY + +#define MAX_WORK_PER_DISK 128 + +/* + * The following can be used to debug the driver + */ +#define RAID1_DEBUG 0 + +#if RAID1_DEBUG +#define PRINTK(x...) printk(x) +#define inline +#define __inline__ +#else +#define PRINTK(x...) do { } while (0) +#endif + + +static mdk_personality_t raid1_personality; +static md_spinlock_t retry_list_lock = MD_SPIN_LOCK_UNLOCKED; +struct raid1_bh *raid1_retry_list = NULL, **raid1_retry_tail; + +static struct buffer_head *raid1_alloc_bh(raid1_conf_t *conf, int cnt) +{ + /* return a linked list of "cnt" struct buffer_heads. + * don't take any off the free list unless we know we can + * get all we need, otherwise we could deadlock + */ + struct buffer_head *bh=NULL; + + while(cnt) { + struct buffer_head *t; + md_spin_lock_irq(&conf->device_lock); + if (conf->freebh_cnt >= cnt) + while (cnt) { + t = conf->freebh; + conf->freebh = t->b_next; + t->b_next = bh; + bh = t; + t->b_state = 0; + conf->freebh_cnt--; + cnt--; + } + md_spin_unlock_irq(&conf->device_lock); + if (cnt == 0) + break; + t = (struct buffer_head *)kmalloc(sizeof(struct buffer_head), GFP_BUFFER); + if (t) { + memset(t, 0, sizeof(*t)); + t->b_next = bh; + bh = t; + cnt--; + } else { + PRINTK("waiting for %d bh\n", cnt); + wait_event(conf->wait_buffer, conf->freebh_cnt >= cnt); + } + } + return bh; +} + +static inline void raid1_free_bh(raid1_conf_t *conf, struct buffer_head *bh) +{ + md_spin_lock_irq(&conf->device_lock); + while (bh) { + struct buffer_head *t = bh; + bh=bh->b_next; + if (t->b_pprev == NULL) + kfree(t); + else { + t->b_next= conf->freebh; + conf->freebh = t; + conf->freebh_cnt++; + } + } + md_spin_unlock_irq(&conf->device_lock); + wake_up(&conf->wait_buffer); +} + +static int raid1_grow_bh(raid1_conf_t *conf, int cnt) +{ + /* allocate cnt buffer_heads, possibly less if kalloc fails */ + int i = 0; + + while (i < cnt) { + struct buffer_head *bh; + bh = kmalloc(sizeof(*bh), GFP_KERNEL); + if (!bh) break; + memset(bh, 0, sizeof(*bh)); + + md_spin_lock_irq(&conf->device_lock); + bh->b_pprev = &conf->freebh; + bh->b_next = conf->freebh; + conf->freebh = bh; + conf->freebh_cnt++; + md_spin_unlock_irq(&conf->device_lock); + + i++; + } + return i; +} + +static int raid1_shrink_bh(raid1_conf_t *conf, int cnt) +{ + /* discard cnt buffer_heads, if we can find them */ + int i = 0; + + md_spin_lock_irq(&conf->device_lock); + while ((i < cnt) && conf->freebh) { + struct buffer_head *bh = conf->freebh; + conf->freebh = bh->b_next; + kfree(bh); + i++; + conf->freebh_cnt--; + } + md_spin_unlock_irq(&conf->device_lock); + return i; +} + + +static struct raid1_bh *raid1_alloc_r1bh(raid1_conf_t *conf) +{ + struct raid1_bh *r1_bh = NULL; + + do { + md_spin_lock_irq(&conf->device_lock); + if (conf->freer1) { + r1_bh = conf->freer1; + conf->freer1 = r1_bh->next_r1; + r1_bh->next_r1 = NULL; + r1_bh->state = 0; + r1_bh->bh_req.b_state = 0; + } + md_spin_unlock_irq(&conf->device_lock); + if (r1_bh) + return r1_bh; + r1_bh = (struct raid1_bh *) kmalloc(sizeof(struct raid1_bh), + GFP_BUFFER); + if (r1_bh) { + memset(r1_bh, 0, sizeof(*r1_bh)); + return r1_bh; + } + wait_event(conf->wait_buffer, conf->freer1); + } while (1); +} + +static inline void raid1_free_r1bh(struct raid1_bh *r1_bh) +{ + struct buffer_head *bh = r1_bh->mirror_bh_list; + raid1_conf_t *conf = mddev_to_conf(r1_bh->mddev); + + r1_bh->mirror_bh_list = NULL; + + if (test_bit(R1BH_PreAlloc, &r1_bh->state)) { + md_spin_lock_irq(&conf->device_lock); + r1_bh->next_r1 = conf->freer1; + conf->freer1 = r1_bh; + md_spin_unlock_irq(&conf->device_lock); + } else { + kfree(r1_bh); + } + raid1_free_bh(conf, bh); +} + +static int raid1_grow_r1bh (raid1_conf_t *conf, int cnt) +{ + int i = 0; + + while (i < cnt) { + struct raid1_bh *r1_bh; + r1_bh = (struct raid1_bh*)kmalloc(sizeof(*r1_bh), GFP_KERNEL); + if (!r1_bh) + break; + memset(r1_bh, 0, sizeof(*r1_bh)); + + md_spin_lock_irq(&conf->device_lock); + set_bit(R1BH_PreAlloc, &r1_bh->state); + r1_bh->next_r1 = conf->freer1; + conf->freer1 = r1_bh; + md_spin_unlock_irq(&conf->device_lock); + + i++; + } + return i; +} + +static void raid1_shrink_r1bh(raid1_conf_t *conf) +{ + md_spin_lock_irq(&conf->device_lock); + while (conf->freer1) { + struct raid1_bh *r1_bh = conf->freer1; + conf->freer1 = r1_bh->next_r1; + kfree(r1_bh); + } + md_spin_unlock_irq(&conf->device_lock); +} + + + +static inline void raid1_free_buf(struct raid1_bh *r1_bh) +{ + struct buffer_head *bh = r1_bh->mirror_bh_list; + raid1_conf_t *conf = mddev_to_conf(r1_bh->mddev); + r1_bh->mirror_bh_list = NULL; + + md_spin_lock_irq(&conf->device_lock); + r1_bh->next_r1 = conf->freebuf; + conf->freebuf = r1_bh; + md_spin_unlock_irq(&conf->device_lock); + raid1_free_bh(conf, bh); +} + +static struct raid1_bh *raid1_alloc_buf(raid1_conf_t *conf) +{ + struct raid1_bh *r1_bh; + + md_spin_lock_irq(&conf->device_lock); + wait_event_lock_irq(conf->wait_buffer, conf->freebuf, conf->device_lock); + r1_bh = conf->freebuf; + conf->freebuf = r1_bh->next_r1; + r1_bh->next_r1= NULL; + md_spin_unlock_irq(&conf->device_lock); + + return r1_bh; +} + +static int raid1_grow_buffers (raid1_conf_t *conf, int cnt) +{ + int i = 0; + + md_spin_lock_irq(&conf->device_lock); + while (i < cnt) { + struct raid1_bh *r1_bh; + struct page *page; + + page = alloc_page(GFP_KERNEL); + if (!page) + break; + + r1_bh = (struct raid1_bh *) kmalloc(sizeof(*r1_bh), GFP_KERNEL); + if (!r1_bh) { + __free_page(page); + break; + } + memset(r1_bh, 0, sizeof(*r1_bh)); + r1_bh->bh_req.b_page = page; + r1_bh->bh_req.b_data = page_address(page); + r1_bh->next_r1 = conf->freebuf; + conf->freebuf = r1_bh; + i++; + } + md_spin_unlock_irq(&conf->device_lock); + return i; +} + +static void raid1_shrink_buffers (raid1_conf_t *conf) +{ + md_spin_lock_irq(&conf->device_lock); + while (conf->freebuf) { + struct raid1_bh *r1_bh = conf->freebuf; + conf->freebuf = r1_bh->next_r1; + __free_page(r1_bh->bh_req.b_page); + kfree(r1_bh); + } + md_spin_unlock_irq(&conf->device_lock); +} + +static int raid1_map (mddev_t *mddev, kdev_t *rdev, unsigned long size) +{ + raid1_conf_t *conf = mddev_to_conf(mddev); + int i, disks = MD_SB_DISKS; + + /* + * Later we do read balancing on the read side + * now we use the first available disk. + */ + + for (i = 0; i < disks; i++) { + if (conf->mirrors[i].operational) { + *rdev = conf->mirrors[i].dev; + return (0); + } + } + + printk (KERN_ERR "raid1_map(): huh, no more operational devices?\n"); + return (-1); +} + +static void raid1_reschedule_retry (struct raid1_bh *r1_bh) +{ + unsigned long flags; + mddev_t *mddev = r1_bh->mddev; + raid1_conf_t *conf = mddev_to_conf(mddev); + + md_spin_lock_irqsave(&retry_list_lock, flags); + if (raid1_retry_list == NULL) + raid1_retry_tail = &raid1_retry_list; + *raid1_retry_tail = r1_bh; + raid1_retry_tail = &r1_bh->next_r1; + r1_bh->next_r1 = NULL; + md_spin_unlock_irqrestore(&retry_list_lock, flags); + md_wakeup_thread(conf->thread); +} + + +static void inline io_request_done(unsigned long sector, raid1_conf_t *conf, int phase) +{ + unsigned long flags; + spin_lock_irqsave(&conf->segment_lock, flags); + if (sector < conf->start_active) + conf->cnt_done--; + else if (sector >= conf->start_future && conf->phase == phase) + conf->cnt_future--; + else if (!--conf->cnt_pending) + wake_up(&conf->wait_ready); + + spin_unlock_irqrestore(&conf->segment_lock, flags); +} + +static void inline sync_request_done (unsigned long sector, raid1_conf_t *conf) +{ + unsigned long flags; + spin_lock_irqsave(&conf->segment_lock, flags); + if (sector >= conf->start_ready) + --conf->cnt_ready; + else if (sector >= conf->start_active) { + if (!--conf->cnt_active) { + conf->start_active = conf->start_ready; + wake_up(&conf->wait_done); + } + } + spin_unlock_irqrestore(&conf->segment_lock, flags); +} + +/* + * raid1_end_bh_io() is called when we have finished servicing a mirrored + * operation and are ready to return a success/failure code to the buffer + * cache layer. + */ +static void raid1_end_bh_io (struct raid1_bh *r1_bh, int uptodate) +{ + struct buffer_head *bh = r1_bh->master_bh; + + io_request_done(bh->b_rsector, mddev_to_conf(r1_bh->mddev), + test_bit(R1BH_SyncPhase, &r1_bh->state)); + + bh->b_end_io(bh, uptodate); + raid1_free_r1bh(r1_bh); +} +void raid1_end_request (struct buffer_head *bh, int uptodate) +{ + struct raid1_bh * r1_bh = (struct raid1_bh *)(bh->b_private); + + /* + * this branch is our 'one mirror IO has finished' event handler: + */ + if (!uptodate) + md_error (mddev_to_kdev(r1_bh->mddev), bh->b_dev); + else + /* + * Set R1BH_Uptodate in our master buffer_head, so that + * we will return a good error code for to the higher + * levels even if IO on some other mirrored buffer fails. + * + * The 'master' represents the complex operation to + * user-side. So if something waits for IO, then it will + * wait for the 'master' buffer_head. + */ + set_bit (R1BH_Uptodate, &r1_bh->state); + + /* + * We split up the read and write side, imho they are + * conceptually different. + */ + + if ( (r1_bh->cmd == READ) || (r1_bh->cmd == READA) ) { + /* + * we have only one buffer_head on the read side + */ + + if (uptodate) { + raid1_end_bh_io(r1_bh, uptodate); + return; + } + /* + * oops, read error: + */ + printk(KERN_ERR "raid1: %s: rescheduling block %lu\n", + partition_name(bh->b_dev), bh->b_blocknr); + raid1_reschedule_retry(r1_bh); + return; + } + + /* + * WRITE: + * + * Let's see if all mirrored write operations have finished + * already. + */ + + if (atomic_dec_and_test(&r1_bh->remaining)) + raid1_end_bh_io(r1_bh, test_bit(R1BH_Uptodate, &r1_bh->state)); +} + +/* + * This routine returns the disk from which the requested read should + * be done. It bookkeeps the last read position for every disk + * in array and when new read requests come, the disk which last + * position is nearest to the request, is chosen. + * + * TODO: now if there are 2 mirrors in the same 2 devices, performance + * degrades dramatically because position is mirror, not device based. + * This should be changed to be device based. Also atomic sequential + * reads should be somehow balanced. + */ + +static int raid1_read_balance (raid1_conf_t *conf, struct buffer_head *bh) +{ + int new_disk = conf->last_used; + const int sectors = bh->b_size >> 9; + const unsigned long this_sector = bh->b_rsector; + int disk = new_disk; + unsigned long new_distance; + unsigned long current_distance; + + /* + * Check if it is sane at all to balance + */ + + if (conf->resync_mirrors) + goto rb_out; + + if (conf->working_disks < 2) { + int i = 0; + + while( !conf->mirrors[new_disk].operational && + (i < MD_SB_DISKS) ) { + new_disk = conf->mirrors[new_disk].next; + i++; + } + + if (i >= MD_SB_DISKS) { + /* + * This means no working disk was found + * Nothing much to do, lets not change anything + * and hope for the best... + */ + + new_disk = conf->last_used; + } + + goto rb_out; + } + + /* + * Don't touch anything for sequential reads. + */ + + if (this_sector == conf->mirrors[new_disk].head_position) + goto rb_out; + + /* + * If reads have been done only on a single disk + * for a time, lets give another disk a change. + * This is for kicking those idling disks so that + * they would find work near some hotspot. + */ + + if (conf->sect_count >= conf->mirrors[new_disk].sect_limit) { + conf->sect_count = 0; + + while( new_disk != conf->mirrors[new_disk].next ) { + if ((conf->mirrors[new_disk].write_only) || + (!conf->mirrors[new_disk].operational) ) + continue; + + new_disk = conf->mirrors[new_disk].next; + break; + } + + goto rb_out; + } + + current_distance = abs(this_sector - + conf->mirrors[disk].head_position); + + /* Find the disk which is closest */ + + while( conf->mirrors[disk].next != conf->last_used ) { + disk = conf->mirrors[disk].next; + + if ((conf->mirrors[disk].write_only) || + (!conf->mirrors[disk].operational)) + continue; + + new_distance = abs(this_sector - + conf->mirrors[disk].head_position); + + if (new_distance < current_distance) { + conf->sect_count = 0; + current_distance = new_distance; + new_disk = disk; + } + } + +rb_out: + conf->mirrors[new_disk].head_position = this_sector + sectors; + + conf->last_used = new_disk; + conf->sect_count += sectors; + + return new_disk; +} + +static int raid1_make_request (mddev_t *mddev, int rw, + struct buffer_head * bh) +{ + raid1_conf_t *conf = mddev_to_conf(mddev); + struct buffer_head *bh_req, *bhl; + struct raid1_bh * r1_bh; + int disks = MD_SB_DISKS; + int i, sum_bhs = 0, sectors; + struct mirror_info *mirror; + + if (!buffer_locked(bh)) + BUG(); + +/* + * make_request() can abort the operation when READA is being + * used and no empty request is available. + * + * Currently, just replace the command with READ/WRITE. + */ + if (rw == READA) + rw = READ; + + r1_bh = raid1_alloc_r1bh (conf); + + spin_lock_irq(&conf->segment_lock); + wait_event_lock_irq(conf->wait_done, + bh->b_rsector < conf->start_active || + bh->b_rsector >= conf->start_future, + conf->segment_lock); + if (bh->b_rsector < conf->start_active) + conf->cnt_done++; + else { + conf->cnt_future++; + if (conf->phase) + set_bit(R1BH_SyncPhase, &r1_bh->state); + } + spin_unlock_irq(&conf->segment_lock); + + /* + * i think the read and write branch should be separated completely, + * since we want to do read balancing on the read side for example. + * Alternative implementations? :) --mingo + */ + + r1_bh->master_bh = bh; + r1_bh->mddev = mddev; + r1_bh->cmd = rw; + + sectors = bh->b_size >> 9; + if (rw == READ) { + /* + * read balancing logic: + */ + mirror = conf->mirrors + raid1_read_balance(conf, bh); + + bh_req = &r1_bh->bh_req; + memcpy(bh_req, bh, sizeof(*bh)); + bh_req->b_blocknr = bh->b_rsector * sectors; + bh_req->b_dev = mirror->dev; + bh_req->b_rdev = mirror->dev; + /* bh_req->b_rsector = bh->n_rsector; */ + bh_req->b_end_io = raid1_end_request; + bh_req->b_private = r1_bh; + generic_make_request (rw, bh_req); + return 0; + } + + /* + * WRITE: + */ + + bhl = raid1_alloc_bh(conf, conf->raid_disks); + for (i = 0; i < disks; i++) { + struct buffer_head *mbh; + if (!conf->mirrors[i].operational) + continue; + + /* + * We should use a private pool (size depending on NR_REQUEST), + * to avoid writes filling up the memory with bhs + * + * Such pools are much faster than kmalloc anyways (so we waste + * almost nothing by not using the master bh when writing and + * win alot of cleanness) but for now we are cool enough. --mingo + * + * It's safe to sleep here, buffer heads cannot be used in a shared + * manner in the write branch. Look how we lock the buffer at the + * beginning of this function to grok the difference ;) + */ + mbh = bhl; + if (mbh == NULL) { + MD_BUG(); + break; + } + bhl = mbh->b_next; + mbh->b_next = NULL; + mbh->b_this_page = (struct buffer_head *)1; + + /* + * prepare mirrored mbh (fields ordered for max mem throughput): + */ + mbh->b_blocknr = bh->b_rsector * sectors; + mbh->b_dev = conf->mirrors[i].dev; + mbh->b_rdev = conf->mirrors[i].dev; + mbh->b_rsector = bh->b_rsector; + mbh->b_state = (1<b_count, 1); + mbh->b_size = bh->b_size; + mbh->b_page = bh->b_page; + mbh->b_data = bh->b_data; + mbh->b_list = BUF_LOCKED; + mbh->b_end_io = raid1_end_request; + mbh->b_private = r1_bh; + + mbh->b_next = r1_bh->mirror_bh_list; + r1_bh->mirror_bh_list = mbh; + sum_bhs++; + } + if (bhl) raid1_free_bh(conf,bhl); + md_atomic_set(&r1_bh->remaining, sum_bhs); + + /* + * We have to be a bit careful about the semaphore above, thats + * why we start the requests separately. Since kmalloc() could + * fail, sleep and make_request() can sleep too, this is the + * safer solution. Imagine, end_request decreasing the semaphore + * before we could have set it up ... We could play tricks with + * the semaphore (presetting it and correcting at the end if + * sum_bhs is not 'n' but we have to do end_request by hand if + * all requests finish until we had a chance to set up the + * semaphore correctly ... lots of races). + */ + bh = r1_bh->mirror_bh_list; + while(bh) { + struct buffer_head *bh2 = bh; + bh = bh->b_next; + generic_make_request(rw, bh2); + } + return (0); +} + +static int raid1_status (char *page, mddev_t *mddev) +{ + raid1_conf_t *conf = mddev_to_conf(mddev); + int sz = 0, i; + + sz += sprintf (page+sz, " [%d/%d] [", conf->raid_disks, + conf->working_disks); + for (i = 0; i < conf->raid_disks; i++) + sz += sprintf (page+sz, "%s", + conf->mirrors[i].operational ? "U" : "_"); + sz += sprintf (page+sz, "]"); + return sz; +} + +static void unlink_disk (raid1_conf_t *conf, int target) +{ + int disks = MD_SB_DISKS; + int i; + + for (i = 0; i < disks; i++) + if (conf->mirrors[i].next == target) + conf->mirrors[i].next = conf->mirrors[target].next; +} + +#define LAST_DISK KERN_ALERT \ +"raid1: only one disk left and IO error.\n" + +#define NO_SPARE_DISK KERN_ALERT \ +"raid1: no spare disk left, degrading mirror level by one.\n" + +#define DISK_FAILED KERN_ALERT \ +"raid1: Disk failure on %s, disabling device. \n" \ +" Operation continuing on %d devices\n" + +#define START_SYNCING KERN_ALERT \ +"raid1: start syncing spare disk.\n" + +#define ALREADY_SYNCING KERN_INFO \ +"raid1: syncing already in progress.\n" + +static void mark_disk_bad (mddev_t *mddev, int failed) +{ + raid1_conf_t *conf = mddev_to_conf(mddev); + struct mirror_info *mirror = conf->mirrors+failed; + mdp_super_t *sb = mddev->sb; + + mirror->operational = 0; + unlink_disk(conf, failed); + mark_disk_faulty(sb->disks+mirror->number); + mark_disk_nonsync(sb->disks+mirror->number); + mark_disk_inactive(sb->disks+mirror->number); + sb->active_disks--; + sb->working_disks--; + sb->failed_disks++; + mddev->sb_dirty = 1; + md_wakeup_thread(conf->thread); + conf->working_disks--; + printk (DISK_FAILED, partition_name (mirror->dev), + conf->working_disks); +} + +static int raid1_error (mddev_t *mddev, kdev_t dev) +{ + raid1_conf_t *conf = mddev_to_conf(mddev); + struct mirror_info * mirrors = conf->mirrors; + int disks = MD_SB_DISKS; + int i; + + if (conf->working_disks == 1) { + /* + * Uh oh, we can do nothing if this is our last disk, but + * first check if this is a queued request for a device + * which has just failed. + */ + for (i = 0; i < disks; i++) { + if (mirrors[i].dev==dev && !mirrors[i].operational) + return 0; + } + printk (LAST_DISK); + } else { + /* + * Mark disk as unusable + */ + for (i = 0; i < disks; i++) { + if (mirrors[i].dev==dev && mirrors[i].operational) { + mark_disk_bad(mddev, i); + break; + } + } + } + return 0; +} + +#undef LAST_DISK +#undef NO_SPARE_DISK +#undef DISK_FAILED +#undef START_SYNCING + +/* + * Insert the spare disk into the drive-ring + */ +static void link_disk(raid1_conf_t *conf, struct mirror_info *mirror) +{ + int j, next; + int disks = MD_SB_DISKS; + struct mirror_info *p = conf->mirrors; + + for (j = 0; j < disks; j++, p++) + if (p->operational && !p->write_only) { + next = p->next; + p->next = mirror->raid_disk; + mirror->next = next; + return; + } + + printk("raid1: bug: no read-operational devices\n"); +} + +static void print_raid1_conf (raid1_conf_t *conf) +{ + int i; + struct mirror_info *tmp; + + printk("RAID1 conf printout:\n"); + if (!conf) { + printk("(conf==NULL)\n"); + return; + } + printk(" --- wd:%d rd:%d nd:%d\n", conf->working_disks, + conf->raid_disks, conf->nr_disks); + + for (i = 0; i < MD_SB_DISKS; i++) { + tmp = conf->mirrors + i; + printk(" disk %d, s:%d, o:%d, n:%d rd:%d us:%d dev:%s\n", + i, tmp->spare,tmp->operational, + tmp->number,tmp->raid_disk,tmp->used_slot, + partition_name(tmp->dev)); + } +} + +static int raid1_diskop(mddev_t *mddev, mdp_disk_t **d, int state) +{ + int err = 0; + int i, failed_disk=-1, spare_disk=-1, removed_disk=-1, added_disk=-1; + raid1_conf_t *conf = mddev->private; + struct mirror_info *tmp, *sdisk, *fdisk, *rdisk, *adisk; + mdp_super_t *sb = mddev->sb; + mdp_disk_t *failed_desc, *spare_desc, *added_desc; + + print_raid1_conf(conf); + md_spin_lock_irq(&conf->device_lock); + /* + * find the disk ... + */ + switch (state) { + + case DISKOP_SPARE_ACTIVE: + + /* + * Find the failed disk within the RAID1 configuration ... + * (this can only be in the first conf->working_disks part) + */ + for (i = 0; i < conf->raid_disks; i++) { + tmp = conf->mirrors + i; + if ((!tmp->operational && !tmp->spare) || + !tmp->used_slot) { + failed_disk = i; + break; + } + } + /* + * When we activate a spare disk we _must_ have a disk in + * the lower (active) part of the array to replace. + */ + if ((failed_disk == -1) || (failed_disk >= conf->raid_disks)) { + MD_BUG(); + err = 1; + goto abort; + } + /* fall through */ + + case DISKOP_SPARE_WRITE: + case DISKOP_SPARE_INACTIVE: + + /* + * Find the spare disk ... (can only be in the 'high' + * area of the array) + */ + for (i = conf->raid_disks; i < MD_SB_DISKS; i++) { + tmp = conf->mirrors + i; + if (tmp->spare && tmp->number == (*d)->number) { + spare_disk = i; + break; + } + } + if (spare_disk == -1) { + MD_BUG(); + err = 1; + goto abort; + } + break; + + case DISKOP_HOT_REMOVE_DISK: + + for (i = 0; i < MD_SB_DISKS; i++) { + tmp = conf->mirrors + i; + if (tmp->used_slot && (tmp->number == (*d)->number)) { + if (tmp->operational) { + err = -EBUSY; + goto abort; + } + removed_disk = i; + break; + } + } + if (removed_disk == -1) { + MD_BUG(); + err = 1; + goto abort; + } + break; + + case DISKOP_HOT_ADD_DISK: + + for (i = conf->raid_disks; i < MD_SB_DISKS; i++) { + tmp = conf->mirrors + i; + if (!tmp->used_slot) { + added_disk = i; + break; + } + } + if (added_disk == -1) { + MD_BUG(); + err = 1; + goto abort; + } + break; + } + + switch (state) { + /* + * Switch the spare disk to write-only mode: + */ + case DISKOP_SPARE_WRITE: + sdisk = conf->mirrors + spare_disk; + sdisk->operational = 1; + sdisk->write_only = 1; + break; + /* + * Deactivate a spare disk: + */ + case DISKOP_SPARE_INACTIVE: + sdisk = conf->mirrors + spare_disk; + sdisk->operational = 0; + sdisk->write_only = 0; + break; + /* + * Activate (mark read-write) the (now sync) spare disk, + * which means we switch it's 'raid position' (->raid_disk) + * with the failed disk. (only the first 'conf->nr_disks' + * slots are used for 'real' disks and we must preserve this + * property) + */ + case DISKOP_SPARE_ACTIVE: + + sdisk = conf->mirrors + spare_disk; + fdisk = conf->mirrors + failed_disk; + + spare_desc = &sb->disks[sdisk->number]; + failed_desc = &sb->disks[fdisk->number]; + + if (spare_desc != *d) { + MD_BUG(); + err = 1; + goto abort; + } + + if (spare_desc->raid_disk != sdisk->raid_disk) { + MD_BUG(); + err = 1; + goto abort; + } + + if (sdisk->raid_disk != spare_disk) { + MD_BUG(); + err = 1; + goto abort; + } + + if (failed_desc->raid_disk != fdisk->raid_disk) { + MD_BUG(); + err = 1; + goto abort; + } + + if (fdisk->raid_disk != failed_disk) { + MD_BUG(); + err = 1; + goto abort; + } + + /* + * do the switch finally + */ + xchg_values(*spare_desc, *failed_desc); + xchg_values(*fdisk, *sdisk); + + /* + * (careful, 'failed' and 'spare' are switched from now on) + * + * we want to preserve linear numbering and we want to + * give the proper raid_disk number to the now activated + * disk. (this means we switch back these values) + */ + + xchg_values(spare_desc->raid_disk, failed_desc->raid_disk); + xchg_values(sdisk->raid_disk, fdisk->raid_disk); + xchg_values(spare_desc->number, failed_desc->number); + xchg_values(sdisk->number, fdisk->number); + + *d = failed_desc; + + if (sdisk->dev == MKDEV(0,0)) + sdisk->used_slot = 0; + /* + * this really activates the spare. + */ + fdisk->spare = 0; + fdisk->write_only = 0; + link_disk(conf, fdisk); + + /* + * if we activate a spare, we definitely replace a + * non-operational disk slot in the 'low' area of + * the disk array. + */ + + conf->working_disks++; + + break; + + case DISKOP_HOT_REMOVE_DISK: + rdisk = conf->mirrors + removed_disk; + + if (rdisk->spare && (removed_disk < conf->raid_disks)) { + MD_BUG(); + err = 1; + goto abort; + } + rdisk->dev = MKDEV(0,0); + rdisk->used_slot = 0; + conf->nr_disks--; + break; + + case DISKOP_HOT_ADD_DISK: + adisk = conf->mirrors + added_disk; + added_desc = *d; + + if (added_disk != added_desc->number) { + MD_BUG(); + err = 1; + goto abort; + } + + adisk->number = added_desc->number; + adisk->raid_disk = added_desc->raid_disk; + adisk->dev = MKDEV(added_desc->major,added_desc->minor); + + adisk->operational = 0; + adisk->write_only = 0; + adisk->spare = 1; + adisk->used_slot = 1; + adisk->head_position = 0; + conf->nr_disks++; + + break; + + default: + MD_BUG(); + err = 1; + goto abort; + } +abort: + md_spin_unlock_irq(&conf->device_lock); + if (state == DISKOP_SPARE_ACTIVE || state == DISKOP_SPARE_INACTIVE) + /* should move to "END_REBUILD" when such exists */ + raid1_shrink_buffers(conf); + + print_raid1_conf(conf); + return err; +} + + +#define IO_ERROR KERN_ALERT \ +"raid1: %s: unrecoverable I/O read error for block %lu\n" + +#define REDIRECT_SECTOR KERN_ERR \ +"raid1: %s: redirecting sector %lu to another mirror\n" + +/* + * This is a kernel thread which: + * + * 1. Retries failed read operations on working mirrors. + * 2. Updates the raid superblock when problems encounter. + * 3. Performs writes following reads for array syncronising. + */ +static void end_sync_write(struct buffer_head *bh, int uptodate); +static void end_sync_read(struct buffer_head *bh, int uptodate); + +static void raid1d (void *data) +{ + struct raid1_bh *r1_bh; + struct buffer_head *bh; + unsigned long flags; + mddev_t *mddev; + kdev_t dev; + + + for (;;) { + md_spin_lock_irqsave(&retry_list_lock, flags); + r1_bh = raid1_retry_list; + if (!r1_bh) + break; + raid1_retry_list = r1_bh->next_r1; + md_spin_unlock_irqrestore(&retry_list_lock, flags); + + mddev = r1_bh->mddev; + if (mddev->sb_dirty) { + printk(KERN_INFO "dirty sb detected, updating.\n"); + mddev->sb_dirty = 0; + md_update_sb(mddev); + } + bh = &r1_bh->bh_req; + switch(r1_bh->cmd) { + case SPECIAL: + /* have to allocate lots of bh structures and + * schedule writes + */ + if (test_bit(R1BH_Uptodate, &r1_bh->state)) { + int i, sum_bhs = 0; + int disks = MD_SB_DISKS; + struct buffer_head *bhl, *mbh; + raid1_conf_t *conf; + int sectors = bh->b_size >> 9; + + conf = mddev_to_conf(mddev); + bhl = raid1_alloc_bh(conf, conf->raid_disks); /* don't really need this many */ + for (i = 0; i < disks ; i++) { + if (!conf->mirrors[i].operational) + continue; + if (i==conf->last_used) + /* we read from here, no need to write */ + continue; + if (i < conf->raid_disks + && !conf->resync_mirrors) + /* don't need to write this, + * we are just rebuilding */ + continue; + mbh = bhl; + if (!mbh) { + MD_BUG(); + break; + } + bhl = mbh->b_next; + mbh->b_this_page = (struct buffer_head *)1; + + + /* + * prepare mirrored bh (fields ordered for max mem throughput): + */ + mbh->b_blocknr = bh->b_blocknr; + mbh->b_dev = conf->mirrors[i].dev; + mbh->b_rdev = conf->mirrors[i].dev; + mbh->b_rsector = bh->b_blocknr * sectors; + mbh->b_state = (1<b_count, 1); + mbh->b_size = bh->b_size; + mbh->b_page = bh->b_page; + mbh->b_data = bh->b_data; + mbh->b_list = BUF_LOCKED; + mbh->b_end_io = end_sync_write; + mbh->b_private = r1_bh; + + mbh->b_next = r1_bh->mirror_bh_list; + r1_bh->mirror_bh_list = mbh; + + sum_bhs++; + } + md_atomic_set(&r1_bh->remaining, sum_bhs); + if (bhl) raid1_free_bh(conf, bhl); + mbh = r1_bh->mirror_bh_list; + while (mbh) { + struct buffer_head *bh1 = mbh; + mbh = mbh->b_next; + generic_make_request(WRITE, bh1); + md_sync_acct(bh1->b_rdev, bh1->b_size/512); + } + } else { + dev = bh->b_dev; + raid1_map (mddev, &bh->b_dev, bh->b_size >> 9); + if (bh->b_dev == dev) { + printk (IO_ERROR, partition_name(bh->b_dev), bh->b_blocknr); + md_done_sync(mddev, bh->b_size>>10, 0); + } else { + printk (REDIRECT_SECTOR, + partition_name(bh->b_dev), bh->b_blocknr); + bh->b_rdev = bh->b_dev; + generic_make_request(READ, bh); + } + } + + break; + case READ: + case READA: + dev = bh->b_dev; + + raid1_map (mddev, &bh->b_dev, bh->b_size >> 9); + if (bh->b_dev == dev) { + printk (IO_ERROR, partition_name(bh->b_dev), bh->b_blocknr); + raid1_end_bh_io(r1_bh, 0); + } else { + printk (REDIRECT_SECTOR, + partition_name(bh->b_dev), bh->b_blocknr); + bh->b_rdev = bh->b_dev; + generic_make_request (r1_bh->cmd, bh); + } + break; + } + } + md_spin_unlock_irqrestore(&retry_list_lock, flags); +} +#undef IO_ERROR +#undef REDIRECT_SECTOR + +/* + * Private kernel thread to reconstruct mirrors after an unclean + * shutdown. + */ +static void raid1syncd (void *data) +{ + raid1_conf_t *conf = data; + mddev_t *mddev = conf->mddev; + + if (!conf->resync_mirrors) + return; + if (conf->resync_mirrors == 2) + return; + down(&mddev->recovery_sem); + if (!md_do_sync(mddev, NULL)) { + /* + * Only if everything went Ok. + */ + conf->resync_mirrors = 0; + } + + /* If reconstruction was interrupted, we need to close the "active" and "pending" + * holes. + * we know that there are no active rebuild requests, os cnt_active == cnt_ready ==0 + */ + /* this is really needed when recovery stops too... */ + spin_lock_irq(&conf->segment_lock); + conf->start_active = conf->start_pending; + conf->start_ready = conf->start_pending; + wait_event_lock_irq(conf->wait_ready, !conf->cnt_pending, conf->segment_lock); + conf->start_active =conf->start_ready = conf->start_pending = conf->start_future; + conf->start_future = mddev->sb->size+1; + conf->cnt_pending = conf->cnt_future; + conf->cnt_future = 0; + conf->phase = conf->phase ^1; + wait_event_lock_irq(conf->wait_ready, !conf->cnt_pending, conf->segment_lock); + conf->start_active = conf->start_ready = conf->start_pending = conf->start_future = 0; + conf->phase = 0; + conf->cnt_future = conf->cnt_done;; + conf->cnt_done = 0; + spin_unlock_irq(&conf->segment_lock); + wake_up(&conf->wait_done); + + up(&mddev->recovery_sem); + raid1_shrink_buffers(conf); +} + +/* + * perform a "sync" on one "block" + * + * We need to make sure that no normal I/O request - particularly write + * requests - conflict with active sync requests. + * This is achieved by conceptually dividing the device space into a + * number of sections: + * DONE: 0 .. a-1 These blocks are in-sync + * ACTIVE: a.. b-1 These blocks may have active sync requests, but + * no normal IO requests + * READY: b .. c-1 These blocks have no normal IO requests - sync + * request may be happening + * PENDING: c .. d-1 These blocks may have IO requests, but no new + * ones will be added + * FUTURE: d .. end These blocks are not to be considered yet. IO may + * be happening, but not sync + * + * We keep a + * phase which flips (0 or 1) each time d moves and + * a count of: + * z = active io requests in FUTURE since d moved - marked with + * current phase + * y = active io requests in FUTURE before d moved, or PENDING - + * marked with previous phase + * x = active sync requests in READY + * w = active sync requests in ACTIVE + * v = active io requests in DONE + * + * Normally, a=b=c=d=0 and z= active io requests + * or a=b=c=d=END and v= active io requests + * Allowed changes to a,b,c,d: + * A: c==d && y==0 -> d+=window, y=z, z=0, phase=!phase + * B: y==0 -> c=d + * C: b=c, w+=x, x=0 + * D: w==0 -> a=b + * E: a==b==c==d==end -> a=b=c=d=0, z=v, v=0 + * + * At start of sync we apply A. + * When y reaches 0, we apply B then A then being sync requests + * When sync point reaches c-1, we wait for y==0, and W==0, and + * then apply apply B then A then D then C. + * Finally, we apply E + * + * The sync request simply issues a "read" against a working drive + * This is marked so that on completion the raid1d thread is woken to + * issue suitable write requests + */ + +static int raid1_sync_request (mddev_t *mddev, unsigned long block_nr) +{ + raid1_conf_t *conf = mddev_to_conf(mddev); + struct mirror_info *mirror; + struct raid1_bh *r1_bh; + struct buffer_head *bh; + int bsize; + + spin_lock_irq(&conf->segment_lock); + if (!block_nr) { + /* initialize ...*/ + int buffs; + conf->start_active = 0; + conf->start_ready = 0; + conf->start_pending = 0; + conf->start_future = 0; + conf->phase = 0; + /* we want enough buffers to hold twice the window of 128*/ + buffs = 128 *2 / (PAGE_SIZE>>9); + buffs = raid1_grow_buffers(conf, buffs); + if (buffs < 2) + goto nomem; + + conf->window = buffs*(PAGE_SIZE>>9)/2; + conf->cnt_future += conf->cnt_done+conf->cnt_pending; + conf->cnt_done = conf->cnt_pending = 0; + if (conf->cnt_ready || conf->cnt_active) + MD_BUG(); + } + while ((block_nr<<1) >= conf->start_pending) { + PRINTK("wait .. sect=%lu start_active=%d ready=%d pending=%d future=%d, cnt_done=%d active=%d ready=%d pending=%d future=%d\n", + block_nr<<1, conf->start_active, conf->start_ready, conf->start_pending, conf->start_future, + conf->cnt_done, conf->cnt_active, conf->cnt_ready, conf->cnt_pending, conf->cnt_future); + wait_event_lock_irq(conf->wait_done, + !conf->cnt_active, + conf->segment_lock); + wait_event_lock_irq(conf->wait_ready, + !conf->cnt_pending, + conf->segment_lock); + conf->start_active = conf->start_ready; + conf->start_ready = conf->start_pending; + conf->start_pending = conf->start_future; + conf->start_future = conf->start_future+conf->window; + // Note: falling off the end is not a problem + conf->phase = conf->phase ^1; + conf->cnt_active = conf->cnt_ready; + conf->cnt_ready = 0; + conf->cnt_pending = conf->cnt_future; + conf->cnt_future = 0; + wake_up(&conf->wait_done); + } + conf->cnt_ready++; + spin_unlock_irq(&conf->segment_lock); + + + /* If reconstructing, and >1 working disc, + * could dedicate one to rebuild and others to + * service read requests .. + */ + mirror = conf->mirrors+conf->last_used; + + r1_bh = raid1_alloc_buf (conf); + r1_bh->master_bh = NULL; + r1_bh->mddev = mddev; + r1_bh->cmd = SPECIAL; + bh = &r1_bh->bh_req; + + bh->b_blocknr = block_nr; + bsize = 1024; + while (!(bh->b_blocknr & 1) && bsize < PAGE_SIZE + && (bh->b_blocknr+2)*(bsize>>10) < mddev->sb->size) { + bh->b_blocknr >>= 1; + bsize <<= 1; + } + bh->b_size = bsize; + bh->b_list = BUF_LOCKED; + bh->b_dev = mirror->dev; + bh->b_rdev = mirror->dev; + bh->b_state = (1<b_page) + BUG(); + if (!bh->b_data) + BUG(); + if (bh->b_data != page_address(bh->b_page)) + BUG(); + bh->b_end_io = end_sync_read; + bh->b_private = r1_bh; + bh->b_rsector = block_nr<<1; + init_waitqueue_head(&bh->b_wait); + + generic_make_request(READ, bh); + md_sync_acct(bh->b_rdev, bh->b_size/512); + + return (bsize >> 10); + +nomem: + raid1_shrink_buffers(conf); + spin_unlock_irq(&conf->segment_lock); + return -ENOMEM; +} + +static void end_sync_read(struct buffer_head *bh, int uptodate) +{ + struct raid1_bh * r1_bh = (struct raid1_bh *)(bh->b_private); + + /* we have read a block, now it needs to be re-written, + * or re-read if the read failed. + * We don't do much here, just schedule handling by raid1d + */ + if (!uptodate) + md_error (mddev_to_kdev(r1_bh->mddev), bh->b_dev); + else + set_bit(R1BH_Uptodate, &r1_bh->state); + raid1_reschedule_retry(r1_bh); +} + +static void end_sync_write(struct buffer_head *bh, int uptodate) +{ + struct raid1_bh * r1_bh = (struct raid1_bh *)(bh->b_private); + + if (!uptodate) + md_error (mddev_to_kdev(r1_bh->mddev), bh->b_dev); + if (atomic_dec_and_test(&r1_bh->remaining)) { + mddev_t *mddev = r1_bh->mddev; + unsigned long sect = bh->b_blocknr * (bh->b_size>>9); + int size = bh->b_size; + raid1_free_buf(r1_bh); + sync_request_done(sect, mddev_to_conf(mddev)); + md_done_sync(mddev,size>>10, uptodate); + } +} + +/* + * This will catch the scenario in which one of the mirrors was + * mounted as a normal device rather than as a part of a raid set. + * + * check_consistency is very personality-dependent, eg. RAID5 cannot + * do this check, it uses another method. + */ +static int __check_consistency (mddev_t *mddev, int row) +{ + raid1_conf_t *conf = mddev_to_conf(mddev); + int disks = MD_SB_DISKS; + kdev_t dev; + struct buffer_head *bh = NULL; + int i, rc = 0; + char *buffer = NULL; + + for (i = 0; i < disks; i++) { + printk("(checking disk %d)\n",i); + if (!conf->mirrors[i].operational) + continue; + printk("(really checking disk %d)\n",i); + dev = conf->mirrors[i].dev; + set_blocksize(dev, 4096); + if ((bh = bread(dev, row / 4, 4096)) == NULL) + break; + if (!buffer) { + buffer = (char *) __get_free_page(GFP_KERNEL); + if (!buffer) + break; + memcpy(buffer, bh->b_data, 4096); + } else if (memcmp(buffer, bh->b_data, 4096)) { + rc = 1; + break; + } + bforget(bh); + fsync_dev(dev); + invalidate_buffers(dev); + bh = NULL; + } + if (buffer) + free_page((unsigned long) buffer); + if (bh) { + dev = bh->b_dev; + bforget(bh); + fsync_dev(dev); + invalidate_buffers(dev); + } + return rc; +} + +static int check_consistency (mddev_t *mddev) +{ + if (__check_consistency(mddev, 0)) +/* + * we do not do this currently, as it's perfectly possible to + * have an inconsistent array when it's freshly created. Only + * newly written data has to be consistent. + */ + return 0; + + return 0; +} + +#define INVALID_LEVEL KERN_WARNING \ +"raid1: md%d: raid level not set to mirroring (%d)\n" + +#define NO_SB KERN_ERR \ +"raid1: disabled mirror %s (couldn't access raid superblock)\n" + +#define ERRORS KERN_ERR \ +"raid1: disabled mirror %s (errors detected)\n" + +#define NOT_IN_SYNC KERN_ERR \ +"raid1: disabled mirror %s (not in sync)\n" + +#define INCONSISTENT KERN_ERR \ +"raid1: disabled mirror %s (inconsistent descriptor)\n" + +#define ALREADY_RUNNING KERN_ERR \ +"raid1: disabled mirror %s (mirror %d already operational)\n" + +#define OPERATIONAL KERN_INFO \ +"raid1: device %s operational as mirror %d\n" + +#define MEM_ERROR KERN_ERR \ +"raid1: couldn't allocate memory for md%d\n" + +#define SPARE KERN_INFO \ +"raid1: spare disk %s\n" + +#define NONE_OPERATIONAL KERN_ERR \ +"raid1: no operational mirrors for md%d\n" + +#define RUNNING_CKRAID KERN_ERR \ +"raid1: detected mirror differences -- running resync\n" + +#define ARRAY_IS_ACTIVE KERN_INFO \ +"raid1: raid set md%d active with %d out of %d mirrors\n" + +#define THREAD_ERROR KERN_ERR \ +"raid1: couldn't allocate thread for md%d\n" + +#define START_RESYNC KERN_WARNING \ +"raid1: raid set md%d not clean; reconstructing mirrors\n" + +static int raid1_run (mddev_t *mddev) +{ + raid1_conf_t *conf; + int i, j, disk_idx; + struct mirror_info *disk; + mdp_super_t *sb = mddev->sb; + mdp_disk_t *descriptor; + mdk_rdev_t *rdev; + struct md_list_head *tmp; + int start_recovery = 0; + + MOD_INC_USE_COUNT; + + if (sb->level != 1) { + printk(INVALID_LEVEL, mdidx(mddev), sb->level); + goto out; + } + /* + * copy the already verified devices into our private RAID1 + * bookkeeping area. [whatever we allocate in raid1_run(), + * should be freed in raid1_stop()] + */ + + conf = kmalloc(sizeof(raid1_conf_t), GFP_KERNEL); + mddev->private = conf; + if (!conf) { + printk(MEM_ERROR, mdidx(mddev)); + goto out; + } + memset(conf, 0, sizeof(*conf)); + + ITERATE_RDEV(mddev,rdev,tmp) { + if (rdev->faulty) { + printk(ERRORS, partition_name(rdev->dev)); + } else { + if (!rdev->sb) { + MD_BUG(); + continue; + } + } + if (rdev->desc_nr == -1) { + MD_BUG(); + continue; + } + descriptor = &sb->disks[rdev->desc_nr]; + disk_idx = descriptor->raid_disk; + disk = conf->mirrors + disk_idx; + + if (disk_faulty(descriptor)) { + disk->number = descriptor->number; + disk->raid_disk = disk_idx; + disk->dev = rdev->dev; + disk->sect_limit = MAX_WORK_PER_DISK; + disk->operational = 0; + disk->write_only = 0; + disk->spare = 0; + disk->used_slot = 1; + disk->head_position = 0; + continue; + } + if (disk_active(descriptor)) { + if (!disk_sync(descriptor)) { + printk(NOT_IN_SYNC, + partition_name(rdev->dev)); + continue; + } + if ((descriptor->number > MD_SB_DISKS) || + (disk_idx > sb->raid_disks)) { + + printk(INCONSISTENT, + partition_name(rdev->dev)); + continue; + } + if (disk->operational) { + printk(ALREADY_RUNNING, + partition_name(rdev->dev), + disk_idx); + continue; + } + printk(OPERATIONAL, partition_name(rdev->dev), + disk_idx); + disk->number = descriptor->number; + disk->raid_disk = disk_idx; + disk->dev = rdev->dev; + disk->sect_limit = MAX_WORK_PER_DISK; + disk->operational = 1; + disk->write_only = 0; + disk->spare = 0; + disk->used_slot = 1; + disk->head_position = 0; + conf->working_disks++; + } else { + /* + * Must be a spare disk .. + */ + printk(SPARE, partition_name(rdev->dev)); + disk->number = descriptor->number; + disk->raid_disk = disk_idx; + disk->dev = rdev->dev; + disk->sect_limit = MAX_WORK_PER_DISK; + disk->operational = 0; + disk->write_only = 0; + disk->spare = 1; + disk->used_slot = 1; + disk->head_position = 0; + } + } + conf->raid_disks = sb->raid_disks; + conf->nr_disks = sb->nr_disks; + conf->mddev = mddev; + conf->device_lock = MD_SPIN_LOCK_UNLOCKED; + + conf->segment_lock = MD_SPIN_LOCK_UNLOCKED; + init_waitqueue_head(&conf->wait_buffer); + init_waitqueue_head(&conf->wait_done); + init_waitqueue_head(&conf->wait_ready); + + if (!conf->working_disks) { + printk(NONE_OPERATIONAL, mdidx(mddev)); + goto out_free_conf; + } + + + /* pre-allocate some buffer_head structures. + * As a minimum, 1 r1bh and raid_disks buffer_heads + * would probably get us by in tight memory situations, + * but a few more is probably a good idea. + * For now, try 16 r1bh and 16*raid_disks bufferheads + * This will allow at least 16 concurrent reads or writes + * even if kmalloc starts failing + */ + if (raid1_grow_r1bh(conf, 16) < 16 || + raid1_grow_bh(conf, 16*conf->raid_disks)< 16*conf->raid_disks) { + printk(MEM_ERROR, mdidx(mddev)); + goto out_free_conf; + } + + for (i = 0; i < MD_SB_DISKS; i++) { + + descriptor = sb->disks+i; + disk_idx = descriptor->raid_disk; + disk = conf->mirrors + disk_idx; + + if (disk_faulty(descriptor) && (disk_idx < conf->raid_disks) && + !disk->used_slot) { + + disk->number = descriptor->number; + disk->raid_disk = disk_idx; + disk->dev = MKDEV(0,0); + + disk->operational = 0; + disk->write_only = 0; + disk->spare = 0; + disk->used_slot = 1; + disk->head_position = 0; + } + } + + /* + * find the first working one and use it as a starting point + * to read balancing. + */ + for (j = 0; !conf->mirrors[j].operational; j++) + /* nothing */; + conf->last_used = j; + + /* + * initialize the 'working disks' list. + */ + for (i = conf->raid_disks - 1; i >= 0; i--) { + if (conf->mirrors[i].operational) { + conf->mirrors[i].next = j; + j = i; + } + } + + if (conf->working_disks != sb->raid_disks) { + printk(KERN_ALERT "raid1: md%d, not all disks are operational -- trying to recover array\n", mdidx(mddev)); + start_recovery = 1; + } + + if (!start_recovery && (sb->state & (1 << MD_SB_CLEAN))) { + /* + * we do sanity checks even if the device says + * it's clean ... + */ + if (check_consistency(mddev)) { + printk(RUNNING_CKRAID); + sb->state &= ~(1 << MD_SB_CLEAN); + } + } + + { + const char * name = "raid1d"; + + conf->thread = md_register_thread(raid1d, conf, name); + if (!conf->thread) { + printk(THREAD_ERROR, mdidx(mddev)); + goto out_free_conf; + } + } + + if (!start_recovery && !(sb->state & (1 << MD_SB_CLEAN))) { + const char * name = "raid1syncd"; + + conf->resync_thread = md_register_thread(raid1syncd, conf,name); + if (!conf->resync_thread) { + printk(THREAD_ERROR, mdidx(mddev)); + goto out_free_conf; + } + + printk(START_RESYNC, mdidx(mddev)); + conf->resync_mirrors = 1; + md_wakeup_thread(conf->resync_thread); + } + + /* + * Regenerate the "device is in sync with the raid set" bit for + * each device. + */ + for (i = 0; i < MD_SB_DISKS; i++) { + mark_disk_nonsync(sb->disks+i); + for (j = 0; j < sb->raid_disks; j++) { + if (!conf->mirrors[j].operational) + continue; + if (sb->disks[i].number == conf->mirrors[j].number) + mark_disk_sync(sb->disks+i); + } + } + sb->active_disks = conf->working_disks; + + if (start_recovery) + md_recover_arrays(); + + + printk(ARRAY_IS_ACTIVE, mdidx(mddev), sb->active_disks, sb->raid_disks); + /* + * Ok, everything is just fine now + */ + return 0; + +out_free_conf: + raid1_shrink_r1bh(conf); + raid1_shrink_bh(conf, conf->freebh_cnt); + raid1_shrink_buffers(conf); + kfree(conf); + mddev->private = NULL; +out: + MOD_DEC_USE_COUNT; + return -EIO; +} + +#undef INVALID_LEVEL +#undef NO_SB +#undef ERRORS +#undef NOT_IN_SYNC +#undef INCONSISTENT +#undef ALREADY_RUNNING +#undef OPERATIONAL +#undef SPARE +#undef NONE_OPERATIONAL +#undef RUNNING_CKRAID +#undef ARRAY_IS_ACTIVE + +static int raid1_stop_resync (mddev_t *mddev) +{ + raid1_conf_t *conf = mddev_to_conf(mddev); + + if (conf->resync_thread) { + if (conf->resync_mirrors) { + conf->resync_mirrors = 2; + md_interrupt_thread(conf->resync_thread); + + printk(KERN_INFO "raid1: mirror resync was not fully finished, restarting next time.\n"); + return 1; + } + return 0; + } + return 0; +} + +static int raid1_restart_resync (mddev_t *mddev) +{ + raid1_conf_t *conf = mddev_to_conf(mddev); + + if (conf->resync_mirrors) { + if (!conf->resync_thread) { + MD_BUG(); + return 0; + } + conf->resync_mirrors = 1; + md_wakeup_thread(conf->resync_thread); + return 1; + } + return 0; +} + +static int raid1_stop (mddev_t *mddev) +{ + raid1_conf_t *conf = mddev_to_conf(mddev); + + md_unregister_thread(conf->thread); + if (conf->resync_thread) + md_unregister_thread(conf->resync_thread); + raid1_shrink_r1bh(conf); + raid1_shrink_bh(conf, conf->freebh_cnt); + raid1_shrink_buffers(conf); + kfree(conf); + mddev->private = NULL; + MOD_DEC_USE_COUNT; + return 0; +} + +static mdk_personality_t raid1_personality= +{ + name: "raid1", + make_request: raid1_make_request, + run: raid1_run, + stop: raid1_stop, + status: raid1_status, + error_handler: raid1_error, + diskop: raid1_diskop, + stop_resync: raid1_stop_resync, + restart_resync: raid1_restart_resync, + sync_request: raid1_sync_request +}; + +int raid1_init (void) +{ + return register_md_personality (RAID1, &raid1_personality); +} + +#ifdef MODULE +int init_module (void) +{ + return raid1_init(); +} + +void cleanup_module (void) +{ + unregister_md_personality (RAID1); +} +#endif diff -u --recursive --new-file v2.4.0-test8/linux/drivers/md/raid5.c linux/drivers/md/raid5.c --- v2.4.0-test8/linux/drivers/md/raid5.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/md/raid5.c Mon Aug 14 08:26:34 2000 @@ -0,0 +1,2371 @@ +/* + * raid5.c : Multiple Devices driver for Linux + * Copyright (C) 1996, 1997 Ingo Molnar, Miguel de Icaza, Gadi Oxman + * Copyright (C) 1999, 2000 Ingo Molnar + * + * RAID-5 management functions. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * You should have received a copy of the GNU General Public License + * (for example /usr/src/linux/COPYING); if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#include +#include +#include +#include +#include +#include +#include + +static mdk_personality_t raid5_personality; + +/* + * Stripe cache + */ + +#define NR_STRIPES 128 +#define HASH_PAGES 1 +#define HASH_PAGES_ORDER 0 +#define NR_HASH (HASH_PAGES * PAGE_SIZE / sizeof(struct stripe_head *)) +#define HASH_MASK (NR_HASH - 1) +#define stripe_hash(conf, sect, size) ((conf)->stripe_hashtbl[((sect) / (size >> 9)) & HASH_MASK]) + +/* + * The following can be used to debug the driver + */ +#define RAID5_DEBUG 0 +#define RAID5_PARANOIA 1 +#if RAID5_PARANOIA && CONFIG_SMP +# define CHECK_DEVLOCK() if (!spin_is_locked(&conf->device_lock)) BUG() +# define CHECK_SHLOCK(sh) if (!stripe_locked(sh)) BUG() +#else +# define CHECK_DEVLOCK() +# define CHECK_SHLOCK(unused) +#endif + +#if RAID5_DEBUG +#define PRINTK(x...) printk(x) +#define inline +#define __inline__ +#else +#define PRINTK(x...) do { } while (0) +#endif + +static void print_raid5_conf (raid5_conf_t *conf); + +static inline int stripe_locked(struct stripe_head *sh) +{ + return test_bit(STRIPE_LOCKED, &sh->state); +} + +static void __unlock_stripe(struct stripe_head *sh) +{ + if (!md_test_and_clear_bit(STRIPE_LOCKED, &sh->state)) + BUG(); + PRINTK("unlocking stripe %lu\n", sh->sector); + wake_up(&sh->wait); +} + +static void finish_unlock_stripe(struct stripe_head *sh) +{ + raid5_conf_t *conf = sh->raid_conf; + sh->cmd = STRIPE_NONE; + sh->phase = PHASE_COMPLETE; + atomic_dec(&conf->nr_pending_stripes); + atomic_inc(&conf->nr_cached_stripes); + __unlock_stripe(sh); + atomic_dec(&sh->count); + wake_up(&conf->wait_for_stripe); +} + +static void remove_hash(raid5_conf_t *conf, struct stripe_head *sh) +{ + PRINTK("remove_hash(), stripe %lu\n", sh->sector); + + CHECK_DEVLOCK(); + CHECK_SHLOCK(sh); + if (sh->hash_pprev) { + if (sh->hash_next) + sh->hash_next->hash_pprev = sh->hash_pprev; + *sh->hash_pprev = sh->hash_next; + sh->hash_pprev = NULL; + atomic_dec(&conf->nr_hashed_stripes); + } +} + +static void lock_get_bh (struct buffer_head *bh) +{ + while (md_test_and_set_bit(BH_Lock, &bh->b_state)) + __wait_on_buffer(bh); + atomic_inc(&bh->b_count); +} + +static __inline__ void insert_hash(raid5_conf_t *conf, struct stripe_head *sh) +{ + struct stripe_head **shp = &stripe_hash(conf, sh->sector, sh->size); + + PRINTK("insert_hash(), stripe %lu, nr_hashed_stripes %d\n", + sh->sector, atomic_read(&conf->nr_hashed_stripes)); + + CHECK_DEVLOCK(); + CHECK_SHLOCK(sh); + if ((sh->hash_next = *shp) != NULL) + (*shp)->hash_pprev = &sh->hash_next; + *shp = sh; + sh->hash_pprev = shp; + atomic_inc(&conf->nr_hashed_stripes); +} + +static struct buffer_head *get_free_buffer(struct stripe_head *sh, int b_size) +{ + struct buffer_head *bh; + unsigned long flags; + + CHECK_SHLOCK(sh); + md_spin_lock_irqsave(&sh->stripe_lock, flags); + bh = sh->buffer_pool; + if (!bh) + goto out_unlock; + sh->buffer_pool = bh->b_next; + bh->b_size = b_size; + if (atomic_read(&bh->b_count)) + BUG(); +out_unlock: + md_spin_unlock_irqrestore(&sh->stripe_lock, flags); + + return bh; +} + +static struct buffer_head *get_free_bh(struct stripe_head *sh) +{ + struct buffer_head *bh; + unsigned long flags; + + CHECK_SHLOCK(sh); + md_spin_lock_irqsave(&sh->stripe_lock, flags); + bh = sh->bh_pool; + if (!bh) + goto out_unlock; + sh->bh_pool = bh->b_next; + if (atomic_read(&bh->b_count)) + BUG(); +out_unlock: + md_spin_unlock_irqrestore(&sh->stripe_lock, flags); + + return bh; +} + +static void put_free_buffer(struct stripe_head *sh, struct buffer_head *bh) +{ + unsigned long flags; + + if (atomic_read(&bh->b_count)) + BUG(); + CHECK_SHLOCK(sh); + md_spin_lock_irqsave(&sh->stripe_lock, flags); + bh->b_next = sh->buffer_pool; + sh->buffer_pool = bh; + md_spin_unlock_irqrestore(&sh->stripe_lock, flags); +} + +static void put_free_bh(struct stripe_head *sh, struct buffer_head *bh) +{ + unsigned long flags; + + if (atomic_read(&bh->b_count)) + BUG(); + CHECK_SHLOCK(sh); + md_spin_lock_irqsave(&sh->stripe_lock, flags); + bh->b_next = sh->bh_pool; + sh->bh_pool = bh; + md_spin_unlock_irqrestore(&sh->stripe_lock, flags); +} + +static struct stripe_head *get_free_stripe(raid5_conf_t *conf) +{ + struct stripe_head *sh; + + md_spin_lock_irq(&conf->device_lock); + sh = conf->free_sh_list; + if (!sh) + goto out; + conf->free_sh_list = sh->free_next; + atomic_dec(&conf->nr_free_sh); + if (!atomic_read(&conf->nr_free_sh) && conf->free_sh_list) + BUG(); + if (sh->hash_pprev || md_atomic_read(&sh->nr_pending) || + atomic_read(&sh->count)) + BUG(); +out: + md_spin_unlock_irq(&conf->device_lock); + return sh; +} + +static void __put_free_stripe (raid5_conf_t *conf, struct stripe_head *sh) +{ + if (atomic_read(&sh->count) != 0) + BUG(); + CHECK_DEVLOCK(); + CHECK_SHLOCK(sh); + clear_bit(STRIPE_LOCKED, &sh->state); + sh->free_next = conf->free_sh_list; + conf->free_sh_list = sh; + atomic_inc(&conf->nr_free_sh); +} + +static void shrink_buffers(struct stripe_head *sh, int num) +{ + struct buffer_head *bh; + + while (num--) { + bh = get_free_buffer(sh, -1); + if (!bh) + return; + free_page((unsigned long) bh->b_data); + kfree(bh); + } +} + +static void shrink_bh(struct stripe_head *sh, int num) +{ + struct buffer_head *bh; + + while (num--) { + bh = get_free_bh(sh); + if (!bh) + return; + kfree(bh); + } +} + +static int grow_raid5_buffers(struct stripe_head *sh, int num, int b_size, int priority) +{ + struct buffer_head *bh; + + while (num--) { + struct page *page; + bh = kmalloc(sizeof(struct buffer_head), priority); + if (!bh) + return 1; + memset(bh, 0, sizeof (struct buffer_head)); + init_waitqueue_head(&bh->b_wait); + page = alloc_page(priority); + bh->b_data = page_address(page); + if (!bh->b_data) { + kfree(bh); + return 1; + } + bh->b_size = b_size; + atomic_set(&bh->b_count, 0); + bh->b_page = page; + put_free_buffer(sh, bh); + } + return 0; +} + +static int grow_bh(struct stripe_head *sh, int num, int priority) +{ + struct buffer_head *bh; + + while (num--) { + bh = kmalloc(sizeof(struct buffer_head), priority); + if (!bh) + return 1; + memset(bh, 0, sizeof (struct buffer_head)); + init_waitqueue_head(&bh->b_wait); + put_free_bh(sh, bh); + } + return 0; +} + +static void raid5_free_buffer(struct stripe_head *sh, struct buffer_head *bh) +{ + put_free_buffer(sh, bh); +} + +static void raid5_free_bh(struct stripe_head *sh, struct buffer_head *bh) +{ + put_free_bh(sh, bh); +} + +static void raid5_free_old_bh(struct stripe_head *sh, int i) +{ + CHECK_SHLOCK(sh); + if (!sh->bh_old[i]) + BUG(); + raid5_free_buffer(sh, sh->bh_old[i]); + sh->bh_old[i] = NULL; +} + +static void raid5_update_old_bh(struct stripe_head *sh, int i) +{ + CHECK_SHLOCK(sh); + PRINTK("stripe %lu, idx %d, updating cache copy\n", sh->sector, i); + if (!sh->bh_copy[i]) + BUG(); + if (sh->bh_old[i]) + raid5_free_old_bh(sh, i); + sh->bh_old[i] = sh->bh_copy[i]; + sh->bh_copy[i] = NULL; +} + +static void free_stripe(struct stripe_head *sh) +{ + raid5_conf_t *conf = sh->raid_conf; + int disks = conf->raid_disks, j; + + if (atomic_read(&sh->count) != 0) + BUG(); + CHECK_DEVLOCK(); + CHECK_SHLOCK(sh); + PRINTK("free_stripe called, stripe %lu\n", sh->sector); + if (sh->phase != PHASE_COMPLETE || atomic_read(&sh->count)) { + PRINTK("raid5: free_stripe(), sector %lu, phase %d, count %d\n", sh->sector, sh->phase, atomic_read(&sh->count)); + return; + } + for (j = 0; j < disks; j++) { + if (sh->bh_old[j]) + raid5_free_old_bh(sh, j); + if (sh->bh_new[j] || sh->bh_copy[j]) + BUG(); + } + remove_hash(conf, sh); + __put_free_stripe(conf, sh); +} + +static int shrink_stripe_cache(raid5_conf_t *conf, int nr) +{ + struct stripe_head *sh; + int i, count = 0; + + PRINTK("shrink_stripe_cache called, %d/%d, clock %d\n", nr, atomic_read(&conf->nr_hashed_stripes), conf->clock); + md_spin_lock_irq(&conf->device_lock); + for (i = 0; i < NR_HASH; i++) { + sh = conf->stripe_hashtbl[(i + conf->clock) & HASH_MASK]; + for (; sh; sh = sh->hash_next) { + if (sh->phase != PHASE_COMPLETE) + continue; + if (atomic_read(&sh->count)) + continue; + /* + * Try to lock this stripe: + */ + if (md_test_and_set_bit(STRIPE_LOCKED, &sh->state)) + continue; + free_stripe(sh); + if (++count == nr) { + conf->clock = (i + conf->clock) & HASH_MASK; + goto out; + } + } + } +out: + md_spin_unlock_irq(&conf->device_lock); + PRINTK("shrink completed, nr_hashed_stripes %d, nr_pending_strips %d\n", + atomic_read(&conf->nr_hashed_stripes), + atomic_read(&conf->nr_pending_stripes)); + return count; +} + +void __wait_lock_stripe(struct stripe_head *sh) +{ + MD_DECLARE_WAITQUEUE(wait, current); + + PRINTK("wait_lock_stripe %lu\n", sh->sector); + if (!atomic_read(&sh->count)) + BUG(); + add_wait_queue(&sh->wait, &wait); +repeat: + set_current_state(TASK_UNINTERRUPTIBLE); + if (md_test_and_set_bit(STRIPE_LOCKED, &sh->state)) { + schedule(); + goto repeat; + } + PRINTK("wait_lock_stripe %lu done\n", sh->sector); + remove_wait_queue(&sh->wait, &wait); + current->state = TASK_RUNNING; +} + +static struct stripe_head *__find_stripe(raid5_conf_t *conf, unsigned long sector, int size) +{ + struct stripe_head *sh; + + PRINTK("__find_stripe, sector %lu\n", sector); + for (sh = stripe_hash(conf, sector, size); sh; sh = sh->hash_next) { + if (sh->sector == sector && sh->raid_conf == conf) { + if (sh->size != size) + BUG(); + return sh; + } + } + PRINTK("__stripe %lu not in cache\n", sector); + return NULL; +} + +static inline struct stripe_head *alloc_stripe(raid5_conf_t *conf, unsigned long sector, int size) +{ + struct stripe_head *sh; + struct buffer_head *buffer_pool, *bh_pool; + MD_DECLARE_WAITQUEUE(wait, current); + + PRINTK("alloc_stripe called\n"); + + + while ((sh = get_free_stripe(conf)) == NULL) { + int cnt; + add_wait_queue(&conf->wait_for_stripe, &wait); + set_current_state(TASK_UNINTERRUPTIBLE); + cnt = shrink_stripe_cache(conf, conf->max_nr_stripes / 8); + sh = get_free_stripe(conf); + if (!sh && cnt < (conf->max_nr_stripes/8)) { + md_wakeup_thread(conf->thread); + PRINTK("waiting for some stripes to complete - %d %d\n", cnt, conf->max_nr_stripes/8); + schedule(); + } + remove_wait_queue(&conf->wait_for_stripe, &wait); + current->state = TASK_RUNNING; + if (sh) + break; + } + + buffer_pool = sh->buffer_pool; + bh_pool = sh->bh_pool; + memset(sh, 0, sizeof(*sh)); + sh->stripe_lock = MD_SPIN_LOCK_UNLOCKED; + md_init_waitqueue_head(&sh->wait); + sh->buffer_pool = buffer_pool; + sh->bh_pool = bh_pool; + sh->phase = PHASE_COMPLETE; + sh->cmd = STRIPE_NONE; + sh->raid_conf = conf; + sh->sector = sector; + sh->size = size; + atomic_inc(&conf->nr_cached_stripes); + + return sh; +} + +static struct stripe_head *get_lock_stripe(raid5_conf_t *conf, unsigned long sector, int size) +{ + struct stripe_head *sh, *new = NULL; + + PRINTK("get_stripe, sector %lu\n", sector); + + /* + * Do this in set_blocksize()! + */ + if (conf->buffer_size != size) { + PRINTK("switching size, %d --> %d\n", conf->buffer_size, size); + shrink_stripe_cache(conf, conf->max_nr_stripes); + conf->buffer_size = size; + } + +repeat: + md_spin_lock_irq(&conf->device_lock); + sh = __find_stripe(conf, sector, size); + if (!sh) { + if (!new) { + md_spin_unlock_irq(&conf->device_lock); + new = alloc_stripe(conf, sector, size); + goto repeat; + } + sh = new; + new = NULL; + if (md_test_and_set_bit(STRIPE_LOCKED, &sh->state)) + BUG(); + insert_hash(conf, sh); + atomic_inc(&sh->count); + md_spin_unlock_irq(&conf->device_lock); + } else { + atomic_inc(&sh->count); + if (new) { + if (md_test_and_set_bit(STRIPE_LOCKED, &new->state)) + BUG(); + __put_free_stripe(conf, new); + } + md_spin_unlock_irq(&conf->device_lock); + PRINTK("get_stripe, waiting, sector %lu\n", sector); + if (md_test_and_set_bit(STRIPE_LOCKED, &sh->state)) + __wait_lock_stripe(sh); + } + return sh; +} + +static int grow_stripes(raid5_conf_t *conf, int num, int priority) +{ + struct stripe_head *sh; + + while (num--) { + sh = kmalloc(sizeof(struct stripe_head), priority); + if (!sh) + return 1; + memset(sh, 0, sizeof(*sh)); + sh->raid_conf = conf; + sh->stripe_lock = MD_SPIN_LOCK_UNLOCKED; + md_init_waitqueue_head(&sh->wait); + + if (md_test_and_set_bit(STRIPE_LOCKED, &sh->state)) + BUG(); + if (grow_raid5_buffers(sh, 2 * conf->raid_disks, PAGE_SIZE, priority)) { + shrink_buffers(sh, 2 * conf->raid_disks); + kfree(sh); + return 1; + } + if (grow_bh(sh, conf->raid_disks, priority)) { + shrink_buffers(sh, 2 * conf->raid_disks); + shrink_bh(sh, conf->raid_disks); + kfree(sh); + return 1; + } + md_spin_lock_irq(&conf->device_lock); + __put_free_stripe(conf, sh); + atomic_inc(&conf->nr_stripes); + md_spin_unlock_irq(&conf->device_lock); + } + return 0; +} + +static void shrink_stripes(raid5_conf_t *conf, int num) +{ + struct stripe_head *sh; + + while (num--) { + sh = get_free_stripe(conf); + if (!sh) + break; + if (md_test_and_set_bit(STRIPE_LOCKED, &sh->state)) + BUG(); + shrink_buffers(sh, conf->raid_disks * 2); + shrink_bh(sh, conf->raid_disks); + kfree(sh); + atomic_dec(&conf->nr_stripes); + } +} + + +static struct buffer_head *raid5_alloc_buffer(struct stripe_head *sh, int b_size) +{ + struct buffer_head *bh; + + bh = get_free_buffer(sh, b_size); + if (!bh) + BUG(); + return bh; +} + +static struct buffer_head *raid5_alloc_bh(struct stripe_head *sh) +{ + struct buffer_head *bh; + + bh = get_free_bh(sh); + if (!bh) + BUG(); + return bh; +} + +static void raid5_end_buffer_io (struct stripe_head *sh, int i, int uptodate) +{ + struct buffer_head *bh = sh->bh_new[i]; + + PRINTK("raid5_end_buffer_io %lu, uptodate: %d.\n", bh->b_blocknr, uptodate); + sh->bh_new[i] = NULL; + raid5_free_bh(sh, sh->bh_req[i]); + sh->bh_req[i] = NULL; + PRINTK("calling %p->end_io: %p.\n", bh, bh->b_end_io); + bh->b_end_io(bh, uptodate); + if (!uptodate) + printk(KERN_ALERT "raid5: %s: unrecoverable I/O error for " + "block %lu\n", + partition_name(mddev_to_kdev(sh->raid_conf->mddev)), + bh->b_blocknr); +} + +static inline void raid5_mark_buffer_uptodate (struct buffer_head *bh, int uptodate) +{ + if (uptodate) + set_bit(BH_Uptodate, &bh->b_state); + else + clear_bit(BH_Uptodate, &bh->b_state); +} + +static void raid5_end_request (struct buffer_head * bh, int uptodate) +{ + struct stripe_head *sh = bh->b_private; + raid5_conf_t *conf = sh->raid_conf; + int disks = conf->raid_disks, i; + unsigned long flags; + + PRINTK("end_request %lu, nr_pending %d, uptodate: %d, (caller: %p,%p,%p,%p).\n", sh->sector, atomic_read(&sh->nr_pending), uptodate, __builtin_return_address(0),__builtin_return_address(1),__builtin_return_address(2), __builtin_return_address(3)); + md_spin_lock_irqsave(&sh->stripe_lock, flags); + raid5_mark_buffer_uptodate(bh, uptodate); + if (!uptodate) + md_error(mddev_to_kdev(conf->mddev), bh->b_dev); + if (conf->failed_disks) { + for (i = 0; i < disks; i++) { + if (conf->disks[i].operational) + continue; + if (bh != sh->bh_old[i] && bh != sh->bh_req[i] && bh != sh->bh_copy[i]) + continue; + if (bh->b_dev != conf->disks[i].dev) + continue; + set_bit(STRIPE_ERROR, &sh->state); + } + } + md_spin_unlock_irqrestore(&sh->stripe_lock, flags); + + if (atomic_dec_and_test(&sh->nr_pending)) { + atomic_inc(&conf->nr_handle); + md_wakeup_thread(conf->thread); + } +} + +static void raid5_build_block (struct stripe_head *sh, struct buffer_head *bh, int i) +{ + raid5_conf_t *conf = sh->raid_conf; + char *b_data; + struct page *b_page; + unsigned long block = sh->sector / (sh->size >> 9); + + b_data = bh->b_data; + b_page = bh->b_page; + memset (bh, 0, sizeof (struct buffer_head)); + init_waitqueue_head(&bh->b_wait); + init_buffer(bh, raid5_end_request, sh); + bh->b_dev = conf->disks[i].dev; + bh->b_blocknr = block; + + bh->b_data = b_data; + bh->b_page = b_page; + + bh->b_rdev = conf->disks[i].dev; + bh->b_rsector = sh->sector; + + bh->b_state = (1 << BH_Req) | (1 << BH_Mapped); + bh->b_size = sh->size; + bh->b_list = BUF_LOCKED; +} + +static int raid5_error (mddev_t *mddev, kdev_t dev) +{ + raid5_conf_t *conf = (raid5_conf_t *) mddev->private; + mdp_super_t *sb = mddev->sb; + struct disk_info *disk; + int i; + + PRINTK("raid5_error called\n"); + conf->resync_parity = 0; + for (i = 0, disk = conf->disks; i < conf->raid_disks; i++, disk++) { + if (disk->dev == dev && disk->operational) { + disk->operational = 0; + mark_disk_faulty(sb->disks+disk->number); + mark_disk_nonsync(sb->disks+disk->number); + mark_disk_inactive(sb->disks+disk->number); + sb->active_disks--; + sb->working_disks--; + sb->failed_disks++; + mddev->sb_dirty = 1; + conf->working_disks--; + conf->failed_disks++; + md_wakeup_thread(conf->thread); + printk (KERN_ALERT + "raid5: Disk failure on %s, disabling device." + " Operation continuing on %d devices\n", + partition_name (dev), conf->working_disks); + return 0; + } + } + /* + * handle errors in spares (during reconstruction) + */ + if (conf->spare) { + disk = conf->spare; + if (disk->dev == dev) { + printk (KERN_ALERT + "raid5: Disk failure on spare %s\n", + partition_name (dev)); + if (!conf->spare->operational) { + MD_BUG(); + return -EIO; + } + disk->operational = 0; + disk->write_only = 0; + conf->spare = NULL; + mark_disk_faulty(sb->disks+disk->number); + mark_disk_nonsync(sb->disks+disk->number); + mark_disk_inactive(sb->disks+disk->number); + sb->spare_disks--; + sb->working_disks--; + sb->failed_disks++; + + return 0; + } + } + MD_BUG(); + return -EIO; +} + +/* + * Input: a 'big' sector number, + * Output: index of the data and parity disk, and the sector # in them. + */ +static unsigned long raid5_compute_sector(unsigned long r_sector, unsigned int raid_disks, + unsigned int data_disks, unsigned int * dd_idx, + unsigned int * pd_idx, raid5_conf_t *conf) +{ + unsigned long stripe; + unsigned long chunk_number; + unsigned int chunk_offset; + unsigned long new_sector; + int sectors_per_chunk = conf->chunk_size >> 9; + + /* First compute the information on this sector */ + + /* + * Compute the chunk number and the sector offset inside the chunk + */ + chunk_number = r_sector / sectors_per_chunk; + chunk_offset = r_sector % sectors_per_chunk; + + /* + * Compute the stripe number + */ + stripe = chunk_number / data_disks; + + /* + * Compute the data disk and parity disk indexes inside the stripe + */ + *dd_idx = chunk_number % data_disks; + + /* + * Select the parity disk based on the user selected algorithm. + */ + if (conf->level == 4) + *pd_idx = data_disks; + else switch (conf->algorithm) { + case ALGORITHM_LEFT_ASYMMETRIC: + *pd_idx = data_disks - stripe % raid_disks; + if (*dd_idx >= *pd_idx) + (*dd_idx)++; + break; + case ALGORITHM_RIGHT_ASYMMETRIC: + *pd_idx = stripe % raid_disks; + if (*dd_idx >= *pd_idx) + (*dd_idx)++; + break; + case ALGORITHM_LEFT_SYMMETRIC: + *pd_idx = data_disks - stripe % raid_disks; + *dd_idx = (*pd_idx + 1 + *dd_idx) % raid_disks; + break; + case ALGORITHM_RIGHT_SYMMETRIC: + *pd_idx = stripe % raid_disks; + *dd_idx = (*pd_idx + 1 + *dd_idx) % raid_disks; + break; + default: + printk ("raid5: unsupported algorithm %d\n", conf->algorithm); + } + + /* + * Finally, compute the new sector number + */ + new_sector = stripe * sectors_per_chunk + chunk_offset; + return new_sector; +} + +static unsigned long compute_blocknr(struct stripe_head *sh, int i) +{ + raid5_conf_t *conf = sh->raid_conf; + int raid_disks = conf->raid_disks, data_disks = raid_disks - 1; + unsigned long new_sector = sh->sector, check; + int sectors_per_chunk = conf->chunk_size >> 9; + unsigned long stripe = new_sector / sectors_per_chunk; + int chunk_offset = new_sector % sectors_per_chunk; + int chunk_number, dummy1, dummy2, dd_idx = i; + unsigned long r_sector, blocknr; + + switch (conf->algorithm) { + case ALGORITHM_LEFT_ASYMMETRIC: + case ALGORITHM_RIGHT_ASYMMETRIC: + if (i > sh->pd_idx) + i--; + break; + case ALGORITHM_LEFT_SYMMETRIC: + case ALGORITHM_RIGHT_SYMMETRIC: + if (i < sh->pd_idx) + i += raid_disks; + i -= (sh->pd_idx + 1); + break; + default: + printk ("raid5: unsupported algorithm %d\n", conf->algorithm); + } + + chunk_number = stripe * data_disks + i; + r_sector = chunk_number * sectors_per_chunk + chunk_offset; + blocknr = r_sector / (sh->size >> 9); + + check = raid5_compute_sector (r_sector, raid_disks, data_disks, &dummy1, &dummy2, conf); + if (check != sh->sector || dummy1 != dd_idx || dummy2 != sh->pd_idx) { + printk("compute_blocknr: map not correct\n"); + return 0; + } + return blocknr; +} + +static void compute_block(struct stripe_head *sh, int dd_idx) +{ + raid5_conf_t *conf = sh->raid_conf; + int i, count, disks = conf->raid_disks; + struct buffer_head *bh_ptr[MAX_XOR_BLOCKS]; + + PRINTK("compute_block, stripe %lu, idx %d\n", sh->sector, dd_idx); + + if (sh->bh_old[dd_idx] == NULL) + sh->bh_old[dd_idx] = raid5_alloc_buffer(sh, sh->size); + raid5_build_block(sh, sh->bh_old[dd_idx], dd_idx); + + memset(sh->bh_old[dd_idx]->b_data, 0, sh->size); + bh_ptr[0] = sh->bh_old[dd_idx]; + count = 1; + for (i = 0; i < disks; i++) { + if (i == dd_idx) + continue; + if (sh->bh_old[i]) { + bh_ptr[count++] = sh->bh_old[i]; + } else { + printk("compute_block() %d, stripe %lu, %d not present\n", dd_idx, sh->sector, i); + } + if (count == MAX_XOR_BLOCKS) { + xor_block(count, &bh_ptr[0]); + count = 1; + } + } + if (count != 1) + xor_block(count, &bh_ptr[0]); + raid5_mark_buffer_uptodate(sh->bh_old[dd_idx], 1); +} + +static void compute_parity(struct stripe_head *sh, int method) +{ + raid5_conf_t *conf = sh->raid_conf; + int i, pd_idx = sh->pd_idx, disks = conf->raid_disks, count; + struct buffer_head *bh_ptr[MAX_XOR_BLOCKS]; + + PRINTK("compute_parity, stripe %lu, method %d\n", sh->sector, method); + for (i = 0; i < disks; i++) { + if (i == pd_idx || !sh->bh_new[i]) + continue; + if (!sh->bh_copy[i]) + sh->bh_copy[i] = raid5_alloc_buffer(sh, sh->size); + raid5_build_block(sh, sh->bh_copy[i], i); + atomic_set_buffer_dirty(sh->bh_copy[i]); + memcpy(sh->bh_copy[i]->b_data, sh->bh_new[i]->b_data, sh->size); + } + if (sh->bh_copy[pd_idx] == NULL) { + sh->bh_copy[pd_idx] = raid5_alloc_buffer(sh, sh->size); + atomic_set_buffer_dirty(sh->bh_copy[pd_idx]); + } + raid5_build_block(sh, sh->bh_copy[pd_idx], sh->pd_idx); + + if (method == RECONSTRUCT_WRITE) { + memset(sh->bh_copy[pd_idx]->b_data, 0, sh->size); + bh_ptr[0] = sh->bh_copy[pd_idx]; + count = 1; + for (i = 0; i < disks; i++) { + if (i == sh->pd_idx) + continue; + if (sh->bh_new[i]) { + bh_ptr[count++] = sh->bh_copy[i]; + } else if (sh->bh_old[i]) { + bh_ptr[count++] = sh->bh_old[i]; + } + if (count == MAX_XOR_BLOCKS) { + xor_block(count, &bh_ptr[0]); + count = 1; + } + } + if (count != 1) { + xor_block(count, &bh_ptr[0]); + } + } else if (method == READ_MODIFY_WRITE) { + memcpy(sh->bh_copy[pd_idx]->b_data, sh->bh_old[pd_idx]->b_data, sh->size); + bh_ptr[0] = sh->bh_copy[pd_idx]; + count = 1; + for (i = 0; i < disks; i++) { + if (i == sh->pd_idx) + continue; + if (sh->bh_new[i] && sh->bh_old[i]) { + bh_ptr[count++] = sh->bh_copy[i]; + bh_ptr[count++] = sh->bh_old[i]; + } + if (count >= (MAX_XOR_BLOCKS - 1)) { + xor_block(count, &bh_ptr[0]); + count = 1; + } + } + if (count != 1) { + xor_block(count, &bh_ptr[0]); + } + } + raid5_mark_buffer_uptodate(sh->bh_copy[pd_idx], 1); +} + +static void add_stripe_bh (struct stripe_head *sh, struct buffer_head *bh, int dd_idx, int rw) +{ + raid5_conf_t *conf = sh->raid_conf; + struct buffer_head *bh_req; + + PRINTK("adding bh b#%lu to stripe s#%lu\n", bh->b_blocknr, sh->sector); + CHECK_SHLOCK(sh); + if (sh->bh_new[dd_idx]) + BUG(); + + bh_req = raid5_alloc_bh(sh); + raid5_build_block(sh, bh_req, dd_idx); + bh_req->b_data = bh->b_data; + bh_req->b_page = bh->b_page; + + md_spin_lock_irq(&conf->device_lock); + if (sh->phase == PHASE_COMPLETE && sh->cmd == STRIPE_NONE) { + PRINTK("stripe s#%lu => PHASE_BEGIN (%s)\n", sh->sector, rw == READ ? "read" : "write"); + sh->phase = PHASE_BEGIN; + sh->cmd = (rw == READ) ? STRIPE_READ : STRIPE_WRITE; + atomic_inc(&conf->nr_pending_stripes); + atomic_inc(&conf->nr_handle); + PRINTK("# of pending stripes: %u, # of handle: %u\n", atomic_read(&conf->nr_pending_stripes), atomic_read(&conf->nr_handle)); + } + sh->bh_new[dd_idx] = bh; + sh->bh_req[dd_idx] = bh_req; + sh->cmd_new[dd_idx] = rw; + sh->new[dd_idx] = 1; + md_spin_unlock_irq(&conf->device_lock); + + PRINTK("added bh b#%lu to stripe s#%lu, disk %d.\n", bh->b_blocknr, sh->sector, dd_idx); +} + +static void complete_stripe(struct stripe_head *sh) +{ + raid5_conf_t *conf = sh->raid_conf; + int disks = conf->raid_disks; + int i, new = 0; + + PRINTK("complete_stripe %lu\n", sh->sector); + for (i = 0; i < disks; i++) { + if (sh->cmd == STRIPE_SYNC && sh->bh_copy[i]) + raid5_update_old_bh(sh, i); + if (sh->cmd == STRIPE_WRITE && i == sh->pd_idx) + raid5_update_old_bh(sh, i); + if (sh->bh_new[i]) { + PRINTK("stripe %lu finishes new bh, sh->new == %d\n", sh->sector, sh->new[i]); + if (!sh->new[i]) { +#if 0 + if (sh->cmd == STRIPE_WRITE) { + if (memcmp(sh->bh_new[i]->b_data, sh->bh_copy[i]->b_data, sh->size)) { + printk("copy differs, %s, sector %lu ", + test_bit(BH_Dirty, &sh->bh_new[i]->b_state) ? "dirty" : "clean", + sh->sector); + } else if (test_bit(BH_Dirty, &sh->bh_new[i]->b_state)) + printk("sector %lu dirty\n", sh->sector); + } +#endif + if (sh->cmd == STRIPE_WRITE) + raid5_update_old_bh(sh, i); + raid5_end_buffer_io(sh, i, 1); + continue; + } else + new++; + } + if (new && sh->cmd == STRIPE_WRITE) + printk("raid5: bug, completed STRIPE_WRITE with new == %d\n", new); + } + if (sh->cmd == STRIPE_SYNC) + md_done_sync(conf->mddev, (sh->size>>10) - sh->sync_redone,1); + if (!new) + finish_unlock_stripe(sh); + else { + PRINTK("stripe %lu, new == %d\n", sh->sector, new); + sh->phase = PHASE_BEGIN; + } +} + + +static void handle_stripe_write (mddev_t *mddev , raid5_conf_t *conf, + struct stripe_head *sh, int nr_write, int * operational, int disks, + int parity, int parity_failed, int nr_cache, int nr_cache_other, + int nr_failed_other, int nr_cache_overwrite, int nr_failed_overwrite) +{ + int i; + unsigned int block; + struct buffer_head *bh; + int method1 = INT_MAX, method2 = INT_MAX; + + /* + * Attempt to add entries :-) + */ + if (nr_write != disks - 1) { + for (i = 0; i < disks; i++) { + if (i == sh->pd_idx) + continue; + if (sh->bh_new[i]) + continue; + block = (int) compute_blocknr(sh, i); + bh = get_hash_table(mddev_to_kdev(mddev), block, sh->size); + if (!bh) + continue; + if (buffer_dirty(bh) && !md_test_and_set_bit(BH_Lock, &bh->b_state)) { + PRINTK("Whee.. sector %lu, index %d (%d) found in the buffer cache!\n", sh->sector, i, block); + add_stripe_bh(sh, bh, i, WRITE); + sh->new[i] = 0; + nr_write++; + if (sh->bh_old[i]) { + nr_cache_overwrite++; + nr_cache_other--; + } else + if (!operational[i]) { + nr_failed_overwrite++; + nr_failed_other--; + } + } + atomic_dec(&bh->b_count); + } + } + PRINTK("handle_stripe() -- begin writing, stripe %lu\n", sh->sector); + /* + * Writing, need to update parity buffer. + * + * Compute the number of I/O requests in the "reconstruct + * write" and "read modify write" methods. + */ + if (!nr_failed_other) + method1 = (disks - 1) - (nr_write + nr_cache_other); + if (!nr_failed_overwrite && !parity_failed) + method2 = nr_write - nr_cache_overwrite + (1 - parity); + + if (method1 == INT_MAX && method2 == INT_MAX) + BUG(); + PRINTK("handle_stripe(), sector %lu, nr_write %d, method1 %d, method2 %d\n", sh->sector, nr_write, method1, method2); + + if (!method1 || !method2) { + sh->phase = PHASE_WRITE; + compute_parity(sh, method1 <= method2 ? RECONSTRUCT_WRITE : READ_MODIFY_WRITE); + + for (i = 0; i < disks; i++) { + if (!operational[i] && !conf->spare && !conf->resync_parity) + continue; + bh = sh->bh_copy[i]; + if (i != sh->pd_idx && ((bh == NULL) ^ (sh->bh_new[i] == NULL))) + printk("raid5: bug: bh == %p, bh_new[%d] == %p\n", bh, i, sh->bh_new[i]); + if (i == sh->pd_idx && !bh) + printk("raid5: bug: bh == NULL, i == pd_idx == %d\n", i); + if (bh) { + PRINTK("making request for buffer %d\n", i); + lock_get_bh(bh); + if (!operational[i] && !conf->resync_parity) { + PRINTK("writing spare %d\n", i); + atomic_inc(&sh->nr_pending); + bh->b_dev = bh->b_rdev = conf->spare->dev; + generic_make_request(WRITE, bh); + } else { + atomic_inc(&sh->nr_pending); + bh->b_dev = bh->b_rdev = conf->disks[i].dev; + generic_make_request(WRITE, bh); + } + atomic_dec(&bh->b_count); + } + } + PRINTK("handle_stripe() %lu, writing back %d buffers\n", sh->sector, md_atomic_read(&sh->nr_pending)); + return; + } + + if (method1 < method2) { + sh->write_method = RECONSTRUCT_WRITE; + for (i = 0; i < disks; i++) { + if (i == sh->pd_idx) + continue; + if (sh->bh_new[i] || sh->bh_old[i]) + continue; + sh->bh_old[i] = raid5_alloc_buffer(sh, sh->size); + raid5_build_block(sh, sh->bh_old[i], i); + } + } else { + sh->write_method = READ_MODIFY_WRITE; + for (i = 0; i < disks; i++) { + if (sh->bh_old[i]) + continue; + if (!sh->bh_new[i] && i != sh->pd_idx) + continue; + sh->bh_old[i] = raid5_alloc_buffer(sh, sh->size); + raid5_build_block(sh, sh->bh_old[i], i); + } + } + sh->phase = PHASE_READ_OLD; + for (i = 0; i < disks; i++) { + if (!sh->bh_old[i]) + continue; + if (test_bit(BH_Uptodate, &sh->bh_old[i]->b_state)) + continue; + lock_get_bh(sh->bh_old[i]); + atomic_inc(&sh->nr_pending); + sh->bh_old[i]->b_dev = sh->bh_old[i]->b_rdev = conf->disks[i].dev; + generic_make_request(READ, sh->bh_old[i]); + atomic_dec(&sh->bh_old[i]->b_count); + } + PRINTK("handle_stripe() %lu, reading %d old buffers\n", sh->sector, md_atomic_read(&sh->nr_pending)); +} + +/* + * Reading + */ +static void handle_stripe_read (mddev_t *mddev , raid5_conf_t *conf, + struct stripe_head *sh, int nr_read, int * operational, int disks, + int parity, int parity_failed, int nr_cache, int nr_cache_other, + int nr_failed_other, int nr_cache_overwrite, int nr_failed_overwrite) +{ + int i; + int method1 = INT_MAX; + + method1 = nr_read - nr_cache_overwrite; + + PRINTK("handle_stripe(), sector %lu, nr_read %d, nr_cache %d, method1 %d\n", sh->sector, nr_read, nr_cache, method1); + + if (!method1 || (method1 == 1 && nr_cache == disks - 1)) { + PRINTK("read %lu completed from cache\n", sh->sector); + for (i = 0; i < disks; i++) { + if (!sh->bh_new[i]) + continue; + if (!sh->bh_old[i]) + compute_block(sh, i); + memcpy(sh->bh_new[i]->b_data, sh->bh_old[i]->b_data, sh->size); + } + complete_stripe(sh); + return; + } + if (nr_failed_overwrite) { + sh->phase = PHASE_READ_OLD; + for (i = 0; i < disks; i++) { + if (sh->bh_old[i]) + continue; + if (!operational[i]) + continue; + sh->bh_old[i] = raid5_alloc_buffer(sh, sh->size); + raid5_build_block(sh, sh->bh_old[i], i); + lock_get_bh(sh->bh_old[i]); + atomic_inc(&sh->nr_pending); + sh->bh_old[i]->b_dev = sh->bh_old[i]->b_rdev = conf->disks[i].dev; + generic_make_request(READ, sh->bh_old[i]); + atomic_dec(&sh->bh_old[i]->b_count); + } + PRINTK("handle_stripe() %lu, phase READ_OLD, pending %d buffers\n", sh->sector, md_atomic_read(&sh->nr_pending)); + return; + } + sh->phase = PHASE_READ; + for (i = 0; i < disks; i++) { + if (!sh->bh_new[i]) + continue; + if (sh->bh_old[i]) { + memcpy(sh->bh_new[i]->b_data, sh->bh_old[i]->b_data, sh->size); + continue; + } +#if RAID5_PARANOIA + if (sh->bh_req[i] == NULL || test_bit(BH_Lock, &sh->bh_req[i]->b_state)) { + int j; + printk("req %d is NULL! or locked \n", i); + for (j=0; jbh_new[j], sh->bh_old[j], sh->bh_req[j], + sh->new[j], sh->cmd_new[j]); + } + + } +#endif + lock_get_bh(sh->bh_req[i]); + atomic_inc(&sh->nr_pending); + sh->bh_req[i]->b_dev = sh->bh_req[i]->b_rdev = conf->disks[i].dev; + generic_make_request(READ, sh->bh_req[i]); + atomic_dec(&sh->bh_req[i]->b_count); + } + PRINTK("handle_stripe() %lu, phase READ, pending %d\n", sh->sector, md_atomic_read(&sh->nr_pending)); +} + +/* + * Syncing + */ +static void handle_stripe_sync (mddev_t *mddev , raid5_conf_t *conf, + struct stripe_head *sh, int * operational, int disks, + int parity, int parity_failed, int nr_cache, int nr_cache_other, + int nr_failed_other, int nr_cache_overwrite, int nr_failed_overwrite) +{ + struct buffer_head *bh; + int i, pd_idx; + + /* firstly, we want to have data from all non-failed drives + * in bh_old + */ + PRINTK("handle_stripe_sync: sec=%lu disks=%d nr_cache=%d\n", sh->sector, disks, nr_cache); + if ((nr_cache < disks-1) || ((nr_cache == disks-1) && !(parity_failed+nr_failed_other+nr_failed_overwrite)) + ) { + sh->phase = PHASE_READ_OLD; + for (i = 0; i < disks; i++) { + if (sh->bh_old[i]) + continue; + if (!conf->disks[i].operational) + continue; + + bh = raid5_alloc_buffer(sh, sh->size); + sh->bh_old[i] = bh; + raid5_build_block(sh, bh, i); + lock_get_bh(bh); + atomic_inc(&sh->nr_pending); + bh->b_dev = bh->b_rdev = conf->disks[i].dev; + generic_make_request(READ, bh); + md_sync_acct(bh->b_rdev, bh->b_size/512); + atomic_dec(&sh->bh_old[i]->b_count); + } + PRINTK("handle_stripe_sync() %lu, phase READ_OLD, pending %d buffers\n", sh->sector, md_atomic_read(&sh->nr_pending)); + + return; + } + /* now, if there is a failed drive, rebuild and write to spare */ + if (nr_cache == disks-1) { + sh->phase = PHASE_WRITE; + /* we can generate the missing block, which will be on the failed drive */ + for (i=0; ispare) { + bh = sh->bh_copy[i]; + if (bh) { + memcpy(bh->b_data, sh->bh_old[i]->b_data, sh->size); + set_bit(BH_Uptodate, &bh->b_state); + } else { + bh = sh->bh_old[i]; + sh->bh_old[i] = NULL; + sh->bh_copy[i] = bh; + } + atomic_inc(&sh->nr_pending); + lock_get_bh(bh); + bh->b_dev = bh->b_rdev = conf->spare->dev; + generic_make_request(WRITE, bh); + md_sync_acct(bh->b_rdev, bh->b_size/512); + atomic_dec(&bh->b_count); + PRINTK("handle_stripe_sync() %lu, phase WRITE, pending %d buffers\n", sh->sector, md_atomic_read(&sh->nr_pending)); + } + break; + } + return; + } + + /* nr_cache == disks: + * check parity and compute/write if needed + */ + + compute_parity(sh, RECONSTRUCT_WRITE); + pd_idx = sh->pd_idx; + if (!memcmp(sh->bh_copy[pd_idx]->b_data, sh->bh_old[pd_idx]->b_data, sh->size)) { + /* the parity is correct - Yay! */ + complete_stripe(sh); + } else { + sh->phase = PHASE_WRITE; + bh = sh->bh_copy[pd_idx]; + atomic_set_buffer_dirty(bh); + lock_get_bh(bh); + atomic_inc(&sh->nr_pending); + bh->b_dev = bh->b_rdev = conf->disks[pd_idx].dev; + generic_make_request(WRITE, bh); + md_sync_acct(bh->b_rdev, bh->b_size/512); + atomic_dec(&bh->b_count); + PRINTK("handle_stripe_sync() %lu phase WRITE, pending %d buffers\n", + sh->sector, md_atomic_read(&sh->nr_pending)); + } +} + +/* + * handle_stripe() is our main logic routine. Note that: + * + * 1. lock_stripe() should be used whenever we can't accept additonal + * buffers, either during short sleeping in handle_stripe() or + * during io operations. + * + * 2. We should be careful to set sh->nr_pending whenever we sleep, + * to prevent re-entry of handle_stripe() for the same sh. + * + * 3. conf->failed_disks and disk->operational can be changed + * from an interrupt. This complicates things a bit, but it allows + * us to stop issuing requests for a failed drive as soon as possible. + */ +static void handle_stripe(struct stripe_head *sh) +{ + raid5_conf_t *conf = sh->raid_conf; + mddev_t *mddev = conf->mddev; + int disks = conf->raid_disks; + int i, nr_read = 0, nr_write = 0, parity = 0; + int nr_cache = 0, nr_cache_other = 0, nr_cache_overwrite = 0; + int nr_failed_other = 0, nr_failed_overwrite = 0, parity_failed = 0; + int operational[MD_SB_DISKS], failed_disks = conf->failed_disks; + + PRINTK("handle_stripe(), stripe %lu\n", sh->sector); + if (!stripe_locked(sh)) + BUG(); + if (md_atomic_read(&sh->nr_pending)) + BUG(); + if (sh->phase == PHASE_COMPLETE) + BUG(); + + atomic_dec(&conf->nr_handle); + + if (md_test_and_clear_bit(STRIPE_ERROR, &sh->state)) { + printk("raid5: restarting stripe %lu\n", sh->sector); + sh->phase = PHASE_BEGIN; + } + + if ((sh->cmd == STRIPE_WRITE && sh->phase == PHASE_WRITE) || + (sh->cmd == STRIPE_READ && sh->phase == PHASE_READ) || + (sh->cmd == STRIPE_SYNC && sh->phase == PHASE_WRITE) + ) { + /* + * Completed + */ + complete_stripe(sh); + if (sh->phase == PHASE_COMPLETE) + return; + } + + md_spin_lock_irq(&conf->device_lock); + for (i = 0; i < disks; i++) { + operational[i] = conf->disks[i].operational; + if (i == sh->pd_idx && conf->resync_parity) + operational[i] = 0; + } + failed_disks = conf->failed_disks; + md_spin_unlock_irq(&conf->device_lock); + + /* + * Make this one more graceful? + */ + if (failed_disks > 1) { + for (i = 0; i < disks; i++) { + if (sh->bh_new[i]) { + raid5_end_buffer_io(sh, i, 0); + continue; + } + } + if (sh->cmd == STRIPE_SYNC) + md_done_sync(conf->mddev, (sh->size>>10) - sh->sync_redone,1); + finish_unlock_stripe(sh); + return; + } + + PRINTK("=== stripe index START ===\n"); + for (i = 0; i < disks; i++) { + PRINTK("disk %d, ", i); + if (sh->bh_old[i]) { + nr_cache++; + PRINTK(" (old cached, %d)", nr_cache); + } + if (i == sh->pd_idx) { + PRINTK(" PARITY."); + if (sh->bh_old[i]) { + PRINTK(" CACHED."); + parity = 1; + } else { + PRINTK(" UNCACHED."); + if (!operational[i]) { + PRINTK(" FAILED."); + parity_failed = 1; + } + } + PRINTK("\n"); + continue; + } + if (!sh->bh_new[i]) { + PRINTK(" (no new data block) "); + if (sh->bh_old[i]) { + PRINTK(" (but old block cached) "); + nr_cache_other++; + } else { + if (!operational[i]) { + PRINTK(" (because failed disk) "); + nr_failed_other++; + } else + PRINTK(" (no old block either) "); + } + PRINTK("\n"); + continue; + } + sh->new[i] = 0; + if (sh->cmd_new[i] == READ) { + nr_read++; + PRINTK(" (new READ %d)", nr_read); + } + if (sh->cmd_new[i] == WRITE) { + nr_write++; + PRINTK(" (new WRITE %d)", nr_write); + } + if (sh->bh_old[i]) { + nr_cache_overwrite++; + PRINTK(" (overwriting old %d)", nr_cache_overwrite); + } else { + if (!operational[i]) { + nr_failed_overwrite++; + PRINTK(" (overwriting failed %d)", nr_failed_overwrite); + } + } + PRINTK("\n"); + } + PRINTK("=== stripe index END ===\n"); + + if (nr_write && nr_read) + BUG(); + + if (nr_write) + handle_stripe_write( + mddev, conf, sh, nr_write, operational, disks, + parity, parity_failed, nr_cache, nr_cache_other, + nr_failed_other, nr_cache_overwrite, + nr_failed_overwrite + ); + else if (nr_read) + handle_stripe_read( + mddev, conf, sh, nr_read, operational, disks, + parity, parity_failed, nr_cache, nr_cache_other, + nr_failed_other, nr_cache_overwrite, + nr_failed_overwrite + ); + else if (sh->cmd == STRIPE_SYNC) + handle_stripe_sync( + mddev, conf, sh, operational, disks, + parity, parity_failed, nr_cache, nr_cache_other, + nr_failed_other, nr_cache_overwrite, nr_failed_overwrite + ); +} + + +static int raid5_make_request (mddev_t *mddev, int rw, struct buffer_head * bh) +{ + raid5_conf_t *conf = (raid5_conf_t *) mddev->private; + const unsigned int raid_disks = conf->raid_disks; + const unsigned int data_disks = raid_disks - 1; + unsigned int dd_idx, pd_idx; + unsigned long new_sector; + + struct stripe_head *sh; + + if (rw == READA) + rw = READ; + + new_sector = raid5_compute_sector(bh->b_rsector, + raid_disks, data_disks, &dd_idx, &pd_idx, conf); + + PRINTK("raid5_make_request, sector %lu\n", new_sector); + sh = get_lock_stripe(conf, new_sector, bh->b_size); +#if 0 + if ((rw == READ && sh->cmd == STRIPE_WRITE) || (rw == WRITE && sh->cmd == STRIPE_READ)) { + PRINTK("raid5: lock contention, rw == %d, sh->cmd == %d\n", rw, sh->cmd); + lock_stripe(sh); + if (!md_atomic_read(&sh->nr_pending)) + handle_stripe(sh); + goto repeat; + } +#endif + sh->pd_idx = pd_idx; + if (sh->phase != PHASE_COMPLETE && sh->phase != PHASE_BEGIN) + PRINTK("stripe %lu catching the bus!\n", sh->sector); + if (sh->bh_new[dd_idx]) + BUG(); + add_stripe_bh(sh, bh, dd_idx, rw); + + md_wakeup_thread(conf->thread); + return 0; +} + +/* + * Determine correct block size for this device. + */ +unsigned int device_bsize (kdev_t dev) +{ + unsigned int i, correct_size; + + correct_size = BLOCK_SIZE; + if (blksize_size[MAJOR(dev)]) { + i = blksize_size[MAJOR(dev)][MINOR(dev)]; + if (i) + correct_size = i; + } + + return correct_size; +} + +static int raid5_sync_request (mddev_t *mddev, unsigned long block_nr) +{ + raid5_conf_t *conf = (raid5_conf_t *) mddev->private; + struct stripe_head *sh; + int sectors_per_chunk = conf->chunk_size >> 9; + unsigned long stripe = (block_nr<<2)/sectors_per_chunk; + int chunk_offset = (block_nr<<2) % sectors_per_chunk; + int dd_idx, pd_idx; + unsigned long first_sector; + int raid_disks = conf->raid_disks; + int data_disks = raid_disks-1; + int redone = 0; + int bufsize; + + if (!conf->buffer_size) + conf->buffer_size = /* device_bsize(mddev_to_kdev(mddev))*/ PAGE_SIZE; + bufsize = conf->buffer_size; + /* Hmm... race on buffer_size ?? */ + redone = block_nr% (bufsize>>10); + block_nr -= redone; + sh = get_lock_stripe(conf, block_nr<<1, bufsize); + first_sector = raid5_compute_sector(stripe*data_disks*sectors_per_chunk + + chunk_offset, raid_disks, data_disks, &dd_idx, &pd_idx, conf); + sh->pd_idx = pd_idx; + sh->cmd = STRIPE_SYNC; + sh->phase = PHASE_BEGIN; + sh->sync_redone = redone; + atomic_inc(&conf->nr_pending_stripes); + atomic_inc(&conf->nr_handle); + md_wakeup_thread(conf->thread); + return (bufsize>>10)-redone; +} + +/* + * This is our raid5 kernel thread. + * + * We scan the hash table for stripes which can be handled now. + * During the scan, completed stripes are saved for us by the interrupt + * handler, so that they will not have to wait for our next wakeup. + */ +static void raid5d (void *data) +{ + struct stripe_head *sh; + raid5_conf_t *conf = data; + mddev_t *mddev = conf->mddev; + int i, handled; + + PRINTK("+++ raid5d active\n"); + + handled = 0; + md_spin_lock_irq(&conf->device_lock); + clear_bit(THREAD_WAKEUP, &conf->thread->flags); +repeat_pass: + if (mddev->sb_dirty) { + md_spin_unlock_irq(&conf->device_lock); + mddev->sb_dirty = 0; + md_update_sb(mddev); + md_spin_lock_irq(&conf->device_lock); + } + for (i = 0; i < NR_HASH; i++) { +repeat: + sh = conf->stripe_hashtbl[i]; + for (; sh; sh = sh->hash_next) { + if (sh->raid_conf != conf) + continue; + if (sh->phase == PHASE_COMPLETE) + continue; + if (md_atomic_read(&sh->nr_pending)) + continue; + md_spin_unlock_irq(&conf->device_lock); + if (!atomic_read(&sh->count)) + BUG(); + + handled++; + handle_stripe(sh); + md_spin_lock_irq(&conf->device_lock); + goto repeat; + } + } + if (conf) { + PRINTK("%d stripes handled, nr_handle %d\n", handled, md_atomic_read(&conf->nr_handle)); + if (test_and_clear_bit(THREAD_WAKEUP, &conf->thread->flags) && + md_atomic_read(&conf->nr_handle)) + goto repeat_pass; + } + md_spin_unlock_irq(&conf->device_lock); + + PRINTK("--- raid5d inactive\n"); +} + +/* + * Private kernel thread for parity reconstruction after an unclean + * shutdown. Reconstruction on spare drives in case of a failed drive + * is done by the generic mdsyncd. + */ +static void raid5syncd (void *data) +{ + raid5_conf_t *conf = data; + mddev_t *mddev = conf->mddev; + + if (!conf->resync_parity) + return; + if (conf->resync_parity == 2) + return; + down(&mddev->recovery_sem); + if (md_do_sync(mddev,NULL)) { + up(&mddev->recovery_sem); + printk("raid5: resync aborted!\n"); + return; + } + conf->resync_parity = 0; + up(&mddev->recovery_sem); + printk("raid5: resync finished.\n"); +} + +static int __check_consistency (mddev_t *mddev, int row) +{ + raid5_conf_t *conf = mddev->private; + kdev_t dev; + struct buffer_head *bh[MD_SB_DISKS], *tmp = NULL; + int i, ret = 0, nr = 0, count; + struct buffer_head *bh_ptr[MAX_XOR_BLOCKS]; + + if (conf->working_disks != conf->raid_disks) + goto out; + tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); + tmp->b_size = 4096; + tmp->b_page = alloc_page(GFP_KERNEL); + tmp->b_data = page_address(tmp->b_page); + if (!tmp->b_data) + goto out; + md_clear_page(tmp->b_data); + memset(bh, 0, MD_SB_DISKS * sizeof(struct buffer_head *)); + for (i = 0; i < conf->raid_disks; i++) { + dev = conf->disks[i].dev; + set_blocksize(dev, 4096); + bh[i] = bread(dev, row / 4, 4096); + if (!bh[i]) + break; + nr++; + } + if (nr == conf->raid_disks) { + bh_ptr[0] = tmp; + count = 1; + for (i = 1; i < nr; i++) { + bh_ptr[count++] = bh[i]; + if (count == MAX_XOR_BLOCKS) { + xor_block(count, &bh_ptr[0]); + count = 1; + } + } + if (count != 1) { + xor_block(count, &bh_ptr[0]); + } + if (memcmp(tmp->b_data, bh[0]->b_data, 4096)) + ret = 1; + } + for (i = 0; i < conf->raid_disks; i++) { + dev = conf->disks[i].dev; + if (bh[i]) { + bforget(bh[i]); + bh[i] = NULL; + } + fsync_dev(dev); + invalidate_buffers(dev); + } + free_page((unsigned long) tmp->b_data); +out: + if (tmp) + kfree(tmp); + return ret; +} + +static int check_consistency (mddev_t *mddev) +{ + if (__check_consistency(mddev, 0)) +/* + * We are not checking this currently, as it's legitimate to have + * an inconsistent array, at creation time. + */ + return 0; + + return 0; +} + +static int raid5_run (mddev_t *mddev) +{ + raid5_conf_t *conf; + int i, j, raid_disk, memory; + mdp_super_t *sb = mddev->sb; + mdp_disk_t *desc; + mdk_rdev_t *rdev; + struct disk_info *disk; + struct md_list_head *tmp; + int start_recovery = 0; + + MOD_INC_USE_COUNT; + + if (sb->level != 5 && sb->level != 4) { + printk("raid5: md%d: raid level not set to 4/5 (%d)\n", mdidx(mddev), sb->level); + MOD_DEC_USE_COUNT; + return -EIO; + } + + mddev->private = kmalloc (sizeof (raid5_conf_t), GFP_KERNEL); + if ((conf = mddev->private) == NULL) + goto abort; + memset (conf, 0, sizeof (*conf)); + conf->mddev = mddev; + + if ((conf->stripe_hashtbl = (struct stripe_head **) md__get_free_pages(GFP_ATOMIC, HASH_PAGES_ORDER)) == NULL) + goto abort; + memset(conf->stripe_hashtbl, 0, HASH_PAGES * PAGE_SIZE); + + conf->device_lock = MD_SPIN_LOCK_UNLOCKED; + md_init_waitqueue_head(&conf->wait_for_stripe); + PRINTK("raid5_run(md%d) called.\n", mdidx(mddev)); + + ITERATE_RDEV(mddev,rdev,tmp) { + /* + * This is important -- we are using the descriptor on + * the disk only to get a pointer to the descriptor on + * the main superblock, which might be more recent. + */ + desc = sb->disks + rdev->desc_nr; + raid_disk = desc->raid_disk; + disk = conf->disks + raid_disk; + + if (disk_faulty(desc)) { + printk(KERN_ERR "raid5: disabled device %s (errors detected)\n", partition_name(rdev->dev)); + if (!rdev->faulty) { + MD_BUG(); + goto abort; + } + disk->number = desc->number; + disk->raid_disk = raid_disk; + disk->dev = rdev->dev; + + disk->operational = 0; + disk->write_only = 0; + disk->spare = 0; + disk->used_slot = 1; + continue; + } + if (disk_active(desc)) { + if (!disk_sync(desc)) { + printk(KERN_ERR "raid5: disabled device %s (not in sync)\n", partition_name(rdev->dev)); + MD_BUG(); + goto abort; + } + if (raid_disk > sb->raid_disks) { + printk(KERN_ERR "raid5: disabled device %s (inconsistent descriptor)\n", partition_name(rdev->dev)); + continue; + } + if (disk->operational) { + printk(KERN_ERR "raid5: disabled device %s (device %d already operational)\n", partition_name(rdev->dev), raid_disk); + continue; + } + printk(KERN_INFO "raid5: device %s operational as raid disk %d\n", partition_name(rdev->dev), raid_disk); + + disk->number = desc->number; + disk->raid_disk = raid_disk; + disk->dev = rdev->dev; + disk->operational = 1; + disk->used_slot = 1; + + conf->working_disks++; + } else { + /* + * Must be a spare disk .. + */ + printk(KERN_INFO "raid5: spare disk %s\n", partition_name(rdev->dev)); + disk->number = desc->number; + disk->raid_disk = raid_disk; + disk->dev = rdev->dev; + + disk->operational = 0; + disk->write_only = 0; + disk->spare = 1; + disk->used_slot = 1; + } + } + + for (i = 0; i < MD_SB_DISKS; i++) { + desc = sb->disks + i; + raid_disk = desc->raid_disk; + disk = conf->disks + raid_disk; + + if (disk_faulty(desc) && (raid_disk < sb->raid_disks) && + !conf->disks[raid_disk].used_slot) { + + disk->number = desc->number; + disk->raid_disk = raid_disk; + disk->dev = MKDEV(0,0); + + disk->operational = 0; + disk->write_only = 0; + disk->spare = 0; + disk->used_slot = 1; + } + } + + conf->raid_disks = sb->raid_disks; + /* + * 0 for a fully functional array, 1 for a degraded array. + */ + conf->failed_disks = conf->raid_disks - conf->working_disks; + conf->mddev = mddev; + conf->chunk_size = sb->chunk_size; + conf->level = sb->level; + conf->algorithm = sb->layout; + conf->max_nr_stripes = NR_STRIPES; + +#if 0 + for (i = 0; i < conf->raid_disks; i++) { + if (!conf->disks[i].used_slot) { + MD_BUG(); + goto abort; + } + } +#endif + if (!conf->chunk_size || conf->chunk_size % 4) { + printk(KERN_ERR "raid5: invalid chunk size %d for md%d\n", conf->chunk_size, mdidx(mddev)); + goto abort; + } + if (conf->algorithm > ALGORITHM_RIGHT_SYMMETRIC) { + printk(KERN_ERR "raid5: unsupported parity algorithm %d for md%d\n", conf->algorithm, mdidx(mddev)); + goto abort; + } + if (conf->failed_disks > 1) { + printk(KERN_ERR "raid5: not enough operational devices for md%d (%d/%d failed)\n", mdidx(mddev), conf->failed_disks, conf->raid_disks); + goto abort; + } + + if (conf->working_disks != sb->raid_disks) { + printk(KERN_ALERT "raid5: md%d, not all disks are operational -- trying to recover array\n", mdidx(mddev)); + start_recovery = 1; + } + + if (!start_recovery && (sb->state & (1 << MD_SB_CLEAN)) && + check_consistency(mddev)) { + printk(KERN_ERR "raid5: detected raid-5 superblock xor inconsistency -- running resync\n"); + sb->state &= ~(1 << MD_SB_CLEAN); + } + + { + const char * name = "raid5d"; + + conf->thread = md_register_thread(raid5d, conf, name); + if (!conf->thread) { + printk(KERN_ERR "raid5: couldn't allocate thread for md%d\n", mdidx(mddev)); + goto abort; + } + } + + memory = conf->max_nr_stripes * (sizeof(struct stripe_head) + + conf->raid_disks * (sizeof(struct buffer_head) + + 2 * (sizeof(struct buffer_head) + PAGE_SIZE))) / 1024; + if (grow_stripes(conf, conf->max_nr_stripes, GFP_KERNEL)) { + printk(KERN_ERR "raid5: couldn't allocate %dkB for buffers\n", memory); + shrink_stripes(conf, conf->max_nr_stripes); + goto abort; + } else + printk(KERN_INFO "raid5: allocated %dkB for md%d\n", memory, mdidx(mddev)); + + /* + * Regenerate the "device is in sync with the raid set" bit for + * each device. + */ + for (i = 0; i < MD_SB_DISKS ; i++) { + mark_disk_nonsync(sb->disks + i); + for (j = 0; j < sb->raid_disks; j++) { + if (!conf->disks[j].operational) + continue; + if (sb->disks[i].number == conf->disks[j].number) + mark_disk_sync(sb->disks + i); + } + } + sb->active_disks = conf->working_disks; + + if (sb->active_disks == sb->raid_disks) + printk("raid5: raid level %d set md%d active with %d out of %d devices, algorithm %d\n", conf->level, mdidx(mddev), sb->active_disks, sb->raid_disks, conf->algorithm); + else + printk(KERN_ALERT "raid5: raid level %d set md%d active with %d out of %d devices, algorithm %d\n", conf->level, mdidx(mddev), sb->active_disks, sb->raid_disks, conf->algorithm); + + if (!start_recovery && !(sb->state & (1 << MD_SB_CLEAN))) { + const char * name = "raid5syncd"; + + conf->resync_thread = md_register_thread(raid5syncd, conf,name); + if (!conf->resync_thread) { + printk(KERN_ERR "raid5: couldn't allocate thread for md%d\n", mdidx(mddev)); + goto abort; + } + + printk("raid5: raid set md%d not clean; reconstructing parity\n", mdidx(mddev)); + conf->resync_parity = 1; + md_wakeup_thread(conf->resync_thread); + } + + print_raid5_conf(conf); + if (start_recovery) + md_recover_arrays(); + print_raid5_conf(conf); + + /* Ok, everything is just fine now */ + return (0); +abort: + if (conf) { + print_raid5_conf(conf); + if (conf->stripe_hashtbl) + free_pages((unsigned long) conf->stripe_hashtbl, + HASH_PAGES_ORDER); + kfree(conf); + } + mddev->private = NULL; + printk(KERN_ALERT "raid5: failed to run raid set md%d\n", mdidx(mddev)); + MOD_DEC_USE_COUNT; + return -EIO; +} + +static int raid5_stop_resync (mddev_t *mddev) +{ + raid5_conf_t *conf = mddev_to_conf(mddev); + mdk_thread_t *thread = conf->resync_thread; + + if (thread) { + if (conf->resync_parity) { + conf->resync_parity = 2; + md_interrupt_thread(thread); + printk(KERN_INFO "raid5: parity resync was not fully finished, restarting next time.\n"); + return 1; + } + return 0; + } + return 0; +} + +static int raid5_restart_resync (mddev_t *mddev) +{ + raid5_conf_t *conf = mddev_to_conf(mddev); + + if (conf->resync_parity) { + if (!conf->resync_thread) { + MD_BUG(); + return 0; + } + printk("raid5: waking up raid5resync.\n"); + conf->resync_parity = 1; + md_wakeup_thread(conf->resync_thread); + return 1; + } else + printk("raid5: no restart-resync needed.\n"); + return 0; +} + + +static int raid5_stop (mddev_t *mddev) +{ + raid5_conf_t *conf = (raid5_conf_t *) mddev->private; + + shrink_stripe_cache(conf, conf->max_nr_stripes); + shrink_stripes(conf, conf->max_nr_stripes); + md_unregister_thread(conf->thread); + if (conf->resync_thread) + md_unregister_thread(conf->resync_thread); + free_pages((unsigned long) conf->stripe_hashtbl, HASH_PAGES_ORDER); + kfree(conf); + mddev->private = NULL; + MOD_DEC_USE_COUNT; + return 0; +} + +#if RAID5_DEBUG +static void print_sh (struct stripe_head *sh) +{ + int i; + + printk("sh %lu, phase %d, size %d, pd_idx %d, state %ld, cmd %d.\n", sh->sector, sh->phase, sh->size, sh->pd_idx, sh->state, sh->cmd); + printk("sh %lu, write_method %d, nr_pending %d, count %d.\n", sh->sector, sh->write_method, atomic_read(&sh->nr_pending), atomic_read(&sh->count)); + printk("sh %lu, ", sh->sector); + for (i = 0; i < MD_SB_DISKS; i++) { + if (sh->bh_old[i]) + printk("(old%d: %p) ", i, sh->bh_old[i]); + if (sh->bh_new[i]) + printk("(new%d: %p) ", i, sh->bh_new[i]); + if (sh->bh_copy[i]) + printk("(copy%d: %p) ", i, sh->bh_copy[i]); + if (sh->bh_req[i]) + printk("(req%d: %p) ", i, sh->bh_req[i]); + } + printk("\n"); + for (i = 0; i < MD_SB_DISKS; i++) + printk("%d(%d/%d) ", i, sh->cmd_new[i], sh->new[i]); + printk("\n"); +} + +static void printall (raid5_conf_t *conf) +{ + struct stripe_head *sh; + int i; + + md_spin_lock_irq(&conf->device_lock); + for (i = 0; i < NR_HASH; i++) { + sh = conf->stripe_hashtbl[i]; + for (; sh; sh = sh->hash_next) { + if (sh->raid_conf != conf) + continue; + print_sh(sh); + } + } + md_spin_unlock_irq(&conf->device_lock); + + PRINTK("--- raid5d inactive\n"); +} +#endif + +static int raid5_status (char *page, mddev_t *mddev) +{ + raid5_conf_t *conf = (raid5_conf_t *) mddev->private; + mdp_super_t *sb = mddev->sb; + int sz = 0, i; + + sz += sprintf (page+sz, " level %d, %dk chunk, algorithm %d", sb->level, sb->chunk_size >> 10, sb->layout); + sz += sprintf (page+sz, " [%d/%d] [", conf->raid_disks, conf->working_disks); + for (i = 0; i < conf->raid_disks; i++) + sz += sprintf (page+sz, "%s", conf->disks[i].operational ? "U" : "_"); + sz += sprintf (page+sz, "]"); +#if RAID5_DEBUG +#define D(x) \ + sz += sprintf (page+sz, "<"#x":%d>", atomic_read(&conf->x)) + D(nr_handle); + D(nr_stripes); + D(nr_hashed_stripes); + D(nr_locked_stripes); + D(nr_pending_stripes); + D(nr_cached_stripes); + D(nr_free_sh); + printall(conf); +#endif + return sz; +} + +static void print_raid5_conf (raid5_conf_t *conf) +{ + int i; + struct disk_info *tmp; + + printk("RAID5 conf printout:\n"); + if (!conf) { + printk("(conf==NULL)\n"); + return; + } + printk(" --- rd:%d wd:%d fd:%d\n", conf->raid_disks, + conf->working_disks, conf->failed_disks); + + for (i = 0; i < MD_SB_DISKS; i++) { + tmp = conf->disks + i; + printk(" disk %d, s:%d, o:%d, n:%d rd:%d us:%d dev:%s\n", + i, tmp->spare,tmp->operational, + tmp->number,tmp->raid_disk,tmp->used_slot, + partition_name(tmp->dev)); + } +} + +static int raid5_diskop(mddev_t *mddev, mdp_disk_t **d, int state) +{ + int err = 0; + int i, failed_disk=-1, spare_disk=-1, removed_disk=-1, added_disk=-1; + raid5_conf_t *conf = mddev->private; + struct disk_info *tmp, *sdisk, *fdisk, *rdisk, *adisk; + mdp_super_t *sb = mddev->sb; + mdp_disk_t *failed_desc, *spare_desc, *added_desc; + + print_raid5_conf(conf); + md_spin_lock_irq(&conf->device_lock); + /* + * find the disk ... + */ + switch (state) { + + case DISKOP_SPARE_ACTIVE: + + /* + * Find the failed disk within the RAID5 configuration ... + * (this can only be in the first conf->raid_disks part) + */ + for (i = 0; i < conf->raid_disks; i++) { + tmp = conf->disks + i; + if ((!tmp->operational && !tmp->spare) || + !tmp->used_slot) { + failed_disk = i; + break; + } + } + /* + * When we activate a spare disk we _must_ have a disk in + * the lower (active) part of the array to replace. + */ + if ((failed_disk == -1) || (failed_disk >= conf->raid_disks)) { + MD_BUG(); + err = 1; + goto abort; + } + /* fall through */ + + case DISKOP_SPARE_WRITE: + case DISKOP_SPARE_INACTIVE: + + /* + * Find the spare disk ... (can only be in the 'high' + * area of the array) + */ + for (i = conf->raid_disks; i < MD_SB_DISKS; i++) { + tmp = conf->disks + i; + if (tmp->spare && tmp->number == (*d)->number) { + spare_disk = i; + break; + } + } + if (spare_disk == -1) { + MD_BUG(); + err = 1; + goto abort; + } + break; + + case DISKOP_HOT_REMOVE_DISK: + + for (i = 0; i < MD_SB_DISKS; i++) { + tmp = conf->disks + i; + if (tmp->used_slot && (tmp->number == (*d)->number)) { + if (tmp->operational) { + err = -EBUSY; + goto abort; + } + removed_disk = i; + break; + } + } + if (removed_disk == -1) { + MD_BUG(); + err = 1; + goto abort; + } + break; + + case DISKOP_HOT_ADD_DISK: + + for (i = conf->raid_disks; i < MD_SB_DISKS; i++) { + tmp = conf->disks + i; + if (!tmp->used_slot) { + added_disk = i; + break; + } + } + if (added_disk == -1) { + MD_BUG(); + err = 1; + goto abort; + } + break; + } + + switch (state) { + /* + * Switch the spare disk to write-only mode: + */ + case DISKOP_SPARE_WRITE: + if (conf->spare) { + MD_BUG(); + err = 1; + goto abort; + } + sdisk = conf->disks + spare_disk; + sdisk->operational = 1; + sdisk->write_only = 1; + conf->spare = sdisk; + break; + /* + * Deactivate a spare disk: + */ + case DISKOP_SPARE_INACTIVE: + sdisk = conf->disks + spare_disk; + sdisk->operational = 0; + sdisk->write_only = 0; + /* + * Was the spare being resynced? + */ + if (conf->spare == sdisk) + conf->spare = NULL; + break; + /* + * Activate (mark read-write) the (now sync) spare disk, + * which means we switch it's 'raid position' (->raid_disk) + * with the failed disk. (only the first 'conf->raid_disks' + * slots are used for 'real' disks and we must preserve this + * property) + */ + case DISKOP_SPARE_ACTIVE: + if (!conf->spare) { + MD_BUG(); + err = 1; + goto abort; + } + sdisk = conf->disks + spare_disk; + fdisk = conf->disks + failed_disk; + + spare_desc = &sb->disks[sdisk->number]; + failed_desc = &sb->disks[fdisk->number]; + + if (spare_desc != *d) { + MD_BUG(); + err = 1; + goto abort; + } + + if (spare_desc->raid_disk != sdisk->raid_disk) { + MD_BUG(); + err = 1; + goto abort; + } + + if (sdisk->raid_disk != spare_disk) { + MD_BUG(); + err = 1; + goto abort; + } + + if (failed_desc->raid_disk != fdisk->raid_disk) { + MD_BUG(); + err = 1; + goto abort; + } + + if (fdisk->raid_disk != failed_disk) { + MD_BUG(); + err = 1; + goto abort; + } + + /* + * do the switch finally + */ + xchg_values(*spare_desc, *failed_desc); + xchg_values(*fdisk, *sdisk); + + /* + * (careful, 'failed' and 'spare' are switched from now on) + * + * we want to preserve linear numbering and we want to + * give the proper raid_disk number to the now activated + * disk. (this means we switch back these values) + */ + + xchg_values(spare_desc->raid_disk, failed_desc->raid_disk); + xchg_values(sdisk->raid_disk, fdisk->raid_disk); + xchg_values(spare_desc->number, failed_desc->number); + xchg_values(sdisk->number, fdisk->number); + + *d = failed_desc; + + if (sdisk->dev == MKDEV(0,0)) + sdisk->used_slot = 0; + + /* + * this really activates the spare. + */ + fdisk->spare = 0; + fdisk->write_only = 0; + + /* + * if we activate a spare, we definitely replace a + * non-operational disk slot in the 'low' area of + * the disk array. + */ + conf->failed_disks--; + conf->working_disks++; + conf->spare = NULL; + + break; + + case DISKOP_HOT_REMOVE_DISK: + rdisk = conf->disks + removed_disk; + + if (rdisk->spare && (removed_disk < conf->raid_disks)) { + MD_BUG(); + err = 1; + goto abort; + } + rdisk->dev = MKDEV(0,0); + rdisk->used_slot = 0; + + break; + + case DISKOP_HOT_ADD_DISK: + adisk = conf->disks + added_disk; + added_desc = *d; + + if (added_disk != added_desc->number) { + MD_BUG(); + err = 1; + goto abort; + } + + adisk->number = added_desc->number; + adisk->raid_disk = added_desc->raid_disk; + adisk->dev = MKDEV(added_desc->major,added_desc->minor); + + adisk->operational = 0; + adisk->write_only = 0; + adisk->spare = 1; + adisk->used_slot = 1; + + + break; + + default: + MD_BUG(); + err = 1; + goto abort; + } +abort: + md_spin_unlock_irq(&conf->device_lock); + print_raid5_conf(conf); + return err; +} + +static mdk_personality_t raid5_personality= +{ + name: "raid5", + make_request: raid5_make_request, + run: raid5_run, + stop: raid5_stop, + status: raid5_status, + error_handler: raid5_error, + diskop: raid5_diskop, + stop_resync: raid5_stop_resync, + restart_resync: raid5_restart_resync, + sync_request: raid5_sync_request +}; + +int raid5_init (void) +{ + int err; + + err = register_md_personality (RAID5, &raid5_personality); + if (err) + return err; + + /* + * pick a XOR routine, runtime. + */ + calibrate_xor_block(); + + return 0; +} + +#ifdef MODULE +int init_module (void) +{ + return raid5_init(); +} + +void cleanup_module (void) +{ + unregister_md_personality (RAID5); +} +#endif diff -u --recursive --new-file v2.4.0-test8/linux/drivers/md/xor.c linux/drivers/md/xor.c --- v2.4.0-test8/linux/drivers/md/xor.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/md/xor.c Mon Aug 28 21:21:57 2000 @@ -0,0 +1,2728 @@ +/* + * xor.c : Multiple Devices driver for Linux + * + * Copyright (C) 1996, 1997, 1998, 1999 Ingo Molnar, Matti Aarnio, Jakub Jelinek + * + * + * optimized RAID-5 checksumming functions. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * You should have received a copy of the GNU General Public License + * (for example /usr/src/linux/COPYING); if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#define BH_TRACE 0 +#include +#include +#ifdef __sparc_v9__ +#include +#include +#include +#endif + +/* + * we use the 'XOR function template' to register multiple xor + * functions runtime. The kernel measures their speed upon bootup + * and decides which one to use. (compile-time registration is + * not enough as certain CPU features like MMX can only be detected + * runtime) + * + * this architecture makes it pretty easy to add new routines + * that are faster on certain CPUs, without killing other CPU's + * 'native' routine. Although the current routines are belived + * to be the physically fastest ones on all CPUs tested, but + * feel free to prove me wrong and add yet another routine =B-) + * --mingo + */ + +#define MAX_XOR_BLOCKS 5 + +#define XOR_ARGS (unsigned int count, struct buffer_head **bh_ptr) + +typedef void (*xor_block_t) XOR_ARGS; +xor_block_t xor_block = NULL; + +#ifndef __sparc_v9__ + +struct xor_block_template; + +struct xor_block_template { + char * name; + xor_block_t xor_block; + int speed; + struct xor_block_template * next; +}; + +struct xor_block_template * xor_functions = NULL; + +#define XORBLOCK_TEMPLATE(x) \ +static void xor_block_##x XOR_ARGS; \ +static struct xor_block_template t_xor_block_##x = \ + { #x, xor_block_##x, 0, NULL }; \ +static void xor_block_##x XOR_ARGS + +#ifdef __i386__ + +#ifdef CONFIG_X86_XMM +/* + * Cache avoiding checksumming functions utilizing KNI instructions + * Copyright (C) 1999 Zach Brown (with obvious credit due Ingo) + */ + +XORBLOCK_TEMPLATE(pIII_kni) +{ + char xmm_save[16*4]; + int cr0; + int lines = (bh_ptr[0]->b_size>>8); + + __asm__ __volatile__ ( + "movl %%cr0,%0 ;\n\t" + "clts ;\n\t" + "movups %%xmm0,(%1) ;\n\t" + "movups %%xmm1,0x10(%1) ;\n\t" + "movups %%xmm2,0x20(%1) ;\n\t" + "movups %%xmm3,0x30(%1) ;\n\t" + : "=r" (cr0) + : "r" (xmm_save) + : "memory" ); + +#define OFFS(x) "8*("#x"*2)" +#define PF0(x) \ + " prefetcht0 "OFFS(x)"(%1) ;\n" +#define LD(x,y) \ + " movaps "OFFS(x)"(%1), %%xmm"#y" ;\n" +#define ST(x,y) \ + " movaps %%xmm"#y", "OFFS(x)"(%1) ;\n" +#define PF1(x) \ + " prefetchnta "OFFS(x)"(%2) ;\n" +#define PF2(x) \ + " prefetchnta "OFFS(x)"(%3) ;\n" +#define PF3(x) \ + " prefetchnta "OFFS(x)"(%4) ;\n" +#define PF4(x) \ + " prefetchnta "OFFS(x)"(%5) ;\n" +#define PF5(x) \ + " prefetchnta "OFFS(x)"(%6) ;\n" +#define XO1(x,y) \ + " xorps "OFFS(x)"(%2), %%xmm"#y" ;\n" +#define XO2(x,y) \ + " xorps "OFFS(x)"(%3), %%xmm"#y" ;\n" +#define XO3(x,y) \ + " xorps "OFFS(x)"(%4), %%xmm"#y" ;\n" +#define XO4(x,y) \ + " xorps "OFFS(x)"(%5), %%xmm"#y" ;\n" +#define XO5(x,y) \ + " xorps "OFFS(x)"(%6), %%xmm"#y" ;\n" + + switch(count) { + case 2: + __asm__ __volatile__ ( +#undef BLOCK +#define BLOCK(i) \ + LD(i,0) \ + LD(i+1,1) \ + PF1(i) \ + PF1(i+2) \ + LD(i+2,2) \ + LD(i+3,3) \ + PF0(i+4) \ + PF0(i+6) \ + XO1(i,0) \ + XO1(i+1,1) \ + XO1(i+2,2) \ + XO1(i+3,3) \ + ST(i,0) \ + ST(i+1,1) \ + ST(i+2,2) \ + ST(i+3,3) \ + + + PF0(0) + PF0(2) + + " .align 32,0x90 ;\n" + " 1: ;\n" + + BLOCK(0) + BLOCK(4) + BLOCK(8) + BLOCK(12) + + " addl $256, %1 ;\n" + " addl $256, %2 ;\n" + " decl %0 ;\n" + " jnz 1b ;\n" + + : + : "r" (lines), + "r" (bh_ptr[0]->b_data), + "r" (bh_ptr[1]->b_data) + : "memory" ); + break; + case 3: + __asm__ __volatile__ ( +#undef BLOCK +#define BLOCK(i) \ + PF1(i) \ + PF1(i+2) \ + LD(i,0) \ + LD(i+1,1) \ + LD(i+2,2) \ + LD(i+3,3) \ + PF2(i) \ + PF2(i+2) \ + PF0(i+4) \ + PF0(i+6) \ + XO1(i,0) \ + XO1(i+1,1) \ + XO1(i+2,2) \ + XO1(i+3,3) \ + XO2(i,0) \ + XO2(i+1,1) \ + XO2(i+2,2) \ + XO2(i+3,3) \ + ST(i,0) \ + ST(i+1,1) \ + ST(i+2,2) \ + ST(i+3,3) \ + + + PF0(0) + PF0(2) + + " .align 32,0x90 ;\n" + " 1: ;\n" + + BLOCK(0) + BLOCK(4) + BLOCK(8) + BLOCK(12) + + " addl $256, %1 ;\n" + " addl $256, %2 ;\n" + " addl $256, %3 ;\n" + " decl %0 ;\n" + " jnz 1b ;\n" + : + : "r" (lines), + "r" (bh_ptr[0]->b_data), + "r" (bh_ptr[1]->b_data), + "r" (bh_ptr[2]->b_data) + : "memory" ); + break; + case 4: + __asm__ __volatile__ ( +#undef BLOCK +#define BLOCK(i) \ + PF1(i) \ + PF1(i+2) \ + LD(i,0) \ + LD(i+1,1) \ + LD(i+2,2) \ + LD(i+3,3) \ + PF2(i) \ + PF2(i+2) \ + XO1(i,0) \ + XO1(i+1,1) \ + XO1(i+2,2) \ + XO1(i+3,3) \ + PF3(i) \ + PF3(i+2) \ + PF0(i+4) \ + PF0(i+6) \ + XO2(i,0) \ + XO2(i+1,1) \ + XO2(i+2,2) \ + XO2(i+3,3) \ + XO3(i,0) \ + XO3(i+1,1) \ + XO3(i+2,2) \ + XO3(i+3,3) \ + ST(i,0) \ + ST(i+1,1) \ + ST(i+2,2) \ + ST(i+3,3) \ + + + PF0(0) + PF0(2) + + " .align 32,0x90 ;\n" + " 1: ;\n" + + BLOCK(0) + BLOCK(4) + BLOCK(8) + BLOCK(12) + + " addl $256, %1 ;\n" + " addl $256, %2 ;\n" + " addl $256, %3 ;\n" + " addl $256, %4 ;\n" + " decl %0 ;\n" + " jnz 1b ;\n" + + : + : "r" (lines), + "r" (bh_ptr[0]->b_data), + "r" (bh_ptr[1]->b_data), + "r" (bh_ptr[2]->b_data), + "r" (bh_ptr[3]->b_data) + : "memory" ); + break; + case 5: + __asm__ __volatile__ ( +#undef BLOCK +#define BLOCK(i) \ + PF1(i) \ + PF1(i+2) \ + LD(i,0) \ + LD(i+1,1) \ + LD(i+2,2) \ + LD(i+3,3) \ + PF2(i) \ + PF2(i+2) \ + XO1(i,0) \ + XO1(i+1,1) \ + XO1(i+2,2) \ + XO1(i+3,3) \ + PF3(i) \ + PF3(i+2) \ + XO2(i,0) \ + XO2(i+1,1) \ + XO2(i+2,2) \ + XO2(i+3,3) \ + PF4(i) \ + PF4(i+2) \ + PF0(i+4) \ + PF0(i+6) \ + XO3(i,0) \ + XO3(i+1,1) \ + XO3(i+2,2) \ + XO3(i+3,3) \ + XO4(i,0) \ + XO4(i+1,1) \ + XO4(i+2,2) \ + XO4(i+3,3) \ + ST(i,0) \ + ST(i+1,1) \ + ST(i+2,2) \ + ST(i+3,3) \ + + + PF0(0) + PF0(2) + + " .align 32,0x90 ;\n" + " 1: ;\n" + + BLOCK(0) + BLOCK(4) + BLOCK(8) + BLOCK(12) + + " addl $256, %1 ;\n" + " addl $256, %2 ;\n" + " addl $256, %3 ;\n" + " addl $256, %4 ;\n" + " addl $256, %5 ;\n" + " decl %0 ;\n" + " jnz 1b ;\n" + + : + : "r" (lines), + "r" (bh_ptr[0]->b_data), + "r" (bh_ptr[1]->b_data), + "r" (bh_ptr[2]->b_data), + "r" (bh_ptr[3]->b_data), + "r" (bh_ptr[4]->b_data) + : "memory"); + break; + } + + __asm__ __volatile__ ( + "sfence ;\n\t" + "movups (%1),%%xmm0 ;\n\t" + "movups 0x10(%1),%%xmm1 ;\n\t" + "movups 0x20(%1),%%xmm2 ;\n\t" + "movups 0x30(%1),%%xmm3 ;\n\t" + "movl %0,%%cr0 ;\n\t" + : + : "r" (cr0), "r" (xmm_save) + : "memory" ); +} + +#undef OFFS +#undef LD +#undef ST +#undef PF0 +#undef PF1 +#undef PF2 +#undef PF3 +#undef PF4 +#undef PF5 +#undef XO1 +#undef XO2 +#undef XO3 +#undef XO4 +#undef XO5 +#undef BLOCK + +#endif /* CONFIG_X86_XMM */ + +/* + * high-speed RAID5 checksumming functions utilizing MMX instructions + * Copyright (C) 1998 Ingo Molnar + */ +XORBLOCK_TEMPLATE(pII_mmx) +{ + char fpu_save[108]; + int lines = (bh_ptr[0]->b_size>>7); + + if (!(current->flags & PF_USEDFPU)) + __asm__ __volatile__ ( " clts;\n"); + + __asm__ __volatile__ ( " fsave %0; fwait\n"::"m"(fpu_save[0]) ); + +#define LD(x,y) \ + " movq 8*("#x")(%1), %%mm"#y" ;\n" +#define ST(x,y) \ + " movq %%mm"#y", 8*("#x")(%1) ;\n" +#define XO1(x,y) \ + " pxor 8*("#x")(%2), %%mm"#y" ;\n" +#define XO2(x,y) \ + " pxor 8*("#x")(%3), %%mm"#y" ;\n" +#define XO3(x,y) \ + " pxor 8*("#x")(%4), %%mm"#y" ;\n" +#define XO4(x,y) \ + " pxor 8*("#x")(%5), %%mm"#y" ;\n" + + switch(count) { + case 2: + __asm__ __volatile__ ( +#undef BLOCK +#define BLOCK(i) \ + LD(i,0) \ + LD(i+1,1) \ + LD(i+2,2) \ + LD(i+3,3) \ + XO1(i,0) \ + ST(i,0) \ + XO1(i+1,1) \ + ST(i+1,1) \ + XO1(i+2,2) \ + ST(i+2,2) \ + XO1(i+3,3) \ + ST(i+3,3) + + " .align 32,0x90 ;\n" + " 1: ;\n" + + BLOCK(0) + BLOCK(4) + BLOCK(8) + BLOCK(12) + + " addl $128, %1 ;\n" + " addl $128, %2 ;\n" + " decl %0 ;\n" + " jnz 1b ;\n" + : + : "r" (lines), + "r" (bh_ptr[0]->b_data), + "r" (bh_ptr[1]->b_data) + : "memory"); + break; + case 3: + __asm__ __volatile__ ( +#undef BLOCK +#define BLOCK(i) \ + LD(i,0) \ + LD(i+1,1) \ + LD(i+2,2) \ + LD(i+3,3) \ + XO1(i,0) \ + XO1(i+1,1) \ + XO1(i+2,2) \ + XO1(i+3,3) \ + XO2(i,0) \ + ST(i,0) \ + XO2(i+1,1) \ + ST(i+1,1) \ + XO2(i+2,2) \ + ST(i+2,2) \ + XO2(i+3,3) \ + ST(i+3,3) + + " .align 32,0x90 ;\n" + " 1: ;\n" + + BLOCK(0) + BLOCK(4) + BLOCK(8) + BLOCK(12) + + " addl $128, %1 ;\n" + " addl $128, %2 ;\n" + " addl $128, %3 ;\n" + " decl %0 ;\n" + " jnz 1b ;\n" + : + : "r" (lines), + "r" (bh_ptr[0]->b_data), + "r" (bh_ptr[1]->b_data), + "r" (bh_ptr[2]->b_data) + : "memory"); + break; + case 4: + __asm__ __volatile__ ( +#undef BLOCK +#define BLOCK(i) \ + LD(i,0) \ + LD(i+1,1) \ + LD(i+2,2) \ + LD(i+3,3) \ + XO1(i,0) \ + XO1(i+1,1) \ + XO1(i+2,2) \ + XO1(i+3,3) \ + XO2(i,0) \ + XO2(i+1,1) \ + XO2(i+2,2) \ + XO2(i+3,3) \ + XO3(i,0) \ + ST(i,0) \ + XO3(i+1,1) \ + ST(i+1,1) \ + XO3(i+2,2) \ + ST(i+2,2) \ + XO3(i+3,3) \ + ST(i+3,3) + + " .align 32,0x90 ;\n" + " 1: ;\n" + + BLOCK(0) + BLOCK(4) + BLOCK(8) + BLOCK(12) + + " addl $128, %1 ;\n" + " addl $128, %2 ;\n" + " addl $128, %3 ;\n" + " addl $128, %4 ;\n" + " decl %0 ;\n" + " jnz 1b ;\n" + : + : "r" (lines), + "r" (bh_ptr[0]->b_data), + "r" (bh_ptr[1]->b_data), + "r" (bh_ptr[2]->b_data), + "r" (bh_ptr[3]->b_data) + : "memory"); + break; + case 5: + __asm__ __volatile__ ( +#undef BLOCK +#define BLOCK(i) \ + LD(i,0) \ + LD(i+1,1) \ + LD(i+2,2) \ + LD(i+3,3) \ + XO1(i,0) \ + XO1(i+1,1) \ + XO1(i+2,2) \ + XO1(i+3,3) \ + XO2(i,0) \ + XO2(i+1,1) \ + XO2(i+2,2) \ + XO2(i+3,3) \ + XO3(i,0) \ + XO3(i+1,1) \ + XO3(i+2,2) \ + XO3(i+3,3) \ + XO4(i,0) \ + ST(i,0) \ + XO4(i+1,1) \ + ST(i+1,1) \ + XO4(i+2,2) \ + ST(i+2,2) \ + XO4(i+3,3) \ + ST(i+3,3) + + " .align 32,0x90 ;\n" + " 1: ;\n" + + BLOCK(0) + BLOCK(4) + BLOCK(8) + BLOCK(12) + + " addl $128, %1 ;\n" + " addl $128, %2 ;\n" + " addl $128, %3 ;\n" + " addl $128, %4 ;\n" + " addl $128, %5 ;\n" + " decl %0 ;\n" + " jnz 1b ;\n" + : + : "g" (lines), + "r" (bh_ptr[0]->b_data), + "r" (bh_ptr[1]->b_data), + "r" (bh_ptr[2]->b_data), + "r" (bh_ptr[3]->b_data), + "r" (bh_ptr[4]->b_data) + : "memory"); + break; + } + + __asm__ __volatile__ ( " frstor %0;\n"::"m"(fpu_save[0]) ); + + if (!(current->flags & PF_USEDFPU)) + stts(); +} + +#undef LD +#undef XO1 +#undef XO2 +#undef XO3 +#undef XO4 +#undef ST +#undef BLOCK + +XORBLOCK_TEMPLATE(p5_mmx) +{ + char fpu_save[108]; + int lines = (bh_ptr[0]->b_size>>6); + + if (!(current->flags & PF_USEDFPU)) + __asm__ __volatile__ ( " clts;\n"); + + __asm__ __volatile__ ( " fsave %0; fwait\n"::"m"(fpu_save[0]) ); + + switch(count) { + case 2: + __asm__ __volatile__ ( + + " .align 32,0x90 ;\n" + " 1: ;\n" + " movq (%1), %%mm0 ;\n" + " movq 8(%1), %%mm1 ;\n" + " pxor (%2), %%mm0 ;\n" + " movq 16(%1), %%mm2 ;\n" + " movq %%mm0, (%1) ;\n" + " pxor 8(%2), %%mm1 ;\n" + " movq 24(%1), %%mm3 ;\n" + " movq %%mm1, 8(%1) ;\n" + " pxor 16(%2), %%mm2 ;\n" + " movq 32(%1), %%mm4 ;\n" + " movq %%mm2, 16(%1) ;\n" + " pxor 24(%2), %%mm3 ;\n" + " movq 40(%1), %%mm5 ;\n" + " movq %%mm3, 24(%1) ;\n" + " pxor 32(%2), %%mm4 ;\n" + " movq 48(%1), %%mm6 ;\n" + " movq %%mm4, 32(%1) ;\n" + " pxor 40(%2), %%mm5 ;\n" + " movq 56(%1), %%mm7 ;\n" + " movq %%mm5, 40(%1) ;\n" + " pxor 48(%2), %%mm6 ;\n" + " pxor 56(%2), %%mm7 ;\n" + " movq %%mm6, 48(%1) ;\n" + " movq %%mm7, 56(%1) ;\n" + + " addl $64, %1 ;\n" + " addl $64, %2 ;\n" + " decl %0 ;\n" + " jnz 1b ;\n" + + : + : "r" (lines), + "r" (bh_ptr[0]->b_data), + "r" (bh_ptr[1]->b_data) + : "memory" ); + break; + case 3: + __asm__ __volatile__ ( + + " .align 32,0x90 ;\n" + " 1: ;\n" + " movq (%1), %%mm0 ;\n" + " movq 8(%1), %%mm1 ;\n" + " pxor (%2), %%mm0 ;\n" + " movq 16(%1), %%mm2 ;\n" + " pxor 8(%2), %%mm1 ;\n" + " pxor (%3), %%mm0 ;\n" + " pxor 16(%2), %%mm2 ;\n" + " movq %%mm0, (%1) ;\n" + " pxor 8(%3), %%mm1 ;\n" + " pxor 16(%3), %%mm2 ;\n" + " movq 24(%1), %%mm3 ;\n" + " movq %%mm1, 8(%1) ;\n" + " movq 32(%1), %%mm4 ;\n" + " movq 40(%1), %%mm5 ;\n" + " pxor 24(%2), %%mm3 ;\n" + " movq %%mm2, 16(%1) ;\n" + " pxor 32(%2), %%mm4 ;\n" + " pxor 24(%3), %%mm3 ;\n" + " pxor 40(%2), %%mm5 ;\n" + " movq %%mm3, 24(%1) ;\n" + " pxor 32(%3), %%mm4 ;\n" + " pxor 40(%3), %%mm5 ;\n" + " movq 48(%1), %%mm6 ;\n" + " movq %%mm4, 32(%1) ;\n" + " movq 56(%1), %%mm7 ;\n" + " pxor 48(%2), %%mm6 ;\n" + " movq %%mm5, 40(%1) ;\n" + " pxor 56(%2), %%mm7 ;\n" + " pxor 48(%3), %%mm6 ;\n" + " pxor 56(%3), %%mm7 ;\n" + " movq %%mm6, 48(%1) ;\n" + " movq %%mm7, 56(%1) ;\n" + + " addl $64, %1 ;\n" + " addl $64, %2 ;\n" + " addl $64, %3 ;\n" + " decl %0 ;\n" + " jnz 1b ;\n" + + : + : "r" (lines), + "r" (bh_ptr[0]->b_data), + "r" (bh_ptr[1]->b_data), + "r" (bh_ptr[2]->b_data) + : "memory" ); + break; + case 4: + __asm__ __volatile__ ( + + " .align 32,0x90 ;\n" + " 1: ;\n" + " movq (%1), %%mm0 ;\n" + " movq 8(%1), %%mm1 ;\n" + " pxor (%2), %%mm0 ;\n" + " movq 16(%1), %%mm2 ;\n" + " pxor 8(%2), %%mm1 ;\n" + " pxor (%3), %%mm0 ;\n" + " pxor 16(%2), %%mm2 ;\n" + " pxor 8(%3), %%mm1 ;\n" + " pxor (%4), %%mm0 ;\n" + " movq 24(%1), %%mm3 ;\n" + " pxor 16(%3), %%mm2 ;\n" + " pxor 8(%4), %%mm1 ;\n" + " movq %%mm0, (%1) ;\n" + " movq 32(%1), %%mm4 ;\n" + " pxor 24(%2), %%mm3 ;\n" + " pxor 16(%4), %%mm2 ;\n" + " movq %%mm1, 8(%1) ;\n" + " movq 40(%1), %%mm5 ;\n" + " pxor 32(%2), %%mm4 ;\n" + " pxor 24(%3), %%mm3 ;\n" + " movq %%mm2, 16(%1) ;\n" + " pxor 40(%2), %%mm5 ;\n" + " pxor 32(%3), %%mm4 ;\n" + " pxor 24(%4), %%mm3 ;\n" + " movq %%mm3, 24(%1) ;\n" + " movq 56(%1), %%mm7 ;\n" + " movq 48(%1), %%mm6 ;\n" + " pxor 40(%3), %%mm5 ;\n" + " pxor 32(%4), %%mm4 ;\n" + " pxor 48(%2), %%mm6 ;\n" + " movq %%mm4, 32(%1) ;\n" + " pxor 56(%2), %%mm7 ;\n" + " pxor 40(%4), %%mm5 ;\n" + " pxor 48(%3), %%mm6 ;\n" + " pxor 56(%3), %%mm7 ;\n" + " movq %%mm5, 40(%1) ;\n" + " pxor 48(%4), %%mm6 ;\n" + " pxor 56(%4), %%mm7 ;\n" + " movq %%mm6, 48(%1) ;\n" + " movq %%mm7, 56(%1) ;\n" + + " addl $64, %1 ;\n" + " addl $64, %2 ;\n" + " addl $64, %3 ;\n" + " addl $64, %4 ;\n" + " decl %0 ;\n" + " jnz 1b ;\n" + + : + : "r" (lines), + "r" (bh_ptr[0]->b_data), + "r" (bh_ptr[1]->b_data), + "r" (bh_ptr[2]->b_data), + "r" (bh_ptr[3]->b_data) + : "memory" ); + break; + case 5: + __asm__ __volatile__ ( + + " .align 32,0x90 ;\n" + " 1: ;\n" + " movq (%1), %%mm0 ;\n" + " movq 8(%1), %%mm1 ;\n" + " pxor (%2), %%mm0 ;\n" + " pxor 8(%2), %%mm1 ;\n" + " movq 16(%1), %%mm2 ;\n" + " pxor (%3), %%mm0 ;\n" + " pxor 8(%3), %%mm1 ;\n" + " pxor 16(%2), %%mm2 ;\n" + " pxor (%4), %%mm0 ;\n" + " pxor 8(%4), %%mm1 ;\n" + " pxor 16(%3), %%mm2 ;\n" + " movq 24(%1), %%mm3 ;\n" + " pxor (%5), %%mm0 ;\n" + " pxor 8(%5), %%mm1 ;\n" + " movq %%mm0, (%1) ;\n" + " pxor 16(%4), %%mm2 ;\n" + " pxor 24(%2), %%mm3 ;\n" + " movq %%mm1, 8(%1) ;\n" + " pxor 16(%5), %%mm2 ;\n" + " pxor 24(%3), %%mm3 ;\n" + " movq 32(%1), %%mm4 ;\n" + " movq %%mm2, 16(%1) ;\n" + " pxor 24(%4), %%mm3 ;\n" + " pxor 32(%2), %%mm4 ;\n" + " movq 40(%1), %%mm5 ;\n" + " pxor 24(%5), %%mm3 ;\n" + " pxor 32(%3), %%mm4 ;\n" + " pxor 40(%2), %%mm5 ;\n" + " movq %%mm3, 24(%1) ;\n" + " pxor 32(%4), %%mm4 ;\n" + " pxor 40(%3), %%mm5 ;\n" + " movq 48(%1), %%mm6 ;\n" + " movq 56(%1), %%mm7 ;\n" + " pxor 32(%5), %%mm4 ;\n" + " pxor 40(%4), %%mm5 ;\n" + " pxor 48(%2), %%mm6 ;\n" + " pxor 56(%2), %%mm7 ;\n" + " movq %%mm4, 32(%1) ;\n" + " pxor 48(%3), %%mm6 ;\n" + " pxor 56(%3), %%mm7 ;\n" + " pxor 40(%5), %%mm5 ;\n" + " pxor 48(%4), %%mm6 ;\n" + " pxor 56(%4), %%mm7 ;\n" + " movq %%mm5, 40(%1) ;\n" + " pxor 48(%5), %%mm6 ;\n" + " pxor 56(%5), %%mm7 ;\n" + " movq %%mm6, 48(%1) ;\n" + " movq %%mm7, 56(%1) ;\n" + + " addl $64, %1 ;\n" + " addl $64, %2 ;\n" + " addl $64, %3 ;\n" + " addl $64, %4 ;\n" + " addl $64, %5 ;\n" + " decl %0 ;\n" + " jnz 1b ;\n" + + : + : "g" (lines), + "r" (bh_ptr[0]->b_data), + "r" (bh_ptr[1]->b_data), + "r" (bh_ptr[2]->b_data), + "r" (bh_ptr[3]->b_data), + "r" (bh_ptr[4]->b_data) + : "memory" ); + break; + } + + __asm__ __volatile__ ( " frstor %0;\n"::"m"(fpu_save[0]) ); + + if (!(current->flags & PF_USEDFPU)) + stts(); +} +#endif /* __i386__ */ +#endif /* !__sparc_v9__ */ + +#ifdef __sparc_v9__ +/* + * High speed xor_block operation for RAID4/5 utilizing the + * UltraSparc Visual Instruction Set. + * + * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) + * + * Requirements: + * !(((long)dest | (long)sourceN) & (64 - 1)) && + * !(len & 127) && len >= 256 + * + * It is done in pure assembly, as otherwise gcc makes it + * a non-leaf function, which is not what we want. + * Also, we don't measure the speeds as on other architectures, + * as the measuring routine does not take into account cold caches + * and the fact that xor_block_VIS bypasses the caches. + * xor_block_32regs might be 5% faster for count 2 if caches are hot + * and things just right (for count 3 VIS is about as fast as 32regs for + * hot caches and for count 4 and 5 VIS is faster by good margin always), + * but I think it is better not to pollute the caches. + * Actually, if I'd just fight for speed for hot caches, I could + * write a hybrid VIS/integer routine, which would do always two + * 64B blocks in VIS and two in IEUs, but I really care more about + * caches. + */ +extern void *VISenter(void); +extern void xor_block_VIS XOR_ARGS; + +void __xor_block_VIS(void) +{ +__asm__ (" + .globl xor_block_VIS +xor_block_VIS: + ldx [%%o1 + 0], %%o4 + ldx [%%o1 + 8], %%o3 + ldx [%%o4 + %1], %%g5 + ldx [%%o4 + %0], %%o4 + ldx [%%o3 + %0], %%o3 + rd %%fprs, %%o5 + andcc %%o5, %2, %%g0 + be,pt %%icc, 297f + sethi %%hi(%5), %%g1 + jmpl %%g1 + %%lo(%5), %%g7 + add %%g7, 8, %%g7 +297: wr %%g0, %4, %%fprs + membar #LoadStore|#StoreLoad|#StoreStore + sub %%g5, 64, %%g5 + ldda [%%o4] %3, %%f0 + ldda [%%o3] %3, %%f16 + cmp %%o0, 4 + bgeu,pt %%xcc, 10f + cmp %%o0, 3 + be,pn %%xcc, 13f + mov -64, %%g1 + sub %%g5, 64, %%g5 + rd %%asi, %%g1 + wr %%g0, %3, %%asi + +2: ldda [%%o4 + 64] %%asi, %%f32 + fxor %%f0, %%f16, %%f16 + fxor %%f2, %%f18, %%f18 + fxor %%f4, %%f20, %%f20 + fxor %%f6, %%f22, %%f22 + fxor %%f8, %%f24, %%f24 + fxor %%f10, %%f26, %%f26 + fxor %%f12, %%f28, %%f28 + fxor %%f14, %%f30, %%f30 + stda %%f16, [%%o4] %3 + ldda [%%o3 + 64] %%asi, %%f48 + ldda [%%o4 + 128] %%asi, %%f0 + fxor %%f32, %%f48, %%f48 + fxor %%f34, %%f50, %%f50 + add %%o4, 128, %%o4 + fxor %%f36, %%f52, %%f52 + add %%o3, 128, %%o3 + fxor %%f38, %%f54, %%f54 + subcc %%g5, 128, %%g5 + fxor %%f40, %%f56, %%f56 + fxor %%f42, %%f58, %%f58 + fxor %%f44, %%f60, %%f60 + fxor %%f46, %%f62, %%f62 + stda %%f48, [%%o4 - 64] %%asi + bne,pt %%xcc, 2b + ldda [%%o3] %3, %%f16 + + ldda [%%o4 + 64] %%asi, %%f32 + fxor %%f0, %%f16, %%f16 + fxor %%f2, %%f18, %%f18 + fxor %%f4, %%f20, %%f20 + fxor %%f6, %%f22, %%f22 + fxor %%f8, %%f24, %%f24 + fxor %%f10, %%f26, %%f26 + fxor %%f12, %%f28, %%f28 + fxor %%f14, %%f30, %%f30 + stda %%f16, [%%o4] %3 + ldda [%%o3 + 64] %%asi, %%f48 + membar #Sync + fxor %%f32, %%f48, %%f48 + fxor %%f34, %%f50, %%f50 + fxor %%f36, %%f52, %%f52 + fxor %%f38, %%f54, %%f54 + fxor %%f40, %%f56, %%f56 + fxor %%f42, %%f58, %%f58 + fxor %%f44, %%f60, %%f60 + fxor %%f46, %%f62, %%f62 + stda %%f48, [%%o4 + 64] %%asi + membar #Sync|#StoreStore|#StoreLoad + wr %%g0, 0, %%fprs + retl + wr %%g1, %%g0, %%asi + +13: ldx [%%o1 + 16], %%o2 + ldx [%%o2 + %0], %%o2 + +3: ldda [%%o2] %3, %%f32 + fxor %%f0, %%f16, %%f48 + fxor %%f2, %%f18, %%f50 + add %%o4, 64, %%o4 + fxor %%f4, %%f20, %%f52 + fxor %%f6, %%f22, %%f54 + add %%o3, 64, %%o3 + fxor %%f8, %%f24, %%f56 + fxor %%f10, %%f26, %%f58 + fxor %%f12, %%f28, %%f60 + fxor %%f14, %%f30, %%f62 + ldda [%%o4] %3, %%f0 + fxor %%f48, %%f32, %%f48 + fxor %%f50, %%f34, %%f50 + fxor %%f52, %%f36, %%f52 + fxor %%f54, %%f38, %%f54 + add %%o2, 64, %%o2 + fxor %%f56, %%f40, %%f56 + fxor %%f58, %%f42, %%f58 + subcc %%g5, 64, %%g5 + fxor %%f60, %%f44, %%f60 + fxor %%f62, %%f46, %%f62 + stda %%f48, [%%o4 + %%g1] %3 + bne,pt %%xcc, 3b + ldda [%%o3] %3, %%f16 + + ldda [%%o2] %3, %%f32 + fxor %%f0, %%f16, %%f48 + fxor %%f2, %%f18, %%f50 + fxor %%f4, %%f20, %%f52 + fxor %%f6, %%f22, %%f54 + fxor %%f8, %%f24, %%f56 + fxor %%f10, %%f26, %%f58 + fxor %%f12, %%f28, %%f60 + fxor %%f14, %%f30, %%f62 + membar #Sync + fxor %%f48, %%f32, %%f48 + fxor %%f50, %%f34, %%f50 + fxor %%f52, %%f36, %%f52 + fxor %%f54, %%f38, %%f54 + fxor %%f56, %%f40, %%f56 + fxor %%f58, %%f42, %%f58 + fxor %%f60, %%f44, %%f60 + fxor %%f62, %%f46, %%f62 + stda %%f48, [%%o4] %3 + membar #Sync|#StoreStore|#StoreLoad + retl + wr %%g0, 0, %%fprs + +10: cmp %%o0, 5 + be,pt %%xcc, 15f + mov -64, %%g1 + +14: ldx [%%o1 + 16], %%o2 + ldx [%%o1 + 24], %%o0 + ldx [%%o2 + %0], %%o2 + ldx [%%o0 + %0], %%o0 + +4: ldda [%%o2] %3, %%f32 + fxor %%f0, %%f16, %%f16 + fxor %%f2, %%f18, %%f18 + add %%o4, 64, %%o4 + fxor %%f4, %%f20, %%f20 + fxor %%f6, %%f22, %%f22 + add %%o3, 64, %%o3 + fxor %%f8, %%f24, %%f24 + fxor %%f10, %%f26, %%f26 + fxor %%f12, %%f28, %%f28 + fxor %%f14, %%f30, %%f30 + ldda [%%o0] %3, %%f48 + fxor %%f16, %%f32, %%f32 + fxor %%f18, %%f34, %%f34 + fxor %%f20, %%f36, %%f36 + fxor %%f22, %%f38, %%f38 + add %%o2, 64, %%o2 + fxor %%f24, %%f40, %%f40 + fxor %%f26, %%f42, %%f42 + fxor %%f28, %%f44, %%f44 + fxor %%f30, %%f46, %%f46 + ldda [%%o4] %3, %%f0 + fxor %%f32, %%f48, %%f48 + fxor %%f34, %%f50, %%f50 + fxor %%f36, %%f52, %%f52 + add %%o0, 64, %%o0 + fxor %%f38, %%f54, %%f54 + fxor %%f40, %%f56, %%f56 + fxor %%f42, %%f58, %%f58 + subcc %%g5, 64, %%g5 + fxor %%f44, %%f60, %%f60 + fxor %%f46, %%f62, %%f62 + stda %%f48, [%%o4 + %%g1] %3 + bne,pt %%xcc, 4b + ldda [%%o3] %3, %%f16 + + ldda [%%o2] %3, %%f32 + fxor %%f0, %%f16, %%f16 + fxor %%f2, %%f18, %%f18 + fxor %%f4, %%f20, %%f20 + fxor %%f6, %%f22, %%f22 + fxor %%f8, %%f24, %%f24 + fxor %%f10, %%f26, %%f26 + fxor %%f12, %%f28, %%f28 + fxor %%f14, %%f30, %%f30 + ldda [%%o0] %3, %%f48 + fxor %%f16, %%f32, %%f32 + fxor %%f18, %%f34, %%f34 + fxor %%f20, %%f36, %%f36 + fxor %%f22, %%f38, %%f38 + fxor %%f24, %%f40, %%f40 + fxor %%f26, %%f42, %%f42 + fxor %%f28, %%f44, %%f44 + fxor %%f30, %%f46, %%f46 + membar #Sync + fxor %%f32, %%f48, %%f48 + fxor %%f34, %%f50, %%f50 + fxor %%f36, %%f52, %%f52 + fxor %%f38, %%f54, %%f54 + fxor %%f40, %%f56, %%f56 + fxor %%f42, %%f58, %%f58 + fxor %%f44, %%f60, %%f60 + fxor %%f46, %%f62, %%f62 + stda %%f48, [%%o4] %3 + membar #Sync|#StoreStore|#StoreLoad + retl + wr %%g0, 0, %%fprs + +15: ldx [%%o1 + 16], %%o2 + ldx [%%o1 + 24], %%o0 + ldx [%%o1 + 32], %%o1 + ldx [%%o2 + %0], %%o2 + ldx [%%o0 + %0], %%o0 + ldx [%%o1 + %0], %%o1 + +5: ldda [%%o2] %3, %%f32 + fxor %%f0, %%f16, %%f48 + fxor %%f2, %%f18, %%f50 + add %%o4, 64, %%o4 + fxor %%f4, %%f20, %%f52 + fxor %%f6, %%f22, %%f54 + add %%o3, 64, %%o3 + fxor %%f8, %%f24, %%f56 + fxor %%f10, %%f26, %%f58 + fxor %%f12, %%f28, %%f60 + fxor %%f14, %%f30, %%f62 + ldda [%%o0] %3, %%f16 + fxor %%f48, %%f32, %%f48 + fxor %%f50, %%f34, %%f50 + fxor %%f52, %%f36, %%f52 + fxor %%f54, %%f38, %%f54 + add %%o2, 64, %%o2 + fxor %%f56, %%f40, %%f56 + fxor %%f58, %%f42, %%f58 + fxor %%f60, %%f44, %%f60 + fxor %%f62, %%f46, %%f62 + ldda [%%o1] %3, %%f32 + fxor %%f48, %%f16, %%f48 + fxor %%f50, %%f18, %%f50 + add %%o0, 64, %%o0 + fxor %%f52, %%f20, %%f52 + fxor %%f54, %%f22, %%f54 + add %%o1, 64, %%o1 + fxor %%f56, %%f24, %%f56 + fxor %%f58, %%f26, %%f58 + fxor %%f60, %%f28, %%f60 + fxor %%f62, %%f30, %%f62 + ldda [%%o4] %3, %%f0 + fxor %%f48, %%f32, %%f48 + fxor %%f50, %%f34, %%f50 + fxor %%f52, %%f36, %%f52 + fxor %%f54, %%f38, %%f54 + fxor %%f56, %%f40, %%f56 + fxor %%f58, %%f42, %%f58 + subcc %%g5, 64, %%g5 + fxor %%f60, %%f44, %%f60 + fxor %%f62, %%f46, %%f62 + stda %%f48, [%%o4 + %%g1] %3 + bne,pt %%xcc, 5b + ldda [%%o3] %3, %%f16 + + ldda [%%o2] %3, %%f32 + fxor %%f0, %%f16, %%f48 + fxor %%f2, %%f18, %%f50 + fxor %%f4, %%f20, %%f52 + fxor %%f6, %%f22, %%f54 + fxor %%f8, %%f24, %%f56 + fxor %%f10, %%f26, %%f58 + fxor %%f12, %%f28, %%f60 + fxor %%f14, %%f30, %%f62 + ldda [%%o0] %3, %%f16 + fxor %%f48, %%f32, %%f48 + fxor %%f50, %%f34, %%f50 + fxor %%f52, %%f36, %%f52 + fxor %%f54, %%f38, %%f54 + fxor %%f56, %%f40, %%f56 + fxor %%f58, %%f42, %%f58 + fxor %%f60, %%f44, %%f60 + fxor %%f62, %%f46, %%f62 + ldda [%%o1] %3, %%f32 + fxor %%f48, %%f16, %%f48 + fxor %%f50, %%f18, %%f50 + fxor %%f52, %%f20, %%f52 + fxor %%f54, %%f22, %%f54 + fxor %%f56, %%f24, %%f56 + fxor %%f58, %%f26, %%f58 + fxor %%f60, %%f28, %%f60 + fxor %%f62, %%f30, %%f62 + membar #Sync + fxor %%f48, %%f32, %%f48 + fxor %%f50, %%f34, %%f50 + fxor %%f52, %%f36, %%f52 + fxor %%f54, %%f38, %%f54 + fxor %%f56, %%f40, %%f56 + fxor %%f58, %%f42, %%f58 + fxor %%f60, %%f44, %%f60 + fxor %%f62, %%f46, %%f62 + stda %%f48, [%%o4] %3 + membar #Sync|#StoreStore|#StoreLoad + retl + wr %%g0, 0, %%fprs + " : : + "i" (&((struct buffer_head *)0)->b_data), + "i" (&((struct buffer_head *)0)->b_size), + "i" (FPRS_FEF|FPRS_DU), "i" (ASI_BLK_P), + "i" (FPRS_FEF), "i" (VISenter)); +} +#endif /* __sparc_v9__ */ + +#if defined(__sparc__) && !defined(__sparc_v9__) +/* + * High speed xor_block operation for RAID4/5 utilizing the + * ldd/std SPARC instructions. + * + * Copyright (C) 1999 Jakub Jelinek (jj@ultra.linux.cz) + * + */ + +XORBLOCK_TEMPLATE(SPARC) +{ + int size = bh_ptr[0]->b_size; + int lines = size / (sizeof (long)) / 8, i; + long *destp = (long *) bh_ptr[0]->b_data; + long *source1 = (long *) bh_ptr[1]->b_data; + long *source2, *source3, *source4; + + switch (count) { + case 2: + for (i = lines; i > 0; i--) { + __asm__ __volatile__(" + ldd [%0 + 0x00], %%g2 + ldd [%0 + 0x08], %%g4 + ldd [%0 + 0x10], %%o0 + ldd [%0 + 0x18], %%o2 + ldd [%1 + 0x00], %%o4 + ldd [%1 + 0x08], %%l0 + ldd [%1 + 0x10], %%l2 + ldd [%1 + 0x18], %%l4 + xor %%g2, %%o4, %%g2 + xor %%g3, %%o5, %%g3 + xor %%g4, %%l0, %%g4 + xor %%g5, %%l1, %%g5 + xor %%o0, %%l2, %%o0 + xor %%o1, %%l3, %%o1 + xor %%o2, %%l4, %%o2 + xor %%o3, %%l5, %%o3 + std %%g2, [%0 + 0x00] + std %%g4, [%0 + 0x08] + std %%o0, [%0 + 0x10] + std %%o2, [%0 + 0x18] + " : : "r" (destp), "r" (source1) : "g2", "g3", "g4", "g5", "o0", + "o1", "o2", "o3", "o4", "o5", "l0", "l1", "l2", "l3", "l4", "l5"); + destp += 8; + source1 += 8; + } + break; + case 3: + source2 = (long *) bh_ptr[2]->b_data; + for (i = lines; i > 0; i--) { + __asm__ __volatile__(" + ldd [%0 + 0x00], %%g2 + ldd [%0 + 0x08], %%g4 + ldd [%0 + 0x10], %%o0 + ldd [%0 + 0x18], %%o2 + ldd [%1 + 0x00], %%o4 + ldd [%1 + 0x08], %%l0 + ldd [%1 + 0x10], %%l2 + ldd [%1 + 0x18], %%l4 + xor %%g2, %%o4, %%g2 + xor %%g3, %%o5, %%g3 + ldd [%2 + 0x00], %%o4 + xor %%g4, %%l0, %%g4 + xor %%g5, %%l1, %%g5 + ldd [%2 + 0x08], %%l0 + xor %%o0, %%l2, %%o0 + xor %%o1, %%l3, %%o1 + ldd [%2 + 0x10], %%l2 + xor %%o2, %%l4, %%o2 + xor %%o3, %%l5, %%o3 + ldd [%2 + 0x18], %%l4 + xor %%g2, %%o4, %%g2 + xor %%g3, %%o5, %%g3 + xor %%g4, %%l0, %%g4 + xor %%g5, %%l1, %%g5 + xor %%o0, %%l2, %%o0 + xor %%o1, %%l3, %%o1 + xor %%o2, %%l4, %%o2 + xor %%o3, %%l5, %%o3 + std %%g2, [%0 + 0x00] + std %%g4, [%0 + 0x08] + std %%o0, [%0 + 0x10] + std %%o2, [%0 + 0x18] + " : : "r" (destp), "r" (source1), "r" (source2) + : "g2", "g3", "g4", "g5", "o0", "o1", "o2", "o3", "o4", "o5", + "l0", "l1", "l2", "l3", "l4", "l5"); + destp += 8; + source1 += 8; + source2 += 8; + } + break; + case 4: + source2 = (long *) bh_ptr[2]->b_data; + source3 = (long *) bh_ptr[3]->b_data; + for (i = lines; i > 0; i--) { + __asm__ __volatile__(" + ldd [%0 + 0x00], %%g2 + ldd [%0 + 0x08], %%g4 + ldd [%0 + 0x10], %%o0 + ldd [%0 + 0x18], %%o2 + ldd [%1 + 0x00], %%o4 + ldd [%1 + 0x08], %%l0 + ldd [%1 + 0x10], %%l2 + ldd [%1 + 0x18], %%l4 + xor %%g2, %%o4, %%g2 + xor %%g3, %%o5, %%g3 + ldd [%2 + 0x00], %%o4 + xor %%g4, %%l0, %%g4 + xor %%g5, %%l1, %%g5 + ldd [%2 + 0x08], %%l0 + xor %%o0, %%l2, %%o0 + xor %%o1, %%l3, %%o1 + ldd [%2 + 0x10], %%l2 + xor %%o2, %%l4, %%o2 + xor %%o3, %%l5, %%o3 + ldd [%2 + 0x18], %%l4 + xor %%g2, %%o4, %%g2 + xor %%g3, %%o5, %%g3 + ldd [%3 + 0x00], %%o4 + xor %%g4, %%l0, %%g4 + xor %%g5, %%l1, %%g5 + ldd [%3 + 0x08], %%l0 + xor %%o0, %%l2, %%o0 + xor %%o1, %%l3, %%o1 + ldd [%3 + 0x10], %%l2 + xor %%o2, %%l4, %%o2 + xor %%o3, %%l5, %%o3 + ldd [%3 + 0x18], %%l4 + xor %%g2, %%o4, %%g2 + xor %%g3, %%o5, %%g3 + xor %%g4, %%l0, %%g4 + xor %%g5, %%l1, %%g5 + xor %%o0, %%l2, %%o0 + xor %%o1, %%l3, %%o1 + xor %%o2, %%l4, %%o2 + xor %%o3, %%l5, %%o3 + std %%g2, [%0 + 0x00] + std %%g4, [%0 + 0x08] + std %%o0, [%0 + 0x10] + std %%o2, [%0 + 0x18] + " : : "r" (destp), "r" (source1), "r" (source2), "r" (source3) + : "g2", "g3", "g4", "g5", "o0", "o1", "o2", "o3", "o4", "o5", + "l0", "l1", "l2", "l3", "l4", "l5"); + destp += 8; + source1 += 8; + source2 += 8; + source3 += 8; + } + break; + case 5: + source2 = (long *) bh_ptr[2]->b_data; + source3 = (long *) bh_ptr[3]->b_data; + source4 = (long *) bh_ptr[4]->b_data; + for (i = lines; i > 0; i--) { + __asm__ __volatile__(" + ldd [%0 + 0x00], %%g2 + ldd [%0 + 0x08], %%g4 + ldd [%0 + 0x10], %%o0 + ldd [%0 + 0x18], %%o2 + ldd [%1 + 0x00], %%o4 + ldd [%1 + 0x08], %%l0 + ldd [%1 + 0x10], %%l2 + ldd [%1 + 0x18], %%l4 + xor %%g2, %%o4, %%g2 + xor %%g3, %%o5, %%g3 + ldd [%2 + 0x00], %%o4 + xor %%g4, %%l0, %%g4 + xor %%g5, %%l1, %%g5 + ldd [%2 + 0x08], %%l0 + xor %%o0, %%l2, %%o0 + xor %%o1, %%l3, %%o1 + ldd [%2 + 0x10], %%l2 + xor %%o2, %%l4, %%o2 + xor %%o3, %%l5, %%o3 + ldd [%2 + 0x18], %%l4 + xor %%g2, %%o4, %%g2 + xor %%g3, %%o5, %%g3 + ldd [%3 + 0x00], %%o4 + xor %%g4, %%l0, %%g4 + xor %%g5, %%l1, %%g5 + ldd [%3 + 0x08], %%l0 + xor %%o0, %%l2, %%o0 + xor %%o1, %%l3, %%o1 + ldd [%3 + 0x10], %%l2 + xor %%o2, %%l4, %%o2 + xor %%o3, %%l5, %%o3 + ldd [%3 + 0x18], %%l4 + xor %%g2, %%o4, %%g2 + xor %%g3, %%o5, %%g3 + ldd [%4 + 0x00], %%o4 + xor %%g4, %%l0, %%g4 + xor %%g5, %%l1, %%g5 + ldd [%4 + 0x08], %%l0 + xor %%o0, %%l2, %%o0 + xor %%o1, %%l3, %%o1 + ldd [%4 + 0x10], %%l2 + xor %%o2, %%l4, %%o2 + xor %%o3, %%l5, %%o3 + ldd [%4 + 0x18], %%l4 + xor %%g2, %%o4, %%g2 + xor %%g3, %%o5, %%g3 + xor %%g4, %%l0, %%g4 + xor %%g5, %%l1, %%g5 + xor %%o0, %%l2, %%o0 + xor %%o1, %%l3, %%o1 + xor %%o2, %%l4, %%o2 + xor %%o3, %%l5, %%o3 + std %%g2, [%0 + 0x00] + std %%g4, [%0 + 0x08] + std %%o0, [%0 + 0x10] + std %%o2, [%0 + 0x18] + " : : "r" (destp), "r" (source1), "r" (source2), "r" (source3), "r" (source4) + : "g2", "g3", "g4", "g5", "o0", "o1", "o2", "o3", "o4", "o5", + "l0", "l1", "l2", "l3", "l4", "l5"); + destp += 8; + source1 += 8; + source2 += 8; + source3 += 8; + source4 += 8; + } + break; + } +} +#endif /* __sparc_v[78]__ */ + +#ifdef __alpha__ +/* + * High speed xor_block operation for RAID4/5 pipelined for Alpha EV5. + * There is a second version using EV6 prefetch instructions. + * + * Copyright (C) 2000 Richard Henderson (rth@redhat.com) + */ + +XORBLOCK_TEMPLATE(alpha) +{ + long lines = bh_ptr[0]->b_size / sizeof (long) / 8; + long *d = (long *) bh_ptr[0]->b_data; + long *s1 = (long *) bh_ptr[1]->b_data; + long *s2, *s3, *s4; + + if (count == 2) goto two_blocks; + + s2 = (long *) bh_ptr[2]->b_data; + if (count == 3) goto three_blocks; + + s3 = (long *) bh_ptr[3]->b_data; + if (count == 4) goto four_blocks; + + s4 = (long *) bh_ptr[4]->b_data; + goto five_blocks; + +two_blocks: +asm volatile (" + .align 4 +2: + ldq $0,0(%0) + ldq $1,0(%1) + ldq $2,8(%0) + ldq $3,8(%1) + + ldq $4,16(%0) + ldq $5,16(%1) + ldq $6,24(%0) + ldq $7,24(%1) + + ldq $16,32(%0) + ldq $17,32(%1) + ldq $18,40(%0) + ldq $19,40(%1) + + ldq $20,48(%0) + ldq $21,48(%1) + ldq $22,56(%0) + xor $0,$1,$0 # 7 cycles from $1 load + + ldq $23,56(%1) + xor $2,$3,$2 + stq $0,0(%0) + xor $4,$5,$4 + + stq $2,8(%0) + xor $6,$7,$6 + stq $4,16(%0) + xor $16,$17,$16 + + stq $6,24(%0) + xor $18,$19,$18 + stq $16,32(%0) + xor $20,$21,$20 + + stq $18,40(%0) + xor $22,$23,$22 + stq $20,48(%0) + subq %2,1,%2 + + stq $22,56(%0) + addq %0,64,%0 + addq %1,64,%1 + bgt %2,2b" + : "=r"(d), "=r"(s1), "=r"(lines) + : "0"(d), "1"(s1), "2"(lines) + : "memory", "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", + "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23"); + return; + +three_blocks: +asm volatile (" + .align 4 +3: + ldq $0,0(%0) + ldq $1,0(%1) + ldq $2,0(%2) + ldq $3,8(%0) + + ldq $4,8(%1) + ldq $6,16(%0) + ldq $7,16(%1) + ldq $17,24(%0) + + ldq $18,24(%1) + ldq $20,32(%0) + ldq $21,32(%1) + ldq $5,8(%2) + + ldq $16,16(%2) + ldq $19,24(%2) + ldq $22,32(%2) + nop + + xor $0,$1,$1 # 8 cycles from $0 load + xor $3,$4,$4 # 6 cycles from $4 load + xor $6,$7,$7 # 6 cycles from $7 load + xor $17,$18,$18 # 5 cycles from $18 load + + xor $1,$2,$2 # 9 cycles from $2 load + xor $20,$21,$21 # 5 cycles from $21 load + stq $2,0(%0) + xor $4,$5,$5 # 6 cycles from $5 load + + stq $5,8(%0) + xor $7,$16,$16 # 7 cycles from $16 load + stq $16,16(%0) + xor $18,$19,$19 # 7 cycles from $19 load + + stq $19,24(%0) + xor $21,$22,$22 # 7 cycles from $22 load + stq $22,32(%0) + nop + + ldq $0,40(%0) + ldq $1,40(%1) + ldq $3,48(%0) + ldq $4,48(%1) + + ldq $6,56(%0) + ldq $7,56(%1) + ldq $2,40(%2) + ldq $5,48(%2) + + ldq $16,56(%2) + xor $0,$1,$1 # 4 cycles from $1 load + xor $3,$4,$4 # 5 cycles from $4 load + xor $6,$7,$7 # 5 cycles from $7 load + + xor $1,$2,$2 # 4 cycles from $2 load + xor $4,$5,$5 # 5 cycles from $5 load + stq $2,40(%0) + xor $7,$16,$16 # 4 cycles from $16 load + + stq $5,48(%0) + subq %3,1,%3 + stq $16,56(%0) + addq %2,64,%2 + + addq %1,64,%1 + addq %0,64,%0 + bgt %3,3b" + : "=r"(d), "=r"(s1), "=r"(s2), "=r"(lines) + : "0"(d), "1"(s1), "2"(s2), "3"(lines) + : "memory", "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", + "$16", "$17", "$18", "$19", "$20", "$21", "$22"); + return; + +four_blocks: +asm volatile (" + .align 4 +4: + ldq $0,0(%0) + ldq $1,0(%1) + ldq $2,0(%2) + ldq $3,0(%3) + + ldq $4,8(%0) + ldq $5,8(%1) + ldq $6,8(%2) + ldq $7,8(%3) + + ldq $16,16(%0) + ldq $17,16(%1) + ldq $18,16(%2) + ldq $19,16(%3) + + ldq $20,24(%0) + xor $0,$1,$1 # 6 cycles from $1 load + ldq $21,24(%1) + xor $2,$3,$3 # 6 cycles from $3 load + + ldq $0,24(%2) + xor $1,$3,$3 + ldq $1,24(%3) + xor $4,$5,$5 # 7 cycles from $5 load + + stq $3,0(%0) + xor $6,$7,$7 + xor $16,$17,$17 # 7 cycles from $17 load + xor $5,$7,$7 + + stq $7,8(%0) + xor $18,$19,$19 # 7 cycles from $19 load + ldq $2,32(%0) + xor $17,$19,$19 + + ldq $3,32(%1) + ldq $4,32(%2) + ldq $5,32(%3) + xor $20,$21,$21 # 8 cycles from $21 load + + ldq $6,40(%0) + ldq $7,40(%1) + ldq $16,40(%2) + ldq $17,40(%3) + + stq $19,16(%0) + xor $0,$1,$1 # 9 cycles from $1 load + xor $2,$3,$3 # 5 cycles from $3 load + xor $21,$1,$1 + + ldq $18,48(%0) + xor $4,$5,$5 # 5 cycles from $5 load + ldq $19,48(%1) + xor $3,$5,$5 + + ldq $20,48(%2) + ldq $21,48(%3) + ldq $0,56(%0) + ldq $1,56(%1) + + ldq $2,56(%2) + xor $6,$7,$7 # 8 cycles from $6 load + ldq $3,56(%3) + xor $16,$17,$17 # 8 cycles from $17 load + + xor $7,$17,$17 + xor $18,$19,$19 # 5 cycles from $19 load + xor $20,$21,$21 # 5 cycles from $21 load + xor $19,$21,$21 + + stq $1,24(%0) + xor $0,$1,$1 # 5 cycles from $1 load + stq $5,32(%0) + xor $2,$3,$3 # 4 cycles from $3 load + + stq $17,40(%0) + xor $1,$3,$3 + stq $21,48(%0) + subq %4,1,%4 + + stq $3,56(%0) + addq %3,64,%3 + addq %2,64,%2 + addq %1,64,%1 + + addq %0,64,%0 + bgt %4,4b" + : "=r"(d), "=r"(s1), "=r"(s2), "=r"(s3), "=r"(lines) + : "0"(d), "1"(s1), "2"(s2), "3"(s3), "4"(lines) + : "memory", "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", + "$16", "$17", "$18", "$19", "$20", "$21"); + return; + +five_blocks: +asm volatile (" + ldq %0,0(%6) + ldq %1,8(%6) + ldq %2,16(%6) + ldq %3,24(%6) + ldq %4,32(%6) + ldq %0,%7(%0) + ldq %1,%7(%1) + ldq %2,%7(%2) + ldq %3,%7(%3) + ldq %4,%7(%4) + .align 4 +5: + ldq $0,0(%0) + ldq $1,0(%1) + ldq $2,0(%2) + ldq $3,0(%3) + + ldq $4,0(%4) + ldq $5,8(%0) + ldq $6,8(%1) + ldq $7,8(%2) + + ldq $16,8(%3) + ldq $17,8(%4) + ldq $18,16(%0) + ldq $19,16(%1) + + ldq $20,16(%2) + xor $0,$1,$1 # 6 cycles from $1 load + ldq $21,16(%3) + xor $2,$3,$3 # 6 cycles from $3 load + + ldq $0,16(%4) + xor $1,$3,$3 + ldq $1,24(%0) + xor $3,$4,$4 # 7 cycles from $4 load + + stq $4,0(%0) + xor $5,$6,$6 # 7 cycles from $6 load + xor $7,$16,$16 # 7 cycles from $16 load + xor $6,$17,$17 # 7 cycles from $17 load + + ldq $2,24(%1) + xor $16,$17,$17 + ldq $3,24(%2) + xor $18,$19,$19 # 8 cycles from $19 load + + stq $17,8(%0) + xor $19,$20,$20 # 8 cycles from $20 load + ldq $4,24(%3) + xor $21,$0,$0 # 7 cycles from $0 load + + ldq $5,24(%4) + xor $20,$0,$0 + ldq $6,32(%0) + ldq $7,32(%1) + + stq $0,16(%0) + xor $1,$2,$2 # 6 cycles from $2 load + ldq $16,32(%2) + xor $3,$4,$4 # 4 cycles from $4 load + + ldq $17,32(%3) + xor $2,$4,$4 + ldq $18,32(%4) + ldq $19,40(%0) + + ldq $20,40(%1) + ldq $21,40(%2) + ldq $0,40(%3) + xor $4,$5,$5 # 7 cycles from $5 load + + stq $5,24(%0) + xor $6,$7,$7 # 7 cycles from $7 load + ldq $1,40(%4) + ldq $2,48(%0) + + ldq $3,48(%1) + xor $7,$16,$16 # 7 cycles from $16 load + ldq $4,48(%2) + xor $17,$18,$18 # 6 cycles from $18 load + + ldq $5,48(%3) + xor $16,$18,$18 + ldq $6,48(%4) + xor $19,$20,$20 # 7 cycles from $20 load + + stq $18,32(%0) + xor $20,$21,$21 # 8 cycles from $21 load + ldq $7,56(%0) + xor $0,$1,$1 # 6 cycles from $1 load + + ldq $16,56(%1) + ldq $17,56(%2) + ldq $18,56(%3) + ldq $19,56(%4) + + xor $21,$1,$1 + xor $2,$3,$3 # 9 cycles from $3 load + xor $3,$4,$4 # 9 cycles from $4 load + xor $5,$6,$6 # 8 cycles from $6 load + + unop + xor $4,$6,$6 + xor $7,$16,$16 # 7 cycles from $16 load + xor $17,$18,$18 # 6 cycles from $18 load + + stq $6,48(%0) + xor $16,$18,$18 + subq %5,1,%5 + xor $18,$19,$19 # 8 cycles from $19 load + + stq $19,56(%0) + addq %4,64,%4 + addq %3,64,%3 + addq %2,64,%2 + + addq %1,64,%1 + addq %0,64,%0 + bgt %5,5b" + : "=&r"(d), "=&r"(s1), "=&r"(s2), "=&r"(s3), "=r"(s4), "=r"(lines) + /* ARG! We've run out of asm arguments! We've got to reload + all those pointers we just loaded. */ + : "r"(bh_ptr), "i" (&((struct buffer_head *)0)->b_data), "5"(lines) + : "memory", "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", + "$16", "$17", "$18", "$19", "$20", "$21"); + return; +} + +#define prefetch(base, ofs) \ + asm("ldq $31,%2(%0)" : "=r"(base) : "0"(base), "i"(ofs)) + +XORBLOCK_TEMPLATE(alpha_prefetch) +{ + long lines = bh_ptr[0]->b_size / sizeof (long) / 8; + long *d = (long *) bh_ptr[0]->b_data; + long *s1 = (long *) bh_ptr[1]->b_data; + long *s2, *s3, *s4; + long p; + + p = count == 2; + prefetch(d, 0); + prefetch(s1, 0); + prefetch(d, 64); + prefetch(s1, 64); + prefetch(d, 128); + prefetch(s1, 128); + prefetch(d, 192); + prefetch(s1, 192); + if (p) goto two_blocks; + + s2 = (long *) bh_ptr[2]->b_data; + p = count == 3; + prefetch(s2, 0); + prefetch(s2, 64); + prefetch(s2, 128); + prefetch(s2, 192); + if (p) goto three_blocks; + + s3 = (long *) bh_ptr[3]->b_data; + p = count == 4; + prefetch(s3, 0); + prefetch(s3, 64); + prefetch(s3, 128); + prefetch(s3, 192); + if (p) goto four_blocks; + + s4 = (long *) bh_ptr[4]->b_data; + prefetch(s4, 0); + prefetch(s4, 64); + prefetch(s4, 128); + prefetch(s4, 192); + goto five_blocks; + +two_blocks: +asm volatile (" + .align 4 +2: + ldq $0,0(%0) + ldq $1,0(%1) + ldq $2,8(%0) + ldq $3,8(%1) + + ldq $4,16(%0) + ldq $5,16(%1) + ldq $6,24(%0) + ldq $7,24(%1) + + ldq $16,32(%0) + ldq $17,32(%1) + ldq $18,40(%0) + ldq $19,40(%1) + + ldq $20,48(%0) + ldq $21,48(%1) + ldq $22,56(%0) + ldq $23,56(%1) + + ldq $31,256(%0) + xor $0,$1,$0 # 8 cycles from $1 load + ldq $31,256(%1) + xor $2,$3,$2 + + stq $0,0(%0) + xor $4,$5,$4 + stq $2,8(%0) + xor $6,$7,$6 + + stq $4,16(%0) + xor $16,$17,$16 + stq $6,24(%0) + xor $18,$19,$18 + + stq $16,32(%0) + xor $20,$21,$20 + stq $18,40(%0) + xor $22,$23,$22 + + stq $20,48(%0) + subq %2,1,%2 + stq $22,56(%0) + addq %0,64,%0 + + addq %1,64,%1 + bgt %2,2b" + : "=r"(d), "=r"(s1), "=r"(lines) + : "0"(d), "1"(s1), "2"(lines) + : "memory", "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", + "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23"); + return; + +three_blocks: +asm volatile (" + .align 4 +3: + ldq $0,0(%0) + ldq $1,0(%1) + ldq $2,0(%2) + ldq $3,8(%0) + + ldq $4,8(%1) + ldq $6,16(%0) + ldq $7,16(%1) + ldq $17,24(%0) + + ldq $18,24(%1) + ldq $20,32(%0) + ldq $21,32(%1) + ldq $5,8(%2) + + ldq $16,16(%2) + ldq $19,24(%2) + ldq $22,32(%2) + nop + + xor $0,$1,$1 # 8 cycles from $0 load + xor $3,$4,$4 # 7 cycles from $4 load + xor $6,$7,$7 # 6 cycles from $7 load + xor $17,$18,$18 # 5 cycles from $18 load + + xor $1,$2,$2 # 9 cycles from $2 load + xor $20,$21,$21 # 5 cycles from $21 load + stq $2,0(%0) + xor $4,$5,$5 # 6 cycles from $5 load + + stq $5,8(%0) + xor $7,$16,$16 # 7 cycles from $16 load + stq $16,16(%0) + xor $18,$19,$19 # 7 cycles from $19 load + + stq $19,24(%0) + xor $21,$22,$22 # 7 cycles from $22 load + stq $22,32(%0) + nop + + ldq $0,40(%0) + ldq $1,40(%1) + ldq $3,48(%0) + ldq $4,48(%1) + + ldq $6,56(%0) + ldq $7,56(%1) + ldq $2,40(%2) + ldq $5,48(%2) + + ldq $16,56(%2) + ldq $31,256(%0) + ldq $31,256(%1) + ldq $31,256(%2) + + xor $0,$1,$1 # 6 cycles from $1 load + xor $3,$4,$4 # 5 cycles from $4 load + xor $6,$7,$7 # 5 cycles from $7 load + xor $1,$2,$2 # 4 cycles from $2 load + + xor $4,$5,$5 # 5 cycles from $5 load + xor $7,$16,$16 # 4 cycles from $16 load + stq $2,40(%0) + subq %3,1,%3 + + stq $5,48(%0) + addq %2,64,%2 + stq $16,56(%0) + addq %1,64,%1 + + addq %0,64,%0 + bgt %3,3b" + : "=r"(d), "=r"(s1), "=r"(s2), "=r"(lines) + : "0"(d), "1"(s1), "2"(s2), "3"(lines) + : "memory", "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", + "$16", "$17", "$18", "$19", "$20", "$21", "$22"); + return; + +four_blocks: +asm volatile (" + .align 4 +4: + ldq $0,0(%0) + ldq $1,0(%1) + ldq $2,0(%2) + ldq $3,0(%3) + + ldq $4,8(%0) + ldq $5,8(%1) + ldq $6,8(%2) + ldq $7,8(%3) + + ldq $16,16(%0) + ldq $17,16(%1) + ldq $18,16(%2) + ldq $19,16(%3) + + ldq $20,24(%0) + xor $0,$1,$1 # 6 cycles from $1 load + ldq $21,24(%1) + xor $2,$3,$3 # 6 cycles from $3 load + + ldq $0,24(%2) + xor $1,$3,$3 + ldq $1,24(%3) + xor $4,$5,$5 # 7 cycles from $5 load + + stq $3,0(%0) + xor $6,$7,$7 + xor $16,$17,$17 # 7 cycles from $17 load + xor $5,$7,$7 + + stq $7,8(%0) + xor $18,$19,$19 # 7 cycles from $19 load + ldq $2,32(%0) + xor $17,$19,$19 + + ldq $3,32(%1) + ldq $4,32(%2) + ldq $5,32(%3) + xor $20,$21,$21 # 8 cycles from $21 load + + ldq $6,40(%0) + ldq $7,40(%1) + ldq $16,40(%2) + ldq $17,40(%3) + + stq $19,16(%0) + xor $0,$1,$1 # 9 cycles from $1 load + xor $2,$3,$3 # 5 cycles from $3 load + xor $21,$1,$1 + + ldq $18,48(%0) + xor $4,$5,$5 # 5 cycles from $5 load + ldq $19,48(%1) + xor $3,$5,$5 + + ldq $20,48(%2) + ldq $21,48(%3) + ldq $0,56(%0) + ldq $1,56(%1) + + ldq $2,56(%2) + xor $6,$7,$7 # 8 cycles from $6 load + ldq $3,56(%3) + xor $16,$17,$17 # 8 cycles from $17 load + + ldq $31,256(%0) + xor $7,$17,$17 + ldq $31,256(%1) + xor $18,$19,$19 # 6 cycles from $19 load + + ldq $31,256(%2) + xor $20,$21,$21 # 6 cycles from $21 load + ldq $31,256(%3) + xor $19,$21,$21 + + stq $1,24(%0) + xor $0,$1,$1 # 7 cycles from $1 load + stq $5,32(%0) + xor $2,$3,$3 # 6 cycles from $3 load + + stq $17,40(%0) + xor $1,$3,$3 + stq $21,48(%0) + subq %4,1,%4 + + stq $3,56(%0) + addq %3,64,%3 + addq %2,64,%2 + addq %1,64,%1 + + addq %0,64,%0 + bgt %4,4b" + : "=r"(d), "=r"(s1), "=r"(s2), "=r"(s3), "=r"(lines) + : "0"(d), "1"(s1), "2"(s2), "3"(s3), "4"(lines) + : "memory", "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", + "$16", "$17", "$18", "$19", "$20", "$21"); + return; + +five_blocks: +asm volatile (" + ldq %0,0(%6) + ldq %1,8(%6) + ldq %2,16(%6) + ldq %3,24(%6) + ldq %4,32(%6) + ldq %0,%7(%0) + ldq %1,%7(%1) + ldq %2,%7(%2) + ldq %3,%7(%3) + ldq %4,%7(%4) + .align 4 +5: + ldq $0,0(%0) + ldq $1,0(%1) + ldq $2,0(%2) + ldq $3,0(%3) + + ldq $4,0(%4) + ldq $5,8(%0) + ldq $6,8(%1) + ldq $7,8(%2) + + ldq $16,8(%3) + ldq $17,8(%4) + ldq $18,16(%0) + ldq $19,16(%1) + + ldq $20,16(%2) + xor $0,$1,$1 # 6 cycles from $1 load + ldq $21,16(%3) + xor $2,$3,$3 # 6 cycles from $3 load + + ldq $0,16(%4) + xor $1,$3,$3 + ldq $1,24(%0) + xor $3,$4,$4 # 7 cycles from $4 load + + stq $4,0(%0) + xor $5,$6,$6 # 7 cycles from $6 load + xor $7,$16,$16 # 7 cycles from $16 load + xor $6,$17,$17 # 7 cycles from $17 load + + ldq $2,24(%1) + xor $16,$17,$17 + ldq $3,24(%2) + xor $18,$19,$19 # 8 cycles from $19 load + + stq $17,8(%0) + xor $19,$20,$20 # 8 cycles from $20 load + ldq $4,24(%3) + xor $21,$0,$0 # 7 cycles from $0 load + + ldq $5,24(%4) + xor $20,$0,$0 + ldq $6,32(%0) + ldq $7,32(%1) + + stq $0,16(%0) + xor $1,$2,$2 # 6 cycles from $2 load + ldq $16,32(%2) + xor $3,$4,$4 # 4 cycles from $4 load + + ldq $17,32(%3) + xor $2,$4,$4 + ldq $18,32(%4) + ldq $19,40(%0) + + ldq $20,40(%1) + ldq $21,40(%2) + ldq $0,40(%3) + xor $4,$5,$5 # 7 cycles from $5 load + + stq $5,24(%0) + xor $6,$7,$7 # 7 cycles from $7 load + ldq $1,40(%4) + ldq $2,48(%0) + + ldq $3,48(%1) + xor $7,$16,$16 # 7 cycles from $16 load + ldq $4,48(%2) + xor $17,$18,$18 # 6 cycles from $18 load + + ldq $5,48(%3) + xor $16,$18,$18 + ldq $6,48(%4) + xor $19,$20,$20 # 7 cycles from $20 load + + stq $18,32(%0) + xor $20,$21,$21 # 8 cycles from $21 load + ldq $7,56(%0) + xor $0,$1,$1 # 6 cycles from $1 load + + ldq $16,56(%1) + ldq $17,56(%2) + ldq $18,56(%3) + ldq $19,56(%4) + + ldq $31,256(%0) + xor $21,$1,$1 + ldq $31,256(%1) + xor $2,$3,$3 # 9 cycles from $3 load + + ldq $31,256(%2) + xor $3,$4,$4 # 9 cycles from $4 load + ldq $31,256(%3) + xor $5,$6,$6 # 8 cycles from $6 load + + ldq $31,256(%4) + xor $4,$6,$6 + xor $7,$16,$16 # 7 cycles from $16 load + xor $17,$18,$18 # 6 cycles from $18 load + + stq $6,48(%0) + xor $16,$18,$18 + subq %5,1,%5 + xor $18,$19,$19 # 8 cycles from $19 load + + stq $19,56(%0) + addq %4,64,%4 + addq %3,64,%3 + addq %2,64,%2 + + addq %1,64,%1 + addq %0,64,%0 + bgt %5,5b" + : "=&r"(d), "=&r"(s1), "=&r"(s2), "=&r"(s3), "=r"(s4), "=r"(lines) + /* ARG! We've run out of asm arguments! We've got to reload + all those pointers we just loaded. */ + : "r"(bh_ptr), "i" (&((struct buffer_head *)0)->b_data), "5"(lines) + : "memory", "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", + "$16", "$17", "$18", "$19", "$20", "$21"); + return; +} + +#undef prefetch + +#endif /* __alpha__ */ + +#ifndef __sparc_v9__ + +/* + * this one works reasonably on any x86 CPU + * (send me an assembly version for inclusion if you can make it faster) + * + * this one is just as fast as written in pure assembly on x86. + * the reason for this separate version is that the + * fast open-coded xor routine "32reg" produces suboptimal code + * on x86, due to lack of registers. + */ +XORBLOCK_TEMPLATE(8regs) +{ + int len = bh_ptr[0]->b_size; + long *destp = (long *) bh_ptr[0]->b_data; + long *source1, *source2, *source3, *source4; + long lines = len / (sizeof (long)) / 8, i; + + switch(count) { + case 2: + source1 = (long *) bh_ptr[1]->b_data; + for (i = lines; i > 0; i--) { + *(destp + 0) ^= *(source1 + 0); + *(destp + 1) ^= *(source1 + 1); + *(destp + 2) ^= *(source1 + 2); + *(destp + 3) ^= *(source1 + 3); + *(destp + 4) ^= *(source1 + 4); + *(destp + 5) ^= *(source1 + 5); + *(destp + 6) ^= *(source1 + 6); + *(destp + 7) ^= *(source1 + 7); + source1 += 8; + destp += 8; + } + break; + case 3: + source2 = (long *) bh_ptr[2]->b_data; + source1 = (long *) bh_ptr[1]->b_data; + for (i = lines; i > 0; i--) { + *(destp + 0) ^= *(source1 + 0); + *(destp + 0) ^= *(source2 + 0); + *(destp + 1) ^= *(source1 + 1); + *(destp + 1) ^= *(source2 + 1); + *(destp + 2) ^= *(source1 + 2); + *(destp + 2) ^= *(source2 + 2); + *(destp + 3) ^= *(source1 + 3); + *(destp + 3) ^= *(source2 + 3); + *(destp + 4) ^= *(source1 + 4); + *(destp + 4) ^= *(source2 + 4); + *(destp + 5) ^= *(source1 + 5); + *(destp + 5) ^= *(source2 + 5); + *(destp + 6) ^= *(source1 + 6); + *(destp + 6) ^= *(source2 + 6); + *(destp + 7) ^= *(source1 + 7); + *(destp + 7) ^= *(source2 + 7); + source1 += 8; + source2 += 8; + destp += 8; + } + break; + case 4: + source3 = (long *) bh_ptr[3]->b_data; + source2 = (long *) bh_ptr[2]->b_data; + source1 = (long *) bh_ptr[1]->b_data; + for (i = lines; i > 0; i--) { + *(destp + 0) ^= *(source1 + 0); + *(destp + 0) ^= *(source2 + 0); + *(destp + 0) ^= *(source3 + 0); + *(destp + 1) ^= *(source1 + 1); + *(destp + 1) ^= *(source2 + 1); + *(destp + 1) ^= *(source3 + 1); + *(destp + 2) ^= *(source1 + 2); + *(destp + 2) ^= *(source2 + 2); + *(destp + 2) ^= *(source3 + 2); + *(destp + 3) ^= *(source1 + 3); + *(destp + 3) ^= *(source2 + 3); + *(destp + 3) ^= *(source3 + 3); + *(destp + 4) ^= *(source1 + 4); + *(destp + 4) ^= *(source2 + 4); + *(destp + 4) ^= *(source3 + 4); + *(destp + 5) ^= *(source1 + 5); + *(destp + 5) ^= *(source2 + 5); + *(destp + 5) ^= *(source3 + 5); + *(destp + 6) ^= *(source1 + 6); + *(destp + 6) ^= *(source2 + 6); + *(destp + 6) ^= *(source3 + 6); + *(destp + 7) ^= *(source1 + 7); + *(destp + 7) ^= *(source2 + 7); + *(destp + 7) ^= *(source3 + 7); + source1 += 8; + source2 += 8; + source3 += 8; + destp += 8; + } + break; + case 5: + source4 = (long *) bh_ptr[4]->b_data; + source3 = (long *) bh_ptr[3]->b_data; + source2 = (long *) bh_ptr[2]->b_data; + source1 = (long *) bh_ptr[1]->b_data; + for (i = lines; i > 0; i--) { + *(destp + 0) ^= *(source1 + 0); + *(destp + 0) ^= *(source2 + 0); + *(destp + 0) ^= *(source3 + 0); + *(destp + 0) ^= *(source4 + 0); + *(destp + 1) ^= *(source1 + 1); + *(destp + 1) ^= *(source2 + 1); + *(destp + 1) ^= *(source3 + 1); + *(destp + 1) ^= *(source4 + 1); + *(destp + 2) ^= *(source1 + 2); + *(destp + 2) ^= *(source2 + 2); + *(destp + 2) ^= *(source3 + 2); + *(destp + 2) ^= *(source4 + 2); + *(destp + 3) ^= *(source1 + 3); + *(destp + 3) ^= *(source2 + 3); + *(destp + 3) ^= *(source3 + 3); + *(destp + 3) ^= *(source4 + 3); + *(destp + 4) ^= *(source1 + 4); + *(destp + 4) ^= *(source2 + 4); + *(destp + 4) ^= *(source3 + 4); + *(destp + 4) ^= *(source4 + 4); + *(destp + 5) ^= *(source1 + 5); + *(destp + 5) ^= *(source2 + 5); + *(destp + 5) ^= *(source3 + 5); + *(destp + 5) ^= *(source4 + 5); + *(destp + 6) ^= *(source1 + 6); + *(destp + 6) ^= *(source2 + 6); + *(destp + 6) ^= *(source3 + 6); + *(destp + 6) ^= *(source4 + 6); + *(destp + 7) ^= *(source1 + 7); + *(destp + 7) ^= *(source2 + 7); + *(destp + 7) ^= *(source3 + 7); + *(destp + 7) ^= *(source4 + 7); + source1 += 8; + source2 += 8; + source3 += 8; + source4 += 8; + destp += 8; + } + break; + } +} + +/* + * platform independent RAID5 checksum calculation, this should + * be very fast on any platform that has a decent amount of + * registers. (32 or more) + */ +XORBLOCK_TEMPLATE(32regs) +{ + int size = bh_ptr[0]->b_size; + int lines = size / (sizeof (long)) / 8, i; + long *destp = (long *) bh_ptr[0]->b_data; + long *source1, *source2, *source3, *source4; + + /* LOTS of registers available... + We do explicite loop-unrolling here for code which + favours RISC machines. In fact this is almoast direct + RISC assembly on Alpha and SPARC :-) */ + + + switch(count) { + case 2: + source1 = (long *) bh_ptr[1]->b_data; + for (i = lines; i > 0; i--) { + register long d0, d1, d2, d3, d4, d5, d6, d7; + d0 = destp[0]; /* Pull the stuff into registers */ + d1 = destp[1]; /* ... in bursts, if possible. */ + d2 = destp[2]; + d3 = destp[3]; + d4 = destp[4]; + d5 = destp[5]; + d6 = destp[6]; + d7 = destp[7]; + d0 ^= source1[0]; + d1 ^= source1[1]; + d2 ^= source1[2]; + d3 ^= source1[3]; + d4 ^= source1[4]; + d5 ^= source1[5]; + d6 ^= source1[6]; + d7 ^= source1[7]; + destp[0] = d0; /* Store the result (in burts) */ + destp[1] = d1; + destp[2] = d2; + destp[3] = d3; + destp[4] = d4; /* Store the result (in burts) */ + destp[5] = d5; + destp[6] = d6; + destp[7] = d7; + source1 += 8; + destp += 8; + } + break; + case 3: + source2 = (long *) bh_ptr[2]->b_data; + source1 = (long *) bh_ptr[1]->b_data; + for (i = lines; i > 0; i--) { + register long d0, d1, d2, d3, d4, d5, d6, d7; + d0 = destp[0]; /* Pull the stuff into registers */ + d1 = destp[1]; /* ... in bursts, if possible. */ + d2 = destp[2]; + d3 = destp[3]; + d4 = destp[4]; + d5 = destp[5]; + d6 = destp[6]; + d7 = destp[7]; + d0 ^= source1[0]; + d1 ^= source1[1]; + d2 ^= source1[2]; + d3 ^= source1[3]; + d4 ^= source1[4]; + d5 ^= source1[5]; + d6 ^= source1[6]; + d7 ^= source1[7]; + d0 ^= source2[0]; + d1 ^= source2[1]; + d2 ^= source2[2]; + d3 ^= source2[3]; + d4 ^= source2[4]; + d5 ^= source2[5]; + d6 ^= source2[6]; + d7 ^= source2[7]; + destp[0] = d0; /* Store the result (in burts) */ + destp[1] = d1; + destp[2] = d2; + destp[3] = d3; + destp[4] = d4; /* Store the result (in burts) */ + destp[5] = d5; + destp[6] = d6; + destp[7] = d7; + source1 += 8; + source2 += 8; + destp += 8; + } + break; + case 4: + source3 = (long *) bh_ptr[3]->b_data; + source2 = (long *) bh_ptr[2]->b_data; + source1 = (long *) bh_ptr[1]->b_data; + for (i = lines; i > 0; i--) { + register long d0, d1, d2, d3, d4, d5, d6, d7; + d0 = destp[0]; /* Pull the stuff into registers */ + d1 = destp[1]; /* ... in bursts, if possible. */ + d2 = destp[2]; + d3 = destp[3]; + d4 = destp[4]; + d5 = destp[5]; + d6 = destp[6]; + d7 = destp[7]; + d0 ^= source1[0]; + d1 ^= source1[1]; + d2 ^= source1[2]; + d3 ^= source1[3]; + d4 ^= source1[4]; + d5 ^= source1[5]; + d6 ^= source1[6]; + d7 ^= source1[7]; + d0 ^= source2[0]; + d1 ^= source2[1]; + d2 ^= source2[2]; + d3 ^= source2[3]; + d4 ^= source2[4]; + d5 ^= source2[5]; + d6 ^= source2[6]; + d7 ^= source2[7]; + d0 ^= source3[0]; + d1 ^= source3[1]; + d2 ^= source3[2]; + d3 ^= source3[3]; + d4 ^= source3[4]; + d5 ^= source3[5]; + d6 ^= source3[6]; + d7 ^= source3[7]; + destp[0] = d0; /* Store the result (in burts) */ + destp[1] = d1; + destp[2] = d2; + destp[3] = d3; + destp[4] = d4; /* Store the result (in burts) */ + destp[5] = d5; + destp[6] = d6; + destp[7] = d7; + source1 += 8; + source2 += 8; + source3 += 8; + destp += 8; + } + break; + case 5: + source4 = (long *) bh_ptr[4]->b_data; + source3 = (long *) bh_ptr[3]->b_data; + source2 = (long *) bh_ptr[2]->b_data; + source1 = (long *) bh_ptr[1]->b_data; + for (i = lines; i > 0; i--) { + register long d0, d1, d2, d3, d4, d5, d6, d7; + d0 = destp[0]; /* Pull the stuff into registers */ + d1 = destp[1]; /* ... in bursts, if possible. */ + d2 = destp[2]; + d3 = destp[3]; + d4 = destp[4]; + d5 = destp[5]; + d6 = destp[6]; + d7 = destp[7]; + d0 ^= source1[0]; + d1 ^= source1[1]; + d2 ^= source1[2]; + d3 ^= source1[3]; + d4 ^= source1[4]; + d5 ^= source1[5]; + d6 ^= source1[6]; + d7 ^= source1[7]; + d0 ^= source2[0]; + d1 ^= source2[1]; + d2 ^= source2[2]; + d3 ^= source2[3]; + d4 ^= source2[4]; + d5 ^= source2[5]; + d6 ^= source2[6]; + d7 ^= source2[7]; + d0 ^= source3[0]; + d1 ^= source3[1]; + d2 ^= source3[2]; + d3 ^= source3[3]; + d4 ^= source3[4]; + d5 ^= source3[5]; + d6 ^= source3[6]; + d7 ^= source3[7]; + d0 ^= source4[0]; + d1 ^= source4[1]; + d2 ^= source4[2]; + d3 ^= source4[3]; + d4 ^= source4[4]; + d5 ^= source4[5]; + d6 ^= source4[6]; + d7 ^= source4[7]; + destp[0] = d0; /* Store the result (in burts) */ + destp[1] = d1; + destp[2] = d2; + destp[3] = d3; + destp[4] = d4; /* Store the result (in burts) */ + destp[5] = d5; + destp[6] = d6; + destp[7] = d7; + source1 += 8; + source2 += 8; + source3 += 8; + source4 += 8; + destp += 8; + } + break; + } +} + +/* + * (the -6*32 shift factor colors the cache) + */ +#define SIZE (PAGE_SIZE-6*32) + +static void xor_speed ( struct xor_block_template * func, + struct buffer_head *b1, struct buffer_head *b2) +{ + int speed; + unsigned long now; + int i, count, max; + struct buffer_head *bh_ptr[6]; + + func->next = xor_functions; + xor_functions = func; + bh_ptr[0] = b1; + bh_ptr[1] = b2; + + /* + * count the number of XORs done during a whole jiffy. + * calculate the speed of checksumming from this. + * (we use a 2-page allocation to have guaranteed + * color L1-cache layout) + */ + max = 0; + for (i = 0; i < 5; i++) { + now = jiffies; + count = 0; + while (jiffies == now) { + mb(); + func->xor_block(2,bh_ptr); + mb(); + count++; + mb(); + } + if (count > max) + max = count; + } + + speed = max * (HZ*SIZE/1024); + func->speed = speed; + + printk( " %-10s: %5d.%03d MB/sec\n", func->name, + speed / 1000, speed % 1000); +} + +static inline void pick_fastest_function(void) +{ + struct xor_block_template *f, *fastest; + + fastest = xor_functions; + for (f = fastest; f; f = f->next) { + if (f->speed > fastest->speed) + fastest = f; + } +#ifdef CONFIG_X86_XMM + if (cpu_has_xmm) { + /* we force the use of the KNI xor block because it + can write around l2. we may also be able + to load into the l1 only depending on how + the cpu deals with a load to a line that is + being prefetched. + */ + fastest = &t_xor_block_pIII_kni; + } +#endif +#ifdef __alpha__ + if (implver() == IMPLVER_EV6) { + /* Force the use of alpha_prefetch if EV6, as it + is significantly faster in the cold cache case. */ + fastest = &t_xor_block_alpha_prefetch; + } +#endif + xor_block = fastest->xor_block; + printk( "using fastest function: %s (%d.%03d MB/sec)\n", fastest->name, + fastest->speed / 1000, fastest->speed % 1000); +} + +static struct buffer_head b1, b2; + +void calibrate_xor_block(void) +{ + if (xor_block) + return; + memset(&b1,0,sizeof(b1)); + b2 = b1; + + b1.b_data = (char *) md__get_free_pages(GFP_KERNEL,2); + if (!b1.b_data) { + pick_fastest_function(); + return; + } + b2.b_data = b1.b_data + 2*PAGE_SIZE + SIZE; + + b1.b_size = SIZE; + + printk(KERN_INFO "raid5: measuring checksumming speed\n"); + + sti(); /* should be safe */ + +#if defined(__sparc__) && !defined(__sparc_v9__) + printk(KERN_INFO "raid5: trying high-speed SPARC checksum routine\n"); + xor_speed(&t_xor_block_SPARC,&b1,&b2); +#endif + +#ifdef CONFIG_X86_XMM + if (cpu_has_xmm) { + printk(KERN_INFO + "raid5: KNI detected, trying cache-avoiding KNI checksum routine\n"); + xor_speed(&t_xor_block_pIII_kni,&b1,&b2); + } +#endif /* CONFIG_X86_XMM */ + +#ifdef __i386__ + if (md_cpu_has_mmx()) { + printk(KERN_INFO + "raid5: MMX detected, trying high-speed MMX checksum routines\n"); + xor_speed(&t_xor_block_pII_mmx,&b1,&b2); + xor_speed(&t_xor_block_p5_mmx,&b1,&b2); + } +#endif /* __i386__ */ + +#ifdef __alpha__ + xor_speed(&t_xor_block_alpha,&b1,&b2); + xor_speed(&t_xor_block_alpha_prefetch,&b1,&b2); +#endif + + xor_speed(&t_xor_block_8regs,&b1,&b2); + xor_speed(&t_xor_block_32regs,&b1,&b2); + + free_pages((unsigned long)b1.b_data,2); + pick_fastest_function(); +} + +#else /* __sparc_v9__ */ + +void calibrate_xor_block(void) +{ + if (xor_block) + return; + printk(KERN_INFO "raid5: using high-speed VIS checksum routine\n"); + xor_block = xor_block_VIS; +} + +#endif /* __sparc_v9__ */ + +MD_EXPORT_SYMBOL(xor_block); +MD_EXPORT_SYMBOL(calibrate_xor_block); + +#ifdef MODULE +int init_module(void) +{ + calibrate_xor_block(); + return 0; +} +#endif diff -u --recursive --new-file v2.4.0-test8/linux/drivers/media/radio/Config.in linux/drivers/media/radio/Config.in --- v2.4.0-test8/linux/drivers/media/radio/Config.in Wed Aug 23 14:59:55 2000 +++ linux/drivers/media/radio/Config.in Tue Sep 19 08:01:34 2000 @@ -21,6 +21,7 @@ if [ "$CONFIG_RADIO_GEMTEK" = "y" ]; then hex ' GemTek i/o port (0x20c, 0x30c, 0x24c or 0x34c)' CONFIG_RADIO_GEMTEK_PORT 34c fi +dep_tristate ' Maestro on board radio' CONFIG_RADIO_MAESTRO $CONFIG_VIDEO_DEV dep_tristate ' Miro PCM20 Radio' CONFIG_RADIO_MIROPCM20 $CONFIG_VIDEO_DEV dep_tristate ' SF16FMI Radio' CONFIG_RADIO_SF16FMI $CONFIG_VIDEO_DEV if [ "$CONFIG_RADIO_SF16FMI" = "y" ]; then diff -u --recursive --new-file v2.4.0-test8/linux/drivers/media/radio/Makefile linux/drivers/media/radio/Makefile --- v2.4.0-test8/linux/drivers/media/radio/Makefile Tue Aug 22 11:29:02 2000 +++ linux/drivers/media/radio/Makefile Tue Sep 19 08:01:34 2000 @@ -45,6 +45,7 @@ obj-$(CONFIG_RADIO_MIROPCM20) += radio-miropcm20.o obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o obj-$(CONFIG_RADIO_TRUST) += radio-trust.o +obj-$(CONFIG_RADIO_MAESTRO) += radio-maestro.o # Extract lists of the multi-part drivers. # The 'int-*' lists are the intermediate files used to build the multi's. diff -u --recursive --new-file v2.4.0-test8/linux/drivers/media/radio/radio-maestro.c linux/drivers/media/radio/radio-maestro.c --- v2.4.0-test8/linux/drivers/media/radio/radio-maestro.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/media/radio/radio-maestro.c Tue Sep 19 08:01:34 2000 @@ -0,0 +1,384 @@ +/* Maestro PCI sound card radio driver for Linux support + * (c) 2000 A. Tlalka, atlka@pg.gda.pl + * Notes on the hardware + * + * + Frequency control is done digitally + * + No volume control - only mute/unmute - you have to use Aux line volume + * control on Maestro card to set the volume + * + Radio status (tuned/not_tuned and stereo/mono) is valid some time after + * frequency setting (>100ms) and only when the radio is unmuted. + * version 0.02 + * + io port is automatically detected - only the first radio is used + * version 0.03 + * + thread access locking additions + * version 0.04 + * + code improvements + * + VIDEO_TUNER_LOW is permanent + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_VERSION "0.04" + +#define PCI_VENDOR_ESS 0x125D +#define PCI_DEVICE_ID_ESS_ESS1968 0x1968 /* Maestro 2 */ +#define PCI_DEVICE_ID_ESS_ESS1978 0x1978 /* Maestro 2E */ + +#define GPIO_DATA 0x60 /* port offset from ESS_IO_BASE */ + +#define IO_MASK 4 /* mask register offset from GPIO_DATA + bits 1=unmask write to given bit */ +#define IO_DIR 8 /* direction register offset from GPIO_DATA + bits 0/1=read/write direction */ + +#define GPIO6 0x0040 /* mask bits for GPIO lines */ +#define GPIO7 0x0080 +#define GPIO8 0x0100 +#define GPIO9 0x0200 + +#define STR_DATA GPIO6 /* radio TEA5757 pins and GPIO bits */ +#define STR_CLK GPIO7 +#define STR_WREN GPIO8 +#define STR_MOST GPIO9 + +#define FREQ_LO 50*16000 +#define FREQ_HI 150*16000 + +#define FREQ_IF 171200 /* 10.7*16000 */ +#define FREQ_STEP 200 /* 12.5*16 */ + +#define FREQ2BITS(x) ((((unsigned int)(x)+FREQ_IF+(FREQ_STEP<<1))\ + /(FREQ_STEP<<2))<<2) /* (x==fmhz*16*1000) -> bits */ + +#define BITS2FREQ(x) ((x) * FREQ_STEP - FREQ_IF) + + + +static int radio_open(struct video_device *, int); +static int radio_ioctl(struct video_device *, unsigned int, void *); +static void radio_close(struct video_device *); + +static struct video_device maestro_radio= +{ + "Maestro radio", + VID_TYPE_TUNER, + VID_HARDWARE_SF16MI, + radio_open, + radio_close, + NULL, + NULL, + NULL, + radio_ioctl, + NULL, + NULL +}; + +static struct radio_device +{ + __u16 io, /* base of Maestro card radio io (GPIO_DATA)*/ + muted, /* VIDEO_AUDIO_MUTE */ + stereo, /* VIDEO_TUNER_STEREO_ON */ + tuned; /* signal strength (0 or 0xffff) */ + struct semaphore lock; +} radio_unit = {0, 0, 0, 0, }; + +static int users = 0; + +static void sleep_125ms(void) +{ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ >> 3); +} + +static void udelay2(void) +{ + udelay(2); +} + +static void udelay4(void) +{ + udelay(4); +} + +static void udelay16(void) +{ + udelay(16); +} + +static __u32 radio_bits_get(struct radio_device *dev) +{ + register __u16 io=dev->io, l, rdata; + register __u32 data=0; + __u16 omask; + omask = inw(io + IO_MASK); + outw(~(STR_CLK | STR_WREN), io + IO_MASK); + outw(0, io); + udelay16(); + for (l=24;l--;) { + outw(STR_CLK, io); /* HI state */ + udelay2(); + if(!l) + dev->tuned = inw(io) & STR_MOST ? 0 : 0xffff; + outw(0, io); /* LO state */ + udelay2(); + data <<= 1; /* shift data */ + rdata = inw(io); + if(!l) + dev->stereo = rdata & STR_MOST ? + 0 : VIDEO_TUNER_STEREO_ON; + else + if(rdata & STR_DATA) + data++; + udelay2(); + } + if(dev->muted) + outw(STR_WREN, io); + udelay4(); + outw(omask, io + IO_MASK); + return data & 0x3ffe; +} + +static void radio_bits_set(struct radio_device *dev, __u32 data) +{ + register __u16 io=dev->io, l, bits; + __u16 omask, odir; + omask = inw(io + IO_MASK); + odir = (inw(io + IO_DIR) & ~STR_DATA) | (STR_CLK | STR_WREN); + outw(odir | STR_DATA, io + IO_DIR); + outw(~(STR_DATA | STR_CLK | STR_WREN), io + IO_MASK); + udelay16(); + for (l=25;l;l--) { + bits = ((data >> 18) & STR_DATA) | STR_WREN ; + data <<= 1; /* shift data */ + outw(bits, io); /* start strobe */ + udelay2(); + outw(bits | STR_CLK, io); /* HI level */ + udelay2(); + outw(bits, io); /* LO level */ + udelay4(); + } + if(!dev->muted) + outw(0, io); + udelay4(); + outw(omask, io + IO_MASK); + outw(odir, io + IO_DIR); + sleep_125ms(); +} + +inline static int radio_function(struct video_device *dev, + unsigned int cmd, void *arg) +{ + struct radio_device *card=dev->priv; + switch(cmd) { + case VIDIOCGCAP: { + struct video_capability v; + strcpy(v.name, "Maestro radio"); + v.type=VID_TYPE_TUNER; + v.channels=v.audios=1; + v.maxwidth=v.maxheight=v.minwidth=v.minheight=0; + if(copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCGTUNER: { + struct video_tuner v; + if(copy_from_user(&v, arg,sizeof(v))!=0) + return -EFAULT; + if(v.tuner) + return -EINVAL; + (void)radio_bits_get(card); + v.flags = VIDEO_TUNER_LOW | card->stereo; + v.signal = card->tuned; + strcpy(v.name, "FM"); + v.rangelow = FREQ_LO; + v.rangehigh = FREQ_HI; + v.mode = VIDEO_MODE_AUTO; + if(copy_to_user(arg,&v, sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSTUNER: { + struct video_tuner v; + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if(v.tuner!=0) + return -EINVAL; + return 0; + } + case VIDIOCGFREQ: { + unsigned long tmp=BITS2FREQ(radio_bits_get(card)); + if(copy_to_user(arg, &tmp, sizeof(tmp))) + return -EFAULT; + return 0; + } + case VIDIOCSFREQ: { + unsigned long tmp; + if(copy_from_user(&tmp, arg, sizeof(tmp))) + return -EFAULT; + if ( tmpFREQ_HI ) + return -EINVAL; + radio_bits_set(card, FREQ2BITS(tmp)); + return 0; + } + case VIDIOCGAUDIO: { + struct video_audio v; + strcpy(v.name, "Radio"); + v.audio=v.volume=v.bass=v.treble=v.balance=v.step=0; + v.flags=VIDEO_AUDIO_MUTABLE | card->muted; + v.mode=VIDEO_SOUND_STEREO; + if(copy_to_user(arg,&v, sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSAUDIO: { + struct video_audio v; + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + if(v.audio) + return -EINVAL; + { + register __u16 io=card->io; + register __u16 omask = inw(io + IO_MASK); + outw(~STR_WREN, io + IO_MASK); + outw((card->muted = v.flags & VIDEO_AUDIO_MUTE) + ? STR_WREN : 0, io); + udelay4(); + outw(omask, io + IO_MASK); + sleep_125ms(); + return 0; + } + } + case VIDIOCGUNIT: { + struct video_unit v; + v.video=VIDEO_NO_UNIT; + v.vbi=VIDEO_NO_UNIT; + v.radio=dev->minor; + v.audio=0; + v.teletext=VIDEO_NO_UNIT; + if(copy_to_user(arg, &v, sizeof(v))) + return -EFAULT; + return 0; + } + default: return -ENOIOCTLCMD; + } +} + +static int radio_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct radio_device *card=dev->priv; + int ret; + down(&card->lock); + ret = radio_function(dev, cmd, arg); + up(&card->lock); + return ret; +} + +static int radio_open(struct video_device *dev, int flags) +{ + if(users) + return -EBUSY; + users++; + MOD_INC_USE_COUNT; + return 0; +} + +static void radio_close(struct video_device *dev) +{ + users--; + MOD_DEC_USE_COUNT; +} + + +inline static __u16 radio_install(struct pci_dev *pcidev); + +#ifdef MODULE +MODULE_AUTHOR("Adam Tlalka, atlka@pg.gda.pl"); +MODULE_DESCRIPTION("Radio driver for the Maestro PCI sound card radio."); + +EXPORT_NO_SYMBOLS; + +void cleanup_module(void) +{ + video_unregister_device(&maestro_radio); +} + +int init_module(void) +#else +int __init maestro_radio_init(struct video_init *v) +#endif +{ + register __u16 found=0; + struct pci_dev *pcidev = NULL; + if(!pci_present()) + return -ENODEV; + while(!found && (pcidev = pci_find_device(PCI_VENDOR_ESS, + PCI_DEVICE_ID_ESS_ESS1968, + pcidev))) + found |= radio_install(pcidev); + while(!found && (pcidev = pci_find_device(PCI_VENDOR_ESS, + PCI_DEVICE_ID_ESS_ESS1978, + pcidev))) + found |= radio_install(pcidev); + if(!found) { + printk(KERN_INFO "radio-maestro: no devices found.\n"); + return -ENODEV; + } + return 0; +} + +inline static __u16 radio_power_on(struct radio_device *dev) +{ + register __u16 io=dev->io; + register __u32 ofreq; + __u16 omask, odir; + omask = inw(io + IO_MASK); + odir = (inw(io + IO_DIR) & ~STR_DATA) | (STR_CLK | STR_WREN); + outw(odir & ~STR_WREN, io + IO_DIR); + dev->muted = inw(io) & STR_WREN ? 0 : VIDEO_AUDIO_MUTE; + outw(odir, io + IO_DIR); + outw(~(STR_WREN | STR_CLK), io + IO_MASK); + outw(dev->muted ? 0 : STR_WREN, io); + udelay16(); + outw(omask, io + IO_MASK); + ofreq = radio_bits_get(dev); + if((ofreqFREQ2BITS(FREQ_HI))) + ofreq = FREQ2BITS(FREQ_LO); + radio_bits_set(dev, ofreq); + return (ofreq == radio_bits_get(dev)); +} + +inline static __u16 radio_install(struct pci_dev *pcidev) +{ + if(((pcidev->class >> 8) & 0xffff) != PCI_CLASS_MULTIMEDIA_AUDIO) + return 0; + + radio_unit.io = pcidev->resource[0].start + GPIO_DATA; + maestro_radio.priv = &radio_unit; + init_MUTEX(&radio_unit.lock); + + if(radio_power_on(&radio_unit)) { + if(video_register_device(&maestro_radio, VFL_TYPE_RADIO)==-1) { + printk("radio-maestro: can't register device!"); + return 0; + } + printk(KERN_INFO "radio-maestro: version " + DRIVER_VERSION + " time " + __TIME__ " " + __DATE__ + "\n"); + printk(KERN_INFO "radio-maestro: radio chip initialized\n"); + return 1; + } else + return 0; +} + diff -u --recursive --new-file v2.4.0-test8/linux/drivers/media/video/bttv-driver.c linux/drivers/media/video/bttv-driver.c --- v2.4.0-test8/linux/drivers/media/video/bttv-driver.c Mon Aug 7 21:01:35 2000 +++ linux/drivers/media/video/bttv-driver.c Sun Sep 17 09:45:06 2000 @@ -3027,11 +3027,11 @@ * Scan for a Bt848 card, request the irq and map the io memory */ -static void __devinit bttv_remove(struct pci_dev *pci_dev) +static void __devexit bttv_remove(struct pci_dev *pci_dev) { u8 command; int j; - struct bttv *btv = PCI_GET_DRIVER_DATA(pci_dev); + struct bttv *btv = pci_get_drvdata(pci_dev); /* unregister i2c_bus */ if (0 == btv->i2c_ok) @@ -3093,6 +3093,8 @@ btv->shutdown=1; wake_up(&btv->gpioq); + pci_set_drvdata(pci_dev, NULL); + return; } @@ -3198,7 +3200,7 @@ } } - PCI_SET_DRIVER_DATA(dev,btv); + pci_set_drvdata(dev,btv); if(init_bt848(btv) < 0) { bttv_remove(dev); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/media/video/bttv.h linux/drivers/media/video/bttv.h --- v2.4.0-test8/linux/drivers/media/video/bttv.h Sun Aug 6 12:45:28 2000 +++ linux/drivers/media/video/bttv.h Sun Sep 17 09:45:06 2000 @@ -23,11 +23,6 @@ #define BTTV_VERSION_CODE KERNEL_VERSION(0,7,38) -#ifndef PCI_GET_DRIVER_DATA -# define PCI_GET_DRIVER_DATA(pdev) ((pdev)->driver_data) -# define PCI_SET_DRIVER_DATA(pdev,data) (((pdev)->driver_data) = (data)) -#endif /* PCI_GET_DRIVER_DATA */ - #include #include #include diff -u --recursive --new-file v2.4.0-test8/linux/drivers/media/video/buz.c linux/drivers/media/video/buz.c --- v2.4.0-test8/linux/drivers/media/video/buz.c Mon Aug 7 21:01:35 2000 +++ linux/drivers/media/video/buz.c Tue Sep 19 08:01:34 2000 @@ -202,6 +202,7 @@ mem_map_reserve(virt_to_page(mem + off)); DEBUG(printk(BUZ_INFO ": V4L frame %d mem 0x%x (bus: 0x%x=%d)\n", i, mem, virt_to_bus(mem), virt_to_bus(mem))); } else { + v4l_fbuffer_free(zr); return -ENOBUFS; } } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/media/video/cpia_usb.c linux/drivers/media/video/cpia_usb.c --- v2.4.0-test8/linux/drivers/media/video/cpia_usb.c Tue Sep 5 13:42:52 2000 +++ linux/drivers/media/video/cpia_usb.c Mon Sep 18 17:31:25 2000 @@ -187,7 +187,7 @@ if (ret < 0) { printk(KERN_ERR "cpia_usb_open: usb_set_interface error (ret = %d)\n", ret); retval = -EBUSY; - goto error_all; + goto error_1; } ucpia->buffers[0]->status = FRAME_EMPTY; @@ -204,7 +204,7 @@ if (!urb) { printk(KERN_ERR "cpia_init_isoc: usb_alloc_urb 0\n"); retval = -ENOMEM; - goto error_all; + goto error_1; } ucpia->sbuf[0].urb = urb; @@ -223,9 +223,9 @@ urb = usb_alloc_urb(FRAMES_PER_DESC); if (!urb) { - printk(KERN_ERR "cpia_init_isoc: usb_alloc_urb 0\n"); + printk(KERN_ERR "cpia_init_isoc: usb_alloc_urb 1\n"); retval = -ENOMEM; - goto error_all; + goto error_urb0; } ucpia->sbuf[1].urb = urb; @@ -246,20 +246,30 @@ ucpia->sbuf[0].urb->next = ucpia->sbuf[1].urb; err = usb_submit_urb(ucpia->sbuf[0].urb); - if (err) + if (err) { printk(KERN_ERR "cpia_init_isoc: usb_submit_urb 0 ret %d\n", err); + goto error_urb1; + } err = usb_submit_urb(ucpia->sbuf[1].urb); - if (err) + if (err) { printk(KERN_ERR "cpia_init_isoc: usb_submit_urb 1 ret %d\n", err); + goto error_urb1; + } ucpia->streaming = 1; ucpia->open = 1; return 0; -error_all: +error_urb1: /* free urb 1 */ + usb_free_urb(ucpia->sbuf[1].urb); + +error_urb0: /* free urb 0 */ + usb_free_urb(ucpia->sbuf[0].urb); + +error_1: kfree (ucpia->sbuf[1].data); error_0: kfree (ucpia->sbuf[0].data); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/mtd/cfi_cmdset_0002.c linux/drivers/mtd/cfi_cmdset_0002.c --- v2.4.0-test8/linux/drivers/mtd/cfi_cmdset_0002.c Thu Jul 13 10:19:55 2000 +++ linux/drivers/mtd/cfi_cmdset_0002.c Thu Sep 21 13:24:44 2000 @@ -437,7 +437,7 @@ adr = instr->addr - (chipnum << cfi->chipshift) * (cfi->interleave); len = instr->len; -printk("erase : 0x%x 0x%x 0x%x\n", adr, len, chipnum, mtd->size); +printk("erase : 0x%lx 0x%lx 0x%x 0x%x\n", adr, len, chipnum, mtd->size); while(len) { //printk("erase : 0x%x 0x%x 0x%x 0x%x\n", chipnum, adr, len, cfi->chipshift); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/mtd/mapped.c linux/drivers/mtd/mapped.c --- v2.4.0-test8/linux/drivers/mtd/mapped.c Tue Jul 4 10:10:05 2000 +++ linux/drivers/mtd/mapped.c Sun Sep 24 12:12:33 2000 @@ -21,7 +21,6 @@ #include #include #include -#include struct JEDECTable mtd_JEDEC_table[] = {{0x01AD,"AMD Am29F016",2*1024*1024,64*1024,MTD_CAP_NORFLASH}, diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/3c505.c linux/drivers/net/3c505.c --- v2.4.0-test8/linux/drivers/net/3c505.c Tue May 2 12:40:58 2000 +++ linux/drivers/net/3c505.c Mon Oct 2 14:22:40 2000 @@ -130,15 +130,15 @@ #define INVALID_PCB_MSG(len) \ printk(invalid_pcb_msg, (len),filename,__FUNCTION__,__LINE__) -static const char *search_msg = "%s: Looking for 3c505 adapter at address %#x..."; +static char search_msg[] __initdata = "%s: Looking for 3c505 adapter at address %#x..."; -static const char *stilllooking_msg = "still looking..."; +static char stilllooking_msg[] __initdata = "still looking..."; -static const char *found_msg = "found.\n"; +static char found_msg[] __initdata = "found.\n"; -static const char *notfound_msg = "not found (reason = %d)\n"; +static char notfound_msg[] __initdata = "not found (reason = %d)\n"; -static const char *couldnot_msg = "%s: 3c505 not found\n"; +static char couldnot_msg[] __initdata = "%s: 3c505 not found\n"; /********************************************************* * @@ -180,7 +180,7 @@ * Last element MUST BE 0! *****************************************************************/ -static const int addr_list[] __initdata = {0x300, 0x280, 0x310, 0}; +static int addr_list[] __initdata = {0x300, 0x280, 0x310, 0}; /* Dma Memory related stuff */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/3c507.c linux/drivers/net/3c507.c --- v2.4.0-test8/linux/drivers/net/3c507.c Mon Jun 19 13:30:56 2000 +++ linux/drivers/net/3c507.c Sun Sep 17 09:41:28 2000 @@ -332,6 +332,7 @@ { static unsigned char init_ID_done = 0, version_printed = 0; int i, irq, irqval; + struct net_local *lp; if (init_ID_done == 0) { ushort lrs_state = 0xff; @@ -355,7 +356,7 @@ /* Allocate a new 'dev' if needed. */ if (dev == NULL) - dev = init_etherdev(0, sizeof(struct net_local)); + dev = init_etherdev(0, 0); if (net_debug && version_printed++ == 0) printk(version); @@ -417,10 +418,11 @@ printk(version); /* Initialize the device structure. */ - dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); + lp = dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); if (dev->priv == NULL) return -ENOMEM; memset(dev->priv, 0, sizeof(struct net_local)); + spin_lock_init(&lp->lock); dev->open = el16_open; dev->stop = el16_close; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/3c509.c linux/drivers/net/3c509.c --- v2.4.0-test8/linux/drivers/net/3c509.c Tue Jul 11 11:12:23 2000 +++ linux/drivers/net/3c509.c Sun Sep 17 09:41:28 2000 @@ -193,6 +193,7 @@ int el3_probe(struct net_device *dev) { + struct el3_private *lp; short lrs_state = 0xff, i; int ioaddr, irq, if_port; u16 phys_addr[3]; @@ -200,7 +201,7 @@ int mca_slot = -1; #ifdef __ISAPNP__ static int pnp_cards = 0; -#endif +#endif /* __ISAPNP__ */ /* First check all slots of the EISA bus. The next slot address to probe is kept in 'eisa_addr' to support multiple probe() calls. */ @@ -292,7 +293,7 @@ /* if we get here, we didn't find an MCA adapter */ return -ENODEV; } -#endif +#endif /* CONFIG_MCA */ #ifdef __ISAPNP__ if (nopnp == 1) @@ -330,7 +331,7 @@ } } no_pnp: -#endif +#endif /* __ISAPNP__ */ /* Select an open I/O location at 0x1*0 to do contention select. */ for ( ; id_port < 0x200; id_port += 0x10) { @@ -396,7 +397,7 @@ } } } -#endif +#endif /* __ISAPNP__ */ { unsigned int iobase = id_read_eeprom(8); @@ -466,9 +467,10 @@ return -ENOMEM; memset(dev->priv, 0, sizeof(struct el3_private)); - ((struct el3_private *)dev->priv)->mca_slot = mca_slot; - ((struct el3_private *)dev->priv)->next_dev = el3_root_dev; - ((struct el3_private *)dev->priv)->lock = (spinlock_t) SPIN_LOCK_UNLOCKED; + lp = dev->priv; + lp->mca_slot = mca_slot; + lp->next_dev = el3_root_dev; + spin_lock_init(&lp->lock); el3_root_dev = dev; if (el3_debug > 0) diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/3c527.c linux/drivers/net/3c527.c --- v2.4.0-test8/linux/drivers/net/3c527.c Tue Jul 18 16:09:27 2000 +++ linux/drivers/net/3c527.c Tue Sep 19 08:01:34 2000 @@ -146,7 +146,7 @@ char *name; }; -const struct mca_adapters_t mc32_adapters[] = { +static struct mca_adapters_t mc32_adapters[] __initdata = { { 0x0041, "3COM EtherLink MC/32" }, { 0x8EF5, "IBM High Performance Lan Adapter" }, { 0x0000, NULL } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/3c59x.c linux/drivers/net/3c59x.c --- v2.4.0-test8/linux/drivers/net/3c59x.c Sun Aug 13 19:27:39 2000 +++ linux/drivers/net/3c59x.c Fri Sep 15 16:28:25 2000 @@ -98,6 +98,18 @@ - Added INVERT_LED_PWR, used it. - Backed out the extra_reset stuff + LK1.1.9 2 Sep 2000 andrewm + - Backed out the tx_reset_resume flags. It was a no-op. + - In vortex_error, don't reset the Tx on txReclaim errors + - In vortex_error, don't reset the Tx on maxCollisions errors. + Hence backed out all the DownListPtr logic here. + - In vortex_error, give Tornado cards a partial TxReset on + maxCollisions (David Hinds). Defined MAX_COLLISION_RESET for this. + - Redid some driver flags and device names based on pcmcia_cs-3.1.20. + - Fixed a bug where, if vp->tx_full is set when the interface + is downed, it remains set when the interface is upped. Bad + things happen. + - See http://www.uow.edu.au/~andrewm/linux/#3c59x-2.3 for more details. - Also see Documentation/networking/vortex.txt */ @@ -183,7 +195,7 @@ #include static char version[] __devinitdata = -"3c59x.c:LK1.1.8 13 Aug 2000 Donald Becker and others. http://www.scyld.com/network/vortex.html " "$Revision: 1.102.2.25 $\n"; +"3c59x.c:LK1.1.9 2 Sep 2000 Donald Becker and others. http://www.scyld.com/network/vortex.html " "$Revision: 1.102.2.38 $\n"; MODULE_AUTHOR("Donald Becker "); MODULE_DESCRIPTION("3Com 3c59x/3c90x/3c575 series Vortex/Boomerang/Cyclone driver"); @@ -303,7 +315,7 @@ enum { IS_VORTEX=1, IS_BOOMERANG=2, IS_CYCLONE=4, IS_TORNADO=8, EEPROM_8BIT=0x10, /* AKPM: Uses 0x230 as the base bitmaps for EEPROM reads */ HAS_PWR_CTRL=0x20, HAS_MII=0x40, HAS_NWAY=0x80, HAS_CB_FNS=0x100, - INVERT_MII_PWR=0x200, INVERT_LED_PWR=0x400 }; + INVERT_MII_PWR=0x200, INVERT_LED_PWR=0x400, MAX_COLLISION_RESET=0x800 }; enum vortex_chips { @@ -415,14 +427,14 @@ {"3CCFE575BT Cyclone CardBus", PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_LED_PWR, 128, }, - {"3CCFE575CT Cyclone CardBus", - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR, 128, }, + {"3CCFE575CT Tornado CardBus", + PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|MAX_COLLISION_RESET, 128, }, {"3CCFE656 Cyclone CardBus", PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|INVERT_LED_PWR, 128, }, {"3CCFEM656B Cyclone+Winmodem CardBus", PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|INVERT_LED_PWR, 128, }, - {"3CCFE656C Tornado+Winmodem CardBus", /* From pcmcia-cs-3.1.5 */ - PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR, 128, }, + {"3CXFEM656C Tornado+Winmodem CardBus", /* From pcmcia-cs-3.1.5 */ + PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|MAX_COLLISION_RESET, 128, }, {"3c450 HomePNA Tornado", /* AKPM: from Don's 0.99Q */ PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY, 128, }, @@ -652,7 +664,6 @@ open:1, must_free_region:1; /* Flag: if zero, Cardbus owns the I/O region */ int drv_flags; - int tx_reset_resume; /* Flag to retart timer after vortex_error handling */ u16 status_enable; u16 intr_enable; u16 available_media; /* From Wn3_Options. */ @@ -1369,6 +1380,7 @@ vortex_up(dev); vp->open = 1; + vp->tx_full = 0; return 0; out_free_irq: @@ -1570,7 +1582,7 @@ { struct vortex_private *vp = (struct vortex_private *)dev->priv; long ioaddr = dev->base_addr; - int do_tx_reset = 0; + int do_tx_reset = 0, reset_mask = 0; unsigned char tx_status = 0; if (vortex_debug > 2) { @@ -1589,10 +1601,14 @@ if (tx_status & 0x14) vp->stats.tx_fifo_errors++; if (tx_status & 0x38) vp->stats.tx_aborted_errors++; outb(0, ioaddr + TxStatus); - if (tx_status & 0x3a) /* TxReset after 16 collisions, despite what the manual says */ - do_tx_reset = 1; /* Also reset on reclaim errors */ - else /* Merely re-enable the transmitter. */ + if (tx_status & 0x30) { /* txJabber or txUnderrun */ + do_tx_reset = 1; + } else if ((tx_status & 0x08) && (vp->drv_flags & MAX_COLLISION_RESET)) { /* maxCollisions */ + do_tx_reset = 1; + reset_mask = 0x0108; /* Reset interface logic, but not download logic */ + } else { /* Merely re-enable the transmitter. */ outw(TxEnable, ioaddr + EL3_CMD); + } } if (status & RxEarly) { /* Rx early is unused. */ @@ -1644,40 +1660,11 @@ } } - /* - * Black magic. If we're resetting the transmitter, remember the current downlist - * pointer and restore it afterwards. We can't usr cur_tx because that could - * lag the actual hardware index. - */ if (do_tx_reset) { - if (vp->full_bus_master_tx) { - unsigned long old_down_list_ptr; - - wait_for_completion(dev, DownStall); - old_down_list_ptr = inl(ioaddr + DownListPtr); - wait_for_completion(dev, TxReset); - outw(TxEnable, ioaddr + EL3_CMD); - - /* Restart DMA if necessary */ - outl(old_down_list_ptr, ioaddr + DownListPtr); - if (vortex_debug > 2) - printk(KERN_DEBUG "reset DMA to 0x%08x\n", inl(ioaddr + DownListPtr)); - outw(DownUnstall, ioaddr + EL3_CMD); - - /* - * Here we make a single attempt to prevent a timeout by - * restarting the timer if we think that the ISR has a good - * chance of unjamming things. - */ - if (vp->tx_reset_resume == 0 && vp->tx_full) { - vp->tx_reset_resume = 1; - dev->trans_start = jiffies; - } - } else { - wait_for_completion(dev, TxReset); - outw(TxEnable, ioaddr + EL3_CMD); + wait_for_completion(dev, TxReset|reset_mask); + outw(TxEnable, ioaddr + EL3_CMD); + if (!vp->full_bus_master_tx) netif_wake_queue(dev); - } } } @@ -1785,7 +1772,6 @@ /* netif_start_queue (dev); */ /* AKPM: redundant? */ } outw(DownUnstall, ioaddr + EL3_CMD); - vp->tx_reset_resume = 0; spin_unlock_irqrestore(&vp->lock, flags); dev->trans_start = jiffies; return 0; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/8139too.c linux/drivers/net/8139too.c --- v2.4.0-test8/linux/drivers/net/8139too.c Fri Sep 8 12:37:34 2000 +++ linux/drivers/net/8139too.c Sun Sep 17 09:41:28 2000 @@ -2,8 +2,37 @@ 8139too.c: A RealTek RTL-8139 Fast Ethernet driver for Linux. - Copyright 2000 Jeff Garzik - Originally: Written 1997-1999 by Donald Becker. + Maintained by Jeff Garzik + + Much code comes from Donald Becker's rtl8139.c driver, + versions 1.11 and older. This driver was originally based + on rtl8139.c version 1.07. Header of rtl8139.c version 1.11: + + ---------- + + Written 1997-2000 by Donald Becker. + This software may be used and distributed according to the + terms of the GNU General Public License (GPL), incorporated + herein by reference. Drivers based on or derived from this + code fall under the GPL and must retain the authorship, + copyright and license notice. This file is not a complete + program and may only be used when the entire operating + system is licensed under the GPL. + + This driver is for boards based on the RTL8129 and RTL8139 + PCI ethernet chips. + + The author may be reached as becker@scyld.com, or C/O Scyld + Computing Corporation 410 Severn Ave., Suite 210 Annapolis + MD 21403 + + Support and updates available at + http://www.scyld.com/network/rtl8139.html + + Twister-tuning table provided by Kinston + . + + ---------- This software may be used and distributed according to the terms of the GNU Public License, incorporated herein by reference. @@ -16,7 +45,7 @@ Tigran Aivazian - bug fixes, skbuff free cleanup Martin Mares - suggestions for PCI cleanup - + David S. Miller - PCI DMA and softnet updates Ernst Gill - fixes ported from BSD driver @@ -24,7 +53,22 @@ Daniel Kobras - identified specific locations of posted MMIO write bugginess - Gerard Sharp - bug fix + Gerard Sharp - bug fix, testing and feedback + + David Ford - Rx ring wrap fix + + Dan DeMaggio - swapped RTL8139 cards with me, and allowed me + to find and fix a crucial bug on older chipsets. + + Donald Becker/Chris Butterworth/Marcus Westergren - + Noticed various Rx packet size-related buglets. + + Santiago Garcia Mantinan - testing and feedback + + Jens David - 2.2.x kernel backports + + Martin Dennett - incredibly helpful insight on undocumented + features of the 8139 chips Submitting bug reports: @@ -73,7 +117,7 @@ IVb. References http://www.realtek.com.tw/cn/cn.html -http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html +http://www.scyld.com/expert/NWay.html IVc. Errata @@ -97,25 +141,33 @@ #include -#define RTL8139_VERSION "0.9.8" +#define RTL8139_VERSION "0.9.10" #define RTL8139_MODULE_NAME "8139too" #define RTL8139_DRIVER_NAME RTL8139_MODULE_NAME " Fast Ethernet driver " RTL8139_VERSION #define PFX RTL8139_MODULE_NAME ": " -#undef RTL8139_DEBUG /* define to 1 to enable copious debugging info */ + +/* define to 1 to enable PIO instead of MMIO */ +#undef USE_IO_OPS + +/* define to 1 to enable copious debugging info */ +#undef RTL8139_DEBUG + +/* define to 1 to disable lightweight runtime debugging checks */ +#undef RTL8139_NDEBUG + #ifdef RTL8139_DEBUG /* note: prints function name for you */ -#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) +# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) #else -#define DPRINTK(fmt, args...) +# define DPRINTK(fmt, args...) #endif -#undef RTL8139_NDEBUG /* define to 1 to disable lightweight runtime checks */ #ifdef RTL8139_NDEBUG -#define assert(expr) +# define assert(expr) do {} while (0) #else -#define assert(expr) \ +# define assert(expr) \ if(!(expr)) { \ printk( "Assertion failed! %s,%s,%s,line=%d\n", \ #expr,__FILE__,__FUNCTION__,__LINE__); \ @@ -125,12 +177,6 @@ #define arraysize(x) (sizeof(x)/sizeof(*(x))) -#ifndef PCI_GET_DRIVER_DATA - #define PCI_GET_DRIVER_DATA(pdev) ((pdev)->driver_data) - #define PCI_SET_DRIVER_DATA(pdev,data) (((pdev)->driver_data) = (data)) -#endif /* PCI_GET_DRIVER_DATA */ - - /* A few user-configurable values. */ /* media options */ static int media[] = {-1, -1, -1, -1, -1, -1, -1, -1}; @@ -146,7 +192,8 @@ #define RX_BUF_LEN_IDX 2 /* 0==8K, 1==16K, 2==32K, 3==64K */ #define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX) #define RX_BUF_PAD 16 -#define RX_BUF_TOT_LEN (RX_BUF_LEN + RX_BUF_PAD) +#define RX_BUF_WRAP_PAD 2048 /* spare padding to handle lack of packet wrap */ +#define RX_BUF_TOT_LEN (RX_BUF_LEN + RX_BUF_PAD + RX_BUF_WRAP_PAD) /* Number of Tx descriptor registers. */ #define NUM_TX_DESC 4 @@ -160,9 +207,9 @@ #define TX_FIFO_THRESH 256 /* In bytes, rounded down to 32 byte units. */ /* The following settings are log_2(bytes)-4: 0 == 16 bytes .. 6==1024, 7==end of packet. */ -#define RX_FIFO_THRESH 4 /* Rx buffer level before first PCI xfer. */ -#define RX_DMA_BURST 4 /* Maximum PCI burst, '7' is unlimited */ -#define TX_DMA_BURST 4 /* Maximum PCI burst, '4' is 256 */ +#define RX_FIFO_THRESH 6 /* Rx buffer level before first PCI xfer. */ +#define RX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */ +#define TX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */ /* Operational parameters that usually are not changed. */ @@ -321,6 +368,7 @@ TxLoopBack = (1 << 18) | (1 << 17), /* enable loopback test mode */ TxCRC = (1 << 16), /* DISABLE appending CRC to end of Tx packets */ TxClearAbt = (1 << 0), /* Clear abort (WO) */ + TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */ TxVersionMask = 0x7C800000, /* mask out version bits 30-26, 23 */ }; @@ -341,7 +389,7 @@ /* Early Rx threshold, none or X/16 */ RxCfgEarlyRxNone = 0, RxCfgEarlyRxShift = 24, - + /* rx fifo threshold */ RxCfgFIFOShift = 13, RxCfgFIFONone = (7 << RxCfgFIFOShift), @@ -355,6 +403,9 @@ RxCfgRcv16K = (1 << 11), RxCfgRcv32K = (1 << 12), RxCfgRcv64K = (1 << 11) | (1 << 12), + + /* Disable packet wrap at end of Rx buffer */ + RxNoWrap = (1 << 7), }; @@ -411,17 +462,17 @@ 0x40, 0xf0fe0040, /* XXX copied from RTL8139A, verify */ }, - + { "RTL-8139 rev K", 0x60, - 0xf0fe0040, /* XXX copied from RTL8139A, verify */ + 0xf0fe0040, }, - + { "RTL-8139A", 0x70, 0xf0fe0040, }, - + { "RTL-8139B", 0x78, 0xf0fc0040 @@ -497,6 +548,32 @@ static void rtl8139_hw_start (struct net_device *dev); +#ifdef USE_IO_OPS + +#define RTL_R8(reg) inb (((unsigned long)ioaddr) + (reg)) +#define RTL_R16(reg) inw (((unsigned long)ioaddr) + (reg)) +#define RTL_R32(reg) inl (((unsigned long)ioaddr) + (reg)) +#define RTL_W8(reg, val8) outb ((val8), ((unsigned long)ioaddr) + (reg)) +#define RTL_W16(reg, val16) outw ((val16), ((unsigned long)ioaddr) + (reg)) +#define RTL_W32(reg, val32) outl ((val32), ((unsigned long)ioaddr) + (reg)) +#define RTL_W8_F RTL_W8 +#define RTL_W16_F RTL_W16 +#define RTL_W32_F RTL_W32 +#undef readb +#undef readw +#undef readl +#undef writeb +#undef writew +#undef writel +#define readb(addr) inb((unsigned long)(addr)) +#define readw(addr) inw((unsigned long)(addr)) +#define readl(addr) inl((unsigned long)(addr)) +#define writeb(val,addr) outb((val),(unsigned long)(addr)) +#define writew(val,addr) outw((val),(unsigned long)(addr)) +#define writel(val,addr) outl((val),(unsigned long)(addr)) + +#else + /* write MMIO register, with flush */ /* Flush avoids rtl8139 bug w/ posted MMIO writes */ #define RTL_W8_F(reg, val8) do { writeb ((val8), ioaddr + (reg)); readb (ioaddr + (reg)); } while (0) @@ -525,13 +602,17 @@ #define RTL_R16(reg) readw (ioaddr + (reg)) #define RTL_R32(reg) readl (ioaddr + (reg)) +#endif /* USE_IO_OPS */ -static const u16 rtl8139_intr_mask = + +static const u16 rtl8139_intr_mask = PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver | TxErr | TxOK | RxErr | RxOK; static const unsigned int rtl8139_rx_config = - RxCfgEarlyRxNone | RxCfgFIFONone | RxCfgRcv32K | RxCfgDMAUnlimited; + RxCfgEarlyRxNone | RxCfgRcv32K | RxNoWrap | + (RX_FIFO_THRESH << RxCfgFIFOShift) | + (RX_DMA_BURST << RxCfgDMAShift); static int __devinit rtl8139_init_board (struct pci_dev *pdev, @@ -577,7 +658,7 @@ /* set this immediately, we need to know before * we talk to the chip directly */ DPRINTK("PIO region size == 0x%02X\n", pio_len); - DPRINTK("MMIO region size == 0x%02X\n", mmio_len); + DPRINTK("MMIO region size == 0x%02lX\n", mmio_len); if (pio_len == RTL8139B_IO_SIZE) tp->chipset = CH_8139B; @@ -587,14 +668,14 @@ rc = -ENODEV; goto err_out; } - + /* make sure PCI base addr 1 is MMIO */ if (!(mmio_flags & IORESOURCE_MEM)) { printk (KERN_ERR PFX "region #1 not an MMIO resource, aborting\n"); rc = -ENODEV; goto err_out; } - + /* check for weird/broken PCI region reporting */ if ((pio_len != mmio_len) || (pio_len < RTL_MIN_IO_SIZE) || @@ -610,14 +691,14 @@ rc = -EBUSY; goto err_out; } - + /* make sure our MMIO region in PCI space is available */ if (!request_mem_region (mmio_start, mmio_len, dev->name)) { printk (KERN_ERR PFX "no mem resource available, aborting\n"); rc = -EBUSY; goto err_out_free_pio; } - + /* enable device (incl. PCI PM wakeup), and bus-mastering */ rc = pci_enable_device (pdev); if (rc) @@ -625,6 +706,9 @@ pci_set_master (pdev); +#ifdef USE_IO_OPS + ioaddr = (void *) pio_start; +#else /* ioremap MMIO region */ ioaddr = ioremap (mmio_start, mmio_len); if (ioaddr == NULL) { @@ -632,6 +716,7 @@ rc = -EIO; goto err_out_free_mmio; } +#endif /* USE_IO_OPS */ /* Soft reset the chip. */ RTL_W8 (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear) | CmdReset); @@ -653,12 +738,14 @@ RTL_W8 (Config1, 0); } +#ifndef USE_IO_OPS /* sanity checks -- ensure PIO and MMIO registers agree */ assert (inb (pio_start+Config0) == readb (ioaddr+Config0)); assert (inb (pio_start+Config1) == readb (ioaddr+Config1)); assert (inb (pio_start+TxConfig) == readb (ioaddr+TxConfig)); assert (inb (pio_start+RxConfig) == readb (ioaddr+RxConfig)); - +#endif /* !USE_IO_OPS */ + /* make sure chip thinks PIO and MMIO are enabled */ tmp8 = RTL_R8 (Config1); if ((tmp8 & Cfg1_PIO) == 0) { @@ -671,7 +758,7 @@ rc = -EIO; goto err_out_iounmap; } - + /* identify chip attached to board */ tmp = RTL_R8 (ChipVersion); for (i = arraysize (rtl_chip_info) - 1; i >= 0; i--) @@ -691,15 +778,17 @@ tmp, tp->chipset, rtl_chip_info[tp->chipset].name); - + DPRINTK ("EXIT, returning 0\n"); *ioaddr_out = ioaddr; *dev_out = dev; - return 0; + return 0; err_out_iounmap: assert (ioaddr > 0); +#ifndef USE_IO_OPS iounmap (ioaddr); +#endif /* !USE_IO_OPS */ err_out_free_mmio: release_mem_region (mmio_start, mmio_len); err_out_free_pio: @@ -720,14 +809,11 @@ int i, addr_len, option; void *ioaddr = NULL; static int board_idx = -1; - u8 tmp; - -#ifndef RTL8139_NDEBUG static int printed_version = 0; -#endif /* RTL8139_NDEBUG */ + u8 tmp; DPRINTK ("ENTER\n"); - + assert (pdev != NULL); assert (ent != NULL); @@ -743,9 +829,9 @@ DPRINTK ("EXIT, returning %d\n", i); return i; } - + tp = dev->priv; - + assert (ioaddr != NULL); assert (dev != NULL); assert (tp != NULL); @@ -766,7 +852,7 @@ dev->watchdog_timeo = TX_TIMEOUT; dev->irq = pdev->irq; - dev->base_addr = pci_resource_start (pdev, 1); + dev->base_addr = (unsigned long) ioaddr; /* dev->priv/tp zeroed and aligned in init_etherdev */ tp = dev->priv; @@ -779,24 +865,23 @@ tp->mmio_addr = ioaddr; tp->lock = SPIN_LOCK_UNLOCKED; - PCI_SET_DRIVER_DATA (pdev, dev); + pdev->driver_data = dev; tp->phys[0] = 32; - printk (KERN_INFO "%s: %s board found at 0x%lx, IRQ %d\n", - dev->name, board_info[ent->driver_data].name, - dev->base_addr, dev->irq); - - printk (KERN_INFO "%s: Chip is '%s'\n", - dev->name, - rtl_chip_info[tp->chipset].name); - - printk (KERN_INFO "%s: MAC address " - "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", + printk (KERN_INFO "%s: %s at 0x%lx, " + "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, " + "IRQ %d\n", dev->name, + board_info[ent->driver_data].name, + dev->base_addr, dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], dev->dev_addr[3], - dev->dev_addr[4], dev->dev_addr[5]); + dev->dev_addr[4], dev->dev_addr[5], + dev->irq); + + printk (KERN_DEBUG "%s: Identified 8139 chip type '%s'\n", + dev->name, rtl_chip_info[tp->chipset].name); /* Put the chip into low-power mode. */ RTL_W8_F (Cfg9346, Cfg9346_Unlock); @@ -831,7 +916,7 @@ static void __devexit rtl8139_remove_one (struct pci_dev *pdev) { - struct net_device *dev = PCI_GET_DRIVER_DATA (pdev); + struct net_device *dev = pdev->driver_data; struct rtl8139_private *np; DPRINTK ("ENTER\n"); @@ -843,7 +928,10 @@ unregister_netdev (dev); +#ifndef USE_IO_OPS iounmap (np->mmio_addr); +#endif /* !USE_IO_OPS */ + release_region (pci_resource_start (pdev, 0), pci_resource_len (pdev, 0)); release_mem_region (pci_resource_start (pdev, 1), @@ -857,7 +945,9 @@ #endif /* RTL8139_NDEBUG */ kfree (dev); - + + pdev->driver_data = NULL; + DPRINTK ("EXIT\n"); } @@ -1094,9 +1184,9 @@ DPRINTK ("EXIT, returning -ENOMEM\n"); MOD_DEC_USE_COUNT; return -ENOMEM; - + } - + tp->full_duplex = tp->duplex_lock; tp->tx_flag = (TX_FIFO_THRESH << 11) & 0x003f0000; @@ -1131,7 +1221,7 @@ u8 tmp; DPRINTK ("ENTER\n"); - + /* Soft reset the chip. */ RTL_W8 (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear) | CmdReset); udelay (100); @@ -1154,7 +1244,7 @@ RTL_W32_F (RxConfig, i); /* Check this value: the documentation for IFG contradicts ifself. */ - RTL_W32 (TxConfig, (TX_DMA_BURST << 8)); + RTL_W32 (TxConfig, (TX_DMA_BURST << TxDMAShift)); /* unlock Config[01234] and BMCR register writes */ RTL_W8_F (Cfg9346, Cfg9346_Unlock); @@ -1175,9 +1265,9 @@ if (tp->chipset >= CH_8139B) { tmp = RTL_R8 (Config4) & ~(1<<2); /* chip will clear Rx FIFO overflow automatically */ - tmp |= (1<<7); + tmp |= (1<<7); RTL_W8 (Config4, tmp); - + /* disable magic packet scanning, which is enabled * when PM is enabled above (Config1) */ RTL_W8 (Config3, RTL_R8 (Config3) & ~(1<<5)); @@ -1334,15 +1424,13 @@ { struct net_device *dev = (struct net_device *) data; struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; + void *ioaddr = tp->mmio_addr; int next_tick = 60 * HZ; int mii_reg5; - spin_lock_irq (&tp->lock); - mii_reg5 = mdio_read (dev, tp->phys[0], 5); if (!tp->duplex_lock && mii_reg5 != 0xffff) { - void *ioaddr = tp->mmio_addr; int duplex = (mii_reg5 & 0x0100) || (mii_reg5 & 0x01C0) == 0x0040; if (tp->full_duplex != duplex) { @@ -1371,8 +1459,6 @@ dev->name, RTL_R8 (Config0), RTL_R8 (Config1)); - spin_unlock_irq (&tp->lock); - tp->timer.expires = jiffies + next_tick; add_timer (&tp->timer); } @@ -1383,6 +1469,7 @@ struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; void *ioaddr = tp->mmio_addr; int i; + unsigned long flags; DPRINTK ("%s: Transmit timeout, status %2.2x %4.4x " "media %2.2x.\n", dev->name, @@ -1390,25 +1477,20 @@ RTL_R16 (IntrStatus), RTL_R8 (MediaStatus)); - spin_lock_irq (&tp->lock); - /* Disable interrupts by clearing the interrupt mask. */ RTL_W16 (IntrMask, 0x0000); - spin_unlock_irq (&tp->lock); - /* Emit info to figure out what went wrong. */ - printk (KERN_DEBUG - "%s: Tx queue start entry %d dirty entry %d.\n", + printk (KERN_DEBUG "%s: Tx queue start entry %d dirty entry %d.\n", dev->name, atomic_read (&tp->cur_tx), atomic_read (&tp->dirty_tx)); for (i = 0; i < NUM_TX_DESC; i++) printk (KERN_DEBUG "%s: Tx descriptor %d is %8.8x.%s\n", dev->name, i, RTL_R32 (TxStatus0 + (i * 4)), - i == - atomic_read (&tp->dirty_tx) % NUM_TX_DESC ? " (queue head)" : ""); + i == atomic_read (&tp->dirty_tx) % NUM_TX_DESC ? + " (queue head)" : ""); - spin_lock_irq (&tp->lock); + spin_lock_irqsave (&tp->lock, flags); /* Stop a shared interrupt from scavenging while we are. */ atomic_set (&tp->cur_tx, 0); @@ -1418,7 +1500,8 @@ for (i = 0; i < NUM_TX_DESC; i++) { struct ring_info *rp = &tp->tx_info[i]; if (rp->mapping != 0) { - pci_unmap_single (tp->pci_dev, rp->mapping, rp->skb->len, PCI_DMA_TODEVICE); + pci_unmap_single (tp->pci_dev, rp->mapping, + rp->skb->len, PCI_DMA_TODEVICE); rp->mapping = 0; } if (rp->skb) { @@ -1427,9 +1510,10 @@ tp->stats.tx_dropped++; } } - - spin_unlock_irq (&tp->lock); + spin_unlock_irqrestore (&tp->lock, flags); + + /* ...and finally, reset everything */ rtl8139_hw_start (dev); } @@ -1444,18 +1528,17 @@ /* Calculate the next Tx descriptor entry. */ entry = atomic_read (&tp->cur_tx) % NUM_TX_DESC; + assert (tp->tx_info[entry].skb == NULL); + assert (tp->tx_info[entry].mapping == 0); + tp->tx_info[entry].skb = skb; - tp->tx_info[entry].mapping = 0; + /* tp->tx_info[entry].mapping = 0; */ memcpy (tp->tx_buf[entry], skb->data, skb->len); - spin_lock_irq (&tp->lock); - /* Note: the chip doesn't have auto-pad! */ RTL_W32 (TxStatus0 + (entry * sizeof(u32)), tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN)); - spin_unlock_irq (&tp->lock); - dev->trans_start = jiffies; atomic_inc (&tp->cur_tx); if ((atomic_read (&tp->cur_tx) - atomic_read (&tp->dirty_tx)) >= NUM_TX_DESC) @@ -1477,20 +1560,15 @@ assert (dev != NULL); assert (tp != NULL); assert (ioaddr != NULL); - - /* drop lock held in rtl8139_interrupt */ - spin_unlock (&tp->lock); - + dirty_tx = atomic_read (&tp->dirty_tx); while ((atomic_read (&tp->cur_tx) - dirty_tx) > 0) { int entry = dirty_tx % NUM_TX_DESC; int txstatus; - spin_lock (&tp->lock); - txstatus = RTL_R32 (TxStatus0 + (entry * 4)); - spin_unlock (&tp->lock); - + txstatus = RTL_R32 (TxStatus0 + (entry * sizeof (u32))); + if (!(txstatus & (TxStatOK | TxUnderrun | TxAborted))) break; /* It still hasn't been Txed */ @@ -1502,9 +1580,7 @@ tp->stats.tx_errors++; if (txstatus & TxAborted) { tp->stats.tx_aborted_errors++; - spin_lock (&tp->lock); - RTL_W32 (TxConfig, (TX_DMA_BURST << 8)); - spin_unlock (&tp->lock); + RTL_W32 (TxConfig, TxClearAbt | (TX_DMA_BURST << TxDMAShift)); } if (txstatus & TxCarrierLost) tp->stats.tx_carrier_errors++; @@ -1551,17 +1627,63 @@ #endif /* RTL8139_NDEBUG */ atomic_set (&tp->dirty_tx, dirty_tx); - - /* obtain lock need for rtl8139_interrupt */ - spin_lock (&tp->lock); +} + + +/* TODO: clean this up! Rx reset need not be this intensive */ +static void rtl8139_rx_err (u32 rx_status, struct net_device *dev, + struct rtl8139_private *tp, void *ioaddr) +{ + u8 tmp8; + int tmp_work = 1000; + + DPRINTK ("%s: Ethernet frame had errors, status %8.8x.\n", + dev->name, rx_status); + if (rx_status & RxTooLong) { + DPRINTK ("%s: Oversized Ethernet frame, status %4.4x!\n", + dev->name, rx_status); + /* A.C.: The chip hangs here. */ + } + tp->stats.rx_errors++; + if (rx_status & (RxBadSymbol | RxBadAlign)) + tp->stats.rx_frame_errors++; + if (rx_status & (RxRunt | RxTooLong)) + tp->stats.rx_length_errors++; + if (rx_status & RxCRCErr) + tp->stats.rx_crc_errors++; + /* Reset the receiver, based on RealTek recommendation. (Bug?) */ + tp->cur_rx = 0; + + /* disable receive */ + tmp8 = RTL_R8 (ChipCmd) & ChipCmdClear; + RTL_W8_F (ChipCmd, tmp8 | CmdTxEnb); + + /* A.C.: Reset the multicast list. */ + rtl8139_set_rx_mode (dev); + + /* XXX potentially temporary hack to + * restart hung receiver */ + while (--tmp_work > 0) { + tmp8 = RTL_R8 (ChipCmd); + if ((tmp8 & CmdRxEnb) && (tmp8 & CmdTxEnb)) + break; + RTL_W8_F (ChipCmd, + (tmp8 & ChipCmdClear) | CmdRxEnb | CmdTxEnb); + } + + /* G.S.: Re-enable receiver */ + /* XXX temporary hack to work around receiver hang */ + rtl8139_set_rx_mode (dev); + + if (tmp_work <= 0) + printk (KERN_WARNING PFX "tx/rx enable wait too long\n"); } /* The data sheet doesn't describe the Rx ring at all, so I'm guessing at the field alignments and semantics. */ static void rtl8139_rx_interrupt (struct net_device *dev, - struct rtl8139_private *tp, - void *ioaddr) + struct rtl8139_private *tp, void *ioaddr) { unsigned char *rx_ring; u16 cur_rx; @@ -1569,31 +1691,33 @@ assert (dev != NULL); assert (tp != NULL); assert (ioaddr != NULL); - + rx_ring = tp->rx_ring; cur_rx = tp->cur_rx; DPRINTK ("%s: In rtl8139_rx(), current %4.4x BufAddr %4.4x," - " free to %4.4x, Cmd %2.2x.\n", dev->name, cur_rx, - RTL_R16 (RxBufAddr), - RTL_R16 (RxBufPtr), - RTL_R8 (ChipCmd)); + " free to %4.4x, Cmd %2.2x.\n", dev->name, cur_rx, + RTL_R16 (RxBufAddr), + RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd)); while ((RTL_R8 (ChipCmd) & RxBufEmpty) == 0) { int ring_offset = cur_rx % RX_BUF_LEN; u32 rx_status = le32_to_cpu (*(u32 *) (rx_ring + ring_offset)); int rx_size = rx_status >> 16; + struct sk_buff *skb; + int pkt_size = rx_size - 4; DPRINTK ("%s: rtl8139_rx() status %4.4x, size %4.4x," - " cur %4.4x.\n", dev->name, rx_status, - rx_size, cur_rx); + " cur %4.4x.\n", dev->name, rx_status, + rx_size, cur_rx); #if RTL8139_DEBUG > 2 { - int i; - DPRINTK ("%s: Frame contents ", dev->name); - for (i = 0; i < 70; i++) - printk (" %2.2x", rx_ring[ring_offset + i]); - printk (".\n"); + int i; + DPRINTK ("%s: Frame contents ", dev->name); + for (i = 0; i < 70; i++) + printk (" %2.2x", + rx_ring[ring_offset + i]); + printk (".\n"); } #endif @@ -1609,128 +1733,68 @@ if (rx_size == 0xfff0) break; + /* if Rx err received, Rx process gets reset, so + * we abort any further Rx processing + */ if (rx_status & - (RxBadSymbol | RxRunt | RxTooLong | RxCRCErr | - RxBadAlign)) { - u8 tmp8; - int tmp_work = 1000; - - DPRINTK ("%s: Ethernet frame had errors," - " status %8.8x.\n", dev->name, - rx_status); - if (rx_status & RxTooLong) { - DPRINTK ("%s: Oversized Ethernet frame, status %4.4x!\n", - dev->name, rx_status); - /* A.C.: The chip hangs here. */ - } - tp->stats.rx_errors++; - if (rx_status & (RxBadSymbol | RxBadAlign)) - tp->stats.rx_frame_errors++; - if (rx_status & (RxRunt | RxTooLong)) - tp->stats.rx_length_errors++; - if (rx_status & RxCRCErr) - tp->stats.rx_crc_errors++; - /* Reset the receiver, based on RealTek recommendation. (Bug?) */ - tp->cur_rx = 0; - - /* disable receive */ - tmp8 = RTL_R8 (ChipCmd) & ChipCmdClear; - RTL_W8_F (ChipCmd, tmp8 | CmdTxEnb); - - /* A.C.: Reset the multicast list. */ - rtl8139_set_rx_mode (dev); - - /* XXX potentially temporary hack to - * restart hung receiver */ - while (--tmp_work > 0) { - tmp8 = RTL_R8 (ChipCmd); - if ((tmp8 & CmdRxEnb) && (tmp8 & CmdTxEnb)) - break; - RTL_W8_F (ChipCmd, (tmp8 & ChipCmdClear) | CmdRxEnb | CmdTxEnb); - } + (RxBadSymbol | RxRunt | RxTooLong | RxCRCErr | RxBadAlign)) { + rtl8139_rx_err (rx_status, dev, tp, ioaddr); + return; + } - /* G.S.: Re-enable receiver */ - /* XXX temporary hack to work around receiver hang */ - rtl8139_set_rx_mode (dev); + /* Malloc up new buffer, compatible with net-2e. */ + /* Omit the four octet CRC from the length. */ - if (tmp_work <= 0) - printk (KERN_WARNING PFX "tx/rx enable wait too long\n"); - } else { - /* Malloc up new buffer, compatible with net-2e. */ - /* Omit the four octet CRC from the length. */ - struct sk_buff *skb; - int pkt_size = rx_size - 4; - - skb = dev_alloc_skb (pkt_size + 2); - if (skb == NULL) { - printk (KERN_WARNING - "%s: Memory squeeze, dropping packet.\n", - dev->name); - /* We should check that some rx space is free. - If not, free one and mark stats->rx_dropped++. */ - tp->stats.rx_dropped++; - break; - } - skb->dev = dev; - skb_reserve (skb, 2); /* 16 byte align the IP fields. */ + /* TODO: consider allocating skb's outside of + * interrupt context, both to speed interrupt processing, + * and also to reduce the chances of having to + * drop packets here under memory pressure. + */ - if (ring_offset + rx_size + 4 > RX_BUF_LEN) { - int semi_count = - RX_BUF_LEN - ring_offset - 4; - /* This could presumably use two calls to copy_and_sum()? */ - memcpy (skb_put (skb, semi_count), - &rx_ring[ring_offset + 4], - semi_count); - memcpy (skb_put (skb, pkt_size - semi_count), - rx_ring, pkt_size - semi_count); -#ifdef RTL8139_DEBUG - { - int i; - printk (KERN_DEBUG "%s: Frame wrap @%d", - dev->name, semi_count); - for (i = 0; i < 16; i++) - printk (" %2.2x", rx_ring[i]); - printk ("\n"); - memset (rx_ring, 0xcc, 16); - } -#endif /* RTL8139_DEBUG */ - - } else { - eth_copy_and_sum (skb, - &rx_ring[ring_offset + 4], - pkt_size, 0); - skb_put (skb, pkt_size); - } - skb->protocol = eth_type_trans (skb, dev); - netif_rx (skb); - tp->stats.rx_bytes += pkt_size; - tp->stats.rx_packets++; + skb = dev_alloc_skb (pkt_size + 2); + if (skb == NULL) { + printk (KERN_WARNING + "%s: Memory squeeze, dropping packet.\n", + dev->name); + tp->stats.rx_dropped++; + break; } + skb->dev = dev; + skb_reserve (skb, 2); /* 16 byte align the IP fields. */ + + eth_copy_and_sum (skb, &rx_ring[ring_offset + 4], pkt_size, 0); + skb_put (skb, pkt_size); + + skb->protocol = eth_type_trans (skb, dev); + netif_rx (skb); + tp->stats.rx_bytes += pkt_size; + tp->stats.rx_packets++; cur_rx = (cur_rx + rx_size + 4 + 3) & ~3; RTL_W16_F (RxBufPtr, cur_rx - 16); } + DPRINTK ("%s: Done rtl8139_rx(), current %4.4x BufAddr %4.4x," - " free to %4.4x, Cmd %2.2x.\n", dev->name, cur_rx, - RTL_R16 (RxBufAddr), - RTL_R16 (RxBufPtr), - RTL_R8 (ChipCmd)); + " free to %4.4x, Cmd %2.2x.\n", dev->name, cur_rx, + RTL_R16 (RxBufAddr), + RTL_R16 (RxBufPtr), RTL_R8 (ChipCmd)); + tp->cur_rx = cur_rx; } -static int rtl8139_weird_interrupt (struct net_device *dev, - struct rtl8139_private *tp, - void *ioaddr, - int status, int link_changed) -{ - DPRINTK ("%s: Abnormal interrupt, status %8.8x.\n", - dev->name, status); - +static void rtl8139_weird_interrupt (struct net_device *dev, + struct rtl8139_private *tp, + void *ioaddr, + int status, int link_changed) +{ + printk (KERN_DEBUG "%s: Abnormal interrupt, status %8.8x.\n", + dev->name, status); + assert (dev != NULL); assert (tp != NULL); assert (ioaddr != NULL); - + /* Update the error count. */ tp->stats.rx_missed_errors += RTL_R32 (RxMissed); RTL_W32 (RxMissed, 0); @@ -1768,8 +1832,6 @@ printk (KERN_ERR "%s: PCI Bus error %4.4x.\n", dev->name, pci_cmd_status); } - - return 0; } @@ -1785,14 +1847,14 @@ int status = 0, link_changed = 0; /* avoid bogus "uninit" warning */ spin_lock (&tp->lock); - + do { status = RTL_R16 (IntrStatus); /* h/w no longer present (hotplug?) or major error, bail */ if (status == 0xFFFF) break; - + /* Acknowledge all of the current interrupt sources ASAP, but an first get an additional status bit from CSCR. */ if (status & RxUnderrun) @@ -1854,7 +1916,7 @@ } spin_unlock (&tp->lock); - + DPRINTK ("%s: exiting interrupt, intr_status=%#4.4x.\n", dev->name, RTL_R16 (IntrStatus)); } @@ -1875,7 +1937,7 @@ dev->name, RTL_R16 (IntrStatus)); del_timer_sync (&tp->timer); - + spin_lock_irqsave (&tp->lock, flags); /* Disable interrupts by clearing the interrupt mask. */ @@ -1889,7 +1951,7 @@ RTL_W32 (RxMissed, 0); spin_unlock_irqrestore (&tp->lock, flags); - + /* snooze for a small bit */ if (current->need_resched) schedule (); @@ -2053,7 +2115,7 @@ set_bit (ether_crc (ETH_ALEN, mclist->dmi_addr) >> 26, mc_filter); } - + /* if called from irq handler, lock already acquired */ if (!in_irq ()) spin_lock_irq (&tp->lock); @@ -2074,13 +2136,13 @@ static void rtl8139_suspend (struct pci_dev *pdev) { - struct net_device *dev = PCI_GET_DRIVER_DATA (pdev); + struct net_device *dev = pdev->driver_data; struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv; void *ioaddr = tp->mmio_addr; unsigned long flags; netif_device_detach (dev); - + spin_lock_irqsave (&tp->lock, flags); /* Disable interrupts, stop Tx and Rx. */ @@ -2097,7 +2159,7 @@ static void rtl8139_resume (struct pci_dev *pdev) { - struct net_device *dev = PCI_GET_DRIVER_DATA (pdev); + struct net_device *dev = pdev->driver_data; netif_device_attach (dev); rtl8139_hw_start (dev); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/8390.h linux/drivers/net/8390.h --- v2.4.0-test8/linux/drivers/net/8390.h Fri Sep 8 12:53:27 2000 +++ linux/drivers/net/8390.h Mon Oct 2 12:05:22 2000 @@ -53,11 +53,11 @@ #if defined(LOAD_8390_BY_KMOD) && defined(MODULE) && !defined(NS8390_CORE) /* Function pointers to be mapped onto the 8390 core support */ -static int (*S_ethdev_init)(struct net_device *dev) = NULL; -static void (*S_NS8390_init)(struct net_device *dev, int startp) = NULL; -static int (*S_ei_open)(struct net_device *dev) = NULL; -static int (*S_ei_close)(struct net_device *dev) = NULL; -static void (*S_ei_interrupt)(int irq, void *dev_id, struct pt_regs *regs) = NULL; +static int (*S_ethdev_init)(struct net_device *dev); +static void (*S_NS8390_init)(struct net_device *dev, int startp); +static int (*S_ei_open)(struct net_device *dev); +static int (*S_ei_close)(struct net_device *dev); +static void (*S_ei_interrupt)(int irq, void *dev_id, struct pt_regs *regs); extern __inline__ void unload_8390_module(void) { diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/Config.in linux/drivers/net/Config.in --- v2.4.0-test8/linux/drivers/net/Config.in Wed Aug 23 09:30:13 2000 +++ linux/drivers/net/Config.in Thu Sep 21 13:27:10 2000 @@ -151,17 +151,16 @@ tristate ' Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)' CONFIG_NE3210 fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate ' RealTek 8129 (not 8019/8029!) support (EXPERIMENTAL)' CONFIG_RTL8129 - fi - tristate ' RealTek RTL-8139 PCI Fast Ethernet Adapter support' CONFIG_8139TOO - tristate ' SiS 900/7016 PCI Fast Ethernet Adapter support' CONFIG_SIS900 - # tristate ' Sundance Alta support' CONFIG_ALTA - tristate ' TI ThunderLAN support' CONFIG_TLAN - tristate ' VIA Rhine support' CONFIG_VIA_RHINE - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate ' Racal-Interlan EISA ES3210 support (EXPERIMENTAL)' CONFIG_ES3210 - tristate ' SMC EtherPower II (EXPERIMENTAL)' CONFIG_EPIC100 + dep_tristate ' RealTek 8129 (not 8019/8029/8139!) support (EXPERIMENTAL)' CONFIG_RTL8129 $CONFIG_PCI fi + dep_tristate ' RealTek RTL-8139 PCI Fast Ethernet Adapter support' CONFIG_8139TOO $CONFIG_PCI + dep_tristate ' SiS 900/7016 PCI Fast Ethernet Adapter support' CONFIG_SIS900 $CONFIG_PCI + dep_tristate ' SMC EtherPower II' CONFIG_EPIC100 $CONFIG_PCI + dep_tristate ' Sundance Alta support' CONFIG_SUNDANCE $CONFIG_PCI + tristate ' TI ThunderLAN support' CONFIG_TLAN + dep_tristate ' VIA Rhine support' CONFIG_VIA_RHINE $CONFIG_PCI + dep_tristate ' Winbond W89c840 Ethernet support' CONFIG_WINBOND_840 $CONFIG_PCI if [ "$CONFIG_OBSOLETE" = "y" ]; then bool ' Zenith Z-Note support (EXPERIMENTAL)' CONFIG_ZNET fi @@ -185,21 +184,21 @@ mainmenu_option next_comment comment 'Ethernet (1000 Mbit)' -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - # tristate 'Packet Engines Hamachi GNIC-II support (EXPERIMENTAL)' CONFIG_HAMACHI - tristate 'Packet Engines Yellowfin Gigabit-NIC support (EXPERIMENTAL)' CONFIG_YELLOWFIN -fi -tristate 'Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support' CONFIG_ACENIC +dep_tristate 'Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support' CONFIG_ACENIC $CONFIG_PCI if [ "$CONFIG_ACENIC" != "n" ]; then bool ' Omit support for old Tigon I based AceNICs' CONFIG_ACENIC_OMIT_TIGON_I fi +dep_tristate 'Packet Engines Hamachi GNIC-II support' CONFIG_HAMACHI $CONFIG_PCI +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + dep_tristate 'Packet Engines Yellowfin Gigabit-NIC support (EXPERIMENTAL)' CONFIG_YELLOWFIN $CONFIG_PCI +fi tristate 'SysKonnect SK-98xx support' CONFIG_SK98LIN endmenu bool 'FDDI driver support' CONFIG_FDDI if [ "$CONFIG_FDDI" = "y" ]; then - tristate ' Digital DEFEA and DEFPA adapter support' CONFIG_DEFXX + dep_tristate ' Digital DEFEA and DEFPA adapter support' CONFIG_DEFXX $CONFIG_PCI tristate ' SysKonnect FDDI PCI support' CONFIG_SKFP fi diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/Makefile linux/drivers/net/Makefile --- v2.4.0-test8/linux/drivers/net/Makefile Wed Aug 23 09:30:13 2000 +++ linux/drivers/net/Makefile Thu Sep 21 13:27:10 2000 @@ -170,6 +170,9 @@ obj-$(CONFIG_AIRONET4500_PROC) += aironet4500_proc.o obj-$(CONFIG_AIRONET4500_CS) += aironet4500_proc.o +obj-$(CONFIG_WINBOND_840) += winbond-840.o +obj-$(CONFIG_SUNDANCE) += sundance.o +obj-$(CONFIG_HAMACHI) += hamachi.o obj-$(CONFIG_NET) += Space.o setup.o net_init.o loopback.o obj-$(CONFIG_SEEQ8005) += seeq8005.o obj-$(CONFIG_ETHERTAP) += ethertap.o @@ -304,7 +307,7 @@ MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) ifneq ($(ARCH),s390) -O_OBJS += auto_irq.o +OX_OBJS += auto_irq.o endif include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/Space.c linux/drivers/net/Space.c --- v2.4.0-test8/linux/drivers/net/Space.c Wed Aug 23 09:30:13 2000 +++ linux/drivers/net/Space.c Fri Sep 22 15:19:30 2000 @@ -440,7 +440,7 @@ #endif -/* Pad device name to IFNAMSIZ=16. F.e. __PAD6 is tring of 9 zeros. */ +/* Pad device name to IFNAMSIZ=16. F.e. __PAD6 is string of 9 zeros. */ #define __PAD6 "\0\0\0\0\0\0\0\0\0" #define __PAD5 __PAD6 "\0" #define __PAD4 __PAD5 "\0" @@ -677,14 +677,6 @@ #undef NEXT_DEV #define NEXT_DEV (&escon0_dev) #endif - -#ifdef CONFIG_TUN - extern int tun_init(struct net_device *dev); - static struct net_device tun_dev = { - "tun", 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV, tun_init }; -# undef NEXT_DEV -# define NEXT_DEV (&tun_dev) -#endif /* * The loopback device is global so it can be directly referenced diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/acenic.c linux/drivers/net/acenic.c --- v2.4.0-test8/linux/drivers/net/acenic.c Fri Jul 28 12:47:19 2000 +++ linux/drivers/net/acenic.c Mon Oct 2 14:22:40 2000 @@ -29,7 +29,16 @@ * infrastructure and Sparc support * Pierrick Pinasseau (CERN): For lending me an Ultra 5 to test the * driver under Linux/Sparc64 - * Matt Domsch : Detect 1000baseT cards + * Matt Domsch : Detect Alteon 1000baseT cards + * Chip Salzenberg : Fix race condition between tx + * handler and close() cleanup. + * Ken Aaker : Correct check for whether + * memory mapped IO is enabled to + * make the driver work on RS/6000. + * Takayoshi Kouchi : Identifying problem + * where the driver would disable + * bus master mode if it had to disable + * write and invalidate. */ #include @@ -83,8 +92,13 @@ #define PCI_VENDOR_ID_NETGEAR 0x1385 #define PCI_DEVICE_ID_NETGEAR_GA620 0x620a #endif +#ifndef PCI_DEVICE_ID_NETGEAR_GA620T +#define PCI_DEVICE_ID_NETGEAR_GA620T 0x630a +#endif + /* - * They used the DEC vendor ID by mistake + * Farallon used the DEC vendor ID by mistake and they seem not + * to care - stinky! */ #ifndef PCI_DEVICE_ID_FARALLON_PN9000SX #define PCI_DEVICE_ID_FARALLON_PN9000SX 0x1a @@ -379,22 +393,22 @@ #define DEF_TRACE 0 #define DEF_STAT (2 * TICKS_PER_SEC) -static int link[ACE_MAX_MOD_PARMS] = {0, }; -static int trace[ACE_MAX_MOD_PARMS] = {0, }; -static int tx_coal_tick[ACE_MAX_MOD_PARMS] = {0, }; -static int rx_coal_tick[ACE_MAX_MOD_PARMS] = {0, }; -static int max_tx_desc[ACE_MAX_MOD_PARMS] = {0, }; -static int max_rx_desc[ACE_MAX_MOD_PARMS] = {0, }; -static int tx_ratio[ACE_MAX_MOD_PARMS] = {0, }; +static int link[ACE_MAX_MOD_PARMS]; +static int trace[ACE_MAX_MOD_PARMS]; +static int tx_coal_tick[ACE_MAX_MOD_PARMS]; +static int rx_coal_tick[ACE_MAX_MOD_PARMS]; +static int max_tx_desc[ACE_MAX_MOD_PARMS]; +static int max_rx_desc[ACE_MAX_MOD_PARMS]; +static int tx_ratio[ACE_MAX_MOD_PARMS]; static int dis_pci_mem_inval[ACE_MAX_MOD_PARMS] = {1, 1, 1, 1, 1, 1, 1, 1}; -static const char __initdata *version = - "acenic.c: v0.44 05/11/2000 Jes Sorensen, linux-acenic@SunSITE.auc.dk\n" +static char version[] __initdata = + "acenic.c: v0.47 09/18/2000 Jes Sorensen, linux-acenic@SunSITE.auc.dk\n" " http://home.cern.ch/~jes/gige/acenic.html\n"; -static struct net_device *root_dev = NULL; +static struct net_device *root_dev; -static int probed __initdata = 0; +static int probed __initdata; #ifdef NEW_NETINIT @@ -429,7 +443,8 @@ !((pdev->vendor == PCI_VENDOR_ID_3COM) && (pdev->device == PCI_DEVICE_ID_3COM_3C985)) && !((pdev->vendor == PCI_VENDOR_ID_NETGEAR) && - (pdev->device == PCI_DEVICE_ID_NETGEAR_GA620)) && + ((pdev->device == PCI_DEVICE_ID_NETGEAR_GA620) || + (pdev->device == PCI_DEVICE_ID_NETGEAR_GA620T))) && /* * Farallon used the DEC vendor ID on their cards by * mistake for a while @@ -477,10 +492,17 @@ printk(version); } + /* + * Enable master mode before we start playing with the + * pci_command word since pci_set_master() will modify + * it. + */ + pci_set_master(pdev); + pci_read_config_word(pdev, PCI_COMMAND, &ap->pci_command); /* OpenFirmware on Mac's does not set this - DOH.. */ - if (!ap->pci_command & PCI_COMMAND_MEMORY) { + if (!(ap->pci_command & PCI_COMMAND_MEMORY)) { printk(KERN_INFO "%s: Enabling PCI Memory Mapped " "access - was not enabled by BIOS/Firmware\n", dev->name); @@ -498,8 +520,6 @@ ap->pci_latency); } - pci_set_master(pdev); - /* * Remap the regs into kernel space - this is abuse of * dev->base_addr since it was means for I/O port @@ -606,9 +626,9 @@ MODULE_PARM(max_tx_desc, "1-" __MODULE_STRING(8) "i"); MODULE_PARM(rx_coal_tick, "1-" __MODULE_STRING(8) "i"); MODULE_PARM(max_rx_desc, "1-" __MODULE_STRING(8) "i"); - #endif + void __exit ace_module_cleanup(void) { struct ace_private *ap; @@ -713,6 +733,7 @@ } +#ifdef MODULE #if (LINUX_VERSION_CODE < 0x02032a) int init_module(void) { @@ -728,6 +749,7 @@ module_init(ace_module_init); module_exit(ace_module_cleanup); #endif +#endif static void ace_free_descriptors(struct net_device *dev) @@ -1994,18 +2016,34 @@ if (txcsm != idx) { do { struct sk_buff *skb; - dma_addr_t mapping; skb = ap->skb->tx_skbuff[idx].skb; - mapping = ap->skb->tx_skbuff[idx].mapping; + /* + * Race condition between the code cleaning + * the tx queue in the interrupt handler and the + * interface close, + * + * This is a kludge that really should be fixed + * by preventing the driver from generating a tx + * interrupt when the packet has already been + * removed from the tx queue. + * + * Nailed by Don Dugger and Chip Salzenberg of + * VA Linux. + */ + if (skb) { + dma_addr_t mapping; - ap->stats.tx_packets++; - ap->stats.tx_bytes += skb->len; - pci_unmap_single(ap->pdev, mapping, skb->len, - PCI_DMA_TODEVICE); - dev_kfree_skb_irq(skb); + mapping = ap->skb->tx_skbuff[idx].mapping; - ap->skb->tx_skbuff[idx].skb = NULL; + ap->stats.tx_packets++; + ap->stats.tx_bytes += skb->len; + pci_unmap_single(ap->pdev, mapping, skb->len, + PCI_DMA_TODEVICE); + dev_kfree_skb_irq(skb); + + ap->skb->tx_skbuff[idx].skb = NULL; + } /* * Question here is whether one should not skip diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/acenic.h linux/drivers/net/acenic.h --- v2.4.0-test8/linux/drivers/net/acenic.h Fri May 12 11:38:35 2000 +++ linux/drivers/net/acenic.h Mon Sep 18 15:16:48 2000 @@ -609,7 +609,7 @@ struct timer_list timer; unsigned long std_refill_busy - __attribute__ ((aligned (L1_CACHE_BYTES))); + __attribute__ ((aligned (SMP_CACHE_BYTES))); unsigned long mini_refill_busy, jumbo_refill_busy; atomic_t cur_rx_bufs, cur_mini_bufs, @@ -642,7 +642,7 @@ char name[48]; #ifdef INDEX_DEBUG spinlock_t debug_lock - __attribute__ ((aligned (L1_CACHE_BYTES)));; + __attribute__ ((aligned (SMP_CACHE_BYTES)));; u32 last_tx, last_std_rx, last_mini_rx; #endif struct net_device_stats stats; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/acenic_firmware.h linux/drivers/net/acenic_firmware.h --- v2.4.0-test8/linux/drivers/net/acenic_firmware.h Thu Jul 6 19:27:48 2000 +++ linux/drivers/net/acenic_firmware.h Mon Sep 18 15:16:48 2000 @@ -17,6 +17,9 @@ #define tigonFwSbssLen 0x38 #define tigonFwBssAddr 0x00015dd0 #define tigonFwBssLen 0x2080 +u32 tigonFwText[]; +u32 tigonFwData[]; +u32 tigonFwRodata[]; #ifndef CONFIG_ACENIC_OMIT_TIGON_I /* Generated by genfw.c */ u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = { @@ -4592,10 +4595,6 @@ 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x30001, 0x1, 0x30201, 0x0, 0x0, 0x0 }; -#else -#define tigonFwText NULL -#define tigonFwData NULL -#define tigonFwRodata NULL #endif /* Generated by genfw.c */ #define tigon2FwReleaseMajor 0xc diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/aironet4500_core.c linux/drivers/net/aironet4500_core.c --- v2.4.0-test8/linux/drivers/net/aironet4500_core.c Tue Jul 11 11:12:23 2000 +++ linux/drivers/net/aironet4500_core.c Fri Sep 22 14:21:16 2000 @@ -2613,7 +2613,7 @@ long long jiff; - DEBUG(2, " awc_reset dev %x \n", (int)dev); + DEBUG(2, " awc_reset dev %p \n", dev); DEBUG(2, "%s: awc_reset \n", dev->name); awc_issue_soft_reset(dev); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/am79c961a.c linux/drivers/net/am79c961a.c --- v2.4.0-test8/linux/drivers/net/am79c961a.c Tue Jul 11 11:12:23 2000 +++ linux/drivers/net/am79c961a.c Mon Sep 18 15:15:22 2000 @@ -1,9 +1,13 @@ /* - * linux/drivers/net/am79c961.c + * linux/drivers/net/am79c961.c * - * Derived from various things including skeleton.c + * by Russell King 1995-2000. + * + * 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. * - * Russell King 1995-2000. + * Derived from various things including skeleton.c * * This is a special driver for the am79c961A Lance chip used in the * Intel (formally Digital Equipment Corp) EBSA110 platform. @@ -204,9 +208,12 @@ u_int hdr_addr, first_free_addr; int i; - save_flags_cli (flags); + /* + * Stop the chip. + */ + spin_lock_irqsave(priv->chip_lock, flags); write_rreg (dev->base_addr, CSR0, CSR0_BABL|CSR0_CERR|CSR0_MISS|CSR0_MERR|CSR0_TINT|CSR0_RINT|CSR0_STOP); - restore_flags (flags); + spin_unlock_irqrestore(priv->chip_lock, flags); write_ireg (dev->base_addr, 5, 0x00a0); /* Receive address LED */ write_ireg (dev->base_addr, 6, 0x0081); /* Collision LED */ @@ -301,16 +308,15 @@ static int am79c961_close(struct net_device *dev) { + struct dev_priv *priv = (struct dev_priv *)dev->priv; unsigned long flags; netif_stop_queue(dev); - save_flags_cli (flags); - + spin_lock_irqsave(priv->chip_lock, flags); write_rreg (dev->base_addr, CSR0, CSR0_STOP); write_rreg (dev->base_addr, CSR3, CSR3_MASKALL); - - restore_flags (flags); + spin_unlock_irqrestore(priv->chip_lock, flags); free_irq (dev->irq, dev); @@ -368,6 +374,7 @@ */ static void am79c961_setmulticastlist (struct net_device *dev) { + struct dev_priv *priv = (struct dev_priv *)dev->priv; unsigned long flags; unsigned short multi_hash[4], mode; int i, stopped; @@ -387,7 +394,7 @@ am79c961_mc_hash(dmi, multi_hash); } - save_flags_cli(flags); + spin_lock_irqsave(priv->chip_lock, flags); stopped = read_rreg(dev->base_addr, CSR0) & CSR0_STOP; @@ -401,9 +408,9 @@ * Spin waiting for chip to report suspend mode */ while ((read_rreg(dev->base_addr, CTRL1) & CTRL1_SPND) == 0) { - restore_flags(flags); + spin_unlock_irqrestore(priv->chip_lock, flags); nop(); - save_flags_cli(flags); + spin_lock_irqsave(priv->chip_lock, flags); } } @@ -425,7 +432,7 @@ write_rreg(dev->base_addr, CTRL1, 0); } - restore_flags(flags); + spin_unlock_irqrestore(priv->chip_lock, flags); } static void am79c961_timeout(struct net_device *dev) @@ -464,10 +471,10 @@ am_writeword (dev, hdraddr + 2, TMD_OWN|TMD_STP|TMD_ENP); priv->txhead = head; - save_flags_cli (flags); + spin_lock_irqsave(priv->chip_lock, flags); write_rreg (dev->base_addr, CSR0, CSR0_TDMD|CSR0_IENA); dev->trans_start = jiffies; - restore_flags (flags); + spin_unlock_irqrestore(priv->chip_lock, flags); /* * If the next packet is owned by the ethernet device, @@ -611,20 +618,22 @@ priv->stats.rx_dropped ++; } +/* + * Initialise the chip. Note that we always expect + * to be entered with interrupts enabled. + */ static int am79c961_hw_init(struct net_device *dev) { - unsigned long flags; - - am79c961_ramtest(dev, 0x66); - am79c961_ramtest(dev, 0x99); - - save_flags_cli (flags); + struct dev_priv *priv = (struct dev_priv *)dev->priv; + spin_lock_irq(priv->chip_lock); write_rreg (dev->base_addr, CSR0, CSR0_STOP); write_rreg (dev->base_addr, CSR3, CSR3_MASKALL); + spin_unlock_irq(priv->chip_lock); - restore_flags (flags); + am79c961_ramtest(dev, 0x66); + am79c961_ramtest(dev, 0x99); return 0; } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/am79c961a.h linux/drivers/net/am79c961a.h --- v2.4.0-test8/linux/drivers/net/am79c961a.h Tue Jul 11 11:12:23 2000 +++ linux/drivers/net/am79c961a.h Mon Sep 18 15:15:22 2000 @@ -1,5 +1,9 @@ /* * linux/drivers/net/am79c961.h + * + * 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. */ #ifndef _LINUX_am79c961a_H @@ -118,6 +122,7 @@ unsigned char rxtail; unsigned long rxhdr; unsigned long txhdr; + spinlock_t chip_lock; }; extern int am79c961_probe (struct net_device *dev); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/appletalk/Makefile linux/drivers/net/appletalk/Makefile --- v2.4.0-test8/linux/drivers/net/appletalk/Makefile Fri Mar 3 12:54:44 2000 +++ linux/drivers/net/appletalk/Makefile Fri Sep 22 14:21:15 2000 @@ -16,13 +16,13 @@ obj- := export-objs := -obj-$(CONFIG_LTPC) += ltpc.o -obj-$(CONFIG_COPS) += cops.o obj-$(CONFIG_IPDDP) += ipddp.o +obj-$(CONFIG_COPS) += cops.o +obj-$(CONFIG_LTPC) += ltpc.o -L_TARGET := appletalk.a -L_OBJS := $(filter-out $(export-objs), $(obj-y)) -LX_OBJS := $(filter $(export-objs), $(obj-y)) +O_TARGET := appletalk.o +O_OBJS := $(filter-out $(export-objs), $(obj-y)) +OX_OBJS := $(filter $(export-objs), $(obj-y)) M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/appletalk/ipddp.c linux/drivers/net/appletalk/ipddp.c --- v2.4.0-test8/linux/drivers/net/appletalk/ipddp.c Tue Jul 18 16:52:35 2000 +++ linux/drivers/net/appletalk/ipddp.c Fri Sep 22 14:21:16 2000 @@ -27,36 +27,15 @@ "ipddp.c:v0.01 8/28/97 Bradford W. Johnson \n"; #include -#ifdef MODULE #include -#include -#endif - #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include -#include -#include -#include -#include -#include #include +#include +#include #include -#include +#include #include "ipddp.h" /* Our stuff */ @@ -85,23 +64,17 @@ static int ipddp_open(struct net_device *dev) { -#ifdef MODULE MOD_INC_USE_COUNT; -#endif - return 0; } static int ipddp_close(struct net_device *dev) { -#ifdef MODULE MOD_DEC_USE_COUNT; -#endif - return 0; } -int ipddp_init(struct net_device *dev) +static int __init ipddp_init(struct net_device *dev) { static unsigned version_printed = 0; @@ -151,7 +124,7 @@ */ static struct net_device_stats *ipddp_get_stats(struct net_device *dev) { - return (struct net_device_stats *)dev->priv; + return dev->priv; } /* @@ -242,7 +215,10 @@ rt->next = NULL; rt->dev = atrtr_get_dev(&rt->at); if(rt->dev == NULL) + { + kfree(rt); return (-ENETUNREACH); + } test = ipddp_find_route(rt); if(test != NULL) @@ -322,19 +298,11 @@ } } -#ifdef MODULE /* Module specific functions for ipddp.c */ - -static struct net_device dev_ipddp= -{ - "ipddp0\0 ", - 0, 0, 0, 0, - 0x0, 0, - 0, 0, 0, NULL, ipddp_init -}; +static struct net_device dev_ipddp = { init: ipddp_init }; MODULE_PARM(ipddp_mode, "i"); -int init_module(void) +static int __init ipddp_init_module(void) { int err; @@ -348,11 +316,14 @@ return 0; } -void cleanup_module(void) +static void __exit ipddp_cleanup_module(void) { unregister_netdev(&dev_ipddp); kfree(dev_ipddp.priv); - dev_ipddp.priv = NULL; + + memset(&dev_ipddp, 0, sizeof(dev_ipddp)); + dev_ipddp.init = ipddp_init; } -#endif /* MODULE */ +module_init(ipddp_init_module); +module_exit(ipddp_cleanup_module); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/arcnet/arcnet.c linux/drivers/net/arcnet/arcnet.c --- v2.4.0-test8/linux/drivers/net/arcnet/arcnet.c Thu Jun 29 11:11:22 2000 +++ linux/drivers/net/arcnet/arcnet.c Sun Sep 17 09:45:05 2000 @@ -155,9 +155,6 @@ #ifdef CONFIG_ARCNET_COM90xx com90xx_probe(NULL); #endif -#ifdef CONFIG_ARCNET_COM20020_PCI - com20020pci_probe_all(); -#endif #endif } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/arcnet/com20020-isa.c linux/drivers/net/arcnet/com20020-isa.c --- v2.4.0-test8/linux/drivers/net/arcnet/com20020-isa.c Sat May 13 07:50:25 2000 +++ linux/drivers/net/arcnet/com20020-isa.c Sun Sep 17 09:45:05 2000 @@ -205,7 +205,7 @@ case 6: /* Timeout */ lp->timeout = ints[6]; case 5: /* CKP value */ - lp->clock = ints[5]; + lp->clockp = ints[5]; case 4: /* Backplane flag */ lp->backplane = ints[4]; case 3: /* Node ID */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/arcnet/com20020-pci.c linux/drivers/net/arcnet/com20020-pci.c --- v2.4.0-test8/linux/drivers/net/arcnet/com20020-pci.c Sat May 13 08:19:21 2000 +++ linux/drivers/net/arcnet/com20020-pci.c Sun Sep 17 09:45:05 2000 @@ -148,7 +148,7 @@ remove: com20020pci_remove }; -int com20020pci_init(void) +static int __init com20020pci_init(void) { BUGLVL(D_NORMAL) printk(VERSION); #ifndef MODULE @@ -157,7 +157,7 @@ return pci_module_init(&com20020pci_driver); } -void com20020pci_cleanup(void) +static void __exit com20020pci_cleanup(void) { pci_unregister_driver(&com20020pci_driver); } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/atp.c linux/drivers/net/atp.c --- v2.4.0-test8/linux/drivers/net/atp.c Fri Aug 11 15:57:57 2000 +++ linux/drivers/net/atp.c Thu Sep 21 13:33:32 2000 @@ -1,27 +1,59 @@ /* atp.c: Attached (pocket) ethernet adapter driver for linux. */ /* - This is a driver for a commonly OEMed pocket (parallel port) - ethernet adapter. + This is a driver for commonly OEM pocket (parallel port) + ethernet adapters based on the Realtek RTL8002 and RTL8012 chips. - Written 1993,1994,1995 by Donald Becker. + Written 1993-2000 by Donald Becker. - Copyright 1993 United States Government as represented by the - Director, National Security Agency. + This software may be used and distributed according to the terms of + the GNU General Public License (GPL), incorporated herein by reference. + Drivers based on or derived from this code fall under the GPL and must + retain the authorship, copyright and license notice. This file is not + a complete program and may only be used when the entire operating + system is licensed under the GPL. + + Copyright 1993 United States Government as represented by the Director, + National Security Agency. Copyright 1994-2000 retained by the original + author, Donald Becker. The timer-based reset code was supplied in 1995 + by Bill Carlson, wwc@super.org. + + The author may be reached as becker@scyld.com, or C/O + Scyld Computing Corporation + 410 Severn Ave., Suite 210 + Annapolis MD 21403 - This software may be used and distributed according to the terms - of the GNU Public License, incorporated herein by reference. + Support information and updates available at + http://www.scyld.com/network/atp.html - The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O - Center of Excellence in Space Data and Information Sciences - Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 - The timer-based reset code was written by Bill Carlson, wwc@super.org. - Modular support/softnet added by Alan Cox. + */ -static const char *version = - "atp.c:v1.01 1/18/95 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n"; +static const char versionA[] = +"atp.c:v1.09 8/9/2000 Donald Becker \n"; +static const char versionB[] = +" http://www.scyld.com/network/atp.html\n"; + +/* The user-configurable values. + These may be modified when a driver module is loaded.*/ + +static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ +#define net_debug debug + +/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ +static int max_interrupt_work = 15; + +#define NUM_UNITS 2 +/* The standard set of ISA module parameters. */ +static int io[NUM_UNITS] = {0, 0}; +static int irq[NUM_UNITS] = {0, 0}; +static int xcvr[NUM_UNITS] = {0, 0}; /* The data transfer mode. */ + +/* Operational parameters that are set at compile time. */ + +/* Time in jiffies before concluding the transmitter is hung. */ +#define TX_TIMEOUT (400*HZ/1000) /* This file is a device driver for the RealTek (aka AT-Lan-Tec) pocket @@ -35,8 +67,12 @@ description is written based on guesses and writing lots of special-purpose code to test my theorized operation. + In 1997 Realtek made available the documentation for the second generation + RTL8012 chip, which has lead to several driver improvements. + http://www.realtek.com.tw/cn/cn.html + Theory of Operation - + The RTL8002 adapter seems to be built around a custom spin of the SEEQ controller core. It probably has a 16K or 64K internal packet buffer, of which the first 4K is devoted to transmit and the rest to receive. @@ -60,6 +96,10 @@ timing and control bits. The data is then read from status port or written to the data port. + Correction: the controller has two banks of 16 registers. The second + bank contains only the multicast filter table (now used) and the EEPROM + access registers. + Since the bulk data transfer of the actual packets through the slow parallel port dominates the driver's running time, four distinct data (non-register) transfer modes are provided by the adapter, two in each @@ -105,18 +145,40 @@ #include #include #include +#include #include "atp.h" -/* use 0 for production, 1 for verification, >2 for debug */ -#ifndef NET_DEBUG -#define NET_DEBUG 1 -#endif -static unsigned int net_debug = NET_DEBUG; +MODULE_AUTHOR("Donald Becker "); +MODULE_DESCRIPTION("RealTek RTL8002/8012 parallel port Ethernet driver"); +MODULE_PARM(max_interrupt_work, "i"); +MODULE_PARM(debug, "i"); +MODULE_PARM(io, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(xcvr, "1-" __MODULE_STRING(MAX_UNITS) "i"); + +#define RUN_AT(x) (jiffies + (x)) /* The number of low I/O ports used by the ethercard. */ #define ETHERCARD_TOTAL_SIZE 3 +/* Sequence to switch an 8012 from printer mux to ethernet mode. */ +static char mux_8012[] = { 0xff, 0xf7, 0xff, 0xfb, 0xf3, 0xfb, 0xff, 0xf7,}; + +struct net_local { + spinlock_t lock; + struct net_device *next_module; + struct net_device_stats stats; + struct timer_list timer; /* Media selection timer. */ + long last_rx_time; /* Last Rx, in jiffies, to handle Rx hang. */ + int saved_tx_size; + unsigned int tx_unit_busy:1; + unsigned char re_tx, /* Number of packet retransmissions. */ + addr_mode, /* Current Rx filter e.g. promiscuous, etc. */ + pac_cnt_in_tx_buf, + chip_type; +}; + /* This code, written by wwc@super.org, resets the adapter every TIMED_CHECKER ticks. This recovers from an unknown error which hangs the device. */ @@ -124,40 +186,41 @@ #ifdef TIMED_CHECKER #include static void atp_timed_checker(unsigned long ignored); -static struct net_device *atp_timed_dev; -static struct timer_list atp_timer = { function: atp_timed_checker }; #endif /* Index to functions, as function prototypes. */ -static int atp_probe1(struct net_device *dev, short ioaddr); +static int atp_probe1(struct net_device *dev, long ioaddr); static void get_node_ID(struct net_device *dev); -static unsigned short eeprom_op(short ioaddr, unsigned int cmd); +static unsigned short eeprom_op(long ioaddr, unsigned int cmd); static int net_open(struct net_device *dev); static void hardware_init(struct net_device *dev); -static void tx_timeout(struct net_device *dev); -static void write_packet(short ioaddr, int length, unsigned char *packet, int mode); -static void trigger_send(short ioaddr, int length); -static int net_send_packet(struct sk_buff *skb, struct net_device *dev); -static void net_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static void write_packet(long ioaddr, int length, unsigned char *packet, int mode); +static void trigger_send(long ioaddr, int length); +static int atp_send_packet(struct sk_buff *skb, struct net_device *dev); +static void atp_interrupt(int irq, void *dev_id, struct pt_regs *regs); static void net_rx(struct net_device *dev); -static void read_block(short ioaddr, int length, unsigned char *buffer, int data_mode); +static void read_block(long ioaddr, int length, unsigned char *buffer, int data_mode); static int net_close(struct net_device *dev); static struct net_device_stats *net_get_stats(struct net_device *dev); -static void set_multicast_list(struct net_device *dev); +static void set_rx_mode_8002(struct net_device *dev); +static void set_rx_mode_8012(struct net_device *dev); +static void tx_timeout(struct net_device *dev); + + +/* A list of all installed ATP devices, for removing the driver module. */ +static struct net_device *root_atp_dev = NULL; - /* Check for a network adapter of this type, and return '0' iff one exists. If dev->base_addr == 0, probe all likely locations. If dev->base_addr == 1, always return failure. If dev->base_addr == 2, allocate space for the device and return success (detachable devices only). */ - static int __init atp_init(struct net_device *dev) { int *port, ports[] = {0x378, 0x278, 0x3bc, 0}; - int base_addr = dev->base_addr; + int base_addr = dev ? dev->base_addr : io[0]; if (base_addr > 0x1ff) /* Check a single specified location. */ return atp_probe1(dev, base_addr); @@ -165,7 +228,7 @@ return -ENXIO; for (port = ports; *port; port++) { - int ioaddr = *port; + long ioaddr = *port; outb(0x57, ioaddr + PAR_DATA); if (inb(ioaddr + PAR_DATA) != 0x57) continue; @@ -176,36 +239,68 @@ return -ENODEV; } -static int __init atp_probe1(struct net_device *dev, short ioaddr) +static int __init atp_probe1(struct net_device *dev, long ioaddr) { - int saved_ctrl_reg, status; + struct net_local *lp; + int saved_ctrl_reg, status, i; outb(0xff, ioaddr + PAR_DATA); /* Save the original value of the Control register, in case we guessed wrong. */ saved_ctrl_reg = inb(ioaddr + PAR_CONTROL); + if (net_debug > 3) + printk("atp: Control register was %#2.2x.\n", saved_ctrl_reg); /* IRQEN=0, SLCTB=high INITB=high, AUTOFDB=high, STBB=high. */ outb(0x04, ioaddr + PAR_CONTROL); +#ifndef final_version + if (net_debug > 3) { + /* Turn off the printer multiplexer on the 8012. */ + for (i = 0; i < 8; i++) + outb(mux_8012[i], ioaddr + PAR_DATA); + write_reg(ioaddr, MODSEL, 0x00); + printk("atp: Registers are "); + for (i = 0; i < 32; i++) + printk(" %2.2x", read_nibble(ioaddr, i)); + printk(".\n"); + } +#endif + /* Turn off the printer multiplexer on the 8012. */ + for (i = 0; i < 8; i++) + outb(mux_8012[i], ioaddr + PAR_DATA); write_reg_high(ioaddr, CMR1, CMR1h_RESET); - udelay(100); + /* udelay() here? */ status = read_nibble(ioaddr, CMR1); + if (net_debug > 3) { + printk(KERN_DEBUG "atp: Status nibble was %#2.2x..", status); + for (i = 0; i < 32; i++) + printk(" %2.2x", read_nibble(ioaddr, i)); + printk("\n"); + } + if ((status & 0x78) != 0x08) { /* The pocket adapter probe failed, restore the control register. */ outb(saved_ctrl_reg, ioaddr + PAR_CONTROL); - return 1; + return -ENODEV; } status = read_nibble(ioaddr, CMR2_h); if ((status & 0x78) != 0x10) { outb(saved_ctrl_reg, ioaddr + PAR_CONTROL); - return 1; + return -ENODEV; } + + dev = init_etherdev(dev, sizeof(struct net_local)); + if (!dev) + return -ENOMEM; + /* Find the IRQ used by triggering an interrupt. */ write_reg_byte(ioaddr, CMR2, 0x01); /* No accept mode, IRQ out. */ write_reg_high(ioaddr, CMR1, CMR1h_RxENABLE | CMR1h_TxENABLE); /* Enable Tx and Rx. */ /* Omit autoIRQ routine for now. Use "table lookup" instead. Uhgggh. */ - if (ioaddr == 0x378) + if (irq[0]) + dev->irq = irq[0]; + else if (ioaddr == 0x378) dev->irq = 7; else dev->irq = 5; @@ -217,69 +312,73 @@ /* Read the station address PROM. */ get_node_ID(dev); - printk("%s: Pocket adapter found at %#3lx, IRQ %d, SAPROM " +#ifndef MODULE + if (net_debug) + printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB); +#endif + + printk(KERN_NOTICE "%s: Pocket adapter found at %#3lx, IRQ %d, SAPROM " "%02X:%02X:%02X:%02X:%02X:%02X.\n", dev->name, dev->base_addr, dev->irq, dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); - /* Leave the hardware in a reset state. */ - write_reg_high(ioaddr, CMR1, CMR1h_RESET); - - if (net_debug) - printk(version); + /* Reset the ethernet hardware and activate the printer pass-through. */ + write_reg_high(ioaddr, CMR1, CMR1h_RESET | CMR1h_MUX); /* Initialize the device structure. */ ether_setup(dev); - dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); + if (dev->priv == NULL) + dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); if (dev->priv == NULL) return -ENOMEM; memset(dev->priv, 0, sizeof(struct net_local)); - { - struct net_local *lp = (struct net_local *)dev->priv; - lp->addr_mode = CMR2h_Normal; - spin_lock_init(&lp->lock); - } + + lp = (struct net_local *)dev->priv; + lp->chip_type = RTL8002; + lp->addr_mode = CMR2h_Normal; + spin_lock_init(&lp->lock); + + lp->next_module = root_atp_dev; + root_atp_dev = dev; /* For the ATP adapter the "if_port" is really the data transfer mode. */ - dev->if_port = (dev->mem_start & 0xf) ? dev->mem_start & 0x7 : 4; + if (xcvr[0]) + dev->if_port = xcvr[0]; + else + dev->if_port = (dev->mem_start & 0xf) ? (dev->mem_start & 0x7) : 4; if (dev->mem_end & 0xf) net_debug = dev->mem_end & 7; dev->open = net_open; dev->stop = net_close; - dev->hard_start_xmit = net_send_packet; + dev->hard_start_xmit = atp_send_packet; dev->get_stats = net_get_stats; - dev->set_multicast_list = set_multicast_list; + dev->set_multicast_list = + lp->chip_type == RTL8002 ? &set_rx_mode_8002 : &set_rx_mode_8012; dev->tx_timeout = tx_timeout; - dev->watchdog_timeo = HZ/20; + dev->watchdog_timeo = TX_TIMEOUT; -#ifdef TIMED_CHECKER - del_timer(&atp_timer); - atp_timer.expires = jiffies + TIMED_CHECKER; - atp_timed_dev = dev; - add_timer(&atp_timer); -#endif return 0; } /* Read the station address PROM, usually a word-wide EEPROM. */ static void __init get_node_ID(struct net_device *dev) { - short ioaddr = dev->base_addr; + long ioaddr = dev->base_addr; int sa_offset = 0; int i; - + write_reg(ioaddr, CMR2, CMR2_EEPROM); /* Point to the EEPROM control registers. */ - + /* Some adapters have the station address at offset 15 instead of offset zero. Check for it, and fix it if needed. */ if (eeprom_op(ioaddr, EE_READ(0)) == 0xffff) sa_offset = 15; - + for (i = 0; i < 3; i++) - ((unsigned short *)dev->dev_addr)[i] = - ntohs(eeprom_op(ioaddr, EE_READ(sa_offset + i))); - + ((u16 *)dev->dev_addr)[i] = + be16_to_cpu(eeprom_op(ioaddr, EE_READ(sa_offset + i))); + write_reg(ioaddr, CMR2, CMR2_NULL); } @@ -295,26 +394,24 @@ * DO : _________X_______X */ -static unsigned short __init eeprom_op(short ioaddr, unsigned int cmd) +static unsigned short __init eeprom_op(long ioaddr, unsigned int cmd) { unsigned eedata_out = 0; int num_bits = EE_CMD_SIZE; - + while (--num_bits >= 0) { char outval = test_bit(num_bits, &cmd) ? EE_DATA_WRITE : 0; write_reg_high(ioaddr, PROM_CMD, outval | EE_CLK_LOW); - udelay(5); write_reg_high(ioaddr, PROM_CMD, outval | EE_CLK_HIGH); eedata_out <<= 1; if (read_nibble(ioaddr, PROM_DATA) & EE_DATA_READ) eedata_out++; - udelay(5); } write_reg_high(ioaddr, PROM_CMD, EE_CLK_LOW & ~EE_CS); return eedata_out; } - + /* Open/initialize the board. This is called (in the current kernel) sometime after booting when the 'ifconfig' program is run. @@ -327,17 +424,25 @@ */ static int net_open(struct net_device *dev) { + struct net_local *lp = (struct net_local *)dev->priv; + + MOD_INC_USE_COUNT; /* The interrupt line is turned off (tri-stated) when the device isn't in use. That's especially important for "attached" interfaces where the port or interrupt may be shared. */ - - if (request_irq(dev->irq, &net_interrupt, 0, "ATP", dev)) { + if (request_irq(dev->irq, &atp_interrupt, 0, "ATP Ethernet", dev)) { + MOD_DEC_USE_COUNT; return -EAGAIN; } + hardware_init(dev); - MOD_INC_USE_COUNT; + init_timer(&lp->timer); + lp->timer.expires = RUN_AT(TIMED_CHECKER); + lp->timer.data = (unsigned long)dev; + lp->timer.function = &atp_timed_checker; /* timer handler */ + add_timer(&lp->timer); netif_start_queue(dev); return 0; @@ -348,54 +453,57 @@ static void hardware_init(struct net_device *dev) { struct net_local *lp = (struct net_local *)dev->priv; - int ioaddr = dev->base_addr; - int i; + long ioaddr = dev->base_addr; + int i; + /* Turn off the printer multiplexer on the 8012. */ + for (i = 0; i < 8; i++) + outb(mux_8012[i], ioaddr + PAR_DATA); write_reg_high(ioaddr, CMR1, CMR1h_RESET); - - for (i = 0; i < 6; i++) + + for (i = 0; i < 6; i++) write_reg_byte(ioaddr, PAR0 + i, dev->dev_addr[i]); write_reg_high(ioaddr, CMR2, lp->addr_mode); if (net_debug > 2) { - printk("%s: Reset: current Rx mode %d.\n", dev->name, + printk(KERN_DEBUG "%s: Reset: current Rx mode %d.\n", dev->name, (read_nibble(ioaddr, CMR2_h) >> 3) & 0x0f); } - write_reg(ioaddr, CMR2, CMR2_IRQOUT); - write_reg_high(ioaddr, CMR1, CMR1h_RxENABLE | CMR1h_TxENABLE); + write_reg(ioaddr, CMR2, CMR2_IRQOUT); + write_reg_high(ioaddr, CMR1, CMR1h_RxENABLE | CMR1h_TxENABLE); /* Enable the interrupt line from the serial port. */ outb(Ctrl_SelData + Ctrl_IRQEN, ioaddr + PAR_CONTROL); /* Unmask the interesting interrupts. */ - write_reg(ioaddr, IMR, ISR_RxOK | ISR_TxErr | ISR_TxOK); - write_reg_high(ioaddr, IMR, ISRh_RxErr); + write_reg(ioaddr, IMR, ISR_RxOK | ISR_TxErr | ISR_TxOK); + write_reg_high(ioaddr, IMR, ISRh_RxErr); lp->tx_unit_busy = 0; - lp->pac_cnt_in_tx_buf = 0; + lp->pac_cnt_in_tx_buf = 0; lp->saved_tx_size = 0; } -static void trigger_send(short ioaddr, int length) +static void trigger_send(long ioaddr, int length) { write_reg_byte(ioaddr, TxCNT0, length & 0xff); write_reg(ioaddr, TxCNT1, length >> 8); write_reg(ioaddr, CMR1, CMR1_Xmit); } -static void write_packet(short ioaddr, int length, unsigned char *packet, int data_mode) +static void write_packet(long ioaddr, int length, unsigned char *packet, int data_mode) { - length = (length + 1) & ~1; /* Round up to word length. */ - outb(EOC+MAR, ioaddr + PAR_DATA); - if ((data_mode & 1) == 0) { + length = (length + 1) & ~1; /* Round up to word length. */ + outb(EOC+MAR, ioaddr + PAR_DATA); + if ((data_mode & 1) == 0) { /* Write the packet out, starting with the write addr. */ outb(WrAddr+MAR, ioaddr + PAR_DATA); do { write_byte_mode0(ioaddr, *packet++); } while (--length > 0) ; - } else { + } else { /* Write the packet out in slow mode. */ unsigned char outbyte = *packet++; @@ -409,77 +517,85 @@ outb(Ctrl_HNibWrite + Ctrl_IRQEN, ioaddr + PAR_CONTROL); while (--length > 0) write_byte_mode1(ioaddr, *packet++); - } - /* Terminate the Tx frame. End of write: ECB. */ - outb(0xff, ioaddr + PAR_DATA); - outb(Ctrl_HNibWrite | Ctrl_SelData | Ctrl_IRQEN, ioaddr + PAR_CONTROL); + } + /* Terminate the Tx frame. End of write: ECB. */ + outb(0xff, ioaddr + PAR_DATA); + outb(Ctrl_HNibWrite | Ctrl_SelData | Ctrl_IRQEN, ioaddr + PAR_CONTROL); } static void tx_timeout(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; - int ioaddr = dev->base_addr; - /* If we get here, some higher level has decided we are broken. */ - printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name, + struct net_local *np = (struct net_local *)dev->priv; + long ioaddr = dev->base_addr; + + printk(KERN_WARNING "%s: Transmit timed out, %s?\n", dev->name, inb(ioaddr + PAR_CONTROL) & 0x10 ? "network cable problem" : "IRQ conflict"); - lp->stats.tx_errors++; + np->stats.tx_errors++; /* Try to restart the adapter. */ hardware_init(dev); dev->trans_start = jiffies; netif_wake_queue(dev); + np->stats.tx_errors++; + return; } -static int net_send_packet(struct sk_buff *skb, struct net_device *dev) +static int atp_send_packet(struct sk_buff *skb, struct net_device *dev) { struct net_local *lp = (struct net_local *)dev->priv; - int ioaddr = dev->base_addr; - short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; - unsigned char *buf = skb->data; - unsigned long flags; - + long ioaddr = dev->base_addr; + int length; + long flags; + + length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; + netif_stop_queue(dev); - + /* Disable interrupts by writing 0x00 to the Interrupt Mask Register. This sequence must not be interrupted by an incoming packet. */ - + spin_lock_irqsave(&lp->lock, flags); write_reg(ioaddr, IMR, 0); write_reg_high(ioaddr, IMR, 0); spin_unlock_irqrestore(&lp->lock, flags); - - write_packet(ioaddr, length, buf, dev->if_port); + + write_packet(ioaddr, length, skb->data, dev->if_port); lp->pac_cnt_in_tx_buf++; if (lp->tx_unit_busy == 0) { trigger_send(ioaddr, length); lp->saved_tx_size = 0; /* Redundant */ lp->re_tx = 0; - lp->tx_unit_busy = 1; + lp->tx_unit_busy = 1; } else lp->saved_tx_size = length; - - dev->trans_start = jiffies; /* Re-enable the LPT interrupts. */ write_reg(ioaddr, IMR, ISR_RxOK | ISR_TxErr | ISR_TxOK); write_reg_high(ioaddr, IMR, ISRh_RxErr); + + dev->trans_start = jiffies; dev_kfree_skb (skb); return 0; } - + + /* The typical workload of the driver: Handle the network interface interrupts. */ -static void -net_interrupt(int irq, void *dev_id, struct pt_regs * regs) +static void atp_interrupt(int irq, void *dev_instance, struct pt_regs * regs) { - struct net_device *dev = dev_id; + struct net_device *dev = (struct net_device *)dev_instance; struct net_local *lp; - int ioaddr, status, boguscount = 20; + long ioaddr; static int num_tx_since_rx = 0; + int boguscount = max_interrupt_work; + if (dev == NULL) { + printk(KERN_ERR "ATP_interrupt(): irq %d for unknown device.\n", irq); + return; + } ioaddr = dev->base_addr; lp = (struct net_local *)dev->priv; - + spin_lock(&lp->lock); /* Disable additional spurious interrupts. */ @@ -489,14 +605,10 @@ write_reg(ioaddr, CMR2, CMR2_NULL); write_reg(ioaddr, IMR, 0); - if (net_debug > 5) - printk("%s: In interrupt ", dev->name); - - while (--boguscount > 0) - { - status = read_nibble(ioaddr, ISR); - if (net_debug > 5) - printk("loop status %02x..", status); + if (net_debug > 5) printk(KERN_DEBUG "%s: In interrupt ", dev->name); + while (--boguscount > 0) { + int status = read_nibble(ioaddr, ISR); + if (net_debug > 5) printk("loop status %02x..", status); if (status & (ISR_RxOK<<3)) { write_reg(ioaddr, ISR, ISR_RxOK); /* Clear the Rx interrupt. */ @@ -534,8 +646,7 @@ break; } /* Attempt to retransmit. */ - if (net_debug > 6) - printk("attempting to ReTx"); + if (net_debug > 6) printk("attempting to ReTx"); write_reg(ioaddr, CMR1, CMR1_ReXmit + CMR1_Xmit); } else { /* Finish up the transmit. */ @@ -551,10 +662,10 @@ } num_tx_since_rx++; } else if (num_tx_since_rx > 8 - && jiffies - dev->last_rx > 100) { + && jiffies > dev->last_rx + HZ) { if (net_debug > 2) - printk("%s: Missed packet? No Rx after %d Tx and %ld jiffies" - " status %02x CMR1 %02x.\n", dev->name, + printk(KERN_DEBUG "%s: Missed packet? No Rx after %d Tx and " + "%ld jiffies status %02x CMR1 %02x.\n", dev->name, num_tx_since_rx, jiffies - dev->last_rx, status, (read_nibble(ioaddr, CMR1) >> 3) & 15); lp->stats.rx_missed_errors++; @@ -563,7 +674,7 @@ break; } else break; - } + } /* This following code fixes a rare (and very difficult to track down) problem where the adapter forgets its ethernet address. */ @@ -571,40 +682,62 @@ int i; for (i = 0; i < 6; i++) write_reg_byte(ioaddr, PAR0 + i, dev->dev_addr[i]); -#ifdef TIMED_CHECKER - mod_timer(&atp_timer, jiffies+TIMED_CHECKER); +#if 0 && defined(TIMED_CHECKER) + mod_timer(&lp->timer, RUN_AT(TIMED_CHECKER)); #endif } /* Tell the adapter that it can go back to using the output line as IRQ. */ - write_reg(ioaddr, CMR2, CMR2_IRQOUT); + write_reg(ioaddr, CMR2, CMR2_IRQOUT); /* Enable the physical interrupt line, which is sure to be low until.. */ outb(Ctrl_SelData + Ctrl_IRQEN, ioaddr + PAR_CONTROL); /* .. we enable the interrupt sources. */ write_reg(ioaddr, IMR, ISR_RxOK | ISR_TxErr | ISR_TxOK); write_reg_high(ioaddr, IMR, ISRh_RxErr); /* Hmmm, really needed? */ - if (net_debug > 5) - printk("exiting interrupt.\n"); - spin_unlock(&lp->lock); + + if (net_debug > 5) printk("exiting interrupt.\n"); return; } #ifdef TIMED_CHECKER /* This following code fixes a rare (and very difficult to track down) problem where the adapter forgets its ethernet address. */ -static void atp_timed_checker(unsigned long ignored) +static void atp_timed_checker(unsigned long data) { + struct net_device *dev = (struct net_device *)data; + long ioaddr = dev->base_addr; + struct net_local *lp = (struct net_local *)dev->priv; + int tickssofar = jiffies - lp->last_rx_time; int i; - struct net_local *lp = (struct net_local *)atp_timed_dev->priv; - int ioaddr = atp_timed_dev->base_addr; spin_lock(&lp->lock); - for (i = 0; i < 6; i++) - write_reg_byte(ioaddr, PAR0 + i, atp_timed_dev->dev_addr[i]); + if (tickssofar > 2*HZ) { +#if 1 + for (i = 0; i < 6; i++) + write_reg_byte(ioaddr, PAR0 + i, dev->dev_addr[i]); + lp->last_rx_time = jiffies; +#else + for (i = 0; i < 6; i++) + if (read_cmd_byte(ioaddr, PAR0 + i) != atp_timed_dev->dev_addr[i]) + { + struct net_local *lp = (struct net_local *)atp_timed_dev->priv; + write_reg_byte(ioaddr, PAR0 + i, atp_timed_dev->dev_addr[i]); + if (i == 2) + lp->stats.tx_errors++; + else if (i == 3) + lp->stats.tx_dropped++; + else if (i == 4) + lp->stats.collisions++; + else + lp->stats.rx_errors++; + } +#endif + } spin_unlock(&lp->lock); - mod_timer(&atp_timer, jiffies+TIMED_CHECKER); + lp->timer.expires = RUN_AT(TIMED_CHECKER); + add_timer(&lp->timer); } #endif @@ -612,61 +745,57 @@ static void net_rx(struct net_device *dev) { struct net_local *lp = (struct net_local *)dev->priv; - int ioaddr = dev->base_addr; -#ifdef notdef - ushort header[4]; -#else + long ioaddr = dev->base_addr; struct rx_header rx_head; -#endif /* Process the received packet. */ outb(EOC+MAR, ioaddr + PAR_DATA); read_block(ioaddr, 8, (unsigned char*)&rx_head, dev->if_port); if (net_debug > 5) - printk(" rx_count %04x %04x %04x %04x..", rx_head.pad, + printk(KERN_DEBUG " rx_count %04x %04x %04x %04x..", rx_head.pad, rx_head.rx_count, rx_head.rx_status, rx_head.cur_addr); if ((rx_head.rx_status & 0x77) != 0x01) { lp->stats.rx_errors++; - /* Ackkk! I don't have any documentation on what the error bits mean! - The best I can do is slap the device around a bit. */ - if (net_debug > 3) printk("%s: Unknown ATP Rx error %04x.\n", - dev->name, rx_head.rx_status); - hardware_init(dev); + if (rx_head.rx_status & 0x0004) lp->stats.rx_frame_errors++; + else if (rx_head.rx_status & 0x0002) lp->stats.rx_crc_errors++; + if (net_debug > 3) + printk(KERN_DEBUG "%s: Unknown ATP Rx error %04x.\n", + dev->name, rx_head.rx_status); + if (rx_head.rx_status & 0x0020) { + lp->stats.rx_fifo_errors++; + write_reg_high(ioaddr, CMR1, CMR1h_TxENABLE); + write_reg_high(ioaddr, CMR1, CMR1h_RxENABLE | CMR1h_TxENABLE); + } else if (rx_head.rx_status & 0x0050) + hardware_init(dev); return; } else { - /* Malloc up new buffer. */ - int pkt_len = (rx_head.rx_count & 0x7ff) - 4; /* The "-4" is omits the FCS (CRC). */ + /* Malloc up new buffer. The "-4" omits the FCS (CRC). */ + int pkt_len = (rx_head.rx_count & 0x7ff) - 4; struct sk_buff *skb; - - skb = dev_alloc_skb(pkt_len); + + skb = dev_alloc_skb(pkt_len + 2); if (skb == NULL) { - printk("%s: Memory squeeze, dropping packet.\n", dev->name); + printk(KERN_ERR "%s: Memory squeeze, dropping packet.\n", + dev->name); lp->stats.rx_dropped++; goto done; } skb->dev = dev; - - read_block(ioaddr, pkt_len, skb_put(skb,pkt_len), dev->if_port); - if (net_debug > 6) { - unsigned char *data = skb->data; - printk(" data %02x%02x%02x %02x%02x%02x %02x%02x%02x" - "%02x%02x%02x %02x%02x..", - data[0], data[1], data[2], data[3], data[4], data[5], - data[6], data[7], data[8], data[9], data[10], data[11], - data[12], data[13]); - } - - skb->protocol=eth_type_trans(skb,dev); + skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ + read_block(ioaddr, pkt_len, skb_put(skb,pkt_len), dev->if_port); + skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); lp->stats.rx_packets++; + lp->stats.rx_bytes += pkt_len; } done: write_reg(ioaddr, CMR1, CMR1_NextPkt); + lp->last_rx_time = jiffies; return; } -static void read_block(short ioaddr, int length, unsigned char *p, int data_mode) +static void read_block(long ioaddr, int length, unsigned char *p, int data_mode) { if (data_mode <= 3) { /* Mode 0 or 1 */ @@ -682,18 +811,21 @@ else do *p++ = read_byte_mode6(ioaddr); while (--length > 0); - outb(EOC+HNib+MAR, ioaddr + PAR_DATA); + outb(EOC+HNib+MAR, ioaddr + PAR_DATA); outb(Ctrl_SelData, ioaddr + PAR_CONTROL); } /* The inverse routine to net_open(). */ -static int net_close(struct net_device *dev) +static int +net_close(struct net_device *dev) { struct net_local *lp = (struct net_local *)dev->priv; - int ioaddr = dev->base_addr; + long ioaddr = dev->base_addr; netif_stop_queue(dev); + del_timer_sync(&lp->timer); + /* Flush the Tx and disable Rx here. */ lp->addr_mode = CMR2h_OFF; write_reg_high(ioaddr, CMR2, CMR2h_OFF); @@ -702,8 +834,8 @@ outb(0x00, ioaddr + PAR_CONTROL); free_irq(dev->irq, dev); - /* Leave the hardware in a reset state. */ - write_reg_high(ioaddr, CMR1, CMR1h_RESET); + /* Reset the ethernet hardware and activate the printer pass-through. */ + write_reg_high(ioaddr, CMR1, CMR1h_RESET | CMR1h_MUX); MOD_DEC_USE_COUNT; @@ -712,7 +844,8 @@ /* Get the current statistics. This may be called with the card open or closed. */ -static struct net_device_stats *net_get_stats(struct net_device *dev) +static struct net_device_stats * +net_get_stats(struct net_device *dev) { struct net_local *lp = (struct net_local *)dev->priv; return &lp->stats; @@ -721,46 +854,101 @@ /* * Set or clear the multicast filter for this adapter. */ - -static void set_multicast_list(struct net_device *dev) + +/* The little-endian AUTODIN32 ethernet CRC calculation. + This is common code and should be moved to net/core/crc.c */ +static unsigned const ethernet_polynomial_le = 0xedb88320U; +static inline unsigned ether_crc_le(int length, unsigned char *data) +{ + unsigned int crc = 0xffffffff; /* Initial value. */ + while(--length >= 0) { + unsigned char current_octet = *data++; + int bit; + for (bit = 8; --bit >= 0; current_octet >>= 1) { + if ((crc ^ current_octet) & 1) { + crc >>= 1; + crc ^= ethernet_polynomial_le; + } else + crc >>= 1; + } + } + return crc; +} + +static void set_rx_mode_8002(struct net_device *dev) { struct net_local *lp = (struct net_local *)dev->priv; - short ioaddr = dev->base_addr; - int num_addrs=dev->mc_count; - - if(dev->flags&(IFF_ALLMULTI|IFF_PROMISC)) - num_addrs=1; - /* - * We must make the kernel realise we had to move - * into promisc mode or we start all out war on - * the cable. - AC - */ - if(num_addrs) - dev->flags|=IFF_PROMISC; - lp->addr_mode = num_addrs ? CMR2h_PROMISC : CMR2h_Normal; + long ioaddr = dev->base_addr; + + if ( dev->mc_count > 0 || (dev->flags & (IFF_ALLMULTI|IFF_PROMISC))) { + /* We must make the kernel realise we had to move + * into promisc mode or we start all out war on + * the cable. - AC + */ + dev->flags|=IFF_PROMISC; + lp->addr_mode = CMR2h_PROMISC; + } else + lp->addr_mode = CMR2h_Normal; write_reg_high(ioaddr, CMR2, lp->addr_mode); } -/* module stuff */ -static int io; -static struct net_device atp_dev = { init: atp_init }; -MODULE_AUTHOR("Donald Becker "); -MODULE_DESCRIPTION("Realtek 8002/8012 Pocket Lan Adapter"); -MODULE_PARM(io, "I/O port of the pocket adapter"); +static void set_rx_mode_8012(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + long ioaddr = dev->base_addr; + unsigned char new_mode, mc_filter[8]; /* Multicast hash filter */ + int i; -static int __init atp_init_module(void) { - atp_dev.base_addr = io; + if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ + new_mode = CMR2h_PROMISC; + } else if ((dev->mc_count > 1000) || (dev->flags & IFF_ALLMULTI)) { + /* Too many to filter perfectly -- accept all multicasts. */ + memset(mc_filter, 0xff, sizeof(mc_filter)); + new_mode = CMR2h_Normal; + } else { + struct dev_mc_list *mclist; - if (register_netdev(&atp_dev) != 0) - return -EIO; + memset(mc_filter, 0, sizeof(mc_filter)); + for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + i++, mclist = mclist->next) + set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x3f, + mc_filter); + new_mode = CMR2h_Normal; + } + lp->addr_mode = new_mode; + write_reg(ioaddr, CMR2, CMR2_IRQOUT | 0x04); /* Switch to page 1. */ + for (i = 0; i < 8; i++) + write_reg_byte(ioaddr, i, mc_filter[i]); + if (net_debug > 2 || 1) { + lp->addr_mode = 1; + printk(KERN_DEBUG "%s: Mode %d, setting multicast filter to", + dev->name, lp->addr_mode); + for (i = 0; i < 8; i++) + printk(" %2.2x", mc_filter[i]); + printk(".\n"); + } - return 0; + write_reg_high(ioaddr, CMR2, lp->addr_mode); + write_reg(ioaddr, CMR2, CMR2_IRQOUT); /* Switch back to page 0 */ +} + +static int __init atp_init_module(void) { + if (debug) /* Emit version even if no cards detected. */ + printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB); + return atp_init(NULL); } static void __exit atp_cleanup_module(void) { - unregister_netdev(&atp_dev); + struct net_device *next_dev; + + while (root_atp_dev) { + next_dev = ((struct net_local *)root_atp_dev->priv)->next_module; + unregister_netdev(root_atp_dev); + /* No need to release_region(), since we never snarf it. */ + kfree(root_atp_dev); + root_atp_dev = next_dev; + } } module_init(atp_init_module); module_exit(atp_cleanup_module); - diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/atp.h linux/drivers/net/atp.h --- v2.4.0-test8/linux/drivers/net/atp.h Sun Feb 13 18:20:21 2000 +++ linux/drivers/net/atp.h Thu Sep 21 13:33:32 2000 @@ -1,30 +1,23 @@ +/* Linux header file for the ATP pocket ethernet adapter. */ +/* v1.09 8/9/2000 becker@scyld.com. */ + #include #include -#include - -struct net_local -{ - struct net_device_stats stats; - ushort saved_tx_size; - unsigned char - re_tx, /* Number of packet retransmissions. */ - tx_unit_busy, - addr_mode, /* Current Rx filter e.g. promiscuous, etc. */ - pac_cnt_in_tx_buf; - spinlock_t lock; /* Safety lock */ -}; +/* The header prepended to received packets. */ struct rx_header { - ushort pad; /* The first read is always corrupted. */ - ushort rx_count; - ushort rx_status; /* Unknown bit assignments :-<. */ - ushort cur_addr; /* Apparently the current buffer address(?) */ + ushort pad; /* Pad. */ + ushort rx_count; + ushort rx_status; /* Unknown bit assignments :-<. */ + ushort cur_addr; /* Apparently the current buffer address(?) */ }; #define PAR_DATA 0 #define PAR_STATUS 1 #define PAR_CONTROL 2 +enum chip_type { RTL8002, RTL8012 }; + #define Ctrl_LNibRead 0x08 /* LP_PSELECP */ #define Ctrl_HNibRead 0 #define Ctrl_LNibWrite 0x08 /* LP_PSELECP */ @@ -40,18 +33,19 @@ enum page0_regs { - /* The first six registers hold the ethernet physical station address. */ - PAR0 = 0, PAR1 = 1, PAR2 = 2, PAR3 = 3, PAR4 = 4, PAR5 = 5, - TxCNT0 = 6, TxCNT1 = 7, /* The transmit byte count. */ - TxSTAT = 8, RxSTAT = 9, /* Tx and Rx status. */ - ISR = 10, IMR = 11, /* Interrupt status and mask. */ - CMR1 = 12, /* Command register 1. */ - CMR2 = 13, /* Command register 2. */ - MAR = 14, /* Memory address register. */ - CMR2_h = 0x1d, -}; + /* The first six registers hold the ethernet physical station address. */ + PAR0 = 0, PAR1 = 1, PAR2 = 2, PAR3 = 3, PAR4 = 4, PAR5 = 5, + TxCNT0 = 6, TxCNT1 = 7, /* The transmit byte count. */ + TxSTAT = 8, RxSTAT = 9, /* Tx and Rx status. */ + ISR = 10, IMR = 11, /* Interrupt status and mask. */ + CMR1 = 12, /* Command register 1. */ + CMR2 = 13, /* Command register 2. */ + MODSEL = 14, /* Mode select register. */ + MAR = 14, /* Memory address register (?). */ + CMR2_h = 0x1d, }; -enum eepage_regs { PROM_CMD = 6, PROM_DATA = 7 }; /* Note that PROM_CMD is in the "high" bits. */ +enum eepage_regs +{ PROM_CMD = 6, PROM_DATA = 7 }; /* Note that PROM_CMD is in the "high" bits. */ #define ISR_TxOK 0x01 @@ -59,6 +53,7 @@ #define ISR_TxErr 0x02 #define ISRh_RxErr 0x11 /* ISR, high nibble */ +#define CMR1h_MUX 0x08 /* Select printer multiplexor on 8012. */ #define CMR1h_RESET 0x04 /* Reset. */ #define CMR1h_RxENABLE 0x02 /* Rx unit enable. */ #define CMR1h_TxENABLE 0x01 /* Tx unit enable. */ @@ -81,139 +76,135 @@ /* An inline function used below: it differs from inb() by explicitly return an unsigned char, saving a truncation. */ - -extern inline unsigned char inbyte(unsigned short port) +static inline unsigned char inbyte(unsigned short port) { - unsigned char _v; - __asm__ __volatile__ ("inb %w1,%b0" :"=a" (_v):"d" (port)); - return _v; + unsigned char _v; + __asm__ __volatile__ ("inb %w1,%b0" :"=a" (_v):"d" (port)); + return _v; } /* Read register OFFSET. This command should always be terminated with read_end(). */ - -extern inline unsigned char read_nibble(short port, unsigned char offset) +static inline unsigned char read_nibble(short port, unsigned char offset) { - unsigned char retval; - outb(EOC+offset, port + PAR_DATA); - outb(RdAddr+offset, port + PAR_DATA); - inbyte(port + PAR_STATUS); /* Settling time delay */ - retval = inbyte(port + PAR_STATUS); - outb(EOC+offset, port + PAR_DATA); + unsigned char retval; + outb(EOC+offset, port + PAR_DATA); + outb(RdAddr+offset, port + PAR_DATA); + inbyte(port + PAR_STATUS); /* Settling time delay */ + retval = inbyte(port + PAR_STATUS); + outb(EOC+offset, port + PAR_DATA); - return retval; + return retval; } /* Functions for bulk data read. The interrupt line is always disabled. */ /* Get a byte using read mode 0, reading data from the control lines. */ - -extern inline unsigned char read_byte_mode0(short ioaddr) +static inline unsigned char read_byte_mode0(short ioaddr) { - unsigned char low_nib; + unsigned char low_nib; - outb(Ctrl_LNibRead, ioaddr + PAR_CONTROL); - inbyte(ioaddr + PAR_STATUS); - low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f; - outb(Ctrl_HNibRead, ioaddr + PAR_CONTROL); - inbyte(ioaddr + PAR_STATUS); /* Settling time delay -- needed! */ - inbyte(ioaddr + PAR_STATUS); /* Settling time delay -- needed! */ - return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0); + outb(Ctrl_LNibRead, ioaddr + PAR_CONTROL); + inbyte(ioaddr + PAR_STATUS); + low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f; + outb(Ctrl_HNibRead, ioaddr + PAR_CONTROL); + inbyte(ioaddr + PAR_STATUS); /* Settling time delay -- needed! */ + inbyte(ioaddr + PAR_STATUS); /* Settling time delay -- needed! */ + return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0); } /* The same as read_byte_mode0(), but does multiple inb()s for stability. */ - -extern inline unsigned char read_byte_mode2(short ioaddr) +static inline unsigned char read_byte_mode2(short ioaddr) { - unsigned char low_nib; + unsigned char low_nib; - outb(Ctrl_LNibRead, ioaddr + PAR_CONTROL); - inbyte(ioaddr + PAR_STATUS); - low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f; - outb(Ctrl_HNibRead, ioaddr + PAR_CONTROL); - inbyte(ioaddr + PAR_STATUS); /* Settling time delay -- needed! */ - return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0); + outb(Ctrl_LNibRead, ioaddr + PAR_CONTROL); + inbyte(ioaddr + PAR_STATUS); + low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f; + outb(Ctrl_HNibRead, ioaddr + PAR_CONTROL); + inbyte(ioaddr + PAR_STATUS); /* Settling time delay -- needed! */ + return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0); } /* Read a byte through the data register. */ - -extern inline unsigned char read_byte_mode4(short ioaddr) +static inline unsigned char read_byte_mode4(short ioaddr) { - unsigned char low_nib; + unsigned char low_nib; - outb(RdAddr | MAR, ioaddr + PAR_DATA); - low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f; - outb(RdAddr | HNib | MAR, ioaddr + PAR_DATA); - return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0); + outb(RdAddr | MAR, ioaddr + PAR_DATA); + low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f; + outb(RdAddr | HNib | MAR, ioaddr + PAR_DATA); + return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0); } /* Read a byte through the data register, double reading to allow settling. */ - -extern inline unsigned char read_byte_mode6(short ioaddr) +static inline unsigned char read_byte_mode6(short ioaddr) { - unsigned char low_nib; + unsigned char low_nib; - outb(RdAddr | MAR, ioaddr + PAR_DATA); - inbyte(ioaddr + PAR_STATUS); - low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f; - outb(RdAddr | HNib | MAR, ioaddr + PAR_DATA); - inbyte(ioaddr + PAR_STATUS); - return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0); + outb(RdAddr | MAR, ioaddr + PAR_DATA); + inbyte(ioaddr + PAR_STATUS); + low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f; + outb(RdAddr | HNib | MAR, ioaddr + PAR_DATA); + inbyte(ioaddr + PAR_STATUS); + return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0); } -extern inline void write_reg(short port, unsigned char reg, unsigned char value) +static inline void +write_reg(short port, unsigned char reg, unsigned char value) { - unsigned char outval; - outb(EOC | reg, port + PAR_DATA); - outval = WrAddr | reg; - outb(outval, port + PAR_DATA); - outb(outval, port + PAR_DATA); /* Double write for PS/2. */ + unsigned char outval; + outb(EOC | reg, port + PAR_DATA); + outval = WrAddr | reg; + outb(outval, port + PAR_DATA); + outb(outval, port + PAR_DATA); /* Double write for PS/2. */ - outval &= 0xf0; - outval |= value; - outb(outval, port + PAR_DATA); - outval &= 0x1f; - outb(outval, port + PAR_DATA); - outb(outval, port + PAR_DATA); + outval &= 0xf0; + outval |= value; + outb(outval, port + PAR_DATA); + outval &= 0x1f; + outb(outval, port + PAR_DATA); + outb(outval, port + PAR_DATA); - outb(EOC | outval, port + PAR_DATA); + outb(EOC | outval, port + PAR_DATA); } -extern inline void write_reg_high(short port, unsigned char reg, unsigned char value) +static inline void +write_reg_high(short port, unsigned char reg, unsigned char value) { - unsigned char outval = EOC | HNib | reg; + unsigned char outval = EOC | HNib | reg; - outb(outval, port + PAR_DATA); - outval &= WrAddr | HNib | 0x0f; - outb(outval, port + PAR_DATA); - outb(outval, port + PAR_DATA); /* Double write for PS/2. */ + outb(outval, port + PAR_DATA); + outval &= WrAddr | HNib | 0x0f; + outb(outval, port + PAR_DATA); + outb(outval, port + PAR_DATA); /* Double write for PS/2. */ - outval = WrAddr | HNib | value; - outb(outval, port + PAR_DATA); - outval &= HNib | 0x0f; /* HNib | value */ - outb(outval, port + PAR_DATA); - outb(outval, port + PAR_DATA); + outval = WrAddr | HNib | value; + outb(outval, port + PAR_DATA); + outval &= HNib | 0x0f; /* HNib | value */ + outb(outval, port + PAR_DATA); + outb(outval, port + PAR_DATA); - outb(EOC | HNib | outval, port + PAR_DATA); + outb(EOC | HNib | outval, port + PAR_DATA); } /* Write a byte out using nibble mode. The low nibble is written first. */ - -extern inline void write_reg_byte(short port, unsigned char reg, unsigned char value) +static inline void +write_reg_byte(short port, unsigned char reg, unsigned char value) { - unsigned char outval; - outb(EOC | reg, port + PAR_DATA); /* Reset the address register. */ - outval = WrAddr | reg; - outb(outval, port + PAR_DATA); - outb(outval, port + PAR_DATA); /* Double write for PS/2. */ - - outb((outval & 0xf0) | (value & 0x0f), port + PAR_DATA); - outb(value & 0x0f, port + PAR_DATA); - value >>= 4; - outb(value, port + PAR_DATA); - outb(0x10 | value, port + PAR_DATA); - outb(0x10 | value, port + PAR_DATA); + unsigned char outval; + outb(EOC | reg, port + PAR_DATA); /* Reset the address register. */ + outval = WrAddr | reg; + outb(outval, port + PAR_DATA); + outb(outval, port + PAR_DATA); /* Double write for PS/2. */ + + outb((outval & 0xf0) | (value & 0x0f), port + PAR_DATA); + outb(value & 0x0f, port + PAR_DATA); + value >>= 4; + outb(value, port + PAR_DATA); + outb(0x10 | value, port + PAR_DATA); + outb(0x10 | value, port + PAR_DATA); - outb(EOC | value, port + PAR_DATA); /* Reset the address register. */ + outb(EOC | value, port + PAR_DATA); /* Reset the address register. */ } /* @@ -223,32 +214,30 @@ * It should only be needed when there is skew between the individual data * lines. */ - -extern inline void write_byte_mode0(short ioaddr, unsigned char value) +static inline void write_byte_mode0(short ioaddr, unsigned char value) { - outb(value & 0x0f, ioaddr + PAR_DATA); - outb((value>>4) | 0x10, ioaddr + PAR_DATA); + outb(value & 0x0f, ioaddr + PAR_DATA); + outb((value>>4) | 0x10, ioaddr + PAR_DATA); } -extern inline void write_byte_mode1(short ioaddr, unsigned char value) +static inline void write_byte_mode1(short ioaddr, unsigned char value) { - outb(value & 0x0f, ioaddr + PAR_DATA); - outb(Ctrl_IRQEN | Ctrl_LNibWrite, ioaddr + PAR_CONTROL); - outb((value>>4) | 0x10, ioaddr + PAR_DATA); - outb(Ctrl_IRQEN | Ctrl_HNibWrite, ioaddr + PAR_CONTROL); + outb(value & 0x0f, ioaddr + PAR_DATA); + outb(Ctrl_IRQEN | Ctrl_LNibWrite, ioaddr + PAR_CONTROL); + outb((value>>4) | 0x10, ioaddr + PAR_DATA); + outb(Ctrl_IRQEN | Ctrl_HNibWrite, ioaddr + PAR_CONTROL); } /* Write 16bit VALUE to the packet buffer: the same as above just doubled. */ - -extern inline void write_word_mode0(short ioaddr, unsigned short value) +static inline void write_word_mode0(short ioaddr, unsigned short value) { - outb(value & 0x0f, ioaddr + PAR_DATA); - value >>= 4; - outb((value & 0x0f) | 0x10, ioaddr + PAR_DATA); - value >>= 4; - outb(value & 0x0f, ioaddr + PAR_DATA); - value >>= 4; - outb((value & 0x0f) | 0x10, ioaddr + PAR_DATA); + outb(value & 0x0f, ioaddr + PAR_DATA); + value >>= 4; + outb((value & 0x0f) | 0x10, ioaddr + PAR_DATA); + value >>= 4; + outb(value & 0x0f, ioaddr + PAR_DATA); + value >>= 4; + outb((value & 0x0f) | 0x10, ioaddr + PAR_DATA); } /* EEPROM_Ctrl bits. */ @@ -258,6 +247,10 @@ #define EE_CLK_LOW 0x16 #define EE_DATA_WRITE 0x01 /* EEPROM chip data in. */ #define EE_DATA_READ 0x08 /* EEPROM chip data out. */ + +/* Delay between EEPROM clock transitions. */ +#define eeprom_delay(ticks) \ +do { int _i = 40; while (--_i > 0) { __SLOW_DOWN_IO; }} while (0) /* The EEPROM commands include the alway-set leading bit. */ #define EE_WRITE_CMD(offset) (((5 << 6) + (offset)) << 17) diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/auto_irq.c linux/drivers/net/auto_irq.c --- v2.4.0-test8/linux/drivers/net/auto_irq.c Tue Feb 10 12:56:44 1998 +++ linux/drivers/net/auto_irq.c Sun Sep 17 09:45:05 2000 @@ -32,6 +32,7 @@ "auto_irq.c:v1.11 Donald Becker (becker@cesdis.gsfc.nasa.gov)"; #endif +#include #include #include #include @@ -53,6 +54,10 @@ BUSY_LOOP_UNTIL(delay) return probe_irq_off(irqs); } + +EXPORT_SYMBOL(autoirq_setup); +EXPORT_SYMBOL(autoirq_report); + /* * Local variables: diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/bonding.c linux/drivers/net/bonding.c --- v2.4.0-test8/linux/drivers/net/bonding.c Wed Jul 5 22:15:27 2000 +++ linux/drivers/net/bonding.c Fri Sep 22 14:21:16 2000 @@ -31,29 +31,10 @@ * */ -#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - +#include #include -#include -#include - +#include #include typedef struct slave @@ -228,13 +209,13 @@ return NOTIFY_DONE; } -struct notifier_block bond_netdev_notifier={ +static struct notifier_block bond_netdev_notifier={ bond_event, NULL, 0 }; -int __init bond_init(struct net_device *dev) +static int __init bond_init(struct net_device *dev) { bonding_t *bond; @@ -308,15 +289,13 @@ return &bond->stats; } -#ifdef MODULE - static struct net_device dev_bond = { "", 0, 0, 0, 0, 0x0, 0, 0, 0, 0, NULL, bond_init }; -int init_module(void) +static int __init bonding_init(void) { /* Find a name for this unit */ int err=dev_alloc_name(&dev_bond,"bond%d"); @@ -330,7 +309,7 @@ return 0; } -void cleanup_module(void) +static void __exit bonding_exit(void) { unregister_netdevice_notifier(&bond_netdev_notifier); @@ -338,7 +317,9 @@ kfree(dev_bond.priv); } -#endif /* MODULE */ + +module_init(bonding_init); +module_exit(bonding_exit); /* * Local variables: diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/cs89x0.c linux/drivers/net/cs89x0.c --- v2.4.0-test8/linux/drivers/net/cs89x0.c Wed Jul 5 11:54:11 2000 +++ linux/drivers/net/cs89x0.c Tue Sep 19 08:31:53 2000 @@ -61,6 +61,11 @@ : MOD_INC/DEC race fix (see : http://www.uwsg.indiana.edu/hypermail/linux/kernel/0003.3/1532.html) + Andrew Morton : andrewm@uow.edu.au / Kernel 2.4.0-test7-pre2 + : Enhanced EEPROM support to cover more devices, + : abstracted IRQ mapping to support CONFIG_ARCH_CLPS7500 arch + : (Jason Gunthorpe ) + */ static char *version = @@ -71,6 +76,7 @@ /* Always include 'config.h' first in case the user wants to turn on or override something. */ +#include #ifdef MODULE #include #include @@ -128,10 +134,26 @@ #include "cs89x0.h" -/* First, a few definitions that the brave might change. */ -/* A zero-terminated list of I/O addresses to be probed. */ +/* First, a few definitions that the brave might change. + A zero-terminated list of I/O addresses to be probed. Some special flags.. + Addr & 1 = Read back the address port, look for signature and reset + the page window before probing + Addr & 3 = Reset the page window and probe + The CLPS eval board has the Cirrus chip at 0x80090300, in ARM IO space, + but it is possible that a Cirrus board could be plugged into the ISA + slots. */ +/* The cs8900 has 4 IRQ pins, software selectable. cs8900_irq_map maps + them to system IRQ numbers. This mapping is card specific and is set to + the configuration of the Cirrus Eval board for this chip. */ +#ifdef CONFIG_ARCH_CLPS7500 +static unsigned int netcard_portlist[] __initdata = + { 0x80090303, 0x300, 0x320, 0x340, 0x360, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0}; +static unsigned int cs8900_irq_map[] = {12,0,0,0}; +#else static unsigned int netcard_portlist[] __initdata = { 0x300, 0x320, 0x340, 0x360, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0}; +static unsigned int cs8900_irq_map[] = {10,11,12,5}; +#endif #if DEBUGGING static unsigned int net_debug = DEBUGGING; @@ -343,7 +365,7 @@ dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); if (dev->priv == 0) { - retval = ENOMEM; + retval = -ENOMEM; goto out; } lp = (struct net_local *)dev->priv; @@ -362,18 +384,20 @@ /* if they give us an odd I/O address, then do ONE write to the address port, to get it back to address zero, where we - expect to find the EISA signature word. */ + expect to find the EISA signature word. An IO with a base of 0x3 + will skip the test for the ADD_PORT. */ if (ioaddr & 1) { - ioaddr &= ~1; - if ((inw(ioaddr + ADD_PORT) & ADD_MASK) != ADD_SIG) - return -ENODEV; + if ((ioaddr & 2) != 2) + if ((inw((ioaddr & ~3)+ ADD_PORT) & ADD_MASK) != ADD_SIG) + return -ENODEV; + ioaddr &= ~3; outw(PP_ChipID, ioaddr + ADD_PORT); } - if (inw(ioaddr + DATA_PORT) != CHIP_EISA_ID_SIG) - { - retval = ENODEV; - goto out1; + if (inw(ioaddr + DATA_PORT) != CHIP_EISA_ID_SIG) + { + retval = -ENODEV; + goto out1; } /* Fill in the 'dev' fields. */ @@ -403,15 +427,77 @@ dev->base_addr); reset_chip(dev); - - /* First check to see if an EEPROM is attached*/ + + /* Here we read the current configuration of the chip. If there + is no Extended EEPROM then the idea is to not disturb the chip + configuration, it should have been correctly setup by automatic + EEPROM read on reset. So, if the chip says it read the EEPROM + the driver will always do *something* instead of complain that + adapter_cnf is 0. */ + if ((readreg(dev, PP_SelfST) & (EEPROM_OK | EEPROM_PRESENT)) == + (EEPROM_OK|EEPROM_PRESENT)) { + /* Load the MAC. */ + for (i=0; i < ETH_ALEN/2; i++) { + unsigned int Addr; + Addr = readreg(dev, PP_IA+i*2); + dev->dev_addr[i*2] = Addr & 0xFF; + dev->dev_addr[i*2+1] = Addr >> 8; + } + + /* Load the Adapter Configuration. + Note: Barring any more specific information from some + other source (ie EEPROM+Schematics), we would not know + how to operate a 10Base2 interface on the AUI port. + However, since we do read the status of HCB1 and use + settings that always result in calls to control_dc_dc(dev,0) + a BNC interface should work if the enable pin + (dc/dc converter) is on HCB1. It will be called AUI + however. */ + + lp->adapter_cnf = 0; + i = readreg(dev, PP_LineCTL); + /* Preserve the setting of the HCB1 pin. */ + if ((i & (HCB1 | HCB1_ENBL)) == (HCB1 | HCB1_ENBL)) + lp->adapter_cnf |= A_CNF_DC_DC_POLARITY; + /* Save the sqelch bit */ + if ((i & LOW_RX_SQUELCH) == LOW_RX_SQUELCH) + lp->adapter_cnf |= A_CNF_EXTND_10B_2 | A_CNF_LOW_RX_SQUELCH; + /* Check if the card is in 10Base-t only mode */ + if ((i & (AUI_ONLY | AUTO_AUI_10BASET)) == 0) + lp->adapter_cnf |= A_CNF_10B_T | A_CNF_MEDIA_10B_T; + /* Check if the card is in AUI only mode */ + if ((i & (AUI_ONLY | AUTO_AUI_10BASET)) == AUI_ONLY) + lp->adapter_cnf |= A_CNF_AUI | A_CNF_MEDIA_AUI; + /* Check if the card is in Auto mode. */ + if ((i & (AUI_ONLY | AUTO_AUI_10BASET)) == AUTO_AUI_10BASET) + lp->adapter_cnf |= A_CNF_AUI | A_CNF_10B_T | + A_CNF_MEDIA_AUI | A_CNF_MEDIA_10B_T | A_CNF_MEDIA_AUTO; + + /* IRQ. Other chips already probe, see below. */ + if (lp->chip_type == CS8900) + lp->isa_config = readreg(dev, PP_CS8900_ISAINT) & INT_NO_MASK; + + printk( "[Cirrus EEPROM] "); + } + + printk("\n"); + + /* First check to see if an EEPROM is attached. */ if ((readreg(dev, PP_SelfST) & EEPROM_PRESENT) == 0) - printk(KERN_WARNING "\ncs89x0: No EEPROM, relying on command line....\n"); + printk(KERN_WARNING "cs89x0: No EEPROM, relying on command line....\n"); else if (get_eeprom_data(dev, START_EEPROM_DATA,CHKSUM_LEN,eeprom_buff) < 0) { printk(KERN_WARNING "\ncs89x0: EEPROM read failed, relying on command line.\n"); } else if (get_eeprom_cksum(START_EEPROM_DATA,CHKSUM_LEN,eeprom_buff) < 0) { - printk(KERN_WARNING "\ncs89x0: EEPROM checksum bad, relying on command line\n"); + /* Check if the chip was able to read its own configuration starting + at 0 in the EEPROM*/ + if ((readreg(dev, PP_SelfST) & (EEPROM_OK | EEPROM_PRESENT)) != + (EEPROM_OK|EEPROM_PRESENT)) + printk(KERN_WARNING "cs89x0: Extended EEPROM checksum bad and no Cirrus EEPROM, relying on command line\n"); + } else { + /* This reads an extended EEPROM that is not documented + in the CS8900 datasheet. */ + /* get transmission control word but keep the autonegotiation bits */ if (!lp->auto_neg_cnf) lp->auto_neg_cnf = eeprom_buff[AUTO_NEG_CNF_OFFSET/2]; /* Store adapter configuration */ @@ -464,17 +550,12 @@ } else { i = lp->isa_config & INT_NO_MASK; if (lp->chip_type == CS8900) { - /* the table that follows is dependent upon how you wired up your cs8900 - * in your system. The table is the same as the cs8900 engineering demo - * board. irq_map also depends on the contents of the table. Also see - * write_irq, which is the reverse mapping of the table below. */ - switch(i) { - case 0: i = 10; break; - case 1: i = 11; break; - case 2: i = 12; break; - case 3: i = 5; break; - default: printk("\ncs89x0: bug: isa_config is %d\n", i); - } + /* Translate the IRQ using the IRQ mapping table. */ + if (i > sizeof(cs8900_irq_map)/sizeof(cs8900_irq_map[0])) + printk("\ncs89x0: bug: isa_config is %d\n", i); + else + i = cs8900_irq_map[i]; + lp->irq_map = CS8900_IRQ_MAP; /* fixed IRQ map for CS8900 */ } else { int irq_map_buff[IRQ_MAP_LEN/2]; @@ -490,7 +571,7 @@ dev->irq = i; } - printk(", IRQ %d", dev->irq); + printk(" IRQ %d", dev->irq); #if ALLOW_DMA if (lp->use_dma) @@ -741,7 +822,9 @@ struct net_local *lp = (struct net_local *)dev->priv; unsigned int selfcontrol; int timenow = jiffies; - /* control the DC to DC convertor in the SelfControl register. */ + /* control the DC to DC convertor in the SelfControl register. + Note: This is hooked up to a general purpose pin, might not + always be a DC to DC convertor. */ selfcontrol = HCB1_ENBL; /* Enable the HCB1 bit as an output */ if (((lp->adapter_cnf & A_CNF_DC_DC_POLARITY) != 0) ^ on_not_off) @@ -753,7 +836,6 @@ /* Wait for the DC/DC converter to power up - 500ms */ while (jiffies - timenow < HZ) ; - } #define DETECTED_NONE 0 @@ -916,13 +998,13 @@ int i; if (chip_type == CS8900) { - switch(irq) { - case 10: i = 0; break; - case 11: i = 1; break; - case 12: i = 2; break; - case 5: i = 3; break; - default: i = 3; break; - } + /* Search the mapping table for the corrisponding IRQ pin. */ + for (i = 0; i != sizeof(cs8900_irq_map)/sizeof(cs8900_irq_map[0]); i++) + if (cs8900_irq_map[i] == irq) + break; + /* Not found */ + if (i == sizeof(cs8900_irq_map)/sizeof(cs8900_irq_map[0])) + i = 3; writereg(dev, PP_CS8900_ISAINT, i); } else { writereg(dev, PP_CS8920_ISAINT, irq); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/declance.c linux/drivers/net/declance.c --- v2.4.0-test8/linux/drivers/net/declance.c Sat May 13 08:29:40 2000 +++ linux/drivers/net/declance.c Sun Sep 17 09:41:29 2000 @@ -1030,6 +1030,7 @@ /* Make certain the data structures used by the LANCE are aligned. */ dev->priv = (void *) (((unsigned long) dev->priv + 7) & ~7); lp = (struct lance_private *) dev->priv; + spin_lock_init(&lp->lock); switch (type) { #ifdef CONFIG_TC @@ -1193,9 +1194,9 @@ lp->multicast_timer.function = &lance_set_multicast_retry; #ifdef MODULE - dev->ifindex = dev_new_index(); - lp->next_module = root_lance_dev; - root_lance_dev = lp; + dev->ifindex = dev_new_index(); + lp->next_module = root_lance_dev; + root_lance_dev = lp; #endif return 0; } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/dummy.c linux/drivers/net/dummy.c --- v2.4.0-test8/linux/drivers/net/dummy.c Thu Jun 22 07:23:26 2000 +++ linux/drivers/net/dummy.c Fri Sep 22 14:21:16 2000 @@ -31,27 +31,10 @@ /* To have statistics (just packets sent) define this */ #include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - +#include #include -#include -#include +#include static int dummy_xmit(struct sk_buff *skb, struct net_device *dev); static struct net_device_stats *dummy_get_stats(struct net_device *dev); @@ -80,7 +63,7 @@ } #endif -int __init dummy_init(struct net_device *dev) +static int __init dummy_init(struct net_device *dev) { /* Initialize the device structure. */ dev->hard_start_xmit = dummy_xmit; @@ -121,25 +104,12 @@ static struct net_device_stats *dummy_get_stats(struct net_device *dev) { - struct net_device_stats *stats = (struct net_device_stats *) dev->priv; - return stats; -} - -#ifdef MODULE - -static int __init dummy_probe(struct net_device *dev) -{ - dummy_init(dev); - return 0; + return dev->priv; } -static struct net_device dev_dummy = { - "", - 0, 0, 0, 0, - 0x0, 0, - 0, 0, 0, NULL, dummy_probe }; +static struct net_device dev_dummy = { init: dummy_init }; -int init_module(void) +static int __init dummy_init_module(void) { /* Find a name for this unit */ int err=dev_alloc_name(&dev_dummy,"dummy%d"); @@ -150,10 +120,14 @@ return 0; } -void cleanup_module(void) +static void __exit dummy_cleanup_module(void) { unregister_netdev(&dev_dummy); kfree(dev_dummy.priv); - dev_dummy.priv = NULL; + + memset(&dev_dummy, 0, sizeof(dev_dummy)); + dev_dummy.init = dummy_init; } -#endif /* MODULE */ + +module_init(dummy_init_module); +module_exit(dummy_cleanup_module); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/eepro100.c linux/drivers/net/eepro100.c --- v2.4.0-test8/linux/drivers/net/eepro100.c Fri Aug 11 19:14:46 2000 +++ linux/drivers/net/eepro100.c Wed Sep 20 21:57:26 2000 @@ -2273,6 +2273,8 @@ PCI_ANY_ID, PCI_ANY_ID, }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ID1030, PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82820FW_4, + PCI_ANY_ID, PCI_ANY_ID, }, { 0,} }; MODULE_DEVICE_TABLE(pci, eepro100_pci_tbl); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/eexpress.c linux/drivers/net/eexpress.c --- v2.4.0-test8/linux/drivers/net/eexpress.c Mon Jun 19 13:30:58 2000 +++ linux/drivers/net/eexpress.c Sun Sep 17 09:41:29 2000 @@ -1084,6 +1084,7 @@ return -ENOMEM; memset(dev->priv, 0, sizeof(struct net_local)); + spin_lock_init(&lp->lock); printk("(IRQ %d, %s connector, %d-bit bus", dev->irq, eexp_ifmap[dev->if_port], buswidth?8:16); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/epic100.c linux/drivers/net/epic100.c --- v2.4.0-test8/linux/drivers/net/epic100.c Fri Sep 8 12:34:55 2000 +++ linux/drivers/net/epic100.c Sun Sep 10 13:21:13 2000 @@ -33,9 +33,9 @@ LK1.1.4 (jgarzik): * Merge becker test version 1.09 (5/29/2000) - LK1.1.5 (jgarzik): - * Fix locking - * Limit 83c175 probe to ethernet-class PCI devices + LK1.1.5: + * Fix locking (jgarzik) + * Limit 83c175 probe to ethernet-class PCI devices (rgooch) */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/eql.c linux/drivers/net/eql.c --- v2.4.0-test8/linux/drivers/net/eql.c Mon Mar 13 09:50:16 2000 +++ linux/drivers/net/eql.c Fri Sep 22 14:21:16 2000 @@ -113,32 +113,18 @@ */ #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 EQL_DEBUG /* #undef EQL_DEBUG -* print nothing at all, not even a boot-banner */ /* #define EQL_DEBUG 1 -* print only the boot-banner */ @@ -150,7 +136,7 @@ #endif static unsigned int eql_debug = EQL_DEBUG; -int eql_init(struct net_device *dev); /* */ +static int eql_init(struct net_device *dev); /* */ static int eql_open(struct net_device *dev); /* */ static int eql_close(struct net_device *dev); /* */ static int eql_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); /* */ @@ -209,7 +195,7 @@ --------------------------------------------------------- */ -int __init eql_init(struct net_device *dev) +static int __init eql_init(struct net_device *dev) { static unsigned version_printed = 0; /* static unsigned num_masters = 0; */ @@ -273,6 +259,8 @@ equalizer_t *eql = (equalizer_t *) dev->priv; slave_queue_t *new_queue; + MOD_INC_USE_COUNT; + #ifdef EQL_DEBUG if (eql_debug >= 5) printk ("%s: open\n", dev->name); @@ -294,10 +282,10 @@ eql->timer_on = 1; add_timer (&eql->timer); - MOD_INC_USE_COUNT; return 0; } - return 1; + MOD_DEC_USE_COUNT; + return -ENOMEM; } @@ -409,16 +397,14 @@ struct net_device *master_dev; struct net_device *slave_dev; slaving_request_t srq; - int err; - err = copy_from_user(&srq, srqp, sizeof (slaving_request_t)); - if (err) + if (copy_from_user(&srq, srqp, sizeof (slaving_request_t))) { #ifdef EQL_DEBUG if (eql_debug >= 20) printk ("EQL enslave: error detected by copy_from_user\n"); #endif - return err; + return -EFAULT; } #ifdef EQL_DEBUG @@ -470,11 +456,9 @@ struct net_device *master_dev; struct net_device *slave_dev; slaving_request_t srq; - int err; - err = copy_from_user(&srq, srqp, sizeof (slaving_request_t)); - if (err) - return err; + if (copy_from_user(&srq, srqp, sizeof (slaving_request_t))) + return -EFAULT; #ifdef EQL_DEBUG if (eql_debug >= 20) @@ -500,11 +484,9 @@ equalizer_t *eql; struct net_device *slave_dev; slave_config_t sc; - int err; - err = copy_from_user (&sc, scp, sizeof (slave_config_t)); - if (err) - return err; + if (copy_from_user (&sc, scp, sizeof (slave_config_t))) + return -EFAULT; #ifdef EQL_DEBUG if (eql_debug >= 20) @@ -519,10 +501,8 @@ if (slave != 0) { sc.priority = slave->priority; - err = verify_area(VERIFY_WRITE, (void *)scp, sizeof (slave_config_t)); - if (err) - return err; - copy_to_user (scp, &sc, sizeof (slave_config_t)); + if (copy_to_user (scp, &sc, sizeof (slave_config_t))) + return -EFAULT; return 0; } } @@ -536,11 +516,9 @@ equalizer_t *eql; struct net_device *slave_dev; slave_config_t sc; - int err; - err = copy_from_user (&sc, scp, sizeof (slave_config_t)); - if (err) - return err; + if (copy_from_user (&sc, scp, sizeof (slave_config_t))) + return -EFAULT; #ifdef EQL_DEBUG if (eql_debug >= 20) @@ -578,13 +556,11 @@ if ( eql_is_master (dev) ) { - int err; eql = (equalizer_t *) dev->priv; mc.max_slaves = eql->max_slaves; mc.min_slaves = eql->min_slaves; - err = copy_to_user (mcp, &mc, sizeof (master_config_t)); - if (err) - return err; + if (copy_to_user (mcp, &mc, sizeof (master_config_t))) + return -EFAULT; return 0; } return -EINVAL; @@ -595,11 +571,9 @@ { equalizer_t *eql; master_config_t mc; - int err; - err = copy_from_user (&mc, mcp, sizeof (master_config_t)); - if (err) - return err; + if (copy_from_user (&mc, mcp, sizeof (master_config_t))) + return -EFAULT; #if EQL_DEBUG if (eql_debug >= 20) printk ("%s: set master config\n", dev->name); @@ -646,11 +620,8 @@ slave = (slave_t *) kmalloc (sizeof (slave_t), GFP_KERNEL); if (slave) - { memset(slave, 0, sizeof (slave_t)); - return slave; - } - return 0; + return slave; } @@ -702,31 +673,32 @@ slave_t *tail_slave; queue = (slave_queue_t *) kmalloc (sizeof (slave_queue_t), GFP_KERNEL); - if (queue == NULL) - return 0; - memset (queue, 0, sizeof (slave_queue_t)); + if (!queue) + goto err_out; + head_slave = eql_new_slave (); + if (!head_slave) + goto err_out_queue; + tail_slave = eql_new_slave (); + if (!tail_slave) + goto err_out_hs; - if ( head_slave != 0 && - tail_slave != 0 ) - { - head_slave->next = tail_slave; - tail_slave->next = 0; - queue->head = head_slave; - queue->num_slaves = 0; - queue->master_dev = dev; - } - else - { - if (head_slave) - kfree(head_slave); - if (tail_slave) - kfree(tail_slave); - kfree (queue); - return 0; - } + memset (queue, 0, sizeof (slave_queue_t)); + + head_slave->next = tail_slave; + tail_slave->next = 0; + queue->head = head_slave; + queue->num_slaves = 0; + queue->master_dev = dev; return queue; + +err_out_hs: + kfree (head_slave); +err_out_queue: + kfree (queue); +err_out: + return NULL; } @@ -1013,13 +985,13 @@ } } -#ifdef MODULE static struct net_device dev_eql = { - "eql", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, eql_init + name: "eql", + init: eql_init, }; -int init_module(void) +static int __init eql_init_module(void) { if (register_netdev(&dev_eql) != 0) { printk("eql: register_netdev() returned non-zero.\n"); @@ -1028,13 +1000,15 @@ return 0; } -void cleanup_module(void) +static void __exit eql_cleanup_module(void) { kfree(((equalizer_t *)dev_eql.priv)->stats ); kfree(dev_eql.priv); unregister_netdev(&dev_eql); } -#endif /* MODULE */ + +module_init(eql_init_module); +module_exit(eql_cleanup_module); /* * Local Variables: diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/gmac.c linux/drivers/net/gmac.c --- v2.4.0-test8/linux/drivers/net/gmac.c Wed Aug 9 13:49:29 2000 +++ linux/drivers/net/gmac.c Sun Sep 17 09:48:05 2000 @@ -9,10 +9,15 @@ * Changes: * Arnaldo Carvalho de Melo - 08/06/2000 * - check init_etherdev return in gmac_probe1 + * BenH - 03/09/2000 + * - Add support for new PHYs + * - Add some PowerBook sleep code * */ #include + +#include #include #include #include @@ -29,13 +34,19 @@ #include #include #include +#include +#ifdef CONFIG_PMAC_PBOOK +#include +#include +#include +#endif #include "gmac.h" #define DEBUG_PHY -/* Driver version 1.1, kernel 2.4.x */ -#define GMAC_VERSION "v1.1k4" +/* Driver version 1.2, kernel 2.4.x */ +#define GMAC_VERSION "v1.2k4" static unsigned char dummy_buf[RX_BUF_ALLOC_SIZE + RX_OFFSET + GMAC_BUFFER_ALIGN]; static struct net_device *gmacs = NULL; @@ -48,9 +59,12 @@ static void mii_interrupt(struct gmac *gm); static int mii_lookup_and_reset(struct gmac *gm); static void mii_setup_phy(struct gmac *gm); +static int mii_do_reset_phy(struct gmac *gm, int phy_addr); +static void mii_init_BCM5400(struct gmac *gm); static void gmac_set_power(struct gmac *gm, int power_up); static int gmac_powerup_and_reset(struct net_device *dev); +static void gmac_set_gigabit_mode(struct gmac *gm, int gigabit); static void gmac_set_duplex_mode(struct gmac *gm, int full_duplex); static void gmac_mac_init(struct gmac *gm, unsigned char *mac_addr); static void gmac_init_rings(struct gmac *gm, int from_irq); @@ -71,6 +85,13 @@ extern int pci_device_loc(struct device_node *dev, unsigned char *bus_ptr, unsigned char *devfn_ptr); +#ifdef CONFIG_PMAC_PBOOK +int gmac_sleep_notify(struct pmu_sleep_notifier *self, int when); +static struct pmu_sleep_notifier gmac_sleep_notifier = { + gmac_sleep_notify, SLEEP_LEVEL_NET, +}; +#endif + /* * Read via the mii interface from a PHY register */ @@ -161,6 +182,19 @@ * a timer and control the autoneg. process more closely. Also, we may * want to stop rx and tx side when the link is down. */ + +/* Link modes of the BCM5400 PHY */ +static int phy_BCM5400_link_table[8][3] = { + { 0, 0, 0 }, /* No link */ + { 0, 0, 0 }, /* 10BT Half Duplex */ + { 1, 0, 0 }, /* 10BT Full Duplex */ + { 0, 1, 0 }, /* 100BT Half Duplex */ + { 0, 1, 0 }, /* 100BT Half Duplex */ + { 1, 1, 0 }, /* 100BT Full Duplex*/ + { 1, 0, 1 }, /* 1000BT */ + { 1, 0, 1 }, /* 1000BT */ +}; + static void mii_interrupt(struct gmac *gm) { @@ -175,8 +209,9 @@ /* We read the Auxilliary Status Summary register */ phy_status = mii_read(gm, gm->phy_addr, MII_SR); if ((phy_status ^ gm->phy_status) & (MII_SR_ASSC | MII_SR_LKS)) { - int full_duplex; - int link_100; + int full_duplex = 0; + int link_100 = 0; + int gigabit = 0; #ifdef DEBUG_PHY printk("Link state change, phy_status: 0x%04x\n", phy_status); #endif @@ -188,8 +223,9 @@ else GM_BIC(GM_MAC_CTRL_CONFIG, GM_MAC_CTRL_CONF_SND_PAUSE_EN); - /* Link ? For now we handle only the 5201 PHY */ + /* Link ? Check for speed and duplex */ if ((phy_status & MII_SR_LKS) && (phy_status & MII_SR_ASSC)) { + int restart = 0; if (gm->phy_type == PHY_B5201) { int aux_stat = mii_read(gm, gm->phy_addr, MII_BCM5201_AUXCTLSTATUS); #ifdef DEBUG_PHY @@ -197,19 +233,41 @@ #endif full_duplex = ((aux_stat & MII_BCM5201_AUXCTLSTATUS_DUPLEX) != 0); link_100 = ((aux_stat & MII_BCM5201_AUXCTLSTATUS_SPEED) != 0); - } else { - full_duplex = 1; - link_100 = 1; + } else if (gm->phy_type == PHY_B5400) { + int aux_stat = mii_read(gm, gm->phy_addr, MII_BCM5400_AUXSTATUS); + int link = (aux_stat & MII_BCM5400_AUXSTATUS_LINKMODE_MASK) >> + MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT; +#ifdef DEBUG_PHY + printk(" Link up ! BCM5400 aux_stat: 0x%04x (link mode: %d)\n", + aux_stat, link); +#endif + full_duplex = phy_BCM5400_link_table[link][0]; + link_100 = phy_BCM5400_link_table[link][1]; + gigabit = phy_BCM5400_link_table[link][2]; + } else if (gm->phy_type == PHY_LXT971) { + int stat2 = mii_read(gm, gm->phy_addr, MII_LXT971_STATUS2); +#ifdef DEBUG_PHY + printk(" Link up ! LXT971 stat2: 0x%04x\n", stat2); +#endif + full_duplex = ((stat2 & MII_LXT971_STATUS2_FULLDUPLEX) != 0); + link_100 = ((stat2 & MII_LXT971_STATUS2_SPEED) != 0); } #ifdef DEBUG_PHY printk(" full_duplex: %d, speed: %s\n", full_duplex, - link_100 ? "100" : "10"); + gigabit ? "1000" : (link_100 ? "100" : "10")); #endif + if (gigabit != gm->gigabit) { + gm->gigabit = gigabit; + gmac_set_gigabit_mode(gm, gm->gigabit); + restart = 1; + } if (full_duplex != gm->full_duplex) { gm->full_duplex = full_duplex; gmac_set_duplex_mode(gm, gm->full_duplex); - gmac_start_dma(gm); + restart = 1; } + if (restart) + gmac_start_dma(gm); } else if (!(phy_status & MII_SR_LKS)) { #ifdef DEBUG_PHY printk(" Link down !\n"); @@ -218,19 +276,73 @@ } } -/* - * Lookup for a PHY on the mii interface and reset it - */ +static int +mii_do_reset_phy(struct gmac *gm, int phy_addr) +{ + int mii_control, timeout; + + mii_control = mii_read(gm, phy_addr, MII_CR); + mii_write(gm, phy_addr, MII_CR, mii_control | MII_CR_RST); + mdelay(10); + for (timeout = 100; timeout > 0; --timeout) { + mii_control = mii_read(gm, phy_addr, MII_CR); + if (mii_control == -1) { + printk(KERN_ERR "%s PHY died after reset !\n", + gm->dev->name); + return 1; + } + if ((mii_control & MII_CR_RST) == 0) + break; + mdelay(10); + } + if (mii_control & MII_CR_RST) { + printk(KERN_ERR "%s PHY reset timeout !\n", gm->dev->name); + return 1; + } + mii_write(gm, phy_addr, MII_CR, mii_control & ~MII_CR_ISOL); + return 0; +} + +static void +mii_init_BCM5400(struct gmac *gm) +{ + int data; + + data = mii_read(gm, gm->phy_addr, MII_BCM5400_AUXCONTROL); + data |= MII_BCM5400_AUXCONTROL_PWR10BASET; + mii_write(gm, gm->phy_addr, MII_BCM5400_AUXCONTROL, data); + + data = mii_read(gm, gm->phy_addr, MII_BCM5400_GB_CONTROL); + data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP; + mii_write(gm, gm->phy_addr, MII_BCM5400_GB_CONTROL, data); + + mdelay(10); + mii_do_reset_phy(gm, 0x1f); + + data = mii_read(gm, 0x1f, MII_BCM5201_MULTIPHY); + data |= MII_BCM5201_MULTIPHY_SERIALMODE; + mii_write(gm, 0x1f, MII_BCM5201_MULTIPHY, data); + + data = mii_read(gm, gm->phy_addr, MII_BCM5400_AUXCONTROL); + data &= ~MII_BCM5400_AUXCONTROL_PWR10BASET; + mii_write(gm, gm->phy_addr, MII_BCM5400_AUXCONTROL, data); +} + static int mii_lookup_and_reset(struct gmac *gm) { - int i, timeout; - int mii_status, mii_control; + int i, mii_status, mii_control; - /* Find the PHY */ gm->phy_addr = -1; gm->phy_type = PHY_UNKNOWN; + + /* Hard reset the PHY */ + feature_set_gmac_phy_reset(gm->of_node, KL_GPIO_ETH_PHY_RESET_ASSERT); + mdelay(10); + feature_set_gmac_phy_reset(gm->of_node, KL_GPIO_ETH_PHY_RESET_RELEASE); + mdelay(10); + /* Find the PHY */ for(i=31; i>0; --i) { mii_control = mii_read(gm, i, MII_CR); mii_status = mii_read(gm, i, MII_SR); @@ -243,25 +355,9 @@ return 0; /* Reset it */ - mii_write(gm, gm->phy_addr, MII_CR, mii_control | MII_CR_RST); - mdelay(10); - for (timeout = 100; timeout > 0; --timeout) { - mii_control = mii_read(gm, gm->phy_addr, MII_CR); - if (mii_control == -1) { - printk(KERN_ERR "%s PHY died after reset !\n", - gm->dev->name); - goto fail; - } - if ((mii_control & MII_CR_RST) == 0) - break; - mdelay(10); - } - if (mii_control & MII_CR_RST) { - printk(KERN_ERR "%s PHY reset timeout !\n", gm->dev->name); + if (mii_do_reset_phy(gm, gm->phy_addr)) goto fail; - } - mii_write(gm, gm->phy_addr, MII_CR, mii_control & ~MII_CR_ISOL); - + /* Read the PHY ID */ gm->phy_id = (mii_read(gm, gm->phy_addr, MII_ID0) << 16) | mii_read(gm, gm->phy_addr, MII_ID1); @@ -270,10 +366,15 @@ #endif if ((gm->phy_id & MII_BCM5400_MASK) == MII_BCM5400_ID) { gm->phy_type = PHY_B5400; - printk(KERN_ERR "%s Warning ! Unsupported BCM5400 PHY !\n", + printk(KERN_ERR "%s Found Broadcom BCM5400 PHY (Gigabit)\n", gm->dev->name); + mii_init_BCM5400(gm); } else if ((gm->phy_id & MII_BCM5201_MASK) == MII_BCM5201_ID) { gm->phy_type = PHY_B5201; + printk(KERN_INFO "%s Found Broadcom BCM5201 PHY\n", gm->dev->name); + } else if ((gm->phy_id & MII_LXT971_MASK) == MII_LXT971_ID) { + gm->phy_type = PHY_LXT971; + printk(KERN_INFO "%s Found LevelOne LX971 PHY\n", gm->dev->name); } else { printk(KERN_ERR "%s: Warning ! Unknown PHY ID 0x%08x !\n", gm->dev->name, gm->phy_id); @@ -405,6 +506,22 @@ } } +/* Set the MAC gigabit mode. Side effect: stops Tx MAC */ +static void +gmac_set_gigabit_mode(struct gmac *gm, int gigabit) +{ + /* Stop Tx MAC */ + GM_BIC(GM_MAC_TX_CONFIG, GM_MAC_TX_CONF_ENABLE); + while(GM_IN(GM_MAC_TX_CONFIG) & GM_MAC_TX_CONF_ENABLE) + ; + + if (gigabit) { + GM_BIS(GM_MAC_XIF_CONFIG, GM_MAC_XIF_CONF_GMII_MODE); + } else { + GM_BIC(GM_MAC_XIF_CONFIG, GM_MAC_XIF_CONF_GMII_MODE); + } +} + /* * Initialize a bunch of registers to put the chip into a known * and hopefully happy state @@ -788,6 +905,65 @@ return 0; } +#ifdef CONFIG_PMAC_PBOOK +int +gmac_sleep_notify(struct pmu_sleep_notifier *self, int when) +{ + struct gmac *gm; + int i; + + /* XXX should handle more than one */ + if (gmacs == NULL) + return PBOOK_SLEEP_OK; + + gm = (struct gmac *) gmacs->priv; + if (!gm->opened) + return PBOOK_SLEEP_OK; + + switch (when) { + case PBOOK_SLEEP_REQUEST: + break; + case PBOOK_SLEEP_REJECT: + break; + case PBOOK_SLEEP_NOW: + disable_irq(gm->dev->irq); + netif_stop_queue(gm->dev); + gmac_stop_dma(gm); + mii_poll_stop(gm); + gmac_set_power(gm, 0); + for (i = 0; i < NRX; ++i) { + if (gm->rx_buff[i] != 0) { + dev_kfree_skb(gm->rx_buff[i]); + gm->rx_buff[i] = 0; + } + } + for (i = 0; i < NTX; ++i) { + if (gm->tx_buff[i] != 0) { + dev_kfree_skb(gm->tx_buff[i]); + gm->tx_buff[i] = 0; + } + } + break; + case PBOOK_WAKE: + /* see if this is enough */ + gmac_powerup_and_reset(gm->dev); + gm->full_duplex = 0; + gm->phy_status = 0; + mii_lookup_and_reset(gm); + mii_setup_phy(gm); + gmac_init_rings(gm, 0); + gmac_mac_init(gm, gm->dev->dev_addr); + gmac_set_multicast(gm->dev); + mii_interrupt(gm); + gmac_start_dma(gm); + netif_start_queue(gm->dev); + enable_irq(gm->dev->irq); + break; + } + return PBOOK_SLEEP_OK; +} +#endif /* CONFIG_PMAC_PBOOK */ + /* * Handle a transmit timeout */ @@ -1196,7 +1372,8 @@ ioremap(gmac->addrs[0].address, 0x10000); dev->irq = gmac->intrs[0].line; gm->dev = dev; - + gm->of_node = gmac; + if (pci_device_loc(gmac, &gm->pci_bus, &gm->pci_devfn)) { gm->pci_bus = gm->pci_devfn = 0xff; printk(KERN_ERR "Can't locate GMAC PCI entry\n"); @@ -1229,6 +1406,10 @@ gm->next_gmac = gmacs; gmacs = dev; + +#ifdef CONFIG_PMAC_PBOOK + pmu_register_sleep_notifier(&gmac_sleep_notifier); +#endif } MODULE_AUTHOR("Paul Mackerras/Ben Herrenschmidt"); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/gmac.h linux/drivers/net/gmac.h --- v2.4.0-test8/linux/drivers/net/gmac.h Wed Jul 26 15:53:45 2000 +++ linux/drivers/net/gmac.h Sun Sep 17 09:48:05 2000 @@ -730,8 +730,9 @@ */ /* Supported PHYs (phy_type field ) */ -#define PHY_B5400 5400 -#define PHY_B5201 5201 +#define PHY_B5400 0x5400 +#define PHY_B5201 0x5201 +#define PHY_LXT971 0x0971 #define PHY_UNKNOWN 0 /* Identification (for multi-PHY) */ @@ -745,6 +746,11 @@ #define MII_BCM5400_REV 0x01 #define MII_BCM5400_ID ((MII_BCM5400_OUI << 10) | (MII_BCM5400_MODEL << 4)) #define MII_BCM5400_MASK 0xfffffff0 +#define MII_LXT971_OUI 0x0004de +#define MII_LXT971_MODEL 0x0e +#define MII_LXT971_REV 0x00 +#define MII_LXT971_ID ((MII_LXT971_OUI << 10) | (MII_LXT971_MODEL << 4)) +#define MII_LXT971_MASK 0xfffffff0 /* BCM5201 AUX STATUS register */ #define MII_BCM5201_AUXCTLSTATUS 0x18 @@ -764,6 +770,26 @@ #define MII_BCM5201_MULTIPHY_SERIALMODE 0x0002 #define MII_BCM5201_MULTIPHY_SUPERISOLATE 0x0008 +/* MII BCM5400 1000-BASET Control register */ +#define MII_BCM5400_GB_CONTROL 0x09 +#define MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP 0x0200 + +/* MII BCM5400 AUXCONTROL register */ +#define MII_BCM5400_AUXCONTROL 0x18 +#define MII_BCM5400_AUXCONTROL_PWR10BASET 0x0004 + +/* MII BCM5400 AUXSTATUS register */ +#define MII_BCM5400_AUXSTATUS 0x19 +#define MII_BCM5400_AUXSTATUS_LINKMODE_MASK 0x0700 +#define MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT 8 + +/* MII LXT971 STATUS2 register */ +#define MII_LXT971_STATUS2 0x11 +#define MII_LXT971_STATUS2_SPEED 0x4000 +#define MII_LXT971_STATUS2_LINK 0x0400 +#define MII_LXT971_STATUS2_FULLDUPLEX 0x0200 +#define MII_LXT971_STATUS2_AUTONEG_COMPLETE 0x0080 + /* @@ -845,6 +871,7 @@ int phy_type; int phy_status; /* Cached PHY status */ int full_duplex; /* Current set to full duplex */ + int gigabit; /* Current set to 1000BT */ struct net_device_stats stats; u8 pci_bus; u8 pci_devfn; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/hamachi.c linux/drivers/net/hamachi.c --- v2.4.0-test8/linux/drivers/net/hamachi.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/hamachi.c Mon Oct 2 12:00:15 2000 @@ -0,0 +1,1904 @@ +/* hamachi.c: A Packet Engines GNIC-II Gigabit Ethernet driver for Linux. */ +/* + Written 1998-2000 by Donald Becker. + Updates 2000 by Keith Underwood. + + This software may be used and distributed according to the terms of + the GNU Public License (GPL), incorporated herein by reference. + Drivers based on or derived from this code fall under the GPL and must + retain the authorship, copyright and license notice. This file is not + a complete program and may only be used when the entire operating + system is licensed under the GPL. + + The author may be reached as becker@scyld.com, or C/O + Scyld Computing Corporation + 410 Severn Ave., Suite 210 + Annapolis MD 21403 + + This driver is for the Packet Engines GNIC-II PCI Gigabit Ethernet + adapter. + + Support and updates available at + http://www.scyld.com/network/hamachi.html + or + http://www.parl.clemson.edu/~keithu/hamachi.html + + For best viewing, set your tabs to 3. + +*/ + +static const char *version = +"hamachi.c:v1.01 5/16/2000 Written by Donald Becker\n" +" Some modifications by Eric kasten \n" +" Further modifications by Keith Underwood \n" +" Support by many others\n" +" http://www.scyld.com/network/hamachi.html\n" +" or\n" +" http://www.parl.clemson.edu/~keithu/drivers/hamachi.html\n"; + + +/* A few user-configurable values. */ + +static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ +#define final_version +#define hamachi_debug debug +/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ +static int max_interrupt_work = 40; +static int mtu = 0; +/* Default values selected by testing on a dual processor PIII-450 */ +/* These six interrupt control parameters may be set directly when loading the + * module, or through the rx_params and tx_params variables + */ +static int max_rx_latency = 0x11; +static int max_rx_gap = 0x05; +static int min_rx_pkt = 0x18; +static int max_tx_latency = 0x00; +static int max_tx_gap = 0x00; +static int min_tx_pkt = 0x30; + +/* Set the copy breakpoint for the copy-only-tiny-frames scheme. + -Setting to > 1518 causes all frames to be copied + -Setting to 0 disables copies +*/ +static int rx_copybreak = 0; + +/* An override for the hardware detection of bus width. + Set to 1 to force 32 bit PCI bus detection. Set to 4 to force 64 bit. + Add 2 to disable parity detection. +*/ +static int force32 = 0; + + +/* Used to pass the media type, etc. + These exist for driver interoperability. + No media types are currently defined. + - The lower 4 bits are reserved for the media type. + - The next three bits may be set to one of the following: + 0x00000000 : Autodetect PCI bus + 0x00000010 : Force 32 bit PCI bus + 0x00000020 : Disable parity detection + 0x00000040 : Force 64 bit PCI bus + Default is autodetect + - The next bit can be used to force half-duplex. This is a bad + idea since no known implementations implement half-duplex, and, + in general, half-duplex for gigabit ethernet is a bad idea. + 0x00000080 : Force half-duplex + Default is full-duplex. + - In the original driver, the ninth bit could be used to force + full-duplex. Maintain that for compatibility + 0x00000200 : Force full-duplex +*/ +#define MAX_UNITS 8 /* More are supported, limit only on options */ +static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; +static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; +/* The Hamachi chipset supports 3 parameters each for Rx and Tx + * interruput management. Parameters will be loaded as specified into + * the TxIntControl and RxIntControl registers. + * + * The registers are arranged as follows: + * 23 - 16 15 - 8 7 - 0 + * _________________________________ + * | min_pkt | max_gap | max_latency | + * --------------------------------- + * min_pkt : The minimum number of packets processed between + * interrupts. + * max_gap : The maximum inter-packet gap in units of 8.192 us + * max_latency : The absolute time between interrupts in units of 8.192 us + * + */ +static int rx_params[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; +static int tx_params[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; + +/* Operational parameters that are set at compile time. */ + +/* Keep the ring sizes a power of two for compile efficiency. + The compiler will convert '%'<2^N> into a bit mask. + Making the Tx ring too large decreases the effectiveness of channel + bonding and packet priority. + There are no ill effects from too-large receive rings, except for + excessive memory usage */ +/* Empirically it appears that the Tx ring needs to be a little bigger + for these Gbit adapters or you get into an overrun condition really + easily. Also, things appear to work a bit better in back-to-back + configurations if the Rx ring is 8 times the size of the Tx ring +*/ +#define TX_RING_SIZE 64 +#define RX_RING_SIZE 512 + +/* + * Enable mii_ioctl. Added interrupt coalescing parameter adjustment. + * 2/19/99 Pete Wyckoff + */ +#define HAVE_PRIVATE_IOCTL + +/* play with 64-bit addrlen; seems to be a teensy bit slower --pw */ +/* #define ADDRLEN 64 */ + +/* + * RX_CHECKSUM turns on card-generated receive checksum generation for + * TCP and UDP packets. Otherwise the upper layers do the calculation. + * TX_CHECKSUM won't do anything too useful, even if it works. There's no + * easy mechanism by which to tell the TCP/UDP stack that it need not + * generate checksums for this device. But if somebody can find a way + * to get that to work, most of the card work is in here already. + * 3/10/1999 Pete Wyckoff + */ +#undef TX_CHECKSUM +#define RX_CHECKSUM + +/* Operational parameters that usually are not changed. */ +/* Time in jiffies before concluding the transmitter is hung. */ +#define TX_TIMEOUT (5*HZ) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include /* Processor type for cache alignment. */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* IP_MF appears to be only defined in , however, + we need it for hardware checksumming support. FYI... some of + the definitions in conflict/duplicate those in + other linux headers causing many compiler warnings. +*/ +#ifndef IP_MF + #define IP_MF 0x2000 /* IP more frags from */ +#endif + +/* Define IP_OFFSET to be IPOPT_OFFSET */ +#ifndef IP_OFFSET + #ifdef IPOPT_OFFSET + #define IP_OFFSET IPOPT_OFFSET + #else + #define IP_OFFSET 2 + #endif +#endif + +#define RUN_AT(x) (jiffies + (x)) + +/* Condensed bus+endian portability operations. */ +#if ADDRLEN == 64 +#define virt_to_desc(addr) cpu_to_le64(virt_to_bus(addr)) +#else +#define virt_to_desc(addr) cpu_to_le32(virt_to_bus(addr)) +#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr)) +#endif + + +/* + Theory of Operation + +I. Board Compatibility + +This device driver is designed for the Packet Engines "Hamachi" +Gigabit Ethernet chip. The only PCA currently supported is the GNIC-II 64-bit +66Mhz PCI card. + +II. Board-specific settings + +No jumpers exist on the board. The chip supports software correction of +various motherboard wiring errors, however this driver does not support +that feature. + +III. Driver operation + +IIIa. Ring buffers + +The Hamachi uses a typical descriptor based bus-master architecture. +The descriptor list is similar to that used by the Digital Tulip. +This driver uses two statically allocated fixed-size descriptor lists +formed into rings by a branch from the final descriptor to the beginning of +the list. The ring sizes are set at compile time by RX/TX_RING_SIZE. + +This driver uses a zero-copy receive and transmit scheme similar my other +network drivers. +The driver allocates full frame size skbuffs for the Rx ring buffers at +open() time and passes the skb->data field to the Hamachi as receive data +buffers. When an incoming frame is less than RX_COPYBREAK bytes long, +a fresh skbuff is allocated and the frame is copied to the new skbuff. +When the incoming frame is larger, the skbuff is passed directly up the +protocol stack and replaced by a newly allocated skbuff. + +The RX_COPYBREAK value is chosen to trade-off the memory wasted by +using a full-sized skbuff for small frames vs. the copying costs of larger +frames. Gigabit cards are typically used on generously configured machines +and the underfilled buffers have negligible impact compared to the benefit of +a single allocation size, so the default value of zero results in never +copying packets. + +IIIb/c. Transmit/Receive Structure + +The Rx and Tx descriptor structure are straight-forward, with no historical +baggage that must be explained. Unlike the awkward DBDMA structure, there +are no unused fields or option bits that had only one allowable setting. + +Two details should be noted about the descriptors: The chip supports both 32 +bit and 64 bit address structures, and the length field is overwritten on +the receive descriptors. The descriptor length is set in the control word +for each channel. The development driver uses 32 bit addresses only, however +64 bit addresses may be enabled for 64 bit architectures e.g. the Alpha. + +IIId. Synchronization + +This driver is very similar to my other network drivers. +The driver runs as two independent, single-threaded flows of control. One +is the send-packet routine, which enforces single-threaded use by the +dev->tbusy flag. The other thread is the interrupt handler, which is single +threaded by the hardware and other software. + +The send packet thread has partial control over the Tx ring and 'dev->tbusy' +flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the next +queue slot is empty, it clears the tbusy flag when finished otherwise it sets +the 'hmp->tx_full' flag. + +The interrupt handler has exclusive control over the Rx ring and records stats +from the Tx ring. After reaping the stats, it marks the Tx queue entry as +empty by incrementing the dirty_tx mark. Iff the 'hmp->tx_full' flag is set, it +clears both the tx_full and tbusy flags. + +IV. Notes + +Thanks to Kim Stearns of Packet Engines for providing a pair of GNIC-II boards. + +IVb. References + +Hamachi Engineering Design Specification, 5/15/97 +(Note: This version was marked "Confidential".) + +IVc. Errata + +None noted. + +V. Recent Changes + +01/15/1999 EPK Enlargement of the TX and RX ring sizes. This appears + to help avoid some stall conditions -- this needs further research. + +01/15/1999 EPK Creation of the hamachi_tx function. This function cleans + the Tx ring and is called from hamachi_start_xmit (this used to be + called from hamachi_interrupt but it tends to delay execution of the + interrupt handler and thus reduce bandwidth by reducing the latency + between hamachi_rx()'s). Notably, some modification has been made so + that the cleaning loop checks only to make sure that the DescOwn bit + isn't set in the status flag since the card is not required + to set the entire flag to zero after processing. + +01/15/1999 EPK In the hamachi_start_tx function, the Tx ring full flag is + checked before attempting to add a buffer to the ring. If the ring is full + an attempt is made to free any dirty buffers and thus find space for + the new buffer or the function returns non-zero which should case the + scheduler to reschedule the buffer later. + +01/15/1999 EPK Some adjustments were made to the chip intialization. + End-to-end flow control should now be fully active and the interrupt + algorithm vars have been changed. These could probably use further tuning. + +01/15/1999 EPK Added the max_{rx,tx}_latency options. These are used to + set the rx and tx latencies for the Hamachi interrupts. If you're having + problems with network stalls, try setting these to higher values. + Valid values are 0x00 through 0xff. + +01/15/1999 EPK In general, the overall bandwidth has increased and + latencies are better (sometimes by a factor of 2). Stalls are rare at + this point, however there still appears to be a bug somewhere between the + hardware and driver. TCP checksum errors under load also appear to be + eliminated at this point. + +01/18/1999 EPK Ensured that the DescEndRing bit was being set on both the + Rx and Tx rings. This appears to have been affecting whether a particular + peer-to-peer connection would hang under high load. I believe the Rx + rings was typically getting set correctly, but the Tx ring wasn't getting + the DescEndRing bit set during initialization. ??? Does this mean the + hamachi card is using the DescEndRing in processing even if a particular + slot isn't in use -- hypothetically, the card might be searching the + entire Tx ring for slots with the DescOwn bit set and then processing + them. If the DescEndRing bit isn't set, then it might just wander off + through memory until it hits a chunk of data with that bit set + and then looping back. + +02/09/1999 EPK Added Michel Mueller's TxDMA Interrupt and Tx-timeout + problem (TxCmd and RxCmd need only to be set when idle or stopped. + +02/09/1999 EPK Added code to check/reset dev->tbusy in hamachi_interrupt. + (Michel Mueller pointed out the ``permanently busy'' potential + problem here). + +02/22/1999 EPK Added Pete Wyckoff's ioctl to control the Tx/Rx latencies. + +02/23/1999 EPK Verified that the interrupt status field bits for Tx were + incorrectly defined and corrected (as per Michel Mueller). + +02/23/1999 EPK Corrected the Tx full check to check that at least 4 slots + were available before reseting the tbusy and tx_full flags + (as per Michel Mueller). + +03/11/1999 EPK Added Pete Wyckoff's hardware checksumming support. + +12/31/1999 KDU Cleaned up assorted things and added Don's code to force +32 bit. + +02/20/2000 KDU Some of the control was just plain odd. Cleaned up the +hamachi_start_xmit() and hamachi_interrupt() code. There is still some +re-structuring I would like to do. + +03/01/2000 KDU Experimenting with a WIDE range of interrupt mitigation +parameters on a dual P3-450 setup yielded the new default interrupt +mitigation parameters. Tx should interrupt VERY infrequently due to +Eric's scheme. Rx should be more often... + +03/13/2000 KDU Added a patch to make the Rx Checksum code interact +nicely with non-linux machines. + +03/13/2000 KDU Experimented with some of the configuration values: + + -It seems that enabling PCI performance commands for descriptors + (changing RxDMACtrl and TxDMACtrl lower nibble from 5 to D) has minimal + performance impact for any of my tests. (ttcp, netpipe, netperf) I will + leave them that way until I hear further feedback. + + -Increasing the PCI_LATENCY_TIMER to 130 + (2 + (burst size of 128 * (0 wait states + 1))) seems to slightly + degrade performance. Leaving default at 64 pending further information. + +03/14/2000 KDU Further tuning: + + -adjusted boguscnt in hamachi_rx() to depend on interrupt + mitigation parameters chosen. + + -Selected a set of interrupt parameters based on some extensive testing. + These may change with more testing. + +TO DO: + +-Consider borrowing from the acenic driver code to check PCI_COMMAND for +PCI_COMMAND_INVALIDATE. Set maximum burst size to cache line size in +that case. + +-fix the reset procedure. It doesn't quite work. +*/ + +/* A few values that may be tweaked. */ +/* Size of each temporary Rx buffer, calculated as: + * 1518 bytes (ethernet packet) + 2 bytes (to get 8 byte alignment for + * the card) + 8 bytes of status info + 8 bytes for the Rx Checksum + + * 2 more because we use skb_reserve. + */ +#define PKT_BUF_SZ 1538 + +/* For now, this is going to be set to the maximum size of an ethernet + * packet. Eventually, we may want to make it a variable that is + * related to the MTU + */ +#define MAX_FRAME_SIZE 1518 + +/* The rest of these values should never change. */ + +static void hamachi_timer(unsigned long data); + +enum capability_flags {CanHaveMII=1, }; +static struct chip_info { + u16 vendor_id, device_id, device_id_mask, pad; + const char *name; + void (*media_timer)(unsigned long data); + int flags; +} chip_tbl[] = { + {0x1318, 0x0911, 0xffff, 0, "Hamachi GNIC-II", hamachi_timer, 0}, + {0,}, +}; + +/* Offsets to the Hamachi registers. Various sizes. */ +enum hamachi_offsets { + TxDMACtrl=0x00, TxCmd=0x04, TxStatus=0x06, TxPtr=0x08, TxCurPtr=0x10, + RxDMACtrl=0x20, RxCmd=0x24, RxStatus=0x26, RxPtr=0x28, RxCurPtr=0x30, + PCIClkMeas=0x060, MiscStatus=0x066, ChipRev=0x68, ChipReset=0x06B, + LEDCtrl=0x06C, VirtualJumpers=0x06D, GPIO=0x6E, + TxChecksum=0x074, RxChecksum=0x076, + TxIntrCtrl=0x078, RxIntrCtrl=0x07C, + InterruptEnable=0x080, InterruptClear=0x084, IntrStatus=0x088, + EventStatus=0x08C, + MACCnfg=0x0A0, FrameGap0=0x0A2, FrameGap1=0x0A4, + /* See enum MII_offsets below. */ + MACCnfg2=0x0B0, RxDepth=0x0B8, FlowCtrl=0x0BC, MaxFrameSize=0x0CE, + AddrMode=0x0D0, StationAddr=0x0D2, + /* Gigabit AutoNegotiation. */ + ANCtrl=0x0E0, ANStatus=0x0E2, ANXchngCtrl=0x0E4, ANAdvertise=0x0E8, + ANLinkPartnerAbility=0x0EA, + EECmdStatus=0x0F0, EEData=0x0F1, EEAddr=0x0F2, + FIFOcfg=0x0F8, +}; + +/* Offsets to the MII-mode registers. */ +enum MII_offsets { + MII_Cmd=0xA6, MII_Addr=0xA8, MII_Wr_Data=0xAA, MII_Rd_Data=0xAC, + MII_Status=0xAE, +}; + +/* Bits in the interrupt status/mask registers. */ +enum intr_status_bits { + IntrRxDone=0x01, IntrRxPCIFault=0x02, IntrRxPCIErr=0x04, + IntrTxDone=0x100, IntrTxPCIFault=0x200, IntrTxPCIErr=0x400, + LinkChange=0x10000, NegotiationChange=0x20000, StatsMax=0x40000, }; + +/* The Hamachi Rx and Tx buffer descriptors. */ +struct hamachi_desc { + u32 status_n_length; +#if ADDRLEN == 64 + u32 pad; + u64 addr; +#else + u32 addr; +#endif +}; + +/* Bits in hamachi_desc.status_n_length */ +enum desc_status_bits { + DescOwn=0x80000000, DescEndPacket=0x40000000, DescEndRing=0x20000000, + DescIntr=0x10000000, +}; + +#define PRIV_ALIGN 15 /* Required alignment mask */ +struct hamachi_private { + /* Descriptor rings first for alignment. Tx requires a second descriptor + for status. */ + struct hamachi_desc rx_ring[RX_RING_SIZE]; + struct hamachi_desc tx_ring[TX_RING_SIZE]; + /* The addresses of receive-in-place skbuffs. */ + struct sk_buff* rx_skbuff[RX_RING_SIZE]; + /* The saved address of a sent-in-place packet/buffer, for skfree(). */ + struct sk_buff* tx_skbuff[TX_RING_SIZE]; + struct net_device_stats stats; + struct timer_list timer; /* Media selection timer. */ + /* Frequently used and paired value: keep adjacent for cache effect. */ + spinlock_t lock; + int chip_id; + struct hamachi_desc *rx_head_desc; + unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ + unsigned int cur_tx, dirty_tx; + unsigned int rx_buf_sz; /* Based on MTU+slack. */ + unsigned int tx_full:1; /* The Tx queue is full. */ + unsigned int full_duplex:1; /* Full-duplex operation requested. */ + unsigned int duplex_lock:1; + unsigned int medialock:1; /* Do not sense media. */ + unsigned int default_port:4; /* Last dev->if_port value. */ + /* MII transceiver section. */ + int mii_cnt; /* MII device addresses. */ + u16 advertising; /* NWay media advertisement */ + unsigned char phys[2]; /* MII device addresses. */ + u_int32_t rx_int_var, tx_int_var; /* interrupt control variables */ + u_int32_t option; /* Hold on to a copy of the options */ + u_int8_t pad[16]; /* Used for 32-byte alignment */ +}; + +MODULE_AUTHOR("Donald Becker , Eric Kasten , Keith Underwood "); +MODULE_DESCRIPTION("Packet Engines 'Hamachi' GNIC-II Gigabit Ethernet driver"); +MODULE_PARM(max_interrupt_work, "i"); +MODULE_PARM(mtu, "i"); +MODULE_PARM(debug, "i"); +MODULE_PARM(min_rx_pkt, "i"); +MODULE_PARM(max_rx_gap, "i"); +MODULE_PARM(max_rx_latency, "i"); +MODULE_PARM(min_tx_pkt, "i"); +MODULE_PARM(max_tx_gap, "i"); +MODULE_PARM(max_tx_latency, "i"); +MODULE_PARM(rx_copybreak, "i"); +MODULE_PARM(rx_params, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(tx_params, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(force32, "i"); + +static int read_eeprom(long ioaddr, int location); +static int mdio_read(long ioaddr, int phy_id, int location); +static void mdio_write(long ioaddr, int phy_id, int location, int value); +static int hamachi_open(struct net_device *dev); +#ifdef HAVE_PRIVATE_IOCTL +static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +#endif +static void hamachi_timer(unsigned long data); +static void hamachi_tx_timeout(struct net_device *dev); +static void hamachi_init_ring(struct net_device *dev); +static int hamachi_start_xmit(struct sk_buff *skb, struct net_device *dev); +static void hamachi_interrupt(int irq, void *dev_instance, struct pt_regs *regs); +static inline int hamachi_rx(struct net_device *dev); +static inline int hamachi_tx(struct net_device *dev); +static void hamachi_error(struct net_device *dev, int intr_status); +static int hamachi_close(struct net_device *dev); +static struct net_device_stats *hamachi_get_stats(struct net_device *dev); +static void set_rx_mode(struct net_device *dev); + + +static int __init hamachi_init_one (struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + static int did_version = 0; /* Already printed version info. */ + struct hamachi_private *hmp; + int option, i, rx_int_var, tx_int_var, boguscnt; + int chip_id = ent->driver_data; + int irq = pdev->irq; + long ioaddr; + static int card_idx = 0; + struct net_device *dev; + + if (hamachi_debug > 0 && did_version++ == 0) + printk(version); + + ioaddr = pci_resource_start(pdev, 0); +#ifdef __alpha__ /* Really "64 bit addrs" */ + ioaddr |= (pci_resource_start(pdev, 1) << 32); +#endif + + if (pci_enable_device(pdev)) + return -EIO; + pci_set_master(pdev); + + ioaddr = (long) ioremap(ioaddr, 0x400); + if (!ioaddr) + return -ENOMEM; + + dev = init_etherdev(NULL, sizeof(struct hamachi_private)); + if (!dev) { + iounmap((char *)ioaddr); + return -ENOMEM; + } + +#ifdef TX_CHECKSUM + printk("check that skbcopy in ip_queue_xmit isn't happening\n"); + dev->hard_header_len += 8; /* for cksum tag */ +#endif + + printk(KERN_INFO "%s: %s type %x at 0x%lx, ", + dev->name, chip_tbl[chip_id].name, readl(ioaddr + ChipRev), + ioaddr); + + for (i = 0; i < 6; i++) + dev->dev_addr[i] = 1 ? read_eeprom(ioaddr, 4 + i) + : readb(ioaddr + StationAddr + i); + for (i = 0; i < 5; i++) + printk("%2.2x:", dev->dev_addr[i]); + printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); + +#if ! defined(final_version) + if (hamachi_debug > 4) + for (i = 0; i < 0x10; i++) + printk("%2.2x%s", + read_eeprom(ioaddr, i), i % 16 != 15 ? " " : "\n"); +#endif + +#if 0 /* Moving this until after the force 32 check and reset. */ + i = readb(ioaddr + PCIClkMeas); + printk(KERN_INFO "%s: %d-bit %d Mhz PCI bus (%d), Virtual Jumpers " + "%2.2x, LPA %4.4x.\n", + dev->name, readw(ioaddr + MiscStatus) & 1 ? 64 : 32, + i ? 2000/(i&0x7f) : 0, i&0x7f, (int)readb(ioaddr + VirtualJumpers), + readw(ioaddr + ANLinkPartnerAbility)); +#endif + + hmp = dev->priv; + spin_lock_init(&hmp->lock); + + /* Check for options being passed in */ + option = card_idx < MAX_UNITS ? options[card_idx] : 0; + if (dev->mem_start) + option = dev->mem_start; + + /* If the bus size is misidentified, do the following. */ + force32 = force32 ? force32 : + ((option >= 0) ? ((option & 0x00000070) >> 4) : 0 ); + if (force32) + writeb(force32, ioaddr + VirtualJumpers); + + /* Hmmm, do we really need to reset the chip???. */ + writeb(0x01, ioaddr + ChipReset); + + /* After a reset, the clock speed measurement of the PCI bus will not + * be valid for a moment. Wait for a little while until it is. If + * it takes more than 10ms, forget it. + */ + udelay(10); + i = readb(ioaddr + PCIClkMeas); + for (boguscnt = 0; (!(i & 0x080)) && boguscnt < 1000; boguscnt++){ + udelay(10); + i = readb(ioaddr + PCIClkMeas); + } + + printk(KERN_INFO "%s: %d-bit %d Mhz PCI bus (%d), Virtual Jumpers " + "%2.2x, LPA %4.4x.\n", + dev->name, readw(ioaddr + MiscStatus) & 1 ? 64 : 32, + i ? 2000/(i&0x7f) : 0, i&0x7f, (int)readb(ioaddr + VirtualJumpers), + readw(ioaddr + ANLinkPartnerAbility)); + + dev->base_addr = ioaddr; + dev->irq = irq; + + hmp->chip_id = chip_id; + + /* The lower four bits are the media type. */ + if (option > 0) { + hmp->option = option; + if (option & 0x200) + hmp->full_duplex = 1; + else if (option & 0x080) + hmp->full_duplex = 0; + hmp->default_port = option & 15; + if (hmp->default_port) + hmp->medialock = 1; + } + if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0) + hmp->full_duplex = 1; + + /* lock the duplex mode if someone specified a value */ + if (hmp->full_duplex || (option & 0x080)) + hmp->duplex_lock = 1; + + /* Set interrupt tuning parameters */ + max_rx_latency = max_rx_latency & 0x00ff; + max_rx_gap = max_rx_gap & 0x00ff; + min_rx_pkt = min_rx_pkt & 0x00ff; + max_tx_latency = max_tx_latency & 0x00ff; + max_tx_gap = max_tx_gap & 0x00ff; + min_tx_pkt = min_tx_pkt & 0x00ff; + + rx_int_var = card_idx < MAX_UNITS ? rx_params[card_idx] : -1; + tx_int_var = card_idx < MAX_UNITS ? tx_params[card_idx] : -1; + hmp->rx_int_var = rx_int_var >= 0 ? rx_int_var : + (min_rx_pkt << 16 | max_rx_gap << 8 | max_rx_latency); + hmp->tx_int_var = tx_int_var >= 0 ? tx_int_var : + (min_tx_pkt << 16 | max_tx_gap << 8 | max_tx_latency); + + + /* The Hamachi-specific entries in the device structure. */ + dev->open = &hamachi_open; + dev->hard_start_xmit = &hamachi_start_xmit; + dev->stop = &hamachi_close; + dev->get_stats = &hamachi_get_stats; + dev->set_multicast_list = &set_rx_mode; +#ifdef HAVE_PRIVATE_IOCTL + dev->do_ioctl = &mii_ioctl; +#endif + dev->tx_timeout = &hamachi_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + if (mtu) + dev->mtu = mtu; + + if (chip_tbl[hmp->chip_id].flags & CanHaveMII) { + int phy, phy_idx = 0; + for (phy = 0; phy < 32 && phy_idx < 4; phy++) { + int mii_status = mdio_read(ioaddr, phy, 1); + if (mii_status != 0xffff && + mii_status != 0x0000) { + hmp->phys[phy_idx++] = phy; + hmp->advertising = mdio_read(ioaddr, phy, 4); + printk(KERN_INFO "%s: MII PHY found at address %d, status " + "0x%4.4x advertising %4.4x.\n", + dev->name, phy, mii_status, hmp->advertising); + } + } + hmp->mii_cnt = phy_idx; + } + /* Configure gigabit autonegotiation. */ + writew(0x0400, ioaddr + ANXchngCtrl); /* Enable legacy links. */ + writew(0x08e0, ioaddr + ANAdvertise); /* Set our advertise word. */ + writew(0x1000, ioaddr + ANCtrl); /* Enable negotiation */ + + card_idx++; + return 0; +} + +static int read_eeprom(long ioaddr, int location) +{ + int bogus_cnt = 1000; + + /* We should check busy first - per docs -KDU */ + while ((readb(ioaddr + EECmdStatus) & 0x40) && --bogus_cnt > 0); + writew(location, ioaddr + EEAddr); + writeb(0x02, ioaddr + EECmdStatus); + bogus_cnt = 1000; + while ((readb(ioaddr + EECmdStatus) & 0x40) && --bogus_cnt > 0); + if (hamachi_debug > 5) + printk(" EEPROM status is %2.2x after %d ticks.\n", + (int)readb(ioaddr + EECmdStatus), 1000- bogus_cnt); + return readb(ioaddr + EEData); +} + +/* MII Managemen Data I/O accesses. + These routines assume the MDIO controller is idle, and do not exit until + the command is finished. */ + +static int mdio_read(long ioaddr, int phy_id, int location) +{ + int i; + + /* We should check busy first - per docs -KDU */ + for (i = 10000; i >= 0; i--) + if ((readw(ioaddr + MII_Status) & 1) == 0) + break; + writew((phy_id<<8) + location, ioaddr + MII_Addr); + writew(0x0001, ioaddr + MII_Cmd); + for (i = 10000; i >= 0; i--) + if ((readw(ioaddr + MII_Status) & 1) == 0) + break; + return readw(ioaddr + MII_Rd_Data); +} + +static void mdio_write(long ioaddr, int phy_id, int location, int value) +{ + int i; + + /* We should check busy first - per docs -KDU */ + for (i = 10000; i >= 0; i--) + if ((readw(ioaddr + MII_Status) & 1) == 0) + break; + writew((phy_id<<8) + location, ioaddr + MII_Addr); + writew(value, ioaddr + MII_Wr_Data); + + /* Wait for the command to finish. */ + for (i = 10000; i >= 0; i--) + if ((readw(ioaddr + MII_Status) & 1) == 0) + break; + return; +} + + +static int hamachi_open(struct net_device *dev) +{ + struct hamachi_private *hmp = (struct hamachi_private *)dev->priv; + long ioaddr = dev->base_addr; + int i; + u_int32_t rx_int_var, tx_int_var; + u_int16_t fifo_info; + + MOD_INC_USE_COUNT; + + if (request_irq(dev->irq, &hamachi_interrupt, SA_SHIRQ, dev->name, dev)) { + MOD_DEC_USE_COUNT; + return -EAGAIN; + } + + if (hamachi_debug > 1) + printk(KERN_DEBUG "%s: hamachi_open() irq %d.\n", + dev->name, dev->irq); + + hamachi_init_ring(dev); + +#if ADDRLEN == 64 + writel(virt_to_bus(hmp->rx_ring), ioaddr + RxPtr); + writel(virt_to_bus(hmp->rx_ring) >> 32, ioaddr + RxPtr + 4); + writel(virt_to_bus(hmp->tx_ring), ioaddr + TxPtr); + writel(virt_to_bus(hmp->tx_ring) >> 32, ioaddr + TxPtr + 4); +#else + writel(virt_to_bus(hmp->rx_ring), ioaddr + RxPtr); + writel(virt_to_bus(hmp->tx_ring), ioaddr + TxPtr); +#endif + + /* TODO: It would make sense to organize this as words since the card + * documentation does. -KDU + */ + for (i = 0; i < 6; i++) + writeb(dev->dev_addr[i], ioaddr + StationAddr + i); + + /* Initialize other registers: with so many this eventually this will + converted to an offset/value list. */ + + /* Configure the FIFO */ + fifo_info = (readw(ioaddr + GPIO) & 0x00C0) >> 6; + switch (fifo_info){ + case 0 : + /* No FIFO */ + writew(0x0000, ioaddr + FIFOcfg); + break; + case 1 : + /* Configure the FIFO for 512K external, 16K used for Tx. */ + writew(0x0028, ioaddr + FIFOcfg); + break; + case 2 : + /* Configure the FIFO for 1024 external, 32K used for Tx. */ + writew(0x004C, ioaddr + FIFOcfg); + break; + case 3 : + /* Configure the FIFO for 2048 external, 32K used for Tx. */ + writew(0x006C, ioaddr + FIFOcfg); + break; + default : + printk(KERN_WARNING "%s: Unsupported external memory config!\n", + dev->name); + /* Default to no FIFO */ + writew(0x0000, ioaddr + FIFOcfg); + break; + } + + if (dev->if_port == 0) + dev->if_port = hmp->default_port; + + + /* Setting the Rx mode will start the Rx process. */ + /* If someone didn't choose a duplex, default to full-duplex */ + if (hmp->duplex_lock != 1) + hmp->full_duplex = 1; + + /* always 1, takes no more time to do it */ + writew(0x0001, ioaddr + RxChecksum); +#ifdef TX_CHECKSUM + writew(0x0001, ioaddr + TxChecksum); +#else + writew(0x0000, ioaddr + TxChecksum); +#endif + writew(0x8000, ioaddr + MACCnfg); /* Soft reset the MAC */ + writew(0x215F, ioaddr + MACCnfg); + writew(0x000C, ioaddr + FrameGap0); + /* WHAT?!?!? Why isn't this documented somewhere? -KDU */ + writew(0x1018, ioaddr + FrameGap1); + /* Why do we enable receives/transmits here? -KDU */ + writew(0x0780, ioaddr + MACCnfg2); /* Upper 16 bits control LEDs. */ + /* Enable automatic generation of flow control frames, period 0xffff. */ + writel(0x0030FFFF, ioaddr + FlowCtrl); + writew(MAX_FRAME_SIZE, ioaddr + MaxFrameSize); /* dev->mtu+14 ??? */ + + /* Enable legacy links. */ + writew(0x0400, ioaddr + ANXchngCtrl); /* Enable legacy links. */ + /* Initial Link LED to blinking red. */ + writeb(0x03, ioaddr + LEDCtrl); + + /* Configure interrupt mitigation. This has a great effect on + performance, so systems tuning should start here!. */ + + rx_int_var = hmp->rx_int_var; + tx_int_var = hmp->tx_int_var; + + if (hamachi_debug > 1) { + printk("max_tx_latency: %d, max_tx_gap: %d, min_tx_pkt: %d\n", + tx_int_var & 0x00ff, (tx_int_var & 0x00ff00) >> 8, + (tx_int_var & 0x00ff0000) >> 16); + printk("max_rx_latency: %d, max_rx_gap: %d, min_rx_pkt: %d\n", + rx_int_var & 0x00ff, (rx_int_var & 0x00ff00) >> 8, + (rx_int_var & 0x00ff0000) >> 16); + printk("rx_int_var: %x, tx_int_var: %x\n", rx_int_var, tx_int_var); + } + + writel(tx_int_var, ioaddr + TxIntrCtrl); + writel(rx_int_var, ioaddr + RxIntrCtrl); + + set_rx_mode(dev); + + netif_start_queue(dev); + + /* Enable interrupts by setting the interrupt mask. */ + writel(0x80878787, ioaddr + InterruptEnable); + writew(0x0000, ioaddr + EventStatus); /* Clear non-interrupting events */ + + /* Configure and start the DMA channels. */ + /* Burst sizes are in the low three bits: size = 4<<(val&7) */ +#if ADDRLEN == 64 + writew(0x005D, ioaddr + RxDMACtrl); /* 128 dword bursts */ + writew(0x005D, ioaddr + TxDMACtrl); +#else + writew(0x001D, ioaddr + RxDMACtrl); + writew(0x001D, ioaddr + TxDMACtrl); +#endif + writew(0x0001, dev->base_addr + RxCmd); + + if (hamachi_debug > 2) { + printk(KERN_DEBUG "%s: Done hamachi_open(), status: Rx %x Tx %x.\n", + dev->name, readw(ioaddr + RxStatus), readw(ioaddr + TxStatus)); + } + /* Set the timer to check for link beat. */ + init_timer(&hmp->timer); + hmp->timer.expires = RUN_AT((24*HZ)/10); /* 2.4 sec. */ + hmp->timer.data = (unsigned long)dev; + hmp->timer.function = &hamachi_timer; /* timer handler */ + add_timer(&hmp->timer); + + return 0; +} + +static inline int hamachi_tx(struct net_device *dev) +{ + struct hamachi_private *hmp = (struct hamachi_private *)dev->priv; + + /* Update the dirty pointer until we find an entry that is + still owned by the card */ + for (; hmp->cur_tx - hmp->dirty_tx > 0; hmp->dirty_tx++) { + int entry = hmp->dirty_tx % TX_RING_SIZE; + if (hmp->tx_ring[entry].status_n_length & cpu_to_le32(DescOwn)) + break; + /* Free the original skb. */ + if (hmp->tx_skbuff[entry] != 0) { + dev_kfree_skb(hmp->tx_skbuff[entry]); + hmp->tx_skbuff[entry] = 0; + } + hmp->tx_ring[entry].status_n_length = 0; + if (entry >= TX_RING_SIZE-1) + hmp->tx_ring[TX_RING_SIZE-1].status_n_length |= + cpu_to_le32(DescEndRing); + hmp->stats.tx_packets++; + } + + return 0; +} + +static void hamachi_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct hamachi_private *hmp = (struct hamachi_private *)dev->priv; + long ioaddr = dev->base_addr; + int next_tick = 10*HZ; + + if (hamachi_debug > 2) { + printk(KERN_INFO "%s: Hamachi Autonegotiation status %4.4x, LPA " + "%4.4x.\n", dev->name, readw(ioaddr + ANStatus), + readw(ioaddr + ANLinkPartnerAbility)); + printk(KERN_INFO "%s: Autonegotiation regs %4.4x %4.4x %4.4x " + "%4.4x %4.4x %4.4x.\n", dev->name, + readw(ioaddr + 0x0e0), + readw(ioaddr + 0x0e2), + readw(ioaddr + 0x0e4), + readw(ioaddr + 0x0e6), + readw(ioaddr + 0x0e8), + readw(ioaddr + 0x0eA)); + } + /* We could do something here... nah. */ + hmp->timer.expires = RUN_AT(next_tick); + add_timer(&hmp->timer); +} + +static void hamachi_tx_timeout(struct net_device *dev) +{ + int i; + struct hamachi_private *hmp = (struct hamachi_private *)dev->priv; + long ioaddr = dev->base_addr; + + printk(KERN_WARNING "%s: Hamachi transmit timed out, status %8.8x," + " resetting...\n", dev->name, (int)readw(ioaddr + TxStatus)); + +#ifndef __alpha__ + { + int i; + printk(KERN_DEBUG " Rx ring %8.8x: ", (int)hmp->rx_ring); + for (i = 0; i < RX_RING_SIZE; i++) + printk(" %8.8x", (unsigned int)hmp->rx_ring[i].status_n_length); + printk("\n"KERN_DEBUG" Tx ring %8.8x: ", (int)hmp->tx_ring); + for (i = 0; i < TX_RING_SIZE; i++) + printk(" %4.4x", hmp->tx_ring[i].status_n_length); + printk("\n"); + } +#endif + + /* Reinit the hardware and make sure the Rx and Tx processes + are up and running. + */ + dev->if_port = 0; + /* The right way to do Reset. -KDU + * -Clear OWN bit in all Rx/Tx descriptors + * -Wait 50 uS for channels to go idle + * -Turn off MAC receiver + * -Issue Reset + */ + + for (i = 0; i < RX_RING_SIZE; i++) + hmp->rx_ring[i].status_n_length &= ~DescOwn; + + /* Presume that all packets in the Tx queue are gone if we have to + * re-init the hardware. + */ + for (i = 0; i < TX_RING_SIZE; i++){ + if (i >= TX_RING_SIZE - 1) + hmp->tx_ring[i].status_n_length = DescEndRing | + (hmp->tx_ring[i].status_n_length & 0x0000FFFF); + else + hmp->tx_ring[i].status_n_length &= 0x0000ffff; + if (hmp->tx_skbuff[i]){ + dev_kfree_skb(hmp->tx_skbuff[i]); + hmp->tx_skbuff[i] = 0; + } + } + + udelay(60); /* Sleep 60 us just for safety sake */ + writew(0x0002, dev->base_addr + RxCmd); /* STOP Rx */ + + writeb(0x01, ioaddr + ChipReset); /* Reinit the hardware */ + + hmp->tx_full = 0; + hmp->cur_rx = hmp->cur_tx = 0; + hmp->dirty_rx = hmp->dirty_tx = 0; + hmp->rx_head_desc = &hmp->rx_ring[0]; + /* Rx packets are also presumed lost; however, we need to make sure a + * ring of buffers is in tact. -KDU + */ + for (i = 0; i < RX_RING_SIZE; i++){ + if (hmp->rx_skbuff[i]){ + dev_kfree_skb(hmp->rx_skbuff[i]); + hmp->rx_skbuff[i] = 0; + } + } + /* Fill in the Rx buffers. Handle allocation failure gracefully. */ + for (i = 0; i < RX_RING_SIZE; i++) { + struct sk_buff *skb = dev_alloc_skb(hmp->rx_buf_sz); + hmp->rx_skbuff[i] = skb; + if (skb == NULL) + break; + skb->dev = dev; /* Mark as being used by this device. */ + skb_reserve(skb, 2); /* 16 byte align the IP header. */ + hmp->rx_ring[i].addr = virt_to_desc(skb->tail); + hmp->rx_ring[i].status_n_length = + cpu_to_le32(DescOwn | DescEndPacket | DescIntr | (hmp->rx_buf_sz - 2)); + } + hmp->dirty_rx = (unsigned int)(i - RX_RING_SIZE); + /* Mark the last entry as wrapping the ring. */ + hmp->rx_ring[RX_RING_SIZE-1].status_n_length |= cpu_to_le32(DescEndRing); + + + /* Trigger an immediate transmit demand. */ + dev->trans_start = jiffies; + hmp->stats.tx_errors++; + + /* Restart the chip's Tx/Rx processes . */ + writew(0x0002, dev->base_addr + TxCmd); /* STOP Tx */ + writew(0x0001, dev->base_addr + TxCmd); /* START Tx */ + writew(0x0001, dev->base_addr + RxCmd); /* START Rx */ +} + + +/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ +static void hamachi_init_ring(struct net_device *dev) +{ + struct hamachi_private *hmp = (struct hamachi_private *)dev->priv; + int i; + + hmp->tx_full = 0; + hmp->cur_rx = hmp->cur_tx = 0; + hmp->dirty_rx = hmp->dirty_tx = 0; + +#if 0 + /* This is wrong. I'm not sure what the original plan was, but this + * is wrong. An MTU of 1 gets you a buffer of 1536, while an MTU + * of 1501 gets a buffer of 1533? -KDU + */ + hmp->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); +#endif + /* My attempt at a reasonable correction */ + /* +26 gets the maximum ethernet encapsulation, +7 & ~7 because the + * card needs room to do 8 byte alignment, +2 so we can reserve + * the first 2 bytes, and +16 gets room for the status word from the + * card. -KDU + */ + hmp->rx_buf_sz = (dev->mtu <= 1492 ? PKT_BUF_SZ : + (((dev->mtu+26+7) & ~7) + 2 + 16)); + + hmp->rx_head_desc = &hmp->rx_ring[0]; + + /* Initialize all Rx descriptors. */ + for (i = 0; i < RX_RING_SIZE; i++) { + hmp->rx_ring[i].status_n_length = 0; + hmp->rx_skbuff[i] = 0; + } + /* Fill in the Rx buffers. Handle allocation failure gracefully. */ + for (i = 0; i < RX_RING_SIZE; i++) { + struct sk_buff *skb = dev_alloc_skb(hmp->rx_buf_sz); + hmp->rx_skbuff[i] = skb; + if (skb == NULL) + break; + skb->dev = dev; /* Mark as being used by this device. */ + skb_reserve(skb, 2); /* 16 byte align the IP header. */ + hmp->rx_ring[i].addr = virt_to_desc(skb->tail); + /* -2 because it doesn't REALLY have that first 2 bytes -KDU */ + hmp->rx_ring[i].status_n_length = + cpu_to_le32(DescOwn | DescEndPacket | DescIntr | (hmp->rx_buf_sz -2)); + } + hmp->dirty_rx = (unsigned int)(i - RX_RING_SIZE); + /* Mark the last entry as wrapping the ring. */ + hmp->rx_ring[RX_RING_SIZE-1].status_n_length |= cpu_to_le32(DescEndRing); + + + /* Mark the last entry as wrapping the ring. */ + hmp->rx_ring[RX_RING_SIZE-1].status_n_length |= DescEndRing; + + for (i = 0; i < TX_RING_SIZE; i++) { + hmp->tx_skbuff[i] = 0; + hmp->tx_ring[i].status_n_length = 0; + } + /* Mark the last entry as wrapping the ring. */ + hmp->tx_ring[TX_RING_SIZE-1].status_n_length |= cpu_to_le32(DescEndRing); + + return; +} + + +#ifdef TX_CHECKSUM +#define csum_add(it, val) \ +do { \ + it += (u16) (val); \ + if (it & 0xffff0000) { \ + it &= 0xffff; \ + ++it; \ + } \ +} while (0) + /* printk("add %04x --> %04x\n", val, it); \ */ + +/* uh->len already network format, do not swap */ +#define pseudo_csum_udp(sum,ih,uh) do { \ + sum = 0; \ + csum_add(sum, (ih)->saddr >> 16); \ + csum_add(sum, (ih)->saddr & 0xffff); \ + csum_add(sum, (ih)->daddr >> 16); \ + csum_add(sum, (ih)->daddr & 0xffff); \ + csum_add(sum, __constant_htons(IPPROTO_UDP)); \ + csum_add(sum, (uh)->len); \ +} while (0) + +/* swap len */ +#define pseudo_csum_tcp(sum,ih,len) do { \ + sum = 0; \ + csum_add(sum, (ih)->saddr >> 16); \ + csum_add(sum, (ih)->saddr & 0xffff); \ + csum_add(sum, (ih)->daddr >> 16); \ + csum_add(sum, (ih)->daddr & 0xffff); \ + csum_add(sum, __constant_htons(IPPROTO_TCP)); \ + csum_add(sum, htons(len)); \ +} while (0) +#endif + +static int hamachi_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct hamachi_private *hmp = (struct hamachi_private *)dev->priv; + unsigned entry; + u16 status; + + /* Ok, now make sure that the queue has space before trying to + add another skbuff. if we return non-zero the scheduler + should interpret this as a queue full and requeue the buffer + for later. + */ + if (hmp->tx_full) { + /* We should NEVER reach this point -KDU */ + printk(KERN_WARNING "%s: Hamachi transmit queue full at slot %d.\n",dev->name, hmp->cur_tx); + + /* Wake the potentially-idle transmit channel. */ + /* If we don't need to read status, DON'T -KDU */ + status=readw(dev->base_addr + TxStatus); + if( !(status & 0x0001) || (status & 0x0002)) + writew(0x0001, dev->base_addr + TxCmd); + return 1; + } + + /* Caution: the write order is important here, set the field + with the "ownership" bits last. */ + + /* Calculate the next Tx descriptor entry. */ + entry = hmp->cur_tx % TX_RING_SIZE; + + hmp->tx_skbuff[entry] = skb; + +#ifdef TX_CHECKSUM + { + /* tack on checksum tag */ + u32 tagval = 0; + struct ethhdr *eh = (struct ethhdr *)skb->data; + if (eh->h_proto == __constant_htons(ETH_P_IP)) { + struct iphdr *ih = (struct iphdr *)((char *)eh + ETH_HLEN); + if (ih->protocol == IPPROTO_UDP) { + struct udphdr *uh + = (struct udphdr *)((char *)ih + ih->ihl*4); + u32 offset = ((unsigned char *)uh + 6) - skb->data; + u32 pseudo; + pseudo_csum_udp(pseudo, ih, uh); + pseudo = htons(pseudo); + printk("udp cksum was %04x, sending pseudo %04x\n", + uh->check, pseudo); + uh->check = 0; /* zero out uh->check before card calc */ + /* + * start at 14 (skip ethhdr), store at offset (uh->check), + * use pseudo value given. + */ + tagval = (14 << 24) | (offset << 16) | pseudo; + } else if (ih->protocol == IPPROTO_TCP) { + printk("tcp, no auto cksum\n"); + } + } + *(u32 *)skb_push(skb, 8) = tagval; + } +#endif + + hmp->tx_ring[entry].addr = virt_to_desc(skb->data); + + /* Hmmmm, could probably put a DescIntr on these, but the way + the driver is currently coded makes Tx interrupts unnecessary + since the clearing of the Tx ring is handled by the start_xmit + routine. This organization helps mitigate the interrupts a + bit and probably renders the max_tx_latency param useless. + + Update: Putting a DescIntr bit on all of the descriptors and + mitigating interrupt frequency with the tx_min_pkt parameter. -KDU + */ + if (entry >= TX_RING_SIZE-1) /* Wrap ring */ + hmp->tx_ring[entry].status_n_length = + cpu_to_le32(DescOwn|DescEndPacket|DescEndRing|DescIntr | skb->len); + else + hmp->tx_ring[entry].status_n_length = + cpu_to_le32(DescOwn|DescEndPacket|DescIntr | skb->len); + hmp->cur_tx++; + + /* Non-x86 Todo: explicitly flush cache lines here. */ + + /* Wake the potentially-idle transmit channel. */ + /* If we don't need to read status, DON'T -KDU */ + status=readw(dev->base_addr + TxStatus); + if( !(status & 0x0001) || (status & 0x0002)) + writew(0x0001, dev->base_addr + TxCmd); + + /* Immediately before returning, let's clear as many entries as we can. */ + hamachi_tx(dev); + + /* We should kick the bottom half here, since we are not accepting + * interrupts with every packet. i.e. realize that Gigabit ethernet + * can transmit faster than ordinary machines can load packets; + * hence, any packet that got put off because we were in the transmit + * routine should IMMEDIATELY get a chance to be re-queued. -KDU + */ + if ((hmp->cur_tx - hmp->dirty_tx) < (TX_RING_SIZE - 4)) + netif_wake_queue(dev); /* Typical path */ + else { + hmp->tx_full = 1; + netif_stop_queue(dev); + } + dev->trans_start = jiffies; + + if (hamachi_debug > 4) { + printk(KERN_DEBUG "%s: Hamachi transmit frame #%d queued in slot %d.\n", + dev->name, hmp->cur_tx, entry); + } + return 0; +} + +/* The interrupt handler does all of the Rx thread work and cleans up + after the Tx thread. */ +static void hamachi_interrupt(int irq, void *dev_instance, struct pt_regs *rgs) +{ + struct net_device *dev = (struct net_device *)dev_instance; + struct hamachi_private *hmp; + long ioaddr, boguscnt = max_interrupt_work; + +#ifndef final_version /* Can never occur. */ + if (dev == NULL) { + printk (KERN_ERR "hamachi_interrupt(): irq %d for unknown device.\n", irq); + return; + } +#endif + + ioaddr = dev->base_addr; + hmp = (struct hamachi_private *)dev->priv; + spin_lock(&hmp->lock); + + do { + u32 intr_status = readl(ioaddr + InterruptClear); + + if (hamachi_debug > 4) + printk(KERN_DEBUG "%s: Hamachi interrupt, status %4.4x.\n", + dev->name, intr_status); + + if (intr_status == 0) + break; + + if (intr_status & IntrRxDone) + hamachi_rx(dev); + + if (intr_status & IntrTxDone){ + /* This code should RARELY need to execute. After all, this is + * a gigabit link, it should consume packets as fast as we put + * them in AND we clear the Tx ring in hamachi_start_xmit(). + */ + if (hmp->tx_full){ + for (; hmp->cur_tx - hmp->dirty_tx > 0; hmp->dirty_tx++){ + int entry = hmp->dirty_tx % TX_RING_SIZE; + if (hmp->tx_ring[entry].status_n_length & cpu_to_le32(DescOwn)) + break; + /* Free the original skb. */ + if (hmp->tx_skbuff[entry]){ + dev_kfree_skb_irq(hmp->tx_skbuff[entry]); + hmp->tx_skbuff[entry] = 0; + } + hmp->tx_ring[entry].status_n_length = 0; + if (entry >= TX_RING_SIZE-1) + hmp->tx_ring[TX_RING_SIZE-1].status_n_length |= + cpu_to_le32(DescEndRing); + hmp->stats.tx_packets++; + } + if (hmp->cur_tx - hmp->dirty_tx < TX_RING_SIZE - 4){ + /* The ring is no longer full */ + hmp->tx_full = 0; + netif_wake_queue(dev); + } + } else { + netif_wake_queue(dev); + } + } + + + /* Abnormal error summary/uncommon events handlers. */ + if (intr_status & + (IntrTxPCIFault | IntrTxPCIErr | IntrRxPCIFault | IntrRxPCIErr | + LinkChange | NegotiationChange | StatsMax)) + hamachi_error(dev, intr_status); + + if (--boguscnt < 0) { + printk(KERN_WARNING "%s: Too much work at interrupt, status=0x%4.4x.\n", + dev->name, intr_status); + break; + } + } while (1); + + if (hamachi_debug > 3) + printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", + dev->name, readl(ioaddr + IntrStatus)); + +#ifndef final_version + /* Code that should never be run! Perhaps remove after testing.. */ + { + static int stopit = 10; + if (dev->start == 0 && --stopit < 0) { + printk(KERN_ERR "%s: Emergency stop, looping startup interrupt.\n", + dev->name); + free_irq(irq, dev); + } + } +#endif + + spin_unlock(&hmp->lock); +} + +#ifdef TX_CHECKSUM +/* + * Copied from eth_type_trans(), with reduced header, since we don't + * get it on RX, only on TX. + */ +static unsigned short hamachi_eth_type_trans(struct sk_buff *skb, + struct net_device *dev) +{ + struct ethhdr *eth; + unsigned char *rawp; + + skb->mac.raw=skb->data; + skb_pull(skb,dev->hard_header_len-8); /* artificially enlarged on tx */ + eth= skb->mac.ethernet; + + if(*eth->h_dest&1) + { + if(memcmp(eth->h_dest,dev->broadcast, ETH_ALEN)==0) + skb->pkt_type=PACKET_BROADCAST; + else + skb->pkt_type=PACKET_MULTICAST; + } + + /* + * This ALLMULTI check should be redundant by 1.4 + * so don't forget to remove it. + * + * Seems, you forgot to remove it. All silly devices + * seems to set IFF_PROMISC. + */ + + else if(dev->flags&(IFF_PROMISC/*|IFF_ALLMULTI*/)) + { + if(memcmp(eth->h_dest,dev->dev_addr, ETH_ALEN)) + skb->pkt_type=PACKET_OTHERHOST; + } + + if (ntohs(eth->h_proto) >= 1536) + return eth->h_proto; + + rawp = skb->data; + + /* + * This is a magic hack to spot IPX packets. Older Novell breaks + * the protocol design and runs IPX over 802.3 without an 802.2 LLC + * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This + * won't work for fault tolerant netware but does for the rest. + */ + if (*(unsigned short *)rawp == 0xFFFF) + return htons(ETH_P_802_3); + + /* + * Real 802.2 LLC + */ + return htons(ETH_P_802_2); +} +#endif /* TX_CHECKSUM */ + +/* This routine is logically part of the interrupt handler, but seperated + for clarity and better register allocation. */ +static int hamachi_rx(struct net_device *dev) +{ + struct hamachi_private *hmp = (struct hamachi_private *)dev->priv; + int entry = hmp->cur_rx % RX_RING_SIZE; + int boguscnt = (hmp->dirty_rx + RX_RING_SIZE) - hmp->cur_rx; + + if (hamachi_debug > 4) { + printk(KERN_DEBUG " In hamachi_rx(), entry %d status %4.4x.\n", + entry, hmp->rx_ring[entry].status_n_length); + } + + /* If EOP is set on the next entry, it's a new packet. Send it up. */ + while ( ! (hmp->rx_head_desc->status_n_length & cpu_to_le32(DescOwn))) { + struct hamachi_desc *desc = hmp->rx_head_desc; + u32 desc_status = le32_to_cpu(desc->status_n_length); + u16 data_size = desc_status; /* Implicit truncate */ + u8 *buf_addr = le32desc_to_virt(desc->addr); + s32 frame_status = + le32_to_cpu(get_unaligned((s32*)&(buf_addr[data_size - 12]))); + + if (hamachi_debug > 4) + printk(KERN_DEBUG " hamachi_rx() status was %8.8x.\n", + frame_status); + if (--boguscnt < 0) + break; + if ( ! (desc_status & DescEndPacket)) { + printk(KERN_WARNING "%s: Oversized Ethernet frame spanned " + "multiple buffers, entry %#x length %d status %4.4x!\n", + dev->name, hmp->cur_rx, data_size, desc_status); + printk(KERN_WARNING "%s: Oversized Ethernet frame %p vs %p.\n", + dev->name, desc, &hmp->rx_ring[hmp->cur_rx % RX_RING_SIZE]); + printk(KERN_WARNING "%s: Oversized Ethernet frame -- next status %x/%x last status %x.\n", + dev->name, + hmp->rx_ring[(hmp->cur_rx+1) % RX_RING_SIZE].status_n_length & 0xffff0000, + hmp->rx_ring[(hmp->cur_rx+1) % RX_RING_SIZE].status_n_length & 0x0000ffff, + hmp->rx_ring[(hmp->cur_rx-1) % RX_RING_SIZE].status_n_length); + hmp->stats.rx_length_errors++; + } /* else Omit for prototype errata??? */ + if (frame_status & 0x00380000) { + /* There was an error. */ + if (hamachi_debug > 2) + printk(KERN_DEBUG " hamachi_rx() Rx error was %8.8x.\n", + frame_status); + hmp->stats.rx_errors++; + if (frame_status & 0x00600000) hmp->stats.rx_length_errors++; + if (frame_status & 0x00080000) hmp->stats.rx_frame_errors++; + if (frame_status & 0x00100000) hmp->stats.rx_crc_errors++; + if (frame_status < 0) hmp->stats.rx_dropped++; + } else { + struct sk_buff *skb; + /* Omit CRC */ + u16 pkt_len = (frame_status & 0x07ff) - 4; +#ifdef RX_CHECKSUM + u32 pfck = *(u32 *) &buf_addr[data_size - 8]; +#endif + + +#ifndef final_version + if (hamachi_debug > 4) + printk(KERN_DEBUG " hamachi_rx() normal Rx pkt length %d" + " of %d, bogus_cnt %d.\n", + pkt_len, data_size, boguscnt); + if (hamachi_debug > 5) + printk(KERN_DEBUG"%s: rx status %8.8x %8.8x %8.8x %8.8x %8.8x.\n", + dev->name, + *(s32*)&(buf_addr[data_size - 20]), + *(s32*)&(buf_addr[data_size - 16]), + *(s32*)&(buf_addr[data_size - 12]), + *(s32*)&(buf_addr[data_size - 8]), + *(s32*)&(buf_addr[data_size - 4])); +#endif + /* Check if the packet is long enough to accept without copying + to a minimally-sized skbuff. */ + if (pkt_len < rx_copybreak + && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { +#ifdef RX_CHECKSUM + printk(KERN_ERR "%s: rx_copybreak non-zero " + "not good with RX_CHECKSUM\n", dev->name); +#endif + skb->dev = dev; + skb_reserve(skb, 2); /* 16 byte align the IP header */ + /* Call copy + cksum if available. */ +#if 1 || USE_IP_COPYSUM + eth_copy_and_sum(skb, bus_to_virt(desc->addr), pkt_len, 0); + skb_put(skb, pkt_len); +#else + memcpy(skb_put(skb, pkt_len), bus_to_virt(desc->addr),pkt_len); +#endif + } else { + char *temp = skb_put(skb = hmp->rx_skbuff[entry], pkt_len); + hmp->rx_skbuff[entry] = NULL; +#ifndef final_version /* Remove after testing. */ + if (bus_to_virt(desc->addr) != temp) + printk(KERN_ERR "%s: Internal fault: The skbuff addresses " + "do not match in hamachi_rx: %p vs. %p / %p.\n", + dev->name, bus_to_virt(desc->addr), + skb->head, temp); +#else + (void) temp; +#endif + } +#ifdef TX_CHECKSUM + /* account for extra TX hard_header bytes */ + skb->protocol = hamachi_eth_type_trans(skb, dev); +#else + skb->protocol = eth_type_trans(skb, dev); +#endif + + +#ifdef RX_CHECKSUM + /* TCP or UDP on ipv4, DIX encoding */ + if (pfck>>24 == 0x91 || pfck>>24 == 0x51) { + struct iphdr *ih = (struct iphdr *) skb->data; + /* Check that IP packet is at least 46 bytes, otherwise, + * there may be pad bytes included in the hardware checksum. + * This wouldn't happen if everyone padded with 0. + */ + if (ntohs(ih->tot_len) >= 46){ + /* don't worry about frags */ + if (!(ih->frag_off & __constant_htons(IP_MF|IP_OFFSET))) { + u32 inv = *(u32 *) &buf_addr[data_size - 16]; + u32 *p = (u32 *) &buf_addr[data_size - 20]; + register u32 crc, p_r, p_r1; + + if (inv & 4) { + inv &= ~4; + --p; + } + p_r = *p; + p_r1 = *(p-1); + switch (inv) { + case 0: + crc = (p_r & 0xffff) + (p_r >> 16); + break; + case 1: + crc = (p_r >> 16) + (p_r & 0xffff) + + (p_r1 >> 16 & 0xff00); + break; + case 2: + crc = p_r + (p_r1 >> 16); + break; + case 3: + crc = p_r + (p_r1 & 0xff00) + (p_r1 >> 16); + break; + default: /*NOTREACHED*/ crc = 0; + } + if (crc & 0xffff0000) { + crc &= 0xffff; + ++crc; + } + /* tcp/udp will add in pseudo */ + skb->csum = ntohs(pfck & 0xffff); + if (skb->csum > crc) + skb->csum -= crc; + else + skb->csum += (~crc & 0xffff); + /* + * could do the pseudo myself and return + * CHECKSUM_UNNECESSARY + */ + skb->ip_summed = CHECKSUM_HW; + } + } + } +#endif /* RX_CHECKSUM */ + + netif_rx(skb); + dev->last_rx = jiffies; + hmp->stats.rx_packets++; + } + entry = (++hmp->cur_rx) % RX_RING_SIZE; + hmp->rx_head_desc = &hmp->rx_ring[entry]; + } + + /* Refill the Rx ring buffers. */ + for (; hmp->cur_rx - hmp->dirty_rx > 0; hmp->dirty_rx++) { + struct sk_buff *skb; + entry = hmp->dirty_rx % RX_RING_SIZE; + if (hmp->rx_skbuff[entry] == NULL) { + skb = dev_alloc_skb(hmp->rx_buf_sz); + hmp->rx_skbuff[entry] = skb; + if (skb == NULL) + break; /* Better luck next round. */ + skb->dev = dev; /* Mark as being used by this device. */ + skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ + hmp->rx_ring[entry].addr = virt_to_desc(skb->tail); + } + hmp->rx_ring[entry].status_n_length = cpu_to_le32(hmp->rx_buf_sz); + if (entry >= RX_RING_SIZE-1) + hmp->rx_ring[entry].status_n_length |= + cpu_to_le32(DescOwn | DescEndPacket | DescEndRing | DescIntr); + else + hmp->rx_ring[entry].status_n_length |= + cpu_to_le32(DescOwn | DescEndPacket | DescIntr); + } + + /* Restart Rx engine if stopped. */ + /* If we don't need to check status, don't. -KDU */ + if (readw(dev->base_addr + RxStatus) & 0x0002) + writew(0x0001, dev->base_addr + RxCmd); + + return 0; +} + +/* This is more properly named "uncommon interrupt events", as it covers more + than just errors. */ +static void hamachi_error(struct net_device *dev, int intr_status) +{ + long ioaddr = dev->base_addr; + struct hamachi_private *hmp = (struct hamachi_private *)dev->priv; + + if (intr_status & (LinkChange|NegotiationChange)) { + if (hamachi_debug > 1) + printk(KERN_INFO "%s: Link changed: AutoNegotiation Ctrl" + " %4.4x, Status %4.4x %4.4x Intr status %4.4x.\n", + dev->name, readw(ioaddr + 0x0E0), readw(ioaddr + 0x0E2), + readw(ioaddr + ANLinkPartnerAbility), + readl(ioaddr + IntrStatus)); + if (readw(ioaddr + ANStatus) & 0x20) + writeb(0x01, ioaddr + LEDCtrl); + else + writeb(0x03, ioaddr + LEDCtrl); + } + if (intr_status & StatsMax) { + hamachi_get_stats(dev); + /* Read the overflow bits to clear. */ + readl(ioaddr + 0x370); + readl(ioaddr + 0x3F0); + } + if ((intr_status & ~(LinkChange|StatsMax|NegotiationChange|IntrRxDone|IntrTxDone)) + && hamachi_debug) + printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n", + dev->name, intr_status); + /* Hmmmmm, it's not clear how to recover from PCI faults. */ + if (intr_status & (IntrTxPCIErr | IntrTxPCIFault)) + hmp->stats.tx_fifo_errors++; + if (intr_status & (IntrRxPCIErr | IntrRxPCIFault)) + hmp->stats.rx_fifo_errors++; +} + +static int hamachi_close(struct net_device *dev) +{ + long ioaddr = dev->base_addr; + struct hamachi_private *hmp = (struct hamachi_private *)dev->priv; + int i; + + netif_stop_queue(dev); + + if (hamachi_debug > 1) { + printk(KERN_DEBUG "%s: Shutting down ethercard, status was Tx %4.4x Rx %4.4x Int %2.2x.\n", + dev->name, readw(ioaddr + TxStatus), + readw(ioaddr + RxStatus), readl(ioaddr + IntrStatus)); + printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d, Rx %d / %d.\n", + dev->name, hmp->cur_tx, hmp->dirty_tx, hmp->cur_rx, hmp->dirty_rx); + } + + /* Disable interrupts by clearing the interrupt mask. */ + writel(0x0000, ioaddr + InterruptEnable); + + /* Stop the chip's Tx and Rx processes. */ + writel(2, ioaddr + RxCmd); + writew(2, ioaddr + TxCmd); + +#ifdef __i386__ + if (hamachi_debug > 2) { + printk("\n"KERN_DEBUG" Tx ring at %8.8x:\n", + (int)virt_to_bus(hmp->tx_ring)); + for (i = 0; i < TX_RING_SIZE; i++) + printk(" %c #%d desc. %8.8x %8.8x.\n", + readl(ioaddr + TxCurPtr) == (long)&hmp->tx_ring[i] ? '>' : ' ', + i, hmp->tx_ring[i].status_n_length, hmp->tx_ring[i].addr); + printk("\n"KERN_DEBUG " Rx ring %8.8x:\n", + (int)virt_to_bus(hmp->rx_ring)); + for (i = 0; i < RX_RING_SIZE; i++) { + printk(KERN_DEBUG " %c #%d desc. %4.4x %8.8x\n", + readl(ioaddr + RxCurPtr) == (long)&hmp->rx_ring[i] ? '>' : ' ', + i, hmp->rx_ring[i].status_n_length, hmp->rx_ring[i].addr); + if (hamachi_debug > 6) { + if (*(u8*)bus_to_virt(hmp->rx_ring[i].addr) != 0x69) { + int j; + for (j = 0; j < 0x50; j++) + printk(" %4.4x",((u16*)le32desc_to_virt(hmp->rx_ring[i].addr))[j]); + printk("\n"); + } + } + } + } +#endif /* __i386__ debugging only */ + + free_irq(dev->irq, dev); + + del_timer_sync(&hmp->timer); + + /* Free all the skbuffs in the Rx queue. */ + for (i = 0; i < RX_RING_SIZE; i++) { + hmp->rx_ring[i].status_n_length = 0; + hmp->rx_ring[i].addr = 0xBADF00D0; /* An invalid address. */ + if (hmp->rx_skbuff[i]) { + dev_kfree_skb(hmp->rx_skbuff[i]); + } + hmp->rx_skbuff[i] = 0; + } + for (i = 0; i < TX_RING_SIZE; i++) { + if (hmp->tx_skbuff[i]) + dev_kfree_skb(hmp->tx_skbuff[i]); + hmp->tx_skbuff[i] = 0; + } + + writeb(0x00, ioaddr + LEDCtrl); + + MOD_DEC_USE_COUNT; + + return 0; +} + +static struct net_device_stats *hamachi_get_stats(struct net_device *dev) +{ + long ioaddr = dev->base_addr; + struct hamachi_private *hmp = (struct hamachi_private *)dev->priv; + + /* We should lock this segment of code for SMP eventually, although + the vulnerability window is very small and statistics are + non-critical. */ + /* Ok, what goes here? This appears to be stuck at 21 packets + according to ifconfig. It does get incremented in hamachi_tx(), + so I think I'll comment it out here and see if better things + happen. + */ + /* hmp->stats.tx_packets = readl(ioaddr + 0x000); */ + + hmp->stats.rx_bytes = readl(ioaddr + 0x330); /* Total Uni+Brd+Multi */ + hmp->stats.tx_bytes = readl(ioaddr + 0x3B0); /* Total Uni+Brd+Multi */ + hmp->stats.multicast = readl(ioaddr + 0x320); /* Multicast Rx */ + + hmp->stats.rx_length_errors = readl(ioaddr + 0x368); /* Over+Undersized */ + hmp->stats.rx_over_errors = readl(ioaddr + 0x35C); /* Jabber */ + hmp->stats.rx_crc_errors = readl(ioaddr + 0x360); /* Jabber */ + hmp->stats.rx_frame_errors = readl(ioaddr + 0x364); /* Symbol Errs */ + hmp->stats.rx_missed_errors = readl(ioaddr + 0x36C); /* Dropped */ + + return &hmp->stats; +} + +static void set_rx_mode(struct net_device *dev) +{ + long ioaddr = dev->base_addr; + + if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ + /* Unconditionally log net taps. */ + printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name); + writew(0x000F, ioaddr + AddrMode); + } else if ((dev->mc_count > 63) || (dev->flags & IFF_ALLMULTI)) { + /* Too many to match, or accept all multicasts. */ + writew(0x000B, ioaddr + AddrMode); + } else if (dev->mc_count > 0) { /* Must use the CAM filter. */ + struct dev_mc_list *mclist; + int i; + for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + i++, mclist = mclist->next) { + writel(*(u32*)(mclist->dmi_addr), ioaddr + 0x100 + i*8); + writel(0x20000 | (*(u16*)&mclist->dmi_addr[4]), + ioaddr + 0x104 + i*8); + } + /* Clear remaining entries. */ + for (; i < 64; i++) + writel(0, ioaddr + 0x104 + i*8); + writew(0x0003, ioaddr + AddrMode); + } else { /* Normal, unicast/broadcast-only mode. */ + writew(0x0001, ioaddr + AddrMode); + } +} + +#ifdef HAVE_PRIVATE_IOCTL +static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + long ioaddr = dev->base_addr; + u16 *data = (u16 *)&rq->ifr_data; + + switch(cmd) { + case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ + data[0] = ((struct hamachi_private *)dev->priv)->phys[0] & 0x1f; + /* Fall Through */ + case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ + data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f); + return 0; + case SIOCDEVPRIVATE+2: /* Write the specified MII register */ + /* TODO: Check the sequencing of this. Might need to stop and + * restart Rx and Tx engines. -KDU + */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]); + return 0; + case SIOCDEVPRIVATE+3: { /* set rx,tx intr params */ + u32 *d = (u32 *)&rq->ifr_data; + /* Should add this check here or an ordinary user can do nasty + * things. -KDU + * + * TODO: Shut down the Rx and Tx engines while doing this. + */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + writel(d[0], dev->base_addr + TxIntrCtrl); + writel(d[1], dev->base_addr + RxIntrCtrl); + printk(KERN_NOTICE "%s: tx %08x, rx %08x intr\n", dev->name, + (u32) readl(dev->base_addr + TxIntrCtrl), + (u32) readl(dev->base_addr + RxIntrCtrl)); + return 0; + } + default: + return -EOPNOTSUPP; + } +} +#endif /* HAVE_PRIVATE_IOCTL */ + + +static void __exit hamachi_remove_one (struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + + /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ + if (dev) { + unregister_netdev(dev); + iounmap((char *)dev->base_addr); + kfree(dev); + pci_set_drvdata(pdev, NULL); + } +} + +static struct pci_device_id hamachi_pci_tbl[] __initdata = { + { 0x1318, 0x0911, PCI_ANY_ID, PCI_ANY_ID, }, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, hamachi_pci_tbl); + +static struct pci_driver hamachi_driver = { + name: "hamachi", + id_table: hamachi_pci_tbl, + probe: hamachi_init_one, + remove: hamachi_remove_one, +}; + +static int __init hamachi_init (void) +{ + if (pci_register_driver(&hamachi_driver) > 0) + return 0; + pci_unregister_driver(&hamachi_driver); + return -ENODEV; +} + +static void __exit hamachi_exit (void) +{ + pci_unregister_driver(&hamachi_driver); +} + + +module_init(hamachi_init); +module_exit(hamachi_exit); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/hamradio/pi2.c linux/drivers/net/hamradio/pi2.c --- v2.4.0-test8/linux/drivers/net/hamradio/pi2.c Mon Jun 19 13:30:58 2000 +++ linux/drivers/net/hamradio/pi2.c Fri Sep 8 17:56:49 2000 @@ -1182,7 +1182,7 @@ } -int __init pi_init(void) +int __init pi2_init(void) { int *port; int ioaddr = 0; @@ -1658,7 +1658,7 @@ int init_module(void) { - return pi_init(); + return pi2_init(); } void cleanup_module(void) diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/hamradio/pt.c linux/drivers/net/hamradio/pt.c --- v2.4.0-test8/linux/drivers/net/hamradio/pt.c Mon Jun 19 13:30:58 2000 +++ linux/drivers/net/hamradio/pt.c Fri Sep 8 17:56:49 2000 @@ -474,7 +474,7 @@ } /* chipset_init() */ -int __init pt_init(void) +int __init ptwin_init(void) { int *port; int ioaddr = 0; @@ -531,7 +531,7 @@ pt0b.irq = pt0a.irq; /* IRQ is shared */ return 0; -} /* pt_init() */ +} /* ptwin_init() */ /* * Probe for PT card. Also initialises the timers @@ -1758,7 +1758,7 @@ int init_module(void) { - return pt_init(); + return ptwin_init(); } void cleanup_module(void) diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/ioc3-eth.c linux/drivers/net/ioc3-eth.c --- v2.4.0-test8/linux/drivers/net/ioc3-eth.c Thu Jul 27 18:36:54 2000 +++ linux/drivers/net/ioc3-eth.c Mon Sep 25 14:55:04 2000 @@ -64,7 +64,7 @@ #include #include #include -#include +#include #include #include diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/irda/toshoboe.c linux/drivers/net/irda/toshoboe.c --- v2.4.0-test8/linux/drivers/net/irda/toshoboe.c Tue Mar 21 11:17:28 2000 +++ linux/drivers/net/irda/toshoboe.c Sun Sep 17 09:45:07 2000 @@ -900,7 +900,6 @@ static void toshoboe_wakeup (struct toshoboe_cb *self) { - struct net_device *dev = self->netdev; unsigned long flags; if (!self->stopped) diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/lne390.c linux/drivers/net/lne390.c --- v2.4.0-test8/linux/drivers/net/lne390.c Mon Jun 19 13:30:58 2000 +++ linux/drivers/net/lne390.c Sun Sep 17 09:49:42 2000 @@ -26,10 +26,13 @@ You can try if you want more info, as I've never even seen one of these cards. :) + Arnaldo Carvalho de Melo - 2000/09/01 + - get rid of check_region + - no need to check if dev == NULL in lne390_probe1 */ static const char *version = - "lne390.c: Driver revision v0.99, 12/05/98\n"; + "lne390.c: Driver revision v0.99.1, 01/09/2000\n"; #include #include @@ -103,9 +106,16 @@ int __init lne390_probe(struct net_device *dev) { unsigned short ioaddr = dev->base_addr; + int ret; - if (ioaddr > 0x1ff) /* Check a single specified location. */ - return lne390_probe1(dev, ioaddr); + if (ioaddr > 0x1ff) { /* Check a single specified location. */ + if (!request_region(ioaddr, LNE390_IO_EXTENT, "lne390")) + return -EBUSY; + ret = lne390_probe1(dev, ioaddr); + if (ret) + release_region(ioaddr, LNE390_IO_EXTENT); + return ret; + } else if (ioaddr > 0) /* Don't probe at all. */ return -ENXIO; @@ -118,10 +128,11 @@ /* EISA spec allows for up to 16 slots, but 8 is typical. */ for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) { - if (check_region(ioaddr , LNE390_IO_EXTENT)) + if (!request_region(ioaddr, LNE390_IO_EXTENT, "lne390")) continue; if (lne390_probe1(dev, ioaddr) == 0) return 0; + release_region(ioaddr, LNE390_IO_EXTENT); } return -ENODEV; @@ -129,7 +140,7 @@ int __init lne390_probe1(struct net_device *dev, int ioaddr) { - int i, revision; + int i, revision, ret; unsigned long eisa_id; if (inb_p(ioaddr + LNE390_ID_PORT) == 0xff) return -ENODEV; @@ -161,13 +172,6 @@ return -ENODEV; } #endif - - /* We should have a "dev" from Space.c or the static module table. */ - if (dev == NULL) { - printk("lne390.c: Passed a NULL device.\n"); - dev = init_etherdev(0, 0); - } - /* Allocate dev->priv and fill in 8390 specific dev fields. */ if (ethdev_init(dev)) { printk ("lne390.c: unable to allocate memory for dev->priv!\n"); @@ -225,20 +229,16 @@ printk(KERN_CRIT "lne390.c: Use EISA SCU to set card memory below 1MB,\n"); printk(KERN_CRIT "lne390.c: or to an address above 0x%lx.\n", virt_to_bus(high_memory)); printk(KERN_CRIT "lne390.c: Driver NOT installed.\n"); - free_irq(dev->irq, dev); - kfree(dev->priv); - dev->priv = NULL; - return -EINVAL; + ret = -EINVAL; + goto cleanup; } dev->mem_start = (unsigned long)ioremap(dev->mem_start, LNE390_STOP_PG*0x100); if (dev->mem_start == 0) { printk(KERN_ERR "lne390.c: Unable to remap card memory above 1MB !!\n"); printk(KERN_ERR "lne390.c: Try using EISA SCU to set memory below 1MB.\n"); printk(KERN_ERR "lne390.c: Driver NOT installed.\n"); - free_irq(dev->irq, dev); - kfree(dev->priv); - dev->priv = NULL; - return -EAGAIN; + ret = -EAGAIN; + goto cleanup; } ei_status.reg0 = 1; /* Use as remap flag */ printk("lne390.c: remapped %dkB card memory to virtual address %#lx\n", @@ -251,7 +251,6 @@ /* The 8390 offset is zero for the LNE390 */ dev->base_addr = ioaddr; - request_region(dev->base_addr, LNE390_IO_EXTENT, "lne390"); ei_status.name = "LNE390"; ei_status.tx_start_page = LNE390_START_PG; @@ -271,6 +270,11 @@ dev->stop = &lne390_close; NS8390_init(dev, 0); return 0; +cleanup: + free_irq(dev->irq, dev); + kfree(dev->priv); + dev->priv = NULL; + return ret; } /* diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/ne2.c linux/drivers/net/ne2.c --- v2.4.0-test8/linux/drivers/net/ne2.c Mon Jun 19 13:30:58 2000 +++ linux/drivers/net/ne2.c Tue Sep 19 08:01:34 2000 @@ -110,16 +110,16 @@ #define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */ /* From the .ADF file: */ -static unsigned int addresses[7]= +static unsigned int addresses[7] __initdata = {0x1000, 0x2020, 0x8020, 0xa0a0, 0xb0b0, 0xc0c0, 0xc3d0}; -static int irqs[4] = {3, 4, 5, 9}; +static int irqs[4] __initdata = {3, 4, 5, 9}; struct ne2_adapters_t { unsigned int id; char *name; }; -const struct ne2_adapters_t ne2_adapters[] = { +static struct ne2_adapters_t ne2_adapters[] __initdata = { { 0x6354, "Arco Ethernet Adapter AE/2" }, { 0x70DE, "Compex ENET-16 MC/P" }, { 0x7154, "Novell Ethernet Adapter NE/2" }, diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/ne2k-pci.c linux/drivers/net/ne2k-pci.c --- v2.4.0-test8/linux/drivers/net/ne2k-pci.c Mon Jun 19 13:30:58 2000 +++ linux/drivers/net/ne2k-pci.c Mon Sep 18 14:57:01 2000 @@ -286,7 +286,7 @@ /* Set up the rest of the parameters. */ dev->irq = irq; dev->base_addr = ioaddr; - pdev->driver_data = dev; + pci_set_drvdata(pdev, dev); /* Allocate dev->priv and fill in 8390 specific dev fields. */ if (ethdev_init(dev)) { @@ -535,16 +535,17 @@ static void __devexit ne2k_pci_remove_one (struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata(pdev); if (!dev) { printk (KERN_ERR "bug! ne2k_pci_remove_one called w/o net_device\n"); return; } - unregister_netdev (dev); - release_region (dev->base_addr, NE_IO_EXTENT); - kfree (dev); + unregister_netdev(dev); + release_region(dev->base_addr, NE_IO_EXTENT); + kfree(dev); + pci_set_drvdata(pdev, NULL); } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/net_init.c linux/drivers/net/net_init.c --- v2.4.0-test8/linux/drivers/net/net_init.c Fri Jul 14 14:46:30 2000 +++ linux/drivers/net/net_init.c Tue Sep 19 08:31:43 2000 @@ -96,7 +96,8 @@ * setup. */ -static struct net_device *init_netdev(struct net_device *dev, int sizeof_priv, char *mask, void (*setup)(struct net_device *)) +static struct net_device *init_netdev(struct net_device *dev, int sizeof_priv, + char *mask, void (*setup)(struct net_device *)) { int new_device = 0; @@ -117,16 +118,14 @@ if (dev->name[0] == '\0' || dev->name[0] == ' ') { strcpy(dev->name, mask); - if (!netdev_boot_setup_check(dev)) { - if (dev_alloc_name(dev, mask)<0) { - if (new_device) - kfree(dev); - return NULL; - } + if (dev_alloc_name(dev, mask)<0) { + if (new_device) + kfree(dev); + return NULL; } - } else { - netdev_boot_setup_check(dev); } + + netdev_boot_setup_check(dev); /* * Configure via the caller provided setup function then @@ -198,7 +197,7 @@ return(0); } -#endif +#endif /* CONFIG_FDDI */ #ifdef CONFIG_HIPPI @@ -256,7 +255,7 @@ return 0; } -#endif +#endif /* CONFIG_HIPPI */ void ether_setup(struct net_device *dev) { @@ -314,7 +313,7 @@ return; } -#endif +#endif /* CONFIG_FDDI */ #ifdef CONFIG_HIPPI void hippi_setup(struct net_device *dev) @@ -350,7 +349,7 @@ dev_init_buffers(dev); } -#endif +#endif /* CONFIG_HIPPI */ #if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE) @@ -389,7 +388,7 @@ dev_init_buffers(dev); } -#endif +#endif /* CONFIG_ATALK || CONFIG_ATALK_MODULE */ int ether_config(struct net_device *dev, struct ifmap *map) { @@ -506,7 +505,7 @@ unregister_netdevice(dev); rtnl_unlock(); } -#endif +#endif /* CONFIG_TR */ #ifdef CONFIG_NET_FC @@ -555,10 +554,3 @@ #endif /* CONFIG_NET_FC */ -/* - * Local variables: - * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c net_init.c" - * version-control: t - * kept-new-versions: 5 - * End: - */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/pcmcia/xircom_tulip_cb.c linux/drivers/net/pcmcia/xircom_tulip_cb.c --- v2.4.0-test8/linux/drivers/net/pcmcia/xircom_tulip_cb.c Mon Aug 21 07:54:43 2000 +++ linux/drivers/net/pcmcia/xircom_tulip_cb.c Sun Sep 17 09:41:29 2000 @@ -3034,10 +3034,7 @@ if (entry == TX_RING_SIZE-1) tx_flags |= DESC_RING_WRAP; /* Wrap ring. */ tp->tx_ring[entry].length = tx_flags; - if(tp->chip_id == X3201_3) - tp->tx_ring[entry].buffer1 = (virt_to_bus(tp->setup_frame) + 4); - else - tp->tx_ring[entry].buffer1 = virt_to_bus(tp->setup_frame); + tp->tx_ring[entry].buffer1 = virt_to_bus(tp->setup_frame); tp->tx_ring[entry].status = DescOwned; if (tp->cur_tx - tp->dirty_tx >= TX_RING_SIZE - 2) { tp->tx_full = 1; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/pppox.c linux/drivers/net/pppox.c --- v2.4.0-test8/linux/drivers/net/pppox.c Fri May 12 11:32:08 2000 +++ linux/drivers/net/pppox.c Fri Sep 22 14:21:16 2000 @@ -17,7 +17,6 @@ * */ -#include #include #include @@ -141,22 +140,22 @@ pppox_create }; +extern int pppoe_init (void); + #ifdef MODULE int init_module(void) #else -void __init pppox_proto_init(struct net_proto *pro) +int __init pppox_proto_init(struct net_proto *pro) #endif { int err = 0; err = sock_register(&pppox_proto_family); - if (err == 0) + if (err == 0) { printk(KERN_INFO "Registered PPPoX v0.5\n"); - -#ifdef CONFIG_PPPOE - pppoe_init(); -#endif + pppoe_init(); + } return err; } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/rrunner.c linux/drivers/net/rrunner.c --- v2.4.0-test8/linux/drivers/net/rrunner.c Mon Jun 19 13:42:38 2000 +++ linux/drivers/net/rrunner.c Mon Oct 2 14:22:40 2000 @@ -102,7 +102,7 @@ * stack will need to know about I/O vectors or something similar. */ -static const char __initdata *version = "rrunner.c: v0.22 03/01/2000 Jes Sorensen (Jes.Sorensen@cern.ch)\n"; +static char version[] __initdata = "rrunner.c: v0.22 03/01/2000 Jes Sorensen (Jes.Sorensen@cern.ch)\n"; static struct net_device *root_dev = NULL; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/rtl8129.c linux/drivers/net/rtl8129.c --- v2.4.0-test8/linux/drivers/net/rtl8129.c Tue Jul 11 11:12:24 2000 +++ linux/drivers/net/rtl8129.c Sun Sep 17 09:41:29 2000 @@ -406,6 +406,8 @@ printk(KERN_INFO "%s", version); dev = init_etherdev(NULL, 0); + if (dev == NULL) + goto out; printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", dev->name, pci_tbl[chip_idx].name, ioaddr, irq); @@ -427,13 +429,17 @@ printk("%2.2x.\n", dev->dev_addr[i]); /* We do a request_region() to register /proc/ioports info. */ - request_region(ioaddr, pci_tbl[chip_idx].io_size, dev->name); + if (!request_region(ioaddr, pci_tbl[chip_idx].io_size, dev->name)) + goto out_free_dev; dev->base_addr = ioaddr; dev->irq = irq; /* Some data structures must be quadword aligned. */ tp = kmalloc(sizeof(*tp), GFP_KERNEL | GFP_DMA); + if (tp == NULL) + goto out_release_region; + memset(tp, 0, sizeof(*tp)); dev->priv = tp; @@ -499,8 +505,15 @@ dev->get_stats = &rtl8129_get_stats; dev->set_multicast_list = &set_rx_mode; dev->do_ioctl = &mii_ioctl; - return dev; + +out_release_region: + release_region(ioaddr, pci_tbl[chip_idx].io_size); +out_free_dev: + unregister_netdev(dev); + kfree(dev); +out: + return NULL; } /* Serial EEPROM section. */ @@ -660,17 +673,18 @@ { struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; long ioaddr = dev->base_addr; - int i; + int i, retval; + + MOD_INC_USE_COUNT; /* Soft reset the chip. */ outb(CmdReset, ioaddr + ChipCmd); - if (request_irq(dev->irq, &rtl8129_interrupt, SA_SHIRQ, dev->name, dev)) { - return -EAGAIN; + if ((retval = request_irq(dev->irq, &rtl8129_interrupt, SA_SHIRQ, dev->name, dev))) { + MOD_DEC_USE_COUNT; + return retval; } - MOD_INC_USE_COUNT; - tp->tx_bufs = pci_alloc_consistent(tp->pdev, TX_BUF_SIZE * NUM_TX_DESC, &tp->tx_bufs_dma); @@ -690,6 +704,7 @@ if (rtl8129_debug > 0) printk(KERN_ERR "%s: Couldn't allocate a %d byte receive ring.\n", dev->name, RX_BUF_LEN); + MOD_DEC_USE_COUNT; return -ENOMEM; } rtl8129_init_ring(dev); @@ -1226,8 +1241,9 @@ /* Malloc up new buffer, compatible with net-2e. */ /* Omit the four octet CRC from the length. */ struct sk_buff *skb; + int pkt_size = rx_size - 4; - skb = dev_alloc_skb(rx_size + 2); + skb = dev_alloc_skb(pkt_size + 2); if (skb == NULL) { printk(KERN_WARNING"%s: Memory squeeze, deferring packet.\n", dev->name); @@ -1238,12 +1254,12 @@ } skb->dev = dev; skb_reserve(skb, 2); /* 16 byte align the IP fields. */ - if (ring_offset+rx_size+4 > RX_BUF_LEN) { + if (ring_offset+rx_size > RX_BUF_LEN) { int semi_count = RX_BUF_LEN - ring_offset - 4; memcpy(skb_put(skb, semi_count), &rx_ring[ring_offset + 4], semi_count); - memcpy(skb_put(skb, rx_size-semi_count), rx_ring, - rx_size-semi_count); + memcpy(skb_put(skb, pkt_size-semi_count), rx_ring, + pkt_size-semi_count); if (rtl8129_debug > 4) { int i; printk(KERN_DEBUG"%s: Frame wrap @%d", @@ -1256,17 +1272,17 @@ } else { #if 1 /* USE_IP_COPYSUM */ eth_copy_and_sum(skb, &rx_ring[ring_offset + 4], - rx_size, 0); - skb_put(skb, rx_size); + pkt_size, 0); + skb_put(skb, pkt_size); #else - memcpy(skb_put(skb, rx_size), &rx_ring[ring_offset + 4], - rx_size); + memcpy(skb_put(skb, pkt_size), &rx_ring[ring_offset + 4], + pkt_size); #endif } skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); #if LINUX_VERSION_CODE > 0x20119 - tp->stats.rx_bytes += rx_size; + tp->stats.rx_bytes += pkt_size; #endif tp->stats.rx_packets++; } @@ -1292,6 +1308,8 @@ netif_stop_queue(dev); + del_timer_sync(&tp->timer); + if (rtl8129_debug > 1) printk(KERN_DEBUG"%s: Shutting down ethercard, status was 0x%4.4x.\n", dev->name, inw(ioaddr + IntrStatus)); @@ -1305,8 +1323,6 @@ /* Update the error counts. */ tp->stats.rx_missed_errors += inl(ioaddr + RxMissed); outl(0, ioaddr + RxMissed); - - del_timer(&tp->timer); free_irq(dev->irq, dev); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/setup.c linux/drivers/net/setup.c --- v2.4.0-test8/linux/drivers/net/setup.c Tue May 23 08:21:51 2000 +++ linux/drivers/net/setup.c Fri Sep 22 14:21:16 2000 @@ -1,3 +1,4 @@ + /* * New style setup code for the network devices */ @@ -22,6 +23,7 @@ extern int awc4500_365_probe(void); extern int arcnet_init(void); extern int scc_enet_init(void); +extern int fec_enet_init(void); extern int dlci_setup(void); extern int lapbeth_init(void); extern int sdla_setup(void); @@ -75,6 +77,9 @@ #if defined(CONFIG_SCC_ENET) {scc_enet_init, 0}, #endif +#if defined(CONFIG_FEC_ENET) + {fec_enet_init, 0}, +#endif #if defined(CONFIG_COMX) {comx_init, 0}, #endif @@ -162,58 +167,8 @@ } -static void __init appletalk_device_init(void) -{ -#if defined(CONFIG_IPDDP) - extern int ipddp_init(struct net_device *dev); - static struct net_device dev_ipddp = { - "ipddp0" __PAD6, - 0, 0, 0, 0, - 0x0, 0, - 0, 0, 0, NULL, ipddp_init - }; - - dev_ipddp.init(&dev_ipddp); -#endif /* CONFIG_IPDDP */ -} - -static void special_device_init(void) +static void __init special_device_init(void) { -#ifdef CONFIG_DUMMY - { - extern int dummy_init(struct net_device *dev); - static struct net_device dummy_dev = { - "dummy" __PAD5, 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NULL, dummy_init, - }; - register_netdev(&dummy_dev); - } -#endif -#ifdef CONFIG_EQUALIZER - { - extern int eql_init(struct net_device *dev); - static struct net_device eql_dev = - { - "eql" __PAD3, /* Master device for IP traffic load balancing */ - 0x0, 0x0, 0x0, 0x0, /* recv end/start; mem end/start */ - 0, /* base I/O address */ - 0, /* IRQ */ - 0, 0, 0, /* flags */ - NULL, /* next device */ - eql_init /* set up the rest */ - }; - register_netdev(&eql_dev); - } -#endif -#ifdef CONFIG_APBIF - { - extern int bif_init(struct net_device *dev); - static struct net_device bif_dev = - { - "bif" __PAD3, 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NULL, bif_init - }; - register_netdev(&bif_dev); - } -#endif #ifdef CONFIG_NET_SB1000 { extern int sb1000_probe(struct net_device *dev); @@ -224,15 +179,6 @@ register_netdev(&sb1000_dev); } #endif -#ifdef CONFIG_BONDING - { - extern int bond_init(struct net_device *dev); - static struct net_device bond_dev = { - "bond" __PAD4, 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NULL, bond_init, - }; - register_netdev(&bond_dev); - } -#endif } /* @@ -245,8 +191,6 @@ network_probe(); /* Line disciplines */ network_ldisc_init(); - /* Appletalk */ - appletalk_device_init(); /* Special devices */ special_device_init(); /* That kicks off the legacy init functions */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/sis900.c linux/drivers/net/sis900.c --- v2.4.0-test8/linux/drivers/net/sis900.c Wed Aug 9 14:24:09 2000 +++ linux/drivers/net/sis900.c Tue Sep 19 08:31:27 2000 @@ -1,6 +1,6 @@ /* sis900.c: A SiS 900/7016 PCI Fast Ethernet driver for Linux. Copyright 1999 Silicon Integrated System Corporation - Revision: 1.07.01 Aug. 08 2000 + Revision: 1.07.04 Sep. 6 2000 Modified from the driver which is originally written by Donald Becker. @@ -18,7 +18,9 @@ preliminary Rev. 1.0 Jan. 18, 1998 http://www.sis.com.tw/support/databook.htm - Rev 1.07.01 Aug. 08 2000 Ollie Lho minor update fro SiS 630E and SiS 630E A1 + Rev 1.07.04 Sep. 6 2000 Lei-Chun Chang added ICS1893 PHY support + Rev 1.07.03 Aug. 24 2000 Lei-Chun Chang (lcchang@sis.com.tw) modified 630E eqaulizer workaroung rule + Rev 1.07.01 Aug. 08 2000 Ollie Lho minor update for SiS 630E and SiS 630E A1 Rev 1.07 Mar. 07 2000 Ollie Lho bug fix in Rx buffer ring Rev 1.06.04 Feb. 11 2000 Jeff Garzik softnet and init for kernel 2.4 Rev 1.06.03 Dec. 23 1999 Ollie Lho Third release @@ -54,7 +56,7 @@ #include "sis900.h" static const char *version = -"sis900.c: v1.07.01 08/08/2000\n"; +"sis900.c: v1.07.04 09/06/2000\n"; static int max_interrupt_work = 20; static int multicast_filter_limit = 128; @@ -88,6 +90,7 @@ static void sis900_read_mode(struct net_device *net_dev, int phy_addr, int *speed, int *duplex); static void amd79c901_read_mode(struct net_device *net_dev, int phy_addr, int *speed, int *duplex); +static void ics1893_read_mode(struct net_device *net_dev, int phy_addr, int *speed, int *duplex); static struct mii_chip_info { const char * name; @@ -99,6 +102,7 @@ {"SiS 7014 Physical Layer Solution", 0x0016, 0xf830,sis900_read_mode}, {"AMD 79C901 10BASE-T PHY", 0x0000, 0x35b9, amd79c901_read_mode}, {"AMD 79C901 HomePNA PHY", 0x0000, 0x35c8, amd79c901_read_mode}, + {"ICS 1893 Integrated PHYceiver" , 0x0015, 0xf441,ics1893_read_mode}, {0,}, }; @@ -166,6 +170,7 @@ static u16 sis900_compute_hashtable_index(u8 *addr); static void set_rx_mode(struct net_device *net_dev); static void sis900_reset(struct net_device *net_dev); +static void sis630e_set_eq(struct net_device *net_dev); /* walk through every ethernet PCI devices to see if some of them are matched with our card list*/ static int __init sis900_probe (struct pci_dev *pci_dev, const struct pci_device_id *pci_id) @@ -242,29 +247,6 @@ return 1; } -/* SiS630E A1, The Mac address is hardcoded in the RFCR register so it is actually not necessary to - probe the MAC address */ -static int sis630ea1_get_mac_addr(struct pci_dev * pci_dev, struct net_device *net_dev) -{ - long ioaddr = pci_resource_start(pci_dev, 0); - u32 reg; - int i; - - /* reload MAC address */ - reg = inl(ioaddr + cr); - outl(reg | RELOAD, ioaddr + cr); - - reg = inl(ioaddr + cr); - outl(reg & ~RELOAD, ioaddr + cr); - - for (i = 0; i < 3; i++) { - outl((u32)(0x00000004+i) << RFADDR_shift, ioaddr + rfcr); - ((u16 *)(net_dev->dev_addr))[i] = inl(ioaddr + rfdr); - } - - return 1; -} - static struct net_device * __init sis900_mac_probe (struct pci_dev * pci_dev, char * card_name) { struct sis900_private *sis_priv; @@ -278,10 +260,10 @@ return NULL; pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &revision); - if (revision == SIS630E_REV) + if (revision == SIS630E_REV || revision == SIS630EA1_REV) + ret = sis630e_get_mac_addr(pci_dev, net_dev); + else if (revision == SIS630S_REV) ret = sis630e_get_mac_addr(pci_dev, net_dev); - else if (revision == SIS630EA1_REV) - ret = sis630ea1_get_mac_addr(pci_dev, net_dev); else ret = sis900_get_mac_addr(pci_dev, net_dev); @@ -301,7 +283,7 @@ unregister_netdevice(net_dev); return NULL; } - + sis_priv = net_dev->priv; memset(sis_priv, 0, sizeof(struct sis900_private)); @@ -311,7 +293,7 @@ net_dev->irq = irq; sis_priv->pci_dev = pci_dev; spin_lock_init(&sis_priv->lock); - + /* probe for mii transciver */ if (sis900_mii_probe(net_dev) == 0) { unregister_netdev(net_dev); @@ -366,7 +348,7 @@ printk(KERN_INFO "%s: %s transceiver found at address %d.\n", net_dev->name, mii_chip_table[i].name, - phy_addr);; + phy_addr); if ((mii_phy = kmalloc(sizeof(struct mii_phy), GFP_KERNEL)) != NULL) { mii_phy->chip_info = mii_chip_table+i; mii_phy->phy_addr = phy_addr; @@ -559,12 +541,18 @@ { struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; long ioaddr = net_dev->base_addr; + u8 revision; MOD_INC_USE_COUNT; /* Soft reset the chip. */ sis900_reset(net_dev); + /* Equalizer workaroung Rule */ + pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision); + if (revision == SIS630E_REV || revision == SIS630EA1_REV) + sis630e_set_eq(net_dev); + if (request_irq(net_dev->irq, &sis900_interrupt, SA_SHIRQ, net_dev->name, net_dev)) { MOD_DEC_USE_COUNT; return -EAGAIN; @@ -700,6 +688,64 @@ printk(KERN_INFO "%s: RX descriptor register loaded with: %8.8x\n", net_dev->name, inl(ioaddr + rxdp)); } + +/* 630E equalizer workaroung rule(Cyrus Huang 08/15) + PHY register 14h(Test) + Bit 14: 0 -- Automatically dectect (default) + 1 -- Manually set Equalizer filter + Bit 13: 0 -- (Default) + 1 -- Speed up convergence of equalizer setting + Bit 9 : 0 -- (Default) + 1 -- Disable Baseline Wander + Bit 3~7 -- Equalizer filter setting + + Link ON: Set Bit 9, 13 to 1, Bit 14 to 0 + Then calculate equalizer value + Then set equalizer value, and set Bit 14 to 1, Bit 9 to 0 + Link Off:Set Bit 13 to 1, Bit 14 to 0 + + Calculate Equalizer value: + When Link is ON and Bit 14 is 0, SIS900PHY will auto-dectect proper equalizer value. + When the equalizer is stable, this value is not a fixed value. It will be within + a small range(eg. 7~9). Then we get a minimum and a maximum value(eg. min=7, max=9) + 0 <= max <= 4 --> set equalizer to max + 5 <= max <= 14 --> set equalizer to max+1 or + set equalizer to max+2 if max == min + max >= 15 --> set equalizer to max+5 or + set equalizer to max+6 if max == min +*/ +static void sis630e_set_eq(struct net_device *net_dev) +{ + struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; + u16 reg14h, eq_value, max_value=0, min_value=0; + int i, maxcount=10; + + if (sis_priv->LinkOn == TRUE) { + reg14h=mdio_read(net_dev, sis_priv->cur_phy, MII_RESV); + mdio_write(net_dev, sis_priv->cur_phy, MII_RESV, (0x2200 | reg14h) & 0xBFFF); + for (i=0; i < maxcount; i++) { + eq_value=(0x00F8 & mdio_read(net_dev, sis_priv->cur_phy, MII_RESV)) >> 3; + max_value=(eq_value > max_value) ? eq_value : max_value; + min_value=(eq_value < min_value) ? eq_value : min_value; + } + if (max_value < 5) + eq_value=max_value; + else if (max_value >= 5 && max_value < 15) + eq_value=(max_value == min_value) ? max_value+2 : max_value+1; + else if (max_value >= 15) + eq_value=(max_value == min_value) ? max_value+6 : max_value+5; + reg14h=mdio_read(net_dev, sis_priv->cur_phy, MII_RESV); + reg14h=(reg14h & 0xFF07) | ((eq_value << 3) & 0x00F8); + reg14h=(reg14h | 0x6000) & 0xFDFF; + mdio_write(net_dev, sis_priv->cur_phy, MII_RESV, reg14h); + } + else { + reg14h=mdio_read(net_dev, sis_priv->cur_phy, MII_RESV); + mdio_write(net_dev, sis_priv->cur_phy, MII_RESV, (reg14h | 0x2000) & 0xBFFF); + } + return; +} + /* on each timer ticks we check two things, Link Status (ON/OFF) and Link Mode (10/100/Full/Half) */ @@ -710,6 +756,7 @@ struct mii_phy *mii_phy = sis_priv->mii; static int next_tick = 5*HZ; u16 status; + u8 revision; status = mdio_read(net_dev, sis_priv->cur_phy, MII_STATUS); status = mdio_read(net_dev, sis_priv->cur_phy, MII_STATUS); @@ -721,6 +768,12 @@ /* link stat change from ON to OFF */ next_tick = HZ; sis_priv->LinkOn = FALSE; + + /* Equalizer workaroung Rule */ + pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision); + if (revision == SIS630E_REV || revision == SIS630EA1_REV) + sis630e_set_eq(net_dev); + printk(KERN_INFO "%s: Media Link Off\n", net_dev->name); } @@ -736,6 +789,12 @@ /* link stat change forn OFF to ON, read and report link mode */ sis_priv->LinkOn = TRUE; next_tick = 5*HZ; + + /* Equalizer workaroung Rule */ + pci_read_config_byte(sis_priv->pci_dev, PCI_CLASS_REVISION, &revision); + if (revision == SIS630E_REV || revision == SIS630EA1_REV) + sis630e_set_eq(net_dev); + /* change what cur_phy means */ if (mii_phy->phy_addr != sis_priv->cur_phy) { printk(KERN_INFO "%s: Changing transceiver to %s\n", @@ -856,6 +915,37 @@ printk(KERN_INFO "%s: Media Link Off\n", net_dev->name); } } +/* ICS1893 PHY use Quick Poll Detailed Status Register to get its status */ +static void ics1893_read_mode(struct net_device *net_dev, int phy_addr, int *speed, int *duplex) +{ + int i = 0; + u32 status; + + /* MII_QPDSTS is Latched, read twice in succession will reflect the current state */ + for (i = 0; i < 2; i++) + status = mdio_read(net_dev, phy_addr, MII_QPDSTS); + + if (status & MII_STSICS_SPD) + *speed = HW_SPEED_100_MBPS; + else + *speed = HW_SPEED_10_MBPS; + + if (status & MII_STSICS_DPLX) + *duplex = FDX_CAPABLE_FULL_SELECTED; + else + *duplex = FDX_CAPABLE_HALF_SELECTED; + + if (status & MII_STSICS_LINKSTS) + printk(KERN_INFO "%s: Media Link On %s %s-duplex \n", + net_dev->name, + *speed == HW_SPEED_100_MBPS ? + "100mbps" : "10mbps", + *duplex == FDX_CAPABLE_FULL_SELECTED ? + "full" : "half"); + else + printk(KERN_INFO "%s: Media Link Off\n", net_dev->name); +} + static void sis900_tx_timeout(struct net_device *net_dev) { struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/sis900.h linux/drivers/net/sis900.h --- v2.4.0-test8/linux/drivers/net/sis900.h Wed Aug 9 14:24:09 2000 +++ linux/drivers/net/sis900.h Tue Sep 19 08:31:27 2000 @@ -165,7 +165,13 @@ /* mii registers specific to SiS 900 */ enum sis_mii_registers { MII_CONFIG1 = 0x0010, MII_CONFIG2 = 0x0011, MII_STSOUT = 0x0012, - MII_MASK = 0x0013 + MII_MASK = 0x0013, MII_RESV = 0x0014 +}; + +/* mii registers specific to ICS 1893 */ +enum ics_mii_registers { + MII_EXTCTRL = 0x0010, MII_QPDSTS = 0x0011, MII_10BTOP = 0x0012, + MII_EXTCTRL2 = 0x0013 }; /* mii registers specific to AMD 79C901 */ @@ -212,13 +218,19 @@ MII_STSOUT_SPD = 0x0080, MII_STSOUT_DPLX = 0x0040 }; +enum mii_stsics_register_bits { + MII_STSICS_SPD = 0x8000, MII_STSICS_DPLX = 0x4000, + MII_STSICS_LINKSTS = 0x0001 +}; + enum mii_stssum_register_bits { MII_STSSUM_LINK = 0x0008, MII_STSSUM_DPLX = 0x0004, MII_STSSUM_AUTO = 0x0002, MII_STSSUM_SPD = 0x0001 }; enum sis630_revision_id { - SIS630E_REV = 0x81, SIS630EA1_REV = 0x83 + SIS630E_REV = 0x81, SIS630EA1_REV = 0x83, + SIS630S_REV = 0x82 }; #define FDX_CAPABLE_DUPLEX_UNKNOWN 0 diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/sk98lin/h/lm80.h linux/drivers/net/sk98lin/h/lm80.h --- v2.4.0-test8/linux/drivers/net/sk98lin/h/lm80.h Tue Nov 23 10:15:42 1999 +++ linux/drivers/net/sk98lin/h/lm80.h Fri Sep 15 14:34:19 2000 @@ -2,8 +2,8 @@ * * Name: lm80.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.2 $ - * Date: $Date: 1999/03/12 13:26:51 $ + * Version: $Revision: 1.3 $ + * Date: $Date: 1999/11/22 13:41:19 $ * Purpose: Contains all defines for the LM80 Chip * (National Semiconductor). * @@ -27,6 +27,9 @@ * * History: * $Log: lm80.h,v $ + * Revision 1.3 1999/11/22 13:41:19 cgoos + * Changed license header to GPL. + * * Revision 1.2 1999/03/12 13:26:51 malthoff * remove __STDC__. * diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/sk98lin/h/skaddr.h linux/drivers/net/sk98lin/h/skaddr.h --- v2.4.0-test8/linux/drivers/net/sk98lin/h/skaddr.h Tue Nov 23 10:15:42 1999 +++ linux/drivers/net/sk98lin/h/skaddr.h Fri Sep 15 14:34:19 2000 @@ -2,15 +2,15 @@ * * Name: skaddr.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.19 $ - * Date: $Date: 1999/05/28 10:56:07 $ - * Purpose: Header file for Address Management (MC, UC, Prom) + * Version: $Revision: 1.23 $ + * Date: $Date: 2000/08/10 11:27:50 $ + * Purpose: Header file for Address Management (MC, UC, Prom). * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998,1999 SysKonnect, + * (C)Copyright 1998-2000 SysKonnect, * a business unit of Schneider & Koch & Co. Datensysteme GmbH. * * This program is free software; you can redistribute it and/or modify @@ -27,6 +27,21 @@ * History: * * $Log: skaddr.h,v $ + * Revision 1.23 2000/08/10 11:27:50 rassmann + * Editorial changes. + * Preserving 32-bit alignment in structs for the adapter context. + * + * Revision 1.22 2000/08/07 11:10:40 rassmann + * Editorial changes. + * + * Revision 1.21 2000/05/04 09:39:59 rassmann + * Editorial changes. + * Corrected multicast address hashing. + * + * Revision 1.20 1999/11/22 13:46:14 cgoos + * Changed license header to GPL. + * Allowing overwrite for SK_ADDR_EQUAL. + * * Revision 1.19 1999/05/28 10:56:07 rassmann * Editorial changes. * @@ -115,32 +130,33 @@ #define __INC_SKADDR_H #ifdef __cplusplus -xxxx /* not supported yet - force error */ +#error C++ is not yet supported. extern "C" { #endif /* cplusplus */ /* defines ********************************************************************/ -#define SK_MAC_ADDR_LEN 6 /* Length of MAC address. */ -#define SK_MAX_ADDRS 14 /* #Addrs for exact match. */ +#define SK_MAC_ADDR_LEN 6 /* Length of MAC address. */ +#define SK_MAX_ADDRS 14 /* #Addrs for exact match. */ /* ----- Common return values ----- */ -#define SK_ADDR_SUCCESS 0 /* Function returned successfully. */ -#define SK_ADDR_ILLEGAL_PORT 100 /* Port number too high. */ -#define SK_ADDR_TOO_EARLY 101 /* Function called too early. */ +#define SK_ADDR_SUCCESS 0 /* Function returned successfully. */ +#define SK_ADDR_ILLEGAL_PORT 100 /* Port number too high. */ +#define SK_ADDR_TOO_EARLY 101 /* Function called too early. */ /* ----- Clear/Add flag bits ----- */ -#define SK_ADDR_PERMANENT 1 /* RLMT Address */ +#define SK_ADDR_PERMANENT 1 /* RLMT Address */ /* ----- Additional Clear flag bits ----- */ -#define SK_MC_SW_ONLY 2 /* Do not update HW when clearing. */ +#define SK_MC_SW_ONLY 2 /* Do not update HW when clearing. */ /* ----- Override flag bits ----- */ -#define SK_ADDR_VIRTUAL_ADDRESS 0 +#define SK_ADDR_LOGICAL_ADDRESS 0 +#define SK_ADDR_VIRTUAL_ADDRESS (SK_ADDR_LOGICAL_ADDRESS) /* old */ #define SK_ADDR_PHYSICAL_ADDRESS 1 /* ----- Override return values ----- */ @@ -151,7 +167,7 @@ /* ----- Partitioning of excact match table ----- */ -#define SK_ADDR_EXACT_MATCHES 16 /* #Exact match entries. */ +#define SK_ADDR_EXACT_MATCHES 16 /* #Exact match entries. */ #define SK_ADDR_FIRST_MATCH_RLMT 1 #define SK_ADDR_LAST_MATCH_RLMT 2 @@ -160,21 +176,21 @@ /* ----- SkAddrMcAdd/SkAddrMcUpdate return values ----- */ -#define SK_MC_FILTERING_EXACT 0 /* Exact filtering. */ -#define SK_MC_FILTERING_INEXACT 1 /* Inexact filtering. */ +#define SK_MC_FILTERING_EXACT 0 /* Exact filtering. */ +#define SK_MC_FILTERING_INEXACT 1 /* Inexact filtering. */ /* ----- Additional SkAddrMcAdd return values ----- */ -#define SK_MC_ILLEGAL_ADDRESS 2 /* Illegal address. */ -#define SK_MC_ILLEGAL_PORT 3 /* Illegal port (not the active one). */ -#define SK_MC_RLMT_OVERFLOW 4 /* Too many RLMT mc addresses. */ +#define SK_MC_ILLEGAL_ADDRESS 2 /* Illegal address. */ +#define SK_MC_ILLEGAL_PORT 3 /* Illegal port (not the active one). */ +#define SK_MC_RLMT_OVERFLOW 4 /* Too many RLMT mc addresses. */ /* Promiscuous mode bits ----- */ -#define SK_PROM_MODE_NONE 0 /* Normal receive. */ -#define SK_PROM_MODE_LLC 1 /* Receive all LLC frames. */ -#define SK_PROM_MODE_ALL_MC 2 /* Receive all multicast frames. */ -/* #define SK_PROM_MODE_NON_LLC 4 */ /* Receive all non-LLC frames. */ +#define SK_PROM_MODE_NONE 0 /* Normal receive. */ +#define SK_PROM_MODE_LLC 1 /* Receive all LLC frames. */ +#define SK_PROM_MODE_ALL_MC 2 /* Receive all multicast frames. */ +/* #define SK_PROM_MODE_NON_LLC 4 */ /* Receive all non-LLC frames. */ /* Macros */ @@ -192,7 +208,7 @@ *(SK_U32 *)&(((SK_U8 *)(A1))[2]) == *(SK_U32 *)&(((SK_U8 *)(A2))[2]) && \ *(SK_U32 *)&(((SK_U8 *)(A1))[0]) == *(SK_U32 *)&(((SK_U8 *)(A2))[0])) #endif /* SK_ADDR_DWORD_COMPARE */ -#endif /* SK_ADDR_EQUAL */ +#endif /* SK_ADDR_EQUAL */ /* typedefs *******************************************************************/ @@ -203,27 +219,28 @@ /* SK_FILTER is used to ensure alignment of the filter. */ typedef union s_InexactFilter { SK_U8 Bytes[8]; - SK_U64 Val; /* Dummy entry for alignment only. */ + SK_U64 Val; /* Dummy entry for alignment only. */ } SK_FILTER64; typedef struct s_AddrPort { /* ----- Public part (read-only) ----- */ - SK_MAC_ADDR PermanentMacAddress; /* Physical MAC Address. */ - SK_MAC_ADDR CurrentMacAddress; /* Physical MAC Address. */ - int PromMode; /* Promiscuous Mode. */ + SK_MAC_ADDR CurrentMacAddress; /* Current physical MAC Address. */ + SK_MAC_ADDR PermanentMacAddress; /* Permanent physical MAC Address. */ + int PromMode; /* Promiscuous Mode. */ /* ----- Private part ----- */ + SK_MAC_ADDR PreviousMacAddress; /* Prev. phys. MAC Address. */ SK_BOOL CurrentMacAddressSet; /* CurrentMacAddress is set. */ - SK_MAC_ADDR PreviousMacAddress; /* Prev. phys. MAC Address. */ + SK_U8 Align01; SK_U32 FirstExactMatchRlmt; SK_U32 NextExactMatchRlmt; SK_U32 FirstExactMatchDrv; SK_U32 NextExactMatchDrv; SK_MAC_ADDR Exact[SK_ADDR_EXACT_MATCHES]; - SK_FILTER64 InexactFilter; /* For 64-bit hash register. */ + SK_FILTER64 InexactFilter; /* For 64-bit hash register. */ } SK_ADDR_PORT; typedef struct s_Addr { @@ -232,22 +249,21 @@ SK_ADDR_PORT Port[SK_MAX_MACS]; SK_MAC_ADDR PermanentMacAddress; /* Logical MAC Address. */ - SK_MAC_ADDR CurrentMacAddress; /* Logical MAC Address. */ + SK_MAC_ADDR CurrentMacAddress; /* Logical MAC Address. */ /* ----- Private part ----- */ -#if 0 - SK_BOOL Initialized; /* Flag: Addr module is initialized. */ -#endif /* 0 */ + SK_U32 ActivePort; /* View of module ADDR. */ SK_BOOL CurrentMacAddressSet; /* CurrentMacAddress is set. */ - SK_U32 ActivePort; /* Vie of module ADDR. */ + SK_U8 Align01; + SK_U16 Align02; } SK_ADDR; /* function prototypes ********************************************************/ #ifndef SK_KR_PROTO -/* Functions provided by SkRlmt */ +/* Functions provided by SkAddr */ /* ANSI/C++ compliant function prototypes */ @@ -297,7 +313,7 @@ /* Non-ANSI/C++ compliant function prototypes */ -xxxx /* not supported yet - force error */ +#error KR-style prototypes are not yet provided. #endif /* defined(SK_KR_PROTO)) */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/sk98lin/h/skcsum.h linux/drivers/net/sk98lin/h/skcsum.h --- v2.4.0-test8/linux/drivers/net/sk98lin/h/skcsum.h Tue Nov 23 10:15:42 1999 +++ linux/drivers/net/sk98lin/h/skcsum.h Fri Sep 15 14:34:19 2000 @@ -1,9 +1,9 @@ /****************************************************************************** * * Name: skcsum.h - * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.2 $ - * Date: $Date: 1998/09/04 12:16:34 $ + * Project: GEnesis - SysKonnect SK-NET Gigabit Ethernet (SK-98xx) + * Version: $Revision: 1.7 $ + * Date: $Date: 2000/06/29 13:17:05 $ * Purpose: Store/verify Internet checksum in send/receive packets. * ******************************************************************************/ @@ -27,6 +27,25 @@ * History: * * $Log: skcsum.h,v $ + * Revision 1.7 2000/06/29 13:17:05 rassmann + * Corrected reception of a packet with UDP checksum == 0 (which means there + * is no UDP checksum). + * + * Revision 1.6 2000/02/28 12:33:44 cgoos + * Changed C++ style comments to C style. + * + * Revision 1.5 2000/02/21 12:10:05 cgoos + * Fixed license comment. + * + * Revision 1.4 2000/02/21 11:08:37 cgoos + * Merged changes back into common source. + * + * Revision 1.1 1999/07/26 14:47:49 mkarl + * changed from common source to windows specific source + * added return SKCS_STATUS_IP_CSUM_ERROR_UDP and + * SKCS_STATUS_IP_CSUM_ERROR_TCP to pass the NidsTester + * changes for Tx csum offload + * * Revision 1.2 1998/09/04 12:16:34 mhaveman * Checked in for Stephan to allow compilation. * -Added definition SK_CSUM_EVENT_CLEAR_PROTO_STATS to clear statistic @@ -98,24 +117,32 @@ * * SKCS_STATUS_UNKNOWN_IP_VERSION - Not an IP v4 frame. * SKCS_STATUS_IP_CSUM_ERROR - IP checksum error. + * SKCS_STATUS_IP_CSUM_ERROR_TCP - IP checksum error in TCP frame. + * SKCS_STATUS_IP_CSUM_ERROR_UDP - IP checksum error in UDP frame * SKCS_STATUS_IP_FRAGMENT - IP fragment (IP checksum ok). * SKCS_STATUS_IP_CSUM_OK - IP checksum ok (not a TCP or UDP frame). * SKCS_STATUS_TCP_CSUM_ERROR - TCP checksum error (IP checksum ok). * SKCS_STATUS_UDP_CSUM_ERROR - UDP checksum error (IP checksum ok). * SKCS_STATUS_TCP_CSUM_OK - IP and TCP checksum ok. * SKCS_STATUS_UDP_CSUM_OK - IP and UDP checksum ok. + * SKCS_STATUS_IP_CSUM_OK_NO_UDP - IP checksum OK and no UDP checksum. */ #ifndef SKCS_OVERWRITE_STATUS /* User overwrite? */ #define SKCS_STATUS int /* Define status type. */ #define SKCS_STATUS_UNKNOWN_IP_VERSION 1 -#define SKCS_STATUS_IP_CSUM_ERROR 2 -#define SKCS_STATUS_IP_FRAGMENT 3 -#define SKCS_STATUS_IP_CSUM_OK 4 -#define SKCS_STATUS_TCP_CSUM_ERROR 5 -#define SKCS_STATUS_UDP_CSUM_ERROR 6 -#define SKCS_STATUS_TCP_CSUM_OK 7 -#define SKCS_STATUS_UDP_CSUM_OK 8 +#define SKCS_STATUS_IP_CSUM_ERROR 2 +#define SKCS_STATUS_IP_FRAGMENT 3 +#define SKCS_STATUS_IP_CSUM_OK 4 +#define SKCS_STATUS_TCP_CSUM_ERROR 5 +#define SKCS_STATUS_UDP_CSUM_ERROR 6 +#define SKCS_STATUS_TCP_CSUM_OK 7 +#define SKCS_STATUS_UDP_CSUM_OK 8 +/* needed for Microsoft */ +#define SKCS_STATUS_IP_CSUM_ERROR_UDP 9 +#define SKCS_STATUS_IP_CSUM_ERROR_TCP 10 +/* UDP checksum may be omitted */ +#define SKCS_STATUS_IP_CSUM_OK_NO_UDP 11 #endif /* !SKCS_OVERWRITE_STATUS */ /* Clear protocol statistics event. */ @@ -158,7 +185,7 @@ SK_U64 RxUnableCts; /* Unable to verify receive checksum. */ SK_U64 RxErrCts; /* Receive checksum error. */ SK_U64 TxOkCts; /* Transmit checksum ok. */ - SK_U64 TxUnableCts; /* Unable to verify transmit checksum. */ + SK_U64 TxUnableCts; /* Unable to calculate checksum in hw. */ } SKCS_PROTO_STATS; /* @@ -167,6 +194,9 @@ typedef struct s_Csum { /* Enabled receive SK_PROTO_XXX bit flags. */ unsigned ReceiveFlags; +#ifdef TX_CSUM + unsigned TransmitFlags; +#endif /* TX_CSUM */ /* The protocol statistics structure; one per supported protocol. */ SKCS_PROTO_STATS ProtoStats[SKCS_NUM_PROTOCOLS]; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/sk98lin/h/skdebug.h linux/drivers/net/sk98lin/h/skdebug.h --- v2.4.0-test8/linux/drivers/net/sk98lin/h/skdebug.h Tue Nov 23 10:15:42 1999 +++ linux/drivers/net/sk98lin/h/skdebug.h Fri Sep 15 14:34:19 2000 @@ -2,8 +2,8 @@ * * Name: skdebug.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.9 $ - * Date: $Date: 1999/09/14 14:02:43 $ + * Version: $Revision: 1.10 $ + * Date: $Date: 1999/11/22 13:47:40 $ * Purpose: SK specific DEBUG support * ******************************************************************************/ @@ -26,6 +26,9 @@ * * History: * $Log: skdebug.h,v $ + * Revision 1.10 1999/11/22 13:47:40 cgoos + * Changed license header to GPL. + * * Revision 1.9 1999/09/14 14:02:43 rwahl * Added SK_DBGMOD_PECP. * diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/sk98lin/h/skdrv1st.h linux/drivers/net/sk98lin/h/skdrv1st.h --- v2.4.0-test8/linux/drivers/net/sk98lin/h/skdrv1st.h Tue Nov 23 10:15:42 1999 +++ linux/drivers/net/sk98lin/h/skdrv1st.h Fri Sep 15 14:34:19 2000 @@ -2,8 +2,8 @@ * * Name: skdrv1st.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.6 $ - * Date: $Date: 1999/07/27 08:03:33 $ + * Version: $Revision: 1.8 $ + * Date: $Date: 2000/02/21 12:19:18 $ * Purpose: First header file for driver and all other modules * ******************************************************************************/ @@ -27,6 +27,15 @@ * History: * * $Log: skdrv1st.h,v $ + * Revision 1.8 2000/02/21 12:19:18 cgoos + * Added default for SK_DEBUG_CHKMOD/_CHKCAT + * + * Revision 1.7 1999/11/22 13:50:00 cgoos + * Changed license header to GPL. + * Added overwrite for several functions. + * Removed linux 2.0.x definitions. + * Removed PCI vendor ID definition (now in kernel). + * * Revision 1.6 1999/07/27 08:03:33 cgoos * Changed SK_IN/OUT macros to readX/writeX instead of memory * accesses (necessary for ALPHA). @@ -175,6 +184,12 @@ #ifdef DEBUG #define SK_DBG_PRINTF printk +#ifndef SK_DEBUG_CHKMOD +#define SK_DEBUG_CHKMOD 0 +#endif +#ifndef SK_DEBUG_CHKCAT +#define SK_DEBUG_CHKCAT 0 +#endif /* those come from the makefile */ #define SK_DBG_CHKMOD(pAC) (SK_DEBUG_CHKMOD) #define SK_DBG_CHKCAT(pAC) (SK_DEBUG_CHKCAT) diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/sk98lin/h/skerror.h linux/drivers/net/sk98lin/h/skerror.h --- v2.4.0-test8/linux/drivers/net/sk98lin/h/skerror.h Tue Nov 23 10:15:42 1999 +++ linux/drivers/net/sk98lin/h/skerror.h Fri Sep 15 14:34:19 2000 @@ -2,8 +2,8 @@ * * Name: skerror.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.3 $ - * Date: $Date: 1999/09/14 14:04:42 $ + * Version: $Revision: 1.4 $ + * Date: $Date: 1999/11/22 13:51:59 $ * Purpose: SK specific Error log support * ******************************************************************************/ @@ -26,6 +26,9 @@ * * History: * $Log: skerror.h,v $ + * Revision 1.4 1999/11/22 13:51:59 cgoos + * Changed license header to GPL. + * * Revision 1.3 1999/09/14 14:04:42 rwahl * Added error base SK_ERRBASE_PECP. * Changed error base for driver. diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/sk98lin/h/skgedrv.h linux/drivers/net/sk98lin/h/skgedrv.h --- v2.4.0-test8/linux/drivers/net/sk98lin/h/skgedrv.h Tue Nov 23 10:15:42 1999 +++ linux/drivers/net/sk98lin/h/skgedrv.h Fri Sep 15 14:34:19 2000 @@ -2,8 +2,8 @@ * * Name: skgedrv.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.3 $ - * Date: $Date: 1998/12/01 13:31:39 $ + * Version: $Revision: 1.4 $ + * Date: $Date: 1999/11/22 13:52:46 $ * Purpose: Interface with the driver * ******************************************************************************/ @@ -27,6 +27,9 @@ * History: * * $Log: skgedrv.h,v $ + * Revision 1.4 1999/11/22 13:52:46 cgoos + * Changed license header to GPL. + * * Revision 1.3 1998/12/01 13:31:39 cgoos * SWITCH INTERN Event added. * diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/sk98lin/h/skgehw.h linux/drivers/net/sk98lin/h/skgehw.h --- v2.4.0-test8/linux/drivers/net/sk98lin/h/skgehw.h Tue Nov 23 10:15:42 1999 +++ linux/drivers/net/sk98lin/h/skgehw.h Fri Sep 15 14:34:19 2000 @@ -2,8 +2,8 @@ * * Name: skgehw.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.33 $ - * Date: $Date: 1999/08/27 11:17:10 $ + * Version: $Revision: 1.35 $ + * Date: $Date: 2000/05/19 10:17:13 $ * Purpose: Defines and Macros for the Gigabit Ethernet Adapter Product * Family * @@ -27,6 +27,12 @@ * * History: * $Log: skgehw.h,v $ + * Revision 1.35 2000/05/19 10:17:13 cgoos + * Added inactivity check in PHY_READ (in DEBUG mode only). + * + * Revision 1.34 1999/11/22 13:53:40 cgoos + * Changed license header to GPL. + * * Revision 1.33 1999/08/27 11:17:10 malthoff * It's more savely to put bracket around marco parameters. * Brackets added for PHY_READ and PHY_WRITE. @@ -1627,19 +1633,44 @@ * written. * * usage: PHY_READ(IoC, pPort, MAC_1, PHY_CTRL, Value); + * Warning: a PHY_READ on an uninitialized PHY (PHY still in reset) never + * comes back. This is checked in DEBUG mode. */ +#ifndef DEBUG +#define PHY_READ(IoC, pPort, Mac, PhyReg, pVal) { \ + SK_U16 Mmu; \ + \ + XM_OUT16((IoC),(Mac), XM_PHY_ADDR, (PhyReg)|(pPort)->PhyAddr); \ + XM_IN16((IoC), (Mac), XM_PHY_DATA, (pVal)); \ + if ((pPort)->PhyType != SK_PHY_XMAC) { \ + do { \ + XM_IN16((IoC), (Mac), XM_MMU_CMD, &Mmu); \ + } while ((Mmu & XM_MMU_PHY_RDY) == 0); \ + XM_IN16((IoC), (Mac), XM_PHY_DATA, (pVal)); \ + } \ +} +#else #define PHY_READ(IoC, pPort, Mac, PhyReg, pVal) { \ SK_U16 Mmu; \ + int __i = 0; \ \ XM_OUT16((IoC),(Mac), XM_PHY_ADDR, (PhyReg)|(pPort)->PhyAddr); \ XM_IN16((IoC), (Mac), XM_PHY_DATA, (pVal)); \ if ((pPort)->PhyType != SK_PHY_XMAC) { \ do { \ XM_IN16((IoC), (Mac), XM_MMU_CMD, &Mmu); \ + __i++; \ + if (__i > 10000) { \ + SK_DBG_PRINTF("*****************************\n"); \ + SK_DBG_PRINTF("PHY_READ on uninitialized PHY\n"); \ + SK_DBG_PRINTF("*****************************\n"); \ + break; \ + } \ } while ((Mmu & XM_MMU_PHY_RDY) == 0); \ XM_IN16((IoC), (Mac), XM_PHY_DATA, (pVal)); \ } \ } +#endif #define PHY_WRITE(IoC, pPort, Mac, PhyReg, Val) { \ SK_U16 Mmu; \ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/sk98lin/h/skgehwt.h linux/drivers/net/sk98lin/h/skgehwt.h --- v2.4.0-test8/linux/drivers/net/sk98lin/h/skgehwt.h Tue Nov 23 10:15:42 1999 +++ linux/drivers/net/sk98lin/h/skgehwt.h Fri Sep 15 14:34:19 2000 @@ -2,8 +2,8 @@ * * Name: skhwt.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.4 $ - * Date: $Date: 1998/08/19 09:50:58 $ + * Version: $Revision: 1.5 $ + * Date: $Date: 1999/11/22 13:54:24 $ * Purpose: Defines for the hardware timer functions * ******************************************************************************/ @@ -27,6 +27,9 @@ * History: * * $Log: skgehwt.h,v $ + * Revision 1.5 1999/11/22 13:54:24 cgoos + * Changed license header to GPL. + * * Revision 1.4 1998/08/19 09:50:58 gklug * fix: remove struct keyword from c-code (see CCC) add typedefs * diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/sk98lin/h/skgei2c.h linux/drivers/net/sk98lin/h/skgei2c.h --- v2.4.0-test8/linux/drivers/net/sk98lin/h/skgei2c.h Tue Nov 23 10:15:42 1999 +++ linux/drivers/net/sk98lin/h/skgei2c.h Fri Sep 15 14:34:19 2000 @@ -2,8 +2,8 @@ * * Name: skgei2c.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.16 $ - * Date: $Date: 1999/11/12 08:24:10 $ + * Version: $Revision: 1.17 $ + * Date: $Date: 1999/11/22 13:55:25 $ * Purpose: Special genesis defines for I2C * (taken from Monalisa (taken from Concentrator)) * @@ -28,6 +28,9 @@ * History: * * $Log: skgei2c.h,v $ + * Revision 1.17 1999/11/22 13:55:25 cgoos + * Changed license header to GPL. + * * Revision 1.16 1999/11/12 08:24:10 malthoff * Change voltage warning and error limits * (warning +-5%, error +-10%). diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/sk98lin/h/skgeinit.h linux/drivers/net/sk98lin/h/skgeinit.h --- v2.4.0-test8/linux/drivers/net/sk98lin/h/skgeinit.h Tue Nov 23 10:15:42 1999 +++ linux/drivers/net/sk98lin/h/skgeinit.h Fri Sep 15 14:34:19 2000 @@ -2,15 +2,15 @@ * * Name: skgeinit.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.44 $ - * Date: $Date: 1999/10/26 07:34:15 $ + * Version: $Revision: 1.46 $ + * Date: $Date: 2000/08/10 11:28:00 $ * Purpose: Structures and prototypes for the GE Init Module * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998,1999 SysKonnect, + * (C)Copyright 1998-2000 SysKonnect, * a business unit of Schneider & Koch & Co. Datensysteme GmbH. * * This program is free software; you can redistribute it and/or modify @@ -27,6 +27,13 @@ * History: * * $Log: skgeinit.h,v $ + * Revision 1.46 2000/08/10 11:28:00 rassmann + * Editorial changes. + * Preserving 32-bit alignment in structs for the adapter context. + * + * Revision 1.45 1999/11/22 13:56:19 cgoos + * Changed license header to GPL. + * * Revision 1.44 1999/10/26 07:34:15 malthoff * The define SK_LNK_ON has been lost in v1.41. * @@ -443,61 +450,63 @@ SK_TIMER PWaTimer; /* Workaround Timer */ #endif SK_U64 PPrevShorts; /* Previous short Counter checking */ - SK_U64 PPrevRx; /* Previous RxOk Counter checking */ - SK_U64 PPrevFcs; /* Previous FCS Error Counter checking */ - SK_U64 PRxLim; /* Previous RxOk Counter checking */ - int PLinkResCt; /* Link Restart Counter */ - int PAutoNegTimeOut;/* AutoNegotiation timeout current value */ - int PRxQSize; /* Port Rx Queue Size in kB */ - int PXSQSize; /* Port Synchronous Transmit Queue Size in kB */ - int PXAQSize; /* Port Asynchronous Transmit Queue Size in kB*/ + SK_U64 PPrevRx; /* Previous RxOk Counter checking */ + SK_U64 PPrevFcs; /* Previous FCS Error Counter checking */ + SK_U64 PRxLim; /* Previous RxOk Counter checking */ + int PLinkResCt; /* Link Restart Counter */ + int PAutoNegTimeOut;/* AutoNegotiation timeout current value */ + int PRxQSize; /* Port Rx Queue Size in kB */ + int PXSQSize; /* Port Synchronous Transmit Queue Size in kB */ + int PXAQSize; /* Port Asynchronous Transmit Queue Size in kB*/ SK_U32 PRxQRamStart; /* Receive Queue RAM Buffer Start Address */ - SK_U32 PRxQRamEnd; /* Receive Queue RAM Buffer End Address */ + SK_U32 PRxQRamEnd; /* Receive Queue RAM Buffer End Address */ SK_U32 PXsQRamStart; /* Sync Tx Queue RAM Buffer Start Address */ - SK_U32 PXsQRamEnd; /* Sync Tx Queue RAM Buffer End Address */ + SK_U32 PXsQRamEnd; /* Sync Tx Queue RAM Buffer End Address */ SK_U32 PXaQRamStart; /* Async Tx Queue RAM Buffer Start Address */ - SK_U32 PXaQRamEnd; /* Async Tx Queue RAM Buffer End Address */ - int PRxQOff; /* Rx Queue Address Offset */ - int PXsQOff; /* Synchronous Tx Queue Address Offset */ - int PXaQOff; /* Asynchronous Tx Queue Address Offset */ - SK_U16 PRxCmd; /* Port Receive Command Configuration Value */ - SK_U16 PIsave; /* Saved Interrupt status word */ - SK_U16 PSsave; /* Saved PHY status word */ - SK_BOOL PHWLinkUp; /* The hardware Link is up (wireing) */ - SK_BOOL PState; /* Is port initialized ? */ + SK_U32 PXaQRamEnd; /* Async Tx Queue RAM Buffer End Address */ + int PRxQOff; /* Rx Queue Address Offset */ + int PXsQOff; /* Synchronous Tx Queue Address Offset */ + int PXaQOff; /* Asynchronous Tx Queue Address Offset */ + SK_U16 PRxCmd; /* Port Receive Command Configuration Value */ + SK_U16 PIsave; /* Saved Interrupt status word */ + SK_U16 PSsave; /* Saved PHY status word */ + SK_BOOL PHWLinkUp; /* The hardware Link is up (wireing) */ + SK_BOOL PState; /* Is port initialized ? */ SK_BOOL PLinkBroken; /* Is Link broken ? */ - SK_BOOL PCheckPar; /* Do we check for parity errors ? */ - SK_U8 PLinkCap; /* Link Capabilities */ + SK_BOOL PCheckPar; /* Do we check for parity errors ? */ + SK_U8 PLinkCap; /* Link Capabilities */ SK_U8 PLinkModeConf; /* Link Mode configured */ - SK_U8 PLinkMode; /* Link Mode currently used */ - SK_U8 PLinkModeStatus; /* Link Mode Status */ + SK_U8 PLinkMode; /* Link Mode currently used */ + SK_U8 PLinkModeStatus;/* Link Mode Status */ SK_U8 PFlowCtrlCap; /* Flow Control Capabilities */ SK_U8 PFlowCtrlMode; /* Flow Control Mode */ - SK_U8 PFlowCtrlStatus; /* Flow Control Status */ - SK_U8 PMSCap; /* Master/Slave Capabilities */ - SK_U8 PMSMode; /* Master/Slave Mode */ - SK_U8 PMSStatus; /* Master/Slave Status */ + SK_U8 PFlowCtrlStatus;/* Flow Control Status */ + SK_U8 PMSCap; /* Master/Slave Capabilities */ + SK_U8 PMSMode; /* Master/Slave Mode */ + SK_U8 PMSStatus; /* Master/Slave Status */ SK_U8 PAutoNegFail; /* Autonegotiation fail flag */ SK_U8 PLipaAutoNeg; /* Autonegotiation possible with Link Partner */ + SK_U16 PhyAddr; /* MDIO/MDC PHY address */ int PhyType; /* PHY used on this port */ - SK_U16 PhyAddr; /* MDIO/MDC PHY address */ } SK_GEPORT; /* * Gigabit Ethernet Initalization Struct - * (has to be included in the adapter context + * (has to be included in the adapter context) */ typedef struct s_GeInit { - int GIMacsFound; /* Number of MACs found on this adapter */ - int GIPciHwRev; /* PCI HW Revision Number */ - SK_U32 GIRamOffs; /* RAM Address Offset for addr calculation */ - int GIRamSize; /* The RAM size of the adapter in kB */ - int GIHstClkFact; /* Host Clock Factor (62.5 / HstClk * 100) */ - int GIPortUsage; /* driver port usage: SK_RED_LINK/SK_MUL_LINK */ - SK_U32 GIPollTimerVal; /* Descriptor Poll Timer Init Val in clk ticks*/ - int GILevel; /* Initialization Level Completed */ - SK_BOOL GIAnyPortAct; /* Is True if one or more port is initialized */ - SK_GEPORT GP[SK_MAX_MACS]; /* Port Dependent Information */ + int GIMacsFound; /* Number of MACs found on this adapter */ + int GIPciHwRev; /* PCI HW Revision Number */ + SK_U32 GIRamOffs; /* RAM Address Offset for addr calculation */ + int GIRamSize; /* The RAM size of the adapter in kB */ + int GIHstClkFact; /* Host Clock Factor (62.5 / HstClk * 100) */ + int GIPortUsage; /* driver port usage: SK_RED_LINK/SK_MUL_LINK */ + SK_U32 GIPollTimerVal; /* Descriptor Poll Timer Init Val in clk ticks*/ + int GILevel; /* Initialization Level Completed */ + SK_GEPORT GP[SK_MAX_MACS];/* Port Dependent Information */ + SK_BOOL GIAnyPortAct; /* Is True if one or more port is initialized */ + SK_U8 Align01; + SK_U16 Align02; } SK_GEINIT; /* diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/sk98lin/h/skgepnm2.h linux/drivers/net/sk98lin/h/skgepnm2.h --- v2.4.0-test8/linux/drivers/net/sk98lin/h/skgepnm2.h Tue Nov 23 10:15:42 1999 +++ linux/drivers/net/sk98lin/h/skgepnm2.h Fri Sep 15 14:34:19 2000 @@ -2,8 +2,8 @@ * * Name: skgepnm2.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.24 $ - * Date: $Date: 1999/04/13 15:11:11 $ + * Version: $Revision: 1.28 $ + * Date: $Date: 2000/08/03 15:12:48 $ * Purpose: Defines for Private Network Management Interface * ****************************************************************************/ @@ -27,6 +27,20 @@ * History: * * $Log: skgepnm2.h,v $ + * Revision 1.28 2000/08/03 15:12:48 rwahl + * - Additional comment for MAC statistic data structure. + * + * Revision 1.27 2000/08/01 16:10:18 rwahl + * - Added mac statistic data structure for StatRxLongFrame counter. + * + * Revision 1.26 2000/03/31 13:51:34 rwahl + * Added SK_UPTR cast to offset calculation for PNMI struct fields; + * missing cast caused compiler warnings by Win64 compiler. + * + * Revision 1.25 1999/11/22 13:57:41 cgoos + * Changed license header to GPL. + * Allowing overwrite for SK_PNMI_STORE/_READ defines. + * * Revision 1.24 1999/04/13 15:11:11 mhaveman * Changed copyright. * @@ -203,6 +217,8 @@ /* * MAC statistic data structures + * Only for the first 64 counters: the number relates to the bit in the + * XMAC overflow status register */ #define SK_PNMI_HTX 0 #define SK_PNMI_HTX_OCTET 1 @@ -274,6 +290,8 @@ #define SK_PNMI_HTX_SYNC 64 #define SK_PNMI_HTX_SYNC_OCTET 65 +#define SK_PNMI_HRX_LONGFRAMES 66 + #define SK_PNMI_MAX_IDX (SK_PNMI_CNT_NO) /* @@ -288,25 +306,25 @@ /* * SK_PNMI_STRUCT_DATA copy offset evaluation macros */ -#define SK_PNMI_OFF(e) ((SK_U32)&(((SK_PNMI_STRUCT_DATA *)0)->e)) -#define SK_PNMI_MAI_OFF(e) ((SK_U32)&(((SK_PNMI_STRUCT_DATA *)0)->e)) -#define SK_PNMI_VPD_OFF(e) ((SK_U32)&(((SK_PNMI_VPD *)0)->e)) -#define SK_PNMI_SEN_OFF(e) ((SK_U32)&(((SK_PNMI_SENSOR *)0)->e)) -#define SK_PNMI_CHK_OFF(e) ((SK_U32)&(((SK_PNMI_CHECKSUM *)0)->e)) -#define SK_PNMI_STA_OFF(e) ((SK_U32)&(((SK_PNMI_STAT *)0)->e)) -#define SK_PNMI_CNF_OFF(e) ((SK_U32)&(((SK_PNMI_CONF *)0)->e)) -#define SK_PNMI_RLM_OFF(e) ((SK_U32)&(((SK_PNMI_RLMT *)0)->e)) -#define SK_PNMI_MON_OFF(e) ((SK_U32)&(((SK_PNMI_RLMT_MONITOR *)0)->e)) -#define SK_PNMI_TRP_OFF(e) ((SK_U32)&(((SK_PNMI_TRAP *)0)->e)) +#define SK_PNMI_OFF(e) ((SK_U32)(SK_UPTR)&(((SK_PNMI_STRUCT_DATA *)0)->e)) +#define SK_PNMI_MAI_OFF(e) ((SK_U32)(SK_UPTR)&(((SK_PNMI_STRUCT_DATA *)0)->e)) +#define SK_PNMI_VPD_OFF(e) ((SK_U32)(SK_UPTR)&(((SK_PNMI_VPD *)0)->e)) +#define SK_PNMI_SEN_OFF(e) ((SK_U32)(SK_UPTR)&(((SK_PNMI_SENSOR *)0)->e)) +#define SK_PNMI_CHK_OFF(e) ((SK_U32)(SK_UPTR)&(((SK_PNMI_CHECKSUM *)0)->e)) +#define SK_PNMI_STA_OFF(e) ((SK_U32)(SK_UPTR)&(((SK_PNMI_STAT *)0)->e)) +#define SK_PNMI_CNF_OFF(e) ((SK_U32)(SK_UPTR)&(((SK_PNMI_CONF *)0)->e)) +#define SK_PNMI_RLM_OFF(e) ((SK_U32)(SK_UPTR)&(((SK_PNMI_RLMT *)0)->e)) +#define SK_PNMI_MON_OFF(e) ((SK_U32)(SK_UPTR)&(((SK_PNMI_RLMT_MONITOR *)0)->e)) +#define SK_PNMI_TRP_OFF(e) ((SK_U32)(SK_UPTR)&(((SK_PNMI_TRAP *)0)->e)) #define SK_PNMI_SET_STAT(b,s,o) {SK_U32 Val32; char *pVal; \ Val32 = (s); \ - pVal = (char *)(b) + ((SK_U32) \ + pVal = (char *)(b) + ((SK_U32)(SK_UPTR) \ &(((SK_PNMI_STRUCT_DATA *)0)-> \ ReturnStatus.ErrorStatus)); \ SK_PNMI_STORE_U32(pVal, Val32); \ Val32 = (o); \ - pVal = (char *)(b) + ((SK_U32) \ + pVal = (char *)(b) + ((SK_U32)(SK_UPTR) \ &(((SK_PNMI_STRUCT_DATA *)0)-> \ ReturnStatus.ErrorOffset)); \ SK_PNMI_STORE_U32(pVal, Val32);} diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/sk98lin/h/skgepnmi.h linux/drivers/net/sk98lin/h/skgepnmi.h --- v2.4.0-test8/linux/drivers/net/sk98lin/h/skgepnmi.h Tue Nov 23 10:15:42 1999 +++ linux/drivers/net/sk98lin/h/skgepnmi.h Fri Sep 15 14:34:19 2000 @@ -2,8 +2,8 @@ * * Name: skgepnmi.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.37 $ - * Date: $Date: 1999/09/14 14:25:32 $ + * Version: $Revision: 1.44 $ + * Date: $Date: 2000/09/07 07:35:27 $ * Purpose: Defines for Private Network Management Interface * ****************************************************************************/ @@ -27,6 +27,34 @@ * History: * * $Log: skgepnmi.h,v $ + * Revision 1.44 2000/09/07 07:35:27 rwahl + * - removed NDIS counter specific data type. + * - fixed spelling for OID_SKGE_RLMT_PORT_PREFERRED. + * + * Revision 1.43 2000/08/04 11:41:08 rwahl + * - Fixed compiler warning (port is always >= 0) for macros + * SK_PNMI_CNT_RX_LONGFRAMES & SK_PNMI_CNT_SYNC_OCTETS + * + * Revision 1.42 2000/08/03 15:14:07 rwahl + * - Corrected error in driver macros addressing a physical port. + * + * Revision 1.41 2000/08/01 16:22:29 rwahl + * - Changed MDB version to 3.1. + * - Added definitions for StatRxLongFrames counter. + * - Added macro to be used by driver to count long frames received. + * - Added directive to control width (default = 32bit) of NDIS statistic + * counters (SK_NDIS_64BIT_CTR). + * + * Revision 1.40 2000/03/31 13:51:34 rwahl + * Added SK_UPTR cast to offset calculation for PNMI struct fields; + * missing cast caused compiler warnings by Win64 compiler. + * + * Revision 1.39 1999/12/06 10:09:47 rwahl + * Added new error log message. + * + * Revision 1.38 1999/11/22 13:57:55 cgoos + * Changed license header to GPL. + * * Revision 1.37 1999/09/14 14:25:32 rwahl * Set MDB version for 1000Base-T (sensors, Master/Slave) changes. * @@ -164,7 +192,7 @@ /* * Management Database Version */ -#define SK_PNMI_MDB_VERSION 0x00030000 /* 3.0 */ +#define SK_PNMI_MDB_VERSION 0x00030001 /* 3.1 */ /* @@ -383,6 +411,7 @@ #define OID_SKGE_STAT_RX_511 0xFF020154 #define OID_SKGE_STAT_RX_1023 0xFF020155 #define OID_SKGE_STAT_RX_MAX 0xFF020156 +#define OID_SKGE_STAT_RX_LONGFRAMES 0xFF020157 #define OID_SKGE_PHYS_CUR_ADDR 0xFF010120 #define OID_SKGE_PHYS_FAC_ADDR 0xFF010121 @@ -405,7 +434,7 @@ #define OID_SKGE_RLMT_MODE 0xFF010140 #define OID_SKGE_RLMT_PORT_NUMBER 0xFF010141 #define OID_SKGE_RLMT_PORT_ACTIVE 0xFF010142 -#define OID_SKGE_RLMT_PORT_PREFERED 0xFF010143 +#define OID_SKGE_RLMT_PORT_PREFERRED 0xFF010143 #define OID_SKGE_RLMT_CHANGE_CTS 0xFF020160 #define OID_SKGE_RLMT_CHANGE_TIME 0xFF020161 #define OID_SKGE_RLMT_CHANGE_ESTIM 0xFF020162 @@ -559,6 +588,8 @@ #define SK_PNMI_ERR050MSG "MacUpdate: Cannot update statistic counter" #define SK_PNMI_ERR051 (SK_ERRBASE_PNMI + 51) #define SK_PNMI_ERR051MSG "SkPnmiEvent: Port switch suspicious" +#define SK_PNMI_ERR052 (SK_ERRBASE_PNMI + 52) +#define SK_PNMI_ERR052MSG "MacPrivateConf: SK_HWEV_SET_ROLE returned not 0" /* * Management counter macros called by the driver @@ -592,9 +623,16 @@ #define SK_PNMI_CNT_SYNC_OCTETS(pAC,p,v) \ { \ - if (((p) >= 0) && ((p) < SK_MAX_MACS)) { \ - ((pAC)->Pnmi.StatSyncCts[p])++; \ - (pAC)->Pnmi.StatSyncOctetsCts[p] += (SK_U64)(v); \ + if ((p) < SK_MAX_MACS) { \ + ((pAC)->Pnmi.Port[p].StatSyncCts)++; \ + (pAC)->Pnmi.Port[p].StatSyncOctetsCts += (SK_U64)(v); \ + } \ + } + +#define SK_PNMI_CNT_RX_LONGFRAMES(pAC,p) \ + { \ + if ((p) < SK_MAX_MACS) { \ + ((pAC)->Pnmi.Port[p].StatRxLongFrameCts)++; \ } \ } @@ -687,6 +725,7 @@ SK_U64 StatRxBroadcastOkCts; SK_U64 StatRxMulticastOkCts; SK_U64 StatRxUnicastOkCts; + SK_U64 StatRxLongFramesCts; SK_U64 StatRxPauseMacCtrlCts; SK_U64 StatRxMacCtrlCts; SK_U64 StatRxPauseMacCtrlErrorCts; @@ -809,8 +848,9 @@ } SK_PNMI_STRUCT_DATA; #define SK_PNMI_STRUCT_SIZE (sizeof(SK_PNMI_STRUCT_DATA)) -#define SK_PNMI_MIN_STRUCT_SIZE ((unsigned int)&(((SK_PNMI_STRUCT_DATA *)0)->\ - VpdFreeBytes)) /* +#define SK_PNMI_MIN_STRUCT_SIZE ((unsigned int)(SK_UPTR)\ + &(((SK_PNMI_STRUCT_DATA *)0)->VpdFreeBytes)) + /* * ReturnStatus field * must be located * before VpdFreeBytes @@ -822,7 +862,7 @@ #define SK_PNMI_MAX_PROTOS 3 #define SK_PNMI_SCNT_NOT 64 -#define SK_PNMI_CNT_NO 66 +#define SK_PNMI_CNT_NO 67 /* * Estimate data structure @@ -843,6 +883,7 @@ SK_U64 CounterOffset[SK_PNMI_CNT_NO]; SK_U64 StatSyncCts; SK_U64 StatSyncOctetsCts; + SK_U64 StatRxLongFrameCts; SK_BOOL ActiveFlag; } SK_PNMI_PORT; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/sk98lin/h/skgesirq.h linux/drivers/net/sk98lin/h/skgesirq.h --- v2.4.0-test8/linux/drivers/net/sk98lin/h/skgesirq.h Tue Nov 23 10:15:42 1999 +++ linux/drivers/net/sk98lin/h/skgesirq.h Fri Sep 15 14:34:19 2000 @@ -2,8 +2,8 @@ * * Name: skgesirq.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.18 $ - * Date: $Date: 1999/05/19 07:32:59 $ + * Version: $Revision: 1.20 $ + * Date: $Date: 1999/12/06 10:00:44 $ * Purpose: SK specific Gigabit Ethernet special IRQ functions * ******************************************************************************/ @@ -26,6 +26,12 @@ * * History: * $Log: skgesirq.h,v $ + * Revision 1.20 1999/12/06 10:00:44 cgoos + * Added SET event for role. + * + * Revision 1.19 1999/11/22 13:58:26 cgoos + * Changed license header to GPL. + * * Revision 1.18 1999/05/19 07:32:59 cgoos * Changes for 1000Base-T. * @@ -99,6 +105,7 @@ #define SK_HWEV_UPDATE_STAT 5 /* Update Statistics by PNMI */ #define SK_HWEV_SET_LMODE 6 /* Set Link Mode by PNMI */ #define SK_HWEV_SET_FLOWMODE 7 /* Set Flow Control Mode by PNMI */ +#define SK_HWEV_SET_ROLE 8 /* Set Master/Slave (Role) by PNMI */ #define SK_WA_ACT_TIME (5000000L) /* 5 sec */ #define SK_WA_INA_TIME (100000L) /* 100 msec */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/sk98lin/h/ski2c.h linux/drivers/net/sk98lin/h/ski2c.h --- v2.4.0-test8/linux/drivers/net/sk98lin/h/ski2c.h Tue Nov 23 10:15:42 1999 +++ linux/drivers/net/sk98lin/h/ski2c.h Fri Sep 15 14:34:19 2000 @@ -2,8 +2,8 @@ * * Name: ski2c.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.27 $ - * Date: $Date: 1999/05/20 09:23:10 $ + * Version: $Revision: 1.29 $ + * Date: $Date: 2000/08/03 14:28:17 $ * Purpose: Defines to access Voltage and Temperature Sensor * (taken from Monalisa (taken from Concentrator)) * @@ -28,6 +28,13 @@ * History: * * $Log: ski2c.h,v $ + * Revision 1.29 2000/08/03 14:28:17 rassmann + * - Added function to wait for I2C being ready before resetting the board. + * - Replaced one duplicate "out of range" message with correct one. + * + * Revision 1.28 1999/11/22 13:55:46 cgoos + * Changed license header to GPL. + * * Revision 1.27 1999/05/20 09:23:10 cgoos * Changes for 1000Base-T (Fan sensors). * @@ -254,9 +261,9 @@ extern int SkI2cReadSensor(SK_AC *pAC, SK_IOC IoC, SK_SENSOR *pSen); #ifndef SK_DIAG -extern int SkI2cEvent(SK_AC *pAC, SK_IOC IoC, SK_U32 Event, - SK_EVPARA Para); +extern int SkI2cEvent(SK_AC *pAC, SK_IOC IoC, SK_U32 Event, SK_EVPARA Para); extern int SkI2cInit(SK_AC *pAC, SK_IOC IoC, int Level); +extern void SkI2cWaitIrq(SK_AC *pAC, SK_IOC IoC); extern void SkI2cIsr(SK_AC *pAC, SK_IOC IoC); #endif diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/sk98lin/h/skqueue.h linux/drivers/net/sk98lin/h/skqueue.h --- v2.4.0-test8/linux/drivers/net/sk98lin/h/skqueue.h Tue Nov 23 10:15:42 1999 +++ linux/drivers/net/sk98lin/h/skqueue.h Fri Sep 15 14:34:19 2000 @@ -2,8 +2,8 @@ * * Name: skqueue.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.12 $ - * Date: $Date: 1998/09/08 08:48:01 $ + * Version: $Revision: 1.13 $ + * Date: $Date: 1999/11/22 13:59:05 $ * Purpose: Defines for the Event queue * ******************************************************************************/ @@ -27,6 +27,9 @@ * History: * * $Log: skqueue.h,v $ + * Revision 1.13 1999/11/22 13:59:05 cgoos + * Changed license header to GPL. + * * Revision 1.12 1998/09/08 08:48:01 gklug * add: init level handling * diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/sk98lin/h/skrlmt.h linux/drivers/net/sk98lin/h/skrlmt.h --- v2.4.0-test8/linux/drivers/net/sk98lin/h/skrlmt.h Tue Nov 23 10:15:42 1999 +++ linux/drivers/net/sk98lin/h/skrlmt.h Fri Sep 15 14:34:19 2000 @@ -2,8 +2,8 @@ * * Name: skrlmt.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.26 $ - * Date: $Date: 1999/10/04 14:01:19 $ + * Version: $Revision: 1.27 $ + * Date: $Date: 1999/11/22 13:59:56 $ * Purpose: Header file for Redundant Link ManagemenT. * ******************************************************************************/ @@ -27,6 +27,9 @@ * History: * * $Log: skrlmt.h,v $ + * Revision 1.27 1999/11/22 13:59:56 cgoos + * Changed license header to GPL. + * * Revision 1.26 1999/10/04 14:01:19 rassmann * Corrected reaction to reception of BPDU frames. * Added parameter descriptions to "For Readme" section skrlmt.txt. diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/sk98lin/h/sktimer.h linux/drivers/net/sk98lin/h/sktimer.h --- v2.4.0-test8/linux/drivers/net/sk98lin/h/sktimer.h Tue Nov 23 10:15:42 1999 +++ linux/drivers/net/sk98lin/h/sktimer.h Fri Sep 15 14:34:19 2000 @@ -2,8 +2,8 @@ * * Name: sktimer.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.8 $ - * Date: $Date: 1998/09/08 08:48:02 $ + * Version: $Revision: 1.9 $ + * Date: $Date: 1999/11/22 14:00:29 $ * Purpose: Defines for the timer functions * ******************************************************************************/ @@ -27,6 +27,9 @@ * History: * * $Log: sktimer.h,v $ + * Revision 1.9 1999/11/22 14:00:29 cgoos + * Changed license header to GPL. + * * Revision 1.8 1998/09/08 08:48:02 gklug * add: init level handling * diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/sk98lin/h/sktypes.h linux/drivers/net/sk98lin/h/sktypes.h --- v2.4.0-test8/linux/drivers/net/sk98lin/h/sktypes.h Tue Nov 23 10:15:42 1999 +++ linux/drivers/net/sk98lin/h/sktypes.h Fri Sep 15 14:34:19 2000 @@ -2,8 +2,8 @@ * * Name: sktypes.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.1 $ - * Date: $Date: 1999/02/16 07:41:40 $ + * Version: $Revision: 1.2 $ + * Date: $Date: 1999/11/22 14:01:58 $ * Purpose: Define data types for Linux * ******************************************************************************/ @@ -27,6 +27,10 @@ * History: * * $Log: sktypes.h,v $ + * Revision 1.2 1999/11/22 14:01:58 cgoos + * Changed license header to GPL. + * Now using Linux' fixed size types instead of standard types. + * * Revision 1.1 1999/02/16 07:41:40 cgoos * First version. * diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/sk98lin/h/skvpd.h linux/drivers/net/sk98lin/h/skvpd.h --- v2.4.0-test8/linux/drivers/net/sk98lin/h/skvpd.h Tue Nov 23 10:15:42 1999 +++ linux/drivers/net/sk98lin/h/skvpd.h Fri Sep 15 14:34:19 2000 @@ -2,15 +2,15 @@ * * Name: skvpd.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.8 $ - * Date: $Date: 1999/03/11 14:26:40 $ + * Version: $Revision: 1.10 $ + * Date: $Date: 2000/08/10 11:29:07 $ * Purpose: Defines and Macros for VPD handling * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998,1999 SysKonnect, + * (C)Copyright 1998-2000 SysKonnect, * a business unit of Schneider & Koch & Co. Datensysteme GmbH. * * This program is free software; you can redistribute it and/or modify @@ -27,6 +27,15 @@ * History: * * $Log: skvpd.h,v $ + * Revision 1.10 2000/08/10 11:29:07 rassmann + * Editorial changes. + * Preserving 32-bit alignment in structs for the adapter context. + * Removed unused function VpdWriteDword() (#if 0). + * Made VpdReadKeyword() available for SKDIAG only. + * + * Revision 1.9 1999/11/22 14:02:27 cgoos + * Changed license header to GPL. + * * Revision 1.8 1999/03/11 14:26:40 malthoff * Replace __STDC__ with SK_KR_PROTO. * @@ -112,40 +121,42 @@ /* VPD status */ /* bit 7..1 reserved */ -#define VPD_VALID (1<<0) /* VPD data buffer, vpd_free_ro, */ - /* and vpd_free_rw valid */ +#define VPD_VALID (1<<0) /* VPD data buffer, vpd_free_ro, */ + /* and vpd_free_rw valid */ /* * VPD structs */ typedef struct s_vpd_status { - unsigned short vpd_status ; /* VPD status, description see above */ - int vpd_free_ro ; /* unused bytes in read only area */ - int vpd_free_rw ; /* bytes available in read/write area */ + unsigned short Align01; /* Alignment */ + unsigned short vpd_status; /* VPD status, description see above */ + int vpd_free_ro; /* unused bytes in read only area */ + int vpd_free_rw; /* bytes available in read/write area */ } SK_VPD_STATUS; typedef struct s_vpd { - SK_VPD_STATUS v ; /* VPD status structure */ - char vpd_buf[VPD_SIZE] ; /* VPD buffer */ + SK_VPD_STATUS v; /* VPD status structure */ + char vpd_buf[VPD_SIZE]; /* VPD buffer */ } SK_VPD; typedef struct s_vpd_para { - unsigned int p_len ; /* parameter length */ - char *p_val ; /* points to the value */ + unsigned int p_len; /* parameter length */ + char *p_val; /* points to the value */ } SK_VPD_PARA; /* * structure of Large Resource Type Identifiers */ -/* was removed, because of alignment problems */ + +/* was removed because of alignment problems */ /* * sturcture of VPD keywords */ typedef struct s_vpd_key { - char p_key[2] ; /* 2 bytes ID string */ - unsigned char p_len ; /* 1 byte length */ - char p_val ; /* start of the value string */ + char p_key[2]; /* 2 bytes ID string */ + unsigned char p_len; /* 1 byte length */ + char p_val; /* start of the value string */ } SK_VPD_KEY; @@ -169,39 +180,39 @@ #define VPD_IN32(pAC,IoC,Addr,pVal) SK_IN32(IoC,PCI_C(Addr),pVal) #endif /* VPD_DO_IO */ #else /* SKDIAG */ -#define VPD_OUT8(pAC,Ioc,Addr,Val) { \ +#define VPD_OUT8(pAC,Ioc,Addr,Val) { \ if ((pAC)->DgT.DgUseCfgCycle) \ - SkPciWriteCfgByte(pAC,Addr,Val) ; \ - else \ + SkPciWriteCfgByte(pAC,Addr,Val); \ + else \ SK_OUT8(pAC,PCI_C(Addr),Val); \ } -#define VPD_OUT16(pAC,Ioc,Addr,Val) { \ +#define VPD_OUT16(pAC,Ioc,Addr,Val) { \ if ((pAC)->DgT.DgUseCfgCycle) \ - SkPciWriteCfgWord(pAC,Addr,Val) ; \ + SkPciWriteCfgWord(pAC,Addr,Val); \ else \ SK_OUT16(pAC,PCI_C(Addr),Val); \ } -#define VPD_OUT32(pAC,Ioc,Addr,Val) { \ +#define VPD_OUT32(pAC,Ioc,Addr,Val) { \ if ((pAC)->DgT.DgUseCfgCycle) \ - SkPciWriteCfgDWord(pAC,Addr,Val) ; \ + SkPciWriteCfgDWord(pAC,Addr,Val); \ else \ SK_OUT32(pAC,PCI_C(Addr),Val); \ } -#define VPD_IN8(pAC,Ioc,Addr,pVal) { \ +#define VPD_IN8(pAC,Ioc,Addr,pVal) { \ if ((pAC)->DgT.DgUseCfgCycle) \ - SkPciReadCfgByte(pAC,Addr,pVal) ; \ + SkPciReadCfgByte(pAC,Addr,pVal); \ else \ SK_IN8(pAC,PCI_C(Addr),pVal); \ } -#define VPD_IN16(pAC,Ioc,Addr,pVal) { \ +#define VPD_IN16(pAC,Ioc,Addr,pVal) { \ if ((pAC)->DgT.DgUseCfgCycle) \ - SkPciReadCfgWord(pAC,Addr,pVal) ; \ + SkPciReadCfgWord(pAC,Addr,pVal); \ else \ SK_IN16(pAC,PCI_C(Addr),pVal); \ } -#define VPD_IN32(pAC,Ioc,Addr,pVal) { \ +#define VPD_IN32(pAC,Ioc,Addr,pVal) { \ if ((pAC)->DgT.DgUseCfgCycle) \ - SkPciReadCfgDWord(pAC,Addr,pVal) ; \ + SkPciReadCfgDWord(pAC,Addr,pVal); \ else \ SK_IN32(pAC,PCI_C(Addr),pVal); \ } @@ -210,50 +221,52 @@ /* function prototypes ********************************************************/ #ifndef SK_KR_PROTO +#ifdef SKDIAG extern SK_U32 VpdReadDWord( SK_AC *pAC, SK_IOC IoC, - int addr) ; + int addr); +#endif /* SKDIAG */ extern int VpdSetupPara( SK_AC *pAC, char *key, char *buf, - int len, - int type, - int op) ; + int len, + int type, + int op); extern SK_VPD_STATUS *VpdStat( SK_AC *pAC, - SK_IOC IoC) ; + SK_IOC IoC); extern int VpdKeys( SK_AC *pAC, SK_IOC IoC, char *buf, - int *len, - int *elements) ; + int *len, + int *elements); extern int VpdRead( SK_AC *pAC, SK_IOC IoC, char *key, char *buf, - int *len) ; + int *len); extern SK_BOOL VpdMayWrite( - char *key) ; + char *key); extern int VpdWrite( SK_AC *pAC, SK_IOC IoC, char *key, - char *buf) ; + char *buf); extern int VpdDelete( SK_AC *pAC, SK_IOC IoC, - char *key) ; + char *key); extern int VpdUpdate( SK_AC *pAC, @@ -262,34 +275,34 @@ extern void VpdErrLog( SK_AC *pAC, SK_IOC IoC, - char *msg) ; + char *msg); #ifdef SKDIAG extern int VpdReadBlock( SK_AC *pAC, SK_IOC IoC, char *buf, - int addr, - int len) ; + int addr, + int len); extern int VpdWriteBlock( SK_AC *pAC, SK_IOC IoC, char *buf, - int addr, - int len) ; + int addr, + int len); #endif /* SKDIAG */ #else /* SK_KR_PROTO */ -extern SK_U32 VpdReadDWord() ; -extern int VpdSetupPara() ; -extern SK_VPD_STATUS *VpdStat() ; -extern int VpdKeys() ; -extern int VpdRead() ; -extern SK_BOOL VpdMayWrite() ; -extern int VpdWrite() ; -extern int VpdDelete() ; -extern int VpdUpdate() ; -extern void VpdErrLog() ; +extern SK_U32 VpdReadDWord(); +extern int VpdSetupPara(); +extern SK_VPD_STATUS *VpdStat(); +extern int VpdKeys(); +extern int VpdRead(); +extern SK_BOOL VpdMayWrite(); +extern int VpdWrite(); +extern int VpdDelete(); +extern int VpdUpdate(); +extern void VpdErrLog(); #endif /* SK_KR_PROTO */ #endif /* __INC_SKVPD_H_ */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/sk98lin/h/xmac_ii.h linux/drivers/net/sk98lin/h/xmac_ii.h --- v2.4.0-test8/linux/drivers/net/sk98lin/h/xmac_ii.h Tue Nov 23 10:15:42 1999 +++ linux/drivers/net/sk98lin/h/xmac_ii.h Fri Sep 15 14:34:19 2000 @@ -2,8 +2,8 @@ * * Name: xmac_ii.h * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.25 $ - * Date: $Date: 1999/08/12 19:19:38 $ + * Version: $Revision: 1.27 $ + * Date: $Date: 2000/05/17 11:00:46 $ * Purpose: Defines and Macros for XaQti's Gigabit Ethernet Controller * ******************************************************************************/ @@ -27,6 +27,12 @@ * History: * * $Log: xmac_ii.h,v $ + * Revision 1.27 2000/05/17 11:00:46 malthoff + * Add bit for enable/disable power management in BCOM chip. + * + * Revision 1.26 1999/11/22 14:03:00 cgoos + * Changed license header to GPL. + * * Revision 1.25 1999/08/12 19:19:38 malthoff * Add PHY_B_AC_TX_TST bit according to BCOM A1 errata sheet. * @@ -930,7 +936,9 @@ #define PHY_B_AC_TX_TST (1<<10) /* Bit 10: tx test bit, always 1 */ /* Bit 9.. 8: reserved */ #define PHY_B_AC_DIS_PRF (1<<7) /* Bit 7: dis part resp filter */ - /* Bit 6.. 4: reserved */ + /* Bit 6: reserved */ +#define PHY_B_AC_DIS_PM (1<<5) /* Bit 5: dis power management */ + /* Bit 4: reserved */ #define PHY_B_AC_DIAG (1<<3) /* Bit 3: Diagnostic Mode */ /* Bit 2.. 0: reserved */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/sk98lin/skaddr.c linux/drivers/net/sk98lin/skaddr.c --- v2.4.0-test8/linux/drivers/net/sk98lin/skaddr.c Tue Nov 23 10:15:42 1999 +++ linux/drivers/net/sk98lin/skaddr.c Fri Sep 15 14:34:19 2000 @@ -2,19 +2,17 @@ * * Name: skaddr.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.33 $ - * Date: $Date: 1999/05/28 10:56:06 $ - * Purpose: Manage Addresses (Multicast and Unicast) and Promiscuous Mode + * Version: $Revision: 1.36 $ + * Date: $Date: 2000/08/07 11:10:39 $ + * Purpose: Manage Addresses (Multicast and Unicast) and Promiscuous Mode. * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998,1999 SysKonnect, + * (C)Copyright 1998-2000 SysKonnect, * a business unit of Schneider & Koch & Co. Datensysteme GmbH. * - * See the file "skge.c" for further information. - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -29,6 +27,16 @@ * History: * * $Log: skaddr.c,v $ + * Revision 1.36 2000/08/07 11:10:39 rassmann + * Editorial changes. + * + * Revision 1.35 2000/05/04 09:38:41 rassmann + * Editorial changes. + * Corrected multicast address hashing. + * + * Revision 1.34 1999/11/22 13:23:44 cgoos + * Changed license header to GPL. + * * Revision 1.33 1999/05/28 10:56:06 rassmann * Editorial changes. * @@ -164,13 +172,13 @@ #ifndef lint static const char SysKonnectFileId[] = - "@(#) $Id: skaddr.c,v 1.33 1999/05/28 10:56:06 rassmann Exp $ (C) SysKonnect."; + "@(#) $Id: skaddr.c,v 1.36 2000/08/07 11:10:39 rassmann Exp $ (C) SysKonnect."; #endif /* !defined(lint) */ #define __SKADDR_C #ifdef __cplusplus -xxxx /* not supported yet - force error */ +#error C++ is not yet supported. extern "C" { #endif /* cplusplus */ @@ -179,19 +187,9 @@ /* defines ********************************************************************/ -#define SK_ADDR_CHEAT YES /* Cheat. */ - -/* - * G32: - * POLY equ 04C11DB6h ; CRC polynominal term - * bit-reversed: 6DB88320 - */ #define CRC32_POLY 0xEDB88320UL /* CRC32-Poly - XMAC: Little Endian */ -#if 0 -#define CRC32_POLY 0x6DB88320UL /* CRC32-Poly - XMAC: Little Endian */ -#endif /* 0 */ -#define HASH_BITS 6 /* #bits in hash */ +#define HASH_BITS 6 /* #bits in hash */ #define SK_MC_BIT 0x01 /* Error numbers and messages. */ @@ -219,13 +217,6 @@ /* functions ******************************************************************/ -#if 0 -void SkAddrDummy(void) -{ - SkAddrInit(NULL, NULL, 0); -} /* SkAddrDummy */ -#endif /* 0 */ - /****************************************************************************** * * SkAddrInit - initialize data, set state to init @@ -236,7 +227,7 @@ * ============ * * This routine clears the multicast tables and resets promiscuous mode. - * Some entries are reserved for the "logical board address", the + * Some entries are reserved for the "logical MAC address", the * SK-RLMT multicast address, and the BPDU multicast address. * * @@ -263,12 +254,12 @@ int SkAddrInit( SK_AC *pAC, /* the adapter context */ SK_IOC IoC, /* I/O context */ -int Level) /* initialization level */ +int Level) /* initialization level */ { - int j; - SK_U32 i; - SK_U8 *InAddr; - SK_U16 *OutAddr; + int j; + SK_U32 i; + SK_U8 *InAddr; + SK_U16 *OutAddr; SK_ADDR_PORT *pAPort; switch (Level) { @@ -279,20 +270,15 @@ pAPort = &pAC->Addr.Port[i]; pAPort->PromMode = SK_PROM_MODE_NONE; - pAPort->FirstExactMatchRlmt = - SK_ADDR_FIRST_MATCH_RLMT; - pAPort->FirstExactMatchDrv = - SK_ADDR_FIRST_MATCH_DRV; - pAPort->NextExactMatchRlmt = - SK_ADDR_FIRST_MATCH_RLMT; - pAPort->NextExactMatchDrv = - SK_ADDR_FIRST_MATCH_DRV; + pAPort->FirstExactMatchRlmt = SK_ADDR_FIRST_MATCH_RLMT; + pAPort->FirstExactMatchDrv = SK_ADDR_FIRST_MATCH_DRV; + pAPort->NextExactMatchRlmt = SK_ADDR_FIRST_MATCH_RLMT; + pAPort->NextExactMatchDrv = SK_ADDR_FIRST_MATCH_DRV; #if 0 - /* Not here ... */ + /* Don't do this here ... */ /* Reset Promiscuous mode. */ - (void)SkAddrPromiscuousChange( pAC, IoC, @@ -325,8 +311,7 @@ } #endif /* DEBUG */ - /* Read permanent virtual address from Control Register File. */ - + /* Read permanent logical MAC address from Control Register File. */ for (j = 0; j < SK_MAC_ADDR_LEN; j++) { InAddr = (SK_U8 *)&pAC->Addr.PermanentMacAddress.a[j]; SK_IN8(IoC, B2_MAC_1 + j, InAddr); @@ -334,17 +319,15 @@ if (!pAC->Addr.CurrentMacAddressSet) { /* - * Set the current virtual MAC address + * Set the current logical MAC address * to the permanent one. */ - pAC->Addr.CurrentMacAddress = pAC->Addr.PermanentMacAddress; pAC->Addr.CurrentMacAddressSet = SK_TRUE; } - /* Set the current virtual MAC address. */ - + /* Set the current logical MAC address. */ pAC->Addr.Port[pAC->Addr.ActivePort].Exact[0] = pAC->Addr.CurrentMacAddress; @@ -354,27 +337,27 @@ SK_DBGMOD_ADDR, SK_DBGCAT_INIT, ("Permanent MAC Address: %02X %02X %02X %02X %02X %02X\n", - pAC->Addr.PermanentMacAddress.a[0], - pAC->Addr.PermanentMacAddress.a[1], - pAC->Addr.PermanentMacAddress.a[2], - pAC->Addr.PermanentMacAddress.a[3], - pAC->Addr.PermanentMacAddress.a[4], - pAC->Addr.PermanentMacAddress.a[5])) + pAC->Addr.PermanentMacAddress.a[0], + pAC->Addr.PermanentMacAddress.a[1], + pAC->Addr.PermanentMacAddress.a[2], + pAC->Addr.PermanentMacAddress.a[3], + pAC->Addr.PermanentMacAddress.a[4], + pAC->Addr.PermanentMacAddress.a[5])) SK_DBG_MSG( pAC, SK_DBGMOD_ADDR, SK_DBGCAT_INIT, - ("Virtual MAC Address: %02X %02X %02X %02X %02X %02X\n", - pAC->Addr.CurrentMacAddress.a[0], - pAC->Addr.CurrentMacAddress.a[1], - pAC->Addr.CurrentMacAddress.a[2], - pAC->Addr.CurrentMacAddress.a[3], - pAC->Addr.CurrentMacAddress.a[4], - pAC->Addr.CurrentMacAddress.a[5])) + ("Logical MAC Address: %02X %02X %02X %02X %02X %02X\n", + pAC->Addr.CurrentMacAddress.a[0], + pAC->Addr.CurrentMacAddress.a[1], + pAC->Addr.CurrentMacAddress.a[2], + pAC->Addr.CurrentMacAddress.a[3], + pAC->Addr.CurrentMacAddress.a[4], + pAC->Addr.CurrentMacAddress.a[5])) #endif /* DEBUG */ #if 0 - /* Not here ... */ + /* Don't do this here ... */ (void)SkAddrMcUpdate(pAC, IoC, pAC->Addr.ActivePort); #endif /* 0 */ @@ -386,10 +369,8 @@ * Read permanent port addresses from * Control Register File. */ - for (j = 0; j < SK_MAC_ADDR_LEN; j++) { - InAddr = (SK_U8 *) - &pAPort->PermanentMacAddress.a[j]; + InAddr = (SK_U8 *)&pAPort->PermanentMacAddress.a[j]; SK_IN8(IoC, B2_MAC_2 + 8 * i + j, InAddr); } @@ -399,16 +380,12 @@ * MAC address of this port to its permanent * MAC address. */ - - pAPort->CurrentMacAddress = - pAPort->PermanentMacAddress; - pAPort->PreviousMacAddress = - pAPort->PermanentMacAddress; + pAPort->CurrentMacAddress = pAPort->PermanentMacAddress; + pAPort->PreviousMacAddress = pAPort->PermanentMacAddress; pAPort->CurrentMacAddressSet = SK_TRUE; } /* Set port's current MAC addresses. */ - OutAddr = (SK_U16 *)&pAPort->CurrentMacAddress.a[0]; XM_OUTADDR(IoC, i, XM_SA, OutAddr); @@ -484,7 +461,7 @@ SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* I/O context */ SK_U32 PortIdx, /* Index of affected port */ -int Flags) /* permanent/non-perm, sw-only */ +int Flags) /* permanent/non-perm, sw-only */ { int i; @@ -495,9 +472,7 @@ if (Flags & SK_ADDR_PERMANENT) { /* Clear RLMT multicast addresses. */ - - pAC->Addr.Port[PortIdx].NextExactMatchRlmt = - SK_ADDR_FIRST_MATCH_RLMT; + pAC->Addr.Port[PortIdx].NextExactMatchRlmt = SK_ADDR_FIRST_MATCH_RLMT; } else { /* not permanent => DRV */ @@ -509,8 +484,7 @@ /* Clear DRV multicast addresses. */ - pAC->Addr.Port[PortIdx].NextExactMatchDrv = - SK_ADDR_FIRST_MATCH_DRV; + pAC->Addr.Port[PortIdx].NextExactMatchDrv = SK_ADDR_FIRST_MATCH_DRV; } if (!(Flags & SK_MC_SW_ONLY)) { @@ -521,7 +495,7 @@ } /* SkAddrMcClear */ #ifndef SK_ADDR_CHEAT -// RA;:;: + /****************************************************************************** * * SkCrc32McHash - hash multicast address @@ -548,15 +522,13 @@ Crc = 0xFFFFFFFFUL; for (Idx = 0; Idx < SK_MAC_ADDR_LEN; Idx++) { - Data = *pMc++; + Data = *pMc++; for (Bit = 0; Bit < 8; Bit++, Data >>= 1) { - Crc = (Crc >> 1) ^ - (((Crc ^ Data) & 1) ? CRC32_POLY : 0); + Crc = (Crc >> 1) ^ (((Crc ^ Data) & 1) ? CRC32_POLY : 0); } } return (Crc & ((1 << HASH_BITS) - 1)); - } /* SkCrc32McHash */ #endif /* not SK_ADDR_CHEAT */ @@ -593,7 +565,7 @@ SK_IOC IoC, /* I/O context */ SK_U32 PortIdx, /* Port Index */ SK_MAC_ADDR *pMc, /* multicast address to be added */ -int Flags) /* permanent/non-permanent */ +int Flags) /* permanent/non-permanent */ { int i; SK_U8 Inexact; @@ -628,11 +600,9 @@ } /* Not PERMANENT => DRV */ - if (PortIdx != pAC->Addr.ActivePort) { /* Only RLMT is allowed to do this. */ - return (SK_MC_ILLEGAL_PORT); } @@ -647,41 +617,31 @@ if (pAC->Addr.Port[PortIdx].NextExactMatchDrv <= SK_ADDR_LAST_MATCH_DRV) { /* Set exact match entry. */ - pAC->Addr.Port[PortIdx].Exact[ pAC->Addr.Port[PortIdx].NextExactMatchDrv++] = *pMc; /* Clear InexactFilter. */ - for (i = 0; i < 8; i++) { - pAC->Addr.Port[PortIdx - ].InexactFilter.Bytes[i] = 0; + pAC->Addr.Port[PortIdx].InexactFilter.Bytes[i] = 0; } } else { if (!(pMc->a[0] & SK_MC_BIT)) { - /* * Hashing only possible with * multicast addresses. */ - return (SK_MC_ILLEGAL_ADDRESS); } #ifndef SK_ADDR_CHEAT /* Compute hash value of address. */ -RA;:;: untested - HashBit = SkCrc32McHash(&pMc->a[0]); + HashBit = 63 - SkCrc32McHash(&pMc->a[0]); /* Add bit to InexactFilter. */ - pAC->Addr.Port[PortIdx].InexactFilter.Bytes[HashBit / 8] |= 1 << (HashBit % 8); - #else /* SK_ADDR_CHEAT */ - /* Set all bits in InexactFilter. */ - for (i = 0; i < 8; i++) { pAC->Addr.Port[PortIdx].InexactFilter.Bytes[i] = 0xFF; } @@ -727,10 +687,10 @@ SK_IOC IoC, /* I/O context */ SK_U32 PortIdx) /* Port Index */ { - SK_U32 i; - SK_U8 Inexact; - SK_U16 *OutAddr; - SK_U16 LoMode; /* Lower 16 bits of XMAC Mode Reg. */ + SK_U32 i; + SK_U8 Inexact; + SK_U16 *OutAddr; + SK_U16 LoMode; /* Lower 16 bits of XMAC Mode Reg. */ SK_ADDR_PORT *pAPort; if (PortIdx >= (SK_U32)pAC->GIni.GIMacsFound) { @@ -753,18 +713,16 @@ ("Next0 on Port %d: %d\n", PortIdx, Next0[PortIdx])) #endif /* DEBUG */ - for (i = 0; /* Also program the virtual address. */ + for (i = 0; /* Also program the logical MAC address. */ i < pAPort->NextExactMatchRlmt; i++) { /* Set exact match address i on HW. */ - OutAddr = (SK_U16 *)&pAPort->Exact[i].a[0]; XM_OUTADDR(IoC, PortIdx, XM_EXM(i), OutAddr); } /* Clear other permanent exact match addresses on HW. */ - if (pAPort->NextExactMatchRlmt <= SK_ADDR_LAST_MATCH_RLMT) { SkXmClrExactAddr( pAC, @@ -774,17 +732,12 @@ SK_ADDR_LAST_MATCH_RLMT); } - for (i = pAPort->FirstExactMatchDrv; - i < pAPort->NextExactMatchDrv; - i++) { - + for (i = pAPort->FirstExactMatchDrv; i < pAPort->NextExactMatchDrv; i++) { OutAddr = (SK_U16 *)&pAPort->Exact[i].a[0]; XM_OUTADDR(IoC, PortIdx, XM_EXM(i), OutAddr); - } /* Clear other non-permanent exact match addresses on HW. */ - if (pAPort->NextExactMatchDrv <= SK_ADDR_LAST_MATCH_DRV) { SkXmClrExactAddr( pAC, @@ -794,67 +747,51 @@ SK_ADDR_LAST_MATCH_DRV); } - for (Inexact = 0xFF, i = 0; i < 8; i++) { - Inexact &= pAPort->InexactFilter.Bytes[i]; + for (Inexact = 0, i = 0; i < 8; i++) { + Inexact |= pAPort->InexactFilter.Bytes[i]; } - if (pAPort->PromMode & SK_PROM_MODE_ALL_MC) { + if (pAPort->PromMode & SK_PROM_MODE_ALL_MC) { /* Set all bits in 64-bit hash register. */ - XM_OUTHASH(IoC, PortIdx, XM_HSM, &OnesHash); /* Set bit 15 in mode register. */ - XM_IN16(IoC, PortIdx, XM_MODE, &LoMode); LoMode |= XM_MD_ENA_HSH; XM_OUT16(IoC, PortIdx, XM_MODE, LoMode); } - else if (Inexact != 0xFF) { - - /* Clear bit 15 in mode register. */ + else if (Inexact != 0) { + /* Set 64-bit hash register to InexactFilter. */ + XM_OUTHASH(IoC, PortIdx, XM_HSM, &pAPort->InexactFilter.Bytes[0]); + /* Set bit 15 in mode register. */ XM_IN16(IoC, PortIdx, XM_MODE, &LoMode); - LoMode &= ~XM_MD_ENA_HSH; + LoMode |= XM_MD_ENA_HSH; XM_OUT16(IoC, PortIdx, XM_MODE, LoMode); } else { - /* Set 64-bit hash register to InexactFilter. */ - - XM_OUTHASH( - IoC, - PortIdx, - XM_HSM, - &pAPort->InexactFilter.Bytes[0]); - - /* Set bit 15 in mode register. */ - + /* Clear bit 15 in mode register. */ XM_IN16(IoC, PortIdx, XM_MODE, &LoMode); - LoMode |= XM_MD_ENA_HSH; + LoMode &= ~XM_MD_ENA_HSH; XM_OUT16(IoC, PortIdx, XM_MODE, LoMode); } if (pAPort->PromMode != SK_PROM_MODE_NONE) { - (void)SkAddrPromiscuousChange( - pAC, - IoC, - PortIdx, - pAPort->PromMode); + (void)SkAddrPromiscuousChange(pAC, IoC, PortIdx, pAPort->PromMode); } /* Set port's current MAC address. */ - OutAddr = (SK_U16 *)&pAPort->CurrentMacAddress.a[0]; XM_OUTADDR(IoC, PortIdx, XM_SA, OutAddr); #ifdef DEBUG - for (i = 0; /* Also program the virtual address. */ + for (i = 0; /* Also program the logical MAC address. */ i < pAPort->NextExactMatchRlmt; i++) { SK_U8 InAddr8[6]; SK_U16 *InAddr; /* Get exact match address i from port PortIdx. */ - InAddr = (SK_U16 *)&InAddr8[0]; XM_INADDR(IoC, PortIdx, XM_EXM(i), InAddr); SK_DBG_MSG( @@ -880,10 +817,6 @@ #endif /* DEBUG */ /* Determine return value. */ - - for (Inexact = 0, i = 0; i < 8; i++) { - Inexact |= pAPort->InexactFilter.Bytes[i]; - } if (Inexact == 0 && pAPort->PromMode == 0) { return (SK_MC_FILTERING_EXACT); } @@ -915,7 +848,7 @@ SK_IOC IoC, /* I/O context */ SK_U32 PortIdx, /* Port Index */ SK_MAC_ADDR *pNewAddr, /* new MAC address */ -int Flags) /* logical/physical address */ +int Flags) /* logical/physical MAC address */ { SK_U32 i; SK_U16 *OutAddr; @@ -957,7 +890,7 @@ return (SK_ADDR_TOO_EARLY); } - if (Flags & SK_ADDR_PHYSICAL_ADDRESS) { /* Physical address. */ + if (Flags & SK_ADDR_PHYSICAL_ADDRESS) { /* Physical MAC address. */ if (SK_ADDR_EQUAL(pNewAddr->a, pAC->Addr.CurrentMacAddress.a)) { return (SK_ADDR_DUPLICATE_ADDRESS); } @@ -984,16 +917,14 @@ pAC->Addr.Port[PortIdx].CurrentMacAddress = *pNewAddr; /* Change port's address. */ - OutAddr = (SK_U16 *)pNewAddr; XM_OUTADDR(IoC, PortIdx, XM_SA, OutAddr); /* Report address change to RLMT. */ - Para.Para32[0] = PortIdx; SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_PORT_ADDR, Para); } - else { /* Logical Address. */ + else { /* Logical MAC address. */ if (SK_ADDR_EQUAL(pNewAddr->a, pAC->Addr.CurrentMacAddress.a)) { return (SK_ADDR_SUCCESS); } @@ -1019,27 +950,26 @@ SK_DBGMOD_ADDR, SK_DBGCAT_CTRL, ("Permanent MAC Address: %02X %02X %02X %02X %02X %02X\n", - pAC->Addr.PermanentMacAddress.a[0], - pAC->Addr.PermanentMacAddress.a[1], - pAC->Addr.PermanentMacAddress.a[2], - pAC->Addr.PermanentMacAddress.a[3], - pAC->Addr.PermanentMacAddress.a[4], - pAC->Addr.PermanentMacAddress.a[5])) + pAC->Addr.PermanentMacAddress.a[0], + pAC->Addr.PermanentMacAddress.a[1], + pAC->Addr.PermanentMacAddress.a[2], + pAC->Addr.PermanentMacAddress.a[3], + pAC->Addr.PermanentMacAddress.a[4], + pAC->Addr.PermanentMacAddress.a[5])) SK_DBG_MSG( pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL, - ("New Virtual MAC Address: %02X %02X %02X %02X %02X %02X\n", - pAC->Addr.CurrentMacAddress.a[0], - pAC->Addr.CurrentMacAddress.a[1], - pAC->Addr.CurrentMacAddress.a[2], - pAC->Addr.CurrentMacAddress.a[3], - pAC->Addr.CurrentMacAddress.a[4], - pAC->Addr.CurrentMacAddress.a[5])) + ("New logical MAC Address: %02X %02X %02X %02X %02X %02X\n", + pAC->Addr.CurrentMacAddress.a[0], + pAC->Addr.CurrentMacAddress.a[1], + pAC->Addr.CurrentMacAddress.a[2], + pAC->Addr.CurrentMacAddress.a[3], + pAC->Addr.CurrentMacAddress.a[4], + pAC->Addr.CurrentMacAddress.a[5])) #endif /* DEBUG */ /* Write address to first exact match entry of active port. */ - (void)SkAddrMcUpdate(pAC, IoC, PortIdx); } @@ -1066,25 +996,24 @@ * SK_ADDR_ILLEGAL_PORT */ int SkAddrPromiscuousChange( -SK_AC *pAC, /* adapter context */ -SK_IOC IoC, /* I/O context */ -SK_U32 PortIdx, /* port whose promiscuous mode changes */ -int NewPromMode) /* new promiscuous mode */ +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* I/O context */ +SK_U32 PortIdx, /* port whose promiscuous mode changes */ +int NewPromMode) /* new promiscuous mode */ { - int i; + int i; SK_BOOL InexactModeBit; SK_U8 Inexact; SK_U8 HwInexact; SK_FILTER64 HwInexactFilter; SK_U16 LoMode; /* Lower 16 bits of XMAC Mode Register. */ - int CurPromMode = SK_PROM_MODE_NONE; + int CurPromMode = SK_PROM_MODE_NONE; if (PortIdx >= (SK_U32)pAC->GIni.GIMacsFound) { return (SK_ADDR_ILLEGAL_PORT); } /* Read CurPromMode from Hardware. */ - XM_IN16(IoC, PortIdx, XM_MODE, &LoMode); if (LoMode & XM_MD_ENA_PROM) { @@ -1095,18 +1024,15 @@ Inexact &= pAC->Addr.Port[PortIdx].InexactFilter.Bytes[i]; } if (Inexact == 0xFF) { - CurPromMode |= (pAC->Addr.Port[PortIdx].PromMode & - SK_PROM_MODE_ALL_MC); + CurPromMode |= (pAC->Addr.Port[PortIdx].PromMode & SK_PROM_MODE_ALL_MC); } else { /* Read InexactModeBit (bit 15 in mode register). */ - XM_IN16(IoC, PortIdx, XM_MODE, &LoMode); - - InexactModeBit = (LoMode & XM_MD_ENA_HSH) != 0; + + InexactModeBit = (LoMode & XM_MD_ENA_HSH) != 0; /* Read 64-bit hash register from HW. */ - XM_INHASH(IoC, PortIdx, XM_HSM, &HwInexactFilter.Bytes[0]); for (HwInexact = 0xFF, i = 0; i < 8; i++) { @@ -1126,43 +1052,34 @@ if ((NewPromMode & SK_PROM_MODE_ALL_MC) && !(CurPromMode & SK_PROM_MODE_ALL_MC)) { /* All MC. */ - /* Set all bits in 64-bit hash register. */ - XM_OUTHASH(IoC, PortIdx, XM_HSM, &OnesHash); /* Set bit 15 in mode register. */ - XM_IN16(IoC, PortIdx, XM_MODE, &LoMode); LoMode |= XM_MD_ENA_HSH; XM_OUT16(IoC, PortIdx, XM_MODE, LoMode); } else if ((CurPromMode & SK_PROM_MODE_ALL_MC) && !(NewPromMode & SK_PROM_MODE_ALL_MC)) { /* Norm MC. */ - for (Inexact = 0, i = 0; i < 8; i++) { - Inexact |= - pAC->Addr.Port[PortIdx].InexactFilter.Bytes[i]; + Inexact |= pAC->Addr.Port[PortIdx].InexactFilter.Bytes[i]; } if (Inexact == 0) { /* Clear bit 15 in mode register. */ - XM_IN16(IoC, PortIdx, XM_MODE, &LoMode); LoMode &= ~XM_MD_ENA_HSH; XM_OUT16(IoC, PortIdx, XM_MODE, LoMode); } else { /* Set 64-bit hash register to InexactFilter. */ - XM_OUTHASH( IoC, PortIdx, XM_HSM, - &pAC->Addr.Port[PortIdx - ].InexactFilter.Bytes[0]); + &pAC->Addr.Port[PortIdx].InexactFilter.Bytes[0]); /* Set bit 15 in mode register. */ - XM_IN16(IoC, PortIdx, XM_MODE, &LoMode); LoMode |= XM_MD_ENA_HSH; XM_OUT16(IoC, PortIdx, XM_MODE, LoMode); @@ -1171,29 +1088,27 @@ if ((NewPromMode & SK_PROM_MODE_LLC) && !(CurPromMode & SK_PROM_MODE_LLC)) { /* Prom. LLC */ - /* Set promiscuous bit in mode register. */ - XM_IN16(IoC, PortIdx, XM_MODE, &LoMode); + #if 0 /* Receive MAC frames. */ - LoMode |= XM_MD_RX_MCTRL; #endif /* 0 */ + LoMode |= XM_MD_ENA_PROM; XM_OUT16(IoC, PortIdx, XM_MODE, LoMode); } else if ((CurPromMode & SK_PROM_MODE_LLC) && !(NewPromMode & SK_PROM_MODE_LLC)) { /* Norm. LLC. */ - /* Clear promiscuous bit in mode register. */ - XM_IN16(IoC, PortIdx, XM_MODE, &LoMode); + #if 0 /* Don't receive MAC frames. */ - LoMode &= ~XM_MD_RX_MCTRL; #endif /* 0 */ + LoMode &= ~XM_MD_ENA_PROM; XM_OUT16(IoC, PortIdx, XM_MODE, LoMode); } @@ -1218,12 +1133,12 @@ * SK_ADDR_ILLEGAL_PORT */ int SkAddrSwap( -SK_AC *pAC, /* adapter context */ -SK_IOC IoC, /* I/O context */ +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* I/O context */ SK_U32 FromPortIdx, /* Port1 Index */ -SK_U32 ToPortIdx) /* Port2 Index */ +SK_U32 ToPortIdx) /* Port2 Index */ { - int i; + int i; SK_U8 Byte; SK_MAC_ADDR MacAddr; SK_U32 DWord; @@ -1263,8 +1178,7 @@ } i = pAC->Addr.Port[FromPortIdx].PromMode; - pAC->Addr.Port[FromPortIdx].PromMode = - pAC->Addr.Port[ToPortIdx].PromMode; + pAC->Addr.Port[FromPortIdx].PromMode = pAC->Addr.Port[ToPortIdx].PromMode; pAC->Addr.Port[ToPortIdx].PromMode = i; DWord = pAC->Addr.Port[FromPortIdx].FirstExactMatchRlmt; @@ -1287,7 +1201,7 @@ pAC->Addr.Port[ToPortIdx].NextExactMatchDrv; pAC->Addr.Port[ToPortIdx].NextExactMatchDrv = DWord; - pAC->Addr.ActivePort = ToPortIdx; + pAC->Addr.ActivePort = ToPortIdx; (void)SkAddrMcUpdate(pAC, IoC, FromPortIdx); (void)SkAddrMcUpdate(pAC, IoC, ToPortIdx); @@ -1298,3 +1212,4 @@ #ifdef __cplusplus } #endif /* __cplusplus */ + diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/sk98lin/skcsum.c linux/drivers/net/sk98lin/skcsum.c --- v2.4.0-test8/linux/drivers/net/sk98lin/skcsum.c Tue Nov 23 10:15:42 1999 +++ linux/drivers/net/sk98lin/skcsum.c Fri Sep 15 14:34:19 2000 @@ -2,19 +2,17 @@ * * Name: skcsum.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.3 $ - * Date: $Date: 1999/05/10 08:39:33 $ + * Version: $Revision: 1.7 $ + * Date: $Date: 2000/06/29 13:17:05 $ * Purpose: Store/verify Internet checksum in send/receive packets. * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998,1999 SysKonnect, + * (C)Copyright 1998-2000 SysKonnect, * a business unit of Schneider & Koch & Co. Datensysteme GmbH. * - * See the file "skge.c" for further information. - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -29,6 +27,23 @@ * History: * * $Log: skcsum.c,v $ + * Revision 1.7 2000/06/29 13:17:05 rassmann + * Corrected reception of a packet with UDP checksum == 0 (which means there + * is no UDP checksum). + * + * Revision 1.6 2000/02/21 12:35:10 cgoos + * Fixed license header comment. + * + * Revision 1.5 2000/02/21 11:05:19 cgoos + * Merged changes back to common source. + * Fixed rx path for BIG ENDIAN architecture. + * + * Revision 1.1 1999/07/26 15:28:12 mkarl + * added return SKCS_STATUS_IP_CSUM_ERROR_UDP and + * SKCS_STATUS_IP_CSUM_ERROR_TCP to pass the NidsTester + * changed from common source to windows specific source + * therefore restarting with v1.0 + * * Revision 1.3 1999/05/10 08:39:33 mkarl * prevent overflows in SKCS_HTON16 * fixed a bug in pseudo header checksum calculation @@ -48,7 +63,7 @@ #ifndef lint static const char SysKonnectFileId[] = "@(#)" - "$Id: skcsum.c,v 1.3 1999/05/10 08:39:33 mkarl Exp $" + "$Id: skcsum.c,v 1.7 2000/06/29 13:17:05 rassmann Exp $" " (C) SysKonnect."; #endif /* !lint */ @@ -94,13 +109,13 @@ /* defines ********************************************************************/ /* The size of an Ethernet MAC header. */ -#define SKCS_ETHERNET_MAC_HEADER_SIZE (6+6+2) +#define SKCS_ETHERNET_MAC_HEADER_SIZE (6+6+2) /* The size of the used topology's MAC header. */ #define SKCS_MAC_HEADER_SIZE SKCS_ETHERNET_MAC_HEADER_SIZE /* The size of the IP header without any option fields. */ -#define SKCS_IP_HEADER_SIZE 20 +#define SKCS_IP_HEADER_SIZE 20 /* * Field offsets within the IP header. @@ -110,23 +125,31 @@ #define SKCS_OFS_IP_HEADER_VERSION_AND_LENGTH 0 /* "Total Length". */ -#define SKCS_OFS_IP_TOTAL_LENGTH 2 +#define SKCS_OFS_IP_TOTAL_LENGTH 2 /* "Flags" "Fragment Offset". */ #define SKCS_OFS_IP_FLAGS_AND_FRAGMENT_OFFSET 6 /* "Next Level Protocol" identifier. */ -#define SKCS_OFS_IP_NEXT_LEVEL_PROTOCOL 9 +#define SKCS_OFS_IP_NEXT_LEVEL_PROTOCOL 9 /* Source IP address. */ -#define SKCS_OFS_IP_SOURCE_ADDRESS 12 +#define SKCS_OFS_IP_SOURCE_ADDRESS 12 /* Destination IP address. */ -#define SKCS_OFS_IP_DESTINATION_ADDRESS 16 +#define SKCS_OFS_IP_DESTINATION_ADDRESS 16 + + +/* + * Field offsets within the UDP header. + */ + +/* UDP checksum. */ +#define SKCS_OFS_UDP_CHECKSUM 6 /* IP "Next Level Protocol" identifiers (see RFC 790). */ -#define SKCS_PROTO_ID_TCP 6 /* Transport Control Protocol */ -#define SKCS_PROTO_ID_UDP 17 /* User Datagram Protocol */ +#define SKCS_PROTO_ID_TCP 6 /* Transport Control Protocol */ +#define SKCS_PROTO_ID_UDP 17 /* User Datagram Protocol */ /* IP "Don't Fragment" bit. */ #define SKCS_IP_DONT_FRAGMENT SKCS_HTON16(0x4000) @@ -224,8 +247,8 @@ * of the TCP or UDP pseudo header is returned here. */ void SkCsGetSendInfo( -SK_AC *pAc, /* Adapter context struct. */ -void *pIpHeader, /* IP header. */ +SK_AC *pAc, /* Adapter context struct. */ +void *pIpHeader, /* IP header. */ SKCS_PACKET_INFO *pPacketInfo) /* Packet information struct. */ { /* Internet Header Version found in IP header. */ @@ -397,7 +420,8 @@ SKCS_OC_ADD(pPacketInfo->PseudoHeaderChecksum, PseudoHeaderChecksum, 0); NextLevelProtoStats->TxOkCts++; /* Success. */ -} +} /* SkCsGetSendInfo */ + /****************************************************************************** * @@ -415,7 +439,8 @@ * pAc - Pointer to adapter context struct. * * pIpHeader - Pointer to IP header. Must be at least the length in bytes - * of the received IP header including any option fields. + * of the received IP header including any option fields. For UDP packets, + * 8 additional bytes are needed to access the UDP checksum. * * Note: The actual length of the IP header is stored in the lower four * bits of the first octet of the IP header as the number of 4-byte words, @@ -431,18 +456,20 @@ * Returns: * SKCS_STATUS_UNKNOWN_IP_VERSION - Not an IP v4 frame. * SKCS_STATUS_IP_CSUM_ERROR - IP checksum error. + * SKCS_STATUS_IP_CSUM_ERROR_TCP - IP checksum error in TCP frame. + * SKCS_STATUS_IP_CSUM_ERROR_UDP - IP checksum error in UDP frame * SKCS_STATUS_IP_FRAGMENT - IP fragment (IP checksum ok). * SKCS_STATUS_IP_CSUM_OK - IP checksum ok (not a TCP or UDP frame). * SKCS_STATUS_TCP_CSUM_ERROR - TCP checksum error (IP checksum ok). * SKCS_STATUS_UDP_CSUM_ERROR - UDP checksum error (IP checksum ok). * SKCS_STATUS_TCP_CSUM_OK - IP and TCP checksum ok. * SKCS_STATUS_UDP_CSUM_OK - IP and UDP checksum ok. + * SKCS_STATUS_IP_CSUM_OK_NO_UDP - IP checksum OK and no UDP checksum. * - * Note: The SKCS_STATUS_XXX values returned here are *not* defined by - * the CSUM module but must be defined in some header file by the module - * using CSUM. In this way, the calling module can assign return values - * for its own needs, e.g. by assigning bit flags to the individual - * protocols. + * Note: If SKCS_OVERWRITE_STATUS is defined, the SKCS_STATUS_XXX values + * returned here can be defined in some header file by the module using CSUM. + * In this way, the calling module can assign return values for its own needs, + * e.g. by assigning bit flags to the individual protocols. */ SKCS_STATUS SkCsGetReceiveInfo( SK_AC *pAc, /* Adapter context struct. */ @@ -544,30 +571,36 @@ /* Adjust the IP header and IP data checksums. */ - SKCS_OC_ADD(IpHeaderChecksum, - IpHeaderChecksum, IpOptionsChecksum); + SKCS_OC_ADD(IpHeaderChecksum, IpHeaderChecksum, IpOptionsChecksum); - SKCS_OC_SUB(IpDataChecksum, - IpDataChecksum, IpOptionsChecksum); + SKCS_OC_SUB(IpDataChecksum, IpDataChecksum, IpOptionsChecksum); } - /* Check if the IP header checksum is ok. */ /* - * NOTE: We must check the IP header checksum even if the caller does - * not want us to do so because we cannot do any further processing of - * the packet without a valid IP checksum. + * Check if the IP header checksum is ok. + * + * NOTE: We must check the IP header checksum even if the caller just wants + * us to check upper-layer checksums, because we cannot do any further + * processing of the packet without a valid IP checksum. */ + + /* Get the next level protocol identifier. */ + + NextLevelProtocol = *(SK_U8 *) + SKCS_IDX(pIpHeader, SKCS_OFS_IP_NEXT_LEVEL_PROTOCOL); if (IpHeaderChecksum != 0xFFFF) { pAc->Csum.ProtoStats[SKCS_PROTO_STATS_IP].RxErrCts++; + /* the NDIS tester wants to know the upper level protocol too */ + if (NextLevelProtocol == SKCS_PROTO_ID_TCP) { + return(SKCS_STATUS_IP_CSUM_ERROR_TCP); + } + else if (NextLevelProtocol == SKCS_PROTO_ID_UDP) { + return(SKCS_STATUS_IP_CSUM_ERROR_UDP); + } return (SKCS_STATUS_IP_CSUM_ERROR); } - /* Get the next level protocol identifier. */ - - NextLevelProtocol = - *(SK_U8 *) SKCS_IDX(pIpHeader, SKCS_OFS_IP_NEXT_LEVEL_PROTOCOL); - /* * Check if this is a TCP or UDP frame and if we should calculate the * TCP/UDP pseudo header checksum. @@ -579,14 +612,12 @@ if ((pAc->Csum.ReceiveFlags & SKCS_PROTO_TCP) != 0 && NextLevelProtocol == SKCS_PROTO_ID_TCP) { /* TCP/IP frame. */ - NextLevelProtoStats = - &pAc->Csum.ProtoStats[SKCS_PROTO_STATS_TCP]; + NextLevelProtoStats = &pAc->Csum.ProtoStats[SKCS_PROTO_STATS_TCP]; } else if ((pAc->Csum.ReceiveFlags & SKCS_PROTO_UDP) != 0 && NextLevelProtocol == SKCS_PROTO_ID_UDP) { /* UDP/IP frame. */ - NextLevelProtoStats = - &pAc->Csum.ProtoStats[SKCS_PROTO_STATS_UDP]; + NextLevelProtoStats = &pAc->Csum.ProtoStats[SKCS_PROTO_STATS_UDP]; } else { /* @@ -615,6 +646,24 @@ } /* + * 08-May-2000 ra + * + * From RFC 768 (UDP) + * If the computed checksum is zero, it is transmitted as all ones (the + * equivalent in one's complement arithmetic). An all zero transmitted + * checksum value means that the transmitter generated no checksum (for + * debugging or for higher level protocols that don't care). + */ + + if (NextLevelProtocol == SKCS_PROTO_ID_UDP && + *(SK_U16*)SKCS_IDX(pIpHeader, IpHeaderLength + 6) == 0x0000) { + + NextLevelProtoStats->RxOkCts++; + + return (SKCS_STATUS_IP_CSUM_OK_NO_UDP); + } + + /* * Calculate the TCP/UDP checksum. */ @@ -639,7 +688,7 @@ SKCS_OFS_IP_DESTINATION_ADDRESS + 0) + (unsigned long) *(SK_U16 *) SKCS_IDX(pIpHeader, SKCS_OFS_IP_DESTINATION_ADDRESS + 2) + - (unsigned long) (NextLevelProtocol << 8) + + (unsigned long) SKCS_HTON16(NextLevelProtocol) + (unsigned long) SKCS_HTON16(IpDataLength) + /* Add the TCP/UDP header checksum. */ @@ -672,7 +721,8 @@ return (NextLevelProtocol == SKCS_PROTO_ID_TCP ? SKCS_STATUS_TCP_CSUM_ERROR : SKCS_STATUS_UDP_CSUM_ERROR); -} +} /* SkCsGetReceiveInfo */ + /****************************************************************************** * @@ -702,7 +752,7 @@ * Returns the two hardware checksum start offsets. */ void SkCsSetReceiveFlags( -SK_AC *pAc, /* Adapter context struct. */ +SK_AC *pAc, /* Adapter context struct. */ unsigned ReceiveFlags, /* New receive flags. */ unsigned *pChecksum1Offset, /* Offset for hardware checksum 1. */ unsigned *pChecksum2Offset) /* Offset for hardware checksum 2. */ @@ -719,9 +769,10 @@ * if there are any IP header options in the actual packet. */ *pChecksum2Offset = SKCS_MAC_HEADER_SIZE + SKCS_IP_HEADER_SIZE; -} +} /* SkCsSetReceiveFlags */ #ifndef SkCsCalculateChecksum + /****************************************************************************** * * SkCsCalculateChecksum - calculate checksum for specified data @@ -783,7 +834,8 @@ /* Note: All bits beyond the 16-bit limit are now zero. */ return ((unsigned) Checksum); -} +} /* SkCsCalculateChecksum */ + #endif /* SkCsCalculateChecksum */ /****************************************************************************** @@ -833,7 +885,7 @@ memset(&pAc->Csum.ProtoStats[0], 0, sizeof(pAc->Csum.ProtoStats)); } - else { /* Clear for individual protocol. */ + else { /* Clear for individual protocol. */ memset(&pAc->Csum.ProtoStats[ProtoIndex], 0, sizeof(pAc->Csum.ProtoStats[ProtoIndex])); } @@ -842,6 +894,6 @@ break; } return (0); /* Success. */ -} +} /* SkCsEvent */ #endif /* SK_USE_CSUM */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/sk98lin/skge.c linux/drivers/net/sk98lin/skge.c --- v2.4.0-test8/linux/drivers/net/sk98lin/skge.c Sun Aug 6 22:20:09 2000 +++ linux/drivers/net/sk98lin/skge.c Fri Sep 15 14:34:19 2000 @@ -2,8 +2,8 @@ * * Name: skge.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.27 $ - * Date: $Date: 1999/11/25 09:06:28 $ + * Version: $Revision: 1.29 $ + * Date: $Date: 2000/02/21 13:31:56 $ * Purpose: The main driver source module * ******************************************************************************/ @@ -46,6 +46,25 @@ * History: * * $Log: skge.c,v $ + * Kernel 2.4.x specific: + * Revision 1.xx 2000/09/12 13:31:56 cgoos + * Fixed missign "dev=NULL in skge_probe. + * Added counting for jumbo frames (corrects error statistic). + * Removed VLAN tag check (enables VLAN support). + * + * Kernel 2.2.x specific: + * Revision 1.29 2000/02/21 13:31:56 cgoos + * Fixed "unused" warning for UltraSPARC change. + * + * Partially kernel 2.2.x specific: + * Revision 1.28 2000/02/21 10:32:36 cgoos + * Added fixes for UltraSPARC. + * Now printing RlmtMode and PrefPort setting at startup. + * Changed XmitFrame return value. + * Fixed rx checksum calculation for BIG ENDIAN systems. + * Fixed rx jumbo frames counted as ierrors. + * + * * Revision 1.27 1999/11/25 09:06:28 cgoos * Changed base_addr to unsigned long. * @@ -225,7 +244,7 @@ static const char SysKonnectFileId[] = "@(#)" __FILE__ " (C) SysKonnect."; static const char SysKonnectBuildNumber[] = - "@(#)SK-BUILD: 3.02 (19991111) PL: 01"; + "@(#)SK-BUILD: 3.05 (20000907) PL: 01"; #include #include @@ -235,10 +254,10 @@ /* defines ******************************************************************/ -#define BOOT_STRING "sk98lin: Network Device Driver v3.02\n" \ - "Copyright (C) 1999 SysKonnect" +#define BOOT_STRING "sk98lin: Network Device Driver v3.05\n" \ + "Copyright (C) 1999-2000 SysKonnect" -#define VER_STRING "3.02" +#define VER_STRING "3.05" /* for debuging on x86 only */ @@ -373,6 +392,8 @@ PCI_DEVICE_ID_SYSKONNECT_GE, pdev)) != NULL) { if (pci_enable_device(pdev)) continue; + + dev = NULL; dev = init_etherdev(dev, sizeof(SK_AC)); if (dev == NULL) { @@ -785,6 +806,14 @@ ProductStr(pAC); printk("%s: %s\n", dev->name, pAC->DeviceStr); + /* Print configuration settings */ + printk(" PrefPort:%c RlmtMode:%s\n", + 'A' + pAC->Rlmt.PrefPort, + (pAC->RlmtMode==0) ? "ChkLink" : + ((pAC->RlmtMode==1) ? "ChkLink" : + ((pAC->RlmtMode==3) ? "ChkOth" : + ((pAC->RlmtMode==7) ? "ChkSeg" : "Error")))); + SkGeYellowLED(pAC, pAC->IoBase, 1); /* @@ -1936,6 +1965,10 @@ } /* frame > SK_COPY_TRESHOLD */ FrameStat = pRxd->FrameStat; + if ((FrameStat & XMR_FS_LNG_ERR) != 0) { + /* jumbo frame, count to correct statistic */ + SK_PNMI_CNT_RX_LONGFRAMES(pAC, pRxPort->PortIndex); + } pRxd = pRxd->pNextRxd; pRxPort->pRxdRingHead = pRxd; pRxPort->RxdRingFree ++; @@ -1947,9 +1980,9 @@ pRxPort->RxdRingFree)); if ((Control & RX_CTRL_STAT_VALID) == RX_CTRL_STAT_VALID && - (FrameStat & - (XMR_FS_ANY_ERR | XMR_FS_1L_VLAN | XMR_FS_2L_VLAN)) - == 0) { + (FrameStat & XMR_FS_ANY_ERR) == 0) { + // was the following, changed to allow VLAN support + // (XMR_FS_ANY_ERR | XMR_FS_1L_VLAN | XMR_FS_2L_VLAN) SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_RX_PROGRESS,("V")); ForRlmt = SK_RLMT_RX_PROTOCOL; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/sk98lin/skgehwt.c linux/drivers/net/sk98lin/skgehwt.c --- v2.4.0-test8/linux/drivers/net/sk98lin/skgehwt.c Tue Nov 23 10:15:42 1999 +++ linux/drivers/net/sk98lin/skgehwt.c Fri Sep 15 14:34:19 2000 @@ -2,8 +2,8 @@ * * Name: skgehwt.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.12 $ - * Date: $Date: 1998/10/15 15:11:34 $ + * Version: $Revision: 1.13 $ + * Date: $Date: 1999/11/22 13:31:12 $ * Purpose: Hardware Timer. * ******************************************************************************/ @@ -13,8 +13,6 @@ * (C)Copyright 1998,1999 SysKonnect, * a business unit of Schneider & Koch & Co. Datensysteme GmbH. * - * See the file "skge.c" for further information. - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -29,6 +27,9 @@ * History: * * $Log: skgehwt.c,v $ + * Revision 1.13 1999/11/22 13:31:12 cgoos + * Changed license header to GPL. + * * Revision 1.12 1998/10/15 15:11:34 gklug * fix: ID_sccs to SysKonnectFileId * @@ -76,7 +77,7 @@ Event queue and dispatcher */ static const char SysKonnectFileId[] = - "$Header: /usr56/projects/ge/schedule/skgehwt.c,v 1.12 1998/10/15 15:11:34 gklug Exp $" ; + "$Header: /usr56/projects/ge/schedule/skgehwt.c,v 1.13 1999/11/22 13:31:12 cgoos Exp $" ; #include "h/skdrv1st.h" /* Driver Specific Definitions */ #include "h/skdrv2nd.h" /* Adapter Control- and Driver specific Def. */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/sk98lin/skgeinit.c linux/drivers/net/sk98lin/skgeinit.c --- v2.4.0-test8/linux/drivers/net/sk98lin/skgeinit.c Tue Nov 23 10:15:42 1999 +++ linux/drivers/net/sk98lin/skgeinit.c Fri Sep 15 14:34:19 2000 @@ -2,19 +2,17 @@ * * Name: skgeinit.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.54 $ - * Date: $Date: 1999/10/26 07:32:54 $ + * Version: $Revision: 1.57 $ + * Date: $Date: 2000/08/03 14:55:28 $ * Purpose: Contains functions to initialize the GE HW * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998,1999 SysKonnect, + * (C)Copyright 1998-2000 SysKonnect, * a business unit of Schneider & Koch & Co. Datensysteme GmbH. * - * See the file "skge.c" for further information. - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -29,6 +27,16 @@ * History: * * $Log: skgeinit.c,v $ + * Revision 1.57 2000/08/03 14:55:28 rassmann + * Waiting for I2C to be ready before de-initializing adapter + * (prevents sensors from hanging up). + * + * Revision 1.56 2000/07/27 12:16:48 gklug + * fix: Stop Port check of the STOP bit does now take 2/18 sec as wanted + * + * Revision 1.55 1999/11/22 13:32:26 cgoos + * Changed license header to GPL. + * * Revision 1.54 1999/10/26 07:32:54 malthoff * Initialize PHWLinkUp with SK_FALSE. Required for Diagnostics. * @@ -199,7 +207,7 @@ * DoInitRamQueue(), and SkGeCfgSync(). * Add coding for SkGeInitMacArb(), SkGeInitPktArb(), * SkGeInitMacFifo(), SkGeInitRamBufs(), - * SkGeInitRamIface(), and SkGeInitBmu(). + * SkGeInitRamIface(), and SkGeInitBmu(). * * Revision 1.11 1998/09/29 08:26:29 malthoff * bug fix: SkGeInit0() 'i' should be increment. @@ -275,7 +283,7 @@ /* local variables ************************************************************/ static const char SysKonnectFileId[] = - "@(#)$Id: skgeinit.c,v 1.54 1999/10/26 07:32:54 malthoff Exp $ (C) SK "; + "@(#)$Id: skgeinit.c,v 1.57 2000/08/03 14:55:28 rassmann Exp $ (C) SK "; struct s_QOffTab { int RxQOff; /* Receive Queue Address Offset */ @@ -283,7 +291,7 @@ int XaQOff; /* Async Tx Queue Address Offset */ }; static struct s_QOffTab QOffTab[] = { - { Q_R1, Q_XS1, Q_XA1 }, { Q_R2, Q_XS2, Q_XA2 } + {Q_R1, Q_XS1, Q_XA1}, {Q_R2, Q_XS2, Q_XA2} }; @@ -303,7 +311,7 @@ void SkGePollRxD( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* IO context */ -int Port, /* Port Index (MAC_1 + n) */ +int Port, /* Port Index (MAC_1 + n) */ SK_BOOL PollRxD) /* SK_TRUE (enable pol.), SK_FALSE (disable pol.) */ { SK_GEPORT *pPrt; @@ -311,12 +319,13 @@ pPrt = &pAC->GIni.GP[Port]; if (PollRxD) { - SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff,Q_CSR), CSR_ENA_POL); + SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_CSR), CSR_ENA_POL); } else { - SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff,Q_CSR), CSR_DIS_POL); + SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_CSR), CSR_DIS_POL); } -} +} /* SkGePollRxD */ + /****************************************************************************** * @@ -334,7 +343,7 @@ void SkGePollTxD( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* IO context */ -int Port, /* Port Index (MAC_1 + n) */ +int Port, /* Port Index (MAC_1 + n) */ SK_BOOL PollTxD) /* SK_TRUE (enable pol.), SK_FALSE (disable pol.) */ { SK_GEPORT *pPrt; @@ -350,12 +359,12 @@ } if (pPrt->PXSQSize != 0) { - SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff,Q_CSR), DWord); + SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_CSR), DWord); } if (pPrt->PXAQSize != 0) { - SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff,Q_CSR), DWord); + SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_CSR), DWord); } -} +} /* SkGePollTxD */ /****************************************************************************** @@ -374,17 +383,18 @@ void SkGeYellowLED( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* IO context */ -int State) /* yellow LED state, 0 = OFF, 0 != ON */ +int State) /* yellow LED state, 0 = OFF, 0 != ON */ { if (State == 0) { /* Switch yellow LED OFF */ - SK_OUT8(IoC, B0_LED, LED_STAT_OFF) ; + SK_OUT8(IoC, B0_LED, LED_STAT_OFF); } else { /* Switch yellow LED ON */ - SK_OUT8(IoC, B0_LED, LED_STAT_ON) ; + SK_OUT8(IoC, B0_LED, LED_STAT_ON); } -} +} /* SkGeYellowLED */ + /****************************************************************************** * @@ -398,7 +408,7 @@ * 'Led' must contain the address offset of the LEDs INI register. * * Usage: - * SkGeXmitLED(pAC, IoC, MR_ADDR(Port,TX_LED_INI), SK_LED_ENA); + * SkGeXmitLED(pAC, IoC, MR_ADDR(Port, TX_LED_INI), SK_LED_ENA); * * Returns: * nothing @@ -406,31 +416,31 @@ void SkGeXmitLED( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* IO context */ -int Led, /* offset to the LED Init Value register */ -int Mode) /* Mode may be SK_LED_DIS, SK_LED_ENA, SK_LED_TST */ +int Led, /* offset to the LED Init Value register */ +int Mode) /* Mode may be SK_LED_DIS, SK_LED_ENA, SK_LED_TST */ { SK_U32 LedIni; switch (Mode) { case SK_LED_ENA: LedIni = SK_XMIT_DUR * (SK_U32)pAC->GIni.GIHstClkFact / 100; - SK_OUT32(IoC, Led+XMIT_LED_INI, LedIni); - SK_OUT8(IoC, Led+XMIT_LED_CTRL, LED_START); - break ; + SK_OUT32(IoC, Led + XMIT_LED_INI, LedIni); + SK_OUT8(IoC, Led + XMIT_LED_CTRL, LED_START); + break; case SK_LED_TST: - SK_OUT8(IoC, Led+XMIT_LED_TST, LED_T_ON); - SK_OUT32(IoC, Led+XMIT_LED_CNT, 100); - SK_OUT8(IoC, Led+XMIT_LED_CTRL, LED_START); - break ; + SK_OUT8(IoC, Led + XMIT_LED_TST, LED_T_ON); + SK_OUT32(IoC, Led + XMIT_LED_CNT, 100); + SK_OUT8(IoC, Led + XMIT_LED_CTRL, LED_START); + break; case SK_LED_DIS: default: /* * Do NOT stop the LED Timer here. The LED might be * in on state. But it needs to go off. */ - SK_OUT32(IoC, Led+XMIT_LED_CNT, 0); - SK_OUT8(IoC, Led+XMIT_LED_TST, LED_T_OFF); - break ; + SK_OUT32(IoC, Led + XMIT_LED_CNT, 0); + SK_OUT8(IoC, Led + XMIT_LED_TST, LED_T_OFF); + break; } /* @@ -440,7 +450,8 @@ * (Broadcom: It may be that PHY_B_PEC_EN_LTR has to be set.) * (In this case it has to be added here. But we will see. XXX) */ -} +} /* SkGeXmitLED */ + /****************************************************************************** * @@ -461,12 +472,12 @@ * 1: configuration error */ static int DoCalcAddr( -SK_AC *pAC, /* adapter context */ -SK_GEPORT *pPrt, /* port index */ -int QuSize, /* size of the queue to configure in kB */ -SK_U32 *StartVal, /* start value for address calculation */ -SK_U32 *QuStartAddr, /* start addr to calculate */ -SK_U32 *QuEndAddr) /* end address to calculate */ +SK_AC *pAC, /* adapter context */ +SK_GEPORT *pPrt, /* port index */ +int QuSize, /* size of the queue to configure in kB */ +SK_U32 *StartVal, /* start value for address calculation */ +SK_U32 *QuStartAddr, /* start addr to calculate */ +SK_U32 *QuEndAddr) /* end address to calculate */ { SK_U32 EndVal; SK_U32 NextStart; @@ -494,7 +505,7 @@ *StartVal = NextStart; return (Rtv); -} +} /* DoCalcAddr */ /****************************************************************************** @@ -521,8 +532,8 @@ * 1: Queue Size Configuration invalid */ static int SkGeCheckQSize( -SK_AC *pAC, /* adapter context */ -int Port) /* port index */ +SK_AC *pAC, /* adapter context */ +int Port) /* port index */ { SK_GEPORT *pPrt; int UsedMem; @@ -540,9 +551,7 @@ (pPrt->PXSQSize & QZ_UNITS) || (pPrt->PXAQSize & QZ_UNITS)) { - SK_ERR_LOG(pAC, SK_ERRCL_SW, - SKERR_HWI_E012, - SKERR_HWI_E012MSG); + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E012, SKERR_HWI_E012MSG); Rtv = 1; goto CheckQSizeEnd; } @@ -550,9 +559,7 @@ UsedMem += pPrt->PRxQSize + pPrt->PXSQSize + pPrt->PXAQSize; if (i == Port && pPrt->PRxQSize < SK_MIN_RXQ_SIZE) { - SK_ERR_LOG(pAC, SK_ERRCL_SW, - SKERR_HWI_E011, - SKERR_HWI_E011MSG); + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E011, SKERR_HWI_E011MSG); Rtv = 1; goto CheckQSizeEnd; } @@ -584,17 +591,15 @@ Rtv |= Rtv2; if (Rtv) { - SK_ERR_LOG(pAC, SK_ERRCL_SW, - SKERR_HWI_E013, - SKERR_HWI_E013MSG); + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E013, SKERR_HWI_E013MSG); break; } } - CheckQSizeEnd: return (Rtv); -} +} /* SkGeCheckQSize */ + /****************************************************************************** * @@ -633,7 +638,8 @@ * There is not start or enable buttom to push, therefore * the MAC arbiter is configured and enabled now. */ -} +} /* SkGeInitMacArb */ + /****************************************************************************** * @@ -666,10 +672,11 @@ SK_OUT16(IoC, B3_PA_CTRL, PA_ENA_TO_TX1); } else { - SK_OUT16(IoC, B3_PA_CTRL,(PA_ENA_TO_TX1|PA_ENA_TO_TX2)); + SK_OUT16(IoC, B3_PA_CTRL,(PA_ENA_TO_TX1 | PA_ENA_TO_TX2)); } } -} +} /* SkGeInitPktArb */ + /****************************************************************************** * @@ -684,7 +691,7 @@ static void SkGeInitMacFifo( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* IO context */ -int Port) /* Port Index (MAC_1 + n) */ +int Port) /* Port Index (MAC_1 + n) */ { /* * For each FIFO: @@ -707,7 +714,8 @@ if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK) { SK_OUT16(IoC, MR_ADDR(Port, RX_MFF_CTRL1), MFF_ENA_FLUSH); } -} +} /* SkGeInitMacFifo */ + /****************************************************************************** * @@ -731,7 +739,7 @@ void SkGeLoadLnkSyncCnt( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* IO context */ -int Port, /* Port Index (MAC_1 + n) */ +int Port, /* Port Index (MAC_1 + n) */ SK_U32 CntVal) /* Counter value */ { SK_U32 OrgIMsk; @@ -740,7 +748,7 @@ SK_BOOL IrqPend; /* stop counter */ - SK_OUT8(IoC, MR_ADDR(Port,LNK_SYNC_CTRL), LED_STOP); + SK_OUT8(IoC, MR_ADDR(Port, LNK_SYNC_CTRL), LED_STOP); /* * ASIC problem: @@ -770,17 +778,18 @@ } /* load counter */ - SK_OUT32(IoC, MR_ADDR(Port,LNK_SYNC_INI), CntVal); + SK_OUT32(IoC, MR_ADDR(Port, LNK_SYNC_INI), CntVal); /* start counter */ - SK_OUT8(IoC, MR_ADDR(Port,LNK_SYNC_CTRL), LED_START); + SK_OUT8(IoC, MR_ADDR(Port, LNK_SYNC_CTRL), LED_START); if (!IrqPend) { /* clear the unexpected IRQ, and restore the interrupt mask */ - SK_OUT8(IoC, MR_ADDR(Port,LNK_SYNC_CTRL), LED_CLR_IRQ); + SK_OUT8(IoC, MR_ADDR(Port, LNK_SYNC_CTRL), LED_CLR_IRQ); SK_OUT32(IoC, B0_IMSK, OrgIMsk); } -} +} /* SkGeLoadLnkSyncCnt*/ + /****************************************************************************** * @@ -813,10 +822,10 @@ int SkGeCfgSync( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* IO context */ -int Port, /* Port Index (MAC_1 + n) */ +int Port, /* Port Index (MAC_1 + n) */ SK_U32 IntTime, /* Interval Timer Value in units of 8ns */ SK_U32 LimCount, /* Number of bytes to transfer during IntTime */ -int SyncMode) /* Sync Mode: TXA_ENA_ALLOC | TXA_DIS_ALLOC | 0 */ +int SyncMode) /* Sync Mode: TXA_ENA_ALLOC | TXA_DIS_ALLOC | 0 */ { int Rtv; @@ -836,8 +845,7 @@ IntTime = (IntTime / 2) * pAC->GIni.GIHstClkFact / 100; LimCount = LimCount / 8; if (IntTime > TXA_MAX_VAL || LimCount > TXA_MAX_VAL) { - SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E010, - SKERR_HWI_E010MSG); + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E010, SKERR_HWI_E010MSG); Rtv = 1; goto CfgSyncEnd; } @@ -852,14 +860,14 @@ * - start 'Rate Control' and disable 'Force Sync' * if Interval Timer or Limit Counter not zero. */ - SK_OUT8(IoC, MR_ADDR(Port,TXA_CTRL), + SK_OUT8(IoC, MR_ADDR(Port, TXA_CTRL), TXA_ENA_FSYNC | TXA_DIS_ALLOC | TXA_STOP_RC); - SK_OUT32(IoC, MR_ADDR(Port,TXA_ITI_INI), IntTime); - SK_OUT32(IoC, MR_ADDR(Port,TXA_LIM_INI), LimCount); - SK_OUT8(IoC, MR_ADDR(Port,TXA_CTRL), + SK_OUT32(IoC, MR_ADDR(Port, TXA_ITI_INI), IntTime); + SK_OUT32(IoC, MR_ADDR(Port, TXA_LIM_INI), LimCount); + SK_OUT8(IoC, MR_ADDR(Port, TXA_CTRL), (SyncMode & (TXA_ENA_ALLOC|TXA_DIS_ALLOC))); if (IntTime != 0 || LimCount != 0) { - SK_OUT8(IoC, MR_ADDR(Port,TXA_CTRL), + SK_OUT8(IoC, MR_ADDR(Port, TXA_CTRL), TXA_DIS_FSYNC|TXA_START_RC); } } @@ -870,7 +878,8 @@ CfgSyncEnd: return (Rtv); -} +} /* SkGeCfgSync */ + /****************************************************************************** * @@ -884,12 +893,12 @@ * nothing */ static void DoInitRamQueue( -SK_AC *pAC, /* adapter context */ -SK_IOC IoC, /* IO context */ -int QuIoOffs, /* Queue IO Address Offset */ +SK_AC *pAC, /* adapter context */ +SK_IOC IoC, /* IO context */ +int QuIoOffs, /* Queue IO Address Offset */ SK_U32 QuStartAddr, /* Queue Start Address */ -SK_U32 QuEndAddr, /* Queue End Address */ -int QuType) /* Queue Type (SK_RX_SRAM_Q|SK_RX_BRAM_Q|SK_TX_RAM_Q) */ +SK_U32 QuEndAddr, /* Queue End Address */ +int QuType) /* Queue Type (SK_RX_SRAM_Q|SK_RX_BRAM_Q|SK_TX_RAM_Q) */ { SK_U32 RxUpThresVal; SK_U32 RxLoThresVal; @@ -904,13 +913,13 @@ QuEndAddr = QuEndAddr / 8; /* release local reset */ - SK_OUT8(IoC, RB_ADDR(QuIoOffs,RB_CTRL), RB_RST_CLR); + SK_OUT8(IoC, RB_ADDR(QuIoOffs, RB_CTRL), RB_RST_CLR); /* configure addresses */ - SK_OUT32(IoC, RB_ADDR(QuIoOffs,RB_START), QuStartAddr); - SK_OUT32(IoC, RB_ADDR(QuIoOffs,RB_END), QuEndAddr); - SK_OUT32(IoC, RB_ADDR(QuIoOffs,RB_WP), QuStartAddr); - SK_OUT32(IoC, RB_ADDR(QuIoOffs,RB_RP), QuStartAddr); + SK_OUT32(IoC, RB_ADDR(QuIoOffs, RB_START), QuStartAddr); + SK_OUT32(IoC, RB_ADDR(QuIoOffs, RB_END), QuEndAddr); + SK_OUT32(IoC, RB_ADDR(QuIoOffs, RB_WP), QuStartAddr); + SK_OUT32(IoC, RB_ADDR(QuIoOffs, RB_RP), QuStartAddr); switch (QuType) { case SK_RX_SRAM_Q: @@ -921,10 +930,9 @@ case SK_RX_BRAM_Q: /* write threshold for Rx Queue */ - SK_OUT32(IoC, RB_ADDR(QuIoOffs,RB_RX_UTPP), - RxUpThresVal); - SK_OUT32(IoC, RB_ADDR(QuIoOffs,RB_RX_LTPP), - RxLoThresVal); + SK_OUT32(IoC, RB_ADDR(QuIoOffs, RB_RX_UTPP), RxUpThresVal); + SK_OUT32(IoC, RB_ADDR(QuIoOffs,RB_RX_LTPP), RxLoThresVal); + /* the high priority threshold not used */ break; case SK_TX_RAM_Q: @@ -939,20 +947,20 @@ * enable Store & Forward Mode for the * Tx Side */ - SK_OUT8(IoC, RB_ADDR(QuIoOffs,RB_CTRL), - RB_ENA_STFWD); + SK_OUT8(IoC, RB_ADDR(QuIoOffs, RB_CTRL), RB_ENA_STFWD); } break; } /* set queue operational */ - SK_OUT8(IoC, RB_ADDR(QuIoOffs,RB_CTRL), RB_ENA_OP_MD); + SK_OUT8(IoC, RB_ADDR(QuIoOffs, RB_CTRL), RB_ENA_OP_MD); } else { /* ensure the queue is still disabled */ - SK_OUT8(IoC, RB_ADDR(QuIoOffs,RB_CTRL), RB_RST_SET); + SK_OUT8(IoC, RB_ADDR(QuIoOffs, RB_CTRL), RB_RST_SET); } -} +} /* DoInitRamQueue*/ + /****************************************************************************** * @@ -967,7 +975,7 @@ static void SkGeInitRamBufs( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* IO context */ -int Port) /* Port Index (MAC_1 + n) */ +int Port) /* Port Index (MAC_1 + n) */ { SK_GEPORT *pPrt; int RxQType; @@ -987,7 +995,8 @@ pPrt->PXsQRamEnd, SK_TX_RAM_Q); DoInitRamQueue(pAC, IoC, pPrt->PXaQOff, pPrt->PXaQRamStart, pPrt->PXaQRamEnd, SK_TX_RAM_Q); -} +} /* SkGeInitRamBufs */ + /****************************************************************************** * @@ -1022,7 +1031,8 @@ SK_OUT8(IoC, B3_RI_RTO_R2, SK_RI_TO_53); SK_OUT8(IoC, B3_RI_RTO_XA2, SK_RI_TO_53); SK_OUT8(IoC, B3_RI_RTO_XS2, SK_RI_TO_53); -} +} /* SkGeInitRamIface */ + /****************************************************************************** * @@ -1037,33 +1047,34 @@ static void SkGeInitBmu( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* IO context */ -int Port) /* Port Index (MAC_1 + n) */ +int Port) /* Port Index (MAC_1 + n) */ { SK_GEPORT *pPrt; pPrt = &pAC->GIni.GP[Port]; /* Rx Queue: Release all local resets and set the watermark */ - SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff,Q_CSR), CSR_CLR_RESET); - SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff,Q_F), SK_BMU_RX_WM); + SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_CSR), CSR_CLR_RESET); + SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_F), SK_BMU_RX_WM); /* * Tx Queue: Release all local resets if the queue is used! * set watermark */ if (pPrt->PXSQSize != 0) { - SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff,Q_CSR), CSR_CLR_RESET); - SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff,Q_F), SK_BMU_TX_WM); + SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_CSR), CSR_CLR_RESET); + SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_F), SK_BMU_TX_WM); } if (pPrt->PXAQSize != 0) { - SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff,Q_CSR), CSR_CLR_RESET); - SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff,Q_F), SK_BMU_TX_WM); + SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_CSR), CSR_CLR_RESET); + SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_F), SK_BMU_TX_WM); } /* * Do NOT enable the descriptor poll timers here, because * the descriptor addresses are not specified yet. */ -} +} /* SkGeInitBmu */ + /****************************************************************************** * @@ -1081,17 +1092,18 @@ static SK_U32 TestStopBit( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* IO Context */ -int QuIoOffs) /* Queue IO Address Offset */ +int QuIoOffs) /* Queue IO Address Offset */ { SK_U32 QuCsr; /* CSR contents */ - SK_IN32(IoC, Q_ADDR(QuIoOffs,Q_CSR), &QuCsr); + SK_IN32(IoC, Q_ADDR(QuIoOffs, Q_CSR), &QuCsr); if ((QuCsr & (CSR_STOP|CSR_SV_IDLE)) == 0) { - SK_OUT32(IoC, Q_ADDR(QuIoOffs,Q_CSR), CSR_STOP); - SK_IN32(IoC, Q_ADDR(QuIoOffs,Q_CSR), &QuCsr); + SK_OUT32(IoC, Q_ADDR(QuIoOffs, Q_CSR), CSR_STOP); + SK_IN32(IoC, Q_ADDR(QuIoOffs, Q_CSR), &QuCsr); } return (QuCsr); -} +} /* TestStopBit*/ + /****************************************************************************** * @@ -1173,10 +1185,10 @@ */ void SkGeStopPort( SK_AC *pAC, /* adapter context */ -SK_IOC IoC, /* IO context */ -int Port, /* port to stop (MAC_1 + n) */ -int Dir, /* Direction to Stop (SK_STOP_RX, SK_STOP_TX, SK_STOP_ALL) */ -int RstMode)/* Reset Mode (SK_SOFT_RST, SK_HARD_RST) */ +SK_IOC IoC, /* I/O context */ +int Port, /* port to stop (MAC_1 + n) */ +int Dir, /* Direction to Stop (SK_STOP_RX, SK_STOP_TX, SK_STOP_ALL) */ +int RstMode)/* Reset Mode (SK_SOFT_RST, SK_HARD_RST) */ { #ifndef SK_DIAG SK_EVPARA Para; @@ -1196,8 +1208,7 @@ if (Dir & SK_STOP_TX) { /* disable the XMACs receiver and transmitter */ XM_IN16(IoC, Port, XM_MMU_CMD, &Word); - XM_OUT16(IoC, Port, XM_MMU_CMD, - Word & ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX)); + XM_OUT16(IoC, Port, XM_MMU_CMD, Word & ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX)); /* dummy read to ensure writing */ XM_IN16(IoC, Port, XM_MMU_CMD, &Word); @@ -1207,8 +1218,8 @@ * If the BMU is in the reset state CSR_STOP will terminate * immediately. */ - SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff,Q_CSR), CSR_STOP); - SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff,Q_CSR), CSR_STOP); + SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_CSR), CSR_STOP); + SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_CSR), CSR_STOP); ToutStart = SkOsGetTime(pAC); ToutCnt = 0; @@ -1231,17 +1242,16 @@ * transmit FIFO ! */ XM_IN32(IoC, Port, XM_MODE, &DWord); - DWord |= XM_MD_FTF ; + DWord |= XM_MD_FTF; XM_OUT32(IoC, Port, XM_MODE, DWord); XsCsr = TestStopBit(pAC, IoC, pPrt->PXsQOff); XaCsr = TestStopBit(pAC, IoC, pPrt->PXaQOff); - if (ToutStart + (SK_TICKS_PER_SEC / 18) < - SkOsGetTime(pAC)) { - + if (ToutStart + (SK_TICKS_PER_SEC / 18) >= SkOsGetTime(pAC)) { /* * Timeout of 1/18 second reached. + * This needs to be checked at 1/18 sec only. */ ToutCnt++; switch (ToutCnt) { @@ -1253,35 +1263,36 @@ */ ToutStart = SkOsGetTime(pAC); if (XsCsr & CSR_STOP) { - SK_OUT32(IoC, - Q_ADDR(pPrt->PXsQOff, - Q_CSR), CSR_START); + SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_CSR), CSR_START); } if (XaCsr & CSR_STOP) { - SK_OUT32(IoC, - Q_ADDR(pPrt->PXaQOff, - Q_CSR), CSR_START); + SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_CSR), CSR_START); } break; case 2: - default: /* Fatal Error, Loop aborted */ + default: + /* Might be a problem when the driver event handler + * calls StopPort again. + * XXX. + */ + /* Fatal Error, Loop aborted */ /* Create an Error Log Entry */ - SK_ERR_LOG(pAC, SK_ERRCL_HW, + SK_ERR_LOG( + pAC, + SK_ERRCL_HW, SKERR_HWI_E018, SKERR_HWI_E018MSG); #ifndef SK_DIAG Para.Para64 = Port; - SkEventQueue(pAC, SKGE_DRV, - SK_DRV_PORT_FAIL, Para); + SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para); #endif /* !SK_DIAG */ return; } } /* - * because of the ASIC problem report entry from 21.08.98 - * it is required to wait until CSR_STOP is reset and - * CSR_SV_IDLE is set. + * Because of the ASIC problem report entry from 21.08.1998 it is + * required to wait until CSR_STOP is reset and CSR_SV_IDLE is set. */ } while ((XsCsr & (CSR_STOP|CSR_SV_IDLE)) != CSR_SV_IDLE || (XaCsr & (CSR_STOP|CSR_SV_IDLE)) != CSR_SV_IDLE); @@ -1298,10 +1309,10 @@ * Stop Interval Timer and Limit Counter of Tx Arbiter, * also disable Force Sync bit and Enable Alloc bit. */ - SK_OUT8(IoC, MR_ADDR(Port,TXA_CTRL), + SK_OUT8(IoC, MR_ADDR(Port, TXA_CTRL), TXA_DIS_FSYNC | TXA_DIS_ALLOC | TXA_STOP_RC); - SK_OUT32(IoC, MR_ADDR(Port,TXA_ITI_INI), 0x00000000L); - SK_OUT32(IoC, MR_ADDR(Port,TXA_LIM_INI), 0x00000000L); + SK_OUT32(IoC, MR_ADDR(Port, TXA_ITI_INI), 0x00000000L); + SK_OUT32(IoC, MR_ADDR(Port, TXA_LIM_INI), 0x00000000L); /* * perform a local reset of the port's tx path @@ -1311,16 +1322,16 @@ * - reset the RAM Butter sync tx queue * - reset the MAC Tx FIFO */ - SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff,Q_CSR), CSR_SET_RESET); - SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff,Q_CSR), CSR_SET_RESET); - SK_OUT8(IoC, RB_ADDR(pPrt->PXaQOff,RB_CTRL), RB_RST_SET); - SK_OUT8(IoC, RB_ADDR(pPrt->PXsQOff,RB_CTRL), RB_RST_SET); + SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_CSR), CSR_SET_RESET); + SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_CSR), CSR_SET_RESET); + SK_OUT8(IoC, RB_ADDR(pPrt->PXaQOff, RB_CTRL), RB_RST_SET); + SK_OUT8(IoC, RB_ADDR(pPrt->PXsQOff, RB_CTRL), RB_RST_SET); /* Note: MFF_RST_SET does NOT reset the XMAC! */ SK_OUT8(IoC, MR_ADDR(Port, TX_MFF_CTRL2), MFF_RST_SET); /* switch Link and Tx LED off, stop the LED counters */ /* Link LED is switched off by the RLMT and the Diag itself */ - SkGeXmitLED(pAC, IoC, MR_ADDR(Port,TX_LED_INI), SK_LED_DIS); + SkGeXmitLED(pAC, IoC, MR_ADDR(Port, TX_LED_INI), SK_LED_DIS); } if (Dir & SK_STOP_RX) { @@ -1331,7 +1342,7 @@ * stop the transfer of received packets. */ /* stop the port's receive queue */ - SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff,Q_CSR), CSR_STOP); + SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_CSR), CSR_STOP); i = 100; do { /* @@ -1368,12 +1379,12 @@ * - reset the RAM Buffer receive queue * - reset the MAC Rx FIFO */ - SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff,Q_CSR), CSR_SET_RESET); - SK_OUT8(IoC, RB_ADDR(pPrt->PRxQOff,RB_CTRL), RB_RST_SET); + SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_CSR), CSR_SET_RESET); + SK_OUT8(IoC, RB_ADDR(pPrt->PRxQOff, RB_CTRL), RB_RST_SET); SK_OUT8(IoC, MR_ADDR(Port, RX_MFF_CTRL2), MFF_RST_SET); /* switch Rx LED off, stop the LED counter */ - SkGeXmitLED(pAC, IoC, MR_ADDR(Port,RX_LED_INI), SK_LED_DIS); + SkGeXmitLED(pAC, IoC, MR_ADDR(Port, RX_LED_INI), SK_LED_DIS); } @@ -1391,7 +1402,8 @@ if (AllPortsDis) { pAC->GIni.GIAnyPortAct = SK_FALSE; } -} +} /* SkGeStopPort */ + /****************************************************************************** * @@ -1444,7 +1456,88 @@ pAC->GIni.GIPortUsage = SK_RED_LINK; pAC->GIni.GIAnyPortAct = SK_FALSE; -} +} /* SkGeInit0*/ + +#ifdef SK_PCI_RESET + +/****************************************************************************** + * + * SkGePciReset() - Reset PCI interface + * + * Description: + * o Read PCI configuration. + * o Change power state to 3. + * o Change power state to 0. + * o Restore PCI configuration. + * + * Returns: + * 0: Success. + * 1: Power state could not be changed to 3. + */ +static int SkGePciReset( +SK_AC *pAC, /* adapter context */ +SK_IOC IoC) /* IO context */ +{ + int i; + SK_U16 PmCtlSts; + SK_U32 Bp1; + SK_U32 Bp2; + SK_U16 PciCmd; + SK_U8 Cls; + SK_U8 Lat; + SK_U8 ConfigSpace[PCI_CFG_SIZE]; + + /* + * Note: Switching to D3 state is like a software reset. + * Switching from D3 to D0 is a hardware reset. + * We have to save and restore the configuration space. + */ + for (i = 0; i < PCI_CFG_SIZE; i++) { + SkPciReadCfgDWord(pAC, i*4, &ConfigSpace[i]); + } + + /* We know the RAM Interface Arbiter is enabled. */ + SkPciWriteCfgWord(pAC, PCI_PM_CTL_STS, PCI_PM_STATE_D3); + SkPciReadCfgWord(pAC, PCI_PM_CTL_STS, &PmCtlSts); + if ((PmCtlSts & PCI_PM_STATE) != PCI_PM_STATE_D3) { + return (1); + } + + /* + * Return to D0 state. + */ + SkPciWriteCfgWord(pAC, PCI_PM_CTL_STS, PCI_PM_STATE_D0); + + /* Check for D0 state. */ + SkPciReadCfgWord(pAC, PCI_PM_CTL_STS, &PmCtlSts); + if ((PmCtlSts & PCI_PM_STATE) != PCI_PM_STATE_D0) { + return (1); + } + + /* + * Check PCI Config Registers. + */ + SkPciReadCfgWord(pAC, PCI_COMMAND, &PciCmd); + SkPciReadCfgByte(pAC, PCI_CACHE_LSZ, &Cls); + SkPciReadCfgDWord(pAC, PCI_BASE_1ST, &Bp1); + SkPciReadCfgDWord(pAC, PCI_BASE_2ND, &Bp2); + SkPciReadCfgByte(pAC, PCI_LAT_TIM, &lat); + if (PciCmd != 0 || Cls != 0 || (Bp1 & 0xfffffff0L) != 0 || Bp2 != 1 || + Lat != 0 ) { + return (0); + } + + /* + * Restore Config Space. + */ + for (i = 0; i < PCI_CFG_SIZE; i++) { + SkPciWriteCfgDWord(pAC, i*4, ConfigSpace[i]); + } + + return (0); +} /* SkGePciReset */ + +#endif /* SK_PCI_RESET */ /****************************************************************************** * @@ -1477,6 +1570,10 @@ RetVal = 0; +#ifdef SK_PCI_RESET + (void)SkGePciReset(pAC, IoC); +#endif /* SK_PCI_RESET */ + /* Do the reset */ SK_OUT8(IoC, B0_CTST, CS_RST_SET); @@ -1486,7 +1583,7 @@ /* Reset all error bits in the PCI STATUS register */ /* * Note: Cfg cycles cannot be used, because they are not - * available on some platforms after 'boot time'. + * available on some platforms after 'boot time'. */ SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_ON); SK_IN16(IoC, PCI_C(PCI_STATUS), &Word); @@ -1547,12 +1644,13 @@ break; } } - SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_INIT, + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_INIT, ("PHY type: %d PHY addr: %x\n", pAC->GIni.GP[i].PhyType, - pAC->GIni.GP[i].PhyAddr)) ; + pAC->GIni.GP[i].PhyAddr)); return (RetVal); -} +} /* SkGeInit1*/ + /****************************************************************************** * @@ -1588,8 +1686,7 @@ pAC->GIni.GIPollTimerVal = SK_DPOLL_MAX; /* Create an Error Log Entry */ - SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E017, - SKERR_HWI_E017MSG); + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E017, SKERR_HWI_E017MSG); } SK_OUT32(IoC, B28_DPT_INI, pAC->GIni.GIPollTimerVal); SK_OUT8(IoC, B28_DPT_CTRL, DPT_START); @@ -1607,9 +1704,9 @@ SkGeInitPktArb(pAC, IoC); /* enable the Tx Arbiters */ - SK_OUT8(IoC, MR_ADDR(MAC_1,TXA_CTRL), TXA_ENA_ARB); + SK_OUT8(IoC, MR_ADDR(MAC_1, TXA_CTRL), TXA_ENA_ARB); if (pAC->GIni.GIMacsFound > 1) { - SK_OUT8(IoC, MR_ADDR(MAC_2,TXA_CTRL), TXA_ENA_ARB); + SK_OUT8(IoC, MR_ADDR(MAC_2, TXA_CTRL), TXA_ENA_ARB); } /* enable the RAM Interface Arbiter */ @@ -1621,7 +1718,7 @@ pPrt->PRxCmd |= XM_RX_BIG_PK_OK; } } -} +} /* SkGeInit2 */ /****************************************************************************** * @@ -1660,24 +1757,24 @@ int SkGeInit( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* IO context */ -int Level) /* initialization level */ +int Level) /* initialization level */ { int RetVal; /* return value */ SK_U32 DWord; RetVal = 0; - SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_INIT, - ("SkGeInit(Level %d)\n",Level)) ; + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_INIT, + ("SkGeInit(Level %d)\n", Level)); switch (Level) { case SK_INIT_DATA: /* Initialization Level 0 */ - SkGeInit0(pAC,IoC) ; + SkGeInit0(pAC, IoC); pAC->GIni.GILevel = SK_INIT_DATA; break; case SK_INIT_IO: /* Initialization Level 1 */ - RetVal = SkGeInit1(pAC,IoC) ; + RetVal = SkGeInit1(pAC, IoC); /* Check if the adapter seems to be accessable */ SK_OUT32(IoC, B2_IRQM_INI, 0x11335577L); @@ -1701,13 +1798,12 @@ /* Initialization Level 2 */ if (pAC->GIni.GILevel != SK_INIT_IO) { #ifndef SK_DIAG - SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E002, - SKERR_HWI_E002MSG); + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E002, SKERR_HWI_E002MSG); #endif RetVal = 4; break; } - SkGeInit2(pAC,IoC) ; + SkGeInit2(pAC, IoC); /* Level 2 successfully passed */ pAC->GIni.GILevel = SK_INIT_RUN; @@ -1715,12 +1811,13 @@ default: /* Create an Error Log Entry */ SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E003, SKERR_HWI_E003MSG); - RetVal = 3 ; + RetVal = 3; break; } return (RetVal); -} +} /* SkGeInit*/ + /****************************************************************************** * @@ -1740,6 +1837,9 @@ int i; SK_U16 Word; + /* Ensure I2C is ready. */ + SkI2cWaitIrq(pAC, IoC); + /* Stop all current transfer activity */ for (i = 0; i < pAC->GIni.GIMacsFound; i++) { if (pAC->GIni.GP[i].PState != SK_PRT_STOP && @@ -1761,7 +1861,8 @@ /* Do the reset, all LEDs are switched off now */ SK_OUT8(IoC, B0_CTST, CS_RST_SET); -} +} /* SkGeDeInit*/ + /****************************************************************************** * @@ -1795,13 +1896,13 @@ int SkGeInitPort( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* IO context */ -int Port) /* Port to configure */ +int Port) /* Port to configure */ { SK_GEPORT *pPrt; pPrt = &pAC->GIni.GP[Port]; - if (SkGeCheckQSize(pAC,Port) != 0) { + if (SkGeCheckQSize(pAC, Port) != 0) { SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E004, SKERR_HWI_E004MSG); return (1); } @@ -1817,8 +1918,8 @@ * If 1000BT Phy needs LED initialization than swap * LED and XMAC initialization order */ - SkGeXmitLED(pAC, IoC, MR_ADDR(Port,TX_LED_INI), SK_LED_ENA); - SkGeXmitLED(pAC, IoC, MR_ADDR(Port,RX_LED_INI), SK_LED_ENA); + SkGeXmitLED(pAC, IoC, MR_ADDR(Port, TX_LED_INI), SK_LED_ENA); + SkGeXmitLED(pAC, IoC, MR_ADDR(Port, RX_LED_INI), SK_LED_ENA); /* The Link LED is initialized by RLMT or Diagnostics itself */ /* Do NOT initialize the Link Sync Counter */ @@ -1844,4 +1945,4 @@ pAC->GIni.GIAnyPortAct = SK_TRUE; return (0); -} +} /* SkGeInitPort */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/sk98lin/skgepnmi.c linux/drivers/net/sk98lin/skgepnmi.c --- v2.4.0-test8/linux/drivers/net/sk98lin/skgepnmi.c Tue Nov 23 10:15:42 1999 +++ linux/drivers/net/sk98lin/skgepnmi.c Fri Sep 15 14:34:19 2000 @@ -2,8 +2,8 @@ * * Name: skgepnmi.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.69 $ - * Date: $Date: 1999/10/18 11:42:15 $ + * Version: $Revision: 1.78 $ + * Date: $Date: 2000/09/12 10:44:58 $ * Purpose: Private Network Management Interface * ****************************************************************************/ @@ -13,8 +13,6 @@ * (C)Copyright 1998,1999 SysKonnect, * a business unit of Schneider & Koch & Co. Datensysteme GmbH. * - * See the file "skge.c" for further information. - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -29,6 +27,43 @@ * History: * * $Log: skgepnmi.c,v $ + * Revision 1.78 2000/09/12 10:44:58 cgoos + * Fixed SK_PNMI_STORE_U32 calls with typecasted argument. + * + * Revision 1.77 2000/09/07 08:10:19 rwahl + * - Modified algorithm for 64bit NDIS statistic counters; + * returns 64bit or 32bit value depending on passed buffer + * size. Indicate capability for 64bit NDIS counter, if passed + * buffer size is zero. OID_GEN_XMIT_ERROR, OID_GEN_RCV_ERROR, + * and OID_GEN_RCV_NO_BUFFER handled as 64bit counter, too. + * - corrected OID_SKGE_RLMT_PORT_PREFERRED. + * + * Revision 1.76 2000/08/03 15:23:39 rwahl + * - Correction for FrameTooLong counter has to be moved to OID handling + * routines (instead of statistic counter routine). + * - Fix in XMAC Reset Event handling: Only offset counter for hardware + * statistic registers are updated. + * + * Revision 1.75 2000/08/01 16:46:05 rwahl + * - Added StatRxLongFrames counter and correction of FrameTooLong counter. + * - Added directive to control width (default = 32bit) of NDIS statistic + * counters (SK_NDIS_64BIT_CTR). + * + * Revision 1.74 2000/07/04 11:41:53 rwahl + * - Added volition connector type. + * + * Revision 1.73 2000/03/15 16:33:10 rwahl + * Fixed bug 10510; wrong reset of virtual port statistic counters. + * + * Revision 1.72 1999/12/06 16:15:53 rwahl + * Fixed problem of instance range for current and factory MAC address. + * + * Revision 1.71 1999/12/06 10:14:20 rwahl + * Fixed bug 10476; set operation for PHY_OPERATION_MODE. + * + * Revision 1.70 1999/11/22 13:33:34 cgoos + * Changed license header to GPL. + * * Revision 1.69 1999/10/18 11:42:15 rwahl * Added typecasts for checking event dependent param (debug only). * @@ -297,7 +332,8 @@ static const char SysKonnectFileId[] = - "@(#) $Id: skgepnmi.c,v 1.69 1999/10/18 11:42:15 rwahl Exp $ (C) SysKonnect."; + "@(#) $Id: skgepnmi.c,v 1.78 2000/09/12 10:44:58 cgoos Exp $" + " (C) SysKonnect."; #include "h/skdrv1st.h" #include "h/sktypes.h" @@ -982,6 +1018,11 @@ sizeof(SK_PNMI_STAT), SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxUnicastOkCts), SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_UNICAST}, + {OID_SKGE_STAT_RX_LONGFRAMES, + SK_PNMI_MAC_ENTRIES, + sizeof(SK_PNMI_STAT), + SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxLongFramesCts), + SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_LONGFRAMES}, {OID_SKGE_STAT_RX_PFLOWC, SK_PNMI_MAC_ENTRIES, sizeof(SK_PNMI_STAT), @@ -1197,7 +1238,7 @@ 0, SK_PNMI_MAI_OFF(RlmtPortActive), SK_PNMI_RO, Rlmt, 0}, - {OID_SKGE_RLMT_PORT_PREFERED, + {OID_SKGE_RLMT_PORT_PREFERRED, 1, 0, SK_PNMI_MAI_OFF(RlmtPortPreferred), @@ -1353,7 +1394,8 @@ /* 62 */ {TRUE, XM_RXF_1023B}, /* 63 */ {TRUE, XM_RXF_MAX_SZ}, /* 64 */ {FALSE, 0}, - /* 65 */ {FALSE, 0} + /* 65 */ {FALSE, 0}, + /* 66 */ {TRUE, 0} }; @@ -1520,6 +1562,10 @@ pAC->Pnmi.Connector = 5; break; + case 'V': + pAC->Pnmi.Connector = 6; + break; + default: pAC->Pnmi.Connector = 1; break; @@ -2074,8 +2120,13 @@ case SK_PNMI_HRX_OCTETLOW: case SK_PNMI_HRX_IRLENGTH: case SK_PNMI_HRX_RESERVED22: + + /* + * the following counters aren't be handled (id > 63) + */ case SK_PNMI_HTX_SYNC: case SK_PNMI_HTX_SYNC_OCTET: + case SK_PNMI_HRX_LONGFRAMES: break; default: @@ -2270,7 +2321,7 @@ */ pAC->Pnmi.MacUpdatedFlag ++; - for (CounterIndex = 0; CounterIndex < SK_PNMI_MAX_IDX; + for (CounterIndex = 0; CounterIndex < SK_PNMI_SCNT_NOT; CounterIndex ++) { if (!StatAddress[CounterIndex].GetOffset) { @@ -2985,9 +3036,9 @@ SK_U32 Instance, /* Instance (1..n) that is to be queried or -1 */ unsigned int TableIndex) /* Index to the Id table */ { - int Ret; - SK_U32 StatVal; - + int Ret; + SK_U64 StatVal; + SK_BOOL Is64BitReq = SK_FALSE; /* * Only the active Mac is returned @@ -3022,11 +3073,28 @@ break; default: - if (*pLen < 4) { +#ifndef SK_NDIS_64BIT_CTR + if (*pLen < sizeof(SK_U32)) { + *pLen = sizeof(SK_U32); + return (SK_PNMI_ERR_TOO_SHORT); + } - *pLen = 4; +#else /* SK_NDIS_64BIT_CTR */ + + /* + * for compatibility, at least 32bit are required for oid + */ + if (*pLen < sizeof(SK_U32)) { + /* + * but indicate handling for 64bit values, + * if insufficient space is provided + */ + *pLen = sizeof(SK_U64); return (SK_PNMI_ERR_TOO_SHORT); } + + Is64BitReq = (*pLen < sizeof(SK_U64)) ? SK_FALSE : SK_TRUE; +#endif /* SK_NDIS_64BIT_CTR */ break; } @@ -3059,10 +3127,21 @@ break; default: - StatVal = (SK_U32)GetStatVal(pAC, IoC, 0, - IdTable[TableIndex].Param); - SK_PNMI_STORE_U32(pBuf, StatVal); - *pLen = sizeof(SK_U32); + StatVal = GetStatVal(pAC, IoC, 0, IdTable[TableIndex].Param); + + /* + * by default 32bit values are evaluated + */ + if (!Is64BitReq) { + SK_U32 StatVal32; + StatVal32 = (SK_U32)StatVal; + SK_PNMI_STORE_U32(pBuf, StatVal32); + *pLen = sizeof(SK_U32); + } + else { + SK_PNMI_STORE_U64(pBuf, StatVal); + *pLen = sizeof(SK_U64); + } break; } @@ -3177,6 +3256,20 @@ case OID_SKGE_STAT_RX_UTIL: return (SK_PNMI_ERR_GENERAL); */ + /* + * Frames longer than IEEE 802.3 frame max size are counted + * by XMAC in frame_too_long counter even reception of long + * frames was enabled and the frame was correct. + * So correct the value by subtracting RxLongFrame counter. + */ + case OID_SKGE_STAT_RX_TOO_LONG: + StatVal = GetStatVal(pAC, IoC, LogPortIndex, + IdTable[TableIndex].Param) - + GetStatVal(pAC, IoC, LogPortIndex, + SK_PNMI_HRX_LONGFRAMES); + SK_PNMI_STORE_U64(pBuf + Offset, StatVal); + break; + default: StatVal = GetStatVal(pAC, IoC, LogPortIndex, IdTable[TableIndex].Param); @@ -3245,7 +3338,7 @@ if ((Instance != (SK_U32)(-1))) { - if ((Instance < 1) || (Instance > SKCS_NUM_PROTOCOLS)) { + if ((Instance < 1) || (Instance > LogPortMax)) { *pLen = 0; return (SK_PNMI_ERR_UNKNOWN_INST); @@ -4289,6 +4382,7 @@ SK_U64 Val64; SK_U64 Val64RxHwErrs = 0; SK_U64 Val64TxHwErrs = 0; + SK_BOOL Is64BitReq = SK_FALSE; char Buf[256]; @@ -4315,13 +4409,37 @@ */ switch (Id) { + case OID_GEN_XMIT_ERROR: + case OID_GEN_RCV_ERROR: + case OID_GEN_RCV_NO_BUFFER: +#ifndef SK_NDIS_64BIT_CTR + if (*pLen < sizeof(SK_U32)) { + *pLen = sizeof(SK_U32); + return (SK_PNMI_ERR_TOO_SHORT); + } + +#else /* SK_NDIS_64BIT_CTR */ + + /* + * for compatibility, at least 32bit are required for oid + */ + if (*pLen < sizeof(SK_U32)) { + /* + * but indicate handling for 64bit values, + * if insufficient space is provided + */ + *pLen = sizeof(SK_U64); + return (SK_PNMI_ERR_TOO_SHORT); + } + + Is64BitReq = (*pLen < sizeof(SK_U64)) ? SK_FALSE : SK_TRUE; +#endif /* SK_NDIS_64BIT_CTR */ + break; + case OID_SKGE_PORT_NUMBER: case OID_SKGE_DEVICE_TYPE: case OID_SKGE_RESULT: case OID_SKGE_RLMT_MONITOR_NUMBER: - case OID_GEN_XMIT_ERROR: - case OID_GEN_RCV_ERROR: - case OID_GEN_RCV_NO_BUFFER: case OID_GEN_TRANSMIT_QUEUE_LENGTH: case OID_SKGE_TRAP_NUMBER: case OID_SKGE_MDB_VERSION: @@ -4420,7 +4538,8 @@ GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_SYMBOL) + GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_SHORTS) + GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_RUNT) + - GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_TOO_LONG)+ + GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_TOO_LONG)- + GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_LONGFRAMES)+ GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_FCS) + GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_CEXT); break; @@ -4748,21 +4867,57 @@ break; case OID_GEN_RCV_ERROR: - Val32 = (SK_U32)(Val64RxHwErrs + pAC->Pnmi.RxNoBufCts); - SK_PNMI_STORE_U32(pBuf, Val32); - *pLen = sizeof(SK_U32); + Val64 = Val64RxHwErrs + pAC->Pnmi.RxNoBufCts; + + /* + * by default 32bit values are evaluated + */ + if (!Is64BitReq) { + SK_U32 Val32; + Val32 = (SK_U32)Val64; + SK_PNMI_STORE_U32(pBuf, Val32); + *pLen = sizeof(SK_U32); + } + else { + SK_PNMI_STORE_U64(pBuf, Val64); + *pLen = sizeof(SK_U64); + } break; case OID_GEN_XMIT_ERROR: - Val32 = (SK_U32)(Val64TxHwErrs + pAC->Pnmi.TxNoBufCts); - SK_PNMI_STORE_U32(pBuf, Val32); - *pLen = sizeof(SK_U32); + Val64 = Val64TxHwErrs + pAC->Pnmi.TxNoBufCts; + + /* + * by default 32bit values are evaluated + */ + if (!Is64BitReq) { + SK_U32 Val32; + Val32 = (SK_U32)Val64; + SK_PNMI_STORE_U32(pBuf, Val32); + *pLen = sizeof(SK_U32); + } + else { + SK_PNMI_STORE_U64(pBuf, Val64); + *pLen = sizeof(SK_U64); + } break; case OID_GEN_RCV_NO_BUFFER: - Val32 = (SK_U32)pAC->Pnmi.RxNoBufCts; - SK_PNMI_STORE_U32(pBuf, Val32); - *pLen = sizeof(SK_U32); + Val64 = pAC->Pnmi.RxNoBufCts; + + /* + * by default 32bit values are evaluated + */ + if (!Is64BitReq) { + SK_U32 Val32; + Val32 = (SK_U32)Val64; + SK_PNMI_STORE_U32(pBuf, Val32); + *pLen = sizeof(SK_U32); + } + else { + SK_PNMI_STORE_U64(pBuf, Val64); + *pLen = sizeof(SK_U64); + } break; case OID_GEN_TRANSMIT_QUEUE_LENGTH: @@ -4853,7 +5008,7 @@ case OID_SKGE_RLMT_MODE: case OID_SKGE_RLMT_PORT_ACTIVE: - case OID_SKGE_RLMT_PORT_PREFERED: + case OID_SKGE_RLMT_PORT_PREFERRED: if (*pLen < sizeof(SK_U8)) { *pLen = sizeof(SK_U8); @@ -4941,7 +5096,7 @@ *pLen = sizeof(char); break; - case OID_SKGE_RLMT_PORT_PREFERED: + case OID_SKGE_RLMT_PORT_PREFERRED: *pBuf = (char)SK_PNMI_PORT_PHYS2LOG( pAC->Rlmt.MacPreferred); *pLen = sizeof(char); @@ -5021,7 +5176,7 @@ } break; - case OID_SKGE_RLMT_PORT_PREFERED: + case OID_SKGE_RLMT_PORT_PREFERRED: /* Check if the buffer length is plausible */ if (*pLen < sizeof(char)) { @@ -5622,6 +5777,7 @@ case OID_SKGE_LINK_MODE: case OID_SKGE_FLOWCTRL_MODE: + case OID_SKGE_PHY_OPERATION_MODE: if (*pLen < Limit - LogPortIndex) { *pLen = Limit - LogPortIndex; @@ -5798,6 +5954,82 @@ Offset += sizeof(char); break; + case OID_SKGE_PHY_OPERATION_MODE : + /* Check the value range */ + Val8 = *(pBuf + Offset); + if (Val8 == 0) { + /* mode of this port remains unchanged */ + Offset += sizeof(char); + break; + } + if (Val8 < SK_MS_MODE_AUTO || + Val8 > SK_MS_MODE_SLAVE) { + + *pLen = 0; + return (SK_PNMI_ERR_BAD_VALUE); + } + + /* The preset ends here */ + if (Action == SK_PNMI_PRESET) { + + return (SK_PNMI_ERR_OK); + } + + if (LogPortIndex == 0) { + + /* + * The virtual port consists of all currently + * active ports. Find them and send an event + * with new master/slave (role) mode to SIRQ. + */ + for (PhysPortIndex = 0; + PhysPortIndex < PhysPortMax; + PhysPortIndex ++) { + + if (!pAC->Pnmi.Port[PhysPortIndex]. + ActiveFlag) { + + continue; + } + + EventParam.Para32[0] = PhysPortIndex; + EventParam.Para32[1] = (SK_U32)Val8; + if (SkGeSirqEvent(pAC, IoC, + SK_HWEV_SET_ROLE, + EventParam) > 0) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, + SK_PNMI_ERR052, + SK_PNMI_ERR052MSG); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + } + } + else { + /* + * Send an event with the new master/slave + * (role) mode to the SIRQ module. + */ + EventParam.Para32[0] = SK_PNMI_PORT_LOG2PHYS( + pAC, LogPortIndex); + EventParam.Para32[1] = (SK_U32)Val8; + if (SkGeSirqEvent(pAC, IoC, + SK_HWEV_SET_ROLE, EventParam) > 0) { + + SK_ERR_LOG(pAC, SK_ERRCL_SW, + SK_PNMI_ERR052, + SK_PNMI_ERR052MSG); + + *pLen = 0; + return (SK_PNMI_ERR_GENERAL); + } + } + + Offset += sizeof(char); + break; + default: SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR045, SK_PNMI_ERR045MSG); @@ -6670,6 +6902,12 @@ 32); break; + case SK_PNMI_HRX_LONGFRAMES: + LowVal = (SK_U32)pAC->Pnmi.Port[PhysPortIndex].StatRxLongFrameCts; + HighVal = (SK_U32) + (pAC->Pnmi.Port[PhysPortIndex].StatRxLongFrameCts >> 32); + break; + case SK_PNMI_HRX_FCS: /* * Broadcom filters fcs errors and counts it in @@ -6765,11 +7003,16 @@ SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex]. StatSyncOctetsCts, 0, sizeof(pAC->Pnmi.Port[ PhysPortIndex].StatSyncOctetsCts)); + SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex]. + StatRxLongFrameCts, 0, sizeof(pAC->Pnmi.Port[ + PhysPortIndex].StatRxLongFrameCts)); } /* * Clear local statistics */ + SK_MEMSET((char *)&pAC->Pnmi.VirtualCounterOffset, 0, + sizeof(pAC->Pnmi.VirtualCounterOffset)); pAC->Pnmi.RlmtChangeCts = 0; pAC->Pnmi.RlmtChangeTime = 0; SK_MEMSET((char *)&pAC->Pnmi.RlmtChangeEstimate.EstValue[0], 0, diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/sk98lin/skgesirq.c linux/drivers/net/sk98lin/skgesirq.c --- v2.4.0-test8/linux/drivers/net/sk98lin/skgesirq.c Tue Nov 23 10:15:42 1999 +++ linux/drivers/net/sk98lin/skgesirq.c Fri Sep 15 14:34:19 2000 @@ -2,8 +2,8 @@ * * Name: skgesirq.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.46 $ - * Date: $Date: 1999/09/16 10:30:07 $ + * Version: $Revision: 1.55 $ + * Date: $Date: 2000/06/19 08:36:25 $ * Purpose: Special IRQ module * ******************************************************************************/ @@ -13,8 +13,6 @@ * (C)Copyright 1998,1999 SysKonnect, * a business unit of Schneider & Koch & Co. Datensysteme GmbH. * - * See the file "skge.c" for further information. - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -29,6 +27,34 @@ * History: * * $Log: skgesirq.c,v $ + * Revision 1.55 2000/06/19 08:36:25 cgoos + * Changed comment. + * + * Revision 1.54 2000/05/22 08:45:57 malthoff + * Fix: #10523 is valid for all BCom PHYs. + * + * Revision 1.53 2000/05/19 10:20:30 cgoos + * Removed Solaris debug output code. + * + * Revision 1.52 2000/05/19 10:19:37 cgoos + * Added PHY state check in HWLinkDown. + * Move PHY interrupt code to IS_EXT_REG case in SkGeSirqIsr. + * + * Revision 1.51 2000/05/18 05:56:20 cgoos + * Fixed typo. + * + * Revision 1.50 2000/05/17 12:49:49 malthoff + * Fixes BCom link bugs (#10523). + * + * Revision 1.49 1999/12/17 11:02:50 gklug + * fix: read PHY_STAT of Broadcom chip more often to assure good status + * + * Revision 1.48 1999/12/06 10:01:17 cgoos + * Added SET function for Role. + * + * Revision 1.47 1999/11/22 13:34:24 cgoos + * Changed license header to GPL. + * * Revision 1.46 1999/09/16 10:30:07 cgoos * Removed debugging output statement from Linux. * @@ -215,7 +241,7 @@ */ static const char SysKonnectFileId[] = - "$Id: skgesirq.c,v 1.46 1999/09/16 10:30:07 cgoos Exp $" ; + "$Id: skgesirq.c,v 1.55 2000/06/19 08:36:25 cgoos Exp $" ; #include "h/skdrv1st.h" /* Driver Specific Definitions */ #include "h/skgepnmi.h" /* PNMI Definitions */ @@ -385,6 +411,15 @@ /* disable all PHY interrupts */ switch (pAC->GIni.GP[Port].PhyType) { case SK_PHY_BCOM: + /* make sure that PHY is initialized */ + if (pAC->GIni.GP[Port].PState) { + /* Workaround BCOM Errata (#10523) all BCom */ + /* Disable Power Management if link is down */ + PHY_READ(IoC, pPrt, Port, PHY_BCOM_AUX_CTRL, + &Word); + PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_AUX_CTRL, + Word | PHY_B_AC_DIS_PM); + } PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_INT_MASK, 0xffff); break; @@ -766,12 +801,11 @@ } /* - * I2C Ready interrupt + * external reg interrupt */ - if (Istatus & IS_I2C_READY) { + if (Istatus & IS_EXT_REG) { SK_U16 PhyInt; SK_U16 PhyIMsk; - SK_BOOL IsPhyInt = SK_FALSE; int i; /* test IRQs from PHY */ for (i=0; iGIni.GIMacsFound; i++) { @@ -794,7 +828,6 @@ SkPhyIsrBcom(pAC, IoC, i, (SK_U16) (PhyInt & (~PhyIMsk))); - IsPhyInt = SK_TRUE; } } else { @@ -814,7 +847,6 @@ i, PhyInt, PhyIMsk)); SkPhyIsrLone(pAC, IoC, i, (SK_U16) (PhyInt & PhyIMsk)); - IsPhyInt = SK_TRUE; } break; case SK_PHY_NAT: @@ -822,9 +854,13 @@ break; } } - if (!IsPhyInt) { - SkI2cIsr(pAC, IoC); - } + } + + /* + * I2C Ready interrupt + */ + if (Istatus & IS_I2C_READY) { + SkI2cIsr(pAC, IoC); } if (Istatus & IS_LNK_SYNC_M1) { @@ -1328,8 +1364,23 @@ SK_U16 PhyStat; /* Phy Status Register */ int Done; SK_U16 ResAb; + SK_U16 SWord; pPrt = &pAC->GIni.GP[Port]; + + /* Check for No HCD Link events (#10523) */ + PHY_READ(IoC, pPrt, Port, PHY_BCOM_INT_STAT, &Isrc); + if ((Isrc & PHY_B_IS_NO_HDCL) == PHY_B_IS_NO_HDCL) { + + /* Workaround BCOM Errata */ + /* enable and disable Loopback mode if NO HCD occurs */ + PHY_READ(IoC, pPrt, Port, PHY_BCOM_CTRL, &SWord); + PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_CTRL, SWord | PHY_CT_LOOP); + PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_CTRL, SWord & ~PHY_CT_LOOP); + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("No HCD Link event, Port %d\n", Port)); + } + PHY_READ(IoC, pPrt, Port, PHY_BCOM_STAT, &PhyStat); if (pPrt->PHWLinkUp) { @@ -1338,7 +1389,7 @@ pPrt->PIsave = 0; - /* Now wait for each ports link */ + /* Now wait for each port's link */ if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) { AutoNeg = SK_FALSE; @@ -1355,13 +1406,43 @@ PHY_READ(IoC, pPrt, Port, PHY_BCOM_STAT, &PhyStat); SkXmAutoNegLipaBcom(pAC, IoC, Port, PhyStat); - if ((PhyStat & PHY_ST_LSYNC) == 0){ - return(SK_HW_PS_NONE) ; + + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("AutoNeg:%d, PhyStat: %Xh.\n", AutoNeg, PhyStat)); + + PHY_READ(IoC, pPrt, Port, PHY_BCOM_1000T_STAT, &ResAb); + + if ((PhyStat & PHY_ST_LSYNC) == 0) { + if (ResAb & (PHY_B_1000S_MSF)) { + /* Error */ + SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL, + ("Master/Slave Fault port %d\n", Port)); + pPrt->PAutoNegFail = SK_TRUE; + pPrt->PMSStatus = SK_MS_STAT_FAULT; + return (SK_AND_OTHER); + } + return (SK_HW_PS_NONE); + } + + if (ResAb & (PHY_B_1000S_MSF)) { + /* Error */ + SK_DBG_MSG(pAC,SK_DBGMOD_HWM,SK_DBGCAT_CTRL, + ("Master/Slave Fault port %d\n", Port)); + pPrt->PAutoNegFail = SK_TRUE; + pPrt->PMSStatus = SK_MS_STAT_FAULT; + return (SK_AND_OTHER); + } else if (ResAb & PHY_B_1000S_MSR) { + pPrt->PMSStatus = SK_MS_STAT_MASTER; + } else { + pPrt->PMSStatus = SK_MS_STAT_SLAVE; } + + SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL, + ("AutoNeg:%d, PhyStat: %Xh.\n", AutoNeg, PhyStat)); if (AutoNeg) { if (PhyStat & PHY_ST_AN_OVER) { - SkHWLinkUp(pAC, IoC, Port) ; + SkHWLinkUp(pAC, IoC, Port); Done = SkXmAutoNegDone(pAC,IoC,Port); if (Done != SK_AND_OK) { /* Get PHY parameters, for debuging only */ @@ -1400,6 +1481,8 @@ Port)); } #endif + +#if 0 PHY_READ(IoC, pPrt, Port, PHY_BCOM_1000T_STAT, &ResAb); if (ResAb & (PHY_B_1000S_MSF)) { /* Error */ @@ -1413,6 +1496,7 @@ } else { pPrt->PMSStatus = SK_MS_STAT_SLAVE ; } +#endif /* 0 */ /* @@ -1753,6 +1837,18 @@ if (pAC->GIni.GP[Port].PFlowCtrlMode != Val8) { /* Set New Flow Control mode */ pAC->GIni.GP[Port].PFlowCtrlMode = Val8; + + /* Restart Port */ + SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_STOP, Para); + SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_START, Para); + } + break; + + case SK_HWEV_SET_ROLE: + Val8 = (SK_U8) Para.Para32[1]; + if (pAC->GIni.GP[Port].PMSMode != Val8) { + /* Set New link mode */ + pAC->GIni.GP[Port].PMSMode = Val8; /* Restart Port */ SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_STOP, Para); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/sk98lin/ski2c.c linux/drivers/net/sk98lin/ski2c.c --- v2.4.0-test8/linux/drivers/net/sk98lin/ski2c.c Tue Nov 23 10:15:42 1999 +++ linux/drivers/net/sk98lin/ski2c.c Fri Sep 15 14:34:19 2000 @@ -2,8 +2,8 @@ * * Name: ski2c.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.41 $ - * Date: $Date: 1999/09/14 14:11:30 $ + * Version: $Revision: 1.44 $ + * Date: $Date: 2000/08/07 15:49:03 $ * Purpose: Funktions to access Voltage and Temperature Sensor * (taken from Monalisa (taken from Concentrator)) * @@ -11,11 +11,9 @@ /****************************************************************************** * - * (C)Copyright 1998,1999 SysKonnect, + * (C)Copyright 1998-2000 SysKonnect, * a business unit of Schneider & Koch & Co. Datensysteme GmbH. * - * See the file "skge.c" for further information. - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -30,6 +28,16 @@ * History: * * $Log: ski2c.c,v $ + * Revision 1.44 2000/08/07 15:49:03 gklug + * fix: SK_INFAST only in NetWare driver + * + * Revision 1.43 2000/08/03 14:28:17 rassmann + * - Added function to wait for I2C being ready before resetting the board. + * - Replaced one duplicate "out of range" message with correct one. + * + * Revision 1.42 1999/11/22 13:35:12 cgoos + * Changed license header to GPL. + * * Revision 1.41 1999/09/14 14:11:30 malthoff * The 1000BT Dual Link adapter has got only one Fan. * The second Fan has been removed. @@ -172,10 +180,10 @@ /* - i2C Protocol + I2C Protocol */ static const char SysKonnectFileId[] = - "$Id: ski2c.c,v 1.41 1999/09/14 14:11:30 malthoff Exp $" ; + "$Id: ski2c.c,v 1.44 2000/08/07 15:49:03 gklug Exp $"; #include "h/skdrv1st.h" /* Driver Specific Definitions */ #include "h/lm80.h" @@ -193,9 +201,9 @@ This file covers functions that allow to read write and do some bulk requests a specified I2C address. - The Genesis has 2 I2C busses. One for the EEPROM which holds + The Genesis has 2 I2C buses. One for the EEPROM which holds the VPD Data and one for temperature and voltage sensor. - The following picture shows the I2C busses, I2C devices and + The following picture shows the I2C buses, I2C devices and there control registers. Note: The VPD functions are in skvpd.c @@ -292,13 +300,13 @@ * serial data line simultaneously (ASIC: last bit of a byte = '1', I2C client * send an 'ACK'). See also Concentrator Bugreport No. 10192. */ -#define I2C_DATA_HIGH(IoC) SK_I2C_SET_BIT(IoC,I2C_DATA) -#define I2C_DATA_LOW(IoC) SK_I2C_CLR_BIT(IoC,I2C_DATA) -#define I2C_DATA_OUT(IoC) SK_I2C_SET_BIT(IoC,I2C_DATA_DIR) -#define I2C_DATA_IN(IoC) SK_I2C_CLR_BIT(IoC,I2C_DATA_DIR|I2C_DATA) -#define I2C_CLK_HIGH(IoC) SK_I2C_SET_BIT(IoC,I2C_CLK) -#define I2C_CLK_LOW(IoC) SK_I2C_CLR_BIT(IoC,I2C_CLK|I2C_DATA_DIR) -#define I2C_START_COND(IoC) SK_I2C_CLR_BIT(IoC,I2C_CLK) +#define I2C_DATA_HIGH(IoC) SK_I2C_SET_BIT(IoC, I2C_DATA) +#define I2C_DATA_LOW(IoC) SK_I2C_CLR_BIT(IoC, I2C_DATA) +#define I2C_DATA_OUT(IoC) SK_I2C_SET_BIT(IoC, I2C_DATA_DIR) +#define I2C_DATA_IN(IoC) SK_I2C_CLR_BIT(IoC, I2C_DATA_DIR|I2C_DATA) +#define I2C_CLK_HIGH(IoC) SK_I2C_SET_BIT(IoC, I2C_CLK) +#define I2C_CLK_LOW(IoC) SK_I2C_CLR_BIT(IoC, I2C_CLK|I2C_DATA_DIR) +#define I2C_START_COND(IoC) SK_I2C_CLR_BIT(IoC, I2C_CLK) #define NS2CLKT(x) ((x*125L)/10000) @@ -308,25 +316,24 @@ * sending one bit */ void SkI2cSndBit( -SK_IOC IoC, /* IoContext */ +SK_IOC IoC, /* I/O Context */ SK_U8 Bit) /* Bit to send */ { - I2C_DATA_OUT(IoC) ; + I2C_DATA_OUT(IoC); if (Bit) { I2C_DATA_HIGH(IoC); } else { I2C_DATA_LOW(IoC); } - SkDgWaitTime(IoC,NS2BCLK(T_DATA_IN_SETUP)); + SkDgWaitTime(IoC, NS2BCLK(T_DATA_IN_SETUP)); I2C_CLK_HIGH(IoC); - SkDgWaitTime(IoC,NS2BCLK(T_CLK_HIGH)); + SkDgWaitTime(IoC, NS2BCLK(T_CLK_HIGH)); I2C_CLK_LOW(IoC); -} - +} /* SkI2cSndBit*/ /* - * Signal a start to the i2C Bus. + * Signal a start to the I2C Bus. * * A start is signaled when data goes to low in a high clock cycle. * @@ -334,66 +341,70 @@ * * Status: not tested */ -void SkI2cStart(SK_IOC IoC) /* I/O Context */ +void SkI2cStart( +SK_IOC IoC) /* I/O Context */ { /* Init data and Clock to output lines */ /* Set Data high */ - I2C_DATA_OUT(IoC) ; - I2C_DATA_HIGH(IoC) ; + I2C_DATA_OUT(IoC); + I2C_DATA_HIGH(IoC); /* Set Clock high */ - I2C_CLK_HIGH(IoC) ; + I2C_CLK_HIGH(IoC); - SkDgWaitTime(IoC,NS2BCLK(T_START_SETUP)) ; + SkDgWaitTime(IoC, NS2BCLK(T_START_SETUP)); /* Set Data Low */ - I2C_DATA_LOW(IoC) ; + I2C_DATA_LOW(IoC); - SkDgWaitTime(IoC,NS2BCLK(T_START_HOLD)) ; + SkDgWaitTime(IoC, NS2BCLK(T_START_HOLD)); /* Clock low without Data to Input */ - I2C_START_COND(IoC) ; + I2C_START_COND(IoC); - SkDgWaitTime(IoC,NS2BCLK(T_CLK_LOW)) ; -} + SkDgWaitTime(IoC, NS2BCLK(T_CLK_LOW)); +} /* SkI2cStart */ -void SkI2cStop(SK_IOC IoC) /* I/O Context */ +void SkI2cStop( +SK_IOC IoC) /* I/O Context */ { /* Init data and Clock to output lines */ /* Set Data low */ - I2C_DATA_OUT(IoC) ; - I2C_DATA_LOW(IoC) ; + I2C_DATA_OUT(IoC); + I2C_DATA_LOW(IoC); - SkDgWaitTime(IoC,NS2BCLK(T_CLK_2_DATA_OUT)) ; + SkDgWaitTime(IoC, NS2BCLK(T_CLK_2_DATA_OUT)); /* Set Clock high */ - I2C_CLK_HIGH(IoC) ; + I2C_CLK_HIGH(IoC); - SkDgWaitTime(IoC,NS2BCLK(T_STOP_SETUP)) ; + SkDgWaitTime(IoC, NS2BCLK(T_STOP_SETUP)); /* * Set Data High: Do it by setting the Data Line to Input. * Because of a pull up resistor the Data Line * floods to high. */ - I2C_DATA_IN(IoC) ; + I2C_DATA_IN(IoC); /* * When I2C activity is stopped * o DATA should be set to input and * o CLOCK should be set to high! */ - SkDgWaitTime(IoC,NS2BCLK(T_BUS_IDLE)) ; -} + SkDgWaitTime(IoC, NS2BCLK(T_BUS_IDLE)); +} /* SkI2cStop */ + /* - * Receive just one bit via the i2C bus. + * Receive just one bit via the I2C bus. * * Note: Clock must be set to LOW before calling this function. * * Returns The received bit. */ -int SkI2cRcvBit(SK_IOC IoC) /* I/O Context */ +int SkI2cRcvBit( +SK_IOC IoC) /* I/O Context */ { int Bit; SK_U8 I2cSwCtrl; @@ -401,13 +412,13 @@ /* Init data as input line */ I2C_DATA_IN(IoC); - SkDgWaitTime(IoC,NS2BCLK(T_CLK_2_DATA_OUT)) ; + SkDgWaitTime(IoC, NS2BCLK(T_CLK_2_DATA_OUT)); I2C_CLK_HIGH(IoC); - SkDgWaitTime(IoC,NS2BCLK(T_CLK_HIGH)) ; + SkDgWaitTime(IoC, NS2BCLK(T_CLK_HIGH)); - SK_I2C_GET_SW(IoC,&I2cSwCtrl) ; + SK_I2C_GET_SW(IoC, &I2cSwCtrl); if (I2cSwCtrl & I2C_DATA) { Bit = 1; } else { @@ -415,10 +426,11 @@ } I2C_CLK_LOW(IoC); - SkDgWaitTime(IoC,NS2BCLK(T_CLK_LOW-T_CLK_2_DATA_OUT)) ; + SkDgWaitTime(IoC, NS2BCLK(T_CLK_LOW-T_CLK_2_DATA_OUT)); return(Bit); -} +} /* SkI2cRcvBit */ + /* * Receive an ACK. @@ -426,58 +438,64 @@ * returns 0 If acknoledged * 1 in case of an error */ -int SkI2cRcvAck(SK_IOC IoC) /* I/O Context */ +int SkI2cRcvAck( +SK_IOC IoC) /* I/O Context */ { /* * Received bit must be zero. */ - return (SkI2cRcvBit(IoC) != 0) ; -} + return (SkI2cRcvBit(IoC) != 0); +} /* SkI2cRcvAck */ + /* * Send an NACK. */ -void SkI2cSndNAck(SK_IOC IoC) /* I/O Context */ +void SkI2cSndNAck( +SK_IOC IoC) /* I/O Context */ { /* * Received bit must be zero. */ - SkI2cSndBit(IoC,1) ; -} + SkI2cSndBit(IoC, 1); +} /* SkI2cSndNAck */ + /* * Send an ACK. */ -void SkI2cSndAck(SK_IOC IoC) /* I/O Context */ +void SkI2cSndAck( +SK_IOC IoC) /* I/O Context */ { /* * Received bit must be zero. * */ - SkI2cSndBit(IoC,0) ; -} + SkI2cSndBit(IoC, 0); +} /* SkI2cSndAck */ + /* - * Send one byte to the i2C device and wait for ACK. + * Send one byte to the I2C device and wait for ACK. * * Return acknoleged status. */ int SkI2cSndByte( SK_IOC IoC, /* I/O Context */ -int Byte) /* byte to send */ +int Byte) /* byte to send */ { int i; for (i=0; i<8; i++) { if (Byte & (1<<(7-i))) { - SkI2cSndBit(IoC,1) ; + SkI2cSndBit(IoC, 1); } else { - SkI2cSndBit(IoC,0) ; + SkI2cSndBit(IoC, 0); } } - return(SkI2cRcvAck(IoC)) ; -} + return(SkI2cRcvAck(IoC)); +} /* SkI2cSndByte */ /* @@ -487,24 +505,24 @@ */ int SkI2cRcvByte( SK_IOC IoC, /* I/O Context */ -int Last) /* Last Byte Flag */ +int Last) /* Last Byte Flag */ { int i; int Byte = 0; for (i=0; i<8; i++) { - Byte <<= 1 ; - Byte |= SkI2cRcvBit(IoC) ; + Byte <<= 1; + Byte |= SkI2cRcvBit(IoC); } if (Last) { - SkI2cSndNAck(IoC) ; + SkI2cSndNAck(IoC); } else { - SkI2cSndAck(IoC) ; + SkI2cSndAck(IoC); } - return(Byte) ; -} + return(Byte); +} /* SkI2cRcvByte */ /* @@ -514,68 +532,106 @@ */ int SkI2cSndDev( SK_IOC IoC, /* I/O Context */ -int Addr, /* Device Address */ -int Rw) /* Read / Write Flag */ +int Addr, /* Device Address */ +int Rw) /* Read / Write Flag */ { - SkI2cStart(IoC) ; - Rw = ~Rw ; - Rw &= I2C_WRITE ; - return(SkI2cSndByte(IoC, (Addr<<1) | Rw)) ; -} + SkI2cStart(IoC); + Rw = ~Rw; + Rw &= I2C_WRITE; + return(SkI2cSndByte(IoC, (Addr<<1) | Rw)); +} /* SkI2cSndDev */ #endif /* SK_DIAG */ /*----------------- I2C CTRL Register Functions ----------*/ /* - * waits for a completetion of a I2C transfer + * waits for a completion of an I2C transfer * * returns 0: success, transfer completes - * 1: error, transfer does not complete, I2C transfer - * killed, wait loop terminated. + * 1: error, transfer does not complete, I2C transfer + * killed, wait loop terminated. */ int SkI2cWait( SK_AC *pAC, /* Adapter Context */ -SK_IOC IoC, /* IoContext */ -int Event) /* complete event to wait for (I2C_READ or I2C_WRITE) */ +SK_IOC IoC, /* I/O Context */ +int Event) /* complete event to wait for (I2C_READ or I2C_WRITE) */ +{ + SK_U64 StartTime; + SK_U32 I2cCtrl; + + StartTime = SkOsGetTime(pAC); + do { + if (SkOsGetTime(pAC) - StartTime > SK_TICKS_PER_SEC / 8) { + SK_I2C_STOP(IoC); +#ifndef SK_DIAG + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_I2C_E002, SKERR_I2C_E002MSG); +#endif /* !SK_DIAG */ + return(1); + } + SK_I2C_GET_CTL(IoC, &I2cCtrl); + } while ((I2cCtrl & I2C_FLAG) == (SK_U32)Event << 31); + + return(0); +} /* SkI2cWait */ + + +/* + * waits for a completion of an I2C transfer + * + * Returns + * Nothing + */ +void SkI2cWaitIrq( +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC) /* I/O Context */ { - SK_U64 StartTime ; - SK_U32 I2cCtrl ; + SK_SENSOR *pSen; + SK_U64 StartTime; + SK_U32 IrqSrc; - StartTime = SkOsGetTime(pAC) ; + pSen = &pAC->I2c.SenTable[pAC->I2c.CurrSens]; + + if (pSen->SenState == SK_SEN_IDLE) { + return; + } + + StartTime = SkOsGetTime(pAC); do { - if (SkOsGetTime(pAC) - StartTime > SK_TICKS_PER_SEC/16) { - SK_I2C_STOP(IoC) ; + if (SkOsGetTime(pAC) - StartTime > SK_TICKS_PER_SEC / 8) { + SK_I2C_STOP(IoC); #ifndef SK_DIAG - SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_I2C_E002, - SKERR_I2C_E002MSG) ; + SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_I2C_E002, SKERR_I2C_E002MSG); #endif /* !SK_DIAG */ - return(1) ; + return; } - SK_I2C_GET_CTL(IoC,&I2cCtrl) ; - } while((I2cCtrl & I2C_FLAG) == (SK_U32)Event << 31) ; + SK_IN32(pAC, B0_ISRC, &IrqSrc); + } while ((IrqSrc & IS_I2C_READY) == 0); - return(0) ; -} + return; +} /* SkI2cWaitIrq */ #ifdef SK_DIAG + /* * writes a single byte or 4 bytes into the I2C device * * returns 0: success - * 1: error + * 1: error */ int SkI2cWrite( -SK_AC *pAC, /* Adapter Context */ +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ SK_U32 I2cData, /* I2C Data to write */ -int I2cDev, /* I2C Device Address */ -int I2cReg, /* I2C Device Register Address */ -int I2cBurst) /* I2C Burst Flag ( 0 || I2C_BURST ) */ -{ - SK_OUT32(pAC,B2_I2C_DATA,I2cData) ; - SK_I2C_CTL(pAC,I2C_WRITE,I2cDev,I2cReg,I2cBurst); - return(SkI2cWait(pAC,pAC,I2C_WRITE)) ; -} +int I2cDev, /* I2C Device Address */ +int I2cReg, /* I2C Device Register Address */ +int I2cBurst) /* I2C Burst Flag ( 0 || I2C_BURST ) */ +{ + SK_OUT32(IoC, B2_I2C_DATA, I2cData); + SK_I2C_CTL(IoC, I2C_WRITE, I2cDev, I2cReg, I2cBurst); + return(SkI2cWait(pAC, IoC, I2C_WRITE)); +} /* SkI2cWrite*/ + /* * reads a single byte or 4 bytes from the I2C device @@ -583,39 +639,42 @@ * returns the word read */ SK_U32 SkI2cRead( -SK_AC *pAC, /* Adapter Context */ -int I2cDev, /* I2C Device Address */ -int I2cReg, /* I2C Device Register Address */ -int I2cBurst) /* I2C Burst Flag ( 0 || I2C_BURST ) */ -{ - SK_U32 Data ; - - SK_OUT32(pAC,B2_I2C_DATA,0) ; - SK_I2C_CTL(pAC,I2C_READ,I2cDev,I2cReg,I2cBurst); - if (SkI2cWait(pAC,pAC,I2C_READ)) { - w_print("I2c Transfer Timeout!\n"); - } - SK_IN32(pAC,B2_I2C_DATA,&Data) ; - return(Data) ; -} +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +int I2cDev, /* I2C Device Address */ +int I2cReg, /* I2C Device Register Address */ +int I2cBurst) /* I2C Burst Flag ( 0 || I2C_BURST ) */ +{ + SK_U32 Data; + + SK_OUT32(IoC, B2_I2C_DATA, 0); + SK_I2C_CTL(IoC, I2C_READ, I2cDev, I2cReg, I2cBurst); + if (SkI2cWait(pAC, IoC, I2C_READ)) { + w_print("I2C Transfer Timeout!\n"); + } + SK_IN32(IoC, B2_I2C_DATA, &Data); + return(Data); +} /* SkI2cRead */ + #endif /* SK_DIAG */ + /* - * read a sensors value + * read a sensor's value * - * This function read a sensors value from the I2c sensor chip. The sensor + * This function read a sensors value from the I2C sensor chip. The sensor * is defined by its index into the sensors database in the struct pAC points * to. * Returns 1 if the read is completed - * 0 if the read must be continued (I2c Bus still allocated) + * 0 if the read must be continued (I2C Bus still allocated) */ int SkI2cReadSensor( SK_AC *pAC, /* Adapter Context */ -SK_IOC IoC, /* IoContext */ +SK_IOC IoC, /* I/O Context */ SK_SENSOR *pSen) /* Sensor to be read */ { - return((*pSen->SenRead)(pAC,IoC,pSen)) ; -} + return((*pSen->SenRead)(pAC, IoC, pSen)); +} /* SkI2cReadSensor*/ /* * Do the Init state 0 initialization @@ -639,7 +698,7 @@ for (i=0; i < SK_MAX_SENSORS; i ++) { switch (i) { case 0: - pAC->I2c.SenTable[i].SenDesc = "Temperature" ; + pAC->I2c.SenTable[i].SenDesc = "Temperature"; pAC->I2c.SenTable[i].SenType = SK_SEN_TEMP; pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_ERRHIGH0; pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_ERRLOW0; @@ -733,10 +792,11 @@ pAC->I2c.SenTable[i].SenDev = LM80_ADDR; } - /* Now we are INIT dataed */ + /* Now we are "INIT data"ed */ pAC->I2c.InitLevel = SK_INIT_DATA; return(0); -} +} /* SkI2cInit0*/ + /* * Do the init state 1 initialization @@ -760,7 +820,7 @@ */ static int SkI2cInit1( SK_AC *pAC, /* Adapter Context */ -SK_IOC IoC) /* IoContext needed in level 1 */ +SK_IOC IoC) /* I/O Context */ { if (pAC->I2c.InitLevel != SK_INIT_DATA) { /* ReInit not needed in I2C module */ @@ -769,27 +829,27 @@ SK_OUT32(IoC, B2_I2C_DATA, 0); SK_I2C_CTL(IoC, I2C_WRITE, LM80_ADDR, LM80_CFG, 0); - (void)SkI2cWait(pAC, IoC, I2C_WRITE) ; + (void)SkI2cWait(pAC, IoC, I2C_WRITE); SK_OUT32(IoC, B2_I2C_DATA, 0xff); SK_I2C_CTL(IoC, I2C_WRITE, LM80_ADDR, LM80_IMSK_1, 0); - (void)SkI2cWait(pAC, IoC, I2C_WRITE) ; + (void)SkI2cWait(pAC, IoC, I2C_WRITE); SK_OUT32(IoC, B2_I2C_DATA, 0xff); SK_I2C_CTL(IoC, I2C_WRITE, LM80_ADDR, LM80_IMSK_2, 0); - (void)SkI2cWait(pAC, IoC, I2C_WRITE) ; + (void)SkI2cWait(pAC, IoC, I2C_WRITE); SK_OUT32(IoC, B2_I2C_DATA, 0x0); SK_I2C_CTL(IoC, I2C_WRITE, LM80_ADDR, LM80_FAN_CTRL, 0); - (void)SkI2cWait(pAC, IoC, I2C_WRITE) ; + (void)SkI2cWait(pAC, IoC, I2C_WRITE); SK_OUT32(IoC, B2_I2C_DATA, 0); SK_I2C_CTL(IoC, I2C_WRITE, LM80_ADDR, LM80_TEMP_CTRL, 0); - (void)SkI2cWait(pAC, IoC, I2C_WRITE) ; + (void)SkI2cWait(pAC, IoC, I2C_WRITE); SK_OUT32(IoC, B2_I2C_DATA, LM80_CFG_START); SK_I2C_CTL(IoC, I2C_WRITE, LM80_ADDR, LM80_CFG, 0); - (void)SkI2cWait(pAC, IoC, I2C_WRITE) ; + (void)SkI2cWait(pAC, IoC, I2C_WRITE); /* * MaxSens has to be initialized here, because PhyType is not @@ -820,14 +880,15 @@ /* Now we are IO initialized */ pAC->I2c.InitLevel = SK_INIT_IO; return(0); -} +} /* SkI2cInit1 */ + /* * Init level 2: Start first sensors read */ static int SkI2cInit2( SK_AC *pAC, /* Adapter Context */ -SK_IOC IoC) /* IoContext needed in level 1 */ +SK_IOC IoC) /* I/O Context */ { int ReadComplete; SK_SENSOR *pSen; @@ -839,18 +900,18 @@ } pSen = &pAC->I2c.SenTable[pAC->I2c.CurrSens]; - ReadComplete = SkI2cReadSensor(pAC,IoC,pSen); + ReadComplete = SkI2cReadSensor(pAC, IoC, pSen); if (ReadComplete) { - SK_ERR_LOG(pAC, SK_ERRCL_INIT, SKERR_I2C_E008, - SKERR_I2C_E008MSG); + SK_ERR_LOG(pAC, SK_ERRCL_INIT, SKERR_I2C_E008, SKERR_I2C_E008MSG); } /* Now we are correctly initialized */ pAC->I2c.InitLevel = SK_INIT_RUN; return(0); -} +} /* SkI2cInit2*/ + /* * Initialize I2C devices @@ -871,27 +932,29 @@ */ int SkI2cInit( SK_AC *pAC, /* Adapter Context */ -SK_IOC IoC, /* IoContext needed in level 1 */ -int Level) /* Init Level */ +SK_IOC IoC, /* I/O Context needed in levels 1 and 2 */ +int Level) /* Init Level */ { switch (Level) { case SK_INIT_DATA: - return(SkI2cInit0(pAC)) ; + return(SkI2cInit0(pAC)); case SK_INIT_IO: - return(SkI2cInit1(pAC, IoC)) ; + return(SkI2cInit1(pAC, IoC)); case SK_INIT_RUN: - return(SkI2cInit2(pAC, IoC)) ; + return(SkI2cInit2(pAC, IoC)); default: break; } - return(0) ; -} + return(0); +} /* SkI2cInit */ + #ifndef SK_DIAG + /* - * Interrupt service function for the I2c Interface + * Interrupt service function for the I2C Interface * * Clears the Interrupt source * @@ -900,23 +963,24 @@ * Starts the timer if necessary. */ void SkI2cIsr( -SK_AC *pAC, /* Adapters context */ -SK_IOC IoC) /* Io Context */ +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC) /* I/O Context */ { SK_EVPARA Para; /* Clear the interrupt source */ - SK_OUT32(IoC, B2_I2C_IRQ, I2C_CLR_IRQ) ; + SK_OUT32(IoC, B2_I2C_IRQ, I2C_CLR_IRQ); Para.Para64 = 0; SkEventQueue(pAC, SKGE_I2C, SK_I2CEV_IRQ, Para); -} +} /* SkI2cIsr */ + /* * Check this sensors Value against the threshold and send events. */ static void SkI2cCheckSensor( -SK_AC *pAC, /* Adapters context */ +SK_AC *pAC, /* Adapter Context */ SK_SENSOR *pSen) { SK_EVPARA ParaLocal; @@ -929,12 +993,12 @@ /* Check Dummy Reads first */ if (pAC->I2c.DummyReads > 0) { - pAC->I2c.DummyReads -- ; + pAC->I2c.DummyReads --; return; } /* Get the current time */ - CurrTime = SkOsGetTime(pAC) ; + CurrTime = SkOsGetTime(pAC); /* Set para to the most usefull setting: * The current sensor. @@ -943,17 +1007,17 @@ /* Check the Value against the thresholds */ /* First: Error Thresholds */ - TooHigh = (pSen->SenValue > pSen->SenThreErrHigh) ; - TooLow = (pSen->SenValue < pSen->SenThreErrLow) ; + TooHigh = (pSen->SenValue > pSen->SenThreErrHigh); + TooLow = (pSen->SenValue < pSen->SenThreErrLow); - IsError = SK_FALSE ; + IsError = SK_FALSE; if (TooHigh || TooLow) { - /* Error condition is satiesfied */ + /* Error condition is satisfied */ DoTrapSend = SK_TRUE; DoErrLog = SK_TRUE; /* Now error condition is satisfied */ - IsError = SK_TRUE ; + IsError = SK_TRUE; if (pSen->SenErrFlag == SK_SEN_ERR_ERR) { /* This state is the former one */ @@ -981,7 +1045,7 @@ /* We came from a different state */ /* -> Set Begin Time Stamp */ pSen->SenBegErrTS = CurrTime; - pSen->SenErrFlag = SK_SEN_ERR_ERR ; + pSen->SenErrFlag = SK_SEN_ERR_ERR; } if (DoTrapSend) { @@ -993,7 +1057,7 @@ SkEventQueue(pAC, SKGE_PNMI, (TooHigh ? SK_PNMI_EVT_SEN_ERR_UPP : SK_PNMI_EVT_SEN_ERR_LOW), - ParaLocal) ; + ParaLocal); } if (DoErrLog) { @@ -1016,12 +1080,12 @@ /* Check the Value against the thresholds */ /* 2nd: Warning thresholds */ - TooHigh = (pSen->SenValue > pSen->SenThreWarnHigh) ; - TooLow = (pSen->SenValue < pSen->SenThreWarnLow) ; + TooHigh = (pSen->SenValue > pSen->SenThreWarnHigh); + TooLow = (pSen->SenValue < pSen->SenThreWarnLow); if (!IsError && (TooHigh || TooLow)) { - /* Error condition is satiesfied */ + /* Error condition is satisfied */ DoTrapSend = SK_TRUE; DoErrLog = SK_TRUE; @@ -1051,7 +1115,7 @@ /* We came from a different state */ /* -> Set Begin Time Stamp */ pSen->SenBegWarnTS = CurrTime; - pSen->SenErrFlag = SK_SEN_ERR_WARN ; + pSen->SenErrFlag = SK_SEN_ERR_WARN; } if (DoTrapSend) { @@ -1063,7 +1127,7 @@ SkEventQueue(pAC, SKGE_PNMI, (TooHigh ? SK_PNMI_EVT_SEN_WAR_UPP : SK_PNMI_EVT_SEN_WAR_LOW), - ParaLocal) ; + ParaLocal); } if (DoErrLog) { @@ -1074,8 +1138,8 @@ SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E009, SKERR_I2C_E009MSG); } else if (pSen->SenType == SK_SEN_VOLT) { - SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E009, - SKERR_I2C_E009MSG); + SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E010, + SKERR_I2C_E010MSG); } else { SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E014, @@ -1087,7 +1151,7 @@ /* Check for NO error at all */ if (!IsError && !TooHigh && !TooLow) { /* Set o.k. Status if no error and no warning condition */ - pSen->SenErrFlag = SK_SEN_ERR_OK ; + pSen->SenErrFlag = SK_SEN_ERR_OK; } /* End of check against the thresholds */ @@ -1115,17 +1179,18 @@ if (!pSen->SenInit) { SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E013, SKERR_I2C_E013MSG); } -} +} /* SkI2cCheckSensor*/ + /* * The only Event to be served is the timeout event * */ int SkI2cEvent( -SK_AC *pAC, /* Adapters context */ -SK_IOC IoC, /* Io Context */ -SK_U32 Event, /* Module specific Event */ -SK_EVPARA Para) /* Event specific Parameter */ +SK_AC *pAC, /* Adapter Context */ +SK_IOC IoC, /* I/O Context */ +SK_U32 Event, /* Module specific Event */ +SK_EVPARA Para) /* Event specific Parameter */ { int ReadComplete; SK_SENSOR *pSen; @@ -1141,7 +1206,7 @@ if (ReadComplete) { /* Check sensor against defined thresholds */ - SkI2cCheckSensor (pAC, pSen) ; + SkI2cCheckSensor (pAC, pSen); /* Increment Current and set appropriate Timeout */ Time = SK_I2C_TIM_SHORT; @@ -1155,7 +1220,7 @@ /* Start Timer */ ParaLocal.Para64 = (SK_U64) 0; SkTimerStart(pAC, IoC, &pAC->I2c.SenTimer, Time, - SKGE_I2C, SK_I2CEV_TIM, ParaLocal) ; + SKGE_I2C, SK_I2CEV_TIM, ParaLocal); } break; case SK_I2CEV_CLEAR: @@ -1176,6 +1241,6 @@ } return(0); -} -#endif /* !SK_DIAG */ -/* End of File */ +} /* SkI2cEvent*/ + +#endif /* !SK_DIAG */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/sk98lin/sklm80.c linux/drivers/net/sk98lin/sklm80.c --- v2.4.0-test8/linux/drivers/net/sk98lin/sklm80.c Tue Nov 23 10:15:42 1999 +++ linux/drivers/net/sk98lin/sklm80.c Fri Sep 15 14:34:19 2000 @@ -2,8 +2,8 @@ * * Name: sklm80.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.16 $ - * Date: $Date: 1999/05/27 14:05:47 $ + * Version: $Revision: 1.17 $ + * Date: $Date: 1999/11/22 13:35:51 $ * Purpose: Funktions to access Voltage and Temperature Sensor (LM80) * ******************************************************************************/ @@ -13,8 +13,6 @@ * (C)Copyright 1998,1999 SysKonnect, * a business unit of Schneider & Koch & Co. Datensysteme GmbH. * - * See the file "skge.c" for further information. - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -29,6 +27,9 @@ * History: * * $Log: sklm80.c,v $ + * Revision 1.17 1999/11/22 13:35:51 cgoos + * Changed license header to GPL. + * * Revision 1.16 1999/05/27 14:05:47 malthoff * Fans: Set SenVal to 0 if the fan value is 0 or 0xff. Both values * are outside the limits (0: div zero error, 0xff: value not in @@ -92,7 +93,7 @@ LM80 functions */ static const char SysKonnectFileId[] = - "$Id: sklm80.c,v 1.16 1999/05/27 14:05:47 malthoff Exp $" ; + "$Id: sklm80.c,v 1.17 1999/11/22 13:35:51 cgoos Exp $" ; #include "h/skdrv1st.h" /* Driver Specific Definitions */ #include "h/lm80.h" diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/sk98lin/skqueue.c linux/drivers/net/sk98lin/skqueue.c --- v2.4.0-test8/linux/drivers/net/sk98lin/skqueue.c Tue Nov 23 10:15:42 1999 +++ linux/drivers/net/sk98lin/skqueue.c Fri Sep 15 14:34:19 2000 @@ -2,8 +2,8 @@ * * Name: skqueue.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.14 $ - * Date: $Date: 1998/10/15 15:11:35 $ + * Version: $Revision: 1.15 $ + * Date: $Date: 1999/11/22 13:36:29 $ * Purpose: Management of an event queue. * ******************************************************************************/ @@ -13,8 +13,6 @@ * (C)Copyright 1998,1999 SysKonnect, * a business unit of Schneider & Koch & Co. Datensysteme GmbH. * - * See the file "skge.c" for further information. - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -29,6 +27,9 @@ * History: * * $Log: skqueue.c,v $ + * Revision 1.15 1999/11/22 13:36:29 cgoos + * Changed license header to GPL. + * * Revision 1.14 1998/10/15 15:11:35 gklug * fix: ID_sccs to SysKonnectFileId * @@ -81,7 +82,7 @@ Event queue and dispatcher */ static const char SysKonnectFileId[] = - "$Header: /usr56/projects/ge/schedule/skqueue.c,v 1.14 1998/10/15 15:11:35 gklug Exp $" ; + "$Header: /usr56/projects/ge/schedule/skqueue.c,v 1.15 1999/11/22 13:36:29 cgoos Exp $" ; #include "h/skdrv1st.h" /* Driver Specific Definitions */ #include "h/skqueue.h" /* Queue Definitions */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/sk98lin/skrlmt.c linux/drivers/net/sk98lin/skrlmt.c --- v2.4.0-test8/linux/drivers/net/sk98lin/skrlmt.c Tue Nov 23 10:15:42 1999 +++ linux/drivers/net/sk98lin/skrlmt.c Fri Sep 15 14:34:19 2000 @@ -2,8 +2,8 @@ * * Name: skrlmt.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.48 $ - * Date: $Date: 1999/10/04 14:01:17 $ + * Version: $Revision: 1.49 $ + * Date: $Date: 1999/11/22 13:38:02 $ * Purpose: Manage links on SK-NET Adapters, esp. redundant ones. * ******************************************************************************/ @@ -13,8 +13,6 @@ * (C)Copyright 1998,1999 SysKonnect, * a business unit of Schneider & Koch & Co. Datensysteme GmbH. * - * See the file "skge.c" for further information. - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -29,6 +27,10 @@ * History: * * $Log: skrlmt.c,v $ + * Revision 1.49 1999/11/22 13:38:02 cgoos + * Changed license header to GPL. + * Added initialization to some variables to avoid compiler warnings. + * * Revision 1.48 1999/10/04 14:01:17 rassmann * Corrected reaction to reception of BPDU frames. * Added parameter descriptions to "For Readme" section skrlmt.txt. @@ -216,7 +218,7 @@ #ifndef lint static const char SysKonnectFileId[] = - "@(#) $Id: skrlmt.c,v 1.48 1999/10/04 14:01:17 rassmann Exp $ (C) SysKonnect."; + "@(#) $Id: skrlmt.c,v 1.49 1999/11/22 13:38:02 cgoos Exp $ (C) SysKonnect."; #endif /* !defined(lint) */ #define __SKRLMT_C diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/sk98lin/sktimer.c linux/drivers/net/sk98lin/sktimer.c --- v2.4.0-test8/linux/drivers/net/sk98lin/sktimer.c Tue Nov 23 10:15:42 1999 +++ linux/drivers/net/sk98lin/sktimer.c Fri Sep 15 14:34:19 2000 @@ -2,8 +2,8 @@ * * Name: sktimer.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.11 $ - * Date: $Date: 1998/12/17 13:24:13 $ + * Version: $Revision: 1.12 $ + * Date: $Date: 1999/11/22 13:38:51 $ * Purpose: High level timer functions. * ******************************************************************************/ @@ -13,8 +13,6 @@ * (C)Copyright 1998,1999 SysKonnect, * a business unit of Schneider & Koch & Co. Datensysteme GmbH. * - * See the file "skge.c" for further information. - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -29,6 +27,9 @@ * History: * * $Log: sktimer.c,v $ + * Revision 1.12 1999/11/22 13:38:51 cgoos + * Changed license header to GPL. + * * Revision 1.11 1998/12/17 13:24:13 gklug * fix: restart problem: do NOT destroy timer queue if init 1 is done * @@ -75,7 +76,7 @@ Event queue and dispatcher */ static const char SysKonnectFileId[] = - "$Header: /usr56/projects/ge/schedule/sktimer.c,v 1.11 1998/12/17 13:24:13 gklug Exp $" ; + "$Header: /usr56/projects/ge/schedule/sktimer.c,v 1.12 1999/11/22 13:38:51 cgoos Exp $" ; #include "h/skdrv1st.h" /* Driver Specific Definitions */ #include "h/skdrv2nd.h" /* Adapter Control- and Driver specific Def. */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/sk98lin/skvpd.c linux/drivers/net/sk98lin/skvpd.c --- v2.4.0-test8/linux/drivers/net/sk98lin/skvpd.c Wed Jul 5 10:56:13 2000 +++ linux/drivers/net/sk98lin/skvpd.c Fri Sep 15 14:34:19 2000 @@ -2,19 +2,17 @@ * * Name: skvpd.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.24 $ - * Date: $Date: 1999/03/11 14:25:49 $ + * Version: $Revision: 1.27 $ + * Date: $Date: 2000/08/10 11:29:06 $ * Purpose: Shared software to read and write VPD data * ******************************************************************************/ /****************************************************************************** * - * (C)Copyright 1998,1999 SysKonnect, + * (C)Copyright 1998-2000 SysKonnect, * a business unit of Schneider & Koch & Co. Datensysteme GmbH. * - * See the file "skge.c" for further information. - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -29,6 +27,18 @@ * History: * * $Log: skvpd.c,v $ + * Revision 1.27 2000/08/10 11:29:06 rassmann + * Editorial changes. + * Preserving 32-bit alignment in structs for the adapter context. + * Removed unused function VpdWriteDword() (#if 0). + * Made VpdReadKeyword() available for SKDIAG only. + * + * Revision 1.26 2000/06/13 08:00:01 mkarl + * additional cast to avoid compile problems in 64 bit environment + * + * Revision 1.25 1999/11/22 13:39:32 cgoos + * Changed license header to GPL. + * * Revision 1.24 1999/03/11 14:25:49 malthoff * Replace __STDC__ with SK_KR_PROTO. * @@ -62,7 +72,7 @@ * * Revision 1.14 1998/10/28 07:20:38 gklug * chg: Interface functions to use IoC as parameter as well - * fix: VpdRead/WriteDWord now return SK_U32 + * fix: VpdRead/WriteDWord now returns SK_U32 * chg: VPD_IN/OUT names conform to SK_IN/OUT * add: usage of VPD_IN/OUT8 macros * add: VpdRead/Write Stream functions to r/w a stream of data @@ -120,7 +130,7 @@ Please refer skvpd.txt for infomation how to include this module */ static const char SysKonnectFileId[] = - "@(#)$Id: skvpd.c,v 1.24 1999/03/11 14:25:49 malthoff Exp $ (C) SK" ; + "@(#)$Id: skvpd.c,v 1.27 2000/08/10 11:29:06 rassmann Exp $ (C) SK"; #include "h/skdrv1st.h" #include "h/sktypes.h" @@ -134,9 +144,9 @@ static SK_VPD_PARA *vpd_find_para( SK_AC *pAC, char *key, - SK_VPD_PARA *p) ; + SK_VPD_PARA *p); #else /* SK_KR_PROTO */ -static SK_VPD_PARA *vpd_find_para() ; +static SK_VPD_PARA *vpd_find_para(); #endif /* SK_KR_PROTO */ /* @@ -151,28 +161,29 @@ SK_IOC IoC, /* IO Context */ int event) /* event to wait for (VPD_READ / VPD_write) completion*/ { - SK_U64 start_time ; - SK_U16 state ; + SK_U64 start_time; + SK_U16 state; SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL, - ("vpd wait for %s\n",event?"Write":"Read")) ; - start_time = SkOsGetTime(pAC) ; + ("vpd wait for %s\n",event?"Write":"Read")); + start_time = SkOsGetTime(pAC); do { if (SkOsGetTime(pAC) - start_time > SK_TICKS_PER_SEC/16) { - VPD_STOP(pAC,IoC) ; + VPD_STOP(pAC,IoC); SK_DBG_MSG(pAC,SK_DBGMOD_VPD, SK_DBGCAT_FATAL|SK_DBGCAT_ERR, - ("ERROR:vpd wait timeout\n")) ; - return(1) ; + ("ERROR:vpd wait timeout\n")); + return(1); } - VPD_IN16(pAC,IoC,PCI_VPD_ADR_REG,&state) ; + VPD_IN16(pAC,IoC,PCI_VPD_ADR_REG,&state); SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL, - ("state = %x, event %x\n",state,event)) ; - } while((int)(state & PCI_VPD_FLAG) == event) ; + ("state = %x, event %x\n",state,event)); + } while((int)(state & PCI_VPD_FLAG) == event); - return(0) ; + return(0); } +#ifdef SKDIAG /* * Read the dword at address 'addr' from the VPD EEPROM. @@ -189,27 +200,31 @@ SK_IOC IoC, /* IO Context */ int addr) /* VPD address */ { - SK_U32 Rtv ; + SK_U32 Rtv; /* start VPD read */ SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL, - ("vpd read dword at 0x%x\n",addr)) ; - addr &= ~VPD_WRITE ; /* ensure the R/W bit is set to read */ + ("vpd read dword at 0x%x\n",addr)); + addr &= ~VPD_WRITE; /* ensure the R/W bit is set to read */ - VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, (SK_U16) addr) ; + VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, (SK_U16) addr); /* ignore return code here */ - (void)VpdWait(pAC,IoC,VPD_READ) ; + (void)VpdWait(pAC,IoC,VPD_READ); /* Don't swap here, it's a data stream of bytes */ - Rtv = 0 ; + Rtv = 0; - VPD_IN32(pAC,IoC,PCI_VPD_DAT_REG,&Rtv) ; + VPD_IN32(pAC,IoC,PCI_VPD_DAT_REG,&Rtv); SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL, - ("vpd read dword data = 0x%x\n",Rtv)) ; - return (Rtv) ; + ("vpd read dword data = 0x%x\n",Rtv)); + return (Rtv); } +#endif // SKDIAG + +#if 0 + /* Write the dword 'data' at address 'addr' into the VPD EEPROM, and verify that the data is written. @@ -229,11 +244,10 @@ Returns 0: success - 1: error, I2C transfer does not terminate - 2: error, data verify error + 1: error, I2C transfer does not terminate + 2: error, data verify error */ -#if 0 /* unused */ static int VpdWriteDWord( SK_AC *pAC, /* pAC pointer */ SK_IOC IoC, /* IO Context */ @@ -243,29 +257,30 @@ /* start VPD write */ /* Don't swap here, it's a data stream of bytes */ SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL, - ("vpd write dword at addr 0x%x, data = 0x%x\n",addr,data)) ; - VPD_OUT32(pAC,IoC,PCI_VPD_DAT_REG, (SK_U32)data) ; + ("vpd write dword at addr 0x%x, data = 0x%x\n",addr,data)); + VPD_OUT32(pAC,IoC,PCI_VPD_DAT_REG, (SK_U32)data); /* But do it here */ - addr |= VPD_WRITE ; + addr |= VPD_WRITE; - VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, (SK_U16)(addr | VPD_WRITE)) ; + VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, (SK_U16)(addr | VPD_WRITE)); /* this may take up to 10,6 ms */ if (VpdWait(pAC,IoC,VPD_WRITE)) { SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, - ("Write Timed Out\n")) ; - return(1) ; - } ; + ("Write Timed Out\n")); + return(1); + }; /* verify data */ if (VpdReadDWord(pAC,IoC,addr) != data) { SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR|SK_DBGCAT_FATAL, - ("Data Verify Error\n")) ; - return(2) ; + ("Data Verify Error\n")); + return(2); } - return(0) ; -} -#endif /* unused */ + return(0); +} /* VpdWriteDWord */ + +#endif /* 0 */ /* * Read one Stream of 'len' bytes of VPD data, starting at 'addr' from @@ -280,12 +295,12 @@ int Addr, /* VPD start address */ int Len) /* number of bytes to read / to write */ { - int i ; - int j ; - SK_U16 AdrReg ; - int Rtv ; + int i; + int j; + SK_U16 AdrReg; + int Rtv; SK_U8 * pComp; /* Compare pointer */ - SK_U8 Data ; /* Input Data for Compare */ + SK_U8 Data; /* Input Data for Compare */ /* Init Compare Pointer */ pComp = (SK_U8 *) buf; @@ -297,56 +312,56 @@ * So it is initialized even if only a few bytes * are written. */ - AdrReg = (SK_U16) Addr ; - AdrReg &= ~VPD_WRITE ; /* READ operation */ + AdrReg = (SK_U16) Addr; + AdrReg &= ~VPD_WRITE; /* READ operation */ - VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, AdrReg) ; + VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, AdrReg); /* ignore return code here */ - Rtv = VpdWait(pAC,IoC,VPD_READ) ; + Rtv = VpdWait(pAC,IoC,VPD_READ); if (Rtv != 0) { - return(i) ; + return(i); } } /* Write current Byte */ VPD_OUT8(pAC,IoC,PCI_VPD_DAT_REG+(i%sizeof(SK_U32)), - *(SK_U8*)buf) ; + *(SK_U8*)buf); if (((i%sizeof(SK_U32)) == 3) || (i == (Len - 1))) { /* New Address needs to be written to VPD_ADDR reg */ - AdrReg = (SK_U16) Addr ; + AdrReg = (SK_U16) Addr; Addr += sizeof(SK_U32); - AdrReg |= VPD_WRITE ; /* WRITE operation */ + AdrReg |= VPD_WRITE; /* WRITE operation */ - VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, AdrReg) ; + VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, AdrReg); /* Wait for termination */ - Rtv = VpdWait(pAC,IoC,VPD_WRITE) ; + Rtv = VpdWait(pAC,IoC,VPD_WRITE); if (Rtv != 0) { SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, - ("Write Timed Out\n")) ; - return(i - (i%sizeof(SK_U32))) ; + ("Write Timed Out\n")); + return(i - (i%sizeof(SK_U32))); } /* * Now re-read to verify */ - AdrReg &= ~VPD_WRITE ; /* READ operation */ + AdrReg &= ~VPD_WRITE; /* READ operation */ - VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, AdrReg) ; + VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, AdrReg); /* Wait for termination */ - Rtv = VpdWait(pAC,IoC,VPD_READ) ; + Rtv = VpdWait(pAC,IoC,VPD_READ); if (Rtv != 0) { SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, - ("Verify Timed Out\n")) ; - return(i - (i%sizeof(SK_U32))) ; + ("Verify Timed Out\n")); + return(i - (i%sizeof(SK_U32))); } for (j = 0; j <= (int) (i%sizeof(SK_U32)); j ++, pComp ++ ) { - VPD_IN8(pAC,IoC,PCI_VPD_DAT_REG+j, &Data) ; + VPD_IN8(pAC,IoC,PCI_VPD_DAT_REG+j, &Data); if (Data != *pComp) { /* Verify Error */ SK_DBG_MSG(pAC,SK_DBGMOD_VPD, @@ -376,31 +391,31 @@ int Addr, /* VPD start address */ int Len) /* number of bytes to read / to write */ { - int i ; - SK_U16 AdrReg ; - int Rtv ; + int i; + SK_U16 AdrReg; + int Rtv; for (i=0; i < Len; i ++, buf++) { if ((i%sizeof(SK_U32)) == 0) { /* New Address needs to be written to VPD_ADDR reg */ - AdrReg = (SK_U16) Addr ; + AdrReg = (SK_U16) Addr; Addr += sizeof(SK_U32); - AdrReg &= ~VPD_WRITE ; /* READ operation */ + AdrReg &= ~VPD_WRITE; /* READ operation */ - VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, AdrReg) ; + VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG, AdrReg); /* ignore return code here */ - Rtv = VpdWait(pAC,IoC,VPD_READ) ; + Rtv = VpdWait(pAC,IoC,VPD_READ); if (Rtv != 0) { - return(i) ; + return(i); } } VPD_IN8(pAC,IoC,PCI_VPD_DAT_REG+(i%sizeof(SK_U32)), - (SK_U8 *)buf) ; + (SK_U8 *)buf); } - return(Len) ; + return(Len); } /* @@ -417,29 +432,29 @@ int len, /* number of bytes to read / to write */ int dir) /* transfer direction may be VPD_READ or VPD_WRITE */ { - int Rtv ; /* Return value */ - int vpd_rom_size ; - SK_U32 our_reg2 ; + int Rtv; /* Return value */ + int vpd_rom_size; + SK_U32 our_reg2; SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL, ("vpd %s block, addr = 0x%x, len = %d\n", - dir?"write":"read",addr,len)) ; + dir?"write":"read",addr,len)); if (len == 0) - return (0) ; + return (0); - VPD_IN32(pAC,IoC,PCI_OUR_REG_2,&our_reg2) ; + VPD_IN32(pAC,IoC,PCI_OUR_REG_2,&our_reg2); vpd_rom_size = 256 << ((our_reg2 & PCI_VPD_ROM_SZ) >> 14); if (addr > vpd_rom_size - 4) { SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR|SK_DBGCAT_FATAL, ("Address error: 0x%x, exp. < 0x%x\n", - addr, vpd_rom_size - 4)) ; - return (0) ; + addr, vpd_rom_size - 4)); + return (0); } if (addr + len > vpd_rom_size) { - len = vpd_rom_size - addr ; + len = vpd_rom_size - addr; SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, - ("Warning: len was cut to %d\n",len)) ; + ("Warning: len was cut to %d\n",len)); } if (dir == VPD_READ) { @@ -448,7 +463,7 @@ Rtv = VpdWriteStream(pAC, IoC, buf, addr, len); } - return (Rtv) ; + return (Rtv); } #ifdef SKDIAG @@ -465,7 +480,7 @@ int addr, /* start reading at the VPD address */ int len) /* number of bytes to read */ { - return (VpdTransferBlock(pAC, IoC, buf, addr, len, VPD_READ)) ; + return (VpdTransferBlock(pAC, IoC, buf, addr, len, VPD_READ)); } /* @@ -480,7 +495,7 @@ int addr, /* start writing at the VPD address */ int len) /* number of bytes to write */ { - return (VpdTransferBlock(pAC, IoC, buf, addr, len, VPD_WRITE)) ; + return (VpdTransferBlock(pAC, IoC, buf, addr, len, VPD_WRITE)); } #endif /* SKDIAG */ @@ -497,64 +512,64 @@ SK_AC *pAC, /* Adapters context */ SK_IOC IoC) /* IO Context */ { - SK_VPD_PARA *r, rp ; /* RW or RV */ - int i ; - unsigned char x ; + SK_VPD_PARA *r, rp; /* RW or RV */ + int i; + unsigned char x; - SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_INIT,("VpdInit .. ")) ; + SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_INIT,("VpdInit .. ")); /* read the VPD data into the VPD buffer */ if (VpdTransferBlock(pAC,IoC,pAC->vpd.vpd_buf,0,VPD_SIZE,VPD_READ) != VPD_SIZE) { SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, - ("Block Read Error\n")) ; - return(1) ; + ("Block Read Error\n")); + return(1); } /* find the end tag of the RO area */ if (!(r = vpd_find_para(pAC,VPD_RV,&rp))) { SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL, - ("Encoding Error: RV Tag not found\n")) ; - return (1) ; + ("Encoding Error: RV Tag not found\n")); + return (1); } if (r->p_val + r->p_len > pAC->vpd.vpd_buf + VPD_SIZE/2) { SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL, - ("Encoding Error: Invalid VPD struct size\n")) ; - return (1) ; + ("Encoding Error: Invalid VPD struct size\n")); + return (1); } - pAC->vpd.v.vpd_free_ro = r->p_len - 1 ; + pAC->vpd.v.vpd_free_ro = r->p_len - 1; /* test the checksum */ for (i = 0, x = 0; (unsigned)i<=(unsigned)VPD_SIZE/2 - r->p_len; i++) { - x += pAC->vpd.vpd_buf[i] ; + x += pAC->vpd.vpd_buf[i]; } if (x != 0) { /* checksum error */ SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL, - ("VPD Checksum Error\n")) ; - return (1) ; + ("VPD Checksum Error\n")); + return (1); } /* find and check the end tag of the RW area */ if (!(r = vpd_find_para(pAC,VPD_RW,&rp))) { SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL, - ("Encoding Error: RV Tag not found\n")) ; - return (1) ; + ("Encoding Error: RV Tag not found\n")); + return (1); } if (r->p_val < pAC->vpd.vpd_buf + VPD_SIZE/2) { SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL, - ("Encoding Error: Invalid VPD struct size\n")) ; - return (1) ; + ("Encoding Error: Invalid VPD struct size\n")); + return (1); } - pAC->vpd.v.vpd_free_rw = r->p_len ; + pAC->vpd.v.vpd_free_rw = r->p_len; /* everything seems to be ok */ - pAC->vpd.v.vpd_status |= VPD_VALID ; + pAC->vpd.v.vpd_status |= VPD_VALID; SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_INIT, ("done. Free RO = %d, Free RW = %d\n", - pAC->vpd.v.vpd_free_ro, pAC->vpd.v.vpd_free_rw)) ; + pAC->vpd.v.vpd_free_ro, pAC->vpd.v.vpd_free_rw)); - return(0) ; + return(0); } /* @@ -570,62 +585,62 @@ SK_VPD_PARA *p) /* parameter description struct */ { char *v ; /* points to vpd buffer */ - int max ; /* Maximum Number of Iterations */ + int max; /* Maximum Number of Iterations */ - v = pAC->vpd.vpd_buf ; - max = 128 ; + v = pAC->vpd.vpd_buf; + max = 128; SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL, - ("vpd find para %s .. ",key)) ; + ("vpd find para %s .. ",key)); /* check mandatory resource type ID string (Product Name) */ if (*v != (char) RES_ID) { SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL, - ("Error: 0x%x missing\n",RES_ID)) ; - return (0) ; + ("Error: 0x%x missing\n",RES_ID)); + return (0); } if (strcmp(key,VPD_NAME) == 0) { - p->p_len = VPD_GET_RES_LEN(v) ; - p->p_val = VPD_GET_VAL(v) ; + p->p_len = VPD_GET_RES_LEN(v); + p->p_val = VPD_GET_VAL(v); SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL, - ("found, len = %d\n",p->p_len)) ; - return(p) ; + ("found, len = %d\n",p->p_len)); + return(p); } - v += 3 + VPD_GET_RES_LEN(v) + 3 ; - for ( ; ; ) { + v += 3 + VPD_GET_RES_LEN(v) + 3; + for (;; ) { if (SK_MEMCMP(key,v,2) == 0) { - p->p_len = VPD_GET_VPD_LEN(v) ; - p->p_val = VPD_GET_VAL(v) ; + p->p_len = VPD_GET_VPD_LEN(v); + p->p_val = VPD_GET_VAL(v); SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL, - ("found, len = %d\n",p->p_len)) ; - return (p) ; + ("found, len = %d\n",p->p_len)); + return (p); } /* exit when reaching the "RW" Tag or the maximum of itera. */ - max-- ; + max--; if (SK_MEMCMP(VPD_RW,v,2) == 0 || max == 0) { - break ; + break; } if (SK_MEMCMP(VPD_RV,v,2) == 0) { - v += 3 + VPD_GET_VPD_LEN(v) + 3 ; /* skip VPD-W */ + v += 3 + VPD_GET_VPD_LEN(v) + 3; /* skip VPD-W */ } else { - v += 3 + VPD_GET_VPD_LEN(v) ; + v += 3 + VPD_GET_VPD_LEN(v); } SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL, - ("scanning '%c%c' len = %d\n",v[0],v[1],v[2])) ; + ("scanning '%c%c' len = %d\n",v[0],v[1],v[2])); } #ifdef DEBUG - SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,("not found\n")) ; + SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL,("not found\n")); if (max == 0) { SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL, - ("Key/Len Encoding error\n")) ; + ("Key/Len Encoding error\n")); } #endif - return (0) ; + return (0); } /* @@ -639,24 +654,24 @@ char *end, /* end of memory block to move */ int n) /* number of bytes the memory block has to be moved */ { - char *p ; - int i ; /* number of byte copied */ + char *p; + int i; /* number of byte copied */ if (n == 0) - return ; + return; - i = end - start + 1 ; + i = (int) (end - start + 1); if (n < 0) { - p = start + n ; + p = start + n; while (i != 0) { - *p++ = *start++ ; - i-- ; + *p++ = *start++; + i--; } } else { - p = end + n ; + p = end + n; while (i != 0) { - *p-- = *end-- ; - i-- ; + *p-- = *end--; + i--; } } } @@ -672,13 +687,13 @@ int len, /* length of the value string */ char *ip) /* inseration point */ { - SK_VPD_KEY *p ; + SK_VPD_KEY *p; - p = (SK_VPD_KEY *) ip ; - p->p_key[0] = key[0] ; - p->p_key[1] = key[1] ; - p->p_len = (unsigned char) len ; - SK_MEMCPY(&p->p_val,buf,len) ; + p = (SK_VPD_KEY *) ip; + p->p_key[0] = key[0]; + p->p_key[1] = key[1]; + p->p_len = (unsigned char) len; + SK_MEMCPY(&p->p_val,buf,len); } /* @@ -692,46 +707,46 @@ SK_AC *pAC, /* common data base */ char *etp) /* end pointer input position */ { - SK_VPD_KEY *p ; - unsigned char x ; - int i ; + SK_VPD_KEY *p; + unsigned char x; + int i; SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL, - ("vpd modify endtag at 0x%x = '%c%c'\n",etp,etp[0],etp[1])) ; + ("vpd modify endtag at 0x%x = '%c%c'\n",etp,etp[0],etp[1])); - p = (SK_VPD_KEY *) etp ; + p = (SK_VPD_KEY *) etp; if (p->p_key[0] != 'R' || (p->p_key[1] != 'V' && p->p_key[1] != 'W')) { /* something wrong here, encoding error */ SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL, - ("Encoding Error: invalid end tag\n")) ; - return(1) ; + ("Encoding Error: invalid end tag\n")); + return(1); } if (etp > pAC->vpd.vpd_buf + VPD_SIZE/2) { /* create "RW" tag */ - p->p_len = (unsigned char)(pAC->vpd.vpd_buf+VPD_SIZE-etp-3-1) ; - pAC->vpd.v.vpd_free_rw = (int) p->p_len ; - i = pAC->vpd.v.vpd_free_rw ; - etp += 3 ; + p->p_len = (unsigned char)(pAC->vpd.vpd_buf+VPD_SIZE-etp-3-1); + pAC->vpd.v.vpd_free_rw = (int) p->p_len; + i = pAC->vpd.v.vpd_free_rw; + etp += 3; } else { /* create "RV" tag */ - p->p_len = (unsigned char)(pAC->vpd.vpd_buf+VPD_SIZE/2-etp-3) ; - pAC->vpd.v.vpd_free_ro = (int) p->p_len - 1 ; + p->p_len = (unsigned char)(pAC->vpd.vpd_buf+VPD_SIZE/2-etp-3); + pAC->vpd.v.vpd_free_ro = (int) p->p_len - 1; /* setup checksum */ for (i = 0, x = 0; i < VPD_SIZE/2 - p->p_len; i++) { - x += pAC->vpd.vpd_buf[i] ; + x += pAC->vpd.vpd_buf[i]; } - p->p_val = (char) 0 - x ; - i = pAC->vpd.v.vpd_free_ro ; - etp += 4 ; + p->p_val = (char) 0 - x; + i = pAC->vpd.v.vpd_free_ro; + etp += 4; } while (i) { - *etp++ = 0x00 ; - i-- ; + *etp++ = 0x00; + i--; } - return (0) ; + return (0); } /* @@ -756,76 +771,76 @@ int type, /* VPD_RO_KEY or VPD_RW_KEY */ int op) /* operation to do: ADD_KEY or OWR_KEY */ { - SK_VPD_PARA vp ; - char *etp ; /* end tag position */ - int free ; /* remaining space in selected area */ - char *ip ; /* input position inside the VPD buffer */ - int rtv ; /* return code */ - int head ; /* additional haeder bytes to move */ - int found ; /* additinoal bytes if the keyword was found */ + SK_VPD_PARA vp; + char *etp; /* end tag position */ + int free; /* remaining space in selected area */ + char *ip; /* input position inside the VPD buffer */ + int rtv; /* return code */ + int head; /* additional haeder bytes to move */ + int found; /* additinoal bytes if the keyword was found */ SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL, - ("vpd setup para key = %s, val = %s\n",key,buf)) ; + ("vpd setup para key = %s, val = %s\n",key,buf)); - rtv = 0 ; - ip = 0 ; + rtv = 0; + ip = 0; if (type == VPD_RW_KEY) { /* end tag is "RW" */ - free = pAC->vpd.v.vpd_free_rw ; - etp = pAC->vpd.vpd_buf + (VPD_SIZE - free - 1 - 3) ; + free = pAC->vpd.v.vpd_free_rw; + etp = pAC->vpd.vpd_buf + (VPD_SIZE - free - 1 - 3); } else { /* end tag is "RV" */ - free = pAC->vpd.v.vpd_free_ro ; - etp = pAC->vpd.vpd_buf + (VPD_SIZE/2 - free - 4) ; + free = pAC->vpd.v.vpd_free_ro; + etp = pAC->vpd.vpd_buf + (VPD_SIZE/2 - free - 4); } SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL, ("Free RO = %d, Free RW = %d\n", - pAC->vpd.v.vpd_free_ro, pAC->vpd.v.vpd_free_rw)) ; + pAC->vpd.v.vpd_free_ro, pAC->vpd.v.vpd_free_rw)); - head = 0 ; - found = 0 ; + head = 0; + found = 0; if (op == OWR_KEY) { if (vpd_find_para(pAC,key,&vp)) { - found = 3 ; - ip = vp.p_val - 3 ; - free += vp.p_len + 3 ; + found = 3; + ip = vp.p_val - 3; + free += vp.p_len + 3; SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL, - ("Overwrite Key\n")) ; + ("Overwrite Key\n")); } else { - op = ADD_KEY ; + op = ADD_KEY; SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_CTRL, - ("Add Key\n")) ; + ("Add Key\n")); } } if (op == ADD_KEY) { - ip = etp ; - vp.p_len = 0 ; - head = 3 ; + ip = etp; + vp.p_len = 0; + head = 3; } if (len + 3 > free) { if (free < 7) { SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, ("VPD Buffer Overflow, keyword not written\n")); - return (4) ; + return (4); } /* cut it again */ - len = free - 3 ; - rtv = 2 ; + len = free - 3; + rtv = 2; SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, - ("VPD Buffer Full, Keyword was cut\n")) ; + ("VPD Buffer Full, Keyword was cut\n")); } - vpd_move_para(ip + vp.p_len + found, etp+2, len-vp.p_len+head) ; - vpd_insert_key(key, buf, len, ip) ; + vpd_move_para(ip + vp.p_len + found, etp+2, len-vp.p_len+head); + vpd_insert_key(key, buf, len, ip); if (vpd_mod_endtag(pAC, etp + len - vp.p_len + head)) { - pAC->vpd.v.vpd_status &= ~VPD_VALID ; + pAC->vpd.v.vpd_status &= ~VPD_VALID; SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, - ("VPD Encoding Error\n")) ; - return(6) ; + ("VPD Encoding Error\n")); + return(6); } - return (rtv) ; + return (rtv); } @@ -833,7 +848,7 @@ * Read the contents of the VPD EEPROM and copy it to the * VPD buffer if not already done. * - * return: A pointer to the vpd_status structure. The structure contain + * return: A pointer to the vpd_status structure. The structure contains * this fields. */ SK_VPD_STATUS *VpdStat( @@ -841,9 +856,9 @@ SK_IOC IoC) /* IO Context */ { if (!(pAC->vpd.v.vpd_status & VPD_VALID)) { - (void)VpdInit(pAC,IoC) ; + (void)VpdInit(pAC,IoC); } - return(&pAC->vpd.v) ; + return(&pAC->vpd.v); } @@ -876,67 +891,67 @@ int *len, /* buffer length */ int *elements) /* number of keywords returned */ { - char *v ; - int n ; + char *v; + int n; - SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_RX,("list vpd keys .. ")) ; - *elements = 0 ; + SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_RX,("list vpd keys .. ")); + *elements = 0; if (!(pAC->vpd.v.vpd_status & VPD_VALID)) { if (VpdInit(pAC,IoC) != 0 ) { - *len = 0 ; + *len = 0; SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, - ("VPD Init Error, terminated\n")) ; - return(6) ; + ("VPD Init Error, terminated\n")); + return(6); } } if ((signed)strlen(VPD_NAME) + 1 <= *len) { - v = pAC->vpd.vpd_buf ; - strcpy(buf,VPD_NAME) ; - n = strlen(VPD_NAME) + 1 ; - buf += n ; - *elements = 1 ; + v = pAC->vpd.vpd_buf; + strcpy(buf,VPD_NAME); + n = strlen(VPD_NAME) + 1; + buf += n; + *elements = 1; SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_RX, - ("'%c%c' ",v[0],v[1])) ; + ("'%c%c' ",v[0],v[1])); } else { - *len = 0 ; + *len = 0; SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, - ("buffer overflow\n")) ; - return(2) ; + ("buffer overflow\n")); + return(2); } - v += 3 + VPD_GET_RES_LEN(v) + 3 ; - for ( ; ; ) { + v += 3 + VPD_GET_RES_LEN(v) + 3; + for (;; ) { /* exit when reaching the "RW" Tag */ if (SK_MEMCMP(VPD_RW,v,2) == 0) { - break ; + break; } if (SK_MEMCMP(VPD_RV,v,2) == 0) { - v += 3 + VPD_GET_VPD_LEN(v) + 3 ; /* skip VPD-W */ - continue ; + v += 3 + VPD_GET_VPD_LEN(v) + 3; /* skip VPD-W */ + continue; } if (n+3 <= *len) { - SK_MEMCPY(buf,v,2) ; - buf += 2 ; - *buf++ = '\0' ; - n += 3 ; - v += 3 + VPD_GET_VPD_LEN(v) ; - *elements += 1 ; + SK_MEMCPY(buf,v,2); + buf += 2; + *buf++ = '\0'; + n += 3; + v += 3 + VPD_GET_VPD_LEN(v); + *elements += 1; SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_RX, - ("'%c%c' ",v[0],v[1])) ; + ("'%c%c' ",v[0],v[1])); } else { - *len = n ; + *len = n; SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, - ("buffer overflow\n")) ; - return (2) ; + ("buffer overflow\n")); + return (2); } } - SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_RX,("\n")) ; - *len = n ; - return(0) ; + SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_RX,("\n")); + *len = n; + return(0); } @@ -960,34 +975,34 @@ char *buf, /* buffer where to copy the keyword value */ int *len) /* buffer length */ { - SK_VPD_PARA *p, vp ; + SK_VPD_PARA *p, vp; - SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_RX,("vpd read %s .. ",key)) ; + SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_RX,("vpd read %s .. ",key)); if (!(pAC->vpd.v.vpd_status & VPD_VALID)) { if (VpdInit(pAC,IoC) != 0 ) { - *len = 0 ; + *len = 0; SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, - ("vpd init error\n")) ; - return(6) ; + ("vpd init error\n")); + return(6); } } if ((p = vpd_find_para(pAC,key,&vp))) { if (p->p_len > (*(unsigned *)len)-1) { - p->p_len = *len - 1 ; + p->p_len = *len - 1; } - SK_MEMCPY(buf,p->p_val,p->p_len) ; - buf[p->p_len] = '\0' ; - *len = p->p_len ; + SK_MEMCPY(buf,p->p_val,p->p_len); + buf[p->p_len] = '\0'; + *len = p->p_len; SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_RX, ("%c%c%c%c.., len = %d\n", - buf[0],buf[1],buf[2],buf[3],*len)) ; + buf[0],buf[1],buf[2],buf[3],*len)); } else { - *len = 0 ; - SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,("not found\n")) ; - return (1) ; + *len = 0; + SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,("not found\n")); + return (1); } - return (0) ; + return (0); } @@ -1005,9 +1020,9 @@ key[1] < '0' || key[1] > 'Z' || (key[1] > '9' && key[1] < 'A') || strlen(key) != 2) { - return (SK_FALSE) ; + return (SK_FALSE); } - return (SK_TRUE) ; + return (SK_TRUE); } /* @@ -1029,46 +1044,46 @@ char *key, /* keyword to write (allowed values "Yx", "Vx") */ char *buf) /* buffer where the keyword value can be read from */ { - int len ; /* lenght of the keyword to write */ - int rtv ; /* return code */ - int rtv2 ; + int len; /* lenght of the keyword to write */ + int rtv; /* return code */ + int rtv2; SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX, - ("vpd write %s = %s\n",key,buf)) ; + ("vpd write %s = %s\n",key,buf)); if ((*key != 'Y' && *key != 'V') || key[1] < '0' || key[1] > 'Z' || (key[1] > '9' && key[1] < 'A') || strlen(key) != 2) { SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, - ("illegal key tag, keyword not written\n")) ; - return (5) ; + ("illegal key tag, keyword not written\n")); + return (5); } if (!(pAC->vpd.v.vpd_status & VPD_VALID)) { if (VpdInit(pAC,IoC) != 0 ) { SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, - ("vpd init error\n")) ; - return(6) ; + ("vpd init error\n")); + return(6); } } - rtv = 0 ; - len = strlen(buf) ; + rtv = 0; + len = strlen(buf); if (len > VPD_MAX_LEN) { /* cut it */ - len = VPD_MAX_LEN ; - rtv = 2 ; + len = VPD_MAX_LEN; + rtv = 2; SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, - ("keyword to long, cut after %d bytes\n",VPD_MAX_LEN)) ; + ("keyword to long, cut after %d bytes\n",VPD_MAX_LEN)); } if ((rtv2 = VpdSetupPara(pAC,key,buf,len,VPD_RW_KEY,OWR_KEY)) != 0) { SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, - ("vpd write error\n")) ; - return(rtv2) ; + ("vpd write error\n")); + return(rtv2); } - return (rtv) ; + return (rtv); } /* @@ -1088,15 +1103,15 @@ SK_IOC IoC, /* IO Context */ char *key) /* keyword to read (e.g. "MN") */ { - SK_VPD_PARA *p, vp ; - char *etp ; + SK_VPD_PARA *p, vp; + char *etp; - SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("vpd delete key %s\n",key)) ; + SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("vpd delete key %s\n",key)); if (!(pAC->vpd.v.vpd_status & VPD_VALID)) { if (VpdInit(pAC,IoC) != 0 ) { SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, - ("vpd init error\n")) ; - return(6) ; + ("vpd init error\n")); + return(6); } } @@ -1104,27 +1119,27 @@ if (p->p_val < pAC->vpd.vpd_buf + VPD_SIZE/2) { /* try to delete read only keyword */ SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, - ("cannot delete RO keyword\n")) ; - return (5) ; + ("cannot delete RO keyword\n")); + return (5); } - etp = pAC->vpd.vpd_buf + (VPD_SIZE-pAC->vpd.v.vpd_free_rw-1-3) ; + etp = pAC->vpd.vpd_buf + (VPD_SIZE-pAC->vpd.v.vpd_free_rw-1-3); vpd_move_para(vp.p_val+vp.p_len, etp+2, - - ((int)(vp.p_len + 3))) ; + - ((int)(vp.p_len + 3))); if (vpd_mod_endtag(pAC, etp - vp.p_len - 3)) { - pAC->vpd.v.vpd_status &= ~VPD_VALID ; + pAC->vpd.v.vpd_status &= ~VPD_VALID; SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, - ("vpd encoding error\n")) ; - return(6) ; + ("vpd encoding error\n")); + return(6); } } else { SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, - ("keyword not found\n")) ; - return (1) ; + ("keyword not found\n")); + return (1); } - return (0) ; + return (0); } /* @@ -1138,18 +1153,18 @@ SK_AC *pAC, /* Adapters context */ SK_IOC IoC) /* IO Context */ { - SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("vpd update .. ")) ; + SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("vpd update .. ")); if (pAC->vpd.v.vpd_status & VPD_VALID) { if (VpdTransferBlock(pAC,IoC,pAC->vpd.vpd_buf + VPD_SIZE/2, VPD_SIZE/2, VPD_SIZE/2, VPD_WRITE) != VPD_SIZE/2) { SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, - ("transfer timed out\n")) ; - return(3) ; + ("transfer timed out\n")); + return(3); } } - SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("done\n")) ; - return (0) ; + SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("done\n")); + return (0); } @@ -1169,32 +1184,32 @@ SK_IOC IoC, /* IO Context */ char *msg) /* error log message */ { - SK_VPD_PARA *v, vf ; /* VF */ - int len ; + SK_VPD_PARA *v, vf; /* VF */ + int len; SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX, - ("vpd error log msg %s\n",msg)) ; + ("vpd error log msg %s\n",msg)); if (!(pAC->vpd.v.vpd_status & VPD_VALID)) { if (VpdInit(pAC,IoC) != 0 ) { SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR, - ("vpd init error\n")) ; - return ; + ("vpd init error\n")); + return; } } - len = strlen(msg) ; + len = strlen(msg); if (len > VPD_MAX_LEN) { /* cut it */ - len = VPD_MAX_LEN ; + len = VPD_MAX_LEN; } if ((v = vpd_find_para(pAC,VPD_VF,&vf))) { - SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("overwrite VL\n")) ; - (void)VpdSetupPara(pAC,VPD_VL,msg,len,VPD_RW_KEY,OWR_KEY) ; + SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("overwrite VL\n")); + (void)VpdSetupPara(pAC,VPD_VL,msg,len,VPD_RW_KEY,OWR_KEY); } else { - SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("write VF\n")) ; - (void)VpdSetupPara(pAC,VPD_VF,msg,len,VPD_RW_KEY,ADD_KEY) ; + SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("write VF\n")); + (void)VpdSetupPara(pAC,VPD_VF,msg,len,VPD_RW_KEY,ADD_KEY); } - (void)VpdUpdate(pAC,IoC) ; + (void)VpdUpdate(pAC,IoC); } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/sk98lin/skxmac2.c linux/drivers/net/sk98lin/skxmac2.c --- v2.4.0-test8/linux/drivers/net/sk98lin/skxmac2.c Tue Nov 23 10:15:42 1999 +++ linux/drivers/net/sk98lin/skxmac2.c Fri Sep 15 14:34:19 2000 @@ -2,8 +2,8 @@ * * Name: skxmac2.c * Project: GEnesis, PCI Gigabit Ethernet Adapter - * Version: $Revision: 1.49 $ - * Date: $Date: 1999/11/22 08:12:13 $ + * Version: $Revision: 1.53 $ + * Date: $Date: 2000/07/27 12:22:11 $ * Purpose: Contains functions to initialize the XMAC II * ******************************************************************************/ @@ -13,8 +13,6 @@ * (C)Copyright 1998,1999 SysKonnect, * a business unit of Schneider & Koch & Co. Datensysteme GmbH. * - * See the file "skge.c" for further information. - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -29,6 +27,18 @@ * History: * * $Log: skxmac2.c,v $ + * Revision 1.53 2000/07/27 12:22:11 gklug + * fix: possible endless loop in XmHardRst. + * + * Revision 1.52 2000/05/22 08:48:31 malthoff + * Fix: #10523 errata valid for all BCOM PHYs. + * + * Revision 1.51 2000/05/17 12:52:18 malthoff + * Fixes BCom link errata (#10523). + * + * Revision 1.50 1999/11/22 13:40:14 cgoos + * Changed license header to GPL. + * * Revision 1.49 1999/11/22 08:12:13 malthoff * Add workaround for power consumption feature of Bcom C0 chip. * @@ -224,7 +234,7 @@ /* local variables ************************************************************/ static const char SysKonnectFileId[] = - "@(#)$Id: skxmac2.c,v 1.49 1999/11/22 08:12:13 malthoff Exp $ (C) SK "; + "@(#)$Id: skxmac2.c,v 1.53 2000/07/27 12:22:11 gklug Exp $ (C) SK "; /* BCOM PHY magic pattern list */ typedef struct s_PhyHack { @@ -558,6 +568,10 @@ * register (Timing requirements: Broadcom: 400ns, Level One: * none, National: 80ns). * + * ATTENTION: + * It is absolutely neccessary to reset the SW_RST Bit first + * before calling this function. + * * Returns: * nothing */ @@ -568,6 +582,7 @@ { SK_U16 Word; int i; + int TOut; SK_U32 Reg; for (i=0; i<4; i++) { @@ -575,12 +590,25 @@ /* bit contains buttoms to press */ SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), (SK_U16) MFF_CLR_MAC_RST); - SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), - (SK_U16) MFF_SET_MAC_RST); + + TOut = 0; do { + TOut ++; + if (TOut > 10000) { + /* + * Adapter seems to be in RESET state. + * Registers cannot be written. + */ + return; + } + + SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), + (SK_U16) MFF_SET_MAC_RST); SK_IN16(IoC,MR_ADDR(Port,TX_MFF_CTRL1), &Word); } while ((Word & MFF_SET_MAC_RST) == 0); } + + /* For external PHYs there must be special handling */ if (pAC->GIni.GP[Port].PhyType != SK_PHY_XMAC) { /* reset external PHY */ @@ -696,6 +724,11 @@ i++; } } + /* Workaround BCOM Errata (#10523) for all BCom PHYs*/ + /* Disable Power Management after reset */ + PHY_READ(IoC, pPrt, Port, PHY_BCOM_AUX_CTRL, &SWord); + PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_AUX_CTRL, + SWord | PHY_B_AC_DIS_PM); /* * PHY LED initialization is performed in @@ -1845,6 +1878,7 @@ SK_GEPORT *pPrt; SK_U16 Reg ; /* 16bit register value */ SK_U16 IntMask; /* XMac interrupt mask */ + SK_U16 SWord; pPrt = &pAC->GIni.GP[Port]; @@ -1892,6 +1926,11 @@ } switch (pPrt->PhyType) { case SK_PHY_BCOM: + /* Workaround BCOM Errata (#10523) for all BCom Phys */ + /* Enable Power Management after link up */ + PHY_READ(IoC, pPrt, Port, PHY_BCOM_AUX_CTRL, &SWord); + PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_AUX_CTRL, + SWord & ~PHY_B_AC_DIS_PM); PHY_WRITE(IoC, pPrt, Port, PHY_BCOM_INT_MASK, PHY_B_DEF_MSK); break; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/skfp/skfddi.c linux/drivers/net/skfp/skfddi.c --- v2.4.0-test8/linux/drivers/net/skfp/skfddi.c Tue Jul 11 11:12:24 2000 +++ linux/drivers/net/skfp/skfddi.c Fri Sep 15 14:34:36 2000 @@ -1654,7 +1654,8 @@ virt = mac_drv_get_space(smc, size); - size = (u_int) ((0 - (unsigned long) virt) & 15UL); + size = (u_int) (16 - (((unsigned long) virt) & 15UL)); + size = size % 16; PRINTK("Allocate %u bytes alignment gap ", size); PRINTK("for descriptor memory.\n"); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/sundance.c linux/drivers/net/sundance.c --- v2.4.0-test8/linux/drivers/net/sundance.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/sundance.c Sun Sep 24 12:12:33 2000 @@ -0,0 +1,1271 @@ +/* sundance.c: A Linux device driver for the Sundance ST201 "Alta". */ +/* + Written 1999-2000 by Donald Becker. + + This software may be used and distributed according to the terms of + the GNU General Public License (GPL), incorporated herein by reference. + Drivers based on or derived from this code fall under the GPL and must + retain the authorship, copyright and license notice. This file is not + a complete program and may only be used when the entire operating + system is licensed under the GPL. + + The author may be reached as becker@scyld.com, or C/O + Scyld Computing Corporation + 410 Severn Ave., Suite 210 + Annapolis MD 21403 + + Support and updates available at + http://www.scyld.com/network/sundance.html +*/ + +/* These identify the driver base version and may not be removed. */ +static const char version1[] = +"sundance.c:v1.01 4/09/00 Written by Donald Becker\n"; +static const char version2[] = +" http://www.scyld.com/network/sundance.html\n"; + +/* The user-configurable values. + These may be modified when a driver module is loaded.*/ + +static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ +/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ +static int max_interrupt_work = 20; +static int mtu = 0; +/* Maximum number of multicast addresses to filter (vs. rx-all-multicast). + Typical is a 64 element hash table based on the Ethernet CRC. */ +static int multicast_filter_limit = 32; + +/* Set the copy breakpoint for the copy-only-tiny-frames scheme. + Setting to > 1518 effectively disables this feature. + This chip can receive into offset buffers, so the Alpha does not + need a copy-align. */ +static int rx_copybreak = 0; + +/* Used to pass the media type, etc. + Both 'options[]' and 'full_duplex[]' should exist for driver + interoperability. + The media type is usually passed in 'options[]'. +*/ +#define MAX_UNITS 8 /* More are supported, limit only on options */ +static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; +static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; + +/* Operational parameters that are set at compile time. */ + +/* Keep the ring sizes a power of two for compile efficiency. + The compiler will convert '%'<2^N> into a bit mask. + Making the Tx ring too large decreases the effectiveness of channel + bonding and packet priority, and more than 128 requires modifying the + Tx error recovery. + Large receive rings merely waste memory. */ +#define TX_RING_SIZE 16 +#define TX_QUEUE_LEN 10 /* Limit ring entries actually used. */ +#define RX_RING_SIZE 32 + +/* Operational parameters that usually are not changed. */ +/* Time in jiffies before concluding the transmitter is hung. */ +#define TX_TIMEOUT (2*HZ) + +#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ + +#ifndef __KERNEL__ +#define __KERNEL__ +#endif +#if !defined(__OPTIMIZE__) +#warning You must compile this file with the correct options! +#warning See the last lines of the source file. +#error You must compile this driver with "-O". +#endif + +/* Include files, designed to support most kernel versions 2.0.0 and later. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* Processor type for cache alignment. */ +#include +#include + +#include + + +/* Condensed operations for readability. */ +#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr)) +#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr)) + + +MODULE_AUTHOR("Donald Becker "); +MODULE_DESCRIPTION("Sundance Alta Ethernet driver"); +MODULE_PARM(max_interrupt_work, "i"); +MODULE_PARM(mtu, "i"); +MODULE_PARM(debug, "i"); +MODULE_PARM(rx_copybreak, "i"); +MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); + +/* + Theory of Operation + +I. Board Compatibility + +This driver is designed for the Sundance Technologies "Alta" ST201 chip. + +II. Board-specific settings + +III. Driver operation + +IIIa. Ring buffers + +This driver uses two statically allocated fixed-size descriptor lists +formed into rings by a branch from the final descriptor to the beginning of +the list. The ring sizes are set at compile time by RX/TX_RING_SIZE. +Some chips explicitly use only 2^N sized rings, while others use a +'next descriptor' pointer that the driver forms into rings. + +IIIb/c. Transmit/Receive Structure + +This driver uses a zero-copy receive and transmit scheme. +The driver allocates full frame size skbuffs for the Rx ring buffers at +open() time and passes the skb->data field to the chip as receive data +buffers. When an incoming frame is less than RX_COPYBREAK bytes long, +a fresh skbuff is allocated and the frame is copied to the new skbuff. +When the incoming frame is larger, the skbuff is passed directly up the +protocol stack. Buffers consumed this way are replaced by newly allocated +skbuffs in a later phase of receives. + +The RX_COPYBREAK value is chosen to trade-off the memory wasted by +using a full-sized skbuff for small frames vs. the copying costs of larger +frames. New boards are typically used in generously configured machines +and the underfilled buffers have negligible impact compared to the benefit of +a single allocation size, so the default value of zero results in never +copying packets. When copying is done, the cost is usually mitigated by using +a combined copy/checksum routine. Copying also preloads the cache, which is +most useful with small frames. + +A subtle aspect of the operation is that the IP header at offset 14 in an +ethernet frame isn't longword aligned for further processing. +Unaligned buffers are permitted by the Sundance hardware, so +frames are received into the skbuff at an offset of "+2", 16-byte aligning +the IP header. + +IIId. Synchronization + +The driver runs as two independent, single-threaded flows of control. One +is the send-packet routine, which enforces single-threaded use by the +dev->tbusy flag. The other thread is the interrupt handler, which is single +threaded by the hardware and interrupt handling software. + +The send packet thread has partial control over the Tx ring and 'dev->tbusy' +flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the next +queue slot is empty, it clears the tbusy flag when finished otherwise it sets +the 'lp->tx_full' flag. + +The interrupt handler has exclusive control over the Rx ring and records stats +from the Tx ring. After reaping the stats, it marks the Tx queue entry as +empty by incrementing the dirty_tx mark. Iff the 'lp->tx_full' flag is set, it +clears both the tx_full and tbusy flags. + +IV. Notes + +IVb. References + +The Sundance ST201 datasheet, preliminary version. +http://cesdis.gsfc.nasa.gov/linux/misc/100mbps.html +http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html + +IVc. Errata + +*/ + + + +enum pci_id_flags_bits { + /* Set PCI command register bits before calling probe1(). */ + PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4, + /* Read and map the single following PCI BAR. */ + PCI_ADDR0=0<<4, PCI_ADDR1=1<<4, PCI_ADDR2=2<<4, PCI_ADDR3=3<<4, + PCI_ADDR_64BITS=0x100, PCI_NO_ACPI_WAKE=0x200, PCI_NO_MIN_LATENCY=0x400, +}; +enum chip_capability_flags {CanHaveMII=1, }; +#ifdef USE_IO_OPS +#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_IO | PCI_ADDR0) +#else +#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR1) +#endif + +static struct pci_device_id sundance_pci_tbl[] __devinitdata = { + { 0x1186, 0x1002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0x13F0, 0x0201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 }, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, sundance_pci_tbl); + +struct pci_id_info { + const char *name; + struct match_info { + int pci, pci_mask, subsystem, subsystem_mask; + int revision, revision_mask; /* Only 8 bits. */ + } id; + enum pci_id_flags_bits pci_flags; + int io_size; /* Needed for I/O region check or ioremap(). */ + int drv_flags; /* Driver use, intended as capability flags. */ +}; +static struct pci_id_info pci_id_tbl[] = { + {"OEM Sundance Technology ST201", {0x10021186, 0xffffffff, }, + PCI_IOTYPE, 128, CanHaveMII}, + {"Sundance Technology Alta", {0x020113F0, 0xffffffff, }, + PCI_IOTYPE, 128, CanHaveMII}, + {0,}, /* 0 terminated list. */ +}; + +/* This driver was written to use PCI memory space, however x86-oriented + hardware often uses I/O space accesses. */ +#ifdef USE_IO_OPS +#undef readb +#undef readw +#undef readl +#undef writeb +#undef writew +#undef writel +#define readb inb +#define readw inw +#define readl inl +#define writeb outb +#define writew outw +#define writel outl +#endif + +/* Offsets to the device registers. + Unlike software-only systems, device drivers interact with complex hardware. + It's not useful to define symbolic names for every register bit in the + device. The name can only partially document the semantics and make + the driver longer and more difficult to read. + In general, only the important configuration values or bits changed + multiple times should be defined symbolically. +*/ +enum alta_offsets { + DMACtrl=0x00, TxListPtr=0x04, TxDMACtrl=0x08, TxDescPoll=0x0a, + RxDMAStatus=0x0c, RxListPtr=0x10, RxDMACtrl=0x14, RxDescPoll=0x16, + LEDCtrl=0x1a, ASICCtrl=0x30, + EEData=0x34, EECtrl=0x36, TxThreshold=0x3c, + FlashAddr=0x40, FlashData=0x44, TxStatus=0x46, DownCounter=0x48, + IntrClear=0x4a, IntrEnable=0x4c, IntrStatus=0x4e, + MACCtrl0=0x50, MACCtrl1=0x52, StationAddr=0x54, + MaxTxSize=0x5A, RxMode=0x5c, MIICtrl=0x5e, + MulticastFilter0=0x60, MulticastFilter1=0x64, + RxOctetsLow=0x68, RxOctetsHigh=0x6a, TxOctetsLow=0x6c, TxOctetsHigh=0x6e, + TxFramesOK=0x70, RxFramesOK=0x72, StatsCarrierError=0x74, + StatsLateColl=0x75, StatsMultiColl=0x76, StatsOneColl=0x77, + StatsTxDefer=0x78, RxMissed=0x79, StatsTxXSDefer=0x7a, StatsTxAbort=0x7b, + StatsBcastTx=0x7c, StatsBcastRx=0x7d, StatsMcastTx=0x7e, StatsMcastRx=0x7f, + /* Aliased and bogus values! */ + RxStatus=0x0c, +}; + +/* Bits in the interrupt status/mask registers. */ +enum intr_status_bits { + IntrSummary=0x0001, IntrPCIErr=0x0002, IntrMACCtrl=0x0008, + IntrTxDone=0x0004, IntrRxDone=0x0010, IntrRxStart=0x0020, + IntrDrvRqst=0x0040, + StatsMax=0x0080, LinkChange=0x0100, + IntrTxDMADone=0x0200, IntrRxDMADone=0x0400, +}; + +/* Bits in the RxMode register. */ +enum rx_mode_bits { + AcceptAllIPMulti=0x20, AcceptMultiHash=0x10, AcceptAll=0x08, + AcceptBroadcast=0x04, AcceptMulticast=0x02, AcceptMyPhys=0x01, +}; +/* Bits in MACCtrl. */ +enum mac_ctrl0_bits { + EnbFullDuplex=0x20, EnbRcvLargeFrame=0x40, + EnbFlowCtrl=0x100, EnbPassRxCRC=0x200, +}; +enum mac_ctrl1_bits { + StatsEnable=0x0020, StatsDisable=0x0040, StatsEnabled=0x0080, + TxEnable=0x0100, TxDisable=0x0200, TxEnabled=0x0400, + RxEnable=0x0800, RxDisable=0x1000, RxEnabled=0x2000, +}; + +/* The Rx and Tx buffer descriptors. */ +/* Note that using only 32 bit fields simplifies conversion to big-endian + architectures. */ +struct netdev_desc { + u32 next_desc; + u32 status; + struct desc_frag { u32 addr, length; } frag[1]; +}; + +/* Bits in netdev_desc.status */ +enum desc_status_bits { + DescOwn=0x8000, DescEndPacket=0x4000, DescEndRing=0x2000, + LastFrag=0x80000000, DescIntrOnTx=0x8000, DescIntrOnDMADone=0x80000000, +}; + +#define PRIV_ALIGN 15 /* Required alignment mask */ +/* Use __attribute__((aligned (L1_CACHE_BYTES))) to maintain alignment + within the structure. */ +struct netdev_private { + /* Descriptor rings first for alignment. */ + struct netdev_desc rx_ring[RX_RING_SIZE]; + struct netdev_desc tx_ring[TX_RING_SIZE]; + /* The addresses of receive-in-place skbuffs. */ + struct sk_buff* rx_skbuff[RX_RING_SIZE]; + /* The saved address of a sent-in-place packet/buffer, for later free(). */ + struct sk_buff* tx_skbuff[TX_RING_SIZE]; + struct net_device_stats stats; + struct timer_list timer; /* Media monitoring timer. */ + /* Frequently used values: keep some adjacent for cache effect. */ + spinlock_t lock; + int chip_id, drv_flags; + /* Note: Cache paragraph grouped variables. */ + struct netdev_desc *rx_head_desc; + unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ + unsigned int rx_buf_sz; /* Based on MTU+slack. */ + spinlock_t txlock; /* Group with Tx control cache line. */ + struct netdev_desc *last_tx; /* Last Tx descriptor used. */ + unsigned int cur_tx, dirty_tx; + unsigned int tx_full:1; /* The Tx queue is full. */ + /* These values are keep track of the transceiver/media in use. */ + unsigned int full_duplex:1; /* Full-duplex operation requested. */ + unsigned int duplex_lock:1; + unsigned int medialock:1; /* Do not sense media. */ + unsigned int default_port:4; /* Last dev->if_port value. */ + /* Multicast and receive mode. */ + spinlock_t mcastlock; /* SMP lock multicast updates. */ + u16 mcast_filter[4]; + /* MII transceiver section. */ + int mii_cnt; /* MII device addresses. */ + u16 advertising; /* NWay media advertisement */ + unsigned char phys[2]; /* MII device addresses. */ +}; + +/* The station address location in the EEPROM. */ +#define EEPROM_SA_OFFSET 0x10 + +static int eeprom_read(long ioaddr, int location); +static int mdio_read(struct net_device *dev, int phy_id, int location); +static void mdio_write(struct net_device *dev, int phy_id, int location, int value); +static int netdev_open(struct net_device *dev); +static void check_duplex(struct net_device *dev); +static void netdev_timer(unsigned long data); +static void tx_timeout(struct net_device *dev); +static void init_ring(struct net_device *dev); +static int start_tx(struct sk_buff *skb, struct net_device *dev); +static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs); +static void netdev_error(struct net_device *dev, int intr_status); +static int netdev_rx(struct net_device *dev); +static void netdev_error(struct net_device *dev, int intr_status); +static void set_rx_mode(struct net_device *dev); +static struct net_device_stats *get_stats(struct net_device *dev); +static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static int netdev_close(struct net_device *dev); + + + +static int __devinit sundance_probe1 (struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct net_device *dev; + struct netdev_private *np; + static int card_idx; + int chip_idx = ent->driver_data; + int irq = pdev->irq; + int i, option = card_idx < MAX_UNITS ? options[card_idx] : 0; + long ioaddr; + + if (pci_enable_device(pdev)) + return -EIO; + pci_set_master(pdev); + + dev = init_etherdev(NULL, sizeof(*np)); + if (!dev) + return -ENOMEM; + +#ifdef USE_IO_OPS + ioaddr = pci_resource_start(pdev, 0); + if (!request_region(ioaddr, pci_id_tbl[chip_idx].io_size, dev->name)) + goto err_out_netdev; +#else + ioaddr = pci_resource_start(pdev, 1); + if (!request_mem_region(ioaddr, pci_id_tbl[chip_idx].io_size, dev->name)) + goto err_out_netdev; + ioaddr = (long) ioremap (ioaddr, pci_id_tbl[chip_idx].io_size); + if (!ioaddr) + goto err_out_iomem; +#endif + + printk(KERN_INFO "%s: %s at 0x%lx, ", + dev->name, pci_id_tbl[chip_idx].name, ioaddr); + + for (i = 0; i < 3; i++) + ((u16 *)dev->dev_addr)[i] = + le16_to_cpu(eeprom_read(ioaddr, i + EEPROM_SA_OFFSET)); + for (i = 0; i < 5; i++) + printk("%2.2x:", dev->dev_addr[i]); + printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); + + dev->base_addr = ioaddr; + dev->irq = irq; + + np = dev->priv; + np->chip_id = chip_idx; + np->drv_flags = pci_id_tbl[chip_idx].drv_flags; + spin_lock_init(&np->lock); + + if (dev->mem_start) + option = dev->mem_start; + + /* The lower four bits are the media type. */ + if (option > 0) { + if (option & 0x200) + np->full_duplex = 1; + np->default_port = option & 15; + if (np->default_port) + np->medialock = 1; + } + if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0) + np->full_duplex = 1; + + if (np->full_duplex) + np->duplex_lock = 1; + + /* The chip-specific entries in the device structure. */ + dev->open = &netdev_open; + dev->hard_start_xmit = &start_tx; + dev->stop = &netdev_close; + dev->get_stats = &get_stats; + dev->set_multicast_list = &set_rx_mode; + dev->do_ioctl = &mii_ioctl; + dev->tx_timeout = &tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + + if (mtu) + dev->mtu = mtu; + + if (1) { + int phy, phy_idx = 0; + np->phys[0] = 1; /* Default setting */ + for (phy = 0; phy < 32 && phy_idx < 4; phy++) { + int mii_status = mdio_read(dev, phy, 1); + if (mii_status != 0xffff && mii_status != 0x0000) { + np->phys[phy_idx++] = phy; + np->advertising = mdio_read(dev, phy, 4); + printk(KERN_INFO "%s: MII PHY found at address %d, status " + "0x%4.4x advertising %4.4x.\n", + dev->name, phy, mii_status, np->advertising); + } + } + np->mii_cnt = phy_idx; + if (phy_idx == 0) + printk(KERN_INFO "%s: No MII transceiver found!, ASIC status %x\n", + dev->name, readl(ioaddr + ASICCtrl)); + } + + /* Perhaps move the reset here? */ + /* Reset the chip to erase previous misconfiguration. */ + if (debug > 1) + printk("ASIC Control is %x.\n", readl(ioaddr + ASICCtrl)); + writew(0x007f, ioaddr + ASICCtrl + 2); + if (debug > 1) + printk("ASIC Control is now %x.\n", readl(ioaddr + ASICCtrl)); + + card_idx++; + return 0; + +#ifndef USE_IO_OPS +err_out_iomem: + release_mem_region(pci_resource_start(pdev, 1), + pci_id_tbl[chip_idx].io_size); +#endif +err_out_netdev: + unregister_netdev (dev); + kfree (dev); + return -ENODEV; +} + + +/* Read the EEPROM and MII Management Data I/O (MDIO) interfaces. */ +static int eeprom_read(long ioaddr, int location) +{ + int boguscnt = 1000; /* Typical 190 ticks. */ + writew(0x0200 | (location & 0xff), ioaddr + EECtrl); + do { + if (! (readw(ioaddr + EECtrl) & 0x8000)) { + return readw(ioaddr + EEData); + } + } while (--boguscnt > 0); + return 0; +} + +/* MII transceiver control section. + Read and write the MII registers using software-generated serial + MDIO protocol. See the MII specifications or DP83840A data sheet + for details. + + The maximum data clock rate is 2.5 Mhz. The minimum timing is usually + met by back-to-back 33Mhz PCI cycles. */ +#define mdio_delay() readb(mdio_addr) + +/* Set iff a MII transceiver on any interface requires mdio preamble. + This only set with older tranceivers, so the extra + code size of a per-interface flag is not worthwhile. */ +static char mii_preamble_required = 0; + +enum mii_reg_bits { + MDIO_ShiftClk=0x0001, MDIO_Data=0x0002, MDIO_EnbOutput=0x0004, +}; +#define MDIO_EnbIn (0) +#define MDIO_WRITE0 (MDIO_EnbOutput) +#define MDIO_WRITE1 (MDIO_Data | MDIO_EnbOutput) + +/* Generate the preamble required for initial synchronization and + a few older transceivers. */ +static void mdio_sync(long mdio_addr) +{ + int bits = 32; + + /* Establish sync by sending at least 32 logic ones. */ + while (--bits >= 0) { + writeb(MDIO_WRITE1, mdio_addr); + mdio_delay(); + writeb(MDIO_WRITE1 | MDIO_ShiftClk, mdio_addr); + mdio_delay(); + } +} + +static int mdio_read(struct net_device *dev, int phy_id, int location) +{ + long mdio_addr = dev->base_addr + MIICtrl; + int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location; + int i, retval = 0; + + if (mii_preamble_required) + mdio_sync(mdio_addr); + + /* Shift the read command bits out. */ + for (i = 15; i >= 0; i--) { + int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0; + + writeb(dataval, mdio_addr); + mdio_delay(); + writeb(dataval | MDIO_ShiftClk, mdio_addr); + mdio_delay(); + } + /* Read the two transition, 16 data, and wire-idle bits. */ + for (i = 19; i > 0; i--) { + writeb(MDIO_EnbIn, mdio_addr); + mdio_delay(); + retval = (retval << 1) | ((readb(mdio_addr) & MDIO_Data) ? 1 : 0); + writeb(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr); + mdio_delay(); + } + return (retval>>1) & 0xffff; +} + +static void mdio_write(struct net_device *dev, int phy_id, int location, int value) +{ + long mdio_addr = dev->base_addr + MIICtrl; + int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value; + int i; + + if (mii_preamble_required) + mdio_sync(mdio_addr); + + /* Shift the command bits out. */ + for (i = 31; i >= 0; i--) { + int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0; + + writeb(dataval, mdio_addr); + mdio_delay(); + writeb(dataval | MDIO_ShiftClk, mdio_addr); + mdio_delay(); + } + /* Clear out extra bits. */ + for (i = 2; i > 0; i--) { + writeb(MDIO_EnbIn, mdio_addr); + mdio_delay(); + writeb(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr); + mdio_delay(); + } + return; +} + + +static int netdev_open(struct net_device *dev) +{ + struct netdev_private *np = (struct netdev_private *)dev->priv; + long ioaddr = dev->base_addr; + int i; + + /* Do we need to reset the chip??? */ + + MOD_INC_USE_COUNT; + + if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev)) { + MOD_DEC_USE_COUNT; + return -EAGAIN; + } + + if (debug > 1) + printk(KERN_DEBUG "%s: netdev_open() irq %d.\n", + dev->name, dev->irq); + + init_ring(dev); + + writel(virt_to_bus(np->rx_ring), ioaddr + RxListPtr); + /* The Tx list pointer is written as packets are queued. */ + + for (i = 0; i < 6; i++) + writeb(dev->dev_addr[i], ioaddr + StationAddr + i); + + /* Initialize other registers. */ + /* Configure the PCI bus bursts and FIFO thresholds. */ + + if (dev->if_port == 0) + dev->if_port = np->default_port; + + np->full_duplex = np->duplex_lock; + np->mcastlock = (spinlock_t) SPIN_LOCK_UNLOCKED; + + set_rx_mode(dev); + writew(0, ioaddr + DownCounter); + /* Set the chip to poll every N*320nsec. */ + writeb(100, ioaddr + RxDescPoll); + writeb(127, ioaddr + TxDescPoll); + netif_start_queue(dev); + + /* Enable interrupts by setting the interrupt mask. */ + writew(IntrRxDone | IntrRxDMADone | IntrPCIErr | IntrDrvRqst | IntrTxDone + | StatsMax | LinkChange, ioaddr + IntrEnable); + + writew(StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl1); + + if (debug > 2) + printk(KERN_DEBUG "%s: Done netdev_open(), status: Rx %x Tx %x " + "MAC Control %x, %4.4x %4.4x.\n", + dev->name, readl(ioaddr + RxStatus), readb(ioaddr + TxStatus), + readl(ioaddr + MACCtrl0), + readw(ioaddr + MACCtrl1), readw(ioaddr + MACCtrl0)); + + /* Set the timer to check for link beat. */ + init_timer(&np->timer); + np->timer.expires = jiffies + 3*HZ; + np->timer.data = (unsigned long)dev; + np->timer.function = &netdev_timer; /* timer handler */ + add_timer(&np->timer); + + return 0; +} + +static void check_duplex(struct net_device *dev) +{ + struct netdev_private *np = (struct netdev_private *)dev->priv; + long ioaddr = dev->base_addr; + int mii_reg5 = mdio_read(dev, np->phys[0], 5); + int negotiated = mii_reg5 & np->advertising; + int duplex; + + if (np->duplex_lock || mii_reg5 == 0xffff) + return; + duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040; + if (np->full_duplex != duplex) { + np->full_duplex = duplex; + if (debug) + printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d " + "negotiated capability %4.4x.\n", dev->name, + duplex ? "full" : "half", np->phys[0], negotiated); + writew(duplex ? 0x20 : 0, ioaddr + MACCtrl0); + } +} + +static void netdev_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct netdev_private *np = (struct netdev_private *)dev->priv; + long ioaddr = dev->base_addr; + int next_tick = 10*HZ; + + if (debug > 3) { + printk(KERN_DEBUG "%s: Media selection timer tick, intr status %4.4x, " + "Tx %x Rx %x.\n", + dev->name, readw(ioaddr + IntrEnable), + readb(ioaddr + TxStatus), readl(ioaddr + RxStatus)); + } + check_duplex(dev); + np->timer.expires = jiffies + next_tick; + add_timer(&np->timer); +} + +static void tx_timeout(struct net_device *dev) +{ + struct netdev_private *np = (struct netdev_private *)dev->priv; + long ioaddr = dev->base_addr; + + printk(KERN_WARNING "%s: Transmit timed out, status %2.2x," + " resetting...\n", dev->name, readb(ioaddr + TxStatus)); + +#ifndef __alpha__ + { + int i; + printk(KERN_DEBUG " Rx ring %8.8x: ", (int)np->rx_ring); + for (i = 0; i < RX_RING_SIZE; i++) + printk(" %8.8x", (unsigned int)np->rx_ring[i].status); + printk("\n"KERN_DEBUG" Tx ring %8.8x: ", (int)np->tx_ring); + for (i = 0; i < TX_RING_SIZE; i++) + printk(" %4.4x", np->tx_ring[i].status); + printk("\n"); + } +#endif + + /* Perhaps we should reinitialize the hardware here. */ + dev->if_port = 0; + /* Stop and restart the chip's Tx processes . */ + + /* Trigger an immediate transmit demand. */ + writew(IntrRxDone | IntrRxDMADone | IntrPCIErr | IntrDrvRqst | IntrTxDone + | StatsMax | LinkChange, ioaddr + IntrEnable); + + dev->trans_start = jiffies; + np->stats.tx_errors++; + return; +} + + +/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ +static void init_ring(struct net_device *dev) +{ + struct netdev_private *np = (struct netdev_private *)dev->priv; + int i; + + np->tx_full = 0; + np->cur_rx = np->cur_tx = 0; + np->dirty_rx = np->dirty_tx = 0; + + np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); + np->rx_head_desc = &np->rx_ring[0]; + + /* Initialize all Rx descriptors. */ + for (i = 0; i < RX_RING_SIZE; i++) { + np->rx_ring[i].next_desc = virt_to_le32desc(&np->rx_ring[i+1]); + np->rx_ring[i].status = 0; + np->rx_ring[i].frag[0].length = 0; + np->rx_skbuff[i] = 0; + } + /* Wrap the ring. */ + np->rx_ring[i-1].next_desc = virt_to_le32desc(&np->rx_ring[0]); + + /* Fill in the Rx buffers. Handle allocation failure gracefully. */ + for (i = 0; i < RX_RING_SIZE; i++) { + struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz); + np->rx_skbuff[i] = skb; + if (skb == NULL) + break; + skb->dev = dev; /* Mark as being used by this device. */ + skb_reserve(skb, 2); /* 16 byte align the IP header. */ + np->rx_ring[i].frag[0].addr = virt_to_le32desc(skb->tail); + np->rx_ring[i].frag[0].length = cpu_to_le32(np->rx_buf_sz | LastFrag); + } + np->dirty_rx = (unsigned int)(i - RX_RING_SIZE); + + for (i = 0; i < TX_RING_SIZE; i++) { + np->tx_skbuff[i] = 0; + np->tx_ring[i].status = 0; + } + return; +} + +static int start_tx(struct sk_buff *skb, struct net_device *dev) +{ + struct netdev_private *np = (struct netdev_private *)dev->priv; + struct netdev_desc *txdesc; + unsigned entry; + + /* Note: Ordering is important here, set the field with the + "ownership" bit last, and only then increment cur_tx. */ + + /* Calculate the next Tx descriptor entry. */ + entry = np->cur_tx % TX_RING_SIZE; + np->tx_skbuff[entry] = skb; + txdesc = &np->tx_ring[entry]; + + txdesc->next_desc = 0; + /* Note: disable the interrupt generation here before releasing. */ + txdesc->status = + cpu_to_le32((entry<<2) | DescIntrOnDMADone | DescIntrOnTx); + txdesc->frag[0].addr = virt_to_le32desc(skb->data); + txdesc->frag[0].length = cpu_to_le32(skb->len | LastFrag); + if (np->last_tx) + np->last_tx->next_desc = virt_to_le32desc(txdesc); + np->last_tx = txdesc; + np->cur_tx++; + + /* On some architectures: explicitly flush cache lines here. */ + + if (np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 1) { + /* do nothing */ + } else { + np->tx_full = 1; + netif_stop_queue(dev); + } + /* Side effect: The read wakes the potentially-idle transmit channel. */ + if (readl(dev->base_addr + TxListPtr) == 0) + writel(virt_to_bus(&np->tx_ring[entry]), dev->base_addr + TxListPtr); + + dev->trans_start = jiffies; + + if (debug > 4) { + printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n", + dev->name, np->cur_tx, entry); + } + return 0; +} + +/* The interrupt handler does all of the Rx thread work and cleans up + after the Tx thread. */ +static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) +{ + struct net_device *dev = (struct net_device *)dev_instance; + struct netdev_private *np; + long ioaddr; + int boguscnt = max_interrupt_work; + + ioaddr = dev->base_addr; + np = (struct netdev_private *)dev->priv; + spin_lock(&np->lock); + + do { + int intr_status = readw(ioaddr + IntrStatus); + writew(intr_status & (IntrRxDone | IntrRxDMADone | IntrPCIErr | + IntrDrvRqst |IntrTxDone|IntrTxDMADone | + StatsMax | LinkChange), + ioaddr + IntrStatus); + + if (debug > 4) + printk(KERN_DEBUG "%s: Interrupt, status %4.4x.\n", + dev->name, intr_status); + + if (intr_status == 0) + break; + + if (intr_status & (IntrRxDone|IntrRxDMADone)) + netdev_rx(dev); + + if (intr_status & IntrTxDone) { + int boguscnt = 32; + int tx_status = readw(ioaddr + TxStatus); + while (tx_status & 0x80) { + if (debug > 4) + printk("%s: Transmit status is %2.2x.\n", + dev->name, tx_status); + if (tx_status & 0x1e) { + np->stats.tx_errors++; + if (tx_status & 0x10) np->stats.tx_fifo_errors++; +#ifdef ETHER_STATS + if (tx_status & 0x08) np->stats.collisions16++; +#else + if (tx_status & 0x08) np->stats.collisions++; +#endif + if (tx_status & 0x04) np->stats.tx_fifo_errors++; + if (tx_status & 0x02) np->stats.tx_window_errors++; + /* This reset has not been verified!. */ + if (tx_status & 0x10) { /* Reset the Tx. */ + writew(0x001c, ioaddr + ASICCtrl + 2); +#if 0 /* Do we need to reset the Tx pointer here? */ + writel(virt_to_bus(&np->tx_ring[np->dirty_tx]), + dev->base_addr + TxListPtr); +#endif + } + if (tx_status & 0x1e) /* Restart the Tx. */ + writew(TxEnable, ioaddr + MACCtrl1); + } + /* Yup, this is a documentation bug. It cost me *hours*. */ + writew(0, ioaddr + TxStatus); + tx_status = readb(ioaddr + TxStatus); + if (--boguscnt < 0) + break; + } + } + for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) { + int entry = np->dirty_tx % TX_RING_SIZE; + if ( ! (np->tx_ring[entry].status & 0x00010000)) + break; + /* Free the original skb. */ + dev_kfree_skb_irq(np->tx_skbuff[entry]); + np->tx_skbuff[entry] = 0; + } + if (np->tx_full + && np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4) { + /* The ring is no longer full, clear tbusy. */ + np->tx_full = 0; + netif_wake_queue(dev); + } + + /* Abnormal error summary/uncommon events handlers. */ + if (intr_status & (IntrDrvRqst | IntrPCIErr | LinkChange | StatsMax)) + netdev_error(dev, intr_status); + + if (--boguscnt < 0) { + get_stats(dev); + printk(KERN_WARNING "%s: Too much work at interrupt, " + "status=0x%4.4x / 0x%4.4x.\n", + dev->name, intr_status, readw(ioaddr + IntrClear)); + /* Re-enable us in 3.2msec. */ + writew(1000, ioaddr + DownCounter); + writew(IntrDrvRqst, ioaddr + IntrEnable); + break; + } + } while (1); + + if (debug > 3) + printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", + dev->name, readw(ioaddr + IntrStatus)); + + spin_unlock(&np->lock); +} + +/* This routine is logically part of the interrupt handler, but separated + for clarity and better register allocation. */ +static int netdev_rx(struct net_device *dev) +{ + struct netdev_private *np = (struct netdev_private *)dev->priv; + int entry = np->cur_rx % RX_RING_SIZE; + int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx; + + if (debug > 4) { + printk(KERN_DEBUG " In netdev_rx(), entry %d status %4.4x.\n", + entry, np->rx_ring[entry].status); + } + + /* If EOP is set on the next entry, it's a new packet. Send it up. */ + while (np->rx_head_desc->status & DescOwn) { + struct netdev_desc *desc = np->rx_head_desc; + u32 frame_status = le32_to_cpu(desc->status); + int pkt_len = frame_status & 0x1fff; /* Chip omits the CRC. */ + + if (debug > 4) + printk(KERN_DEBUG " netdev_rx() status was %8.8x.\n", + frame_status); + if (--boguscnt < 0) + break; + if (frame_status & 0x001f4000) { + /* There was a error. */ + if (debug > 2) + printk(KERN_DEBUG " netdev_rx() Rx error was %8.8x.\n", + frame_status); + np->stats.rx_errors++; + if (frame_status & 0x00100000) np->stats.rx_length_errors++; + if (frame_status & 0x00010000) np->stats.rx_fifo_errors++; + if (frame_status & 0x00060000) np->stats.rx_frame_errors++; + if (frame_status & 0x00080000) np->stats.rx_crc_errors++; + if (frame_status & 0x00100000) { + printk(KERN_WARNING "%s: Oversized Ethernet frame," + " status %8.8x.\n", + dev->name, frame_status); + } + } else { + struct sk_buff *skb; + +#ifndef final_version + if (debug > 4) + printk(KERN_DEBUG " netdev_rx() normal Rx pkt length %d" + ", bogus_cnt %d.\n", + pkt_len, boguscnt); +#endif + /* Check if the packet is long enough to accept without copying + to a minimally-sized skbuff. */ + if (pkt_len < rx_copybreak + && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { + skb->dev = dev; + skb_reserve(skb, 2); /* 16 byte align the IP header */ + eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0); + skb_put(skb, pkt_len); + } else { + skb_put(skb = np->rx_skbuff[entry], pkt_len); + np->rx_skbuff[entry] = NULL; + } + skb->protocol = eth_type_trans(skb, dev); + /* Note: checksum -> skb->ip_summed = CHECKSUM_UNNECESSARY; */ + netif_rx(skb); + dev->last_rx = jiffies; + } + entry = (++np->cur_rx) % RX_RING_SIZE; + np->rx_head_desc = &np->rx_ring[entry]; + } + + /* Refill the Rx ring buffers. */ + for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) { + struct sk_buff *skb; + entry = np->dirty_rx % RX_RING_SIZE; + if (np->rx_skbuff[entry] == NULL) { + skb = dev_alloc_skb(np->rx_buf_sz); + np->rx_skbuff[entry] = skb; + if (skb == NULL) + break; /* Better luck next round. */ + skb->dev = dev; /* Mark as being used by this device. */ + skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ + np->rx_ring[entry].frag[0].addr = virt_to_le32desc(skb->tail); + } + /* Perhaps we need not reset this field. */ + np->rx_ring[entry].frag[0].length = + cpu_to_le32(np->rx_buf_sz | LastFrag); + np->rx_ring[entry].status = 0; + } + + /* No need to restart Rx engine, it will poll. */ + return 0; +} + +static void netdev_error(struct net_device *dev, int intr_status) +{ + long ioaddr = dev->base_addr; + struct netdev_private *np = (struct netdev_private *)dev->priv; + + if (intr_status & IntrDrvRqst) { + /* Stop the down counter and turn interrupts back on. */ + printk("%s: Turning interrupts back on.\n", dev->name); + writew(0, ioaddr + DownCounter); + writew(IntrRxDone | IntrRxDMADone | IntrPCIErr | IntrDrvRqst | + IntrTxDone | StatsMax | LinkChange, ioaddr + IntrEnable); + } + if (intr_status & LinkChange) { + printk(KERN_ERR "%s: Link changed: Autonegotiation advertising" + " %4.4x partner %4.4x.\n", dev->name, + mdio_read(dev, np->phys[0], 4), + mdio_read(dev, np->phys[0], 5)); + check_duplex(dev); + } + if (intr_status & StatsMax) { + get_stats(dev); + } + if (intr_status & IntrPCIErr) { + printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n", + dev->name, intr_status); + /* We must do a global reset of DMA to continue. */ + } +} + +static struct net_device_stats *get_stats(struct net_device *dev) +{ + long ioaddr = dev->base_addr; + struct netdev_private *np = (struct netdev_private *)dev->priv; + int i; + + /* We should lock this segment of code for SMP eventually, although + the vulnerability window is very small and statistics are + non-critical. */ + /* The chip only need report frame silently dropped. */ + np->stats.rx_missed_errors += readb(ioaddr + RxMissed); + np->stats.tx_packets += readw(ioaddr + TxFramesOK); + np->stats.rx_packets += readw(ioaddr + RxFramesOK); + np->stats.collisions += readb(ioaddr + StatsLateColl); + np->stats.collisions += readb(ioaddr + StatsMultiColl); + np->stats.collisions += readb(ioaddr + StatsOneColl); + readb(ioaddr + StatsCarrierError); + readb(ioaddr + StatsTxDefer); + for (i = StatsTxDefer; i <= StatsMcastRx; i++) + readb(ioaddr + i); + np->stats.tx_bytes += readw(ioaddr + TxOctetsLow); + np->stats.tx_bytes += readw(ioaddr + TxOctetsHigh) << 16; + np->stats.rx_bytes += readw(ioaddr + RxOctetsLow); + np->stats.rx_bytes += readw(ioaddr + RxOctetsHigh) << 16; + + return &np->stats; +} + +/* The little-endian AUTODIN II ethernet CRC calculations. + A big-endian version is also available. + This is slow but compact code. Do not use this routine for bulk data, + use a table-based routine instead. + This is common code and should be moved to net/core/crc.c. + Chips may use the upper or lower CRC bits, and may reverse and/or invert + them. Select the endian-ness that results in minimal calculations. +*/ +static unsigned const ethernet_polynomial_le = 0xedb88320U; +static inline unsigned ether_crc_le(int length, unsigned char *data) +{ + unsigned int crc = 0xffffffff; /* Initial value. */ + while(--length >= 0) { + unsigned char current_octet = *data++; + int bit; + for (bit = 8; --bit >= 0; current_octet >>= 1) { + if ((crc ^ current_octet) & 1) { + crc >>= 1; + crc ^= ethernet_polynomial_le; + } else + crc >>= 1; + } + } + return crc; +} + +static void set_rx_mode(struct net_device *dev) +{ + long ioaddr = dev->base_addr; + u16 mc_filter[4]; /* Multicast hash filter */ + u32 rx_mode; + int i; + + if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ + /* Unconditionally log net taps. */ + printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name); + memset(mc_filter, 0xff, sizeof(mc_filter)); + rx_mode = AcceptBroadcast | AcceptMulticast | AcceptAll | AcceptMyPhys; + } else if ((dev->mc_count > multicast_filter_limit) + || (dev->flags & IFF_ALLMULTI)) { + /* Too many to match, or accept all multicasts. */ + memset(mc_filter, 0xff, sizeof(mc_filter)); + rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; + } else if (dev->mc_count) { + struct dev_mc_list *mclist; + memset(mc_filter, 0, sizeof(mc_filter)); + for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + i++, mclist = mclist->next) { + set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x3f, + mc_filter); + } + rx_mode = AcceptBroadcast | AcceptMultiHash | AcceptMyPhys; + } else { + writeb(AcceptBroadcast | AcceptMyPhys, ioaddr + RxMode); + return; + } + for (i = 0; i < 4; i++) + writew(mc_filter[i], ioaddr + MulticastFilter0 + i*2); + writeb(rx_mode, ioaddr + RxMode); +} + +static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + u16 *data = (u16 *)&rq->ifr_data; + + switch(cmd) { + case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ + data[0] = ((struct netdev_private *)dev->priv)->phys[0] & 0x1f; + /* Fall Through */ + case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ + data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f); + return 0; + case SIOCDEVPRIVATE+2: /* Write the specified MII register */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); + return 0; + default: + return -EOPNOTSUPP; + } +} + +static int netdev_close(struct net_device *dev) +{ + long ioaddr = dev->base_addr; + struct netdev_private *np = (struct netdev_private *)dev->priv; + int i; + + netif_stop_queue(dev); + + if (debug > 1) { + printk(KERN_DEBUG "%s: Shutting down ethercard, status was Tx %2.2x " + "Rx %4.4x Int %2.2x.\n", + dev->name, readb(ioaddr + TxStatus), + readl(ioaddr + RxStatus), readw(ioaddr + IntrStatus)); + printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d, Rx %d / %d.\n", + dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx); + } + + /* Disable interrupts by clearing the interrupt mask. */ + writew(0x0000, ioaddr + IntrEnable); + + /* Stop the chip's Tx and Rx processes. */ + writew(TxDisable | RxDisable | StatsDisable, ioaddr + MACCtrl1); + +#ifdef __i386__ + if (debug > 2) { + printk("\n"KERN_DEBUG" Tx ring at %8.8x:\n", + (int)virt_to_bus(np->tx_ring)); + for (i = 0; i < TX_RING_SIZE; i++) + printk(" #%d desc. %4.4x %8.8x %8.8x.\n", + i, np->tx_ring[i].status, np->tx_ring[i].frag[0].addr, + np->tx_ring[i].frag[0].length); + printk("\n"KERN_DEBUG " Rx ring %8.8x:\n", + (int)virt_to_bus(np->rx_ring)); + for (i = 0; i < /*RX_RING_SIZE*/4 ; i++) { + printk(KERN_DEBUG " #%d desc. %4.4x %4.4x %8.8x\n", + i, np->rx_ring[i].status, np->rx_ring[i].frag[0].addr, + np->rx_ring[i].frag[0].length); + } + } +#endif /* __i386__ debugging only */ + + free_irq(dev->irq, dev); + + del_timer_sync(&np->timer); + + /* Free all the skbuffs in the Rx queue. */ + for (i = 0; i < RX_RING_SIZE; i++) { + np->rx_ring[i].status = 0; + np->rx_ring[i].frag[0].addr = 0xBADF00D0; /* An invalid address. */ + if (np->rx_skbuff[i]) { + dev_kfree_skb(np->rx_skbuff[i]); + } + np->rx_skbuff[i] = 0; + } + for (i = 0; i < TX_RING_SIZE; i++) { + if (np->tx_skbuff[i]) + dev_kfree_skb(np->tx_skbuff[i]); + np->tx_skbuff[i] = 0; + } + + MOD_DEC_USE_COUNT; + + return 0; +} + +static void __devexit sundance_remove1 (struct pci_dev *pdev) +{ + struct net_device *dev = pdev->driver_data; + + /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ + while (dev) { + struct netdev_private *np = (void *)(dev->priv); + unregister_netdev(dev); +#ifdef USE_IO_OPS + release_region(dev->base_addr, pci_id_tbl[np->chip_id].io_size); +#else + release_mem_region(pci_resource_start(pdev, 1), + pci_id_tbl[np->chip_id].io_size); + iounmap((char *)(dev->base_addr)); +#endif + kfree(dev); + } + + pdev->driver_data = NULL; +} + +static struct pci_driver sundance_driver = { + name: "sundance", + id_table: sundance_pci_tbl, + probe: sundance_probe1, + remove: sundance_remove1, +}; + +static int __init sundance_init(void) +{ + return pci_module_init(&sundance_driver); +} + +static void __exit sundance_exit(void) +{ + pci_unregister_driver(&sundance_driver); +} + +module_init(sundance_init); +module_exit(sundance_exit); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/sunlance.c linux/drivers/net/sunlance.c --- v2.4.0-test8/linux/drivers/net/sunlance.c Sun Aug 13 12:01:54 2000 +++ linux/drivers/net/sunlance.c Sun Sep 17 09:41:29 2000 @@ -1332,6 +1332,7 @@ /* Make certain the data structures used by the LANCE are aligned. */ dev->priv = (void *)(((unsigned long)dev->priv + 7) & ~7); lp = (struct lance_private *) dev->priv; + spin_lock_init(&lp->lock); /* Copy the IDPROM ethernet address to the device structure, later we * will copy the address in the device structure to the lance diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/tokenring/tms380tr.c linux/drivers/net/tokenring/tms380tr.c --- v2.4.0-test8/linux/drivers/net/tokenring/tms380tr.c Tue Jul 11 11:12:24 2000 +++ linux/drivers/net/tokenring/tms380tr.c Fri Sep 22 14:21:17 2000 @@ -96,6 +96,7 @@ #include #include #include +#include #include #include diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/tulip/tulip_core.c linux/drivers/net/tulip/tulip_core.c --- v2.4.0-test8/linux/drivers/net/tulip/tulip_core.c Fri Sep 8 12:34:58 2000 +++ linux/drivers/net/tulip/tulip_core.c Mon Sep 18 14:57:01 2000 @@ -1092,7 +1092,7 @@ dev->base_addr = ioaddr; dev->irq = irq; - pdev->driver_data = dev; + pci_set_drvdata(pdev, dev); #ifdef TULIP_FULL_DUPLEX tp->full_duplex = 1; @@ -1393,7 +1393,7 @@ static void tulip_suspend (struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata(pdev); if (dev && netif_device_present (dev)) { netif_device_detach (dev); @@ -1405,7 +1405,7 @@ static void tulip_resume(struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata(pdev); pci_enable_device(pdev); if (dev && !netif_device_present (dev)) { @@ -1417,7 +1417,7 @@ static void __devexit tulip_remove_one (struct pci_dev *pdev) { - struct net_device *dev = pdev->driver_data; + struct net_device *dev = pci_get_drvdata(pdev); if (dev) { struct tulip_private *tp = (struct tulip_private *)dev->priv; @@ -1432,6 +1432,8 @@ release_region (pci_resource_start (pdev, 0), pci_resource_len (pdev, 0)); kfree(dev); + + pci_set_drvdata(pdev, NULL); } } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/tun.c linux/drivers/net/tun.c --- v2.4.0-test8/linux/drivers/net/tun.c Wed Aug 23 09:30:13 2000 +++ linux/drivers/net/tun.c Fri Sep 22 15:19:30 2000 @@ -12,7 +12,7 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * $Id: tun.c,v 1.1 2000/08/23 05:59:28 davem Exp $ + * $Id: tun.c,v 1.2 2000/09/22 12:40:31 maxk Exp $ */ /* @@ -20,7 +20,7 @@ * Modifications for 2.3.99-pre5 kernel. */ -#define TUN_VER "1.1" +#define TUN_VER "1.2" #include @@ -32,12 +32,12 @@ #include #include #include -#include #include +#include #include #include -#include +#include #include #include #include @@ -497,38 +497,29 @@ fasync: tun_chr_fasync }; -static devfs_handle_t devfs_handle = NULL; +static struct miscdevice tun_miscdev= +{ + TUN_MINOR, + "net/tun", + &tun_fops +}; int __init tun_init(void) { printk(KERN_INFO "Universal TUN/TAP device driver %s " "(C)1999-2000 Maxim Krasnyansky\n", TUN_VER); - if (devfs_register_chrdev(TUN_MAJOR, "tun", &tun_fops)) { - printk(KERN_ERR "tun: Can't register char device %d\n", - TUN_MAJOR); + if (misc_register(&tun_miscdev)) { + printk(KERN_ERR "tun: Can't register misc device %d\n", TUN_MINOR); return -EIO; } - devfs_handle = devfs_register(NULL, "net/tun", DEVFS_FL_DEFAULT, - TUN_MAJOR, 0, - S_IFCHR | S_IRUSR | S_IWUSR, - &tun_fops, NULL); - -#ifdef MODULE return 0; -#else - /* If driver is not module, tun_init will be called from Space.c. - * Return non-zero not to register fake device. - */ - return 1; -#endif } void tun_cleanup(void) { - devfs_unregister_chrdev(TUN_MAJOR,"tun"); - devfs_unregister(devfs_handle); + misc_deregister(&tun_miscdev); } module_init(tun_init); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/wan/Makefile linux/drivers/net/wan/Makefile --- v2.4.0-test8/linux/drivers/net/wan/Makefile Mon Aug 14 10:19:03 2000 +++ linux/drivers/net/wan/Makefile Sun Oct 1 19:53:56 2000 @@ -35,6 +35,8 @@ obj-$(CONFIG_COMX_PROTO_FR) += comx-proto-fr.o obj-$(CONFIG_COSA) += syncppp.o cosa.o obj-$(CONFIG_LANMEDIA) += syncppp.o +obj-$(CONFIG_SYNCLINK_SYNCPPP) += syncppp.o +obj-$(CONFIG_X25_ASY) += x25_asy.o ifeq ($(CONFIG_LANMEDIA),y) SUB_DIRS += lmc diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/wan/comx-hw-comx.c linux/drivers/net/wan/comx-hw-comx.c --- v2.4.0-test8/linux/drivers/net/wan/comx-hw-comx.c Sun May 21 20:34:37 2000 +++ linux/drivers/net/wan/comx-hw-comx.c Mon Oct 2 12:00:16 2000 @@ -9,6 +9,9 @@ * * Copyright (C) 1995-2000 ITConsult-Pro Co. * + * Contributors: + * Arnaldo Carvalho de Melo - 0.86 + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version @@ -37,13 +40,12 @@ * Version 0.85 (00/01/14): * - some additional workarounds :/ * - printk cleanups + * Version 0.86 (00/08/15): + * - resource release on failure at COMX_init */ -#define VERSION "0.85" +#define VERSION "0.86" -#include -#include -#include #include #include #include @@ -52,6 +54,9 @@ #include #include #include +#include +#include +#include #include "comx.h" #include "comxhw.h" @@ -1224,7 +1229,7 @@ if ((new_file = create_proc_entry(FILENAME_IO, S_IFREG | 0644, ch->procdir)) == NULL) { - return -EIO; + goto cleanup_HW_privdata; } new_file->data = (void *)new_file; new_file->read_proc = &comxhw_read_proc; @@ -1234,7 +1239,7 @@ if ((new_file = create_proc_entry(FILENAME_IRQ, S_IFREG | 0644, ch->procdir)) == NULL) { - return -EIO; + goto cleanup_filename_io; } new_file->data = (void *)new_file; new_file->read_proc = &comxhw_read_proc; @@ -1244,7 +1249,7 @@ if ((new_file = create_proc_entry(FILENAME_CHANNEL, S_IFREG | 0644, ch->procdir)) == NULL) { - return -EIO; + goto cleanup_filename_irq; } new_file->data = (void *)new_file; new_file->read_proc = &comxhw_read_proc; @@ -1255,7 +1260,7 @@ if (ch->hardware == &hicomx_hw || ch->hardware == &cmx_hw) { if ((new_file = create_proc_entry(FILENAME_CLOCK, S_IFREG | 0644, ch->procdir)) == NULL) { - return -EIO; + goto cleanup_filename_channel; } new_file->data = (void *)new_file; new_file->read_proc = &comxhw_read_proc; @@ -1266,7 +1271,7 @@ if ((new_file = create_proc_entry(FILENAME_MEMADDR, S_IFREG | 0644, ch->procdir)) == NULL) { - return -EIO; + goto cleanup_filename_clock; } new_file->data = (void *)new_file; new_file->read_proc = &comxhw_read_proc; @@ -1276,7 +1281,7 @@ if ((new_file = create_proc_entry(FILENAME_TWIN, S_IFREG | 0444, ch->procdir)) == NULL) { - return -EIO; + goto cleanup_filename_memaddr; } new_file->data = (void *)new_file; new_file->read_proc = &comxhw_read_proc; @@ -1285,7 +1290,7 @@ if ((new_file = create_proc_entry(FILENAME_FIRMWARE, S_IFREG | 0644, ch->procdir)) == NULL) { - return -EIO; + goto cleanup_filename_twin; } new_file->data = (void *)new_file; new_file->read_proc = &comxhw_read_proc; @@ -1326,6 +1331,23 @@ MOD_INC_USE_COUNT; return 0; + +cleanup_filename_twin: + remove_proc_entry(FILENAME_TWIN, ch->procdir); +cleanup_filename_memaddr: + remove_proc_entry(FILENAME_MEMADDR, ch->procdir); +cleanup_filename_clock: + if (ch->hardware == &hicomx_hw || ch->hardware == &cmx_hw) + remove_proc_entry(FILENAME_CLOCK, ch->procdir); +cleanup_filename_channel: + remove_proc_entry(FILENAME_CHANNEL, ch->procdir); +cleanup_filename_irq: + remove_proc_entry(FILENAME_IRQ, ch->procdir); +cleanup_filename_io: + remove_proc_entry(FILENAME_IO, ch->procdir); +cleanup_HW_privdata: + kfree(ch->HW_privdata); + return -EIO; } /* Called on echo valami >boardtype */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/wan/comx-hw-locomx.c linux/drivers/net/wan/comx-hw-locomx.c --- v2.4.0-test8/linux/drivers/net/wan/comx-hw-locomx.c Sun May 21 20:34:37 2000 +++ linux/drivers/net/wan/comx-hw-locomx.c Mon Sep 18 15:02:03 2000 @@ -7,6 +7,9 @@ * Based on skeleton code and old LoCOMX driver by Tivadar Szemethy * and the hostess_sv11 driver * + * Contributors: + * Arnaldo Carvalho de Melo (0.14) + * * Copyright (C) 1999 ITConsult-Pro Co. * * This program is free software; you can redistribute it and/or @@ -27,9 +30,11 @@ * Version 0.13 (99/07/08): * - Fix the transmitter status check * - Handle the net device statistics better + * Version 0.14 (00/08/15): + * - resource release on failure at LOCOMX_init */ -#define VERSION "0.13" +#define VERSION "0.14" #include #include @@ -385,7 +390,7 @@ /* Register /proc files */ if ((new_file = create_proc_entry(FILENAME_IO, S_IFREG | 0644, ch->procdir)) == NULL) { - return -EIO; + goto cleanup_HW_privdata; } new_file->data = (void *)new_file; new_file->read_proc = &locomx_read_proc; @@ -394,7 +399,7 @@ if ((new_file = create_proc_entry(FILENAME_IRQ, S_IFREG | 0644, ch->procdir)) == NULL) { - return -EIO; + goto cleanup_filename_io; } new_file->data = (void *)new_file; new_file->read_proc = &locomx_read_proc; @@ -432,6 +437,11 @@ /* O.K. Count one more user on this module */ MOD_INC_USE_COUNT; return 0; +cleanup_filename_io: + remove_proc_entry(FILENAME_IO, ch->procdir); +cleanup_HW_privdata: + kfree(ch->HW_privdata); + return -EIO; } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/wan/comx-hw-mixcom.c linux/drivers/net/wan/comx-hw-mixcom.c --- v2.4.0-test8/linux/drivers/net/wan/comx-hw-mixcom.c Sun May 21 20:34:37 2000 +++ linux/drivers/net/wan/comx-hw-mixcom.c Mon Sep 18 15:02:03 2000 @@ -8,6 +8,9 @@ * * Copyright (C) 1998-1999 ITConsult-Pro Co. * + * Contributors: + * Arnaldo Carvalho de Melo (0.65) + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version @@ -29,9 +32,12 @@ * * Version 0.64 (99/12/01): * - some more cosmetical fixes + * + * Version 0.65 (00/08/15) + * - resource release on failure at MIXCOM_init */ -#define VERSION "0.64" +#define VERSION "0.65" #include #include @@ -819,7 +825,7 @@ if ((new_file = create_proc_entry(FILENAME_IO, S_IFREG | 0644, ch->procdir)) == NULL) { - return -EIO; + goto cleanup_HW_privdata; } new_file->data = (void *)new_file; new_file->read_proc = &mixcom_read_proc; @@ -828,7 +834,7 @@ if ((new_file = create_proc_entry(FILENAME_IRQ, S_IFREG | 0644, ch->procdir)) == NULL) { - return -EIO; + goto cleanup_filename_io; } new_file->data = (void *)new_file; new_file->read_proc = &mixcom_read_proc; @@ -848,7 +854,7 @@ if ((new_file = create_proc_entry(FILENAME_CHANNEL, S_IFREG | 0644, ch->procdir)) == NULL) { - return -EIO; + goto cleanup_filename_irq; } new_file->data = (void *)new_file; new_file->read_proc = &mixcom_read_proc; @@ -857,7 +863,7 @@ if ((new_file = create_proc_entry(FILENAME_TWIN, S_IFREG | 0444, ch->procdir)) == NULL) { - return -EIO; + goto cleanup_filename_channel; } new_file->data = (void *)new_file; new_file->read_proc = &mixcom_read_proc; @@ -881,6 +887,15 @@ MOD_INC_USE_COUNT; return 0; +cleanup_filename_channel: + remove_proc_entry(FILENAME_CHANNEL, ch->procdir); +cleanup_filename_irq: + remove_proc_entry(FILENAME_IRQ, ch->procdir); +cleanup_filename_io: + remove_proc_entry(FILENAME_IO, ch->procdir); +cleanup_HW_privdata: + kfree(ch->HW_privdata); + return -EIO; } static int MIXCOM_exit(struct net_device *dev) diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/wan/comx-proto-fr.c linux/drivers/net/wan/comx-proto-fr.c --- v2.4.0-test8/linux/drivers/net/wan/comx-proto-fr.c Sun May 21 20:34:37 2000 +++ linux/drivers/net/wan/comx-proto-fr.c Mon Sep 18 15:02:03 2000 @@ -6,6 +6,9 @@ * Maintainer: Gergely Madarasz * * Copyright (C) 1998-1999 ITConsult-Pro Co. + * + * Contributors: + * Arnaldo Carvalho de Melo (0.73) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -25,9 +28,13 @@ * Version 0.72 (99/07/09): * - handle slave tbusy with master tbusy (should be fixed) * - fix the keepalive timer addition/deletion + * + * Version 0.73 (00/08/15) + * - resource release on failure at fr_master_init and + * fr_slave_init */ -#define VERSION "0.72" +#define VERSION "0.73" #include #include @@ -793,7 +800,7 @@ if ((new_file = create_proc_entry(FILENAME_DLCI, S_IFREG | 0644, ch->procdir)) == NULL) { - return -ENOMEM; + goto cleanup_LINE_privdata; } new_file->data = (void *)new_file; new_file->read_proc = &fr_read_proc; @@ -803,7 +810,7 @@ if ((new_file = create_proc_entry(FILENAME_KEEPALIVE, S_IFREG | 0644, ch->procdir)) == NULL) { - return -ENOMEM; + goto cleanup_filename_dlci; } new_file->data = (void *)new_file; new_file->read_proc = &fr_read_proc; @@ -815,6 +822,11 @@ MOD_INC_USE_COUNT; return 0; +cleanup_filename_dlci: + remove_proc_entry(FILENAME_DLCI, ch->procdir); +cleanup_LINE_privdata: + kfree(fr); + return -EIO; } static int fr_slave_init(struct net_device *dev) @@ -847,7 +859,7 @@ if ((new_file = create_proc_entry(FILENAME_DLCI, S_IFREG | 0644, ch->procdir)) == NULL) { - return -ENOMEM; + goto cleanup_LINE_privdata; } new_file->data = (void *)new_file; @@ -858,7 +870,7 @@ if ((new_file = create_proc_entry(FILENAME_MASTER, S_IFREG | 0644, ch->procdir)) == NULL) { - return -EIO; + goto cleanup_filename_dlci; } new_file->data = (void *)new_file; new_file->read_proc = &fr_read_proc; @@ -867,6 +879,11 @@ new_file->nlink = 1; MOD_INC_USE_COUNT; return 0; +cleanup_filename_dlci: + remove_proc_entry(FILENAME_DLCI, ch->procdir); +cleanup_LINE_privdata: + kfree(fr); + return -EIO; } static int dlci_open(struct net_device *dev) diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/wan/comx-proto-ppp.c linux/drivers/net/wan/comx-proto-ppp.c --- v2.4.0-test8/linux/drivers/net/wan/comx-proto-ppp.c Mon Mar 13 13:55:09 2000 +++ linux/drivers/net/wan/comx-proto-ppp.c Mon Sep 18 15:02:03 2000 @@ -200,6 +200,8 @@ struct ppp_device *pppdev = (struct ppp_device *)ch->if_ptr; ch->LINE_privdata = kmalloc(sizeof(struct syncppp_data), GFP_KERNEL); + if (!ch->LINE_privdata) + return -ENOMEM; pppdev->dev = dev; sppp_attach(pppdev); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/wan/comx.c linux/drivers/net/wan/comx.c --- v2.4.0-test8/linux/drivers/net/wan/comx.c Wed Jun 21 10:10:02 2000 +++ linux/drivers/net/wan/comx.c Mon Sep 18 15:02:03 2000 @@ -10,6 +10,9 @@ * * Copyright (C) 1995-1999 ITConsult-Pro Co. * + * Contributors: + * Arnaldo Carvalho de Melo (0.85) + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version @@ -39,9 +42,13 @@ * Version 0.84 (99/12/01): * - comx_status should not check for IFF_UP (to report * line status from dev->open()) + * + * Version 0.85 (00/08/15): + * - resource release on failure in comx_mkdir + * - fix return value on failure at comx_write_proc */ -#define VERSION "0.84" +#define VERSION "0.85" #include #include @@ -506,6 +513,7 @@ ch->loadavg_size = ch->loadavg[2] / ch->loadavg[0] + 1; if ((ch->avg_bytes = kmalloc(ch->loadavg_size * sizeof(unsigned long) * 2, GFP_KERNEL)) == NULL) { + kfree(ch); return -ENOMEM; } @@ -629,7 +637,7 @@ ch->debug_start = ch->debug_end = 0; restore_flags(flags); free_page((unsigned long)page); - return count; + return ret ? ret : count; } if (*page != '+' && *page != '-') { @@ -762,10 +770,16 @@ struct proc_dir_entry *new_dir, *debug_file; struct net_device *dev; struct comx_channel *ch; + int ret = -EIO; + + if ((dev = kmalloc(sizeof(struct net_device), GFP_KERNEL)) == NULL) { + return -ENOMEM; + } + memset(dev, 0, sizeof(struct net_device)); if ((new_dir = create_proc_entry(dentry->d_name.name, mode | S_IFDIR, comx_root_dir)) == NULL) { - return -EIO; + goto cleanup_dev; } new_dir->nlink = 2; @@ -774,42 +788,38 @@ /* Ezek kellenek */ if (!create_comx_proc_entry(FILENAME_HARDWARE, 0644, strlen(HWNAME_NONE) + 1, new_dir)) { - return -ENOMEM; + goto cleanup_new_dir; } if (!create_comx_proc_entry(FILENAME_PROTOCOL, 0644, strlen(PROTONAME_NONE) + 1, new_dir)) { - return -ENOMEM; + goto cleanup_filename_hardware; } if (!create_comx_proc_entry(FILENAME_STATUS, 0444, 0, new_dir)) { - return -ENOMEM; + goto cleanup_filename_protocol; } if (!create_comx_proc_entry(FILENAME_LINEUPDELAY, 0644, 2, new_dir)) { - return -ENOMEM; + goto cleanup_filename_status; } if ((debug_file = create_proc_entry(FILENAME_DEBUG, S_IFREG | 0644, new_dir)) == NULL) { - return -ENOMEM; + goto cleanup_filename_lineupdelay; } debug_file->data = (void *)debug_file; debug_file->read_proc = NULL; // see below debug_file->write_proc = &comx_write_proc; debug_file->nlink = 1; - if ((dev = kmalloc(sizeof(struct net_device), GFP_KERNEL)) == NULL) { - return -ENOMEM; - } - memset(dev, 0, sizeof(struct net_device)); strcpy(dev->name, (char *)new_dir->name); dev->init = comx_init_dev; if (register_netdevice(dev)) { - return -EIO; + goto cleanup_filename_debug; } ch=dev->priv; if((ch->if_ptr = (void *)kmalloc(sizeof(struct ppp_device), GFP_KERNEL)) == NULL) { - return -ENOMEM; + goto cleanup_register; } memset(ch->if_ptr, 0, sizeof(struct ppp_device)); ch->debug_file = debug_file; @@ -819,13 +829,33 @@ ch->debug_start = ch->debug_end = 0; if ((ch->debug_area = kmalloc(ch->debug_size = DEFAULT_DEBUG_SIZE, GFP_KERNEL)) == NULL) { - return -ENOMEM; + ret = -ENOMEM; + goto cleanup_if_ptr; } ch->lineup_delay = DEFAULT_LINEUP_DELAY; MOD_INC_USE_COUNT; return 0; +cleanup_if_ptr: + kfree(ch->if_ptr); +cleanup_register: + unregister_netdevice(dev); +cleanup_filename_debug: + remove_proc_entry(FILENAME_DEBUG, new_dir); +cleanup_filename_lineupdelay: + remove_proc_entry(FILENAME_LINEUPDELAY, new_dir); +cleanup_filename_status: + remove_proc_entry(FILENAME_STATUS, new_dir); +cleanup_filename_protocol: + remove_proc_entry(FILENAME_PROTOCOL, new_dir); +cleanup_filename_hardware: + remove_proc_entry(FILENAME_HARDWARE, new_dir); +cleanup_new_dir: + remove_proc_entry(dentry->d_name.name, &comx_root_dir); +cleanup_dev: + kfree(dev); + return ret; } static int comx_rmdir(struct inode *dir, struct dentry *dentry) diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/wan/cosa.c linux/drivers/net/wan/cosa.c --- v2.4.0-test8/linux/drivers/net/wan/cosa.c Tue Aug 29 14:09:15 2000 +++ linux/drivers/net/wan/cosa.c Mon Oct 2 12:00:16 2000 @@ -303,8 +303,7 @@ static char *chrdev_setup_rx(struct channel_data *channel, int size); static int chrdev_rx_done(struct channel_data *channel); static int chrdev_tx_done(struct channel_data *channel, int size); -static long long cosa_lseek(struct file *file, - long long offset, int origin); +static loff_t cosa_lseek(struct file *file, loff_t offset, int origin); static ssize_t cosa_read(struct file *file, char *buf, size_t count, loff_t *ppos); static ssize_t cosa_write(struct file *file, @@ -783,8 +782,7 @@ init_MUTEX(&chan->wsem); } -static long long cosa_lseek(struct file * file, - long long offset, int origin) +static loff_t cosa_lseek(struct file * file, loff_t offset, int origin) { return -ESPIPE; } @@ -1212,7 +1210,7 @@ { int rv; struct channel_data *chan = (struct channel_data *)dev->priv; - rv = cosa_ioctl_common(chan->cosa, chan, cmd, (int)ifr->ifr_data); + rv = cosa_ioctl_common(chan->cosa, chan, cmd, (unsigned long)ifr->ifr_data); if (rv == -ENOIOCTLCMD) { return sppp_do_ioctl(dev, ifr, cmd); } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/wan/sdla.c linux/drivers/net/wan/sdla.c --- v2.4.0-test8/linux/drivers/net/wan/sdla.c Mon Mar 13 09:50:16 2000 +++ linux/drivers/net/wan/sdla.c Tue Sep 19 08:01:34 2000 @@ -1203,7 +1203,10 @@ return(-ENOMEM); sdla_read(dev, mem.addr, temp, mem.len); if(copy_to_user(mem.data, temp, mem.len)) + { + kfree(temp); return -EFAULT; + } kfree(temp); } else @@ -1212,7 +1215,10 @@ if (!temp) return(-ENOMEM); if(copy_from_user(temp, mem.data, mem.len)) + { + kfree(temp); return -EFAULT; + } sdla_write(dev, mem.addr, temp, mem.len); kfree(temp); } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/net/winbond-840.c linux/drivers/net/winbond-840.c --- v2.4.0-test8/linux/drivers/net/winbond-840.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/winbond-840.c Sun Sep 24 12:12:33 2000 @@ -0,0 +1,1352 @@ +/* winbond-840.c: A Linux PCI network adapter skeleton device driver. */ +/* + Written 1998-2000 by Donald Becker. + + This software may be used and distributed according to the terms of + the GNU General Public License (GPL), incorporated herein by reference. + Drivers based on or derived from this code fall under the GPL and must + retain the authorship, copyright and license notice. This file is not + a complete program and may only be used when the entire operating + system is licensed under the GPL. + + The author may be reached as becker@scyld.com, or C/O + Scyld Computing Corporation + 410 Severn Ave., Suite 210 + Annapolis MD 21403 + + Support and updates available at + http://www.scyld.com/network/drivers.html + + Do not remove the copyright infomation. + Do not change the version information unless an improvement has been made. + Merely removing my name, as Compex has done in the past, does not count + as an improvement. +*/ + +/* These identify the driver base version and may not be removed. */ +static const char version1[] = +"winbond-840.c:v1.01 5/15/2000 Donald Becker \n"; +static const char version2[] = +" http://www.scyld.com/network/drivers.html\n"; + +/* Automatically extracted configuration info: +probe-func: winbond840_probe +config-in: tristate 'Winbond W89c840 Ethernet support' CONFIG_WINBOND_840 + +c-help-name: Winbond W89c840 PCI Ethernet support +c-help-symbol: CONFIG_WINBOND_840 +c-help: This driver is for the Winbond W89c840 chip. It also works with +c-help: the TX9882 chip on the Compex RL100-ATX board. +c-help: More specific information and updates are available from +c-help: http://www.scyld.com/network/drivers.html +*/ + +/* The user-configurable values. + These may be modified when a driver module is loaded.*/ + +static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ +static int max_interrupt_work = 20; +/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). + The '840 uses a 64 element hash table based on the Ethernet CRC. */ +static int multicast_filter_limit = 32; + +/* Set the copy breakpoint for the copy-only-tiny-frames scheme. + Setting to > 1518 effectively disables this feature. */ +static int rx_copybreak = 0; + +/* Used to pass the media type, etc. + Both 'options[]' and 'full_duplex[]' should exist for driver + interoperability. + The media type is usually passed in 'options[]'. +*/ +#define MAX_UNITS 8 /* More are supported, limit only on options */ +static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; +static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; + +/* Operational parameters that are set at compile time. */ + +/* Keep the ring sizes a power of two for compile efficiency. + The compiler will convert '%'<2^N> into a bit mask. + Making the Tx ring too large decreases the effectiveness of channel + bonding and packet priority. + There are no ill effects from too-large receive rings. */ +#define TX_RING_SIZE 16 +#define TX_QUEUE_LEN 10 /* Limit ring entries actually used. */ +#define RX_RING_SIZE 32 + +/* The presumed FIFO size for working around the Tx-FIFO-overflow bug. + To avoid overflowing we don't queue again until we have room for a + full-size packet. + */ +#define TX_FIFO_SIZE (2048) +#define TX_BUG_FIFO_LIMIT (TX_FIFO_SIZE-1514-16) + +/* Operational parameters that usually are not changed. */ +/* Time in jiffies before concluding the transmitter is hung. */ +#define TX_TIMEOUT (2*HZ) + +#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/ + +#ifndef __KERNEL__ +#define __KERNEL__ +#endif +#if !defined(__OPTIMIZE__) +#warning You must compile this file with the correct options! +#warning See the last lines of the source file. +#error You must compile this driver with "-O". +#endif + +/* Include files, designed to support most kernel versions 2.0.0 and later. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* Processor type for cache alignment. */ +#include +#include + +/* Condensed operations for readability. + The compatibility defines are in kern_compat.h */ + +#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr)) +#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr)) + +MODULE_AUTHOR("Donald Becker "); +MODULE_DESCRIPTION("Winbond W89c840 Ethernet driver"); +MODULE_PARM(max_interrupt_work, "i"); +MODULE_PARM(debug, "i"); +MODULE_PARM(rx_copybreak, "i"); +MODULE_PARM(multicast_filter_limit, "i"); +MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); + +/* + Theory of Operation + +I. Board Compatibility + +This driver is for the Winbond w89c840 chip. + +II. Board-specific settings + +None. + +III. Driver operation + +This chip is very similar to the Digital 21*4* "Tulip" family. The first +twelve registers and the descriptor format are nearly identical. Read a +Tulip manual for operational details. + +A significant difference is that the multicast filter and station address are +stored in registers rather than loaded through a pseudo-transmit packet. + +Unlike the Tulip, transmit buffers are limited to 1KB. To transmit a +full-sized packet we must use both data buffers in a descriptor. Thus the +driver uses ring mode where descriptors are implicitly sequential in memory, +rather than using the second descriptor address as a chain pointer to +subsequent descriptors. + +IV. Notes + +If you are going to almost clone a Tulip, why not go all the way and avoid +the need for a new driver? + +IVb. References + +http://www.scyld.com/expert/100mbps.html +http://www.scyld.com/expert/NWay.html +http://www.winbond.com.tw/ + +IVc. Errata + +A horrible bug exists in the transmit FIFO. Apparently the chip doesn't +correctly detect a full FIFO, and queuing more than 2048 bytes may result in +silent data corruption. + +*/ + + + +/* + PCI probe table. +*/ +enum pci_id_flags_bits { + /* Set PCI command register bits before calling probe1(). */ + PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4, + /* Read and map the single following PCI BAR. */ + PCI_ADDR0=0<<4, PCI_ADDR1=1<<4, PCI_ADDR2=2<<4, PCI_ADDR3=3<<4, + PCI_ADDR_64BITS=0x100, PCI_NO_ACPI_WAKE=0x200, PCI_NO_MIN_LATENCY=0x400, +}; +enum chip_capability_flags {CanHaveMII=1, HasBrokenTx=2}; +#ifdef USE_IO_OPS +#define W840_FLAGS (PCI_USES_IO | PCI_ADDR0 | PCI_USES_MASTER) +#else +#define W840_FLAGS (PCI_USES_MEM | PCI_ADDR1 | PCI_USES_MASTER) +#endif + +static struct pci_device_id w840_pci_tbl[] __devinitdata = { + { 0x1050, 0x0840, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0x11f6, 0x2011, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 }, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, w840_pci_tbl); + +struct pci_id_info { + const char *name; + struct match_info { + int pci, pci_mask, subsystem, subsystem_mask; + int revision, revision_mask; /* Only 8 bits. */ + } id; + enum pci_id_flags_bits pci_flags; + int io_size; /* Needed for I/O region check or ioremap(). */ + int drv_flags; /* Driver use, intended as capability flags. */ +}; +static struct pci_id_info pci_id_tbl[] = { + {"Winbond W89c840", { 0x08401050, 0xffffffff, }, + W840_FLAGS, 128, CanHaveMII | HasBrokenTx}, + {"Compex RL100-ATX", { 0x201111F6, 0xffffffff,}, + W840_FLAGS, 128, CanHaveMII | HasBrokenTx}, + {0,}, /* 0 terminated list. */ +}; + +/* This driver was written to use PCI memory space, however some x86 systems + work only with I/O space accesses. Pass -DUSE_IO_OPS to use PCI I/O space + accesses instead of memory space. */ + +#ifdef USE_IO_OPS +#undef readb +#undef readw +#undef readl +#undef writeb +#undef writew +#undef writel +#define readb inb +#define readw inw +#define readl inl +#define writeb outb +#define writew outw +#define writel outl +#endif + +/* Offsets to the Command and Status Registers, "CSRs". + While similar to the Tulip, these registers are longword aligned. + Note: It's not useful to define symbolic names for every register bit in + the device. The name can only partially document the semantics and make + the driver longer and more difficult to read. +*/ +enum w840_offsets { + PCIBusCfg=0x00, TxStartDemand=0x04, RxStartDemand=0x08, + RxRingPtr=0x0C, TxRingPtr=0x10, + IntrStatus=0x14, NetworkConfig=0x18, IntrEnable=0x1C, + RxMissed=0x20, EECtrl=0x24, MIICtrl=0x24, BootRom=0x28, GPTimer=0x2C, + CurRxDescAddr=0x30, CurRxBufAddr=0x34, /* Debug use */ + MulticastFilter0=0x38, MulticastFilter1=0x3C, StationAddr=0x40, + CurTxDescAddr=0x4C, CurTxBufAddr=0x50, +}; + +/* Bits in the interrupt status/enable registers. */ +/* The bits in the Intr Status/Enable registers, mostly interrupt sources. */ +enum intr_status_bits { + NormalIntr=0x10000, AbnormalIntr=0x8000, + IntrPCIErr=0x2000, TimerInt=0x800, + IntrRxDied=0x100, RxNoBuf=0x80, IntrRxDone=0x40, + TxFIFOUnderflow=0x20, RxErrIntr=0x10, + TxIdle=0x04, IntrTxStopped=0x02, IntrTxDone=0x01, +}; + +/* Bits in the NetworkConfig register. */ +enum rx_mode_bits { + AcceptErr=0x80, AcceptRunt=0x40, + AcceptBroadcast=0x20, AcceptMulticast=0x10, + AcceptAllPhys=0x08, AcceptMyPhys=0x02, +}; + +enum mii_reg_bits { + MDIO_ShiftClk=0x10000, MDIO_DataIn=0x80000, MDIO_DataOut=0x20000, + MDIO_EnbOutput=0x40000, MDIO_EnbIn = 0x00000, +}; + +/* The Tulip Rx and Tx buffer descriptors. */ +struct w840_rx_desc { + s32 status; + s32 length; + u32 buffer1; + u32 next_desc; +}; + +struct w840_tx_desc { + s32 status; + s32 length; + u32 buffer1, buffer2; /* We use only buffer 1. */ +}; + +/* Bits in network_desc.status */ +enum desc_status_bits { + DescOwn=0x80000000, DescEndRing=0x02000000, DescUseLink=0x01000000, + DescWholePkt=0x60000000, DescStartPkt=0x20000000, DescEndPkt=0x40000000, + DescIntr=0x80000000, +}; + +#define PRIV_ALIGN 15 /* Required alignment mask */ +struct netdev_private { + /* Descriptor rings first for alignment. */ + struct w840_rx_desc rx_ring[RX_RING_SIZE]; + struct w840_tx_desc tx_ring[TX_RING_SIZE]; + /* The addresses of receive-in-place skbuffs. */ + struct sk_buff* rx_skbuff[RX_RING_SIZE]; + /* The saved address of a sent-in-place packet/buffer, for later free(). */ + struct sk_buff* tx_skbuff[TX_RING_SIZE]; + struct net_device_stats stats; + struct timer_list timer; /* Media monitoring timer. */ + /* Frequently used values: keep some adjacent for cache effect. */ + spinlock_t lock; + int chip_id, drv_flags; + int csr6; + struct w840_rx_desc *rx_head_desc; + unsigned int cur_rx, dirty_rx; /* Producer/consumer ring indices */ + unsigned int rx_buf_sz; /* Based on MTU+slack. */ + unsigned int cur_tx, dirty_tx; + int tx_q_bytes; + unsigned int tx_full:1; /* The Tx queue is full. */ + /* These values are keep track of the transceiver/media in use. */ + unsigned int full_duplex:1; /* Full-duplex operation requested. */ + unsigned int duplex_lock:1; + unsigned int medialock:1; /* Do not sense media. */ + unsigned int default_port:4; /* Last dev->if_port value. */ + /* MII transceiver section. */ + int mii_cnt; /* MII device addresses. */ + u16 advertising; /* NWay media advertisement */ + unsigned char phys[2]; /* MII device addresses. */ +}; + +static int eeprom_read(long ioaddr, int location); +static int mdio_read(struct net_device *dev, int phy_id, int location); +static void mdio_write(struct net_device *dev, int phy_id, int location, int value); +static int netdev_open(struct net_device *dev); +static void check_duplex(struct net_device *dev); +static void netdev_timer(unsigned long data); +static void tx_timeout(struct net_device *dev); +static void init_ring(struct net_device *dev); +static int start_tx(struct sk_buff *skb, struct net_device *dev); +static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs); +static void netdev_error(struct net_device *dev, int intr_status); +static int netdev_rx(struct net_device *dev); +static void netdev_error(struct net_device *dev, int intr_status); +static inline unsigned ether_crc(int length, unsigned char *data); +static void set_rx_mode(struct net_device *dev); +static struct net_device_stats *get_stats(struct net_device *dev); +static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static int netdev_close(struct net_device *dev); + + + +static int __devinit w840_probe1 (struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct net_device *dev; + struct netdev_private *np; + static int find_cnt; + int chip_idx = ent->driver_data; + int irq = pdev->irq; + int i, option = find_cnt < MAX_UNITS ? options[find_cnt] : 0; + long ioaddr; + + if (pci_enable_device(pdev)) + return -EIO; + pci_set_master(pdev); + + dev = init_etherdev(NULL, sizeof(*np)); + if (!dev) + return -ENOMEM; + +#ifdef USE_IO_OPS + ioaddr = pci_resource_start(pdev, 0); + if (!request_region(ioaddr, pci_id_tbl[chip_idx].io_size, dev->name)) + goto err_out_netdev; +#else + ioaddr = pci_resource_start(pdev, 1); + if (!request_mem_region(ioaddr, pci_id_tbl[chip_idx].io_size, dev->name)) + goto err_out_netdev; + ioaddr = (long) ioremap (ioaddr, pci_id_tbl[chip_idx].io_size); + if (!ioaddr) + goto err_out_iomem; +#endif + + printk(KERN_INFO "%s: %s at 0x%lx, ", + dev->name, pci_id_tbl[chip_idx].name, ioaddr); + + /* Warning: broken for big-endian machines. */ + for (i = 0; i < 3; i++) + ((u16 *)dev->dev_addr)[i] = le16_to_cpu(eeprom_read(ioaddr, i)); + + for (i = 0; i < 5; i++) + printk("%2.2x:", dev->dev_addr[i]); + printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq); + + /* Reset the chip to erase previous misconfiguration. + No hold time required! */ + writel(0x00000001, ioaddr + PCIBusCfg); + + dev->base_addr = ioaddr; + dev->irq = irq; + + np = dev->priv; + np->chip_id = chip_idx; + np->drv_flags = pci_id_tbl[chip_idx].drv_flags; + spin_lock_init(&np->lock); + + pdev->driver_data = dev; + + if (dev->mem_start) + option = dev->mem_start; + + /* The lower four bits are the media type. */ + if (option > 0) { + if (option & 0x200) + np->full_duplex = 1; + np->default_port = option & 15; + if (np->default_port) + np->medialock = 1; + } + if (find_cnt < MAX_UNITS && full_duplex[find_cnt] > 0) + np->full_duplex = 1; + + if (np->full_duplex) + np->duplex_lock = 1; + + /* The chip-specific entries in the device structure. */ + dev->open = &netdev_open; + dev->hard_start_xmit = &start_tx; + dev->stop = &netdev_close; + dev->get_stats = &get_stats; + dev->set_multicast_list = &set_rx_mode; + dev->do_ioctl = &mii_ioctl; + dev->tx_timeout = &tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; + + if (np->drv_flags & CanHaveMII) { + int phy, phy_idx = 0; + for (phy = 1; phy < 32 && phy_idx < 4; phy++) { + int mii_status = mdio_read(dev, phy, 1); + if (mii_status != 0xffff && mii_status != 0x0000) { + np->phys[phy_idx++] = phy; + np->advertising = mdio_read(dev, phy, 4); + printk(KERN_INFO "%s: MII PHY found at address %d, status " + "0x%4.4x advertising %4.4x.\n", + dev->name, phy, mii_status, np->advertising); + } + } + np->mii_cnt = phy_idx; + if (phy_idx == 0) { + printk(KERN_WARNING "%s: MII PHY not found -- this device may " + "not operate correctly.\n", dev->name); + } + } + + find_cnt++; + return 0; + +#ifndef USE_IO_OPS +err_out_iomem: + release_mem_region(pci_resource_start(pdev, 1), + pci_id_tbl[chip_idx].io_size); +#endif +err_out_netdev: + unregister_netdev (dev); + kfree (dev); + return -ENODEV; +} + + +/* Read the EEPROM and MII Management Data I/O (MDIO) interfaces. These are + often serial bit streams generated by the host processor. + The example below is for the common 93c46 EEPROM, 64 16 bit words. */ + +/* Delay between EEPROM clock transitions. + No extra delay is needed with 33Mhz PCI, but future 66Mhz access may need + a delay. Note that pre-2.0.34 kernels had a cache-alignment bug that + made udelay() unreliable. + The old method of using an ISA access as a delay, __SLOW_DOWN_IO__, is + depricated. +*/ +#define eeprom_delay(ee_addr) readl(ee_addr) + +enum EEPROM_Ctrl_Bits { + EE_ShiftClk=0x02, EE_Write0=0x801, EE_Write1=0x805, + EE_ChipSelect=0x801, EE_DataIn=0x08, +}; + +/* The EEPROM commands include the alway-set leading bit. */ +enum EEPROM_Cmds { + EE_WriteCmd=(5 << 6), EE_ReadCmd=(6 << 6), EE_EraseCmd=(7 << 6), +}; + +static int eeprom_read(long addr, int location) +{ + int i; + int retval = 0; + int ee_addr = addr + EECtrl; + int read_cmd = location | EE_ReadCmd; + writel(EE_ChipSelect, ee_addr); + + /* Shift the read command bits out. */ + for (i = 10; i >= 0; i--) { + short dataval = (read_cmd & (1 << i)) ? EE_Write1 : EE_Write0; + writel(dataval, ee_addr); + eeprom_delay(ee_addr); + writel(dataval | EE_ShiftClk, ee_addr); + eeprom_delay(ee_addr); + } + writel(EE_ChipSelect, ee_addr); + + for (i = 16; i > 0; i--) { + writel(EE_ChipSelect | EE_ShiftClk, ee_addr); + eeprom_delay(ee_addr); + retval = (retval << 1) | ((readl(ee_addr) & EE_DataIn) ? 1 : 0); + writel(EE_ChipSelect, ee_addr); + eeprom_delay(ee_addr); + } + + /* Terminate the EEPROM access. */ + writel(0, ee_addr); + return retval; +} + +/* MII transceiver control section. + Read and write the MII registers using software-generated serial + MDIO protocol. See the MII specifications or DP83840A data sheet + for details. + + The maximum data clock rate is 2.5 Mhz. The minimum timing is usually + met by back-to-back 33Mhz PCI cycles. */ +#define mdio_delay(mdio_addr) readl(mdio_addr) + +/* Set iff a MII transceiver on any interface requires mdio preamble. + This only set with older tranceivers, so the extra + code size of a per-interface flag is not worthwhile. */ +static char mii_preamble_required = 1; + +#define MDIO_WRITE0 (MDIO_EnbOutput) +#define MDIO_WRITE1 (MDIO_DataOut | MDIO_EnbOutput) + +/* Generate the preamble required for initial synchronization and + a few older transceivers. */ +static void mdio_sync(long mdio_addr) +{ + int bits = 32; + + /* Establish sync by sending at least 32 logic ones. */ + while (--bits >= 0) { + writel(MDIO_WRITE1, mdio_addr); + mdio_delay(mdio_addr); + writel(MDIO_WRITE1 | MDIO_ShiftClk, mdio_addr); + mdio_delay(mdio_addr); + } +} + +static int mdio_read(struct net_device *dev, int phy_id, int location) +{ + long mdio_addr = dev->base_addr + MIICtrl; + int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location; + int i, retval = 0; + + if (mii_preamble_required) + mdio_sync(mdio_addr); + + /* Shift the read command bits out. */ + for (i = 15; i >= 0; i--) { + int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0; + + writel(dataval, mdio_addr); + mdio_delay(mdio_addr); + writel(dataval | MDIO_ShiftClk, mdio_addr); + mdio_delay(mdio_addr); + } + /* Read the two transition, 16 data, and wire-idle bits. */ + for (i = 20; i > 0; i--) { + writel(MDIO_EnbIn, mdio_addr); + mdio_delay(mdio_addr); + retval = (retval << 1) | ((readl(mdio_addr) & MDIO_DataIn) ? 1 : 0); + writel(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr); + mdio_delay(mdio_addr); + } + return (retval>>1) & 0xffff; +} + +static void mdio_write(struct net_device *dev, int phy_id, int location, int value) +{ + struct netdev_private *np = (struct netdev_private *)dev->priv; + long mdio_addr = dev->base_addr + MIICtrl; + int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value; + int i; + + if (location == 4 && phy_id == np->phys[0]) + np->advertising = value; + + if (mii_preamble_required) + mdio_sync(mdio_addr); + + /* Shift the command bits out. */ + for (i = 31; i >= 0; i--) { + int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0; + + writel(dataval, mdio_addr); + mdio_delay(mdio_addr); + writel(dataval | MDIO_ShiftClk, mdio_addr); + mdio_delay(mdio_addr); + } + /* Clear out extra bits. */ + for (i = 2; i > 0; i--) { + writel(MDIO_EnbIn, mdio_addr); + mdio_delay(mdio_addr); + writel(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr); + mdio_delay(mdio_addr); + } + return; +} + + +static int netdev_open(struct net_device *dev) +{ + struct netdev_private *np = (struct netdev_private *)dev->priv; + long ioaddr = dev->base_addr; + int i; + + writel(0x00000001, ioaddr + PCIBusCfg); /* Reset */ + + MOD_INC_USE_COUNT; + + if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev)) { + MOD_DEC_USE_COUNT; + return -EAGAIN; + } + + if (debug > 1) + printk(KERN_DEBUG "%s: w89c840_open() irq %d.\n", + dev->name, dev->irq); + + init_ring(dev); + + writel(virt_to_bus(np->rx_ring), ioaddr + RxRingPtr); + writel(virt_to_bus(np->tx_ring), ioaddr + TxRingPtr); + + for (i = 0; i < 6; i++) + writeb(dev->dev_addr[i], ioaddr + StationAddr + i); + + /* Initialize other registers. */ + /* Configure the PCI bus bursts and FIFO thresholds. + 486: Set 8 longword cache alignment, 8 longword burst. + 586: Set 16 longword cache alignment, no burst limit. + Cache alignment bits 15:14 Burst length 13:8 + 0000 0000 align to cache 0800 8 longwords + 4000 8 longwords 0100 1 longword 1000 16 longwords + 8000 16 longwords 0200 2 longwords 2000 32 longwords + C000 32 longwords 0400 4 longwords + Wait the specified 50 PCI cycles after a reset by initializing + Tx and Rx queues and the address filter list. */ +#if defined(__powerpc__) /* Big-endian */ + writel(0x00100080 | 0xE010, ioaddr + PCIBusCfg); +#elif defined(__alpha__) + writel(0xE010, ioaddr + PCIBusCfg); +#elif defined(__i386__) +#if defined(MODULE) + writel(0xE010, ioaddr + PCIBusCfg); +#else + /* When not a module we can work around broken '486 PCI boards. */ +#define x86 boot_cpu_data.x86 + writel((x86 <= 4 ? 0x4810 : 0xE010), ioaddr + PCIBusCfg); + if (x86 <= 4) + printk(KERN_INFO "%s: This is a 386/486 PCI system, setting cache " + "alignment to %x.\n", dev->name, + (x86 <= 4 ? 0x4810 : 0x8010)); +#endif +#else + writel(0xE010, ioaddr + PCIBusCfg); +#warning Processor architecture undefined! +#endif + + if (dev->if_port == 0) + dev->if_port = np->default_port; + + writel(0, ioaddr + RxStartDemand); + np->csr6 = 0x20022002; + check_duplex(dev); + set_rx_mode(dev); + + netif_start_queue(dev); + + /* Clear and Enable interrupts by setting the interrupt mask. */ + writel(0x1A0F5, ioaddr + IntrStatus); + writel(0x1A0F5, ioaddr + IntrEnable); + + if (debug > 2) + printk(KERN_DEBUG "%s: Done netdev_open().\n", dev->name); + + /* Set the timer to check for link beat. */ + init_timer(&np->timer); + np->timer.expires = jiffies + 3*HZ; + np->timer.data = (unsigned long)dev; + np->timer.function = &netdev_timer; /* timer handler */ + add_timer(&np->timer); + + return 0; +} + +static void check_duplex(struct net_device *dev) +{ + struct netdev_private *np = (struct netdev_private *)dev->priv; + int mii_reg5 = mdio_read(dev, np->phys[0], 5); + int negotiated = mii_reg5 & np->advertising; + int duplex; + + if (np->duplex_lock || mii_reg5 == 0xffff) + return; + duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040; + if (np->full_duplex != duplex) { + np->full_duplex = duplex; + if (debug) + printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d " + "negotiated capability %4.4x.\n", dev->name, + duplex ? "full" : "half", np->phys[0], negotiated); + np->csr6 &= ~0x200; + np->csr6 |= duplex ? 0x200 : 0; + } +} + +static void netdev_timer(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct netdev_private *np = (struct netdev_private *)dev->priv; + long ioaddr = dev->base_addr; + int next_tick = 10*HZ; + int old_csr6 = np->csr6; + + if (debug > 2) + printk(KERN_DEBUG "%s: Media selection timer tick, status %8.8x " + "config %8.8x.\n", + dev->name, (int)readl(ioaddr + IntrStatus), + (int)readl(ioaddr + NetworkConfig)); + check_duplex(dev); + if (np->csr6 != old_csr6) { + writel(np->csr6 & ~0x0002, ioaddr + NetworkConfig); + writel(np->csr6 | 0x2002, ioaddr + NetworkConfig); + } + np->timer.expires = jiffies + next_tick; + add_timer(&np->timer); +} + +static void tx_timeout(struct net_device *dev) +{ + struct netdev_private *np = (struct netdev_private *)dev->priv; + long ioaddr = dev->base_addr; + + printk(KERN_WARNING "%s: Transmit timed out, status %8.8x," + " resetting...\n", dev->name, (int)readl(ioaddr + IntrStatus)); + +#ifndef __alpha__ + { + int i; + printk(KERN_DEBUG " Rx ring %8.8x: ", (int)np->rx_ring); + for (i = 0; i < RX_RING_SIZE; i++) + printk(" %8.8x", (unsigned int)np->rx_ring[i].status); + printk("\n"KERN_DEBUG" Tx ring %8.8x: ", (int)np->tx_ring); + for (i = 0; i < TX_RING_SIZE; i++) + printk(" %4.4x", np->tx_ring[i].status); + printk("\n"); + } +#endif + + /* Perhaps we should reinitialize the hardware here. Just trigger a + Tx demand for now. */ + writel(0, ioaddr + TxStartDemand); + dev->if_port = 0; + /* Stop and restart the chip's Tx processes . */ + + dev->trans_start = jiffies; + np->stats.tx_errors++; + return; +} + + +/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ +static void init_ring(struct net_device *dev) +{ + struct netdev_private *np = (struct netdev_private *)dev->priv; + int i; + + np->tx_full = 0; + np->tx_q_bytes = np->cur_rx = np->cur_tx = 0; + np->dirty_rx = np->dirty_tx = 0; + + np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32); + np->rx_head_desc = &np->rx_ring[0]; + + /* Initial all Rx descriptors. */ + for (i = 0; i < RX_RING_SIZE; i++) { + np->rx_ring[i].length = cpu_to_le32(np->rx_buf_sz); + np->rx_ring[i].status = 0; + np->rx_ring[i].next_desc = virt_to_le32desc(&np->rx_ring[i+1]); + np->rx_skbuff[i] = 0; + } + /* Mark the last entry as wrapping the ring. */ + np->rx_ring[i-1].length |= cpu_to_le32(DescEndRing); + np->rx_ring[i-1].next_desc = virt_to_le32desc(&np->rx_ring[0]); + + /* Fill in the Rx buffers. Handle allocation failure gracefully. */ + for (i = 0; i < RX_RING_SIZE; i++) { + struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz); + np->rx_skbuff[i] = skb; + if (skb == NULL) + break; + skb->dev = dev; /* Mark as being used by this device. */ + np->rx_ring[i].buffer1 = virt_to_le32desc(skb->tail); + np->rx_ring[i].status = cpu_to_le32(DescOwn | DescIntr); + } + np->dirty_rx = (unsigned int)(i - RX_RING_SIZE); + + for (i = 0; i < TX_RING_SIZE; i++) { + np->tx_skbuff[i] = 0; + np->tx_ring[i].status = 0; + } + return; +} + +static int start_tx(struct sk_buff *skb, struct net_device *dev) +{ + struct netdev_private *np = (struct netdev_private *)dev->priv; + unsigned entry; + + /* Caution: the write order is important here, set the field + with the "ownership" bits last. */ + + /* Calculate the next Tx descriptor entry. */ + entry = np->cur_tx % TX_RING_SIZE; + + np->tx_skbuff[entry] = skb; + np->tx_ring[entry].buffer1 = virt_to_le32desc(skb->data); + +#define one_buffer +#define BPT 1022 +#if defined(one_buffer) + np->tx_ring[entry].length = cpu_to_le32(DescWholePkt | skb->len); + if (entry >= TX_RING_SIZE-1) /* Wrap ring */ + np->tx_ring[entry].length |= cpu_to_le32(DescIntr | DescEndRing); + np->tx_ring[entry].status = cpu_to_le32(DescOwn); + np->cur_tx++; +#elif defined(two_buffer) + if (skb->len > BPT) { + unsigned int entry1 = ++np->cur_tx % TX_RING_SIZE; + np->tx_ring[entry].length = cpu_to_le32(DescStartPkt | BPT); + np->tx_ring[entry1].length = cpu_to_le32(DescEndPkt | (skb->len - BPT)); + np->tx_ring[entry1].buffer1 = virt_to_le32desc((skb->data) + BPT); + np->tx_ring[entry1].status = cpu_to_le32(DescOwn); + np->tx_ring[entry].status = cpu_to_le32(DescOwn); + if (entry >= TX_RING_SIZE-1) + np->tx_ring[entry].length |= cpu_to_le32(DescIntr|DescEndRing); + else if (entry1 >= TX_RING_SIZE-1) + np->tx_ring[entry1].length |= cpu_to_le32(DescIntr|DescEndRing); + np->cur_tx++; + } else { + np->tx_ring[entry].length = cpu_to_le32(DescWholePkt | skb->len); + if (entry >= TX_RING_SIZE-1) /* Wrap ring */ + np->tx_ring[entry].length |= cpu_to_le32(DescIntr | DescEndRing); + np->tx_ring[entry].status = cpu_to_le32(DescOwn); + np->cur_tx++; + } +#elif defined(split_buffer) + { + /* Work around the Tx-FIFO-full bug by splitting our transmit packet + into two pieces, the first which may be loaded without overflowing + the FIFO, and the second which contains the remainder of the + packet. When we get a Tx-done interrupt that frees enough room + in the FIFO we mark the remainder of the packet as loadable. + + This has the problem that the Tx descriptors are written both + here and in the interrupt handler. + */ + + int buf1size = TX_FIFO_SIZE - np->tx_q_bytes; + int buf2size = skb->len - buf1size; + + if (buf2size <= 0) { /* We fit into one descriptor. */ + np->tx_ring[entry].length = cpu_to_le32(DescWholePkt | skb->len); + } else { /* We must use two descriptors. */ + unsigned int entry2; + np->tx_ring[entry].length = + cpu_to_le32(DescIntr | DescStartPkt | buf1size); + if (entry >= TX_RING_SIZE-1) { /* Wrap ring */ + np->tx_ring[entry].length |= cpu_to_le32(DescEndRing); + entry2 = 0; + } else + entry2 = entry + 1; + np->cur_tx++; + np->tx_ring[entry2].buffer1 = + virt_to_le32desc(skb->data + buf1size); + np->tx_ring[entry2].length = cpu_to_le32(DescEndPkt | buf2size); + if (entry2 >= TX_RING_SIZE-1) /* Wrap ring */ + np->tx_ring[entry2].length |= cpu_to_le32(DescEndRing); + } + np->tx_ring[entry].status = cpu_to_le32(DescOwn); + np->cur_tx++; + } +#endif + np->tx_q_bytes += skb->len; + writel(0, dev->base_addr + TxStartDemand); + + /* Work around horrible bug in the chip by marking the queue as full + when we do not have FIFO room for a maximum sized packet. */ + if (np->cur_tx - np->dirty_tx > TX_QUEUE_LEN) + np->tx_full = 1; + else if ((np->drv_flags & HasBrokenTx) + && np->tx_q_bytes > TX_BUG_FIFO_LIMIT) + np->tx_full = 1; + if (np->tx_full) + netif_stop_queue(dev); + + dev->trans_start = jiffies; + + if (debug > 4) { + printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n", + dev->name, np->cur_tx, entry); + } + return 0; +} + +/* The interrupt handler does all of the Rx thread work and cleans up + after the Tx thread. */ +static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) +{ + struct net_device *dev = (struct net_device *)dev_instance; + struct netdev_private *np = (struct netdev_private *)dev->priv; + long ioaddr = dev->base_addr; + int work_limit = max_interrupt_work; + + spin_lock(&np->lock); + + do { + u32 intr_status = readl(ioaddr + IntrStatus); + + /* Acknowledge all of the current interrupt sources ASAP. */ + writel(intr_status & 0x001ffff, ioaddr + IntrStatus); + + if (debug > 4) + printk(KERN_DEBUG "%s: Interrupt, status %4.4x.\n", + dev->name, intr_status); + + if ((intr_status & (NormalIntr|AbnormalIntr)) == 0) + break; + + if (intr_status & (IntrRxDone | RxNoBuf)) + netdev_rx(dev); + + for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) { + int entry = np->dirty_tx % TX_RING_SIZE; + int tx_status = le32_to_cpu(np->tx_ring[entry].status); + + if (tx_status < 0) + break; + if (tx_status & 0x8000) { /* There was an error, log it. */ +#ifndef final_version + if (debug > 1) + printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n", + dev->name, tx_status); +#endif + np->stats.tx_errors++; + if (tx_status & 0x0104) np->stats.tx_aborted_errors++; + if (tx_status & 0x0C80) np->stats.tx_carrier_errors++; + if (tx_status & 0x0200) np->stats.tx_window_errors++; + if (tx_status & 0x0002) np->stats.tx_fifo_errors++; + if ((tx_status & 0x0080) && np->full_duplex == 0) + np->stats.tx_heartbeat_errors++; +#ifdef ETHER_STATS + if (tx_status & 0x0100) np->stats.collisions16++; +#endif + } else { +#ifdef ETHER_STATS + if (tx_status & 0x0001) np->stats.tx_deferred++; +#endif + np->stats.tx_bytes += np->tx_skbuff[entry]->len; + np->stats.collisions += (tx_status >> 3) & 15; + np->stats.tx_packets++; + } + /* Free the original skb. */ + np->tx_q_bytes -= np->tx_skbuff[entry]->len; + dev_kfree_skb_irq(np->tx_skbuff[entry]); + np->tx_skbuff[entry] = 0; + } + if (np->tx_full && + np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4 + && np->tx_q_bytes < TX_BUG_FIFO_LIMIT) { + /* The ring is no longer full, clear tbusy. */ + np->tx_full = 0; + netif_wake_queue(dev); + } + + /* Abnormal error summary/uncommon events handlers. */ + if (intr_status & (AbnormalIntr | TxFIFOUnderflow | IntrPCIErr | + TimerInt | IntrTxStopped)) + netdev_error(dev, intr_status); + + if (--work_limit < 0) { + printk(KERN_WARNING "%s: Too much work at interrupt, " + "status=0x%4.4x.\n", dev->name, intr_status); + /* Set the timer to re-enable the other interrupts after + 10*82usec ticks. */ + writel(AbnormalIntr | TimerInt, ioaddr + IntrEnable); + writel(10, ioaddr + GPTimer); + break; + } + } while (1); + + if (debug > 3) + printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", + dev->name, (int)readl(ioaddr + IntrStatus)); + + spin_unlock(&np->lock); +} + +/* This routine is logically part of the interrupt handler, but separated + for clarity and better register allocation. */ +static int netdev_rx(struct net_device *dev) +{ + struct netdev_private *np = (struct netdev_private *)dev->priv; + int entry = np->cur_rx % RX_RING_SIZE; + int work_limit = np->dirty_rx + RX_RING_SIZE - np->cur_rx; + + if (debug > 4) { + printk(KERN_DEBUG " In netdev_rx(), entry %d status %4.4x.\n", + entry, np->rx_ring[entry].status); + } + + /* If EOP is set on the next entry, it's a new packet. Send it up. */ + while (--work_limit >= 0) { + struct w840_rx_desc *desc = np->rx_head_desc; + s32 status = le32_to_cpu(desc->status); + + if (debug > 4) + printk(KERN_DEBUG " netdev_rx() status was %8.8x.\n", + status); + if (status < 0) + break; + if ((status & 0x38008300) != 0x0300) { + if ((status & 0x38000300) != 0x0300) { + /* Ingore earlier buffers. */ + if ((status & 0xffff) != 0x7fff) { + printk(KERN_WARNING "%s: Oversized Ethernet frame spanned " + "multiple buffers, entry %#x status %4.4x!\n", + dev->name, np->cur_rx, status); + np->stats.rx_length_errors++; + } + } else if (status & 0x8000) { + /* There was a fatal error. */ + if (debug > 2) + printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n", + dev->name, status); + np->stats.rx_errors++; /* end of a packet.*/ + if (status & 0x0890) np->stats.rx_length_errors++; + if (status & 0x004C) np->stats.rx_frame_errors++; + if (status & 0x0002) np->stats.rx_crc_errors++; + } + } else { + struct sk_buff *skb; + /* Omit the four octet CRC from the length. */ + int pkt_len = ((status >> 16) & 0x7ff) - 4; + +#ifndef final_version + if (debug > 4) + printk(KERN_DEBUG " netdev_rx() normal Rx pkt length %d" + " status %x.\n", pkt_len, status); +#endif + /* Check if the packet is long enough to accept without copying + to a minimally-sized skbuff. */ + if (pkt_len < rx_copybreak + && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { + skb->dev = dev; + skb_reserve(skb, 2); /* 16 byte align the IP header */ + /* Call copy + cksum if available. */ +#if HAS_IP_COPYSUM + eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0); + skb_put(skb, pkt_len); +#else + memcpy(skb_put(skb, pkt_len), np->rx_skbuff[entry]->tail, + pkt_len); +#endif + } else { + char *temp = skb_put(skb = np->rx_skbuff[entry], pkt_len); + np->rx_skbuff[entry] = NULL; +#ifndef final_version /* Remove after testing. */ + if (le32desc_to_virt(desc->buffer1) != temp) + printk(KERN_ERR "%s: Internal fault: The skbuff addresses " + "do not match in netdev_rx: %p vs. %p / %p.\n", + dev->name, le32desc_to_virt(desc->buffer1), + skb->head, temp); +#endif + } +#ifndef final_version /* Remove after testing. */ + /* You will want this info for the initial debug. */ + if (debug > 5) + printk(KERN_DEBUG " Rx data %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:" + "%2.2x %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x %2.2x%2.2x " + "%d.%d.%d.%d.\n", + skb->data[0], skb->data[1], skb->data[2], skb->data[3], + skb->data[4], skb->data[5], skb->data[6], skb->data[7], + skb->data[8], skb->data[9], skb->data[10], + skb->data[11], skb->data[12], skb->data[13], + skb->data[14], skb->data[15], skb->data[16], + skb->data[17]); +#endif + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); + dev->last_rx = jiffies; + np->stats.rx_packets++; + np->stats.rx_bytes += pkt_len; + } + entry = (++np->cur_rx) % RX_RING_SIZE; + np->rx_head_desc = &np->rx_ring[entry]; + } + + /* Refill the Rx ring buffers. */ + for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) { + struct sk_buff *skb; + entry = np->dirty_rx % RX_RING_SIZE; + if (np->rx_skbuff[entry] == NULL) { + skb = dev_alloc_skb(np->rx_buf_sz); + np->rx_skbuff[entry] = skb; + if (skb == NULL) + break; /* Better luck next round. */ + skb->dev = dev; /* Mark as being used by this device. */ + np->rx_ring[entry].buffer1 = virt_to_le32desc(skb->tail); + } + np->rx_ring[entry].status = cpu_to_le32(DescOwn); + } + + return 0; +} + +static void netdev_error(struct net_device *dev, int intr_status) +{ + long ioaddr = dev->base_addr; + struct netdev_private *np = (struct netdev_private *)dev->priv; + + if (debug > 2) + printk(KERN_DEBUG "%s: Abnormal event, %8.8x.\n", + dev->name, intr_status); + if (intr_status == 0xffffffff) + return; + if (intr_status & TxFIFOUnderflow) { + np->csr6 += 0x4000; /* Bump up the Tx threshold */ + printk(KERN_DEBUG "%s: Tx underflow, increasing threshold to %8.8x.\n", + dev->name, np->csr6); + writel(np->csr6, ioaddr + NetworkConfig); + } + if (intr_status & IntrRxDied) { /* Missed a Rx frame. */ + np->stats.rx_errors++; + } + if (intr_status & TimerInt) { + /* Re-enable other interrupts. */ + writel(0x1A0F5, ioaddr + IntrEnable); + } + np->stats.rx_missed_errors += readl(ioaddr + RxMissed) & 0xffff; + writel(0, ioaddr + RxStartDemand); +} + +static struct net_device_stats *get_stats(struct net_device *dev) +{ + long ioaddr = dev->base_addr; + struct netdev_private *np = (struct netdev_private *)dev->priv; + + /* The chip only need report frame silently dropped. */ + if (netif_running(dev)) + np->stats.rx_missed_errors += readl(ioaddr + RxMissed) & 0xffff; + + return &np->stats; +} + +static unsigned const ethernet_polynomial = 0x04c11db7U; +static inline u32 ether_crc(int length, unsigned char *data) +{ + int crc = -1; + + while(--length >= 0) { + unsigned char current_octet = *data++; + int bit; + for (bit = 0; bit < 8; bit++, current_octet >>= 1) { + crc = (crc << 1) ^ + ((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0); + } + } + return crc; +} + +static void set_rx_mode(struct net_device *dev) +{ + struct netdev_private *np = (struct netdev_private *)dev->priv; + long ioaddr = dev->base_addr; + u32 mc_filter[2]; /* Multicast hash filter */ + u32 rx_mode; + + if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ + /* Unconditionally log net taps. */ + printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name); + memset(mc_filter, 0xff, sizeof(mc_filter)); + rx_mode = AcceptBroadcast | AcceptMulticast | AcceptAllPhys + | AcceptMyPhys; + } else if ((dev->mc_count > multicast_filter_limit) + || (dev->flags & IFF_ALLMULTI)) { + /* Too many to match, or accept all multicasts. */ + memset(mc_filter, 0xff, sizeof(mc_filter)); + rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; + } else { + struct dev_mc_list *mclist; + int i; + memset(mc_filter, 0, sizeof(mc_filter)); + for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + i++, mclist = mclist->next) { + set_bit((ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26) ^ 0x3F, + mc_filter); + } + rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; + } + writel(mc_filter[0], ioaddr + MulticastFilter0); + writel(mc_filter[1], ioaddr + MulticastFilter1); + np->csr6 &= ~0x00F8; + np->csr6 |= rx_mode; + writel(np->csr6, ioaddr + NetworkConfig); +} + +static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + u16 *data = (u16 *)&rq->ifr_data; + + switch(cmd) { + case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ + data[0] = ((struct netdev_private *)dev->priv)->phys[0] & 0x1f; + /* Fall Through */ + case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ + data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f); + return 0; + case SIOCDEVPRIVATE+2: /* Write the specified MII register */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]); + return 0; + default: + return -EOPNOTSUPP; + } +} + +static int netdev_close(struct net_device *dev) +{ + long ioaddr = dev->base_addr; + struct netdev_private *np = (struct netdev_private *)dev->priv; + int i; + + netif_stop_queue(dev); + + if (debug > 1) { + printk(KERN_DEBUG "%s: Shutting down ethercard, status was %8.8x " + "Config %8.8x.\n", dev->name, (int)readl(ioaddr + IntrStatus), + (int)readl(ioaddr + NetworkConfig)); + printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d, Rx %d / %d.\n", + dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx); + } + + /* Disable interrupts by clearing the interrupt mask. */ + writel(0x0000, ioaddr + IntrEnable); + + /* Stop the chip's Tx and Rx processes. */ + writel(np->csr6 &= ~0x20FA, ioaddr + NetworkConfig); + + if (readl(ioaddr + NetworkConfig) != 0xffffffff) + np->stats.rx_missed_errors += readl(ioaddr + RxMissed) & 0xffff; + +#ifdef __i386__ + if (debug > 2) { + printk("\n"KERN_DEBUG" Tx ring at %8.8x:\n", + (int)virt_to_le32desc(np->tx_ring)); + for (i = 0; i < TX_RING_SIZE; i++) + printk(" #%d desc. %4.4x %4.4x %8.8x.\n", + i, np->tx_ring[i].length, + np->tx_ring[i].status, np->tx_ring[i].buffer1); + printk("\n"KERN_DEBUG " Rx ring %8.8x:\n", + (int)virt_to_le32desc(np->rx_ring)); + for (i = 0; i < RX_RING_SIZE; i++) { + printk(KERN_DEBUG " #%d desc. %4.4x %4.4x %8.8x\n", + i, np->rx_ring[i].length, + np->rx_ring[i].status, np->rx_ring[i].buffer1); + } + } +#endif /* __i386__ debugging only */ + + free_irq(dev->irq, dev); + + del_timer_sync(&np->timer); + + /* Free all the skbuffs in the Rx queue. */ + for (i = 0; i < RX_RING_SIZE; i++) { + np->rx_ring[i].status = 0; + if (np->rx_skbuff[i]) { + dev_kfree_skb(np->rx_skbuff[i]); + } + np->rx_skbuff[i] = 0; + } + for (i = 0; i < TX_RING_SIZE; i++) { + if (np->tx_skbuff[i]) + dev_kfree_skb(np->tx_skbuff[i]); + np->tx_skbuff[i] = 0; + } + + MOD_DEC_USE_COUNT; + + return 0; +} + +static void __devexit w840_remove1 (struct pci_dev *pdev) +{ + struct net_device *dev = pdev->driver_data; + + /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ + while (dev) { + struct netdev_private *np = (void *)(dev->priv); + unregister_netdev(dev); +#ifdef USE_IO_OPS + release_region(dev->base_addr, pci_id_tbl[np->chip_id].io_size); +#else + release_mem_region(pci_resource_start(pdev, 1), + pci_id_tbl[np->chip_id].io_size); + iounmap((char *)(dev->base_addr)); +#endif + kfree(dev); + } + + pdev->driver_data = NULL; +} + +static struct pci_driver w840_driver = { + name: "winbond-840", + id_table: w840_pci_tbl, + probe: w840_probe1, + remove: w840_remove1, +}; + +static int __init w840_init(void) +{ + return pci_module_init(&w840_driver); +} + +static void __exit w840_exit(void) +{ + pci_unregister_driver(&w840_driver); +} + +module_init(w840_init); +module_exit(w840_exit); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/parport/ChangeLog linux/drivers/parport/ChangeLog --- v2.4.0-test8/linux/drivers/parport/ChangeLog Mon Jul 24 18:59:27 2000 +++ linux/drivers/parport/ChangeLog Sun Sep 17 09:45:07 2000 @@ -1,3 +1,8 @@ +2000-09-16 Cesar Eduardo Barros + + * parport_pc.c (sio_via_686a_probe): Handle case + where hardware returns 255 for IRQ or DMA. + 2000-07-20 Eddie C. Dost * share.c (attach_driver_chain): attach[i](port) needs to be diff -u --recursive --new-file v2.4.0-test8/linux/drivers/parport/parport_pc.c linux/drivers/parport/parport_pc.c --- v2.4.0-test8/linux/drivers/parport/parport_pc.c Sun Aug 6 11:24:58 2000 +++ linux/drivers/parport/parport_pc.c Sun Sep 17 09:45:07 2000 @@ -2239,11 +2239,13 @@ irq = ((irq >> 4) & 0x0F); /* filter bogus IRQs */ + /* 255 means NONE, and is bogus as well */ switch (irq) { case 0: case 2: case 8: case 13: + case 255: irq = PARPORT_IRQ_NONE; break; @@ -2252,7 +2254,9 @@ } /* if ECP not enabled, DMA is not enabled, assumed bogus 'dma' value */ - if (!have_eppecp) + /* 255 means NONE. Looks like some BIOS don't set the DMA correctly + * even on ECP mode */ + if (!have_eppecp || dma == 255) dma = PARPORT_DMA_NONE; /* finally, do the probe with values obtained */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/pci/names.c linux/drivers/pci/names.c --- v2.4.0-test8/linux/drivers/pci/names.c Mon Jan 3 11:15:05 2000 +++ linux/drivers/pci/names.c Mon Oct 2 12:00:16 2000 @@ -131,4 +131,5 @@ return NULL; } -#endif +#endif /* CONFIG_PCI_NAMES */ + diff -u --recursive --new-file v2.4.0-test8/linux/drivers/pci/pci.c linux/drivers/pci/pci.c --- v2.4.0-test8/linux/drivers/pci/pci.c Mon Jun 19 13:42:38 2000 +++ linux/drivers/pci/pci.c Wed Sep 20 13:34:06 2000 @@ -657,134 +657,89 @@ return child; } -/* - * A CardBus bridge is basically the same as a regular PCI bridge, - * except we don't scan behind it because it will be changing. - */ -static int __init pci_scan_cardbus(struct pci_bus *bus, struct pci_dev *dev, int busnr) -{ - int i; - unsigned short cr; - unsigned int buses; - struct pci_bus *child; - - /* - * Insert it into the tree of buses. - */ - DBG("Scanning CardBus bridge %s\n", dev->slot_name); - child = pci_add_new_bus(bus, dev, ++busnr); - - for (i = 0; i < 4; i++) - child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i]; - - /* - * Maybe we'll have another bus behind this one? - */ - child->subordinate = ++busnr; - sprintf(child->name, "PCI CardBus #%02x", child->number); - - /* - * Clear all status bits and turn off memory, - * I/O and master enables. - */ - pci_read_config_word(dev, PCI_COMMAND, &cr); - pci_write_config_word(dev, PCI_COMMAND, 0x0000); - pci_write_config_word(dev, PCI_STATUS, 0xffff); - - /* - * Read the existing primary/secondary/subordinate bus - * number configuration to determine if the bridge - * has already been configured by the system. If so, - * do not modify the configuration, merely note it. - */ - pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses); - if ((buses & 0xFFFFFF) != 0 && ! pcibios_assign_all_busses()) { - child->primary = buses & 0xFF; - child->secondary = (buses >> 8) & 0xFF; - child->subordinate = (buses >> 16) & 0xFF; - child->number = child->secondary; - if (child->subordinate > busnr) - busnr = child->subordinate; - } else { - /* - * Configure the bus numbers for this bridge: - */ - buses &= 0xff000000; - buses |= - (((unsigned int)(child->primary) << 0) | - ((unsigned int)(child->secondary) << 8) | - ((unsigned int)(child->subordinate) << 16)); - pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses); - } - pci_write_config_word(dev, PCI_COMMAND, cr); - return busnr; -} - static unsigned int __init pci_do_scan_bus(struct pci_bus *bus); /* - * If it's a bridge, scan the bus behind it. + * If it's a bridge, configure it and scan the bus behind it. + * For CardBus bridges, we don't scan behind as the devices will + * be handled by the bridge driver itself. + * + * We need to process bridges in two passes -- first we scan those + * already configured by the BIOS and after we are done with all of + * them, we proceed to assigning numbers to the remaining buses in + * order to avoid overlaps between old and new bus numbers. */ -static int __init pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max) +static int __init pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass) { unsigned int buses; unsigned short cr; struct pci_bus *child; + int is_cardbus = (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS); - /* - * Insert it into the tree of buses. - */ - DBG("Scanning behind PCI bridge %s\n", dev->slot_name); - child = pci_add_new_bus(bus, dev, ++max); - sprintf(child->name, "PCI Bus #%02x", child->number); - - /* - * Clear all status bits and turn off memory, - * I/O and master enables. - */ - pci_read_config_word(dev, PCI_COMMAND, &cr); - pci_write_config_word(dev, PCI_COMMAND, 0x0000); - pci_write_config_word(dev, PCI_STATUS, 0xffff); - - /* - * Read the existing primary/secondary/subordinate bus - * number configuration to determine if the PCI bridge - * has already been configured by the system. If so, - * do not modify the configuration, merely note it. - */ pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses); - if ((buses & 0xFFFFFF) != 0 && ! pcibios_assign_all_busses()) { - unsigned int cmax; + DBG("Scanning behind PCI bridge %s, config %06x, pass %d\n", dev->slot_name, buses & 0xffffff, pass); + if ((buses & 0xffffff) && !pcibios_assign_all_busses()) { + /* + * Bus already configured by firmware, process it in the first + * pass and just note the configuration. + */ + if (pass) + return max; + child = pci_add_new_bus(bus, dev, 0); child->primary = buses & 0xFF; child->secondary = (buses >> 8) & 0xFF; child->subordinate = (buses >> 16) & 0xFF; child->number = child->secondary; - cmax = pci_do_scan_bus(child); - if (cmax > max) max = cmax; + if (!is_cardbus) { + unsigned int cmax = pci_do_scan_bus(child); + if (cmax > max) max = cmax; + } else { + int i; + for (i = 0; i < 4; i++) + child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i]; + } } else { /* - * Configure the bus numbers for this bridge: + * We need to assign a number to this bus which we always + * do in the second pass. We also keep all address decoders + * on the bridge disabled during scanning. FIXME: Why? */ - buses &= 0xff000000; - buses |= - (((unsigned int)(child->primary) << 0) | - ((unsigned int)(child->secondary) << 8) | - ((unsigned int)(child->subordinate) << 16)); - pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses); + if (!pass) + return max; + pci_read_config_word(dev, PCI_COMMAND, &cr); + pci_write_config_word(dev, PCI_COMMAND, 0x0000); + pci_write_config_word(dev, PCI_STATUS, 0xffff); + child = pci_add_new_bus(bus, dev, ++max); + buses = (buses & 0xff000000) + | ((unsigned int)(child->primary) << 0) + | ((unsigned int)(child->secondary) << 8) + | ((unsigned int)(child->subordinate) << 16); /* - * Now we can scan all subordinate buses: + * We need to blast all three values with a single write. */ - max = pci_do_scan_bus(child); + pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses); + if (!is_cardbus) { + /* Now we can scan all subordinate buses... */ + max = pci_do_scan_bus(child); + } else { + int i; + /* + * For CardBus bridges, we leave 4 bus numbers + * as cards with a PCI-to-PCI bridge can be + * inserted later. + */ + max += 3; + for (i = 0; i < 4; i++) + child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i]; + } /* - * Set the subordinate bus number to its real - * value: + * Set the subordinate bus number to its real value. */ child->subordinate = max; - buses = (buses & 0xff00ffff) - | ((unsigned int)(child->subordinate) << 16); - pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses); + pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, max); + pci_write_config_word(dev, PCI_COMMAND, cr); } - pci_write_config_word(dev, PCI_COMMAND, cr); + sprintf(child->name, (is_cardbus ? "PCI CardBus #%02x" : "PCI Bus #%02x"), child->number); return max; } @@ -933,7 +888,7 @@ static unsigned int __init pci_do_scan_bus(struct pci_bus *bus) { - unsigned int devfn, max; + unsigned int devfn, max, pass; struct list_head *ln; struct pci_dev *dev, dev0; @@ -957,17 +912,12 @@ */ DBG("Fixups for bus %02x\n", bus->number); pcibios_fixup_bus(bus); - for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) { - dev = pci_dev_b(ln); - switch (dev->class >> 8) { - case PCI_CLASS_BRIDGE_PCI: - max = pci_scan_bridge(bus, dev, max); - break; - case PCI_CLASS_BRIDGE_CARDBUS: - max = pci_scan_cardbus(bus, dev, max); - break; + for (pass=0; pass < 2; pass++) + for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) { + dev = pci_dev_b(ln); + if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) + max = pci_scan_bridge(bus, dev, max, pass); } - } /* * We've scanned the bus and so we know all about what's on diff -u --recursive --new-file v2.4.0-test8/linux/drivers/pci/pci.ids linux/drivers/pci/pci.ids --- v2.4.0-test8/linux/drivers/pci/pci.ids Sun Aug 13 19:37:15 2000 +++ linux/drivers/pci/pci.ids Thu Sep 21 15:55:32 2000 @@ -1471,9 +1471,9 @@ 6055 3c556 Laptop Hurricane 5057 3c575 [Megahertz] 10/100 LAN CardBus 10b7 5a57 3C575 Megahertz 10/100 LAN Cardbus PC Card - 5157 3c575 [Megahertz] 10/100 LAN CardBus + 5157 3CCFE575BT Cyclone CardBus 10b7 5b57 3C575 Megahertz 10/100 LAN Cardbus PC Card - 5257 3CCFE575CT Cyclone CardBus + 5257 3CCFE575CT Tornado CardBus 5900 3c590 10BaseT [Vortex] 5920 3c592 EISA 10mbps Demon/Vortex 5950 3c595 100BaseTX [Vortex] @@ -1483,8 +1483,8 @@ 5b57 3c595 [Megahertz] 10/100 LAN CardBus 10b7 5b57 3C575 Megahertz 10/100 LAN Cardbus PC Card 6560 3CCFE656 Cyclone CardBus - 6562 3CCFEM656 [id 6562] Cyclone CardBus - 6564 3CCFEM656 [id 6564] Cyclone CardBus + 6562 3CCFEM656B Cyclone CardBus + 6564 3CXFEM656C Tornado CardBus 7646 3cSOHO100-TX Hurricane 8811 Token ring 9000 3c900 10BaseT [Boomerang] @@ -2694,6 +2694,10 @@ 0105 Cyclom_8Y above first megabyte 0200 Cyclom_Z below first megabyte 0201 Cyclom_Z above first megabyte + 0300 PC300 RX 2 + 0301 PC300 RX 1 + 0310 PC300 TE 2 + 0311 PC300 TE 1 120f Essential Communications 0001 Roadrunner serial HIPPI 1210 Hyperparallel Technologies @@ -2752,6 +2756,7 @@ 121a 0060 Voodoo3 3500 TV (NTSC) 121a 0061 Voodoo3 3500 TV (PAL) 121a 0062 Voodoo3 3500 TV (SECAM) + 0009 Voodoo 4 121b Advanced Telecommunications Modules 121c Nippon Texaco., Ltd 121d Lippert Automationstechnik GmbH diff -u --recursive --new-file v2.4.0-test8/linux/drivers/pci/proc.c linux/drivers/pci/proc.c --- v2.4.0-test8/linux/drivers/pci/proc.c Mon Aug 21 09:07:15 2000 +++ linux/drivers/pci/proc.c Mon Sep 18 17:36:14 2000 @@ -46,8 +46,8 @@ const struct inode *ino = file->f_dentry->d_inode; const struct proc_dir_entry *dp = ino->u.generic_ip; struct pci_dev *dev = dp->data; - int pos = *ppos; - int cnt, size; + unsigned int pos = *ppos; + unsigned int cnt, size; /* * Normal users can read only the standardized portion of the diff -u --recursive --new-file v2.4.0-test8/linux/drivers/pci/quirks.c linux/drivers/pci/quirks.c --- v2.4.0-test8/linux/drivers/pci/quirks.c Fri Aug 4 11:23:37 2000 +++ linux/drivers/pci/quirks.c Sun Oct 1 20:35:16 2000 @@ -46,7 +46,7 @@ chipset level fix */ -int isa_dma_bridge_buggy = 0; /* Exported */ +int isa_dma_bridge_buggy; /* Exported */ static void __init quirk_isa_dma_hangs(struct pci_dev *dev) { @@ -56,7 +56,7 @@ } } -int pci_pci_problems = 0; +int pci_pci_problems; /* * Chipsets where PCI->PCI transfers vanish or hang diff -u --recursive --new-file v2.4.0-test8/linux/drivers/pcmcia/cardbus.c linux/drivers/pcmcia/cardbus.c --- v2.4.0-test8/linux/drivers/pcmcia/cardbus.c Tue Sep 5 12:56:51 2000 +++ linux/drivers/pcmcia/cardbus.c Mon Sep 18 15:11:51 2000 @@ -58,11 +58,6 @@ #include #include -#ifndef PCMCIA_DEBUG -#define PCMCIA_DEBUG 1 -#endif -static int pc_debug = PCMCIA_DEBUG; - #define IN_CARD_SERVICES #include #include @@ -73,6 +68,10 @@ #include "cs_internal.h" #include "rsrc_mgr.h" +#ifdef PCMCIA_DEBUG +static int pc_debug = PCMCIA_DEBUG; +#endif + /*====================================================================*/ #define FIND_FIRST_BIT(n) ((n) - ((n) & ((n)-1))) @@ -372,9 +371,9 @@ void cb_enable(socket_info_t * s) { struct pci_dev *dev; - u_char i, bus = s->cap.cb_dev->subordinate->number; + u_char i; - DEBUG(0, "cs: cb_enable(bus %d)\n", bus); + DEBUG(0, "cs: cb_enable(bus %d)\n", s->cap.cb_dev->subordinate->number); /* Configure bridge */ cb_release_cis_mem(s); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/pcmcia/cs.c linux/drivers/pcmcia/cs.c --- v2.4.0-test8/linux/drivers/pcmcia/cs.c Thu Sep 7 09:13:00 2000 +++ linux/drivers/pcmcia/cs.c Mon Sep 18 15:11:51 2000 @@ -103,13 +103,13 @@ #define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i") -INT_MODULE_PARM(setup_delay, HZ/20); /* ticks */ -INT_MODULE_PARM(resume_delay, HZ/5); /* ticks */ -INT_MODULE_PARM(shutdown_delay, HZ/40); /* ticks */ -INT_MODULE_PARM(vcc_settle, 400); /* msecs */ +INT_MODULE_PARM(setup_delay, 10); /* centiseconds */ +INT_MODULE_PARM(resume_delay, 20); /* centiseconds */ +INT_MODULE_PARM(shutdown_delay, 3); /* centiseconds */ +INT_MODULE_PARM(vcc_settle, 40); /* centiseconds */ INT_MODULE_PARM(reset_time, 10); /* usecs */ -INT_MODULE_PARM(unreset_delay, 100); /* msecs */ -INT_MODULE_PARM(unreset_check, 100); /* msecs */ +INT_MODULE_PARM(unreset_delay, 10); /* centiseconds */ +INT_MODULE_PARM(unreset_check, 10); /* centiseconds */ INT_MODULE_PARM(unreset_limit, 30); /* unreset_check's */ /* Access speed for attribute memory windows */ @@ -446,10 +446,13 @@ static int send_event(socket_info_t *s, event_t event, int priority); -static void msleep(unsigned int msec) +/* + * Sleep for n_cs centiseconds (1 cs = 1/100th of a second) + */ +static void cs_sleep(unsigned int n_cs) { current->state = TASK_INTERRUPTIBLE; - schedule_timeout( (msec * HZ + 999) / 1000); + schedule_timeout( (n_cs * HZ + 99) / 100); } static void shutdown_socket(socket_info_t *s) @@ -504,7 +507,7 @@ if (!(val & SS_PENDING)) break; if (--setup_timeout) { - msleep(100); + cs_sleep(10); continue; } printk(KERN_NOTICE "cs: socket %p voltage interrogation" @@ -516,7 +519,7 @@ if (val & SS_DETECT) { DEBUG(1, "cs: setup_socket(%p): applying power\n", s); s->state |= SOCKET_PRESENT; - s->socket.flags = 0; + s->socket.flags &= SS_DEBOUNCED; if (val & SS_3VCARD) s->socket.Vcc = s->socket.Vpp = 33; else if (!(val & SS_XVCARD)) @@ -533,7 +536,7 @@ #endif } set_socket(s, &s->socket); - msleep(vcc_settle); + cs_sleep(vcc_settle); reset_socket(s); ret = 1; } else { @@ -561,7 +564,7 @@ udelay((long)reset_time); s->socket.flags &= ~SS_RESET; set_socket(s, &s->socket); - msleep(unreset_delay); + cs_sleep(unreset_delay); unreset_socket(s); } /* reset_socket */ @@ -580,11 +583,11 @@ break; DEBUG(2, "cs: socket %d not ready yet\n", s->sock); if (--setup_timeout) { - msleep(unreset_check); + cs_sleep(unreset_check); continue; } printk(KERN_NOTICE "cs: socket %p timed out during" - " reset\n", s); + " reset. Try increasing setup_delay.\n", s); s->state &= ~EVENT_MASK; return; } @@ -656,7 +659,7 @@ DEBUG(0, "cs: flushing pending setup\n"); s->state &= ~EVENT_MASK; } - msleep(shutdown_delay); + cs_sleep(shutdown_delay); s->state &= ~SOCKET_PRESENT; shutdown_socket(s); } @@ -679,11 +682,13 @@ } s->state |= SOCKET_SETUP_PENDING; if (s->state & SOCKET_SUSPEND) - msleep(resume_delay); + cs_sleep(resume_delay); else - msleep(setup_delay); + cs_sleep(setup_delay); + s->socket.flags |= SS_DEBOUNCED; if (setup_socket(s) == 0) s->state &= ~SOCKET_SETUP_PENDING; + s->socket.flags &= ~SS_DEBOUNCED; } } if (events & SS_BATDEAD) diff -u --recursive --new-file v2.4.0-test8/linux/drivers/pcmcia/yenta.c linux/drivers/pcmcia/yenta.c --- v2.4.0-test8/linux/drivers/pcmcia/yenta.c Wed Sep 6 11:48:58 2000 +++ linux/drivers/pcmcia/yenta.c Fri Sep 15 16:31:09 2000 @@ -233,6 +233,11 @@ { u16 bridge; + if (state->flags & SS_DEBOUNCED) { + /* The insertion debounce period has ended. Clear any pending insertion events */ + socket->events &= ~SS_DETECT; + state->flags &= ~SS_DEBOUNCED; /* SS_DEBOUNCED is oneshot */ + } yenta_set_power(socket, state); socket->io_irq = state->io_irq; bridge = config_readw(socket, CB_BRIDGE_CONTROL) & ~(CB_BRIDGE_CRST | CB_BRIDGE_INTR); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/pnp/isapnp.c linux/drivers/pnp/isapnp.c --- v2.4.0-test8/linux/drivers/pnp/isapnp.c Mon Aug 28 22:13:12 2000 +++ linux/drivers/pnp/isapnp.c Sun Oct 1 20:35:16 2000 @@ -48,14 +48,14 @@ #define ISAPNP_DEBUG #endif -struct resource *pidxr_res = NULL; -struct resource *pnpwrp_res = NULL; -struct resource *isapnp_rdp_res = NULL; +struct resource *pidxr_res; +struct resource *pnpwrp_res; +struct resource *isapnp_rdp_res; -int isapnp_disable = 0; /* Disable ISA PnP */ -int isapnp_rdp = 0; /* Read Data Port */ +int isapnp_disable; /* Disable ISA PnP */ +int isapnp_rdp; /* Read Data Port */ int isapnp_reset = 1; /* reset all PnP cards (deactivate) */ -int isapnp_skip_pci_scan = 0; /* skip PCI resource scanning */ +int isapnp_skip_pci_scan; /* skip PCI resource scanning */ int isapnp_verbose = 1; /* verbose mode */ int isapnp_reserve_irq[16] = { [0 ... 15] = -1 }; /* reserve (don't use) some IRQ */ int isapnp_reserve_dma[8] = { [0 ... 7] = -1 }; /* reserve (don't use) some DMA */ @@ -108,7 +108,7 @@ static unsigned char isapnp_checksum_value; static DECLARE_MUTEX(isapnp_cfg_mutex); -static int isapnp_detected = 0; +static int isapnp_detected; /* some prototypes */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/s390/Config.in linux/drivers/s390/Config.in --- v2.4.0-test8/linux/drivers/s390/Config.in Fri May 12 11:41:44 2000 +++ linux/drivers/s390/Config.in Tue Sep 19 10:58:38 2000 @@ -5,16 +5,7 @@ if [ "$CONFIG_NET" = "y" ]; then tristate 'Network block device support' CONFIG_BLK_DEV_NBD fi -bool 'Multiple devices driver support' CONFIG_BLK_DEV_MD -if [ "$CONFIG_BLK_DEV_MD" = "y" ]; then - tristate ' Linear (append) mode' CONFIG_MD_LINEAR - tristate ' RAID-0 (striping) mode' CONFIG_MD_STRIPED - tristate ' RAID-1 (mirroring) mode' CONFIG_MD_MIRRORING - tristate ' RAID-4/RAID-5 mode' CONFIG_MD_RAID5 -fi -if [ "$CONFIG_MD_LINEAR" = "y" -o "$CONFIG_MD_STRIPED" = "y" ]; then - bool ' Boot support (linear, striped)' CONFIG_MD_BOOT -fi +include drivers/md/Config.in tristate 'RAM disk support' CONFIG_BLK_DEV_RAM if [ "$CONFIG_BLK_DEV_RAM" = "y" ]; then bool ' Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/3w-xxxx.c linux/drivers/scsi/3w-xxxx.c --- v2.4.0-test8/linux/drivers/scsi/3w-xxxx.c Fri Aug 4 17:56:25 2000 +++ linux/drivers/scsi/3w-xxxx.c Mon Sep 18 14:57:01 2000 @@ -3,6 +3,7 @@ Written By: Adam Radford Modifications By: Joel Jacobson + Arnaldo Carvalho de Melo Copyright (C) 1999-2000 3ware Inc. @@ -64,6 +65,8 @@ Bug fix so hot spare drives don't show up. 1.02.00.002 - Fix bug with tw_setfeature() call that caused oops on some systems. + 08/21/00 - release previously allocated resources on failure at + tw_allocate_memory (acme) */ #include @@ -410,35 +413,26 @@ /* This function will allocate memory and check if it is 16 d-word aligned */ int tw_allocate_memory(TW_Device_Extension *tw_dev, int request_id, int size, int which) { - u32 *virt_addr; + u32 *virt_addr = kmalloc(size, GFP_ATOMIC); dprintk(KERN_NOTICE "3w-xxxx: tw_allocate_memory()\n"); + if (!virt_addr) { + printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): kmalloc() failed.\n"); + return 1; + } + + if ((u32)virt_addr % TW_ALIGNMENT) { + kfree(virt_addr); + printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): Found unaligned address.\n"); + return 1; + } + if (which == 0) { - /* Allocate command packet memory */ - virt_addr = kmalloc(size, GFP_ATOMIC); - if (virt_addr == NULL) { - printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): kmalloc() failed.\n"); - return 1; - } - if ((u32)virt_addr % TW_ALIGNMENT) { - printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): Found unaligned address.\n"); - return 1; - } tw_dev->command_packet_virtual_address[request_id] = virt_addr; tw_dev->command_packet_physical_address[request_id] = virt_to_bus(virt_addr); } else { - /* Allocate generic buffer */ - virt_addr = kmalloc(size, GFP_ATOMIC); - if (virt_addr == NULL) { - printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): kmalloc() failed.\n"); - return 1; - } - if ((u32)virt_addr % TW_ALIGNMENT) { - printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): Found unaligned address.\n"); - return 1; - } tw_dev->alignment_virtual_address[request_id] = virt_addr; tw_dev->alignment_physical_address[request_id] = virt_to_bus(virt_addr); } @@ -2390,7 +2384,6 @@ /* Now get things going */ -#ifdef MODULE -Scsi_Host_Template driver_template = TWXXXX; +static Scsi_Host_Template driver_template = TWXXXX; #include "scsi_module.c" -#endif + diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/3w-xxxx.h linux/drivers/scsi/3w-xxxx.h --- v2.4.0-test8/linux/drivers/scsi/3w-xxxx.h Fri Sep 8 12:54:35 2000 +++ linux/drivers/scsi/3w-xxxx.h Mon Sep 18 14:09:49 2000 @@ -338,7 +338,6 @@ int tw_state_request_start(TW_Device_Extension *tw_dev, int *request_id); void tw_unmask_command_interrupt(TW_Device_Extension *tw_dev); -#if defined(HOSTS_C) || defined(MODULE) /* Scsi_Host_Template Initializer */ #define TWXXXX { \ next : NULL, \ @@ -371,5 +370,4 @@ use_new_eh_code : 1, \ emulated : 1 \ } -#endif /* HOSTS_C */ #endif /* _3W_XXXX_H */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/53c7,8xx.c linux/drivers/scsi/53c7,8xx.c --- v2.4.0-test8/linux/drivers/scsi/53c7,8xx.c Tue Aug 8 09:19:25 2000 +++ linux/drivers/scsi/53c7,8xx.c Mon Sep 18 13:36:24 2000 @@ -6425,6 +6425,7 @@ vfree ((void *)hostdata->events); return 1; } -Scsi_Host_Template driver_template = NCR53c7xx; -#include "scsi_module.c" #endif /* def MODULE */ + +static Scsi_Host_Template driver_template = NCR53c7xx; +#include "scsi_module.c" diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/53c7,8xx.h linux/drivers/scsi/53c7,8xx.h --- v2.4.0-test8/linux/drivers/scsi/53c7,8xx.h Fri Sep 8 12:54:35 2000 +++ linux/drivers/scsi/53c7,8xx.h Mon Sep 18 14:09:49 2000 @@ -46,7 +46,6 @@ * array. */ -#if defined(HOSTS_C) || defined(MODULE) #include extern int NCR53c7xx_abort(Scsi_Cmnd *); @@ -71,8 +70,6 @@ sg_tablesize: 127, \ cmd_per_lun: 3, \ use_clustering: DISABLE_CLUSTERING} - -#endif /* defined(HOSTS_C) || defined(MODULE) */ #ifndef HOSTS_C diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/53c7xx.c linux/drivers/scsi/53c7xx.c --- v2.4.0-test8/linux/drivers/scsi/53c7xx.c Tue Aug 8 09:19:25 2000 +++ linux/drivers/scsi/53c7xx.c Mon Sep 18 13:36:24 2000 @@ -6102,6 +6102,7 @@ free_pages ((u32)hostdata, 1); return 1; } -Scsi_Host_Template driver_template = NCR53c7xx; -#include "scsi_module.c" #endif /* def MODULE */ + +static Scsi_Host_Template driver_template = NCR53c7xx; +#include "scsi_module.c" diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/53c7xx.h linux/drivers/scsi/53c7xx.h --- v2.4.0-test8/linux/drivers/scsi/53c7xx.h Tue Nov 23 10:29:15 1999 +++ linux/drivers/scsi/53c7xx.h Mon Sep 18 14:09:49 2000 @@ -59,7 +59,6 @@ * array. */ -#if defined(HOSTS_C) || defined(MODULE) #include extern int NCR53c7xx_abort(Scsi_Cmnd *); @@ -79,8 +78,6 @@ NULL /* slave attach */, scsicam_bios_param, /* can queue */ 24, \ /* id */ 7, 127 /* old SG_ALL */, /* cmd per lun */ 3, \ /* present */ 0, /* unchecked isa dma */ 0, DISABLE_CLUSTERING} - -#endif /* defined(HOSTS_C) || defined(MODULE) */ #ifndef HOSTS_C diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/AM53C974.c linux/drivers/scsi/AM53C974.c --- v2.4.0-test8/linux/drivers/scsi/AM53C974.c Mon Jun 19 17:59:41 2000 +++ linux/drivers/scsi/AM53C974.c Mon Sep 18 13:36:24 2000 @@ -2456,11 +2456,10 @@ #ifdef MODULE -static Scsi_Host_Template driver_template = AM53C974; - /* You can specify overrides=a,b,c,d in the same format at AM53C974=a,b,c,d on boot up */ - MODULE_PARM(overrides, "1-32i"); -#include "scsi_module.c" #endif + +static Scsi_Host_Template driver_template = AM53C974; +#include "scsi_module.c" diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/BusLogic.c linux/drivers/scsi/BusLogic.c --- v2.4.0-test8/linux/drivers/scsi/BusLogic.c Mon Jul 10 13:06:35 2000 +++ linux/drivers/scsi/BusLogic.c Mon Sep 18 13:36:24 2000 @@ -61,7 +61,7 @@ */ static int - BusLogic_DriverOptionsCount = 0; + BusLogic_DriverOptionsCount; /* @@ -79,7 +79,7 @@ */ #ifdef MODULE -static char *BusLogic = NULL; +static char *BusLogic; MODULE_PARM(BusLogic, "s"); #endif @@ -90,7 +90,7 @@ */ static BusLogic_ProbeOptions_T - BusLogic_ProbeOptions = { 0 }; + BusLogic_ProbeOptions; /* @@ -99,7 +99,7 @@ */ static BusLogic_GlobalOptions_T - BusLogic_GlobalOptions = { 0 }; + BusLogic_GlobalOptions; /* @@ -108,8 +108,8 @@ */ static BusLogic_HostAdapter_T - *BusLogic_FirstRegisteredHostAdapter = NULL, - *BusLogic_LastRegisteredHostAdapter = NULL; + *BusLogic_FirstRegisteredHostAdapter, + *BusLogic_LastRegisteredHostAdapter; /* @@ -117,7 +117,7 @@ */ static int - BusLogic_ProbeInfoCount = 0; + BusLogic_ProbeInfoCount; /* @@ -128,7 +128,7 @@ */ static BusLogic_ProbeInfo_T - *BusLogic_ProbeInfoList = NULL; + *BusLogic_ProbeInfoList; /* @@ -4982,13 +4982,9 @@ __setup("BusLogic=", BusLogic_Setup); /* - Include Module support if requested. + Get it all started */ -#ifdef MODULE - -SCSI_Host_Template_T driver_template = BUSLOGIC; +static SCSI_Host_Template_T driver_template = BUSLOGIC; #include "scsi_module.c" - -#endif diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/ChangeLog.ips linux/drivers/scsi/ChangeLog.ips --- v2.4.0-test8/linux/drivers/scsi/ChangeLog.ips Tue Jun 20 14:14:51 2000 +++ linux/drivers/scsi/ChangeLog.ips Tue Sep 19 08:01:34 2000 @@ -1,7 +1,22 @@ IBM ServeRAID driver Change Log ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 4.20.14 - Update patch files for kernel 2.4.0-test5 + + 4.20.13 - Fix some failure cases / reset code + - Hook into the reboot_notifier to flush the controller + cache + + 4.20.03 - Rename version to coincide with new release schedules + - Performance fixes + - Fix truncation of /proc files with cat + - Merge in changes through kernel 2.4.0test1ac21 + + 4.10.13 - Fix for dynamic unload and proc file system + + 4.10.00 - Add support for ServeRAID 4M/4L + 4.00.06 - Fix timeout with initial FFDC command - + 4.00.05 - Remove wish_block from init routine - Use linux/spinlock.h instead of asm/spinlock.h for kernels 2.3.18 and later diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in --- v2.4.0-test8/linux/drivers/scsi/Config.in Mon Mar 27 09:45:33 2000 +++ linux/drivers/scsi/Config.in Tue Sep 19 08:01:34 2000 @@ -55,9 +55,6 @@ bool ' Collect statistics to report in /proc' CONFIG_AIC7XXX_PROC_STATS int ' Delay in seconds after SCSI bus reset' CONFIG_AIC7XXX_RESET_DELAY 5 fi -if [ "$CONFIG_X86" = "y" ]; then - dep_tristate 'IBM ServeRAID support' CONFIG_SCSI_IPS $CONFIG_SCSI -fi dep_tristate 'AdvanSys SCSI support' CONFIG_SCSI_ADVANSYS $CONFIG_SCSI dep_tristate 'Always IN2000 SCSI support' CONFIG_SCSI_IN2000 $CONFIG_SCSI dep_tristate 'AM53/79C974 PCI SCSI support' CONFIG_SCSI_AM53C974 $CONFIG_SCSI @@ -67,6 +64,9 @@ if [ "$CONFIG_SCSI_BUSLOGIC" != "n" ]; then bool ' Omit FlashPoint support' CONFIG_SCSI_OMIT_FLASHPOINT fi +if [ "$CONFIG_PCI" = "y" ]; then + dep_tristate 'Compaq Fibre Channel 64-bit/66Mhz HBA support' CONFIG_SCSI_CPQFCTS $CONFIG_SCSI +fi dep_tristate 'DMX3191D SCSI support' CONFIG_SCSI_DMX3191D $CONFIG_SCSI $CONFIG_PCI dep_tristate 'DTC3180/3280 SCSI support' CONFIG_SCSI_DTC3280 $CONFIG_SCSI dep_tristate 'EATA ISA/EISA/PCI (DPT and generic EATA/DMA-compliant boards) support' CONFIG_SCSI_EATA $CONFIG_SCSI @@ -89,6 +89,16 @@ "Port CONFIG_SCSI_G_NCR5380_PORT \ Memory CONFIG_SCSI_G_NCR5380_MEM" Port fi +if [ "$CONFIG_MCA" = "y" ]; then + dep_tristate 'IBMMCA SCSI support' CONFIG_SCSI_IBMMCA $CONFIG_SCSI + if [ "$CONFIG_SCSI_IBMMCA" != "n" ]; then + bool ' Standard SCSI-order' CONFIG_IBMMCA_SCSI_ORDER_STANDARD + bool ' Reset SCSI-devices at boottime' CONFIG_IBMMCA_SCSI_DEV_RESET + fi +fi +if [ "$CONFIG_X86" = "y" ]; then + dep_tristate 'IBM ServeRAID support' CONFIG_SCSI_IPS $CONFIG_SCSI +fi dep_tristate 'Initio 9100U(W) support' CONFIG_SCSI_INITIO $CONFIG_SCSI $CONFIG_PCI dep_tristate 'Initio INI-A100U2W support' CONFIG_SCSI_INIA100 $CONFIG_SCSI $CONFIG_PCI if [ "$CONFIG_PARPORT" != "n" ]; then @@ -100,8 +110,6 @@ fi fi dep_tristate 'NCR53c406a SCSI support' CONFIG_SCSI_NCR53C406A $CONFIG_SCSI -dep_tristate 'symbios 53c416 SCSI support' CONFIG_SCSI_SYM53C416 $CONFIG_SCSI -dep_tristate 'Simple 53c710 SCSI support (Compaq, NCR machines)' CONFIG_SCSI_SIM710 $CONFIG_SCSI dep_tristate 'NCR53c7,8xx SCSI support' CONFIG_SCSI_NCR53C7xx $CONFIG_SCSI $CONFIG_PCI if [ "$CONFIG_SCSI_NCR53C7xx" != "n" ]; then bool ' always negotiate synchronous transfers' CONFIG_SCSI_NCR53C7xx_sync @@ -129,13 +137,6 @@ fi fi if [ "$CONFIG_MCA" = "y" ]; then - dep_tristate 'IBMMCA SCSI support' CONFIG_SCSI_IBMMCA $CONFIG_SCSI - if [ "$CONFIG_SCSI_IBMMCA" != "n" ]; then - bool ' Standard SCSI-order' CONFIG_IBMMCA_SCSI_ORDER_STANDARD - bool ' Reset SCSI-devices at boottime' CONFIG_IBMMCA_SCSI_DEV_RESET - fi -fi -if [ "$CONFIG_MCA" = "y" ]; then dep_tristate 'NCR MCA 53C9x SCSI support' CONFIG_SCSI_MCA_53C9X $CONFIG_SCSI fi dep_tristate 'PAS16 SCSI support' CONFIG_SCSI_PAS16 $CONFIG_SCSI @@ -151,6 +152,8 @@ if [ "$CONFIG_X86" = "y" ]; then dep_tristate 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE $CONFIG_SCSI fi +dep_tristate 'Simple 53c710 SCSI support (Compaq, NCR machines)' CONFIG_SCSI_SIM710 $CONFIG_SCSI +dep_tristate 'Symbios 53c416 SCSI support' CONFIG_SCSI_SYM53C416 $CONFIG_SCSI if [ "$CONFIG_PCI" = "y" ]; then dep_tristate 'Tekram DC390(T) and Am53/79C974 SCSI support' CONFIG_SCSI_DC390T $CONFIG_SCSI if [ "$CONFIG_SCSI_DC390T" != "n" ]; then diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile --- v2.4.0-test8/linux/drivers/scsi/Makefile Tue Sep 19 16:37:04 2000 +++ linux/drivers/scsi/Makefile Wed Sep 20 13:12:13 2000 @@ -4,6 +4,8 @@ # 30 May 2000, Christoph Hellwig # Rewritten to use lists instead of if-statements. # +# 20 Sep 2000, Torben Mathiasen +# Changed link order to reflect new scsi initialization. O_TARGET := scsidrv.o @@ -22,25 +24,14 @@ endif export-objs := scsi_syms.o -list-multi := scsi_mod.o sr_mod.o initio.o a100u2w.o +list-multi := scsi_mod.o initio.o a100u2w.o CFLAGS_aha152x.o = -DAHA152X_STAT -DAUTOCONF CFLAGS_gdth.o = # -DDEBUG_GDTH=2 -D__SERIAL__ -D__COM2__ -DGDTH_STATISTICS CFLAGS_seagate.o = -DARBITRATE -DPARITY -DSEAGATE_USE_ASM -obj-$(CONFIG_SCSI) += scsi_mod.o -obj-$(CONFIG_CHR_DEV_ST) += st.o -obj-$(CONFIG_BLK_DEV_SD) += sd.o -obj-$(CONFIG_BLK_DEV_SR) += sr_mod.o -obj-$(CONFIG_CHR_DEV_SG) += sg.o +obj-$(CONFIG_SCSI) += scsi_mod.o scsi_syms.o -obj-$(CONFIG_SCSI_ADVANSYS) += advansys.o -obj-$(CONFIG_SCSI_PCI2000) += pci2000.o -obj-$(CONFIG_SCSI_PCI2220I) += pci2220i.o -obj-$(CONFIG_SCSI_PSI240I) += psi240i.o -obj-$(CONFIG_MVME16x_SCSI) += mvme16x.o 53c7xx.o -obj-$(CONFIG_BVME6000_SCSI) += bvme6000.o 53c7xx.o -obj-$(CONFIG_SCSI_SIM710) += sim710.o obj-$(CONFIG_A4000T_SCSI) += amiga7xx.o 53c7xx.o obj-$(CONFIG_A4091_SCSI) += amiga7xx.o 53c7xx.o obj-$(CONFIG_BLZ603EPLUS_SCSI) += amiga7xx.o 53c7xx.o @@ -48,8 +39,6 @@ obj-$(CONFIG_A3000_SCSI) += a3000.o wd33c93.o obj-$(CONFIG_A2091_SCSI) += a2091.o wd33c93.o obj-$(CONFIG_GVP11_SCSI) += gvp11.o wd33c93.o -obj-$(CONFIG_SCSI_SGIWD93) += sgiwd93.o wd33c93.o -obj-$(CONFIG_SCSI_MCA_53C9X) += NCR53C9x.o mca_53c9x.o obj-$(CONFIG_CYBERSTORM_SCSI) += NCR53C9x.o cyberstorm.o obj-$(CONFIG_CYBERSTORMII_SCSI) += NCR53C9x.o cyberstormII.o obj-$(CONFIG_BLZ2060_SCSI) += NCR53C9x.o blz2060.o @@ -58,69 +47,82 @@ obj-$(CONFIG_OKTAGON_SCSI) += NCR53C9x.o oktagon_esp.o oktagon_io.o obj-$(CONFIG_ATARI_SCSI) += atari_scsi.o obj-$(CONFIG_MAC_SCSI) += mac_scsi.o -obj-$(CONFIG_SUN3_SCSI) += sun3_scsi.o obj-$(CONFIG_SCSI_MAC_ESP) += mac_esp.o NCR53C9x.o -obj-$(CONFIG_SCSI_PPA) += ppa.o -obj-$(CONFIG_SCSI_IMM) += imm.o -obj-$(CONFIG_SCSI_QLOGIC_FAS) += qlogicfas.o -obj-$(CONFIG_SCSI_QLOGIC_ISP) += qlogicisp.o -obj-$(CONFIG_SCSI_QLOGIC_1280) += qla1280.o -obj-$(CONFIG_SCSI_ACARD) += atp870u.o -obj-$(CONFIG_SCSI_INITIO) += initio.o -obj-$(CONFIG_SCSI_INIA100) += a100u2w.o -obj-$(CONFIG_SCSI_QLOGIC_FC) += qlogicfc.o +obj-$(CONFIG_SUN3_SCSI) += sun3_scsi.o +obj-$(CONFIG_MVME16x_SCSI) += mvme16x.o 53c7xx.o +obj-$(CONFIG_BVME6000_SCSI) += bvme6000.o 53c7xx.o +obj-$(CONFIG_SCSI_SIM710) += sim710.o +obj-$(CONFIG_SCSI_ADVANSYS) += advansys.o +obj-$(CONFIG_SCSI_PCI2000) += pci2000.o +obj-$(CONFIG_SCSI_PCI2220I) += pci2220i.o +obj-$(CONFIG_SCSI_PSI240I) += psi240i.o +obj-$(CONFIG_SCSI_BUSLOGIC) += BusLogic.o +obj-$(CONFIG_SCSI_U14_34F) += u14-34f.o +obj-$(CONFIG_SCSI_ULTRASTOR) += ultrastor.o obj-$(CONFIG_SCSI_AHA152X) += aha152x.o obj-$(CONFIG_SCSI_AHA1542) += aha1542.o obj-$(CONFIG_SCSI_AHA1740) += aha1740.o obj-$(CONFIG_SCSI_AIC7XXX) += aic7xxx.o obj-$(CONFIG_SCSI_IPS) += ips.o -obj-$(CONFIG_SCSI_DC390T) += tmscsim.o -obj-$(CONFIG_SCSI_AM53C974) += AM53C974.o -obj-$(CONFIG_SCSI_BUSLOGIC) += BusLogic.o -obj-$(CONFIG_SCSI_EATA_DMA) += eata_dma.o -obj-$(CONFIG_SCSI_EATA_PIO) += eata_pio.o -obj-$(CONFIG_SCSI_U14_34F) += u14-34f.o -obj-$(CONFIG_SCSI_SUNESP) += esp.o -obj-$(CONFIG_SCSI_QLOGICPTI) += qlogicpti.o -obj-$(CONFIG_SCSI_MESH) += mesh.o -obj-$(CONFIG_SCSI_MAC53C94) += mac53c94.o -obj-$(CONFIG_SCSI_GDTH) += gdth.o - -obj-$(CONFIG_SCSI_DEBUG) += scsi_debug.o - +obj-$(CONFIG_SCSI_FD_MCS) += fd_mcs.o obj-$(CONFIG_SCSI_FUTURE_DOMAIN)+= fdomain.o obj-$(CONFIG_SCSI_IN2000) += in2000.o obj-$(CONFIG_SCSI_GENERIC_NCR5380) += g_NCR5380.o -obj-$(CONFIG_SCSI_NCR53C7xx) += 53c7,8xx.o -obj-$(CONFIG_SCSI_NCR53C8XX) += ncr53c8xx.o -obj-$(CONFIG_SCSI_SYM53C8XX) += sym53c8xx.o +obj-$(CONFIG_SCSI_NCR53C406A) += NCR53c406a.o +obj-$(CONFIG_SCSI_SYM53C416) += sym53c416.o +obj-$(CONFIG_SCSI_QLOGIC_FAS) += qlogicfas.o +obj-$(CONFIG_SCSI_QLOGIC_ISP) += qlogicisp.o +obj-$(CONFIG_SCSI_QLOGIC_FC) += qlogicfc.o +obj-$(CONFIG_SCSI_QLOGIC_1280) += qla1280.o obj-$(CONFIG_SCSI_PAS16) += pas16.o obj-$(CONFIG_SCSI_SEAGATE) += seagate.o obj-$(CONFIG_SCSI_FD_8xx) += seagate.o -obj-$(CONFIG_SCSI_7000FASST) += wd7000.o -obj-$(CONFIG_SCSI_IBMMCA) += ibmmca.o -obj-$(CONFIG_SCSI_FD_MCS) += fd_mcs.o obj-$(CONFIG_SCSI_T128) += t128.o obj-$(CONFIG_SCSI_DMX3191D) += dmx3191d.o obj-$(CONFIG_SCSI_DTC3280) += dtc.o -obj-$(CONFIG_SCSI_ULTRASTOR) += ultrastor.o -obj-$(CONFIG_SCSI_PLUTO) += pluto.o -obj-$(CONFIG_SCSI_FCAL) += fcal.o +obj-$(CONFIG_SCSI_NCR53C7xx) += 53c7,8xx.o +obj-$(CONFIG_SCSI_SYM53C8XX) += sym53c8xx.o +obj-$(CONFIG_SCSI_NCR53C8XX) += ncr53c8xx.o +obj-$(CONFIG_SCSI_EATA_DMA) += eata_dma.o +obj-$(CONFIG_SCSI_EATA_PIO) += eata_pio.o +obj-$(CONFIG_SCSI_7000FASST) += wd7000.o +obj-$(CONFIG_SCSI_MCA_53C9X) += NCR53C9x.o mca_53c9x.o +obj-$(CONFIG_SCSI_IBMMCA) += ibmmca.o obj-$(CONFIG_SCSI_EATA) += eata.o -obj-$(CONFIG_SCSI_NCR53C406A) += NCR53c406a.o +obj-$(CONFIG_SCSI_DC390T) += tmscsim.o +obj-$(CONFIG_SCSI_AM53C974) += AM53C974.o obj-$(CONFIG_SCSI_MEGARAID) += megaraid.o -obj-$(CONFIG_SCSI_SYM53C416) += sym53c416.o +obj-$(CONFIG_SCSI_ACARD) += atp870u.o +obj-$(CONFIG_SCSI_SUNESP) += esp.o +obj-$(CONFIG_SCSI_GDTH) += gdth.o +obj-$(CONFIG_SCSI_INITIO) += initio.o +obj-$(CONFIG_SCSI_INIA100) += a100u2w.o +obj-$(CONFIG_SCSI_QLOGICPTI) += qlogicpti.o obj-$(CONFIG_BLK_DEV_IDESCSI) += ide-scsi.o -obj-$(CONFIG_JAZZ_ESP) += NCR53C9x.o jazz_esp.o +obj-$(CONFIG_SCSI_MESH) += mesh.o +obj-$(CONFIG_SCSI_MAC53C94) += mac53c94.o +obj-$(CONFIG_SCSI_PLUTO) += pluto.o obj-$(CONFIG_SCSI_DECNCR) += NCR53C9x.o dec_esp.o -obj-$(CONFIG_SUN3X_ESP) += NCR53C9x.o sun3x_esp.o obj-$(CONFIG_BLK_DEV_3W_XXXX_RAID) += 3w-xxxx.o +obj-$(CONFIG_SCSI_PPA) += ppa.o +obj-$(CONFIG_SCSI_IMM) += imm.o +obj-$(CONFIG_JAZZ_ESP) += NCR53C9x.o jazz_esp.o +obj-$(CONFIG_SUN3X_ESP) += NCR53C9x.o sun3x_esp.o +obj-$(CONFIG_SCSI_DEBUG) += scsi_debug.o +obj-$(CONFIG_SCSI_FCAL) += fcal.o + +obj-$(CONFIG_CHR_DEV_ST) += st.o +obj-$(CONFIG_BLK_DEV_SD) += sd_mod.o +obj-$(CONFIG_BLK_DEV_SR) += sr_mod.o +obj-$(CONFIG_CHR_DEV_SG) += sg.o + -scsi_mod-objs := hosts.o scsi.o scsi_ioctl.o constants.o \ + +scsi_mod-objs := scsi.o hosts.o scsi_ioctl.o constants.o \ scsicam.o scsi_proc.o scsi_error.o \ scsi_obsolete.o scsi_queue.o scsi_lib.o \ scsi_merge.o scsi_dma.o scsi_scan.o \ - scsi_syms.o + sr_mod-objs := sr.o sr_ioctl.o sr_vendor.o initio-objs := ini9100u.o i91uscsi.o a100u2w-objs := inia100.o i60uscsi.o @@ -136,9 +138,6 @@ obj-m := $(filter-out $(obj-y), $(obj-m)) int-m := $(filter-out $(int-y), $(int-m)) -# Take multi-part drivers out of obj-y and put components in. -obj-y := $(filter-out $(list-multi), $(obj-y)) $(int-y) - O_OBJS := $(filter-out $(export-objs), $(obj-y)) OX_OBJS := $(filter $(export-objs), $(obj-y)) M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) @@ -151,6 +150,9 @@ scsi_mod.o: $(scsi_mod-objs) $(LD) -r -o $@ $(scsi_mod-objs) + +sd_mod.o: sd.o + $(LD) -r -o $@ sd.o sr_mod.o: $(sr_mod-objs) $(LD) -r -o $@ $(sr_mod-objs) diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/NCR53c406a.c linux/drivers/scsi/NCR53c406a.c --- v2.4.0-test8/linux/drivers/scsi/NCR53c406a.c Thu Nov 11 16:57:30 1999 +++ linux/drivers/scsi/NCR53c406a.c Mon Sep 18 13:36:24 2000 @@ -1059,12 +1059,10 @@ /* CONFIG6 = (port_base+0x0F);*/ } -#ifdef MODULE /* Eventually this will go into an include file, but this will be later */ -Scsi_Host_Template driver_template = NCR53c406a; +static Scsi_Host_Template driver_template = NCR53c406a; #include "scsi_module.c" -#endif /* * Overrides for Emacs so that we get a uniform tabbing style. diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/a2091.c linux/drivers/scsi/a2091.c --- v2.4.0-test8/linux/drivers/scsi/a2091.c Wed Jan 26 12:45:20 2000 +++ linux/drivers/scsi/a2091.c Mon Sep 18 13:36:24 2000 @@ -226,17 +226,13 @@ return num_a2091; } -#ifdef MODULE - #define HOSTS_C #include "a2091.h" -Scsi_Host_Template driver_template = A2091_SCSI; +static Scsi_Host_Template driver_template = A2091_SCSI; #include "scsi_module.c" - -#endif int a2091_release(struct Scsi_Host *instance) { diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/a2091.h linux/drivers/scsi/a2091.h --- v2.4.0-test8/linux/drivers/scsi/a2091.h Fri Sep 8 12:54:34 2000 +++ linux/drivers/scsi/a2091.h Mon Sep 18 14:12:01 2000 @@ -29,8 +29,6 @@ #define CAN_QUEUE 16 #endif -#ifdef HOSTS_C - #define A2091_SCSI { proc_name: "A2901", \ name: "Commodore A2091/A590 SCSI", \ detect: a2091_detect, \ @@ -43,7 +41,6 @@ sg_tablesize: SG_ALL, \ cmd_per_lun: CMD_PER_LUN, \ use_clustering: DISABLE_CLUSTERING } -#else /* * if the transfer address ANDed with this results in a non-zero @@ -91,7 +88,5 @@ #define ISTR_OE_INT (1<<2) #define ISTR_FF_FLG (1<<1) #define ISTR_FE_FLG (1<<0) - -#endif /* else def HOSTS_C */ #endif /* A2091_H */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/a3000.c linux/drivers/scsi/a3000.c --- v2.4.0-test8/linux/drivers/scsi/a3000.c Wed Jan 26 12:45:20 2000 +++ linux/drivers/scsi/a3000.c Mon Sep 18 13:36:24 2000 @@ -188,17 +188,13 @@ return 1; } -#ifdef MODULE - #define HOSTS_C #include "a3000.h" -Scsi_Host_Template driver_template = A3000_SCSI; +static Scsi_Host_Template driver_template = A3000_SCSI; #include "scsi_module.c" - -#endif int a3000_release(struct Scsi_Host *instance) { diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/a3000.h linux/drivers/scsi/a3000.h --- v2.4.0-test8/linux/drivers/scsi/a3000.h Fri Sep 8 12:54:34 2000 +++ linux/drivers/scsi/a3000.h Mon Sep 18 14:12:01 2000 @@ -29,8 +29,6 @@ #define CAN_QUEUE 16 #endif -#ifdef HOSTS_C - #define A3000_SCSI { proc_name: "A3000", \ proc_info: NULL, \ name: "Amiga 3000 built-in SCSI", \ @@ -44,7 +42,6 @@ sg_tablesize: SG_ALL, \ cmd_per_lun: CMD_PER_LUN, \ use_clustering: ENABLE_CLUSTERING } -#else /* * if the transfer address ANDed with this results in a non-zero @@ -95,7 +92,5 @@ #define ISTR_OE_INT (1<<2) #define ISTR_FF_FLG (1<<1) #define ISTR_FE_FLG (1<<0) - -#endif /* else def HOSTS_C */ #endif /* A3000_H */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/advansys.c linux/drivers/scsi/advansys.c --- v2.4.0-test8/linux/drivers/scsi/advansys.c Mon Jun 19 13:42:40 2000 +++ linux/drivers/scsi/advansys.c Mon Sep 18 13:36:25 2000 @@ -6785,10 +6785,8 @@ * --- Loadable Driver Support */ -#ifdef MODULE -Scsi_Host_Template driver_template = ADVANSYS; +static Scsi_Host_Template driver_template = ADVANSYS; # include "scsi_module.c" -#endif /* MODULE */ /* diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/aha152x.c linux/drivers/scsi/aha152x.c --- v2.4.0-test8/linux/drivers/scsi/aha152x.c Mon Jun 19 13:42:40 2000 +++ linux/drivers/scsi/aha152x.c Mon Sep 18 13:36:25 2000 @@ -3813,9 +3813,7 @@ return thislength < length ? thislength : length; } -#if defined(MODULE) /* Eventually this will go into an include file, but this will be later */ -Scsi_Host_Template driver_template = AHA152X; +static Scsi_Host_Template driver_template = AHA152X; #include "scsi_module.c" -#endif diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/aha1542.c linux/drivers/scsi/aha1542.c --- v2.4.0-test8/linux/drivers/scsi/aha1542.c Fri Jan 28 08:04:58 2000 +++ linux/drivers/scsi/aha1542.c Mon Sep 18 13:36:25 2000 @@ -1764,9 +1764,7 @@ } -#ifdef MODULE /* Eventually this will go into an include file, but this will be later */ -Scsi_Host_Template driver_template = AHA1542; +static Scsi_Host_Template driver_template = AHA1542; #include "scsi_module.c" -#endif diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/aha1740.c linux/drivers/scsi/aha1740.c --- v2.4.0-test8/linux/drivers/scsi/aha1740.c Thu Nov 11 16:57:30 1999 +++ linux/drivers/scsi/aha1740.c Mon Sep 18 13:36:25 2000 @@ -601,12 +601,10 @@ return 0; } -#ifdef MODULE /* Eventually this will go into an include file, but this will be later */ -Scsi_Host_Template driver_template = AHA1740; +static Scsi_Host_Template driver_template = AHA1740; #include "scsi_module.c" -#endif /* Okay, you made it all the way through. As of this writing, 3/31/93, I'm brad@saturn.gaylord.com or brad@bradpc.gaylord.com. I'll try to help as time diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/aic7xxx.c linux/drivers/scsi/aic7xxx.c --- v2.4.0-test8/linux/drivers/scsi/aic7xxx.c Thu Aug 10 13:14:40 2000 +++ linux/drivers/scsi/aic7xxx.c Mon Sep 18 13:36:25 2000 @@ -12217,12 +12217,10 @@ #include "aic7xxx_proc.c" -#ifdef MODULE /* Eventually this will go into an include file, but this will be later */ -Scsi_Host_Template driver_template = AIC7XXX; +static Scsi_Host_Template driver_template = AIC7XXX; #include "scsi_module.c" -#endif /* * Overrides for Emacs so that we almost follow Linus's tabbing style. diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/amiga7xx.h linux/drivers/scsi/amiga7xx.h --- v2.4.0-test8/linux/drivers/scsi/amiga7xx.h Fri Sep 8 12:54:34 2000 +++ linux/drivers/scsi/amiga7xx.h Mon Sep 18 14:09:49 2000 @@ -22,7 +22,6 @@ #define CAN_QUEUE 24 #endif -#if defined(HOSTS_C) || defined(MODULE) #include #define AMIGA7XX_SCSI {name: "Amiga NCR53c710 SCSI", \ @@ -36,5 +35,5 @@ sg_tablesize: 63, \ cmd_per_lun: 3, \ use_clustering: DISABLE_CLUSTERING } -#endif + #endif /* AMIGA7XX_H */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/atari_scsi.c linux/drivers/scsi/atari_scsi.c --- v2.4.0-test8/linux/drivers/scsi/atari_scsi.c Thu Nov 11 16:57:30 1999 +++ linux/drivers/scsi/atari_scsi.c Mon Sep 18 13:36:25 2000 @@ -1126,8 +1126,5 @@ #include "atari_NCR5380.c" -#ifdef MODULE -Scsi_Host_Template driver_template = ATARI_SCSI; - +static Scsi_Host_Template driver_template = ATARI_SCSI; #include "scsi_module.c" -#endif diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/atari_scsi.h linux/drivers/scsi/atari_scsi.h --- v2.4.0-test8/linux/drivers/scsi/atari_scsi.h Sun Dec 21 17:04:48 1997 +++ linux/drivers/scsi/atari_scsi.h Mon Sep 18 14:12:01 2000 @@ -51,8 +51,6 @@ #define DEFAULT_USE_TAGGED_QUEUING 0 -#if defined (HOSTS_C) || defined (MODULE) - #define ATARI_SCSI { proc_info: atari_scsi_proc_info, \ name: "Atari native SCSI", \ detect: atari_scsi_detect, \ @@ -67,10 +65,6 @@ cmd_per_lun: 0, /* initialized at run-time */ \ use_clustering: DISABLE_CLUSTERING } -#endif - -#ifndef HOSTS_C - #define NCR5380_implementation_fields /* none */ #define NCR5380_read(reg) atari_scsi_reg_read( reg ) @@ -267,7 +261,6 @@ #define NDEBUG_ANY 0xffffffff -#endif /* else def HOSTS_C */ #endif /* ndef ASM */ #endif /* ATARI_SCSI_H */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/atp870u.c linux/drivers/scsi/atp870u.c --- v2.4.0-test8/linux/drivers/scsi/atp870u.c Fri Jul 7 15:55:24 2000 +++ linux/drivers/scsi/atp870u.c Mon Sep 18 13:36:25 2000 @@ -1971,8 +1971,5 @@ } -#ifdef MODULE -Scsi_Host_Template driver_template = ATP870U; - +static Scsi_Host_Template driver_template = ATP870U; #include "scsi_module.c" -#endif diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/blz1230.c linux/drivers/scsi/blz1230.c --- v2.4.0-test8/linux/drivers/scsi/blz1230.c Fri Jan 28 08:04:58 2000 +++ linux/drivers/scsi/blz1230.c Mon Sep 18 13:36:25 2000 @@ -274,17 +274,13 @@ } } -#ifdef MODULE - #define HOSTS_C #include "blz1230.h" -Scsi_Host_Template driver_template = SCSI_BLZ1230; +static Scsi_Host_Template driver_template = SCSI_BLZ1230; #include "scsi_module.c" - -#endif int blz1230_esp_release(struct Scsi_Host *instance) { diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/blz2060.c linux/drivers/scsi/blz2060.c --- v2.4.0-test8/linux/drivers/scsi/blz2060.c Fri Jan 28 08:04:58 2000 +++ linux/drivers/scsi/blz2060.c Mon Sep 18 13:36:25 2000 @@ -236,17 +236,13 @@ } } -#ifdef MODULE - #define HOSTS_C #include "blz2060.h" -Scsi_Host_Template driver_template = SCSI_BLZ2060; +static Scsi_Host_Template driver_template = SCSI_BLZ2060; #include "scsi_module.c" - -#endif int blz2060_esp_release(struct Scsi_Host *instance) { diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/bvme6000.h linux/drivers/scsi/bvme6000.h --- v2.4.0-test8/linux/drivers/scsi/bvme6000.h Fri Sep 8 12:54:34 2000 +++ linux/drivers/scsi/bvme6000.h Mon Sep 18 14:09:49 2000 @@ -23,7 +23,6 @@ #define CAN_QUEUE 24 #endif -#if defined(HOSTS_C) || defined(MODULE) #include #define BVME6000_SCSI {name: "BVME6000 NCR53c710 SCSI", \ @@ -37,5 +36,5 @@ sg_tablesize: 63, \ cmd_per_lun: 3, \ use_clustering: DISABLE_CLUSTERING } -#endif + #endif /* BVME6000_SCSI_H */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/cpqfc.Readme linux/drivers/scsi/cpqfc.Readme --- v2.4.0-test8/linux/drivers/scsi/cpqfc.Readme Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/cpqfc.Readme Tue Sep 19 08:01:34 2000 @@ -0,0 +1,216 @@ +Notes for CPQFCTS driver for Compaq Tachyon TS +Fibre Channel Host Bus Adapter, PCI 64-bit, 66MHz +for Linux (RH 6.1, 6.2 kernel 2.2.12-32, 2.2.14-5) +SMP tested +Tested in single and dual HBA configuration, 32 and 64bit busses, +33 and 66MHz. Only supports FC-AL. +SEST size 512 Exchanges (simultaneous I/Os) limited by module kmalloc() + max of 128k bytes contiguous. +Ver 1.3.4 Sep 7, 2000 + Added Modinfo information + Fixed problem with statically linking the driver + +Ver 1.3.3, Aug 23, 2000 + Fixed device/function number in ioctl + +Ver 1.3.2, July 27, 2000 + Add include for Alpha compile on 2.2.14 kernel (cpq*i2c.c) + Change logic for different FCP-RSP sense_buffer location for HSG80 target + And search for Agilent Tachyon XL2 HBAs (not finished! - in test) + +Tested with +(storage): + Compaq RA-4x000, RAID firmware ver 2.40 - 2.54 + Seagate FC drives model ST39102FC, rev 0006 + Hitachi DK31CJ-72FC rev J8A8 + IBM DDYF-T18350R rev F60K + Compaq FC-SCSI bridge w/ DLT 35/70 Gb DLT (tape) +(servers): + Compaq PL-1850R + Compaq PL-6500 Xeon (400MHz) + Compaq PL-8500 (500MHz, 66MHz, 64bit PCI) + Compaq Alpha DS20 (RH 6.1) +(hubs): + Vixel Rapport 1000 (7-port "dumb") + Gadzoox Gibralter (12-port "dumb") + Gadzoox Capellix 2000, 3000 +(switches): + Brocade 2010, 2400, 2800, rev 2.0.3a (& later) + Gadzoox 3210 (Fabric blade beta) + Vixel 7100 (Fabric beta firmare - known hot plug issues) +using "qa_test" (esp. io_test script) suite modified from Unix tests. + +Installation: +copy file cpqfcTS.patch to /usr/src/linux +patch -p1 < cpqfcTS.patch +make menuconfig + (select SCSI low-level, Compaq FC HBA) +make dep +make modules +make modules_install + +e.g. insmod -f cpqfc + +Due to Fabric/switch delays, driver requires 4 seconds +to initialize. If adapters are found, there will be a entries at +/proc/scsi/cpqfcTS/* + +sample contents of startup messages + +************************* + scsi_register allocating 3596 bytes for CPQFCHBA + ioremap'd Membase: c887e600 + HBA Tachyon RevId 1.2 +Allocating 119808 for 576 Exchanges @ c0dc0000 +Allocating 112904 for LinkQ @ c0c20000 (576 elements) +Allocating 110600 for TachSEST for 512 Exchanges + cpqfcTS: writing IMQ BASE 7C0000h PI 7C4000h + cpqfcTS: SEST c0e40000(virt): Wrote base E40000h @ c887e740 +cpqfcTS: New FC port 0000E8h WWN: 500507650642499D SCSI Chan/Trgt 0/0 +cpqfcTS: New FC port 0000EFh WWN: 50000E100000D5A6 SCSI Chan/Trgt 0/1 +cpqfcTS: New FC port 0000E4h WWN: 21000020370097BB SCSI Chan/Trgt 0/2 +cpqfcTS: New FC port 0000E2h WWN: 2100002037009946 SCSI Chan/Trgt 0/3 +cpqfcTS: New FC port 0000E1h WWN: 21000020370098FE SCSI Chan/Trgt 0/4 +cpqfcTS: New FC port 0000E0h WWN: 21000020370097B2 SCSI Chan/Trgt 0/5 +cpqfcTS: New FC port 0000DCh WWN: 2100002037006CC1 SCSI Chan/Trgt 0/6 +cpqfcTS: New FC port 0000DAh WWN: 21000020370059F6 SCSI Chan/Trgt 0/7 +cpqfcTS: New FC port 00000Fh WWN: 500805F1FADB0E20 SCSI Chan/Trgt 0/8 +cpqfcTS: New FC port 000008h WWN: 500805F1FADB0EBA SCSI Chan/Trgt 0/9 +cpqfcTS: New FC port 000004h WWN: 500805F1FADB1EB9 SCSI Chan/Trgt 0/10 +cpqfcTS: New FC port 000002h WWN: 500805F1FADB1ADE SCSI Chan/Trgt 0/11 +cpqfcTS: New FC port 000001h WWN: 500805F1FADBA2CA SCSI Chan/Trgt 0/12 +scsi4 : Compaq FibreChannel HBA Tachyon TS HPFC-5166A/1.2: WWN 500508B200193F50 + on PCI bus 0 device 0xa0fc irq 5 IObaseL 0x3400, MEMBASE 0xc6ef8600 +PCI bus width 32 bits, bus speed 33 MHz +FCP-SCSI Driver v1.3.0 +GBIC detected: Short-wave. LPSM 0h Monitor +scsi : 5 hosts. + Vendor: IBM Model: DDYF-T18350R Rev: F60K + Type: Direct-Access ANSI SCSI revision: 03 +Detected scsi disk sdb at scsi4, channel 0, id 0, lun 0 + Vendor: HITACHI Model: DK31CJ-72FC Rev: J8A8 + Type: Direct-Access ANSI SCSI revision: 02 +Detected scsi disk sdc at scsi4, channel 0, id 1, lun 0 + Vendor: SEAGATE Model: ST39102FC Rev: 0006 + Type: Direct-Access ANSI SCSI revision: 02 +Detected scsi disk sdd at scsi4, channel 0, id 2, lun 0 + Vendor: SEAGATE Model: ST39102FC Rev: 0006 + Type: Direct-Access ANSI SCSI revision: 02 +Detected scsi disk sde at scsi4, channel 0, id 3, lun 0 + Vendor: SEAGATE Model: ST39102FC Rev: 0006 + Type: Direct-Access ANSI SCSI revision: 02 +Detected scsi disk sdf at scsi4, channel 0, id 4, lun 0 + Vendor: SEAGATE Model: ST39102FC Rev: 0006 + Type: Direct-Access ANSI SCSI revision: 02 +Detected scsi disk sdg at scsi4, channel 0, id 5, lun 0 + Vendor: SEAGATE Model: ST39102FC Rev: 0006 + Type: Direct-Access ANSI SCSI revision: 02 +Detected scsi disk sdh at scsi4, channel 0, id 6, lun 0 + Vendor: SEAGATE Model: ST39102FC Rev: 0006 + Type: Direct-Access ANSI SCSI revision: 02 +Detected scsi disk sdi at scsi4, channel 0, id 7, lun 0 + Vendor: COMPAQ Model: LOGICAL VOLUME Rev: 2.48 + Type: Direct-Access ANSI SCSI revision: 02 +Detected scsi disk sdj at scsi4, channel 0, id 8, lun 0 + Vendor: COMPAQ Model: LOGICAL VOLUME Rev: 2.48 + Type: Direct-Access ANSI SCSI revision: 02 +Detected scsi disk sdk at scsi4, channel 0, id 8, lun 1 + Vendor: COMPAQ Model: LOGICAL VOLUME Rev: 2.40 + Type: Direct-Access ANSI SCSI revision: 02 +Detected scsi disk sdl at scsi4, channel 0, id 9, lun 0 + Vendor: COMPAQ Model: LOGICAL VOLUME Rev: 2.40 + Type: Direct-Access ANSI SCSI revision: 02 +Detected scsi disk sdm at scsi4, channel 0, id 9, lun 1 + Vendor: COMPAQ Model: LOGICAL VOLUME Rev: 2.54 + Type: Direct-Access ANSI SCSI revision: 02 +Detected scsi disk sdn at scsi4, channel 0, id 10, lun 0 + Vendor: COMPAQ Model: LOGICAL VOLUME Rev: 2.54 + Type: Direct-Access ANSI SCSI revision: 02 +Detected scsi disk sdo at scsi4, channel 0, id 11, lun 0 + Vendor: COMPAQ Model: LOGICAL VOLUME Rev: 2.54 + Type: Direct-Access ANSI SCSI revision: 02 +Detected scsi disk sdp at scsi4, channel 0, id 11, lun 1 + Vendor: COMPAQ Model: LOGICAL VOLUME Rev: 2.54 + Type: Direct-Access ANSI SCSI revision: 02 +Detected scsi disk sdq at scsi4, channel 0, id 12, lun 0 + Vendor: COMPAQ Model: LOGICAL VOLUME Rev: 2.54 + Type: Direct-Access ANSI SCSI revision: 02 +Detected scsi disk sdr at scsi4, channel 0, id 12, lun 1 +resize_dma_pool: unknown device type 12 +resize_dma_pool: unknown device type 12 +SCSI device sdb: hdwr sector= 512 bytes. Sectors= 35843670 [17501 MB] [17.5 GB] + sdb: sdb1 +SCSI device sdc: hdwr sector= 512 bytes. Sectors= 144410880 [70513 MB] [70.5 GB] + sdc: sdc1 +SCSI device sdd: hdwr sector= 512 bytes. Sectors= 17783240 [8683 MB] [8.7 GB] + sdd: sdd1 +SCSI device sde: hdwr sector= 512 bytes. Sectors= 17783240 [8683 MB] [8.7 GB] + sde: sde1 +SCSI device sdf: hdwr sector= 512 bytes. Sectors= 17783240 [8683 MB] [8.7 GB] + sdf: sdf1 +SCSI device sdg: hdwr sector= 512 bytes. Sectors= 17783240 [8683 MB] [8.7 GB] + sdg: sdg1 +SCSI device sdh: hdwr sector= 512 bytes. Sectors= 17783240 [8683 MB] [8.7 GB] + sdh: sdh1 +SCSI device sdi: hdwr sector= 512 bytes. Sectors= 17783240 [8683 MB] [8.7 GB] + sdi: sdi1 +SCSI device sdj: hdwr sector= 512 bytes. Sectors= 2056160 [1003 MB] [1.0 GB] + sdj: sdj1 +SCSI device sdk: hdwr sector= 512 bytes. Sectors= 2052736 [1002 MB] [1.0 GB] + sdk: sdk1 +SCSI device sdl: hdwr sector= 512 bytes. Sectors= 17764320 [8673 MB] [8.7 GB] + sdl: sdl1 +SCSI device sdm: hdwr sector= 512 bytes. Sectors= 8380320 [4091 MB] [4.1 GB] + sdm: sdm1 +SCSI device sdn: hdwr sector= 512 bytes. Sectors= 17764320 [8673 MB] [8.7 GB] + sdn: sdn1 +SCSI device sdo: hdwr sector= 512 bytes. Sectors= 17764320 [8673 MB] [8.7 GB] + sdo: sdo1 +SCSI device sdp: hdwr sector= 512 bytes. Sectors= 17764320 [8673 MB] [8.7 GB] + sdp: sdp1 +SCSI device sdq: hdwr sector= 512 bytes. Sectors= 2056160 [1003 MB] [1.0 GB] + sdq: sdq1 +SCSI device sdr: hdwr sector= 512 bytes. Sectors= 2052736 [1002 MB] [1.0 GB] + sdr: sdr1 + +************************* + +If a GBIC of type Short-wave, Long-wave, or Copper is detected, it will +print out; otherwise, "none" is displayed. If the cabling is correct +and a loop circuit is completed, you should see "Monitor"; otherwise, +"LoopFail" (on open circuit) or some LPSM number/state with bit 3 set. + + +ERRATA: +1. Normally, Linux Scsi queries FC devices with INQUIRY strings. All LUNs +found according to INQUIRY should get READ commands at sector 0 to find +partition table, etc. Older kernels only query the first 4 devices. Some +Linux kernels only look for one LUN per target (i.e. FC device). + +2. Physically removing a device, or a malfunctioning system which hides a +device, leads to a 30-second timeout and subsequent _abort call. +In some process contexts, this will hang the kernel (crashing the system). +Single bit errors in frames and virtually all hot plugging events are +gracefully handled with internal driver timer and Abort processing. + +3. Some SCSI drives with error conditions will not handle the 7 second timeout +in this software driver, leading to infinite retries on timed out SCSI commands. +The 7 secs balances the need to quickly recover from lost frames (esp. on sequence +initiatives) and time needed by older/slower/error-state drives in responding. +This can be easily changed in "Exchanges[].timeOut". + +4. Due to the nature of FC soft addressing, there is no assurance that the +same LUNs (drives) will have the same path (e.g. /dev/sdb1) from one boot to +next. Dynamic soft address changes (i.e. 24-bit FC port_id) are +supported during run time (e.g. due to hot plug event) by the use of WWN to +SCSI Nexus (channel/target/LUN) mapping. + +5. Compaq RA4x00 firmware version 2.54 and later supports SSP (Selective +Storage Presentation), which maps LUNs to a WWN. If RA4x00 firmware prior +2.54 (e.g. older controller) is used, or the FC HBA is replaced (another WWN +is used), logical volumes on the RA4x00 will no longer be visible. + + +Send questions/comments to: +donald.zimmerman@compaq.com +dszimmerman@yahoo.com diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/cpqfcTS.h linux/drivers/scsi/cpqfcTS.h --- v2.4.0-test8/linux/drivers/scsi/cpqfcTS.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/cpqfcTS.h Tue Sep 19 08:01:34 2000 @@ -0,0 +1,39 @@ +#ifndef CPQFCTS_H +#define CPQFCTS_H +#include "cpqfcTSstructs.h" + +// These functions are required by the Linux SCSI layers +extern int cpqfcTS_detect(Scsi_Host_Template *); +extern int cpqfcTS_release(struct Scsi_Host *); +const char * cpqfcTS_info(struct Scsi_Host *); +extern int cpqfcTS_proc_info(char *, char **, off_t, int, int, int); +extern int cpqfcTS_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *)); +extern int cpqfcTS_abort(Scsi_Cmnd *); +extern int cpqfcTS_reset(Scsi_Cmnd *, unsigned int); +extern int cpqfcTS_biosparam(Disk *, kdev_t, int[]); +extern int cpqfcTS_ioctl( Scsi_Device *ScsiDev, int Cmnd, void *arg); + +// note: since Tachyon TS supports an extended scatter/gather +// linked list of infinite length (with linked Ext S/G pages, +// limited only by available physical memory) we use SG_ALL. + +#define CPQFCTS { \ + detect: cpqfcTS_detect, \ + release: cpqfcTS_release, \ + info: cpqfcTS_info, \ + proc_info: cpqfcTS_proc_info, \ + ioctl: cpqfcTS_ioctl, \ + queuecommand: cpqfcTS_queuecommand, \ + eh_abort_handler: cpqfcTS_abort, \ + reset: cpqfcTS_reset, \ + bios_param: cpqfcTS_biosparam, \ + can_queue: CPQFCTS_REQ_QUEUE_LEN, \ + this_id: -1, \ + sg_tablesize: SG_ALL, \ + cmd_per_lun: CPQFCTS_CMD_PER_LUN, \ + present: 0, \ + unchecked_isa_dma: 0, \ + use_clustering: ENABLE_CLUSTERING \ +} + +#endif /* CPQFCTS_H */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/cpqfcTSchip.h linux/drivers/scsi/cpqfcTSchip.h --- v2.4.0-test8/linux/drivers/scsi/cpqfcTSchip.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/cpqfcTSchip.h Tue Sep 19 08:01:34 2000 @@ -0,0 +1,238 @@ +/* Copyright(c) 2000, Compaq Computer Corporation + * Fibre Channel Host Bus Adapter + * 64-bit, 66MHz PCI + * Originally developed and tested on: + * (front): [chip] Tachyon TS HPFC-5166A/1.2 L2C1090 ... + * SP# P225CXCBFIEL6T, Rev XC + * SP# 161290-001, Rev XD + * (back): Board No. 010008-001 A/W Rev X5, FAB REV X5 + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * Written by Don Zimmerman +*/ +#ifndef CPQFCTSCHIP_H +#define CPQFCTSCHIP_H +#ifndef TACHYON_CHIP_INC + +// FC-PH (Physical) specification levels for Login payloads +// NOTE: These are NOT strictly complied with by any FC vendors + +#define FC_PH42 0x08 +#define FC_PH43 0x09 +#define FC_PH3 0x20 + +#define TACHLITE_TS_RX_SIZE 1024 // max inbound frame size +// "I" prefix is for Include + +#define IVENDID 0x00 // word +#define IDEVID 0x02 +#define ITLCFGCMD 0x04 +#define IMEMBASE 0x18 // Tachyon +#define ITLMEMBASE 0x1C // Tachlite +#define IIOBASEL 0x10 // Tachyon I/O base address, lower 256 bytes +#define IIOBASEU 0x14 // Tachyon I/O base address, upper 256 bytes +#define ITLIOBASEL 0x14 // TachLite I/O base address, lower 256 bytes +#define ITLIOBASEU 0x18 // TachLite I/O base address, upper 256 bytes +#define ITLRAMBASE 0x20 // TL on-board RAM start +#define ISROMBASE 0x24 +#define IROMBASE 0x30 + +#define ICFGCMD 0x04 // PCI config - PCI config access (word) +#define ICFGSTAT 0x06 // PCI status (R - word) +#define IRCTR_WCTR 0x1F2 // ROM control / pre-fetch wait counter +#define IPCIMCTR 0x1F3 // PCI master control register +#define IINTPEND 0x1FD // Interrupt pending (I/O Upper - Tachyon & TL) +#define IINTEN 0x1FE // Interrupt enable (I/O Upper - Tachyon & TL) +#define IINTSTAT 0x1FF // Interrupt status (I/O Upper - Tachyon & TL) + +#define IMQ_BASE 0x80 +#define IMQ_LENGTH 0x84 +#define IMQ_CONSUMER_INDEX 0x88 +#define IMQ_PRODUCER_INDEX 0x8C // Tach copies its INDX to bits 0-7 of value + +/* +// IOBASE UPPER +#define SFSBQ_BASE 0x00 // single-frame sequences +#define SFSBQ_LENGTH 0x04 +#define SFSBQ_PRODUCER_INDEX 0x08 +#define SFSBQ_CONSUMER_INDEX 0x0C // (R) +#define SFS_BUFFER_LENGTH 0X10 + // SCSI-FCP hardware assists +#define SEST_BASE 0x40 // SSCI Exchange State Table +#define SEST_LENGTH 0x44 +#define SCSI_BUFFER_LENGTH 0x48 +#define SEST_LINKED_LIST 0x4C + +#define TACHYON_My_ID 0x6C +#define TACHYON_CONFIGURATION 0x84 // (R/W) reset val 2 +#define TACHYON_CONTROL 0x88 +#define TACHYON_STATUS 0x8C // (R) +#define TACHYON_FLUSH_SEST 0x90 // (R/W) +#define TACHYON_EE_CREDIT_TMR 0x94 // (R) +#define TACHYON_BB_CREDIT_TMR 0x98 // (R) +#define TACHYON_RCV_FRAME_ERR 0x9C // (R) +#define FRAME_MANAGER_CONFIG 0xC0 // (R/W) +#define FRAME_MANAGER_CONTROL 0xC4 +#define FRAME_MANAGER_STATUS 0xC8 // (R) +#define FRAME_MANAGER_ED_TOV 0xCC +#define FRAME_MANAGER_LINK_ERR1 0xD0 // (R) +#define FRAME_MANAGER_LINK_ERR2 0xD4 // (R) +#define FRAME_MANAGER_TIMEOUT2 0xD8 // (W) +#define FRAME_MANAGER_BB_CREDIT 0xDC // (R) +#define FRAME_MANAGER_WWN_HI 0xE0 // (R/W) +#define FRAME_MANAGER_WWN_LO 0xE4 // (R/W) +#define FRAME_MANAGER_RCV_AL_PA 0xE8 // (R) +#define FRAME_MANAGER_PRIMITIVE 0xEC // {K28.5} byte1 byte2 byte3 +*/ + +#define TL_MEM_ERQ_BASE 0x0 //ERQ Base +#define TL_IO_ERQ_BASE 0x0 //ERQ base + +#define TL_MEM_ERQ_LENGTH 0x4 //ERQ Length +#define TL_IO_ERQ_LENGTH 0x4 //ERQ Length + +#define TL_MEM_ERQ_PRODUCER_INDEX 0x8 //ERQ Producer Index register +#define TL_IO_ERQ_PRODUCER_INDEX 0x8 //ERQ Producer Index register + +#define TL_MEM_ERQ_CONSUMER_INDEX_ADR 0xC //ERQ Consumer Index address register +#define TL_IO_ERQ_CONSUMER_INDEX_ADR 0xC //ERQ Consumer Index address register + +#define TL_MEM_ERQ_CONSUMER_INDEX 0xC //ERQ Consumer Index +#define TL_IO_ERQ_CONSUMER_INDEX 0xC //ERQ Consumer Index + +#define TL_MEM_SFQ_BASE 0x50 //SFQ Base +#define TL_IO_SFQ_BASE 0x50 //SFQ base + +#define TL_MEM_SFQ_LENGTH 0x54 //SFQ Length +#define TL_IO_SFQ_LENGTH 0x54 //SFQ Length + +#define TL_MEM_SFQ_CONSUMER_INDEX 0x58 //SFQ Consumer Index +#define TL_IO_SFQ_CONSUMER_INDEX 0x58 //SFQ Consumer Index + +#define TL_MEM_IMQ_BASE 0x80 //IMQ Base +#define TL_IO_IMQ_BASE 0x80 //IMQ base + +#define TL_MEM_IMQ_LENGTH 0x84 //IMQ Length +#define TL_IO_IMQ_LENGTH 0x84 //IMQ Length + +#define TL_MEM_IMQ_CONSUMER_INDEX 0x88 //IMQ Consumer Index +#define TL_IO_IMQ_CONSUMER_INDEX 0x88 //IMQ Consumer Index + +#define TL_MEM_IMQ_PRODUCER_INDEX_ADR 0x8C //IMQ Producer Index address register +#define TL_IO_IMQ_PRODUCER_INDEX_ADR 0x8C //IMQ Producer Index address register + +#define TL_MEM_SEST_BASE 0x140 //SFQ Base +#define TL_IO_SEST_BASE 0x40 //SFQ base + +#define TL_MEM_SEST_LENGTH 0x144 //SFQ Length +#define TL_IO_SEST_LENGTH 0x44 //SFQ Length + +#define TL_MEM_SEST_LINKED_LIST 0x14C + +#define TL_MEM_SEST_SG_PAGE 0x168 // Extended Scatter/Gather page size + +#define TL_MEM_TACH_My_ID 0x16C +#define TL_IO_TACH_My_ID 0x6C //My AL_PA ID + +#define TL_MEM_TACH_CONFIG 0x184 //Tachlite Configuration register +#define TL_IO_CONFIG 0x84 //Tachlite Configuration register + +#define TL_MEM_TACH_CONTROL 0x188 //Tachlite Control register +#define TL_IO_CTR 0x88 //Tachlite Control register + +#define TL_MEM_TACH_STATUS 0x18C //Tachlite Status register +#define TL_IO_STAT 0x8C //Tachlite Status register + +#define TL_MEM_FM_CONFIG 0x1C0 //Frame Manager Configuration register +#define TL_IO_FM_CONFIG 0xC0 //Frame Manager Configuration register + +#define TL_MEM_FM_CONTROL 0x1C4 //Frame Manager Control +#define TL_IO_FM_CTL 0xC4 //Frame Manager Control + +#define TL_MEM_FM_STATUS 0x1C8 //Frame Manager Status +#define TL_IO_FM_STAT 0xC8 //Frame Manager Status + +#define TL_MEM_FM_LINK_STAT1 0x1D0 //Frame Manager Link Status 1 +#define TL_IO_FM_LINK_STAT1 0xD0 //Frame Manager Link Status 1 + +#define TL_MEM_FM_LINK_STAT2 0x1D4 //Frame Manager Link Status 2 +#define TL_IO_FM_LINK_STAT2 0xD4 //Frame Manager Link Status 2 + +#define TL_MEM_FM_TIMEOUT2 0x1D8 // (W) + +#define TL_MEM_FM_BB_CREDIT0 0x1DC + +#define TL_MEM_FM_WWN_HI 0x1E0 //Frame Manager World Wide Name High +#define TL_IO_FM_WWN_HI 0xE0 //Frame Manager World Wide Name High + +#define TL_MEM_FM_WWN_LO 0x1E4 //Frame Manager World Wide Name LOW +#define TL_IO_FM_WWN_LO 0xE4 //Frame Manager World Wide Name Low + +#define TL_MEM_FM_RCV_AL_PA 0x1E8 //Frame Manager AL_PA Received register +#define TL_IO_FM_ALPA 0xE8 //Frame Manager AL_PA Received register + +#define TL_MEM_FM_ED_TOV 0x1CC + +#define TL_IO_ROMCTR 0xFA //TL PCI ROM Control Register +#define TL_IO_PCIMCTR 0xFB //TL PCI Master Control Register +#define TL_IO_SOFTRST 0xFC //Tachlite Configuration register +#define TL_MEM_SOFTRST 0x1FC //Tachlite Configuration register + +// completion message types (bit 8 set means Interrupt generated) +// CM_Type +#define OUTBOUND_COMPLETION 0 +#define ERROR_IDLE_COMPLETION 0x01 +#define OUT_HI_PRI_COMPLETION 0x01 +#define INBOUND_MFS_COMPLETION 0x02 +#define INBOUND_000_COMPLETION 0x03 +#define INBOUND_SFS_COMPLETION 0x04 // Tachyon & TachLite +#define ERQ_FROZEN_COMPLETION 0x06 // TachLite +#define INBOUND_C1_TIMEOUT 0x05 +#define INBOUND_BUSIED_FRAME 0x06 +#define SFS_BUF_WARN 0x07 +#define FCP_FROZEN_COMPLETION 0x07 // TachLite +#define MFS_BUF_WARN 0x08 +#define IMQ_BUF_WARN 0x09 +#define FRAME_MGR_INTERRUPT 0x0A +#define READ_STATUS 0x0B +#define INBOUND_SCSI_DATA_COMPLETION 0x0C +#define INBOUND_FCP_XCHG_COMPLETION 0x0C // TachLite +#define INBOUND_SCSI_DATA_COMMAND 0x0D +#define BAD_SCSI_FRAME 0x0E +#define INB_SCSI_STATUS_COMPLETION 0x0F +#define BUFFER_PROCESSED_COMPLETION 0x11 + +// FC-AL (Tachyon) Loop Port State Machine defs +// (loop "Up" states) +#define MONITORING 0x0 +#define ARBITRATING 0x1 +#define ARBITRAT_WON 0x2 +#define OPEN 0x3 +#define OPENED 0x4 +#define XMITTD_CLOSE 0x5 +#define RCVD_CLOSE 0x6 +#define TRANSFER 0x7 + +// (loop "Down" states) +#define INITIALIZING 0x8 +#define O_I_INIT 0x9 +#define O_I_PROTOCOL 0xa +#define O_I_LIP_RCVD 0xb +#define HOST_CONTROL 0xc +#define LOOP_FAIL 0xd +// (no 0xe) +#define OLD_PORT 0xf + + + +#define TACHYON_CHIP_INC +#endif +#endif /* CPQFCTSCHIP_H */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/cpqfcTScontrol.c linux/drivers/scsi/cpqfcTScontrol.c --- v2.4.0-test8/linux/drivers/scsi/cpqfcTScontrol.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/cpqfcTScontrol.c Tue Sep 19 08:01:34 2000 @@ -0,0 +1,2200 @@ +/* Copyright 2000, Compaq Computer Corporation + * Fibre Channel Host Bus Adapter + * 64-bit, 66MHz PCI + * Originally developed and tested on: + * (front): [chip] Tachyon TS HPFC-5166A/1.2 L2C1090 ... + * SP# P225CXCBFIEL6T, Rev XC + * SP# 161290-001, Rev XD + * (back): Board No. 010008-001 A/W Rev X5, FAB REV X5 + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * Written by Don Zimmerman +*/ +/* These functions control the host bus adapter (HBA) hardware. The main chip + control takes place in the interrupt handler where we process the IMQ + (Inbound Message Queue). The IMQ is Tachyon's way of communicating FC link + events and state information to the driver. The Single Frame Queue (SFQ) + buffers incoming FC frames for processing by the driver. References to + "TL/TS UG" are for: + "HP HPFC-5100/5166 Tachyon TL/TS ICs User Guide", August 16, 1999, 1st Ed. + Hewlitt Packard Manual Part Number 5968-1083E. +*/ + +#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s)) + +#include +#include +#include +#include // request_region() prototype +#include +#include // need "kfree" for ext. S/G pages +#include +#include +#include +#include +#include // struct pt_regs for IRQ handler & Port I/O +#include +#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,18) +#include +#else +#include +#endif + +#include "sd.h" +#include "hosts.h" // Scsi_Host definition for INT handler +#include "cpqfcTSchip.h" +#include "cpqfcTSstructs.h" + +//#define IMQ_DEBUG 1 + +static void fcParseLinkStatusCounters(TACHYON * fcChip); +static void CpqTsGetSFQEntry(TACHYON * fcChip, + USHORT pi, ULONG * buffr, BOOLEAN UpdateChip); + + +// Note special requirements for Q alignment! (TL/TS UG pg. 190) +// We place critical index pointers at end of QUE elements to assist +// in non-symbolic (i.e. memory dump) debugging +// opcode defines placement of Queues (e.g. local/external RAM) + +int CpqTsCreateTachLiteQues( void* pHBA, int opcode) +{ + CPQFCHBA *cpqfcHBAdata = (CPQFCHBA*)pHBA; + PTACHYON fcChip = &cpqfcHBAdata->fcChip; + + int iStatus=0; + unsigned long ulAddr; + + + // NOTE! fcMemManager() will return system virtual addresses. + // System (kernel) virtual addresses, though non-paged, still + // aren't physical addresses. Convert to PHYSICAL_ADDRESS for Tachyon's + // DMA use. + ENTER("CreateTachLiteQues"); + + + // Allocate primary EXCHANGES array... + + printk("Allocating %u for %u Exchanges ", + (ULONG)sizeof(FC_EXCHANGES), TACH_MAX_XID); + fcChip->Exchanges = kmalloc( sizeof( FC_EXCHANGES), GFP_KERNEL ); + printk("@ %p\n", fcChip->Exchanges); + + if( fcChip->Exchanges == NULL ) // fatal error!! + { + printk("kmalloc failure on Exchanges: fatal error\n"); + return -1; + } + // zero out the entire EXCHANGE space + memset( fcChip->Exchanges, 0, sizeof( FC_EXCHANGES)); + + + printk("Allocating %u for LinkQ ", (ULONG)sizeof(FC_LINK_QUE)); + cpqfcHBAdata->fcLQ = kmalloc( sizeof( FC_LINK_QUE), GFP_KERNEL ); + printk("@ %p (%u elements)\n", cpqfcHBAdata->fcLQ, FC_LINKQ_DEPTH); + memset( cpqfcHBAdata->fcLQ, 0, sizeof( FC_LINK_QUE)); + + if( cpqfcHBAdata->fcLQ == NULL ) // fatal error!! + { + printk("kmalloc failure on fc Link Que: fatal error\n"); + return -1; + } + // zero out the entire EXCHANGE space + memset( cpqfcHBAdata->fcLQ, 0, sizeof( FC_LINK_QUE)); + + + + + // Verify that basic Tach I/O registers are not NULL + + if( !fcChip->Registers.ReMapMemBase ) + { + printk("HBA base address NULL: fatal error\n"); + return -1; + } + + + // Initialize the fcMemManager memory pairs (stores allocated/aligned + // pairs for future freeing) + memset( cpqfcHBAdata->dynamic_mem, 0, sizeof(cpqfcHBAdata->dynamic_mem)); + + + // Allocate Tach's Exchange Request Queue (each ERQ entry 32 bytes) + + fcChip->ERQ = fcMemManager( &cpqfcHBAdata->dynamic_mem[0], + sizeof( TachLiteERQ ), 32*(ERQ_LEN), 0L ); + if( !fcChip->ERQ ) + { + printk("kmalloc/alignment failure on ERQ: fatal error\n"); + return -1; + } + fcChip->ERQ->length = ERQ_LEN-1; + ulAddr = virt_to_bus( fcChip->ERQ); +#if BITS_PER_LONG > 32 + if( (ulAddr >> 32) ) + { + printk(" FATAL! ERQ ptr %p exceeds Tachyon's 32-bit register size\n", + (void*)ulAddr); + return -1; // failed + } +#endif + fcChip->ERQ->base = (ULONG)ulAddr; // copy for quick reference + + + // Allocate Tach's Inbound Message Queue (32 bytes per entry) + + fcChip->IMQ = fcMemManager( &cpqfcHBAdata->dynamic_mem[0], + sizeof( TachyonIMQ ), 32*(IMQ_LEN), 0L ); + if( !fcChip->IMQ ) + { + printk("kmalloc/alignment failure on IMQ: fatal error\n"); + return -1; + } + fcChip->IMQ->length = IMQ_LEN-1; + + ulAddr = virt_to_bus( fcChip->IMQ); +#if BITS_PER_LONG > 32 + if( (ulAddr >> 32) ) + { + printk(" FATAL! IMQ ptr %p exceeds Tachyon's 32-bit register size\n", + (void*)ulAddr); + return -1; // failed + } +#endif + fcChip->IMQ->base = (ULONG)ulAddr; // copy for quick reference + + + // Allocate Tach's Single Frame Queue (64 bytes per entry) + fcChip->SFQ = fcMemManager( &cpqfcHBAdata->dynamic_mem[0], + sizeof( TachLiteSFQ ), 64*(SFQ_LEN),0L ); + if( !fcChip->SFQ ) + { + printk("kmalloc/alignment failure on SFQ: fatal error\n"); + return -1; + } + fcChip->SFQ->length = SFQ_LEN-1; // i.e. Que length [# entries - + // min. 32; max. 4096 (0xffff)] + + ulAddr = virt_to_bus( fcChip->SFQ); +#if BITS_PER_LONG > 32 + if( (ulAddr >> 32) ) + { + printk(" FATAL! SFQ ptr %p exceeds Tachyon's 32-bit register size\n", + (void*)ulAddr); + return -1; // failed + } +#endif + fcChip->SFQ->base = (ULONG)ulAddr; // copy for quick reference + + + // Allocate SCSI Exchange State Table; aligned nearest @sizeof + // power-of-2 boundary + // LIVE DANGEROUSLY! Assume the boundary for SEST mem will + // be on physical page (e.g. 4k) boundary. + printk("Allocating %u for TachSEST for %u Exchanges\n", + (ULONG)sizeof(TachSEST), TACH_SEST_LEN); + fcChip->SEST = fcMemManager( &cpqfcHBAdata->dynamic_mem[0], + sizeof(TachSEST), 4, 0L ); +// sizeof(TachSEST), 64*TACH_SEST_LEN, 0L ); + if( !fcChip->SEST ) + { + printk("kmalloc/alignment failure on SEST: fatal error\n"); + return -1; + } + + fcChip->SEST->length = TACH_SEST_LEN; // e.g. DON'T subtract one + // (TL/TS UG, pg 153) + + ulAddr = virt_to_bus( fcChip->SEST); +#if BITS_PER_LONG > 32 + if( (ulAddr >> 32) ) + { + printk(" FATAL! SFQ ptr %p exceeds Tachyon's 32-bit register size\n", + (void*)ulAddr); + return -1; // failed + } +#endif + fcChip->SEST->base = (ULONG)ulAddr; // copy for quick reference + + + // Now that structures are defined, + // fill in Tachyon chip registers... + + // EEEEEEEE EXCHANGE REQUEST QUEUE + + writel( fcChip->ERQ->base, + (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_BASE)); + + writel( fcChip->ERQ->length, + (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_LENGTH)); + + + fcChip->ERQ->producerIndex = 0L; + writel( fcChip->ERQ->producerIndex, + (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_PRODUCER_INDEX)); + + + // NOTE! write consumer index last, since the write + // causes Tachyon to process the other registers + + ulAddr = virt_to_bus( &fcChip->ERQ->consumerIndex); + + // NOTE! Tachyon DMAs to the ERQ consumer Index host + // address; must be correctly aligned + writel( (ULONG)ulAddr, + (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_CONSUMER_INDEX_ADR)); + + + + // IIIIIIIIIIIII INBOUND MESSAGE QUEUE + // Tell Tachyon where the Que starts + + // set the Host's pointer for Tachyon to access + + printk(" cpqfcTS: writing IMQ BASE %Xh ", fcChip->IMQ->base ); + writel( fcChip->IMQ->base, + (fcChip->Registers.ReMapMemBase + IMQ_BASE)); + + writel( fcChip->IMQ->length, + (fcChip->Registers.ReMapMemBase + IMQ_LENGTH)); + + writel( fcChip->IMQ->consumerIndex, + (fcChip->Registers.ReMapMemBase + IMQ_CONSUMER_INDEX)); + + + // NOTE: TachLite DMAs to the producerIndex host address + // must be correctly aligned with address bits 1-0 cleared + // Writing the BASE register clears the PI register, so write it last + ulAddr = virt_to_bus( &fcChip->IMQ->producerIndex); +#if BITS_PER_LONG > 32 + if( (ulAddr >> 32) ) + { + printk(" FATAL! IMQ ptr %p exceeds Tachyon's 32-bit register size\n", + (void*)ulAddr); + return -1; // failed + } +#endif +//#if DBG + printk(" PI %Xh\n", (ULONG)ulAddr ); +//#endif + writel( (ULONG)ulAddr, + (fcChip->Registers.ReMapMemBase + IMQ_PRODUCER_INDEX)); + + + + // SSSSSSSSSSSSSSS SINGLE FRAME SEQUENCE + // Tell TachLite where the Que starts + + writel( fcChip->SFQ->base, + (fcChip->Registers.ReMapMemBase + TL_MEM_SFQ_BASE)); + + writel( fcChip->SFQ->length, + (fcChip->Registers.ReMapMemBase + TL_MEM_SFQ_LENGTH)); + + + // tell TachLite where SEST table is & how long + writel( fcChip->SEST->base, + (fcChip->Registers.ReMapMemBase + TL_MEM_SEST_BASE)); + + printk(" cpqfcTS: SEST %p(virt): Wrote base %Xh @ %p\n", + fcChip->SEST, fcChip->SEST->base, + fcChip->Registers.ReMapMemBase + TL_MEM_SEST_BASE); + + writel( fcChip->SEST->length, + (fcChip->Registers.ReMapMemBase + TL_MEM_SEST_LENGTH)); + + writel( (TL_EXT_SG_PAGE_COUNT-1), + (fcChip->Registers.ReMapMemBase + TL_MEM_SEST_SG_PAGE)); + + + LEAVE("CreateTachLiteQues"); + + return iStatus; +} + + + +// function to return TachLite to Power On state +// 1st - reset tachyon ('SOFT' reset) +// others - future + +int CpqTsResetTachLite(void *pHBA, int type) +{ + CPQFCHBA *cpqfcHBAdata = (CPQFCHBA*)pHBA; + PTACHYON fcChip = &cpqfcHBAdata->fcChip; + ULONG ulBuff, i; + int ret_status=0; // def. success + + ENTER("ResetTach"); + + switch(type) + { + + case CLEAR_FCPORTS: + + // in case he was running previously, mask Tach's interrupt + writeb( 0, (fcChip->Registers.ReMapMemBase + IINTEN)); + + // de-allocate mem for any Logged in ports + // (e.g., our module is unloading) + // search the forward linked list, de-allocating + // the memory we allocated when the port was initially logged in + { + PFC_LOGGEDIN_PORT pLoggedInPort = fcChip->fcPorts.pNextPort; + PFC_LOGGEDIN_PORT ptr; +// printk("checking for allocated LoggedInPorts...\n"); + + while( pLoggedInPort ) + { + ptr = pLoggedInPort; + pLoggedInPort = ptr->pNextPort; +// printk("kfree(%p) on FC LoggedInPort port_id 0x%06lX\n", +// ptr, ptr->port_id); + kfree( ptr ); + } + } + // (continue resetting hardware...) + + case 1: // RESTART Tachyon (power-up state) + + // in case he was running previously, mask Tach's interrupt + writeb( 0, (fcChip->Registers.ReMapMemBase + IINTEN)); + // turn OFF laser (NOTE: laser is turned + // off during reset, because GPIO4 is cleared + // to 0 by reset action - see TLUM, sec 7.22) + // However, CPQ 64-bit HBAs have a "health + // circuit" which keeps laser ON for a brief + // period after it is turned off ( < 1s) + + fcChip->LaserControl( fcChip->Registers.ReMapMemBase, 0); + + + + // soft reset timing constraints require: + // 1. set RST to 1 + // 2. read SOFTRST register + // (128 times per R. Callison code) + // 3. clear PCI ints + // 4. clear RST to 0 + writel( 0xff000001L, + (fcChip->Registers.ReMapMemBase + TL_MEM_SOFTRST)); + + for( i=0; i<128; i++) + ulBuff = readl( fcChip->Registers.ReMapMemBase + TL_MEM_SOFTRST); + + // clear the soft reset + for( i=0; i<8; i++) + writel( 0, (fcChip->Registers.ReMapMemBase + TL_MEM_SOFTRST)); + + + + // clear out our copy of Tach regs, + // because they must be invalid now, + // since TachLite reset all his regs. + CpqTsDestroyTachLiteQues(cpqfcHBAdata,0); // remove Host-based Que structs + cpqfcTSClearLinkStatusCounters(fcChip); // clear our s/w accumulators + // lower bits give GBIC info + fcChip->Registers.TYstatus.value = + readl( fcChip->Registers.TYstatus.address ); + break; + +/* + case 2: // freeze SCSI + case 3: // reset Outbound command que (ERQ) + case 4: // unfreeze OSM (Outbound Seq. Man.) 'er' + case 5: // report status + + break; +*/ + default: + ret_status = -1; // invalid option passed to RESET function + break; + } + LEAVE("ResetTach"); + return ret_status; +} + + + + + + +// 'addrBase' is IOBaseU for both TachLite and (older) Tachyon +int CpqTsLaserControl( void* addrBase, int opcode ) +{ + ULONG dwBuff; + + dwBuff = readl((addrBase + TL_MEM_TACH_CONTROL) ); // read TL Control reg + // (change only bit 4) + if( opcode == 1) + dwBuff |= ~0xffffffefL; // set - ON + else + dwBuff &= 0xffffffefL; // clear - OFF + writel( dwBuff, (addrBase + TL_MEM_TACH_CONTROL)); // write TL Control reg + return 0; +} + + + + + +// Use controller's "Options" field to determine loopback mode (if any) +// internal loopback (silicon - no GBIC) +// external loopback (GBIC - no FC loop) +// no loopback: L_PORT, external cable from GBIC required + +int CpqTsInitializeFrameManager( void *pChip, int opcode) +{ + PTACHYON fcChip; + int iStatus; + ULONG wwnLo, wwnHi; // for readback verification + + ENTER("InitializeFrameManager"); + fcChip = (PTACHYON)pChip; + if( !fcChip->Registers.ReMapMemBase ) // undefined controller? + return -1; + + // TL/TS UG, pg. 184 + // 0x0065 = 100ms for RT_TOV + // 0x01f5 = 500ms for ED_TOV + // 0x07D1 = 2000ms + fcChip->Registers.ed_tov.value = 0x006507D1; + writel( fcChip->Registers.ed_tov.value, + (fcChip->Registers.ed_tov.address)); + + + // Set LP_TOV to the FC-AL2 specified 2 secs. + // TL/TS UG, pg. 185 + writel( 0x07d00010, fcChip->Registers.ReMapMemBase +TL_MEM_FM_TIMEOUT2); + + + // Now try to read the WWN from the adapter's NVRAM + iStatus = CpqTsReadWriteWWN( fcChip, 1); // '1' for READ + + if( iStatus ) // NVRAM read failed? + { + printk(" WARNING! HBA NVRAM WWN read failed - make alias\n"); + // make up a WWN. If NULL or duplicated on loop, FC loop may hang! + + + fcChip->Registers.wwn_hi = (__u32)jiffies; + fcChip->Registers.wwn_hi |= 0x50000000L; + fcChip->Registers.wwn_lo = 0x44556677L; + } + + + writel( fcChip->Registers.wwn_hi, + fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_HI); + + writel( fcChip->Registers.wwn_lo, + fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_LO); + + + // readback for verification: + wwnHi = readl( fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_HI ); + + wwnLo = readl( fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_LO); + // test for correct chip register WRITE/READ + DEBUG_PCI( printk(" WWN %08X%08X\n", + fcChip->Registers.wwn_hi, fcChip->Registers.wwn_lo ) ); + + if( wwnHi != fcChip->Registers.wwn_hi || + wwnLo != fcChip->Registers.wwn_lo ) + { + printk( "cpqfcTS: WorldWideName register load failed\n"); + return -1; // FAILED! + } + + + + // set Frame Manager Initialize command + fcChip->Registers.FMcontrol.value = 0x06; + + // Note: for test/debug purposes, we may use "Hard" address, + // but we completely support "soft" addressing, including + // dynamically changing our address. + if( fcChip->Options.intLoopback == 1 ) // internal loopback + fcChip->Registers.FMconfig.value = 0x0f002080L; + else if( fcChip->Options.extLoopback == 1 ) // internal loopback + fcChip->Registers.FMconfig.value = 0x0f004080L; + else // L_Port + fcChip->Registers.FMconfig.value = 0x55000100L; // hard address (55h start) +// fcChip->Registers.FMconfig.value = 0x01000080L; // soft address (can't pick) +// fcChip->Registers.FMconfig.value = 0x55000100L; // hard address (55h start) + + // write config to FM + + if( !fcChip->Options.intLoopback && !fcChip->Options.extLoopback ) + // (also need LASER for real LOOP) + fcChip->LaserControl( fcChip->Registers.ReMapMemBase, 1); // turn on LASER + + writel( fcChip->Registers.FMconfig.value, + fcChip->Registers.FMconfig.address); + + + // issue INITIALIZE command to FM - ACTION! + writel( fcChip->Registers.FMcontrol.value, + fcChip->Registers.FMcontrol.address); + + LEAVE("InitializeFrameManager"); + + return 0; +} + + + + + +// This "look ahead" function examines the IMQ for occurence of +// "type". Returns 1 if found, 0 if not. +static int PeekIMQEntry( PTACHYON fcChip, ULONG type) +{ + ULONG CI = fcChip->IMQ->consumerIndex; + ULONG PI = fcChip->IMQ->producerIndex; // snapshot of IMQ indexes + + while( CI != PI ) + { // proceed with search + if( (++CI) >= IMQ_LEN ) CI = 0; // rollover check + + switch( type ) + { + case ELS_LILP_FRAME: + { + // first, we need to find an Inbound Completion message, + // If we find it, check the incoming frame payload (1st word) + // for LILP frame + if( (fcChip->IMQ->QEntry[CI].type & 0x1FF) == 0x104 ) + { + TachFCHDR_GCMND* fchs; + ULONG ulFibreFrame[2048/4]; // max DWORDS in incoming FC Frame + USHORT SFQpi = (USHORT)(fcChip->IMQ->QEntry[CI].word[0] & 0x0fffL); + + CpqTsGetSFQEntry( fcChip, + SFQpi, // SFQ producer ndx + ulFibreFrame, // contiguous dest. buffer + FALSE); // DON'T update chip--this is a "lookahead" + + fchs = (TachFCHDR_GCMND*)&ulFibreFrame; + if( fchs->pl[0] == ELS_LILP_FRAME) + { + return 1; // found the LILP frame! + } + else + { + // keep looking... + } + } + } + break; + + case OUTBOUND_COMPLETION: + if( (fcChip->IMQ->QEntry[CI].type & 0x1FF) == 0x00 ) + { + + // any OCM errors? + if( fcChip->IMQ->QEntry[CI].word[2] & 0x7a000000L ) + return 1; // found OCM error + } + break; + + + + default: + break; + } + } + return 0; // failed to find "type" +} + + +static void SetTachTOV( CPQFCHBA* cpqfcHBAdata) +{ + PTACHYON fcChip = &cpqfcHBAdata->fcChip; + + // TL/TS UG, pg. 184 + // 0x0065 = 100ms for RT_TOV + // 0x01f5 = 500ms for ED_TOV + // 0x07d1 = 2000ms for ED_TOV + + // SANMark Level 1 requires an "initialization backoff" + // (See "SANMark Test Suite Level 1": + // initialization_timeout.fcal.SANMark-1.fc) + // We have to use 2sec, 24sec, then 128sec when login/ + // port discovery processes fail to complete. + + // when port discovery completes (logins done), we set + // ED_TOV to 500ms -- this is the normal operational case + // On the first Link Down, we'll move to 2 secs (7D1 ms) + if( (fcChip->Registers.ed_tov.value &0xFFFF) <= 0x1f5) + fcChip->Registers.ed_tov.value = 0x006507D1; + + // If we get another LST after we moved TOV to 2 sec, + // increase to 24 seconds (5DC1 ms) per SANMark! + else if( (fcChip->Registers.ed_tov.value &0xFFFF) <= 0x7D1) + fcChip->Registers.ed_tov.value = 0x00655DC1; + + // If we get still another LST, set the max TOV (Tachyon + // has only 16 bits for ms timer, so the max is 65.5 sec) + else if( (fcChip->Registers.ed_tov.value &0xFFFF) <= 0x5DC1) + fcChip->Registers.ed_tov.value = 0x0065FFFF; + + writel( fcChip->Registers.ed_tov.value, + (fcChip->Registers.ed_tov.address)); + // keep the same 2sec LP_TOV + writel( 0x07D00010, fcChip->Registers.ReMapMemBase +TL_MEM_FM_TIMEOUT2); +} + + +// The IMQ is an array with IMQ_LEN length, each element (QEntry) +// with eight 32-bit words. Tachyon PRODUCES a QEntry with each +// message it wants to send to the host. The host CONSUMES IMQ entries + +// This function copies the current +// (or oldest not-yet-processed) QEntry to +// the caller, clears/ re-enables the interrupt, and updates the +// (Host) Consumer Index. +// Return value: +// 0 message processed, none remain (producer and consumer +// indexes match) +// 1 message processed, more messages remain +// -1 no message processed - none were available to process +// Remarks: +// TL/TS UG specifices that the following actions for +// INTA_L handling: +// 1. read PCI Interrupt Status register (0xff) +// 2. all IMQ messages should be processed before writing the +// IMQ consumer index. + + +int CpqTsProcessIMQEntry(void *host) +{ + struct Scsi_Host *HostAdapter = (struct Scsi_Host *)host; + CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata; + PTACHYON fcChip = &cpqfcHBAdata->fcChip; + FC_EXCHANGES *Exchanges = fcChip->Exchanges; + int iStatus; + USHORT i, RPCset, DPCset; + ULONG x_ID; + ULONG ulBuff, dwStatus; + TachFCHDR_GCMND* fchs; + ULONG ulFibreFrame[2048/4]; // max number of DWORDS in incoming Fibre Frame + UCHAR ucInboundMessageType; // Inbound CM, dword 3 "type" field + + ENTER("ProcessIMQEntry"); + + + // check TachLite's IMQ producer index - + // is a new message waiting for us? + // equal indexes means empty que + + if( fcChip->IMQ->producerIndex != fcChip->IMQ->consumerIndex ) + { // need to process message + + +#ifdef IMQ_DEBUG + printk("PI %X, CI %X type: %X\n", + fcChip->IMQ->producerIndex,fcChip->IMQ->consumerIndex, + fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].type); +#endif + // Examine Completion Messages in IMQ + // what CM_Type? + switch( (UCHAR)(fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].type + & 0xffL) ) + { + case OUTBOUND_COMPLETION: + + // Remarks: + // x_IDs (OX_ID, RX_ID) are partitioned by SEST entries + // (starting at 0), and SFS entries (starting at + // SEST_LEN -- outside the SEST space). + // Psuedo code: + // x_ID (OX_ID or RX_ID) from message is Trans_ID or SEST index + // range check - x_ID + // if x_ID outside 'Transactions' length, error - exit + // if any OCM error, copy error status to Exchange slot + // if FCP ASSIST transaction (x_ID within SEST), + // call fcComplete (to App) + // ... + + + ulBuff = fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1]; + x_ID = ulBuff & 0x7fffL; // lower 14 bits SEST_Index/Trans_ID + // Range check CM OX/RX_ID value... + if( x_ID < TACH_MAX_XID ) // don't go beyond array space + { + + + if( ulBuff & 0x20000000L ) // RPC -Response Phase Complete? + RPCset = 1; // (SEST transactions only) + else + RPCset = 0; + + if( ulBuff & 0x40000000L ) // DPC -Data Phase Complete? + DPCset = 1; // (SEST transactions only) + else + DPCset = 0; + // set the status for this Outbound transaction's ID + dwStatus = 0L; + if( ulBuff & 0x10000000L ) // SPE? (SEST Programming Error) + dwStatus |= SESTPROG_ERR; + + ulBuff = fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2]; + if( ulBuff & 0x7a000000L ) // any other errs? + { + if( ulBuff & 0x40000000L ) + dwStatus |= INV_ENTRY; + if( ulBuff & 0x20000000L ) + dwStatus |= FRAME_TO; // FTO + if( ulBuff & 0x10000000L ) + dwStatus |= HOSTPROG_ERR; + if( ulBuff & 0x08000000L ) + dwStatus |= LINKFAIL_TX; + if( ulBuff & 0x02000000L ) + dwStatus |= ABORTSEQ_NOTIFY; // ASN + } + + + if( dwStatus ) // any errors? + { + // set the Outbound Completion status + Exchanges->fcExchange[ x_ID ].status |= dwStatus; + + // if this Outbound frame was for a SEST entry, automatically + // reque it in the case of LINKFAIL (it will restart on PDISC) + if( x_ID < TACH_SEST_LEN ) + { + + printk(" #OCM error %Xh x_ID %X# ", + dwStatus, x_ID); + + Exchanges->fcExchange[x_ID].timeOut = 30000; // seconds default + + + // We Q ABTS for each exchange. + // NOTE: We can get FRAME_TO on bad alpa (device gone). Since + // bad alpa is reported before FRAME_TO, examine the status + // flags to see if the device is removed. If so, DON'T + // post an ABTS, since it will be terminated by the bad alpa + // message. + if( dwStatus & FRAME_TO ) // check for device removed... + { + if( !(Exchanges->fcExchange[x_ID].status & DEVICE_REMOVED) ) + { + // presumes device is still there: send ABTS. + + cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID); + } + } + else // Abort all other errors + { + cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID); + } + + // if the HPE bit is set, we have to CLose the LOOP + // (see TL/TS UG, pg. 239) + + if( dwStatus &= HOSTPROG_ERR ) + // set CL bit (see TL/TS UG, pg. 172) + writel( 4, fcChip->Registers.FMcontrol.address); + } + } + // NOTE: we don't necessarily care about ALL completion messages... + // SCSI resp. complete OR + if( ((x_ID < TACH_SEST_LEN) && RPCset)|| + (x_ID >= TACH_SEST_LEN) ) // non-SCSI command + { + // exchange done; complete to upper levels with status + // (if necessary) and free the exchange slot + + + if( x_ID >= TACH_SEST_LEN ) // Link Service Outbound frame? + // A Request or Reply has been sent + { // signal waiting WorkerThread + + up( cpqfcHBAdata->TYOBcomplete); // frame is OUT of Tach + + // WorkerThread will complete Xchng + } + else // X_ID is for FCP assist (SEST) + { + // TBD (target mode) +// fcCompleteExchange( fcChip, x_ID); // TRE completed + } + } + } + else // ERROR CONDITION! bogus x_ID in completion message + { + + printk(" ProcessIMQ (OBCM) x_id out of range %Xh\n", x_ID); + + } + + + + // Load the Frame Manager's error counters. We check them here + // because presumably the link is up and healthy enough for the + // counters to be meaningful (i.e., don't check them while loop + // is initializing). + fcChip->Registers.FMLinkStatus1.value = // get TL's counter + readl(fcChip->Registers.FMLinkStatus1.address); + + fcChip->Registers.FMLinkStatus2.value = // get TL's counter + readl(fcChip->Registers.FMLinkStatus2.address); + + + fcParseLinkStatusCounters( fcChip); // load into 6 s/w accumulators + break; + + + + case ERROR_IDLE_COMPLETION: // TachLite Error Idle... + + // We usually get this when the link goes down during heavy traffic. + // For now, presume that if SEST Exchanges are open, we will + // get this as our cue to INVALIDATE all SEST entries + // (and we OWN all the SEST entries). + // See TL/TS UG, pg. 53 + + for( x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++) + { + + // Does this VALid SEST entry need to be invalidated for Abort? + fcChip->SEST->u[ x_ID].IWE.Hdr_Len &= 0x7FFFFFFF; + } + + CpqTsUnFreezeTachlite( fcChip, 2); // unfreeze Tachyon, if Link OK + + break; + + + case INBOUND_SFS_COMPLETION: //0x04 + // NOTE! we must process this SFQ message to avoid SFQ filling + // up and stopping TachLite. Incoming commands are placed here, + // as well as 'unknown' frames (e.g. LIP loop position data) + // write this CM's producer index to global... + // TL/TS UG, pg 234: + // Type: 0 - reserved + // 1 - Unassisted FCP + // 2 - BAD FCP + // 3 - Unkown Frame + // 4-F reserved + + + fcChip->SFQ->producerIndex = (USHORT) + (fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[0] & 0x0fffL); + + + ucInboundMessageType = 0; // default to useless frame + + // we can only process two Types: 1, Unassisted FCP, and 3, Unknown + // Also, we aren't interested in processing frame fragments + // so don't Que anything with 'LKF' bit set + if( !(fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2] + & 0x40000000) ) // 'LKF' link failure bit clear? + { + ucInboundMessageType = (UCHAR) // ICM DWord3, "Type" + (fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2] & 0x0fL); + } + else + { + fcChip->fcStats.linkFailRX++; +// printk("LKF (link failure) bit set on inbound message\n"); + } + + // clears SFQ entry from Tachyon buffer; copies to contiguous ulBuff + CpqTsGetSFQEntry( + fcChip, // i.e. this Device Object + (USHORT)fcChip->SFQ->producerIndex, // SFQ producer ndx + ulFibreFrame, TRUE); // contiguous destination buffer, update chip + + // analyze the incoming frame outside the INT handler... + // (i.e., Worker) + + if( ucInboundMessageType == 1 ) + { + fchs = (TachFCHDR_GCMND*)ulFibreFrame; // cast to examine IB frame + // don't fill up our Q with garbage - only accept FCP-CMND + // or XRDY frames + if( (fchs->d_id & 0xFF000000) == 0x06000000 ) // CMND + { + // someone sent us a SCSI command + +// fcPutScsiQue( cpqfcHBAdata, +// SFQ_UNASSISTED_FCP, ulFibreFrame); + } + else if( ((fchs->d_id & 0xFF000000) == 0x07000000) || // RSP (status) + (fchs->d_id & 0xFF000000) == 0x05000000 ) // XRDY + { + ULONG x_ID; + // Unfortunately, ABTS requires a Freeze on the chip so + // we can modify the shared memory SEST. When frozen, + // any received Exchange frames cannot be processed by + // Tachyon, so they will be dumped in here. It is too + // complex to attempt the reconstruct these frames in + // the correct Exchange context, so we simply seek to + // find status or transfer ready frames, and cause the + // exchange to complete with errors before the timeout + // expires. We use a Linux Scsi Cmnd result code that + // causes immediate retry. + + + // Do we have an open exchange that matches this s_id + // and ox_id? + for( x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++) + { + if( (fchs->s_id & 0xFFFFFF) == + (Exchanges->fcExchange[x_ID].fchs.d_id & 0xFFFFFF) + && + (fchs->ox_rx_id & 0xFFFF0000) == + (Exchanges->fcExchange[x_ID].fchs.ox_rx_id & 0xFFFF0000) ) + { + // printk(" #R/X frame x_ID %08X# ", fchs->ox_rx_id ); + // simulate the anticipated error - since the + // SEST was frozen, frames were lost... + Exchanges->fcExchange[ x_ID ].status |= SFQ_FRAME; + + // presumes device is still there: send ABTS. + cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID); + break; // done + } + } + } + + } + + else if( ucInboundMessageType == 3) + { + // FC Link Service frames (e.g. PLOGI, ACC) come in here. + cpqfcTSPutLinkQue( cpqfcHBAdata, SFQ_UNKNOWN, ulFibreFrame); + + } + + else if( ucInboundMessageType == 2 ) // "bad FCP"? + { +#ifdef IMQ_DEBUG + printk("Bad FCP incoming frame discarded\n"); +#endif + } + + else // don't know this type + { +#ifdef IMQ_DEBUG + printk("Incoming frame discarded, type: %Xh\n", ucInboundMessageType); +#endif + } + + // Check the Frame Manager's error counters. We check them here + // because presumably the link is up and healthy enough for the + // counters to be meaningful (i.e., don't check them while loop + // is initializing). + fcChip->Registers.FMLinkStatus1.value = // get TL's counter + readl(fcChip->Registers.FMLinkStatus1.address); + + + fcChip->Registers.FMLinkStatus2.value = // get TL's counter + readl(fcChip->Registers.FMLinkStatus2.address); + + + break; + + + + + // We get this CM because we issued a freeze + // command to stop outbound frames. We issue the + // freeze command at Link Up time; when this message + // is received, the ERQ base can be switched and PDISC + // frames can be sent. + + + case ERQ_FROZEN_COMPLETION: // note: expect ERQ followed immediately + // by FCP when freezing TL + fcChip->Registers.TYstatus.value = // read what's frozen + readl(fcChip->Registers.TYstatus.address); + // (do nothing; wait for FCP frozen message) + break; + case FCP_FROZEN_COMPLETION: + + fcChip->Registers.TYstatus.value = // read what's frozen + readl(fcChip->Registers.TYstatus.address); + + // Signal the kernel thread to proceed with SEST modification + up( cpqfcHBAdata->TachFrozen); + + break; + + + + case INBOUND_C1_TIMEOUT: + case MFS_BUF_WARN: + case IMQ_BUF_WARN: + break; + + + + + + // In older Tachyons, we 'clear' the internal 'core' interrupt state + // by reading the FMstatus register. In newer TachLite (Tachyon), + // we must WRITE the register + // to clear the condition (TL/TS UG, pg 179) + case FRAME_MGR_INTERRUPT: + { + PFC_LOGGEDIN_PORT pLoggedInPort; + + fcChip->Registers.FMstatus.value = + readl( fcChip->Registers.FMstatus.address ); + + // PROBLEM: It is possible, especially with "dumb" hubs that + // don't automatically LIP on by-pass of ports that are going + // away, for the hub by-pass process to destroy critical + // ordered sets of a frame. The result of this is a hung LPSM + // (Loop Port State Machine), which on Tachyon results in a + // (default 2 sec) Loop State Timeout (LST) FM message. We + // want to avoid this relatively huge timeout by detecting + // likely scenarios which will result in LST. + // To do this, we could examine FMstatus for Loss of Synchronization + // and/or Elastic Store (ES) errors. Of these, Elastic Store is better + // because we get this indication more quickly than the LOS. + // Not all ES errors are harmfull, so we don't want to LIP on every + // ES. Instead, on every ES, detect whether our LPSM in in one + // of the LST states: ARBITRATING, OPEN, OPENED, XMITTED CLOSE, + // or RECEIVED CLOSE. (See TL/TS UG, pg. 181) + // If any of these LPSM states are detected + // in combination with the LIP while LDn is not set, + // send an FM init (LIP F7,F7 for loops)! + // It is critical to the physical link stability NOT to reset (LIP) + // more than absolutely necessary; this is a basic premise of the + // SANMark level 1 spec. + { + ULONG Lpsm = (fcChip->Registers.FMstatus.value & 0xF0) >>4; + + if( (fcChip->Registers.FMstatus.value & 0x400) // ElasticStore? + && + !(fcChip->Registers.FMstatus.value & 0x100) // NOT LDn + && + !(fcChip->Registers.FMstatus.value & 0x1000)) // NOT LF + { + if( (Lpsm != 0) || // not MONITORING? or + !(Lpsm & 0x8) )// not already offline? + { + // now check the particular LST states... + if( (Lpsm == ARBITRATING) || (Lpsm == OPEN) || + (Lpsm == OPENED) || (Lpsm == XMITTD_CLOSE) || + (Lpsm == RCVD_CLOSE) ) + { + // re-init the loop before it hangs itself! + printk(" #req FMinit on E-S: LPSM %Xh# ",Lpsm); + + + fcChip->fcStats.FMinits++; + writel( 6, fcChip->Registers.FMcontrol.address); // LIP + } + } + } + else if( fcChip->Registers.FMstatus.value & 0x40000 ) // LST? + { + printk(" #req FMinit on LST, LPSM %Xh# ",Lpsm); + + fcChip->fcStats.FMinits++; + writel( 6, fcChip->Registers.FMcontrol.address); // LIP + } + } + + + // clear only the 'interrupting' type bits for this REG read + writel( (fcChip->Registers.FMstatus.value & 0xff3fff00L), + fcChip->Registers.FMstatus.address); + + + // copy frame manager status to unused ULONG slot + fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[0] = + fcChip->Registers.FMstatus.value; // (for debugging) + + + // Load the Frame Manager's error counters. We check them here + // because presumably the link is up and healthy enough for the + // counters to be meaningful (i.e., don't check them while loop + // is initializing). + fcChip->Registers.FMLinkStatus1.value = // get TL's counter + readl(fcChip->Registers.FMLinkStatus1.address); + + fcChip->Registers.FMLinkStatus2.value = // get TL's counter + readl(fcChip->Registers.FMLinkStatus2.address); + + // Get FM BB_Credit Zero Reg - does not clear on READ + fcChip->Registers.FMBB_CreditZero.value = // get TL's counter + readl(fcChip->Registers.FMBB_CreditZero.address); + + + + fcParseLinkStatusCounters( fcChip); // load into 6 s/w accumulators + + + // LINK DOWN + + if( fcChip->Registers.FMstatus.value & 0x100L ) // Link DOWN bit + { + +#ifdef IMQ_DEBUG + printk("LinkDn\n"); +#endif + printk(" #LDn# "); + + fcChip->fcStats.linkDown++; + + SetTachTOV( cpqfcHBAdata); // must set according to SANMark + + // Check the ERQ - force it to be "empty" to prevent Tach + // from sending out frames before we do logins. + + + if( fcChip->ERQ->producerIndex != fcChip->ERQ->consumerIndex) + { +// printk("#ERQ PI != CI#"); + CpqTsFreezeTachlite( fcChip, 1); // freeze ERQ only + fcChip->ERQ->producerIndex = fcChip->ERQ->consumerIndex = 0; + writel( fcChip->ERQ->base, + (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_BASE)); + // re-writing base forces ERQ PI to equal CI + + } + + // link down transition occurred -- port_ids can change + // on next LinkUp, so we must invalidate current logins + // (and any I/O in progress) until PDISC or PLOGI/PRLI + // completes + { + pLoggedInPort = &fcChip->fcPorts; + while( pLoggedInPort ) // for all ports which are expecting + // PDISC after the next LIP, set the + // logoutTimer + { + + if( pLoggedInPort->pdisc) // expecting PDISC within 2 sec? + { + pLoggedInPort->LOGO_timer = 3; // we want 2 seconds + // but Timer granularity + // is 1 second + } + // suspend any I/O in progress until + // PDISC received... + pLoggedInPort->prli = FALSE; // block FCP-SCSI commands + + pLoggedInPort = pLoggedInPort->pNextPort; + } // ... all Previously known ports checked + } + + // since any hot plugging device may NOT support LILP frames + // (such as early Tachyon chips), clear this flag indicating + // we shouldn't use (our copy of) a LILP map. + // If we receive an LILP frame, we'll set it again. + fcChip->Options.LILPin = 0; // our LILPmap is invalid + cpqfcHBAdata->PortDiscDone = 0; // must re-validate FC ports! + + // also, we want to invalidate (i.e. INITIATOR_ABORT) any + // open Login exchanges, in case the LinkDown happened in the + // middle of logins. It's possible that some ports already + // ACCepted login commands which we have not processed before + // another LinkDown occured. Any accepted Login exhanges are + // invalidated by LinkDown, even before they are acknowledged. + // It's also possible for a port to have a Queued Reply or Request + // for login which was interrupted by LinkDown; it may come later, + // but it will be unacceptable to us. + + // we must scan the entire exchange space, find every Login type + // originated by us, and abort it. This is NOT an abort due to + // timeout, so we don't actually send abort to the other port - + // we just complete it to free up the fcExchange slot. + + for( i=TACH_SEST_LEN; i< TACH_MAX_XID; i++) + { // looking for Extended Link Serv.Exchanges + if( Exchanges->fcExchange[i].type == ELS_PDISC || + Exchanges->fcExchange[i].type == ELS_PLOGI || + Exchanges->fcExchange[i].type == ELS_PRLI ) + { + // ABORT the exchange! +#ifdef IMQ_DEBUG + printk("Originator ABORT x_id %Xh, type %Xh, port_id %Xh on LDn\n", + i, Exchanges->fcExchange[i].type, + Exchanges->fcExchange[i].fchs.d_id); +#endif + + Exchanges->fcExchange[i].status |= INITIATOR_ABORT; + cpqfcTSCompleteExchange( fcChip, i); // abort on LDn + } + } + + } + + // ################ LINK UP ################## + if( fcChip->Registers.FMstatus.value & 0x200L ) // Link Up bit + { // AL_PA could have changed + + // We need the following code, duplicated from LinkDn condition, + // because it's possible for the Tachyon to re-initialize (hard + // reset) without ever getting a LinkDn indication. + pLoggedInPort = &fcChip->fcPorts; + while( pLoggedInPort ) // for all ports which are expecting + // PDISC after the next LIP, set the + // logoutTimer + { + if( pLoggedInPort->pdisc) // expecting PDISC within 2 sec? + { + pLoggedInPort->LOGO_timer = 3; // we want 2 seconds + // but Timer granularity + // is 1 second + + // suspend any I/O in progress until + // PDISC received... + + } + pLoggedInPort = pLoggedInPort->pNextPort; + } // ... all Previously known ports checked + + // CpqTs acquired AL_PA in register AL_PA (ACQ_ALPA) + fcChip->Registers.rcv_al_pa.value = + readl(fcChip->Registers.rcv_al_pa.address); + + // Now, if our acquired address is DIFFERENT from our + // previous one, we are not allow to do PDISC - we + // must go back to PLOGI, which will terminate I/O in + // progress for ALL logged in FC devices... + // (This is highly unlikely). + + if( (fcChip->Registers.my_al_pa & 0xFF) != + ((fcChip->Registers.rcv_al_pa.value >> 16) &0xFF) ) + { + +// printk(" #our HBA port_id changed!# "); // FC port_id changed!! + + pLoggedInPort = &fcChip->fcPorts; + while( pLoggedInPort ) // for all ports which are expecting + // PDISC after the next LIP, set the + // logoutTimer + { + pLoggedInPort->pdisc = FALSE; + pLoggedInPort->prli = FALSE; + pLoggedInPort = pLoggedInPort->pNextPort; + } // ... all Previously known ports checked + + // when the port_id changes, we must terminate + // all open exchanges. + cpqfcTSTerminateExchange( cpqfcHBAdata, NULL, PORTID_CHANGED); + + } + + // Replace the entire 24-bit port_id. We only know the + // lower 8 bits (alpa) from Tachyon; if a FLOGI is done, + // we'll get the upper 16-bits from the FLOGI ACC frame. + // If someone plugs into Fabric switch, we'll do FLOGI and + // get full 24-bit port_id; someone could then remove and + // hot-plug us into a dumb hub. If we send a 24-bit PLOGI + // to a "private" loop device, it might blow up. + // Consequently, we force the upper 16-bits of port_id to + // be re-set on every LinkUp transition + fcChip->Registers.my_al_pa = + (fcChip->Registers.rcv_al_pa.value >> 16) & 0xFF; + + + // copy frame manager status to unused ULONG slot + fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1] = + fcChip->Registers.my_al_pa; // (for debugging) + + // for TachLite, we need to write the acquired al_pa + // back into the FMconfig register, because after + // first initialization, the AQ (prev. acq.) bit gets + // set, causing TL FM to use the AL_PA field in FMconfig. + // (In Tachyon, FM writes the acquired AL_PA for us.) + ulBuff = readl( fcChip->Registers.FMconfig.address); + ulBuff &= 0x00ffffffL; // mask out current al_pa + ulBuff |= ( fcChip->Registers.my_al_pa << 24 ); // or in acq. al_pa + fcChip->Registers.FMconfig.value = ulBuff; // copy it back + writel( fcChip->Registers.FMconfig.value, // put in TachLite + fcChip->Registers.FMconfig.address); + + +#ifdef IMQ_DEBUG + printk("#LUp %Xh, FMstat 0x%08X#", + fcChip->Registers.my_al_pa, fcChip->Registers.FMstatus.value); +#endif + + // also set the WRITE-ONLY My_ID Register (for Fabric + // initialization) + writel( fcChip->Registers.my_al_pa, + fcChip->Registers.ReMapMemBase +TL_MEM_TACH_My_ID); + + + fcChip->fcStats.linkUp++; + + // reset TL statistics counters + // (we ignore these error counters + // while link is down) + ulBuff = // just reset TL's counter + readl( fcChip->Registers.FMLinkStatus1.address); + + ulBuff = // just reset TL's counter + readl( fcChip->Registers.FMLinkStatus2.address); + + // for initiator, need to start verifying ports (e.g. PDISC) + + + + + + + CpqTsUnFreezeTachlite( fcChip, 2); // unfreeze Tachlite, if Link OK + + // Tachyon creates an interesting problem for us on LILP frames. + // Instead of writing the incoming LILP frame into the SFQ before + // indicating LINK UP (the actual order of events), Tachyon tells + // us LINK UP, and later us the LILP. So we delay, then examine the + // IMQ for an Inbound CM (x04); if found, we can set + // LINKACTIVE after processing the LILP. Otherwise, just proceed. + // Since Tachyon imposes this time delay (and doesn't tell us + // what it is), we have to impose a delay before "Peeking" the IMQ + // for Tach hardware (DMA) delivery. + // Processing LILP is required by SANMark + udelay( 1000); // microsec delay waiting for LILP (if it comes) + if( PeekIMQEntry( fcChip, ELS_LILP_FRAME) ) + { // found SFQ LILP, which will post LINKACTIVE +// printk("skipping LINKACTIVE post\n"); + + } + else + cpqfcTSPutLinkQue( cpqfcHBAdata, LINKACTIVE, ulFibreFrame); + } + + + + // ******* Set Fabric Login indication ******** + if( fcChip->Registers.FMstatus.value & 0x2000 ) + { + printk(" #Fabric# "); + fcChip->Options.fabric = 1; + } + else + fcChip->Options.fabric = 0; + + + + // ******* LIP(F8,x) or BAD AL_PA? ******** + if( fcChip->Registers.FMstatus.value & 0x30000L ) + { + // copy the error AL_PAs + fcChip->Registers.rcv_al_pa.value = + readl(fcChip->Registers.rcv_al_pa.address); + + // Bad AL_PA? + if( fcChip->Registers.FMstatus.value & 0x10000L ) + { + PFC_LOGGEDIN_PORT pLoggedInPort; + + // copy "BAD" al_pa field + fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1] = + (fcChip->Registers.rcv_al_pa.value & 0xff00L) >> 8; + + pLoggedInPort = fcFindLoggedInPort( fcChip, + NULL, // DON'T search Scsi Nexus + fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1], // port id + NULL, // DON'T search linked list for FC WWN + NULL); // DON'T care about end of list + + if( pLoggedInPort ) + { + // Just in case we got this BAD_ALPA because a device + // quietly disappeared (can happen on non-managed hubs such + // as the Vixel Rapport 1000), + // do an Implicit Logout. We never expect this on a Logged + // in port (but do expect it on port discovery). + // (As a reasonable alternative, this could be changed to + // simply start the implicit logout timer, giving the device + // several seconds to "come back".) + // + printk(" #BAD alpa %Xh# ", + fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1]); + cpqfcTSImplicitLogout( cpqfcHBAdata, pLoggedInPort); + } + } + // LIP(f8,x)? + if( fcChip->Registers.FMstatus.value & 0x20000L ) + { + // for debugging, copy al_pa field + fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2] = + (fcChip->Registers.rcv_al_pa.value & 0xffL); + // get the other port's al_pa + // (one that sent LIP(F8,?) ) + } + } + + // Elastic store err + if( fcChip->Registers.FMstatus.value & 0x400L ) + { + // don't count e-s if loop is down! + if( !(USHORT)(fcChip->Registers.FMstatus.value & 0x80) ) + fcChip->fcStats.e_stores++; + + } + } + break; + + + case INBOUND_FCP_XCHG_COMPLETION: // 0x0C + + // Remarks: + // On Tachlite TL/TS, we get this message when the data phase + // of a SEST inbound transfer is complete. For example, if a WRITE command + // was received with OX_ID 0, we might respond with XFER_RDY with + // RX_ID 8001. This would start the SEST controlled data phases. When + // all data frames are received, we get this inbound completion. This means + // we should send a status frame to complete the status phase of the + // FCP-SCSI exchange, using the same OX_ID,RX_ID that we used for data + // frames. + // See Outbound CM discussion of x_IDs + // Psuedo Code + // Get SEST index (x_ID) + // x_ID out of range, return (err condition) + // set status bits from 2nd dword + // free transactionID & SEST entry + // call fcComplete with transactionID & status + + ulBuff = fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[0]; + x_ID = ulBuff & 0x7fffL; // lower 14 bits SEST_Index/Trans_ID + // (mask out MSB "direction" bit) + // Range check CM OX/RX_ID value... + if( x_ID < TACH_SEST_LEN ) // don't go beyond SEST array space + { + +//#define FCP_COMPLETION_DBG 1 +#ifdef FCP_COMPLETION_DBG + printk(" FCP_CM x_ID %Xh, status %Xh, Cmnd %p\n", + x_ID, ulBuff, Exchanges->fcExchange[x_ID].Cmnd); +#endif + if( ulBuff & 0x08000000L ) // RPC -Response Phase Complete - or - + // time to send response frame? + RPCset = 1; // (SEST transaction) + else + RPCset = 0; + // set the status for this Inbound SCSI transaction's ID + dwStatus = 0L; + if( ulBuff & 0x70000000L ) // any errs? + { + + if( ulBuff & 0x40000000L ) + dwStatus |= LINKFAIL_RX; + + if( ulBuff & 0x20000000L ) + dwStatus |= COUNT_ERROR; + + if( ulBuff & 0x10000000L ) + dwStatus |= OVERFLOW; + } + + + // FCP transaction done - copy status + Exchanges->fcExchange[ x_ID ].status = dwStatus; + + + // Did the exchange get an FCP-RSP response frame? + // (Note the little endian/big endian FC payload difference) + + if( RPCset ) // SEST transaction Response frame rec'd + { + // complete the command in our driver... + cpqfcTSCompleteExchange( fcChip, x_ID); + + } // end "RPCset" + + else // ("target" logic) + { + // Tachlite says all data frames have been received - now it's time + // to analyze data transfer (successful?), then send a response + // frame for this exchange + + ulFibreFrame[0] = x_ID; // copy for later reference + + // if this was a TWE, we have to send satus response + if( Exchanges->fcExchange[ x_ID].type == SCSI_TWE ) + { +// fcPutScsiQue( cpqfcHBAdata, +// NEED_FCP_RSP, ulFibreFrame); // (ulFibreFrame not used here) + } + } + } + else // ERROR CONDITION! bogus x_ID in completion message + { + printk("IN FCP_XCHG: bad x_ID: %Xh\n", x_ID); + } + + break; + + + + + case INBOUND_SCSI_DATA_COMMAND: + case BAD_SCSI_FRAME: + case INB_SCSI_STATUS_COMPLETION: + case BUFFER_PROCESSED_COMPLETION: + break; + } + + // Tachyon is producing; + // we are consuming + fcChip->IMQ->consumerIndex++; // increment OUR consumerIndex + if( fcChip->IMQ->consumerIndex >= IMQ_LEN)// check for rollover + fcChip->IMQ->consumerIndex = 0L; // reset it + + + if( fcChip->IMQ->producerIndex == fcChip->IMQ->consumerIndex ) + { // all Messages are processed - + iStatus = 0; // no more messages to process + + } + else + iStatus = 1; // more messages to process + + // update TachLite's ConsumerIndex... (clears INTA_L) + // NOTE: according to TL/TS UG, the + // "host must return completion messages in sequential order". + // Does this mean one at a time, in the order received? We + // presume so. + + writel( fcChip->IMQ->consumerIndex, + (fcChip->Registers.ReMapMemBase + IMQ_CONSUMER_INDEX)); + +#if IMQ_DEBUG + printk("Process IMQ: writing consumer ndx %d\n ", + fcChip->IMQ->consumerIndex); + printk("PI %X, CI %X\n", + fcChip->IMQ->producerIndex,fcChip->IMQ->consumerIndex ); +#endif + + + + } + else + { + // hmmm... why did we get interrupted/called with no message? + iStatus = -1; // nothing to process +#if IMQ_DEBUG + printk("Process IMQ: no message PI %Xh CI %Xh", + fcChip->IMQ->producerIndex, + fcChip->IMQ->consumerIndex); +#endif + } + + LEAVE("ProcessIMQEntry"); + + return iStatus; +} + + + + + +// This routine initializes Tachyon according to the following +// options (opcode1): +// 1 - RESTART Tachyon, simulate power on condition by shutting +// down laser, resetting the hardware, de-allocating all buffers; +// continue +// 2 - Config Tachyon / PCI registers; +// continue +// 3 - Allocating memory and setting Tachyon queues (write Tachyon regs); +// continue +// 4 - Config frame manager registers, initialize, turn on laser +// +// Returns: +// -1 on fatal error +// 0 on success + +int CpqTsInitializeTachLite( void *pHBA, int opcode1, int opcode2) +{ + CPQFCHBA *cpqfcHBAdata = (CPQFCHBA*)pHBA; + PTACHYON fcChip = &cpqfcHBAdata->fcChip; + ULONG ulBuff; + UCHAR bBuff; + int iStatus=-1; // assume failure + + ENTER("InitializeTachLite"); + + // verify board's base address (sanity check) + + if( !fcChip->Registers.ReMapMemBase) // NULL address for card? + return -1; // FATAL error! + + + + switch( opcode1 ) + { + case 1: // restore hardware to power-on (hard) restart + + + iStatus = fcChip->ResetTachyon( + cpqfcHBAdata, opcode2); // laser off, reset hardware + // de-allocate aligned buffers + + +/* TBD // reset FC link Q (producer and consumer = 0) + fcLinkQReset(cpqfcHBAdata); + +*/ + + if( iStatus ) + break; + + case 2: // Config PCI/Tachyon registers + // NOTE: For Tach TL/TS, bit 31 must be set to 1. For TS chips, a read + // of bit 31 indicates state of M66EN signal; if 1, chip may run at + // 33-66MHz (see TL/TS UG, pg 159) + + ulBuff = 0x80000000; // TachLite Configuration Register + + writel( ulBuff, fcChip->Registers.TYconfig.address); +// ulBuff = 0x0147L; // CpqTs PCI CFGCMD register +// WritePCIConfiguration( fcChip->Backplane.bus, +// fcChip->Backplane.slot, TLCFGCMD, ulBuff, 4); +// ulBuff = 0x0L; // test! +// ReadPCIConfiguration( fcChip->Backplane.bus, +// fcChip->Backplane.slot, TLCFGCMD, &ulBuff, 4); + + // read back for reference... + fcChip->Registers.TYconfig.value = + readl( fcChip->Registers.TYconfig.address ); + + // what is the PCI bus width? + pci_read_config_byte( cpqfcHBAdata->PciDev, + 0x43, // PCIMCTR offset + &bBuff); + + fcChip->Registers.PCIMCTR = bBuff; + + // set string identifying the chip on the circuit board + + fcChip->Registers.TYstatus.value = + readl( fcChip->Registers.TYstatus.address); + + { +// Now that we are supporting multiple boards, we need to change +// this logic to check for PCI vendor/device IDs... +// for now, quick & dirty is simply checking Chip rev + + ULONG RevId = (fcChip->Registers.TYstatus.value &0x3E0)>>5; + UCHAR Minor = (UCHAR)(RevId & 0x3); + UCHAR Major = (UCHAR)((RevId & 0x1C) >>2); + + printk(" HBA Tachyon RevId %d.%d\n", Major, Minor); + if( (Major == 1) && (Minor == 2) ) + { + sprintf( cpqfcHBAdata->fcChip.Name, STACHLITE66_TS12); + + } + else if( (Major == 1) && (Minor == 3) ) + { + sprintf( cpqfcHBAdata->fcChip.Name, STACHLITE66_TS13); + } + else if( (Major == 2) && (Minor == 1) ) + { + sprintf( cpqfcHBAdata->fcChip.Name, SAGILENT_XL2_21); + } + else + sprintf( cpqfcHBAdata->fcChip.Name, STACHLITE_UNKNOWN); + } + + + + case 3: // allocate mem, set Tachyon Que registers + iStatus = CpqTsCreateTachLiteQues( cpqfcHBAdata, opcode2); + + // now that the Queues exist, Tach can DMA to them, so + // we can begin processing INTs + // INTEN register - enable INT (TachLite interrupt) + writeb( 0x1F, fcChip->Registers.ReMapMemBase + IINTEN); + + + if( iStatus ) + break; + + + case 4: // Config Fame Manager, Init Loop Command, laser on + + // L_PORT or loopback + // depending on Options + iStatus = CpqTsInitializeFrameManager( fcChip,0 ); + if( iStatus ) + { + // failed to initialize Frame Manager + break; + } + + default: + break; + } + LEAVE("InitializeTachLite"); + + return iStatus; +} + + + + +// Depending on the type of platform memory allocation (e.g. dynamic), +// it's probably best to free memory in opposite order as it was allocated. +// Order of allocation: see other function + + +int CpqTsDestroyTachLiteQues( void *pHBA, int opcode) +{ + CPQFCHBA *cpqfcHBAdata = (CPQFCHBA*)pHBA; + PTACHYON fcChip = &cpqfcHBAdata->fcChip; + USHORT i, j, iStatus=0; + void* vPtr; // mem Align manager sets this to the freed address on success + unsigned long ulPtr; // for 64-bit pointer cast (e.g. Alpa machine) + + ENTER("DestroyTachLiteQues"); + + if( fcChip->SEST ) + { + // search out and free Pool for Extended S/G list pages + + for( i=0, j=0; i < TACH_SEST_LEN; i++, j=0) // for each exchange + { + // It's possible that extended S/G pages were allocated and + // not cleared due to error conditions or O/S driver termination. + // Make sure they're all gone. + while( fcChip->SEST->sgPages[i].PoolPage[j] && + (j < TL_MAX_SGPAGES)) + kfree( fcChip->SEST->sgPages[i].PoolPage[j++]); + + } + ulPtr = (unsigned long)fcChip->SEST; + vPtr = fcMemManager( &cpqfcHBAdata->dynamic_mem[0], + 0,0, (ULONG)ulPtr ); // 'free' mem + fcChip->SEST = 0L; // null invalid ptr + if( !vPtr ) + { + printk("SEST mem not freed\n"); + iStatus = -1; + } + } + + if( fcChip->SFQ ) + { + + ulPtr = (unsigned long)fcChip->SFQ; + vPtr = fcMemManager( &cpqfcHBAdata->dynamic_mem[0], + 0,0, (ULONG)ulPtr ); // 'free' mem + fcChip->SFQ = 0L; // null invalid ptr + if( !vPtr ) + { + printk("SFQ mem not freed\n"); + iStatus = -2; + } + } + + + if( fcChip->IMQ ) + { + // clear Indexes to show empty Queue + fcChip->IMQ->producerIndex = 0; + fcChip->IMQ->consumerIndex = 0; + + ulPtr = (unsigned long)fcChip->IMQ; + vPtr = fcMemManager( &cpqfcHBAdata->dynamic_mem[0], + 0,0, (ULONG)ulPtr ); // 'free' mem + fcChip->IMQ = 0L; // null invalid ptr + if( !vPtr ) + { + printk("IMQ mem not freed\n"); + iStatus = -3; + } + } + + if( fcChip->ERQ ) // release memory blocks used by the queues + { + ulPtr = (unsigned long)fcChip->ERQ; + vPtr = fcMemManager( &cpqfcHBAdata->dynamic_mem[0], + 0,0, (ULONG)ulPtr ); // 'free' mem + fcChip->ERQ = 0L; // null invalid ptr + if( !vPtr ) + { + printk("ERQ mem not freed\n"); + iStatus = -4; + } + } + + // free up the primary EXCHANGES struct + if( fcChip->Exchanges != NULL) + { +// printk("kfree() on Exchanges @%p\n", fcChip->Exchanges); + kfree( fcChip->Exchanges); + } + + // free up Link Q + if( cpqfcHBAdata->fcLQ != NULL ) + { +// printk("kfree() on LinkQ @%p\n", fcChip->fcLQ); + kfree( cpqfcHBAdata->fcLQ); + } + + LEAVE("DestroyTachLiteQues"); + + return iStatus; // non-zero (failed) if any memory not freed +} + + + + + +// The SFQ is an array with SFQ_LEN length, each element (QEntry) +// with eight 32-bit words. TachLite places incoming FC frames (i.e. +// a valid FC frame with our AL_PA ) in contiguous SFQ entries +// and sends a completion message telling the host where the frame is +// in the que. +// This function copies the current (or oldest not-yet-processed) QEntry to +// a caller's contiguous buffer and updates the Tachyon chip's consumer index +// +// NOTE: +// An FC frame may consume one or many SFQ entries. We know the total +// length from the completion message. The caller passes a buffer large +// enough for the complete message (max 2k). + +static void CpqTsGetSFQEntry( + PTACHYON fcChip, + USHORT producerNdx, + ULONG *ulDestPtr, // contiguous destination buffer + BOOLEAN UpdateChip) +{ + ULONG total_bytes=0; + ULONG consumerIndex = fcChip->SFQ->consumerIndex; + + // check passed copy of SFQ producer index - + // is a new message waiting for us? + // equal indexes means SFS is copied + + while( producerNdx != consumerIndex ) + { // need to process message + total_bytes += 64; // maintain count to prevent writing past buffer + // don't allow copies over Fibre Channel defined length! + if( total_bytes <= 2048 ) + { + memcpy( ulDestPtr, + &fcChip->SFQ->QEntry[consumerIndex], + 64 ); // each SFQ entry is 64 bytes + ulDestPtr += 16; // advance pointer to next 64 byte block + } + // Tachyon is producing, + // and we are consuming + + if( ++consumerIndex >= SFQ_LEN)// check for rollover + consumerIndex = 0L; // reset it + } + + // if specified, update the Tachlite chip ConsumerIndex... + if( UpdateChip ) + { + fcChip->SFQ->consumerIndex = consumerIndex; + writel( fcChip->SFQ->consumerIndex, + fcChip->Registers.SFQconsumerIndex.address); + } +} + + + +// TachLite routinely freezes it's core ques - Outbound FIFO, Inbound FIFO, +// and Exchange Request Queue (ERQ) on error recover - +// (e.g. whenever a LIP occurs). Here +// we routinely RESUME by clearing these bits, but only if the loop is up +// to avoid ERROR IDLE messages forever. + +void CpqTsUnFreezeTachlite( void *pChip, int type ) +{ + PTACHYON fcChip = (PTACHYON)pChip; + fcChip->Registers.TYcontrol.value = + readl(fcChip->Registers.TYcontrol.address); + + // (bit 4 of value is GBIC LASER) + // if we 'unfreeze' the core machines before the loop is healthy + // (i.e. FLT, OS, LS failure bits set in FMstatus) + // we can get 'error idle' messages forever. Verify that + // FMstatus (Link Status) is OK before unfreezing. + + if( !(fcChip->Registers.FMstatus.value & 0x07000000L) && // bits clear? + !(fcChip->Registers.FMstatus.value & 0x80 )) // Active LPSM? + { + fcChip->Registers.TYcontrol.value &= ~0x300L; // clear FEQ, FFA + if( type == 1 ) // unfreeze ERQ only + { +// printk("Unfreezing ERQ\n"); + fcChip->Registers.TYcontrol.value |= 0x10000L; // set REQ + } + else // unfreeze both ERQ and FCP-ASSIST (SEST) + { +// printk("Unfreezing ERQ & FCP-ASSIST\n"); + + // set ROF, RIF, REQ - resume Outbound FCP, Inbnd FCP, ERQ + fcChip->Registers.TYcontrol.value |= 0x70000L; // set ROF, RIF, REQ + } + + writel( fcChip->Registers.TYcontrol.value, + fcChip->Registers.TYcontrol.address); + + } + // readback for verify (TachLite still frozen?) + fcChip->Registers.TYstatus.value = + readl(fcChip->Registers.TYstatus.address); +} + + +// Whenever an FC Exchange Abort is required, we must manipulate the +// Host/Tachyon shared memory SEST table. Before doing this, we +// must freeze Tachyon, which flushes certain buffers and ensure we +// can manipulate the SEST without contention. +// This freeze function will result in FCP & ERQ FROZEN completion +// messages (per argument "type"). + +void CpqTsFreezeTachlite( void *pChip, int type ) +{ + PTACHYON fcChip = (PTACHYON)pChip; + fcChip->Registers.TYcontrol.value = + readl(fcChip->Registers.TYcontrol.address); + + //set FFA, FEQ - freezes SCSI assist and ERQ + if( type == 1) // freeze ERQ only + fcChip->Registers.TYcontrol.value |= 0x100L; // (bit 4 is laser) + else // freeze both FCP assists (SEST) and ERQ + fcChip->Registers.TYcontrol.value |= 0x300L; // (bit 4 is laser) + + writel( fcChip->Registers.TYcontrol.value, + fcChip->Registers.TYcontrol.address); + +} + + + + +// TL has two Frame Manager Link Status Registers, with three 8-bit +// fields each. These eight bit counters are cleared after each read, +// so we define six 32-bit accumulators for these TL counters. This +// function breaks out each 8-bit field and adds the value to the existing +// sum. (s/w counters cleared independently) + +void fcParseLinkStatusCounters(PTACHYON fcChip) +{ + UCHAR bBuff; + ULONG ulBuff; + + +// The BB0 timer usually increments when TL is initialized, resulting +// in an initially bogus count. If our own counter is ZERO, it means we +// are reading this thing for the first time, so we ignore the first count. +// Also, reading the register does not clear it, so we have to keep an +// additional static counter to detect rollover (yuk). + + if( fcChip->fcStats.lastBB0timer == 0L) // TL was reset? (ignore 1st values) + { + // get TL's register counter - the "last" count + fcChip->fcStats.lastBB0timer = + fcChip->Registers.FMBB_CreditZero.value & 0x00ffffffL; + } + else // subsequent pass - check for rollover + { + // "this" count + ulBuff = fcChip->Registers.FMBB_CreditZero.value & 0x00ffffffL; + if( fcChip->fcStats.lastBB0timer > ulBuff ) // rollover happened + { + // counter advanced to max... + fcChip->fcStats.BB0_Timer += (0x00FFFFFFL - fcChip->fcStats.lastBB0timer); + fcChip->fcStats.BB0_Timer += ulBuff; // plus some more + + + } + else // no rollover -- more counts or no change + { + fcChip->fcStats.BB0_Timer += (ulBuff - fcChip->fcStats.lastBB0timer); + + } + + fcChip->fcStats.lastBB0timer = ulBuff; + } + + + + bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus1.value >> 24); + fcChip->fcStats.LossofSignal += bBuff; + + bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus1.value >> 16); + fcChip->fcStats.BadRXChar += bBuff; + + bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus1.value >> 8); + fcChip->fcStats.LossofSync += bBuff; + + + bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus2.value >> 24); + fcChip->fcStats.Rx_EOFa += bBuff; + + bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus2.value >> 16); + fcChip->fcStats.Dis_Frm += bBuff; + + bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus2.value >> 8); + fcChip->fcStats.Bad_CRC += bBuff; +} + + +void cpqfcTSClearLinkStatusCounters(PTACHYON fcChip) +{ + ENTER("ClearLinkStatusCounters"); + memset( &fcChip->fcStats, 0, sizeof( FCSTATS)); + LEAVE("ClearLinkStatusCounters"); + +} + + + + +// The following function reads the I2C hardware to get the adapter's +// World Wide Name (WWN). +// If the WWN is "500805f1fadb43e8" (as printed on the card), the +// Tachyon WWN_hi (32-bit) register is 500805f1, and WWN_lo register +// is fadb43e8. +// In the NVRAM, the bytes appear as: +// [2d] .. +// [2e] .. +// [2f] 50 +// [30] 08 +// [31] 05 +// [32] f1 +// [33] fa +// [34] db +// [35] 43 +// [36] e8 +// +// In the Fibre Channel (Big Endian) format, the FC-AL LISM frame will +// be correctly loaded by Tachyon silicon. In the login payload, bytes +// must be correctly swapped for Big Endian format. + +int CpqTsReadWriteWWN( PVOID pChip, int Read) +{ + PTACHYON fcChip = (PTACHYON)pChip; +#define NVRAM_SIZE 512 + unsigned short i, count = NVRAM_SIZE; + UCHAR nvRam[NVRAM_SIZE], WWNbuf[8]; + ULONG ulBuff; + int iStatus=-1; // assume failure + int WWNoffset; + + ENTER("ReadWriteWWN"); + // Now try to read the WWN from the adapter's NVRAM + + if( Read ) // READing NVRAM WWN? + { + ulBuff = cpqfcTS_ReadNVRAM( fcChip->Registers.TYstatus.address, + fcChip->Registers.TYcontrol.address, + count, &nvRam[0] ); + + if( ulBuff ) // NVRAM read successful? + { + iStatus = 0; // success! + + // for engineering/ prototype boards, the data may be + // invalid (GIGO, usually all "FF"); this prevents the + // parse routine from working correctly, which means + // nothing will be written to our passed buffer. + + WWNoffset = cpqfcTS_GetNVRAM_data( WWNbuf, nvRam ); + + if( !WWNoffset ) // uninitialized NVRAM -- copy bytes directly + { + printk( "CAUTION: Copying NVRAM data on fcChip\n"); + for( i= 0; i < 8; i++) + WWNbuf[i] = nvRam[i +0x2f]; // dangerous! some formats won't work + } + + fcChip->Registers.wwn_hi = 0L; + fcChip->Registers.wwn_lo = 0L; + for( i=0; i<4; i++) // WWN bytes are big endian in NVRAM + { + ulBuff = 0L; + ulBuff = (ULONG)(WWNbuf[i]) << (8 * (3-i)); + fcChip->Registers.wwn_hi |= ulBuff; + } + for( i=0; i<4; i++) // WWN bytes are big endian in NVRAM + { + ulBuff = 0L; + ulBuff = (ULONG)(WWNbuf[i+4]) << (8 * (3-i)); + fcChip->Registers.wwn_lo |= ulBuff; + } + } // done reading + else + { + + printk( "cpqfcTS: NVRAM read failed\n"); + + } + } + + else // WRITE + { + + // NOTE: WRITE not supported & not used in released driver. + + + printk("ReadWriteNRAM: can't write NVRAM; aborting write\n"); + } + + LEAVE("ReadWriteWWN"); + return iStatus; +} + + + + + +// The following function reads or writes the entire "NVRAM" contents of +// the I2C hardware (i.e. the NM24C03). Note that HP's 5121A (TS 66Mhz) +// adapter does not use the NM24C03 chip, so this function only works on +// Compaq's adapters. + +int CpqTsReadWriteNVRAM( PVOID pChip, PVOID buf, int Read) +{ + PTACHYON fcChip = (PTACHYON)pChip; +#define NVRAM_SIZE 512 + ULONG ulBuff; + UCHAR *ucPtr = buf; // cast caller's void ptr to UCHAR array + int iStatus=-1; // assume failure + + + if( Read ) // READing NVRAM? + { + ulBuff = cpqfcTS_ReadNVRAM( // TRUE on success + fcChip->Registers.TYstatus.address, + fcChip->Registers.TYcontrol.address, + 256, // bytes to write + ucPtr ); // source ptr + + + if( ulBuff ) + iStatus = 0; // success + else + { +#ifdef DBG + printk( "CAUTION: NVRAM read failed\n"); +#endif + } + } // done reading + + else // WRITING NVRAM + { + + printk("cpqfcTS: WRITE of FC Controller's NVRAM disabled\n"); + } + + return iStatus; +} diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/cpqfcTSi2c.c linux/drivers/scsi/cpqfcTSi2c.c --- v2.4.0-test8/linux/drivers/scsi/cpqfcTSi2c.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/cpqfcTSi2c.c Thu Sep 21 13:22:05 2000 @@ -0,0 +1,493 @@ +/* Copyright(c) 2000, Compaq Computer Corporation + * Fibre Channel Host Bus Adapter + * 64-bit, 66MHz PCI + * Originally developed and tested on: + * (front): [chip] Tachyon TS HPFC-5166A/1.2 L2C1090 ... + * SP# P225CXCBFIEL6T, Rev XC + * SP# 161290-001, Rev XD + * (back): Board No. 010008-001 A/W Rev X5, FAB REV X5 + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * Written by Don Zimmerman +*/ +// These functions control the NVRAM I2C hardware on +// non-intelligent Fibre Host Adapters. +// The primary purpose is to read the HBA's NVRAM to get adapter's +// manufactured WWN to copy into Tachyon chip registers +// Orignal source author unknown + +#include +enum boolean { FALSE, TRUE } ; + + +#ifndef UCHAR +typedef __u8 UCHAR; +#endif +#ifndef BOOLEAN +typedef __u8 BOOLEAN; +#endif +#ifndef USHORT +typedef __u16 USHORT; +#endif +#ifndef ULONG +typedef __u32 ULONG; +#endif + + +#include +#include +#include +#include +#include // struct pt_regs for IRQ handler & Port I/O + +#include "cpqfcTSchip.h" + +static void tl_i2c_tx_byte( void* GPIOout, UCHAR data ); +/*static BOOLEAN tl_write_i2c_page_portion( void* GPIOin, void* GPIOout, + USHORT startOffset, // e.g. 0x2f for WWN start + USHORT count, + UCHAR *buf ); +*/ + +// +// Tachlite GPIO2, GPIO3 (I2C) DEFINES +// The NVRAM chip NM24C03 defines SCL (serial clock) and SDA (serial data) +// GPIO2 drives SDA, and GPIO3 drives SCL +// +// Since Tachlite inverts the state of the GPIO 0-3 outputs, SET writes 0 +// and clear writes 1. The input lines (read in TL status) is NOT inverted +// This really helps confuse the code and debugging. + +#define SET_DATA_HI 0x0 +#define SET_DATA_LO 0x8 +#define SET_CLOCK_HI 0x0 +#define SET_CLOCK_LO 0x4 + +#define SENSE_DATA_HI 0x8 +#define SENSE_DATA_LO 0x0 +#define SENSE_CLOCK_HI 0x4 +#define SENSE_CLOCK_LO 0x0 + +#define SLAVE_READ_ADDRESS 0xA1 +#define SLAVE_WRITE_ADDRESS 0xA0 + + +static void i2c_delay(ULONG mstime); +static void tl_i2c_clock_pulse( UCHAR , void* GPIOout); +static UCHAR tl_read_i2c_data( void* ); + + +//----------------------------------------------------------------------------- +// +// Name: I2C_RX_ACK +// +// This routine receives an acknowledge over the I2C bus. +// +//----------------------------------------------------------------------------- +static unsigned short tl_i2c_rx_ack( void* GPIOin, void* GPIOout ) +{ + unsigned long value; + + // do clock pulse, let data line float high + tl_i2c_clock_pulse( SET_DATA_HI, GPIOout ); + + // slave must drive data low for acknowledge + value = tl_read_i2c_data( GPIOin); + if (value & SENSE_DATA_HI ) + return( FALSE ); + + return( TRUE ); +} +//----------------------------------------------------------------------------- +// +// Name: READ_I2C_REG +// +// This routine reads the I2C control register using the global +// IO address stored in gpioreg. +// +//----------------------------------------------------------------------------- +static UCHAR tl_read_i2c_data( void* gpioreg ) +{ + return( (UCHAR)(readl( gpioreg ) & 0x08L) ); // GPIO3 +} +//----------------------------------------------------------------------------- +// +// Name: WRITE_I2C_REG +// +// This routine writes the I2C control register using the global +// IO address stored in gpioreg. +// In Tachlite, we don't want to modify other bits in TL Control reg. +// +//----------------------------------------------------------------------------- +static void tl_write_i2c_reg( void* gpioregOUT, UCHAR value ) +{ + ULONG temp; + + // First read the register and clear out the old bits + temp = readl( gpioregOUT ) & 0xfffffff3L; + + // Now or in the new data and send it back out + writel( temp | value, gpioregOUT); +} +//----------------------------------------------------------------------------- +// +// Name: I2C_TX_START +// +// This routine transmits a start condition over the I2C bus. +// 1. Set SCL (clock, GPIO2) HIGH, set SDA (data, GPIO3) HIGH, +// wait 5us to stabilize. +// 2. With SCL still HIGH, drive SDA low. The low transition marks +// the start condition to NM24Cxx (the chip) +// NOTE! In TL control reg., output 1 means chip sees LOW +// +//----------------------------------------------------------------------------- +static unsigned short tl_i2c_tx_start( void* GPIOin, void* GPIOout ) +{ + unsigned short i; + ULONG value; + + if ( !(tl_read_i2c_data(GPIOin) & SENSE_DATA_HI)) + { + // start with clock high, let data float high + tl_write_i2c_reg( GPIOout, SET_DATA_HI | SET_CLOCK_HI ); + + // keep sending clock pulses if slave is driving data line + for (i = 0; i < 10; i++) + { + tl_i2c_clock_pulse( SET_DATA_HI, GPIOout ); + + if ( tl_read_i2c_data(GPIOin) & SENSE_DATA_HI ) + break; + } + + // if he's still driving data low after 10 clocks, abort + value = tl_read_i2c_data( GPIOin ); // read status + if (!(value & 0x08) ) + return( FALSE ); + } + + + // To START, bring data low while clock high + tl_write_i2c_reg( GPIOout, SET_CLOCK_HI | SET_DATA_LO ); + + i2c_delay(0); + + return( TRUE ); // TX start successful +} +//----------------------------------------------------------------------------- +// +// Name: I2C_TX_STOP +// +// This routine transmits a stop condition over the I2C bus. +// +//----------------------------------------------------------------------------- + +static unsigned short tl_i2c_tx_stop( void* GPIOin, void* GPIOout ) +{ + int i; + + for (i = 0; i < 10; i++) + { + // Send clock pulse, drive data line low + tl_i2c_clock_pulse( SET_DATA_LO, GPIOout ); + + // To STOP, bring data high while clock high + tl_write_i2c_reg( GPIOout, SET_DATA_HI | SET_CLOCK_HI ); + + // Give the data line time to float high + i2c_delay(0); + + // If slave is driving data line low, there's a problem; retry + if ( tl_read_i2c_data(GPIOin) & SENSE_DATA_HI ) + return( TRUE ); // TX STOP successful! + } + + return( FALSE ); // error +} +//----------------------------------------------------------------------------- +// +// Name: I2C_TX_uchar +// +// This routine transmits a byte across the I2C bus. +// +//----------------------------------------------------------------------------- +static void tl_i2c_tx_byte( void* GPIOout, UCHAR data ) +{ + UCHAR bit; + + for (bit = 0x80; bit; bit >>= 1) + { + if( data & bit ) + tl_i2c_clock_pulse( (UCHAR)SET_DATA_HI, GPIOout); + else + tl_i2c_clock_pulse( (UCHAR)SET_DATA_LO, GPIOout); + } +} +//----------------------------------------------------------------------------- +// +// Name: I2C_RX_uchar +// +// This routine receives a byte across the I2C bus. +// +//----------------------------------------------------------------------------- +static UCHAR tl_i2c_rx_byte( void* GPIOin, void* GPIOout ) +{ + UCHAR bit; + UCHAR data = 0; + + + for (bit = 0x80; bit; bit >>= 1) { + // do clock pulse, let data line float high + tl_i2c_clock_pulse( SET_DATA_HI, GPIOout ); + + // read data line + if ( tl_read_i2c_data( GPIOin) & 0x08 ) + data |= bit; + } + + return (data); +} +//***************************************************************************** +//***************************************************************************** +// Function: read_i2c_nvram +// Arguments: UCHAR count number of bytes to read +// UCHAR *buf area to store the bytes read +// Returns: 0 - failed +// 1 - success +//***************************************************************************** +//***************************************************************************** +unsigned long cpqfcTS_ReadNVRAM( void* GPIOin, void* GPIOout , USHORT count, + UCHAR *buf ) +{ + unsigned short i; + + if( !( tl_i2c_tx_start(GPIOin, GPIOout) )) + return FALSE; + + // Select the NVRAM for "dummy" write, to set the address + tl_i2c_tx_byte( GPIOout , SLAVE_WRITE_ADDRESS ); + if ( !tl_i2c_rx_ack(GPIOin, GPIOout ) ) + return( FALSE ); + + // Now send the address where we want to start reading + tl_i2c_tx_byte( GPIOout , 0 ); + if ( !tl_i2c_rx_ack(GPIOin, GPIOout ) ) + return( FALSE ); + + // Send a repeated start condition and select the + // slave for reading now. + if( tl_i2c_tx_start(GPIOin, GPIOout) ) + tl_i2c_tx_byte( GPIOout, SLAVE_READ_ADDRESS ); + + if ( !tl_i2c_rx_ack(GPIOin, GPIOout) ) + return( FALSE ); + + // this loop will now read out the data and store it + // in the buffer pointed to by buf + for ( i=0; i> 3; + if (name == 0x0F) + done = TRUE; + } + else + { + name = z & 0x7F; + len = 3 + data_ptr[i+1] + (data_ptr[i+2] << 8); + + switch (name) + { + case 0x0D: + // + j = i + 3; + // + if ( data_ptr[j] == 0x3b ) { + len = 6; + break; + } + + while ( j<(i+len) ) { + sub_name = (data_ptr[j] & 0x3f); + sub_len = data_ptr[j+1] + + (data_ptr[j+2] << 8); + ptr_inc = sub_len + 3; + switch (sub_name) + { + case 0x3C: + memcpy( wwnbuf, &data_ptr[j+3], 8); + iReturn = j+3; + break; + default: + break; + } + j += ptr_inc; + } + break; + default: + break; + } + } + // + i += len; + } // end while + return iReturn; +} + + + + + +// define a short 5 micro sec delay, and longer (ms) delay + +static void i2c_delay(ULONG mstime) +{ + ULONG i; + +// NOTE: we only expect to use these delays when reading +// our adapter's NVRAM, which happens only during adapter reset. +// Delay technique from "Linux Device Drivers", A. Rubini +// (1st Ed.) pg 137. + +// printk(" delay %lx ", mstime); + if( mstime ) // ms delay? + { + // delay technique + for( i=0; i < mstime; i++) + udelay(1000); // 1ms per loop + + } + else // 5 micro sec delay + + udelay( 5 ); // micro secs + +// printk("done\n"); +} + + + diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/cpqfcTSinit.c linux/drivers/scsi/cpqfcTSinit.c --- v2.4.0-test8/linux/drivers/scsi/cpqfcTSinit.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/cpqfcTSinit.c Tue Sep 19 08:01:34 2000 @@ -0,0 +1,1815 @@ +/* Copyright(c) 2000, Compaq Computer Corporation + * Fibre Channel Host Bus Adapter + * 64-bit, 66MHz PCI + * Originally developed and tested on: + * (front): [chip] Tachyon TS HPFC-5166A/1.2 L2C1090 ... + * SP# P225CXCBFIEL6T, Rev XC + * SP# 161290-001, Rev XD + * (back): Board No. 010008-001 A/W Rev X5, FAB REV X5 + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * Written by Don Zimmerman + * IOCTL and procfs added by Jouke Numan + * SMP testing by Chel Van Gennip + * + * portions copied from: + * QLogic CPQFCTS SCSI-FCP + * Written by Erik H. Moe, ehm@cris.com + * Copyright 1995, Erik H. Moe + * Renamed and updated to 1.3.x by Michael Griffith + * Chris Loveland to support the isp2100 and isp2200 +*/ + + +#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s)) + +#include +#include +#include +#include +#include +#include +#include +#include +#include // request_region() prototype +#include // ioremap() +#ifdef __alpha__ +#define __KERNEL_SYSCALLS__ +#endif +#include +#include +#include // ioctl related +#include +#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,18) +#include +#else +#include +#endif +#include "sd.h" +#include +#include "hosts.h" +#include "cpqfcTSchip.h" +#include "cpqfcTSstructs.h" + +#include "cpqfcTS.h" + +#include +/* Embedded module documentation macros - see module.h */ +MODULE_AUTHOR("Compaq Computer Corporation"); +MODULE_DESCRIPTION("Driver for Compaq 64-bit/66Mhz PCI Fibre Channel HBA"); + +// This struct was originally defined in +// /usr/src/linux/include/linux/proc_fs.h +// since it's only partially implemented, we only use first +// few fields... +// NOTE: proc_fs changes in 2.4 kernel + +#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,27) +static struct proc_dir_entry proc_scsi_cpqfcTS = +{ + PROC_SCSI_CPQFCTS, // ushort low_ino (enumerated list) + 7, // ushort namelen + DEV_NAME, // const char* name + S_IFDIR | S_IRUGO | S_IXUGO, // mode_t mode + 2 // nlink_t nlink + // etc. ... +}; + + +#endif + + + +/* local function to load our per-HBA (local) data for chip + registers, FC link state, all FC exchanges, etc. + + We allocate space and compute address offsets for the + most frequently accessed addresses; others (like World Wide + Name) are not necessary. + +*/ +static void Cpqfc_initHBAdata( CPQFCHBA *cpqfcHBAdata, struct pci_dev *PciDev ) +{ + + cpqfcHBAdata->PciDev = PciDev; // copy PCI info ptr + + // since x86 port space is 64k, we only need the lower 16 bits + cpqfcHBAdata->fcChip.Registers.IOBaseL = + PciDev->base_address[1] & PCI_BASE_ADDRESS_IO_MASK; + + cpqfcHBAdata->fcChip.Registers.IOBaseU = + PciDev->base_address[2] & PCI_BASE_ADDRESS_IO_MASK; + + // 32-bit memory addresses + cpqfcHBAdata->fcChip.Registers.MemBase = + PciDev->base_address[3] & PCI_BASE_ADDRESS_MEM_MASK; + + cpqfcHBAdata->fcChip.Registers.ReMapMemBase = + ioremap( PciDev->base_address[3] & PCI_BASE_ADDRESS_MEM_MASK, + 0x200); + + cpqfcHBAdata->fcChip.Registers.RAMBase = + PciDev->base_address[4]; + + cpqfcHBAdata->fcChip.Registers.SROMBase = // NULL for HP TS adapter + PciDev->base_address[5]; + + // now the Tachlite chip registers + // the REGISTER struct holds both the physical address & last + // written value (some TL registers are WRITE ONLY) + + cpqfcHBAdata->fcChip.Registers.SFQconsumerIndex.address = + cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_SFQ_CONSUMER_INDEX; + + cpqfcHBAdata->fcChip.Registers.ERQproducerIndex.address = + cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_ERQ_PRODUCER_INDEX; + + // TL Frame Manager + cpqfcHBAdata->fcChip.Registers.FMconfig.address = + cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_CONFIG; + cpqfcHBAdata->fcChip.Registers.FMcontrol.address = + cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_CONTROL; + cpqfcHBAdata->fcChip.Registers.FMstatus.address = + cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_STATUS; + cpqfcHBAdata->fcChip.Registers.FMLinkStatus1.address = + cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_LINK_STAT1; + cpqfcHBAdata->fcChip.Registers.FMLinkStatus2.address = + cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_LINK_STAT2; + cpqfcHBAdata->fcChip.Registers.FMBB_CreditZero.address = + cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_BB_CREDIT0; + + // TL Control Regs + cpqfcHBAdata->fcChip.Registers.TYconfig.address = + cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_TACH_CONFIG; + cpqfcHBAdata->fcChip.Registers.TYcontrol.address = + cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_TACH_CONTROL; + cpqfcHBAdata->fcChip.Registers.TYstatus.address = + cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_TACH_STATUS; + cpqfcHBAdata->fcChip.Registers.rcv_al_pa.address = + cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_RCV_AL_PA; + cpqfcHBAdata->fcChip.Registers.ed_tov.address = + cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_ED_TOV; + + + cpqfcHBAdata->fcChip.Registers.INTEN.address = + cpqfcHBAdata->fcChip.Registers.ReMapMemBase + IINTEN; + cpqfcHBAdata->fcChip.Registers.INTPEND.address = + cpqfcHBAdata->fcChip.Registers.ReMapMemBase + IINTPEND; + cpqfcHBAdata->fcChip.Registers.INTSTAT.address = + cpqfcHBAdata->fcChip.Registers.ReMapMemBase + IINTSTAT; + + DEBUG_PCI(printk(" cpqfcHBAdata->fcChip.Registers. :\n")); + DEBUG_PCI(printk(" IOBaseL = %x\n", + cpqfcHBAdata->fcChip.Registers.IOBaseL)); + DEBUG_PCI(printk(" IOBaseU = %x\n", + cpqfcHBAdata->fcChip.Registers.IOBaseU)); + + printk(" ioremap'd Membase: %p\n", cpqfcHBAdata->fcChip.Registers.ReMapMemBase); + + DEBUG_PCI(printk(" SFQconsumerIndex.address = %p\n", + cpqfcHBAdata->fcChip.Registers.SFQconsumerIndex.address)); + DEBUG_PCI(printk(" ERQproducerIndex.address = %p\n", + cpqfcHBAdata->fcChip.Registers.ERQproducerIndex.address)); + DEBUG_PCI(printk(" TYconfig.address = %p\n", + cpqfcHBAdata->fcChip.Registers.TYconfig.address)); + DEBUG_PCI(printk(" FMconfig.address = %p\n", + cpqfcHBAdata->fcChip.Registers.FMconfig.address)); + DEBUG_PCI(printk(" FMcontrol.address = %p\n", + cpqfcHBAdata->fcChip.Registers.FMcontrol.address)); + + // set default options for FC controller (chip) + cpqfcHBAdata->fcChip.Options.initiator = 1; // default: SCSI initiator + cpqfcHBAdata->fcChip.Options.target = 0; // default: SCSI target + cpqfcHBAdata->fcChip.Options.extLoopback = 0;// default: no loopback @GBIC + cpqfcHBAdata->fcChip.Options.intLoopback = 0;// default: no loopback inside chip + + // set highest and lowest FC-PH version the adapter/driver supports + // (NOT strict compliance) + cpqfcHBAdata->fcChip.highest_FCPH_ver = FC_PH3; + cpqfcHBAdata->fcChip.lowest_FCPH_ver = FC_PH43; + + // set function points for this controller / adapter + cpqfcHBAdata->fcChip.ResetTachyon = CpqTsResetTachLite; + cpqfcHBAdata->fcChip.FreezeTachyon = CpqTsFreezeTachlite; + cpqfcHBAdata->fcChip.UnFreezeTachyon = CpqTsUnFreezeTachlite; + cpqfcHBAdata->fcChip.CreateTachyonQues = CpqTsCreateTachLiteQues; + cpqfcHBAdata->fcChip.DestroyTachyonQues = CpqTsDestroyTachLiteQues; + cpqfcHBAdata->fcChip.InitializeTachyon = CpqTsInitializeTachLite; + cpqfcHBAdata->fcChip.LaserControl = CpqTsLaserControl; + cpqfcHBAdata->fcChip.ProcessIMQEntry = CpqTsProcessIMQEntry; + cpqfcHBAdata->fcChip.InitializeFrameManager = CpqTsInitializeFrameManager;; + cpqfcHBAdata->fcChip.ReadWriteWWN = CpqTsReadWriteWWN; + cpqfcHBAdata->fcChip.ReadWriteNVRAM = CpqTsReadWriteNVRAM; + + + +} + + +/* (borrowed from linux/drivers/scsi/hosts.c) */ +static void launch_FCworker_thread(struct Scsi_Host *HostAdapter) +{ + DECLARE_MUTEX_LOCKED(sem); + + CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata; + + ENTER("launch_FC_worker_thread"); + + cpqfcHBAdata->notify_wt = &sem; + + kernel_thread((int (*)(void *))cpqfcTSWorkerThread, + (void *) HostAdapter, 0); + /* + * Now wait for the kernel error thread to initialize itself + + */ + down (&sem); + cpqfcHBAdata->notify_wt = NULL; + + LEAVE("launch_FC_worker_thread"); + +} + + +/* "Entry" point to discover if any supported PCI + bus adapter can be found +*/ +// We're supporting: +// Compaq 64-bit, 66MHz HBA with Tachyon TS +// Agilent XL2 +#define HBA_TYPES 2 + + +int cpqfcTS_detect(Scsi_Host_Template *ScsiHostTemplate) +{ + int NumberOfAdapters=0; // how many of our PCI adapters are found? + struct pci_dev *PciDev = NULL; + struct Scsi_Host *HostAdapter = NULL; + CPQFCHBA *cpqfcHBAdata = NULL; + struct timer_list *cpqfcTStimer = NULL; + SupportedPCIcards PCIids[HBA_TYPES]; + int i; + + ENTER("cpqfcTS_detect"); + +#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,27) + ScsiHostTemplate->proc_dir = &proc_scsi_cpqfcTS; +#else + ScsiHostTemplate->proc_name = "cpqfcTS"; +#endif + + if( pci_present() == 0) // no PCI busses? + { + printk( " no PCI bus?@#!\n"); + return NumberOfAdapters; + } + + // what HBA adapters are we supporting? + PCIids[0].vendor_id = PCI_VENDOR_ID_COMPAQ; + PCIids[0].device_id = CPQ_DEVICE_ID; + PCIids[1].vendor_id = PCI_VENDOR_ID_HP; // i.e. 103Ch (Agilent == HP for now) + PCIids[1].device_id = AGILENT_XL2_ID; // i.e. 1029h + + for( i=0; i < HBA_TYPES; i++) + { + // look for all HBAs of each type + + while( (PciDev = + pci_find_device( PCIids[i].vendor_id, PCIids[i].device_id, PciDev) )) + { + // NOTE: (kernel 2.2.12-32) limits allocation to 128k bytes... + printk(" scsi_register allocating %d bytes for FC HBA\n", + (ULONG)sizeof(CPQFCHBA)); + + HostAdapter = scsi_register( ScsiHostTemplate, sizeof( CPQFCHBA ) ); + DEBUG_PCI( printk(" HBA found!\n")); + DEBUG_PCI( printk(" HostAdapter->PciDev->irq = %u\n", PciDev->irq) ); + DEBUG_PCI(printk(" PciDev->baseaddress[]= %lx\n", PciDev->base_address[0])); + DEBUG_PCI(printk(" PciDev->baseaddress[]= %lx\n", PciDev->base_address[1])); + DEBUG_PCI(printk(" PciDev->baseaddress[]= %lx\n", PciDev->base_address[2])); + DEBUG_PCI(printk(" PciDev->baseaddress[]= %lx\n", PciDev->base_address[3])); + + + HostAdapter->irq = PciDev->irq; // copy for Scsi layers + + // HP Tachlite uses two (255-byte) ranges of Port I/O (lower & upper), + // for a total I/O port address space of 512 bytes. + // mask out the I/O port address (lower) & record + HostAdapter->io_port = (unsigned int) + PciDev->base_address[1] & PCI_BASE_ADDRESS_IO_MASK; + HostAdapter->n_io_port = 0xff; + + // i.e., expect 128 targets (arbitrary number), while the + // RA-4000 supports 32 LUNs + HostAdapter->max_id = 0; // incremented as devices log in + HostAdapter->max_lun = CPQFCTS_MAX_LUN; // LUNs per FC device + HostAdapter->max_channel = CPQFCTS_MAX_CHANNEL; // multiple busses? + HostAdapter->hostt->use_new_eh_code = 1; // new error handling + + // get the pointer to our HBA specific data... (one for + // each HBA on the PCI bus(ses)). + cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata; + + // make certain our data struct is clear + memset( cpqfcHBAdata, 0, sizeof( CPQFCHBA ) ); + + + // initialize our HBA info + cpqfcHBAdata->HBAnum = NumberOfAdapters; + + cpqfcHBAdata->HostAdapter = HostAdapter; // back ptr + Cpqfc_initHBAdata( cpqfcHBAdata, PciDev ); // fill MOST fields + + cpqfcHBAdata->HBAnum = NumberOfAdapters; + + + // request necessary resources and check for conflicts + if( request_irq( HostAdapter->irq, + cpqfcTS_intr_handler, + SA_INTERRUPT | SA_SHIRQ, + DEV_NAME, + HostAdapter) ) + { + printk(" IRQ %u already used\n", HostAdapter->irq); + scsi_unregister( HostAdapter); + continue; + } + + // Since we have two 256-byte I/O port ranges (upper + // and lower), check them both + if( check_region( cpqfcHBAdata->fcChip.Registers.IOBaseU, 0xff) ) + { + printk(" cpqfcTS address in use: %x\n", + cpqfcHBAdata->fcChip.Registers.IOBaseU); + free_irq( HostAdapter->irq, HostAdapter); + scsi_unregister( HostAdapter); + continue; + } + + if( check_region( cpqfcHBAdata->fcChip.Registers.IOBaseL, 0xff) ) + { + printk(" cpqfcTS address in use: %x\n", + cpqfcHBAdata->fcChip.Registers.IOBaseL); + free_irq( HostAdapter->irq, HostAdapter); + scsi_unregister( HostAdapter); + continue; + } + + // OK, we should be able to grab everything we need now. + request_region( cpqfcHBAdata->fcChip.Registers.IOBaseL, 0xff, DEV_NAME); + request_region( cpqfcHBAdata->fcChip.Registers.IOBaseU, 0xff, DEV_NAME); + DEBUG_PCI(printk(" Requesting 255 I/O addresses @ %x\n", + cpqfcHBAdata->fcChip.Registers.IOBaseL )); + DEBUG_PCI(printk(" Requesting 255 I/O addresses @ %x\n", + cpqfcHBAdata->fcChip.Registers.IOBaseU )); + + + // start our kernel worker thread + + launch_FCworker_thread(HostAdapter); + + + // start our TimerTask... + + cpqfcTStimer = &cpqfcHBAdata->cpqfcTStimer; + + init_timer( cpqfcTStimer); // Linux clears next/prev values + cpqfcTStimer->expires = jiffies + HZ; // one second + cpqfcTStimer->data = (unsigned long)cpqfcHBAdata; // this adapter + cpqfcTStimer->function = cpqfcTSheartbeat; // handles timeouts, housekeeping + + add_timer( cpqfcTStimer); // give it to Linux + + + // now initialize our hardware... + + cpqfcHBAdata->fcChip.InitializeTachyon( cpqfcHBAdata, 1,1); + + cpqfcHBAdata->fcStatsTime = jiffies; // (for FC Statistics delta) + + // give our HBA time to initialize and login current devices... + { + // The Brocade switch (e.g. 2400, 2010, etc.) as of March 2000, + // has the following algorithm for FL_Port startup: + // Time(sec) Action + // 0: Device Plugin and LIP(F7,F7) transmission + // 1.0 LIP incoming + // 1.027 LISA incoming, no CLS! (link not up) + // 1.028 NOS incoming (switch test for N_Port) + // 1.577 ED_TOV expired, transmit LIPs again + // 3.0 LIP(F8,F7) incoming (switch passes Tach Prim.Sig) + // 3.028 LILP received, link up, FLOGI starts + // slowest(worst) case, measured on 1Gb Finisar GT analyzer + + int wait_time; + for( wait_time = jiffies + 4*HZ; wait_time > jiffies; ) + schedule(); // (our worker task needs to run) + + } + + NumberOfAdapters++; + } // end of while() + } + + LEAVE("cpqfcTS_detect"); + + return NumberOfAdapters; +} + + +static void my_ioctl_done (Scsi_Cmnd * SCpnt) +{ + struct request * req; + + req = &SCpnt->request; + req->rq_status = RQ_SCSI_DONE; /* Busy, but indicate request done */ + + if (req->sem != NULL) { + up(req->sem); + } +} + + + +int cpqfcTS_ioctl( Scsi_Device *ScsiDev, int Cmnd, void *arg) +{ + int result = 0; + struct Scsi_Host *HostAdapter = ScsiDev->host; + CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata; + PTACHYON fcChip = &cpqfcHBAdata->fcChip; + PFC_LOGGEDIN_PORT pLoggedInPort; + Scsi_Cmnd DumCmnd; + int i, j; + VENDOR_IOCTL_REQ ioc; + cpqfc_passthru_t *vendor_cmd; + Scsi_Device *SDpnt; + Scsi_Cmnd *ScsiPassThruCmnd; + unsigned long flags; + + ENTER("cpqfcTS_ioctl"); + + // can we find an FC device mapping to this SCSI target? + DumCmnd.channel = ScsiDev->channel; // For searching + DumCmnd.target = ScsiDev->id; + pLoggedInPort = fcFindLoggedInPort( fcChip, + &DumCmnd, // search Scsi Nexus + 0, // DON'T search linked list for FC port id + NULL, // DON'T search linked list for FC WWN + NULL); // DON'T care about end of list + + if( pLoggedInPort == NULL ) // not found! + { + result = -ENXIO; + } + + else // we know what FC device to operate on... + { + switch (Cmnd) + { + // Passthrough provides a mechanism to bypass the RAID + // or other controller and talk directly to the devices + // (e.g. physical disk drive) + // Passthrough commands, unfortunately, tend to be vendor + // specific; this is tailored to COMPAQ's RAID (RA4x00) + case CPQFCTS_SCSI_PASSTHRU: + { + void *buf = NULL; // for kernel space buffer for user data + + if( !arg) + return -EINVAL; + + // must be super user to send stuff directly to the + // controller and/or physical drives... + if( !suser() ) + return -EPERM; + + // copy the caller's struct to our space. + copy_from_user_ret( &ioc, arg, + sizeof( VENDOR_IOCTL_REQ), -EFAULT); + + vendor_cmd = ioc.argp; // i.e., CPQ specific command struct + + // If necessary, grab a kernel/DMA buffer + if( vendor_cmd->len) + { + buf = kmalloc( vendor_cmd->len, GFP_KERNEL); + if( !buf) + return -ENOMEM; + } + + // Now build a SCSI_CMND to pass down... + // This function allocates and sets Scsi_Cmnd ptrs such as + // ->channel, ->target, ->host + ScsiPassThruCmnd = scsi_allocate_device(NULL, ScsiDev, 1); + + // Need data from user? + // make sure caller's buffer is in kernel space. + if( (vendor_cmd->rw_flag == VENDOR_WRITE_OPCODE) && + vendor_cmd->len) + copy_from_user_ret( buf, vendor_cmd->bufp, vendor_cmd->len, -EFAULT); + + // copy the CDB (if/when MAX_COMMAND_SIZE is 16, remove copy below) + memcpy( &ScsiPassThruCmnd->cmnd[0], + &vendor_cmd->cdb[0], + MAX_COMMAND_SIZE); + // we want to copy all 16 bytes into the FCP-SCSI CDB, + // although the actual passthru only uses up to the + // first 12. + + ScsiPassThruCmnd->cmd_len = 16; // sizeof FCP-SCSI CDB + + // Unfortunately, the SCSI command cmnd[] field has only + // 12 bytes. Ideally the MAX_COMMAND_SIZE should be increased + // to 16 for newer Fibre Channel and SCSI-3 larger CDBs. + // However, to avoid a mandatory kernel rebuild, we use the SCp + // spare field to store the extra 4 bytes ( ugly :-( + + if( MAX_COMMAND_SIZE < 16) + { + memcpy( &ScsiPassThruCmnd->SCp.buffers_residual, + &vendor_cmd->cdb[12], 4); + } + + + ScsiPassThruCmnd->SCp.sent_command = 1; // PASSTHRU! + // suppress LUN masking + // and VSA logic + + // Use spare fields to copy FCP-SCSI LUN address info... + ScsiPassThruCmnd->SCp.phase = vendor_cmd->bus; + ScsiPassThruCmnd->SCp.have_data_in = vendor_cmd->pdrive; + + + + // We copy the scheme used by scsi.c to submit commands + // to our own HBA. We do this in order to stall the + // thread calling the IOCTL until it completes, and use + // the same "_quecommand" function for synchronizing + // FC Link events with our "worker thread". + + spin_lock_irqsave(&io_request_lock, flags); + { + DECLARE_MUTEX_LOCKED(sem); + ScsiPassThruCmnd->request.sem = &sem; + // eventually gets us to our own _quecommand routine + scsi_do_cmd( ScsiPassThruCmnd, &vendor_cmd->cdb[0], + buf, + vendor_cmd->len, + my_ioctl_done, + 10*HZ, 1);// timeout,retries + spin_unlock_irqrestore(&io_request_lock, flags); + // Other I/Os can now resume; we wait for our ioctl + // command to complete + down(&sem); + spin_lock_irqsave(&io_request_lock, flags); + ScsiPassThruCmnd->request.sem = NULL; + } + + result = ScsiPassThruCmnd->result; + + // copy any sense data back to caller + if( result != 0 ) + { + memcpy( vendor_cmd->sense_data, // see struct def - size=40 + ScsiPassThruCmnd->sense_buffer, + sizeof(ScsiPassThruCmnd->sense_buffer)); + } + SDpnt = ScsiPassThruCmnd->device; + scsi_release_command(ScsiPassThruCmnd); // "de-allocate" + ScsiPassThruCmnd = NULL; + + if (!SDpnt->was_reset && SDpnt->scsi_request_fn) + (*SDpnt->scsi_request_fn)(); + + wake_up(&SDpnt->device_wait); + spin_unlock_irqrestore(&io_request_lock, flags); + + // need to pass data back to user (space)? + if( (vendor_cmd->rw_flag == VENDOR_READ_OPCODE) && + vendor_cmd->len ) + copy_to_user_ret( vendor_cmd->bufp, buf, vendor_cmd->len, -EFAULT); + + if( buf) + kfree( buf); + + return result; + } + + case CPQFCTS_GETPCIINFO: + { + cpqfc_pci_info_struct pciinfo; + + if( !arg) + return -EINVAL; + + + + pciinfo.bus = cpqfcHBAdata->PciDev->bus->number; + pciinfo.dev_fn = cpqfcHBAdata->PciDev->devfn; + pciinfo.board_id = cpqfcHBAdata->PciDev->device | + (cpqfcHBAdata->PciDev->vendor <<16); + + copy_to_user_ret( arg, &pciinfo, + sizeof(cpqfc_pci_info_struct), -EFAULT); + return 0; + } + + case CPQFCTS_GETDRIVVER: + { + DriverVer_type DriverVer = + CPQFCTS_DRIVER_VER( VER_MAJOR,VER_MINOR,VER_SUBMINOR); + + if( !arg) + return -EINVAL; + + copy_to_user_ret( arg, &DriverVer, + sizeof(DriverVer), -EFAULT); + return 0; + } + + + + case SCSI_IOCTL_FC_TARGET_ADDRESS: + result = + verify_area(VERIFY_WRITE, arg, sizeof(Scsi_FCTargAddress)); + if (result) + break; + + put_user(pLoggedInPort->port_id, + &((Scsi_FCTargAddress *) arg)->host_port_id); + + for( i=3,j=0; i>=0; i--) // copy the LOGIN port's WWN + put_user(pLoggedInPort->u.ucWWN[i], + &((Scsi_FCTargAddress *) arg)->host_wwn[j++]); + for( i=7; i>3; i--) // copy the LOGIN port's WWN + put_user(pLoggedInPort->u.ucWWN[i], + &((Scsi_FCTargAddress *) arg)->host_wwn[j++]); + break; + default: + result = -EINVAL; + break; + } + } + + LEAVE("cpqfcTS_ioctl"); + return result; +} + + +/* "Release" the Host Bus Adapter... + disable interrupts, stop the HBA, release the interrupt, + and free all resources */ + +int cpqfcTS_release(struct Scsi_Host *HostAdapter) +{ + CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata; + + + ENTER("cpqfcTS_release"); + + DEBUG_PCI( printk(" cpqfcTS: delete timer...\n")); + del_timer( &cpqfcHBAdata->cpqfcTStimer); + + // disable the hardware... + DEBUG_PCI( printk(" disable hardware, destroy queues, free mem\n")); + cpqfcHBAdata->fcChip.ResetTachyon( cpqfcHBAdata, CLEAR_FCPORTS); + + // kill kernel thread + if( cpqfcHBAdata->worker_thread ) // (only if exists) + { + DECLARE_MUTEX_LOCKED(sem); // synchronize thread kill + + cpqfcHBAdata->notify_wt = &sem; + DEBUG_PCI( printk(" killing kernel thread\n")); + send_sig( SIGKILL, cpqfcHBAdata->worker_thread, 1); + down( &sem); + cpqfcHBAdata->notify_wt = NULL; + + } + + // free Linux resources + DEBUG_PCI( printk(" cpqfcTS: freeing resources...\n")); + free_irq( HostAdapter->irq, HostAdapter); + scsi_unregister( HostAdapter); + release_region( cpqfcHBAdata->fcChip.Registers.IOBaseL, 0xff); + release_region( cpqfcHBAdata->fcChip.Registers.IOBaseU, 0xff); + /* we get "vfree: bad address" executing this - need to investigate... + if( (void*)((unsigned long)cpqfcHBAdata->fcChip.Registers.MemBase) != + cpqfcHBAdata->fcChip.Registers.ReMapMemBase) + vfree( cpqfcHBAdata->fcChip.Registers.ReMapMemBase); +*/ + + LEAVE("cpqfcTS_release"); + return 0; +} + + +const char * cpqfcTS_info(struct Scsi_Host *HostAdapter) +{ + static char buf[300]; + CPQFCHBA *cpqfcHBA; + int BusSpeed, BusWidth; + + // get the pointer to our Scsi layer HBA buffer + cpqfcHBA = (CPQFCHBA *)HostAdapter->hostdata; + + BusWidth = (cpqfcHBA->fcChip.Registers.PCIMCTR &0x4) > 0 ? + 64 : 32; + + if( cpqfcHBA->fcChip.Registers.TYconfig.value & 0x80000000) + BusSpeed = 66; + else + BusSpeed = 33; + + sprintf(buf, +"%s: WWN %08X%08X\n on PCI bus %d device 0x%02x irq %d IObaseL 0x%x, MEMBASE 0x%x\nPCI bus width %d bits, bus speed %d MHz\nFCP-SCSI Driver v%d.%d.%d", + cpqfcHBA->fcChip.Name, + cpqfcHBA->fcChip.Registers.wwn_hi, + cpqfcHBA->fcChip.Registers.wwn_lo, + cpqfcHBA->PciDev->bus->number, + cpqfcHBA->PciDev->device, + HostAdapter->irq, + cpqfcHBA->fcChip.Registers.IOBaseL, + cpqfcHBA->fcChip.Registers.MemBase, + BusWidth, + BusSpeed, + VER_MAJOR, VER_MINOR, VER_SUBMINOR +); + + + cpqfcTSDecodeGBICtype( &cpqfcHBA->fcChip, &buf[ strlen(buf)]); + cpqfcTSGetLPSM( &cpqfcHBA->fcChip, &buf[ strlen(buf)]); + return buf; +} + +// +// /proc/scsi support. The following routines allow us to do 'normal' +// sprintf like calls to return the currently requested piece (buflenght +// chars, starting at bufoffset) of the file. Although procfs allows for +// a 1 Kb bytes overflow after te supplied buffer, I consider it bad +// programming to use it to make programming a little simpler. This piece +// of coding is borrowed from ncr53c8xx.c with some modifications +// +struct info_str +{ + char *buffer; // Pointer to output buffer + int buflength; // It's length + int bufoffset; // File offset corresponding with buf[0] + int buffillen; // Current filled length + int filpos; // Current file offset +}; + +static void copy_mem_info(struct info_str *info, char *data, int datalen) +{ + + if (info->filpos < info->bufoffset) { // Current offset before buffer offset + if (info->filpos + datalen <= info->bufoffset) { + info->filpos += datalen; // Discard if completely before buffer + return; + } else { // Partial copy, set to begin + data += (info->bufoffset - info->filpos); + datalen -= (info->bufoffset - info->filpos); + info->filpos = info->bufoffset; + } + } + + info->filpos += datalen; // Update current offset + + if (info->buffillen == info->buflength) // Buffer full, discard + return; + + if (info->buflength - info->buffillen < datalen) // Overflows buffer ? + datalen = info->buflength - info->buffillen; + + memcpy(info->buffer + info->buffillen, data, datalen); + info->buffillen += datalen; +} + +static int copy_info(struct info_str *info, char *fmt, ...) +{ + va_list args; + char buf[400]; + int len; + + va_start(args, fmt); + len = vsprintf(buf, fmt, args); + va_end(args); + + copy_mem_info(info, buf, len); + return len; +} + + +// Routine to get data for /proc RAM filesystem +// +int cpqfcTS_proc_info (char *buffer, char **start, off_t offset, int length, + int hostno, int inout) +{ + struct Scsi_Host *host; + Scsi_Cmnd DumCmnd; + int Chan, Targ, i; + struct info_str info; + CPQFCHBA *cpqfcHBA; + PTACHYON fcChip; + PFC_LOGGEDIN_PORT pLoggedInPort; + char buf[81]; + + // Search the Scsi host list for our controller + for (host=scsi_hostlist; host; host=host->next) + if (host->host_no == hostno) + break; + + if (!host) return -ESRCH; + + if (inout) return -EINVAL; + + // get the pointer to our Scsi layer HBA buffer + cpqfcHBA = (CPQFCHBA *)host->hostdata; + fcChip = &cpqfcHBA->fcChip; + + *start = buffer; + + info.buffer = buffer; + info.buflength = length; + info.bufoffset = offset; + info.filpos = 0; + info.buffillen = 0; + copy_info(&info, "Driver version = %d.%d.%d", VER_MAJOR, VER_MINOR, VER_SUBMINOR); + cpqfcTSDecodeGBICtype( &cpqfcHBA->fcChip, &buf[0]); + cpqfcTSGetLPSM( &cpqfcHBA->fcChip, &buf[ strlen(buf)]); + copy_info(&info, "%s\n", buf); + + +#define DISPLAY_WWN_INFO +#ifdef DISPLAY_WWN_INFO + copy_info(&info, "WWN database: (\"port_id: 000000\" means disconnected)\n"); + for ( Chan=0; Chan <= host->max_channel; Chan++) { + DumCmnd.channel = Chan; + for (Targ=0; Targ <= host->max_id; Targ++) { + DumCmnd.target = Targ; + if ((pLoggedInPort = fcFindLoggedInPort( fcChip, + &DumCmnd, // search Scsi Nexus + 0, // DON'T search list for FC port id + NULL, // DON'T search list for FC WWN + NULL))){ // DON'T care about end of list + copy_info(&info, "Host: scsi%d Channel: %02d TargetId: %02d -> WWN: ", + hostno, Chan, Targ); + for( i=3; i>=0; i--) // copy the LOGIN port's WWN + copy_info(&info, "%02X", pLoggedInPort->u.ucWWN[i]); + for( i=7; i>3; i--) // copy the LOGIN port's WWN + copy_info(&info, "%02X", pLoggedInPort->u.ucWWN[i]); + copy_info(&info, " port_id: %06X\n", pLoggedInPort->port_id); + } + } + } +#endif + + +// Unfortunately, the proc_info buffer isn't big enough +// for everything we would like... +// For FC stats, compile this and turn off WWN stuff above +//#define DISPLAY_FC_STATS +#ifdef DISPLAY_FC_STATS +// get the Fibre Channel statistics + { + int DeltaSecs = (jiffies - cpqfcHBA->fcStatsTime) / HZ; + int days,hours,minutes,secs; + + days = DeltaSecs / (3600*24); // days + hours = (DeltaSecs% (3600*24)) / 3600; // hours + minutes = (DeltaSecs%3600 /60); // minutes + secs = DeltaSecs%60; // secs +copy_info( &info, "Fibre Channel Stats (time dd:hh:mm:ss %02u:%02u:%02u:%02u\n", + days, hours, minutes, secs); + } + + cpqfcHBA->fcStatsTime = jiffies; // (for next delta) + + copy_info( &info, " LinkUp %9u LinkDown %u\n", + fcChip->fcStats.linkUp, fcChip->fcStats.linkDown); + + copy_info( &info, " Loss of Signal %9u Loss of Sync %u\n", + fcChip->fcStats.LossofSignal, fcChip->fcStats.LossofSync); + + copy_info( &info, " Discarded Frames %9u Bad CRC Frame %u\n", + fcChip->fcStats.Dis_Frm, fcChip->fcStats.Bad_CRC); + + copy_info( &info, " TACH LinkFailTX %9u TACH LinkFailRX %u\n", + fcChip->fcStats.linkFailTX, fcChip->fcStats.linkFailRX); + + copy_info( &info, " TACH RxEOFa %9u TACH Elastic Store %u\n", + fcChip->fcStats.Rx_EOFa, fcChip->fcStats.e_stores); + + copy_info( &info, " BufferCreditWait %9uus TACH FM Inits %u\n", + fcChip->fcStats.BB0_Timer*10, fcChip->fcStats.FMinits ); + + copy_info( &info, " FC-2 Timeouts %9u FC-2 Logouts %u\n", + fcChip->fcStats.timeouts, fcChip->fcStats.logouts); + + copy_info( &info, " FC-2 Aborts %9u FC-4 Aborts %u\n", + fcChip->fcStats.FC2aborted, fcChip->fcStats.FC4aborted); + + // clear the counters + cpqfcTSClearLinkStatusCounters( fcChip); +#endif + + return info.buffillen; +} + + +#if DEBUG_CMND + +UCHAR *ScsiToAscii( UCHAR ScsiCommand) +{ + +/*++ + +Routine Description: + + Converts a SCSI command to a text string for debugging purposes. + + +Arguments: + + ScsiCommand -- hex value SCSI Command + + +Return Value: + + An ASCII, null-terminated string if found, else returns NULL. + +Original code from M. McGowen, Compaq +--*/ + + + switch (ScsiCommand) + { + case 0x00: + return( "Test Unit Ready" ); + + case 0x01: + return( "Rezero Unit or Rewind" ); + + case 0x02: + return( "Request Block Address" ); + + case 0x03: + return( "Requese Sense" ); + + case 0x04: + return( "Format Unit" ); + + case 0x05: + return( "Read Block Limits" ); + + case 0x07: + return( "Reassign Blocks" ); + + case 0x08: + return( "Read (6)" ); + + case 0x0a: + return( "Write (6)" ); + + case 0x0b: + return( "Seek (6)" ); + + case 0x12: + return( "Inquiry" ); + + case 0x15: + return( "Mode Select (6)" ); + + case 0x16: + return( "Reserve" ); + + case 0x17: + return( "Release" ); + + case 0x1a: + return( "ModeSen(6)" ); + + case 0x1b: + return( "Start/Stop Unit" ); + + case 0x1c: + return( "Receive Diagnostic Results" ); + + case 0x1d: + return( "Send Diagnostic" ); + + case 0x25: + return( "Read Capacity" ); + + case 0x28: + return( "Read (10)" ); + + case 0x2a: + return( "Write (10)" ); + + case 0x2b: + return( "Seek (10)" ); + + case 0x2e: + return( "Write and Verify" ); + + case 0x2f: + return( "Verify" ); + + case 0x34: + return( "Pre-Fetch" ); + + case 0x35: + return( "Synchronize Cache" ); + + case 0x37: + return( "Read Defect Data (10)" ); + + case 0x3b: + return( "Write Buffer" ); + + case 0x3c: + return( "Read Buffer" ); + + case 0x3e: + return( "Read Long" ); + + case 0x3f: + return( "Write Long" ); + + case 0x41: + return( "Write Same" ); + + case 0x4c: + return( "Log Select" ); + + case 0x4d: + return( "Log Sense" ); + + case 0x56: + return( "Reserve (10)" ); + + case 0x57: + return( "Release (10)" ); + + case 0xa0: + return( "ReportLuns" ); + + case 0xb7: + return( "Read Defect Data (12)" ); + + case 0xca: + return( "Peripheral Device Addressing SCSI Passthrough" ); + + case 0xcb: + return( "Compaq Array Firmware Passthrough" ); + + default: + return( NULL ); + } + +} // end ScsiToAscii() + +void cpqfcTS_print_scsi_cmd(Scsi_Cmnd * cmd) +{ + +printk("cpqfcTS: (%s) chnl 0x%02x, trgt = 0x%02x, lun = 0x%02x, cmd_len = 0x%02x\n", + ScsiToAscii( cmd->cmnd[0]), cmd->channel, cmd->target, cmd->lun, cmd->cmd_len); + +if( cmd->cmnd[0] == 0) // Test Unit Ready? +{ + int i; + + printk("Cmnd->request_bufflen = 0x%X, ->use_sg = %d, ->bufflen = %d\n", + cmd->request_bufflen, cmd->use_sg, cmd->bufflen); + printk("Cmnd->request_buffer = %p, ->sglist_len = %d, ->buffer = %p\n", + cmd->request_buffer, cmd->sglist_len, cmd->buffer); + for (i = 0; i < cmd->cmd_len; i++) + printk("0x%02x ", cmd->cmnd[i]); + printk("\n"); +} + +} + +#endif /* DEBUG_CMND */ + + + + +static void QueCmndOnBoardLock( CPQFCHBA *cpqfcHBAdata, Scsi_Cmnd *Cmnd) +{ + int i; + + for( i=0; i< CPQFCTS_REQ_QUEUE_LEN; i++) + { // find spare slot + if( cpqfcHBAdata->BoardLockCmnd[i] == NULL ) + { + cpqfcHBAdata->BoardLockCmnd[i] = Cmnd; +// printk(" BoardLockCmnd[%d] %p Queued, chnl/target/lun %d/%d/%d\n", +// i,Cmnd, Cmnd->channel, Cmnd->target, Cmnd->lun); + break; + } + } + if( i >= CPQFCTS_REQ_QUEUE_LEN) + { + printk(" cpqfcTS WARNING: Lost Cmnd %p on BoardLock Q full!", Cmnd); + } + +} + + +static void QueLinkDownCmnd( CPQFCHBA *cpqfcHBAdata, Scsi_Cmnd *Cmnd) +{ + int indx; + + // Remember the command ptr so we can return; we'll complete when + // the device comes back, causing immediate retry + for( indx=0; indx < CPQFCTS_REQ_QUEUE_LEN; indx++)//, SCptr++) + { + if( cpqfcHBAdata->LinkDnCmnd[indx] == NULL ) // available? + { +#ifdef DUMMYCMND_DBG + printk(" @add Cmnd %p to LnkDnCmnd[%d]@ ", Cmnd,indx); +#endif + cpqfcHBAdata->LinkDnCmnd[indx] = Cmnd; + break; + } + } + + if( indx >= CPQFCTS_REQ_QUEUE_LEN ) // no space for Cmnd?? + { + // this will result in an _abort call later (with possible trouble) + printk("no buffer for LinkDnCmnd!! %p\n", Cmnd); + } +} + + + + + +// The file "hosts.h" says not to call scsi_done from +// inside _queuecommand, so we'll do it from the heartbeat timer + +static void QueBadTargetCmnd( CPQFCHBA *cpqfcHBAdata, Scsi_Cmnd *Cmnd) +{ + int i; + // printk(" can't find target %d\n", Cmnd->target); + + for( i=0; i< CPQFCTS_MAX_TARGET_ID; i++) + { // find spare slot + if( cpqfcHBAdata->BadTargetCmnd[i] == NULL ) + { + cpqfcHBAdata->BadTargetCmnd[i] = Cmnd; +// printk(" BadTargetCmnd[%d] %p Queued, chnl/target/lun %d/%d/%d\n", +// i,Cmnd, Cmnd->channel, Cmnd->target, Cmnd->lun); + break; + } + } +} + + +// This is the "main" entry point for Linux Scsi commands -- +// it all starts here. + +int cpqfcTS_queuecommand(Scsi_Cmnd *Cmnd, void (* done)(Scsi_Cmnd *)) +{ + struct Scsi_Host *HostAdapter = Cmnd->host; + CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata; + PTACHYON fcChip = &cpqfcHBAdata->fcChip; + TachFCHDR_GCMND fchs; // only use for FC destination id field + PFC_LOGGEDIN_PORT pLoggedInPort; + ULONG ulStatus, SESTtype; + LONG ExchangeID; + + + + + ENTER("cpqfcTS_queuecommand"); + + PCI_TRACEO( (ULONG)Cmnd, 0x98) + + + Cmnd->scsi_done = done; +#ifdef DEBUG_CMND + cpqfcTS_print_scsi_cmd( Cmnd); +#endif + + // prevent board contention with kernel thread... + + if( cpqfcHBAdata->BoardLock ) + { +// printk(" @BrdLck Hld@ "); + QueCmndOnBoardLock( cpqfcHBAdata, Cmnd); + } + + else + { + + // in the current system (2.2.12), this routine is called + // after spin_lock_irqsave(), so INTs are disabled. However, + // we might have something pending in the LinkQ, which + // might cause the WorkerTask to run. In case that + // happens, make sure we lock it out. + + + + PCI_TRACE( 0x98) + CPQ_SPINLOCK_HBA( cpqfcHBAdata) + PCI_TRACE( 0x98) + + // can we find an FC device mapping to this SCSI target? + pLoggedInPort = fcFindLoggedInPort( fcChip, + Cmnd, // search Scsi Nexus + 0, // DON'T search linked list for FC port id + NULL, // DON'T search linked list for FC WWN + NULL); // DON'T care about end of list + + if( pLoggedInPort == NULL ) // not found! + { +// printk(" @Q bad targ cmnd %p@ ", Cmnd); + QueBadTargetCmnd( cpqfcHBAdata, Cmnd); + } + + else // we know what FC device to send to... + { + + // does this device support FCP target functions? + // (determined by PRLI field) + + if( !(pLoggedInPort->fcp_info & TARGET_FUNCTION) ) + { + printk(" Doesn't support TARGET functions port_id %Xh\n", + pLoggedInPort->port_id ); + QueBadTargetCmnd( cpqfcHBAdata, Cmnd); + } + + // In this case (previous login OK), the device is temporarily + // unavailable waiting for re-login, in which case we expect it + // to be back in between 25 - 500ms. + // If the FC port doesn't log back in within several seconds + // (i.e. implicit "logout"), or we get an explicit logout, + // we set "device_blocked" in Scsi_Device struct; in this + // case 30 seconds will elapse before Linux/Scsi sends another + // command to the device. + else if( pLoggedInPort->prli != TRUE ) + { +// printk("Device (Chnl/Target %d/%d) invalid PRLI, port_id %06lXh\n", +// Cmnd->channel, Cmnd->target, pLoggedInPort->port_id); + QueLinkDownCmnd( cpqfcHBAdata, Cmnd); +// Need to use "blocked" flag?? +// Cmnd->device->device_blocked = TRUE; // just let it timeout + } + else // device supports TARGET functions, and is logged in... + { + // (context of fchs is to "reply" to...) + fchs.s_id = pLoggedInPort->port_id; // destination FC address + + // what is the data direction? For data TO the device, + // we need IWE (Intiator Write Entry). Otherwise, IRE. + + if( Cmnd->cmnd[0] == WRITE_10 || + Cmnd->cmnd[0] == WRITE_6 || + Cmnd->cmnd[0] == WRITE_BUFFER || + Cmnd->cmnd[0] == VENDOR_WRITE_OPCODE || // CPQ specific + Cmnd->cmnd[0] == MODE_SELECT ) + { + SESTtype = SCSI_IWE; // data from HBA to Device + } + else + SESTtype = SCSI_IRE; // data from Device to HBA + + ulStatus = cpqfcTSBuildExchange( + cpqfcHBAdata, + SESTtype, // e.g. Initiator Read Entry (IRE) + &fchs, // we are originator; only use d_id + Cmnd, // Linux SCSI command (with scatter/gather list) + &ExchangeID );// fcController->fcExchanges index, -1 if failed + + if( !ulStatus ) // Exchange setup? + + { + if( cpqfcHBAdata->BoardLock ) + { + TriggerHBA( fcChip->Registers.ReMapMemBase, 0); + printk(" @bl! %d, xID %Xh@ ", current->pid, ExchangeID); + } + + ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID ); + if( !ulStatus ) + { + PCI_TRACEO( ExchangeID, 0xB8) + // submitted to Tach's Outbound Que (ERQ PI incremented) + // waited for completion for ELS type (Login frames issued + // synchronously) + } + else + // check reason for Exchange not being started - we might + // want to Queue and start later, or fail with error + { + printk("quecommand: cpqfcTSStartExchange failed: %Xh\n", ulStatus ); + } + } // end good BuildExchange status + + else // SEST table probably full -- why? hardware hang? + { + printk("quecommand: cpqfcTSBuildExchange faild: %Xh\n", ulStatus); + } + } // end can't do FCP-SCSI target functions + } // end can't find target (FC device) + + CPQ_SPINUNLOCK_HBA( cpqfcHBAdata) + } + + PCI_TRACEO( (ULONG)Cmnd, 0x9C) + LEAVE("cpqfcTS_queuecommand"); + return 0; +} + + +// Entry point for upper Scsi layer intiated abort. Typically +// this is called if the command (for hard disk) fails to complete +// in 30 seconds. This driver intends to complete all disk commands +// within Exchange ".timeOut" seconds (now 7) with target status, or +// in case of ".timeOut" expiration, a DID_SOFT_ERROR which causes +// immediate retry. +// If any disk commands get the _abort call, except for the case that +// the physical device was removed or unavailable due to hardware +// errors, it should be considered a driver error and reported to +// the author. + +int cpqfcTS_abort(Scsi_Cmnd *Cmnd) +{ + struct Scsi_Host *HostAdapter = Cmnd->host; + // get the pointer to our Scsi layer HBA buffer + CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata; + PTACHYON fcChip = &cpqfcHBAdata->fcChip; + FC_EXCHANGES *Exchanges = fcChip->Exchanges; + int i; + ENTER("cpqfcTS_abort"); + + Cmnd->result = DID_ABORT <<16; // assume we'll find it + + printk(" @Linux _abort Scsi_Cmnd %p ", Cmnd); + // See if we can find a Cmnd pointer that matches... + // The most likely case is we accepted the command + // from Linux Scsi (e.g. ceated a SEST entry) and it + // got lost somehow. If we can't find any reference + // to the passed pointer, we can only presume it + // got completed as far as our driver is concerned. + // If we found it, we will try to abort it through + // common mechanism. If FC ABTS is successful (ACC) + // or is rejected (RJT) by target, we will call + // Scsi "done" quickly. Otherwise, the ABTS will timeout + // and we'll call "done" later. + + // Search the SEST exchanges for a matching Cmnd ptr. + for( i=0; i< TACH_SEST_LEN; i++) + { + if( Exchanges->fcExchange[i].Cmnd == Cmnd ) + { + + // found it! + printk(" x_ID %Xh, type %Xh\n", i, Exchanges->fcExchange[i].type); + + Exchanges->fcExchange[i].status = INITIATOR_ABORT; // seconds default + Exchanges->fcExchange[i].timeOut = 10; // seconds default (changed later) + + // Since we need to immediately return the aborted Cmnd to Scsi + // upper layers, we can't make future reference to any of it's + // fields (e.g the Nexus). + + cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &i); + + break; + } + } + + if( i >= TACH_SEST_LEN ) // didn't find Cmnd ptr in chip's SEST? + { + // now search our non-SEST buffers (i.e. Cmnd waiting to + // start on the HBA or waiting to complete with error for retry). + + // first check BadTargetCmnd + for( i=0; i< CPQFCTS_MAX_TARGET_ID; i++) + { + if( cpqfcHBAdata->BadTargetCmnd[i] == Cmnd ) + { + cpqfcHBAdata->BadTargetCmnd[i] = NULL; + printk("in BadTargetCmnd Q\n"); + goto Done; // exit + } + } + + // if not found above... + + for( i=0; i < CPQFCTS_REQ_QUEUE_LEN; i++) + { + if( cpqfcHBAdata->LinkDnCmnd[i] == Cmnd ) + { + cpqfcHBAdata->LinkDnCmnd[i] = NULL; + printk("in LinkDnCmnd Q\n"); + goto Done; + } + } + + + for( i=0; i< CPQFCTS_REQ_QUEUE_LEN; i++) + { // find spare slot + if( cpqfcHBAdata->BoardLockCmnd[i] == Cmnd ) + { + cpqfcHBAdata->BoardLockCmnd[i] = NULL; + printk("in BoardLockCmnd Q\n"); + goto Done; + } + } + + Cmnd->result = DID_ERROR <<16; // Hmmm... + printk("Not found! "); +// panic("_abort"); + } + +Done: + +// panic("_abort"); + LEAVE("cpqfcTS_abort"); + return 0; // (see scsi.h) +} + + + + +// To be done... +int cpqfcTS_reset(Scsi_Cmnd *Cmnd, unsigned int reset_flags) +{ + int return_status = SUCCESS; + + ENTER("cpqfcTS_reset"); + + + + + LEAVE("cpqfcTS_reset"); + return return_status; +} + + + +/* This function determines the bios parameters for a given + harddisk. These tend to be numbers that are made up by the + host adapter. Parameters: + size, device number, list (heads, sectors,cylinders). + (from hosts.h) +*/ + +int cpqfcTS_biosparam(Disk *disk, kdev_t n, int ip[]) +{ + int size = disk->capacity; + + ENTER("cpqfcTS_biosparam"); + ip[0] = 64; + ip[1] = 32; + ip[2] = size >> 11; + + if( ip[2] > 1024 ) + { + ip[0] = 255; + ip[1] = 63; + ip[2] = size / (ip[0] * ip[1]); + } + + LEAVE("cpqfcTS_biosparam"); + return 0; +} + + + +void cpqfcTS_intr_handler( int irq, + void *dev_id, + struct pt_regs *regs) +{ + + unsigned long flags, InfLoopBrk=0; + struct Scsi_Host *HostAdapter = dev_id; + CPQFCHBA *cpqfcHBA = (CPQFCHBA *)HostAdapter->hostdata; + int MoreMessages = 1; // assume we have something to do + UCHAR IntPending; + + ENTER("intr_handler"); + + spin_lock_irqsave( &io_request_lock, flags); + // is this our INT? + IntPending = readb( cpqfcHBA->fcChip.Registers.INTPEND.address); + + // broken boards can generate messages forever, so + // prevent the infinite loop +#define INFINITE_IMQ_BREAK 10000 + if( IntPending ) + { + + // mask our HBA interrupts until we handle it... + writeb( 0, cpqfcHBA->fcChip.Registers.INTEN.address); + + if( IntPending & 0x4) // "INT" - Tach wrote to IMQ + { + while( (++InfLoopBrk < INFINITE_IMQ_BREAK) && (MoreMessages ==1) ) + { + MoreMessages = CpqTsProcessIMQEntry( HostAdapter); // ret 0 when done + } + if( InfLoopBrk >= INFINITE_IMQ_BREAK ) + { + printk("WARNING: Compaq FC adapter generating excessive INTs -REPLACE\n"); + printk("or investigate alternate causes (e.g. physical FC layer)\n"); + } + + else // working normally - re-enable INTs and continue + writeb( 0x1F, cpqfcHBA->fcChip.Registers.INTEN.address); + + } // (...ProcessIMQEntry() clears INT by writing IMQ consumer) + else // indications of errors or problems... + // these usually indicate critical system hardware problems. + { + if( IntPending & 0x10 ) + printk(" cpqfcTS adapter external memory parity error detected\n"); + if( IntPending & 0x8 ) + printk(" cpqfcTS adapter PCI master address crossed 45-bit boundary\n"); + if( IntPending & 0x2 ) + printk(" cpqfcTS adapter DMA error detected\n"); + if( IntPending & 0x1 ) + printk(" cpqfcTS adapter PCI error detected\n"); + } + } + spin_unlock_irqrestore( &io_request_lock, flags); + LEAVE("intr_handler"); +} + + + + +int cpqfcTSDecodeGBICtype( PTACHYON fcChip, char cErrorString[]) +{ + // Verify GBIC type (if any) and correct Tachyon Port State Machine + // (GBIC) module definition is: + // GPIO1, GPIO0, GPIO4 for MD2, MD1, MD0. The input states appear + // to be inverted -- i.e., a setting of 111 is read when there is NO + // GBIC present. The Module Def (MD) spec says 000 is "no GBIC" + // Hard code the bit states to detect Copper, + // Long wave (single mode), Short wave (multi-mode), and absent GBIC + + ULONG ulBuff; + + sprintf( cErrorString, "\nGBIC detected: "); + + ulBuff = fcChip->Registers.TYstatus.value & 0x13; + switch( ulBuff ) + { + case 0x13: // GPIO4, GPIO1, GPIO0 = 111; no GBIC! + sprintf( &cErrorString[ strlen( cErrorString)], + "NONE! "); + return FALSE; + + + case 0x11: // Copper GBIC detected + sprintf( &cErrorString[ strlen( cErrorString)], + "Copper. "); + break; + + case 0x10: // Long-wave (single mode) GBIC detected + sprintf( &cErrorString[ strlen( cErrorString)], + "Long-wave. "); + break; + case 0x1: // Short-wave (multi mode) GBIC detected + sprintf( &cErrorString[ strlen( cErrorString)], + "Short-wave. "); + break; + default: // unknown GBIC - presumably it will work (?) + sprintf( &cErrorString[ strlen( cErrorString)], + "Unknown. "); + + break; + } // end switch GBIC detection + + return TRUE; +} + + + + + + +int cpqfcTSGetLPSM( PTACHYON fcChip, char cErrorString[]) +{ + // Tachyon's Frame Manager LPSM in LinkDown state? + // (For non-loop port, check PSM instead.) + // return string with state and FALSE is Link Down + + int LinkUp; + + if( fcChip->Registers.FMstatus.value & 0x80 ) + LinkUp = FALSE; + else + LinkUp = TRUE; + + sprintf( &cErrorString[ strlen( cErrorString)], + " LPSM %Xh ", + (fcChip->Registers.FMstatus.value >>4) & 0xf ); + + + switch( fcChip->Registers.FMstatus.value & 0xF0) + { + // bits set in LPSM + case 0x10: + sprintf( &cErrorString[ strlen( cErrorString)], "ARB"); + break; + case 0x20: + sprintf( &cErrorString[ strlen( cErrorString)], "ARBwon"); + break; + case 0x30: + sprintf( &cErrorString[ strlen( cErrorString)], "OPEN"); + break; + case 0x40: + sprintf( &cErrorString[ strlen( cErrorString)], "OPENed"); + break; + case 0x50: + sprintf( &cErrorString[ strlen( cErrorString)], "XmitCLS"); + break; + case 0x60: + sprintf( &cErrorString[ strlen( cErrorString)], "RxCLS"); + break; + case 0x70: + sprintf( &cErrorString[ strlen( cErrorString)], "Xfer"); + break; + case 0x80: + sprintf( &cErrorString[ strlen( cErrorString)], "Init"); + break; + case 0x90: + sprintf( &cErrorString[ strlen( cErrorString)], "O-IInitFin"); + break; + case 0xa0: + sprintf( &cErrorString[ strlen( cErrorString)], "O-IProtocol"); + break; + case 0xb0: + sprintf( &cErrorString[ strlen( cErrorString)], "O-ILipRcvd"); + break; + case 0xc0: + sprintf( &cErrorString[ strlen( cErrorString)], "HostControl"); + break; + case 0xd0: + sprintf( &cErrorString[ strlen( cErrorString)], "LoopFail"); + break; + case 0xe0: + sprintf( &cErrorString[ strlen( cErrorString)], "Offline"); + break; + case 0xf0: + sprintf( &cErrorString[ strlen( cErrorString)], "OldPort"); + break; + case 0: + default: + sprintf( &cErrorString[ strlen( cErrorString)], "Monitor"); + break; + + } + + return LinkUp; +} + + + + +#include "linux/malloc.h" + +// Dynamic memory allocation alignment routines +// HP's Tachyon Fibre Channel Controller chips require +// certain memory queues and register pointers to be aligned +// on various boundaries, usually the size of the Queue in question. +// Alignment might be on 2, 4, 8, ... or even 512 byte boundaries. +// Since most O/Ss don't allow this (usually only Cache aligned - +// 32-byte boundary), these routines provide generic alignment (after +// O/S allocation) at any boundary, and store the original allocated +// pointer for deletion (O/S free function). Typically, we expect +// these functions to only be called at HBA initialization and +// removal time (load and unload times) +// ALGORITHM notes: +// Memory allocation varies by compiler and platform. In the worst case, +// we are only assured BYTE allignment, but in the best case, we can +// request allocation on any desired boundary. Our strategy: pad the +// allocation request size (i.e. waste memory) so that we are assured +// of passing desired boundary near beginning of contiguous space, then +// mask out lower address bits. +// We define the following algorithm: +// allocBoundary - compiler/platform specific address alignment +// in number of bytes (default is single byte; i.e. 1) +// n_alloc - number of bytes application wants @ aligned address +// ab - alignment boundary, in bytes (e.g. 4, 32, ...) +// t_alloc - total allocation needed to ensure desired boundary +// mask - to clear least significant address bits for boundary +// Compute: +// t_alloc = n_alloc + (ab - allocBoundary) +// allocate t_alloc bytes @ alloc_address +// mask = NOT (ab - 1) +// (e.g. if ab=32 _0001 1111 -> _1110 0000 +// aligned_address = alloc_address & mask +// set n_alloc bytes to 0 +// return aligned_address (NULL if failed) +// +// If u32_AlignedAddress is non-zero, then search for BaseAddress (stored +// from previous allocation). If found, invoke call to FREE the memory. +// Return NULL if BaseAddress not found + +// we need about 8 allocations per HBA. Figuring at most 10 HBAs per server +// size the dynamic_mem array at 80. + +void* fcMemManager( ALIGNED_MEM *dynamic_mem, ULONG n_alloc, ULONG ab, + ULONG u32_AlignedAddress) +{ + USHORT allocBoundary=1; // compiler specific - worst case 1 + // best case - replace malloc() call + // with function that allocates exactly + // at desired boundary + + unsigned long ulAddress; + ULONG t_alloc, i; + void *alloc_address = 0; // def. error code / address not found + LONG mask; // must be 32-bits wide! + + ENTER("fcMemManager"); + if( u32_AlignedAddress ) // are we freeing existing memory? + { +// printk(" freeing AlignedAddress %Xh\n", u32_AlignedAddress); + for( i=0; i // timer declaration in our host data +#include // task queue sched +#include +#include "cpqfcTSioctl.h" + +#define DbgDelay(secs) { int wait_time; printk( " DbgDelay %ds ", secs); \ + for( wait_time=jiffies + (secs*HZ); \ + wait_time > jiffies ;) ; } +#define CPQFCTS_DRIVER_VER(maj,min,submin) ((maj<<16)|(min<<8)|(submin)) +#define VER_MAJOR 1 +#define VER_MINOR 3 +#define VER_SUBMINOR 4 + +// Macros for kernel (esp. SMP) tracing using a PCI analyzer +// (e.g. x86). +//#define PCI_KERNEL_TRACE +#ifdef PCI_KERNEL_TRACE +#define PCI_TRACE(x) inl( fcChip->Registers.IOBaseL +x); +#define PCI_TRACEO(x,y) outl( x, (fcChip->Registers.IOBaseL +y)); +#else + +#define PCI_TRACE(x) +#define PCI_TRACEO(x,y) +#endif + + +//#define DEBUG_CMND 1 // debug output for Linux Scsi CDBs +//#define DUMMYCMND_DBG 1 + +//#define DEBUG_CPQFCTS 1 +//#undef DEBUG_CPQFCTS +#ifdef DEBUG_CPQFCTS +#define ENTER(x) printk("cpqfcts : entering %s()\n", x); +#define LEAVE(x) printk("cpqfcts : leaving %s()\n", x); +#define DEBUG(x) x +#else +#define ENTER(x) +#define LEAVE(x) +#define DEBUG(x) +#endif /* DEBUG_CPQFCTS */ + +//#define DEBUG_CPQFCTS_PCI 1 +//#undef DEBUG_CPQFCTS_PCI +#if DEBUG_CPQFCTS_PCI +#define DEBUG_PCI(x) x +#else +#define DEBUG_PCI(x) +#endif /* DEBUG_CPQFCTS_PCI */ + +#define STACHLITE66_TS12 "Compaq FibreChannel HBA Tachyon TS HPFC-5166A/1.2" +#define STACHLITE66_TS13 "Compaq FibreChannel HBA Tachyon TS HPFC-5166A/1.3" +#define STACHLITE_UNKNOWN "Compaq FibreChannel HBA Tachyon Chip/Board Ver??" +#define SAGILENT_XL2_21 "Agilent FC HBA, Tachyon XL2 HPFC-5200B/2.1" + +// PDA is Peripheral Device Address, VSA is Volume Set Addressing +// Linux SCSI parameters +#define CPQFCTS_MAX_TARGET_ID 64 +#define CPQFCTS_MAX_LUN 8 // The RA-4x00 supports 32 (Linux SCSI supports 8) +#define CPQFCTS_MAX_CHANNEL 0 // One FC port on cpqfcTS HBA + +#define CPQFCTS_CMD_PER_LUN 15 // power of 2 -1, must be >0 +#define CPQFCTS_REQ_QUEUE_LEN (TACH_SEST_LEN/2) // must be < TACH_SEST_LEN + +#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s)) +#ifndef DECLARE_MUTEX_LOCKED +#define DECLARE_MUTEX_LOCKED(sem) struct semaphore sem = MUTEX_LOCKED +#endif + +#define DEV_NAME "cpqfcTS" + +#define CPQ_DEVICE_ID 0xA0FC +#define AGILENT_XL2_ID 0x1029 + +typedef struct +{ + __u16 vendor_id; + __u16 device_id; +} SupportedPCIcards; + +// nn:nn denotes bit field + // TachyonHeader struct def. + // the fields shared with ODB + // need to have same value + + + + +#ifndef BYTE +//typedef UCHAR BYTE; +typedef __u8 BYTE; +#endif +#ifndef UCHAR +typedef __u8 UCHAR; +#endif +#ifndef LONG +typedef __s32 LONG; +#endif +#ifndef ULONG +typedef __u32 ULONG; +#endif +#ifndef PVOID +typedef void * PVOID; +#endif +#ifndef USHORT +typedef __u16 USHORT; +#endif +#ifndef BOOLEAN +typedef __u8 BOOLEAN; +#endif + + +// macro for FC-PH reject codes +// payload format for LS_RJT (FC payloads are big endian): +// byte 0 1 2 3 (MSB) +// DWORD 0 01 00 00 00 +// DWORD 1 resvd code expl. vendor + +#define LS_RJT_REASON( code, expl) (( code<<8) | (expl <<16)) + + +#define TachLiteSTATUS 0x12 + +// Fibre Channel EXCHANGE status codes for Tachyon chips/ driver software +// 32-bit ERROR word defines +#define INVALID_ARGS 0x1 +#define LNKDWN_OSLS 0x2 +#define LNKDWN_LASER 0x4 +#define OUTQUE_FULL 0x8 +#define DRIVERQ_FULL 0x10 +#define SEST_FULL 0x20 +#define BAD_ALPA 0x40 +#define OVERFLOW 0x80 // inbound CM +#define COUNT_ERROR 0x100 // inbound CM +#define LINKFAIL_RX 0x200 // inbound CM +#define ABORTSEQ_NOTIFY 0x400 // outbound CM +#define LINKFAIL_TX 0x800 // outbound CM +#define HOSTPROG_ERR 0x1000 // outbound CM +#define FRAME_TO 0x2000 // outbound CM +#define INV_ENTRY 0x4000 // outbound CM +#define SESTPROG_ERR 0x8000 // outbound CM +#define OUTBOUND_TIMEOUT 0x10000L // timeout waiting for Tachyon outbound CM +#define INITIATOR_ABORT 0x20000L // initiator exchange timeout or O/S ABORT +#define MEMPOOL_FAIL 0x40000L // O/S memory pool allocation failed +#define FC2_TIMEOUT 0x80000L // driver timeout for lost frames +#define TARGET_ABORT 0x100000L // ABTS received from FC port +#define EXCHANGE_QUEUED 0x200000L // e.g. Link State was LDn on fcStart +#define PORTID_CHANGED 0x400000L // fc Port address changed +#define DEVICE_REMOVED 0x800000L // fc Port address changed +// Several error scenarios result in SEST Exchange frames +// unexpectedly arriving in the SFQ +#define SFQ_FRAME 0x1000000L // SFQ frames from open Exchange + +// Maximum number of Host Bus Adapters (HBA) / controllers supported +// only important for mem allocation dimensions - increase as necessary + +#define MAX_ADAPTERS 8 +#define MAX_RX_PAYLOAD 1024 // hardware dependent max frame payload +// Tach header struc defines +#define SOFi3 0x7 +#define SOFf 0x8 +#define SOFn3 0xB +#define EOFn 0x5 +#define EOFt 0x6 + +// FCP R_CTL defines +#define FCP_CMND 0x6 +#define FCP_XFER_RDY 0x5 +#define FCP_RSP 0x7 +#define FCP_RESPONSE 0x777 // (arbitrary #) +#define NEED_FCP_RSP 0x77 // (arbitrary #) +#define FCP_DATA 0x1 + +#define RESET_TACH 0x100 // Reset Tachyon/TachLite +#define SCSI_IWE 0x2000 // initiator write entry (for SEST) +#define SCSI_IRE 0x3000 // initiator read entry (for SEST) +#define SCSI_TRE 0x400 // target read entry (for SEST) +#define SCSI_TWE 0x500 // target write entry (for SEST) +#define TOGGLE_LASER 0x800 +#define LIP 0x900 +#define CLEAR_FCPORTS 99 // (arbitrary #) free mem for Logged in ports +#define FMINIT 0x707 // (arbitrary) for Frame Manager Init command + +// BLS == Basic Link Service +// ELS == Extended Link Service +#define BLS_NOP 4 +#define BLS_ABTS 0x10 // FC-PH Basic Link Service Abort Sequence +#define BLS_ABTS_ACC 0x100 // FC-PH Basic Link Service Abort Sequence Accept +#define BLS_ABTS_RJT 0x101 // FC-PH Basic Link Service Abort Sequence Reject +#define ELS_PLOGI 0x03 // FC-PH Port Login (arbitrary assign) +#define ELS_SCR 0x70 // (arb assign) State Change Registration (Fabric) +#define FCS_NSR 0x72 // (arb assign) Name Service Request (Fabric) +#define ELS_FLOGI 0x44 // (arb assign) Fabric Login +#define ELS_FDISC 0x41 // (arb assign) Fabric Discovery (Login) +#define ELS_PDISC 0x50 // FC-PH2 Port Discovery +#define ELS_ABTX 0x06 // FC-PH Abort Exchange +#define ELS_LOGO 0x05 // FC-PH Port Logout +#define ELS_PRLI 0x20 // FCP-SCSI Process Login +#define ELS_PRLO 0x21 // FCP-SCSI Process Logout +#define ELS_LOGO_ACC 0x07 // {FC-PH} Port Logout Accept +#define ELS_PLOGI_ACC 0x08 // {FC-PH} Port Login Accept +#define ELS_ACC 0x18 // {FC-PH} (generic) ACCept +#define ELS_PRLI_ACC 0x22 // {FCP-SCSI} Process Login Accept +#define ELS_RJT 0x1000000 +#define SCSI_REPORT_LUNS 0x0A0 +#define REPORT_LUNS 0xA0 // SCSI-3 command op-code + +#define ELS_LILP_FRAME 0x00000711 // 1st payload word of LILP frame + +#define SFQ_UNASSISTED_FCP 1 // ICM, DWord3, "Type" unassisted FCP +#define SFQ_UNKNOWN 0x31 // (arbitrary) ICM, DWord3, "Type" unknown + +// these "LINK" bits refer to loop or non-loop +#define LINKACTIVE 0x2 // fcLinkQ type - LINK UP Tachyon FM 'Lup' bit set +#define LINKDOWN 0xf2 // fcLinkQ type - LINK DOWN Tachyon FM 'Ldn' bit set + +//#define VOLUME_SET_ADDRESSING 1 // "channel" or "bus" 1 + +typedef struct // 32 bytes hdr ONLY (e.g. FCP_DATA buffer for SEST) +{ + ULONG reserved; // dword 0 (don't use) + ULONG sof_eof; + ULONG d_id; // dword 2 - 31:24 R_CTL, 23:0 D_ID + ULONG s_id; // dword 3 - 31:24 CS_CTL, 23:0 S_ID + ULONG f_ctl; // dword 4 - 31:24 Type, 23:0 F_CTL + ULONG seq_cnt; // dword 5 - 31:24 SEQ_ID, 23:16 DF_CTL, 15:0 SEQ_CNT + ULONG ox_rx_id; // dword 6 - 31:16 OX_ID, 15:0 RX_ID + ULONG ro; // dword 7 - relative offset +} TachFCHDR; + + // NOTE!! the following struct MUST be 64 bytes. +typedef struct // 32 bytes hdr + 32 bytes payload +{ + ULONG reserved; // dword 0 (don't use - must clear to 0) + ULONG sof_eof; // dword 1 - 31:24 SOF:EOF, UAM,CLS, LCr, TFV, TimeStamp + ULONG d_id; // dword 2 - 31:24 R_CTL, 23:0 D_ID + ULONG s_id; // dword 3 - 31:24 CS_CTL, 23:0 S_ID + ULONG f_ctl; // dword 4 - 31:24 Type, 23:0 F_CTL + ULONG seq_cnt; // dword 5 - 31:24 SEQ_ID, 23:16 DF_CTL, 15:0 SEQ_CNT + ULONG ox_rx_id; // dword 6 - 31:16 OX_ID, 15:0 RX_ID + ULONG ro; // dword 7 - relative offset +//--------- + __u32 pl[8]; // dwords 8-15 frame data payload +} TachFCHDR_CMND; + + +typedef struct // 32 bytes hdr + 120 bytes payload +{ + ULONG reserved; // dword 0 (don't use - must clear to 0) + ULONG sof_eof; // dword 1 - 31:24 SOF:EOF, UAM,CLS, LCr, TFV, TimeStamp + ULONG d_id; // dword 2 - 31:24 R_CTL, 23:0 D_ID + ULONG s_id; // dword 3 - 31:24 CS_CTL, 23:0 S_ID + ULONG f_ctl; // dword 4 - 31:24 Type, 23:0 F_CTL + ULONG seq_cnt; // dword 5 - 31:24 SEQ_ID, 23:16 DF_CTL, 15:0 SEQ_CNT + ULONG ox_rx_id; // dword 6 - 31:16 OX_ID, 15:0 RX_ID + ULONG ro; // dword 7 - relative offset +//--------- + __u32 pl[30]; // largest necessary payload (for LOGIN cmnds) +} TachFCHDR_GCMND; + +typedef struct // 32 bytes hdr + 64 bytes payload +{ + ULONG reserved; // dword 0 (don't use) + ULONG sof_eof; + ULONG d_id; // dword 2 - 31:24 R_CTL, 23:0 D_ID + ULONG s_id; // dword 3 - 31:24 CS_CTL, 23:0 S_ID + ULONG f_ctl; // dword 4 - 31:24 Type, 23:0 F_CTL + ULONG seq_cnt; // dword 5 - 31:24 SEQ_ID, 23:16 DF_CTL, 15:0 SEQ_CNT + ULONG ox_rx_id; // dword 6 - 31:16 OX_ID, 15:0 RX_ID + ULONG ro; // dword 7 - relative offset +//--------- + __u32 pl[18]; // payload for FCP-RSP (response buffer) RA-4x00 is 72bytes +} TachFCHDR_RSP; + + + + + + +// Inbound Message Queue structures... +typedef struct // each entry 8 words (32 bytes) +{ + ULONG type; // IMQ completion message types + ULONG word[7]; // remainder of structure + // interpreted by IMQ type +} TachyonIMQE; + + +// Queues for TachLite not in original Tachyon +// ERQ - Exchange Request Queue (for outbound commands) +// SFQ - Single Frame Queue (for incoming frames) + + // Define Tachyon Outbound Command Que + // (Since many Tachyon registers are Read + // only, maintain copies for debugging) + // most Tach ques need power-of-2 sizes, + // where registers are loaded with po2 -1 +#define TACH_SEST_LEN 512 // TachLite SEST + +#define ELS_EXCHANGES 64 // e.g. PLOGI, RSCN, ... +// define the total number of outstanding (simultaneous) exchanges +#define TACH_MAX_XID (TACH_SEST_LEN + ELS_EXCHANGES) // ELS exchanges + +#define ERQ_LEN 128 // power of 2, max 4096 + +// Inbound Message Queue structures... +#define IMQ_LEN 512 // minimum 4 entries [(power of 2) - 1] +typedef struct // 8 words - 32 bytes +{ + TachyonIMQE QEntry[IMQ_LEN]; + ULONG producerIndex; // IMQ Producer Index register + // @32 byte align + ULONG consumerIndex; // Consumer Index register (in Tachyon) + ULONG length; // Length register + ULONG base; +} TachyonIMQ; // @ 32 * IMQ_LEN align + + + +typedef struct // inbound completion message +{ + ULONG Type; + ULONG Index; + ULONG TransferLength; +} TachyonInbCM; + + + +// arbitrary numeric tags for TL structures +#define TL_FCHS 1 // TachLite Fibre Channel Header Structure +#define TL_IWE 2 // initiator write entry (for SEST) +#define TL_TWE 3 // target write entry (for SEST) +#define TL_IRE 4 // initiator read entry (for SEST) +#define TL_TRE 5 // target read entry (for SEST) +#define TL_IRB 6 // I/O request block + + // for INCOMING frames +#define SFQ_LEN 32 // minimum 32 entries, max 4096 + +typedef struct // Single Frame Que +{ + TachFCHDR_CMND QEntry[SFQ_LEN]; // must be 64 bytes!! + ULONG producerIndex; // IMQ Producer Index register + // @32 byte align + ULONG consumerIndex; // Consumer Index register (in Tachyon) + ULONG length; // Length register + ULONG base; +} TachLiteSFQ; + + +typedef struct // I/O Request Block flags +{ + UCHAR BRD : 1; + UCHAR : 1; // reserved + UCHAR SFA : 1; + UCHAR DNC : 1; + UCHAR DIN : 1; + UCHAR DCM : 1; + UCHAR CTS : 1; + UCHAR SBV : 1; // IRB entry valid - IRB'B' only +} IRBflags; + +typedef struct // I/O Request Block +{ // Request 'A' + ULONG Req_A_SFS_Len; // total frame len (hdr + payload), min 32 + ULONG Req_A_SFS_Addr; // 32-bit pointer to FCHS struct (to be sent) + ULONG Req_A_SFS_D_ID; // 24-bit FC destination (i.e. 8 bit al_pa) + ULONG Req_A_Trans_ID; // X_ID (OX_ID or RX_ID) and/or Index in SEST + // Request 'B' + ULONG Req_B_SFS_Len; // total frame len (hdr + payload), min 32 + ULONG Req_B_SFS_Addr; // 32-bit pointer to FCHS struct (to be sent) + ULONG Req_B_SFS_D_ID; // 24-bit FC destination (i.e. 8 bit al_pa) + ULONG Req_B_Trans_ID; // X_ID (OX_ID or RX_ID) and/or Index in SEST +} TachLiteIRB; + + +typedef struct // TachLite placeholder for IRBs +{ // aligned @sizeof(ERQ) for TachLite + // MAX commands is sum of SEST len and ERQ + // we know that each SEST entry requires an + // IRB (ERQ) entry; in addition, we provide + // ERQ_LEN + TachLiteIRB QEntry[ERQ_LEN]; // Base register; entries 32 bytes ea. + ULONG consumerIndex; // Consumer Index register + ULONG producerIndex; // ERQ Producer Index register + ULONG length; // Length register + ULONG base; // copy of base ptr for debug + // struct is sized for largest expected cmnd (LOGIN) +} TachLiteERQ; + + +#define TL_MAX_SGPAGES 4 // arbitrary limit to # of TL Ext. S/G pages + // stores array of allocated page blocks used + // in extended S/G lists. Affects amount of static + // memory consumed by driver. +#define TL_EXT_SG_PAGE_COUNT 256 // Number of Extended Scatter/Gather a/l PAIRS + // Tachyon register (IOBaseU 0x68) + // power-of-2 value ONLY! 4 min, 256 max + + // byte len is #Pairs * 2 ULONG/Pair * 4 bytes/ULONG +#define TL_EXT_SG_PAGE_BYTELEN (TL_EXT_SG_PAGE_COUNT *2 *4) + + + +// SEST entry types: IWE, IRE, TWE, TRE +typedef struct +{ + ULONG Hdr_Len; + ULONG Hdr_Addr; + ULONG RSP_Len; + ULONG RSP_Addr; + ULONG Buff_Off; + ULONG Link; + ULONG RX_ID; + ULONG Data_Len; + ULONG Exp_RO; + ULONG Exp_Byte_Cnt; + // --- extended/local Gather Len/Address pairs + ULONG GLen1; + ULONG GAddr1; + ULONG GLen2; + ULONG GAddr2; + ULONG GLen3; + ULONG GAddr3; +} TachLiteIWE; + + +typedef struct +{ + ULONG Seq_Accum; + ULONG reserved; // must clear to 0 + ULONG RSP_Len; + ULONG RSP_Addr; + ULONG Buff_Off; + ULONG Buff_Index; // ULONG 5 + ULONG Exp_RO; + ULONG Byte_Count; + ULONG reserved_; // ULONG 8 + ULONG Exp_Byte_Cnt; + // --- extended/local Scatter Len/Address pairs + ULONG SLen1; + ULONG SAddr1; + ULONG SLen2; + ULONG SAddr2; + ULONG SLen3; + ULONG SAddr3; +} TachLiteIRE; + + +typedef struct // Target Write Entry +{ + ULONG Seq_Accum; // dword 0 + ULONG reserved; // dword 1 must clear to 0 + ULONG Remote_Node_ID; + ULONG reserved1; // dword 3 must clear to 0 + ULONG Buff_Off; + ULONG Buff_Index; // ULONG 5 + ULONG Exp_RO; + ULONG Byte_Count; + ULONG reserved_; // ULONG 8 + ULONG Exp_Byte_Cnt; + // --- extended/local Scatter Len/Address pairs + ULONG SLen1; + ULONG SAddr1; + ULONG SLen2; + ULONG SAddr2; + ULONG SLen3; + ULONG SAddr3; +} TachLiteTWE; + +typedef struct +{ + ULONG Hdr_Len; + ULONG Hdr_Addr; + ULONG RSP_Len; // DWord 2 + ULONG RSP_Addr; + ULONG Buff_Off; + ULONG Buff_Index; // DWord 5 + ULONG reserved; + ULONG Data_Len; + ULONG reserved_; + ULONG reserved__; + // --- extended/local Gather Len/Address pairs + ULONG GLen1; // DWord A + ULONG GAddr1; + ULONG GLen2; + ULONG GAddr2; + ULONG GLen3; + ULONG GAddr3; +} TachLiteTRE; + +typedef struct +{ + void *PoolPage[TL_MAX_SGPAGES]; +} SGPAGES, *PSGPAGES; // linked list of S/G pairs, by Exchange + + + +typedef struct // SCSI Exchange State Table +{ + union // Entry can be IWE, IRE, TWE, TRE + { // 64 bytes per entry + TachLiteIWE IWE; + TachLiteIRE IRE; + TachLiteTWE TWE; + TachLiteTRE TRE; + } u[TACH_SEST_LEN]; + + TachFCHDR DataHDR[TACH_SEST_LEN]; // for SEST FCP_DATA frame hdr (no pl) + TachFCHDR_RSP RspHDR[TACH_SEST_LEN]; // space for SEST FCP_RSP frame + SGPAGES sgPages[TACH_SEST_LEN]; // array of Pool-allocations + ULONG length; // Length register + ULONG base; // copy of base ptr for debug +} TachSEST; + + + +typedef struct // each register has it's own address + // and value (used for write-only regs) +{ + void* address; + volatile ULONG value; +} FCREGISTER; + +typedef struct // Host copy - TachLite Registers +{ + ULONG IOBaseL, IOBaseU; // I/O port lower and upper TL register addresses + ULONG MemBase; // memory mapped register addresses + void* ReMapMemBase; // O/S VM reference for MemBase + ULONG wwn_hi; // WWN is set once at startup + ULONG wwn_lo; + ULONG my_al_pa; // al_pa received after LIP() + ULONG ROMCTR; // flags for on-board RAM/ROM + ULONG RAMBase; // on-board RAM (i.e. some Tachlites) + ULONG SROMBase; // on-board EEPROM (some Tachlites) + ULONG PCIMCTR; // PCI Master Control Reg (has bus width) + + FCREGISTER INTEN; // copy of interrupt enable mask + FCREGISTER INTPEND; // interrupt pending + FCREGISTER INTSTAT; // interrupt status + FCREGISTER SFQconsumerIndex; + FCREGISTER ERQproducerIndex; + FCREGISTER TYconfig; // TachYon (chip level) + FCREGISTER TYcontrol; + FCREGISTER TYstatus; + FCREGISTER FMconfig; // Frame Manager (FC loop level) + FCREGISTER FMcontrol; + FCREGISTER FMstatus; + FCREGISTER FMLinkStatus1; + FCREGISTER FMLinkStatus2; + FCREGISTER FMBB_CreditZero; + FCREGISTER status; + FCREGISTER ed_tov; // error detect time-out value + FCREGISTER rcv_al_pa; // received arb. loop physical address + FCREGISTER primitive; // e.g. LIP(), OPN(), ... +} TL_REGISTERS; + + + +typedef struct +{ + ULONG ok; + ULONG invalidArgs; + ULONG linkDown; + ULONG linkUp; + ULONG outQueFull; + ULONG SESTFull; + ULONG hpe; // host programming err (from Tach) + ULONG FC4aborted; // aborts from Application or upper driver layer + ULONG FC2aborted; // aborts from our driver's timeouts + ULONG timeouts; // our driver timeout (on individual exchanges) + ULONG logouts; // explicit - sent LOGO; implicit - device removed + ULONG retries; + ULONG linkFailTX; + ULONG linkFailRX; + ULONG CntErrors; // byte count expected != count received (typ. SEST) + ULONG e_stores; // elastic store errs + ULONG resets; // hard or soft controller resets + ULONG FMinits; // TACH Frame Manager Init (e.g. LIPs) + ULONG lnkQueFull; // too many LOGIN, loop commands + ULONG ScsiQueFull; // too many FCP-SCSI inbound frames + ULONG LossofSignal; // FM link status 1 regs + ULONG BadRXChar; // FM link status 1 regs + ULONG LossofSync; // FM link status 1 regs + ULONG Rx_EOFa; // FM link status 2 regs (received EOFa) + ULONG Dis_Frm; // FM link status 2 regs (discarded frames) + ULONG Bad_CRC; // FM link status 2 regs + ULONG BB0_Timer; // FM BB_Credit Zero Timer Reg + ULONG loopBreaks; // infinite loop exits + ULONG lastBB0timer; // static accum. buffer needed by Tachlite +} FCSTATS; + + +typedef struct // Config Options +{ // LS Bit first + USHORT : 1; // bit0: + USHORT flogi : 1; // bit1: We sent FLOGI - wait for Fabric logins + USHORT fabric: 1; // bit2: Tachyon detected Fabric (FM stat LG) + USHORT LILPin: 1; // bit3: We can use an FC-AL LILP frame + USHORT target: 1; // bit4: this Port has SCSI target capability + USHORT initiator: 1; // bit5: this Port has SCSI initiator capability + USHORT extLoopback: 1; // bit6: loopback at GBIC + USHORT intLoopback: 1; // bit7: loopback in HP silicon + USHORT : 1; // bit8: + USHORT : 1; // bit9: + USHORT : 1; // bit10: + USHORT : 1; // bit11: + USHORT : 1; // bit12: + USHORT : 1; // bit13: + USHORT : 1; // bit14: + USHORT : 1; // bit15: +} FC_OPTIONS; + + + +typedef struct dyn_mem_pair +{ + void *BaseAllocated; // address as allocated from O/S; + unsigned long AlignedAddress; // aligned address (used by Tachyon DMA) +} ALIGNED_MEM; + + + + +// these structs contain only CRUCIAL (stuff we actually use) parameters +// from FC-PH(n) logins. (Don't save entire LOGIN payload to save mem.) + +// Implicit logout happens when the loop goes down - we require PDISC +// to restore. Explicit logout is when WE decide never to talk to someone, +// or when a target refuses to talk to us, i.e. sends us a LOGO frame or +// LS_RJT reject in response to our PLOGI request. + +#define IMPLICIT_LOGOUT 1 +#define EXPLICIT_LOGOUT 2 + +typedef struct +{ + UCHAR channel; // SCSI "bus" + UCHAR target; + UCHAR InqDeviceType; // byte 0 from SCSI Inquiry response + UCHAR VolumeSetAddressing; // FCP-SCSI LUN coding (40h for VSA) + UCHAR LunMasking; // True if selective presentation supported + UCHAR lun[CPQFCTS_MAX_LUN]; +} SCSI_NEXUS; + + +typedef struct +{ + union + { + UCHAR ucWWN[8]; // a FC 64-bit World Wide Name/ PortID of target + // addressing of single target on single loop... + u64 liWWN; + } u; + + ULONG port_id; // a FC 24-bit address of port (lower 8 bits = al_pa) + + Scsi_Cmnd ScsiCmnd; // command buffer for Report Luns +#define REPORT_LUNS_PL 256 + UCHAR ReportLunsPayload[REPORT_LUNS_PL]; + + SCSI_NEXUS ScsiNexus; // LUNs per FC device + + ULONG LOGO_counter; // might try several times before logging out for good + ULONG LOGO_timer; // after LIP, ports expecting PDISC must time-out and + // LOGOut if successful PDISC not completed in 2 secs + + ULONG concurrent_seq; // must be 1 or greater + ULONG rx_data_size; // e.g. 128, 256, 1024, 2048 per FC-PH spec + ULONG BB_credit; + ULONG EE_credit; + + ULONG fcp_info; // from PRLI (i.e. INITIATOR/ TARGET flags) + // flags for login process + BOOLEAN Originator; // Login sequence Originated (if false, we + // responded to another port's login sequence) + BOOLEAN plogi; // PLOGI frame ACCepted (originated or responded) + BOOLEAN pdisc; // PDISC frame was ORIGINATED (self-login logic) + BOOLEAN prli; // PRLI frame ACCepted (originated or responded) + BOOLEAN flogi; // FLOGI frame ACCepted (originated or responded) + BOOLEAN logo; // port permanently logged out (invalid login param) + BOOLEAN flogiReq; // Fabric login required (set in LIP process) + UCHAR highest_ver; + UCHAR lowest_ver; + + + // when the "target" (actually FC Port) is waiting for login + // (e.g. after Link reset), set the device_blocked bit; + // after Port completes login, un-block target. + UCHAR device_blocked; // see Scsi_Device struct + + // define singly-linked list of logged-in ports + // once a port_id is identified, it is remembered, + // even if the port is removed indefinitely + PVOID pNextPort; // actually, type PFC_LOGGEDIN_PORT; void for Compiler + +} FC_LOGGEDIN_PORT, *PFC_LOGGEDIN_PORT; + + + +// This serves as the ESB (Exchange Status Block), +// and has timeout counter; used for ABORTs +typedef struct +{ // FC-1 X_IDs + ULONG type; // ELS_PLOGI, SCSI_IWE, ... (0 if free) + PFC_LOGGEDIN_PORT pLoggedInPort; // FC device on other end of Exchange + Scsi_Cmnd *Cmnd; // Linux SCSI command packet includes S/G list + ULONG timeOut; // units of ??, DEC by driver, Abort when 0 + ULONG reTries; // need one or more retries? + ULONG status; // flags indicating errors (0 if none) + TachLiteIRB IRB; // I/O Request Block, gets copied to ERQ + TachFCHDR_GCMND fchs; // location of IRB's Req_A_SFS_Addr +} FC_EXCHANGE, *PFC_EXCHANGE; + +// Unfortunately, Linux limits our kmalloc() allocations to 128k. +// Because of this and the fact that our ScsiRegister allocation +// is also constrained, we move this large structure out for +// allocation after Scsi Register. +// (In other words, this cumbersome indirection is necessary +// because of kernel memory allocation constraints!) + +typedef struct // we will allocate this dynamically +{ + FC_EXCHANGE fcExchange[ TACH_MAX_XID ]; +} FC_EXCHANGES; + + + + + + + + + + + +typedef struct +{ + char Name[64]; // name of controller ("HP Tachlite TL Rev2.0, 33MHz, 64bit bus") + //PVOID pAdapterDevExt; // back pointer to device object/extension + ULONG ChipType; // local numeric key for Tachyon Type / Rev. + ULONG status; // our Driver - logical status + + TL_REGISTERS Registers; // reg addresses & host memory copies + // FC-4 mapping of 'transaction' to X_IDs + UCHAR LILPmap[32*4]; // Loop Position Map of ALPAs (late FC-AL only) + FC_OPTIONS Options; // e.g. Target, Initiator, loopback... + UCHAR highest_FCPH_ver; // FC-PH version limits + UCHAR lowest_FCPH_ver; // FC-PH version limits + + FC_EXCHANGES *Exchanges; + ULONG fcLsExchangeLRU; // Least Recently Used counter (Link Service) + ULONG fcSestExchangeLRU; // Least Recently Used counter (FCP-SCSI) + FC_LOGGEDIN_PORT fcPorts; // linked list of every FC port ever seen + FCSTATS fcStats; // FC comm err counters + + // Host memory QUEUE pointers + TachLiteERQ *ERQ; // Exchange Request Que + TachyonIMQ *IMQ; // Inbound Message Que + TachLiteSFQ *SFQ; // Single Frame Queue + TachSEST *SEST; // SCSI Exchange State Table + + // these function pointers are for "generic" functions, which are + // replaced with Host Bus Adapter types at + // runtime. + int (*CreateTachyonQues)( void* , int); + int (*DestroyTachyonQues)( void* , int); + int (*LaserControl)(void*, int ); // e.g. On/Off + int (*ResetTachyon)(void*, int ); + void (*FreezeTachyon)(void*, int ); + void (*UnFreezeTachyon)(void*, int ); + int (*InitializeTachyon)(void*, int, int ); + int (*InitializeFrameManager)(void*, int ); + int (*ProcessIMQEntry)(void*); + int (*ReadWriteWWN)(void*, int ReadWrite); + int (*ReadWriteNVRAM)(void*, void*, int ReadWrite); + +} TACHYON, *PTACHYON; + + +void cpqfcTSClearLinkStatusCounters(TACHYON * fcChip); + +int CpqTsCreateTachLiteQues( void* pHBA, int opcode); +int CpqTsDestroyTachLiteQues( void* , int); +int CpqTsInitializeTachLite( void *pHBA, int opcode1, int opcode2); + +int CpqTsProcessIMQEntry(void* pHBA); +int CpqTsResetTachLite(void *pHBA, int type); +void CpqTsFreezeTachlite(void *pHBA, int type); +void CpqTsUnFreezeTachlite(void *pHBA, int type); +int CpqTsInitializeFrameManager(void *pHBA, int); +int CpqTsLaserControl( void* addrBase, int opcode ); +int CpqTsReadWriteWWN(void*, int ReadWrite); +int CpqTsReadWriteNVRAM(void*, void* data, int ReadWrite); + +void cpqfcTS_WorkTask( struct Scsi_Host *HostAdapter); +void cpqfcTSWorkerThread( void *host); + +int cpqfcTS_GetNVRAM_data( UCHAR *wwnbuf, UCHAR *buf ); +ULONG cpqfcTS_ReadNVRAM( void* GPIOin, void* GPIOout , USHORT count, + UCHAR *buf ); + +BOOLEAN tl_write_i2c_nvram( void* GPIOin, void* GPIOout, + USHORT startOffset, // e.g. 0x2f for WWN start + USHORT count, + UCHAR *buf ); + + +// define misc functions +int cpqfcTSGetLPSM( PTACHYON fcChip, char cErrorString[]); +int cpqfcTSDecodeGBICtype( PTACHYON fcChip, char cErrorString[]); +void* fcMemManager( ALIGNED_MEM *dyn_mem_pair, ULONG n_alloc, ULONG ab, + ULONG ulAlignedAddress); + +void BigEndianSwap( UCHAR *source, UCHAR *dest, USHORT cnt); + +//ULONG virt_to_phys( PVOID virtaddr ); + + +// Linux interrupt handler +void cpqfcTS_intr_handler( int irq,void *dev_id,struct pt_regs *regs); +void cpqfcTSheartbeat( unsigned long ptr ); + + + +// The biggest Q element we deal with is Aborts - we +// need 4 bytes for x_ID, and a Scsi_Cmnd (~284 bytes) +//#define LINKQ_ITEM_SIZE ((4+sizeof(Scsi_Cmnd)+3)/4) +#define LINKQ_ITEM_SIZE (3*16) +typedef struct +{ + ULONG Type; // e.g. LINKUP, SFQENTRY, PDISC, BLS_ABTS, ... + ULONG ulBuff[ LINKQ_ITEM_SIZE ]; +} LINKQ_ITEM; + +#define FC_LINKQ_DEPTH TACH_MAX_XID +typedef struct +{ + ULONG producer; + ULONG consumer; // when producer equals consumer, Q empty + + LINKQ_ITEM Qitem[ FC_LINKQ_DEPTH ]; + +} FC_LINK_QUE, *PFC_LINK_QUE; + + + // DPC routines post to here on Inbound SCSI frames + // User thread processes +#define FC_SCSIQ_DEPTH 32 + +typedef struct +{ + int Type; // e.g. SCSI + ULONG ulBuff[ 3*16 ]; +} SCSIQ_ITEM; + +typedef struct +{ + ULONG producer; + ULONG consumer; // when producer equals consumer, Q empty + + SCSIQ_ITEM Qitem[ FC_SCSIQ_DEPTH ]; + +} FC_SCSI_QUE, *PFC_SCSI_QUE; + + + + + +#define DYNAMIC_ALLOCATIONS 4 // Tachyon aligned allocations: ERQ,IMQ,SFQ,SEST + +// Linux space allocated per HBA (chip state, etc.) +typedef struct +{ + struct Scsi_Host *HostAdapter; // back pointer to Linux Scsi struct + + TACHYON fcChip; // All Tachyon registers, Queues, functions + ALIGNED_MEM dynamic_mem[DYNAMIC_ALLOCATIONS]; + + struct pci_dev *PciDev; + + Scsi_Cmnd *LinkDnCmnd[CPQFCTS_REQ_QUEUE_LEN]; // collects Cmnds during LDn + // (for Acceptable targets) + Scsi_Cmnd *BoardLockCmnd[CPQFCTS_REQ_QUEUE_LEN]; // SEST was full + + Scsi_Cmnd *BadTargetCmnd[CPQFCTS_MAX_TARGET_ID]; // missing targets + + u_char HBAnum; // 0-based host number + + + struct timer_list cpqfcTStimer; // FC utility timer for implicit + // logouts, FC protocol timeouts, etc. + int fcStatsTime; // Statistics delta reporting time + + struct task_struct *worker_thread; // our kernel thread + int PortDiscDone; // set by SendLogins(), cleared by LDn + + struct semaphore *TachFrozen; + struct semaphore *TYOBcomplete; // handshake for Tach outbound frames + struct semaphore *fcQueReady; // FibreChannel work for our kernel thread + struct semaphore *notify_wt; // synchronizes kernel thread kill + struct semaphore *BoardLock; + + PFC_LINK_QUE fcLQ; // the WorkerThread operates on this + + spinlock_t hba_spinlock; // held/released by WorkerThread + +} CPQFCHBA; + +#define CPQ_SPINLOCK_HBA( x ) spin_lock(&x->hba_spinlock); +#define CPQ_SPINUNLOCK_HBA(x) spin_unlock(&x->hba_spinlock); + + + +void cpqfcTSImplicitLogout( CPQFCHBA* cpqfcHBAdata, + PFC_LOGGEDIN_PORT pFcPort); + + +void cpqfcTSTerminateExchange( CPQFCHBA*, SCSI_NEXUS *target, int ); + +PFC_LOGGEDIN_PORT fcPortLoggedIn( + CPQFCHBA *cpqfcHBAdata, + TachFCHDR_GCMND* fchs, + BOOLEAN, + BOOLEAN); +void fcProcessLoggedIn( + CPQFCHBA *cpqfcHBAdata, TachFCHDR_GCMND* fchs); + + +ULONG cpqfcTSBuildExchange( + CPQFCHBA *cpqfcHBAdata, + ULONG type, // e.g. PLOGI + TachFCHDR_GCMND* InFCHS, // incoming FCHS + void *Data, // the CDB, scatter/gather, etc. + LONG *ExchangeID ); // allocated exchange ID + +ULONG cpqfcTSStartExchange( + CPQFCHBA *cpqfcHBAdata, + LONG ExchangeID ); + +void cpqfcTSCompleteExchange( + PTACHYON fcChip, + ULONG exchange_ID); + + +PFC_LOGGEDIN_PORT fcFindLoggedInPort( + PTACHYON fcChip, + Scsi_Cmnd *Cmnd, // (We want the channel/target/lun Nexus from Cmnd) + ULONG port_id, // search linked list for al_pa, or + UCHAR wwn[8], // search linked list for WWN, or... + PFC_LOGGEDIN_PORT *pLastLoggedInPort +); + +// don't do this unless you have the right hardware! +#define TRIGGERABLE_HBA 1 +#ifdef TRIGGERABLE_HBA +void TriggerHBA( void*, int); +#endif + +void cpqfcTSPutLinkQue( + CPQFCHBA *cpqfcHBAdata, + int Type, + void *QueContent); + +void fcPutScsiQue( + CPQFCHBA *cpqfcHBAdata, + int Type, + void *QueContent); + +void fcLinkQReset( + CPQFCHBA *); +void fcScsiQReset( + CPQFCHBA *); +void fcSestReset( + CPQFCHBA *); + + + + + +extern const UCHAR valid_al_pa[]; +extern const int number_of_al_pa; + +#define FCP_RESID_UNDER 0x80000 +#define FCP_RESID_OVER 0x40000 +#define FCP_SNS_LEN_VALID 0x20000 +#define FCP_RSP_LEN_VALID 0x10000 + +// RSP_CODE definitions (dpANS Fibre Channel Protocol for SCSI, pg 34) +#define FCP_DATA_LEN_NOT_BURST_LEN 0x1000000 +#define FCP_CMND_FIELD_INVALID 0x2000000 +#define FCP_DATA_RO_NOT_XRDY_RO 0x3000000 +#define FCP_TASKFUNCTION_NS 0x4000000 +#define FCP_TASKFUNCTION_FAIL 0x5000000 + +// FCP-SCSI response status struct +typedef struct // see "TachFCHDR_RSP" definition - 64 bytes +{ + __u32 reserved; + __u32 reserved1; + __u32 fcp_status; // field validity and SCSI status + __u32 fcp_resid; + __u32 fcp_sns_len; // length of FCP_SNS_INFO field + __u32 fcp_rsp_len; // length of FCP_RSP_INFO field (expect 8) + __u32 fcp_rsp_info; // 4 bytes of FCP protocol response information + __u32 fcp_rsp_info2; // (4 more bytes, since most implementations use 8) + __u8 fcp_sns_info[36]; // bytes for SCSI sense (ASC, ASCQ) + +} FCP_STATUS_RESPONSE, *PFCP_STATUS_RESPONSE; + + +// Fabric State Change Registration +typedef struct scrpl +{ + __u32 command; + __u32 function; +} SCR_PL; + +// Fabric Name Service Request +typedef struct nsrpl +{ + __u32 CT_Rev; // (& IN_ID) WORD 0 + __u32 FCS_Type; // WORD 1 + __u32 Command_code; // WORD 2 + __u32 reason_code; // WORD 3 + __u32 FCP; // WORD 4 (lower byte) + +} NSR_PL; + + + +// "FC.H" +#define MAX_RX_SIZE 0x800 // Max Receive Buffer Size is 2048 +#define MIN_RX_SIZE 0x100 // Min Size is 256, per FC-PLDA Spec +#define MAX_TARGET_RXIDS SEST_DEPTH +#define TARGET_RX_SIZE SEST_BUFFER_LENGTH + +#define CLASS_1 0x01 +#define CLASS_2 0x02 +#define CLASS_3 0x03 + +#define FC_PH42 0x08 +#define FC_PH43 0x09 +#define FC_PH3 0x20 + +#define RR_TOV 2 // Minimum Time for target to wait for + // PDISC after a LIP. +#define E_D_TOV 2 // Minimum Time to wait for Sequence + // Completion. +#define R_A_TOV 0 // Minimum Time for Target to wait + // before reclaiming resources. +// +// R_CTL Field +// +// Routing Bits (31-28) +// +#define FC4_DEVICE_DATA 0x00000000 +#define EXT_LINK_DATA 0x20000000 +#define FC4_LINK_DATA 0x30000000 +#define VIDEO_DATA 0x40000000 +#define BASIC_LINK_DATA 0x80000000 +#define LINK_CONTROL 0xC0000000 +#define ROUTING_MASK 0xF0000000 + +// +// Information Bits (27-24) +// +#define UNCAT_INFORMATION 0x00000000 +#define SOLICITED_DATA 0x01000000 +#define UNSOLICITED_CONTROL 0x02000000 +#define SOLICITED_CONTROL 0x03000000 +#define UNSOLICITED_DATA 0x04000000 +#define DATA_DESCRIPTOR 0x05000000 +#define UNSOLICITED_COMMAND 0x06000000 +#define COMMAND_STATUS 0x07000000 +#define INFO_MASK 0x0F000000 +// +// (Link Control Codes) +// +#define ACK_1 0x00000000 +#define ACK_0_OR_N 0x01000000 +#define P_RJT 0x02000000 +#define F_RJT 0x03000000 +#define P_BSY 0x04000000 +#define FABRIC_BUSY_TO_DF 0x05000000 // Fabric Busy to Data Frame +#define FABRIC_BUSY_TO_LC 0x06000000 // Fabric Busy to Link Ctl Frame +#define LINK_CREDIT_RESET 0x07000000 +// +// (Link Service Command Codes) +// +//#define LS_RJT 0x01000000 // LS Reject + +#define LS_ACC 0x02000000 // LS Accept +#define LS_PLOGI 0x03000000 // N_PORT Login +#define LS_FLOGI 0x04000000 // F_PORT Login +#define LS_LOGO 0x05000000 // Logout +#define LS_ABTX 0x06000000 // Abort Exchange +#define LS_RCS 0x07000000 // Read Connection Status +#define LS_RES 0x08000000 // Read Exchange Status +#define LS_RSS 0x09000000 // Read Sequence Status +#define LS_RSI 0x0A000000 // Request Seq Initiative +#define LS_ESTS 0x0B000000 // Establish Steaming +#define LS_ESTC 0x0C000000 // Estimate Credit +#define LS_ADVC 0x0D000000 // Advice Credit +#define LS_RTV 0x0E000000 // Read Timeout Value +#define LS_RLS 0x0F000000 // Read Link Status +#define LS_ECHO 0x10000000 // Echo +#define LS_TEST 0x11000000 // Test +#define LS_RRQ 0x12000000 // Reinstate Rec. Qual. +#define LS_PRLI 0x20000000 // Process Login +#define LS_PRLO 0x21000000 // Process Logout +#define LS_TPRLO 0x24000000 // 3rd Party Process Logout +#define LS_PDISC 0x50000000 // Process Discovery +#define LS_FDISC 0x51000000 // Fabric Discovery +#define LS_ADISC 0x52000000 // Discover Address +#define LS_RNC 0x53000000 // Report Node Capability +#define LS_SCR 0x62000000 // State Change Registration +#define LS_MASK 0xFF000000 + +// +// TYPE Bit Masks +// +#define BASIC_LINK_SERVICE 0x00000000 +#define EXT_LINK_SERVICE 0x01000000 + +#define LLC 0x04000000 +#define LLC_SNAP 0x05000000 +#define SCSI_FCP 0x08000000 +#define SCSI_GPP 0x09000000 +#define IPI3_MASTER 0x11000000 +#define IPI3_SLAVE 0x12000000 +#define IPI3_PEER 0x13000000 +#define CP_IPI3_MASTER 0x15000000 +#define CP_IPI3_SLAVE 0x16000000 +#define CP_IPI3_PEER 0x17000000 +#define SBCCS_CHANNEL 0x19000000 +#define SBCCS_CONTROL 0x1A000000 +#define FIBRE_SERVICES 0x20000000 +#define FC_FG 0x21000000 +#define FC_XS 0x22000000 +#define FC_AL 0x23000000 +#define SNMP 0x24000000 +#define HIPPI_FP 0x40000000 +#define TYPE_MASK 0xFF000000 + +typedef struct { + UCHAR seq_id_valid; + UCHAR seq_id; + USHORT reserved; // 2 bytes reserved + ULONG ox_rx_id; + USHORT low_seq_cnt; + USHORT high_seq_cnt; +} BA_ACC_PAYLOAD; + +typedef struct { + UCHAR reserved; + UCHAR reason_code; + UCHAR reason_explain; + UCHAR vendor_unique; +} BA_RJT_PAYLOAD; + + +typedef struct { + ULONG command_code; + ULONG sid; + USHORT ox_id; + USHORT rx_id; +} RRQ_MESSAGE; + +typedef struct { + ULONG command_code; + UCHAR vendor; + UCHAR explain; + UCHAR reason; + UCHAR reserved; +} REJECT_MESSAGE; + + +#define N_OR_F_PORT 0x1000 +#define RANDOM_RELATIVE_OFFSET 0x4000 +#define CONTINUOSLY_INCREASING 0x8000 + +#define CLASS_VALID 0x8000 +#define INTERMIX_MODE 0x4000 +#define TRANSPARENT_STACKED 0x2000 +#define LOCKDOWN_STACKED 0x1000 +#define SEQ_DELIVERY 0x800 + +#define XID_NOT_SUPPORTED 0x00 +#define XID_SUPPORTED 0x4000 +#define XID_REQUIRED 0xC000 + +#define ASSOCIATOR_NOT_SUPPORTED 0x00 +#define ASSOCIATOR_SUPPORTED 0x1000 +#define ASSOCIATOR_REQUIRED 0x3000 + +#define INIT_ACK0_SUPPORT 0x800 +#define INIT_ACKN_SUPPORT 0x400 + +#define RECIP_ACK0_SUPPORT 0x8000 +#define RECIP_ACKN_SUPPORT 0x4000 + +#define X_ID_INTERLOCK 0x2000 + +#define ERROR_POLICY 0x1800 // Error Policy Supported +#define ERROR_DISCARD 0x00 // Only Discard Supported +#define ERROR_DISC_PROCESS 0x02 // Discard and process supported + +#define NODE_ID 0x01 +#define IEEE_EXT 0x20 + +// +// Categories Supported Per Sequence +// +#define CATEGORIES_PER_SEQUENCE 0x300 +#define ONE_CATEGORY_SEQUENCE 0x00 // 1 Category per Sequence +#define TWO_CATEGORY_SEQUENCE 0x01 // 2 Categories per Sequence +#define MANY_CATEGORY_SEQUENCE 0x03 // > 2 Categories/Sequence + +typedef struct { + + USHORT initiator_control; + USHORT service_options; + + USHORT rx_data_size; + USHORT recipient_control; + + USHORT ee_credit; + USHORT concurrent_sequences; + + USHORT reserved; + USHORT open_sequences; + +} CLASS_PARAMETERS; + +typedef struct { + ULONG login_cmd; + // + // Common Service Parameters + // + struct { + + USHORT bb_credit; + UCHAR lowest_ver; + UCHAR highest_ver; + + USHORT bb_rx_size; + USHORT common_features; + + USHORT rel_offset; + USHORT concurrent_seq; + + + ULONG e_d_tov; + } cmn_services; + + // + // Port Name + // + UCHAR port_name[8]; + + // + // Node/Fabric Name + // + UCHAR node_name[8]; + + // + // Class 1, 2 and 3 Service Parameters + // + CLASS_PARAMETERS class1; + CLASS_PARAMETERS class2; + CLASS_PARAMETERS class3; + + ULONG reserved[4]; + + // + // Vendor Version Level + // + UCHAR vendor_id[2]; + UCHAR vendor_version[6]; + ULONG buffer_size; + USHORT rxid_start; + USHORT total_rxids; +} LOGIN_PAYLOAD; + + +typedef struct +{ + ULONG cmd; // 4 bytes + UCHAR n_port_identifier[3]; + UCHAR reserved; + UCHAR port_name[8]; +} LOGOUT_PAYLOAD; + + +// +// PRLI Request Service Parameter Defines +// +#define PRLI_ACC 0x01 +#define PRLI_REQ 0x02 +#define ORIG_PROCESS_ASSOC_VALID 0x8000 +#define RESP_PROCESS_ASSOC_VALID 0x4000 +#define ESTABLISH_PAIR 0x2000 +#define DATA_OVERLAY_ALLOWED 0x40 +#define INITIATOR_FUNCTION 0x20 +#define TARGET_FUNCTION 0x10 +#define CMD_DATA_MIXED 0x08 +#define DATA_RESP_MIXED 0x04 +#define READ_XFER_RDY 0x02 +#define WRITE_XFER_RDY 0x01 + +#define RESPONSE_CODE_MASK 0xF00 +#define REQUEST_EXECUTED 0x100 +#define NO_RESOURCES 0x200 +#define INIT_NOT_COMPLETE 0x300 +#define IMAGE_DOES_NOT_EXIST 0x400 +#define BAD_PREDEFINED_COND 0x500 +#define REQ_EXEC_COND 0x600 +#define NO_MULTI_PAGE 0x700 + +typedef struct { + USHORT payload_length; + UCHAR page_length; + UCHAR cmd; + + + ULONG valid; + + ULONG orig_process_associator; + + ULONG resp_process_associator; + + ULONG fcp_info; +} PRLI_REQUEST; + +typedef struct { + + USHORT payload_length; + UCHAR page_length; + UCHAR cmd; + + ULONG valid; + ULONG orig_process_associator; + + ULONG resp_process_associator; + ULONG reserved; +} PRLO_REQUEST; + +typedef struct { + ULONG cmd; + + ULONG hard_address; + + UCHAR port_name[8]; + + UCHAR node_name[8]; + + ULONG s_id; +} ADISC_PAYLOAD; + +// J. McCarty's LINK.H +// +// LS_RJT Reason Codes +// + +#define INVALID_COMMAND_CODE 0x01 +#define LOGICAL_ERROR 0x03 +#define LOGICAL_BUSY 0x05 +#define PROTOCOL_ERROR 0x07 +#define UNABLE_TO_PERFORM 0x09 +#define COMMAND_NOT_SUPPORTED 0x0B +#define LS_VENDOR_UNIQUE 0xFF + +// +// LS_RJT Reason Codes Explanations +// +#define NO_REASON 0x00 +#define OPTIONS_ERROR 0x01 +#define INITIATOR_CTL_ERROR 0x03 +#define RECIPIENT_CTL_ERROR 0x05 +#define DATA_FIELD_SIZE_ERROR 0x07 +#define CONCURRENT_SEQ_ERROR 0x09 +#define CREDIT_ERROR 0x0B +#define INVALID_PORT_NAME 0x0D +#define INVALID_NODE_NAME 0x0E +#define INVALID_CSP 0x0F // Invalid Service Parameters +#define INVALID_ASSOC_HDR 0x11 // Invalid Association Header +#define ASSOC_HDR_REQUIRED 0x13 // Association Header Required +#define LS_INVALID_S_ID 0x15 +#define INVALID_OX_RX_ID 0x17 // Invalid OX_ID RX_ID Combination +#define CMD_IN_PROCESS 0x19 +#define INVALID_IDENTIFIER 0x1F // Invalid N_PORT Identifier +#define INVALID_SEQ_ID 0x21 +#define ABT_INVALID_XCHNG 0x23 // Attempt to Abort an invalid Exchange +#define ABT_INACTIVE_XCHNG 0x25 // Attempt to Abort an inactive Exchange +#define NEED_REC_QUAL 0x27 // Recovery Qualifier required +#define NO_LOGIN_RESOURCES 0x29 // No resources to support login +#define NO_DATA 0x2A // Unable to supply requested data +#define REQUEST_NOT_SUPPORTED 0x2C // Request Not Supported + +// +// Link Control Codes +// + +// +// P_BSY Action Codes +// +#define SEQUENCE_TERMINATED 0x01000000 +#define SEQUENCE_ACTIVE 0x02000000 + +// +// P_BSY Reason Codes +// +#define PHYS_NPORT_BUSY 0x010000 +#define NPORT_RESOURCE_BUSY 0x020000 + +// +// P_RJT, F_RJT Action Codes +// + +#define RETRYABLE_ERROR 0x01000000 +#define NON_RETRYABLE_ERROR 0x02000000 + +// +// P_RJT, F_RJT Reason Codes +// +#define INVALID_D_ID 0x010000 +#define INVALID_S_ID 0x020000 +#define NPORT_NOT_AVAIL_TMP 0x030000 +#define NPORT_NOT_AVAIL_PERM 0x040000 +#define CLASS_NOT_SUPPORTED 0x050000 +#define USAGE_ERROR 0x060000 +#define TYPE_NOT_SUPPORTED 0x070000 +#define INVAL_LINK_CONTROL 0x080000 +#define INVAL_R_CTL 0x090000 +#define INVAL_F_CTL 0x0A0000 +#define INVAL_OX_ID 0x0B0000 +#define INVAL_RX_ID 0x0C0000 +#define INVAL_SEQ_ID 0x0D0000 +#define INVAL_DF_CTL 0x0E0000 +#define INVAL_SEQ_CNT 0x0F0000 +#define INVAL_PARAMS 0x100000 +#define EXCHANGE_ERROR 0x110000 +#define LS_PROTOCOL_ERROR 0x120000 +#define INCORRECT_LENGTH 0x130000 +#define UNEXPECTED_ACK 0x140000 +#define LOGIN_REQ 0x160000 +#define EXCESSIVE_SEQ 0x170000 +#define NO_EXCHANGE 0x180000 +#define SEC_HDR_NOT_SUPPORTED 0x190000 +#define NO_FABRIC 0x1A0000 +#define P_VENDOR_UNIQUE 0xFF0000 + +// +// BA_RJT Reason Codes +// +#define BA_INVALID_COMMAND 0x00010000 +#define BA_LOGICAL_ERROR 0x00030000 +#define BA_LOGICAL_BUSY 0x00050000 +#define BA_PROTOCOL_ERROR 0x00070000 +#define BA_UNABLE_TO_PERFORM 0x00090000 + +// +// BA_RJT Reason Explanation Codes +// +#define BA_NO_REASON 0x00000000 +#define BA_INVALID_OX_RX 0x00000300 +#define BA_SEQUENCE_ABORTED 0x00000500 + + + +#endif /* CPQFCTSSTRUCTS_H */ + diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/cpqfcTStrigger.c linux/drivers/scsi/cpqfcTStrigger.c --- v2.4.0-test8/linux/drivers/scsi/cpqfcTStrigger.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/cpqfcTStrigger.c Tue Sep 19 08:01:34 2000 @@ -0,0 +1,30 @@ +// Routine to trigger Finisar GTA analyzer. Runs of GPIO2 +// NOTE: DEBUG ONLY! Could interfere with FCMNGR/Miniport operation +// since it writes directly to the Tachyon board. This function +// developed for Compaq HBA Tachyon TS v1.2 (Rev X5 PCB) + +#include +#include +#include +#include +#include + + +void TriggerHBA( void* IOBaseUpper, int Print) +{ + __u32 long value; + + // get initial value in hopes of not modifying any other GPIO line + IOBaseUpper += 0x188; // TachTL/TS Control reg + + value = readl( IOBaseUpper); + // set HIGH to trigger external analyzer (tested on Dolche Finisar 1Gb GTA) + // The Finisar anaylzer triggers on low-to-high TTL transition + value |= 0x01; // set bit 0 + + writel( value, IOBaseUpper); + + if( Print) + printk( " -GPIO0 set- "); +} + diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/cpqfcTSworker.c linux/drivers/scsi/cpqfcTSworker.c --- v2.4.0-test8/linux/drivers/scsi/cpqfcTSworker.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/cpqfcTSworker.c Tue Sep 19 08:01:35 2000 @@ -0,0 +1,6238 @@ +/* Copyright(c) 2000, Compaq Computer Corporation + * Fibre Channel Host Bus Adapter + * 64-bit, 66MHz PCI + * Originally developed and tested on: + * (front): [chip] Tachyon TS HPFC-5166A/1.2 L2C1090 ... + * SP# P225CXCBFIEL6T, Rev XC + * SP# 161290-001, Rev XD + * (back): Board No. 010008-001 A/W Rev X5, FAB REV X5 + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * Written by Don Zimmerman +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define __KERNEL_SYSCALLS__ + +#define SHUTDOWN_SIGS (sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM)) + +#include + +#include +#include +#include + + + +#include "sd.h" +#include "hosts.h" // struct Scsi_Host definition for T handler +#include "cpqfcTSchip.h" +#include "cpqfcTSstructs.h" + +//#define LOGIN_DBG 1 + +// REMARKS: +// Since Tachyon chips may be permitted to wait from 500ms up to 2 sec +// to empty an outgoing frame from its FIFO to the Fibre Channel stream, +// we cannot do everything we need to in the interrupt handler. Specifically, +// every time a link re-init (e.g. LIP) takes place, all SCSI I/O has to be +// suspended until the login sequences have been completed. Login commands +// are frames just like SCSI commands are frames; they are subject to the same +// timeout issues and delays. Also, various specs provide up to 2 seconds for +// devices to log back in (i.e. respond with ACC to a login frame), so I/O to +// that device has to be suspended. +// A serious problem here occurs on highly loaded FC-AL systems. If our FC port +// has a low priority (e.g. high arbitrated loop physical address, alpa), and +// some other device is hogging bandwidth (permissible under FC-AL), we might +// time out thinking the link is hung, when it's simply busy. Many such +// considerations complicate the design. Although Tachyon assumes control +// (in silicon) for many link-specific issues, the Linux driver is left with the +// rest, which turns out to be a difficult, time critical chore. + +// These "worker" functions will handle things like FC Logins; all +// processes with I/O to our device must wait for the Login to complete +// and (if successful) I/O to resume. In the event of a malfunctioning or +// very busy loop, it may take hundreds of millisecs or even seconds to complete +// a frame send. We don't want to hang up the entire server (and all +// processes which don't depend on Fibre) during this wait. + +// The Tachyon chip can have around 30,000 I/O operations ("exchanges") +// open at one time. However, each exchange must be initiated +// synchronously (i.e. each of the 30k I/O had to be started one at a +// time by sending a starting frame via Tachyon's outbound que). + +// To accomodate kernel "module" build, this driver limits the exchanges +// to 256, because of the contiguous physical memory limitation of 128M. + +// Typical FC Exchanges are opened presuming the FC frames start without errors, +// while Exchange completion is handled in the interrupt handler. This +// optimizes performance for the "everything's working" case. +// However, when we have FC related errors or hot plugging of FC ports, we pause +// I/O and handle FC-specific tasks in the worker thread. These FC-specific +// functions will handle things like FC Logins and Aborts. As the Login sequence +// completes to each and every target, I/O can resume to that target. + +// Our kernel "worker thread" must share the HBA with threads calling +// "queuecommand". We define a "BoardLock" semaphore which indicates +// to "queuecommand" that the HBA is unavailable, and Cmnds are added to a +// board lock Q. When the worker thread finishes with the board, the board +// lock Q commands are completed with status causing immediate retry. +// Typically, the board is locked while Logins are in progress after an +// FC Link Down condition. When Cmnds are re-queued after board lock, the +// particular Scsi channel/target may or may not have logged back in. When +// the device is waiting for login, the "prli" flag is clear, in which case +// commands are passed to a Link Down Q. Whenever the login finally completes, +// the LinkDown Q is completed, again with status causing immediate retry. +// When FC devices are logged in, we build and start FC commands to the +// devices. + +// NOTE!! As of May 2000, kernel 2.2.14, the error recovery logic for devices +// that never log back in (e.g. physically removed) is NOT completely +// understood. I've still seen instances of system hangs on failed Write +// commands (possibly from the ext2 layer?) on device removal. Such special +// cases need to be evaluated from a system/application view - e.g., how +// exactly does the system want me to complete commands when the device is +// physically removed?? + +// local functions + +static void SetLoginFields( + PFC_LOGGEDIN_PORT pLoggedInPort, + TachFCHDR_GCMND* fchs, + BOOLEAN PDisc, + BOOLEAN Originator); + +static void AnalyzeIncomingFrame( + CPQFCHBA *cpqfcHBAdata, + ULONG QNdx ); + +static void SendLogins( CPQFCHBA *cpqfcHBAdata, __u32 *FabricPortIds ); + +static int verify_PLOGI( PTACHYON fcChip, + TachFCHDR_GCMND* fchs, ULONG* reject_explain); +static int verify_PRLI( TachFCHDR_GCMND* fchs, ULONG* reject_explain); + +static void LoadWWN( PTACHYON fcChip, UCHAR* dest, UCHAR type); +static void BuildLinkServicePayload( + PTACHYON fcChip, ULONG type, void* payload); + +static void UnblockScsiDevice( struct Scsi_Host *HostAdapter, + PFC_LOGGEDIN_PORT pLoggedInPort); + +static void cpqfcTSCheckandSnoopFCP( PTACHYON fcChip, ULONG x_ID); + +static void CompleteBoardLockCmnd( CPQFCHBA *cpqfcHBAdata); + +static void RevalidateSEST( struct Scsi_Host *HostAdapter, + PFC_LOGGEDIN_PORT pLoggedInPort); + +static void IssueReportLunsCommand( + CPQFCHBA* cpqfcHBAdata, + TachFCHDR_GCMND* fchs); + + +// (see scsi_error.c comments on kernel task creation) + +void cpqfcTSWorkerThread( void *host) +{ + struct Scsi_Host *HostAdapter = (struct Scsi_Host*)host; + CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata; +#ifdef PCI_KERNEL_TRACE + PTACHYON fcChip = &cpqfcHBAdata->fcChip; +#endif + struct fs_struct *fs; + DECLARE_MUTEX_LOCKED(fcQueReady); + DECLARE_MUTEX_LOCKED(fcTYOBcomplete); + DECLARE_MUTEX_LOCKED(TachFrozen); + DECLARE_MUTEX_LOCKED(BoardLock); + + ENTER("WorkerThread"); + + lock_kernel(); + /* + * 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); + + current->session = 1; + current->pgrp = 1; + + /* Become as one with the init task */ + + exit_fs(current); /* current->fs->count--; */ + fs = init_task.fs; + // Some kernels compiled for SMP, while actually running + // on a uniproc machine, will return NULL for this call + if( !fs) + { + printk(" cpqfcTS FATAL: fs is NULL! Is this an SMP kernel on uniproc machine?\n "); + } + + else + { + current->fs = fs; + atomic_inc(&fs->count); + } + + siginitsetinv(¤t->blocked, SHUTDOWN_SIGS); + + + /* + * Set the name of this process. + */ + sprintf(current->comm, "cpqfcTS_wt_%d", HostAdapter->host_no); + + cpqfcHBAdata->fcQueReady = &fcQueReady; // primary wait point + cpqfcHBAdata->TYOBcomplete = &fcTYOBcomplete; + cpqfcHBAdata->TachFrozen = &TachFrozen; + + + cpqfcHBAdata->worker_thread = current; + + unlock_kernel(); + + if( cpqfcHBAdata->notify_wt != NULL ) + up( cpqfcHBAdata->notify_wt); // OK to continue + + while(1) + { + unsigned long flags; + + down_interruptible( &fcQueReady); // wait for something to do + + if (signal_pending(current) ) + break; + + PCI_TRACE( 0x90) + // first, take the IO lock so the SCSI upper layers can't call + // into our _quecommand function (this also disables INTs) + spin_lock_irqsave( &io_request_lock, flags); // STOP _que function + PCI_TRACE( 0x90) + + CPQ_SPINLOCK_HBA( cpqfcHBAdata) + // next, set this pointer to indicate to the _quecommand function + // that the board is in use, so it should que the command and + // immediately return (we don't actually require the semaphore function + // in this driver rev) + + cpqfcHBAdata->BoardLock = &BoardLock; + + PCI_TRACE( 0x90) + + // release the IO lock (and re-enable interrupts) + spin_unlock_irqrestore( &io_request_lock, flags); + + // disable OUR HBA interrupt (keep them off as much as possible + // during error recovery) + disable_irq( cpqfcHBAdata->HostAdapter->irq); + + // OK, let's process the Fibre Channel Link Q and do the work + cpqfcTS_WorkTask( HostAdapter); + + // hopefully, no more "work" to do; + // re-enable our INTs for "normal" completion processing + enable_irq( cpqfcHBAdata->HostAdapter->irq); + + + cpqfcHBAdata->BoardLock = NULL; // allow commands to be queued + CPQ_SPINUNLOCK_HBA( cpqfcHBAdata) + + + // Now, complete any Cmnd we Q'd up while BoardLock was held + + CompleteBoardLockCmnd( cpqfcHBAdata); + + + } + // hopefully, the signal was for our module exit... + if( cpqfcHBAdata->notify_wt != NULL ) + up( cpqfcHBAdata->notify_wt); // yep, we're outta here +} + + +// Freeze Tachyon routine. +// If Tachyon is already frozen, return FALSE +// If Tachyon is not frozen, call freeze function, return TRUE +// +static BOOLEAN FreezeTach( CPQFCHBA *cpqfcHBAdata) +{ + PTACHYON fcChip = &cpqfcHBAdata->fcChip; + BOOLEAN FrozeTach = FALSE; + // It's possible that the chip is already frozen; if so, + // "Freezing" again will NOT! generate another Freeze + // Completion Message. + + if( (fcChip->Registers.TYstatus.value & 0x70000) != 0x70000) + { // (need to freeze...) + fcChip->FreezeTachyon( fcChip, 2); // both ERQ and FCP assists + + // 2. Get Tach freeze confirmation + // (synchronize SEST manipulation with Freeze Completion Message) + // we need INTs on so semaphore can be set. + enable_irq( cpqfcHBAdata->HostAdapter->irq); // only way to get Semaphore + down_interruptible( cpqfcHBAdata->TachFrozen); // wait for INT handler sem. + // can we TIMEOUT semaphore wait?? TBD + disable_irq( cpqfcHBAdata->HostAdapter->irq); + + FrozeTach = TRUE; + } // (else, already frozen) + + return FrozeTach; +} + + + + +// This is the kernel worker thread task, which processes FC +// tasks which were queued by the Interrupt handler or by +// other WorkTask functions. + +#define DBG 1 +//#undef DBG +void cpqfcTS_WorkTask( struct Scsi_Host *HostAdapter) +{ + CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata; + PTACHYON fcChip = &cpqfcHBAdata->fcChip; + FC_EXCHANGES *Exchanges = fcChip->Exchanges; + ULONG QconsumerNdx; + LONG ExchangeID; + ULONG ulStatus=0; + TachFCHDR_GCMND fchs; + PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ; + + ENTER("WorkTask"); + + // copy current index to work on + QconsumerNdx = fcLQ->consumer; + + PCI_TRACEO( fcLQ->Qitem[QconsumerNdx].Type, 0x90) + + + // NOTE: when this switch completes, we will "consume" the Que item +// printk("Que type %Xh\n", fcLQ->Qitem[QconsumerNdx].Type); + switch( fcLQ->Qitem[QconsumerNdx].Type ) + { + // incoming frame - link service (ACC, UNSOL REQ, etc.) + // or FCP-SCSI command + case SFQ_UNKNOWN: + AnalyzeIncomingFrame( cpqfcHBAdata, QconsumerNdx ); + + break; + + + + case EXCHANGE_QUEUED: // an Exchange (i.e. FCP-SCSI) was previously + // Queued because the link was down. The + // heartbeat timer detected it and Queued it here. + // We attempt to start it again, and if + // successful we clear the EXCHANGE_Q flag. + // If the link doesn't come up, the Exchange + // will eventually time-out. + + ExchangeID = (LONG) // x_ID copied from DPC timeout function + fcLQ->Qitem[QconsumerNdx].ulBuff[0]; + + // It's possible that a Q'd exchange could have already + // been started by other logic (e.g. ABTS process) + // Don't start if already started (Q'd flag clear) + + if( Exchanges->fcExchange[ExchangeID].status & EXCHANGE_QUEUED ) + { +// printk(" *Start Q'd x_ID %Xh: type %Xh ", +// ExchangeID, Exchanges->fcExchange[ExchangeID].type); + + ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID); + if( !ulStatus ) + { +// printk("success* "); + } + else + { +#ifdef DBG + + if( ulStatus == EXCHANGE_QUEUED) + printk("Queued* "); + else + printk("failed* "); + +#endif + } + } + break; + + + case LINKDOWN: + // (lots of things already done in INT handler) future here? + break; + + + case LINKACTIVE: // Tachyon set the Lup bit in FM status + // NOTE: some misbehaving FC ports (like Tach2.1) + // can re-LIP immediately after a LIP completes. + + // if "initiator", need to verify LOGs with ports +// printk("\n*LNKUP* "); + + if( fcChip->Options.initiator ) + SendLogins( cpqfcHBAdata, NULL ); // PLOGI or PDISC, based on fcPort data + // if SendLogins successfully completes, PortDiscDone + // will be set. + + + // If SendLogins was successful, then we expect to get incoming + // ACCepts or REJECTs, which are handled below. + + break; + + // LinkService and Fabric request/reply processing + case ELS_FDISC: // need to send Fabric Discovery (Login) + case ELS_FLOGI: // need to send Fabric Login + case ELS_SCR: // need to send State Change Registration + case FCS_NSR: // need to send Name Service Request + case ELS_PLOGI: // need to send PLOGI + case ELS_ACC: // send generic ACCept + case ELS_PLOGI_ACC: // need to send ELS ACCept frame to recv'd PLOGI + case ELS_PRLI_ACC: // need to send ELS ACCept frame to recv'd PRLI + case ELS_LOGO: // need to send ELS LOGO (logout) + case ELS_LOGO_ACC: // need to send ELS ACCept frame to recv'd PLOGI + case ELS_RJT: // ReJecT reply + case ELS_PRLI: // need to send ELS PRLI + + +// printk(" *ELS %Xh* ", fcLQ->Qitem[QconsumerNdx].Type); + // if PortDiscDone is not set, it means the SendLogins routine + // failed to complete -- assume that LDn occured, so login frames + // are invalid + if( !cpqfcHBAdata->PortDiscDone) // cleared by LDn + { + printk("Discard Q'd ELS login frame\n"); + break; + } + + ulStatus = cpqfcTSBuildExchange( + cpqfcHBAdata, + fcLQ->Qitem[QconsumerNdx].Type, // e.g. PLOGI + (TachFCHDR_GCMND*) + fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs + NULL, // no data (no scatter/gather list) + &ExchangeID );// fcController->fcExchanges index, -1 if failed + + if( !ulStatus ) // Exchange setup? + { + ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID ); + if( !ulStatus ) + { + // submitted to Tach's Outbound Que (ERQ PI incremented) + // waited for completion for ELS type (Login frames issued + // synchronously) + } + else + // check reason for Exchange not being started - we might + // want to Queue and start later, or fail with error + { + + } + } + + else // Xchange setup failed... + printk(" cpqfcTSBuildExchange failed: %Xh\n", ulStatus ); + + break; + + case SCSI_REPORT_LUNS: + // pass the incoming frame (actually, it's a PRLI frame) + // so we can send REPORT_LUNS, in order to determine VSA/PDU + // FCP-SCSI Lun address mode + IssueReportLunsCommand( cpqfcHBAdata, (TachFCHDR_GCMND*) + fcLQ->Qitem[QconsumerNdx].ulBuff); + + break; + + + + + case BLS_ABTS: // need to ABORT one or more exchanges + { + LONG x_ID = fcLQ->Qitem[QconsumerNdx].ulBuff[0]; + BOOLEAN FrozeTach = FALSE; + + if( x_ID > TACH_SEST_LEN ) // (in)sanity check + { +// printk( " cpqfcTS ERROR! BOGUS x_ID %Xh", x_ID); + break; + } + + + if( Exchanges->fcExchange[ x_ID].Cmnd == NULL ) // should be RARE + { +// printk(" ABTS %Xh Scsi Cmnd null! ", x_ID); + + break; // nothing to abort! + } + +//#define ABTS_DBG +#ifdef ABTS_DBG + printk("INV SEST[%X] ", x_ID); + if( Exchanges->fcExchange[x_ID].status & FC2_TIMEOUT) + { + printk("FC2TO"); + } + if( Exchanges->fcExchange[x_ID].status & INITIATOR_ABORT) + { + printk("IA"); + } + if( Exchanges->fcExchange[x_ID].status & PORTID_CHANGED) + { + printk("PORTID"); + } + if( Exchanges->fcExchange[x_ID].status & DEVICE_REMOVED) + { + printk("DEVRM"); + } + if( Exchanges->fcExchange[x_ID].status & LINKFAIL_TX) + { + printk("LKF"); + } + if( Exchanges->fcExchange[x_ID].status & FRAME_TO) + { + printk("FRMTO"); + } + if( Exchanges->fcExchange[x_ID].status & ABORTSEQ_NOTIFY) + { + printk("ABSQ"); + } + if( Exchanges->fcExchange[x_ID].status & SFQ_FRAME) + { + printk("SFQFR"); + } + + if( Exchanges->fcExchange[ x_ID].type == 0x2000) + printk(" WR"); + else if( Exchanges->fcExchange[ x_ID].type == 0x3000) + printk(" RD"); + else if( Exchanges->fcExchange[ x_ID].type == 0x10) + printk(" ABTS"); + else + printk(" %Xh", Exchanges->fcExchange[ x_ID].type); + + if( !(Exchanges->fcExchange[x_ID].status & INITIATOR_ABORT)) + { + printk(" Cmd %p, ", + Exchanges->fcExchange[ x_ID].Cmnd); + + printk(" brd/chn/trg/lun %d/%d/%d/%d port_id %06X\n", + cpqfcHBAdata->HBAnum, + Exchanges->fcExchange[ x_ID].Cmnd->channel, + Exchanges->fcExchange[ x_ID].Cmnd->target, + Exchanges->fcExchange[ x_ID].Cmnd->lun, + Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF); + } + else // assume that Cmnd ptr is invalid on _abort() + { + printk(" Cmd ptr invalid\n"); + } + +#endif + + + // Steps to ABORT a SEST exchange: + // 1. Freeze TL SCSI assists & ERQ (everything) + // 2. Receive FROZEN inbound CM (must succeed!) + // 3. Invalidate x_ID SEST entry + // 4. Resume TL SCSI assists & ERQ (everything) + // 5. Build/start on exchange - change "type" to BLS_ABTS, + // timeout to X sec (RA_TOV from PLDA is actually 0) + // 6. Set Exchange Q'd status if ABTS cannot be started, + // or simply complete Exchange in "Terminate" condition + + PCI_TRACEO( x_ID, 0xB4) + + // 1 & 2 . Freeze Tach & get confirmation of freeze + FrozeTach = FreezeTach( cpqfcHBAdata); + + // 3. OK, Tachyon is frozen, so we can invalidate SEST exchange. + // FC2_TIMEOUT means we are originating the abort, while + // TARGET_ABORT means we are ACCepting an abort. + // LINKFAIL_TX, ABORTSEQ_NOFITY, INV_ENTRY or FRAME_TO are + // all from Tachyon: + // Exchange was corrupted by LDn or other FC physical failure + // INITIATOR_ABORT means the upper layer driver/application + // requested the abort. + + + + // clear bit 31 (VALid), to invalidate & take control from TL + fcChip->SEST->u[ x_ID].IWE.Hdr_Len &= 0x7FFFFFFF; + + + // examine and Tach's "Linked List" for IWEs that + // received (nearly) simultaneous transfer ready (XRDY) + // repair linked list if necessary (TBD!) + // (If we ignore the "Linked List", we will time out + // WRITE commands where we received the FCP-SCSI XFRDY + // frame (because Tachyon didn't processes it). Linked List + // management should be done as an optimization. + +// readl( fcChip->Registers.ReMapMemBase+TL_MEM_SEST_LINKED_LIST )); + + + + + // 4. Resume all Tachlite functions (for other open Exchanges) + // as quickly as possible to allow other exchanges to other ports + // to resume. Freezing Tachyon may cause cascading errors, because + // any received SEST frame cannot be processed by the SEST. + // Don't "unfreeze" unless Link is operational + if( FrozeTach ) // did we just freeze it (above)? + fcChip->UnFreezeTachyon( fcChip, 2); // both ERQ and FCP assists + + + PCI_TRACEO( x_ID, 0xB4) + + // Note there is no confirmation that the chip is "unfrozen". Also, + // if the Link is down when unfreeze is called, it has no effect. + // Chip will unfreeze when the Link is back up. + + // 5. Now send out Abort commands if possible + // Some Aborts can't be "sent" (Port_id changed or gone); + // if the device is gone, there is no port_id to send the ABTS to. + + if( !(Exchanges->fcExchange[ x_ID].status & PORTID_CHANGED) + && + !(Exchanges->fcExchange[ x_ID].status & DEVICE_REMOVED) ) + { + Exchanges->fcExchange[ x_ID].type = BLS_ABTS; + fchs.s_id = Exchanges->fcExchange[ x_ID].fchs.d_id; + ulStatus = cpqfcTSBuildExchange( + cpqfcHBAdata, + BLS_ABTS, + &fchs, // (uses only s_id) + NULL, // (no scatter/gather list for ABTS) + &x_ID );// ABTS on this Exchange ID + + if( !ulStatus ) // Exchange setup build OK? + { + + // ABTS may be needed because an Exchange was corrupted + // by a Link disruption. If the Link is UP, we can + // presume that this ABTS can start immediately; otherwise, + // set Que'd status so the Login functions + // can restart it when the FC physical Link is restored + if( ((fcChip->Registers.FMstatus.value &0xF0) &0x80)) // loop init? + { +// printk(" *set Q status x_ID %Xh on LDn* ", x_ID); + Exchanges->fcExchange[ x_ID].status |= EXCHANGE_QUEUED; + } + + else // what FC device (port_id) does the Cmd belong to? + { + PFC_LOGGEDIN_PORT pLoggedInPort = + Exchanges->fcExchange[ x_ID].pLoggedInPort; + + // if Port is logged in, we might start the abort. + + if( (pLoggedInPort != NULL) + && + (pLoggedInPort->prli == TRUE) ) + { + // it's possible that an Exchange has already been Queued + // to start after Login completes. Check and don't + // start it (again) here if Q'd status set +// printk(" ABTS xchg %Xh ", x_ID); + if( Exchanges->fcExchange[x_ID].status & EXCHANGE_QUEUED) + { +// printk("already Q'd "); + } + else + { +// printk("starting "); + + fcChip->fcStats.FC2aborted++; + ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, x_ID ); + if( !ulStatus ) + { + // OK + // submitted to Tach's Outbound Que (ERQ PI incremented) + } + else + { +/* printk("ABTS exchange start failed -status %Xh, x_ID %Xh ", + ulStatus, x_ID); +*/ + } + } + } + else + { +/* printk(" ABTS NOT starting xchg %Xh, %p ", + x_ID, pLoggedInPort); + if( pLoggedInPort ) + printk("prli %d ", pLoggedInPort->prli); +*/ + } + } + } + else // what the #@! + { // how do we fail to build an Exchange for ABTS?? + printk("ABTS exchange build failed -status %Xh, x_ID %Xh\n", + ulStatus, x_ID); + } + } + else // abort without ABTS -- just complete exchange/Cmnd to Linux + { +// printk(" *Terminating x_ID %Xh on %Xh* ", +// x_ID, Exchanges->fcExchange[x_ID].status); + cpqfcTSCompleteExchange( fcChip, x_ID); + + + } + } // end of ABTS case + break; + + + + case BLS_ABTS_ACC: // need to ACCept one ABTS + // (NOTE! this code not updated for Linux yet..) + + + printk(" *ABTS_ACC* "); + // 1. Freeze TL + + fcChip->FreezeTachyon( fcChip, 2); // both ERQ and FCP assists + + memcpy( // copy the incoming ABTS frame + &fchs, + fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs + sizeof( fchs)); + + // 3. OK, Tachyon is frozen so we can invalidate SEST entry + // (if necessary) + // Status FC2_TIMEOUT means we are originating the abort, while + // TARGET_ABORT means we are ACCepting an abort + + ExchangeID = fchs.ox_rx_id & 0x7FFF; // RX_ID for exchange +// printk("ABTS ACC for Target ExchangeID %Xh\n", ExchangeID); + + + // sanity check on received ExchangeID + if( Exchanges->fcExchange[ ExchangeID].status == TARGET_ABORT ) + { + // clear bit 31 (VALid), to invalidate & take control from TL +// printk("Invalidating SEST exchange %Xh\n", ExchangeID); + fcChip->SEST->u[ ExchangeID].IWE.Hdr_Len &= 0x7FFFFFFF; + } + + + // 4. Resume all Tachlite functions (for other open Exchanges) + // as quickly as possible to allow other exchanges to other ports + // to resume. Freezing Tachyon for too long may royally screw + // up everything! + fcChip->UnFreezeTachyon( fcChip, 2); // both ERQ and FCP assists + + // Note there is no confirmation that the chip is "unfrozen". Also, + // if the Link is down when unfreeze is called, it has no effect. + // Chip will unfreeze when the Link is back up. + + // 5. Now send out Abort ACC reply for this exchange + Exchanges->fcExchange[ ExchangeID].type = BLS_ABTS_ACC; + + fchs.s_id = Exchanges->fcExchange[ ExchangeID].fchs.d_id; + ulStatus = cpqfcTSBuildExchange( + cpqfcHBAdata, + BLS_ABTS_ACC, + &fchs, + NULL, // no data (no scatter/gather list) + &ExchangeID );// fcController->fcExchanges index, -1 if failed + + if( !ulStatus ) // Exchange setup? + { + ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID ); + if( !ulStatus ) + { + // submitted to Tach's Outbound Que (ERQ PI incremented) + // waited for completion for ELS type (Login frames issued + // synchronously) + } + else + // check reason for Exchange not being started - we might + // want to Queue and start later, or fail with error + { + + } + } + break; + + + case BLS_ABTS_RJT: // need to ReJecT one ABTS; reject implies the + // exchange doesn't exist in the TARGET context. + // ExchangeID has to come from LinkService space. + + printk(" *ABTS_RJT* "); + ulStatus = cpqfcTSBuildExchange( + cpqfcHBAdata, + BLS_ABTS_RJT, + (TachFCHDR_GCMND*) + fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs + NULL, // no data (no scatter/gather list) + &ExchangeID );// fcController->fcExchanges index, -1 if failed + + if( !ulStatus ) // Exchange setup OK? + { + ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID ); + // If it fails, we aren't required to retry. + } + if( ulStatus ) + { + printk("Failed to send BLS_RJT for ABTS, X_ID %Xh\n", ExchangeID); + } + else + { + printk("Sent BLS_RJT for ABTS, X_ID %Xh\n", ExchangeID); + + } + + break; + + + + default: + break; + } // end switch +//doNothing: + // done with this item - now set the NEXT index + + if( QconsumerNdx+1 >= FC_LINKQ_DEPTH ) // rollover test + { + fcLQ->consumer = 0; + } + else + { + fcLQ->consumer++; + } + + PCI_TRACEO( fcLQ->Qitem[QconsumerNdx].Type, 0x94) + + LEAVE("WorkTask"); + return; +} + + + + +// When Tachyon reports link down, bad al_pa, or Link Service (e.g. Login) +// commands come in, post to the LinkQ so that action can be taken outside the +// interrupt handler. +// This circular Q works like Tachyon's que - the producer points to the next +// (unused) entry. Called by Interrupt handler, WorkerThread, Timer +// sputlinkq +void cpqfcTSPutLinkQue( CPQFCHBA *cpqfcHBAdata, + int Type, + void *QueContent) +{ + PTACHYON fcChip = &cpqfcHBAdata->fcChip; +// FC_EXCHANGES *Exchanges = fcChip->Exchanges; + PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ; + ULONG ndx; + + ENTER("cpqfcTSPutLinkQ"); + + ndx = fcLQ->producer; + + ndx += 1; // test for Que full + + + + if( ndx >= FC_LINKQ_DEPTH ) // rollover test + ndx = 0; + + if( ndx == fcLQ->consumer ) // QUE full test + { + // QUE was full! lost LK command (fatal to logic) + fcChip->fcStats.lnkQueFull++; + + printk("*LinkQ Full!*"); + TriggerHBA( fcChip->Registers.ReMapMemBase, 1); +/* + { + int i; + printk("LinkQ PI %d, CI %d\n", fcLQ->producer, + fcLQ->consumer); + + for( i=0; i< FC_LINKQ_DEPTH; ) + { + printk(" [%d]%Xh ", i, fcLQ->Qitem[i].Type); + if( (++i %8) == 0) printk("\n"); + } + + } +*/ + printk( "cpqfcTS: WARNING!! PutLinkQue - FULL!\n"); // we're hung + } + else // QUE next element + { + // Prevent certain multiple (back-to-back) requests. + // This is important in that we don't want to issue multiple + // ABTS for the same Exchange, or do multiple FM inits, etc. + // We can never be sure of the timing of events reported to + // us by Tach's IMQ, which can depend on system/bus speeds, + // FC physical link circumstances, etc. + + if( (fcLQ->producer != fcLQ->consumer) + && + (Type == FMINIT) ) + { + LONG lastNdx; // compute previous producer index + if( fcLQ->producer) + lastNdx = fcLQ->producer- 1; + else + lastNdx = FC_LINKQ_DEPTH-1; + + + if( fcLQ->Qitem[lastNdx].Type == FMINIT) + { +// printk(" *skip FMINIT Q post* "); +// goto DoneWithPutQ; + } + + } + + // OK, add the Q'd item... + + fcLQ->Qitem[fcLQ->producer].Type = Type; + + memcpy( + fcLQ->Qitem[fcLQ->producer].ulBuff, + QueContent, + sizeof(fcLQ->Qitem[fcLQ->producer].ulBuff)); + + fcLQ->producer = ndx; // increment Que producer + + // set semaphore to wake up Kernel (worker) thread + // + up( cpqfcHBAdata->fcQueReady ); + } + +//DoneWithPutQ: + + LEAVE("cpqfcTSPutLinkQ"); +} + + + + +// reset device ext FC link Q +void cpqfcTSLinkQReset( CPQFCHBA *cpqfcHBAdata) + +{ + PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ; + fcLQ->producer = 0; + fcLQ->consumer = 0; + +} + + + + + +// When Tachyon gets an unassisted FCP-SCSI frame, post here so +// an arbitrary context thread (e.g. IOCTL loopback test function) +// can process it. + +// (NOTE: Not revised for Linux) +// This Q works like Tachyon's que - the producer points to the next +// (unused) entry. +void cpqfcTSPutScsiQue( CPQFCHBA *cpqfcHBAdata, + int Type, + void *QueContent) +{ +// CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata; +// PTACHYON fcChip = &cpqfcHBAdata->fcChip; + +// ULONG ndx; + +// ULONG *pExchangeID; +// LONG ExchangeID; + +/* + KeAcquireSpinLockAtDpcLevel( &pDevExt->fcScsiQueLock); + ndx = pDevExt->fcScsiQue.producer + 1; // test for Que full + + if( ndx >= FC_SCSIQ_DEPTH ) // rollover test + ndx = 0; + + if( ndx == pDevExt->fcScsiQue.consumer ) // QUE full test + { + // QUE was full! lost LK command (fatal to logic) + fcChip->fcStats.ScsiQueFull++; +#ifdef DBG + printk( "fcPutScsiQue - FULL!\n"); +#endif + + } + else // QUE next element + { + pDevExt->fcScsiQue.Qitem[pDevExt->fcScsiQue.producer].Type = Type; + + if( Type == FCP_RSP ) + { + // this TL inbound message type means that a TL SEST exchange has + // copied an FCP response frame into a buffer pointed to by the SEST + // entry. That buffer is allocated in the SEST structure at ->RspHDR. + // Copy the RspHDR for use by the Que handler. + pExchangeID = (ULONG *)QueContent; + + memcpy( + pDevExt->fcScsiQue.Qitem[pDevExt->fcScsiQue.producer].ulBuff, + &fcChip->SEST->RspHDR[ *pExchangeID ], + sizeof(pDevExt->fcScsiQue.Qitem[0].ulBuff)); // (any element for size) + + } + else + { + memcpy( + pDevExt->fcScsiQue.Qitem[pDevExt->fcScsiQue.producer].ulBuff, + QueContent, + sizeof(pDevExt->fcScsiQue.Qitem[pDevExt->fcScsiQue.producer].ulBuff)); + } + + pDevExt->fcScsiQue.producer = ndx; // increment Que + + + KeSetEvent( &pDevExt->TYIBscsi, // signal any waiting thread + 0, // no priority boost + FALSE ); // no waiting later for this event + } + KeReleaseSpinLockFromDpcLevel( &pDevExt->fcScsiQueLock); +*/ +} + + + + + + + +static void ProcessELS_Request( CPQFCHBA*,TachFCHDR_GCMND*); + +static void ProcessELS_Reply( CPQFCHBA*,TachFCHDR_GCMND*); + +static void ProcessFCS_Reply( CPQFCHBA*,TachFCHDR_GCMND*); + +void cpqfcTSImplicitLogout( CPQFCHBA* cpqfcHBAdata, + PFC_LOGGEDIN_PORT pFcPort) +{ + PTACHYON fcChip = &cpqfcHBAdata->fcChip; + + if( pFcPort->port_id != 0xFFFC01 ) // don't care about Fabric + { + fcChip->fcStats.logouts++; + printk("cpqfcTS: Implicit logout of WWN %08X%08X, port_id %06X\n", + (ULONG)pFcPort->u.liWWN, + (ULONG)(pFcPort->u.liWWN >>32), + pFcPort->port_id); + + // Terminate I/O with this (Linux) Scsi target + cpqfcTSTerminateExchange( cpqfcHBAdata, + &pFcPort->ScsiNexus, + DEVICE_REMOVED); + } + + // Do an "implicit logout" - we can't really Logout the device + // (i.e. with LOGOut Request) because of port_id confusion + // (i.e. the Other port has no port_id). + // A new login for that WWN will have to re-write port_id (0 invalid) + pFcPort->port_id = 0; // invalid! + pFcPort->pdisc = FALSE; + pFcPort->prli = FALSE; + pFcPort->plogi = FALSE; + pFcPort->flogi = FALSE; + pFcPort->LOGO_timer = 0; + pFcPort->device_blocked = TRUE; // block Scsi Requests +} + + +// On FC-AL, there is a chance that a previously known device can +// be quietly removed (e.g. with non-managed hub), +// while a NEW device (with different WWN) took the same alpa or +// even 24-bit port_id. This chance is unlikely but we must always +// check for it. +static void TestDuplicatePortId( CPQFCHBA* cpqfcHBAdata, + PFC_LOGGEDIN_PORT pLoggedInPort) +{ + PTACHYON fcChip = &cpqfcHBAdata->fcChip; + // set "other port" at beginning of fcPorts list + PFC_LOGGEDIN_PORT pOtherPortWithPortId = fcChip->fcPorts.pNextPort; + while( pOtherPortWithPortId ) + { + if( (pOtherPortWithPortId->port_id == + pLoggedInPort->port_id) + && + (pOtherPortWithPortId != pLoggedInPort) ) + { + // trouble! (Implicitly) Log the other guy out + printk(" *port_id %Xh is duplicated!* ", + pOtherPortWithPortId->port_id); + cpqfcTSImplicitLogout( cpqfcHBAdata, pOtherPortWithPortId); + } + pOtherPortWithPortId = pOtherPortWithPortId->pNextPort; + } +} + + + + + + +// Dynamic Memory Allocation for newly discovered FC Ports. +// For simplicity, maintain fcPorts structs for ALL +// for discovered devices, including those we never do I/O with +// (e.g. Fabric addresses) + +static PFC_LOGGEDIN_PORT CreateFcPort( + CPQFCHBA* cpqfcHBAdata, + PFC_LOGGEDIN_PORT pLastLoggedInPort, + TachFCHDR_GCMND* fchs, + LOGIN_PAYLOAD* plogi) +{ + PTACHYON fcChip = &cpqfcHBAdata->fcChip; + PFC_LOGGEDIN_PORT pNextLoggedInPort = NULL; + int i; + + + printk("cpqfcTS: New FC port %06Xh WWN: ", fchs->s_id); + for( i=3; i>=0; i--) // copy the LOGIN port's WWN + printk("%02X", plogi->port_name[i]); + for( i=7; i>3; i--) // copy the LOGIN port's WWN + printk("%02X", plogi->port_name[i]); + + + // allocate mem for new port + // (these are small and rare allocations...) + pNextLoggedInPort = kmalloc( sizeof( FC_LOGGEDIN_PORT), GFP_ATOMIC ); + + + // allocation succeeded? Fill out NEW PORT + if( pNextLoggedInPort ) + { + // clear out any garbage (sometimes exists) + memset( pNextLoggedInPort, 0, sizeof( FC_LOGGEDIN_PORT)); + + + // If we login to a Fabric, we don't want to treat it + // as a SCSI device... + if( (fchs->s_id & 0xFFF000) != 0xFFF000) + { + int i; + + // create a unique "virtual" SCSI Nexus (for now, just a + // new target ID) -- we will update channel/target on REPORT_LUNS + // special case for very first SCSI target... + if( cpqfcHBAdata->HostAdapter->max_id == 0) + { + pNextLoggedInPort->ScsiNexus.target = 0; + fcChip->fcPorts.ScsiNexus.target = -1; // don't use "stub" + } + else + { + pNextLoggedInPort->ScsiNexus.target = + cpqfcHBAdata->HostAdapter->max_id; + } + + // initialize the lun[] Nexus struct for lun masking + for( i=0; i< CPQFCTS_MAX_LUN; i++) + pNextLoggedInPort->ScsiNexus.lun[i] = 0xFF; // init to NOT USED + + pNextLoggedInPort->ScsiNexus.channel = 0; // cpqfcTS has 1 FC port + + printk(" SCSI Chan/Trgt %d/%d", + pNextLoggedInPort->ScsiNexus.channel, + pNextLoggedInPort->ScsiNexus.target); + + // tell Scsi layers about the new target... + cpqfcHBAdata->HostAdapter->max_id++; +// printk("HostAdapter->max_id = %d\n", +// cpqfcHBAdata->HostAdapter->max_id); + } + else + { + // device is NOT SCSI (in case of Fabric) + pNextLoggedInPort->ScsiNexus.target = -1; // invalid + } + + // create forward link to new port + pLastLoggedInPort->pNextPort = pNextLoggedInPort; + printk("\n"); + + } + return pNextLoggedInPort; // NULL on allocation failure +} // end NEW PORT (WWN) logic + + + +// For certain cases, we want to terminate exchanges without +// sending ABTS to the device. Examples include when an FC +// device changed it's port_id after Loop re-init, or when +// the device sent us a logout. In the case of changed port_id, +// we want to complete the command and return SOFT_ERROR to +// force a re-try. In the case of LOGOut, we might return +// BAD_TARGET if the device is really gone. +// Since we must ensure that Tachyon is not operating on the +// exchange, we have to freeze the chip +// sterminateex +void cpqfcTSTerminateExchange( + CPQFCHBA* cpqfcHBAdata, SCSI_NEXUS *ScsiNexus, int TerminateStatus) +{ + PTACHYON fcChip = &cpqfcHBAdata->fcChip; + FC_EXCHANGES *Exchanges = fcChip->Exchanges; + ULONG x_ID; + + if( ScsiNexus ) + { +// printk("TerminateExchange: ScsiNexus chan/target %d/%d\n", +// ScsiNexus->channel, ScsiNexus->target); + + } + + for( x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++) + { + if( Exchanges->fcExchange[x_ID].type ) // in use? + { + if( ScsiNexus == NULL ) // our HBA changed - term. all + { + Exchanges->fcExchange[x_ID].status = TerminateStatus; + cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID ); + } + else + { + // If a device, according to WWN, has been removed, it's + // port_id may be used by another working device, so we + // have to terminate by SCSI target, NOT port_id. + if( Exchanges->fcExchange[x_ID].Cmnd) // Cmnd in progress? + { + if( (Exchanges->fcExchange[x_ID].Cmnd->target == ScsiNexus->target) + && + (Exchanges->fcExchange[x_ID].Cmnd->channel == ScsiNexus->channel)) + { + Exchanges->fcExchange[x_ID].status = TerminateStatus; + cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID ); // timed-out + } + } + + // (in case we ever need it...) + // all SEST structures have a remote node ID at SEST DWORD 2 + // if( (fcChip->SEST->u[ x_ID ].TWE.Remote_Node_ID >> 8) + // == port_id) + } + } + } +} + + +static void ProcessELS_Request( + CPQFCHBA* cpqfcHBAdata, TachFCHDR_GCMND* fchs) +{ + PTACHYON fcChip = &cpqfcHBAdata->fcChip; +// FC_EXCHANGES *Exchanges = fcChip->Exchanges; +// ULONG ox_id = (fchs->ox_rx_id >>16); + PFC_LOGGEDIN_PORT pLoggedInPort=NULL, pLastLoggedInPort; + BOOLEAN NeedReject = FALSE; + ULONG ls_reject_code = 0; // default don'n know?? + + + // Check the incoming frame for a supported ELS type + switch( fchs->pl[0] & 0xFFFF) + { + case 0x0050: // PDISC? + + // Payload for PLOGI and PDISC is identical (request & reply) + if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) ) // valid payload? + { + LOGIN_PAYLOAD logi; // FC-PH Port Login + + // PDISC payload OK. If critical login fields + // (e.g. WWN) matches last login for this port_id, + // we may resume any prior exchanges + // with the other port + + + BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi)); + + pLoggedInPort = fcFindLoggedInPort( + fcChip, + NULL, // don't search Scsi Nexus + 0, // don't search linked list for port_id + &logi.port_name[0], // search linked list for WWN + &pLastLoggedInPort); // must return non-NULL; when a port_id + // is not found, this pointer marks the + // end of the singly linked list + + if( pLoggedInPort != NULL) // WWN found (prior login OK) + { + + if( (fchs->s_id & 0xFFFFFF) == pLoggedInPort->port_id) + { + // Yes. We were expecting PDISC? + if( pLoggedInPort->pdisc ) + { + // Yes; set fields accordingly. (PDISC, not Originator) + SetLoginFields( pLoggedInPort, fchs, TRUE, FALSE); + + // send 'ACC' reply + cpqfcTSPutLinkQue( cpqfcHBAdata, + ELS_PLOGI_ACC, // (PDISC same as PLOGI ACC) + fchs ); + + // OK to resume I/O... + } + else + { + printk("Not expecting PDISC (pdisc=FALSE)\n"); + NeedReject = TRUE; + // set reject reason code + ls_reject_code = + LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR); + } + } + else + { + if( pLoggedInPort->port_id != 0) + { + printk("PDISC PortID change: old %Xh, new %Xh\n", + pLoggedInPort->port_id, fchs->s_id &0xFFFFFF); + } + NeedReject = TRUE; + // set reject reason code + ls_reject_code = + LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR); + + } + } + else + { + printk("PDISC Request from unknown WWN\n"); + NeedReject = TRUE; + + // set reject reason code + ls_reject_code = + LS_RJT_REASON( LOGICAL_ERROR, INVALID_PORT_NAME); + } + + } + else // Payload unacceptable + { + printk("payload unacceptable\n"); + NeedReject = TRUE; // reject code already set + + } + + if( NeedReject) + { + ULONG port_id; + // The PDISC failed. Set login struct flags accordingly, + // terminate any I/O to this port, and Q a PLOGI + if( pLoggedInPort ) + { + pLoggedInPort->pdisc = FALSE; + pLoggedInPort->prli = FALSE; + pLoggedInPort->plogi = FALSE; + + cpqfcTSTerminateExchange( cpqfcHBAdata, + &pLoggedInPort->ScsiNexus, PORTID_CHANGED); + port_id = pLoggedInPort->port_id; + } + else + { + port_id = fchs->s_id &0xFFFFFF; + } + fchs->reserved = ls_reject_code; // borrow this (unused) field + cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_RJT, fchs ); + } + + break; + + + + case 0x0003: // PLOGI? + + // Payload for PLOGI and PDISC is identical (request & reply) + if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) ) // valid payload? + { + LOGIN_PAYLOAD logi; // FC-PH Port Login + BOOLEAN NeedReject = FALSE; + + // PDISC payload OK. If critical login fields + // (e.g. WWN) matches last login for this port_id, + // we may resume any prior exchanges + // with the other port + + + BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi)); + + pLoggedInPort = fcFindLoggedInPort( + fcChip, + NULL, // don't search Scsi Nexus + 0, // don't search linked list for port_id + &logi.port_name[0], // search linked list for WWN + &pLastLoggedInPort); // must return non-NULL; when a port_id + // is not found, this pointer marks the + // end of the singly linked list + + if( pLoggedInPort == NULL) // WWN not found -New Port + { + pLoggedInPort = CreateFcPort( + cpqfcHBAdata, + pLastLoggedInPort, + fchs, + &logi); + if( pLoggedInPort == NULL ) + { + printk(" cpqfcTS: New port allocation failed - lost FC device!\n"); + // Now Q a LOGOut Request, since we won't be talking to that device + + NeedReject = TRUE; + + // set reject reason code + ls_reject_code = + LS_RJT_REASON( LOGICAL_ERROR, NO_LOGIN_RESOURCES); + + } + } + if( !NeedReject ) + { + + // OK - we have valid fcPort ptr; set fields accordingly. + // (not PDISC, not Originator) + SetLoginFields( pLoggedInPort, fchs, FALSE, FALSE); + + // send 'ACC' reply + cpqfcTSPutLinkQue( cpqfcHBAdata, + ELS_PLOGI_ACC, // (PDISC same as PLOGI ACC) + fchs ); + } + } + else // Payload unacceptable + { + printk("payload unacceptable\n"); + NeedReject = TRUE; // reject code already set + } + + if( NeedReject) + { + // The PDISC failed. Set login struct flags accordingly, + // terminate any I/O to this port, and Q a PLOGI + pLoggedInPort->pdisc = FALSE; + pLoggedInPort->prli = FALSE; + pLoggedInPort->plogi = FALSE; + + fchs->reserved = ls_reject_code; // borrow this (unused) field + + // send 'RJT' reply + cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_RJT, fchs ); + } + + // terminate any exchanges with this device... + if( pLoggedInPort ) + { + cpqfcTSTerminateExchange( cpqfcHBAdata, + &pLoggedInPort->ScsiNexus, PORTID_CHANGED); + } + break; + + + + case 0x1020: // PRLI? + { + BOOLEAN NeedReject = TRUE; + pLoggedInPort = fcFindLoggedInPort( + fcChip, + NULL, // don't search Scsi Nexus + (fchs->s_id & 0xFFFFFF), // search linked list for port_id + NULL, // DON'T search linked list for WWN + NULL); // don't care + + if( pLoggedInPort == NULL ) + { + // huh? + printk(" Unexpected PRLI Request -not logged in!\n"); + + // set reject reason code + ls_reject_code = LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR); + + // Q a LOGOut here? + } + else + { + // verify the PRLI ACC payload + if( !verify_PRLI( fchs, &ls_reject_code) ) + { + // PRLI Reply is acceptable; were we expecting it? + if( pLoggedInPort->plogi ) + { + // yes, we expected the PRLI ACC (not PDISC; not Originator) + SetLoginFields( pLoggedInPort, fchs, FALSE, FALSE); + + // Q an ACCept Reply + cpqfcTSPutLinkQue( cpqfcHBAdata, + ELS_PRLI_ACC, + fchs ); + + NeedReject = FALSE; + } + else + { + // huh? + printk(" (unexpected) PRLI REQEST with plogi FALSE\n"); + + // set reject reason code + ls_reject_code = LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR); + + // Q a LOGOut here? + + } + } + else + { + printk(" PRLI REQUEST payload failed verify\n"); + // (reject code set by "verify") + + // Q a LOGOut here? + } + } + + if( NeedReject ) + { + // Q a ReJecT Reply with reason code + fchs->reserved = ls_reject_code; + cpqfcTSPutLinkQue( cpqfcHBAdata, + ELS_RJT, // Q Type + fchs ); + } + } + break; + + + + + case 0x0005: // LOGOut? + { + // was this LOGOUT because we sent a ELS_PDISC to an FC device + // with changed (or new) port_id, or does the port refuse + // to communicate to us? + // We maintain a logout counter - if we get 3 consecutive LOGOuts, + // give up! + LOGOUT_PAYLOAD logo; + BOOLEAN GiveUpOnDevice = FALSE; + ULONG ls_reject_code = 0; + + BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logo, sizeof(logo)); + + pLoggedInPort = fcFindLoggedInPort( + fcChip, + NULL, // don't search Scsi Nexus + 0, // don't search linked list for port_id + &logo.port_name[0], // search linked list for WWN + NULL); // don't care about end of list + + if( pLoggedInPort ) // found the device? + { + // Q an ACC reply + cpqfcTSPutLinkQue( cpqfcHBAdata, + ELS_LOGO_ACC, // Q Type + fchs ); // device to respond to + + // set login struct fields (LOGO_counter increment) + SetLoginFields( pLoggedInPort, fchs, FALSE, FALSE); + + // are we an Initiator? + if( fcChip->Options.initiator) + { + // we're an Initiator, so check if we should + // try (another?) login + + // Fabrics routinely log out from us after + // getting device info - don't try to log them + // back in. + if( (fchs->s_id & 0xFFF000) == 0xFFF000 ) + { + ; // do nothing + } + else if( pLoggedInPort->LOGO_counter <= 3) + { + // try (another) login (PLOGI request) + + cpqfcTSPutLinkQue( cpqfcHBAdata, + ELS_PLOGI, // Q Type + fchs ); + + // Terminate I/O with "retry" potential + cpqfcTSTerminateExchange( cpqfcHBAdata, + &pLoggedInPort->ScsiNexus, + PORTID_CHANGED); + } + else + { + printk(" Got 3 LOGOuts - terminating comm. with port_id %Xh\n", + fchs->s_id &&0xFFFFFF); + GiveUpOnDevice = TRUE; + } + } + else + { + GiveUpOnDevice = TRUE; + } + + + if( GiveUpOnDevice == TRUE ) + { + cpqfcTSTerminateExchange( cpqfcHBAdata, + &pLoggedInPort->ScsiNexus, + DEVICE_REMOVED); + } + } + else // we don't know this WWN! + { + // Q a ReJecT Reply with reason code + fchs->reserved = ls_reject_code; + cpqfcTSPutLinkQue( cpqfcHBAdata, + ELS_RJT, // Q Type + fchs ); + } + } + break; + + + + + // FABRIC only case + case 0x0461: // ELS RSCN (Registered State Change Notification)? + { + int Ports; + int i; + __u32 Buff; + // Typically, one or more devices have been added to or dropped + // from the Fabric. + // The format of this frame is defined in FC-FLA (Rev 2.7, Aug 1997) + // The first 32-bit word has a 2-byte Payload Length, which + // includes the 4 bytes of the first word. Consequently, + // this PL len must never be less than 4, must be a multiple of 4, + // and has a specified max value 256. + // (Endianess!) + Ports = ((fchs->pl[0] >>24) - 4) / 4; + Ports = Ports > 63 ? 63 : Ports; + + printk(" RSCN ports: %d\n", Ports); + if( Ports <= 0 ) // huh? + { + // ReJecT the command + fchs->reserved = LS_RJT_REASON( UNABLE_TO_PERFORM, 0); + + cpqfcTSPutLinkQue( cpqfcHBAdata, + ELS_RJT, // Q Type + fchs ); + + break; + } + else // Accept the command + { + cpqfcTSPutLinkQue( cpqfcHBAdata, + ELS_ACC, // Q Type + fchs ); + } + + // Check the "address format" to determine action. + // We have 3 cases: + // 0 = Port Address; 24-bit address of affected device + // 1 = Area Address; MS 16 bits valid + // 2 = Domain Address; MS 8 bits valid + for( i=0; ipl[i+1],(UCHAR*)&Buff, 4); + switch( Buff & 0xFF000000) + { + + case 0: // Port Address? + + case 0x01000000: // Area Domain? + case 0x02000000: // Domain Address + // For example, "port_id" 0x201300 + // OK, let's try a Name Service Request (Query) + fchs->s_id = 0xFFFFFC; // Name Server Address + cpqfcTSPutLinkQue( cpqfcHBAdata, FCS_NSR, fchs); + + break; + + + default: // huh? new value on version change? + break; + } + } + } + break; + + + + + default: // don't support this request (yet) + // set reject reason code + fchs->reserved = LS_RJT_REASON( UNABLE_TO_PERFORM, + REQUEST_NOT_SUPPORTED); + + cpqfcTSPutLinkQue( cpqfcHBAdata, + ELS_RJT, // Q Type + fchs ); + break; + } +} + + +static void ProcessELS_Reply( + CPQFCHBA* cpqfcHBAdata, TachFCHDR_GCMND* fchs) +{ + PTACHYON fcChip = &cpqfcHBAdata->fcChip; + FC_EXCHANGES *Exchanges = fcChip->Exchanges; + ULONG ox_id = (fchs->ox_rx_id >>16); + ULONG ls_reject_code; + PFC_LOGGEDIN_PORT pLoggedInPort, pLastLoggedInPort; + + // If this is a valid reply, then we MUST have sent a request. + // Verify that we can find a valid request OX_ID corresponding to + // this reply + + + if( Exchanges->fcExchange[(fchs->ox_rx_id >>16)].type == 0) + { + printk(" *Discarding ACC/RJT frame, xID %04X/%04X* ", + ox_id, fchs->ox_rx_id & 0xffff); + goto Quit; // exit this routine + } + + + // Is the reply a RJT (reject)? + if( (fchs->pl[0] & 0xFFFFL) == 0x01) // Reject reply? + { +// ****** REJECT REPLY ******** + switch( Exchanges->fcExchange[ox_id].type ) + { + + case ELS_FDISC: // we sent out Fabric Discovery + case ELS_FLOGI: // we sent out FLOGI + + printk("RJT received on Fabric Login from %Xh, reason %Xh\n", + fchs->s_id, fchs->pl[1]); + + break; + + default: + break; + } + + goto Done; + } + + // OK, we have an ACCept... + // What's the ACC type? (according to what we sent) + switch( Exchanges->fcExchange[ox_id].type ) + { + + case ELS_PLOGI: // we sent out PLOGI + if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) ) + { + LOGIN_PAYLOAD logi; // FC-PH Port Login + + // login ACC payload acceptable; search for WWN in our list + // of fcPorts + + BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi)); + + pLoggedInPort = fcFindLoggedInPort( + fcChip, + NULL, // don't search Scsi Nexus + 0, // don't search linked list for port_id + &logi.port_name[0], // search linked list for WWN + &pLastLoggedInPort); // must return non-NULL; when a port_id + // is not found, this pointer marks the + // end of the singly linked list + + if( pLoggedInPort == NULL) // WWN not found - new port + { + + pLoggedInPort = CreateFcPort( + cpqfcHBAdata, + pLastLoggedInPort, + fchs, + &logi); + + if( pLoggedInPort == NULL ) + { + printk(" cpqfcTS: New port allocation failed - lost FC device!\n"); + // Now Q a LOGOut Request, since we won't be talking to that device + + goto Done; // exit with error! dropped login frame + } + } + else // WWN was already known. Ensure that any open + // exchanges for this WWN are terminated. + // NOTE: It's possible that a device can change its + // 24-bit port_id after a Link init or Fabric change + // (e.g. LIP or Fabric RSCN). In that case, the old + // 24-bit port_id may be duplicated, or no longer exist. + { + + cpqfcTSTerminateExchange( cpqfcHBAdata, + &pLoggedInPort->ScsiNexus, PORTID_CHANGED); + } + + // We have an fcPort struct - set fields accordingly + // not PDISC, originator + SetLoginFields( pLoggedInPort, fchs, FALSE, TRUE); + + // We just set a "port_id"; is it duplicated? + TestDuplicatePortId( cpqfcHBAdata, pLoggedInPort); + + // For Fabric operation, we issued PLOGI to 0xFFFFFC + // so we can send SCR (State Change Registration) + // Check for this special case... + if( fchs->s_id == 0xFFFFFC ) + { + // PLOGI ACC was a Fabric response... issue SCR + fchs->s_id = 0xFFFFFD; // address for SCR + cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_SCR, fchs); + } + + else + { + // Now we need a PRLI to enable FCP-SCSI operation + // set flags and Q up a ELS_PRLI + cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_PRLI, fchs); + } + } + else + { + // login payload unacceptable - reason in ls_reject_code + // Q up a Logout Request + printk("Login Payload unacceptable\n"); + + } + break; + + + // PDISC logic very similar to PLOGI, except we never want + // to allocate mem for "new" port, and we set flags differently + // (might combine later with PLOGI logic for efficiency) + case ELS_PDISC: // we sent out PDISC + if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) ) + { + LOGIN_PAYLOAD logi; // FC-PH Port Login + BOOLEAN NeedLogin = FALSE; + + // login payload acceptable; search for WWN in our list + // of (previously seen) fcPorts + + BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi)); + + pLoggedInPort = fcFindLoggedInPort( + fcChip, + NULL, // don't search Scsi Nexus + 0, // don't search linked list for port_id + &logi.port_name[0], // search linked list for WWN + &pLastLoggedInPort); // must return non-NULL; when a port_id + // is not found, this pointer marks the + // end of the singly linked list + + if( pLoggedInPort != NULL) // WWN found? + { + // WWN has same port_id as last login? (Of course, a properly + // working FC device should NEVER ACCept a PDISC if it's + // port_id changed, but check just in case...) + if( (fchs->s_id & 0xFFFFFF) == pLoggedInPort->port_id) + { + // Yes. We were expecting PDISC? + if( pLoggedInPort->pdisc ) + { + int i; + + + // PDISC expected -- set fields. (PDISC, Originator) + SetLoginFields( pLoggedInPort, fchs, TRUE, TRUE); + + // We are ready to resume FCP-SCSI to this device... + // Do we need to start anything that was Queued? + + for( i=0; i< TACH_SEST_LEN; i++) + { + // see if any exchange for this PDISC'd port was queued + if( ((fchs->s_id &0xFFFFFF) == + (Exchanges->fcExchange[i].fchs.d_id & 0xFFFFFF)) + && + (Exchanges->fcExchange[i].status & EXCHANGE_QUEUED)) + { + fchs->reserved = i; // copy ExchangeID +// printk(" *Q x_ID %Xh after PDISC* ",i); + + cpqfcTSPutLinkQue( cpqfcHBAdata, EXCHANGE_QUEUED, fchs ); + } + } + + // Complete commands Q'd while we were waiting for Login + + UnblockScsiDevice( cpqfcHBAdata->HostAdapter, pLoggedInPort); + } + else + { + printk("Not expecting PDISC (pdisc=FALSE)\n"); + NeedLogin = TRUE; + } + } + else + { + printk("PDISC PortID change: old %Xh, new %Xh\n", + pLoggedInPort->port_id, fchs->s_id &0xFFFFFF); + NeedLogin = TRUE; + + } + } + else + { + printk("PDISC ACC from unknown WWN\n"); + NeedLogin = TRUE; + } + + if( NeedLogin) + { + + // The PDISC failed. Set login struct flags accordingly, + // terminate any I/O to this port, and Q a PLOGI + if( pLoggedInPort ) // FC device previously known? + { + + cpqfcTSPutLinkQue( cpqfcHBAdata, + ELS_LOGO, // Q Type + fchs ); // has port_id to send to + + // There are a variety of error scenarios which can result + // in PDISC failure, so as a catchall, add the check for + // duplicate port_id. + TestDuplicatePortId( cpqfcHBAdata, pLoggedInPort); + +// TriggerHBA( fcChip->Registers.ReMapMemBase, 0); + pLoggedInPort->pdisc = FALSE; + pLoggedInPort->prli = FALSE; + pLoggedInPort->plogi = FALSE; + + cpqfcTSTerminateExchange( cpqfcHBAdata, + &pLoggedInPort->ScsiNexus, PORTID_CHANGED); + } + cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_PLOGI, fchs ); + } + } + else + { + // login payload unacceptable - reason in ls_reject_code + // Q up a Logout Request + printk("ERROR: Login Payload unacceptable!\n"); + + } + + break; + + + + case ELS_PRLI: // we sent out PRLI + + + pLoggedInPort = fcFindLoggedInPort( + fcChip, + NULL, // don't search Scsi Nexus + (fchs->s_id & 0xFFFFFF), // search linked list for port_id + NULL, // DON'T search linked list for WWN + NULL); // don't care + + if( pLoggedInPort == NULL ) + { + // huh? + printk(" Unexpected PRLI ACCept frame!\n"); + + // Q a LOGOut here? + + goto Done; + } + + // verify the PRLI ACC payload + if( !verify_PRLI( fchs, &ls_reject_code) ) + { + // PRLI Reply is acceptable; were we expecting it? + if( pLoggedInPort->plogi ) + { + // yes, we expected the PRLI ACC (not PDISC; Originator) + SetLoginFields( pLoggedInPort, fchs, FALSE, TRUE); + + // OK, let's send a REPORT_LUNS command to determine + // whether VSA or PDA FCP-LUN addressing is used. + + cpqfcTSPutLinkQue( cpqfcHBAdata, SCSI_REPORT_LUNS, fchs ); + + // It's possible that a device we were talking to changed + // port_id, and has logged back in. This function ensures + // that I/O will resume. + UnblockScsiDevice( cpqfcHBAdata->HostAdapter, pLoggedInPort); + + } + else + { + // huh? + printk(" (unexpected) PRLI ACCept with plogi FALSE\n"); + + // Q a LOGOut here? + goto Done; + } + } + else + { + printk(" PRLI ACCept payload failed verify\n"); + + // Q a LOGOut here? + } + + break; + + case ELS_FLOGI: // we sent out FLOGI (Fabric Login) + + // update the upper 16 bits of our port_id in Tachyon + // the switch adds those upper 16 bits when responding + // to us (i.e. we are the destination_id) + fcChip->Registers.my_al_pa = (fchs->d_id & 0xFFFFFF); + writel( fcChip->Registers.my_al_pa, + fcChip->Registers.ReMapMemBase + TL_MEM_TACH_My_ID); + + // now send out a PLOGI to the well known port_id 0xFFFFFC + fchs->s_id = 0xFFFFFC; + cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_PLOGI, fchs); + + break; + + + case ELS_FDISC: // we sent out FDISC (Fabric Discovery (Login)) + + printk( " ELS_FDISC success "); + break; + + + case ELS_SCR: // we sent out State Change Registration + // now we can issue Name Service Request to find any + // Fabric-connected devices we might want to login to. + + + fchs->s_id = 0xFFFFFC; // Name Server Address + cpqfcTSPutLinkQue( cpqfcHBAdata, FCS_NSR, fchs); + + + break; + + + default: + printk(" *Discarding unknown ACC frame, xID %04X/%04X* ", + ox_id, fchs->ox_rx_id & 0xffff); + break; + } + + +Done: + // Regardless of whether the Reply is valid or not, the + // the exchange is done - complete + cpqfcTSCompleteExchange( fcChip, (fchs->ox_rx_id >>16)); // complete + +Quit: + return; +} + + + + + + +// **************** Fibre Channel Services ************** +// This is where we process the Directory (Name) Service Reply +// to know which devices are on the Fabric + +static void ProcessFCS_Reply( + CPQFCHBA* cpqfcHBAdata, TachFCHDR_GCMND* fchs) +{ + PTACHYON fcChip = &cpqfcHBAdata->fcChip; + FC_EXCHANGES *Exchanges = fcChip->Exchanges; + ULONG ox_id = (fchs->ox_rx_id >>16); +// ULONG ls_reject_code; +// PFC_LOGGEDIN_PORT pLoggedInPort, pLastLoggedInPort; + + // If this is a valid reply, then we MUST have sent a request. + // Verify that we can find a valid request OX_ID corresponding to + // this reply + + if( Exchanges->fcExchange[(fchs->ox_rx_id >>16)].type == 0) + { + printk(" *Discarding Reply frame, xID %04X/%04X* ", + ox_id, fchs->ox_rx_id & 0xffff); + goto Quit; // exit this routine + } + + + // OK, we were expecting it. Now check to see if it's a + // "Name Service" Reply, and if so force a re-validation of + // Fabric device logins (i.e. Start the login timeout and + // send PDISC or PLOGI) + // (Endianess Byte Swap?) + if( fchs->pl[1] == 0x02FC ) // Name Service + { + // got a new (or NULL) list of Fabric attach devices... + // Invalidate current logins + + PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts; + while( pLoggedInPort ) // for all ports which are expecting + // PDISC after the next LIP, set the + // logoutTimer + { + + if( (pLoggedInPort->port_id & 0xFFFF00) // Fabric device? + && + (pLoggedInPort->port_id != 0xFFFFFC) ) // NOT the F_Port + { + pLoggedInPort->LOGO_timer = 6; // what's the Fabric timeout?? + // suspend any I/O in progress until + // PDISC received... + pLoggedInPort->prli = FALSE; // block FCP-SCSI commands + } + + pLoggedInPort = pLoggedInPort->pNextPort; + } + + if( fchs->pl[2] == 0x0280) // ACCept? + { + // Send PLOGI or PDISC to these Fabric devices + SendLogins( cpqfcHBAdata, &fchs->pl[4] ); + } + + + // As of this writing, the only reason to reject is because NO + // devices are left on the Fabric. We already started + // "logged out" timers; if the device(s) don't come + // back, we'll do the implicit logout in the heart beat + // timer routine + else // ReJecT + { + // this just means no Fabric device is visible at this instant + } + } + + // Regardless of whether the Reply is valid or not, the + // the exchange is done - complete + cpqfcTSCompleteExchange( fcChip, (fchs->ox_rx_id >>16)); // complete + +Quit: + return; +} + + + + + + + +static void AnalyzeIncomingFrame( + CPQFCHBA *cpqfcHBAdata, + ULONG QNdx ) +{ + PTACHYON fcChip = &cpqfcHBAdata->fcChip; + FC_EXCHANGES *Exchanges = fcChip->Exchanges; + PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ; + TachFCHDR_GCMND* fchs = + (TachFCHDR_GCMND*)fcLQ->Qitem[QNdx].ulBuff; +// ULONG ls_reject_code; // reason for rejecting login + LONG ExchangeID; +// FC_LOGGEDIN_PORT *pLoggedInPort; + BOOLEAN AbortAccept; + + ENTER("AnalyzeIncomingFrame"); + + + + switch( fcLQ->Qitem[QNdx].Type) // FCP or Unknown + { + + case SFQ_UNKNOWN: // unknown frame (e.g. LIP position frame, NOP, etc.) + + + // ********* FC-4 Device Data/ Fibre Channel Service ************* + if( ((fchs->d_id &0xF0000000) == 0) // R_CTL (upper nibble) 0x0? + && + (fchs->f_ctl & 0x20000000) ) // TYPE 20h is Fibre Channel Service + { + + // ************** FCS Reply ********************** + + if( (fchs->d_id & 0xff000000L) == 0x03000000L) // (31:23 R_CTL) + { + ProcessFCS_Reply( cpqfcHBAdata, fchs ); + + } // end of FCS logic + + } + + + // *********** Extended Link Service ************** + + else if( fchs->d_id & 0x20000000 // R_CTL 0x2? + && + (fchs->f_ctl & 0x01000000) ) // TYPE = 1 + { + + // these frames are either a response to + // something we sent (0x23) or "unsolicited" + // frames (0x22). + + + // **************Extended Link REPLY ********************** + // R_CTL Solicited Control Reply + + if( (fchs->d_id & 0xff000000L) == 0x23000000L) // (31:23 R_CTL) + { + + ProcessELS_Reply( cpqfcHBAdata, fchs ); + + } // end of "R_CTL Solicited Control Reply" + + + + + // **************Extended Link REQUEST ********************** + // (unsolicited commands from another port or task...) + + // R_CTL Ext Link REQUEST + else if( (fchs->d_id & 0xff000000L) == 0x22000000L && + (fchs->ox_rx_id != 0xFFFFFFFFL) ) // (ignore LIP frame) + { + + + + ProcessELS_Request( cpqfcHBAdata, fchs ); + + } + + + + // ************** LILP ********************** + else if( (fchs->d_id & 0xff000000L) == 0x22000000L && + (fchs->ox_rx_id == 0xFFFFFFFFL)) // (e.g., LIP frames) + + { + // SANMark specifies that when available, we must use + // the LILP frame to determine which ALPAs to send Port Discovery + // to... + + if( fchs->pl[0] == 0x0711L) // ELS_PLOGI? + { +// UCHAR *ptr = (UCHAR*)&fchs->pl[1]; +// printk(" %d ALPAs found\n", *ptr); + memcpy( fcChip->LILPmap, &fchs->pl[1], 32*4); // 32 DWORDs + fcChip->Options.LILPin = 1; // our LILPmap is valid! + // now post to make Port Discovery happen... + cpqfcTSPutLinkQue( cpqfcHBAdata, LINKACTIVE, fchs); + } + } + } + + + // ***************** BASIC LINK SERVICE ***************** + + else if( fchs->d_id & 0x80000000 // R_CTL: + && // Basic Link Service Request + !(fchs->f_ctl & 0xFF000000) ) // type=0 for BLS + { + + // Check for ABTS (Abort Sequence) + if( (fchs->d_id & 0x8F000000) == 0x81000000) + { + // look for OX_ID, S_ID pair that matches in our + // fcExchanges table; if found, reply with ACCept and complete + // the exchange + + // Per PLDA, an ABTS is sent by an initiator; therefore + // assume that if we have an exhange open to the port who + // sent ABTS, it will be the d_id of what we sent. + for( ExchangeID = 0, AbortAccept=FALSE; + ExchangeID < TACH_SEST_LEN; ExchangeID++) + { + // Valid "target" exchange 24-bit port_id matches? + // NOTE: For the case of handling Intiator AND Target + // functions on the same chip, we can have TWO Exchanges + // with the same OX_ID -- OX_ID/FFFF for the CMND, and + // OX_ID/RX_ID for the XRDY or DATA frame(s). Ideally, + // we would like to support ABTS from Initiators or Targets, + // but it's not clear that can be supported on Tachyon for + // all cases (requires more investigation). + + if( (Exchanges->fcExchange[ ExchangeID].type == SCSI_TWE || + Exchanges->fcExchange[ ExchangeID].type == SCSI_TRE) + && + ((Exchanges->fcExchange[ ExchangeID].fchs.d_id & 0xFFFFFF) == + (fchs->s_id & 0xFFFFFF)) ) + { + + // target xchnge port_id matches -- how about OX_ID? + if( (Exchanges->fcExchange[ ExchangeID].fchs.ox_rx_id &0xFFFF0000) + == (fchs->ox_rx_id & 0xFFFF0000) ) + // yes! post ACCept response; will be completed by fcStart + { + Exchanges->fcExchange[ ExchangeID].status = TARGET_ABORT; + + // copy (add) rx_id field for simplified ACCept reply + fchs->ox_rx_id = + Exchanges->fcExchange[ ExchangeID].fchs.ox_rx_id; + + cpqfcTSPutLinkQue( cpqfcHBAdata, + BLS_ABTS_ACC, // Q Type + fchs ); // void QueContent + AbortAccept = TRUE; + printk("ACCepting ABTS for x_ID %8.8Xh, SEST pair %8.8Xh\n", + fchs->ox_rx_id, Exchanges->fcExchange[ ExchangeID].fchs.ox_rx_id); + break; // ABTS can affect only ONE exchange -exit loop + } + } + } // end of FOR loop + if( !AbortAccept ) // can't ACCept ABTS - send Reject + { + printk("ReJecTing: can't find ExchangeID %8.8Xh for ABTS command\n", + fchs->ox_rx_id); + if( Exchanges->fcExchange[ ExchangeID].type + && + !(fcChip->SEST->u[ ExchangeID].IWE.Hdr_Len + & 0x80000000)) + { + cpqfcTSCompleteExchange( fcChip, ExchangeID); + } + else + { + printk("Unexpected ABTS ReJecT! SEST[%X] Dword 0: %Xh\n", + ExchangeID, fcChip->SEST->u[ ExchangeID].IWE.Hdr_Len); + } + } + } + + // Check for BLS {ABTS? (Abort Sequence)} ACCept + else if( (fchs->d_id & 0x8F000000) == 0x84000000) + { + // target has responded with ACC for our ABTS; + // complete the indicated exchange with ABORTED status + // Make no checks for correct RX_ID, since + // all we need to conform ABTS ACC is the OX_ID. + // Verify that the d_id matches! + + ExchangeID = (fchs->ox_rx_id >> 16) & 0x7FFF; // x_id from ACC +// printk("ABTS ACC x_ID 0x%04X 0x%04X, status %Xh\n", +// fchs->ox_rx_id >> 16, fchs->ox_rx_id & 0xffff, +// Exchanges->fcExchange[ExchangeID].status); + + + + if( ExchangeID < TACH_SEST_LEN ) // x_ID makes sense + { + // Does "target" exchange 24-bit port_id match? + // (See "NOTE" above for handling Intiator AND Target in + // the same device driver) + // First, if this is a target response, then we originated + // (initiated) it with BLS_ABTS: + + if( (Exchanges->fcExchange[ ExchangeID].type == BLS_ABTS) + + && + // Second, does the source of this ACC match the destination + // of who we originally sent it to? + ((Exchanges->fcExchange[ ExchangeID].fchs.d_id & 0xFFFFFF) == + (fchs->s_id & 0xFFFFFF)) ) + { + cpqfcTSCompleteExchange( fcChip, ExchangeID ); + } + } + } + // Check for BLS {ABTS? (Abort Sequence)} ReJecT + else if( (fchs->d_id & 0x8F000000) == 0x85000000) + { + // target has responded with RJT for our ABTS; + // complete the indicated exchange with ABORTED status + // Make no checks for correct RX_ID, since + // all we need to conform ABTS ACC is the OX_ID. + // Verify that the d_id matches! + + ExchangeID = (fchs->ox_rx_id >> 16) & 0x7FFF; // x_id from ACC +// printk("BLS_ABTS RJT on Exchange 0x%04X 0x%04X\n", +// fchs->ox_rx_id >> 16, fchs->ox_rx_id & 0xffff); + + if( ExchangeID < TACH_SEST_LEN ) // x_ID makes sense + { + // Does "target" exchange 24-bit port_id match? + // (See "NOTE" above for handling Intiator AND Target in + // the same device driver) + // First, if this is a target response, then we originated + // (initiated) it with BLS_ABTS: + + if( (Exchanges->fcExchange[ ExchangeID].type == BLS_ABTS) + + && + // Second, does the source of this ACC match the destination + // of who we originally sent it to? + ((Exchanges->fcExchange[ ExchangeID].fchs.d_id & 0xFFFFFF) == + (fchs->s_id & 0xFFFFFF)) ) + { + // YES! NOTE: There is a bug in CPQ's RA-4000 box + // where the "reason code" isn't returned in the payload + // For now, simply presume the reject is because the target + // already completed the exchange... + +// printk("complete x_ID %Xh on ABTS RJT\n", ExchangeID); + cpqfcTSCompleteExchange( fcChip, ExchangeID ); + } + } + } // end of ABTS check + } // end of Basic Link Service Request + break; + + default: + printk("AnalyzeIncomingFrame: unknown type: %Xh(%d)\n", + fcLQ->Qitem[QNdx].Type, + fcLQ->Qitem[QNdx].Type); + break; + } +} + + +// Function for Port Discovery necessary after every FC +// initialization (e.g. LIP). +// Also may be called if from Fabric Name Service logic. + +static void SendLogins( CPQFCHBA *cpqfcHBAdata, __u32 *FabricPortIds ) +{ + PTACHYON fcChip = &cpqfcHBAdata->fcChip; + FC_EXCHANGES *Exchanges = fcChip->Exchanges; + ULONG ulStatus=0; + TachFCHDR_GCMND fchs; // copy fields for transmission + int i; + ULONG loginType; + LONG ExchangeID; + PFC_LOGGEDIN_PORT pLoggedInPort; + __u32 PortIds[ number_of_al_pa]; + int NumberOfPorts=0; + + // We're going to presume (for now) that our limit of Fabric devices + // is the same as the number of alpa on a private loop (126 devices). + // (Of course this could be changed to support however many we have + // memory for). + memset( &PortIds[0], 0, sizeof(PortIds)); + + // First, check if this login is for our own Link Initialization + // (e.g. LIP on FC-AL), or if we have knowledge of Fabric devices + // from a switch. If we are logging into Fabric devices, we'll + // have a non-NULL FabricPortId pointer + + if( FabricPortIds != NULL) // may need logins + { + int LastPort=FALSE; + i = 0; + while( !LastPort) + { + // port IDs From NSR payload; byte swap needed? + BigEndianSwap( (UCHAR*)FabricPortIds, (UCHAR*)&PortIds[i], 4); + +// printk("FPortId[%d] %Xh ", i, PortIds[i]); + if( PortIds[i] & 0x80000000) + LastPort = TRUE; + + PortIds[i] &= 0xFFFFFF; // get 24-bit port_id + // some non-Fabric devices (like the Crossroads Fibre/Scsi bridge) + // erroneously use ALPA 0. + if( PortIds[i] ) // need non-zero port_id... + i++; + + if( i >= number_of_al_pa ) // (in)sanity check + break; + FabricPortIds++; // next... + } + + NumberOfPorts = i; +// printk("NumberOf Fabric ports %d", NumberOfPorts); + } + + else // need to send logins on our "local" link + { + + // are we a loop port? If so, check for reception of LILP frame, + // and if received use it (SANMark requirement) + if( fcChip->Options.LILPin ) + { + int j=0; + // sanity check on number of ALPAs from LILP frame... + // For format of LILP frame, see FC-AL specs or + // "Fibre Channel Bench Reference", J. Stai, 1995 (ISBN 1-879936-17-8) + // First byte is number of ALPAs + i = fcChip->LILPmap[0] >= (32*4) ? 32*4 : fcChip->LILPmap[0]; + NumberOfPorts = i; +// printk(" LILP alpa count %d ", i); + while( i > 0) + { + PortIds[j] = fcChip->LILPmap[1+ j]; + j++; i--; + } + } + else // have to send login to everybody + { + int j=0; + i = number_of_al_pa; + NumberOfPorts = i; + while( i > 0) + { + PortIds[j] = valid_al_pa[j]; // all legal ALPAs + j++; i--; + } + } + } + + + // Now we have a copy of the port_ids (and how many)... + for( i = 0; i < NumberOfPorts; i++) + { + // 24-bit FC Port ID + fchs.s_id = PortIds[i]; // note: only 8-bits used for ALPA + + + // don't log into ourselves (Linux Scsi disk scan will stop on + // no TARGET support error on us, and quit trying for rest of devices) + if( (fchs.s_id & 0xFF ) == (fcChip->Registers.my_al_pa & 0xFF) ) + continue; + + // fabric login needed? + if( (fchs.s_id == 0) || + (fcChip->Options.fabric == 1) ) + { + fcChip->Options.flogi = 1; // fabric needs longer for login + // Do we need FLOGI or FDISC? + pLoggedInPort = fcFindLoggedInPort( + fcChip, + NULL, // don't search SCSI Nexus + 0xFFFFFC, // search linked list for Fabric port_id + NULL, // don't search WWN + NULL); // (don't care about end of list) + + if( pLoggedInPort ) // If found, we have prior experience with + // this port -- check whether PDISC is needed + { + if( pLoggedInPort->flogi ) + { + // does the switch support FDISC?? (FLOGI for now...) + loginType = ELS_FLOGI; // prior FLOGI still valid + } + else + loginType = ELS_FLOGI; // expired FLOGI + } + else // first FLOGI? + loginType = ELS_FLOGI; + + + fchs.s_id = 0xFFFFFE; // well known F_Port address + + // Fabrics are not required to support FDISC, and + // it's not clear if that helps us anyway, since + // we'll want a Name Service Request to re-verify + // visible devices... + // Consequently, we always want our upper 16 bit + // port_id to be zero (we'll be rejected if we + // use our prior port_id if we've been plugged into + // a different switch port). + // Trick Tachyon to send to ALPA 0 (see TL/TS UG, pg 87) + // If our ALPA is 55h for instance, we want the FC frame + // s_id to be 0x000055, while Tach's my_al_pa register + // must be 0x000155, to force an OPN at ALPA 0 + // (the Fabric port) + fcChip->Registers.my_al_pa &= 0xFF; // only use ALPA for FLOGI + writel( fcChip->Registers.my_al_pa | 0x0100, + fcChip->Registers.ReMapMemBase + TL_MEM_TACH_My_ID); + } + + else // not FLOGI... + { + // should we send PLOGI or PDISC? Check if any prior port_id + // (e.g. alpa) completed a PLOGI/PRLI exchange by checking + // the pdisc flag. + + pLoggedInPort = fcFindLoggedInPort( + fcChip, + NULL, // don't search SCSI Nexus + fchs.s_id, // search linked list for al_pa + NULL, // don't search WWN + NULL); // (don't care about end of list) + + + + if( pLoggedInPort ) // If found, we have prior experience with + // this port -- check whether PDISC is needed + { + if( pLoggedInPort->pdisc ) + { + loginType = ELS_PDISC; // prior PLOGI and PRLI maybe still valid + + } + else + loginType = ELS_PLOGI; // prior knowledge, but can't use PDISC + } + else // never talked to this port_id before + loginType = ELS_PLOGI; // prior knowledge, but can't use PDISC + } + + + + ulStatus = cpqfcTSBuildExchange( + cpqfcHBAdata, + loginType, // e.g. PLOGI + &fchs, // no incoming frame (we are originator) + NULL, // no data (no scatter/gather list) + &ExchangeID );// fcController->fcExchanges index, -1 if failed + + if( !ulStatus ) // Exchange setup OK? + { + ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID ); + if( !ulStatus ) + { + // submitted to Tach's Outbound Que (ERQ PI incremented) + // waited for completion for ELS type (Login frames issued + // synchronously) + + if( loginType == ELS_PDISC ) + { + // now, we really shouldn't Revalidate SEST exchanges until + // we get an ACC reply from our target and verify that + // the target address/WWN is unchanged. However, when a fast + // target gets the PDISC, they can send SEST Exchange data + // before we even get around to processing the PDISC ACC. + // Consequently, we lose the I/O. + // To avoid this, go ahead and Revalidate when the PDISC goes + // out, anticipating that the ACC will be truly acceptable + // (this happens 99.9999....% of the time). + // If we revalidate a SEST write, and write data goes to a + // target that is NOT the one we originated the WRITE to, + // that target is required (FCP-SCSI specs, etc) to discard + // our WRITE data. + + // Re-validate SEST entries (Tachyon hardware assists) + RevalidateSEST( cpqfcHBAdata->HostAdapter, pLoggedInPort); + //TriggerHBA( fcChip->Registers.ReMapMemBase, 1); + } + } + else // give up immediately on error + { +#ifdef LOGIN_DBG + printk("SendLogins: fcStartExchange failed: %Xh\n", ulStatus ); +#endif + break; + } + + + if( fcChip->Registers.FMstatus.value & 0x080 ) // LDn during Port Disc. + { + ulStatus = LNKDWN_OSLS; +#ifdef LOGIN_DBG + printk("SendLogins: PortDisc aborted (LDn) @alpa %Xh\n", fchs.s_id); +#endif + break; + } + // Check the exchange for bad status (i.e. FrameTimeOut), + // and complete on bad status (most likely due to BAD_ALPA) + // on LDn, DPC function may already complete (ABORT) a started + // exchange, so check type first (type = 0 on complete). + if( Exchanges->fcExchange[ExchangeID].status ) + { +#ifdef LOGIN_DBG + printk("completing x_ID %X on status %Xh\n", + ExchangeID, Exchanges->fcExchange[ExchangeID].status); +#endif + cpqfcTSCompleteExchange( fcChip, ExchangeID); + } + } + else // Xchange setup failed... + { +#ifdef LOGIN_DBG + printk("FC: cpqfcTSBuildExchange failed: %Xh\n", ulStatus ); +#endif + break; + } + } + if( !ulStatus ) + { + // set the event signifying that all ALPAs were sent out. +#ifdef LOGIN_DBG + printk("SendLogins: PortDiscDone\n"); +#endif + cpqfcHBAdata->PortDiscDone = 1; + + + // TL/TS UG, pg. 184 + // 0x0065 = 100ms for RT_TOV + // 0x01f5 = 500ms for ED_TOV + fcChip->Registers.ed_tov.value = 0x006501f5L; + writel( fcChip->Registers.ed_tov.value, + (fcChip->Registers.ed_tov.address)); + + // set the LP_TOV back to ED_TOV (i.e. 500 ms) + writel( 0x00000010, fcChip->Registers.ReMapMemBase +TL_MEM_FM_TIMEOUT2); + } + else + { + printk("SendLogins: failed at xchng %Xh, alpa %Xh, status %Xh\n", + ExchangeID, fchs.s_id, ulStatus); + } + LEAVE("SendLogins"); + +} + + +// for REPORT_LUNS documentation, see "In-Depth Exploration of Scsi", +// D. Deming, 1994, pg 7-19 (ISBN 1-879936-08-9) +static void ScsiReportLunsDone(Scsi_Cmnd *Cmnd) +{ + struct Scsi_Host *HostAdapter = Cmnd->host; + CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata; + PTACHYON fcChip = &cpqfcHBAdata->fcChip; + FC_EXCHANGES *Exchanges = fcChip->Exchanges; + PFC_LOGGEDIN_PORT pLoggedInPort; + int LunListLen=0; + int i; + ULONG x_ID = 0xFFFFFFFF; + UCHAR *ucBuff = Cmnd->request_buffer; + +// printk("cpqfcTS: ReportLunsDone \n"); + // first, we need to find the Exchange for this command, + // so we can find the fcPort struct to make the indicated + // changes. + for( i=0; i< TACH_SEST_LEN; i++) + { + if( Exchanges->fcExchange[i].type // exchange defined? + && + (Exchanges->fcExchange[i].Cmnd == Cmnd) ) // matches? + + { + x_ID = i; // found exchange! + break; + } + } + if( x_ID == 0xFFFFFFFF) + { +// printk("cpqfcTS: ReportLuns failed - no FC Exchange\n"); + goto Done; // Report Luns FC Exchange gone; + // exchange probably Terminated by Implicit logout + } + + + // search linked list for the port_id we sent INQUIRY to + pLoggedInPort = fcFindLoggedInPort( fcChip, + NULL, // DON'T search Scsi Nexus (we will set it) + Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF, + NULL, // DON'T search linked list for FC WWN + NULL); // DON'T care about end of list + + if( !pLoggedInPort ) + { +// printk("cpqfcTS: ReportLuns failed - device gone\n"); + goto Done; // error! can't find logged in Port + } + LunListLen = ucBuff[3]; + LunListLen += ucBuff[2]>>8; + + if( !LunListLen ) // failed + { + // generically speaking, a soft error means we should retry... + if( (Cmnd->result >> 16) == DID_SOFT_ERROR ) + { + if( ((Cmnd->sense_buffer[2] & 0xF) == 0x6) && + (Cmnd->sense_buffer[12] == 0x29) ) // Sense Code "reset" + { + TachFCHDR_GCMND *fchs = &Exchanges->fcExchange[ x_ID].fchs; + // did we fail because of "check condition, device reset?" + // e.g. the device was reset (i.e., at every power up) + // retry the Report Luns + + // who are we sending it to? + // we know this because we have a copy of the command + // frame from the original Report Lun command - + // switch the d_id/s_id fields, because the Exchange Build + // context is "reply to source". + + fchs->s_id = fchs->d_id; // (temporarily re-use the struct) + cpqfcTSPutLinkQue( cpqfcHBAdata, SCSI_REPORT_LUNS, fchs ); + } + } + else // probably, the device doesn't support Report Luns + pLoggedInPort->ScsiNexus.VolumeSetAddressing = 0; + } + else // we have LUN info - check VSA mode + { + // for now, assume all LUNs will have same addr mode + // for VSA, payload byte 8 will be 0x40; otherwise, 0 + pLoggedInPort->ScsiNexus.VolumeSetAddressing = ucBuff[8]; + + // Since we got a Report Luns answer, set lun masking flag + pLoggedInPort->ScsiNexus.LunMasking = 1; + + if( LunListLen > 8*CPQFCTS_MAX_LUN) // We expect CPQFCTS_MAX_LUN max + LunListLen = 8*CPQFCTS_MAX_LUN; + +/* + printk("Device WWN %08X%08X Reports Luns @: ", + (ULONG)(pLoggedInPort->u.liWWN &0xFFFFFFFF), + (ULONG)(pLoggedInPort->u.liWWN>>32)); + + for( i=8; iScsiNexus.lun[j] != 0xFF ) + { + AppendLunList = 1; + break; + } + } + if( AppendLunList ) + { + int k; + int FreeLunIndex; +// printk("cpqfcTS: AppendLunList\n"); + + // If we get a new Report Luns, we cannot change + // any existing LUN mapping! (Only additive entry) + // For all LUNs in ReportLun list + // if RL lun != ScsiNexus lun + // if RL lun present in ScsiNexus lun[], continue + // else find ScsiNexus lun[]==FF and add, continue + + for( i=8, j=0; iScsiNexus.lun[j] != ucBuff[i+1] ) + { + // something changed from the last Report Luns + printk(" cpqfcTS: Report Lun change!\n"); + for( k=0, FreeLunIndex=CPQFCTS_MAX_LUN; + k < CPQFCTS_MAX_LUN; k++) + { + if( pLoggedInPort->ScsiNexus.lun[k] == 0xFF) + { + FreeLunIndex = k; + break; + } + if( pLoggedInPort->ScsiNexus.lun[k] == ucBuff[i+1] ) + break; // we already masked this lun + } + if( k >= CPQFCTS_MAX_LUN ) + { + printk(" no room for new LUN %d\n", ucBuff[i+1]); + } + else if( k == FreeLunIndex ) // need to add LUN + { + pLoggedInPort->ScsiNexus.lun[k] = ucBuff[i+1]; +// printk("add [%d]->%02d\n", k, pLoggedInPort->ScsiNexus.lun[k]); + + } + else + { + // lun already known + } + break; + } + } + // print out the new list... + for( j=0; j< CPQFCTS_MAX_LUN; j++) + { + if( pLoggedInPort->ScsiNexus.lun[j] == 0xFF) + break; // done +// printk("[%d]->%02d ", j, pLoggedInPort->ScsiNexus.lun[j]); + } + } + else + { +// printk("Linux SCSI LUNs[] -> Device LUNs: "); + // first time - this is easy + for( i=8, j=0; iScsiNexus.lun[j] = ucBuff[i+1]; +// printk("[%d]->%02d ", j, pLoggedInPort->ScsiNexus.lun[j]); + } +// printk("\n"); + } + } + } + +Done: +} + +// After successfully getting a "Process Login" (PRLI) from an +// FC port, we want to Discover the LUNs so that we know the +// addressing type (e.g., FCP-SCSI Volume Set Address, Peripheral +// Unit Device), and whether SSP (Selective Storage Presentation or +// Lun Masking) has made the LUN numbers non-zero based or +// non-contiguous. To remain backward compatible with the SCSI-2 +// driver model, which expects a contiguous LUNs starting at 0, +// will use the ReportLuns info to map from "device" to "Linux" +// LUNs. +static void IssueReportLunsCommand( + CPQFCHBA* cpqfcHBAdata, + TachFCHDR_GCMND* fchs) +{ + PTACHYON fcChip = &cpqfcHBAdata->fcChip; + PFC_LOGGEDIN_PORT pLoggedInPort; + Scsi_Cmnd *Cmnd; + LONG x_ID; + ULONG ulStatus; + UCHAR *ucBuff; + + + if( !cpqfcHBAdata->PortDiscDone) // cleared by LDn + { + printk("Discard Q'd ReportLun command\n"); + goto Done; + } + + // find the device (from port_id) we're talking to + pLoggedInPort = fcFindLoggedInPort( fcChip, + NULL, // DON'T search Scsi Nexus + fchs->s_id & 0xFFFFFF, + NULL, // DON'T search linked list for FC WWN + NULL); // DON'T care about end of list + if( pLoggedInPort ) // we'd BETTER find it! + { + + + if( !(pLoggedInPort->fcp_info & TARGET_FUNCTION) ) + goto Done; // forget it - FC device not a "target" + + // now use the port's Scsi Command buffer for the + // Report Luns Command + + Cmnd = &pLoggedInPort->ScsiCmnd; + ucBuff = pLoggedInPort->ReportLunsPayload; + + memset( Cmnd, 0, sizeof(Scsi_Cmnd)); + memset( ucBuff, 0, REPORT_LUNS_PL); + + Cmnd->scsi_done = ScsiReportLunsDone; + Cmnd->host = cpqfcHBAdata->HostAdapter; + + Cmnd->request_buffer = pLoggedInPort->ReportLunsPayload; + Cmnd->request_bufflen = REPORT_LUNS_PL; + + Cmnd->cmnd[0] = 0xA0; + Cmnd->cmnd[8] = REPORT_LUNS_PL >> 8; + Cmnd->cmnd[9] = (UCHAR)REPORT_LUNS_PL; + Cmnd->cmd_len = 12; + + Cmnd->channel = pLoggedInPort->ScsiNexus.channel; + Cmnd->target = pLoggedInPort->ScsiNexus.target; + + + ulStatus = cpqfcTSBuildExchange( + cpqfcHBAdata, + SCSI_IRE, + fchs, + Cmnd, // buffer for Report Lun data + &x_ID );// fcController->fcExchanges index, -1 if failed + + if( !ulStatus ) // Exchange setup? + { + ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, x_ID ); + if( !ulStatus ) + { + // submitted to Tach's Outbound Que (ERQ PI incremented) + // waited for completion for ELS type (Login frames issued + // synchronously) + } + else + // check reason for Exchange not being started - we might + // want to Queue and start later, or fail with error + { + + } + } + + else // Xchange setup failed... + printk(" cpqfcTSBuildExchange failed: %Xh\n", ulStatus ); + } + else // like, we just got a PRLI ACC, and now the port is gone? + { + printk(" can't send ReportLuns - no login for port_id %Xh\n", + fchs->s_id & 0xFFFFFF); + } + + + +Done: + +} + + + + + + + +static void CompleteBoardLockCmnd( CPQFCHBA *cpqfcHBAdata) +{ + int i; + for( i = CPQFCTS_REQ_QUEUE_LEN-1; i>= 0; i--) + { + if( cpqfcHBAdata->BoardLockCmnd[i] != NULL ) + { + Scsi_Cmnd *Cmnd = cpqfcHBAdata->BoardLockCmnd[i]; + cpqfcHBAdata->BoardLockCmnd[i] = NULL; + Cmnd->result = (DID_SOFT_ERROR << 16); // ask for retry +// printk(" BoardLockCmnd[%d] %p Complete, chnl/target/lun %d/%d/%d\n", +// i,Cmnd, Cmnd->channel, Cmnd->target, Cmnd->lun); + if( Cmnd->scsi_done != NULL) + (*Cmnd->scsi_done)(Cmnd); + } + } +} + + + + + + +// runs every 1 second for FC exchange timeouts and implicit FC device logouts + +void cpqfcTSheartbeat( unsigned long ptr ) +{ + CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)ptr; + PTACHYON fcChip = &cpqfcHBAdata->fcChip; + FC_EXCHANGES *Exchanges = fcChip->Exchanges; + PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts; + ULONG i; + unsigned long flags; + DECLARE_MUTEX_LOCKED(BoardLock); + + PCI_TRACE( 0xA8) + + if( cpqfcHBAdata->BoardLock) // Worker Task Running? + goto Skip; + + spin_lock_irqsave( &io_request_lock, flags); // STOP _que function + + PCI_TRACE( 0xA8) + + + cpqfcHBAdata->BoardLock = &BoardLock; // stop Linux SCSI command queuing + + // release the IO lock (and re-enable interrupts) + spin_unlock_irqrestore( &io_request_lock, flags); + + // Ensure no contention from _quecommand or Worker process + CPQ_SPINLOCK_HBA( cpqfcHBAdata) + + PCI_TRACE( 0xA8) + + + disable_irq( cpqfcHBAdata->HostAdapter->irq); // our IRQ + + // Complete the "bad target" commands (normally only used during + // initialization, since we aren't supposed to call "scsi_done" + // inside the queuecommand() function). + + for( i=0; i< CPQFCTS_MAX_TARGET_ID; i++) + { + if( cpqfcHBAdata->BadTargetCmnd[i] ) + { + Scsi_Cmnd *Cmnd = cpqfcHBAdata->BadTargetCmnd[i]; + cpqfcHBAdata->BadTargetCmnd[i] = NULL; + Cmnd->result = (DID_BAD_TARGET << 16); + if( Cmnd->scsi_done != NULL) + (*Cmnd->scsi_done)(Cmnd); + } + else + break; + } + + + // logged in ports -- re-login check (ports required to verify login with + // PDISC after LIP within 2 secs) + + // prevent contention + while( pLoggedInPort ) // for all ports which are expecting + // PDISC after the next LIP, check to see if + // time is up! + { + // Important: we only detect "timeout" condition on TRANSITION + // from non-zero to zero + if( pLoggedInPort->LOGO_timer ) // time-out "armed"? + { + if( !(--pLoggedInPort->LOGO_timer) ) // DEC from 1 to 0? + { + // LOGOUT time! Per PLDA, PDISC hasn't complete in 2 secs, so + // issue LOGO request and destroy all I/O with other FC port(s). + +/* + printk(" ~cpqfcTS heartbeat: LOGOut!~ "); + printk("Linux SCSI Chanl/Target %d/%d (port_id %06Xh) WWN %08X%08X\n", + pLoggedInPort->ScsiNexus.channel, + pLoggedInPort->ScsiNexus.target, + pLoggedInPort->port_id, + (ULONG)(pLoggedInPort->u.liWWN &0xFFFFFFFF), + (ULONG)(pLoggedInPort->u.liWWN>>32)); + +*/ + cpqfcTSImplicitLogout( cpqfcHBAdata, pLoggedInPort); + + } + // else simply decremented - maybe next time... + } + pLoggedInPort = pLoggedInPort->pNextPort; + } + + + + + + // ************ FC EXCHANGE TIMEOUT CHECK ************** + + for( i=0; i< TACH_MAX_XID; i++) + { + if( Exchanges->fcExchange[i].type ) // exchange defined? + { + + if( !Exchanges->fcExchange[i].timeOut ) // time expired + { + // Set Exchange timeout status + Exchanges->fcExchange[i].status |= FC2_TIMEOUT; + + if( i >= TACH_SEST_LEN ) // Link Service Exchange + { + cpqfcTSCompleteExchange( fcChip, i); // Don't "abort" LinkService + } + + else // SEST Exchange TO -- may post ABTS to Worker Thread Que + { + // (Make sure we don't keep timing it out; let other functions + // complete it or set the timeOut as needed) + Exchanges->fcExchange[i].timeOut = 30000; // seconds default + + if( Exchanges->fcExchange[i].type + & + (BLS_ABTS | BLS_ABTS_ACC ) ) + { + // For BLS_ABTS*, an upper level might still have + // an outstanding command waiting for low-level completion. + // Also, in the case of a WRITE, we MUST get confirmation + // of either ABTS ACC or RJT before re-using the Exchange. + // It's possible that the RAID cache algorithm can hang + // if we fail to complete a WRITE to a LBA, when a READ + // comes later to that same LBA. Therefore, we must + // ensure that the target verifies receipt of ABTS for + // the exchange + + printk("~TO Q'd ABTS (x_ID %Xh)~ ", i); +// TriggerHBA( fcChip->Registers.ReMapMemBase); + + // On timeout of a ABTS exchange, check to + // see if the FC device has a current valid login. + // If so, restart it. + pLoggedInPort = fcFindLoggedInPort( fcChip, + Exchanges->fcExchange[i].Cmnd, // find Scsi Nexus + 0, // DON'T search linked list for FC port id + NULL, // DON'T search linked list for FC WWN + NULL); // DON'T care about end of list + + // device exists? + if( pLoggedInPort ) // device exists? + { + if( pLoggedInPort->prli ) // logged in for FCP-SCSI? + { + // attempt to restart the ABTS + printk(" ~restarting ABTS~ "); + cpqfcTSStartExchange( cpqfcHBAdata, i ); + + } + } + } + else // not an ABTS + { + + // We expect the WorkerThread to change the xchng type to + // abort and set appropriate timeout. + cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &i ); // timed-out + } + } + } + else // time not expired... + { + // decrement timeout: 1 or more seconds left + --Exchanges->fcExchange[i].timeOut; + } + } + } + + + enable_irq( cpqfcHBAdata->HostAdapter->irq); + + + CPQ_SPINUNLOCK_HBA( cpqfcHBAdata) + + cpqfcHBAdata->BoardLock = NULL; // Linux SCSI commands may be queued + + // Now, complete any Cmnd we Q'd up while BoardLock was held + + CompleteBoardLockCmnd( cpqfcHBAdata); + + + // restart the timer to run again (1 sec later) +Skip: + mod_timer( &cpqfcHBAdata->cpqfcTStimer, jiffies + HZ); + + PCI_TRACEO( i, 0xA8) + return; +} + + +// put valid FC-AL physical address in spec order +static const UCHAR valid_al_pa[]={ + 0xef, 0xe8, 0xe4, 0xe2, + 0xe1, 0xE0, 0xDC, 0xDA, + 0xD9, 0xD6, 0xD5, 0xD4, + 0xD3, 0xD2, 0xD1, 0xCe, + 0xCd, 0xCc, 0xCb, 0xCa, + 0xC9, 0xC7, 0xC6, 0xC5, + 0xC3, 0xBc, 0xBa, 0xB9, + 0xB6, 0xB5, 0xB4, 0xB3, + 0xB2, 0xB1, 0xae, 0xad, + 0xAc, 0xAb, 0xAa, 0xA9, + + 0xA7, 0xA6, 0xA5, 0xA3, + 0x9f, 0x9e, 0x9d, 0x9b, + 0x98, 0x97, 0x90, 0x8f, + 0x88, 0x84, 0x82, 0x81, + 0x80, 0x7c, 0x7a, 0x79, + 0x76, 0x75, 0x74, 0x73, + 0x72, 0x71, 0x6e, 0x6d, + 0x6c, 0x6b, 0x6a, 0x69, + 0x67, 0x66, 0x65, 0x63, + 0x5c, 0x5a, 0x59, 0x56, + + 0x55, 0x54, 0x53, 0x52, + 0x51, 0x4e, 0x4d, 0x4c, + 0x4b, 0x4a, 0x49, 0x47, + 0x46, 0x45, 0x43, 0x3c, + 0x3a, 0x39, 0x36, 0x35, + 0x34, 0x33, 0x32, 0x31, + 0x2e, 0x2d, 0x2c, 0x2b, + 0x2a, 0x29, 0x27, 0x26, + 0x25, 0x23, 0x1f, 0x1E, + 0x1d, 0x1b, 0x18, 0x17, + + 0x10, 0x0f, 8, 4, 2, 1 }; // ALPA 0 (Fabric) is special case + +const int number_of_al_pa = (sizeof(valid_al_pa) ); + + + +// this function looks up an al_pa from the table of valid al_pa's +// we decrement from the last decimal loop ID, because soft al_pa +// (our typical case) are assigned with highest priority (and high al_pa) +// first. See "In-Depth FC-AL", R. Kembel pg. 38 +// INPUTS: +// al_pa - 24 bit port identifier (8 bit al_pa on private loop) +// RETURN: +// Loop ID - serves are index to array of logged in ports +// -1 - invalid al_pa (not all 8 bit values are legal) + +#if (0) +static int GetLoopID( ULONG al_pa ) +{ + int i; + + for( i = number_of_al_pa -1; i >= 0; i--) // dec. + { + if( valid_al_pa[i] == (UCHAR)al_pa ) // take lowest 8 bits + return i; // success - found valid al_pa; return decimal LoopID + } + return -1; // failed - not found +} +#endif + + +// Search the singly (forward) linked list "fcPorts" looking for +// either the SCSI target (if != -1), port_id (if not NULL), +// or WWN (if not null), in that specific order. +// If we find a SCSI nexus (from Cmnd arg), set the SCp.phase +// field according to VSA or PDU +// RETURNS: +// Ptr to logged in port struct if found +// (NULL if not found) +// pLastLoggedInPort - ptr to last struct (for adding new ones) +// +PFC_LOGGEDIN_PORT fcFindLoggedInPort( + PTACHYON fcChip, + Scsi_Cmnd *Cmnd, // search linked list for Scsi Nexus (channel/target/lun) + ULONG port_id, // search linked list for al_pa, or + UCHAR wwn[8], // search linked list for WWN, or... + PFC_LOGGEDIN_PORT *pLastLoggedInPort ) + +{ + PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts; + BOOLEAN target_id_valid=FALSE; + BOOLEAN port_id_valid=FALSE; + BOOLEAN wwn_valid=FALSE; + int i; + + + if( Cmnd != NULL ) + target_id_valid = TRUE; + + else if( port_id ) // note! 24-bit NULL address is illegal + port_id_valid = TRUE; + + else + { + for( i=0; i<8; i++) // valid WWN passed? NULL WWN invalid + { + if( wwn ) // non-null arg? (OK to pass NULL when not searching WWN) + { + if( wwn[i] != 0 ) + wwn_valid = TRUE; // any non-zero byte makes (presumably) valid + } + } + } + // check other options ... + + + // In case multiple search options are given, we use a priority + // scheme: + // While valid pLoggedIn Ptr + // If port_id is valid + // if port_id matches, return Ptr + // If wwn is valid + // if wwn matches, return Ptr + // Next Ptr in list + // + // Return NULL (not found) + + + while( pLoggedInPort ) // NULL marks end of list (1st ptr always valid) + { + if( pLastLoggedInPort ) // caller's pointer valid? + *pLastLoggedInPort = pLoggedInPort; // end of linked list + + if( target_id_valid ) + { + // check Linux Scsi Cmnd for channel/target Nexus match + // (all luns are accessed through matching "pLoggedInPort") + if( (pLoggedInPort->ScsiNexus.target == Cmnd->target) + && + (pLoggedInPort->ScsiNexus.channel == Cmnd->channel)) + { + // For "passthru" modes, the IOCTL caller is responsible + // for setting the FCP-LUN addressing + if( !Cmnd->SCp.sent_command ) // NOT passthru? + { + + // set the FCP-LUN addressing type + Cmnd->SCp.phase = pLoggedInPort->ScsiNexus.VolumeSetAddressing; + + // set the Device Type we got from the snooped INQUIRY string + Cmnd->SCp.Message = pLoggedInPort->ScsiNexus.InqDeviceType; + + // handle LUN masking; if not "default" (illegal) lun value, + // the use it. These lun values are set by a successful + // Report Luns command + if( pLoggedInPort->ScsiNexus.LunMasking == 1) + { + // we KNOW all the valid LUNs... 0xFF is invalid! + Cmnd->SCp.have_data_in = pLoggedInPort->ScsiNexus.lun[Cmnd->lun]; + } + else + Cmnd->SCp.have_data_in = Cmnd->lun; // Linux & target luns match + } + break; // found it! + } + } + + if( port_id_valid ) // look for alpa first + { + if( pLoggedInPort->port_id == port_id ) + break; // found it! + } + if( wwn_valid ) // look for wwn second + { + + if( !memcmp( &pLoggedInPort->u.ucWWN[0], &wwn[0], 8)) + { + // all 8 bytes of WWN match + break; // found it! + } + } + + pLoggedInPort = pLoggedInPort->pNextPort; // try next port + } + + return pLoggedInPort; +} + + + + +// +// We need to examine the SEST table and re-validate +// any open Exchanges for this LoggedInPort +// To make Tachyon pay attention, Freeze FCP assists, +// set VAL bits, Unfreeze FCP assists +static void RevalidateSEST( struct Scsi_Host *HostAdapter, + PFC_LOGGEDIN_PORT pLoggedInPort) +{ + CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata; + PTACHYON fcChip = &cpqfcHBAdata->fcChip; + FC_EXCHANGES *Exchanges = fcChip->Exchanges; + ULONG x_ID; + BOOLEAN TachFroze = FALSE; + + + // re-validate any SEST exchanges that are permitted + // to survive the link down (e.g., good PDISC performed) + for( x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++) + { + + // If the SEST entry port_id matches the pLoggedInPort, + // we need to re-validate + if( (Exchanges->fcExchange[ x_ID].type == SCSI_IRE) + || + (Exchanges->fcExchange[ x_ID].type == SCSI_IWE)) + { + + if( (Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF) // (24-bit port ID) + == pLoggedInPort->port_id) + { +// printk(" re-val xID %Xh ", x_ID); + if( !TachFroze ) // freeze if not already frozen + TachFroze |= FreezeTach( cpqfcHBAdata); + fcChip->SEST->u[ x_ID].IWE.Hdr_Len |= 0x80000000; // set VAL bit + } + } + } + + if( TachFroze) + { + fcChip->UnFreezeTachyon( fcChip, 2); // both ERQ and FCP assists + } +} + + +// Complete an Linux Cmnds that we Queued because +// our FC link was down (cause immediate retry) + +static void UnblockScsiDevice( struct Scsi_Host *HostAdapter, + PFC_LOGGEDIN_PORT pLoggedInPort) +{ +// Scsi_Device *sdev = HostAdapter->host_queue; + CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata; + Scsi_Cmnd* *SCptr = &cpqfcHBAdata->LinkDnCmnd[0]; + Scsi_Cmnd *Cmnd; + int indx; + + + + // if the device was previously "blocked", make sure + // we unblock it so Linux SCSI will resume + + pLoggedInPort->device_blocked = FALSE; // clear our flag + + // check the Link Down command ptr buffer; + // we can complete now causing immediate retry + for( indx=0; indx < CPQFCTS_REQ_QUEUE_LEN; indx++, SCptr++) + { + if( *SCptr != NULL ) // scsi command to complete? + { +#ifdef DUMMYCMND_DBG + printk("complete Cmnd %p in LinkDnCmnd[%d]\n", *SCptr,indx); +#endif + Cmnd = *SCptr; + + + // Are there any Q'd commands for this target? + if( (Cmnd->target == pLoggedInPort->ScsiNexus.target) + && + (Cmnd->channel == pLoggedInPort->ScsiNexus.channel) ) + { + Cmnd->result = (DID_SOFT_ERROR <<16); // force retry + if( Cmnd->scsi_done != NULL) + (*Cmnd->scsi_done)(Cmnd); + else + printk("LinkDnCmnd scsi_done ptr null, port_id %Xh\n", + pLoggedInPort->port_id); + *SCptr = NULL; // free this slot for next use + } + } + } +} + + +//#define WWN_DBG 1 + +static void SetLoginFields( + PFC_LOGGEDIN_PORT pLoggedInPort, + TachFCHDR_GCMND* fchs, + BOOLEAN PDisc, + BOOLEAN Originator) +{ + LOGIN_PAYLOAD logi; // FC-PH Port Login + PRLI_REQUEST prli; // copy for BIG ENDIAN switch + int i; +#ifdef WWN_DBG + ULONG ulBuff; +#endif + + BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi)); + + pLoggedInPort->Originator = Originator; + pLoggedInPort->port_id = fchs->s_id & 0xFFFFFF; + + switch( fchs->pl[0] & 0xffff ) + { + case 0x00000002: // PLOGI or PDISC ACCept? + if( PDisc ) // PDISC accept + goto PDISC_case; + + case 0x00000003: // ELS_PLOGI or ELS_PLOGI_ACC + + // Login BB_credit typically 0 for Tachyons + pLoggedInPort->BB_credit = logi.cmn_services.bb_credit; + + // e.g. 128, 256, 1024, 2048 per FC-PH spec + // We have to use this when setting up SEST Writes, + // since that determines frame size we send. + pLoggedInPort->rx_data_size = logi.class3.rx_data_size; + pLoggedInPort->plogi = TRUE; + pLoggedInPort->pdisc = FALSE; + pLoggedInPort->prli = FALSE; // ELS_PLOGI resets + pLoggedInPort->flogi = FALSE; // ELS_PLOGI resets + pLoggedInPort->logo = FALSE; // ELS_PLOGI resets + pLoggedInPort->LOGO_counter = 0;// ELS_PLOGI resets + pLoggedInPort->LOGO_timer = 0;// ELS_PLOGI resets + + // was this PLOGI to a Fabric? + if( pLoggedInPort->port_id == 0xFFFFFC ) // well know address + pLoggedInPort->flogi = TRUE; + + + for( i=0; i<8; i++) // copy the LOGIN port's WWN + pLoggedInPort->u.ucWWN[i] = logi.port_name[i]; + +#ifdef WWN_DBG + ulBuff = (ULONG)pLoggedInPort->u.liWWN; + if( pLoggedInPort->Originator) + printk("o"); + else + printk("r"); + printk("PLOGI port_id %Xh, WWN %08X", + pLoggedInPort->port_id, ulBuff); + + ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32); + printk("%08Xh fcPort %p\n", ulBuff, pLoggedInPort); +#endif + break; + + + + + case 0x00000005: // ELS_LOGO (logout) + + + pLoggedInPort->plogi = FALSE; + pLoggedInPort->pdisc = FALSE; + pLoggedInPort->prli = FALSE; // ELS_PLOGI resets + pLoggedInPort->flogi = FALSE; // ELS_PLOGI resets + pLoggedInPort->logo = TRUE; // ELS_PLOGI resets + pLoggedInPort->LOGO_counter++; // ELS_PLOGI resets + pLoggedInPort->LOGO_timer = 0; +#ifdef WWN_DBG + ulBuff = (ULONG)pLoggedInPort->u.liWWN; + if( pLoggedInPort->Originator) + printk("o"); + else + printk("r"); + printk("LOGO port_id %Xh, WWN %08X", + pLoggedInPort->port_id, ulBuff); + + ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32); + printk("%08Xh\n", ulBuff); +#endif + break; + + + +PDISC_case: + case 0x00000050: // ELS_PDISC or ELS_PDISC_ACC + pLoggedInPort->LOGO_timer = 0; // stop the time-out + + pLoggedInPort->prli = TRUE; // ready to accept FCP-SCSI I/O + + + +#ifdef WWN_DBG + ulBuff = (ULONG)pLoggedInPort->u.liWWN; + if( pLoggedInPort->Originator) + printk("o"); + else + printk("r"); + printk("PDISC port_id %Xh, WWN %08X", + pLoggedInPort->port_id, ulBuff); + + ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32); + printk("%08Xh\n", ulBuff); +#endif + + + + break; + + + + case 0x1020L: // PRLI? + case 0x1002L: // PRLI ACCept? + BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&prli, sizeof(prli)); + + pLoggedInPort->fcp_info = prli.fcp_info; // target/initiator flags + pLoggedInPort->prli = TRUE; // PLOGI resets, PDISC doesn't + + pLoggedInPort->pdisc = TRUE; // expect to send (or receive) PDISC + // next time + pLoggedInPort->LOGO_timer = 0; // will be set next LinkDown +#ifdef WWN_DBG + ulBuff = (ULONG)pLoggedInPort->u.liWWN; + if( pLoggedInPort->Originator) + printk("o"); + else + printk("r"); + printk("PRLI port_id %Xh, WWN %08X", + pLoggedInPort->port_id, ulBuff); + + ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32); + printk("%08Xh\n", ulBuff); +#endif + + break; + + } + + return; +} + + + + + + +static void BuildLinkServicePayload( PTACHYON fcChip, ULONG type, void* payload) +{ + LOGIN_PAYLOAD *plogi; // FC-PH Port Login + LOGIN_PAYLOAD PlogiPayload; // copy for BIG ENDIAN switch + PRLI_REQUEST *prli; // FCP-SCSI Process Login + PRLI_REQUEST PrliPayload; // copy for BIG ENDIAN switch + LOGOUT_PAYLOAD *logo; + LOGOUT_PAYLOAD LogoutPayload; +// PRLO_REQUEST *prlo; +// PRLO_REQUEST PrloPayload; + REJECT_MESSAGE rjt, *prjt; + + memset( &PlogiPayload, 0, sizeof( PlogiPayload)); + plogi = &PlogiPayload; // load into stack buffer, + // then BIG-ENDIAN switch a copy to caller + + + switch( type ) // payload type can be ELS_PLOGI, ELS_PRLI, ADISC, ... + { + case ELS_FDISC: + case ELS_FLOGI: + case ELS_PLOGI_ACC: // FC-PH PORT Login Accept + case ELS_PLOGI: // FC-PH PORT Login + case ELS_PDISC: // FC-PH2 Port Discovery - same payload as ELS_PLOGI + plogi->login_cmd = LS_PLOGI; + if( type == ELS_PDISC) + plogi->login_cmd = LS_PDISC; + else if( type == ELS_PLOGI_ACC ) + plogi->login_cmd = LS_ACC; + + plogi->cmn_services.bb_credit = 0x00; + plogi->cmn_services.lowest_ver = fcChip->lowest_FCPH_ver; + plogi->cmn_services.highest_ver = fcChip->highest_FCPH_ver; + plogi->cmn_services.bb_rx_size = TACHLITE_TS_RX_SIZE; + plogi->cmn_services.common_features = CONTINUOSLY_INCREASING | + RANDOM_RELATIVE_OFFSET; + + // fill in with World Wide Name based Port Name - 8 UCHARs + // get from Tach registers WWN hi & lo + LoadWWN( fcChip, plogi->port_name, 0); + // fill in with World Wide Name based Node/Fabric Name - 8 UCHARs + // get from Tach registers WWN hi & lo + LoadWWN( fcChip, plogi->node_name, 1); + + // For Seagate Drives. + // + plogi->cmn_services.common_features |= 0x800; + plogi->cmn_services.rel_offset = 0xFE; + plogi->cmn_services.concurrent_seq = 1; + plogi->class1.service_options = 0x00; + plogi->class2.service_options = 0x00; + plogi->class3.service_options = CLASS_VALID; + plogi->class3.initiator_control = 0x00; + plogi->class3.rx_data_size = MAX_RX_PAYLOAD; + plogi->class3.recipient_control = + ERROR_DISCARD | ONE_CATEGORY_SEQUENCE; + plogi->class3.concurrent_sequences = 1; + plogi->class3.open_sequences = 1; + plogi->vendor_id[0] = 'C'; plogi->vendor_id[1] = 'Q'; + plogi->vendor_version[0] = 'C'; plogi->vendor_version[1] = 'Q'; + plogi->vendor_version[2] = ' '; plogi->vendor_version[3] = '0'; + plogi->vendor_version[4] = '0'; plogi->vendor_version[5] = '0'; + + + // FLOGI specific fields... (see FC-FLA, Rev 2.7, Aug 1999, sec 5.1) + if( (type == ELS_FLOGI) || (type == ELS_FDISC) ) + { + if( type == ELS_FLOGI ) + plogi->login_cmd = LS_FLOGI; + else + plogi->login_cmd = LS_FDISC; + + plogi->cmn_services.lowest_ver = 0x20; + plogi->cmn_services.common_features = 0x0800; + plogi->cmn_services.rel_offset = 0; + plogi->cmn_services.concurrent_seq = 0; + + plogi->class3.service_options = 0x8800; + plogi->class3.rx_data_size = 0; + plogi->class3.recipient_control = 0; + plogi->class3.concurrent_sequences = 0; + plogi->class3.open_sequences = 0; + } + + // copy back to caller's buff, w/ BIG ENDIAN swap + BigEndianSwap( (UCHAR*)&PlogiPayload, payload, sizeof(PlogiPayload)); + break; + + + case ELS_ACC: // generic Extended Link Service ACCept + plogi->login_cmd = LS_ACC; + // copy back to caller's buff, w/ BIG ENDIAN swap + BigEndianSwap( (UCHAR*)&PlogiPayload, payload, 4); + break; + + + + case ELS_SCR: // Fabric State Change Registration + { + SCR_PL scr; // state change registration + + memset( &scr, 0, sizeof(scr)); + + scr.command = LS_SCR; // 0x62000000 + // see FC-FLA, Rev 2.7, Table A.22 (pg 82) + scr.function = 3; // 1 = Events detected by Fabric + // 2 = N_Port detected registration + // 3 = Full registration + + // copy back to caller's buff, w/ BIG ENDIAN swap + BigEndianSwap( (UCHAR*)&scr, payload, sizeof(SCR_PL)); + } + + break; + + + case FCS_NSR: // Fabric Name Service Request + { + NSR_PL nsr; // Name Server Req. payload + + memset( &nsr, 0, sizeof(NSR_PL)); + + // see Brocade Fabric Programming Guide, + // Rev 1.3, pg 4-44 + nsr.CT_Rev = 0x01000000; + nsr.FCS_Type = 0xFC020000; + nsr.Command_code = 0x01710000; + nsr.FCP = 8; + + // copy back to caller's buff, w/ BIG ENDIAN swap + BigEndianSwap( (UCHAR*)&nsr, payload, sizeof(NSR_PL)); + } + + break; + + + + + case ELS_LOGO: // FC-PH PORT LogOut + logo = &LogoutPayload; // load into stack buffer, + // then BIG-ENDIAN switch a copy to caller + logo->cmd = LS_LOGO; + // load the 3 UCHARs of the node name + // (if private loop, upper two UCHARs 0) + logo->reserved = 0; + + logo->n_port_identifier[0] = (UCHAR)(fcChip->Registers.my_al_pa); + logo->n_port_identifier[1] = + (UCHAR)(fcChip->Registers.my_al_pa>>8); + logo->n_port_identifier[2] = + (UCHAR)(fcChip->Registers.my_al_pa>>16); + // fill in with World Wide Name based Port Name - 8 UCHARs + // get from Tach registers WWN hi & lo + LoadWWN( fcChip, logo->port_name, 0); + + BigEndianSwap( (UCHAR*)&LogoutPayload, + payload, sizeof(LogoutPayload) ); // 16 UCHAR struct + break; + + + case ELS_LOGO_ACC: // Logout Accept (FH-PH pg 149, table 74) + logo = &LogoutPayload; // load into stack buffer, + // then BIG-ENDIAN switch a copy to caller + logo->cmd = LS_ACC; + BigEndianSwap( (UCHAR*)&LogoutPayload, payload, 4 ); // 4 UCHAR cmnd + break; + + + case ELS_RJT: // ELS_RJT link service reject (FH-PH pg 155) + + prjt = (REJECT_MESSAGE*)payload; // pick up passed data + rjt.command_code = ELS_RJT; + // reverse fields, because of Swap that follows... + rjt.vendor = prjt->reserved; // vendor specific + rjt.explain = prjt->reason; // + rjt.reason = prjt->explain; // + rjt.reserved = prjt->vendor; // + // BIG-ENDIAN switch a copy to caller + BigEndianSwap( (UCHAR*)&rjt, payload, 8 ); // 8 UCHAR cmnd + break; + + + + + + case ELS_PRLI_ACC: // Process Login ACCept + case ELS_PRLI: // Process Login + case ELS_PRLO: // Process Logout + memset( &PrliPayload, 0, sizeof( PrliPayload)); + prli = &PrliPayload; // load into stack buffer, + + if( type == ELS_PRLI ) + prli->cmd = 0x20; // Login + else if( type == ELS_PRLO ) + prli->cmd = 0x21; // Logout + else if( type == ELS_PRLI_ACC ) + { + prli->cmd = 0x02; // Login ACCept + prli->valid = REQUEST_EXECUTED; + } + + + prli->valid |= SCSI_FCP | ESTABLISH_PAIR; + prli->fcp_info = READ_XFER_RDY; + prli->page_length = 0x10; + prli->payload_length = 20; + // Can be initiator AND target + + if( fcChip->Options.initiator ) + prli->fcp_info |= INITIATOR_FUNCTION; + if( fcChip->Options.target ) + prli->fcp_info |= TARGET_FUNCTION; + + BigEndianSwap( (UCHAR*)&PrliPayload, payload, prli->payload_length); + break; + + + + default: // no can do - programming error + printk(" BuildLinkServicePayload unknown!\n"); + break; + } +} + +// loads 8 UCHARs for PORT name or NODE name base on +// controller's WWN. +void LoadWWN( PTACHYON fcChip, UCHAR* dest, UCHAR type) +{ + UCHAR* bPtr, i; + + switch( type ) + { + case 0: // Port_Name + bPtr = (UCHAR*)&fcChip->Registers.wwn_hi; + for( i =0; i<4; i++) + dest[i] = *bPtr++; + bPtr = (UCHAR*)&fcChip->Registers.wwn_lo; + for( i =4; i<8; i++) + dest[i] = *bPtr++; + break; + case 1: // Node/Fabric _Name + bPtr = (UCHAR*)&fcChip->Registers.wwn_hi; + for( i =0; i<4; i++) + dest[i] = *bPtr++; + bPtr = (UCHAR*)&fcChip->Registers.wwn_lo; + for( i =4; i<8; i++) + dest[i] = *bPtr++; + break; + } + +} + + + +// We check the Port Login payload for required values. Note that +// ELS_PLOGI and ELS_PDISC (Port DISCover) use the same payload. + + +int verify_PLOGI( PTACHYON fcChip, + TachFCHDR_GCMND* fchs, + ULONG* reject_explain) +{ + LOGIN_PAYLOAD login; + + // source, dest, len (should be mult. of 4) + BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&login, sizeof(login)); + + // check FC version + // if other port's highest supported version + // is less than our lowest, and + // if other port's lowest + if( login.cmn_services.highest_ver < fcChip->lowest_FCPH_ver || + login.cmn_services.lowest_ver > fcChip->highest_FCPH_ver ) + { + *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, OPTIONS_ERROR); + return LOGICAL_ERROR; + } + + // Receive Data Field Size must be >=128 + // per FC-PH + if (login.cmn_services.bb_rx_size < 128) + { + *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, DATA_FIELD_SIZE_ERROR); + return LOGICAL_ERROR; + } + + // Only check Class 3 params + if( login.class3.service_options & CLASS_VALID) + { + if (login.class3.rx_data_size < 128) + { + *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, INVALID_CSP); + return LOGICAL_ERROR; + } + if( login.class3.initiator_control & XID_REQUIRED) + { + *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, INITIATOR_CTL_ERROR); + return LOGICAL_ERROR; + } + } + return 0; // success +} + + + + +int verify_PRLI( TachFCHDR_GCMND* fchs, ULONG* reject_explain) +{ + PRLI_REQUEST prli; // buffer for BIG ENDIAN + + // source, dest, len (should be mult. of 4) + BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&prli, sizeof(prli)); + + if( prli.fcp_info == 0 ) // i.e., not target or initiator? + { + *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, OPTIONS_ERROR); + return LOGICAL_ERROR; + } + + return 0; // success +} + + +// SWAP UCHARs as required by Fibre Channel (i.e. BIG ENDIAN) +// INPUTS: +// source - ptr to LITTLE ENDIAN ULONGS +// cnt - number of UCHARs to switch (should be mult. of ULONG) +// OUTPUTS: +// dest - ptr to BIG ENDIAN copy +// RETURN: +// none +// +void BigEndianSwap( UCHAR *source, UCHAR *dest, USHORT cnt) +{ + int i,j; + + source+=3; // start at MSB of 1st ULONG + for( j=0; j < cnt; j+=4, source+=4, dest+=4) // every ULONG + { + for( i=0; i<4; i++) // every UCHAR in ULONG + *(dest+i) = *(source-i); + } +} + + + + +// Build FC Exchanges............ + +static void buildFCPstatus( + PTACHYON fcChip, + ULONG ExchangeID); + +static LONG FindFreeExchange( PTACHYON fcChip, ULONG type ); + +static ULONG build_SEST_sgList( + ULONG *SESTalPairStart, + Scsi_Cmnd *Cmnd, + ULONG *sgPairs, + PSGPAGES sgPages // link list of TL Ext. S/G pages from O/S Pool +); + +static int build_FCP_payload( Scsi_Cmnd *Cmnd, + UCHAR* payload, ULONG type, ULONG fcp_dl ); + + +/* + IRB + ERQ __________________ + | | / | Req_A_SFS_Len | ____________________ + |----------| / | Req_A_SFS_Addr |------->| Reserved | + | IRB | / | Req_A_D_ID | | SOF EOF TimeStamp | + |-----------/ | Req_A_SEST_Index |-+ | R_CTL | D_ID | + | IRB | | Req_B... | | | CS_CTL| S_ID | + |-----------\ | | | | TYPE | F_CTL | + | IRB | \ | | | | SEQ_ID | SEQ_CNT | + |----------- \ | | +-->+--| OX_ID | RX_ID | + | | \ |__________________| | | RO | + | | pl (payload/cmnd) | + | | ..... | + | |___________________| + | + | ++-------------------------------------------+ +| +| +| e.g. IWE +| SEST __________________ for FCP_DATA +| | | / | | Hdr_Len | ____________________ +| |----------| / | Hdr_Addr_Addr |------->| Reserved | +| | [0] | / |Remote_ID| RSP_Len| | SOF EOF TimeStamp | +| |-----------/ | RSP_Addr |---+ | R_CTL | D_ID | ++-> [1] | | | Buff_Off | | | CS_CTL| S_ID | + |-----------\ |BuffIndex| Link | | | TYPE | F_CTL | + | [2] | \ | Rsvd | RX_ID | | | SEQ_ID | SEQ_CNT | + |----------- \ | Data_Len | | | OX_ID | RX_ID | + | ... | \ | Exp_RO | | | RO | + |----------| | Exp_Byte_Cnt | | |___________________| + | SEST_LEN | +--| Len | | + |__________| | | Address | | + | | ... | | for FCP_RSP + | |__________________| | ____________________ + | +----| Reserved | + | | SOF EOF TimeStamp | + | | R_CTL | D_ID | + | | CS_CTL| S_ID | + +--- local or extended | .... | + scatter/gather lists + defining upper-layer + data (e.g. from user's App) + + +*/ +// All TachLite commands must start with a SFS (Single Frame Sequence) +// command. In the simplest case (a NOP Basic Link command), +// only one frame header and ERQ entry is required. The most complex +// case is the SCSI assisted command, which requires an ERQ entry, +// SEST entry, and several frame headers and data buffers all +// logically linked together. +// Inputs: +// cpqfcHBAdata - controller struct +// type - PLOGI, SCSI_IWE, etc. +// InFCHS - Incoming Tachlite FCHS which prompted this exchange +// (only s_id set if we are originating) +// Data - PVOID to data struct consistent with "type" +// fcExchangeIndex - pointer to OX/RD ID value of built exchange +// Return: +// fcExchangeIndex - OX/RD ID value if successful +// 0 - success +// INVALID_ARGS - NULL/ invalid passed args +// BAD_ALPA - Bad source al_pa address +// LNKDWN_OSLS - Link Down (according to this controller) +// OUTQUE_FULL - Outbound Que full +// DRIVERQ_FULL - controller's Exchange array full +// SEST_FULL - SEST table full +// +// Remarks: +// Psuedo code: +// Check for NULL pointers / bad args +// Build outgoing FCHS - the header/payload struct +// Build IRB (for ERQ entry) +// if SCSI command, build SEST entry (e.g. IWE, TRE,...) +// return success + +//sbuildex +ULONG cpqfcTSBuildExchange( + CPQFCHBA *cpqfcHBAdata, + ULONG type, // e.g. PLOGI + TachFCHDR_GCMND* InFCHS, // incoming FCHS + void *Data, // the CDB, scatter/gather, etc. + LONG *fcExchangeIndex ) // points to allocated exchange, +{ + PTACHYON fcChip = &cpqfcHBAdata->fcChip; + FC_EXCHANGES *Exchanges = fcChip->Exchanges; + ULONG ulStatus = 0; // assume OK + USHORT ox_ID, rx_ID=0xFFFF; + ULONG SfsLen=0L; + TachLiteIRB* pIRB; + IRBflags IRB_flags; + UCHAR *pIRB_flags = (UCHAR*)&IRB_flags; + TachFCHDR_GCMND* CMDfchs; + TachFCHDR* dataHDR; // 32 byte HEADER ONLY FCP-DATA buffer + TachFCHDR_RSP* rspHDR; // 32 byte header + RSP payload + Scsi_Cmnd *Cmnd = (Scsi_Cmnd*)Data; // Linux Scsi CDB, S/G, ... + TachLiteIWE* pIWE; + TachLiteIRE* pIRE; + TachLiteTWE* pTWE; + TachLiteTRE* pTRE; + ULONG fcp_dl; // total byte length of DATA transfered + ULONG fl; // frame length (FC frame size, 128, 256, 512, 1024) + ULONG sgPairs; // number of valid scatter/gather pairs + int FCP_SCSI_command; + BA_ACC_PAYLOAD *ba_acc; + BA_RJT_PAYLOAD *ba_rjt; + + // check passed ARGS + if( !fcChip->ERQ ) // NULL ptr means uninitialized Tachlite chip + return INVALID_ARGS; + + + if( type == SCSI_IRE || + type == SCSI_TRE || + type == SCSI_IWE || + type == SCSI_TWE) + FCP_SCSI_command = 1; + + else + FCP_SCSI_command = 0; + + + // for commands that pass payload data (e.g. SCSI write) + // examine command struct - verify that the + // length of s/g buffers is adequate for total payload + // length (end of list is NULL address) + + if( FCP_SCSI_command ) + { + if( Data ) // must have data descriptor (S/G list -- at least + // one address with at least 1 byte of data) + { + // something to do (later)? + } + + else + return INVALID_ARGS; // invalid DATA ptr + } + + + + // we can build an Exchange for later Queuing (on the TL chip) + // if an empty slot is available in the DevExt for this controller + // look for available Exchange slot... + + if( type != FCP_RESPONSE && + type != BLS_ABTS && + type != BLS_ABTS_ACC ) // already have Exchange slot! + *fcExchangeIndex = FindFreeExchange( fcChip, type ); + + if( *fcExchangeIndex != -1 ) // Exchange is available? + { + // assign tmp ptr (shorthand) + CMDfchs = &Exchanges->fcExchange[ *fcExchangeIndex].fchs; + + + if( Cmnd != NULL ) // (necessary for ABTS cases) + { + Exchanges->fcExchange[ *fcExchangeIndex].Cmnd = Cmnd; // Linux Scsi + Exchanges->fcExchange[ *fcExchangeIndex].pLoggedInPort = + fcFindLoggedInPort( fcChip, + Exchanges->fcExchange[ *fcExchangeIndex].Cmnd, // find Scsi Nexus + 0, // DON'T search linked list for FC port id + NULL, // DON'T search linked list for FC WWN + NULL); // DON'T care about end of list + + } + + + // Build the command frame header (& data) according + // to command type + + // fields common for all SFS frame types + CMDfchs->reserved = 0L; // must clear + CMDfchs->sof_eof = 0x75000000L; // SOFi3:EOFn no UAM; LCr=0, no TS + + // get the destination port_id from incoming FCHS + // (initialized before calling if we're Originator) + // Frame goes to port it was from - the source_id + + CMDfchs->d_id = InFCHS->s_id &0xFFFFFF; // destination (add R_CTL later) + CMDfchs->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0 + + + // now enter command-specific fields + switch( type ) + { + + case BLS_NOP: // FC defined basic link service command NO-OP + // ensure unique X_IDs! (use tracking function) + + *pIRB_flags = 0; // clear IRB flags + IRB_flags.SFA = 1; // send SFS (not SEST index) + SfsLen = *pIRB_flags; + + SfsLen <<= 24; // shift flags to MSB + SfsLen += 32L; // add len to LSB (header only - no payload) + + // TYPE[31-24] 00 Basic Link Service + // f_ctl[23:0] exchg originator, 1st seq, xfer S.I. + CMDfchs->d_id |= 0x80000000L; // R_CTL = 80 for NOP (Basic Link Ser.) + CMDfchs->f_ctl = 0x00310000L; // xchng originator, 1st seq,.... + CMDfchs->seq_cnt = 0x0L; + CMDfchs->ox_rx_id = 0xFFFF; // RX_ID for now; OX_ID on start + CMDfchs->ro = 0x0L; // relative offset (n/a) + CMDfchs->pl[0] = 0xaabbccddL; // words 8-15 frame data payload (n/a) + Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 1; // seconds + // (NOP should complete ~instantly) + break; + + + + + case BLS_ABTS_ACC: // Abort Sequence ACCept + *pIRB_flags = 0; // clear IRB flags + IRB_flags.SFA = 1; // send SFS (not SEST index) + SfsLen = *pIRB_flags; + + SfsLen <<= 24; // shift flags to MSB + SfsLen += 32 + 12; // add len to LSB (header + 3 DWORD payload) + + CMDfchs->d_id |= 0x84000000L; // R_CTL = 84 for BASIC ACCept + // TYPE[31-24] 00 Basic Link Service + // f_ctl[23:0] exchg originator, not 1st seq, xfer S.I. + CMDfchs->f_ctl = 0x00910000L; // xchnge responder, last seq, xfer SI + // CMDfchs->seq_id & count might be set from DataHdr? + CMDfchs->ro = 0x0L; // relative offset (n/a) + Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 5; // seconds + // (Timeout in case of weird error) + + // now set the ACCept payload... + ba_acc = (BA_ACC_PAYLOAD*)&CMDfchs->pl[0]; + memset( ba_acc, 0, sizeof( BA_ACC_PAYLOAD)); + // Since PLDA requires (only) entire Exchange aborts, we don't need + // to worry about what the last sequence was. + + // We expect that a "target" task is accepting the abort, so we + // can use the OX/RX ID pair + ba_acc->ox_rx_id = CMDfchs->ox_rx_id; + + // source, dest, #bytes + BigEndianSwap((UCHAR *)&CMDfchs->ox_rx_id, (UCHAR *)&ba_acc->ox_rx_id, 4); + + ba_acc->low_seq_cnt = 0; + ba_acc->high_seq_cnt = 0xFFFF; + + + break; + + + case BLS_ABTS_RJT: // Abort Sequence ACCept + *pIRB_flags = 0; // clear IRB flags + IRB_flags.SFA = 1; // send SFS (not SEST index) + SfsLen = *pIRB_flags; + + SfsLen <<= 24; // shift flags to MSB + SfsLen += 32 + 12; // add len to LSB (header + 3 DWORD payload) + + CMDfchs->d_id |= 0x85000000L; // R_CTL = 85 for BASIC ReJecT + // f_ctl[23:0] exchg originator, not 1st seq, xfer S.I. + // TYPE[31-24] 00 Basic Link Service + CMDfchs->f_ctl = 0x00910000L; // xchnge responder, last seq, xfer SI + // CMDfchs->seq_id & count might be set from DataHdr? + CMDfchs->ro = 0x0L; // relative offset (n/a) + Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 5; // seconds + // (Timeout in case of weird error) + + CMDfchs->ox_rx_id = InFCHS->ox_rx_id; // copy from sender! + + // now set the ReJecT payload... + ba_rjt = (BA_RJT_PAYLOAD*)&CMDfchs->pl[0]; + memset( ba_rjt, 0, sizeof( BA_RJT_PAYLOAD)); + + // We expect that a "target" task couldn't find the Exhange in the + // array of active exchanges, so we use a new LinkService X_ID. + // See Reject payload description in FC-PH (Rev 4.3), pg. 140 + ba_rjt->reason_code = 0x09; // "unable to perform command request" + ba_rjt->reason_explain = 0x03; // invalid OX/RX ID pair + + + break; + + + + case BLS_ABTS: // FC defined basic link service command ABTS + // Abort Sequence + + + *pIRB_flags = 0; // clear IRB flags + IRB_flags.SFA = 1; // send SFS (not SEST index) + SfsLen = *pIRB_flags; + + SfsLen <<= 24; // shift flags to MSB + SfsLen += 32L; // add len to LSB (header only - no payload) + + // TYPE[31-24] 00 Basic Link Service + // f_ctl[23:0] exchg originator, not 1st seq, xfer S.I. + CMDfchs->d_id |= 0x81000000L; // R_CTL = 81 for ABTS + CMDfchs->f_ctl = 0x00110000L; // xchnge originator, last seq, xfer SI + // CMDfchs->seq_id & count might be set from DataHdr? + CMDfchs->ro = 0x0L; // relative offset (n/a) + Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 2; // seconds + // (ABTS must timeout when responder is gone) + break; + + + + case FCS_NSR: // Fabric Name Service Request + Exchanges->fcExchange[ *fcExchangeIndex].reTries = 2; + + + Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 2; // seconds + // OX_ID, linked to Driver Transaction ID + // (fix-up at Queing time) + CMDfchs->ox_rx_id = 0xFFFF; // RX_ID - Responder (target) to modify + // OX_ID set at ERQueing time + *pIRB_flags = 0; // clear IRB flags + IRB_flags.SFA = 1; // send SFS (not SEST index) + SfsLen = *pIRB_flags; + + SfsLen <<= 24; // shift flags to MSB + SfsLen += (32L + sizeof(NSR_PL)); // add len (header & NSR payload) + + CMDfchs->d_id |= 0x02000000L; // R_CTL = 02 for - + // Name Service Request: Unsolicited + // TYPE[31-24] 01 Extended Link Service + // f_ctl[23:0] exchg originator, 1st seq, xfer S.I. + CMDfchs->f_ctl = 0x20210000L; + // OX_ID will be fixed-up at Tachyon enqueing time + CMDfchs->seq_cnt = 0; // seq ID, DF_ctl, seq cnt + CMDfchs->ro = 0x0L; // relative offset (n/a) + + BuildLinkServicePayload( fcChip, type, &CMDfchs->pl[0]); + + + + + + + break; + + + + + case ELS_PLOGI: // FC-PH extended link service command Port Login + // (May, 2000) + // NOTE! This special case facilitates SANMark testing. The SANMark + // test script for initialization-timeout.fcal.SANMark-1.fc + // "eats" the OPN() primitive without issuing an R_RDY, causing + // Tachyon to report LST (loop state timeout), which causes a + // LIP. To avoid this, simply send out the frame (i.e. assuming a + // buffer credit of 1) without waiting for R_RDY. Many FC devices + // (other than Tachyon) have been doing this for years. We don't + // ever want to do this for non-Link Service frames unless the + // other device really did report non-zero login BB credit (i.e. + // in the PLOGI ACCept frame). +// CMDfchs->sof_eof |= 0x00000400L; // LCr=1 + + case ELS_FDISC: // Fabric Discovery (Login) + case ELS_FLOGI: // Fabric Login + case ELS_SCR: // Fabric State Change Registration + case ELS_LOGO: // FC-PH extended link service command Port Logout + case ELS_PDISC: // FC-PH extended link service cmnd Port Discovery + case ELS_PRLI: // FC-PH extended link service cmnd Process Login + + Exchanges->fcExchange[ *fcExchangeIndex].reTries = 2; + + + Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 2; // seconds + // OX_ID, linked to Driver Transaction ID + // (fix-up at Queing time) + CMDfchs->ox_rx_id = 0xFFFF; // RX_ID - Responder (target) to modify + // OX_ID set at ERQueing time + *pIRB_flags = 0; // clear IRB flags + IRB_flags.SFA = 1; // send SFS (not SEST index) + SfsLen = *pIRB_flags; + + SfsLen <<= 24; // shift flags to MSB + if( type == ELS_LOGO ) + SfsLen += (32L + 16L); // add len (header & PLOGI payload) + else if( type == ELS_PRLI ) + SfsLen += (32L + 20L); // add len (header & PRLI payload) + else if( type == ELS_SCR ) + SfsLen += (32L + sizeof(SCR_PL)); // add len (header & SCR payload) + else + SfsLen += (32L + 116L); // add len (header & PLOGI payload) + + CMDfchs->d_id |= 0x22000000L; // R_CTL = 22 for - + // Extended Link_Data: Unsolicited Control + // TYPE[31-24] 01 Extended Link Service + // f_ctl[23:0] exchg originator, 1st seq, xfer S.I. + CMDfchs->f_ctl = 0x01210000L; + // OX_ID will be fixed-up at Tachyon enqueing time + CMDfchs->seq_cnt = 0; // seq ID, DF_ctl, seq cnt + CMDfchs->ro = 0x0L; // relative offset (n/a) + + BuildLinkServicePayload( fcChip, type, &CMDfchs->pl[0]); + + break; + + + + case ELS_LOGO_ACC: // FC-PH extended link service logout accept + case ELS_RJT: // extended link service reject (add reason) + case ELS_ACC: // ext. link service generic accept + case ELS_PLOGI_ACC:// ext. link service login accept (PLOGI or PDISC) + case ELS_PRLI_ACC: // ext. link service process login accept + + + Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 1; // assume done + // ensure unique X_IDs! (use tracking function) + // OX_ID from initiator cmd + ox_ID = (USHORT)(InFCHS->ox_rx_id >> 16); + rx_ID = 0xFFFF; // RX_ID, linked to Driver Exchange ID + + *pIRB_flags = 0; // clear IRB flags + IRB_flags.SFA = 1; // send SFS (not SEST index) + SfsLen = *pIRB_flags; + + SfsLen <<= 24; // shift flags to MSB + if( type == ELS_RJT ) + { + SfsLen += (32L + 8L); // add len (header + payload) + + // ELS_RJT reason codes (utilize unused "reserved" field) + CMDfchs->pl[0] = 1; + CMDfchs->pl[1] = InFCHS->reserved; + + } + else if( (type == ELS_LOGO_ACC) || (type == ELS_ACC) ) + SfsLen += (32L + 4L); // add len (header + payload) + else if( type == ELS_PLOGI_ACC ) + SfsLen += (32L + 116L); // add len (header + payload) + else if( type == ELS_PRLI_ACC ) + SfsLen += (32L + 20L); // add len (header + payload) + + CMDfchs->d_id |= 0x23000000L; // R_CTL = 23 for - + // Extended Link_Data: Control Reply + // TYPE[31-24] 01 Extended Link Service + // f_ctl[23:0] exchg responder, last seq, e_s, tsi + CMDfchs->f_ctl = 0x01990000L; + CMDfchs->seq_cnt = 0x0L; + CMDfchs->ox_rx_id = 0L; // clear + CMDfchs->ox_rx_id = ox_ID; // load upper 16 bits + CMDfchs->ox_rx_id <<= 16; // shift them + + CMDfchs->ro = 0x0L; // relative offset (n/a) + + BuildLinkServicePayload( fcChip, type, &CMDfchs->pl[0]); + + break; + + + // Fibre Channel SCSI 'originator' sequences... + // (originator means 'initiator' in FCP-SCSI) + case SCSI_IWE: // TachLite Initiator Write Entry + { + PFC_LOGGEDIN_PORT pLoggedInPort = + Exchanges->fcExchange[ *fcExchangeIndex].pLoggedInPort; + + Exchanges->fcExchange[ *fcExchangeIndex].reTries = 1; + Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 7; // FC2 timeout + + // first, build FCP_CMND + // unique X_ID fix-ups in StartExchange + + *pIRB_flags = 0; // clear IRB flags + IRB_flags.SFA = 1; // send SFS FCP-CMND (not SEST index) + + // NOTE: unlike FC LinkService login frames, normal + // SCSI commands are sent without outgoing verification + IRB_flags.DCM = 1; // Disable completion message for Cmnd frame + SfsLen = *pIRB_flags; + + SfsLen <<= 24; // shift flags to MSB + SfsLen += 64L; // add len to LSB (header & CMND payload) + + CMDfchs->d_id |= (0x06000000L); // R_CTL = 6 for command + + // TYPE[31-24] 8 for FCP SCSI + // f_ctl[23:0] exchg originator, 1st seq, xfer S.I. + // valid RO + CMDfchs->f_ctl = 0x08210008L; + CMDfchs->seq_cnt = 0x0L; + CMDfchs->ox_rx_id = 0L; // clear for now (-or- in later) + CMDfchs->ro = 0x0L; // relative offset (n/a) + + // now, fill out FCP-DATA header + // (use buffer inside SEST object) + dataHDR = &fcChip->SEST->DataHDR[ *fcExchangeIndex ]; + dataHDR->reserved = 0L; // must clear + dataHDR->sof_eof = 0x75002000L; // SOFi3:EOFn no UAM; no CLS, noLCr, no TS + dataHDR->d_id = (InFCHS->s_id | 0x01000000L); // R_CTL= FCP_DATA + dataHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0 + // TYPE[31-24] 8 for FCP SCSI + // f_ctl[23:0] xfer S.I.| valid RO + dataHDR->f_ctl = 0x08010008L; + dataHDR->seq_cnt = 0x02000000L; // sequence ID: df_ctl : seqence count + dataHDR->ox_rx_id = 0L; // clear; fix-up dataHDR fields later + dataHDR->ro = 0x0L; // relative offset (n/a) + + // Now setup the SEST entry + pIWE = &fcChip->SEST->u[ *fcExchangeIndex ].IWE; + + // fill out the IWE: + + // VALid entry:Dir outbound:DCM:enable CM:enal INT: FC frame len + pIWE->Hdr_Len = 0x8e000020L; // data frame Len always 32 bytes + + + // from login parameters with other port, what's the largest frame + // we can send? + if( pLoggedInPort == NULL) + { + ulStatus = INVALID_ARGS; // failed! give up + break; + } + if( pLoggedInPort->rx_data_size >= 2048) + fl = 0x00020000; // 2048 code (only support 1024!) + else if( pLoggedInPort->rx_data_size >= 1024) + fl = 0x00020000; // 1024 code + else if( pLoggedInPort->rx_data_size >= 512) + fl = 0x00010000; // 512 code + else + fl = 0; // 128 bytes -- should never happen + + + pIWE->Hdr_Len |= fl; // add xmit FC frame len for data phase + pIWE->Hdr_Addr = virt_to_bus( dataHDR ); + pIWE->RSP_Len = sizeof(TachFCHDR_RSP) ; // hdr+data (recv'd RSP frame) + pIWE->RSP_Len |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID + + memset( &fcChip->SEST->RspHDR[ *fcExchangeIndex].pl, 0, + sizeof( FCP_STATUS_RESPONSE) ); // clear out previous status + + pIWE->RSP_Addr = virt_to_bus( + &fcChip->SEST->RspHDR[ *fcExchangeIndex ]); + + // Do we need local or extended gather list? + // depends on size - we can handle 3 len/addr pairs + // locally. + + fcp_dl = build_SEST_sgList( + &pIWE->GLen1, + Cmnd, // S/G list + &sgPairs, // return # of pairs in S/G list (from "Data" descriptor) + &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later) + + if( !fcp_dl ) // error building S/G list? + { + ulStatus = MEMPOOL_FAIL; + break; // give up + } + + // Now that we know total data length in + // the passed S/G buffer, set FCP CMND frame + build_FCP_payload( Cmnd, (UCHAR*)&CMDfchs->pl[0], type, fcp_dl ); + + + + if( sgPairs > 3 ) // need extended s/g list + pIWE->Buff_Off = 0x78000000L; // extended data | (no offset) + else // local data pointers (in SEST) + pIWE->Buff_Off = 0xf8000000L; // local data | (no offset) + + // ULONG 5 + pIWE->Link = 0x0000ffffL; // Buff_Index | Link + + pIWE->RX_ID = 0x0L; // DWord 6: RX_ID set by target XFER_RDY + + // DWord 7 + pIWE->Data_Len = 0L; // TL enters rcv'd XFER_RDY BURST_LEN + pIWE->Exp_RO = 0L; // DWord 8 + // DWord 9 + pIWE->Exp_Byte_Cnt = fcp_dl; // sum of gather buffers + } + break; + + + + + + case SCSI_IRE: // TachLite Initiator Read Entry + + if( Cmnd->timeout != 0) + { +// printk("Cmnd->timeout %d\n", Cmnd->timeout); + // per Linux Scsi + Exchanges->fcExchange[ *fcExchangeIndex].timeOut = Cmnd->timeout; + } + else // use our best guess, based on FC & device + { + + if( Cmnd->SCp.Message == 1 ) // Tape device? (from INQUIRY) + { + // turn off our timeouts (for now...) + Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 0xFFFFFFFF; + } + else + { + Exchanges->fcExchange[ *fcExchangeIndex].reTries = 1; + Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 7; // per SCSI req. + } + } + + + // first, build FCP_CMND + + + *pIRB_flags = 0; // clear IRB flags + IRB_flags.SFA = 1; // send SFS FCP-CMND (not SEST index) + // NOTE: unlike FC LinkService login frames, + // normal SCSI commands are sent "open loop" + IRB_flags.DCM = 1; // Disable completion message for Cmnd frame + SfsLen = *pIRB_flags; + + SfsLen <<= 24; // shift flags to MSB + SfsLen += 64L; // add len to LSB (header & CMND payload) + + CMDfchs->d_id |= (0x06000000L); // R_CTL = 6 for command + + // TYPE[31-24] 8 for FCP SCSI + // f_ctl[23:0] exchg originator, 1st seq, xfer S.I. + // valid RO + CMDfchs->f_ctl = 0x08210008L; + CMDfchs->seq_cnt = 0x0L; + // x_ID & data direction bit set later + CMDfchs->ox_rx_id = 0xFFFF; // clear + CMDfchs->ro = 0x0L; // relative offset (n/a) + + + + // Now setup the SEST entry + pIRE = &fcChip->SEST->u[ *fcExchangeIndex ].IRE; + + // fill out the IRE: + // VALid entry:Dir outbound:enable CM:enal INT: + pIRE->Seq_Accum = 0xCE000000L; // VAL,DIR inbound,DCM| INI,DAT,RSP + + pIRE->reserved = 0L; + pIRE->RSP_Len = sizeof(TachFCHDR_RSP) ; // hdr+data (recv'd RSP frame) + pIRE->RSP_Len |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID + + + pIRE->RSP_Addr = virt_to_bus( + &fcChip->SEST->RspHDR[ *fcExchangeIndex ]); + + + // Do we need local or extended gather list? + // depends on size - we can handle 3 len/addr pairs + // locally. + + fcp_dl = build_SEST_sgList( + &pIRE->SLen1, + Cmnd, // SCSI command Data desc. with S/G list + &sgPairs, // return # of pairs in S/G list (from "Data" descriptor) + &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later) + + + if( !fcp_dl ) // error building S/G list? + { + // It is permissible to have a ZERO LENGTH Read command. + // If there is the case, simply set fcp_dl (and Exp_Byte_Cnt) + // to 0 and continue. + if( Cmnd->request_bufflen == 0 ) + { + fcp_dl = 0; // no FC DATA frames expected + + } + else + { + ulStatus = MEMPOOL_FAIL; + break; // give up + } + } + + // now that we know the S/G length, build CMND payload + build_FCP_payload( Cmnd, (UCHAR*)&CMDfchs->pl[0], type, fcp_dl ); + + + if( sgPairs > 3 ) // need extended s/g list + pIRE->Buff_Off = 0x00000000; // DWord 4: extended s/g list, no offset + else + pIRE->Buff_Off = 0x80000000; // local data, no offset + + pIRE->Buff_Index = 0x0L; // DWord 5: Buff_Index | Reserved + + pIRE->Exp_RO = 0x0L; // DWord 6: Expected Rel. Offset + + pIRE->Byte_Count = 0; // DWord 7: filled in by TL on err + pIRE->reserved_ = 0; // DWord 8: reserved + // NOTE: 0 length READ is OK. + pIRE->Exp_Byte_Cnt = fcp_dl;// DWord 9: sum of scatter buffers + + break; + + + + + // Fibre Channel SCSI 'responder' sequences... + // (originator means 'target' in FCP-SCSI) + case SCSI_TWE: // TachLite Target Write Entry + + Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 10; // per SCSI req. + + // first, build FCP_CMND + + *pIRB_flags = 0; // clear IRB flags + IRB_flags.SFA = 1; // send SFS (XFER_RDY) + SfsLen = *pIRB_flags; + + SfsLen <<= 24; // shift flags to MSB + SfsLen += (32L + 12L);// add SFS len (header & XFER_RDY payload) + + CMDfchs->d_id |= (0x05000000L); // R_CTL = 5 for XFER_RDY + + // TYPE[31-24] 8 for FCP SCSI + // f_ctl[23:0] exchg responder, 1st seq, xfer S.I. + // valid RO + CMDfchs->f_ctl = 0x08810008L; + CMDfchs->seq_cnt = 0x01000000; // sequence ID: df_ctl: sequence count + // use originator (other port's) OX_ID + CMDfchs->ox_rx_id = InFCHS->ox_rx_id; // we want upper 16 bits + CMDfchs->ro = 0x0L; // relative offset (n/a) + + // now, fill out FCP-RSP header + // (use buffer inside SEST object) + + rspHDR = &fcChip->SEST->RspHDR[ *fcExchangeIndex ]; + rspHDR->reserved = 0L; // must clear + rspHDR->sof_eof = 0x75000000L; // SOFi3:EOFn no UAM; no CLS, noLCr, no TS + rspHDR->d_id = (InFCHS->s_id | 0x07000000L); // R_CTL= FCP_RSP + rspHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0 + // TYPE[31-24] 8 for FCP SCSI + // f_ctl[23:0] responder|last seq| xfer S.I. + rspHDR->f_ctl = 0x08910000L; + rspHDR->seq_cnt = 0x03000000; // sequence ID + rspHDR->ox_rx_id = InFCHS->ox_rx_id; // gives us OX_ID + rspHDR->ro = 0x0L; // relative offset (n/a) + + + // Now setup the SEST entry + + pTWE = &fcChip->SEST->u[ *fcExchangeIndex ].TWE; + + // fill out the TWE: + + // VALid entry:Dir outbound:enable CM:enal INT: + pTWE->Seq_Accum = 0xC4000000L; // upper word flags + pTWE->reserved = 0L; + pTWE->Remote_Node_ID = 0L; // no more auto RSP frame! (TL/TS change) + pTWE->Remote_Node_ID |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID + + + // Do we need local or extended gather list? + // depends on size - we can handle 3 len/addr pairs + // locally. + + fcp_dl = build_SEST_sgList( + &pTWE->SLen1, + Cmnd, // S/G list + &sgPairs, // return # of pairs in S/G list (from "Data" descriptor) + &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later) + + + if( !fcp_dl ) // error building S/G list? + { + ulStatus = MEMPOOL_FAIL; + break; // give up + } + + // now that we know the S/G length, build CMND payload + build_FCP_payload( Cmnd, (UCHAR*)&CMDfchs->pl[0], type, fcp_dl ); + + + if( sgPairs > 3 ) // need extended s/g list + pTWE->Buff_Off = 0x00000000; // extended s/g list, no offset + else + pTWE->Buff_Off = 0x80000000; // local data, no offset + + pTWE->Buff_Index = 0; // Buff_Index | Link + pTWE->Exp_RO = 0; + pTWE->Byte_Count = 0; // filled in by TL on err + pTWE->reserved_ = 0; + pTWE->Exp_Byte_Cnt = fcp_dl;// sum of scatter buffers + + break; + + + + + + + case SCSI_TRE: // TachLite Target Read Entry + + // It doesn't make much sense for us to "time-out" a READ, + // but we'll use it for design consistency and internal error recovery. + Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 10; // per SCSI req. + + // I/O request block settings... + *pIRB_flags = 0; // clear IRB flags + // check PRLI (process login) info + // to see if Initiator Requires XFER_RDY + // if not, don't send one! + // { PRLI check...} + IRB_flags.SFA = 0; // don't send XFER_RDY - start data + SfsLen = *pIRB_flags; + + SfsLen <<= 24; // shift flags to MSB + SfsLen += (32L + 12L);// add SFS len (header & XFER_RDY payload) + + + + // now, fill out FCP-DATA header + // (use buffer inside SEST object) + dataHDR = &fcChip->SEST->DataHDR[ *fcExchangeIndex ]; + + dataHDR->reserved = 0L; // must clear + dataHDR->sof_eof = 0x75000000L; // SOFi3:EOFn no UAM; no CLS,noLCr,no TS + dataHDR->d_id = (InFCHS->s_id | 0x01000000L); // R_CTL= FCP_DATA + dataHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0 + + + // TYPE[31-24] 8 for FCP SCSI + // f_ctl[23:0] exchg responder, not 1st seq, xfer S.I. + // valid RO + dataHDR->f_ctl = 0x08810008L; + dataHDR->seq_cnt = 0x01000000; // sequence ID (no XRDY) + dataHDR->ox_rx_id = InFCHS->ox_rx_id & 0xFFFF0000; // we want upper 16 bits + dataHDR->ro = 0x0L; // relative offset (n/a) + + // now, fill out FCP-RSP header + // (use buffer inside SEST object) + rspHDR = &fcChip->SEST->RspHDR[ *fcExchangeIndex ]; + + rspHDR->reserved = 0L; // must clear + rspHDR->sof_eof = 0x75000000L; // SOFi3:EOFn no UAM; no CLS, noLCr, no TS + rspHDR->d_id = (InFCHS->s_id | 0x07000000L); // R_CTL= FCP_RSP + rspHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0 + // TYPE[31-24] 8 for FCP SCSI + // f_ctl[23:0] responder|last seq| xfer S.I. + rspHDR->f_ctl = 0x08910000L; + rspHDR->seq_cnt = 0x02000000; // sequence ID: df_ctl: sequence count + + rspHDR->ro = 0x0L; // relative offset (n/a) + + + // Now setup the SEST entry + pTRE = &fcChip->SEST->u[ *fcExchangeIndex ].TRE; + + + // VALid entry:Dir outbound:enable CM:enal INT: + pTRE->Hdr_Len = 0x86010020L; // data frame Len always 32 bytes + pTRE->Hdr_Addr = virt_to_bus( dataHDR ); + pTRE->RSP_Len = 64L; // hdr+data (TL assisted RSP frame) + pTRE->RSP_Len |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID + pTRE->RSP_Addr = virt_to_bus( rspHDR ); + + + // Do we need local or extended gather list? + // depends on size - we can handle 3 len/addr pairs + // locally. + + fcp_dl = build_SEST_sgList( + &pTRE->GLen1, + Cmnd, // S/G list + &sgPairs, // return # of pairs in S/G list (from "Data" descriptor) + &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later) + + + if( !fcp_dl ) // error building S/G list? + { + ulStatus = MEMPOOL_FAIL; + break; // give up + } + + // no payload or command to build -- READ doesn't need XRDY + + + if( sgPairs > 3 ) // need extended s/g list + pTRE->Buff_Off = 0x78000000L; // extended data | (no offset) + else // local data pointers (in SEST) + pTRE->Buff_Off = 0xf8000000L; // local data | (no offset) + + // ULONG 5 + pTRE->Buff_Index = 0L; // Buff_Index | reserved + pTRE->reserved = 0x0L; // DWord 6 + + // DWord 7: NOTE: zero length will + // hang TachLite! + pTRE->Data_Len = fcp_dl; // e.g. sum of scatter buffers + + pTRE->reserved_ = 0L; // DWord 8 + pTRE->reserved__ = 0L; // DWord 9 + + break; + + + + + + + + case FCP_RESPONSE: + // Target response frame: this sequence uses an OX/RX ID + // pair from a completed SEST exchange. We built most + // of the response frame when we created the TWE/TRE. + + *pIRB_flags = 0; // clear IRB flags + IRB_flags.SFA = 1; // send SFS (RSP) + SfsLen = *pIRB_flags; + + SfsLen <<= 24; // shift flags to MSB + SfsLen += sizeof(TachFCHDR_RSP);// add SFS len (header & RSP payload) + + + Exchanges->fcExchange[ *fcExchangeIndex].type = + FCP_RESPONSE; // change Exchange type to "response" phase + + // take advantage of prior knowledge of OX/RX_ID pair from + // previous XFER outbound frame (still in fchs of exchange) + fcChip->SEST->RspHDR[ *fcExchangeIndex ].ox_rx_id = + CMDfchs->ox_rx_id; + + // Check the status of the DATA phase of the exchange so we can report + // status to the initiator + buildFCPstatus( fcChip, *fcExchangeIndex); // set RSP payload fields + + memcpy( + CMDfchs, // re-use same XFER fchs for Response frame + &fcChip->SEST->RspHDR[ *fcExchangeIndex ], + sizeof( TachFCHDR_RSP )); + + + break; + + default: + printk("cpqfcTS: don't know how to build FC type: %Xh(%d)\n", type,type); + break; + + } + + + + if( !ulStatus) // no errors above? + { + // FCHS is built; now build IRB + + // link the just built FCHS (the "command") to the IRB entry + // for this Exchange. + pIRB = &Exchanges->fcExchange[ *fcExchangeIndex].IRB; + + // len & flags according to command type above + pIRB->Req_A_SFS_Len = SfsLen; // includes IRB flags & len + pIRB->Req_A_SFS_Addr = virt_to_bus(CMDfchs); // TL needs physical addr + // of frame to send + pIRB->Req_A_SFS_D_ID = CMDfchs->d_id << 8; // Dest_ID must be consistent! + + // Exchange is complete except for "fix-up" fields to be set + // at Tachyon Queuing time: + // IRB->Req_A_Trans_ID (OX_ID/ RX_ID): + // for SEST entry, lower bits correspond to actual FC Exchange ID + // fchs->OX_ID or RX_ID + } + else + { +#ifdef DBG + printk( "FC Error: SEST build Pool Allocation failed\n"); +#endif + // return resources... + cpqfcTSCompleteExchange( fcChip, *fcExchangeIndex); // SEST build failed + } + } + else // no Exchanges available + { + ulStatus = SEST_FULL; + printk( "FC Error: no fcExchanges available\n"); + } + return ulStatus; +} + + + + + + +// set RSP payload fields +static void buildFCPstatus( PTACHYON fcChip, ULONG ExchangeID) +{ + FC_EXCHANGES *Exchanges = fcChip->Exchanges; + FC_EXCHANGE *pExchange = &Exchanges->fcExchange[ExchangeID]; // shorthand + PFCP_STATUS_RESPONSE pFcpStatus; + + memset( &fcChip->SEST->RspHDR[ ExchangeID ].pl, 0, + sizeof( FCP_STATUS_RESPONSE) ); + if( pExchange->status ) // something wrong? + { + pFcpStatus = (PFCP_STATUS_RESPONSE) // cast RSP buffer for this xchng + &fcChip->SEST->RspHDR[ ExchangeID ].pl; + if( pExchange->status & COUNT_ERROR ) + { + + // set FCP response len valid (so we can report count error) + pFcpStatus->fcp_status |= FCP_RSP_LEN_VALID; + pFcpStatus->fcp_rsp_len = 0x04000000; // 4 byte len (BIG Endian) + + pFcpStatus->fcp_rsp_info = FCP_DATA_LEN_NOT_BURST_LEN; // RSP_CODE + } + } +} + + + + +// This routine builds scatter/gather lists into SEST entries +// INPUTS: +// SESTalPair - SEST address @DWordA "Local Buffer Length" +// sgList - Scatter/Gather linked list of Len/Address data buffers +// OUTPUT: +// sgPairs - number of valid address/length pairs +// Remarks: +// The SEST data buffer pointers only depend on number of +// length/ address pairs, NOT on the type (IWE, TRE,...) +// Up to 3 pairs can be referenced in the SEST - more than 3 +// require this Extended S/G list page. The page holds 4, 8, 16... +// len/addr pairs, per Scatter/Gather List Page Length Reg. +// TachLite allows pages to be linked to any depth. + +//#define DBG_SEST_SGLIST 1 // for printing out S/G pairs with Ext. pages + +static ULONG build_SEST_sgList( + ULONG *SESTalPairStart, // the 3 len/address buffers in SEST + Scsi_Cmnd *Cmnd, + ULONG *sgPairs, + PSGPAGES sgPages) // link list of TL Ext. S/G pages from O/S Pool + +{ + ULONG i, AllocatedPages=0; // Tach Ext. S/G page allocations + ULONG* alPair = SESTalPairStart; + ULONG alignedPageAddress; // TL hardware alignment requirement + int PairCount; + unsigned long ulBuff; + ULONG total_data_len=0; // (in bytes) + ULONG bytes_to_go = Cmnd->request_bufflen; // total xfer (S/G sum) + ULONG thisMappingLen; + struct scatterlist *sgl; // S/G list (Linux format) + + + + if( !Cmnd->use_sg ) // no S/G list? + { + *sgPairs = 1; // use "local" S/G pair in SEST entry + // (for now, ignore address bits above #31) + *alPair++ = bytes_to_go & 0x7ffff; // bits 18-0, length + ulBuff = virt_to_bus( Cmnd->request_buffer); +#if BITS_PER_LONG > 32 + if( ulBuff >>32 ) + { + printk("FATAL! Tachyon DMA address %p exceeds 32 bits\n", (void*)ulBuff ); + return 0; + } +#endif + *alPair = (ULONG)ulBuff; + return bytes_to_go; + } + + + // [TBD - update for Linux to support > 32 bits addressing] + // since the format for local & extended S/G lists is different, + // check if S/G pairs exceeds 3. + *sgPairs = Cmnd->use_sg; + sgl = (struct scatterlist*)Cmnd->request_buffer; + + if( *sgPairs <= 3 ) // need "local" SEST list + { + while( bytes_to_go) + { + thisMappingLen = sgl->length; // we want them ALL on every pass + bytes_to_go = bytes_to_go - thisMappingLen; + + // we have L/A pair; L = thisMappingLen, A = physicalAddress + // load into SEST... + total_data_len += thisMappingLen & 0x7ffff; // mask in valid bits + // per SEST format + *alPair = thisMappingLen & 0x7ffff; // bits 18-0, length +// physicalAddress.HighPart <= 19; // shift to bit 19 + + // pick up bits 44-32 of upper 64-bit address + // and load into 31-19 LBAU (upper addr) of SEST entry +// *alPair++ |=(ULONG)((physicalAddress.HighPart & 0xFFF8)); + // on Tachlite TS's local S/G, we can handle 13 extra address bits + // i.e., bits 31-19 are actually bits 44-32 of physicalAddress + + alPair++; + + ulBuff = virt_to_bus( sgl->address); +#if BITS_PER_LONG > 32 + if( ulBuff >>32 ) + { + printk("cqpfcTS: Tach DMA address %p > 32 bits\n", (void*)ulBuff ); + return 0; + } +#endif + *alPair++ = (ULONG)ulBuff; // lower 32 bits (31-0) + + ++sgl; // next S/G pair +#ifdef DBG_SEST_SGLIST + printk(" thisLen %d ", thisMappingLen); + printk(" remain %d\n", bytes_to_go); +#endif + + } + } + + + + + else // more than 3 pairs requires Extended S/G page (Pool Allocation) + { + // clear out SEST DWORDs (local S/G addr) C-F (A-B set in following logic) + + + + for( i=2; i<6; i++) + alPair[i] = 0; + + PairCount = TL_EXT_SG_PAGE_COUNT; // forces initial page allocation + + while( bytes_to_go ) + { + + + // Per SEST format, we can support 524287 byte lenghts per + // S/G pair. Typical user buffers are 4k, and very rarely + // exceed 12k due to fragmentation of physical memory pages. + // However, on certain O/S system (not "user") buffers (on platforms + // with huge memories like 256Meg), it's possible to exceed this + // length in a single S/G address/len mapping. + // + // Check for Tachyon length boundary + // + if( sgl->length > 0x7ffff ) + { + // never ask for more than we can handle + thisMappingLen = sgl->length & 0x7ffff; + } + else + thisMappingLen = sgl->length; + + + + // should we load into "this" extended S/G page, or allocate + // new page? + + if( PairCount >= TL_EXT_SG_PAGE_COUNT ) + { + // have we exceeded the max possible extended pages? + if( AllocatedPages >= TL_MAX_SGPAGES) + { + printk("Error: aborted loop on %d Ext. S/G page allocations\n", + AllocatedPages); + + total_data_len = 0; // failure!! Ext. S/G is All-or-none affair + break; // failed + } + + // Allocate the TL Extended S/G list page from O/S pool. We have + // to allocated twice what we want to ensure required TL alignment + // (Tachlite TL/TS User Man. Rev 6.0, p 168) + // We store the original allocated PVOID so we can free later + + sgPages->PoolPage[ AllocatedPages] = + kmalloc( TL_EXT_SG_PAGE_BYTELEN*2,GFP_ATOMIC); // double for alignment + + + if( !sgPages->PoolPage[ AllocatedPages] ) // Allocation failed? + { + + printk("Error: Allocation failed @ %d S/G page allocations\n", + AllocatedPages); + + total_data_len = 0; // failure!! Ext. S/G is All-or-none affair + break; // give up + } + // clear out memory we just allocated + memset( sgPages->PoolPage[AllocatedPages], 0, + TL_EXT_SG_PAGE_BYTELEN*2); + + + // align the memory - TL requires sizeof() Ext. S/G page alignment. + // We doubled the actual required size so we could mask off LSBs + // to get desired offset + + ulBuff = virt_to_bus( sgPages->PoolPage[AllocatedPages]); + +#if BITS_PER_LONG > 32 + if( ulBuff >>32 ) + { + printk("cqpfcTS: Tach ext. S/G DMA address %p > 32 bits\n", + (void*)ulBuff ); + return 0; + } +#endif + + ulBuff += TL_EXT_SG_PAGE_BYTELEN; // ensures we pass align. boundary + ulBuff &= (0xFFFFFFFF - (TL_EXT_SG_PAGE_BYTELEN -1) );// mask off LSBs + + alignedPageAddress = (ULONG)ulBuff; +#ifdef DBG_SEST_SGLIST + printk("new PoolPage: %p, alignedPageAddress %lXh\n", + sgPages->PoolPage[AllocatedPages], ulBuff); +#endif + + + // set pointer, in SEST if first Ext. S/G page, or in last pair + // of linked Ext. S/G pages... + // (Only 32-bit PVOIDs, so just load lower 32 bits) + // NOTE: the Len field must be '0' if this is the first Ext. S/G + // pointer in SEST, and not 0 otherwise. + if( alPair == SESTalPairStart) // initial Ext. S/G list? + *alPair = 0; + else // not the SEST entry... Len must be non-0, so + // arbitrarily set it to number bytes remaining + *alPair = ( bytes_to_go & 0x7ffff); + +#ifdef DBG_SEST_SGLIST + printk("PairCount %d @%p even %Xh, ", + PairCount, alPair, *alPair); +#endif + alPair++; // next DWORD + + *alPair = alignedPageAddress; // TL needs 32-bit physical +#ifdef DBG_SEST_SGLIST + printk("odd %Xh\n", *alPair); +#endif + + // now reset the pointer to the ACTUAL (Extended) S/G page + // which will accept the Len/ PhysicalAddress pairs + alPair = bus_to_virt(alignedPageAddress); + + AllocatedPages++; + PairCount = 1; // starting new Ext. S/G page + } // end of new TL Ext. S/G page allocation + + + *alPair = thisMappingLen; // bits 18-0, length (range check above) + + +// physicalAddress.HighPart <= 19; // shift to bit 19 + + // pick up bits 44-32 of upper 64-bit address + // and load into 31-19 LBAU (upper addr) of SEST entry +// *alPair |=(ULONG)((physicalAddress.HighPart & 0xFFF8)); + + +#ifdef DBG_SEST_SGLIST + printk("PairCount %d @%p, even %Xh, ", + PairCount, alPair, *alPair); +#endif + + alPair++; // next DWORD + // on Tachlite TS's local S/G, we can handle 13 extra address bits + // i.e., bits 31-19 are actually bits 44-32 of physicalAddress + + + ulBuff = virt_to_bus( sgl->address); +#if BITS_PER_LONG > 32 + if( ulBuff >>32 ) + { + printk("cqpfcTS: Tach DMA address %p > 32 bits\n", (void*)ulBuff ); + return 0; + } +#endif + *alPair = (ULONG)ulBuff; // lower 32 bits (31-0) + + +#ifdef DBG_SEST_SGLIST + printk("odd %Xh\n", *alPair); +#endif + alPair++; // next DWORD + + + PairCount++; // next Length/Address pair + bytes_to_go -= thisMappingLen; + total_data_len += thisMappingLen; + sgl++; // next S/G pair + } + } + return total_data_len; +} + + + +// The Tachlite SEST table is referenced to OX_ID (or RX_ID). To optimize +// performance and debuggability, we index the Exchange structure to FC X_ID +// This enables us to build exchanges for later en-queing to Tachyon, +// provided we have an open X_ID slot. At Tachyon queing time, we only +// need an ERQ slot; then "fix-up" references in the +// IRB, FCHS, etc. as needed. +// RETURNS: +// 0 if successful +// non-zero on error +//sstartex +ULONG cpqfcTSStartExchange( + CPQFCHBA *cpqfcHBAdata, + LONG ExchangeID ) +{ + PTACHYON fcChip = &cpqfcHBAdata->fcChip; + FC_EXCHANGES *Exchanges = fcChip->Exchanges; + FC_EXCHANGE *pExchange = &Exchanges->fcExchange[ ExchangeID ]; // shorthand + USHORT producer, consumer; + ULONG ulStatus=0; + short int ErqIndex; + BOOLEAN CompleteExchange = FALSE; // e.g. ACC replies are complete + BOOLEAN SestType=FALSE; + ULONG InboundData=0; + + // We will manipulate Tachlite chip registers here to successfully + // start exchanges. + + // Check that link is not down -- we can't start an exchange on a + // down link! + + if( fcChip->Registers.FMstatus.value & 0x80) // LPSM offline? + { +printk("fcStartExchange: PSM offline (%Xh), x_ID %Xh, type %Xh, port_id %Xh\n", + fcChip->Registers.FMstatus.value & 0xFF, + ExchangeID, + pExchange->type, + pExchange->fchs.d_id); + + if( ExchangeID >= TACH_SEST_LEN ) // Link Service Outbound frame? + { + // Our most popular LinkService commands are port discovery types + // (PLOGI/ PDISC...), which are implicitly nullified by Link Down + // events, so it makes no sense to Que them. However, ABTS should + // be queued, since exchange sequences are likely destroyed by + // Link Down events, and we want to notify other ports of broken + // sequences by aborting the corresponding exchanges. + if( pExchange->type != BLS_ABTS ) + { + ulStatus = LNKDWN_OSLS; + goto Done; + // don't Que most LinkServ exchanges on LINK DOWN + } + } + + printk("fcStartExchange: Que x_ID %Xh, type %Xh\n", + ExchangeID, pExchange->type); + pExchange->status |= EXCHANGE_QUEUED; + ulStatus = EXCHANGE_QUEUED; + goto Done; + } + + // Make sure ERQ has available space. + + producer = (USHORT)fcChip->ERQ->producerIndex; // copies for logical arith. + consumer = (USHORT)fcChip->ERQ->consumerIndex; + producer++; // We are testing for full que by incrementing + + if( producer >= ERQ_LEN ) // rollover condition? + producer = 0; + if( consumer != producer ) // ERQ not full? + { + // ****************** Need Atomic access to chip registers!!******** + + // remember ERQ PI for copying IRB + ErqIndex = (USHORT)fcChip->ERQ->producerIndex; + fcChip->ERQ->producerIndex = producer; // this is written to Tachyon + // we have an ERQ slot! If SCSI command, need SEST slot + // otherwise we are done. + + // Note that Tachyon requires that bit 15 of the OX_ID or RX_ID be + // set according to direction of data to/from Tachyon for SEST assists. + // For consistency, enforce this rule for Link Service (non-SEST) + // exchanges as well. + + // fix-up the X_ID field in IRB + pExchange->IRB.Req_A_Trans_ID = ExchangeID & 0x7FFF; // 15-bit field + + // fix-up the X_ID field in fchs -- depends on Originator or Responder, + // outgoing or incoming data? + switch( pExchange->type ) + { + // ORIGINATOR types... we're setting our OX_ID and + // defaulting the responder's RX_ID to 0xFFFF + + case SCSI_IRE: + // Requirement: set MSB of x_ID for Incoming TL data + // (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50) + InboundData = 0x8000; + + case SCSI_IWE: + SestType = TRUE; + pExchange->fchs.ox_rx_id = (ExchangeID | InboundData); + pExchange->fchs.ox_rx_id <<= 16; // MSW shift + pExchange->fchs.ox_rx_id |= 0xffff; // add default RX_ID + + // now fix-up the Data HDR OX_ID (TL automatically does rx_id) + // (not necessary for IRE -- data buffer unused) + if( pExchange->type == SCSI_IWE) + { + fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id = + pExchange->fchs.ox_rx_id; + + } + + break; + + + case FCS_NSR: // ext. link service Name Service Request + case ELS_SCR: // ext. link service State Change Registration + case ELS_FDISC:// ext. link service login + case ELS_FLOGI:// ext. link service login + case ELS_LOGO: // FC-PH extended link service logout + case BLS_NOP: // Basic link service No OPeration + case ELS_PLOGI:// ext. link service login (PLOGI) + case ELS_PDISC:// ext. link service login (PDISC) + case ELS_PRLI: // ext. link service process login + + pExchange->fchs.ox_rx_id = ExchangeID; + pExchange->fchs.ox_rx_id <<= 16; // MSW shift + pExchange->fchs.ox_rx_id |= 0xffff; // and RX_ID + + break; + + + + + // RESPONDER types... we must set our RX_ID while preserving + // sender's OX_ID + // outgoing (or no) data + case ELS_RJT: // extended link service reject + case ELS_LOGO_ACC: // FC-PH extended link service logout accept + case ELS_ACC: // ext. generic link service accept + case ELS_PLOGI_ACC:// ext. link service login accept (PLOGI or PDISC) + case ELS_PRLI_ACC: // ext. link service process login accept + + CompleteExchange = TRUE; // Reply (ACC or RJT) is end of exchange + pExchange->fchs.ox_rx_id |= (ExchangeID & 0xFFFF); + + break; + + + // since we are a Responder, OX_ID should already be set by + // cpqfcTSBuildExchange(). We need to -OR- in RX_ID + case SCSI_TWE: + SestType = TRUE; + // Requirement: set MSB of x_ID for Incoming TL data + // (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50) + + pExchange->fchs.ox_rx_id &= 0xFFFF0000; // clear RX_ID + // Requirement: set MSB of RX_ID for Incoming TL data + // (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50) + pExchange->fchs.ox_rx_id |= (ExchangeID | 0x8000); + break; + + + case SCSI_TRE: + SestType = TRUE; + + // there is no XRDY for SEST target read; the data + // header needs to be updated. Also update the RSP + // exchange IDs for the status frame, in case it is sent automatically + fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id |= ExchangeID; + fcChip->SEST->RspHDR[ ExchangeID ].ox_rx_id = + fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id; + + // for easier FCP response logic (works for TWE and TRE), + // copy exchange IDs. (Not needed if TRE 'RSP' bit set) + pExchange->fchs.ox_rx_id = + fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id; + + break; + + + case FCP_RESPONSE: // using existing OX_ID/ RX_ID pair, + // start SFS FCP-RESPONSE frame + // OX/RX_ID should already be set! (See "fcBuild" above) + CompleteExchange = TRUE; // RSP is end of FCP-SCSI exchange + + + break; + + + case BLS_ABTS_RJT: // uses new RX_ID, since SEST x_ID non-existent + case BLS_ABTS_ACC: // using existing OX_ID/ RX_ID pair from SEST entry + CompleteExchange = TRUE; // ACC or RJT marks end of FCP-SCSI exchange + case BLS_ABTS: // using existing OX_ID/ RX_ID pair from SEST entry + + + break; + + + default: + printk("Error on fcStartExchange: undefined type %Xh(%d)\n", + pExchange->type, pExchange->type); + return INVALID_ARGS; + } + + + // X_ID fields are entered -- copy IRB to Tachyon's ERQ + + + memcpy( + &fcChip->ERQ->QEntry[ ErqIndex ], // dest. + &pExchange->IRB, + 32); // fixed (hardware) length! + + PCI_TRACEO( ExchangeID, 0xA0) + + // ACTION! May generate INT and IMQ entry + writel( fcChip->ERQ->producerIndex, + fcChip->Registers.ERQproducerIndex.address); + + + if( ExchangeID >= TACH_SEST_LEN ) // Link Service Outbound frame? + { + + // wait for completion! (TDB -- timeout and chip reset) + + + PCI_TRACEO( ExchangeID, 0xA4) + + enable_irq( cpqfcHBAdata->HostAdapter->irq); // only way to get Sem. + + down_interruptible( cpqfcHBAdata->TYOBcomplete); + + disable_irq( cpqfcHBAdata->HostAdapter->irq); + PCI_TRACE( 0xA4) + + // On login exchanges, BAD_ALPA (non-existent port_id) results in + // FTO (Frame Time Out) on the Outbound Completion message. + // If we got an FTO status, complete the exchange (free up slot) + if( CompleteExchange || // flag from Reply frames + pExchange->status ) // typically, can get FRAME_TO + { + cpqfcTSCompleteExchange( fcChip, ExchangeID); + } + } + + else // SEST Exchange + { + ulStatus = 0; // ship & pray success (e.g. FCP-SCSI) + + if( CompleteExchange ) // by Type of exchange (e.g. end-of-xchng) + { + cpqfcTSCompleteExchange( fcChip, ExchangeID); + } + + else + pExchange->status &= ~EXCHANGE_QUEUED; // clear ExchangeQueued flag + + } + } + + + else // ERQ 'producer' = 'consumer' and QUE is full + { + ulStatus = OUTQUE_FULL; // Outbound (ERQ) Que full + } + +Done: + PCI_TRACE( 0xA0) + return ulStatus; +} + + + + + +// Scan fcController->fcExchanges array for a usuable index (a "free" +// exchange). +// Inputs: +// fcChip - pointer to TachLite chip structure +// Return: +// index - exchange array element where exchange can be built +// -1 - exchange array is full +// REMARKS: +// Although this is a (yuk!) linear search, we presume +// that the system will complete exchanges about as quickly as +// they are submitted. A full Exchange array (and hence, max linear +// search time for free exchange slot) almost guarantees a Fibre problem +// of some sort. +// In the interest of making exchanges easier to debug, we want a LRU +// (Least Recently Used) scheme. + + +static LONG FindFreeExchange( PTACHYON fcChip, ULONG type ) +{ + FC_EXCHANGES *Exchanges = fcChip->Exchanges; + ULONG i; + ULONG ulStatus=-1; // assume failure + + + if( type == SCSI_IRE || + type == SCSI_TRE || + type == SCSI_IWE || + type == SCSI_TWE) + { + // SCSI type - X_IDs should be from 0 to TACH_SEST_LEN-1 + if( fcChip->fcSestExchangeLRU >= TACH_SEST_LEN) // rollover? + fcChip->fcSestExchangeLRU = 0; + i = fcChip->fcSestExchangeLRU; // typically it's already free! + + if( Exchanges->fcExchange[i].type == 0 ) // check for "free" element + { + ulStatus = 0; // success! + } + + else + { // YUK! we need to do a linear search for free element. + // Fragmentation of the fcExchange array is due to excessively + // long completions or timeouts. + + while( TRUE ) + { + if( ++i >= TACH_SEST_LEN ) // rollover check + i = 0; // beginning of SEST X_IDs + +// printk( "looping for SCSI xchng ID: i=%d, type=%Xh\n", +// i, Exchanges->fcExchange[i].type); + + if( Exchanges->fcExchange[i].type == 0 ) // "free"? + { + ulStatus = 0; // success! + break; + } + if( i == fcChip->fcSestExchangeLRU ) // wrapped-around array? + { + printk( "SEST X_ID space full\n"); + break; // failed - prevent inf. loop + } + } + } + fcChip->fcSestExchangeLRU = i + 1; // next! (rollover check next pass) + } + + + + else // Link Service type - X_IDs should be from TACH_SEST_LEN + // to TACH_MAX_XID + { + if( fcChip->fcLsExchangeLRU >= TACH_MAX_XID || // range check + fcChip->fcLsExchangeLRU < TACH_SEST_LEN ) // (e.g. startup) + fcChip->fcLsExchangeLRU = TACH_SEST_LEN; + + i = fcChip->fcLsExchangeLRU; // typically it's already free! + if( Exchanges->fcExchange[i].type == 0 ) // check for "free" element + { + ulStatus = 0; // success! + } + + else + { // YUK! we need to do a linear search for free element + // Fragmentation of the fcExchange array is due to excessively + // long completions or timeouts. + + while( TRUE ) + { + if( ++i >= TACH_MAX_XID ) // rollover check + i = TACH_SEST_LEN;// beginning of Link Service X_IDs + +// printk( "looping for xchng ID: i=%d, type=%Xh\n", +// i, Exchanges->fcExchange[i].type); + + if( Exchanges->fcExchange[i].type == 0 ) // "free"? + { + ulStatus = 0; // success! + break; + } + if( i == fcChip->fcLsExchangeLRU ) // wrapped-around array? + { + printk( "LinkService X_ID space full\n"); + break; // failed - prevent inf. loop + } + } + } + fcChip->fcLsExchangeLRU = i + 1; // next! (rollover check next pass) + + } + + if( !ulStatus ) // success? + Exchanges->fcExchange[i].type = type; // allocate it. + + else + i = -1; // error - all exchanges "open" + + return i; +} + + + + + +// We call this routine to free an Exchange for any reason: +// completed successfully, completed with error, aborted, etc. + +// returns FALSE if Exchange failed and "retry" is acceptable +// returns TRUE if Exchange was successful, or retry is impossible +// (e.g. port/device gone). +//scompleteexchange + +void cpqfcTSCompleteExchange( + PTACHYON fcChip, + ULONG x_ID) +{ + FC_EXCHANGES *Exchanges = fcChip->Exchanges; + + if( x_ID < TACH_SEST_LEN ) // SEST-based (or LinkServ for FCP exchange) + { + if( Exchanges->fcExchange[ x_ID ].Cmnd == NULL ) // what#@! + { +// TriggerHBA( fcChip->Registers.ReMapMemBase, 0); + printk(" x_ID %Xh, type %Xh, NULL ptr!\n", x_ID, + Exchanges->fcExchange[ x_ID ].type); + + goto CleanUpSestResources; // this path should be very rare. + } + + // we have Linux Scsi Cmnd ptr..., now check our Exchange status + // to decide how to complete this SEST FCP exchange + + if( Exchanges->fcExchange[ x_ID ].status ) // perhaps a Tach indicated problem, + // or abnormal exchange completion + { + // set FCP Link statistics + + if( Exchanges->fcExchange[ x_ID ].status & FC2_TIMEOUT) + fcChip->fcStats.timeouts++; + if( Exchanges->fcExchange[ x_ID ].status & INITIATOR_ABORT) + fcChip->fcStats.FC4aborted++; + if( Exchanges->fcExchange[ x_ID ].status & COUNT_ERROR) + fcChip->fcStats.CntErrors++; + if( Exchanges->fcExchange[ x_ID ].status & LINKFAIL_TX) + fcChip->fcStats.linkFailTX++; + if( Exchanges->fcExchange[ x_ID ].status & LINKFAIL_RX) + fcChip->fcStats.linkFailRX++; + if( Exchanges->fcExchange[ x_ID ].status & OVERFLOW) + fcChip->fcStats.CntErrors++; + + // First, see if the Scsi upper level initiated an ABORT on this + // exchange... + if( Exchanges->fcExchange[ x_ID ].status == INITIATOR_ABORT ) + { + printk(" DID_ABORT, x_ID %Xh, Cmnd %p ", + x_ID, Exchanges->fcExchange[ x_ID ].Cmnd); + goto CleanUpSestResources; // (we don't expect Linux _aborts) + } + + // Did our driver timeout the Exchange, or did Tachyon indicate + // a failure during transmission? Ask for retry with "SOFT_ERROR" + else if( Exchanges->fcExchange[ x_ID ].status & FC2_TIMEOUT) + { +// printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n", +// x_ID, Exchanges->fcExchange[ x_ID ].Cmnd); + Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16); + } + + // Did frame(s) for an open exchange arrive in the SFQ, + // meaning the SEST was unable to process them? + else if( Exchanges->fcExchange[ x_ID ].status & SFQ_FRAME) + { +// printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n", +// x_ID, Exchanges->fcExchange[ x_ID ].Cmnd); + Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16); + } + + // Did our driver timeout the Exchange, or did Tachyon indicate + // a failure during transmission? Ask for retry with "SOFT_ERROR" + else if( + (Exchanges->fcExchange[ x_ID ].status & LINKFAIL_TX) || + (Exchanges->fcExchange[ x_ID ].status & PORTID_CHANGED) || + (Exchanges->fcExchange[ x_ID ].status & FRAME_TO) || + (Exchanges->fcExchange[ x_ID ].status & INV_ENTRY) || + (Exchanges->fcExchange[ x_ID ].status & ABORTSEQ_NOTIFY) ) + + + { +// printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n", +// x_ID, Exchanges->fcExchange[ x_ID ].Cmnd); + Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16); + + + } + + // e.g., a LOGOut happened, or device never logged back in. + else if( Exchanges->fcExchange[ x_ID ].status & DEVICE_REMOVED) + { +// printk(" *LOGOut or timeout on login!* "); + // trigger? +// TriggerHBA( fcChip->Registers.ReMapMemBase, 0); + + Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_BAD_TARGET <<16); + } + + + // Did Tachyon indicate a CNT error? We need further analysis + // to determine if the exchange is acceptable + else if( Exchanges->fcExchange[ x_ID ].status == COUNT_ERROR) + { + UCHAR ScsiStatus; + FCP_STATUS_RESPONSE *pFcpStatus = + (PFCP_STATUS_RESPONSE)&fcChip->SEST->RspHDR[ x_ID ].pl; + + ScsiStatus = pFcpStatus->fcp_status >>24; + + // If the command is a SCSI Read/Write type, we don't tolerate + // count errors of any kind; assume the count error is due to + // a dropped frame and ask for retry... + + if(( (Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0] == 0x8) || + (Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0] == 0x28) || + (Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0] == 0xA) || + (Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0] == 0x2A) ) + && + ScsiStatus == 0 ) + { + // ask for retry +/* printk("COUNT_ERROR retry, x_ID %Xh, status %Xh, Cmnd %p\n", + x_ID, Exchanges->fcExchange[ x_ID ].status, + Exchanges->fcExchange[ x_ID ].Cmnd);*/ + Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16); + } + + else // need more analysis + { + cpqfcTSCheckandSnoopFCP(fcChip, x_ID); // (will set ->result) + } + } + + // default: NOTE! We don't ever want to get here. Getting here + // implies something new is happening that we've never had a test + // case for. Need code maintenance! Return "ERROR" + else + { + printk("DEFAULT result %Xh, x_ID %Xh, Cmnd %p\n", + Exchanges->fcExchange[ x_ID ].status, x_ID, + Exchanges->fcExchange[ x_ID ].Cmnd); + Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_ERROR <<16); + } + } + else // definitely no Tach problem, but perhaps an FCP problem + { + // set FCP Link statistic + fcChip->fcStats.ok++; + cpqfcTSCheckandSnoopFCP( fcChip, x_ID); // (will set ->result) + } + + // OK, we've set the Scsi "->result" field, so proceed with calling + // Linux Scsi "done" (if not NULL), and free any kernel memory we + // may have allocated for the exchange. + + PCI_TRACEO( (ULONG)Exchanges->fcExchange[x_ID].Cmnd, 0xAC); + // complete the command back to upper Scsi drivers + if( Exchanges->fcExchange[ x_ID ].Cmnd->scsi_done != NULL) + { + // Calling "done" on an Linux _abort() aborted + // Cmnd causes a kernel panic trying to re-free mem. + // Actually, we shouldn't do anything with an _abort CMND + if( Exchanges->fcExchange[ x_ID ].Cmnd->result != (DID_ABORT<<16) ) + { + PCI_TRACE(0xAC) + (*Exchanges->fcExchange[ x_ID ].Cmnd->scsi_done) + (Exchanges->fcExchange[ x_ID ].Cmnd); + } + else + { + +// printk(" not calling scsi_done on x_ID %Xh, Cmnd %p\n", +// x_ID, Exchanges->fcExchange[ x_ID ].Cmnd); + } + } + else{ + printk(" x_ID %Xh, type %Xh, Cdb0 %Xh\n", x_ID, + Exchanges->fcExchange[ x_ID ].type, + Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0]); + printk(" cpqfcTS: Null scsi_done function pointer!\n"); + } + + + // Now, clean up non-Scsi_Cmnd items... +CleanUpSestResources: + + // Was an Extended Scatter/Gather page allocated? We know + // this by checking DWORD 4, bit 31 ("LOC") of SEST entry + if( !(fcChip->SEST->u[ x_ID ].IWE.Buff_Off & 0x80000000)) + { + int i = 0; + + // extended S/G list was used -- Free the allocated ext. S/G pages + + while( fcChip->SEST->sgPages[x_ID].PoolPage[i] && + (i < TL_MAX_SGPAGES) ) + { + kfree( fcChip->SEST->sgPages[x_ID].PoolPage[i]); + fcChip->SEST->sgPages[x_ID].PoolPage[i] = NULL; + i++; + } + } + + Exchanges->fcExchange[ x_ID ].Cmnd = NULL; + } // Done with FCP (SEST) exchanges + + + // the remaining logic is common to ALL Exchanges: + // FCP(SEST) and LinkServ. + + Exchanges->fcExchange[ x_ID ].type = 0; // there -- FREE! + Exchanges->fcExchange[ x_ID ].status = 0; + + PCI_TRACEO( x_ID, 0xAC) + + + return; +} // (END of CompleteExchange function) + + + + +// Unfortunately, we must snoop all command completions in +// order to manipulate certain return fields, and take note of +// device types, etc., to facilitate the Fibre-Channel to SCSI +// "mapping". +// (Watch for BIG Endian confusion on some payload fields) +void cpqfcTSCheckandSnoopFCP( PTACHYON fcChip, ULONG x_ID) +{ + FC_EXCHANGES *Exchanges = fcChip->Exchanges; + Scsi_Cmnd *Cmnd = Exchanges->fcExchange[ x_ID].Cmnd; + FCP_STATUS_RESPONSE *pFcpStatus = + (PFCP_STATUS_RESPONSE)&fcChip->SEST->RspHDR[ x_ID ].pl; + UCHAR ScsiStatus; + + ScsiStatus = pFcpStatus->fcp_status >>24; + +#ifdef FCP_COMPLETION_DBG + printk("ScsiStatus = 0x%X\n", ScsiStatus); +#endif + + // First, check FCP status + if( pFcpStatus->fcp_status & FCP_RSP_LEN_VALID ) + { + // check response code (RSP_CODE) -- most popular is bad len + // 1st 4 bytes of rsp info -- only byte 3 interesting + if( pFcpStatus->fcp_rsp_info & FCP_DATA_LEN_NOT_BURST_LEN ) + { + + // do we EVER get here? + printk("cpqfcTS: FCP data len not burst len, x_ID %Xh\n", x_ID); + } + } + + // for now, go by the ScsiStatus, and manipulate certain + // commands when necessary... + if( ScsiStatus == 0) // SCSI status byte "good"? + { + Cmnd->result = 0; // everything's OK + + if( (Cmnd->cmnd[0] == INQUIRY)) + { + UCHAR *InquiryData = Cmnd->request_buffer; + PFC_LOGGEDIN_PORT pLoggedInPort; + + // We need to manipulate INQUIRY + // strings for COMPAQ RAID controllers to force + // Linux to scan additional LUNs. Namely, set + // the Inquiry string byte 2 (ANSI-approved version) + // to 2. + + if( !memcmp( &InquiryData[8], "COMPAQ", 6 )) + { + InquiryData[2] = 0x2; // claim SCSI-2 compliance, + // so multiple LUNs may be scanned. + // (no SCSI-2 problems known in CPQ) + } + + // snoop the Inquiry to detect Disk, Tape, etc. type + // (search linked list for the port_id we sent INQUIRY to) + pLoggedInPort = fcFindLoggedInPort( fcChip, + NULL, // DON'T search Scsi Nexus (we will set it) + Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF, + NULL, // DON'T search linked list for FC WWN + NULL); // DON'T care about end of list + + if( pLoggedInPort ) + { + pLoggedInPort->ScsiNexus.InqDeviceType = InquiryData[0]; + } + else + { + printk("cpqfcTS: can't find LoggedIn FC port %06X for INQUIRY\n", + Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF); + } + } + } + + + // Scsi Status not good -- pass it back to caller + + else + { + Cmnd->result = ScsiStatus; // SCSI status byte is 1st + + // check for valid "sense" data + + if( pFcpStatus->fcp_status & FCP_SNS_LEN_VALID ) + { // limit Scsi Sense field length! + int SenseLen = pFcpStatus->fcp_sns_len >>24; // (BigEndian) lower byte + + SenseLen = SenseLen > sizeof( Cmnd->sense_buffer) ? + sizeof( Cmnd->sense_buffer) : SenseLen; + + +#ifdef FCP_COMPLETION_DBG + printk("copy sense_buffer %p, len %d, result %Xh\n", + Cmnd->sense_buffer, SenseLen, Cmnd->result); +#endif + + // NOTE: There is some dispute over the FCP response + // format. Most FC devices assume that FCP_RSP_INFO + // is 8 bytes long, in spite of the fact that FCP_RSP_LEN + // is (virtually) always 0 and the field is "invalid". + // Some other devices assume that + // the FCP_SNS_INFO begins after FCP_RSP_LEN bytes (i.e. 0) + // when the FCP_RSP is invalid (this almost appears to be + // one of those "religious" issues). + // Consequently, we test the usual position of FCP_SNS_INFO + // for 7Xh, since the SCSI sense format says the first + // byte ("error code") should be 0x70 or 0x71. In practice, + // we find that every device does in fact have 0x70 or 0x71 + // in the first byte position, so this test works for all + // FC devices. + // (This logic is especially effective for the CPQ/DEC HSG80 + // & HSG60 controllers). + + if( (pFcpStatus->fcp_sns_info[0] & 0x70) == 0x70 ) + memcpy( Cmnd->sense_buffer, + &pFcpStatus->fcp_sns_info[0], SenseLen); + else + { + unsigned char *sbPtr = + (unsigned char *)&pFcpStatus->fcp_sns_info[0]; + sbPtr -= 8; // back up 8 bytes hoping to find the + // start of the sense buffer + memcpy( Cmnd->sense_buffer, sbPtr, SenseLen); + } + + // in the special case of Device Reset, tell upper layer + // to immediately retry (with SOFT_ERROR status) + // look for Sense Key Unit Attention (0x6) with ASC Device + // Reset (0x29) + // printk("SenseLen %d, Key = 0x%X, ASC = 0x%X\n", + // SenseLen, Cmnd->sense_buffer[2], + // Cmnd->sense_buffer[12]); + if( ((Cmnd->sense_buffer[2] & 0xF) == 0x6) && + (Cmnd->sense_buffer[12] == 0x29) ) // Sense Code "reset" + { + Cmnd->result |= (DID_SOFT_ERROR << 16); // "Host" status byte 3rd + } + + // check for SenseKey "HARDWARE ERROR", ASC InternalTargetFailure + else if( ((Cmnd->sense_buffer[2] & 0xF) == 0x4) && // "hardware error" + (Cmnd->sense_buffer[12] == 0x44) ) // Addtl. Sense Code + { +// printk("HARDWARE_ERROR, Channel/Target/Lun %d/%d/%d\n", +// Cmnd->channel, Cmnd->target, Cmnd->lun); + Cmnd->result |= (DID_ERROR << 16); // "Host" status byte 3rd + } + + } // (end of sense len valid) + + // there is no sense data to help out Linux's Scsi layers... + // We'll just return the Scsi status and hope he will "do the + // right thing" + else + { + // as far as we know, the Scsi status is sufficient + Cmnd->result |= (DID_OK << 16); // "Host" status byte 3rd + } + } +} + + + +//PPPPPPPPPPPPPPPPPPPPPPPPP PAYLOAD PPPPPPPPP +// build data PAYLOAD; SCSI FCP_CMND I.U. +// remember BIG ENDIAN payload - DWord values must be byte-reversed +// (hence the affinity for byte pointer building). + +static int build_FCP_payload( Scsi_Cmnd *Cmnd, + UCHAR* payload, ULONG type, ULONG fcp_dl ) +{ + int i; + + + switch( type) + { + + case SCSI_IWE: + case SCSI_IRE: + // 8 bytes FCP_LUN + // Peripheral Device or Volume Set addressing, and LUN mapping + // When the FC port was looked up, we copied address mode + // and any LUN mask to the scratch pad SCp.phase & .mode + + *payload++ = (UCHAR)Cmnd->SCp.phase; + + // Now, because of "lun masking" + // (aka selective storage presentation), + // the contiguous Linux Scsi lun number may not match the + // device's lun number, so we may have to "map". + + *payload++ = (UCHAR)Cmnd->SCp.have_data_in; + + // We don't know of anyone in the FC business using these + // extra "levels" of addressing. In fact, confusion still exists + // just using the FIRST level... ;-) + + *payload++ = 0; // 2nd level addressing + *payload++ = 0; + *payload++ = 0; // 3rd level addressing + *payload++ = 0; + *payload++ = 0; // 4th level addressing + *payload++ = 0; + + // 4 bytes Control Field FCP_CNTL + *payload++ = 0; // byte 0: (MSB) reserved + *payload++ = 0; // byte 1: task codes + *payload++ = 0; // byte 2: task management flags + // byte 3: (LSB) execution management codes + // bit 0 write, bit 1 read (don't set together) + + if( fcp_dl != 0 ) + { + if( type == SCSI_IWE ) // WRITE + *payload++ = 1; + else // READ + *payload++ = 2; + } + else + { + // On some devices, if RD or WR bits are set, + // and fcp_dl is 0, they will generate an error on the command. + // (i.e., if direction is specified, they insist on a length). + *payload++ = 0; // no data (necessary for CPQ) + } + + + // NOTE: clean this up if/when MAX_COMMAND_SIZE is increased to 16 + // FCP_CDB allows 16 byte SCSI command descriptor blk; + // Linux SCSI CDB array is MAX_COMMAND_SIZE (12 at this time...) + for( i=0; (i < Cmnd->cmd_len) && i < MAX_COMMAND_SIZE; i++) + *payload++ = Cmnd->cmnd[i]; + + if( Cmnd->cmd_len == 16 ) + { + memcpy( payload, &Cmnd->SCp.buffers_residual, 4); + } + payload+= (16 - i); + + // FCP_DL is largest number of expected data bytes + // per CDB (i.e. read/write command) + *payload++ = (UCHAR)(fcp_dl >>24); // (MSB) 8 bytes data len FCP_DL + *payload++ = (UCHAR)(fcp_dl >>16); + *payload++ = (UCHAR)(fcp_dl >>8); + *payload++ = (UCHAR)fcp_dl; // (LSB) + break; + + case SCSI_TWE: // need FCP_XFER_RDY + *payload++ = 0; // (4 bytes) DATA_RO (MSB byte 0) + *payload++ = 0; + *payload++ = 0; + *payload++ = 0; // LSB (byte 3) + // (4 bytes) BURST_LEN + // size of following FCP_DATA payload + *payload++ = (UCHAR)(fcp_dl >>24); // (MSB) 8 bytes data len FCP_DL + *payload++ = (UCHAR)(fcp_dl >>16); + *payload++ = (UCHAR)(fcp_dl >>8); + *payload++ = (UCHAR)fcp_dl; // (LSB) + // 4 bytes RESERVED + *payload++ = 0; + *payload++ = 0; + *payload++ = 0; + *payload++ = 0; + break; + + default: + break; + } + + return 0; +} + diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/cpqioctl.c linux/drivers/scsi/cpqioctl.c --- v2.4.0-test8/linux/drivers/scsi/cpqioctl.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/cpqioctl.c Tue Sep 19 08:01:35 2000 @@ -0,0 +1,76 @@ +// Test program for CPQFCTS ioctl calls +// build with: +// gcc -o cpqioctl cpqioctl.c +// ld -o cpqioctl /lib/crt0.o cpqioctl.o -lc + +#include +#include +#include +#include +#include +#include +#include "../../include/scsi/scsi.h" +#include "cpqfcTSioctl.h" + +typedef struct scsi_fctargaddress { + unsigned long host_port_id; + unsigned char host_wwn[8]; +} Scsi_FCTargAddress; + +int main(int argc, char **argv) { + + int fd, i; + Scsi_FCTargAddress targ; + int uselect=0; + + + + if ( argc < 2 ) { + printf("usage: cpqioctl \n"); + exit(1); + } + + if ( (fd = open(argv[1], O_RDONLY)) == -1) { + perror("open"); + exit(1); + } + + if ( ioctl(fd, SCSI_IOCTL_FC_TARGET_ADDRESS, &targ) ) { + perror("ioctl"); + exit(1); + } + + + printf("portid: %08x. wwn: ", targ.host_port_id); + + for (i=0;i<8;i++) printf(" %02x", targ.host_wwn[i]); + printf("\n"); + + while( uselect != 27 ) // not ESC key + { + printf("\n IOCTL \n"); + printf( "1. Get PCI info\n"); + printf( "2. Send Passthru\n"); + printf( " ==> "); + scanf("%c", &uselect); + + switch( uselect ) + { + case '1': + { + cciss_pci_info_struct pciinfo; + + if( ioctl( fd, CCPQFCTS_GETPCIINFO ,&pciinfo )) + perror("ioctl"); + else + printf( "\nPCI bus %d, dev_fn %d, board_id %Xh\n", + pciinfo.bus, pciinfo.dev_fn, pciinfo.board_id); + } + + } + } + + + close(fd); + return 0; +} diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/cyberstorm.c linux/drivers/scsi/cyberstorm.c --- v2.4.0-test8/linux/drivers/scsi/cyberstorm.c Fri Jan 28 08:04:58 2000 +++ linux/drivers/scsi/cyberstorm.c Mon Sep 18 13:36:25 2000 @@ -302,17 +302,13 @@ } } -#ifdef MODULE - #define HOSTS_C #include "cyberstorm.h" -Scsi_Host_Template driver_template = SCSI_CYBERSTORM; +static Scsi_Host_Template driver_template = SCSI_CYBERSTORM; #include "scsi_module.c" - -#endif int cyber_esp_release(struct Scsi_Host *instance) { diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/cyberstormII.c linux/drivers/scsi/cyberstormII.c --- v2.4.0-test8/linux/drivers/scsi/cyberstormII.c Fri Jan 28 08:04:58 2000 +++ linux/drivers/scsi/cyberstormII.c Mon Sep 18 13:36:25 2000 @@ -251,17 +251,14 @@ } } -#ifdef MODULE - #define HOSTS_C #include "cyberstormII.h" -Scsi_Host_Template driver_template = SCSI_CYBERSTORMII; +static Scsi_Host_Template driver_template = SCSI_CYBERSTORMII; #include "scsi_module.c" -#endif int cyberII_esp_release(struct Scsi_Host *instance) { diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/dc390.h linux/drivers/scsi/dc390.h --- v2.4.0-test8/linux/drivers/scsi/dc390.h Fri Sep 8 12:54:35 2000 +++ linux/drivers/scsi/dc390.h Mon Sep 18 14:09:49 2000 @@ -18,8 +18,6 @@ #define DC390_BANNER "Tekram DC390/AM53C974" #define DC390_VERSION "2.0d 1998/12/25" -#if defined(HOSTS_C) || defined(MODULE) - #include extern int DC390_detect(Scsi_Host_Template *psht); @@ -52,7 +50,5 @@ cmd_per_lun: 8, \ use_clustering: DISABLE_CLUSTERING \ } - -#endif /* defined(HOSTS_C) || defined(MODULE) */ #endif /* DC390_H */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/dmx3191d.c linux/drivers/scsi/dmx3191d.c --- v2.4.0-test8/linux/drivers/scsi/dmx3191d.c Mon Jun 19 13:42:40 2000 +++ linux/drivers/scsi/dmx3191d.c Mon Sep 18 13:36:25 2000 @@ -115,10 +115,6 @@ } -#ifdef MODULE -Scsi_Host_Template driver_template = DMX3191D; - +static Scsi_Host_Template driver_template = DMX3191D; #include "scsi_module.c" - -#endif /* MODULE */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/dmx3191d.h linux/drivers/scsi/dmx3191d.h --- v2.4.0-test8/linux/drivers/scsi/dmx3191d.h Mon Mar 27 09:48:11 2000 +++ linux/drivers/scsi/dmx3191d.h Mon Sep 18 14:12:01 2000 @@ -32,7 +32,6 @@ int dmx3191d_reset(Scsi_Cmnd *, unsigned int); -#if defined(HOSTS_C) || defined(MODULE) #define DMX3191D { \ proc_info: dmx3191d_proc_info, \ name: "Domex DMX3191D", \ @@ -49,10 +48,8 @@ cmd_per_lun: 2, \ use_clustering: DISABLE_CLUSTERING \ } -#endif /* HOSTS_C || MODULE */ -#ifndef HOSTS_C #define NCR5380_read(reg) inb(port + reg) #define NCR5380_write(reg, value) outb(value, port + reg) @@ -67,7 +64,6 @@ #define NCR5380_queue_command dmx3191d_queue_command #define NCR5380_reset dmx3191d_reset -#endif /* HOSTS_C */ #endif /* ASM */ #endif /* __DMX3191D_H */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/dtc.c linux/drivers/scsi/dtc.c --- v2.4.0-test8/linux/drivers/scsi/dtc.c Fri Nov 19 11:30:54 1999 +++ linux/drivers/scsi/dtc.c Mon Sep 18 13:36:25 2000 @@ -432,9 +432,6 @@ #include "NCR5380.c" -#ifdef MODULE /* Eventually this will go into an include file, but this will be later */ -Scsi_Host_Template driver_template = DTC3x80; - +static Scsi_Host_Template driver_template = DTC3x80; #include "scsi_module.c" -#endif diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/dtc.h linux/drivers/scsi/dtc.h --- v2.4.0-test8/linux/drivers/scsi/dtc.h Sat Apr 11 11:13:25 1998 +++ linux/drivers/scsi/dtc.h Mon Sep 18 14:12:01 2000 @@ -55,8 +55,6 @@ * macros when this is being used solely for the host stub. */ -#if defined(HOSTS_C) || defined(MODULE) - #define DTC3x80 { \ name: "DTC 3180/3280 ", \ detect: dtc_detect, \ @@ -70,10 +68,6 @@ cmd_per_lun: CMD_PER_LUN , \ use_clustering: DISABLE_CLUSTERING} -#endif - -#ifndef HOSTS_C - #define NCR5380_implementation_fields \ volatile unsigned int base @@ -124,6 +118,5 @@ #define DTC_IRQS 0x9c00 -#endif /* else def HOSTS_C */ #endif /* ndef ASM */ #endif /* DTC3280_H */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/eata.c linux/drivers/scsi/eata.c --- v2.4.0-test8/linux/drivers/scsi/eata.c Mon Jun 19 13:42:40 2000 +++ linux/drivers/scsi/eata.c Mon Sep 18 13:36:25 2000 @@ -2292,12 +2292,11 @@ return FALSE; } -#if defined(MODULE) -Scsi_Host_Template driver_template = EATA; +static Scsi_Host_Template driver_template = EATA; #include "scsi_module.c" -#else +#ifndef MODULE #if LINUX_VERSION_CODE < LinuxVersionCode(2,3,18) void eata2x_setup(char *str, int *ints) { diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/eata_dma.c linux/drivers/scsi/eata_dma.c --- v2.4.0-test8/linux/drivers/scsi/eata_dma.c Mon Jun 19 13:42:40 2000 +++ linux/drivers/scsi/eata_dma.c Mon Sep 18 13:36:25 2000 @@ -1520,11 +1520,9 @@ return(registered_HBAs); } -#ifdef MODULE /* Eventually this will go into an include file, but this will be later */ -Scsi_Host_Template driver_template = EATA_DMA; +static Scsi_Host_Template driver_template = EATA_DMA; #include "scsi_module.c" -#endif /* * Overrides for Emacs so that we almost follow Linus's tabbing style. diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/eata_dma.h linux/drivers/scsi/eata_dma.h --- v2.4.0-test8/linux/drivers/scsi/eata_dma.h Tue Jan 25 13:01:14 2000 +++ linux/drivers/scsi/eata_dma.h Mon Sep 18 14:12:01 2000 @@ -10,8 +10,6 @@ #ifndef _EATA_DMA_H #define _EATA_DMA_H -#ifndef HOSTS_C - #include "eata_generic.h" @@ -66,8 +64,6 @@ #else #define DBG(x, y) #endif - -#endif /* !HOSTS_C */ int eata_detect(Scsi_Host_Template *); const char *eata_info(struct Scsi_Host *); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/eata_pio.c linux/drivers/scsi/eata_pio.c --- v2.4.0-test8/linux/drivers/scsi/eata_pio.c Mon Jun 19 13:42:40 2000 +++ linux/drivers/scsi/eata_pio.c Mon Sep 18 13:36:25 2000 @@ -985,12 +985,10 @@ return (registered_HBAs); } -#ifdef MODULE /* Eventually this will go into an include file, but this will be later */ -Scsi_Host_Template driver_template = EATA_PIO; +static Scsi_Host_Template driver_template = EATA_PIO; #include "scsi_module.c" -#endif /* * Overrides for Emacs so that we almost follow Linus's tabbing style. diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/esp.c linux/drivers/scsi/esp.c --- v2.4.0-test8/linux/drivers/scsi/esp.c Mon Aug 28 21:20:03 2000 +++ linux/drivers/scsi/esp.c Mon Sep 18 13:36:25 2000 @@ -4364,10 +4364,8 @@ return 0; } -#ifdef MODULE -Scsi_Host_Template driver_template = SCSI_SPARC_ESP; +static Scsi_Host_Template driver_template = SCSI_SPARC_ESP; #include "scsi_module.c" EXPORT_NO_SYMBOLS; -#endif /* MODULE */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/fastlane.c linux/drivers/scsi/fastlane.c --- v2.4.0-test8/linux/drivers/scsi/fastlane.c Fri Jan 28 08:04:58 2000 +++ linux/drivers/scsi/fastlane.c Mon Sep 18 13:36:25 2000 @@ -349,17 +349,12 @@ } } -#ifdef MODULE - #define HOSTS_C #include "fastlane.h" -Scsi_Host_Template driver_template = SCSI_FASTLANE; - +static Scsi_Host_Template driver_template = SCSI_FASTLANE; #include "scsi_module.c" - -#endif int fastlane_esp_release(struct Scsi_Host *instance) { diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/fcal.c linux/drivers/scsi/fcal.c --- v2.4.0-test8/linux/drivers/scsi/fcal.c Mon Dec 20 22:06:42 1999 +++ linux/drivers/scsi/fcal.c Mon Sep 18 13:36:25 2000 @@ -292,11 +292,8 @@ return 0; } -#ifdef MODULE - -Scsi_Host_Template driver_template = FCAL; +static Scsi_Host_Template driver_template = FCAL; #include "scsi_module.c" EXPORT_NO_SYMBOLS; -#endif /* MODULE */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/fd_mcs.c linux/drivers/scsi/fd_mcs.c --- v2.4.0-test8/linux/drivers/scsi/fd_mcs.c Thu Nov 11 16:57:30 1999 +++ linux/drivers/scsi/fd_mcs.c Mon Sep 18 13:36:25 2000 @@ -1465,9 +1465,7 @@ return 0; } -#ifdef MODULE /* Eventually this will go into an include file, but this will be later */ -Scsi_Host_Template driver_template = FD_MCS; +static Scsi_Host_Template driver_template = FD_MCS; #include "scsi_module.c" -#endif diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/fdomain.c linux/drivers/scsi/fdomain.c --- v2.4.0-test8/linux/drivers/scsi/fdomain.c Thu Jul 6 19:25:21 2000 +++ linux/drivers/scsi/fdomain.c Mon Sep 18 13:36:25 2000 @@ -2028,9 +2028,7 @@ return 0; } -#ifdef MODULE /* Eventually this will go into an include file, but this will be later */ -Scsi_Host_Template driver_template = FDOMAIN_16X0; +static Scsi_Host_Template driver_template = FDOMAIN_16X0; #include "scsi_module.c" -#endif diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/g_NCR5380.c linux/drivers/scsi/g_NCR5380.c --- v2.4.0-test8/linux/drivers/scsi/g_NCR5380.c Thu Jan 20 10:44:46 2000 +++ linux/drivers/scsi/g_NCR5380.c Mon Sep 18 13:36:25 2000 @@ -885,12 +885,13 @@ #undef PRINTP #undef ANDP -#ifdef MODULE /* Eventually this will go into an include file, but this will be later */ -Scsi_Host_Template driver_template = GENERIC_NCR5380; +static Scsi_Host_Template driver_template = GENERIC_NCR5380; #include #include "scsi_module.c" + +#ifdef MODULE MODULE_PARM(ncr_irq, "i"); MODULE_PARM(ncr_dma, "i"); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/g_NCR5380.h linux/drivers/scsi/g_NCR5380.h --- v2.4.0-test8/linux/drivers/scsi/g_NCR5380.h Wed Dec 8 15:17:55 1999 +++ linux/drivers/scsi/g_NCR5380.h Mon Sep 18 14:25:56 2000 @@ -70,8 +70,6 @@ #define CAN_QUEUE 16 #endif -#if defined(HOSTS_C) || defined(MODULE) - #define GENERIC_NCR5380 { \ proc_info: generic_NCR5380_proc_info, \ name: "Generic NCR5380/NCR53C400 Scsi Driver", \ @@ -87,8 +85,6 @@ sg_tablesize: SG_ALL, \ cmd_per_lun: CMD_PER_LUN , \ use_clustering: DISABLE_CLUSTERING} - -#endif #ifndef HOSTS_C diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/gdth.c linux/drivers/scsi/gdth.c --- v2.4.0-test8/linux/drivers/scsi/gdth.c Mon Jun 26 18:06:55 2000 +++ linux/drivers/scsi/gdth.c Mon Sep 18 13:36:25 2000 @@ -3704,7 +3704,5 @@ } -#ifdef MODULE -Scsi_Host_Template driver_template = GDTH; +static Scsi_Host_Template driver_template = GDTH; #include "scsi_module.c" -#endif diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/gvp11.c linux/drivers/scsi/gvp11.c --- v2.4.0-test8/linux/drivers/scsi/gvp11.c Wed Jan 26 12:45:20 2000 +++ linux/drivers/scsi/gvp11.c Mon Sep 18 13:36:25 2000 @@ -352,17 +352,13 @@ } -#ifdef MODULE - #define HOSTS_C #include "gvp11.h" -Scsi_Host_Template driver_template = GVP11_SCSI; +static Scsi_Host_Template driver_template = GVP11_SCSI; #include "scsi_module.c" - -#endif int gvp11_release(struct Scsi_Host *instance) { diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c --- v2.4.0-test8/linux/drivers/scsi/hosts.c Tue Jul 11 11:17:45 2000 +++ linux/drivers/scsi/hosts.c Tue Sep 19 08:31:53 2000 @@ -11,6 +11,10 @@ * Jiffies wrap fixes (host->resetting), 3 Dec 1998 Andrea Arcangeli * Added QLOGIC QLA1280 SCSI controller kernel host support. * August 4, 1999 Fred Lewis, Intel DuPont + * + * Updated to reflect the new initialization scheme for the higher + * level of scsi drivers (sd/sr/st) + * September 17, 2000 Torben Mathiasen */ @@ -22,8 +26,6 @@ #define __NO_VERSION__ #include - -#include #include #include #include @@ -36,361 +38,8 @@ #include #include "scsi.h" - -#ifndef NULL -#define NULL 0L -#endif - -#define HOSTS_C - #include "hosts.h" -#if defined(CONFIG_A4000T_SCSI) || \ - defined(CONFIG_WARPENGINE_SCSI) || \ - defined(CONFIG_A4091_SCSI) || \ - defined (CONFIG_GVP_TURBO_SCSI) || \ - defined (CONFIG_BLZ603EPLUS_SCSI) -#define AMIGA7XXCONFIG -#endif - -#ifdef AMIGA7XXCONFIG -#include "amiga7xx.h" -#endif - -#ifdef CONFIG_MVME16x_SCSI -#include "mvme16x.h" -#endif - -#ifdef CONFIG_BVME6000_SCSI -#include "bvme6000.h" -#endif - -#ifdef CONFIG_SCSI_SIM710 -#include "sim710.h" -#endif - -#ifdef CONFIG_A3000_SCSI -#include "a3000.h" -#endif - -#ifdef CONFIG_A2091_SCSI -#include "a2091.h" -#endif - -#ifdef CONFIG_GVP11_SCSI -#include "gvp11.h" -#endif - -#ifdef CONFIG_CYBERSTORM_SCSI -#include "cyberstorm.h" -#endif - -#ifdef CONFIG_CYBERSTORMII_SCSI -#include "cyberstormII.h" -#endif - -#ifdef CONFIG_BLZ2060_SCSI -#include "blz2060.h" -#endif - -#ifdef CONFIG_BLZ1230_SCSI -#include "blz1230.h" -#endif - -#ifdef CONFIG_FASTLANE_SCSI -#include "fastlane.h" -#endif - -#ifdef CONFIG_OKTAGON_SCSI -#include "oktagon_esp.h" -#endif - -#ifdef CONFIG_ATARI_SCSI -#include "atari_scsi.h" -#endif - -#if defined(CONFIG_MAC_SCSI) || defined(CONFIG_MAC_SCSI_OLD) -#include "mac_scsi.h" -#endif - -#ifdef CONFIG_SUN3_SCSI -#include "sun3_scsi.h" -#endif - -#ifdef CONFIG_SCSI_MAC_ESP -#include "mac_esp.h" -#endif - -#ifdef CONFIG_SCSI_ADVANSYS -#include "advansys.h" -#endif - -#ifdef CONFIG_SCSI_AHA152X -#include "aha152x.h" -#endif - -#ifdef CONFIG_SCSI_AHA1542 -#include "aha1542.h" -#endif - -#ifdef CONFIG_SCSI_AHA1740 -#include "aha1740.h" -#endif - -#ifdef CONFIG_SCSI_AIC7XXX -#include "aic7xxx.h" -#endif - -#ifdef CONFIG_SCSI_IPS -#include "ips.h" -#endif - -#ifdef CONFIG_SCSI_BUSLOGIC -#include "BusLogic.h" -#endif - -#ifdef CONFIG_SCSI_EATA_DMA -#include "eata_dma.h" -#endif - -#ifdef CONFIG_SCSI_EATA_PIO -#include "eata_pio.h" -#endif - -#ifdef CONFIG_SCSI_U14_34F -#include "u14-34f.h" -#endif - -#ifdef CONFIG_SCSI_FD_MCS -#include "fd_mcs.h" -#endif - -#ifdef CONFIG_SCSI_FUTURE_DOMAIN -#include "fdomain.h" -#endif - -#ifdef CONFIG_SCSI_GENERIC_NCR5380 -#include "g_NCR5380.h" -#endif - -#ifdef CONFIG_SCSI_IN2000 -#include "in2000.h" -#endif - -#ifdef CONFIG_SCSI_PAS16 -#include "pas16.h" -#endif - -#ifdef CONFIG_SCSI_QLOGIC_FAS -#include "qlogicfas.h" -#endif - -#ifdef CONFIG_SCSI_QLOGIC_ISP -#include "qlogicisp.h" -#endif - -#ifdef CONFIG_SCSI_QLOGIC_FC -#include "qlogicfc.h" -#endif - -#ifdef CONFIG_SCSI_QLOGIC_1280 -#include "qla1280.h" -#endif - -#ifdef CONFIG_SCSI_SEAGATE -#include "seagate.h" -#endif - -#ifdef CONFIG_SCSI_T128 -#include "t128.h" -#endif - -#ifdef CONFIG_SCSI_DMX3191D -#include "dmx3191d.h" -#endif - -#ifdef CONFIG_SCSI_DTC3280 -#include "dtc.h" -#endif - -#ifdef CONFIG_SCSI_NCR53C7xx -#include "53c7,8xx.h" -#endif - -#ifdef CONFIG_SCSI_SYM53C8XX -#include "sym53c8xx.h" -#endif - -#ifdef CONFIG_SCSI_NCR53C8XX -#include "ncr53c8xx.h" -#endif - -#ifdef CONFIG_SCSI_ULTRASTOR -#include "ultrastor.h" -#endif - -#ifdef CONFIG_SCSI_7000FASST -#include "wd7000.h" -#endif - -#ifdef CONFIG_SCSI_MCA_53C9X -#include "mca_53c9x.h" -#endif - -#ifdef CONFIG_SCSI_IBMMCA -#include "ibmmca.h" -#endif - -#ifdef CONFIG_SCSI_EATA -#include "eata.h" -#endif - -#ifdef CONFIG_SCSI_NCR53C406A -#include "NCR53c406a.h" -#endif - -#ifdef CONFIG_SCSI_SYM53C416 -#include "sym53c416.h" -#endif - -#ifdef CONFIG_SCSI_DC390T -#include "dc390.h" -#endif - -#ifdef CONFIG_SCSI_AM53C974 -#include "AM53C974.h" -#endif - -#ifdef CONFIG_SCSI_MEGARAID -#include "megaraid.h" -#endif - -#ifdef CONFIG_SCSI_ACARD -#include "atp870u.h" -#endif - -#ifdef CONFIG_SCSI_SUNESP -#include "esp.h" -#endif - -#ifdef CONFIG_SCSI_SGIWD93 -#include "sgiwd93.h" -#endif - -#ifdef CONFIG_SCSI_QLOGICPTI -#include "qlogicpti.h" -#endif - -#ifdef CONFIG_BLK_DEV_IDESCSI -#include "ide-scsi.h" -#endif - -#ifdef CONFIG_SCSI_MESH -#include "mesh.h" -#endif - -#ifdef CONFIG_SCSI_MAC53C94 -#include "mac53c94.h" -#endif - -#ifdef CONFIG_SCSI_GDTH -#include "gdth.h" -#endif - -#ifdef CONFIG_SCSI_PCI2000 -#include "pci2000.h" -#endif - -#ifdef CONFIG_SCSI_PCI2220I -#include "pci2220i.h" -#endif - -#ifdef CONFIG_SCSI_PSI240I -#include "psi240i.h" -#endif - -#ifdef CONFIG_SCSI_PLUTO -#include "pluto.h" -#endif - -#ifdef CONFIG_SCSI_INITIO -#include "ini9100u.h" -#endif - -#ifdef CONFIG_SCSI_INIA100 -#include "inia100.h" -#endif - -#ifdef CONFIG_SCSI_DEBUG -#include "scsi_debug.h" -#endif - -#ifdef CONFIG_SCSI_ACORNSCSI_3 -#include "../acorn/scsi/acornscsi.h" -#endif - -#ifdef CONFIG_SCSI_CUMANA_1 -#include "../acorn/scsi/cumana_1.h" -#endif - -#ifdef CONFIG_SCSI_CUMANA_2 -#include "../acorn/scsi/cumana_2.h" -#endif - -#ifdef CONFIG_SCSI_ECOSCSI -#include "../acorn/scsi/ecoscsi.h" -#endif - -#ifdef CONFIG_SCSI_OAK1 -#include "../acorn/scsi/oak.h" -#endif - -#ifdef CONFIG_SCSI_POWERTECSCSI -#include "../acorn/scsi/powertec.h" -#endif - -#ifdef CONFIG_SCSI_ARXESCSI -#include "../acorn/scsi/arxescsi.h" -#endif - -#ifdef CONFIG_I2O_SCSI -#include "../i2o/i2o_scsi.h" -#endif - -#ifdef CONFIG_JAZZ_ESP -#include "jazz_esp.h" -#endif - -#ifdef CONFIG_SCSI_DECNCR -#include "dec_esp.h" -#endif - -#ifdef CONFIG_SUN3X_ESP -#include "sun3x_esp.h" -#endif - -#ifdef CONFIG_IPHASE5526 -#include "../net/fc/iph5526_scsi.h" -#endif - -#ifdef CONFIG_BLK_DEV_3W_XXXX_RAID -#include "3w-xxxx.h" -#endif - -/* - * Moved ppa driver to the end of the probe list - * since it is a removable host adapter. - * This means the parallel ZIP drive will not bump - * the order of the /dev/sd devices - campbell@torque.net - */ -#ifdef CONFIG_SCSI_PPA -#include "ppa.h" -#endif - -#ifdef CONFIG_SCSI_IMM -#include "imm.h" -#endif - /* static const char RCSid[] = "$Header: /vger/u4/cvs/linux/drivers/scsi/hosts.c,v 1.20 1996/12/12 19:18:32 davem Exp $"; */ @@ -422,281 +71,6 @@ Scsi_Host_Template * scsi_hosts = NULL; -static Scsi_Host_Template builtin_scsi_hosts[] = -{ -#ifdef CONFIG_AMIGA -#ifdef AMIGA7XXCONFIG - AMIGA7XX_SCSI, -#endif -#ifdef CONFIG_A3000_SCSI - A3000_SCSI, -#endif -#ifdef CONFIG_A2091_SCSI - A2091_SCSI, -#endif -#ifdef CONFIG_GVP11_SCSI - GVP11_SCSI, -#endif -#ifdef CONFIG_CYBERSTORM_SCSI - SCSI_CYBERSTORM, -#endif -#ifdef CONFIG_CYBERSTORMII_SCSI - SCSI_CYBERSTORMII, -#endif -#ifdef CONFIG_BLZ2060_SCSI - SCSI_BLZ2060, -#endif -#ifdef CONFIG_BLZ1230_SCSI - SCSI_BLZ1230, -#endif -#ifdef CONFIG_FASTLANE_SCSI - SCSI_FASTLANE, -#endif -#ifdef CONFIG_OKTAGON_SCSI - SCSI_OKTAGON_ESP, -#endif -#endif - -#ifdef CONFIG_ATARI -#ifdef CONFIG_ATARI_SCSI - ATARI_SCSI, -#endif -#endif - -#ifdef CONFIG_MAC -#ifdef CONFIG_MAC_SCSI_OLD - MAC_SCSI, -#endif -#ifdef CONFIG_SCSI_MAC_ESP - SCSI_MAC_ESP, -#endif -#ifdef CONFIG_MAC_SCSI - MAC_NCR5380, -#endif -#endif - -#ifdef CONFIG_SUN3_SCSI - SUN3_NCR5380, -#endif - -#ifdef CONFIG_MVME16x_SCSI - MVME16x_SCSI, -#endif -#ifdef CONFIG_BVME6000_SCSI - BVME6000_SCSI, -#endif -#ifdef CONFIG_SCSI_SIM710 - SIM710_SCSI, -#endif -#ifdef CONFIG_SCSI_ADVANSYS - ADVANSYS, -#endif - -#ifdef CONFIG_SCSI_PCI2000 - PCI2000, -#endif -#ifdef CONFIG_SCSI_PCI2220I - PCI2220I, -#endif -#ifdef CONFIG_SCSI_PSI240I - PSI240I, -#endif - -/* BusLogic must come before aha1542.c */ -#ifdef CONFIG_SCSI_BUSLOGIC - BUSLOGIC, -#endif -#ifdef CONFIG_SCSI_U14_34F - ULTRASTOR_14_34F, -#endif -#ifdef CONFIG_SCSI_ULTRASTOR - ULTRASTOR_14F, -#endif -#ifdef CONFIG_SCSI_AHA152X - AHA152X, -#endif -#ifdef CONFIG_SCSI_AHA1542 - AHA1542, -#endif -#ifdef CONFIG_SCSI_AHA1740 - AHA1740, -#endif -#ifdef CONFIG_SCSI_AIC7XXX - AIC7XXX, -#endif -#ifdef CONFIG_SCSI_IPS - IPS, -#endif -#ifdef CONFIG_SCSI_FD_MCS - FD_MCS, -#endif -#ifdef CONFIG_SCSI_FUTURE_DOMAIN - FDOMAIN_16X0, -#endif -#ifdef CONFIG_SCSI_IN2000 - IN2000, -#endif -#ifdef CONFIG_SCSI_GENERIC_NCR5380 - GENERIC_NCR5380, -#endif -#ifdef CONFIG_SCSI_NCR53C406A /* 53C406A should come before QLOGIC */ - NCR53c406a, -#endif -#ifdef CONFIG_SCSI_SYM53C416 - SYM53C416, -#endif -#ifdef CONFIG_SCSI_QLOGIC_FAS - QLOGICFAS, -#endif -#ifdef CONFIG_SCSI_QLOGIC_ISP - QLOGICISP, -#endif -#ifdef CONFIG_SCSI_QLOGIC_FC - QLOGICFC, -#endif -#ifdef CONFIG_SCSI_QLOGIC_1280 - QLA1280_LINUX_TEMPLATE, -#endif -#ifdef CONFIG_SCSI_PAS16 - MV_PAS16, -#endif -#ifdef CONFIG_SCSI_SEAGATE - SEAGATE_ST0X, -#endif -#ifdef CONFIG_SCSI_T128 - TRANTOR_T128, -#endif -#ifdef CONFIG_SCSI_DMX3191D - DMX3191D, -#endif -#ifdef CONFIG_SCSI_DTC3280 - DTC3x80, -#endif -#ifdef CONFIG_SCSI_NCR53C7xx - NCR53c7xx, -#endif -#ifdef CONFIG_SCSI_SYM53C8XX - SYM53C8XX, -#endif -#ifdef CONFIG_SCSI_NCR53C8XX - NCR53C8XX, -#endif -#ifdef CONFIG_SCSI_EATA_DMA - EATA_DMA, -#endif -#ifdef CONFIG_SCSI_EATA_PIO - EATA_PIO, -#endif -#ifdef CONFIG_SCSI_7000FASST - WD7000, -#endif -#ifdef CONFIG_SCSI_MCA_53C9X - MCA_53C9X, -#endif -#ifdef CONFIG_SCSI_IBMMCA - IBMMCA, -#endif -#ifdef CONFIG_SCSI_EATA - EATA, -#endif -#ifdef CONFIG_SCSI_DC390T - DC390_T, -#endif -#ifdef CONFIG_SCSI_AM53C974 - AM53C974, -#endif -#ifdef CONFIG_SCSI_MEGARAID - MEGARAID, -#endif -#ifdef CONFIG_SCSI_ACARD - ATP870U, -#endif -#ifdef CONFIG_SCSI_SUNESP - SCSI_SPARC_ESP, -#endif -#ifdef CONFIG_SCSI_GDTH - GDTH, -#endif -#ifdef CONFIG_SCSI_INITIO - INI9100U, -#endif -#ifdef CONFIG_SCSI_INIA100 - INIA100, -#endif -#ifdef CONFIG_SCSI_QLOGICPTI - QLOGICPTI, -#endif -#ifdef CONFIG_BLK_DEV_IDESCSI - IDESCSI, -#endif -#ifdef CONFIG_SCSI_MESH - SCSI_MESH, -#endif -#ifdef CONFIG_SCSI_MAC53C94 - SCSI_MAC53C94, -#endif -#ifdef CONFIG_SCSI_PLUTO - PLUTO, -#endif -#ifdef CONFIG_ARCH_ACORN -#ifdef CONFIG_SCSI_ACORNSCSI_3 - ACORNSCSI_3, -#endif -#ifdef CONFIG_SCSI_CUMANA_1 - CUMANA_NCR5380, -#endif -#ifdef CONFIG_SCSI_CUMANA_2 - CUMANA_FAS216, -#endif -#ifdef CONFIG_SCSI_ARXESCSI - ARXEScsi, -#endif -#ifdef CONFIG_SCSI_ECOSCSI - ECOSCSI_NCR5380, -#endif -#ifdef CONFIG_SCSI_OAK1 - OAK_NCR5380, -#endif -#ifdef CONFIG_SCSI_POWERTECSCSI - POWERTECSCSI, -#endif -#endif -#ifdef CONFIG_IPHASE5526 - IPH5526_SCSI_FC, -#endif -#ifdef CONFIG_SCSI_DECNCR - SCSI_DEC_ESP, -#endif -#ifdef CONFIG_BLK_DEV_3W_XXXX_RAID - TWXXXX, -#endif -/* Put I2O last so that host specific controllers always win */ -#ifdef CONFIG_I2O_SCSI - I2OSCSI, -#endif -/* "Removable host adapters" below this line (Parallel Port/USB/other) */ -#ifdef CONFIG_SCSI_PPA - PPA, -#endif -#ifdef CONFIG_SCSI_IMM - IMM, -#endif -#ifdef CONFIG_SCSI_SGIWD93 - SGIWD93_SCSI, -#endif -#ifdef CONFIG_JAZZ_ESP - SCSI_JAZZ_ESP, -#endif -#ifdef CONFIG_SUN3X_ESP - SCSI_SUN3X_ESP, -#endif -#ifdef CONFIG_SCSI_DEBUG - SCSI_DEBUG, -#endif -}; - -#define MAX_SCSI_HOSTS (sizeof(builtin_scsi_hosts) / sizeof(Scsi_Host_Template)) - /* * Our semaphores and timeout counters, where size depends on @@ -771,12 +145,12 @@ hname = (tpnt->proc_name) ? tpnt->proc_name : ""; hname_len = strlen(hname); for (shn = scsi_host_no_list;shn;shn = shn->next) { - if (!(shn->host_registered) && shn->loaded_as_module && + if (!(shn->host_registered) && (hname_len > 0) && (0 == strncmp(hname, shn->name, hname_len))) { flag_new = 0; retval->host_no = shn->host_no; shn->host_registered = 1; - shn->loaded_as_module = scsi_loadable_module_flag; + shn->loaded_as_module = 1; break; } } @@ -785,7 +159,7 @@ retval->host_failed = 0; if(j > 0xffff) panic("Too many extra bytes requested\n"); retval->extra_bytes = j; - retval->loaded_as_module = scsi_loadable_module_flag; + retval->loaded_as_module = 1; if (flag_new) { shn = (Scsi_Host_Name *) kmalloc(sizeof(Scsi_Host_Name), GFP_ATOMIC); shn->name = kmalloc(hname_len + 1, GFP_ATOMIC); @@ -794,7 +168,7 @@ shn->name[hname_len] = 0; shn->host_no = max_scsi_hosts++; shn->host_registered = 1; - shn->loaded_as_module = scsi_loadable_module_flag; + shn->loaded_as_module = 1; shn->next = NULL; if (scsi_host_no_list) { for (shn2 = scsi_host_no_list;shn2->next;shn2 = shn2->next) @@ -886,135 +260,6 @@ if(sdpnt->next) panic("Device already registered"); sdpnt->next = scsi_devicelist; scsi_devicelist = sdpnt; - return 0; -} - -/* - * Why is this a separate function? Because the kernel_thread code - * effectively does a fork, and there is a builtin exit() call when - * the child returns. The difficulty is that scsi_init() is - * marked __init, which means the memory is unmapped after bootup - * is complete, which means that the thread's exit() call gets wiped. - * - * The lesson is to *NEVER*, *NEVER* call kernel_thread() from an - * __init function, if that function could ever return. - */ -static void launch_error_handler_thread(struct Scsi_Host * shpnt) -{ - DECLARE_MUTEX_LOCKED(sem); - - shpnt->eh_notify = &sem; - - kernel_thread((int (*)(void *))scsi_error_handler, - (void *) shpnt, 0); - - /* - * Now wait for the kernel error thread to initialize itself - * as it might be needed when we scan the bus. - */ - down (&sem); - shpnt->eh_notify = NULL; -} - -unsigned int __init scsi_init(void) -{ - static int called = 0; - int i, pcount; - unsigned long flags; - Scsi_Host_Template * tpnt; - struct Scsi_Host * shpnt; - const char * name; - - if(called) return 0; - - called = 1; - for (tpnt = &builtin_scsi_hosts[0], i = 0; i < MAX_SCSI_HOSTS; ++i, tpnt++) - { - /* - * Initialize our semaphores. -1 is interpreted to mean - * "inactive" - where as 0 will indicate a time out condition. - */ - - pcount = next_scsi_host; - if (tpnt->detect) { - - /* The detect routine must carefully spinunlock/spinlock if - it enables interrupts, since all interrupt handlers do - spinlock as well. - All lame drivers are going to fail due to the following - spinlock. For the time beeing let's use it only for drivers - using the new scsi code. NOTE: the detect routine could - redefine the value tpnt->use_new_eh_code. (DB, 13 May 1998) */ - - if (tpnt->use_new_eh_code) { - spin_lock_irqsave(&io_request_lock, flags); - tpnt->present = tpnt->detect(tpnt); - spin_unlock_irqrestore(&io_request_lock, flags); - } - else - tpnt->present = tpnt->detect(tpnt); - - } - - if (tpnt->detect && tpnt->present) - { - /* The only time this should come up is when people use - * some kind of patched driver of some kind or another. */ - if(pcount == next_scsi_host) { - if(tpnt->present > 1) - panic("Failure to register low-level scsi driver"); - /* The low-level driver failed to register a driver. We - * can do this now. */ - scsi_register(tpnt,0); - } - tpnt->next = scsi_hosts; - scsi_hosts = tpnt; - - /* Add the driver to /proc/scsi */ -#if CONFIG_PROC_FS - build_proc_dir_entries(tpnt); -#endif - } - } - - for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next) - { - if(shpnt->hostt->info) - name = shpnt->hostt->info(shpnt); - else - name = shpnt->hostt->name; - printk ("scsi%d : %s\n", /* And print a little message */ - shpnt->host_no, name); - - /* - * Now start the error recovery thread for the host. - */ - if( shpnt->hostt->use_new_eh_code ) - { - launch_error_handler_thread(shpnt); - } - } - - printk ("scsi : %d host%s.\n", next_scsi_host, - (next_scsi_host == 1) ? "" : "s"); - - /* Now attach the high level drivers */ -#ifdef CONFIG_BLK_DEV_SD - scsi_register_device(&sd_template); -#endif -#ifdef CONFIG_BLK_DEV_SR - scsi_register_device(&sr_template); -#endif -#ifdef CONFIG_CHR_DEV_ST - scsi_register_device(&st_template); -#endif -#ifdef CONFIG_CHR_DEV_SG - scsi_register_device(&sg_template); -#endif - -#if 0 - max_scsi_hosts = next_scsi_host; -#endif return 0; } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/hosts.h linux/drivers/scsi/hosts.h --- v2.4.0-test8/linux/drivers/scsi/hosts.h Fri Sep 8 12:54:34 2000 +++ linux/drivers/scsi/hosts.h Mon Oct 2 12:06:21 2000 @@ -459,7 +459,6 @@ extern int next_scsi_host; -extern int scsi_loadable_module_flag; unsigned int scsi_init(void); extern struct Scsi_Host * scsi_register(Scsi_Host_Template *, int j); extern void scsi_unregister(struct Scsi_Host * i); @@ -505,11 +504,6 @@ }; void scsi_initialize_queue(Scsi_Device * SDpnt, struct Scsi_Host * SHpnt); - -extern struct Scsi_Device_Template sd_template; -extern struct Scsi_Device_Template st_template; -extern struct Scsi_Device_Template sr_template; -extern struct Scsi_Device_Template sg_template; int scsi_register_device(struct Scsi_Device_Template * sdpnt); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/ibmmca.c linux/drivers/scsi/ibmmca.c --- v2.4.0-test8/linux/drivers/scsi/ibmmca.c Mon Jul 31 11:35:12 2000 +++ linux/drivers/scsi/ibmmca.c Mon Sep 18 13:36:25 2000 @@ -3294,12 +3294,10 @@ __setup("ibmmcascsi=", option_setup); #endif -#ifdef MODULE /* Eventually this will go into an include file, but this will be later */ -Scsi_Host_Template driver_template = IBMMCA; +static Scsi_Host_Template driver_template = IBMMCA; #include "scsi_module.c" -#endif /*--------------------------------------------------------------------*/ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/ide-scsi.c linux/drivers/scsi/ide-scsi.c --- v2.4.0-test8/linux/drivers/scsi/ide-scsi.c Thu Apr 13 22:50:32 2000 +++ linux/drivers/scsi/ide-scsi.c Thu Sep 21 13:22:05 2000 @@ -31,7 +31,6 @@ #define IDESCSI_VERSION "0.9" -#include #include #include #include @@ -582,16 +581,6 @@ failed = 0; while ((drive = ide_scan_devices (media[i], idescsi_driver.name, NULL, failed++)) != NULL) { -#ifndef CONFIG_BLK_DEV_IDETAPE - /* - * The Onstream DI-30 does not handle clean emulation, yet. - */ - if (strstr(drive->id->model, "OnStream DI-30")) { - printk("ide-tape: ide-scsi emulation is not supported for %s.\n", drive->id->model); - continue; - } -#endif /* CONFIG_BLK_DEV_IDETAPE */ - if ((scsi = (idescsi_scsi_t *) kmalloc (sizeof (idescsi_scsi_t), GFP_KERNEL)) == NULL) { printk (KERN_ERR "ide-scsi: %s: Can't allocate a scsi structure\n", drive->name); continue; @@ -827,18 +816,17 @@ return 0; } -#ifdef MODULE -Scsi_Host_Template idescsi_template = IDESCSI; +static Scsi_Host_Template idescsi_template = IDESCSI; -int init_module (void) +static int __init init_idescsi_module(void) { - idescsi_init (); - idescsi_template.module = &__this_module; + idescsi_init(); + idescsi_template.module = THIS_MODULE; scsi_register_module (MODULE_SCSI_HA, &idescsi_template); return 0; } -void cleanup_module (void) +static void __exit exit_idescsi_module(void) { ide_drive_t *drive; byte media[] = {TYPE_DISK, TYPE_TAPE, TYPE_PROCESSOR, TYPE_WORM, TYPE_ROM, TYPE_SCANNER, TYPE_MOD, 255}; @@ -855,4 +843,6 @@ } ide_unregister_module(&idescsi_module); } -#endif /* MODULE */ + +module_init(init_idescsi_module); +module_exit(exit_idescsi_module); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/imm.c linux/drivers/scsi/imm.c --- v2.4.0-test8/linux/drivers/scsi/imm.c Mon Jul 24 18:59:27 2000 +++ linux/drivers/scsi/imm.c Mon Sep 18 13:36:25 2000 @@ -114,10 +114,8 @@ * Parallel port probing routines * ***************************************************************************/ -#ifdef MODULE -Scsi_Host_Template driver_template = IMM; +static Scsi_Host_Template driver_template = IMM; #include "scsi_module.c" -#endif int imm_detect(Scsi_Host_Template * host) { diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/in2000.c linux/drivers/scsi/in2000.c --- v2.4.0-test8/linux/drivers/scsi/in2000.c Thu Nov 11 16:57:30 1999 +++ linux/drivers/scsi/in2000.c Mon Sep 18 13:36:25 2000 @@ -2359,11 +2359,6 @@ } -#ifdef MODULE - -Scsi_Host_Template driver_template = IN2000; - +static Scsi_Host_Template driver_template = IN2000; #include "scsi_module.c" - -#endif diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/ini9100u.c linux/drivers/scsi/ini9100u.c --- v2.4.0-test8/linux/drivers/scsi/ini9100u.c Mon Jun 19 13:42:40 2000 +++ linux/drivers/scsi/ini9100u.c Mon Sep 18 13:36:25 2000 @@ -143,10 +143,8 @@ unsigned int i91u_debug = DEBUG_DEFAULT; #endif -#ifdef MODULE -Scsi_Host_Template driver_template = INI9100U; +static Scsi_Host_Template driver_template = INI9100U; #include "scsi_module.c" -#endif char *i91uCopyright = "Copyright (C) 1996-98"; char *i91uInitioName = "by Initio Corporation"; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/inia100.c linux/drivers/scsi/inia100.c --- v2.4.0-test8/linux/drivers/scsi/inia100.c Wed Jul 5 17:57:27 2000 +++ linux/drivers/scsi/inia100.c Mon Sep 18 13:36:25 2000 @@ -92,10 +92,8 @@ #include #include "inia100.h" -#ifdef MODULE -Scsi_Host_Template driver_template = INIA100; +static Scsi_Host_Template driver_template = INIA100; #include "scsi_module.c" -#endif #define ORC_RDWORD(x,y) (short)(inl((int)((ULONG)((ULONG)x+(UCHAR)y)) )) diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/ips.c linux/drivers/scsi/ips.c --- v2.4.0-test8/linux/drivers/scsi/ips.c Fri Aug 4 17:58:10 2000 +++ linux/drivers/scsi/ips.c Tue Sep 19 08:01:34 2000 @@ -78,17 +78,40 @@ /* - Sync with other changes from the 2.3 kernels */ /* 4.00.06 - Fix timeout with initial FFDC command */ /* 4.00.06a - Port to 2.4 (trivial) -- Christoph Hellwig */ +/* 4.10.00 - Add support for ServeRAID 4M/4L */ +/* 4.10.13 - Fix for dynamic unload and proc file system */ +/* 4.20.03 - Rename version to coincide with new release schedules */ +/* Performance fixes */ +/* Fix truncation of /proc files with cat */ +/* Merge in changes through kernel 2.4.0test1ac21 */ +/* 4.20.13 - Fix some failure cases / reset code */ +/* - Hook into the reboot_notifier to flush the controller cache */ /* */ /*****************************************************************************/ /* * Conditional Compilation directives for this driver: * - * NO_IPS_RESET - Don't reset the controller (no matter what) - * IPS_DEBUG - More verbose error messages - * IPS_PCI_PROBE_DEBUG - Print out more detail on the PCI probe + * IPS_DEBUG - Turn on debugging info * + * + * Parameters: + * + * debug: - Set debug level to + * NOTE: only works when IPS_DEBUG compile directive + * is used. + * + * 1 - Normal debug messages + * 2 - Verbose debug messages + * 11 - Method trace (non interrupt) + * 12 - Method trace (includes interrupt) + * + * noreset - Don't reset the controller + * nocmdline - Turn off passthru support + * noi2o - Don't use I2O Queues (ServeRAID 4 only) + * nommap - Don't use memory mapped I/O */ + #include @@ -101,10 +124,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include @@ -127,25 +152,29 @@ #include #endif +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,13) +#include +#endif + #include +#ifdef MODULE + static char *ips = NULL; + MODULE_PARM(ips, "s"); +#endif + /* * DRIVER_VER */ -#define IPS_VERSION_HIGH "4.00" /* MUST be 4 chars */ -#define IPS_VERSION_LOW ".06 " /* MUST be 4 chars */ +#define IPS_VERSION_HIGH "4.20" +#define IPS_VERSION_LOW ".20 " #if LINUX_VERSION_CODE < LinuxVersionCode(2,3,27) struct proc_dir_entry proc_scsi_ips = { -#if !defined(PROC_SCSI_IPS) - 0, /* Use dynamic inode allocation */ -#else - PROC_SCSI_IPS, -#endif + 0, 3, "ips", S_IFDIR | S_IRUGO | S_IXUGO, 2 -} -; +}; #endif #if !defined(__i386__) @@ -160,12 +189,14 @@ #error "To use the command-line interface you need to define SG_BIG_BUFF" #endif -#if IPS_DEBUG >= 12 - #define DBG(s) printk(KERN_NOTICE s "\n"); MDELAY(2*IPS_ONE_SEC) -#elif IPS_DEBUG >= 11 - #define DBG(s) printk(KERN_NOTICE s "\n") +#ifdef IPS_DEBUG + #define METHOD_TRACE(s, i) if (ips_debug >= (i+10)) printk(KERN_NOTICE s "\n"); + #define DEBUG(i, s) if (ips_debug >= i) printk(KERN_NOTICE s "\n"); + #define DEBUG_VAR(i, s, v...) if (ips_debug >= i) printk(KERN_NOTICE s "\n", v); #else - #define DBG(s) + #define METHOD_TRACE(s, i) + #define DEBUG(i, s) + #define DEBUG_VAR(i, s, v...) #endif /* @@ -174,11 +205,26 @@ static const char * ips_name = "ips"; static struct Scsi_Host * ips_sh[IPS_MAX_ADAPTERS]; /* Array of host controller structures */ static ips_ha_t * ips_ha[IPS_MAX_ADAPTERS]; /* Array of HA structures */ +static unsigned int ips_next_controller = 0; static unsigned int ips_num_controllers = 0; +static unsigned int ips_released_controllers = 0; static int ips_cmd_timeout = 60; static int ips_reset_timeout = 60 * 5; +static int ips_force_memio = 1; /* Always use Memory Mapped I/O */ +static int ips_force_i2o = 1; /* Always use I2O command delivery */ +static int ips_resetcontroller = 1; /* Reset the controller */ +static int ips_cmdline = 1; /* Support for passthru */ + +#ifdef IPS_DEBUG +static int ips_debug = 0; /* Debug mode */ +#endif + +/* + * Necessary forward function protoypes + */ +static int ips_halt(struct notifier_block *nb, ulong event, void *buf); -#define MAX_ADAPTER_NAME 7 +#define MAX_ADAPTER_NAME 9 static char ips_adapter_name[][30] = { "ServeRAID", @@ -187,7 +233,13 @@ "ServeRAID on motherboard", "ServeRAID 3H", "ServeRAID 3L", - "ServeRAID 4H" + "ServeRAID 4H", + "ServeRAID 4M", + "ServeRAID 4L" +}; + +static struct notifier_block ips_notifier = { + ips_halt, NULL, 0 }; /* @@ -252,8 +304,6 @@ */ int ips_detect(Scsi_Host_Template *); int ips_release(struct Scsi_Host *); -int ips_abort(Scsi_Cmnd *); -int ips_reset(Scsi_Cmnd *, unsigned int); int ips_eh_abort(Scsi_Cmnd *); int ips_eh_reset(Scsi_Cmnd *); int ips_queue(Scsi_Cmnd *, void (*) (Scsi_Cmnd *)); @@ -261,21 +311,26 @@ const char * ips_info(struct Scsi_Host *); void do_ipsintr(int, void *, struct pt_regs *); static int ips_hainit(ips_ha_t *); -static int ips_map_status(ips_scb_t *, ips_stat_t *); +static int ips_map_status(ips_ha_t *, ips_scb_t *, ips_stat_t *); static int ips_send(ips_ha_t *, ips_scb_t *, ips_scb_callback); static int ips_send_wait(ips_ha_t *, ips_scb_t *, int, int); static int ips_send_cmd(ips_ha_t *, ips_scb_t *); -static int ips_chkstatus(ips_ha_t *); static int ips_online(ips_ha_t *, ips_scb_t *); static int ips_inquiry(ips_ha_t *, ips_scb_t *); static int ips_rdcap(ips_ha_t *, ips_scb_t *); static int ips_msense(ips_ha_t *, ips_scb_t *); static int ips_reqsen(ips_ha_t *, ips_scb_t *); static int ips_allocatescbs(ips_ha_t *); -static int ips_reset_adapter(ips_ha_t *); -static int ips_statupd(ips_ha_t *); -static int ips_issue(ips_ha_t *, ips_scb_t *); -static int ips_isintr(ips_ha_t *); +static int ips_reset_copperhead(ips_ha_t *); +static int ips_reset_copperhead_memio(ips_ha_t *); +static int ips_reset_morpheus(ips_ha_t *); +static int ips_issue_copperhead(ips_ha_t *, ips_scb_t *); +static int ips_issue_copperhead_memio(ips_ha_t *, ips_scb_t *); +static int ips_issue_i2o(ips_ha_t *, ips_scb_t *); +static int ips_issue_i2o_memio(ips_ha_t *, ips_scb_t *); +static int ips_isintr_copperhead(ips_ha_t *); +static int ips_isintr_copperhead_memio(ips_ha_t *); +static int ips_isintr_morpheus(ips_ha_t *); static int ips_wait(ips_ha_t *, int, int); static int ips_write_driver_status(ips_ha_t *, int); static int ips_read_adapter_status(ips_ha_t *, int); @@ -283,7 +338,22 @@ static int ips_read_config(ips_ha_t *, int); static int ips_clear_adapter(ips_ha_t *, int); static int ips_readwrite_page5(ips_ha_t *, int, int); -static void ips_intr(ips_ha_t *); +static int ips_init_copperhead(ips_ha_t *); +static int ips_init_copperhead_memio(ips_ha_t *); +static int ips_init_morpheus(ips_ha_t *); +static int ips_isinit_copperhead(ips_ha_t *); +static int ips_isinit_copperhead_memio(ips_ha_t *); +static int ips_isinit_morpheus(ips_ha_t *); +static u32 ips_statupd_copperhead(ips_ha_t *); +static u32 ips_statupd_copperhead_memio(ips_ha_t *); +static u32 ips_statupd_morpheus(ips_ha_t *); +static void ips_select_queue_depth(struct Scsi_Host *, Scsi_Device *); +static void ips_chkstatus(ips_ha_t *, IPS_STATUS *); +static void ips_enable_int_copperhead(ips_ha_t *); +static void ips_enable_int_copperhead_memio(ips_ha_t *); +static void ips_enable_int_morpheus(ips_ha_t *); +static void ips_intr_copperhead(ips_ha_t *); +static void ips_intr_morpheus(ips_ha_t *); static void ips_next(ips_ha_t *, int); static void ipsintr_blocking(ips_ha_t *, struct ips_scb *); static void ipsintr_done(ips_ha_t *, struct ips_scb *); @@ -292,6 +362,7 @@ static void ips_init_scb(ips_ha_t *, ips_scb_t *); static void ips_freescb(ips_ha_t *, ips_scb_t *); static void ips_statinit(ips_ha_t *); +static void ips_statinit_memio(ips_ha_t *); static void ips_fix_ffdc_time(ips_ha_t *, ips_scb_t *, time_t); static void ips_ffdc_reset(ips_ha_t *, int); static void ips_ffdc_time(ips_ha_t *, int); @@ -311,6 +382,9 @@ static int ips_erase_bios(ips_ha_t *); static int ips_program_bios(ips_ha_t *, char *, int); static int ips_verify_bios(ips_ha_t *, char *, int); +static int ips_erase_bios_memio(ips_ha_t *); +static int ips_program_bios_memio(ips_ha_t *, char *, int); +static int ips_verify_bios_memio(ips_ha_t *, char *, int); #ifndef NO_IPS_CMDLINE static int ips_is_passthru(Scsi_Cmnd *); @@ -331,6 +405,76 @@ /****************************************************************************/ /* */ +/* Routine Name: ips_setup */ +/* */ +/* Routine Description: */ +/* */ +/* setup parameters to the driver */ +/* */ +/****************************************************************************/ +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,13) +static int +ips_setup(char *ips_str) { +#else +void +ips_setup(char *ips_str, int *dummy) { +#endif + int i; + char *p; + char *key; + char *value; + char tokens[3] = {',', '.', 0}; + IPS_OPTION options[] = { + {"noreset", &ips_resetcontroller, 0}, +#ifdef IPS_DEBUG + {"debug", &ips_debug, 1}, +#endif + {"noi2o", &ips_force_i2o, 0}, + {"nommap", &ips_force_memio, 0}, + {"nocmdline", &ips_cmdline, 0}, + }; + + METHOD_TRACE("ips_setup", 1); + + for (key = strtok(ips_str, tokens); key; key = strtok(NULL, tokens)) { + p = key; + + /* Search for value */ + while ((p) && (*p != ':')) + p++; + + if (p) { + *p = '\0'; + value = p+1; + } else + value = NULL; + + /* + * We now have key/value pairs. + * Update the variables + */ + for (i = 0; i < (sizeof(options) / sizeof(options[0])); i++) { + if (strnicmp(key, options[i].option_name, strlen(ips_str)) == 0) { + if (value) + *options[i].option_flag = simple_strtoul(value, NULL, 0); + else + *options[i].option_flag = options[i].option_value; + + break; + } + } + } +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,13) + return (1); +#endif +} + +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,13) +__setup("ips=", ips_setup); +#endif + +/****************************************************************************/ +/* */ /* Routine Name: ips_detect */ /* */ /* Routine Description: */ @@ -345,15 +489,38 @@ struct Scsi_Host *sh; ips_ha_t *ha; u32 io_addr; + u32 mem_addr; + u32 io_len; + u32 mem_len; u16 planer; u8 revision_id; u8 bus; u8 func; u8 irq; - int index; - struct pci_dev *dev = NULL; - - DBG("ips_detect"); + u16 deviceID[2]; + int i; + int j; + char *ioremap_ptr; + char *mem_ptr; + struct pci_dev *dev[2]; + struct pci_dev *morpheus = NULL; + struct pci_dev *trombone = NULL; +#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,14) + u32 currbar; + u32 maskbar; + u8 barnum; +#endif + + METHOD_TRACE("ips_detect", 1); + +#ifdef MODULE + if (ips) +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,13) + ips_setup(ips); +#else + ips_setup(ips, NULL); +#endif +#endif SHT->proc_info = ips_proc_info; #if LINUX_VERSION_CODE < LinuxVersionCode(2,3,27) @@ -363,226 +530,524 @@ #endif #if defined(CONFIG_PCI) - + /* initalize number of controllers */ ips_num_controllers = 0; - + ips_next_controller = 0; + ips_released_controllers = 0; + if (!pci_present()) return (0); - for (index = 0; index < IPS_MAX_ADAPTERS; index++) { + morpheus = pci_find_device(IPS_VENDORID, IPS_MORPHEUS_DEVICEID, morpheus); + trombone = pci_find_device(IPS_VENDORID, IPS_COPPERHEAD_DEVICEID, trombone); + + /* determine which controller to probe first */ + if (!morpheus) { + /* we only have trombone */ + dev[0] = trombone; + dev[1] = NULL; + deviceID[0] = IPS_COPPERHEAD_DEVICEID; + } else if (!trombone) { + /* we only have morpheus */ + dev[0] = morpheus; + dev[1] = NULL; + deviceID[0] = IPS_MORPHEUS_DEVICEID; + } else { + /* we have both in the system */ + if (trombone->bus < morpheus->bus) { + dev[0] = trombone; + dev[1] = morpheus; + deviceID[0] = IPS_COPPERHEAD_DEVICEID; + deviceID[1] = IPS_MORPHEUS_DEVICEID; + } else if (trombone->bus > morpheus->bus) { + dev[0] = morpheus; + dev[1] = trombone; + deviceID[0] = IPS_MORPHEUS_DEVICEID; + deviceID[1] = IPS_COPPERHEAD_DEVICEID; + } else { + /* further detection required */ + if (trombone->devfn < morpheus->devfn) { + dev[0] = trombone; + dev[1] = morpheus; + deviceID[0] = IPS_COPPERHEAD_DEVICEID; + deviceID[1] = IPS_MORPHEUS_DEVICEID; + } else { + dev[0] = morpheus; + dev[1] = trombone; + deviceID[0] = IPS_MORPHEUS_DEVICEID; + deviceID[1] = IPS_COPPERHEAD_DEVICEID; + } + } + } - if (!(dev = pci_find_device(IPS_VENDORID, IPS_DEVICEID, dev))) + /* Now scan the controllers */ + for (i = 0; i < 2; i++) { + if (!dev[i]) break; - if (pci_enable_device(dev)) - break; - - /* stuff that we get in dev */ - irq = dev->irq; - bus = dev->bus->number; - func = dev->devfn; - io_addr = pci_resource_start(dev, 0); - - /* check I/O address */ - if (pci_resource_flags(dev, 0) & IORESOURCE_MEM) - continue; + do { + if (ips_next_controller >= IPS_MAX_ADAPTERS) + break; - /* get planer status */ - if (pci_read_config_word(dev, 0x04, &planer)) { - printk(KERN_WARNING "(%s%d) can't get planer status.\n", - ips_name, index); - continue; - } +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0) + if (pci_enable_device(dev[i])) + break; +#endif - /* check to see if an onboard planer controller is disabled */ - if (!(planer & 0x000C)) { + /* stuff that we get in dev */ + irq = dev[i]->irq; + bus = dev[i]->bus->number; + func = dev[i]->devfn; + + /* Init MEM/IO addresses to 0 */ + mem_addr = 0; + io_addr = 0; + mem_len = 0; + io_len = 0; + + for (j = 0; j < 2; j++) { +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0) + if (!pci_resource_start(dev[i], j)) + break; - #ifdef IPS_PCI_PROBE_DEBUG - printk(KERN_NOTICE "(%s%d) detect, Onboard ServeRAID disabled by BIOS\n", - ips_name, index); - #endif + if (pci_resource_flags(dev[i], j) & IORESOURCE_IO) { + io_addr = pci_resource_start(dev[i], j); + io_len = pci_resource_len(dev[i], j); + } else { + mem_addr = pci_resource_start(dev[i], j); + mem_len = pci_resource_len(dev[i], j); + } +#elif LINUX_VERSION_CODE >= LinuxVersionCode(2,3,14) + if (!dev[i]->resource[j].start) + break; - continue; - } + if ((dev[i]->resource[j].start & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) { + io_addr = dev[i]->resource[j].start; + io_len = dev[i]->resource[j].end - dev[i]->resource[j].start + 1; + } else { + mem_addr = dev[i]->resource[j].start; + mem_len = dev[i]->resource[j].end - dev[i]->resource[j].start + 1; + } +#else + if (!dev[i]->base_address[j]) + break; - #ifdef IPS_PCI_PROBE_DEBUG - printk(KERN_NOTICE "(%s%d) detect bus %d, func %x, irq %d, io %x\n", - ips_name, index, bus, func, irq, io_addr); - #endif - - /* get the revision ID */ - if (pci_read_config_byte(dev, 0x08, &revision_id)) { - printk(KERN_WARNING "(%s%d) can't get revision id.\n", - ips_name, index); + if ((dev[i]->base_address[j] & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) { + barnum = PCI_BASE_ADDRESS_0 + (j * 4); + io_addr = dev[i]->base_address[j] & PCI_BASE_ADDRESS_IO_MASK; + + /* Get Size */ + pci_read_config_dword(dev[i], barnum, &currbar); + pci_write_config_dword(dev[i], barnum, ~0); + pci_read_config_dword(dev[i], barnum, &maskbar); + pci_write_config_dword(dev[i], barnum, currbar); - continue; - } + io_len = ~(maskbar & PCI_BASE_ADDRESS_IO_MASK) + 1; + } else { + barnum = PCI_BASE_ADDRESS_0 + (j * 4); + mem_addr = dev[i]->base_address[j] & PCI_BASE_ADDRESS_MEM_MASK; - /* found a controller */ - sh = scsi_register(SHT, sizeof(ips_ha_t)); + /* Get Size */ + pci_read_config_dword(dev[i], barnum, &currbar); + pci_write_config_dword(dev[i], barnum, ~0); + pci_read_config_dword(dev[i], barnum, &maskbar); + pci_write_config_dword(dev[i], barnum, currbar); - if (sh == NULL) { - printk(KERN_WARNING "(%s%d) Unable to register controller with SCSI subsystem - skipping controller\n", - ips_name, index); + mem_len = ~(maskbar & PCI_BASE_ADDRESS_MEM_MASK) + 1; + } +#endif + } - continue; - } + /* setup memory mapped area (if applicable) */ + if (mem_addr) { + u32 base; + u32 offs; + + DEBUG_VAR(1, "(%s%d) detect, Memory region %x, size: %d", + ips_name, ips_next_controller, mem_addr, mem_len); + +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,17) + if (check_mem_region(mem_addr, mem_len)) { + /* Couldn't allocate io space */ + printk(KERN_WARNING "(%s%d) couldn't allocate IO space %x len %d.\n", + ips_name, ips_next_controller, io_addr, io_len); - ha = IPS_HA(sh); - memset(ha, 0, sizeof(ips_ha_t)); + ips_next_controller++; - /* Initialize spin lock */ - spin_lock_init(&ha->scb_lock); - spin_lock_init(&ha->copp_lock); - spin_lock_init(&ha->ips_lock); - spin_lock_init(&ha->copp_waitlist.lock); - spin_lock_init(&ha->scb_waitlist.lock); - spin_lock_init(&ha->scb_activelist.lock); - - ips_sh[ips_num_controllers] = sh; - ips_ha[ips_num_controllers] = ha; - ips_num_controllers++; - ha->active = 1; - - ha->enq = kmalloc(sizeof(IPS_ENQ), GFP_KERNEL|GFP_DMA); - - if (!ha->enq) { - printk(KERN_WARNING "(%s%d) Unable to allocate host inquiry structure - skipping contoller\n", - ips_name, index); + continue; + } - ha->active = 0; + request_mem_region(mem_addr, mem_len, "ips"); +#endif - continue; - } + base = mem_addr & PAGE_MASK; + offs = mem_addr - base; - ha->adapt = kmalloc(sizeof(IPS_ADAPTER), GFP_KERNEL|GFP_DMA); + ioremap_ptr = ioremap(base, PAGE_SIZE); + mem_ptr = ioremap_ptr + offs; + } else { + ioremap_ptr = NULL; + mem_ptr = NULL; + } - if (!ha->adapt) { - printk(KERN_WARNING "(%s%d) Unable to allocate host adapt structure - skipping controller\n", - ips_name, index); + /* setup I/O mapped area (if applicable) */ + if (io_addr) { + DEBUG_VAR(1, "(%s%d) detect, IO region %x, size: %d", + ips_name, ips_next_controller, io_addr, io_len); + + if (check_region(io_addr, io_len)) { + /* Couldn't allocate io space */ + printk(KERN_WARNING "(%s%d) couldn't allocate IO space %x len %d.\n", + ips_name, ips_next_controller, io_addr, io_len); - ha->active = 0; + ips_next_controller++; - continue; - } + continue; + } - ha->conf = kmalloc(sizeof(IPS_CONF), GFP_KERNEL|GFP_DMA); + request_region(io_addr, io_len, "ips"); + } - if (!ha->conf) { - printk(KERN_WARNING "(%s%d) Unable to allocate host conf structure - skipping controller\n", - ips_name, index); + /* get planer status */ + if (pci_read_config_word(dev[i], 0x04, &planer)) { + printk(KERN_WARNING "(%s%d) can't get planer status.\n", + ips_name, ips_next_controller); - ha->active = 0; + ips_next_controller++; - continue; - } + continue; + } + + /* check to see if an onboard planer controller is disabled */ + if (!(planer & 0x000C)) { - ha->nvram = kmalloc(sizeof(IPS_NVRAM_P5), GFP_KERNEL|GFP_DMA); + DEBUG_VAR(1, "(%s%d) detect, Onboard ServeRAID disabled by BIOS", + ips_name, ips_next_controller); - if (!ha->nvram) { - printk(KERN_WARNING "(%s%d) Unable to allocate host nvram structure - skipping controller\n", - ips_name, index); + ips_next_controller++; - ha->active = 0; + continue; + } - continue; - } + DEBUG_VAR(1, "(%s%d) detect bus %d, func %x, irq %d, io %x, mem: %x, ptr: %x", + ips_name, ips_next_controller, bus, func, irq, io_addr, mem_addr, (u32) mem_ptr); - ha->subsys = kmalloc(sizeof(IPS_SUBSYS), GFP_KERNEL|GFP_DMA); + /* get the revision ID */ + if (pci_read_config_byte(dev[i], 0x08, &revision_id)) { + printk(KERN_WARNING "(%s%d) can't get revision id.\n", + ips_name, ips_next_controller); - if (!ha->subsys) { - printk(KERN_WARNING "(%s%d) Unable to allocate host subsystem structure - skipping controller\n", - ips_name, index); + ips_next_controller++; - ha->active = 0; + continue; + } - continue; - } + /* found a controller */ + sh = scsi_register(SHT, sizeof(ips_ha_t)); - ha->dummy = kmalloc(sizeof(IPS_IO_CMD), GFP_KERNEL|GFP_DMA); + if (sh == NULL) { + printk(KERN_WARNING "(%s%d) Unable to register controller with SCSI subsystem - skipping controller\n", + ips_name, ips_next_controller); - if (!ha->dummy) { - printk(KERN_WARNING "(%s%d) Unable to allocate host dummy structure - skipping controller\n", - ips_name, index); + ips_next_controller++; - ha->active = 0; + continue; + } - continue; - } + ha = IPS_HA(sh); + memset(ha, 0, sizeof(ips_ha_t)); - ha->ioctl_data = kmalloc(IPS_IOCTL_SIZE, GFP_KERNEL|GFP_DMA); - ha->ioctl_datasize = IPS_IOCTL_SIZE; - if (!ha->ioctl_data) { - printk(KERN_WARNING "(%s%d) Unable to allocate ioctl data - skipping controller\n", - ips_name, index); + /* Initialize spin lock */ + spin_lock_init(&ha->scb_lock); + spin_lock_init(&ha->copp_lock); + spin_lock_init(&ha->ips_lock); + spin_lock_init(&ha->copp_waitlist.lock); + spin_lock_init(&ha->scb_waitlist.lock); + spin_lock_init(&ha->scb_activelist.lock); + + ips_sh[ips_next_controller] = sh; + ips_ha[ips_next_controller] = ha; + ips_num_controllers++; + ha->active = 1; + + ha->enq = kmalloc(sizeof(IPS_ENQ), GFP_ATOMIC|GFP_DMA); + + if (!ha->enq) { + printk(KERN_WARNING "(%s%d) Unable to allocate host inquiry structure - skipping contoller\n", + ips_name, ips_next_controller); + + ha->active = 0; + ips_free(ha); + ips_next_controller++; + ips_num_controllers--; - ha->active = 0; + continue; + } - continue; - } + ha->adapt = kmalloc(sizeof(IPS_ADAPTER), GFP_ATOMIC|GFP_DMA); - /* Store away needed values for later use */ - sh->io_port = io_addr; - sh->n_io_port = 255; - sh->unique_id = io_addr; - sh->irq = irq; - sh->select_queue_depths = NULL; - sh->sg_tablesize = sh->hostt->sg_tablesize; - sh->can_queue = sh->hostt->can_queue; - sh->cmd_per_lun = sh->hostt->cmd_per_lun; - sh->unchecked_isa_dma = sh->hostt->unchecked_isa_dma; - sh->use_clustering = sh->hostt->use_clustering; - - /* Store info in HA structure */ - ha->io_addr = io_addr; - ha->irq = irq; - ha->host_num = index; - ha->revision_id = revision_id; - - /* install the interrupt handler */ - if (request_irq(irq, do_ipsintr, SA_SHIRQ, ips_name, ha)) { - printk(KERN_WARNING "(%s%d) unable to install interrupt handler - skipping controller\n", - ips_name, index); + if (!ha->adapt) { + printk(KERN_WARNING "(%s%d) Unable to allocate host adapt structure - skipping controller\n", + ips_name, ips_next_controller); + ha->active = 0; + ips_free(ha); + ips_next_controller++; + ips_num_controllers--; - ha->active = 0; + continue; + } - continue; - } + ha->conf = kmalloc(sizeof(IPS_CONF), GFP_ATOMIC|GFP_DMA); - /* - * Allocate a temporary SCB for initialization - */ - ha->scbs = (ips_scb_t *) kmalloc(sizeof(ips_scb_t), GFP_KERNEL|GFP_DMA); - if (!ha->scbs) { - /* couldn't allocate a temp SCB */ - printk(KERN_WARNING "(%s%d) unable to allocate CCBs - skipping contoller\n", - ips_name, index); + if (!ha->conf) { + printk(KERN_WARNING "(%s%d) Unable to allocate host conf structure - skipping controller\n", + ips_name, ips_next_controller); + + ha->active = 0; + ips_free(ha); + ips_next_controller++; + ips_num_controllers--; - ha->active = 0; + continue; + } - continue; - } + ha->nvram = kmalloc(sizeof(IPS_NVRAM_P5), GFP_ATOMIC|GFP_DMA); - memset(ha->scbs, 0, sizeof(ips_scb_t)); - ha->scbs->sg_list = (IPS_SG_LIST *) kmalloc(sizeof(IPS_SG_LIST) * IPS_MAX_SG, GFP_KERNEL|GFP_DMA); - if (!ha->scbs->sg_list) { - /* couldn't allocate a temp SCB S/G list */ - printk(KERN_WARNING "(%s%d) unable to allocate CCBs - skipping contoller\n", - ips_name, index); + if (!ha->nvram) { + printk(KERN_WARNING "(%s%d) Unable to allocate host nvram structure - skipping controller\n", + ips_name, ips_next_controller); + + ha->active = 0; + ips_free(ha); + ips_next_controller++; + ips_num_controllers--; - ha->active = 0; + continue; + } + + ha->subsys = kmalloc(sizeof(IPS_SUBSYS), GFP_ATOMIC|GFP_DMA); + + if (!ha->subsys) { + printk(KERN_WARNING "(%s%d) Unable to allocate host subsystem structure - skipping controller\n", + ips_name, ips_next_controller); + + ha->active = 0; + ips_free(ha); + ips_next_controller++; + ips_num_controllers--; + + continue; + } + + ha->dummy = kmalloc(sizeof(IPS_IO_CMD), GFP_ATOMIC|GFP_DMA); + + if (!ha->dummy) { + printk(KERN_WARNING "(%s%d) Unable to allocate host dummy structure - skipping controller\n", + ips_name, ips_next_controller); + + ha->active = 0; + ips_free(ha); + ips_next_controller++; + ips_num_controllers--; + + continue; + } + + ha->ioctl_data = kmalloc(IPS_IOCTL_SIZE, GFP_ATOMIC|GFP_DMA); + ha->ioctl_datasize = IPS_IOCTL_SIZE; + if (!ha->ioctl_data) { + printk(KERN_WARNING "(%s%d) Unable to allocate ioctl data - skipping controller\n", + ips_name, ips_next_controller); + + ha->active = 0; + ips_free(ha); + ips_next_controller++; + ips_num_controllers--; + + continue; + } + + /* Store away needed values for later use */ + sh->io_port = io_addr; + sh->n_io_port = io_addr ? 255 : 0; + sh->unique_id = (io_addr) ? io_addr : mem_addr; + sh->irq = irq; + sh->select_queue_depths = ips_select_queue_depth; + sh->sg_tablesize = sh->hostt->sg_tablesize; + sh->can_queue = sh->hostt->can_queue; + sh->cmd_per_lun = sh->hostt->cmd_per_lun; + sh->unchecked_isa_dma = sh->hostt->unchecked_isa_dma; + sh->use_clustering = sh->hostt->use_clustering; + +#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,32) + sh->wish_block = FALSE; +#endif + + /* Store info in HA structure */ + ha->irq = irq; + ha->io_addr = io_addr; + ha->io_len = io_len; + ha->mem_addr = mem_addr; + ha->mem_len = mem_len; + ha->mem_ptr = mem_ptr; + ha->ioremap_ptr = ioremap_ptr; + ha->host_num = ips_next_controller; + ha->revision_id = revision_id; + ha->device_id = deviceID[i]; + ha->pcidev = dev[i]; + + /* + * Setup Functions + */ + if (IPS_IS_MORPHEUS(ha)) { + /* morpheus */ + ha->func.isintr = ips_isintr_morpheus; + ha->func.isinit = ips_isinit_morpheus; + ha->func.issue = ips_issue_i2o_memio; + ha->func.init = ips_init_morpheus; + ha->func.statupd = ips_statupd_morpheus; + ha->func.reset = ips_reset_morpheus; + ha->func.intr = ips_intr_morpheus; + ha->func.enableint = ips_enable_int_morpheus; + } else if (IPS_USE_MEMIO(ha)) { + /* copperhead w/MEMIO */ + ha->func.isintr = ips_isintr_copperhead_memio; + ha->func.isinit = ips_isinit_copperhead_memio; + ha->func.init = ips_init_copperhead_memio; + ha->func.statupd = ips_statupd_copperhead_memio; + ha->func.statinit = ips_statinit_memio; + ha->func.reset = ips_reset_copperhead_memio; + ha->func.intr = ips_intr_copperhead; + ha->func.erasebios = ips_erase_bios_memio; + ha->func.programbios = ips_program_bios_memio; + ha->func.verifybios = ips_verify_bios_memio; + ha->func.enableint = ips_enable_int_copperhead_memio; + + if (IPS_USE_I2O_DELIVER(ha)) + ha->func.issue = ips_issue_i2o_memio; + else + ha->func.issue = ips_issue_copperhead_memio; + } else { + /* copperhead */ + ha->func.isintr = ips_isintr_copperhead; + ha->func.isinit = ips_isinit_copperhead; + ha->func.init = ips_init_copperhead; + ha->func.statupd = ips_statupd_copperhead; + ha->func.statinit = ips_statinit; + ha->func.reset = ips_reset_copperhead; + ha->func.intr = ips_intr_copperhead; + ha->func.erasebios = ips_erase_bios; + ha->func.programbios = ips_program_bios; + ha->func.verifybios = ips_verify_bios; + ha->func.enableint = ips_enable_int_copperhead; + + if (IPS_USE_I2O_DELIVER(ha)) + ha->func.issue = ips_issue_i2o; + else + ha->func.issue = ips_issue_copperhead; + } + + /* + * Initialize the card if it isn't already + */ + if (!(*ha->func.isinit)(ha)) { + if (!(*ha->func.init)(ha)) { + /* + * Initialization failed + */ + printk(KERN_WARNING "(%s%d) unable to initialize controller - skipping controller\n", + ips_name, ips_next_controller); + + ha->active = 0; + ips_free(ha); + ips_next_controller++; + ips_num_controllers--; + + continue; + } + } + + /* install the interrupt handler */ + if (request_irq(irq, do_ipsintr, SA_SHIRQ, ips_name, ha)) { + printk(KERN_WARNING "(%s%d) unable to install interrupt handler - skipping controller\n", + ips_name, ips_next_controller); + + ha->active = 0; + ips_free(ha); + ips_next_controller++; + ips_num_controllers--; + + continue; + } + + /* + * Allocate a temporary SCB for initialization + */ + ha->scbs = (ips_scb_t *) kmalloc(sizeof(ips_scb_t), GFP_ATOMIC|GFP_DMA); + if (!ha->scbs) { + /* couldn't allocate a temp SCB */ + printk(KERN_WARNING "(%s%d) unable to allocate CCBs - skipping contoller\n", + ips_name, ips_next_controller); + + ha->active = 0; + ips_free(ha); + free_irq(ha->irq, ha); + ips_next_controller++; + ips_num_controllers--; + + continue; + } + + memset(ha->scbs, 0, sizeof(ips_scb_t)); + ha->scbs->sg_list = (IPS_SG_LIST *) kmalloc(sizeof(IPS_SG_LIST) * IPS_MAX_SG, GFP_ATOMIC|GFP_DMA); + if (!ha->scbs->sg_list) { + /* couldn't allocate a temp SCB S/G list */ + printk(KERN_WARNING "(%s%d) unable to allocate CCBs - skipping contoller\n", + ips_name, ips_next_controller); + + ha->active = 0; + ips_free(ha); + free_irq(ha->irq, ha); + ips_next_controller++; + ips_num_controllers--; + + continue; + } + + ha->max_cmds = 1; + + ips_next_controller++; + } while ((dev[i] = pci_find_device(IPS_VENDORID, deviceID[i], dev[i]))); + } + + /* + * Do Phase 2 Initialization + * Controller init + */ + for (i = 0; i < ips_next_controller; i++) { + ha = ips_ha[i]; + sh = ips_sh[i]; + + if (!ha->active) { + scsi_unregister(sh); + ips_ha[i] = NULL; + ips_sh[i] = NULL; continue; } - ha->max_cmds = 1; - if (!ips_hainit(ha)) { printk(KERN_WARNING "(%s%d) unable to initialize controller - skipping\n", - ips_name, index); + ips_name, i); ha->active = 0; + ips_free(ha); + free_irq(ha->irq, ha); + scsi_unregister(sh); + ips_ha[i] = NULL; + ips_sh[i] = NULL; + ips_num_controllers--; continue; } @@ -597,9 +1062,15 @@ /* allocate CCBs */ if (!ips_allocatescbs(ha)) { printk(KERN_WARNING "(%s%d) unable to allocate CCBs - skipping contoller\n", - ips_name, index); + ips_name, i); ha->active = 0; + ips_free(ha); + free_irq(ha->irq, ha); + scsi_unregister(sh); + ips_ha[i] = NULL; + ips_sh[i] = NULL; + ips_num_controllers--; continue; } @@ -607,9 +1078,12 @@ /* finish setting values */ sh->max_id = ha->ntargets; sh->max_lun = ha->nlun; - sh->max_channel = ha->nbus; + sh->max_channel = ha->nbus - 1; sh->can_queue = ha->max_cmds-1; - } /* end for */ + } + + if (ips_num_controllers > 0) + register_reboot_notifier(&ips_notifier); return (ips_num_controllers); @@ -635,7 +1109,7 @@ ips_ha_t *ha; int i; - DBG("ips_release"); + METHOD_TRACE("ips_release", 1); for (i = 0; i < IPS_MAX_ADAPTERS && ips_sh[i] != sh; i++); @@ -678,17 +1152,85 @@ /* free extra memory */ ips_free(ha); + /* Free I/O Region */ + if (ha->io_addr) + release_region(ha->io_addr, ha->io_len); + +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,17) + if (ha->mem_addr) + release_mem_region(ha->mem_addr, ha->mem_len); +#endif + /* free IRQ */ free_irq(ha->irq, ha); - /* unregister with SCSI sub system */ - scsi_unregister(sh); + ips_released_controllers++; + + if (ips_num_controllers == ips_released_controllers) + unregister_reboot_notifier(&ips_notifier); return (FALSE); } /****************************************************************************/ /* */ +/* Routine Name: ips_halt */ +/* */ +/* Routine Description: */ +/* */ +/* Perform cleanup when the system reboots */ +/* */ +/****************************************************************************/ +static int +ips_halt(struct notifier_block *nb, ulong event, void *buf) { + ips_scb_t *scb; + ips_ha_t *ha; + int i; + + if ((event != SYS_RESTART) && (event != SYS_HALT) && + (event != SYS_POWER_OFF)) + return (NOTIFY_DONE); + + for (i = 0; i < ips_next_controller; i++) { + ha = (ips_ha_t *) ips_ha[i]; + + if (!ha) + continue; + + if (!ha->active) + continue; + + /* flush the cache on the controller */ + scb = &ha->scbs[ha->max_cmds-1]; + + ips_init_scb(ha, scb); + + scb->timeout = ips_cmd_timeout; + scb->cdb[0] = IPS_CMD_FLUSH; + + scb->cmd.flush_cache.op_code = IPS_CMD_FLUSH; + scb->cmd.flush_cache.command_id = IPS_COMMAND_ID(ha, scb); + scb->cmd.flush_cache.state = IPS_NORM_STATE; + scb->cmd.flush_cache.reserved = 0; + scb->cmd.flush_cache.reserved2 = 0; + scb->cmd.flush_cache.reserved3 = 0; + scb->cmd.flush_cache.reserved4 = 0; + + printk("(%s%d) Flushing Cache.\n", ips_name, ha->host_num); + + /* send command */ + if (ips_send_wait(ha, scb, ips_cmd_timeout, IPS_INTR_ON) == IPS_FAILURE) + printk("(%s%d) Incomplete Flush.\n", ips_name, ha->host_num); + else + printk("(%s%d) Flushing Complete.\n", ips_name, ha->host_num); + } + + unregister_reboot_notifier(&ips_notifier); + return (NOTIFY_OK); +} + +/****************************************************************************/ +/* */ /* Routine Name: ips_eh_abort */ /* */ /* Routine Description: */ @@ -701,7 +1243,7 @@ ips_ha_t *ha; ips_copp_wait_item_t *item; - DBG("ips_eh_abort"); + METHOD_TRACE("ips_eh_abort", 1); if (!SC) return (FAILED); @@ -716,9 +1258,7 @@ if (SC->serial_number != SC->serial_number_at_timeout) { /* HMM, looks like a bogus command */ -#if IPS_DEBUG >= 1 - printk(KERN_NOTICE "Abort called with bogus scsi command\n"); -#endif + DEBUG(1, "Abort called with bogus scsi command"); return (FAILED); } @@ -757,114 +1297,42 @@ /****************************************************************************/ /* */ -/* Routine Name: ips_abort */ +/* Routine Name: ips_eh_reset */ /* */ /* Routine Description: */ /* */ -/* Abort a command */ +/* Reset the controller (with new eh error code) */ +/* */ +/* NOTE: this routine is called under the io_request_lock spinlock */ /* */ /****************************************************************************/ int -ips_abort(Scsi_Cmnd *SC) { - ips_ha_t *ha; +ips_eh_reset(Scsi_Cmnd *SC) { + int ret; + int i; + u32 cpu_flags; + ips_ha_t *ha; + ips_scb_t *scb; ips_copp_wait_item_t *item; - DBG("ips_abort"); + METHOD_TRACE("ips_eh_reset", 1); - if (!SC) - return (SCSI_ABORT_SNOOZE); +#ifdef NO_IPS_RESET + return (FAILED); +#else - ha = (ips_ha_t *) SC->host->hostdata; + if (!SC) { + DEBUG(1, "Reset called with NULL scsi command"); - if (!ha) - return (SCSI_ABORT_SNOOZE); + return (FAILED); + } - if (!ha->active) - return (SCSI_ABORT_SNOOZE); + ha = (ips_ha_t *) SC->host->hostdata; - if (SC->serial_number != SC->serial_number_at_timeout) { - /* HMM, looks like a bogus command */ -#if IPS_DEBUG >= 1 - printk(KERN_NOTICE "Abort called with bogus scsi command\n"); -#endif + if (!ha) { + DEBUG(1, "Reset called with NULL ha struct"); - return (SCSI_ABORT_NOT_RUNNING); - } - - if (test_and_set_bit(IPS_IN_ABORT, &ha->flags)) - return (SCSI_ABORT_SNOOZE); - - /* See if the command is on the copp queue */ - IPS_QUEUE_LOCK(&ha->copp_waitlist); - item = ha->copp_waitlist.head; - while ((item) && (item->scsi_cmd != SC)) - item = item->next; - IPS_QUEUE_UNLOCK(&ha->copp_waitlist); - - if (item) { - /* Found it */ - ips_removeq_copp(&ha->copp_waitlist, item); - clear_bit(IPS_IN_ABORT, &ha->flags); - - return (SCSI_ABORT_PENDING); - } - - /* See if the command is on the wait queue */ - if (ips_removeq_wait(&ha->scb_waitlist, SC)) { - /* command not sent yet */ - clear_bit(IPS_IN_ABORT, &ha->flags); - - return (SCSI_ABORT_PENDING); - } else { - /* command must have already been sent */ - clear_bit(IPS_IN_ABORT, &ha->flags); - - return (SCSI_ABORT_SNOOZE); - } -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_eh_reset */ -/* */ -/* Routine Description: */ -/* */ -/* Reset the controller (with new eh error code) */ -/* */ -/* NOTE: this routine is called under the io_request_lock spinlock */ -/* */ -/****************************************************************************/ -int -ips_eh_reset(Scsi_Cmnd *SC) { - u32 cpu_flags; - ips_ha_t *ha; - ips_scb_t *scb; - ips_copp_wait_item_t *item; - - DBG("ips_eh_reset"); - -#ifdef NO_IPS_RESET - return (FAILED); -#else - - if (!SC) { - -#if IPS_DEBUG >= 1 - printk(KERN_NOTICE "Reset called with NULL scsi command\n"); -#endif - - return (FAILED); - } - - ha = (ips_ha_t *) SC->host->hostdata; - - if (!ha) { - -#if IPS_DEBUG >= 1 - printk(KERN_NOTICE "Reset called with NULL ha struct\n"); -#endif - - return (FAILED); + return (FAILED); } if (!ha->active) @@ -900,149 +1368,72 @@ * command must have already been sent * reset the controller */ - if (!ips_reset_adapter(ha)) { - clear_bit(IPS_IN_RESET, &ha->flags); - - return (FAILED); - } - - if (!ips_clear_adapter(ha, IPS_INTR_IORL)) { - clear_bit(IPS_IN_RESET, &ha->flags); - - return (FAILED); - } - - /* FFDC */ - if (ha->subsys->param[3] & 0x300000) { - struct timeval tv; - - do_gettimeofday(&tv); - IPS_HA_LOCK(cpu_flags); - ha->last_ffdc = tv.tv_sec; - ha->reset_count++; - IPS_HA_UNLOCK(cpu_flags); - ips_ffdc_reset(ha, IPS_INTR_IORL); - } - - /* Now fail all of the active commands */ -#if IPS_DEBUG >= 1 - printk(KERN_WARNING "(%s%d) Failing active commands\n", + printk(KERN_NOTICE "(%s%d) Resetting controller.\n", ips_name, ha->host_num); -#endif - while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) { - scb->scsi_cmd->result = (DID_RESET << 16) | (SUGGEST_RETRY << 24); - scb->scsi_cmd->scsi_done(scb->scsi_cmd); - ips_freescb(ha, scb); - } - - /* Reset the number of active IOCTLs */ - IPS_HA_LOCK(cpu_flags); - ha->num_ioctl = 0; - IPS_HA_UNLOCK(cpu_flags); - - clear_bit(IPS_IN_RESET, &ha->flags); - - if (!test_bit(IPS_IN_INTR, &ha->flags)) { - /* - * Only execute the next command when - * we are not being called from the - * interrupt handler. The interrupt - * handler wants to do this and since - * interrupts are turned off here.... - */ - ips_next(ha, IPS_INTR_IORL); - } - - return (SUCCESS); - -#endif /* NO_IPS_RESET */ - -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_reset */ -/* */ -/* Routine Description: */ -/* */ -/* Reset the controller */ -/* */ -/* NOTE: this routine is called under the io_request_lock spinlock */ -/* */ -/****************************************************************************/ -int -ips_reset(Scsi_Cmnd *SC, unsigned int flags) { - u32 cpu_flags; - ips_ha_t *ha; - ips_scb_t *scb; - ips_copp_wait_item_t *item; - - DBG("ips_reset"); + ret = (*ha->func.reset)(ha); -#ifdef NO_IPS_RESET - return (SCSI_RESET_SNOOZE); -#else + if (!ret) { + Scsi_Cmnd *scsi_cmd; - if (!SC) { + printk(KERN_NOTICE + "(%s%d) Controller reset failed - controller now offline.\n", + ips_name, ha->host_num); -#if IPS_DEBUG >= 1 - printk(KERN_NOTICE "Reset called with NULL scsi command\n"); -#endif + /* Now fail all of the active commands */ + DEBUG_VAR(1, "(%s%d) Failing active commands", + ips_name, ha->host_num); - return (SCSI_RESET_SNOOZE); - } + while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) { + scb->scsi_cmd->result = DID_ERROR << 16; + scb->scsi_cmd->scsi_done(scb->scsi_cmd); + ips_freescb(ha, scb); + } - ha = (ips_ha_t *) SC->host->hostdata; + /* Now fail all of the pending commands */ + DEBUG_VAR(1, "(%s%d) Failing pending commands", + ips_name, ha->host_num); - if (!ha) { + while ((scsi_cmd = ips_removeq_wait_head(&ha->scb_waitlist))) { + scsi_cmd->result = DID_ERROR; + scsi_cmd->scsi_done(scsi_cmd); + } -#if IPS_DEBUG >= 1 - printk(KERN_NOTICE "Reset called with NULL ha struct\n"); -#endif + ha->active = FALSE; + clear_bit(IPS_IN_RESET, &ha->flags); - return (SCSI_RESET_SNOOZE); + return (FAILED); } - if (!ha->active) - return (SCSI_RESET_SNOOZE); - - if (test_and_set_bit(IPS_IN_RESET, &ha->flags)) - return (SCSI_RESET_SNOOZE); - - /* See if the command is on the copp queue */ - IPS_QUEUE_LOCK(&ha->copp_waitlist); - item = ha->copp_waitlist.head; - while ((item) && (item->scsi_cmd != SC)) - item = item->next; - IPS_QUEUE_UNLOCK(&ha->copp_waitlist); - - if (item) { - /* Found it */ - ips_removeq_copp(&ha->copp_waitlist, item); - clear_bit(IPS_IN_RESET, &ha->flags); + if (!ips_clear_adapter(ha, IPS_INTR_IORL)) { + Scsi_Cmnd *scsi_cmd; - return (SCSI_RESET_SNOOZE); - } + printk(KERN_NOTICE + "(%s%d) Controller reset failed - controller now offline.\n", + ips_name, ha->host_num); - /* See if the command is on the wait queue */ - if (ips_removeq_wait(&ha->scb_waitlist, SC)) { - /* command not sent yet */ - clear_bit(IPS_IN_RESET, &ha->flags); + /* Now fail all of the active commands */ + DEBUG_VAR(1, "(%s%d) Failing active commands", + ips_name, ha->host_num); - return (SCSI_RESET_SNOOZE); - } + while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) { + scb->scsi_cmd->result = DID_ERROR << 16; + scb->scsi_cmd->scsi_done(scb->scsi_cmd); + ips_freescb(ha, scb); + } - /* reset the controller */ - if (!ips_reset_adapter(ha)) { - clear_bit(IPS_IN_RESET, &ha->flags); + /* Now fail all of the pending commands */ + DEBUG_VAR(1, "(%s%d) Failing pending commands", + ips_name, ha->host_num); - return (SCSI_RESET_ERROR); - } + while ((scsi_cmd = ips_removeq_wait_head(&ha->scb_waitlist))) { + scsi_cmd->result = DID_ERROR << 16; + scsi_cmd->scsi_done(scsi_cmd); + } - if (!ips_clear_adapter(ha, IPS_INTR_IORL)) { + ha->active = FALSE; clear_bit(IPS_IN_RESET, &ha->flags); - return (SCSI_RESET_ERROR); + return (FAILED); } /* FFDC */ @@ -1058,16 +1449,19 @@ } /* Now fail all of the active commands */ -#if IPS_DEBUG >= 1 - printk(KERN_WARNING "(%s%d) Failing active commands\n", - ips_name, ha->host_num); -#endif + DEBUG_VAR(1, "(%s%d) Failing active commands", + ips_name, ha->host_num); + while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) { scb->scsi_cmd->result = (DID_RESET << 16) | (SUGGEST_RETRY << 24); scb->scsi_cmd->scsi_done(scb->scsi_cmd); ips_freescb(ha, scb); } + /* Reset DCDB active command bits */ + for (i = 1; i < ha->nbus; i++) + ha->dcdb_active[i-1] = 0; + /* Reset the number of active IOCTLs */ IPS_HA_LOCK(cpu_flags); ha->num_ioctl = 0; @@ -1086,7 +1480,7 @@ ips_next(ha, IPS_INTR_IORL); } - return (SCSI_RESET_SUCCESS); + return (SUCCESS); #endif /* NO_IPS_RESET */ @@ -1110,7 +1504,7 @@ u32 cpu_flags; DECLARE_MUTEX_LOCKED(sem); - DBG("ips_queue"); + METHOD_TRACE("ips_queue", 1); ha = (ips_ha_t *) SC->host->hostdata; @@ -1118,7 +1512,7 @@ return (1); if (!ha->active) - return (1); + return (DID_ERROR); #ifndef NO_IPS_CMDLINE if (ips_is_passthru(SC)) { @@ -1151,24 +1545,28 @@ SC->scsi_done = done; -#if IPS_DEBUG >= 10 - printk(KERN_NOTICE "%s: ips_queue: cmd 0x%X (%d %d %d)\n", - ips_name, - SC->cmnd[0], - SC->channel, - SC->target, - SC->lun); -#if IPS_DEBUG >= 11 - MDELAY(2*IPS_ONE_SEC); -#endif -#endif + DEBUG_VAR(2, "(%s%d): ips_queue: cmd 0x%X (%d %d %d)", + ips_name, + ha->host_num, + SC->cmnd[0], + SC->channel, + SC->target, + SC->lun); + + /* Check for command to initiator IDs */ + if ((SC->channel > 0) && (SC->target == ha->ha_id[SC->channel])) { + SC->result = DID_NO_CONNECT << 16; + done(SC); + + return (0); + } #ifndef NO_IPS_CMDLINE if (ips_is_passthru(SC)) { ips_copp_wait_item_t *scratch; /* allocate space for the scribble */ - scratch = kmalloc(sizeof(ips_copp_wait_item_t), GFP_KERNEL); + scratch = kmalloc(sizeof(ips_copp_wait_item_t), GFP_ATOMIC); if (!scratch) { SC->result = DID_ERROR << 16; @@ -1224,10 +1622,8 @@ datasize = *((u32 *) &SC->cmnd[8]); if (copy_to_user(user_area, kern_area, datasize) > 0) { -#if IPS_DEBUG_PT >= 1 - printk(KERN_NOTICE "(%s%d) passthru failed - unable to copy out user data\n", - ips_name, ha->host_num); -#endif + DEBUG_VAR(1, "(%s%d) passthru failed - unable to copy out user data", + ips_name, ha->host_num); SC->result = DID_ERROR << 16; SC->scsi_done(SC); @@ -1255,7 +1651,7 @@ int sectors; int cylinders; - DBG("ips_biosparam"); + METHOD_TRACE("ips_biosparam", 1); ha = (ips_ha_t *) disk->device->host->hostdata; @@ -1281,10 +1677,8 @@ cylinders = disk->capacity / (heads * sectors); -#if IPS_DEBUG >= 2 - printk(KERN_NOTICE "Geometry: heads: %d, sectors: %d, cylinders: %d\n", - heads, sectors, cylinders); -#endif + DEBUG_VAR(2, "Geometry: heads: %d, sectors: %d, cylinders: %d", + heads, sectors, cylinders); geom[0] = heads; geom[1] = sectors; @@ -1295,6 +1689,40 @@ /****************************************************************************/ /* */ +/* Routine Name: ips_select_queue_depth */ +/* */ +/* Routine Description: */ +/* */ +/* Select queue depths for the devices on the contoller */ +/* */ +/****************************************************************************/ +static void +ips_select_queue_depth(struct Scsi_Host *host, Scsi_Device *scsi_devs) { + Scsi_Device *device; + ips_ha_t *ha; + int count = 0; + + ha = IPS_HA(host); + + for (device = scsi_devs; device; device = device->next) { + if (device->host == host) { + if ((device->channel == 0) && (device->type == 0)) + count++; + } + } + + for (device = scsi_devs; device; device = device->next) { + if (device->host == host) { + if ((device->channel == 0) && (device->type == 0)) + device->queue_depth = ha->max_cmds / count - 1; + else + device->queue_depth = 2; + } + } +} + +/****************************************************************************/ +/* */ /* Routine Name: do_ipsintr */ /* */ /* Routine Description: */ @@ -1307,7 +1735,7 @@ ips_ha_t *ha; u32 cpu_flags; - DBG("do_ipsintr"); + METHOD_TRACE("do_ipsintr", 2); ha = (ips_ha_t *) dev_id; @@ -1333,7 +1761,7 @@ return; } - ips_intr(ha); + (*ha->func.intr)(ha); clear_bit(IPS_IN_INTR, &ha->flags); @@ -1345,7 +1773,7 @@ /****************************************************************************/ /* */ -/* Routine Name: ips_intr */ +/* Routine Name: ips_intr_copperhead */ /* */ /* Routine Description: */ /* */ @@ -1355,13 +1783,14 @@ /* */ /****************************************************************************/ void -ips_intr(ips_ha_t *ha) { +ips_intr_copperhead(ips_ha_t *ha) { ips_stat_t *sp; ips_scb_t *scb; - int status; + IPS_STATUS cstatus; + int intrstatus; u32 cpu_flags; - DBG("ips_intr"); + METHOD_TRACE("ips_intr", 2); if (!ha) return; @@ -1370,16 +1799,36 @@ return; IPS_HA_LOCK(cpu_flags); - while (ips_isintr(ha)) { + + intrstatus = (*ha->func.isintr)(ha); + + if (!intrstatus) { + /* + * Unexpected/Shared interrupt + */ + IPS_HA_UNLOCK(cpu_flags); + + return; + } + + while (TRUE) { sp = &ha->sp; - if ((status = ips_chkstatus(ha)) < 0) { - /* unexpected interrupt - no ccb */ + intrstatus = (*ha->func.isintr)(ha); + + if (!intrstatus) + break; + else + cstatus.value = (*ha->func.statupd)(ha); + + if (cstatus.fields.command_id > (IPS_MAX_CMDS - 1)) { printk(KERN_WARNING "(%s%d) Spurious interrupt; no ccb.\n", ips_name, ha->host_num); - continue ; + + continue; } + ips_chkstatus(ha, &cstatus); scb = (ips_scb_t *) sp->scb_addr; /* @@ -1389,32 +1838,108 @@ IPS_HA_UNLOCK(cpu_flags); (*scb->callback) (ha, scb); IPS_HA_LOCK(cpu_flags); - } + } /* end while */ IPS_HA_UNLOCK(cpu_flags); } /****************************************************************************/ /* */ -/* Routine Name: ips_info */ +/* Routine Name: ips_intr_morpheus */ /* */ /* Routine Description: */ /* */ -/* Return info about the driver */ +/* Polling interrupt handler */ +/* */ +/* ASSUMES interrupts are disabled */ /* */ /****************************************************************************/ -const char * -ips_info(struct Scsi_Host *SH) { - static char buffer[256]; - char *bp; - ips_ha_t *ha; - - DBG("ips_info"); +void +ips_intr_morpheus(ips_ha_t *ha) { + ips_stat_t *sp; + ips_scb_t *scb; + IPS_STATUS cstatus; + int intrstatus; + u32 cpu_flags; - ha = IPS_HA(SH); + METHOD_TRACE("ips_intr_morpheus", 2); if (!ha) - return (NULL); + return; + + if (!ha->active) + return; + + IPS_HA_LOCK(cpu_flags); + + intrstatus = (*ha->func.isintr)(ha); + + if (!intrstatus) { + /* + * Unexpected/Shared interrupt + */ + IPS_HA_UNLOCK(cpu_flags); + + return; + } + + while (TRUE) { + sp = &ha->sp; + + intrstatus = (*ha->func.isintr)(ha); + + if (!intrstatus) + break; + else + cstatus.value = (*ha->func.statupd)(ha); + + if (cstatus.value == 0xffffffff) + /* No more to process */ + break; + + if (cstatus.fields.command_id > (IPS_MAX_CMDS - 1)) { + printk(KERN_WARNING "(%s%d) Spurious interrupt; no ccb.\n", + ips_name, ha->host_num); + + continue; + } + + ips_chkstatus(ha, &cstatus); + scb = (ips_scb_t *) sp->scb_addr; + + /* + * use the callback function to finish things up + * NOTE: interrupts are OFF for this + */ + IPS_HA_UNLOCK(cpu_flags); + (*scb->callback) (ha, scb); + IPS_HA_LOCK(cpu_flags); + } /* end while */ + + IPS_HA_UNLOCK(cpu_flags); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_info */ +/* */ +/* Routine Description: */ +/* */ +/* Return info about the driver */ +/* */ +/****************************************************************************/ +const char * +ips_info(struct Scsi_Host *SH) { + static char buffer[256]; + char *bp; + ips_ha_t *ha; + + METHOD_TRACE("ips_info", 1); + + ha = IPS_HA(SH); + + if (!ha) + return (NULL); bp = &buffer[0]; memset(bp, 0, sizeof(buffer)); @@ -1449,10 +1974,10 @@ int ret; ips_ha_t *ha = NULL; - DBG("ips_proc_info"); + METHOD_TRACE("ips_proc_info", 1); /* Find our host structure */ - for (i = 0; i < ips_num_controllers; i++) { + for (i = 0; i < ips_next_controller; i++) { if (ips_sh[i] && ips_sh[i]->host_no == hostno) { ha = (ips_ha_t *) ips_sh[i]->hostdata; @@ -1494,7 +2019,7 @@ /****************************************************************************/ static int ips_is_passthru(Scsi_Cmnd *SC) { - DBG("ips_is_passthru"); + METHOD_TRACE("ips_is_passthru", 1); if (!SC) return (0); @@ -1528,24 +2053,20 @@ ips_make_passthru(ips_ha_t *ha, Scsi_Cmnd *SC, ips_scb_t *scb) { ips_passthru_t *pt; - DBG("ips_make_passthru"); + METHOD_TRACE("ips_make_passthru", 1); if (!SC->request_bufflen || !SC->request_buffer) { /* no data */ -#if IPS_DEBUG_PT >= 1 - printk(KERN_NOTICE "(%s%d) No passthru structure\n", - ips_name, ha->host_num); -#endif + DEBUG_VAR(1, "(%s%d) No passthru structure", + ips_name, ha->host_num); return (IPS_FAILURE); } if (SC->request_bufflen < sizeof(ips_passthru_t)) { /* wrong size */ -#if IPS_DEBUG_PT >= 1 - printk(KERN_NOTICE "(%s%d) Passthru structure wrong size\n", + DEBUG_VAR(1, "(%s%d) Passthru structure wrong size", ips_name, ha->host_num); -#endif return (IPS_FAILURE); } @@ -1555,10 +2076,8 @@ (((char *) SC->request_buffer)[2] != 'P') || (((char *) SC->request_buffer)[3] != 'P')) { /* signature doesn't match */ -#if IPS_DEBUG_PT >= 1 - printk(KERN_NOTICE "(%s%d) Wrong signature on passthru structure.\n", - ips_name, ha->host_num); -#endif + DEBUG_VAR(1, "(%s%d) Wrong signature on passthru structure.", + ips_name, ha->host_num); return (IPS_FAILURE); } @@ -1602,10 +2121,8 @@ if (SC->cmnd[0] == IPS_IOCTL_COMMAND) { if (SC->request_bufflen < (sizeof(ips_passthru_t) + pt->CmdBSize)) { /* wrong size */ - #if IPS_DEBUG_PT >= 1 - printk(KERN_NOTICE "(%s%d) Passthru structure wrong size\n", - ips_name, ha->host_num); - #endif + DEBUG_VAR(1, "(%s%d) Passthru structure wrong size", + ips_name, ha->host_num); return (IPS_FAILURE); } @@ -1617,10 +2134,8 @@ } else if (SC->cmnd[0] == IPS_IOCTL_NEW_COMMAND) { if (SC->request_bufflen < (sizeof(ips_passthru_t))) { /* wrong size */ - #if IPS_DEBUG_PT >= 1 - printk(KERN_NOTICE "(%s%d) Passthru structure wrong size\n", - ips_name, ha->host_num); - #endif + DEBUG_VAR(1, "(%s%d) Passthru structure wrong size", + ips_name, ha->host_num); return (IPS_FAILURE); } @@ -1639,14 +2154,23 @@ return (IPS_FAILURE); /* don't flash the BIOS on future cards */ - if (ha->revision_id > IPS_REVID_TROMBONE64) { -#if IPS_DEBUG_PT >= 1 - printk(KERN_NOTICE "(%s%d) flash bios failed - unsupported controller\n", - ips_name, ha->host_num); -#endif + if ((ha->device_id != IPS_COPPERHEAD_DEVICEID) || + (ha->revision_id > IPS_REVID_TROMBONE64)) { + DEBUG_VAR(1, "(%s%d) flash bios failed - unsupported controller", + ips_name, ha->host_num); + return (IPS_FAILURE); } + /* + * Check to make sure we have functions + * to handle the request + */ + if ((!ha->func.programbios) || + (!ha->func.erasebios) || + (!ha->func.verifybios)) + return (IPS_FAILURE); + /* copy in the size/buffer ptr from the scsi command */ memcpy(&pt->CmdBuffer, &SC->cmnd[4], 4); memcpy(&pt->CmdBSize, &SC->cmnd[8], 4); @@ -1660,7 +2184,7 @@ void *bigger_struct; /* try to allocate a bigger struct */ - bigger_struct = kmalloc(pt->CmdBSize, GFP_KERNEL|GFP_DMA); + bigger_struct = kmalloc(pt->CmdBSize, GFP_ATOMIC|GFP_DMA); if (bigger_struct) { /* free the old memory */ kfree(ha->ioctl_data); @@ -1674,37 +2198,29 @@ /* copy in the buffer */ if (copy_from_user(ha->ioctl_data, pt->CmdBuffer, pt->CmdBSize) > 0) { -#if IPS_DEBUG_PT >= 1 - printk(KERN_NOTICE "(%s%d) flash bios failed - unable to copy user buffer\n", - ips_name, ha->host_num); -#endif + DEBUG_VAR(1, "(%s%d) flash bios failed - unable to copy user buffer", + ips_name, ha->host_num); return (IPS_FAILURE); } - if (ips_erase_bios(ha)) { -#if IPS_DEBUG_PT >= 1 - printk(KERN_NOTICE "(%s%d) flash bios failed - unable to erase flash\n", - ips_name, ha->host_num); -#endif + if ((*ha->func.erasebios)(ha)) { + DEBUG_VAR(1, "(%s%d) flash bios failed - unable to erase flash", + ips_name, ha->host_num); return (IPS_FAILURE); } - if (ips_program_bios(ha, ha->ioctl_data, pt->CmdBSize)) { -#if IPS_DEBUG_PT >= 1 - printk(KERN_NOTICE "(%s%d) flash bios failed - unable to program flash\n", - ips_name, ha->host_num); -#endif + if ((*ha->func.programbios)(ha, ha->ioctl_data, pt->CmdBSize)) { + DEBUG_VAR(1, "(%s%d) flash bios failed - unable to program flash", + ips_name, ha->host_num); return (IPS_FAILURE); } - if (ips_verify_bios(ha, ha->ioctl_data, pt->CmdBSize)) { -#if IPS_DEBUG_PT >= 1 - printk(KERN_NOTICE "(%s%d) flash bios failed - unable to verify flash\n", - ips_name, ha->host_num); -#endif + if ((*ha->func.verifybios)(ha, ha->ioctl_data, pt->CmdBSize)) { + DEBUG_VAR(1, "(%s%d) flash bios failed - unable to verify flash", + ips_name, ha->host_num); return (IPS_FAILURE); } @@ -1728,7 +2244,7 @@ ips_usrcmd(ips_ha_t *ha, ips_passthru_t *pt, ips_scb_t *scb) { IPS_SG_LIST *sg_list; - DBG("ips_usrcmd"); + METHOD_TRACE("ips_usrcmd", 1); if ((!scb) || (!pt) || (!ha)) return (0); @@ -1811,7 +2327,7 @@ char *kern_area; u32 datasize; - DBG("ips_usrcmd"); + METHOD_TRACE("ips_usrcmd", 1); if ((!scb) || (!pt) || (!ha)) return (0); @@ -1848,7 +2364,7 @@ void *bigger_struct; /* try to allocate a bigger struct */ - bigger_struct = kmalloc(pt->CmdBSize, GFP_KERNEL|GFP_DMA); + bigger_struct = kmalloc(pt->CmdBSize, GFP_ATOMIC|GFP_DMA); if (bigger_struct) { /* free the old memory */ kfree(ha->ioctl_data); @@ -1869,10 +2385,8 @@ datasize = *((u32 *) &scb->scsi_cmd->cmnd[8]); if (copy_from_user(kern_area, user_area, datasize) > 0) { -#if IPS_DEBUG_PT >= 1 - printk(KERN_NOTICE "(%s%d) passthru failed - unable to copy in user data\n", - ips_name, ha->host_num); -#endif + DEBUG_VAR(1, "(%s%d) passthru failed - unable to copy in user data", + ips_name, ha->host_num); return (0); } @@ -1923,12 +2437,11 @@ ips_cleanup_passthru(ips_ha_t *ha, ips_scb_t *scb) { ips_passthru_t *pt; - DBG("ips_cleanup_passthru"); + METHOD_TRACE("ips_cleanup_passthru", 1); if ((!scb) || (!scb->scsi_cmd) || (!scb->scsi_cmd->request_buffer)) { -#if IPS_DEBUG_PT >= 1 - printk(KERN_NOTICE "IPS couldn't cleanup\n"); -#endif + DEBUG_VAR(1, "(%s%d) couldn't cleanup after passthru", + ips_name, ha->host_num); return ; } @@ -1962,12 +2475,13 @@ ips_host_info(ips_ha_t *ha, char *ptr, off_t offset, int len) { IPS_INFOSTR info; - DBG("ips_host_info"); + METHOD_TRACE("ips_host_info", 1); info.buffer = ptr; info.length = len; info.offset = offset; info.pos = 0; + info.localpos = 0; copy_info(&info, "\nIBM ServeRAID General Information:\n\n"); @@ -1977,7 +2491,16 @@ else copy_info(&info, "\tController Type : Unknown\n"); - copy_info(&info, "\tIO port address : 0x%lx\n", ha->io_addr); + if (ha->io_addr) + copy_info(&info, "\tIO region : 0x%lx (%d bytes)\n", + ha->io_addr, ha->io_len); + + if (ha->mem_addr) { + copy_info(&info, "\tMemory region : 0x%lx (%d bytes)\n", + ha->mem_addr, ha->mem_len); + copy_info(&info, "\tShared memory address : 0x%lx\n", ha->mem_ptr); + } + copy_info(&info, "\tIRQ number : %d\n", ha->irq); if (ha->nvram->signature == IPS_NVRAM_P5_SIG) @@ -2017,7 +2540,7 @@ copy_info(&info, "\n"); - return (info.pos > info.offset ? info.pos - info.offset : 0); + return (info.localpos); } /****************************************************************************/ @@ -2031,10 +2554,7 @@ /****************************************************************************/ static void copy_mem_info(IPS_INFOSTR *info, char *data, int len) { - DBG("copy_mem_info"); - - if (info->pos + len > info->length) - len = info->length - info->pos; + METHOD_TRACE("copy_mem_info", 1); if (info->pos + len < info->offset) { info->pos += len; @@ -2043,12 +2563,17 @@ if (info->pos < info->offset) { data += (info->offset - info->pos); - len -= (info->offset - info->pos); + len -= (info->offset - info->pos); + info->pos += (info->offset - info->pos); } + if (info->localpos + len > info->length) + len = info->length - info->localpos; + if (len > 0) { - memcpy(info->buffer + info->pos, data, len); + memcpy(info->buffer + info->localpos, data, len); info->pos += len; + info->localpos += len; } } @@ -2064,10 +2589,10 @@ static int copy_info(IPS_INFOSTR *info, char *fmt, ...) { va_list args; - char buf[81]; + char buf[128]; int len; - DBG("copy_info"); + METHOD_TRACE("copy_info", 1); va_start(args, fmt); len = vsprintf(buf, fmt, args); @@ -2091,57 +2616,32 @@ /****************************************************************************/ static int ips_hainit(ips_ha_t *ha) { - int i; + int i; + struct timeval tv; - DBG("ips_hainit"); + METHOD_TRACE("ips_hainit", 1); if (!ha) return (0); - /* initialize status queue */ - ips_statinit(ha); + if (ha->func.statinit) + (*ha->func.statinit)(ha); + + if (ha->func.enableint) + (*ha->func.enableint)(ha); + /* Send FFDC */ ha->reset_count = 1; + do_gettimeofday(&tv); + ha->last_ffdc = tv.tv_sec; + ips_ffdc_reset(ha, IPS_INTR_IORL); - /* Setup HBA ID's */ if (!ips_read_config(ha, IPS_INTR_IORL)) { - -#ifndef NO_IPS_RESET - - ha->reset_count++; - - /* Try to reset the controller and try again */ - if (!ips_reset_adapter(ha)) { - printk(KERN_WARNING "(%s%d) unable to reset controller.\n", - ips_name, ha->host_num); - - return (0); - } - - if (!ips_clear_adapter(ha, IPS_INTR_IORL)) { - printk(KERN_WARNING "(%s%d) unable to initialize controller.\n", - ips_name, ha->host_num); - - return (0); - } - -#endif - - if (!ips_read_config(ha, IPS_INTR_IORL)) { - printk(KERN_WARNING "(%s%d) unable to read config from controller.\n", - ips_name, ha->host_num); - - return (0); - } - } /* end if */ - - /* write driver version */ - if (!ips_write_driver_status(ha, IPS_INTR_IORL)) { - printk(KERN_WARNING "(%s%d) unable to write driver info to controller.\n", + printk(KERN_WARNING "(%s%d) unable to read config from controller.\n", ips_name, ha->host_num); return (0); - } + } /* end if */ if (!ips_read_adapter_status(ha, IPS_INTR_IORL)) { printk(KERN_WARNING "(%s%d) unable to read controller status.\n", @@ -2157,19 +2657,18 @@ return (0); } - /* FFDC */ - if (ha->subsys->param[3] & 0x300000) { - struct timeval tv; + /* write nvram user page 5 */ + if (!ips_write_driver_status(ha, IPS_INTR_IORL)) { + printk(KERN_WARNING "(%s%d) unable to write driver info to controller.\n", + ips_name, ha->host_num); - do_gettimeofday(&tv); - ha->last_ffdc = tv.tv_sec; - ips_ffdc_reset(ha, IPS_INTR_IORL); + return (0); } /* set limits on SID, LUN, BUS */ ha->ntargets = IPS_MAX_TARGETS + 1; ha->nlun = 1; - ha->nbus = (ha->enq->ucMaxPhysicalDevices / IPS_MAX_TARGETS); + ha->nbus = (ha->enq->ucMaxPhysicalDevices / IPS_MAX_TARGETS) + 1; switch (ha->conf->logical_drive[0].ucStripeSize) { case 4: @@ -2240,13 +2739,14 @@ ips_scb_t *scb; Scsi_Cmnd *SC; Scsi_Cmnd *p; + Scsi_Cmnd *q; ips_copp_wait_item_t *item; int ret; int intr_status; u32 cpu_flags; u32 cpu_flags2; - DBG("ips_next"); + METHOD_TRACE("ips_next", 1); if (!ha) return ; @@ -2392,7 +2892,8 @@ IPS_HA_UNLOCK(cpu_flags); - SC = ips_removeq_wait(&ha->scb_waitlist, p); + q = p; + SC = ips_removeq_wait(&ha->scb_waitlist, q); SC->result = DID_OK; SC->host_scribble = NULL; @@ -2419,28 +2920,41 @@ sg = SC->request_buffer; - for (i = 0; i < SC->use_sg; i++) { - scb->sg_list[i].address = VIRT_TO_BUS(sg[i].address); - scb->sg_list[i].length = sg[i].length; + if (SC->use_sg == 1) { + if (sg[0].length > ha->max_xfer) { + scb->breakup = 1; + scb->data_len = ha->max_xfer; + } else + scb->data_len = sg[0].length; - if (scb->data_len + sg[i].length > ha->max_xfer) { - /* - * Data Breakup required - */ - scb->breakup = i; - break; - } + scb->dcdb.transfer_length = scb->data_len; + scb->data_busaddr = VIRT_TO_BUS(sg[0].address); + scb->sg_len = 0; + } else { - scb->data_len += sg[i].length; - } + for (i = 0; i < SC->use_sg; i++) { + scb->sg_list[i].address = VIRT_TO_BUS(sg[i].address); + scb->sg_list[i].length = sg[i].length; - if (!scb->breakup) - scb->sg_len = SC->use_sg; - else - scb->sg_len = scb->breakup; + if (scb->data_len + sg[i].length > ha->max_xfer) { + /* + * Data Breakup required + */ + scb->breakup = i; + break; + } + + scb->data_len += sg[i].length; + } + + if (!scb->breakup) + scb->sg_len = SC->use_sg; + else + scb->sg_len = scb->breakup; - scb->dcdb.transfer_length = scb->data_len; - scb->data_busaddr = VIRT_TO_BUS(scb->sg_list); + scb->dcdb.transfer_length = scb->data_len; + scb->data_busaddr = VIRT_TO_BUS(scb->sg_list); + } } else { if (SC->request_bufflen) { if (SC->request_bufflen > ha->max_xfer) { @@ -2527,7 +3041,7 @@ /****************************************************************************/ static inline void ips_putq_scb_head(ips_scb_queue_t *queue, ips_scb_t *item) { - DBG("ips_putq_scb_head"); + METHOD_TRACE("ips_putq_scb_head", 1); if (!item) return ; @@ -2558,7 +3072,7 @@ /****************************************************************************/ static inline void ips_putq_scb_tail(ips_scb_queue_t *queue, ips_scb_t *item) { - DBG("ips_putq_scb_tail"); + METHOD_TRACE("ips_putq_scb_tail", 1); if (!item) return ; @@ -2595,7 +3109,7 @@ ips_removeq_scb_head(ips_scb_queue_t *queue) { ips_scb_t *item; - DBG("ips_removeq_scb_head"); + METHOD_TRACE("ips_removeq_scb_head", 1); IPS_QUEUE_LOCK(queue); @@ -2635,7 +3149,7 @@ ips_removeq_scb(ips_scb_queue_t *queue, ips_scb_t *item) { ips_scb_t *p; - DBG("ips_removeq_scb"); + METHOD_TRACE("ips_removeq_scb", 1); if (!item) return (NULL); @@ -2686,7 +3200,7 @@ /****************************************************************************/ static inline void ips_putq_wait_head(ips_wait_queue_t *queue, Scsi_Cmnd *item) { - DBG("ips_putq_wait_head"); + METHOD_TRACE("ips_putq_wait_head", 1); if (!item) return ; @@ -2717,7 +3231,7 @@ /****************************************************************************/ static inline void ips_putq_wait_tail(ips_wait_queue_t *queue, Scsi_Cmnd *item) { - DBG("ips_putq_wait_tail"); + METHOD_TRACE("ips_putq_wait_tail", 1); if (!item) return ; @@ -2754,7 +3268,7 @@ ips_removeq_wait_head(ips_wait_queue_t *queue) { Scsi_Cmnd *item; - DBG("ips_removeq_wait_head"); + METHOD_TRACE("ips_removeq_wait_head", 1); IPS_QUEUE_LOCK(queue); @@ -2794,7 +3308,7 @@ ips_removeq_wait(ips_wait_queue_t *queue, Scsi_Cmnd *item) { Scsi_Cmnd *p; - DBG("ips_removeq_wait"); + METHOD_TRACE("ips_removeq_wait", 1); if (!item) return (NULL); @@ -2845,7 +3359,7 @@ /****************************************************************************/ static inline void ips_putq_copp_head(ips_copp_queue_t *queue, ips_copp_wait_item_t *item) { - DBG("ips_putq_copp_head"); + METHOD_TRACE("ips_putq_copp_head", 1); if (!item) return ; @@ -2876,7 +3390,7 @@ /****************************************************************************/ static inline void ips_putq_copp_tail(ips_copp_queue_t *queue, ips_copp_wait_item_t *item) { - DBG("ips_putq_copp_tail"); + METHOD_TRACE("ips_putq_copp_tail", 1); if (!item) return ; @@ -2913,7 +3427,7 @@ ips_removeq_copp_head(ips_copp_queue_t *queue) { ips_copp_wait_item_t *item; - DBG("ips_removeq_copp_head"); + METHOD_TRACE("ips_removeq_copp_head", 1); IPS_QUEUE_LOCK(queue); @@ -2953,7 +3467,7 @@ ips_removeq_copp(ips_copp_queue_t *queue, ips_copp_wait_item_t *item) { ips_copp_wait_item_t *p; - DBG("ips_removeq_copp"); + METHOD_TRACE("ips_removeq_copp", 1); if (!item) return (NULL); @@ -3002,7 +3516,7 @@ /****************************************************************************/ static void ipsintr_blocking(ips_ha_t *ha, ips_scb_t *scb) { - DBG("ipsintr_blocking"); + METHOD_TRACE("ipsintr_blocking", 2); if ((ha->waitflag == TRUE) && (ha->cmd_in_progress == scb->cdb[0])) { @@ -3023,7 +3537,14 @@ /****************************************************************************/ static void ipsintr_done(ips_ha_t *ha, ips_scb_t *scb) { - DBG("ipsintr_done"); + METHOD_TRACE("ipsintr_done", 2); + + if (!scb) { + printk(KERN_WARNING "(%s%d) Spurious interrupt; scb NULL.\n", + ips_name, ha->host_num); + + return ; + } if (scb->scsi_cmd == NULL) { /* unexpected interrupt */ @@ -3050,7 +3571,7 @@ int ret; u32 cpu_flags; - DBG("ips_done"); + METHOD_TRACE("ips_done", 1); if (!scb) return ; @@ -3082,31 +3603,46 @@ sg = scb->scsi_cmd->request_buffer; - scb->data_len = 0; - - for (i = bk_save; i < scb->scsi_cmd->use_sg; i++) { - scb->sg_list[i - bk_save].address = VIRT_TO_BUS(sg[i].address); - scb->sg_list[i - bk_save].length = sg[i].length; - - if (scb->data_len + sg[i].length > ha->max_xfer) { - /* - * Data Breakup required - */ - scb->breakup = i; - break; + if (scb->scsi_cmd->use_sg == 1) { + if (sg[0].length - (bk_save * ha->max_xfer)) { + /* Further breakup required */ + scb->data_len = ha->max_xfer; + scb->data_busaddr = VIRT_TO_BUS(sg[0].address + (bk_save * ha->max_xfer)); + scb->breakup = bk_save + 1; + } else { + scb->data_len = sg[0].length - (bk_save * ha->max_xfer); + scb->data_busaddr = VIRT_TO_BUS(sg[0].address + (bk_save * ha->max_xfer)); } - scb->data_len += sg[i].length; - } + scb->dcdb.transfer_length = scb->data_len; + scb->sg_len = 0; + } else { + scb->data_len = 0; - if (!scb->breakup) - scb->sg_len = scb->scsi_cmd->use_sg - bk_save; - else - scb->sg_len = scb->breakup - bk_save; + for (i = bk_save; i < scb->scsi_cmd->use_sg; i++) { + scb->sg_list[i - bk_save].address = VIRT_TO_BUS(sg[i].address); + scb->sg_list[i - bk_save].length = sg[i].length; + + if (scb->data_len + sg[i].length > ha->max_xfer) { + /* + * Data Breakup required + */ + scb->breakup = i; + break; + } - scb->dcdb.transfer_length = scb->data_len; - scb->data_busaddr = VIRT_TO_BUS(scb->sg_list); - } else { + scb->data_len += sg[i].length; + } + + if (!scb->breakup) + scb->sg_len = scb->scsi_cmd->use_sg - bk_save; + else + scb->sg_len = scb->breakup - bk_save; + + scb->dcdb.transfer_length = scb->data_len; + scb->data_busaddr = VIRT_TO_BUS(scb->sg_list); + } + } else { /* Non S/G Request */ if (scb->scsi_cmd->request_bufflen - (bk_save * ha->max_xfer)) { /* Further breakup required */ @@ -3185,31 +3721,29 @@ /* */ /****************************************************************************/ static int -ips_map_status(ips_scb_t *scb, ips_stat_t *sp) { +ips_map_status(ips_ha_t *ha, ips_scb_t *scb, ips_stat_t *sp) { int errcode; + int device_error; - DBG("ips_map_status"); + METHOD_TRACE("ips_map_status", 1); if (scb->bus) { -#if IPS_DEBUG >= 10 - printk(KERN_NOTICE "(%s) Physical device error: %x %x, Sense Key: %x, ASC: %x, ASCQ: %x\n", - ips_name, - scb->basic_status, - scb->extended_status, - scb->dcdb.sense_info[2] & 0xf, - scb->dcdb.sense_info[12], - scb->dcdb.sense_info[13]); -#endif - - /* copy SCSI status and sense data for DCDB commands */ - memcpy(scb->scsi_cmd->sense_buffer, scb->dcdb.sense_info, - sizeof(scb->scsi_cmd->sense_buffer)); - scb->scsi_cmd->result = scb->dcdb.scsi_status; - } else - scb->scsi_cmd->result = 0; + DEBUG_VAR(2, "(%s%d) Physical device error (%d %d %d): %x %x, Sense Key: %x, ASC: %x, ASCQ: %x", + ips_name, + ha->host_num, + scb->scsi_cmd->channel, + scb->scsi_cmd->target, + scb->scsi_cmd->lun, + scb->basic_status, + scb->extended_status, + scb->extended_status == IPS_ERR_CKCOND ? scb->dcdb.sense_info[2] & 0xf : 0, + scb->extended_status == IPS_ERR_CKCOND ? scb->dcdb.sense_info[12] : 0, + scb->extended_status == IPS_ERR_CKCOND ? scb->dcdb.sense_info[13] : 0); + } /* default driver error */ errcode = DID_ERROR; + device_error = 0; switch (scb->basic_status & IPS_GSC_STATUS_MASK) { case IPS_CMD_TIMEOUT: @@ -3224,25 +3758,19 @@ break; case IPS_PHYS_DRV_ERROR: - /* - * For physical drive errors that - * are not on a logical drive should - * be DID_OK. The SCSI errcode will - * show what the real error is. - */ - if (scb->bus) - errcode = DID_OK; - switch (scb->extended_status) { case IPS_ERR_SEL_TO: - if (scb->bus) { - scb->scsi_cmd->result |= DID_TIME_OUT << 16; + if (scb->bus) + errcode = DID_NO_CONNECT; - return (0); - } break; + case IPS_ERR_OU_RUN: if ((scb->bus) && (scb->dcdb.transfer_length < scb->data_len)) { + /* Underrun - set default to no error */ + errcode = DID_OK; + + /* Restrict access to physical DASD */ if ((scb->scsi_cmd->cmnd[0] == INQUIRY) && ((((char *) scb->scsi_cmd->buffer)[0] & 0x1f) == TYPE_DISK)) { /* underflow -- no error */ @@ -3250,23 +3778,16 @@ errcode = DID_TIME_OUT; break; } - - /* normal underflow Occured */ - if (scb->dcdb.transfer_length >= scb->scsi_cmd->underflow) { - scb->scsi_cmd->result |= DID_OK << 16; - - return (0); - } - } + } else + errcode = DID_ERROR; break; + case IPS_ERR_RECOVERY: /* don't fail recovered errors */ - if (scb->bus) { - scb->scsi_cmd->result |= DID_OK << 16; + if (scb->bus) + errcode = DID_OK; - return (0); - } break; case IPS_ERR_HOST_RESET: @@ -3275,11 +3796,25 @@ break; case IPS_ERR_CKCOND: + if (scb->bus) { + memcpy(scb->scsi_cmd->sense_buffer, scb->dcdb.sense_info, + sizeof(scb->scsi_cmd->sense_buffer)); + + device_error = 2; /* check condition */ + } + + errcode = DID_OK; + break; + + default: + errcode = DID_ERROR; + break; + } /* end switch */ } /* end switch */ - scb->scsi_cmd->result |= (errcode << 16); + scb->scsi_cmd->result = device_error | (errcode << 16); return (1); } @@ -3297,7 +3832,7 @@ ips_send(ips_ha_t *ha, ips_scb_t *scb, ips_scb_callback callback) { int ret; - DBG("ips_send"); + METHOD_TRACE("ips_send", 1); scb->callback = callback; @@ -3319,7 +3854,7 @@ ips_send_wait(ips_ha_t *ha, ips_scb_t *scb, int timeout, int intr) { int ret; - DBG("ips_send_wait"); + METHOD_TRACE("ips_send_wait", 1); ha->waitflag = TRUE; ha->cmd_in_progress = scb->cdb[0]; @@ -3347,7 +3882,7 @@ ips_send_cmd(ips_ha_t *ha, ips_scb_t *scb) { int ret; - DBG("ips_send_cmd"); + METHOD_TRACE("ips_send_cmd", 1); ret = IPS_SUCCESS; @@ -3576,7 +4111,7 @@ memcpy(scb->dcdb.scsi_cdb, scb->scsi_cmd->cmnd, scb->scsi_cmd->cmd_len); } - return (ips_issue(ha, scb)); + return ((*ha->func.issue)(ha, scb)); } /****************************************************************************/ @@ -3588,60 +4123,57 @@ /* Check the status of commands to logical drives */ /* */ /****************************************************************************/ -static int -ips_chkstatus(ips_ha_t *ha) { +static void +ips_chkstatus(ips_ha_t *ha, IPS_STATUS *pstatus) { ips_scb_t *scb; - ips_stat_t *sp = &ha->sp; + ips_stat_t *sp; u8 basic_status; u8 ext_status; - int command_id; int errcode; - int ret; - - DBG("ips_chkstatus"); - - command_id = ips_statupd(ha); - if (command_id > (IPS_MAX_CMDS-1)) { - printk(KERN_NOTICE "(%s%d) invalid command id received: %d\n", - ips_name, ha->host_num, command_id); + METHOD_TRACE("ips_chkstatus", 1); - return (-1); - } + scb = &ha->scbs[pstatus->fields.command_id]; + scb->basic_status = basic_status = pstatus->fields.basic_status & IPS_BASIC_STATUS_MASK; + scb->extended_status = ext_status = pstatus->fields.extended_status; - scb = &ha->scbs[command_id]; - sp->scb_addr = (u32) scb; + sp = &ha->sp; sp->residue_len = 0; - scb->basic_status = basic_status = ha->adapt->p_status_tail->basic_status & IPS_BASIC_STATUS_MASK; - scb->extended_status = ext_status = ha->adapt->p_status_tail->extended_status; + sp->scb_addr = (u32) scb; /* Remove the item from the active queue */ ips_removeq_scb(&ha->scb_activelist, scb); if (!scb->scsi_cmd) /* internal commands are handled in do_ipsintr */ - return (0); + return ; + + DEBUG_VAR(2, "(%s%d) ips_chkstatus: cmd 0x%X id %d (%d %d %d)", + ips_name, + ha->host_num, + scb->cdb[0], + scb->cmd.basic_io.command_id, + scb->bus, + scb->target_id, + scb->lun); #ifndef NO_IPS_CMDLINE if ((scb->scsi_cmd) && (ips_is_passthru(scb->scsi_cmd))) /* passthru - just returns the raw result */ - return (0); + return ; #endif errcode = DID_OK; - ret = 0; if (((basic_status & IPS_GSC_STATUS_MASK) == IPS_CMD_SUCCESS) || ((basic_status & IPS_GSC_STATUS_MASK) == IPS_CMD_RECOVERED_ERROR)) { if (scb->bus == 0) { -#if IPS_DEBUG >= 1 if ((basic_status & IPS_GSC_STATUS_MASK) == IPS_CMD_RECOVERED_ERROR) { - printk(KERN_NOTICE "(%s%d) Recovered Logical Drive Error OpCode: %x, BSB: %x, ESB: %x\n", - ips_name, ha->host_num, - scb->cmd.basic_io.op_code, basic_status, ext_status); + DEBUG_VAR(1, "(%s%d) Recovered Logical Drive Error OpCode: %x, BSB: %x, ESB: %x", + ips_name, ha->host_num, + scb->cmd.basic_io.op_code, basic_status, ext_status); } -#endif switch (scb->scsi_cmd->cmnd[0]) { case ALLOW_MEDIUM_REMOVAL: @@ -3650,7 +4182,6 @@ case WRITE_FILEMARKS: case SPACE: errcode = DID_ERROR; - ret = 1; break; case START_STOP: @@ -3659,7 +4190,6 @@ case TEST_UNIT_READY: if (!ips_online(ha, scb)) { errcode = DID_TIME_OUT; - ret = 1; } break; @@ -3668,7 +4198,6 @@ ips_inquiry(ha, scb); } else { errcode = DID_TIME_OUT; - ret = 1; } break; @@ -3687,7 +4216,6 @@ case MODE_SENSE: if (!ips_online(ha, scb) || !ips_msense(ha, scb)) { errcode = DID_ERROR; - ret = 1; } break; @@ -3696,7 +4224,6 @@ ips_rdcap(ha, scb); else { errcode = DID_TIME_OUT; - ret = 1; } break; @@ -3706,7 +4233,6 @@ case FORMAT_UNIT: errcode = DID_ERROR; - ret = 1; break; case SEEK_10: @@ -3718,7 +4244,6 @@ default: errcode = DID_ERROR; - ret = 1; } /* end switch */ scb->scsi_cmd->result = errcode << 16; @@ -3728,23 +4253,17 @@ ((((char *) scb->scsi_cmd->buffer)[0] & 0x1f) == TYPE_DISK)) { scb->scsi_cmd->result = DID_TIME_OUT << 16; - - ret = 1; } } /* else */ } else { /* recovered error / success */ -#if IPS_DEBUG >= 1 if (scb->bus == 0) { - printk(KERN_NOTICE "(%s%d) Unrecovered Logical Drive Error OpCode: %x, BSB: %x, ESB: %x\n", - ips_name, ha->host_num, - scb->cmd.basic_io.op_code, basic_status, ext_status); + DEBUG_VAR(1, "(%s%d) Unrecovered Logical Drive Error OpCode: %x, BSB: %x, ESB: %x", + ips_name, ha->host_num, + scb->cmd.basic_io.op_code, basic_status, ext_status); } -#endif - ret = ips_map_status(scb, sp); + ips_map_status(ha, scb, sp); } /* else */ - - return (ret); } /****************************************************************************/ @@ -3758,7 +4277,7 @@ /****************************************************************************/ static int ips_online(ips_ha_t *ha, ips_scb_t *scb) { - DBG("ips_online"); + METHOD_TRACE("ips_online", 1); if (scb->target_id >= IPS_MAX_LD) return (0); @@ -3792,7 +4311,7 @@ ips_inquiry(ips_ha_t *ha, ips_scb_t *scb) { IPS_INQ_DATA inq; - DBG("ips_inquiry"); + METHOD_TRACE("ips_inquiry", 1); memset(&inq, 0, sizeof(IPS_INQ_DATA)); @@ -3823,7 +4342,7 @@ ips_rdcap(ips_ha_t *ha, ips_scb_t *scb) { IPS_CAPACITY *cap; - DBG("ips_rdcap"); + METHOD_TRACE("ips_rdcap", 1); if (scb->scsi_cmd->bufflen < 8) return (0); @@ -3852,7 +4371,7 @@ u32 cylinders; ips_mdata_t mdata; - DBG("ips_msense"); + METHOD_TRACE("ips_msense", 1); if (ha->enq->ulDriveSize[scb->target_id] > 0x400000 && (ha->enq->ucMiscFlag & 0x8) == 0) { @@ -3930,7 +4449,7 @@ ips_reqsen(ips_ha_t *ha, ips_scb_t *scb) { char *sp; - DBG("ips_reqsen"); + METHOD_TRACE("ips_reqsen", 1); sp = (char *) scb->scsi_cmd->sense_buffer; memset(sp, 0, sizeof(scb->scsi_cmd->sense_buffer)); @@ -3956,7 +4475,7 @@ ips_free(ips_ha_t *ha) { int i; - DBG("ips_free"); + METHOD_TRACE("ips_free", 1); if (ha) { if (ha->enq) { @@ -4004,6 +4523,14 @@ kfree(ha->scbs); ha->scbs = NULL; } /* end if */ + + /* free memory mapped (if applicable) */ + if (ha->mem_ptr) { + iounmap(ha->ioremap_ptr); + ha->ioremap_ptr = NULL; + ha->mem_ptr = NULL; + ha->mem_addr = 0; + } } } @@ -4021,10 +4548,10 @@ ips_scb_t *scb_p; int i; - DBG("ips_allocatescbs"); + METHOD_TRACE("ips_allocatescbs", 1); /* Allocate memory for the CCBs */ - ha->scbs = (ips_scb_t *) kmalloc(ha->max_cmds * sizeof(ips_scb_t), GFP_KERNEL|GFP_DMA); + ha->scbs = (ips_scb_t *) kmalloc(ha->max_cmds * sizeof(ips_scb_t), GFP_ATOMIC|GFP_DMA); memset(ha->scbs, 0, ha->max_cmds * sizeof(ips_scb_t)); @@ -4032,7 +4559,7 @@ scb_p = &ha->scbs[i]; /* allocate S/G list */ - scb_p->sg_list = (IPS_SG_LIST *) kmalloc(sizeof(IPS_SG_LIST) * IPS_MAX_SG, GFP_KERNEL|GFP_DMA); + scb_p->sg_list = (IPS_SG_LIST *) kmalloc(sizeof(IPS_SG_LIST) * IPS_MAX_SG, GFP_ATOMIC|GFP_DMA); if (! scb_p->sg_list) return (0); @@ -4061,7 +4588,7 @@ ips_init_scb(ips_ha_t *ha, ips_scb_t *scb) { IPS_SG_LIST *sg_list; - DBG("ips_init_scb"); + METHOD_TRACE("ips_init_scb", 1); if (scb == NULL) return ; @@ -4102,7 +4629,7 @@ ips_scb_t *scb; u32 cpu_flags; - DBG("ips_getscb"); + METHOD_TRACE("ips_getscb", 1); IPS_SCB_LOCK(cpu_flags); if ((scb = ha->scb_freelist) == NULL) { @@ -4136,7 +4663,7 @@ ips_freescb(ips_ha_t *ha, ips_scb_t *scb) { u32 cpu_flags; - DBG("ips_freescb"); + METHOD_TRACE("ips_freescb", 1); /* check to make sure this is not our "special" scb */ if (IPS_COMMAND_ID(ha, scb) < (ha->max_cmds - 1)) { @@ -4149,7 +4676,7 @@ /****************************************************************************/ /* */ -/* Routine Name: ips_reset_adapter */ +/* Routine Name: ips_isinit_copperhead */ /* */ /* Routine Description: */ /* */ @@ -4157,21 +4684,402 @@ /* */ /****************************************************************************/ static int -ips_reset_adapter(ips_ha_t *ha) { - u8 Isr; - u8 Cbsp; - u8 PostByte[IPS_MAX_POST_BYTES]; +ips_isinit_copperhead(ips_ha_t *ha) { + u8 scpr; + u8 isr; + + METHOD_TRACE("ips_isinit_copperhead", 1); + + isr = inb(ha->io_addr + IPS_REG_HISR); + scpr = inb(ha->io_addr + IPS_REG_SCPR); + + if (((isr & IPS_BIT_EI) == 0) && ((scpr & IPS_BIT_EBM) == 0)) + return (0); + else + return (1); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_isinit_copperhead_memio */ +/* */ +/* Routine Description: */ +/* */ +/* Reset the controller */ +/* */ +/****************************************************************************/ +static int +ips_isinit_copperhead_memio(ips_ha_t *ha) { + u8 isr; + u8 scpr; + + METHOD_TRACE("ips_is_init_copperhead_memio", 1); + + isr = readb(ha->mem_ptr + IPS_REG_HISR); + scpr = readb(ha->mem_ptr + IPS_REG_SCPR); + + if (((isr & IPS_BIT_EI) == 0) && ((scpr & IPS_BIT_EBM) == 0)) + return (0); + else + return (1); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_isinit_morpheus */ +/* */ +/* Routine Description: */ +/* */ +/* Reset the controller */ +/* */ +/****************************************************************************/ +static int +ips_isinit_morpheus(ips_ha_t *ha) { + u32 post; + u32 bits; + + METHOD_TRACE("ips_is_init_morpheus", 1); + + post = readl(ha->mem_ptr + IPS_REG_I960_MSG0); + bits = readl(ha->mem_ptr + IPS_REG_I2O_HIR); + + if (post == 0) + return (0); + else if (bits & 0x3) + return (0); + else + return (1); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_enable_int_copperhead */ +/* */ +/* Routine Description: */ +/* Turn on interrupts */ +/* */ +/****************************************************************************/ +static void +ips_enable_int_copperhead(ips_ha_t *ha) { + METHOD_TRACE("ips_enable_int_copperhead", 1); + + outb(ha->io_addr + IPS_REG_HISR, IPS_BIT_EI); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_enable_int_copperhead_memio */ +/* */ +/* Routine Description: */ +/* Turn on interrupts */ +/* */ +/****************************************************************************/ +static void +ips_enable_int_copperhead_memio(ips_ha_t *ha) { + METHOD_TRACE("ips_enable_int_copperhead_memio", 1); + + writeb(IPS_BIT_EI, ha->mem_ptr + IPS_REG_HISR); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_enable_int_morpheus */ +/* */ +/* Routine Description: */ +/* Turn on interrupts */ +/* */ +/****************************************************************************/ +static void +ips_enable_int_morpheus(ips_ha_t *ha) { + u32 Oimr; + + METHOD_TRACE("ips_enable_int_morpheus", 1); + + Oimr = readl(ha->mem_ptr + IPS_REG_I960_OIMR); + Oimr &= ~0x08; + writel(Oimr, ha->mem_ptr + IPS_REG_I960_OIMR); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_init_copperhead */ +/* */ +/* Routine Description: */ +/* */ +/* Initialize a copperhead controller */ +/* */ +/****************************************************************************/ +static int +ips_init_copperhead(ips_ha_t *ha) { + u8 Isr; + u8 Cbsp; + u8 PostByte[IPS_MAX_POST_BYTES]; + u8 ConfigByte[IPS_MAX_CONFIG_BYTES]; + int i, j; + + METHOD_TRACE("ips_init_copperhead", 1); + + for (i = 0; i < IPS_MAX_POST_BYTES; i++) { + for (j = 0; j < 45; j++) { + Isr = inb(ha->io_addr + IPS_REG_HISR); + if (Isr & IPS_BIT_GHI) + break; + + MDELAY(IPS_ONE_SEC); + } + + if (j >= 45) + /* error occured */ + return (0); + + PostByte[i] = inb(ha->io_addr + IPS_REG_ISPR); + outb(Isr, ha->io_addr + IPS_REG_HISR); + } + + if (PostByte[0] < IPS_GOOD_POST_STATUS) { + printk(KERN_WARNING "(%s%d) reset controller fails (post status %x %x).\n", + ips_name, ha->host_num, PostByte[0], PostByte[1]); + + return (0); + } + + for (i = 0; i < IPS_MAX_CONFIG_BYTES; i++) { + for (j = 0; j < 240; j++) { + Isr = inb(ha->io_addr + IPS_REG_HISR); + if (Isr & IPS_BIT_GHI) + break; + + MDELAY(IPS_ONE_SEC); /* 100 msec */ + } + + if (j >= 240) + /* error occured */ + return (0); + + ConfigByte[i] = inb(ha->io_addr + IPS_REG_ISPR); + outb(Isr, ha->io_addr + IPS_REG_HISR); + } + + for (i = 0; i < 240; i++) { + Cbsp = inb(ha->io_addr + IPS_REG_CBSP); + + if ((Cbsp & IPS_BIT_OP) == 0) + break; + + MDELAY(IPS_ONE_SEC); + } + + if (i >= 240) + /* reset failed */ + return (0); + + /* setup CCCR */ + outw(0x1010, ha->io_addr + IPS_REG_CCCR); + + /* Enable busmastering */ + outb(IPS_BIT_EBM, ha->io_addr + IPS_REG_SCPR); + + if (ha->revision_id == IPS_REVID_TROMBONE64) + /* fix for anaconda64 */ + outl(0, ha->io_addr + IPS_REG_NDAE); + + /* Enable interrupts */ + outb(IPS_BIT_EI, ha->io_addr + IPS_REG_HISR); + + return (1); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_init_copperhead_memio */ +/* */ +/* Routine Description: */ +/* */ +/* Initialize a copperhead controller with memory mapped I/O */ +/* */ +/****************************************************************************/ +static int +ips_init_copperhead_memio(ips_ha_t *ha) { + u8 Isr; + u8 Cbsp; + u8 PostByte[IPS_MAX_POST_BYTES]; u8 ConfigByte[IPS_MAX_CONFIG_BYTES]; int i, j; + + METHOD_TRACE("ips_init_copperhead_memio", 1); + + for (i = 0; i < IPS_MAX_POST_BYTES; i++) { + for (j = 0; j < 45; j++) { + Isr = readb(ha->mem_ptr + IPS_REG_HISR); + if (Isr & IPS_BIT_GHI) + break; + + MDELAY(IPS_ONE_SEC); + } + + if (j >= 45) + /* error occured */ + return (0); + + PostByte[i] = readb(ha->mem_ptr + IPS_REG_ISPR); + writeb(Isr, ha->mem_ptr + IPS_REG_HISR); + } + + if (PostByte[0] < IPS_GOOD_POST_STATUS) { + printk(KERN_WARNING "(%s%d) reset controller fails (post status %x %x).\n", + ips_name, ha->host_num, PostByte[0], PostByte[1]); + + return (0); + } + + for (i = 0; i < IPS_MAX_CONFIG_BYTES; i++) { + for (j = 0; j < 240; j++) { + Isr = readb(ha->mem_ptr + IPS_REG_HISR); + if (Isr & IPS_BIT_GHI) + break; + + MDELAY(IPS_ONE_SEC); /* 100 msec */ + } + + if (j >= 240) + /* error occured */ + return (0); + + ConfigByte[i] = readb(ha->mem_ptr + IPS_REG_ISPR); + writeb(Isr, ha->mem_ptr + IPS_REG_HISR); + } + + for (i = 0; i < 240; i++) { + Cbsp = readb(ha->mem_ptr + IPS_REG_CBSP); + + if ((Cbsp & IPS_BIT_OP) == 0) + break; + + MDELAY(IPS_ONE_SEC); + } + + if (i >= 240) + /* error occured */ + return (0); + + /* setup CCCR */ + writel(0x1010, ha->mem_ptr + IPS_REG_CCCR); + + /* Enable busmastering */ + writeb(IPS_BIT_EBM, ha->mem_ptr + IPS_REG_SCPR); + + if (ha->revision_id == IPS_REVID_TROMBONE64) + /* fix for anaconda64 */ + writel(0, ha->mem_ptr + IPS_REG_NDAE); + + /* Enable interrupts */ + writeb(IPS_BIT_EI, ha->mem_ptr + IPS_REG_HISR); + + /* if we get here then everything went OK */ + return (1); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_init_morpheus */ +/* */ +/* Routine Description: */ +/* */ +/* Initialize a morpheus controller */ +/* */ +/****************************************************************************/ +static int +ips_init_morpheus(ips_ha_t *ha) { + u32 Post; + u32 Config; + u32 Isr; + u32 Oimr; + int i; + + METHOD_TRACE("ips_init_morpheus", 1); + + /* Wait up to 45 secs for Post */ + for (i = 0; i < 45; i++) { + Isr = readl(ha->mem_ptr + IPS_REG_I2O_HIR); + + if (Isr & IPS_BIT_I960_MSG0I) + break; + + MDELAY(IPS_ONE_SEC); + } + + if (i >= 45) { + /* error occured */ + printk(KERN_WARNING "(%s%d) timeout waiting for post.\n", + ips_name, ha->host_num); + + return (0); + } + + Post = readl(ha->mem_ptr + IPS_REG_I960_MSG0); + + /* Clear the interrupt bit */ + Isr = (u32) IPS_BIT_I960_MSG0I; + writel(Isr, ha->mem_ptr + IPS_REG_I2O_HIR); + + if (Post < (IPS_GOOD_POST_STATUS << 8)) { + printk(KERN_WARNING "(%s%d) reset controller fails (post status %x).\n", + ips_name, ha->host_num, Post); + + return (0); + } + + /* Wait up to 240 secs for config bytes */ + for (i = 0; i < 240; i++) { + Isr = readl(ha->mem_ptr + IPS_REG_I2O_HIR); + + if (Isr & IPS_BIT_I960_MSG1I) + break; + + MDELAY(IPS_ONE_SEC); /* 100 msec */ + } + + if (i >= 240) { + /* error occured */ + printk(KERN_WARNING "(%s%d) timeout waiting for config.\n", + ips_name, ha->host_num); + + return (0); + } + + Config = readl(ha->mem_ptr + IPS_REG_I960_MSG1); + + /* Clear interrupt bit */ + Isr = (u32) IPS_BIT_I960_MSG1I; + writel(Isr, ha->mem_ptr + IPS_REG_I2O_HIR); + + /* Turn on the interrupts */ + Oimr = readl(ha->mem_ptr + IPS_REG_I960_OIMR); + Oimr &= ~0x8; + writel(Oimr, ha->mem_ptr + IPS_REG_I960_OIMR); + + /* if we get here then everything went OK */ + return (1); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_reset_copperhead */ +/* */ +/* Routine Description: */ +/* */ +/* Reset the controller */ +/* */ +/****************************************************************************/ +static int +ips_reset_copperhead(ips_ha_t *ha) { int reset_counter; u32 cpu_flags; - DBG("ips_reset_adapter"); + METHOD_TRACE("ips_reset_copperhead", 1); -#if IPS_DEBUG >= 1 - printk(KERN_WARNING "ips_reset_adapter: io addr: %x, irq: %d\n", - ha->io_addr, ha->irq); -#endif + DEBUG_VAR(1, "(%s%d) ips_reset_copperhead: io addr: %x, irq: %d", + ips_name, ha->host_num, ha->io_addr, ha->irq); IPS_HA_LOCK(cpu_flags); @@ -4185,109 +5093,107 @@ outb(0, ha->io_addr + IPS_REG_SCPR); MDELAY(IPS_ONE_SEC); - for (i = 0; i < IPS_MAX_POST_BYTES; i++) { - for (j = 0; j < 45; j++) { - Isr = inb(ha->io_addr + IPS_REG_HISR); - if (Isr & IPS_BIT_GHI) - break; - - MDELAY(IPS_ONE_SEC); - } - - if (j >= 45) { - /* error occured */ - if (reset_counter < 2) - continue; - else { - /* reset failed */ - IPS_HA_UNLOCK(cpu_flags); - - return (0); - } - } + if ((*ha->func.init)(ha)) + break; + else if (reset_counter >= 2) { + IPS_HA_UNLOCK(cpu_flags); - PostByte[i] = inb(ha->io_addr + IPS_REG_ISPR); - outb(Isr, ha->io_addr + IPS_REG_HISR); + return (0); } + } - if (PostByte[0] < IPS_GOOD_POST_STATUS) { - printk("(%s%d) reset controller fails (post status %x %x).\n", - ips_name, ha->host_num, PostByte[0], PostByte[1]); + IPS_HA_UNLOCK(cpu_flags); - IPS_HA_UNLOCK(cpu_flags); + return (1); +} - return (0); - } +/****************************************************************************/ +/* */ +/* Routine Name: ips_reset_copperhead_memio */ +/* */ +/* Routine Description: */ +/* */ +/* Reset the controller */ +/* */ +/****************************************************************************/ +static int +ips_reset_copperhead_memio(ips_ha_t *ha) { + int reset_counter; + u32 cpu_flags; - for (i = 0; i < IPS_MAX_CONFIG_BYTES; i++) { - for (j = 0; j < 240; j++) { - Isr = inb(ha->io_addr + IPS_REG_HISR); - if (Isr & IPS_BIT_GHI) - break; + METHOD_TRACE("ips_reset_copperhead_memio", 1); - MDELAY(IPS_ONE_SEC); /* 100 msec */ - } + DEBUG_VAR(1, "(%s%d) ips_reset_copperhead_memio: mem addr: %x, irq: %d", + ips_name, ha->host_num, ha->mem_addr, ha->irq); - if (j >= 240) { - /* error occured */ - if (reset_counter < 2) - continue; - else { - /* reset failed */ - IPS_HA_UNLOCK(cpu_flags); + IPS_HA_LOCK(cpu_flags); - return (0); - } - } + reset_counter = 0; - ConfigByte[i] = inb(ha->io_addr + IPS_REG_ISPR); - outb(Isr, ha->io_addr + IPS_REG_HISR); - } + while (reset_counter < 2) { + reset_counter++; - if (ConfigByte[0] == 0 && ConfigByte[1] == 2) { - printk("(%s%d) reset controller fails (status %x %x).\n", - ips_name, ha->host_num, ConfigByte[0], ConfigByte[1]); + writeb(IPS_BIT_RST, ha->mem_ptr + IPS_REG_SCPR); + MDELAY(IPS_ONE_SEC); + writeb(0, ha->mem_ptr + IPS_REG_SCPR); + MDELAY(IPS_ONE_SEC); + if ((*ha->func.init)(ha)) + break; + else if (reset_counter >= 2) { IPS_HA_UNLOCK(cpu_flags); return (0); } + } - for (i = 0; i < 240; i++) { - Cbsp = inb(ha->io_addr + IPS_REG_CBSP); + IPS_HA_UNLOCK(cpu_flags); - if ((Cbsp & IPS_BIT_OP) == 0) - break; + return (1); +} - MDELAY(IPS_ONE_SEC); - } +/****************************************************************************/ +/* */ +/* Routine Name: ips_reset_morpheus */ +/* */ +/* Routine Description: */ +/* */ +/* Reset the controller */ +/* */ +/****************************************************************************/ +static int +ips_reset_morpheus(ips_ha_t *ha) { + int reset_counter; + u8 junk; + u32 cpu_flags; - if (i >= 240) { - /* error occured */ - if (reset_counter < 2) - continue; - else { - /* reset failed */ - IPS_HA_UNLOCK(cpu_flags); + METHOD_TRACE("ips_reset_morpheus", 1); - return (0); - } - } + DEBUG_VAR(1, "(%s%d) ips_reset_morpheus: mem addr: %x, irq: %d", + ips_name, ha->host_num, ha->mem_addr, ha->irq); - /* setup CCCR */ - outw(0x1010, ha->io_addr + IPS_REG_CCCR); + IPS_HA_LOCK(cpu_flags); - /* Enable busmastering */ - outb(IPS_BIT_EBM, ha->io_addr + IPS_REG_SCPR); + reset_counter = 0; - /* setup status queues */ - ips_statinit(ha); + while (reset_counter < 2) { + reset_counter++; - /* Enable interrupts */ - outb(IPS_BIT_EI, ha->io_addr + IPS_REG_HISR); + writel(0x80000000, ha->mem_ptr + IPS_REG_I960_IDR); - /* if we get here then everything went OK */ - break; + /* Delay for 300 msec */ + MDELAY(300 * IPS_ONE_MSEC); + + /* Do a PCI config read to wait for adapter */ + pci_read_config_byte(ha->pcidev, 4, &junk); + + if ((*ha->func.init)(ha)) + break; + else if (reset_counter >= 2) { + IPS_HA_UNLOCK(cpu_flags); + + return (0); + } } IPS_HA_UNLOCK(cpu_flags); @@ -4308,7 +5214,7 @@ ips_statinit(ips_ha_t *ha) { u32 phys_status_start; - DBG("ips_statinit"); + METHOD_TRACE("ips_statinit", 1); ha->adapt->p_status_start = ha->adapt->status; ha->adapt->p_status_end = ha->adapt->status + IPS_MAX_CMDS; @@ -4326,18 +5232,45 @@ /****************************************************************************/ /* */ -/* Routine Name: ips_statupd */ +/* Routine Name: ips_statinit_memio */ /* */ /* Routine Description: */ /* */ -/* Remove an element from the status queue */ +/* Initialize the status queues on the controller */ /* */ /****************************************************************************/ -static int -ips_statupd(ips_ha_t *ha) { - int command_id; +static void +ips_statinit_memio(ips_ha_t *ha) { + u32 phys_status_start; + + METHOD_TRACE("ips_statinit_memio", 1); + + ha->adapt->p_status_start = ha->adapt->status; + ha->adapt->p_status_end = ha->adapt->status + IPS_MAX_CMDS; + ha->adapt->p_status_tail = ha->adapt->status; + + phys_status_start = VIRT_TO_BUS(ha->adapt->status); + writel(phys_status_start, ha->mem_ptr + IPS_REG_SQSR); + writel(phys_status_start + IPS_STATUS_Q_SIZE, ha->mem_ptr + IPS_REG_SQER); + writel(phys_status_start + IPS_STATUS_SIZE, ha->mem_ptr + IPS_REG_SQHR); + writel(phys_status_start, ha->mem_ptr + IPS_REG_SQTR); + + ha->adapt->hw_status_start = phys_status_start; + ha->adapt->hw_status_tail = phys_status_start; +} - DBG("ips_statupd"); +/****************************************************************************/ +/* */ +/* Routine Name: ips_statupd_copperhead */ +/* */ +/* Routine Description: */ +/* */ +/* Remove an element from the status queue */ +/* */ +/****************************************************************************/ +static u32 +ips_statupd_copperhead(ips_ha_t *ha) { + METHOD_TRACE("ips_statupd_copperhead", 1); if (ha->adapt->p_status_tail != ha->adapt->p_status_end) { ha->adapt->p_status_tail++; @@ -4349,47 +5282,87 @@ outl(ha->adapt->hw_status_tail, ha->io_addr + IPS_REG_SQTR); - command_id = ha->adapt->p_status_tail->command_id; + return (ha->adapt->p_status_tail->value); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_statupd_copperhead_memio */ +/* */ +/* Routine Description: */ +/* */ +/* Remove an element from the status queue */ +/* */ +/****************************************************************************/ +static u32 +ips_statupd_copperhead_memio(ips_ha_t *ha) { + METHOD_TRACE("ips_statupd_copperhead_memio", 1); + + if (ha->adapt->p_status_tail != ha->adapt->p_status_end) { + ha->adapt->p_status_tail++; + ha->adapt->hw_status_tail += sizeof(IPS_STATUS); + } else { + ha->adapt->p_status_tail = ha->adapt->p_status_start; + ha->adapt->hw_status_tail = ha->adapt->hw_status_start; + } - return (command_id); + writel(ha->adapt->hw_status_tail, ha->mem_ptr + IPS_REG_SQTR); + + return (ha->adapt->p_status_tail->value); } /****************************************************************************/ /* */ -/* Routine Name: ips_issue */ +/* Routine Name: ips_statupd_morpheus */ /* */ /* Routine Description: */ /* */ -/* Send a command down to the controller */ +/* Remove an element from the status queue */ /* */ -/* ASSUMED to be called from within a lock */ +/****************************************************************************/ +static u32 +ips_statupd_morpheus(ips_ha_t *ha) { + u32 val; + + METHOD_TRACE("ips_statupd_morpheus", 1); + + val = readl(ha->mem_ptr + IPS_REG_I2O_OUTMSGQ); + + return (val); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_issue_copperhead */ +/* */ +/* Routine Description: */ +/* */ +/* Send a command down to the controller */ /* */ /****************************************************************************/ static int -ips_issue(ips_ha_t *ha, ips_scb_t *scb) { +ips_issue_copperhead(ips_ha_t *ha, ips_scb_t *scb) { u32 TimeOut; u16 val; u32 cpu_flags; - DBG("ips_issue"); + METHOD_TRACE("ips_issue_copperhead", 1); -#if IPS_DEBUG >= 10 - if (scb->scsi_cmd) - printk(KERN_NOTICE "%s: ips_issue: cmd 0x%X id %d (%d %d %d)\n", - ips_name, - scb->cdb[0], - scb->cmd.basic_io.command_id, - scb->bus, - scb->target_id, - scb->lun); - else - printk(KERN_NOTICE "%s: ips_issue: logical cmd id %d\n", - ips_name, - scb->cmd.basic_io.command_id); -#if IPS_DEBUG >= 11 - MDELAY(IPS_ONE_SEC); -#endif -#endif + if (scb->scsi_cmd) { + DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)", + ips_name, + ha->host_num, + scb->cdb[0], + scb->cmd.basic_io.command_id, + scb->bus, + scb->target_id, + scb->lun); + } else { + DEBUG_VAR(2, KERN_NOTICE "(%s%d) ips_issue: logical cmd id %d", + ips_name, + ha->host_num, + scb->cmd.basic_io.command_id); + } IPS_HA_LOCK(cpu_flags); @@ -4416,14 +5389,189 @@ outl(scb->scb_busaddr, ha->io_addr + IPS_REG_CCSAR); outw(IPS_BIT_START_CMD, ha->io_addr + IPS_REG_CCCR); - IPS_HA_UNLOCK(cpu_flags); + IPS_HA_UNLOCK(cpu_flags); + + return (IPS_SUCCESS); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_issue_copperhead_memio */ +/* */ +/* Routine Description: */ +/* */ +/* Send a command down to the controller */ +/* */ +/****************************************************************************/ +static int +ips_issue_copperhead_memio(ips_ha_t *ha, ips_scb_t *scb) { + u32 TimeOut; + u32 val; + u32 cpu_flags; + + METHOD_TRACE("ips_issue_copperhead_memio", 1); + + if (scb->scsi_cmd) { + DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)", + ips_name, + ha->host_num, + scb->cdb[0], + scb->cmd.basic_io.command_id, + scb->bus, + scb->target_id, + scb->lun); + } else { + DEBUG_VAR(2, "(%s%d) ips_issue: logical cmd id %d", + ips_name, + ha->host_num, + scb->cmd.basic_io.command_id); + } + + IPS_HA_LOCK(cpu_flags); + + TimeOut = 0; + + while ((val = readl(ha->mem_ptr + IPS_REG_CCCR)) & IPS_BIT_SEM) { + UDELAY(1000); + + if (++TimeOut >= IPS_SEM_TIMEOUT) { + if (!(val & IPS_BIT_START_STOP)) + break; + + printk(KERN_WARNING "(%s%d) ips_issue val [0x%x].\n", + ips_name, ha->host_num, val); + printk(KERN_WARNING "(%s%d) ips_issue semaphore chk timeout.\n", + ips_name, ha->host_num); + + IPS_HA_UNLOCK(cpu_flags); + + return (IPS_FAILURE); + } /* end if */ + } /* end while */ + + writel(scb->scb_busaddr, ha->mem_ptr + IPS_REG_CCSAR); + writel(IPS_BIT_START_CMD, ha->mem_ptr + IPS_REG_CCCR); + + IPS_HA_UNLOCK(cpu_flags); + + return (IPS_SUCCESS); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_issue_i2o */ +/* */ +/* Routine Description: */ +/* */ +/* Send a command down to the controller */ +/* */ +/****************************************************************************/ +static int +ips_issue_i2o(ips_ha_t *ha, ips_scb_t *scb) { + u32 cpu_flags; + + METHOD_TRACE("ips_issue_i2o", 1); + + if (scb->scsi_cmd) { + DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)", + ips_name, + ha->host_num, + scb->cdb[0], + scb->cmd.basic_io.command_id, + scb->bus, + scb->target_id, + scb->lun); + } else { + DEBUG_VAR(2, "(%s%d) ips_issue: logical cmd id %d", + ips_name, + ha->host_num, + scb->cmd.basic_io.command_id); + } + + IPS_HA_LOCK(cpu_flags); + + outl(scb->scb_busaddr, ha->io_addr + IPS_REG_I2O_INMSGQ); + + IPS_HA_UNLOCK(cpu_flags); + + return (IPS_SUCCESS); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_issue_i2o_memio */ +/* */ +/* Routine Description: */ +/* */ +/* Send a command down to the controller */ +/* */ +/****************************************************************************/ +static int +ips_issue_i2o_memio(ips_ha_t *ha, ips_scb_t *scb) { + u32 cpu_flags; + + METHOD_TRACE("ips_issue_i2o_memio", 1); + + if (scb->scsi_cmd) { + DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)", + ips_name, + ha->host_num, + scb->cdb[0], + scb->cmd.basic_io.command_id, + scb->bus, + scb->target_id, + scb->lun); + } else { + DEBUG_VAR(2, "(%s%d) ips_issue: logical cmd id %d", + ips_name, + ha->host_num, + scb->cmd.basic_io.command_id); + } + + IPS_HA_LOCK(cpu_flags); + + writel(scb->scb_busaddr, ha->mem_ptr + IPS_REG_I2O_INMSGQ); + + IPS_HA_UNLOCK(cpu_flags); + + return (IPS_SUCCESS); +} + +/****************************************************************************/ +/* */ +/* Routine Name: ips_isintr_copperhead */ +/* */ +/* Routine Description: */ +/* */ +/* Test to see if an interrupt is for us */ +/* */ +/****************************************************************************/ +static int +ips_isintr_copperhead(ips_ha_t *ha) { + u8 Isr; + + METHOD_TRACE("ips_isintr_copperhead", 2); + + Isr = inb(ha->io_addr + IPS_REG_HISR); + + if (Isr == 0xFF) + /* ?!?! Nothing really there */ + return (0); + + if (Isr & IPS_BIT_SCE) + return (1); + else if (Isr & (IPS_BIT_SQO | IPS_BIT_GHI)) { + /* status queue overflow or GHI */ + /* just clear the interrupt */ + outb(Isr, ha->io_addr + IPS_REG_HISR); + } - return (IPS_SUCCESS); + return (0); } /****************************************************************************/ /* */ -/* Routine Name: ips_isintr */ +/* Routine Name: ips_isintr_copperhead_memio */ /* */ /* Routine Description: */ /* */ @@ -4431,12 +5579,12 @@ /* */ /****************************************************************************/ static int -ips_isintr(ips_ha_t *ha) { +ips_isintr_copperhead_memio(ips_ha_t *ha) { u8 Isr; - DBG("ips_isintr"); + METHOD_TRACE("ips_isintr_memio", 2); - Isr = inb(ha->io_addr + IPS_REG_HISR); + Isr = readb(ha->mem_ptr + IPS_REG_HISR); if (Isr == 0xFF) /* ?!?! Nothing really there */ @@ -4447,7 +5595,7 @@ else if (Isr & (IPS_BIT_SQO | IPS_BIT_GHI)) { /* status queue overflow or GHI */ /* just clear the interrupt */ - outb(Isr, ha->io_addr + IPS_REG_HISR); + writeb(Isr, ha->mem_ptr + IPS_REG_HISR); } return (0); @@ -4455,6 +5603,29 @@ /****************************************************************************/ /* */ +/* Routine Name: ips_isintr_morpheus */ +/* */ +/* Routine Description: */ +/* */ +/* Test to see if an interrupt is for us */ +/* */ +/****************************************************************************/ +static int +ips_isintr_morpheus(ips_ha_t *ha) { + u32 Isr; + + METHOD_TRACE("ips_isintr_morpheus", 2); + + Isr = readl(ha->mem_ptr + IPS_REG_I2O_HIR); + + if (Isr & IPS_BIT_I2O_OPQI) + return (1); + else + return (0); +} + +/****************************************************************************/ +/* */ /* Routine Name: ips_wait */ /* */ /* Routine Description: */ @@ -4467,7 +5638,7 @@ int ret; u8 done; - DBG("ips_wait"); + METHOD_TRACE("ips_wait", 1); ret = IPS_FAILURE; done = FALSE; @@ -4502,7 +5673,7 @@ while (test_and_set_bit(IPS_IN_INTR, &ha->flags)) UDELAY(1000); - ips_intr(ha); + (*ha->func.intr)(ha); clear_bit(IPS_IN_INTR, &ha->flags); } else if (intr == IPS_INTR_HAL) { @@ -4528,7 +5699,7 @@ while (test_and_set_bit(IPS_IN_INTR, &ha->flags)) UDELAY(1000); - ips_intr(ha); + (*ha->func.intr)(ha); clear_bit(IPS_IN_INTR, &ha->flags); @@ -4553,7 +5724,7 @@ /****************************************************************************/ static int ips_write_driver_status(ips_ha_t *ha, int intr) { - DBG("ips_write_driver_status"); + METHOD_TRACE("ips_write_driver_status", 1); if (!ips_readwrite_page5(ha, FALSE, intr)) { printk(KERN_WARNING "(%s%d) unable to read NVRAM page 5.\n", @@ -4565,21 +5736,18 @@ /* check to make sure the page has a valid */ /* signature */ if (ha->nvram->signature != IPS_NVRAM_P5_SIG) { -#if IPS_DEBUG >= 1 - printk("(%s%d) NVRAM page 5 has an invalid signature: %X.\n", - ips_name, ha->host_num, ha->nvram->signature); -#endif + DEBUG_VAR(1, "(%s%d) NVRAM page 5 has an invalid signature: %X.", + ips_name, ha->host_num, ha->nvram->signature); + return (1); } -#if IPS_DEBUG >= 2 - printk("(%s%d) Ad Type: %d, Ad Slot: %d, BIOS: %c%c%c%c %c%c%c%c.\n", - ips_name, ha->host_num, ha->nvram->adapter_type, ha->nvram->adapter_slot, - ha->nvram->bios_high[0], ha->nvram->bios_high[1], - ha->nvram->bios_high[2], ha->nvram->bios_high[3], - ha->nvram->bios_low[0], ha->nvram->bios_low[1], - ha->nvram->bios_low[2], ha->nvram->bios_low[3]); -#endif + DEBUG_VAR(2, "(%s%d) Ad Type: %d, Ad Slot: %d, BIOS: %c%c%c%c %c%c%c%c.", + ips_name, ha->host_num, ha->nvram->adapter_type, ha->nvram->adapter_slot, + ha->nvram->bios_high[0], ha->nvram->bios_high[1], + ha->nvram->bios_high[2], ha->nvram->bios_high[3], + ha->nvram->bios_low[0], ha->nvram->bios_low[1], + ha->nvram->bios_low[2], ha->nvram->bios_low[3]); /* save controller type */ ha->ad_type = ha->nvram->adapter_type; @@ -4614,7 +5782,7 @@ ips_scb_t *scb; int ret; - DBG("ips_read_adapter_status"); + METHOD_TRACE("ips_read_adapter_status", 1); scb = &ha->scbs[ha->max_cmds-1]; @@ -4633,8 +5801,9 @@ scb->cmd.basic_io.reserved = 0; /* send command */ - ret = ips_send_wait(ha, scb, ips_cmd_timeout, intr); - if ((ret == IPS_FAILURE) || (ret == IPS_SUCCESS_IMM)) + if (((ret = ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) || + (ret == IPS_SUCCESS_IMM) || + ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) return (0); return (1); @@ -4654,7 +5823,7 @@ ips_scb_t *scb; int ret; - DBG("ips_read_subsystem_parameters"); + METHOD_TRACE("ips_read_subsystem_parameters", 1); scb = &ha->scbs[ha->max_cmds-1]; @@ -4673,8 +5842,9 @@ scb->cmd.basic_io.reserved = 0; /* send command */ - ret = ips_send_wait(ha, scb, ips_cmd_timeout, intr); - if ((ret == IPS_FAILURE) || (ret == IPS_SUCCESS_IMM)) + if (((ret = ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) || + (ret == IPS_SUCCESS_IMM) || + ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) return (0); return (1); @@ -4695,7 +5865,7 @@ int i; int ret; - DBG("ips_read_config"); + METHOD_TRACE("ips_read_config", 1); /* set defaults for initiator IDs */ ha->conf->init_id[0] = IPS_ADAPTER_ID; @@ -4745,7 +5915,7 @@ ips_scb_t *scb; int ret; - DBG("ips_readwrite_page5"); + METHOD_TRACE("ips_readwrite_page5", 1); scb = &ha->scbs[ha->max_cmds-1]; @@ -4789,7 +5959,7 @@ ips_scb_t *scb; int ret; - DBG("ips_clear_adapter"); + METHOD_TRACE("ips_clear_adapter", 1); scb = &ha->scbs[ha->max_cmds-1]; @@ -4807,8 +5977,9 @@ scb->cmd.config_sync.reserved3 = 0; /* issue command */ - ret = ips_send_wait(ha, scb, ips_reset_timeout, intr); - if ((ret == IPS_FAILURE) || (ret == IPS_SUCCESS_IMM)) + if (((ret = ips_send_wait(ha, scb, ips_reset_timeout, intr)) == IPS_FAILURE) || + (ret == IPS_SUCCESS_IMM) || + ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) return (0); /* send unlock stripe command */ @@ -4826,8 +5997,9 @@ scb->cmd.unlock_stripe.reserved3 = 0; /* issue command */ - ret = ips_send_wait(ha, scb, ips_reset_timeout, intr); - if ((ret == IPS_FAILURE) || (ret == IPS_SUCCESS_IMM)) + if (((ret = ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) || + (ret == IPS_SUCCESS_IMM) || + ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) return (0); return (1); @@ -4846,7 +6018,7 @@ ips_ffdc_reset(ips_ha_t *ha, int intr) { ips_scb_t *scb; - DBG("ips_ffdc_reset"); + METHOD_TRACE("ips_ffdc_reset", 1); scb = &ha->scbs[ha->max_cmds-1]; @@ -4879,12 +6051,10 @@ ips_ffdc_time(ips_ha_t *ha, int intr) { ips_scb_t *scb; - DBG("ips_ffdc_time"); + METHOD_TRACE("ips_ffdc_time", 1); -#if IPS_DEBUG >= 1 - printk(KERN_NOTICE "(%s%d) Sending time update.\n", - ips_name, ha->host_num); -#endif + DEBUG_VAR(1, "(%s%d) Sending time update.", + ips_name, ha->host_num); scb = &ha->scbs[ha->max_cmds-1]; @@ -4933,6 +6103,8 @@ {30, 30}, {31, 31} }; + METHOD_TRACE("ips_fix_ffdc_time", 1); + days = current_time / IPS_SECS_DAY; rem = current_time % IPS_SECS_DAY; @@ -4981,6 +6153,8 @@ int timeout; u8 status; + METHOD_TRACE("ips_erase_bios", 1); + /* Clear the status register */ outl(0, ha->io_addr + IPS_REG_FLAP); if (ha->revision_id == IPS_REVID_TROMBONE64) @@ -5077,6 +6251,115 @@ /****************************************************************************/ /* */ +/* Routine Name: ips_erase_bios_memio */ +/* */ +/* Routine Description: */ +/* Erase the BIOS on the adapter */ +/* */ +/****************************************************************************/ +static int +ips_erase_bios_memio(ips_ha_t *ha) { + int timeout; + u8 status; + + METHOD_TRACE("ips_erase_bios_memio", 1); + + /* Clear the status register */ + writel(0, ha->mem_ptr + IPS_REG_FLAP); + if (ha->revision_id == IPS_REVID_TROMBONE64) + UDELAY(5); /* 5 us */ + + writeb(0x50, ha->mem_ptr + IPS_REG_FLDP); + if (ha->revision_id == IPS_REVID_TROMBONE64) + UDELAY(5); /* 5 us */ + + /* Erase Setup */ + writeb(0x20, ha->mem_ptr + IPS_REG_FLDP); + if (ha->revision_id == IPS_REVID_TROMBONE64) + UDELAY(5); /* 5 us */ + + /* Erase Confirm */ + writeb(0xD0, ha->mem_ptr + IPS_REG_FLDP); + if (ha->revision_id == IPS_REVID_TROMBONE64) + UDELAY(5); /* 5 us */ + + /* Erase Status */ + writeb(0x70, ha->mem_ptr + IPS_REG_FLDP); + if (ha->revision_id == IPS_REVID_TROMBONE64) + UDELAY(5); /* 5 us */ + + timeout = 80000; /* 80 seconds */ + + while (timeout > 0) { + if (ha->revision_id == IPS_REVID_TROMBONE64) { + writel(0, ha->mem_ptr + IPS_REG_FLAP); + UDELAY(5); /* 5 us */ + } + + status = readb(ha->mem_ptr + IPS_REG_FLDP); + + if (status & 0x80) + break; + + MDELAY(1); + timeout--; + } + + /* check for timeout */ + if (timeout <= 0) { + /* timeout */ + + /* try to suspend the erase */ + writeb(0xB0, ha->mem_ptr + IPS_REG_FLDP); + if (ha->revision_id == IPS_REVID_TROMBONE64) + UDELAY(5); /* 5 us */ + + /* wait for 10 seconds */ + timeout = 10000; + while (timeout > 0) { + if (ha->revision_id == IPS_REVID_TROMBONE64) { + writel(0, ha->mem_ptr + IPS_REG_FLAP); + UDELAY(5); /* 5 us */ + } + + status = readb(ha->mem_ptr + IPS_REG_FLDP); + + if (status & 0xC0) + break; + + MDELAY(1); + timeout--; + } + + return (1); + } + + /* check for valid VPP */ + if (status & 0x08) + /* VPP failure */ + return (1); + + /* check for succesful flash */ + if (status & 0x30) + /* sequence error */ + return (1); + + /* Otherwise, we were successful */ + /* clear status */ + writeb(0x50, ha->mem_ptr + IPS_REG_FLDP); + if (ha->revision_id == IPS_REVID_TROMBONE64) + UDELAY(5); /* 5 us */ + + /* enable reads */ + writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP); + if (ha->revision_id == IPS_REVID_TROMBONE64) + UDELAY(5); /* 5 us */ + + return (0); +} + +/****************************************************************************/ +/* */ /* Routine Name: ips_program_bios */ /* */ /* Routine Description: */ @@ -5089,6 +6372,8 @@ int timeout; u8 status; + METHOD_TRACE("ips_program_bios", 1); + for (i = 0; i < buffersize; i++) { /* write a byte */ outl(i, ha->io_addr + IPS_REG_FLAP); @@ -5162,6 +6447,93 @@ /****************************************************************************/ /* */ +/* Routine Name: ips_program_bios_memio */ +/* */ +/* Routine Description: */ +/* Program the BIOS on the adapter */ +/* */ +/****************************************************************************/ +static int +ips_program_bios_memio(ips_ha_t *ha, char *buffer, int buffersize) { + int i; + int timeout; + u8 status; + + METHOD_TRACE("ips_program_bios_memio", 1); + + for (i = 0; i < buffersize; i++) { + /* write a byte */ + writel(i, ha->mem_ptr + IPS_REG_FLAP); + if (ha->revision_id == IPS_REVID_TROMBONE64) + UDELAY(5); /* 5 us */ + + writeb(0x40, ha->mem_ptr + IPS_REG_FLDP); + if (ha->revision_id == IPS_REVID_TROMBONE64) + UDELAY(5); /* 5 us */ + + writeb(buffer[i], ha->mem_ptr + IPS_REG_FLDP); + if (ha->revision_id == IPS_REVID_TROMBONE64) + UDELAY(5); /* 5 us */ + + /* wait up to one second */ + timeout = 1000; + while (timeout > 0) { + if (ha->revision_id == IPS_REVID_TROMBONE64) { + writel(0, ha->mem_ptr + IPS_REG_FLAP); + UDELAY(5); /* 5 us */ + } + + status = readb(ha->mem_ptr + IPS_REG_FLDP); + + if (status & 0x80) + break; + + MDELAY(1); + timeout--; + } + + if (timeout == 0) { + /* timeout error */ + writel(0, ha->mem_ptr + IPS_REG_FLAP); + if (ha->revision_id == IPS_REVID_TROMBONE64) + UDELAY(5); /* 5 us */ + + writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP); + if (ha->revision_id == IPS_REVID_TROMBONE64) + UDELAY(5); /* 5 us */ + + return (1); + } + + /* check the status */ + if (status & 0x18) { + /* programming error */ + writel(0, ha->mem_ptr + IPS_REG_FLAP); + if (ha->revision_id == IPS_REVID_TROMBONE64) + UDELAY(5); /* 5 us */ + + writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP); + if (ha->revision_id == IPS_REVID_TROMBONE64) + UDELAY(5); /* 5 us */ + + return (1); + } + } /* end for */ + + /* Enable reading */ + writel(0, ha->mem_ptr + IPS_REG_FLAP); + if (ha->revision_id == IPS_REVID_TROMBONE64) + UDELAY(5); /* 5 us */ + + writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP); + if (ha->revision_id == IPS_REVID_TROMBONE64) + UDELAY(5); /* 5 us */ + + return (0); +} + +/****************************************************************************/ +/* */ /* Routine Name: ips_verify_bios */ /* */ /* Routine Description: */ @@ -5173,6 +6545,8 @@ u8 checksum; int i; + METHOD_TRACE("ips_verify_bios", 1); + /* test 1st byte */ outl(0, ha->io_addr + IPS_REG_FLAP); if (ha->revision_id == IPS_REVID_TROMBONE64) @@ -5205,13 +6579,56 @@ return (0); } -#if defined (MODULE) +/****************************************************************************/ +/* */ +/* Routine Name: ips_verify_bios_memio */ +/* */ +/* Routine Description: */ +/* Verify the BIOS on the adapter */ +/* */ +/****************************************************************************/ +static int +ips_verify_bios_memio(ips_ha_t *ha, char *buffer, int buffersize) { + u8 checksum; + int i; + + METHOD_TRACE("ips_verify_bios_memio", 1); + + /* test 1st byte */ + writel(0, ha->mem_ptr + IPS_REG_FLAP); + if (ha->revision_id == IPS_REVID_TROMBONE64) + UDELAY(5); /* 5 us */ -Scsi_Host_Template driver_template = IPS; + if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0x55) + return (1); - #include "scsi_module.c" + writel(1, ha->mem_ptr + IPS_REG_FLAP); + if (ha->revision_id == IPS_REVID_TROMBONE64) + UDELAY(5); /* 5 us */ + if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0xAA) + return (1); + + checksum = 0xff; + for (i = 2; i < buffersize; i++) { + + writel(i, ha->mem_ptr + IPS_REG_FLAP); + if (ha->revision_id == IPS_REVID_TROMBONE64) + UDELAY(5); /* 5 us */ + + checksum = (u8) checksum + readb(ha->mem_ptr + IPS_REG_FLDP); + } + + if (checksum != 0) + /* failure */ + return (1); + else + /* success */ + return (0); +} + +static Scsi_Host_Template driver_template = IPS; +#include "scsi_module.c" -#endif /* diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/ips.h linux/drivers/scsi/ips.h --- v2.4.0-test8/linux/drivers/scsi/ips.h Fri Sep 8 12:54:34 2000 +++ linux/drivers/scsi/ips.h Thu Sep 21 13:22:05 2000 @@ -1,5 +1,5 @@ /*****************************************************************************/ -/* ips.h -- driver for the IBM ServeRAID adapter */ +/* ips.h -- driver for the IBM ServeRAID controller */ /* */ /* Written By: Keith Mitchell, IBM Corporation */ /* */ @@ -53,8 +53,6 @@ /* Prototypes */ extern int ips_detect(Scsi_Host_Template *); extern int ips_release(struct Scsi_Host *); - extern int ips_abort(Scsi_Cmnd *); - extern int ips_reset(Scsi_Cmnd *, unsigned int); extern int ips_eh_abort(Scsi_Cmnd *); extern int ips_eh_reset(Scsi_Cmnd *); extern int ips_queue(Scsi_Cmnd *, void (*) (Scsi_Cmnd *)); @@ -71,7 +69,21 @@ #define IPS_HA(x) ((ips_ha_t *) x->hostdata) #define IPS_COMMAND_ID(ha, scb) (int) (scb - ha->scbs) - + #define IPS_IS_TROMBONE(ha) (((ha->device_id == IPS_COPPERHEAD_DEVICEID) && \ + (ha->revision_id >= IPS_REVID_TROMBONE32) && \ + (ha->revision_id <= IPS_REVID_TROMBONE64)) ? 1 : 0) + #define IPS_IS_CLARINET(ha) (((ha->device_id == IPS_COPPERHEAD_DEVICEID) && \ + (ha->revision_id >= IPS_REVID_CLARINETP1) && \ + (ha->revision_id <= IPS_REVID_CLARINETP3)) ? 1 : 0) + #define IPS_IS_MORPHEUS(ha) (ha->device_id == IPS_MORPHEUS_DEVICEID) + #define IPS_USE_I2O_DELIVER(ha) ((IPS_IS_MORPHEUS(ha) || \ + (IPS_IS_TROMBONE(ha) && \ + (ips_force_i2o))) ? 1 : 0) + #define IPS_USE_I2O_STATUS(ha) (IPS_IS_MORPHEUS(ha)) + #define IPS_USE_MEMIO(ha) ((IPS_IS_MORPHEUS(ha) || \ + ((IPS_IS_TROMBONE(ha) || IPS_IS_CLARINET(ha)) && \ + (ips_force_memio))) ? 1 : 0) + #ifndef VIRT_TO_BUS #define VIRT_TO_BUS(x) (unsigned int)virt_to_bus((void *) x) #endif @@ -79,7 +91,7 @@ #ifndef UDELAY #define UDELAY udelay #endif - + #ifndef MDELAY #define MDELAY mdelay #endif @@ -87,15 +99,15 @@ #ifndef verify_area_20 #define verify_area_20(t,a,sz) (0) /* success */ #endif - + #ifndef PUT_USER #define PUT_USER put_user #endif - + #ifndef __PUT_USER #define __PUT_USER __put_user #endif - + #ifndef GET_USER #define GET_USER get_user #endif @@ -129,6 +141,14 @@ #define IPS_REG_CBSP 0x07 /* CBSP register */ #define IPS_REG_FLAP 0x18 /* Flash address port */ #define IPS_REG_FLDP 0x1C /* Flash data port */ + #define IPS_REG_NDAE 0x38 /* Anaconda 64 NDAE Register */ + #define IPS_REG_I2O_INMSGQ 0x40 /* I2O Inbound Message Queue */ + #define IPS_REG_I2O_OUTMSGQ 0x44 /* I2O Outbound Message Queue */ + #define IPS_REG_I2O_HIR 0x30 /* I2O Interrupt Status */ + #define IPS_REG_I960_IDR 0x20 /* i960 Inbound Doorbell */ + #define IPS_REG_I960_MSG0 0x18 /* i960 Outbound Reg 0 */ + #define IPS_REG_I960_MSG1 0x1C /* i960 Outbound Reg 1 */ + #define IPS_REG_I960_OIMR 0x34 /* i960 Oubound Int Mask Reg */ /* * Adapter register bit equates @@ -144,6 +164,9 @@ #define IPS_BIT_EBM 0x02 /* SCPR Enable Bus Master */ #define IPS_BIT_EI 0x80 /* HISR Enable Interrupts */ #define IPS_BIT_OP 0x01 /* OP bit in CBSP */ + #define IPS_BIT_I2O_OPQI 0x08 /* General Host Interrupt */ + #define IPS_BIT_I960_MSG0I 0x01 /* Message Register 0 Interrupt*/ + #define IPS_BIT_I960_MSG1I 0x02 /* Message Register 1 Interrupt*/ /* * Adapter Command ID Equates @@ -194,13 +217,15 @@ #define IPS_INTR_HAL 2 #define IPS_ADAPTER_ID 0xF #define IPS_VENDORID 0x1014 - #define IPS_DEVICEID 0x002E + #define IPS_COPPERHEAD_DEVICEID 0x002E + #define IPS_MORPHEUS_DEVICEID 0x01BD #define IPS_IOCTL_SIZE 8192 #define IPS_STATUS_SIZE 4 #define IPS_STATUS_Q_SIZE (IPS_MAX_CMDS+1) * IPS_STATUS_SIZE + #define IPS_MEMMAP_SIZE 128 #define IPS_ONE_MSEC 1 #define IPS_ONE_SEC 1000 - + /* * Geometry Settings */ @@ -328,6 +353,37 @@ /* * Scsi_Host Template */ +#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,27) + #define IPS { \ + next : NULL, \ + module : NULL, \ + proc_info : NULL, \ + proc_dir : NULL, \ + name : NULL, \ + detect : ips_detect, \ + release : ips_release, \ + info : ips_info, \ + command : NULL, \ + queuecommand : ips_queue, \ + eh_strategy_handler : NULL, \ + eh_abort_handler : ips_eh_abort, \ + eh_device_reset_handler : NULL, \ + eh_bus_reset_handler : NULL, \ + eh_host_reset_handler : ips_eh_reset, \ + abort : NULL, \ + reset : NULL, \ + slave_attach : NULL, \ + bios_param : ips_biosparam, \ + can_queue : 0, \ + this_id: -1, \ + sg_tablesize : IPS_MAX_SG, \ + cmd_per_lun: 16, \ + present : 0, \ + unchecked_isa_dma : 0, \ + use_clustering : ENABLE_CLUSTERING, \ + use_new_eh_code : 1 \ +} +#else #define IPS { \ next : NULL, \ module : NULL, \ @@ -343,8 +399,8 @@ eh_device_reset_handler : NULL, \ eh_bus_reset_handler : NULL, \ eh_host_reset_handler : ips_eh_reset, \ - abort : ips_abort, \ - reset : ips_reset, \ + abort : NULL, \ + reset : NULL, \ slave_attach : NULL, \ bios_param : ips_biosparam, \ can_queue : 0, \ @@ -355,7 +411,8 @@ unchecked_isa_dma : 0, \ use_clustering : ENABLE_CLUSTERING, \ use_new_eh_code : 1 \ - } +} +#endif /* * IBM PCI Raid Command Formats @@ -523,11 +580,15 @@ u8 reserved2[3]; } IPS_DCDB_TABLE, *PIPS_DCDB_TABLE; -typedef struct { - volatile u8 reserved; - volatile u8 command_id; - volatile u8 basic_status; - volatile u8 extended_status; +typedef union { + struct { + volatile u8 reserved; + volatile u8 command_id; + volatile u8 basic_status; + volatile u8 extended_status; + } fields; + + volatile u32 value; } IPS_STATUS, *PIPS_STATUS; typedef struct { @@ -602,7 +663,7 @@ u8 ucCompression; u8 ucNvramType; u32 ulNvramSize; -} IPS_HARDWARE, *PIPS_HARDWARE; +} IPS_HARDWARE, *PIPS_HARDWARE; typedef struct { u8 ucLogDriveCount; @@ -769,8 +830,15 @@ int length; int offset; int pos; + int localpos; } IPS_INFOSTR; +typedef struct { + char *option_name; + int *option_flag; + int option_value; +} IPS_OPTION; + /* * Status Info */ @@ -815,6 +883,24 @@ spinlock_t lock; } ips_copp_queue_t; +/* forward decl for host structure */ +struct ips_ha; + +typedef struct { + int (*reset)(struct ips_ha *); + int (*issue)(struct ips_ha *, struct ips_scb *); + int (*isinit)(struct ips_ha *); + int (*isintr)(struct ips_ha *); + int (*init)(struct ips_ha *); + int (*erasebios)(struct ips_ha *); + int (*programbios)(struct ips_ha *, char *, int); + int (*verifybios)(struct ips_ha *, char *, int); + u32 (*statupd)(struct ips_ha *); + void (*statinit)(struct ips_ha *); + void (*intr)(struct ips_ha *); + void (*enableint)(struct ips_ha *); +} ips_hw_func_t; + typedef struct ips_ha { u8 ha_id[IPS_MAX_CHANNELS+1]; u32 dcdb_active[IPS_MAX_CHANNELS]; @@ -849,12 +935,18 @@ u16 reset_count; /* number of resets */ u32 last_ffdc; /* last time we sent ffdc info*/ u8 revision_id; /* Revision level */ - - #if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,0) + u16 device_id; /* PCI device ID */ + u8 reserved; + u32 mem_addr; /* Memory mapped address */ + u32 io_len; /* Size of IO Address */ + u32 mem_len; /* Size of memory address */ + char *mem_ptr; /* Memory mapped Ptr */ + char *ioremap_ptr; /* ioremapped memory pointer */ + ips_hw_func_t func; /* hw function pointers */ + struct pci_dev *pcidev; /* PCI device handle */ spinlock_t scb_lock; spinlock_t copp_lock; spinlock_t ips_lock; - #endif } ips_ha_t; typedef void (*ips_scb_callback) (ips_ha_t *, struct ips_scb *); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/mac53c94.c linux/drivers/scsi/mac53c94.c --- v2.4.0-test8/linux/drivers/scsi/mac53c94.c Thu Nov 11 16:57:30 1999 +++ linux/drivers/scsi/mac53c94.c Tue Sep 19 08:31:53 2000 @@ -47,6 +47,7 @@ Scsi_Cmnd *current_req; /* req we're currently working on */ enum fsc_phase phase; /* what we're currently trying to do */ struct dbdma_cmd *dma_cmds; /* space for dbdma commands, aligned */ + void *dma_cmd_space; }; static struct fsc_state *all_53c94s; @@ -113,6 +114,7 @@ DBDMA_ALIGN(dma_cmd_space); memset(state->dma_cmds, 0, (host->sg_tablesize + 1) * sizeof(struct dbdma_cmd)); + state->dma_cmd_space = dma_cmd_space; *prev_statep = state; prev_statep = &state->next; @@ -130,6 +132,22 @@ } int +mac53c94_release(struct Scsi_Host *host) +{ + struct fsc_state *fp = (struct fsc_state *) host->hostdata; + + if (fp == 0) + return 0; + if (fp->regs) + iounmap((void *) fp->regs); + if (fp->dma) + iounmap((void *) fp->dma); + kfree(fp->dma_cmd_space); + free_irq(fp->intr, fp); + return 0; +} + +int mac53c94_queue(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) { unsigned long flags; @@ -537,3 +555,7 @@ return 0; } } + +static Scsi_Host_Template driver_template = SCSI_MAC53C94; + +#include "scsi_module.c" diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/mac53c94.h linux/drivers/scsi/mac53c94.h --- v2.4.0-test8/linux/drivers/scsi/mac53c94.h Thu Nov 11 16:57:30 1999 +++ linux/drivers/scsi/mac53c94.h Tue Sep 19 08:31:53 2000 @@ -8,6 +8,7 @@ #define _MAC53C94_H int mac53c94_detect(Scsi_Host_Template *); +int mac53c94_release(struct Scsi_Host *); int mac53c94_command(Scsi_Cmnd *); int mac53c94_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); int mac53c94_abort(Scsi_Cmnd *); @@ -17,6 +18,7 @@ proc_name: "53c94", \ name: "53C94", \ detect: mac53c94_detect, \ + release: mac53c94_release, \ command: mac53c94_command, \ queuecommand: mac53c94_queue, \ abort: mac53c94_abort, \ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/mac_scsi.c linux/drivers/scsi/mac_scsi.c --- v2.4.0-test8/linux/drivers/scsi/mac_scsi.c Mon Jun 19 17:59:41 2000 +++ linux/drivers/scsi/mac_scsi.c Mon Sep 18 13:36:25 2000 @@ -662,9 +662,6 @@ -#ifdef MODULE - -Scsi_Host_Template driver_template = MAC_NCR5380; +static Scsi_Host_Template driver_template = MAC_NCR5380; #include "scsi_module.c" -#endif diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/mca_53c9x.c linux/drivers/scsi/mca_53c9x.c --- v2.4.0-test8/linux/drivers/scsi/mca_53c9x.c Tue Sep 7 10:14:37 1999 +++ linux/drivers/scsi/mca_53c9x.c Mon Sep 18 13:36:25 2000 @@ -419,10 +419,8 @@ outb(inb(PS2_SYS_CTR) & 0x3f, PS2_SYS_CTR); } -#ifdef MODULE -Scsi_Host_Template driver_template = MCA_53C9X; +static Scsi_Host_Template driver_template = MCA_53C9X; #include "scsi_module.c" -#endif /* * OK, here's the goods I promised. The NCR 86C01 is an MCA interface chip diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/megaraid.c linux/drivers/scsi/megaraid.c --- v2.4.0-test8/linux/drivers/scsi/megaraid.c Mon Jun 19 13:42:40 2000 +++ linux/drivers/scsi/megaraid.c Mon Sep 18 13:36:25 2000 @@ -2032,8 +2032,6 @@ __setup("megaraid=", megaraid_setup); -#ifdef MODULE -Scsi_Host_Template driver_template = MEGARAID; +static Scsi_Host_Template driver_template = MEGARAID; #include "scsi_module.c" -#endif diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/mesh.c linux/drivers/scsi/mesh.c --- v2.4.0-test8/linux/drivers/scsi/mesh.c Mon Feb 14 13:37:25 2000 +++ linux/drivers/scsi/mesh.c Tue Sep 19 08:31:53 2000 @@ -149,6 +149,8 @@ struct dbdma_cmd *dma_cmds; /* space for dbdma commands, aligned */ int clk_freq; struct mesh_target tgts[8]; + void *dma_cmd_space; + struct device_node *ofnode; #ifndef MESH_NEW_STYLE_EH Scsi_Cmnd *completed_q; Scsi_Cmnd *completed_qtail; @@ -262,6 +264,7 @@ panic("no mesh state"); memset(ms, 0, sizeof(*ms)); ms->host = mesh_host; + ms->ofnode = mesh; ms->mesh = (volatile struct mesh_regs *) ioremap(mesh->addrs[0].address, 0x1000); ms->dma = (volatile struct dbdma_regs *) @@ -278,6 +281,7 @@ ms->dma_cmds = (struct dbdma_cmd *) DBDMA_ALIGN(dma_cmd_space); memset(ms->dma_cmds, 0, (mesh_host->sg_tablesize + 1) * sizeof(struct dbdma_cmd)); + ms->dma_cmd_space = dma_cmd_space; ms->current_req = 0; for (tgt = 0; tgt < 8; ++tgt) { @@ -324,6 +328,23 @@ } int +mesh_release(struct Scsi_Host *host) +{ + struct mesh_state *ms = (struct mesh_state *) host->hostdata; + + if (ms == 0) + return 0; + if (ms->mesh) + iounmap((void *) ms->mesh); + if (ms->dma) + iounmap((void *) ms->dma); + kfree(ms->dma_cmd_space); + free_irq(ms->meshintr, ms); + feature_clear(ms->ofnode, FEATURE_MESH_enable); + return 0; +} + +int mesh_queue(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) { unsigned long flags; @@ -1910,3 +1931,7 @@ } while (i != ms->log_ix); } #endif /* MESH_DBG */ + +static Scsi_Host_Template driver_template = SCSI_MESH; + +#include "scsi_module.c" diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/mesh.h linux/drivers/scsi/mesh.h --- v2.4.0-test8/linux/drivers/scsi/mesh.h Thu Nov 11 16:57:30 1999 +++ linux/drivers/scsi/mesh.h Tue Sep 19 08:31:53 2000 @@ -8,6 +8,7 @@ #define _MESH_H int mesh_detect(Scsi_Host_Template *); +int mesh_release(struct Scsi_Host *); int mesh_command(Scsi_Cmnd *); int mesh_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); int mesh_abort(Scsi_Cmnd *); @@ -17,6 +18,7 @@ proc_name: "mesh", \ name: "MESH", \ detect: mesh_detect, \ + release: mesh_release, \ command: mesh_command, \ queuecommand: mesh_queue, \ abort: mesh_abort, \ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/mvme16x.h linux/drivers/scsi/mvme16x.h --- v2.4.0-test8/linux/drivers/scsi/mvme16x.h Fri Sep 8 12:54:34 2000 +++ linux/drivers/scsi/mvme16x.h Mon Sep 18 14:09:49 2000 @@ -23,7 +23,6 @@ #define CAN_QUEUE 24 #endif -#if defined(HOSTS_C) || defined(MODULE) #include #define MVME16x_SCSI {name: "MVME16x NCR53c710 SCSI", \ @@ -37,5 +36,5 @@ sg_tablesize: 63, \ cmd_per_lun: 3, \ use_clustering: DISABLE_CLUSTERING } -#endif + #endif /* MVME16x_SCSI_H */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/ncr53c8xx.c linux/drivers/scsi/ncr53c8xx.c --- v2.4.0-test8/linux/drivers/scsi/ncr53c8xx.c Mon Jun 19 17:59:41 2000 +++ linux/drivers/scsi/ncr53c8xx.c Mon Sep 18 13:36:25 2000 @@ -9513,7 +9513,5 @@ ** Module stuff */ -#ifdef MODULE -Scsi_Host_Template driver_template = NCR53C8XX; +static Scsi_Host_Template driver_template = NCR53C8XX; #include "scsi_module.c" -#endif diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/ncr53c8xx.h linux/drivers/scsi/ncr53c8xx.h --- v2.4.0-test8/linux/drivers/scsi/ncr53c8xx.h Fri Sep 8 12:54:35 2000 +++ linux/drivers/scsi/ncr53c8xx.h Mon Sep 18 14:09:49 2000 @@ -50,8 +50,6 @@ ** Used by hosts.c and ncr53c8xx.c with module configuration. */ -#if defined(HOSTS_C) || defined(MODULE) - #include int ncr53c8xx_abort(Scsi_Cmnd *); @@ -95,7 +93,5 @@ 0, 0, DISABLE_CLUSTERING} #endif /* LINUX_VERSION_CODE */ - -#endif /* defined(HOSTS_C) || defined(MODULE) */ #endif /* NCR53C8XX_H */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/oktagon_esp.c linux/drivers/scsi/oktagon_esp.c --- v2.4.0-test8/linux/drivers/scsi/oktagon_esp.c Wed Jan 26 12:45:20 2000 +++ linux/drivers/scsi/oktagon_esp.c Mon Sep 18 13:36:25 2000 @@ -570,17 +570,14 @@ sp->SCp.ptr = sp->SCp.buffer->address; } -#ifdef MODULE #define HOSTS_C #include "oktagon_esp.h" -Scsi_Host_Template driver_template = SCSI_OKTAGON_ESP; +static Scsi_Host_Template driver_template = SCSI_OKTAGON_ESP; #include "scsi_module.c" - -#endif int oktagon_esp_release(struct Scsi_Host *instance) { diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/pas16.c linux/drivers/scsi/pas16.c --- v2.4.0-test8/linux/drivers/scsi/pas16.c Thu Nov 11 16:57:30 1999 +++ linux/drivers/scsi/pas16.c Mon Sep 18 13:36:25 2000 @@ -597,12 +597,12 @@ #include "NCR5380.c" -#ifdef MODULE /* Eventually this will go into an include file, but this will be later */ -Scsi_Host_Template driver_template = MV_PAS16; +static Scsi_Host_Template driver_template = MV_PAS16; #include "scsi_module.c" +#ifdef MODULE MODULE_PARM(pas16_addr, "h"); MODULE_PARM(pas16_irq, "i"); #endif diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/pas16.h linux/drivers/scsi/pas16.h --- v2.4.0-test8/linux/drivers/scsi/pas16.h Sat Apr 11 11:13:25 1998 +++ linux/drivers/scsi/pas16.h Mon Sep 18 14:10:10 2000 @@ -140,8 +140,6 @@ * macros when this is being used solely for the host stub. */ -#if defined(HOSTS_C) || defined(MODULE) - #define MV_PAS16 { \ name: "Pro Audio Spectrum-16 SCSI", \ detect: pas16_detect, \ @@ -155,7 +153,6 @@ cmd_per_lun: CMD_PER_LUN , \ use_clustering: DISABLE_CLUSTERING} -#endif #ifndef HOSTS_C #define NCR5380_implementation_fields \ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/pci2000.c linux/drivers/scsi/pci2000.c --- v2.4.0-test8/linux/drivers/scsi/pci2000.c Mon Jun 19 13:42:40 2000 +++ linux/drivers/scsi/pci2000.c Mon Sep 18 13:36:25 2000 @@ -855,9 +855,7 @@ } -#ifdef MODULE /* Eventually this will go into an include file, but this will be later */ -Scsi_Host_Template driver_template = PCI2000; +static Scsi_Host_Template driver_template = PCI2000; #include "scsi_module.c" -#endif diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/pci2220i.c linux/drivers/scsi/pci2220i.c --- v2.4.0-test8/linux/drivers/scsi/pci2220i.c Mon Jun 19 13:42:40 2000 +++ linux/drivers/scsi/pci2220i.c Mon Sep 18 13:36:25 2000 @@ -2509,7 +2509,7 @@ init_timer (&padapter->reconTimer); padapter->reconTimer.function = ReconTimerExpiry; padapter->reconTimer.data = (unsigned long)padapter; - printk("\nPCI-%sI EIDE CONTROLLER: at I/O = %lX/%lX IRQ = %ld\n", str, padapter->basePort, padapter->regBase, irq); + printk("\nPCI-%sI EIDE CONTROLLER: at I/O = %lX/%lX IRQ = %d\n", str, padapter->basePort, padapter->regBase, irq); printk("Version %s, Compiled %s %s\n\n", PCI2220I_VERSION, __DATE__, __TIME__); } /**************************************************************** @@ -2920,9 +2920,7 @@ } -#ifdef MODULE /* Eventually this will go into an include file, but this will be later */ -Scsi_Host_Template driver_template = PCI2220I; +static Scsi_Host_Template driver_template = PCI2220I; #include "scsi_module.c" -#endif diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/pluto.c linux/drivers/scsi/pluto.c --- v2.4.0-test8/linux/drivers/scsi/pluto.c Fri Jul 14 12:20:22 2000 +++ linux/drivers/scsi/pluto.c Mon Sep 18 13:36:25 2000 @@ -331,11 +331,8 @@ return 0; } -#ifdef MODULE - -Scsi_Host_Template driver_template = PLUTO; +static Scsi_Host_Template driver_template = PLUTO; #include "scsi_module.c" EXPORT_NO_SYMBOLS; -#endif /* MODULE */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/ppa.c linux/drivers/scsi/ppa.c --- v2.4.0-test8/linux/drivers/scsi/ppa.c Mon Jul 24 18:59:27 2000 +++ linux/drivers/scsi/ppa.c Mon Sep 18 13:36:25 2000 @@ -99,10 +99,8 @@ * Parallel port probing routines * ***************************************************************************/ -#ifdef MODULE -Scsi_Host_Template driver_template = PPA; +static Scsi_Host_Template driver_template = PPA; #include "scsi_module.c" -#endif /* * Start of Chipset kludges diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/psi240i.c linux/drivers/scsi/psi240i.c --- v2.4.0-test8/linux/drivers/scsi/psi240i.c Thu Nov 11 16:57:30 1999 +++ linux/drivers/scsi/psi240i.c Mon Sep 18 13:36:25 2000 @@ -713,10 +713,8 @@ } -#ifdef MODULE /* Eventually this will go into an include file, but this will be later */ -Scsi_Host_Template driver_template = PSI240I; +static Scsi_Host_Template driver_template = PSI240I; #include "scsi_module.c" -#endif diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/qla1280.c linux/drivers/scsi/qla1280.c --- v2.4.0-test8/linux/drivers/scsi/qla1280.c Mon Jun 19 13:42:40 2000 +++ linux/drivers/scsi/qla1280.c Mon Sep 18 13:36:25 2000 @@ -6163,11 +6163,9 @@ /* * Declarations for load module */ -#ifdef MODULE -Scsi_Host_Template driver_template = QLA1280_LINUX_TEMPLATE; +static Scsi_Host_Template driver_template = QLA1280_LINUX_TEMPLATE; #include "scsi_module.c" -#endif /************************************************************************ * qla1280_check_for_dead_scsi_bus * diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/qlogicfas.c linux/drivers/scsi/qlogicfas.c --- v2.4.0-test8/linux/drivers/scsi/qlogicfas.c Tue Feb 15 08:53:46 2000 +++ linux/drivers/scsi/qlogicfas.c Mon Sep 18 13:36:25 2000 @@ -643,8 +643,10 @@ ip[0] = 0xff; ip[1] = 0x3f; ip[2] = disk->capacity / (ip[0] * ip[1]); +#if 0 if (ip[2] > 1023) ip[2] = 1023; +#endif } return 0; } @@ -674,10 +676,7 @@ return qinfo; } -#ifdef MODULE /* Eventually this will go into an include file, but this will be later */ -Scsi_Host_Template driver_template = QLOGICFAS; - +static Scsi_Host_Template driver_template = QLOGICFAS; #include "scsi_module.c" -#endif diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/qlogicfc.c linux/drivers/scsi/qlogicfc.c --- v2.4.0-test8/linux/drivers/scsi/qlogicfc.c Fri Aug 11 14:30:35 2000 +++ linux/drivers/scsi/qlogicfc.c Mon Sep 18 13:36:25 2000 @@ -2226,10 +2226,6 @@ #endif /* DEBUG_ISP2x00 */ -#ifdef MODULE - -Scsi_Host_Template driver_template = QLOGICFC; +static Scsi_Host_Template driver_template = QLOGICFC; #include "scsi_module.c" - -#endif diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/qlogicisp.c linux/drivers/scsi/qlogicisp.c --- v2.4.0-test8/linux/drivers/scsi/qlogicisp.c Mon Jun 19 13:42:41 2000 +++ linux/drivers/scsi/qlogicisp.c Mon Sep 18 13:36:25 2000 @@ -1989,8 +1989,6 @@ #endif /* DEBUG_ISP1020 */ -#ifdef MODULE -Scsi_Host_Template driver_template = QLOGICISP; +static Scsi_Host_Template driver_template = QLOGICISP; #include "scsi_module.c" -#endif /* MODULE */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/qlogicpti.c linux/drivers/scsi/qlogicpti.c --- v2.4.0-test8/linux/drivers/scsi/qlogicpti.c Mon Aug 28 12:00:08 2000 +++ linux/drivers/scsi/qlogicpti.c Mon Sep 18 13:36:25 2000 @@ -1526,10 +1526,8 @@ return return_status; } -#ifdef MODULE -Scsi_Host_Template driver_template = QLOGICPTI; +static Scsi_Host_Template driver_template = QLOGICPTI; #include "scsi_module.c" EXPORT_NO_SYMBOLS; -#endif /* MODULE */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c --- v2.4.0-test8/linux/drivers/scsi/scsi.c Mon Jul 31 11:00:06 2000 +++ linux/drivers/scsi/scsi.c Wed Sep 27 14:10:54 2000 @@ -36,6 +36,9 @@ * out_of_space hacks, D. Gilbert (dpg) 990608 */ +#define REVISION "Revision: 1.00" +#define VERSION "Id: scsi.c 1.00 2000/09/26" + #include #include @@ -384,7 +387,7 @@ * return NULL. */ SCpnt = NULL; - break; + goto busy; } } /* @@ -402,6 +405,7 @@ if (SCpnt) { break; } + busy: /* * If we have been asked to wait for a free block, then * wait here. @@ -495,30 +499,7 @@ return SCpnt; } -/* - * Function: scsi_release_command - * - * Purpose: Release a command block. - * - * Arguments: SCpnt - command block we are releasing. - * - * Notes: The command block can no longer be used by the caller once - * this funciton is called. This is in effect the inverse - * of scsi_allocate_device. Note that we also must perform - * a couple of additional tasks. We must first wake up any - * processes that might have blocked waiting for a command - * block, and secondly we must hit the queue handler function - * to make sure that the device is busy. - * - * The idea is that a lot of the mid-level internals gunk - * gets hidden in this function. Upper level drivers don't - * have any chickens to wave in the air to get things to - * work reliably. - * - * This function is deprecated, and drivers should be - * rewritten to use Scsi_Request instead of Scsi_Cmnd. - */ -void scsi_release_command(Scsi_Cmnd * SCpnt) +inline void __scsi_release_command(Scsi_Cmnd * SCpnt) { unsigned long flags; Scsi_Device * SDpnt; @@ -562,6 +543,43 @@ * they wake up. */ wake_up(&SDpnt->scpnt_wait); +} + +/* + * Function: scsi_release_command + * + * Purpose: Release a command block. + * + * Arguments: SCpnt - command block we are releasing. + * + * Notes: The command block can no longer be used by the caller once + * this funciton is called. This is in effect the inverse + * of scsi_allocate_device. Note that we also must perform + * a couple of additional tasks. We must first wake up any + * processes that might have blocked waiting for a command + * block, and secondly we must hit the queue handler function + * to make sure that the device is busy. Note - there is an + * option to not do this - there were instances where we could + * recurse too deeply and blow the stack if this happened + * when we were indirectly called from the request function + * itself. + * + * The idea is that a lot of the mid-level internals gunk + * gets hidden in this function. Upper level drivers don't + * have any chickens to wave in the air to get things to + * work reliably. + * + * This function is deprecated, and drivers should be + * rewritten to use Scsi_Request instead of Scsi_Cmnd. + */ +void scsi_release_command(Scsi_Cmnd * SCpnt) +{ + request_queue_t *q; + Scsi_Device * SDpnt; + + SDpnt = SCpnt->device; + + __scsi_release_command(SCpnt); /* * Finally, hit the queue request function to make sure that @@ -569,12 +587,8 @@ * This won't block - if the device cannot take any more, life * will go on. */ - { - request_queue_t *q; - - q = &SDpnt->request_queue; - scsi_queue_next_request(q, NULL); - } + q = &SDpnt->request_queue; + scsi_queue_next_request(q, NULL); } /* @@ -1361,13 +1375,8 @@ SCpnt->done(SCpnt); } -#if defined(CONFIG_MODULES) || defined(CONFIG_BLK_DEV_IDESCSI) || defined(CONFIG_USB_STORAGE) static int scsi_register_host(Scsi_Host_Template *); static void scsi_unregister_host(Scsi_Host_Template *); -#endif - - -int scsi_loadable_module_flag; /* Set after we scan builtin drivers */ /* * Function: scsi_release_commandblocks() @@ -1432,10 +1441,9 @@ kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC | (host->unchecked_isa_dma ? GFP_DMA : 0)); - memset(SCpnt, 0, sizeof(Scsi_Cmnd)); if (NULL == SCpnt) break; /* If not, the next line will oops ... */ - memset(&SCpnt->eh_timeout, 0, sizeof(SCpnt->eh_timeout)); + memset(SCpnt, 0, sizeof(Scsi_Cmnd)); SCpnt->host = host; SCpnt->device = SDpnt; SCpnt->target = SDpnt->id; @@ -1499,120 +1507,6 @@ } } -#ifndef MODULE /* { */ - -char scsi_host_no_table[20][10] __initdata = {}; -int scsi_host_no_set __initdata = 0; - -/* - * scsi_dev_init() is our initialization routine, which in turn calls host - * initialization, bus scanning, and sd/st initialization routines. - * This is only used at boot time. - */ -int __init scsi_dev_init(void) -{ - Scsi_Device *SDpnt; - struct Scsi_Host *shpnt; - struct Scsi_Device_Template *sdtpnt; - struct proc_dir_entry *generic; -#ifdef FOO_ON_YOU - return; -#endif - - /* Initialize list of host_no if kernel parameter set */ - if (scsi_host_no_set) { - int i; - for (i = 0;i < sizeof(scsi_host_no_table)/sizeof(scsi_host_no_table[0]);i++) - scsi_host_no_insert(scsi_host_no_table[i], i); - } - - /* Yes we're here... */ - - scsi_devfs_handle = devfs_mk_dir (NULL, "scsi", NULL); - /* - * This makes /proc/scsi and /proc/scsi/scsi visible. - */ -#ifdef CONFIG_PROC_FS - proc_scsi = proc_mkdir("scsi", 0); - if (!proc_scsi) { - printk (KERN_ERR "cannot init /proc/scsi\n"); - return -ENOMEM; - } - - generic = create_proc_info_entry ("scsi/scsi", 0, 0, scsi_proc_info); - if (!generic) { - printk (KERN_ERR "cannot init /proc/scsi/scsi\n"); - remove_proc_entry("scsi", 0); - return -ENOMEM; - } - generic->write_proc = proc_scsi_gen_write; -#endif - - /* Init a few things so we can "malloc" memory. */ - scsi_loadable_module_flag = 0; - - /* initialize all hosts */ - scsi_init(); - - /* - * This is where the processing takes place for most everything - * when commands are completed. Until we do this, we will not be able - * to queue any commands. - */ - init_bh(SCSI_BH, scsi_bottom_half_handler); - - for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) { - scan_scsis(shpnt, 0, 0, 0, 0); /* scan for scsi devices */ - if (shpnt->select_queue_depths != NULL) - (shpnt->select_queue_depths) (shpnt, shpnt->host_queue); - } - - printk("scsi : detected "); - for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) - if (sdtpnt->dev_noticed && sdtpnt->name) - printk("%d SCSI %s%s ", sdtpnt->dev_noticed, sdtpnt->name, - (sdtpnt->dev_noticed != 1) ? "s" : ""); - printk("total.\n"); - - for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) - if (sdtpnt->init && sdtpnt->dev_noticed) - (*sdtpnt->init) (); - - for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) { - for (SDpnt = shpnt->host_queue; SDpnt; SDpnt = SDpnt->next) { - /* SDpnt->scsi_request_fn = NULL; */ - for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) - if (sdtpnt->attach) - (*sdtpnt->attach) (SDpnt); - if (SDpnt->attached) { - scsi_build_commandblocks(SDpnt); - if (0 == SDpnt->has_cmdblocks) { - printk("scsi_dev_init: DANGER, no command blocks\n"); - /* What to do now ?? */ - } - } - } - } - - /* - * This should build the DMA pool. - */ - scsi_resize_dma_pool(); - - /* - * OK, now we finish the initialization by doing spin-up, read - * capacity, etc, etc - */ - for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) - if (sdtpnt->finish && sdtpnt->nr_dev) - (*sdtpnt->finish) (); - - scsi_loadable_module_flag = 1; - - return 0; -} -#endif /* MODULE */ /* } */ - #ifdef CONFIG_PROC_FS static int scsi_proc_info(char *buffer, char **start, off_t offset, int length) { @@ -1908,15 +1802,8 @@ #endif /* - * Some host adapters that are plugging into other subsystems register - * their hosts through the modules entrypoints, and don't use the big - * list in hosts.c. - */ -#if defined(CONFIG_MODULES) || defined(CONFIG_BLK_DEV_IDESCSI) || defined(CONFIG_USB_STORAGE) || defined(CONFIG_USB_MICROTEK) /* a big #ifdef block... */ - -/* - * This entry point should be called by a loadable module if it is trying - * add a low level scsi driver to the system. + * This entry point should be called by a driver if it is trying + * to add a low level scsi driver to the system. */ static int scsi_register_host(Scsi_Host_Template * tpnt) { @@ -1957,8 +1844,8 @@ return 1; } /* - * The low-level driver failed to register a driver. We - * can do this now. + * The low-level driver failed to register a driver. + * We can do this now. */ scsi_register(tpnt, 0); } @@ -2004,9 +1891,6 @@ } } - printk("scsi : %d host%s.\n", next_scsi_host, - (next_scsi_host == 1) ? "" : "s"); - /* The next step is to call scan_scsis here. This generates the * Scsi_Devices entries */ @@ -2084,15 +1968,13 @@ static void scsi_unregister_host(Scsi_Host_Template * tpnt) { int online_status; - int pcount; + int pcount0, pcount; Scsi_Cmnd *SCpnt; Scsi_Device *SDpnt; Scsi_Device *SDpnt1; struct Scsi_Device_Template *sdtpnt; struct Scsi_Host *sh1; struct Scsi_Host *shpnt; - Scsi_Host_Template *SHT; - Scsi_Host_Template *SHTp; char name[10]; /* host_no>=10^9? I don't think so. */ /* @@ -2226,9 +2108,10 @@ /* Next we go through and remove the instances of the individual hosts * that were detected */ + pcount0 = next_scsi_host; for (shpnt = scsi_hostlist; shpnt; shpnt = sh1) { sh1 = shpnt->next; - if (shpnt->hostt != tpnt || !shpnt->loaded_as_module) + if (shpnt->hostt != tpnt) continue; pcount = next_scsi_host; /* Remove the /proc/scsi directory entry */ @@ -2242,7 +2125,7 @@ * written host adapters. */ if (shpnt->irq) - free_irq(shpnt->irq, NULL); + free_irq(shpnt->irq, NULL); if (shpnt->dma_channel != 0xff) free_dma(shpnt->dma_channel); if (shpnt->io_port && shpnt->n_io_port) @@ -2261,8 +2144,9 @@ if (!scsi_hosts) scsi_resize_dma_pool(); - printk("scsi : %d host%s.\n", next_scsi_host, - (next_scsi_host == 1) ? "" : "s"); + if (pcount0 != next_scsi_host) + printk("scsi : %d host%s left.\n", next_scsi_host, + (next_scsi_host == 1) ? "" : "s"); #if defined(USE_STATIC_SCSI_MEMORY) printk("SCSI memory: total %ldKb, used %ldKb, free %ldKb.\n", @@ -2271,24 +2155,21 @@ (scsi_memory_upper_value - scsi_init_memory_start) / 1024); #endif - /* There were some hosts that were loaded at boot time, so we cannot - do any more than this */ - if (tpnt->present) - return; + /* Remove it from the linked list and /proc */ + if (tpnt->present) { + Scsi_Host_Template **SHTp = &scsi_hosts; + Scsi_Host_Template *SHT; - /* OK, this is the very last step. Remove this host adapter from the - linked list. */ - for (SHTp = NULL, SHT = scsi_hosts; SHT; SHTp = SHT, SHT = SHT->next) - if (SHT == tpnt) { - if (SHTp) - SHTp->next = SHT->next; - else - scsi_hosts = SHT->next; - SHT->next = NULL; - break; + while ((SHT = *SHTp) != NULL) { + if (SHT == tpnt) { + *SHTp = SHT->next; + break; + } + SHTp = &SHT->next; } - /* Rebuild the /proc/scsi directory entries */ - remove_proc_entry(tpnt->proc_name, proc_scsi); + /* Rebuild the /proc/scsi directory entries */ + remove_proc_entry(tpnt->proc_name, proc_scsi); + } MOD_DEC_USE_COUNT; } @@ -2421,6 +2302,10 @@ } +/* This function should be called by drivers which needs to register + * with the midlevel scsi system. As of 2.4.0-test9pre3 this is our + * main device/hosts register function /mathiasen + */ int scsi_register_module(int module_type, void *ptr) { switch (module_type) { @@ -2448,6 +2333,8 @@ } } +/* Reverse the actions taken above + */ void scsi_unregister_module(int module_type, void *ptr) { switch (module_type) { @@ -2466,8 +2353,6 @@ return; } -#endif /* CONFIG_MODULES */ - #ifdef CONFIG_PROC_FS /* * Function: scsi_dump_status @@ -2574,17 +2459,11 @@ } #endif /* CONFIG_PROC_FS */ -static int scsi_host_no_init (char *str) +static int __init scsi_host_no_init (char *str) { static int next_no = 0; char *temp; -#ifndef MODULE - int len; - scsi_host_no_set = 1; - memset(scsi_host_no_table, 0, sizeof(scsi_host_no_table)); -#endif /* MODULE */ - while (str) { temp = str; while (*temp && (*temp != ':') && (*temp != ',')) @@ -2593,35 +2472,34 @@ temp = NULL; else *temp++ = 0; -#ifdef MODULE scsi_host_no_insert(str, next_no); -#else - if (next_no < sizeof(scsi_host_no_table)/sizeof(scsi_host_no_table[0])) { - if ((len = strlen(str)) >= sizeof(scsi_host_no_table[0])) - len = sizeof(scsi_host_no_table[0])-1; - strncpy(scsi_host_no_table[next_no], str, len); - scsi_host_no_table[next_no][len] = 0; - } -#endif /* MODULE */ str = temp; next_no++; } return 1; } -#ifndef MODULE -__setup("scsihosts=", scsi_host_no_init); -#endif - -#ifdef MODULE static char *scsihosts; MODULE_PARM(scsihosts, "s"); +MODULE_DESCRIPTION("SCSI core"); + +#ifndef MODULE +int __init scsi_setup(char *str) +{ + scsihosts = str; + return 1; +} + +__setup("scsihosts=", scsi_setup); +#endif -int init_module(void) +static int __init init_scsi(void) { struct proc_dir_entry *generic; + printk(KERN_INFO "SCSI subsystem driver " REVISION "\n"); + if( scsi_init_minimal_dma_pool() != 0 ) { return 1; @@ -2645,10 +2523,10 @@ generic->write_proc = proc_scsi_gen_write; #endif - scsi_loadable_module_flag = 1; - scsi_devfs_handle = devfs_mk_dir (NULL, "scsi", NULL); - scsi_host_no_init (scsihosts); + if (scsihosts) + printk("scsi: host order: %s\n", scsihosts); + scsi_host_no_init (scsihosts); /* * This is where the processing takes place for most everything * when commands are completed. @@ -2658,7 +2536,7 @@ return 0; } -void cleanup_module(void) +static void __exit exit_scsi(void) { Scsi_Host_Name *shn, *shn2 = NULL; @@ -2688,7 +2566,8 @@ } -#endif /* MODULE */ +module_init(init_scsi); +module_exit(exit_scsi); /* * Function: scsi_get_host_dev() diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h --- v2.4.0-test8/linux/drivers/scsi/scsi.h Fri Sep 8 12:54:34 2000 +++ linux/drivers/scsi/scsi.h Mon Oct 2 12:08:35 2000 @@ -492,6 +492,7 @@ extern void scsi_finish_command(Scsi_Cmnd *); extern int scsi_retry_command(Scsi_Cmnd *); extern Scsi_Cmnd *scsi_allocate_device(Scsi_Device *, int, int); +extern void __scsi_release_command(Scsi_Cmnd *); extern void scsi_release_command(Scsi_Cmnd *); extern void scsi_do_cmd(Scsi_Cmnd *, const void *cmnd, void *buffer, unsigned bufflen, diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/scsi_debug.c linux/drivers/scsi/scsi_debug.c --- v2.4.0-test8/linux/drivers/scsi/scsi_debug.c Mon Mar 13 22:15:03 2000 +++ linux/drivers/scsi/scsi_debug.c Mon Sep 18 13:36:25 2000 @@ -767,12 +767,10 @@ } #endif -#ifdef MODULE /* Eventually this will go into an include file, but this will be later */ -Scsi_Host_Template driver_template = SCSI_DEBUG; +static Scsi_Host_Template driver_template = SCSI_DEBUG; #include "scsi_module.c" -#endif /* * Overrides for Emacs so that we almost follow Linus's tabbing style. diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/scsi_error.c linux/drivers/scsi/scsi_error.c --- v2.4.0-test8/linux/drivers/scsi/scsi_error.c Mon Aug 21 07:37:13 2000 +++ linux/drivers/scsi/scsi_error.c Mon Sep 18 14:57:01 2000 @@ -1861,6 +1861,9 @@ * Flush resources */ + exit_files(current); + current->files = init_task.files; + atomic_inc(¤t->files->count); daemonize(); /* diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/scsi_lib.c linux/drivers/scsi/scsi_lib.c --- v2.4.0-test8/linux/drivers/scsi/scsi_lib.c Wed Jul 5 13:18:05 2000 +++ linux/drivers/scsi/scsi_lib.c Sun Sep 17 10:09:29 2000 @@ -381,6 +381,8 @@ * uptodate - 1 if I/O indicates success, 0 for I/O error. * sectors - number of sectors we want to mark. * requeue - indicates whether we should requeue leftovers. + * frequeue - indicates that if we release the command block + * that the queue request function should be called. * * Lock status: Assumed that lock is not held upon entry. * @@ -395,10 +397,12 @@ static Scsi_Cmnd *__scsi_end_request(Scsi_Cmnd * SCpnt, int uptodate, int sectors, - int requeue) + int requeue, + int frequeue) { struct request *req; struct buffer_head *bh; + Scsi_Device * SDpnt; ASSERT_LOCK(&io_request_lock, 0); @@ -458,11 +462,20 @@ } add_blkdev_randomness(MAJOR(req->rq_dev)); + SDpnt = SCpnt->device; + /* * This will goose the queue request function at the end, so we don't * need to worry about launching another command. */ - scsi_release_command(SCpnt); + __scsi_release_command(SCpnt); + + if( frequeue ) { + request_queue_t *q; + + q = &SDpnt->request_queue; + scsi_queue_next_request(q, NULL); + } return NULL; } @@ -488,7 +501,7 @@ */ Scsi_Cmnd *scsi_end_request(Scsi_Cmnd * SCpnt, int uptodate, int sectors) { - return __scsi_end_request(SCpnt, uptodate, sectors, 1); + return __scsi_end_request(SCpnt, uptodate, sectors, 1, 1); } /* @@ -648,7 +661,8 @@ SCpnt = __scsi_end_request(SCpnt, 1, good_sectors, - result == 0); + result == 0, + 1); /* * If the command completed without error, then either finish off the @@ -718,8 +732,8 @@ } break; case NOT_READY: - printk(KERN_INFO "Device %x not ready.\n", - SCpnt->request.rq_dev); + printk(KERN_INFO "Device %s not ready.\n", + kdevname(SCpnt->request.rq_dev)); SCpnt = scsi_end_request(SCpnt, 0, this_count); return; break; @@ -962,6 +976,7 @@ } } else { + SRpnt = NULL; STpnt = scsi_get_request_dev(req); if (!STpnt) { panic("Unable to find device associated with request"); @@ -1010,7 +1025,7 @@ */ blkdev_dequeue_request(req); - if (req != &SCpnt->request) { + if (req != &SCpnt->request && req != &SRpnt->sr_request ) { memcpy(&SCpnt->request, req, sizeof(struct request)); /* @@ -1048,8 +1063,12 @@ * get those allocated here. */ if (!SDpnt->scsi_init_io_fn(SCpnt)) { - scsi_end_request(SCpnt, 0, - SCpnt->request.nr_sectors); + SCpnt = __scsi_end_request(SCpnt, 0, + SCpnt->request.nr_sectors, 0, 0); + if( SCpnt != NULL ) + { + panic("Should not have leftover blocks\n"); + } spin_lock_irq(&io_request_lock); SHpnt->host_busy--; SDpnt->device_busy--; @@ -1060,8 +1079,12 @@ */ if (!STpnt->init_command(SCpnt)) { scsi_release_buffers(SCpnt); - scsi_end_request(SCpnt, 0, - SCpnt->request.nr_sectors); + SCpnt = __scsi_end_request(SCpnt, 0, + SCpnt->request.nr_sectors, 0, 0); + if( SCpnt != NULL ) + { + panic("Should not have leftover blocks\n"); + } spin_lock_irq(&io_request_lock); SHpnt->host_busy--; SDpnt->device_busy--; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/scsi_module.c linux/drivers/scsi/scsi_module.c --- v2.4.0-test8/linux/drivers/scsi/scsi_module.c Sat Sep 4 10:48:46 1999 +++ linux/drivers/scsi/scsi_module.c Wed Sep 20 13:11:53 2000 @@ -30,22 +30,26 @@ */ #include +#include -int init_module(void) +static int __init init_this_scsi_driver(void) { - driver_template.module = &__this_module; + driver_template.module = THIS_MODULE; scsi_register_module(MODULE_SCSI_HA, &driver_template); if (driver_template.present) return 0; scsi_unregister_module(MODULE_SCSI_HA, &driver_template); - return -1; + return -ENODEV; } -void cleanup_module(void) +static void __exit exit_this_scsi_driver(void) { scsi_unregister_module(MODULE_SCSI_HA, &driver_template); } + +module_init(init_this_scsi_driver); +module_exit(exit_this_scsi_driver); /* * Overrides for Emacs so that we almost follow Linus's tabbing style. diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/scsi_queue.c linux/drivers/scsi/scsi_queue.c --- v2.4.0-test8/linux/drivers/scsi/scsi_queue.c Thu Jan 20 15:15:22 2000 +++ linux/drivers/scsi/scsi_queue.c Sun Sep 17 10:09:29 2000 @@ -118,7 +118,7 @@ * If a host is inactive and cannot queue any commands, I don't see * how things could possibly work anyways. */ - if (cmd->device->device_blocked == 0) { + if (cmd->device->device_busy == 0) { if (scsi_retry_command(cmd) == 0) { return 0; } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/scsi_scan.c linux/drivers/scsi/scsi_scan.c --- v2.4.0-test8/linux/drivers/scsi/scsi_scan.c Tue Sep 5 14:08:55 2000 +++ linux/drivers/scsi/scsi_scan.c Tue Sep 19 08:01:34 2000 @@ -127,12 +127,14 @@ {"REGAL", "CDC-4X", "*", BLIST_MAX5LUN | BLIST_SINGLELUN}, {"NAKAMICH", "MJ-4.8S", "*", BLIST_FORCELUN | BLIST_SINGLELUN}, {"NAKAMICH", "MJ-5.16S", "*", BLIST_FORCELUN | BLIST_SINGLELUN}, - {"PIONEER", "CD-ROM DRM-600", "*", BLIST_FORCELUN | BLIST_SINGLELUN}, - {"PIONEER", "CD-ROM DRM-602X", "*", BLIST_FORCELUN | BLIST_SINGLELUN}, - {"PIONEER", "CD-ROM DRM-604X", "*", BLIST_FORCELUN | BLIST_SINGLELUN}, + {"PIONEER", "CD-ROM DRM-600", "*", BLIST_FORCELUN | BLIST_SINGLELUN}, + {"PIONEER", "CD-ROM DRM-602X", "*", BLIST_FORCELUN | BLIST_SINGLELUN}, + {"PIONEER", "CD-ROM DRM-604X", "*", BLIST_FORCELUN | BLIST_SINGLELUN}, {"EMULEX", "MD21/S2 ESDI", "*", BLIST_SINGLELUN}, {"CANON", "IPUBJD", "*", BLIST_SPARSELUN}, {"nCipher", "Fastness Crypto", "*", BLIST_FORCELUN}, + {"DEC","HSG80","*", BLIST_FORCELUN}, + {"COMPAQ","LOGICAL VOLUME","*", BLIST_FORCELUN}, {"NEC", "PD-1 ODX654P", "*", BLIST_FORCELUN | BLIST_SINGLELUN}, {"MATSHITA", "PD-1", "*", BLIST_FORCELUN | BLIST_SINGLELUN}, {"iomega", "jaz 1GB", "J.86", BLIST_NOTQ | BLIST_NOLUN}, @@ -142,6 +144,8 @@ {"DGC", "DISK", "*", BLIST_SPARSELUN}, // Dell PV 650F (no tgt @ LUN 0) {"DELL", "PV530F", "*", BLIST_SPARSELUN}, // Dell PV 530F {"SONY", "TSL", "*", BLIST_FORCELUN}, // DDS3 & DDS4 autoloaders + {"DELL", "PERCRAID", "*", BLIST_FORCELUN}, + {"HP", "NetRAID-4M", "*", BLIST_FORCELUN}, /* * Must be at end of list... diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/scsi_syms.c linux/drivers/scsi/scsi_syms.c --- v2.4.0-test8/linux/drivers/scsi/scsi_syms.c Mon Mar 13 22:15:03 2000 +++ linux/drivers/scsi/scsi_syms.c Wed Sep 20 13:11:53 2000 @@ -6,8 +6,6 @@ #include #include -#ifdef CONFIG_MODULES - #include #include #include @@ -93,4 +91,3 @@ EXPORT_SYMBOL(scsi_devicelist); EXPORT_SYMBOL(scsi_device_types); -#endif /* CONFIG_MODULES */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c --- v2.4.0-test8/linux/drivers/scsi/sd.c Thu Sep 7 08:56:00 2000 +++ linux/drivers/scsi/sd.c Sun Oct 1 20:35:16 2000 @@ -80,7 +80,7 @@ struct hd_struct *sd; -static Scsi_Disk *rscsi_disks = NULL; +static Scsi_Disk *rscsi_disks; static int *sd_sizes; static int *sd_blocksizes; static int *sd_hardsizes; /* Hardware sector size */ @@ -96,10 +96,30 @@ static int sd_attach(Scsi_Device *); static int sd_detect(Scsi_Device *); static void sd_detach(Scsi_Device *); -static void rw_intr(Scsi_Cmnd * SCpnt); - static int sd_init_command(Scsi_Cmnd *); +static struct Scsi_Device_Template sd_template = { + name:"disk", + tag:"sd", + scsi_type:TYPE_DISK, + major:SCSI_DISK0_MAJOR, + /* + * Secondary range of majors that this driver handles. + */ + min_major:SCSI_DISK1_MAJOR, + max_major:SCSI_DISK7_MAJOR, + blk:1, + detect:sd_detect, + init:sd_init, + finish:sd_finish, + attach:sd_attach, + detach:sd_detach, + init_command:sd_init_command, +}; + + +static void rw_intr(Scsi_Cmnd * SCpnt); + #if defined(CONFIG_PPC) /* * Moved from arch/ppc/pmac_setup.c. This is where it really belongs. @@ -243,25 +263,6 @@ } } -struct Scsi_Device_Template sd_template = { - name:"disk", - tag:"sd", - scsi_type:TYPE_DISK, - major:SCSI_DISK0_MAJOR, - /* - * Secondary range of majors that this driver handles. - */ - min_major:SCSI_DISK1_MAJOR, - max_major:SCSI_DISK7_MAJOR, - blk:1, - detect:sd_detect, - init:sd_init, - finish:sd_finish, - attach:sd_attach, - detach:sd_detach, - init_command:sd_init_command, -}; - static request_queue_t *sd_find_queue(kdev_t dev) { Scsi_Disk *dpnt; @@ -720,13 +721,14 @@ sd_devname(i, nbuff); /* - * If the device is offline, don't try and read capacity or any of the other - * nicities. + * If the device is offline, don't try and read capacity or any + * of the other niceties. */ - if (rscsi_disks[i].device->online == FALSE) { + if (rscsi_disks[i].device->online == FALSE) return i; - } - /* We need to retry the READ_CAPACITY because a UNIT_ATTENTION is + + /* + * We need to retry the READ_CAPACITY because a UNIT_ATTENTION is * considered a fatal error, and many devices report such an error * just after a scsi bus reset. */ @@ -807,7 +809,8 @@ } while(time1); printk("."); } - } while (the_result && spintime && time_after(spintime_value + 100 * HZ, jiffies)); + } while (the_result && spintime && + time_after(spintime_value + 100 * HZ, jiffies)); if (spintime) { if (the_result) printk("not responding...\n"); @@ -836,15 +839,16 @@ /* * The SCSI standard says: * "READ CAPACITY is necessary for self configuring software" - * While not mandatory, support of READ CAPACITY is strongly encouraged. + * While not mandatory, support of READ CAPACITY is strongly + * encouraged. * We used to die if we couldn't successfully do a READ CAPACITY. * But, now we go on about our way. The side effects of this are * - * 1. We can't know block size with certainty. I have said "512 bytes - * is it" as this is most common. + * 1. We can't know block size with certainty. I have said + * "512 bytes is it" as this is most common. * - * 2. Recovery from when some one attempts to read past the end of the - * raw device will be slower. + * 2. Recovery from when someone attempts to read past the + * end of the raw device will be slower. */ if (the_result) { @@ -867,15 +871,15 @@ rscsi_disks[i].capacity = 0x1fffff; sector_size = 512; - /* Set dirty bit for removable devices if not ready - sometimes drives - * will not report this properly. */ + /* Set dirty bit for removable devices if not ready - + * sometimes drives will not report this properly. */ if (rscsi_disks[i].device->removable && SRpnt->sr_sense_buffer[2] == NOT_READY) rscsi_disks[i].device->changed = 1; } else { /* - * FLOPTICAL , if read_capa is ok , drive is assumed to be ready + * FLOPTICAL, if read_capa is ok, drive is assumed to be ready */ rscsi_disks[i].ready = 1; @@ -889,7 +893,8 @@ if (sector_size == 0) { sector_size = 512; - printk("%s : sector size 0 reported, assuming 512.\n", nbuff); + printk("%s : sector size 0 reported, assuming 512.\n", + nbuff); } if (sector_size != 512 && sector_size != 1024 && @@ -924,31 +929,30 @@ * So I have created this table. See ll_rw_blk.c * Jacques Gelinas (Jacques@solucorp.qc.ca) */ - int m, mb; - int sz_quot, sz_rem; + int m; int hard_sector = sector_size; + int sz = rscsi_disks[i].capacity * (hard_sector/256); + /* There are 16 minors allocated for each major device */ for (m = i << 4; m < ((i + 1) << 4); m++) { sd_hardsizes[m] = hard_sector; } - mb = rscsi_disks[i].capacity / 1024 * hard_sector / 1024; - /* sz = div(m/100, 10); this seems to not be in the libr */ - m = (mb + 50) / 100; - sz_quot = m / 10; - sz_rem = m - (10 * sz_quot); - printk("SCSI device %s: hdwr sector= %d bytes." - " Sectors= %d [%d MB] [%d.%1d GB]\n", - nbuff, hard_sector, rscsi_disks[i].capacity, - mb, sz_quot, sz_rem); + + printk("SCSI device %s: " + "%d %d-byte hdwr sectors (%d MB)\n", + nbuff, rscsi_disks[i].capacity, + hard_sector, (sz/2 - sz/1250 + 974)/1950); } + + /* Rescale capacity to 512-byte units */ if (sector_size == 4096) rscsi_disks[i].capacity <<= 3; if (sector_size == 2048) - rscsi_disks[i].capacity <<= 2; /* Change into 512 byte sectors */ + rscsi_disks[i].capacity <<= 2; if (sector_size == 1024) - rscsi_disks[i].capacity <<= 1; /* Change into 512 byte sectors */ + rscsi_disks[i].capacity <<= 1; if (sector_size == 256) - rscsi_disks[i].capacity >>= 1; /* Change into 512 byte sectors */ + rscsi_disks[i].capacity >>= 1; } @@ -1014,7 +1018,7 @@ * their size, and reads partition table entries for them. */ -static int sd_registered = 0; +static int sd_registered; static int sd_init() { @@ -1030,7 +1034,7 @@ sd_template.dev_max = N_SD_MAJORS * SCSI_DISKS_PER_MAJOR; if (!sd_registered) { - for (i = 0; i <= (sd_template.dev_max - 1) / SCSI_DISKS_PER_MAJOR; i++) { + for (i = 0; i < N_USED_SD_MAJORS; i++) { if (devfs_register_blkdev(SD_MAJOR(i), "sd", &sd_fops)) { printk("Unable to get major %d for SCSI disk\n", SD_MAJOR(i)); return 1; @@ -1142,7 +1146,7 @@ struct gendisk *gendisk; int i; - for (i = 0; i <= (sd_template.dev_max - 1) / SCSI_DISKS_PER_MAJOR; i++) { + for (i = 0; i < N_USED_SD_MAJORS; i++) { blk_dev[SD_MAJOR(i)].queue = sd_find_queue; } for (gendisk = gendisk_head; gendisk != NULL; gendisk = gendisk->next) @@ -1335,12 +1339,13 @@ return; } -int init_sd(void) +static int __init init_sd(void) { sd_template.module = THIS_MODULE; return scsi_register_module(MODULE_SCSI_DEV, &sd_template); } -void exit_sd(void) + +static void __exit exit_sd(void) { struct gendisk **prev_sdgd_link; struct gendisk *sdgd; @@ -1349,7 +1354,7 @@ scsi_unregister_module(MODULE_SCSI_DEV, &sd_template); - for (i = 0; i <= (sd_template.dev_max - 1) / SCSI_DISKS_PER_MAJOR; i++) + for (i = 0; i < N_USED_SD_MAJORS; i++) devfs_unregister_blkdev(SD_MAJOR(i), "sd"); sd_registered--; @@ -1378,7 +1383,7 @@ removed > N_USED_SD_MAJORS ? "total" : "just", removed); } - for (i = 0; i <= (sd_template.dev_max - 1) / SCSI_DISKS_PER_MAJOR; i++) { + for (i = 0; i < N_USED_SD_MAJORS; i++) { blk_size[SD_MAJOR(i)] = NULL; hardsect_size[SD_MAJOR(i)] = NULL; read_ahead[SD_MAJOR(i)] = 0; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/seagate.c linux/drivers/scsi/seagate.c --- v2.4.0-test8/linux/drivers/scsi/seagate.c Fri Jul 7 15:55:24 2000 +++ linux/drivers/scsi/seagate.c Mon Sep 18 13:36:25 2000 @@ -5,7 +5,8 @@ * * Note : TMC-880 boards don't work because they have two bits in * the status register flipped, I'll fix this "RSN" - * [why do I have strong feeling that above message is from 1993? :-) pavel@ucw.cz] + * [why do I have strong feeling that above message is from 1993? :-) + * pavel@ucw.cz] * * This card does all the I/O via memory mapped I/O, so there is no need * to check or allocate a region of the I/O address space. @@ -18,6 +19,13 @@ * * 1998-jul-29 - created DPRINTK macros and made it work under * linux 2.1.112, simplified some #defines etc. + * + * Aug 2000 - aeb - deleted seagate_st0x_biosparam(). It would try to + * read the physical disk geometry, a bad mistake. Of course it doesnt + * matter much what geometry one invents, but on large disks it + * returned 256 (or more) heads, causing all kind of failures. + * Of course this means that people might see a different geometry now, + * so boot parameters may be necessary in some cases. */ /* @@ -1702,127 +1710,7 @@ } -int seagate_st0x_biosparam (Disk * disk, kdev_t dev, int *ip) -{ - unsigned char buf[256 + sizeof (Scsi_Ioctl_Command)], - cmd[6], *data, *page; - Scsi_Ioctl_Command *sic = (Scsi_Ioctl_Command *) buf; - int result, formatted_sectors, total_sectors; - int cylinders, heads, sectors; - int capacity; - -/* - * Only SCSI-I CCS drives and later implement the necessary mode sense - * pages. - */ - - if (disk->device->scsi_level < 2) - return -1; - - data = sic->data; - - cmd[0] = MODE_SENSE; - cmd[1] = (disk->device->lun << 5) & 0xe5; - cmd[2] = 0x04; /* Read page 4, rigid disk geometry - page current values */ - cmd[3] = 0; - cmd[4] = 255; - cmd[5] = 0; - -/* - * We are transferring 0 bytes in the out direction, and expect to get back - * 24 bytes for each mode page. - */ - sic->inlen = 0; - sic->outlen = 256; - - memcpy (data, cmd, 6); - - if (!(result = kernel_scsi_ioctl (disk->device, SCSI_IOCTL_SEND_COMMAND, - sic))) - { -/* - * The mode page lies beyond the MODE SENSE header, with length 4, and - * the BLOCK DESCRIPTOR, with length header[3]. - */ - page = data + 4 + data[3]; - heads = (int) page[5]; - cylinders = (page[2] << 16) | (page[3] << 8) | page[4]; - - cmd[2] = 0x03; /* Read page 3, format page current - values */ - memcpy (data, cmd, 6); - - if (!(result = kernel_scsi_ioctl (disk->device, SCSI_IOCTL_SEND_COMMAND, - sic))) - { - page = data + 4 + data[3]; - sectors = (page[10] << 8) | page[11]; -/* - * Get the total number of formatted sectors from the block descriptor, - * so we can tell how many are being used for alternates. - */ - formatted_sectors = (data[4 + 1] << 16) | (data[4 + 2] << 8) - | data[4 + 3]; - - total_sectors = (heads * cylinders * sectors); - -/* - * Adjust the real geometry by subtracting - * (spare sectors / (heads * tracks)) cylinders from the number of cylinders. - * - * It appears that the CE cylinder CAN be a partial cylinder. - */ - - printk ("scsi%d : heads = %d cylinders = %d sectors = %d total = %d formatted = %d\n", - hostno, heads, cylinders, sectors, total_sectors, - formatted_sectors); - - if (!heads || !sectors || !cylinders) - result = -1; - else - cylinders -= ((total_sectors - formatted_sectors) / (heads * sectors)); - -/* - * Now, we need to do a sanity check on the geometry to see if it is - * BIOS compatible. The maximum BIOS geometry is 1024 cylinders * - * 256 heads * 64 sectors. - */ - - if ((cylinders > 1024) || (sectors > 64)) - { - /* The Seagate's seem to have some mapping. Multiply - heads*sectors*cyl to get capacity. Then start rounding down. - */ - capacity = heads * sectors * cylinders; - - /* Old MFM Drives use this, so does the Seagate */ - sectors = 17; - heads = 2; - capacity = capacity / sectors; - while (cylinders > 1024) - { - heads *= 2; /* For some reason, they go in - multiples */ - cylinders = capacity / heads; - } - } - ip[0] = heads; - ip[1] = sectors; - ip[2] = cylinders; -/* - * There should be an alternate mapping for things the seagate doesn't - * understand, but I couldn't say what it is with reasonable certainty. - */ - } - } - - return result; -} - -#ifdef MODULE /* Eventually this will go into an include file, but this will be later */ -Scsi_Host_Template driver_template = SEAGATE_ST0X; +static Scsi_Host_Template driver_template = SEAGATE_ST0X; #include "scsi_module.c" -#endif diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/seagate.h linux/drivers/scsi/seagate.h --- v2.4.0-test8/linux/drivers/scsi/seagate.h Tue Jan 25 13:01:14 2000 +++ linux/drivers/scsi/seagate.h Sun Sep 17 09:51:57 2000 @@ -20,16 +20,12 @@ const char *seagate_st0x_info(struct Scsi_Host *); int seagate_st0x_reset(Scsi_Cmnd *, unsigned int); -#include -int seagate_st0x_biosparam(Disk *, kdev_t, int*); - #define SEAGATE_ST0X { detect: seagate_st0x_detect, \ info: seagate_st0x_info, \ command: seagate_st0x_command, \ queuecommand: seagate_st0x_queue_command, \ abort: seagate_st0x_abort, \ reset: seagate_st0x_reset, \ - bios_param: seagate_st0x_biosparam, \ can_queue: 1, \ this_id: 7, \ sg_tablesize: SG_ALL, \ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/sg.c linux/drivers/scsi/sg.c --- v2.4.0-test8/linux/drivers/scsi/sg.c Sun Aug 6 11:43:17 2000 +++ linux/drivers/scsi/sg.c Tue Oct 3 09:24:40 2000 @@ -17,8 +17,11 @@ * any later version. * */ - static char * sg_version_str = "Version: 3.1.16 (20000716)"; - static int sg_version_num = 30116; /* 2 digits for each component */ +#include +#ifdef CONFIG_PROC_FS + static char * sg_version_str = "Version: 3.1.17 (20001002)"; +#endif + static int sg_version_num = 30117; /* 2 digits for each component */ /* * D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes: * - scsi logging is available via SCSI_LOG_TIMEOUT macros. First @@ -38,7 +41,6 @@ * # cat /proc/scsi/sg/debug * */ -#include #include #include @@ -67,10 +69,8 @@ #ifdef CONFIG_PROC_FS #include static int sg_proc_init(void); -#ifdef MODULE static void sg_proc_cleanup(void); #endif -#endif #ifndef LINUX_VERSION_CODE #include @@ -112,12 +112,12 @@ static int sg_detect(Scsi_Device *); static void sg_detach(Scsi_Device *); -static Scsi_Cmnd * dummy_cmdp = 0; /* only used for sizeof */ +static Scsi_Request * dummy_cmdp = 0; /* only used for sizeof */ static rwlock_t sg_dev_arr_lock = RW_LOCK_UNLOCKED; /* Also used to lock file descriptor list for device */ -struct Scsi_Device_Template sg_template = +static struct Scsi_Device_Template sg_template = { tag:"sg", scsi_type:0xff, @@ -148,12 +148,12 @@ typedef struct sg_request /* SG_MAX_QUEUE requests outstanding per file */ { - Scsi_Cmnd * my_cmdp; /* != 0 when request with lower levels */ + Scsi_Request * my_cmdp; /* != 0 when request with lower levels */ struct sg_request * nextrp; /* NULL -> tail request (slist) */ struct sg_fd * parentfp; /* NULL -> not in use */ Sg_scatter_hold data; /* hold buffer, perhaps scatter list */ sg_io_hdr_t header; /* scsi command+info, see */ - unsigned char sense_b[sizeof(dummy_cmdp->sense_buffer)]; + unsigned char sense_b[sizeof(dummy_cmdp->sr_sense_buffer)]; char res_used; /* 1 -> using reserve buffer, 0 -> not ... */ char orphan; /* 1 -> drop on sight, 0 -> normal */ char sg_io_owned; /* 1 -> packet belongs to SG_IO */ @@ -230,15 +230,17 @@ static int sg_remove_request(Sg_fd * sfp, Sg_request * srp); static int sg_res_in_use(Sg_fd * sfp); static int sg_dio_in_use(Sg_fd * sfp); -static void sg_clr_scpnt(Scsi_Cmnd * SCpnt); -static void sg_shorten_timeout(Scsi_Cmnd * scpnt); +static void sg_clr_srpnt(Scsi_Request * SRpnt); +static void sg_shorten_timeout(Scsi_Request * srpnt); static int sg_ms_to_jif(unsigned int msecs); static unsigned sg_jif_to_ms(int jifs); static int sg_allow_access(unsigned char opcode, char dev_type); -static int sg_last_dev(void); static int sg_build_dir(Sg_request * srp, Sg_fd * sfp, int dxfer_len); static void sg_unmap_and(Sg_scatter_hold * schp, int free_also); static Sg_device * sg_get_dev(int dev); +#ifdef CONFIG_PROC_FS +static int sg_last_dev(void); +#endif static Sg_device ** sg_dev_arr = NULL; @@ -267,7 +269,8 @@ * else try and use this device. Also, if error recovery fails, it * may try and take the device offline, in which case all further * access to the device is prohibited. */ - if(! scsi_block_when_processing_errors(sdp->device)) + if (! ((flags & O_NONBLOCK) || + scsi_block_when_processing_errors(sdp->device))) return -ENXIO; SCSI_LOG_TIMEOUT(3, printk("sg_open: dev=%d, flags=0x%x\n", dev, flags)); @@ -275,7 +278,7 @@ if (flags & O_EXCL) { if (O_RDONLY == (flags & O_ACCMODE)) return -EACCES; /* Can't lock it with read only access */ - if (sdp->headfp && (filp->f_flags & O_NONBLOCK)) + if (sdp->headfp && (flags & O_NONBLOCK)) return -EBUSY; res = 0; /* following is a macro that beats race condition */ __wait_event_interruptible(sdp->o_excl_wait, @@ -285,7 +288,7 @@ return res; /* -ERESTARTSYS because signal hit process */ } else if (sdp->exclude) { /* some other fd has an exclusive lock on dev */ - if (filp->f_flags & O_NONBLOCK) + if (flags & O_NONBLOCK) return -EBUSY; res = 0; /* following is a macro that beats race condition */ __wait_event_interruptible(sdp->o_excl_wait, (! sdp->exclude), res); @@ -349,9 +352,6 @@ return -ENXIO; SCSI_LOG_TIMEOUT(3, printk("sg_read: dev=%d, count=%d\n", MINOR(sdp->i_rdev), (int)count)); - - if(! scsi_block_when_processing_errors(sdp->device)) - return -ENXIO; if (ppos != &filp->f_pos) ; /* FIXME: Hmm. Seek to the right place, or fail? */ if ((k = verify_area(VERIFY_WRITE, buf, count))) @@ -447,20 +447,16 @@ static ssize_t sg_new_read(Sg_fd * sfp, char * buf, size_t count, Sg_request * srp) { - Sg_device * sdp = sfp->parentdp; sg_io_hdr_t * hp = &srp->header; int k, len; - if(! scsi_block_when_processing_errors(sdp->device) ) - return -ENXIO; if (count < size_sg_io_hdr) return -EINVAL; - hp->sb_len_wr = 0; if ((hp->mx_sb_len > 0) && hp->sbp) { if ((CHECK_CONDITION & hp->masked_status) || (DRIVER_SENSE & hp->driver_status)) { - int sb_len = sizeof(dummy_cmdp->sense_buffer); + int sb_len = sizeof(dummy_cmdp->sr_sense_buffer); sb_len = (hp->mx_sb_len > sb_len) ? sb_len : hp->mx_sb_len; len = 8 + (int)srp->sense_b[7]; /* Additional sense length field */ len = (len > sb_len) ? sb_len : len; @@ -492,14 +488,15 @@ Sg_request * srp; struct sg_header old_hdr; sg_io_hdr_t * hp; - unsigned char cmnd[sizeof(dummy_cmdp->cmnd)]; + unsigned char cmnd[sizeof(dummy_cmdp->sr_cmnd)]; if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp))) return -ENXIO; SCSI_LOG_TIMEOUT(3, printk("sg_write: dev=%d, count=%d\n", MINOR(sdp->i_rdev), (int)count)); - if(! scsi_block_when_processing_errors(sdp->device) ) + if (! ((filp->f_flags & O_NONBLOCK) || + scsi_block_when_processing_errors(sdp->device))) return -ENXIO; if (ppos != &filp->f_pos) ; /* FIXME: Hmm. Seek to the right place, or fail? */ @@ -581,7 +578,7 @@ int k; Sg_request * srp; sg_io_hdr_t * hp; - unsigned char cmnd[sizeof(dummy_cmdp->cmnd)]; + unsigned char cmnd[sizeof(dummy_cmdp->sr_cmnd)]; int timeout; if (count < size_sg_io_hdr) @@ -625,7 +622,7 @@ unsigned char * cmnd, int timeout, int blocking) { int k; - Scsi_Cmnd * SCpnt; + Scsi_Request * SRpnt; Sg_device * sdp = sfp->parentdp; sg_io_hdr_t * hp = &srp->header; @@ -652,38 +649,34 @@ return k; } /* SCSI_LOG_TIMEOUT(7, printk("sg_write: allocating device\n")); */ - SCpnt = scsi_allocate_device(sdp->device, blocking, TRUE); - if (! SCpnt) { - sg_finish_rem_req(srp); - return (signal_pending(current)) ? -EINTR : -EAGAIN; - /* No available command blocks, or, interrupted while waiting */ - } + SRpnt = scsi_allocate_request(sdp->device); + /* SCSI_LOG_TIMEOUT(7, printk("sg_write: device allocated\n")); */ - srp->my_cmdp = SCpnt; - SCpnt->request.rq_dev = sdp->i_rdev; - SCpnt->request.rq_status = RQ_ACTIVE; - SCpnt->sense_buffer[0] = 0; - SCpnt->cmd_len = hp->cmd_len; + srp->my_cmdp = SRpnt; + SRpnt->sr_request.rq_dev = sdp->i_rdev; + SRpnt->sr_request.rq_status = RQ_ACTIVE; + SRpnt->sr_sense_buffer[0] = 0; + SRpnt->sr_cmd_len = hp->cmd_len; /* Set the LUN field in the command structure, overriding user input */ if (! (hp->flags & SG_FLAG_LUN_INHIBIT)) cmnd[1] = (cmnd[1] & 0x1f) | (sdp->device->lun << 5); /* SCSI_LOG_TIMEOUT(7, printk("sg_write: do cmd\n")); */ - SCpnt->use_sg = srp->data.k_use_sg; - SCpnt->sglist_len = srp->data.sglist_len; - SCpnt->bufflen = srp->data.bufflen; - SCpnt->underflow = 0; - SCpnt->buffer = srp->data.buffer; + SRpnt->sr_use_sg = srp->data.k_use_sg; + SRpnt->sr_sglist_len = srp->data.sglist_len; + SRpnt->sr_bufflen = srp->data.bufflen; + SRpnt->sr_underflow = 0; + SRpnt->sr_buffer = srp->data.buffer; switch (hp->dxfer_direction) { case SG_DXFER_TO_FROM_DEV: case SG_DXFER_FROM_DEV: - SCpnt->sc_data_direction = SCSI_DATA_READ; break; + SRpnt->sr_data_direction = SCSI_DATA_READ; break; case SG_DXFER_TO_DEV: - SCpnt->sc_data_direction = SCSI_DATA_WRITE; break; + SRpnt->sr_data_direction = SCSI_DATA_WRITE; break; case SG_DXFER_UNKNOWN: - SCpnt->sc_data_direction = SCSI_DATA_UNKNOWN; break; + SRpnt->sr_data_direction = SCSI_DATA_UNKNOWN; break; default: - SCpnt->sc_data_direction = SCSI_DATA_NONE; break; + SRpnt->sr_data_direction = SCSI_DATA_NONE; break; } srp->data.k_use_sg = 0; srp->data.sglist_len = 0; @@ -692,10 +685,10 @@ hp->duration = jiffies; /* unit jiffies now, millisecs after done */ /* Now send everything of to mid-level. The next time we hear about this packet is when sg_cmd_done_bh() is called (i.e. a callback). */ - scsi_do_cmd(SCpnt, (void *)cmnd, - (void *)SCpnt->buffer, hp->dxfer_len, + scsi_do_req(SRpnt, (void *)cmnd, + (void *)SRpnt->sr_buffer, hp->dxfer_len, sg_cmd_done_bh, timeout, SG_DEFAULT_RETRIES); - /* dxfer_len overwrites SCpnt->bufflen, hence need for b_malloc_len */ + /* dxfer_len overwrites SRpnt->sr_bufflen, hence need for b_malloc_len */ return 0; } @@ -712,8 +705,6 @@ return -ENXIO; SCSI_LOG_TIMEOUT(3, printk("sg_ioctl: dev=%d, cmd=0x%x\n", MINOR(sdp->i_rdev), (int)cmd_in)); - if(! scsi_block_when_processing_errors(sdp->device) ) - return -ENXIO; read_only = (O_RDWR != (filp->f_flags & O_ACCMODE)); switch(cmd_in) @@ -885,7 +876,11 @@ case SG_EMULATED_HOST: return put_user(sdp->device->host->hostt->emulated, (int *)arg); case SG_SCSI_RESET: - if (! scsi_block_when_processing_errors(sdp->device)) + if (filp->f_flags & O_NONBLOCK) { + if (sdp->device->host->in_recovery) + return -EBUSY; + } + else if (! scsi_block_when_processing_errors(sdp->device)) return -EBUSY; result = get_user(val, (int *)arg); if (result) return result; @@ -989,7 +984,8 @@ * mid level when a command is completed (or has failed). */ static void sg_cmd_done_bh(Scsi_Cmnd * SCpnt) { - int dev = MINOR(SCpnt->request.rq_dev); + Scsi_Request * SRpnt = SCpnt->sc_request; + int dev = MINOR(SRpnt->sr_request.rq_dev); Sg_device * sdp = NULL; Sg_fd * sfp; Sg_request * srp = NULL; @@ -1002,15 +998,15 @@ if (NULL == sdp) { read_unlock(&sg_dev_arr_lock); SCSI_LOG_TIMEOUT(1, printk("sg...bh: bad args dev=%d\n", dev)); - scsi_release_command(SCpnt); - SCpnt = NULL; + scsi_release_request(SRpnt); + SRpnt = NULL; return; } sfp = sdp->headfp; while (sfp) { read_lock(&sfp->rq_list_lock); for (srp = sfp->headrp; srp; srp = srp->nextrp) { - if (SCpnt == srp->my_cmdp) + if (SRpnt == srp->my_cmdp) break; } read_unlock(&sfp->rq_list_lock); @@ -1021,41 +1017,41 @@ read_unlock(&sg_dev_arr_lock); if (! srp) { SCSI_LOG_TIMEOUT(1, printk("sg...bh: req missing, dev=%d\n", dev)); - scsi_release_command(SCpnt); - SCpnt = NULL; + scsi_release_request(SRpnt); + SRpnt = NULL; return; } /* First transfer ownership of data buffers to sg_device object. */ - srp->data.k_use_sg = SCpnt->use_sg; - srp->data.sglist_len = SCpnt->sglist_len; - srp->data.bufflen = SCpnt->bufflen; - srp->data.buffer = SCpnt->buffer; - sg_clr_scpnt(SCpnt); + srp->data.k_use_sg = SRpnt->sr_use_sg; + srp->data.sglist_len = SRpnt->sr_sglist_len; + srp->data.bufflen = SRpnt->sr_bufflen; + srp->data.buffer = SRpnt->sr_buffer; + sg_clr_srpnt(SRpnt); srp->my_cmdp = NULL; srp->done = 1; SCSI_LOG_TIMEOUT(4, printk("sg...bh: dev=%d, pack_id=%d, res=0x%x\n", - dev, srp->header.pack_id, (int)SCpnt->result)); + dev, srp->header.pack_id, (int)SRpnt->sr_result)); srp->header.resid = SCpnt->resid; /* sg_unmap_and(&srp->data, 0); */ /* unmap locked pages a.s.a.p. */ /* N.B. unit of duration changes here from jiffies to millisecs */ srp->header.duration = sg_jif_to_ms(jiffies - (int)srp->header.duration); - if (0 != SCpnt->result) { - memcpy(srp->sense_b, SCpnt->sense_buffer, sizeof(srp->sense_b)); - srp->header.status = 0xff & SCpnt->result; - srp->header.masked_status = status_byte(SCpnt->result); - srp->header.msg_status = msg_byte(SCpnt->result); - srp->header.host_status = host_byte(SCpnt->result); - srp->header.driver_status = driver_byte(SCpnt->result); + if (0 != SRpnt->sr_result) { + memcpy(srp->sense_b, SRpnt->sr_sense_buffer, sizeof(srp->sense_b)); + srp->header.status = 0xff & SRpnt->sr_result; + srp->header.masked_status = status_byte(SRpnt->sr_result); + srp->header.msg_status = msg_byte(SRpnt->sr_result); + srp->header.host_status = host_byte(SRpnt->sr_result); + srp->header.driver_status = driver_byte(SRpnt->sr_result); if ((sdp->sgdebug > 0) && ((CHECK_CONDITION == srp->header.masked_status) || (COMMAND_TERMINATED == srp->header.masked_status))) - print_sense("sg_cmd_done_bh", SCpnt); + print_req_sense("sg_cmd_done_bh", SRpnt); /* Following if statement is a patch supplied by Eric Youngdale */ - if (driver_byte(SCpnt->result) != 0 - && (SCpnt->sense_buffer[0] & 0x7f) == 0x70 - && (SCpnt->sense_buffer[2] & 0xf) == UNIT_ATTENTION + if (driver_byte(SRpnt->sr_result) != 0 + && (SRpnt->sr_sense_buffer[0] & 0x7f) == 0x70 + && (SRpnt->sr_sense_buffer[2] & 0xf) == UNIT_ATTENTION && sdp->device->removable) { /* Detected disc change. Set the bit - this may be used if */ /* there are filesystems using this device. */ @@ -1064,8 +1060,8 @@ } /* Rely on write phase to clean out srp status values, so no "else" */ - scsi_release_command(SCpnt); - SCpnt = NULL; + scsi_release_request(SRpnt); + SRpnt = NULL; if (sfp->closed) { /* whoops this fd already released, cleanup */ SCSI_LOG_TIMEOUT(1, printk("sg...bh: already closed, freeing ...\n")); @@ -1300,19 +1296,19 @@ return; } -#ifdef MODULE - +MODULE_AUTHOR("Douglas Gilbert"); +MODULE_DESCRIPTION("SCSI generic (sg) driver"); MODULE_PARM(def_reserved_size, "i"); MODULE_PARM_DESC(def_reserved_size, "size of buffer reserved for each fd"); -int init_module(void) { +static int __init init_sg(void) { if (def_reserved_size >= 0) sg_big_buff = def_reserved_size; - sg_template.module = &__this_module; + sg_template.module = THIS_MODULE; return scsi_register_module(MODULE_SCSI_DEV, &sg_template); } -void cleanup_module( void) +static void __exit exit_sg( void) { #ifdef CONFIG_PROC_FS sg_proc_cleanup(); @@ -1327,7 +1323,6 @@ } sg_template.dev_max = 0; } -#endif /* MODULE */ #if 0 @@ -1336,7 +1331,7 @@ #endif /* Can't see clean way to abort a command so shorten timeout to 1 jiffy */ -static void sg_shorten_timeout(Scsi_Cmnd * scpnt) +static void sg_shorten_timeout(Scsi_Request * srpnt) { #if 0 /* scsi_syms.c is very miserly about exported functions */ scsi_delete_timer(scpnt); @@ -1975,6 +1970,7 @@ return resp; } +#ifdef CONFIG_PROC_FS static Sg_request * sg_get_nth_request(Sg_fd * sfp, int nth) { Sg_request * resp; @@ -1988,6 +1984,7 @@ read_unlock_irqrestore(&sfp->rq_list_lock, iflags); return resp; } +#endif /* always adds to end of list */ static Sg_request * sg_add_request(Sg_fd * sfp) @@ -2067,6 +2064,7 @@ return res; } +#ifdef CONFIG_PROC_FS static Sg_fd * sg_get_nth_sfp(Sg_device * sdp, int nth) { Sg_fd * resp; @@ -2080,6 +2078,7 @@ read_unlock_irqrestore(&sg_dev_arr_lock, iflags); return resp; } +#endif static Sg_fd * sg_add_sfp(Sg_device * sdp, int dev) { @@ -2366,14 +2365,14 @@ sg_low_free(buff, size, mem_src); } -static void sg_clr_scpnt(Scsi_Cmnd * SCpnt) +static void sg_clr_srpnt(Scsi_Request * SRpnt) { - SCpnt->use_sg = 0; - SCpnt->sglist_len = 0; - SCpnt->bufflen = 0; - SCpnt->buffer = NULL; - SCpnt->underflow = 0; - SCpnt->request.rq_dev = MKDEV(0, 0); /* "sg" _disowns_ command blk */ + SRpnt->sr_use_sg = 0; + SRpnt->sr_sglist_len = 0; + SRpnt->sr_bufflen = 0; + SRpnt->sr_buffer = NULL; + SRpnt->sr_underflow = 0; + SRpnt->sr_request.rq_dev = MKDEV(0, 0); /* "sg" _disowns_ command blk */ } static int sg_ms_to_jif(unsigned int msecs) @@ -2413,6 +2412,7 @@ } +#ifdef CONFIG_PROC_FS static int sg_last_dev() { int k; @@ -2424,6 +2424,7 @@ read_unlock_irqrestore(&sg_dev_arr_lock, iflags); return k + 1; /* origin 1 */ } +#endif static Sg_device * sg_get_dev(int dev) { @@ -2543,7 +2544,6 @@ return 0; } -#ifdef MODULE static void sg_proc_cleanup() { int k; @@ -2555,7 +2555,6 @@ remove_proc_entry(sg_proc_leaf_names[k], sg_proc_sgp); remove_proc_entry(sg_proc_sg_dirname, proc_scsi); } -#endif static int sg_proc_dressz_read(char * buffer, char ** start, off_t offset, int size, int * eof, void * data) @@ -2642,8 +2641,8 @@ /* stop indenting so far ... */ PRINT_PROC(srp->res_used ? " rb>> " : ((SG_INFO_DIRECT_IO_MASK & hp->info) ? " dio>> " : " ")); - blen = srp->my_cmdp ? srp->my_cmdp->bufflen : srp->data.bufflen; - usg = srp->my_cmdp ? srp->my_cmdp->use_sg : srp->data.k_use_sg; + blen = srp->my_cmdp ? srp->my_cmdp->sr_bufflen : srp->data.bufflen; + usg = srp->my_cmdp ? srp->my_cmdp->sr_use_sg : srp->data.k_use_sg; PRINT_PROC(srp->done ? ((1 == srp->done) ? "rcv:" : "fin:") : (srp->my_cmdp ? "act:" : "prior:")); PRINT_PROC(" id=%d blen=%d", srp->header.pack_id, blen); @@ -2785,3 +2784,7 @@ return 1; } #endif /* CONFIG_PROC_FS */ + + +module_init(init_sg); +module_exit(exit_sg); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/sgiwd93.c linux/drivers/scsi/sgiwd93.c --- v2.4.0-test8/linux/drivers/scsi/sgiwd93.c Tue Jul 11 11:17:45 2000 +++ linux/drivers/scsi/sgiwd93.c Mon Sep 18 13:36:25 2000 @@ -317,17 +317,13 @@ return 1; /* Found one. */ } -#ifdef MODULE - #define HOSTS_C #include "sgiwd93.h" -Scsi_Host_Template driver_template = SGIWD93_SCSI; +static Scsi_Host_Template driver_template = SGIWD93_SCSI; #include "scsi_module.c" - -#endif int sgiwd93_release(struct Scsi_Host *instance) { diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/sim710.c linux/drivers/scsi/sim710.c --- v2.4.0-test8/linux/drivers/scsi/sim710.c Fri Nov 19 11:30:54 1999 +++ linux/drivers/scsi/sim710.c Mon Sep 18 13:36:25 2000 @@ -1603,7 +1603,8 @@ return 1; } -Scsi_Host_Template driver_template = SIM710_SCSI; +#endif + +static Scsi_Host_Template driver_template = SIM710_SCSI; #include "scsi_module.c" -#endif diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/sim710.h linux/drivers/scsi/sim710.h --- v2.4.0-test8/linux/drivers/scsi/sim710.h Fri Sep 8 12:54:34 2000 +++ linux/drivers/scsi/sim710.h Mon Sep 18 14:10:10 2000 @@ -21,7 +21,6 @@ #define sim710_release NULL #endif -#if defined(HOSTS_C) || defined(MODULE) #include #define SIM710_SCSI { proc_name: "sim710", \ @@ -40,8 +39,6 @@ cmd_per_lun: 1, \ use_clustering: DISABLE_CLUSTERING, \ use_new_eh_code: 1} - -#endif #ifndef HOSTS_C diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c --- v2.4.0-test8/linux/drivers/scsi/sr.c Thu Sep 7 08:32:01 2000 +++ linux/drivers/scsi/sr.c Sun Oct 1 20:35:16 2000 @@ -71,7 +71,7 @@ static int sr_init_command(Scsi_Cmnd *); -struct Scsi_Device_Template sr_template = +static struct Scsi_Device_Template sr_template = { name:"cdrom", tag:"sr", @@ -696,7 +696,7 @@ return cgc->stat; } -static int sr_registered = 0; +static int sr_registered; static int sr_init() { @@ -849,13 +849,13 @@ return; } -int init_sr(void) +static int __init init_sr(void) { sr_template.module = THIS_MODULE; return scsi_register_module(MODULE_SCSI_DEV, &sr_template); } -void exit_sr(void) +static void __exit exit_sr(void) { scsi_unregister_module(MODULE_SCSI_DEV, &sr_template); devfs_unregister_blkdev(MAJOR_NR, "sr"); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/st.c linux/drivers/scsi/st.c --- v2.4.0-test8/linux/drivers/scsi/st.c Wed Sep 6 12:53:14 2000 +++ linux/drivers/scsi/st.c Fri Sep 22 14:37:37 2000 @@ -155,7 +155,7 @@ static int st_detect(Scsi_Device *); static void st_detach(Scsi_Device *); -struct Scsi_Device_Template st_template = +static struct Scsi_Device_Template st_template = { name:"tape", tag:"st", @@ -173,6 +173,47 @@ static int update_partition(Scsi_Tape *); static int st_int_ioctl(Scsi_Tape *, unsigned int, unsigned long); + + +/* #include "osst_detect.h" */ +#ifndef SIGS_FROM_OSST +#define SIGS_FROM_OSST \ + {"OnStream", "SC-", "", "osst"}, \ + {"OnStream", "DI-", "", "osst"}, \ + {"OnStream", "DP-", "", "osst"}, \ + {"OnStream", "USB", "", "osst"}, \ + {"OnStream", "FW-", "", "osst"} +#endif + +struct st_reject_data { + char *vendor; + char *model; + char *rev; + char *driver_hint; /* Name of the correct driver, NULL if unknown */ +}; + +static struct st_reject_data reject_list[] = { + /* {"XXX", "Yy-", "", NULL}, example */ + SIGS_FROM_OSST, + {NULL, }}; + +/* If the device signature is on the list of incompatible drives, the + function returns a pointer to the name of the correct driver (if known) */ +static char * st_incompatible(Scsi_Device* SDp) +{ + struct st_reject_data *rp; + + for (rp=&(reject_list[0]); rp->vendor != NULL; rp++) + if (!strncmp(rp->vendor, SDp->vendor, strlen(rp->vendor)) && + !strncmp(rp->model, SDp->model, strlen(rp->model)) && + !strncmp(rp->rev, SDp->rev, strlen(rp->rev))) { + if (rp->driver_hint) + return rp->driver_hint; + else + return "unknown"; + } + return NULL; +} /* Convert the result to success code */ @@ -3460,9 +3501,17 @@ ST_partstat *STps; int i, mode, target_nbr; unsigned long flags = 0; + char *stp; if (SDp->type != TYPE_TAPE) return 1; + if ((stp = st_incompatible(SDp))) { + printk(KERN_INFO + "st: Found incompatible tape at scsi%d, channel %d, id %d, lun %d\n", + SDp->host->host_no, SDp->channel, SDp->id, SDp->lun); + printk(KERN_INFO "st: The suggested driver is %s.\n", stp); + return 1; + } write_lock_irqsave(&st_dev_arr_lock, flags); if (st_template.nr_dev >= st_template.dev_max) { @@ -3626,7 +3675,7 @@ static int st_detect(Scsi_Device * SDp) { - if (SDp->type != TYPE_TAPE) + if (SDp->type != TYPE_TAPE || st_incompatible(SDp)) return 0; printk(KERN_WARNING @@ -3700,17 +3749,15 @@ } -#ifdef MODULE - -int __init init_module(void) +static int __init init_st(void) { validate_options(); - st_template.module = &__this_module; + st_template.module = THIS_MODULE; return scsi_register_module(MODULE_SCSI_DEV, &st_template); } -void cleanup_module(void) +static void __exit exit_st(void) { int i; @@ -3736,4 +3783,6 @@ st_template.dev_max = 0; printk(KERN_INFO "st: Unloaded.\n"); } -#endif /* MODULE */ + +module_init(init_st); +module_exit(exit_st); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/sun3_scsi.c linux/drivers/scsi/sun3_scsi.c --- v2.4.0-test8/linux/drivers/scsi/sun3_scsi.c Sat Feb 26 20:33:03 2000 +++ linux/drivers/scsi/sun3_scsi.c Mon Sep 18 13:36:25 2000 @@ -529,10 +529,7 @@ #include "sun3_NCR5380.c" -#ifdef MODULE - -Scsi_Host_Template driver_template = SUN3_NCR5380; +static Scsi_Host_Template driver_template = SUN3_NCR5380; #include "scsi_module.c" -#endif diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/sym53c416.c linux/drivers/scsi/sym53c416.c --- v2.4.0-test8/linux/drivers/scsi/sym53c416.c Thu Nov 11 16:57:30 1999 +++ linux/drivers/scsi/sym53c416.c Mon Sep 18 13:36:25 2000 @@ -813,7 +813,8 @@ MODULE_PARM(sym53c416_2, "1-2i"); MODULE_PARM(sym53c416_3, "1-2i"); -Scsi_Host_Template driver_template = SYM53C416; +#endif + +static Scsi_Host_Template driver_template = SYM53C416; #include "scsi_module.c" -#endif diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/sym53c8xx.c linux/drivers/scsi/sym53c8xx.c --- v2.4.0-test8/linux/drivers/scsi/sym53c8xx.c Mon Jun 19 17:59:42 2000 +++ linux/drivers/scsi/sym53c8xx.c Tue Sep 19 08:31:53 2000 @@ -107,6 +107,7 @@ #define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s)) +#include #ifdef MODULE #include #endif @@ -698,6 +699,9 @@ #elif defined(__alpha__) # define pcivtobus(p) ((p) & 0xfffffffful) # define memcpy_to_pci(a, b, c) memcpy_toio((a), (b), (c)) +#elif defined(CONFIG_PPC) +# define pcivtobus(p) phys_to_bus(p) +# define memcpy_to_pci(a, b, c) memcpy_toio((a), (b), (c)) #else /* others */ # define pcivtobus(p) (p) # define memcpy_to_pci(a, b, c) memcpy_toio((a), (b), (c)) @@ -15059,7 +15063,5 @@ ** Module stuff */ -#ifdef MODULE -Scsi_Host_Template driver_template = SYM53C8XX; +static Scsi_Host_Template driver_template = SYM53C8XX; #include "scsi_module.c" -#endif diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/sym53c8xx.h linux/drivers/scsi/sym53c8xx.h --- v2.4.0-test8/linux/drivers/scsi/sym53c8xx.h Fri Sep 8 12:54:35 2000 +++ linux/drivers/scsi/sym53c8xx.h Mon Oct 2 11:03:13 2000 @@ -65,8 +65,6 @@ ** Used by hosts.c and sym53c8xx.c with module configuration. */ -#if defined(HOSTS_C) || defined(MODULE) - #include int sym53c8xx_abort(Scsi_Cmnd *); @@ -110,7 +108,5 @@ 0, 0, DISABLE_CLUSTERING} #endif /* LINUX_VERSION_CODE */ - -#endif /* defined(HOSTS_C) || defined(MODULE) */ #endif /* SYM53C8XX_H */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/sym53c8xx_comm.h linux/drivers/scsi/sym53c8xx_comm.h --- v2.4.0-test8/linux/drivers/scsi/sym53c8xx_comm.h Mon Jun 19 17:59:42 2000 +++ linux/drivers/scsi/sym53c8xx_comm.h Mon Sep 18 15:05:20 2000 @@ -498,7 +498,8 @@ # define memcpy_to_pci(a, b, c) memcpy_toio((a), (b), (c)) #endif -#ifndef SCSI_NCR_PCI_MEM_NOT_SUPPORTED +#if (defined(SCSI_NCR_NVRAM_SUPPORT) && !defined(NCR_IOMAPPED)) || \ + (defined(__i386__) && !defined(SCSI_NCR_PCI_MEM_NOT_SUPPORTED)) static u_long __init remap_pci_mem(u_long base, u_long size) { u_long page_base = ((u_long) base) & PAGE_MASK; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/t128.c linux/drivers/scsi/t128.c --- v2.4.0-test8/linux/drivers/scsi/t128.c Fri Nov 19 11:30:54 1999 +++ linux/drivers/scsi/t128.c Mon Sep 18 13:36:25 2000 @@ -393,9 +393,7 @@ #include "NCR5380.c" -#ifdef MODULE /* Eventually this will go into an include file, but this will be later */ -Scsi_Host_Template driver_template = TRANTOR_T128; +static Scsi_Host_Template driver_template = TRANTOR_T128; #include "scsi_module.c" -#endif diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/t128.h linux/drivers/scsi/t128.h --- v2.4.0-test8/linux/drivers/scsi/t128.h Fri Nov 19 11:30:54 1999 +++ linux/drivers/scsi/t128.h Mon Sep 18 14:10:10 2000 @@ -117,8 +117,6 @@ * macros when this is being used solely for the host stub. */ -#if defined(HOSTS_C) || defined(MODULE) - #define TRANTOR_T128 { \ name: "Trantor T128/T128F/T228", \ detect: t128_detect, \ @@ -131,8 +129,6 @@ sg_tablesize: SG_ALL, \ cmd_per_lun: CMD_PER_LUN, \ use_clustering: DISABLE_CLUSTERING} - -#endif #ifndef HOSTS_C diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/tmscsim.c linux/drivers/scsi/tmscsim.c --- v2.4.0-test8/linux/drivers/scsi/tmscsim.c Thu Jul 6 19:27:48 2000 +++ linux/drivers/scsi/tmscsim.c Mon Sep 18 14:26:56 2000 @@ -2588,6 +2588,7 @@ return( 1 ); } -Scsi_Host_Template driver_template = DC390_T; +#endif + +static Scsi_Host_Template driver_template = DC390_T; #include "scsi_module.c" -#endif /* def MODULE */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/u14-34f.c linux/drivers/scsi/u14-34f.c --- v2.4.0-test8/linux/drivers/scsi/u14-34f.c Tue Mar 21 14:43:39 2000 +++ linux/drivers/scsi/u14-34f.c Mon Sep 18 13:36:25 2000 @@ -1964,12 +1964,11 @@ return FALSE; } -#if defined(MODULE) -Scsi_Host_Template driver_template = ULTRASTOR_14_34F; +static Scsi_Host_Template driver_template = ULTRASTOR_14_34F; #include "scsi_module.c" -#else +#ifndef MODULE #if LINUX_VERSION_CODE < LinuxVersionCode(2,3,18) void u14_34f_setup(char *str, int *ints) { diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/ultrastor.c linux/drivers/scsi/ultrastor.c --- v2.4.0-test8/linux/drivers/scsi/ultrastor.c Thu Nov 11 16:57:31 1999 +++ linux/drivers/scsi/ultrastor.c Mon Sep 18 13:36:25 2000 @@ -1161,9 +1161,7 @@ spin_unlock_irqrestore(&io_request_lock, flags); } -#ifdef MODULE /* Eventually this will go into an include file, but this will be later */ -Scsi_Host_Template driver_template = ULTRASTOR_14F; +static Scsi_Host_Template driver_template = ULTRASTOR_14F; #include "scsi_module.c" -#endif diff -u --recursive --new-file v2.4.0-test8/linux/drivers/scsi/wd7000.c linux/drivers/scsi/wd7000.c --- v2.4.0-test8/linux/drivers/scsi/wd7000.c Thu Dec 16 13:57:05 1999 +++ linux/drivers/scsi/wd7000.c Mon Sep 18 13:36:25 2000 @@ -1778,9 +1778,7 @@ return (0); } -#ifdef MODULE /* Eventually this will go into an include file, but this will be later */ -Scsi_Host_Template driver_template = WD7000; +static Scsi_Host_Template driver_template = WD7000; #include "scsi_module.c" -#endif diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/Config.in linux/drivers/sound/Config.in --- v2.4.0-test8/linux/drivers/sound/Config.in Tue Aug 22 11:31:05 2000 +++ linux/drivers/sound/Config.in Mon Sep 25 12:32:54 2000 @@ -16,6 +16,7 @@ fi dep_tristate ' Creative SBLive! (EMU10K1)' CONFIG_SOUND_EMU10K1 $CONFIG_SOUND dep_tristate ' Crystal SoundFusion (CS4280/461x)' CONFIG_SOUND_FUSION $CONFIG_SOUND +dep_tristate ' Crystal Sound CS4281' CONFIG_SOUND_CS4281 $CONFIG_SOUND dep_tristate ' Ensoniq AudioPCI (ES1370)' CONFIG_SOUND_ES1370 $CONFIG_SOUND dep_tristate ' Creative Ensoniq AudioPCI 97 (ES1371)' CONFIG_SOUND_ES1371 $CONFIG_SOUND dep_tristate ' ESS Technology Solo1' CONFIG_SOUND_ESSSOLO1 $CONFIG_SOUND @@ -127,12 +128,6 @@ fi fi - dep_tristate ' SoftOSS software wave table engine' CONFIG_SOUND_SOFTOSS $CONFIG_SOUND_OSS - if [ "$CONFIG_SOUND_SOFTOSS" = "y" ]; then - int 'Sampling rate for SoftOSS 8000 to 48000' CONFIG_SOFTOSS_RATE 22050 - int 'Max # of concurrent voices for SoftOSS 4 to 32' CONFIG_SOFTOSS_VOICES 32 - fi - dep_tristate ' 100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support' CONFIG_SOUND_SB $CONFIG_SOUND_OSS dep_tristate ' AWE32 synth' CONFIG_SOUND_AWE32_SYNTH $CONFIG_SOUND_OSS dep_tristate ' Full support for Turtle Beach WaveFront (Tropez Plus, Tropez, Maui) synth/soundcards' CONFIG_SOUND_WAVEFRONT $CONFIG_SOUND_OSS m diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/Makefile linux/drivers/sound/Makefile --- v2.4.0-test8/linux/drivers/sound/Makefile Tue Aug 22 11:31:05 2000 +++ linux/drivers/sound/Makefile Mon Sep 25 12:32:54 2000 @@ -43,7 +43,6 @@ obj-$(CONFIG_SOUND_PSS) += pss.o ad1848.o mpu401.o obj-$(CONFIG_SOUND_TRIX) += trix.o ad1848.o sb_lib.o uart401.o obj-$(CONFIG_SOUND_OPL3SA1) += opl3sa.o ad1848.o uart401.o -obj-$(CONFIG_SOUND_SOFTOSS) += softoss2.o obj-$(CONFIG_SOUND_SSCAPE) += sscape.o ad1848.o mpu401.o obj-$(CONFIG_SOUND_MAD16) += mad16.o ad1848.o sb_lib.o uart401.o obj-$(CONFIG_SOUND_CS4232) += cs4232.o uart401.o @@ -79,6 +78,7 @@ obj-$(CONFIG_SOUND_ES1371) += es1371.o ac97_codec.o obj-$(CONFIG_SOUND_ESSSOLO1) += esssolo1.o obj-$(CONFIG_SOUND_FUSION) += cs46xx.o ac97_codec.o +obj-$(CONFIG_SOUND_CS4281) += cs4281.o obj-$(CONFIG_SOUND_MAESTRO) += maestro.o obj-$(CONFIG_SOUND_TRIDENT) += trident.o ac97_codec.o @@ -104,7 +104,7 @@ # Declare multi-part drivers. -list-multi := sound.o gus.o pas2.o sb.o sb_lib.o softoss2.o vidc_mod.o \ +list-multi := sound.o gus.o pas2.o sb.o sb_lib.o vidc_mod.o \ soundcore.o wavefront.o sound-objs := \ @@ -119,7 +119,6 @@ pas2-objs := pas2_card.o pas2_midi.o pas2_mixer.o pas2_pcm.o sb-objs := sb_card.o sb_lib-objs := sb_common.o sb_audio.o sb_midi.o sb_mixer.o sb_ess.o -softoss2-objs := softoss.o softoss_rs.o vidc_mod-objs := vidc.o vidc_fill.o wavefront-objs := wavfront.o wf_midi.o yss225.o @@ -180,9 +179,6 @@ sb_lib.o: $(sb_lib-objs) $(LD) -r -o $@ $(sb_lib-objs) - -softoss2.o: $(softoss2-objs) - $(LD) -r -o $@ $(softoss2-objs) vidc_mod.o: $(vidc_mod-objs) $(LD) -r -o $@ $(vidc_mod-objs) diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/ac97_codec.c linux/drivers/sound/ac97_codec.c --- v2.4.0-test8/linux/drivers/sound/ac97_codec.c Tue Aug 29 14:09:15 2000 +++ linux/drivers/sound/ac97_codec.c Sun Oct 1 20:20:20 2000 @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -48,6 +49,7 @@ static int ac97_init_mixer(struct ac97_codec *codec); static int sigmatel_init(struct ac97_codec *codec); +static int enable_eapd(struct ac97_codec *codec); #define arraysize(x) (sizeof(x)/sizeof((x)[0])) @@ -58,11 +60,14 @@ } ac97_codec_ids[] = { {0x414B4D00, "Asahi Kasei AK4540" , NULL}, {0x41445340, "Analog Devices AD1881" , NULL}, + {0x41445360, "Analog Devices AD1885" , enable_eapd}, {0x43525900, "Cirrus Logic CS4297" , NULL}, {0x43525903, "Cirrus Logic CS4297" , NULL}, {0x43525913, "Cirrus Logic CS4297A" , NULL}, {0x43525923, "Cirrus Logic CS4298" , NULL}, + {0x4352592B, "Cirrus Logic CS4294" , NULL}, {0x43525931, "Cirrus Logic CS4299" , NULL}, + {0x43525934, "Cirrus Logic CS4299" , NULL}, {0x4e534331, "National Semiconductor LM4549" , NULL}, {0x53494c22, "Silicon Laboratory Si3036" , NULL}, {0x53494c23, "Silicon Laboratory Si3038" , NULL}, @@ -71,8 +76,10 @@ {0x83847605, "SigmaTel STAC9704" , NULL}, {0x83847608, "SigmaTel STAC9708" , NULL}, {0x83847609, "SigmaTel STAC9721/23" , sigmatel_init}, + {0x54524103, "TriTech TR?????" , NULL}, {0x54524106, "TriTech TR28026" , NULL}, {0x54524108, "TriTech TR28028" , NULL}, + {0x54524123, "TriTech TR?????" , NULL}, {0x574D4C00, "Wolfson WM9704" , NULL}, {0x00000000, NULL, NULL} }; @@ -119,20 +126,20 @@ unsigned int value; } mixer_defaults[SOUND_MIXER_NRDEVICES] = { /* all values 0 -> 100 in bytes */ - {SOUND_MIXER_VOLUME, 0x3232}, - {SOUND_MIXER_BASS, 0x3232}, - {SOUND_MIXER_TREBLE, 0x3232}, - {SOUND_MIXER_PCM, 0x3232}, - {SOUND_MIXER_SPEAKER, 0x3232}, - {SOUND_MIXER_LINE, 0x3232}, - {SOUND_MIXER_MIC, 0x3232}, - {SOUND_MIXER_CD, 0x3232}, - {SOUND_MIXER_ALTPCM, 0x3232}, - {SOUND_MIXER_IGAIN, 0x3232}, - {SOUND_MIXER_LINE1, 0x3232}, - {SOUND_MIXER_PHONEIN, 0x3232}, - {SOUND_MIXER_PHONEOUT, 0x3232}, - {SOUND_MIXER_VIDEO, 0x3232}, + {SOUND_MIXER_VOLUME, 0x4343}, + {SOUND_MIXER_BASS, 0x4343}, + {SOUND_MIXER_TREBLE, 0x4343}, + {SOUND_MIXER_PCM, 0x4343}, + {SOUND_MIXER_SPEAKER, 0x4343}, + {SOUND_MIXER_LINE, 0x4343}, + {SOUND_MIXER_MIC, 0x4343}, + {SOUND_MIXER_CD, 0x4343}, + {SOUND_MIXER_ALTPCM, 0x4343}, + {SOUND_MIXER_IGAIN, 0x4343}, + {SOUND_MIXER_LINE1, 0x4343}, + {SOUND_MIXER_PHONEIN, 0x4343}, + {SOUND_MIXER_PHONEOUT, 0x4343}, + {SOUND_MIXER_VIDEO, 0x4343}, {-1,0} }; @@ -141,20 +148,20 @@ unsigned char offset; int scale; } ac97_hw[SOUND_MIXER_NRDEVICES]= { - [SOUND_MIXER_VOLUME] = {AC97_MASTER_VOL_STEREO,63}, - [SOUND_MIXER_BASS] = {AC97_MASTER_TONE, 15}, - [SOUND_MIXER_TREBLE] = {AC97_MASTER_TONE, 15}, - [SOUND_MIXER_PCM] = {AC97_PCMOUT_VOL, 31}, - [SOUND_MIXER_SPEAKER] = {AC97_PCBEEP_VOL, 15}, - [SOUND_MIXER_LINE] = {AC97_LINEIN_VOL, 31}, - [SOUND_MIXER_MIC] = {AC97_MIC_VOL, 31}, - [SOUND_MIXER_CD] = {AC97_CD_VOL, 31}, - [SOUND_MIXER_ALTPCM] = {AC97_HEADPHONE_VOL, 63}, - [SOUND_MIXER_IGAIN] = {AC97_RECORD_GAIN, 31}, - [SOUND_MIXER_LINE1] = {AC97_AUX_VOL, 31}, - [SOUND_MIXER_PHONEIN] = {AC97_PHONE_VOL, 15}, - [SOUND_MIXER_PHONEOUT] = {AC97_MASTER_VOL_MONO, 63}, - [SOUND_MIXER_VIDEO] = {AC97_VIDEO_VOL, 31}, + [SOUND_MIXER_VOLUME] = {AC97_MASTER_VOL_STEREO,64}, + [SOUND_MIXER_BASS] = {AC97_MASTER_TONE, 16}, + [SOUND_MIXER_TREBLE] = {AC97_MASTER_TONE, 16}, + [SOUND_MIXER_PCM] = {AC97_PCMOUT_VOL, 32}, + [SOUND_MIXER_SPEAKER] = {AC97_PCBEEP_VOL, 16}, + [SOUND_MIXER_LINE] = {AC97_LINEIN_VOL, 32}, + [SOUND_MIXER_MIC] = {AC97_MIC_VOL, 32}, + [SOUND_MIXER_CD] = {AC97_CD_VOL, 32}, + [SOUND_MIXER_ALTPCM] = {AC97_HEADPHONE_VOL, 64}, + [SOUND_MIXER_IGAIN] = {AC97_RECORD_GAIN, 16}, + [SOUND_MIXER_LINE1] = {AC97_AUX_VOL, 32}, + [SOUND_MIXER_PHONEIN] = {AC97_PHONE_VOL, 32}, + [SOUND_MIXER_PHONEOUT] = {AC97_MASTER_VOL_MONO, 64}, + [SOUND_MIXER_VIDEO] = {AC97_VIDEO_VOL, 32}, }; /* the following tables allow us to go from OSS <-> ac97 quickly. */ @@ -196,11 +203,14 @@ { u16 val; int ret = 0; + int scale; struct ac97_mixer_hw *mh = &ac97_hw[oss_channel]; val = codec->codec_read(codec , mh->offset); - if (AC97_STEREO_MASK & (1 << oss_channel)) { + if (val & AC97_MUTE) { + ret = 0; + } else if (AC97_STEREO_MASK & (1 << oss_channel)) { /* nice stereo mixers .. */ int left,right; @@ -211,8 +221,14 @@ right = (right * 100) / mh->scale; left = (left * 100) / mh->scale; } else { - right = 100 - ((right * 100) / mh->scale); - left = 100 - ((left * 100) / mh->scale); + /* these may have 5 or 6 bit resolution */ + if(oss_channel == SOUND_MIXER_VOLUME || oss_channel == SOUND_MIXER_ALTPCM) + scale = (1 << codec->bit_resolution); + else + scale = mh->scale; + + right = 100 - ((right * 100) / scale); + left = 100 - ((left * 100) / scale); } ret = left | (right << 8); } else if (oss_channel == SOUND_MIXER_SPEAKER) { @@ -220,7 +236,8 @@ } else if (oss_channel == SOUND_MIXER_PHONEIN) { ret = 100 - (((val & 0x1f) * 100) / mh->scale); } else if (oss_channel == SOUND_MIXER_PHONEOUT) { - ret = 100 - (((val & 0x1f) * 100) / mh->scale); + scale = (1 << codec->bit_resolution); + ret = 100 - (((val & 0x1f) * 100) / scale); } else if (oss_channel == SOUND_MIXER_MIC) { ret = 100 - (((val & 0x1f) * 100) / mh->scale); /* the low bit is optional in the tone sliders and masking @@ -247,6 +264,7 @@ unsigned int left, unsigned int right) { u16 val = 0; + int scale; struct ac97_mixer_hw *mh = &ac97_hw[oss_channel]; #ifdef DEBUG @@ -258,31 +276,45 @@ if (AC97_STEREO_MASK & (1 << oss_channel)) { /* stereo mixers */ - if (oss_channel == SOUND_MIXER_IGAIN) { - right = (right * mh->scale) / 100; - left = (left * mh->scale) / 100; + if (left == 0 && right == 0) { + val = AC97_MUTE; } else { - right = ((100 - right) * mh->scale) / 100; - left = ((100 - left) * mh->scale) / 100; - } - val = (left << 8) | right; + if (oss_channel == SOUND_MIXER_IGAIN) { + right = (right * mh->scale) / 100; + left = (left * mh->scale) / 100; + } else { + /* these may have 5 or 6 bit resolution */ + if (oss_channel == SOUND_MIXER_VOLUME || + oss_channel == SOUND_MIXER_ALTPCM) + scale = (1 << codec->bit_resolution); + else + scale = mh->scale; + + right = ((100 - right) * scale) / 100; + left = ((100 - left) * scale) / 100; + } + val = (left << 8) | right; + } + } else if (oss_channel == SOUND_MIXER_BASS) { + val = codec->codec_read(codec , mh->offset) & ~0x0f00; + val |= ((((100 - left) * mh->scale) / 100) << 8) & 0x0e00; + } else if (oss_channel == SOUND_MIXER_TREBLE) { + val = codec->codec_read(codec , mh->offset) & ~0x000f; + val |= (((100 - left) * mh->scale) / 100) & 0x000e; + } else if(left == 0) { + val = AC97_MUTE; } else if (oss_channel == SOUND_MIXER_SPEAKER) { val = (((100 - left) * mh->scale) / 100) << 1; } else if (oss_channel == SOUND_MIXER_PHONEIN) { val = (((100 - left) * mh->scale) / 100); } else if (oss_channel == SOUND_MIXER_PHONEOUT) { - val = (((100 - left) * mh->scale) / 100); + scale = (1 << codec->bit_resolution); + val = (((100 - left) * scale) / 100); } else if (oss_channel == SOUND_MIXER_MIC) { val = codec->codec_read(codec , mh->offset) & ~0x801f; val |= (((100 - left) * mh->scale) / 100); /* the low bit is optional in the tone sliders and masking it lets us avoid the 0xf 'bypass'.. */ - } else if (oss_channel == SOUND_MIXER_BASS) { - val = codec->codec_read(codec , mh->offset) & ~0x0f00; - val |= ((((100 - left) * mh->scale) / 100) << 8) & 0x0e00; - } else if (oss_channel == SOUND_MIXER_TREBLE) { - val = codec->codec_read(codec , mh->offset) & ~0x000f; - val |= (((100 - left) * mh->scale) / 100) & 0x000e; } #ifdef DEBUG printk(" 0x%04x", val); @@ -563,7 +595,7 @@ if (codec->codec_wait) codec->codec_wait(codec); else - schedule_timeout(5); + udelay(10); if ((audio = codec->codec_read(codec, AC97_RESET)) & 0x8000) { printk(KERN_ERR "ac97_codec: %s ac97 codec not present\n", @@ -582,6 +614,7 @@ id2 = codec->codec_read(codec, AC97_VENDOR_ID2); for (i = 0; i < arraysize(ac97_codec_ids); i++) { if (ac97_codec_ids[i].id == ((id1 << 16) | id2)) { + codec->type = ac97_codec_ids[i].id; codec->name = ac97_codec_ids[i].name; codec->codec_init = ac97_codec_ids[i].init; break; @@ -589,8 +622,8 @@ } if (codec->name == NULL) codec->name = "Unknown"; - printk(KERN_INFO "ac97_codec: AC97%s codec, id: 0x%04x:0x%04x (%s)\n", - audio ? " audio" : (modem ? " modem" : ""), + printk(KERN_INFO "ac97_codec: AC97 %s codec, vendor id1: 0x%04x, " + "id2: 0x%04x (%s)\n", audio ? "Audio" : (modem ? "Modem" : ""), id1, id2, codec->name); return ac97_init_mixer(codec); @@ -612,18 +645,21 @@ if (!(cap & 0x10)) codec->supported_mixers &= ~SOUND_MASK_ALTPCM; + /* detect bit resolution */ + codec->codec_write(codec, AC97_MASTER_VOL_STEREO, 0x2020); + if(codec->codec_read(codec, AC97_MASTER_VOL_STEREO) == 0x1f1f) + codec->bit_resolution = 5; + else + codec->bit_resolution = 6; + /* generic OSS to AC97 wrapper */ codec->read_mixer = ac97_read_mixer; codec->write_mixer = ac97_write_mixer; codec->recmask_io = ac97_recmask_io; codec->mixer_ioctl = ac97_mixer_ioctl; - /* initialize volume level */ - codec->codec_write(codec, AC97_MASTER_VOL_STEREO, 0L); - codec->codec_write(codec, AC97_PCMOUT_VOL, 0L); - /* codec specific initialization for 4-6 channel output or secondary codec stuff */ - if (codec->id != 0 && codec->codec_init != NULL) { + if (codec->codec_init != NULL) { codec->codec_init(codec); } @@ -642,6 +678,10 @@ static int sigmatel_init(struct ac97_codec * codec) { + /* Only set up secondary codec */ + if (codec->id == 0) + return 1; + codec->codec_write(codec, AC97_SURROUND_MASTER, 0L); /* initialize SigmaTel STAC9721/23 as secondary codec, decoding AC link @@ -659,6 +699,18 @@ return 1; } + +/* + * Bring up an AD1885 + */ + +static int enable_eapd(struct ac97_codec * codec) +{ + codec->codec_write(codec, AC97_POWER_CONTROL, + codec->codec_read(codec, AC97_POWER_CONTROL)|0x8000); + return 0; +} + EXPORT_SYMBOL(ac97_read_proc); EXPORT_SYMBOL(ac97_probe_codec); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/adlib_card.c linux/drivers/sound/adlib_card.c --- v2.4.0-test8/linux/drivers/sound/adlib_card.c Fri Aug 11 08:26:43 2000 +++ linux/drivers/sound/adlib_card.c Sun Sep 17 09:45:06 2000 @@ -20,15 +20,10 @@ static void __init attach_adlib_card(struct address_info *hw_config) { hw_config->slots[0] = opl3_init(hw_config->io_base, hw_config->osp, THIS_MODULE); - request_region(hw_config->io_base, 4, "OPL3/OPL2"); } static int __init probe_adlib(struct address_info *hw_config) { - if (check_region(hw_config->io_base, 4)) { - DDB(printk("opl3.c: I/O port %x already in use\n", hw_config->io_base)); - return 0; - } return opl3_detect(hw_config->io_base, hw_config->osp); } @@ -55,7 +50,6 @@ static void __exit cleanup_adlib(void) { - release_region(cfg.io_base, 4); sound_unload_synthdev(cfg.slots[0]); } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/aedsp16.c linux/drivers/sound/aedsp16.c --- v2.4.0-test8/linux/drivers/sound/aedsp16.c Fri Aug 11 08:26:43 2000 +++ linux/drivers/sound/aedsp16.c Wed Sep 27 13:53:57 2000 @@ -241,6 +241,9 @@ - Module informations added. - Removed aedsp16_delay_10msec(), now using mdelay(10) - All data and funcs moved to .*.init section. + v1.3 + Arnaldo Carvalho de Melo - 2000/09/27 + - got rid of check_region Known Problems: - Audio Excel DSP 16 III don't work with this driver. @@ -252,7 +255,7 @@ */ -#define VERSION "1.2" /* Version of Audio Excel DSP 16 driver */ +#define VERSION "1.3" /* Version of Audio Excel DSP 16 driver */ #undef AEDSP16_DEBUG 1 /* Define this to enable debug code */ #undef AEDSP16_DEBUG_MORE 1 /* Define this to enable more debug */ @@ -1174,25 +1177,18 @@ if (ae_config.init & INIT_MSS) return FALSE; /* - * We must check the CONFIG_AEDSP16_BASE region too because these are the I/O - * ports to access card's control registers. + * We must allocate the CONFIG_AEDSP16_BASE region too because these are the + * I/O ports to access card's control registers. */ if (!(ae_config.init & INIT_MPU401)) { - if (check_region(ae_config.base_io, IOBASE_REGION_SIZE)) { + if (!request_region(ae_config.base_io, IOBASE_REGION_SIZE, + "aedsp16 (base)")) { printk( "AEDSP16 BASE I/O port region is already in use.\n"); return FALSE; } } -/* - * We must allocate the CONFIG_AEDSP16_BASE region too because these are the - * I/O ports to access card's control registers. - */ - if (!(ae_config.init & INIT_MPU401)) - request_region(ae_config.base_io, IOBASE_REGION_SIZE, - "aedsp16 (base)"); - ae_config.init |= INIT_MSS; DBG(("done.\n")); @@ -1222,20 +1218,17 @@ return FALSE; /* - * We must check the CONFIG_AEDSP16_BASE region too because these are the I/O + * We must request the CONFIG_AEDSP16_BASE region too because these are the I/O * ports to access card's control registers. */ if (!(ae_config.init & (INIT_MSS | INIT_SBPRO))) { - if (check_region(ae_config.base_io, IOBASE_REGION_SIZE)) { + if (!request_region(ae_config.base_io, IOBASE_REGION_SIZE, + "aedsp16 (base)")) { printk( "AEDSP16 BASE I/O port region is already in use.\n"); return FALSE; } } - - if (!(ae_config.init & (INIT_MSS | INIT_SBPRO))) - request_region(ae_config.base_io, IOBASE_REGION_SIZE, - "aedsp16 (base)"); ae_config.init |= INIT_MPU401; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/cmpci.c linux/drivers/sound/cmpci.c --- v2.4.0-test8/linux/drivers/sound/cmpci.c Tue Aug 29 14:09:15 2000 +++ linux/drivers/sound/cmpci.c Wed Sep 27 13:53:57 2000 @@ -2287,8 +2287,6 @@ MODULE_PARM(spdif_loop, "i"); MODULE_PARM(four_ch, "i"); MODULE_PARM(rear_out, "i"); - -int __init init_module(void) #else #ifdef CONFIG_SOUND_CMPCI_SPDIFLOOP static int spdif_loop = 1; @@ -2305,9 +2303,9 @@ #else static int rear_out = 0; #endif - -int __init init_cmpci(void) #endif + +static int __init init_cmpci(void) { struct cm_state *s; struct pci_dev *pcidev = NULL; @@ -2372,28 +2370,25 @@ continue; s->irq = pcidev->irq; - if (check_region(s->iobase, CM_EXTENT_CODEC)) { + if (!request_region(s->iobase, CM_EXTENT_CODEC, "cmpci")) { printk(KERN_ERR "cmpci: io ports %#x-%#x in use\n", s->iobase, s->iobase+CM_EXTENT_CODEC-1); goto err_region5; } - request_region(s->iobase, CM_EXTENT_CODEC, "cmpci"); - if (check_region(s->iomidi, CM_EXTENT_MIDI)) { + if (!request_region(s->iomidi, CM_EXTENT_MIDI, "cmpci Midi")) { printk(KERN_WARNING "cmpci: io ports %#x-%#x in use, midi disabled.\n", s->iomidi, s->iomidi+CM_EXTENT_MIDI-1); s->iomidi = 0; } else { - request_region(s->iomidi, CM_EXTENT_MIDI, "cmpci Midi"); /* set IO based at 0x330 */ outb(inb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3) & ~0x60, s->iobase + CODEC_CMI_LEGACY_CTRL + 3); } - if (check_region(s->iosynth, CM_EXTENT_SYNTH)) { + if (!request_region(s->iosynth, CM_EXTENT_SYNTH, "cmpci FM")) { printk(KERN_WARNING "cmpci: io ports %#x-%#x in use, synth disabled.\n", s->iosynth, s->iosynth+CM_EXTENT_SYNTH-1); s->iosynth = 0; } else { - request_region(s->iosynth, CM_EXTENT_SYNTH, "cmpci FM"); /* enable FM */ outb(inb(s->iobase + CODEC_CMI_MISC_CTRL + 2) | 8, s->iobase + CODEC_CMI_MISC_CTRL); } @@ -2499,12 +2494,10 @@ /* --------------------------------------------------------------------- */ -#ifdef MODULE - MODULE_AUTHOR("ChenLi Tien, cltien@home.com"); MODULE_DESCRIPTION("CMPCI Audio Driver"); -void cleanup_module(void) +static void __exit cleanup_cmpci(void) { struct cm_state *s; @@ -2538,4 +2531,5 @@ printk(KERN_INFO "cmpci: unloading\n"); } -#endif /* MODULE */ +module_init(init_cmpci); +module_exit(cleanup_cmpci); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/cs4232.c linux/drivers/sound/cs4232.c --- v2.4.0-test8/linux/drivers/sound/cs4232.c Fri Aug 11 08:26:43 2000 +++ linux/drivers/sound/cs4232.c Wed Sep 27 13:53:56 2000 @@ -39,6 +39,7 @@ * Tropez+ (WaveFront) support * Christoph Hellwig Adapted to module_init/module_exit, * simple cleanups + * Arnaldo C. de Melo got rid of attach_uart401 */ #include @@ -255,10 +256,9 @@ hw_config2.driver_use_2 = 0; hw_config2.card_subtype = 0; - if (probe_uart401(&hw_config2)) + if (probe_uart401(&hw_config2, THIS_MODULE)) { mpu_detected = 1; - attach_uart401(&hw_config2, THIS_MODULE); } else { diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/cs4281.c linux/drivers/sound/cs4281.c --- v2.4.0-test8/linux/drivers/sound/cs4281.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/cs4281.c Sat Sep 23 20:34:58 2000 @@ -0,0 +1,2678 @@ +//***************************************************************************** +// +// "cs4281.c" -- Cirrus Logic-Crystal CS4281 linux audio driver. +// +// Copyright (C) 2000 Cirrus Logic Corp. +// -- adapted from drivers by Thomas Sailer, +// -- but don't bug him; Problems should go to: +// -- gw boynton (wesb@crystal.cirrus.com) or +// -- tom woller (twoller@crystal.cirrus.com). +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// +// Module command line parameters: +// none +// +// Supported devices: +// /dev/dsp standard /dev/dsp device, (mostly) OSS compatible +// /dev/mixer standard /dev/mixer device, (mostly) OSS compatible +// /dev/midi simple MIDI UART interface, no ioctl +// +// +// + +// ***************************************************************************** + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "dm.h" +#include "cs4281_hwdefs.h" + +EXPORT_NO_SYMBOLS; + +#undef OSS_DOCUMENTED_MIXER_SEMANTICS + +// --------------------------------------------------------------------- + +#ifndef PCI_VENDOR_ID_CIRRUS +#define PCI_VENDOR_ID_CIRRUS 0x1013 +#endif +#ifndef PCI_DEVICE_ID_CRYSTAL_CS4281 +#define PCI_DEVICE_ID_CRYSTAL_CS4281 0x6005 +#endif + +#define CS4281_MAGIC ((PCI_DEVICE_ID_CRYSTAL_CS4281<<16) | PCI_VENDOR_ID_CIRRUS) + +#define CSDEBUG 1 +// +// Turn on/off debugging compilation by using 1/0 respectively for CSDEBUG +// +// +// CSDEBUG is usual mode is set to 1, then use the +// cs_debuglevel and cs_debugmask to turn on or off debugging. +// Debug level of 1 has been defined to be kernel errors and info +// that should be printed on any released driver. +// +#if CSDEBUG +extern unsigned cs_debugmask; +extern unsigned cs_debuglevel; +#define CS_DBGOUT(mask,level,x) if((cs_debuglevel >= (level)) && ((mask) & cs_debugmask)) {x;} +#else +#define CS_DBGOUT(mask,level,x) +#endif +// +// cs_debugmask areas +// +#define CS_INIT 0x00000001 // initialization and probe functions +#define CS_ERROR 0x00000002 // tmp debugging bit placeholder +#define CS_INTERRUPT 0x00000004 // interrupt handler (separate from all other) +#define CS_FUNCTION 0x00000008 // enter/leave functions +#define CS_WAVE_WRITE 0x00000010 // write information for wave +#define CS_WAVE_READ 0x00000020 // read information for wave +#define CS_MIDI_WRITE 0x00000040 // write information for midi +#define CS_MIDI_READ 0x00000080 // read information for midi +#define CS_MPU401_WRITE 0x00000100 // write information for mpu401 +#define CS_MPU401_READ 0x00000200 // read information for mpu401 +#define CS_OPEN 0x00000400 // all open functions in the driver +#define CS_RELEASE 0x00000800 // all release functions in the driver +#define CS_PARMS 0x00001000 // functional and operational parameters +#define CS_TMP 0x10000000 // tmp debug mask bit + +unsigned cs_debuglevel=1; // levels range from 1-9 +unsigned cs_debugmask=CS_INIT | CS_ERROR; // use CS_DBGOUT with various mask values +#if MODULE +MODULE_PARM(cs_debuglevel, "i"); +MODULE_PARM(cs_debugmask, "i"); +#endif + +// MIDI buffer sizes +#define MIDIINBUF 500 +#define MIDIOUTBUF 500 + +#define FMODE_MIDI_SHIFT 3 +#define FMODE_MIDI_READ (FMODE_READ << FMODE_MIDI_SHIFT) +#define FMODE_MIDI_WRITE (FMODE_WRITE << FMODE_MIDI_SHIFT) + +#define RSRCISIOREGION(dev,num) ((dev)->resource[(num)].start != 0 && \ + ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) +#define RSRCISMEMORYREGION(dev,num) ((dev)->resource[(num)].start != 0 && \ + ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY) +#define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start) + +#define CS4281_MAJOR_VERSION 0 +#define CS4281_MINOR_VERSION 4 +#ifdef __ia64__ +#define CS4281_ARCH 64 //architecture key +#else +#define CS4281_ARCH 32 //architecture key +#endif + +struct cs4281_state { + // magic + unsigned int magic; + + // we keep the cards in a linked list + struct cs4281_state *next; + + // pcidev is needed to turn off the DDMA controller at driver shutdown + struct pci_dev *pcidev; + + // soundcore stuff + int dev_audio; + int dev_mixer; + int dev_midi; + + // hardware resources + unsigned int pBA0phys, pBA1phys; + char *pBA0, *pBA1; + unsigned int irq; + int endofbuffer; + + // mixer registers + struct { + unsigned short vol[10]; + unsigned int recsrc; + unsigned int modcnt; + unsigned short micpreamp; + } mix; + + // wave stuff // Note that play & record formats must be the same *wb. + unsigned fmt; + unsigned channels; + unsigned rate; + unsigned char clkdiv; + unsigned ena; + + spinlock_t lock; + struct semaphore open_sem; + mode_t open_mode; + wait_queue_head_t open_wait; + + struct dmabuf { + void *rawbuf; // Physical address of + dma_addr_t dmaaddr; + unsigned buforder; // Log base 2 of 'rawbuf' size in bytes.. + unsigned numfrag; // # of 'fragments' in the buffer. + unsigned fragshift; // Log base 2 of fragment size. + unsigned hwptr, swptr; + unsigned total_bytes; // # bytes process since open. + unsigned blocks; // last returned blocks value GETOPTR + int count; + unsigned error; // over/underrun + wait_queue_head_t wait; + // redundant, but makes calculations easier + unsigned fragsize; // 2**fragshift.. + unsigned dmasize; // 2**buforder. + unsigned fragsamples; + // OSS stuff + unsigned mapped:1; // Buffer mapped in cs4281_mmap()? + unsigned ready:1; // prog_dmabuf_dac()/adc() successful? + unsigned endcleared:1; + unsigned ossfragshift; + int ossmaxfrags; + unsigned subdivision; + } dma_dac, dma_adc; + + // midi stuff + struct { + unsigned ird, iwr, icnt; + unsigned ord, owr, ocnt; + wait_queue_head_t iwait; + wait_queue_head_t owait; + struct timer_list timer; + unsigned char ibuf[MIDIINBUF]; + unsigned char obuf[MIDIOUTBUF]; + } midi; + +}; + + +struct cs4281_state *devs = NULL; +// --------------------------------------------------------------------- +// +// Hardware Interfaces For the CS4281 +// + + +//****************************************************************************** +// "delayus()-- Delay for the specified # of microseconds. +//****************************************************************************** +static void delayus(u32 delay) +{ + u32 j; + if(delay > 9999) + { + j = (delay * HZ)/1000000; /* calculate delay in jiffies */ + if(j<1) + j=1; /* minimum one jiffy. */ + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(j); + } + else + udelay(delay); + return; +} + + +//****************************************************************************** +// "cs4281_read_ac97" -- Reads a word from the specified location in the +// CS4281's address space(based on the BA0 register). +// +// 1. Write ACCAD = Command Address Register = 46Ch for AC97 register address +// 2. Write ACCDA = Command Data Register = 470h for data to write to AC97 register, +// 0h for reads. +// 3. Write ACCTL = Control Register = 460h for initiating the write +// 4. Read ACCTL = 460h, DCV should be reset by now and 460h = 17h +// 5. if DCV not cleared, break and return error +// 6. Read ACSTS = Status Register = 464h, check VSTS bit +//**************************************************************************** +static int cs4281_read_ac97(struct cs4281_state *card, u32 offset, u32 *value) +{ + u32 count, status; + + // Make sure that there is not data sitting + // around from a previous uncompleted access. + // ACSDA = Status Data Register = 47Ch + status = readl(card->pBA0+BA0_ACSDA); + + // Setup the AC97 control registers on the CS4281 to send the + // appropriate command to the AC97 to perform the read. + // ACCAD = Command Address Register = 46Ch + // ACCDA = Command Data Register = 470h + // ACCTL = Control Register = 460h + // bit DCV - will clear when process completed + // bit CRW - Read command + // bit VFRM - valid frame enabled + // bit ESYN - ASYNC generation enabled + + // Get the actual AC97 register from the offset + writel(offset - BA0_AC97_RESET, card->pBA0+BA0_ACCAD); + writel(0, card->pBA0+BA0_ACCDA); + writel(ACCTL_DCV | ACCTL_CRW | ACCTL_VFRM | ACCTL_ESYN, card->pBA0+BA0_ACCTL); + + // Wait for the read to occur. + for(count = 0; count < 10; count++) + { + // First, we want to wait for a short time. + udelay(25); + + // Now, check to see if the read has completed. + // ACCTL = 460h, DCV should be reset by now and 460h = 17h + if( !(readl(card->pBA0+BA0_ACCTL) & ACCTL_DCV)) + break; + } + + // Make sure the read completed. + if(readl(card->pBA0+BA0_ACCTL) & ACCTL_DCV) + return 1; + + // Wait for the valid status bit to go active. + for(count = 0; count < 10; count++) + { + // Read the AC97 status register. + // ACSTS = Status Register = 464h + status = readl(card->pBA0+BA0_ACSTS); + + // See if we have valid status. + // VSTS - Valid Status + if(status & ACSTS_VSTS) + break; + // Wait for a short while. + udelay(25); + } + + // Make sure we got valid status. + if(!(status & ACSTS_VSTS)) + return 1; + + // Read the data returned from the AC97 register. + // ACSDA = Status Data Register = 474h + *value = readl(card->pBA0+BA0_ACSDA); + + // Success. + return(0); +} + + +//**************************************************************************** +// +// "cs4281_write_ac97()"-- writes a word to the specified location in the +// CS461x's address space (based on the part's base address zero register). +// +// 1. Write ACCAD = Command Address Register = 46Ch for AC97 register address +// 2. Write ACCDA = Command Data Register = 470h for data to write to AC97 reg. +// 3. Write ACCTL = Control Register = 460h for initiating the write +// 4. Read ACCTL = 460h, DCV should be reset by now and 460h = 07h +// 5. if DCV not cleared, break and return error +// +//**************************************************************************** +static int cs4281_write_ac97(struct cs4281_state *card, u32 offset, u32 value) +{ + u32 count, status; + + CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs4281: cs_4281_write_ac97()+ \n") ); + + // Setup the AC97 control registers on the CS4281 to send the + // appropriate command to the AC97 to perform the read. + // ACCAD = Command Address Register = 46Ch + // ACCDA = Command Data Register = 470h + // ACCTL = Control Register = 460h + // set DCV - will clear when process completed + // reset CRW - Write command + // set VFRM - valid frame enabled + // set ESYN - ASYNC generation enabled + // set RSTN - ARST# inactive, AC97 codec not reset + + // Get the actual AC97 register from the offset + + writel(offset - BA0_AC97_RESET, card->pBA0+BA0_ACCAD); + writel(value, card->pBA0+BA0_ACCDA); + writel(ACCTL_DCV | ACCTL_VFRM | ACCTL_ESYN, card->pBA0+BA0_ACCTL); + + // Wait for the write to occur. + for(count = 0; count < 10; count++) + { + // First, we want to wait for a short time. + udelay(25); + // Now, check to see if the write has completed. + // ACCTL = 460h, DCV should be reset by now and 460h = 07h + status = readl(card->pBA0+BA0_ACCTL); + if(!(status & ACCTL_DCV)) + break; + } + + // Make sure the write completed. + if(status & ACCTL_DCV) + { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO + "cs4281: cs_4281_write_ac97()- unable to write. ACCTL_DCV active\n") ); + return 1; + } + CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs4281: cs_4281_write_ac97()- 0\n") ); + // Success. + return 0; +} + + +//****************************************************************************** +// "Init4281()" -- Bring up the part. +//****************************************************************************** +static int cs4281_hw_init(struct cs4281_state *card) +{ + u32 ac97_slotid; + u32 temp1, temp2; + + CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs4281: cs4281_hw_init()+ \n") ); + //***************************************7 + // Set up the Sound System Configuration + //*************************************** + + // Set the 'Configuration Write Protect' register + // to 4281h. Allows vendor-defined configuration + // space between 0e4h and 0ffh to be written. + + writel(0x4281, card->pBA0+BA0_CWPR); // (3e0h) + + // (0), Blast the clock control register to zero so that the + // PLL starts out in a known state, and blast the master serial + // port control register to zero so that the serial ports also + // start out in a known state. + + writel(0, card->pBA0+BA0_CLKCR1); // (400h) + writel(0, card->pBA0+BA0_SERMC); // (420h) + + + // (1), Make ESYN go to zero to turn off + // the Sync pulse on the AC97 link. + + writel(0, card->pBA0+BA0_ACCTL); + udelay(50); + + + // (2) Drive the ARST# pin low for a minimum of 1uS (as defined in + // the AC97 spec) and then drive it high. This is done for non + // AC97 modes since there might be logic external to the CS461x + // that uses the ARST# line for a reset. + + writel(0, card->pBA0+BA0_SPMC); // (3ech) + udelay(100); + writel(SPMC_RSTN, card->pBA0+BA0_SPMC); + delayus(50000); // Wait 50 ms for ABITCLK to become stable. + + // (3) Turn on the Sound System Clocks. + writel(CLKCR1_PLLP, card->pBA0+BA0_CLKCR1); // (400h) + delayus(50000); // Wait for the PLL to stabilize. + // Turn on clocking of the core (CLKCR1(400h) = 0x00000030) + writel(CLKCR1_PLLP | CLKCR1_SWCE, card->pBA0+BA0_CLKCR1); + + // (4) Power on everything for now.. + writel(0x7E, card->pBA0 + BA0_SSPM); // (740h) + + // (5) Wait for clock stabilization. + for(temp1=0; temp1<1000; temp1++) + { + udelay(1000); + if(readl(card->pBA0+BA0_CLKCR1) & CLKCR1_DLLRDY) + break; + } + if(!(readl(card->pBA0+BA0_CLKCR1) & CLKCR1_DLLRDY)) + { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR "cs4281: DLLRDY failed!\n") ); + return -EIO; + } + + // (6) Enable ASYNC generation. + writel(ACCTL_ESYN, card->pBA0+BA0_ACCTL); // (460h) + + // Now wait 'for a short while' to allow the AC97 + // part to start generating bit clock. (so we don't + // Try to start the PLL without an input clock.) + delayus(50000); + + // Set the serial port timing configuration, so that the + // clock control circuit gets its clock from the right place. + writel(SERMC_PTC_AC97, card->pBA0+BA0_SERMC); // (420h)=2. + + // (7) Wait for the codec ready signal from the AC97 codec. + + for(temp1=0; temp1<1000; temp1++) + { + // Delay a mil to let things settle out and + // to prevent retrying the read too quickly. + udelay(1000); + if( readl(card->pBA0+BA0_ACSTS) & ACSTS_CRDY ) // If ready, (464h) + break; // exit the 'for' loop. + } + if( !(readl(card->pBA0+BA0_ACSTS) & ACSTS_CRDY) ) // If never came ready, + { + CS_DBGOUT(CS_FUNCTION, 2, + printk(KERN_ERR "cs4281: ACSTS never came ready!\n") ); + return -EIO; // exit initialization. + } + + // (8) Assert the 'valid frame' signal so we can + // begin sending commands to the AC97 codec. + writel(ACCTL_VFRM | ACCTL_ESYN, card->pBA0+BA0_ACCTL); // (460h) + + // (9), Wait until CODEC calibration is finished. + // Print an error message if it doesn't. + for(temp1 = 0; temp1 < 1000; temp1++) + { + delayus(10000); + // Read the AC97 Powerdown Control/Status Register. + cs4281_read_ac97(card, BA0_AC97_POWERDOWN, &temp2); + if( (temp2 & 0x0000000F) == 0x0000000F ) + break; + } + if ( (temp2 & 0x0000000F) != 0x0000000F ) + { + CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_ERR + "cs4281: Codec failed to calibrate. Status = %.8x.\n", temp2) ); + return -EIO; + } + + // (10), Set the serial port timing configuration, so that the + // clock control circuit gets its clock from the right place. + writel(SERMC_PTC_AC97, card->pBA0+BA0_SERMC); // (420h)=2. + + + // (11) Wait until we've sampled input slots 3 & 4 as valid, meaning + // that the codec is pumping ADC data across the AC link. + for(temp1=0; temp1<1000; temp1++) + { + // Delay a mil to let things settle out and + // to prevent retrying the read too quickly. + delayus(1000); //(test) + + // Read the input slot valid register; See + // if input slots 3 and 4 are valid yet. + if( (readl(card->pBA0+BA0_ACISV) & (ACISV_ISV3 | ACISV_ISV4) ) + == (ACISV_ISV3 | ACISV_ISV4)) + break; // Exit the 'for' if slots are valid. + } + // If we never got valid data, exit initialization. + if( (readl(card->pBA0+BA0_ACISV) & (ACISV_ISV3 | ACISV_ISV4) ) + != (ACISV_ISV3 | ACISV_ISV4)) + { + CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_ERR "cs4281: Never got valid data!\n")); + return -EIO; // If no valid data, exit initialization. + } + + // (12), Start digital data transfer of audio data to the codec. + writel(ACOSV_SLV3 | ACOSV_SLV4, card->pBA0+BA0_ACOSV); // (468h) + + + //************************************** + // Unmute the Master and Alternate + // (headphone) volumes. Set to max. + //************************************** + cs4281_write_ac97(card,BA0_AC97_HEADPHONE_VOLUME, 0); + cs4281_write_ac97(card,BA0_AC97_MASTER_VOLUME, 0); + + //****************************************** + // Power on the DAC(AddDACUser()from main()) + //****************************************** + cs4281_read_ac97(card,BA0_AC97_POWERDOWN, &temp1); + cs4281_write_ac97(card,BA0_AC97_POWERDOWN, temp1 &= 0xfdff); + + // Wait until we sample a DAC ready state. + for(temp2=0; temp2<32; temp2++) + { + // Let's wait a mil to let things settle. + delayus(1000); + // Read the current state of the power control reg. + cs4281_read_ac97(card, BA0_AC97_POWERDOWN, &temp1); + // If the DAC ready state bit is set, stop waiting. + if(temp1 & 0x2) + break; + } + + //****************************************** + // Power on the ADC(AddADCUser()from main()) + //****************************************** + cs4281_read_ac97(card, BA0_AC97_POWERDOWN, &temp1); + cs4281_write_ac97(card, BA0_AC97_POWERDOWN, temp1 &= 0xfeff); + + // Wait until we sample ADC ready state. + for(temp2=0; temp2<32; temp2++) + { + // Let's wait a mil to let things settle. + delayus(1000); + // Read the current state of the power control reg. + cs4281_read_ac97(card, BA0_AC97_POWERDOWN, &temp1); + // If the ADC ready state bit is set, stop waiting. + if(temp1 & 0x1) + break; + } + // Set up 4281 Register contents that + // don't change for boot duration. + + // For playback, we map AC97 slot 3 and 4(Left + // & Right PCM playback) to DMA Channel 0. + // Set the fifo to be 15 bytes at offset zero. + + ac97_slotid = 0x01000f00; // FCR0.RS[4:0]=1(=>slot4, right PCM playback). + // FCR0.LS[4:0]=0(=>slot3, left PCM playback). + // FCR0.SZ[6-0]=15; FCR0.OF[6-0]=0. + writel(ac97_slotid, card->pBA0 + BA0_FCR0); // (180h) + writel(ac97_slotid | FCRn_FEN, card->pBA0 + BA0_FCR0); // Turn on FIFO Enable. + + // For capture, we map AC97 slot 10 and 11(Left + // and Right PCM Record) to DMA Channel 1. + // Set the fifo to be 15 bytes at offset sixteen. + ac97_slotid = 0x0B0A0f10; // FCR1.RS[4:0]=11(=>slot11, right PCM record). + // FCR1.LS[4:0]=10(=>slot10, left PCM record). + // FCR1.SZ[6-0]=15; FCR1.OF[6-0]=16. + writel(ac97_slotid | FCRn_PSH, card->pBA0 + BA0_FCR1); // (184h) + writel(ac97_slotid | FCRn_FEN, card->pBA0 + BA0_FCR1); // Turn on FIFO Enable. + + // Map the Playback SRC to the same AC97 slots(3 & 4-- + // --Playback left & right)as DMA channel 0. + // Map the record SRC to the same AC97 slots(10 & 11-- + // -- Record left & right) as DMA channel 1. + + ac97_slotid = 0x0b0a0100; // SCRSA.PRSS[4:0]=1(=>slot4, right PCM playback). + // SCRSA.PLSS[4:0]=0(=>slot3, left PCM playback). + // SCRSA.CRSS[4:0]=11(=>slot11, right PCM record) + // SCRSA.CLSS[4:0]=10(=>slot10, left PCM record). + writel(ac97_slotid, card->pBA0 + BA0_SRCSA); // (75ch) + + // Set 'Half Terminal Count Interrupt Enable' and 'Terminal + // Count Interrupt Enable' in DMA Control Registers 0 & 1. + // Set 'MSK' flag to 1 to keep the DMA engines paused. + temp1 = (DCRn_HTCIE | DCRn_TCIE | DCRn_MSK); // (00030001h) + writel(temp1, card->pBA0 + BA0_DCR0); // (154h + writel(temp1, card->pBA0 + BA0_DCR1); // (15ch) + + // Set 'Auto-Initialize Control' to 'enabled'; For playback, + // set 'Transfer Type Control'(TR[1:0]) to 'read transfer', + // for record, set Transfer Type Control to 'write transfer'. + // All other bits set to zero; Some will be changed @ transfer start. + temp1 = (DMRn_DMA | DMRn_AUTO | DMRn_TR_READ); // (20000018h) + writel(temp1, card->pBA0 + BA0_DMR0); // (150h) + temp1 = (DMRn_DMA | DMRn_AUTO | DMRn_TR_WRITE); // (20000014h) + writel(temp1, card->pBA0 + BA0_DMR1); // (158h) + + // Enable DMA interrupts generally, and + // DMA0 & DMA1 interrupts specifically. + temp1 = readl(card->pBA0 + BA0_HIMR) & 0xfffbfcff; + writel(temp1, card->pBA0+BA0_HIMR); + + CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs4281: cs4281_hw_init()- 0\n") ); + return 0; +} + + +//****************************************************************************** +// "cs4281_play_rate()" -- +//****************************************************************************** +static void cs4281_play_rate(struct cs4281_state *card, u32 playrate) +{ + u32 DACSRvalue = 1; + + // Based on the sample rate, program the DACSR register. + if(playrate == 8000) + DACSRvalue = 5; + if(playrate == 11025) + DACSRvalue = 4; + else if(playrate == 22050) + DACSRvalue = 2; + else if(playrate == 44100) + DACSRvalue = 1; + else if((playrate <= 48000) && (playrate >= 6023)) + DACSRvalue = 24576000/(playrate*16); + else if(playrate < 6023) + // Not allowed by open. + return; + else if(playrate > 48000) + // Not allowed by open. + return; + CS_DBGOUT(CS_WAVE_WRITE | CS_PARMS, 2, printk(KERN_INFO + "cs4281: cs4281_play_rate(): DACSRvalue=0x%.8x playrate=%d\n", + DACSRvalue,playrate)); + // Write the 'sample rate select code' + // to the 'DAC Sample Rate' register. + writel(DACSRvalue, card->pBA0 + BA0_DACSR); // (744h) +} + +//****************************************************************************** +// "cs4281_record_rate()" -- Initialize the record sample rate converter. +//****************************************************************************** +static void cs4281_record_rate(struct cs4281_state *card, u32 outrate) +{ + u32 ADCSRvalue = 1; + + // + // Based on the sample rate, program the ADCSR register + // + if(outrate == 8000) + ADCSRvalue = 5; + if(outrate == 11025) + ADCSRvalue = 4; + else if(outrate == 22050) + ADCSRvalue = 2; + else if(outrate == 44100) + ADCSRvalue = 1; + else if((outrate <= 48000) && (outrate >= 6023)) + ADCSRvalue = 24576000/(outrate*16); + else if(outrate < 6023) + { + // Not allowed by open. + return; + } + else if(outrate > 48000) + { + // Not allowed by open. + return; + } + CS_DBGOUT(CS_WAVE_READ | CS_PARMS, 2, printk(KERN_INFO + "cs4281: cs4281_record_rate(): ADCSRvalue=0x%.8x outrate=%d\n", + ADCSRvalue,outrate) ); + // Write the 'sample rate select code + // to the 'ADC Sample Rate' register. + writel(ADCSRvalue, card->pBA0 + BA0_ADCSR); // (748h) +} + + + +static void stop_dac(struct cs4281_state *s) +{ + unsigned long flags; + unsigned temp1; + + CS_DBGOUT(CS_WAVE_WRITE, 3, printk(KERN_INFO "cs4281: stop_dac():\n") ); + spin_lock_irqsave(&s->lock, flags); + s->ena &= ~FMODE_WRITE; + temp1 = readl(s->pBA0+ BA0_DCR0) | DCRn_MSK; + writel(temp1, s->pBA0+BA0_DCR0); + + spin_unlock_irqrestore(&s->lock, flags); +} + + +static void start_dac(struct cs4281_state *s) +{ + unsigned long flags; + unsigned temp1; + + CS_DBGOUT(CS_WAVE_WRITE, 3, printk(KERN_INFO "cs4281: start_dac():\n") ); + spin_lock_irqsave(&s->lock, flags); + if (!(s->ena & FMODE_WRITE) && (s->dma_dac.mapped || + s->dma_dac.count > 0) && s->dma_dac.ready) { + s->ena |= FMODE_WRITE; + temp1 = readl(s->pBA0+BA0_DCR0) & ~DCRn_MSK; // Clear DMA0 channel mask. + writel(temp1, s->pBA0+BA0_DCR0); // Start DMA'ing. + writel(HICR_IEV | HICR_CHGM, s->pBA0+BA0_HICR); // Enable interrupts. + + writel(7, s->pBA0+BA0_PPRVC); + writel(7, s->pBA0+BA0_PPLVC); + + } + spin_unlock_irqrestore(&s->lock, flags); +} + + +static void stop_adc(struct cs4281_state *s) +{ + unsigned long flags; + unsigned temp1; + + CS_DBGOUT(CS_WAVE_READ, 3, printk(KERN_INFO "cs4281: stop_adc():\n") ); + + spin_lock_irqsave(&s->lock, flags); + s->ena &= ~FMODE_READ; + temp1 = readl(s->pBA0+ BA0_DCR1) | DCRn_MSK; + writel(temp1, s->pBA0+BA0_DCR1); + spin_unlock_irqrestore(&s->lock, flags); +} + + +static void start_adc(struct cs4281_state *s) +{ + unsigned long flags; + unsigned temp1; + + CS_DBGOUT(CS_WAVE_WRITE, 3, printk(KERN_INFO "cs4281: start_adc():\n") ); + + spin_lock_irqsave(&s->lock, flags); + if (!(s->ena & FMODE_READ) && (s->dma_adc.mapped + || s->dma_adc.count <= + (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize)) + && s->dma_adc.ready) + { + s->ena |= FMODE_READ; + temp1 = readl(s->pBA0+BA0_DCR1) & ~ DCRn_MSK; // Clear DMA1 channel mask bit. + writel(temp1, s->pBA0+BA0_DCR1); // Start recording + writel(HICR_IEV | HICR_CHGM, s->pBA0+BA0_HICR); // Enable interrupts. + } + spin_unlock_irqrestore(&s->lock, flags); + +} + + +// --------------------------------------------------------------------- +#define DMABUF_DEFAULTORDER (15-PAGE_SHIFT) // == 3(for PC), = log base 2( buff sz = 32k). +#define DMABUF_MINORDER 1 // ==> min buffer size = 8K. + + +extern void dealloc_dmabuf(struct cs4281_state *s, struct dmabuf *db) +{ + struct page *map, *mapend; + + if (db->rawbuf) { + // Undo prog_dmabuf()'s marking the pages as reserved + mapend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1); + for (map = virt_to_page(db->rawbuf); map <= mapend; map++) + clear_bit(PG_reserved, &map->flags); + pci_free_consistent(s->pcidev,PAGE_SIZE<buforder, + db->rawbuf,db->dmaaddr); + } + db->rawbuf = NULL; + db->mapped = db->ready = 0; +} + +static int prog_dmabuf(struct cs4281_state *s, struct dmabuf *db) +{ + int order; + unsigned bytespersec, temp1; + unsigned bufs, sample_shift = 0; + struct page *map, *mapend; + + db->hwptr = db->swptr = db->total_bytes = db->count = + db->error = db->endcleared = db->blocks = 0; + if (!db->rawbuf) { + db->ready = db->mapped = 0; + for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) + if ((db->rawbuf = (void *)pci_alloc_consistent( + s->pcidev, PAGE_SIZE << order, &db->dmaaddr))) + break; + if (!db->rawbuf) + { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR + "cs4281: prog_dmabuf(): unable to allocate rawbuf\n") ); + return -ENOMEM; + } + db->buforder = order; + // Now mark the pages as reserved; otherwise the + // remap_page_range() in cs4281_mmap doesn't work. + // 1. get index to last page in mem_map array for rawbuf. + mapend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1); + + // 2. mark each physical page in range as 'reserved'. + for (map = virt_to_page(db->rawbuf); map <= mapend; map++) + set_bit(PG_reserved, &map->flags); + } + if (s->fmt & (AFMT_S16_LE | AFMT_U16_LE)) + sample_shift++; + if (s->channels > 1) + sample_shift++; + bytespersec = s->rate << sample_shift; + bufs = PAGE_SIZE << db->buforder; + + +#define INTERRUPT_RATE_MS 100 // Interrupt rate in milliseconds. + db->numfrag = 2; + temp1 = bytespersec/(1000/INTERRUPT_RATE_MS); // Nominal frag size(bytes/interrupt) + db->fragshift = 8; // Min 256 bytes. + while( 1 << db->fragshift < temp1) // Calc power of 2 frag size. + db->fragshift +=1; + db->fragsize = 1 << db->fragshift; + db->dmasize = db->fragsize * 2; + + // If the calculated size is larger than the allocated + // buffer, divide the allocated buffer into 2 fragments. + if(db->dmasize > bufs) { + db->numfrag = 2; // Two fragments. + db->fragsize = bufs >> 1; // Each 1/2 the alloc'ed buffer. + db->fragsamples = db->fragsize >> sample_shift; // # samples/fragment. + db->dmasize = bufs; // Use all the alloc'ed buffer. + + db->fragshift = 0; // Calculate 'fragshift'. + temp1 = db->fragsize; // update_ptr() uses it + while( (temp1 >>=1) > 1) // to calc 'total-bytes' + db->fragshift +=1; // returned in DSP_GETI/OPTR. + } + CS_DBGOUT(CS_PARMS, 3, printk(KERN_INFO + "cs4281: prog_dmabuf(): numfrag=%d fragsize=%d fragsamples=%d fragshift=%d\n", + db->numfrag,db->fragsize,db->fragsamples,db->fragshift) ); + return 0; +} + + +static int prog_dmabuf_adc(struct cs4281_state *s) +{ + unsigned long va; + unsigned count; + int c; + stop_adc(s); + if ((c = prog_dmabuf(s, &s->dma_adc))) + return c; + + va = virt_to_bus(s->dma_adc.rawbuf); + + count = s->dma_adc.dmasize; + + if(s->fmt & (AFMT_S16_LE | AFMT_U16_LE | AFMT_S16_BE | AFMT_U16_BE)) + count /= 2; // 16-bit. + + if(s->channels > 1) + count /= 2; // Assume stereo. + + CS_DBGOUT(CS_WAVE_READ, 3, printk(KERN_INFO + "cs4281: prog_dmabuf_adc(): count=%d va=0x%.8x\n", count,(unsigned)va) ); + + writel(va, s->pBA0+BA0_DBA1); // Set buffer start address. + writel(count-1, s->pBA0+BA0_DBC1); // Set count. + s->dma_adc.ready = 1; + return 0; +} + + +static int prog_dmabuf_dac(struct cs4281_state *s) +{ + unsigned long va; + unsigned count; + int c; + stop_dac(s); + if ((c = prog_dmabuf(s, &s->dma_dac))) + return c; + memset(s->dma_dac.rawbuf, (s->fmt & (AFMT_U8 | AFMT_U16_LE)) + ? 0x80 : 0, s->dma_dac.dmasize); + + va = virt_to_bus(s->dma_dac.rawbuf); + + count = s->dma_dac.dmasize; + if(s->fmt & (AFMT_S16_LE | AFMT_U16_LE | AFMT_S16_BE | AFMT_U16_BE)) + count /= 2; // 16-bit. + + if(s->channels > 1) + count /= 2; // Assume stereo. + + writel(va, s->pBA0+BA0_DBA0); // Set buffer start address. + writel(count-1, s->pBA0+BA0_DBC0); // Set count. + + CS_DBGOUT(CS_WAVE_WRITE, 3, printk(KERN_INFO + "cs4281: prog_dmabuf_dac(): count=%d va=0x%.8x\n", count,(unsigned)va) ); + + s->dma_dac.ready = 1; + return 0; +} + + +static void clear_advance(void *buf, unsigned bsize, unsigned bptr, unsigned len, unsigned char c) +{ + if (bptr + len > bsize) { + unsigned x = bsize - bptr; + memset(((char *)buf) + bptr, c, x); + bptr = 0; + len -= x; + } + CS_DBGOUT(CS_WAVE_WRITE, 4, printk(KERN_INFO + "cs4281: clear_advance(): memset %d at 0x%.8x for %d size \n", + (unsigned)c,(unsigned)((char *)buf) + bptr, len) ); + memset(((char *)buf) + bptr, c, len); +} + + + +// call with spinlock held! +static void cs4281_update_ptr(struct cs4281_state *s) +{ + int diff; + unsigned hwptr, va, temp1; + + // update ADC pointer + if (s->ena & FMODE_READ) { + hwptr = readl(s->pBA0+BA0_DCA1); // Read capture DMA address. + va = virt_to_bus(s->dma_adc.rawbuf); + hwptr -= (unsigned)va; + diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize; + s->dma_adc.hwptr = hwptr; + s->dma_adc.total_bytes += diff; + s->dma_adc.count += diff; + if (s->dma_adc.mapped) { + if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) + wake_up(&s->dma_adc.wait); + } else { + if (s->dma_adc.count > 0) + wake_up(&s->dma_adc.wait); + } + CS_DBGOUT(CS_PARMS, 8, printk(KERN_INFO + "cs4281: cs4281_update_ptr(): s=0x%.8x hwptr=%d total_bytes=%d count=%d \n", + (unsigned)s,s->dma_adc.hwptr,s->dma_adc.total_bytes,s->dma_adc.count) ); + } + // update DAC pointer + // + // check for end of buffer, means that we are going to wait for another interrupt + // to allow silence to fill the fifos on the part, to keep pops down to a minimum. + // + if ( (s->ena & FMODE_WRITE) && (!s->endofbuffer) ) + { + hwptr = readl(s->pBA0+BA0_DCA0); // Read play DMA address. + va = virt_to_bus(s->dma_dac.rawbuf); + hwptr -= (unsigned)va; + diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize; + s->dma_dac.hwptr = hwptr; + s->dma_dac.total_bytes += diff; + if (s->dma_dac.mapped) { + s->dma_dac.count += diff; + if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) + wake_up(&s->dma_dac.wait); + } else { + s->dma_dac.count -= diff; + if (s->dma_dac.count <= 0) { + s->ena &= ~FMODE_WRITE; + temp1 = readl(s->pBA0+BA0_DCR0); + // + // fill with silence, and wait on turning off the DAC until interrupt routine. + // wait on "Poke(pBA0+BA0_DCR0, temp1 | DCRn_MSK); // Stop Play DMA" + // + CS_DBGOUT(CS_WAVE_WRITE, 6, printk(KERN_INFO + "cs4281: cs4281_update_ptr(): memset %d at 0x%.8x for %d size \n", + (unsigned)(s->fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0x80 : 0, + (unsigned)s->dma_dac.rawbuf, s->dma_dac.dmasize) ); + memset(s->dma_dac.rawbuf, (s->fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0x80 : 0, + s->dma_dac.dmasize); + s->endofbuffer = 1; + } else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize + && !s->dma_dac.endcleared) { + clear_advance(s->dma_dac.rawbuf, + s->dma_dac.dmasize, s->dma_dac.swptr, + s->dma_dac.fragsize, + (s->fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0x80 : 0); + s->dma_dac.endcleared = 1; + } + if (s->dma_dac.count < (signed)s->dma_dac.dmasize) + wake_up(&s->dma_dac.wait); + } + CS_DBGOUT(CS_PARMS, 8, printk(KERN_INFO + "cs4281: cs4281_update_ptr(): s=0x%.8x hwptr=%d total_bytes=%d count=%d \n", + (unsigned)s,s->dma_dac.hwptr,s->dma_dac.total_bytes,s->dma_dac.count) ); + } +} + + +// --------------------------------------------------------------------- + +static void prog_codec(struct cs4281_state *s) +{ + unsigned long flags; + unsigned temp1, format; + + CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO "cs4281: prog_codec()+ \n") ); + + spin_lock_irqsave(&s->lock, flags); + temp1 = readl(s->pBA0+BA0_DCR0); + writel(temp1 | DCRn_MSK, s->pBA0+BA0_DCR0); // Stop play DMA, if active. + temp1 = readl(s->pBA0+BA0_DCR1); + writel(temp1 | DCRn_MSK, s->pBA0+BA0_DCR1); // Stop capture DMA, if active. + + // program sampling rates + // Note, for CS4281, capture & play rates can be set independently. + cs4281_record_rate(s, s->rate); + + // program ADC parameters + format = DMRn_DMA | DMRn_AUTO | DMRn_TR_WRITE; + if(s->fmt & (AFMT_S16_LE | AFMT_U16_LE | AFMT_S16_BE | AFMT_U16_BE)) { // 16-bit + if(s->fmt & (AFMT_S16_BE | AFMT_U16_BE)) // Big-endian? + format |= DMRn_BEND; + if(s->fmt & (AFMT_U16_LE | AFMT_U16_BE)) + format |= DMRn_USIGN; // Unsigned. + } + else + format |= DMRn_SIZE8 | DMRn_USIGN; // 8-bit, unsigned + if(s->channels < 2) + format |= DMRn_MONO; + + writel(format, s->pBA0+BA0_DMR1); + + + // program DAC parameters + format = DMRn_DMA | DMRn_AUTO | DMRn_TR_READ; + if(s->fmt & (AFMT_S16_LE | AFMT_U16_LE | AFMT_S16_BE | AFMT_U16_BE)) { // 16-bit + if(s->fmt & (AFMT_S16_BE | AFMT_U16_BE)) + format |= DMRn_BEND; // Big Endian. + if(s->fmt & (AFMT_U16_LE | AFMT_U16_BE)) + format |= DMRn_USIGN; // Unsigned. + } + else + format |= DMRn_SIZE8 | DMRn_USIGN; // 8-bit, unsigned + + if(s->channels < 2) + format |= DMRn_MONO; + + writel(format, s->pBA0+BA0_DMR0); + + CS_DBGOUT(CS_PARMS, 2, printk(KERN_INFO + "cs4281: prog_codec(): format=0x%.8x rate=%d\n", format,s->rate) ); + + cs4281_play_rate(s, s->rate); + + s->ena = 0; // Neither writing or reading. + spin_unlock_irqrestore(&s->lock, flags); +} + + +// --------------------------------------------------------------------- + +static const char invalid_magic[] = KERN_CRIT "cs4281: invalid magic value\n"; + +#define VALIDATE_STATE(s) \ +({ \ + if (!(s) || (s)->magic != CS4281_MAGIC) { \ + printk(invalid_magic); \ + return -ENXIO; \ + } \ +}) + +// --------------------------------------------------------------------- + + +static int mixer_ioctl(struct cs4281_state *s, unsigned int cmd, unsigned long arg) +{ + // Index to mixer_src[] is value of AC97 Input Mux Select Reg. + // Value of array member is recording source Device ID Mask. + static const unsigned int mixer_src[8] = { + SOUND_MASK_MIC, SOUND_MASK_CD, 0, SOUND_MASK_LINE1, + SOUND_MASK_LINE, SOUND_MASK_VOLUME, 0, 0 + }; + + // Index of mixtable1[] member is Device ID + // and must be <= SOUND_MIXER_NRDEVICES. + // Value of array member is index into s->mix.vol[] + static const unsigned char mixtable1[SOUND_MIXER_NRDEVICES] = { + [SOUND_MIXER_PCM] = 1, // voice + [SOUND_MIXER_LINE1] = 2, // AUX + [SOUND_MIXER_CD] = 3, // CD + [SOUND_MIXER_LINE] = 4, // Line + [SOUND_MIXER_SYNTH] = 5, // FM + [SOUND_MIXER_MIC] = 6, // Mic + [SOUND_MIXER_SPEAKER] = 7, // Speaker + [SOUND_MIXER_RECLEV] = 8, // Recording level + [SOUND_MIXER_VOLUME] = 9 // Master Volume + }; + + + static const unsigned mixreg[] = { + BA0_AC97_PCM_OUT_VOLUME, + BA0_AC97_AUX_VOLUME, + BA0_AC97_CD_VOLUME, + BA0_AC97_LINE_IN_VOLUME + }; + unsigned char l, r, rl, rr, vidx; + unsigned char attentbl[11] = {63,42,26,17,14,11,8,6,4,2,0}; + unsigned temp1; + int i, val; + + VALIDATE_STATE(s); + + if (cmd == SOUND_MIXER_PRIVATE1) { + // enable/disable/query mixer preamp + if (get_user(val, (int *)arg)) + return -EFAULT; + if (val != -1) { + cs4281_read_ac97(s, BA0_AC97_MIC_VOLUME, &temp1); + temp1 = val ? (temp1 | 0x40) : (temp1 & 0xffbf); + cs4281_write_ac97(s, BA0_AC97_MIC_VOLUME, temp1); + } + cs4281_read_ac97(s, BA0_AC97_MIC_VOLUME, &temp1); + val = (temp1 & 0x40) ? 1 : 0; + return put_user(val, (int *)arg); + } + if (cmd == SOUND_MIXER_PRIVATE2) { + // enable/disable/query spatializer + if (get_user(val, (int *)arg)) + return -EFAULT; + if (val != -1) { + temp1 = (val & 0x3f) >> 2; + cs4281_write_ac97(s, BA0_AC97_3D_CONTROL, temp1); + cs4281_read_ac97(s, BA0_AC97_GENERAL_PURPOSE, &temp1); + cs4281_write_ac97(s, BA0_AC97_GENERAL_PURPOSE,temp1 | 0x2000); + } + cs4281_read_ac97(s, BA0_AC97_3D_CONTROL, &temp1); + return put_user((temp1 << 2) | 3, (int *)arg); + } + if (cmd == SOUND_MIXER_INFO) { + mixer_info info; + strncpy(info.id, "CS4281", sizeof(info.id)); + strncpy(info.name, "Crystal CS4281", sizeof(info.name)); + info.modify_counter = s->mix.modcnt; + if (copy_to_user((void *)arg, &info, sizeof(info))) + return -EFAULT; + return 0; + } + if (cmd == SOUND_OLD_MIXER_INFO) { + _old_mixer_info info; + strncpy(info.id, "CS4281", sizeof(info.id)); + strncpy(info.name, "Crystal CS4281", sizeof(info.name)); + if (copy_to_user((void *)arg, &info, sizeof(info))) + return -EFAULT; + return 0; + } + if (cmd == OSS_GETVERSION) + return put_user(SOUND_VERSION, (int *)arg); + + if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int)) + return -EINVAL; + + // If ioctl has only the IOC_READ bit(bit 31) + // on, process the only-read commands. + if (_IOC_DIR(cmd) == _IOC_READ) { + switch (_IOC_NR(cmd)) { + case SOUND_MIXER_RECSRC: // Arg contains a bit for each recording source + cs4281_read_ac97(s, BA0_AC97_RECORD_SELECT, &temp1); + return put_user(mixer_src[temp1 & 7], (int *)arg); + + case SOUND_MIXER_DEVMASK: // Arg contains a bit for each supported device + return put_user(SOUND_MASK_PCM | SOUND_MASK_SYNTH | SOUND_MASK_CD | + SOUND_MASK_LINE | SOUND_MASK_LINE1 | SOUND_MASK_MIC | + SOUND_MASK_VOLUME | SOUND_MASK_RECLEV | + SOUND_MASK_SPEAKER, (int *)arg); + + case SOUND_MIXER_RECMASK: // Arg contains a bit for each supported recording source + return put_user(SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD + | SOUND_MASK_VOLUME | SOUND_MASK_LINE1, (int *)arg); + + case SOUND_MIXER_STEREODEVS: // Mixer channels supporting stereo + return put_user(SOUND_MASK_PCM | SOUND_MASK_SYNTH | SOUND_MASK_CD | + SOUND_MASK_LINE | SOUND_MASK_LINE1 | SOUND_MASK_MIC | + SOUND_MASK_VOLUME | SOUND_MASK_RECLEV, (int *)arg); + + case SOUND_MIXER_CAPS: + return put_user(SOUND_CAP_EXCL_INPUT, (int *)arg); + + default: + i = _IOC_NR(cmd); + if (i >= SOUND_MIXER_NRDEVICES || !(vidx = mixtable1[i])) + return -EINVAL; + return put_user(s->mix.vol[vidx-1], (int *)arg); + } + } + + // If ioctl doesn't have both the IOC_READ and + // the IOC_WRITE bit set, return invalid. + if (_IOC_DIR(cmd) != (_IOC_READ|_IOC_WRITE)) + return -EINVAL; + + // Increment the count of volume writes. + s->mix.modcnt++; + + // Isolate the command; it must be a write. + switch (_IOC_NR(cmd)) { + + case SOUND_MIXER_RECSRC: // Arg contains a bit for each recording source + if (get_user(val, (int *)arg)) + return -EFAULT; + i = hweight32(val); // i = # bits on in val. + if (i != 1) // One & only 1 bit must be on. + return 0; + for(i=0; i 100) + l = 100; // Max soundcard.h vol is 100. + if(l < 6) { + rl = 63; + l = 0; + } + else + rl = attentbl[(10*l)/100]; // Convert 0-100 vol to 63-0 atten. + + r = (val >> 8) & 0xff; + if (r > 100) + r = 100; // Max right volume is 100, too + if(r < 6) { + rr = 63; + r = 0; + } + else + rr = attentbl[(10*r)/100]; // Convert volume to attenuation. + + if ((rl > 60 ) && (rr > 60)) // If both l & r are 'low', + temp1 = 0x8000; // turn on the mute bit. + else + temp1 = 0; + + temp1 |= (rl << 8) | rr; + + cs4281_write_ac97(s, BA0_AC97_MASTER_VOLUME, temp1); + cs4281_write_ac97(s, BA0_AC97_HEADPHONE_VOLUME, temp1); + +#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS + s->mix.vol[8] = ((unsigned int)r << 8) | l; +#else + s->mix.vol[8] = val; +#endif + return put_user(s->mix.vol[8], (int *)arg); + + case SOUND_MIXER_SPEAKER: + if (get_user(val, (int *)arg)) + return -EFAULT; + l = val & 0xff; + if (l > 100) + l = 100; + if(l < 3 ) { + rl = 0; + l = 0; + } + else { + rl = (l*2 - 5)/13; // Convert 0-100 range to 0-15. + l = (rl*13 +5)/2; + } + + if (rl < 3){ + temp1 = 0x8000; + rl = 0; + } + else + temp1 = 0; + rl = 15 - rl; // Convert volume to attenuation. + temp1 |= rl << 1; + cs4281_write_ac97(s, BA0_AC97_PC_BEEP_VOLUME, temp1); + +#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS + s->mix.vol[6] = l << 8; +#else + s->mix.vol[6] = val; +#endif + return put_user(s->mix.vol[6], (int *)arg); + + case SOUND_MIXER_RECLEV: + if (get_user(val, (int *)arg)) + return -EFAULT; + l = val & 0xff; + if (l > 100) + l = 100; + r = (val >> 8) & 0xff; + if (r > 100) + r = 100; + rl = (l*2 - 5) / 13; // Convert 0-100 scale to 0-15. + rr = (r*2 - 5) / 13; + if (rl <3 && rr <3) + temp1 = 0x8000; + else + temp1 = 0; + + temp1 = temp1 | (rl << 8) | rr; + cs4281_write_ac97(s, BA0_AC97_RECORD_GAIN, temp1); + +#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS + s->mix.vol[7] = ((unsigned int)r << 8) | l; +#else + s->mix.vol[7] = val; +#endif + return put_user(s->mix.vol[7], (int *)arg); + + case SOUND_MIXER_MIC: + if (get_user(val, (int *)arg)) + return -EFAULT; + l = val & 0xff; + if (l > 100) + l = 100; + if (l < 1) { + l = 0; + rl = 0; + } + else { + rl = ((unsigned)l*5 - 4)/16; // Convert 0-100 range to 0-31. + l = (rl*16 +4)/5; + } + cs4281_read_ac97(s, BA0_AC97_MIC_VOLUME, &temp1); + temp1 &= 0x40; // Isolate 20db gain bit. + if (rl < 3){ + temp1 |= 0x8000; + rl = 0; + } + rl = 31 - rl; // Convert volume to attenuation. + temp1 |= rl; + cs4281_write_ac97(s, BA0_AC97_MIC_VOLUME, temp1); + +#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS + s->mix.vol[5] = val << 8; +#else + s->mix.vol[5] = val; +#endif + return put_user(s->mix.vol[5], (int *)arg); + + + case SOUND_MIXER_SYNTH: + if (get_user(val, (int *)arg)) + return -EFAULT; + l = val & 0xff; + if (l > 100) + l = 100; + if (get_user(val, (int *)arg)) + return -EFAULT; + r = (val >> 8) & 0xff; + if (r > 100) + r = 100; + rl = (l * 2 - 11)/3; // Convert 0-100 range to 0-63. + rr = (r * 2 - 11)/3; + if (rl < 3) // If l is low, turn on + temp1 = 0x0080; // the mute bit. + else + temp1 = 0; + + rl = 63 - rl; // Convert vol to attenuation. + writel(temp1|rl, s->pBA0+BA0_FMLVC); + if (rr < 3) // If rr is low, turn on + temp1 = 0x0080; // the mute bit. + else + temp1 = 0; + rr = 63 - rr; // Convert vol to attenuation. + writel(temp1 | rr, s->pBA0+BA0_FMRVC); + +#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS + s->mix.vol[4] = (r << 8) | l; +#else + s->mix.vol[4] = val; +#endif + return put_user(s->mix.vol[4], (int *)arg); + + + default: + i = _IOC_NR(cmd); + if (i >= SOUND_MIXER_NRDEVICES || !(vidx = mixtable1[i])) + return -EINVAL; + if (get_user(val, (int *)arg)) + return -EFAULT; + l = val & 0xff; + if (l > 100) + l = 100; + if (l < 1) { + l = 0; + rl = 31; + } + else + rl = (attentbl[(l*10)/100])>>1; + + r = (val >> 8) & 0xff; + if (r > 100) + r = 100; + if (r < 1) { + r = 0; + rr = 31; + } + else + rr = (attentbl[(r*10)/100])>>1; + if ((rl > 30) && (rr > 30)) + temp1 = 0x8000; + else + temp1 = 0; + temp1 = temp1 | (rl << 8) | rr; + cs4281_write_ac97(s, mixreg[vidx-1], temp1); + +#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS + s->mix.vol[vidx-1] = ((unsigned int)r << 8) | l; +#else + s->mix.vol[vidx-1] = val; +#endif + return put_user(s->mix.vol[vidx-1], (int *)arg); + } +} + + +// --------------------------------------------------------------------- + +static loff_t cs4281_llseek(struct file *file, loff_t offset, int origin) +{ + return -ESPIPE; +} + + +// --------------------------------------------------------------------- + +static int cs4281_open_mixdev(struct inode *inode, struct file *file) +{ + int minor = MINOR(inode->i_rdev); + struct cs4281_state *s = devs; + + while (s && s->dev_mixer != minor) + s = s->next; + if (!s) + return -ENODEV; + VALIDATE_STATE(s); + file->private_data = s; + MOD_INC_USE_COUNT; + return 0; +} + + +static int cs4281_release_mixdev(struct inode *inode, struct file *file) +{ + struct cs4281_state *s = (struct cs4281_state *)file->private_data; + + VALIDATE_STATE(s); + MOD_DEC_USE_COUNT; + return 0; +} + + +static int cs4281_ioctl_mixdev(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + return mixer_ioctl((struct cs4281_state *)file->private_data, cmd, arg); +} + + +// ****************************************************************************************** +// Mixer file operations struct. +// ****************************************************************************************** +static /*const*/ struct file_operations cs4281_mixer_fops = { + llseek: cs4281_llseek, + ioctl: cs4281_ioctl_mixdev, + open: cs4281_open_mixdev, + release: cs4281_release_mixdev, +}; + +// --------------------------------------------------------------------- + +static int drain_dac(struct cs4281_state *s, int nonblock) +{ + DECLARE_WAITQUEUE(wait, current); + unsigned long flags; + int count; + unsigned tmo; + + if (s->dma_dac.mapped) + return 0; + current->state = TASK_INTERRUPTIBLE; + add_wait_queue(&s->dma_dac.wait, &wait); + for (;;) { + spin_lock_irqsave(&s->lock, flags); + count = s->dma_dac.count; + spin_unlock_irqrestore(&s->lock, flags); + if (count <= 0) + break; + if (signal_pending(current)) + break; + if (nonblock) { + remove_wait_queue(&s->dma_dac.wait, &wait); + current->state = TASK_RUNNING; + return -EBUSY; + } + tmo = 3 * HZ * (count + s->dma_dac.fragsize) / 2 / s->rate; + if (s->fmt & (AFMT_S16_LE | AFMT_U16_LE)) + tmo >>= 1; + if (s->channels > 1) + tmo >>= 1; + if (!schedule_timeout(tmo + 1)) + printk(KERN_DEBUG "cs4281: dma timed out??\n"); + } + remove_wait_queue(&s->dma_dac.wait, &wait); + current->state = TASK_RUNNING; + if (signal_pending(current)) + return -ERESTARTSYS; + return 0; +} + + +// --------------------------------------------------------------------- + +static ssize_t cs4281_read(struct file *file, char *buffer, size_t count, loff_t *ppos) +{ + struct cs4281_state *s = (struct cs4281_state *)file->private_data; + ssize_t ret; + unsigned long flags; + unsigned swptr; + int cnt; + + CS_DBGOUT(CS_FUNCTION | CS_WAVE_READ, 2, + printk(KERN_INFO "cs4281: cs4281_read()+ \n") ); + + VALIDATE_STATE(s); + if (ppos != &file->f_pos) + return -ESPIPE; + if (s->dma_adc.mapped) + return -ENXIO; + if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s))) + return ret; + if (!access_ok(VERIFY_WRITE, buffer, count)) + return -EFAULT; + ret = 0; + while (count > 0) { + spin_lock_irqsave(&s->lock, flags); + swptr = s->dma_adc.swptr; + cnt = s->dma_adc.dmasize-swptr; + if (s->dma_adc.count < cnt) + cnt = s->dma_adc.count; + spin_unlock_irqrestore(&s->lock, flags); + if (cnt > count) + cnt = count; + if (cnt <= 0) { + start_adc(s); + if (file->f_flags & O_NONBLOCK) + return ret ? ret : -EAGAIN; + interruptible_sleep_on(&s->dma_adc.wait); + if (signal_pending(current)) + return ret ? ret : -ERESTARTSYS; + continue; + } + if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) + return ret ? ret : -EFAULT; + swptr = (swptr + cnt) % s->dma_adc.dmasize; + spin_lock_irqsave(&s->lock, flags); + s->dma_adc.swptr = swptr; + s->dma_adc.count -= cnt; + spin_unlock_irqrestore(&s->lock, flags); + count -= cnt; + buffer += cnt; + ret += cnt; + start_adc(s); + } + CS_DBGOUT(CS_FUNCTION | CS_WAVE_READ, 2, + printk(KERN_INFO "cs4281: cs4281_read()- %d\n",ret) ); + return ret; +} + + +static ssize_t cs4281_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) +{ + struct cs4281_state *s = (struct cs4281_state *)file->private_data; + ssize_t ret; + unsigned long flags; + unsigned swptr; + int cnt; + + CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE, 2, + printk(KERN_INFO "cs4281: cs4281_write()+ \n") ); + VALIDATE_STATE(s); + + if (ppos != &file->f_pos) + return -ESPIPE; + if (s->dma_dac.mapped) + return -ENXIO; + if (!s->dma_dac.ready && (ret = prog_dmabuf_dac(s))) + return ret; + if (!access_ok(VERIFY_READ, buffer, count)) + return -EFAULT; + ret = 0; + while (count > 0) { + spin_lock_irqsave(&s->lock, flags); + if (s->dma_dac.count < 0) { + s->dma_dac.count = 0; + s->dma_dac.swptr = s->dma_dac.hwptr; + } + swptr = s->dma_dac.swptr; + cnt = s->dma_dac.dmasize-swptr; + if (s->dma_dac.count + cnt > s->dma_dac.dmasize) + cnt = s->dma_dac.dmasize - s->dma_dac.count; + spin_unlock_irqrestore(&s->lock, flags); + if (cnt > count) + cnt = count; + if (cnt <= 0) { + start_dac(s); + if (file->f_flags & O_NONBLOCK) + return ret ? ret : -EAGAIN; + interruptible_sleep_on(&s->dma_dac.wait); + if (signal_pending(current)) + return ret ? ret : -ERESTARTSYS; + continue; + } + if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) + return ret ? ret : -EFAULT; + swptr = (swptr + cnt) % s->dma_dac.dmasize; + spin_lock_irqsave(&s->lock, flags); + s->dma_dac.swptr = swptr; + s->dma_dac.count += cnt; + s->dma_dac.endcleared = 0; + spin_unlock_irqrestore(&s->lock, flags); + count -= cnt; + buffer += cnt; + ret += cnt; + start_dac(s); + } + CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE, 2, + printk(KERN_INFO "cs4281: cs4281_write()- %d\n",ret) ); + return ret; +} + + +static unsigned int cs4281_poll(struct file *file, struct poll_table_struct *wait) +{ + struct cs4281_state *s = (struct cs4281_state *)file->private_data; + unsigned long flags; + unsigned int mask = 0; + + CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4, + printk(KERN_INFO "cs4281: cs4281_poll()+\n") ); + VALIDATE_STATE(s); + if (file->f_mode & FMODE_WRITE) + poll_wait(file, &s->dma_dac.wait, wait); + if (file->f_mode & FMODE_READ) + poll_wait(file, &s->dma_adc.wait, wait); + spin_lock_irqsave(&s->lock, flags); + cs4281_update_ptr(s); + if (file->f_mode & FMODE_READ) { + if (s->dma_adc.mapped) { + if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) + mask |= POLLIN | POLLRDNORM; + } else { + if (s->dma_adc.count > 0) + mask |= POLLIN | POLLRDNORM; + } + } + if (file->f_mode & FMODE_WRITE) { + if (s->dma_dac.mapped) { + if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) + mask |= POLLOUT | POLLWRNORM; + } else { + if ((signed)s->dma_dac.dmasize > s->dma_dac.count) + mask |= POLLOUT | POLLWRNORM; + } + } + spin_unlock_irqrestore(&s->lock, flags); + CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4, + printk(KERN_INFO "cs4281: cs4281_poll()- 0x%.8x\n",mask) ); + return mask; +} + + +static int cs4281_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct cs4281_state *s = (struct cs4281_state *)file->private_data; + struct dmabuf *db; + int ret; + unsigned long size; + + CS_DBGOUT(CS_FUNCTION | CS_PARMS | CS_OPEN, 4, + printk(KERN_INFO "cs4281: cs4281_mmap()+\n") ); + + VALIDATE_STATE(s); + if (vma->vm_flags & VM_WRITE) { + if ((ret = prog_dmabuf_dac(s)) != 0) + return ret; + db = &s->dma_dac; + } else if (vma->vm_flags & VM_READ) { + if ((ret = prog_dmabuf_adc(s)) != 0) + return ret; + db = &s->dma_adc; + } else + return -EINVAL; + if (vma->vm_pgoff != 0) + return -EINVAL; + size = vma->vm_end - vma->vm_start; + if (size > (PAGE_SIZE << db->buforder)) + return -EINVAL; + if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot)) + return -EAGAIN; + db->mapped = 1; + + CS_DBGOUT(CS_FUNCTION | CS_PARMS | CS_OPEN, 4, + printk(KERN_INFO "cs4281: cs4281_mmap()- 0 size=%d\n", + (unsigned)size) ); + + return 0; +} + + +static int cs4281_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + struct cs4281_state *s = (struct cs4281_state *)file->private_data; + unsigned long flags; + audio_buf_info abinfo; + count_info cinfo; + int val, mapped, ret; + + CS_DBGOUT(CS_FUNCTION, 4, + printk(KERN_INFO "cs4281: cs4281_ioctl(): file=0x%.8x cmd=0x%.8x\n", + (unsigned)file,cmd) ); + VALIDATE_STATE(s); + mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) || + ((file->f_mode & FMODE_READ) && s->dma_adc.mapped); + switch (cmd) { + case OSS_GETVERSION: + CS_DBGOUT(CS_FUNCTION | CS_PARMS, 4, printk(KERN_INFO + "cs4281: cs4281_ioctl(): SOUND_VERSION=0x%.8x\n", SOUND_VERSION) ); + return put_user(SOUND_VERSION, (int *)arg); + + case SNDCTL_DSP_SYNC: + if (file->f_mode & FMODE_WRITE) + return drain_dac(s, 0/*file->f_flags & O_NONBLOCK*/); + return 0; + + case SNDCTL_DSP_SETDUPLEX: + return 0; + + case SNDCTL_DSP_GETCAPS: + return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, (int *)arg); + + case SNDCTL_DSP_RESET: + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + synchronize_irq(); + s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = + s->dma_dac.total_bytes = s->dma_dac.blocks = 0; + } + if (file->f_mode & FMODE_READ) { + stop_adc(s); + synchronize_irq(); + s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = + s->dma_adc.total_bytes = s->dma_adc.blocks = 0; + } + prog_codec(s); + return 0; + + case SNDCTL_DSP_SPEED: + if (get_user(val, (int *)arg)) + return -EFAULT; + if (val >= 0) { + stop_adc(s); + stop_dac(s); + s->dma_adc.ready = s->dma_dac.ready = 0; + // program sampling rates + if (val > 48000) + val = 48000; + if (val < 6300) + val = 6300; + s->rate = val; + prog_codec(s); + } + return put_user(s->rate, (int *)arg); + + case SNDCTL_DSP_STEREO: + if (get_user(val, (int *)arg)) + return -EFAULT; + stop_adc(s); + stop_dac(s); + s->dma_adc.ready = s->dma_dac.ready = 0; + // program channels + s->channels = val ? 2 : 1; + prog_codec(s); + return 0; + + case SNDCTL_DSP_CHANNELS: + if (get_user(val, (int *)arg)) + return -EFAULT; + if (val != 0) { + stop_adc(s); + stop_dac(s); + s->dma_adc.ready = s->dma_dac.ready = 0; + // program channels + s->channels = val ? 2 : 1; + prog_codec(s); + } + return put_user(s->channels, (int *)arg); + + case SNDCTL_DSP_GETFMTS: // Returns a mask + return put_user(AFMT_S16_LE|AFMT_U16_LE|AFMT_S8|AFMT_U8, (int *)arg); + + case SNDCTL_DSP_SETFMT: // Selects ONE fmt + if (get_user(val, (int *)arg)) + return -EFAULT; + if (val != AFMT_QUERY) { + stop_adc(s); + stop_dac(s); + s->dma_adc.ready = s->dma_dac.ready = 0; + // program format + if (val != AFMT_S16_LE && val != AFMT_U16_LE && + val != AFMT_S8 && val != AFMT_U8) + val = AFMT_U8; + s->fmt = val; + prog_codec(s); + } + return put_user(s->fmt, (int *)arg); + + case SNDCTL_DSP_POST: + return 0; + + case SNDCTL_DSP_GETTRIGGER: + val = 0; + if (file->f_mode & s->ena & FMODE_READ) + val |= PCM_ENABLE_INPUT; + if (file->f_mode & s->ena & FMODE_WRITE) + val |= PCM_ENABLE_OUTPUT; + return put_user(val, (int *)arg); + + case SNDCTL_DSP_SETTRIGGER: + if (get_user(val, (int *)arg)) + return -EFAULT; + if (file->f_mode & FMODE_READ) { + if (val & PCM_ENABLE_INPUT) { + if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s))) + return ret; + start_adc(s); + } else + stop_adc(s); + } + if (file->f_mode & FMODE_WRITE) { + if (val & PCM_ENABLE_OUTPUT) { + if (!s->dma_dac.ready && (ret = prog_dmabuf_dac(s))) + return ret; + start_dac(s); + } else + stop_dac(s); + } + return 0; + + case SNDCTL_DSP_GETOSPACE: + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + if (!(s->ena & FMODE_WRITE) && (val = prog_dmabuf_dac(s)) != 0) + return val; + spin_lock_irqsave(&s->lock, flags); + cs4281_update_ptr(s); + abinfo.fragsize = s->dma_dac.fragsize; + abinfo.bytes = s->dma_dac.dmasize - s->dma_dac.count; + abinfo.fragstotal = s->dma_dac.numfrag; + abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift; + spin_unlock_irqrestore(&s->lock, flags); + return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; + + case SNDCTL_DSP_GETISPACE: + if (!(file->f_mode & FMODE_READ)) + return -EINVAL; + if (!(s->ena & FMODE_READ) && (val = prog_dmabuf_adc(s)) != 0) + return val; + spin_lock_irqsave(&s->lock, flags); + cs4281_update_ptr(s); + abinfo.fragsize = s->dma_adc.fragsize; + abinfo.bytes = s->dma_adc.count; + abinfo.fragstotal = s->dma_adc.numfrag; + abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift; + spin_unlock_irqrestore(&s->lock, flags); + return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; + + case SNDCTL_DSP_NONBLOCK: + file->f_flags |= O_NONBLOCK; + return 0; + + case SNDCTL_DSP_GETODELAY: + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + spin_lock_irqsave(&s->lock, flags); + cs4281_update_ptr(s); + val = s->dma_dac.count; + spin_unlock_irqrestore(&s->lock, flags); + return put_user(val, (int *)arg); + + case SNDCTL_DSP_GETIPTR: + if (!(file->f_mode & FMODE_READ)) + return -EINVAL; + spin_lock_irqsave(&s->lock, flags); + cs4281_update_ptr(s); + cinfo.bytes = s->dma_adc.total_bytes; + cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift; + cinfo.ptr = s->dma_adc.hwptr; + if (s->dma_adc.mapped) + s->dma_adc.count &= s->dma_adc.fragsize-1; + spin_unlock_irqrestore(&s->lock, flags); + return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); + + case SNDCTL_DSP_GETOPTR: + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + spin_lock_irqsave(&s->lock, flags); + cs4281_update_ptr(s); + cinfo.bytes = s->dma_dac.total_bytes; + if (s->dma_dac.mapped) + { + cinfo.blocks = (cinfo.bytes >> s->dma_dac.fragshift) + - s->dma_adc.blocks; + s->dma_dac.blocks = cinfo.bytes >> s->dma_dac.fragshift; + } + else + { + cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift; + } + cinfo.ptr = s->dma_dac.hwptr; + if (s->dma_dac.mapped) + s->dma_dac.count &= s->dma_dac.fragsize-1; + spin_unlock_irqrestore(&s->lock, flags); + return copy_to_user((void *)arg, &cinfo, sizeof(cinfo)); + + case SNDCTL_DSP_GETBLKSIZE: + if (file->f_mode & FMODE_WRITE) { + if ((val = prog_dmabuf_dac(s))) + return val; + return put_user(s->dma_dac.fragsize, (int *)arg); + } + if ((val = prog_dmabuf_adc(s))) + return val; + return put_user(s->dma_adc.fragsize, (int *)arg); + + case SNDCTL_DSP_SETFRAGMENT: + if (get_user(val, (int *)arg)) + return -EFAULT; + return 0; // Say OK, but do nothing. + + case SNDCTL_DSP_SUBDIVIDE: + if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) || + (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision)) + return -EINVAL; + if (get_user(val, (int *)arg)) + return -EFAULT; + if (val != 1 && val != 2 && val != 4) + return -EINVAL; + if (file->f_mode & FMODE_READ) + s->dma_adc.subdivision = val; + if (file->f_mode & FMODE_WRITE) + s->dma_dac.subdivision = val; + return 0; + + case SOUND_PCM_READ_RATE: + return put_user(s->rate, (int *)arg); + + case SOUND_PCM_READ_CHANNELS: + return put_user(s->channels, (int *)arg); + + case SOUND_PCM_READ_BITS: + return put_user((s->fmt & (AFMT_S8|AFMT_U8)) ? 8 : 16, (int *)arg); + + case SOUND_PCM_WRITE_FILTER: + case SNDCTL_DSP_SETSYNCRO: + case SOUND_PCM_READ_FILTER: + return -EINVAL; + + } + return mixer_ioctl(s, cmd, arg); +} + + +static int cs4281_release(struct inode *inode, struct file *file) +{ + struct cs4281_state *s = (struct cs4281_state *)file->private_data; + + CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2, + printk(KERN_INFO "cs4281: cs4281_release(): inode=0x%.8x file=0x%.8x\n", + (unsigned)inode,(unsigned)file) ); + + VALIDATE_STATE(s); + + if (file->f_mode & FMODE_WRITE) + drain_dac(s, file->f_flags & O_NONBLOCK); + down(&s->open_sem); + if (file->f_mode & FMODE_WRITE) { + stop_dac(s); + dealloc_dmabuf(s,&s->dma_dac); + } + if (file->f_mode & FMODE_READ) { + stop_adc(s); + dealloc_dmabuf(s,&s->dma_adc); + } + s->open_mode &= ~(FMODE_READ | FMODE_WRITE); + up(&s->open_sem); + wake_up(&s->open_wait); + MOD_DEC_USE_COUNT; + return 0; +} + +static int cs4281_open(struct inode *inode, struct file *file) +{ + int minor = MINOR(inode->i_rdev); + struct cs4281_state *s = devs; + + CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2, + printk(KERN_INFO "cs4281: cs4281_open(): inode=0x%.8x file=0x%.8x\n", + (unsigned)inode,(unsigned)file) ); + while (s && ((s->dev_audio ^ minor) & ~0xf)) + s = s->next; + if (!s) + { + CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2, printk(KERN_INFO + "cs4281: cs4281_open(): ERROR unable to find audio state struct\n") ); + return -ENODEV; + } + VALIDATE_STATE(s); + file->private_data = s; + + // wait for device to become free + down(&s->open_sem); + while (s->open_mode & (FMODE_READ | FMODE_WRITE)) { + if (file->f_flags & O_NONBLOCK) { + up(&s->open_sem); + return -EBUSY; + } + up(&s->open_sem); + interruptible_sleep_on(&s->open_wait); + if (signal_pending(current)) + return -ERESTARTSYS; + down(&s->open_sem); + } + s->fmt = AFMT_U8; + s->channels = 1; + s->rate = 8000; + s->clkdiv = 96 | 0x80; + s->ena = s->endofbuffer = 0; + s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0; + s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0; + s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); + up(&s->open_sem); + MOD_INC_USE_COUNT; + + if (prog_dmabuf_dac(s) || prog_dmabuf_adc(s)) { + + printk(KERN_ERR "cs4281: Program dmabufs failed.\n"); + cs4281_release(inode, file); + + return -ENOMEM; + } + prog_codec(s); + CS_DBGOUT(CS_INIT | CS_FUNCTION | CS_OPEN, 2, + printk(KERN_INFO "cs4281: cs4281_open()- 0\n") ); + return 0; +} + + +// ****************************************************************************************** +// Wave (audio) file operations struct. +// ****************************************************************************************** +static /*const*/ struct file_operations cs4281_audio_fops = { + llseek: cs4281_llseek, + read: cs4281_read, + write: cs4281_write, + poll: cs4281_poll, + ioctl: cs4281_ioctl, + mmap: cs4281_mmap, + open: cs4281_open, + release: cs4281_release, +}; + +// --------------------------------------------------------------------- + +// hold spinlock for the following! +static void cs4281_handle_midi(struct cs4281_state *s) +{ + unsigned char ch; + int wake; + unsigned temp1; + + wake = 0; + while (!(readl(s->pBA0+ BA0_MIDSR) & 0x80)) { + ch = readl(s->pBA0+BA0_MIDRP); + if (s->midi.icnt < MIDIINBUF) { + s->midi.ibuf[s->midi.iwr] = ch; + s->midi.iwr = (s->midi.iwr + 1) % MIDIINBUF; + s->midi.icnt++; + } + wake = 1; + } + if (wake) + wake_up(&s->midi.iwait); + wake = 0; + while (!(readl(s->pBA0+ BA0_MIDSR) & 0x40) && s->midi.ocnt > 0) { + temp1 = ( s->midi.obuf[s->midi.ord] ) & 0x000000ff; + writel(temp1, s->pBA0+BA0_MIDWP); + s->midi.ord = (s->midi.ord + 1) % MIDIOUTBUF; + s->midi.ocnt--; + if (s->midi.ocnt < MIDIOUTBUF-16) + wake = 1; + } + if (wake) + wake_up(&s->midi.owait); +} + + + +static void cs4281_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct cs4281_state *s = (struct cs4281_state *)dev_id; + unsigned int temp1; + + // fastpath out, to ease interrupt sharing + temp1 = readl(s->pBA0+BA0_HISR); // Get Int Status reg. + + CS_DBGOUT(CS_INTERRUPT, 6, printk(KERN_INFO + "cs4281: cs4281_interrupt() BA0_HISR=0x%.8x\n",temp1) ); + + if (!(temp1 & (HISR_DMA0 | HISR_DMA1 | HISR_MIDI))) { // If not DMA or MIDI int, + writel(HICR_IEV| HICR_CHGM, s->pBA0+BA0_HICR); // reenable interrupts + CS_DBGOUT(CS_INTERRUPT, 4, printk(KERN_INFO + "cs4281: cs4281_interrupt(): returning not cs4281 interrupt.\n") ); + return; // and return. + } + + if(temp1 & HISR_DMA0) // If play interrupt, + readl(s->pBA0+BA0_HDSR0); // clear the source. + + if(temp1 & HISR_DMA1) // Same for play. + readl(s->pBA0+BA0_HDSR1); + writel(HICR_IEV| HICR_CHGM, s->pBA0+BA0_HICR); // Local EOI + + spin_lock(&s->lock); + // + // ok, at this point we assume that the fifos have been filled + // with silence and so we now turn off the DMA engine. + // if FMODE_WRITE is set that means that some thread + // attempted to start_dac, which probably means that an open + // occurred, so do not stop the dac in this case. + // + if(s->endofbuffer && !(s->ena & FMODE_WRITE)) + { + CS_DBGOUT(CS_INTERRUPT, 2, printk(KERN_INFO + "cs4281: cs4281_interrupt() stopping play DMA\n") ); + writel(temp1|DCRn_MSK, s->pBA0+BA0_DCR0); // Stop Play DMA + s->endofbuffer = 0; + } + else + { + cs4281_update_ptr(s); + } + cs4281_handle_midi(s); + spin_unlock(&s->lock); +} + +// ************************************************************************** + +static void cs4281_midi_timer(unsigned long data) +{ + struct cs4281_state *s = (struct cs4281_state *)data; + unsigned long flags; + + spin_lock_irqsave(&s->lock, flags); + cs4281_handle_midi(s); + spin_unlock_irqrestore(&s->lock, flags); + s->midi.timer.expires = jiffies+1; + add_timer(&s->midi.timer); +} + + +// --------------------------------------------------------------------- + +static ssize_t cs4281_midi_read(struct file *file, char *buffer, size_t count, loff_t *ppos) +{ + struct cs4281_state *s = (struct cs4281_state *)file->private_data; + ssize_t ret; + unsigned long flags; + unsigned ptr; + int cnt; + + VALIDATE_STATE(s); + if (ppos != &file->f_pos) + return -ESPIPE; + if (!access_ok(VERIFY_WRITE, buffer, count)) + return -EFAULT; + ret = 0; + while (count > 0) { + spin_lock_irqsave(&s->lock, flags); + ptr = s->midi.ird; + cnt = MIDIINBUF - ptr; + if (s->midi.icnt < cnt) + cnt = s->midi.icnt; + spin_unlock_irqrestore(&s->lock, flags); + if (cnt > count) + cnt = count; + if (cnt <= 0) { + if (file->f_flags & O_NONBLOCK) + return ret ? ret : -EAGAIN; + interruptible_sleep_on(&s->midi.iwait); + if (signal_pending(current)) + return ret ? ret : -ERESTARTSYS; + continue; + } + if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt)) + return ret ? ret : -EFAULT; + ptr = (ptr + cnt) % MIDIINBUF; + spin_lock_irqsave(&s->lock, flags); + s->midi.ird = ptr; + s->midi.icnt -= cnt; + spin_unlock_irqrestore(&s->lock, flags); + count -= cnt; + buffer += cnt; + ret += cnt; + } + return ret; +} + + +static ssize_t cs4281_midi_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) +{ + struct cs4281_state *s = (struct cs4281_state *)file->private_data; + ssize_t ret; + unsigned long flags; + unsigned ptr; + int cnt; + + VALIDATE_STATE(s); + if (ppos != &file->f_pos) + return -ESPIPE; + if (!access_ok(VERIFY_READ, buffer, count)) + return -EFAULT; + ret = 0; + while (count > 0) { + spin_lock_irqsave(&s->lock, flags); + ptr = s->midi.owr; + cnt = MIDIOUTBUF - ptr; + if (s->midi.ocnt + cnt > MIDIOUTBUF) + cnt = MIDIOUTBUF - s->midi.ocnt; + if (cnt <= 0) + cs4281_handle_midi(s); + spin_unlock_irqrestore(&s->lock, flags); + if (cnt > count) + cnt = count; + if (cnt <= 0) { + if (file->f_flags & O_NONBLOCK) + return ret ? ret : -EAGAIN; + interruptible_sleep_on(&s->midi.owait); + if (signal_pending(current)) + return ret ? ret : -ERESTARTSYS; + continue; + } + if (copy_from_user(s->midi.obuf + ptr, buffer, cnt)) + return ret ? ret : -EFAULT; + ptr = (ptr + cnt) % MIDIOUTBUF; + spin_lock_irqsave(&s->lock, flags); + s->midi.owr = ptr; + s->midi.ocnt += cnt; + spin_unlock_irqrestore(&s->lock, flags); + count -= cnt; + buffer += cnt; + ret += cnt; + spin_lock_irqsave(&s->lock, flags); + cs4281_handle_midi(s); + spin_unlock_irqrestore(&s->lock, flags); + } + return ret; +} + + +static unsigned int cs4281_midi_poll(struct file *file, struct poll_table_struct *wait) +{ + struct cs4281_state *s = (struct cs4281_state *)file->private_data; + unsigned long flags; + unsigned int mask = 0; + + VALIDATE_STATE(s); + if (file->f_flags & FMODE_WRITE) + poll_wait(file, &s->midi.owait, wait); + if (file->f_flags & FMODE_READ) + poll_wait(file, &s->midi.iwait, wait); + spin_lock_irqsave(&s->lock, flags); + if (file->f_flags & FMODE_READ) { + if (s->midi.icnt > 0) + mask |= POLLIN | POLLRDNORM; + } + if (file->f_flags & FMODE_WRITE) { + if (s->midi.ocnt < MIDIOUTBUF) + mask |= POLLOUT | POLLWRNORM; + } + spin_unlock_irqrestore(&s->lock, flags); + return mask; +} + + +static int cs4281_midi_open(struct inode *inode, struct file *file) +{ + int minor = MINOR(inode->i_rdev); + struct cs4281_state *s = devs; + unsigned long flags,temp1; + while (s && s->dev_midi != minor) + s = s->next; + if (!s) + return -ENODEV; + VALIDATE_STATE(s); + file->private_data = s; + // wait for device to become free + down(&s->open_sem); + while (s->open_mode & (file->f_mode << FMODE_MIDI_SHIFT)) { + if (file->f_flags & O_NONBLOCK) { + up(&s->open_sem); + return -EBUSY; + } + up(&s->open_sem); + interruptible_sleep_on(&s->open_wait); + if (signal_pending(current)) + return -ERESTARTSYS; + down(&s->open_sem); + } + spin_lock_irqsave(&s->lock, flags); + if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) { + s->midi.ird = s->midi.iwr = s->midi.icnt = 0; + s->midi.ord = s->midi.owr = s->midi.ocnt = 0; + writel(1, s->pBA0+BA0_MIDCR); // Reset the interface. + writel(0, s->pBA0+BA0_MIDCR); // Return to normal mode. + s->midi.ird = s->midi.iwr = s->midi.icnt = 0; + writel(0x0000000f, s->pBA0+BA0_MIDCR); // Enable transmit, record, ints. + temp1 = readl(s->pBA0+BA0_HIMR); + writel(temp1 & 0xffbfffff, s->pBA0+BA0_HIMR); // Enable midi int. recognition. + writel(HICR_IEV | HICR_CHGM, s->pBA0+BA0_HICR); // Enable interrupts + init_timer(&s->midi.timer); + s->midi.timer.expires = jiffies+1; + s->midi.timer.data = (unsigned long)s; + s->midi.timer.function = cs4281_midi_timer; + add_timer(&s->midi.timer); + } + if (file->f_mode & FMODE_READ) { + s->midi.ird = s->midi.iwr = s->midi.icnt = 0; + } + if (file->f_mode & FMODE_WRITE) { + s->midi.ord = s->midi.owr = s->midi.ocnt = 0; + } + spin_unlock_irqrestore(&s->lock, flags); + s->open_mode |= (file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE); + up(&s->open_sem); + MOD_INC_USE_COUNT; + return 0; +} + + +static int cs4281_midi_release(struct inode *inode, struct file *file) +{ + struct cs4281_state *s = (struct cs4281_state *)file->private_data; + DECLARE_WAITQUEUE(wait, current); + unsigned long flags; + unsigned count, tmo; + + VALIDATE_STATE(s); + + if (file->f_mode & FMODE_WRITE) { + current->state = TASK_INTERRUPTIBLE; + add_wait_queue(&s->midi.owait, &wait); + for (;;) { + spin_lock_irqsave(&s->lock, flags); + count = s->midi.ocnt; + spin_unlock_irqrestore(&s->lock, flags); + if (count <= 0) + break; + if (signal_pending(current)) + break; + if (file->f_flags & O_NONBLOCK) { + remove_wait_queue(&s->midi.owait, &wait); + current->state = TASK_RUNNING; + return -EBUSY; + } + tmo = (count * HZ) / 3100; + if (!schedule_timeout(tmo ? : 1) && tmo) + printk(KERN_DEBUG "cs4281: midi timed out??\n"); + } + remove_wait_queue(&s->midi.owait, &wait); + current->state = TASK_RUNNING; + } + down(&s->open_sem); + s->open_mode &= (~(file->f_mode << FMODE_MIDI_SHIFT)) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE); + spin_lock_irqsave(&s->lock, flags); + if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) { + writel(0, s->pBA0+BA0_MIDCR); // Disable Midi interrupts. + del_timer(&s->midi.timer); + } + spin_unlock_irqrestore(&s->lock, flags); + up(&s->open_sem); + wake_up(&s->open_wait); + MOD_DEC_USE_COUNT; + return 0; +} + +// ****************************************************************************************** +// Midi file operations struct. +// ****************************************************************************************** +static /*const*/ struct file_operations cs4281_midi_fops = { + llseek: cs4281_llseek, + read: cs4281_midi_read, + write: cs4281_midi_write, + poll: cs4281_midi_poll, + open: cs4281_midi_open, + release: cs4281_midi_release, +}; + + +// --------------------------------------------------------------------- + +// maximum number of devices +#define NR_DEVICE 8 // Only eight devices supported currently. + +// --------------------------------------------------------------------- + +static struct initvol { + int mixch; + int vol; +} initvol[] __initdata = { + { SOUND_MIXER_WRITE_VOLUME, 0x4040 }, + { SOUND_MIXER_WRITE_PCM, 0x4040 }, + { SOUND_MIXER_WRITE_SYNTH, 0x4040 }, + { SOUND_MIXER_WRITE_CD, 0x4040 }, + { SOUND_MIXER_WRITE_LINE, 0x4040 }, + { SOUND_MIXER_WRITE_LINE1, 0x4040 }, + { SOUND_MIXER_WRITE_RECLEV, 0x0000 }, + { SOUND_MIXER_WRITE_SPEAKER, 0x4040 }, + { SOUND_MIXER_WRITE_MIC, 0x0000 } +}; + + +static int __devinit cs4281_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid) +{ + struct cs4281_state *s; + dma_addr_t dma_mask; + mm_segment_t fs; + int i, val, index = 0; + unsigned int temp1, temp2; + + CS_DBGOUT(CS_INIT, 2, printk(KERN_INFO "cs4281: probe()+\n") ); + + if (!RSRCISMEMORYREGION(pcidev, 0) || + !RSRCISMEMORYREGION(pcidev, 1)) + { + CS_DBGOUT(CS_ERROR, 1, + printk(KERN_ERR "cs4281: probe()- Memory region not assigned\n") ); + return -1; + } + if (pcidev->irq == 0) { + CS_DBGOUT(CS_ERROR, 1, + printk(KERN_ERR "cs4281: probe() IRQ not assigned\n") ); + return -1; + } + if (!pci_dma_supported(pcidev, 0xffffffff)) { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR + "cs4281: probe() architecture does not support 32bit PCI busmaster DMA\n") ); + return -1; + } + dma_mask = 0xffffffff; /* this enables playback and recording */ + if (!(s = kmalloc(sizeof(struct cs4281_state), GFP_KERNEL))) { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR + "cs4281: probe() no memory for state struct.\n") ); + return -1; + } + memset(s, 0, sizeof(struct cs4281_state)); + init_waitqueue_head(&s->dma_adc.wait); + init_waitqueue_head(&s->dma_dac.wait); + init_waitqueue_head(&s->open_wait); + init_waitqueue_head(&s->midi.iwait); + init_waitqueue_head(&s->midi.owait); + init_MUTEX(&s->open_sem); + spin_lock_init(&s->lock); + s->pBA0phys = RSRCADDRESS(pcidev, 0); + s->pBA1phys = RSRCADDRESS(pcidev, 1); + s->pBA0 = ioremap_nocache(s->pBA0phys, 4096); // Convert phys + s->pBA1 = ioremap_nocache(s->pBA1phys, 65536); // to linear. + temp1 = readl(s->pBA0+ BA0_PCICFG00); + temp2 = readl(s->pBA0+ BA0_PCICFG04); + + CS_DBGOUT(CS_INIT, 2, + printk(KERN_INFO "cs4281: probe() BA0=0x%.8x BA1=0x%.8x pBA0=0x%.8x pBA1=0x%.8x \n", + (unsigned)temp1,(unsigned)temp2,(unsigned)s->pBA0,(unsigned)s->pBA1) ); + + CS_DBGOUT(CS_INIT, 2, + printk(KERN_INFO "cs4281: probe() pBA0phys=0x%.8x pBA1phys=0x%.8x\n", + (unsigned)s->pBA0phys,(unsigned)s->pBA1phys) ); + + temp1 = cs4281_hw_init(s); + if(temp1){ + CS_DBGOUT(CS_ERROR | CS_INIT, 1, + printk(KERN_ERR "cs4281: cs4281_hw_init() failed. Skipping part.\n") ); + return -1; + } + s->magic = CS4281_MAGIC; + s->pcidev = pcidev; + s->irq = pcidev->irq; + if (pci_enable_device(pcidev)) + { + CS_DBGOUT(CS_INIT | CS_ERROR, 1, + printk(KERN_ERR "cs4281: pci_enable_device() failed\n") ); + goto err_irq; + } + if(request_irq(s->irq, cs4281_interrupt, SA_SHIRQ, "Crystal CS4281", s)){ + CS_DBGOUT(CS_INIT | CS_ERROR, 1, + printk(KERN_ERR "cs4281: irq %u in use\n", s->irq) ); + goto err_irq; + } + if ((s->dev_audio = register_sound_dsp(&cs4281_audio_fops, -1)) < 0) + { + CS_DBGOUT(CS_INIT | CS_ERROR, 1, + printk(KERN_ERR "cs4281: probe() register_sound_dsp() failed.\n") ); + goto err_dev1; + } + if ((s->dev_mixer = register_sound_mixer(&cs4281_mixer_fops, -1)) < 0) + { + CS_DBGOUT(CS_INIT | CS_ERROR, 1, + printk(KERN_ERR "cs4281: probe() register_sound_mixer() failed.\n") ); + goto err_dev2; + } + if ((s->dev_midi = register_sound_midi(&cs4281_midi_fops, -1)) < 0) + { + CS_DBGOUT(CS_INIT | CS_ERROR, 1, + printk(KERN_ERR "cs4281: probe() register_sound_midi() failed.\n") ); + goto err_dev3; + } + + pci_set_master(pcidev); // enable bus mastering + + fs = get_fs(); + set_fs(KERNEL_DS); + val = SOUND_MASK_LINE; + mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val); + for (i = 0; i < sizeof(initvol)/sizeof(initvol[0]); i++) { + val = initvol[i].vol; + mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val); + } + val = 1; // enable mic preamp + mixer_ioctl(s, SOUND_MIXER_PRIVATE1, (unsigned long)&val); + set_fs(fs); + + // queue it for later freeing + s->next = devs; + pcidev->driver_data = s; + pcidev->dma_mask = dma_mask; + devs = s; + index++; + return 0; + +err_dev3: + unregister_sound_mixer(s->dev_mixer); +err_dev2: + unregister_sound_dsp(s->dev_audio); +err_dev1: + free_irq(s->irq, s); +err_irq: + kfree(s); + + if (!devs) + { + CS_DBGOUT(CS_INIT | CS_ERROR, 1, + printk(KERN_INFO "cs4281: probe()- no device allocated\n") ); + return -ENODEV; + } + CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, + printk(KERN_INFO "cs4281: probe()- device allocated successfully\n") ); + return 0; +} // probe_cs4281 + + +// --------------------------------------------------------------------- + +static void __devinit cs4281_remove(struct pci_dev *dev) +{ + struct cs4281_state *s = (struct cs4281_state *)dev->driver_data; + // stop DMA controller + synchronize_irq(); + free_irq(s->irq, s); + unregister_sound_dsp(s->dev_audio); + unregister_sound_mixer(s->dev_mixer); + unregister_sound_midi(s->dev_midi); + kfree(s); + dev->driver_data = NULL; + CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, + printk(KERN_INFO "cs4281: cs4281_remove(): remove successful\n") ); +} + +static struct pci_device_id id_table[] __devinitdata = { + { PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CRYSTAL_CS4281, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, id_table); + +static struct pci_driver cs4281_driver = { + name: "cs4281", + id_table: id_table, + probe: cs4281_probe, + remove: cs4281_remove +}; + +static int __init init_cs4281(void) +{ + + CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO "cs4281: init_cs4281()+ \n") ); + if (!pci_present()) /* No PCI bus in this machine! */ + { + CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, + printk(KERN_INFO "cs4281: init_cs4281()- no pci bus found\n") ); + return -ENODEV; + } + printk(KERN_INFO "cs4281: version v%d.%02d.%d time " __TIME__ " " __DATE__ "\n", + CS4281_MAJOR_VERSION, CS4281_MINOR_VERSION, CS4281_ARCH); + if (!pci_register_driver(&cs4281_driver)) { + pci_unregister_driver(&cs4281_driver); + CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, + printk(KERN_INFO "cs4281: init_cs4281()- unable to register pci device \n") ); + return -ENODEV; + } + CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO "cs4281: init_cs4281()- 0\n") ); + return 0; +} + + +// --------------------------------------------------------------------- + + +MODULE_AUTHOR("gw boynton, wesb@crystal.cirrus.com"); +MODULE_DESCRIPTION("Cirrus Logic CS4281 Driver"); + +static void __exit cleanup_cs4281(void) +{ + pci_unregister_driver(&cs4281_driver); + CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, + printk(KERN_INFO "cs4281: cleanup_cs4281() finished\n") ); +} + +// --------------------------------------------------------------------- + +module_init(init_cs4281); +module_exit(cleanup_cs4281); + diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/cs4281_hwdefs.h linux/drivers/sound/cs4281_hwdefs.h --- v2.4.0-test8/linux/drivers/sound/cs4281_hwdefs.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/cs4281_hwdefs.h Sat Sep 23 20:23:09 2000 @@ -0,0 +1,1234 @@ +//**************************************************************************** +// +// HWDEFS.H - Definitions of the registers and data structures used by the +// CS4281 +// +// Copyright (c) 1999 Crystal Semiconductor Corp. +// +//**************************************************************************** + +#ifndef _H_HWDEFS +#define _H_HWDEFS + +//**************************************************************************** +// +// The following define the offsets of the registers located in the PCI +// configuration space of the CS4281 part. +// +//**************************************************************************** +#define PCICONFIG_DEVID_VENID 0x00000000L +#define PCICONFIG_STATUS_COMMAND 0x00000004L +#define PCICONFIG_CLASS_REVISION 0x00000008L +#define PCICONFIG_LATENCY_TIMER 0x0000000CL +#define PCICONFIG_BA0 0x00000010L +#define PCICONFIG_BA1 0x00000014L +#define PCICONFIG_SUBSYSID_SUBSYSVENID 0x0000002CL +#define PCICONFIG_INTERRUPT 0x0000003CL + +//**************************************************************************** +// +// The following define the offsets of the registers accessed via base address +// register zero on the CS4281 part. +// +//**************************************************************************** +#define BA0_HISR 0x00000000L +#define BA0_HICR 0x00000008L +#define BA0_HIMR 0x0000000CL +#define BA0_IIER 0x00000010L +#define BA0_HDSR0 0x000000F0L +#define BA0_HDSR1 0x000000F4L +#define BA0_HDSR2 0x000000F8L +#define BA0_HDSR3 0x000000FCL +#define BA0_DCA0 0x00000110L +#define BA0_DCC0 0x00000114L +#define BA0_DBA0 0x00000118L +#define BA0_DBC0 0x0000011CL +#define BA0_DCA1 0x00000120L +#define BA0_DCC1 0x00000124L +#define BA0_DBA1 0x00000128L +#define BA0_DBC1 0x0000012CL +#define BA0_DCA2 0x00000130L +#define BA0_DCC2 0x00000134L +#define BA0_DBA2 0x00000138L +#define BA0_DBC2 0x0000013CL +#define BA0_DCA3 0x00000140L +#define BA0_DCC3 0x00000144L +#define BA0_DBA3 0x00000148L +#define BA0_DBC3 0x0000014CL +#define BA0_DMR0 0x00000150L +#define BA0_DCR0 0x00000154L +#define BA0_DMR1 0x00000158L +#define BA0_DCR1 0x0000015CL +#define BA0_DMR2 0x00000160L +#define BA0_DCR2 0x00000164L +#define BA0_DMR3 0x00000168L +#define BA0_DCR3 0x0000016CL +#define BA0_DLMR 0x00000170L +#define BA0_DLSR 0x00000174L +#define BA0_FCR0 0x00000180L +#define BA0_FCR1 0x00000184L +#define BA0_FCR2 0x00000188L +#define BA0_FCR3 0x0000018CL +#define BA0_FPDR0 0x00000190L +#define BA0_FPDR1 0x00000194L +#define BA0_FPDR2 0x00000198L +#define BA0_FPDR3 0x0000019CL +#define BA0_FCHS 0x0000020CL +#define BA0_FSIC0 0x00000210L +#define BA0_FSIC1 0x00000214L +#define BA0_FSIC2 0x00000218L +#define BA0_FSIC3 0x0000021CL +#define BA0_PCICFG00 0x00000300L +#define BA0_PCICFG04 0x00000304L +#define BA0_PCICFG08 0x00000308L +#define BA0_PCICFG0C 0x0000030CL +#define BA0_PCICFG10 0x00000310L +#define BA0_PCICFG14 0x00000314L +#define BA0_PCICFG18 0x00000318L +#define BA0_PCICFG1C 0x0000031CL +#define BA0_PCICFG20 0x00000320L +#define BA0_PCICFG24 0x00000324L +#define BA0_PCICFG28 0x00000328L +#define BA0_PCICFG2C 0x0000032CL +#define BA0_PCICFG30 0x00000330L +#define BA0_PCICFG34 0x00000334L +#define BA0_PCICFG38 0x00000338L +#define BA0_PCICFG3C 0x0000033CL +#define BA0_PCICFG40 0x00000340L +#define BA0_PMCS 0x00000344L +#define BA0_CWPR 0x000003E0L +#define BA0_EPPMC 0x000003E4L +#define BA0_GPIOR 0x000003E8L +#define BA0_SPMC 0x000003ECL +#define BA0_CFLR 0x000003F0L +#define BA0_IISR 0x000003F4L +#define BA0_TMS 0x000003F8L +#define BA0_SSVID 0x000003FCL +#define BA0_CLKCR1 0x00000400L +#define BA0_FRR 0x00000410L +#define BA0_SLT12O 0x0000041CL +#define BA0_SERMC 0x00000420L +#define BA0_SERC1 0x00000428L +#define BA0_SERC2 0x0000042CL +#define BA0_SLT12M 0x0000045CL +#define BA0_ACCTL 0x00000460L +#define BA0_ACSTS 0x00000464L +#define BA0_ACOSV 0x00000468L +#define BA0_ACCAD 0x0000046CL +#define BA0_ACCDA 0x00000470L +#define BA0_ACISV 0x00000474L +#define BA0_ACSAD 0x00000478L +#define BA0_ACSDA 0x0000047CL +#define BA0_JSPT 0x00000480L +#define BA0_JSCTL 0x00000484L +#define BA0_MIDCR 0x00000490L +#define BA0_MIDCMD 0x00000494L +#define BA0_MIDSR 0x00000494L +#define BA0_MIDWP 0x00000498L +#define BA0_MIDRP 0x0000049CL +#define BA0_AODSD1 0x000004A8L +#define BA0_AODSD2 0x000004ACL +#define BA0_CFGI 0x000004B0L +#define BA0_SLT12M2 0x000004DCL +#define BA0_ACSTS2 0x000004E4L +#define BA0_ACISV2 0x000004F4L +#define BA0_ACSAD2 0x000004F8L +#define BA0_ACSDA2 0x000004FCL +#define BA0_IOTGP 0x00000500L +#define BA0_IOTSB 0x00000504L +#define BA0_IOTFM 0x00000508L +#define BA0_IOTDMA 0x0000050CL +#define BA0_IOTAC0 0x00000500L +#define BA0_IOTAC1 0x00000504L +#define BA0_IOTAC2 0x00000508L +#define BA0_IOTAC3 0x0000050CL +#define BA0_IOTPCP 0x0000052CL +#define BA0_IOTCC 0x00000530L +#define BA0_IOTCR 0x0000058CL +#define BA0_PCPRR 0x00000600L +#define BA0_PCPGR 0x00000604L +#define BA0_PCPCR 0x00000608L +#define BA0_PCPCIEN 0x00000608L +#define BA0_SBMAR 0x00000700L +#define BA0_SBMDR 0x00000704L +#define BA0_SBRR 0x00000708L +#define BA0_SBRDP 0x0000070CL +#define BA0_SBWDP 0x00000710L +#define BA0_SBWBS 0x00000710L +#define BA0_SBRBS 0x00000714L +#define BA0_FMSR 0x00000730L +#define BA0_B0AP 0x00000730L +#define BA0_FMDP 0x00000734L +#define BA0_B1AP 0x00000738L +#define BA0_B1DP 0x0000073CL +#define BA0_SSPM 0x00000740L +#define BA0_DACSR 0x00000744L +#define BA0_ADCSR 0x00000748L +#define BA0_SSCR 0x0000074CL +#define BA0_FMLVC 0x00000754L +#define BA0_FMRVC 0x00000758L +#define BA0_SRCSA 0x0000075CL +#define BA0_PPLVC 0x00000760L +#define BA0_PPRVC 0x00000764L +#define BA0_PASR 0x00000768L +#define BA0_CASR 0x0000076CL + +//**************************************************************************** +// +// The following define the offsets of the AC97 shadow registers, which appear +// as a virtual extension to the base address register zero memory range. +// +//**************************************************************************** +#define AC97_REG_OFFSET_MASK 0x0000007EL +#define AC97_CODEC_NUMBER_MASK 0x00003000L + +#define BA0_AC97_RESET 0x00001000L +#define BA0_AC97_MASTER_VOLUME 0x00001002L +#define BA0_AC97_HEADPHONE_VOLUME 0x00001004L +#define BA0_AC97_MASTER_VOLUME_MONO 0x00001006L +#define BA0_AC97_MASTER_TONE 0x00001008L +#define BA0_AC97_PC_BEEP_VOLUME 0x0000100AL +#define BA0_AC97_PHONE_VOLUME 0x0000100CL +#define BA0_AC97_MIC_VOLUME 0x0000100EL +#define BA0_AC97_LINE_IN_VOLUME 0x00001010L +#define BA0_AC97_CD_VOLUME 0x00001012L +#define BA0_AC97_VIDEO_VOLUME 0x00001014L +#define BA0_AC97_AUX_VOLUME 0x00001016L +#define BA0_AC97_PCM_OUT_VOLUME 0x00001018L +#define BA0_AC97_RECORD_SELECT 0x0000101AL +#define BA0_AC97_RECORD_GAIN 0x0000101CL +#define BA0_AC97_RECORD_GAIN_MIC 0x0000101EL +#define BA0_AC97_GENERAL_PURPOSE 0x00001020L +#define BA0_AC97_3D_CONTROL 0x00001022L +#define BA0_AC97_MODEM_RATE 0x00001024L +#define BA0_AC97_POWERDOWN 0x00001026L +#define BA0_AC97_EXT_AUDIO_ID 0x00001028L +#define BA0_AC97_EXT_AUDIO_POWER 0x0000102AL +#define BA0_AC97_PCM_FRONT_DAC_RATE 0x0000102CL +#define BA0_AC97_PCM_SURR_DAC_RATE 0x0000102EL +#define BA0_AC97_PCM_LFE_DAC_RATE 0x00001030L +#define BA0_AC97_PCM_LR_ADC_RATE 0x00001032L +#define BA0_AC97_MIC_ADC_RATE 0x00001034L +#define BA0_AC97_6CH_VOL_C_LFE 0x00001036L +#define BA0_AC97_6CH_VOL_SURROUND 0x00001038L +#define BA0_AC97_RESERVED_3A 0x0000103AL +#define BA0_AC97_EXT_MODEM_ID 0x0000103CL +#define BA0_AC97_EXT_MODEM_POWER 0x0000103EL +#define BA0_AC97_LINE1_CODEC_RATE 0x00001040L +#define BA0_AC97_LINE2_CODEC_RATE 0x00001042L +#define BA0_AC97_HANDSET_CODEC_RATE 0x00001044L +#define BA0_AC97_LINE1_CODEC_LEVEL 0x00001046L +#define BA0_AC97_LINE2_CODEC_LEVEL 0x00001048L +#define BA0_AC97_HANDSET_CODEC_LEVEL 0x0000104AL +#define BA0_AC97_GPIO_PIN_CONFIG 0x0000104CL +#define BA0_AC97_GPIO_PIN_TYPE 0x0000104EL +#define BA0_AC97_GPIO_PIN_STICKY 0x00001050L +#define BA0_AC97_GPIO_PIN_WAKEUP 0x00001052L +#define BA0_AC97_GPIO_PIN_STATUS 0x00001054L +#define BA0_AC97_MISC_MODEM_AFE_STAT 0x00001056L +#define BA0_AC97_RESERVED_58 0x00001058L +#define BA0_AC97_CRYSTAL_REV_N_FAB_ID 0x0000105AL +#define BA0_AC97_TEST_AND_MISC_CTRL 0x0000105CL +#define BA0_AC97_AC_MODE 0x0000105EL +#define BA0_AC97_MISC_CRYSTAL_CONTROL 0x00001060L +#define BA0_AC97_LINE1_HYPRID_CTRL 0x00001062L +#define BA0_AC97_VENDOR_RESERVED_64 0x00001064L +#define BA0_AC97_VENDOR_RESERVED_66 0x00001066L +#define BA0_AC97_SPDIF_CONTROL 0x00001068L +#define BA0_AC97_VENDOR_RESERVED_6A 0x0000106AL +#define BA0_AC97_VENDOR_RESERVED_6C 0x0000106CL +#define BA0_AC97_VENDOR_RESERVED_6E 0x0000106EL +#define BA0_AC97_VENDOR_RESERVED_70 0x00001070L +#define BA0_AC97_VENDOR_RESERVED_72 0x00001072L +#define BA0_AC97_VENDOR_RESERVED_74 0x00001074L +#define BA0_AC97_CAL_ADDRESS 0x00001076L +#define BA0_AC97_CAL_DATA 0x00001078L +#define BA0_AC97_VENDOR_RESERVED_7A 0x0000107AL +#define BA0_AC97_VENDOR_ID1 0x0000107CL +#define BA0_AC97_VENDOR_ID2 0x0000107EL + +//**************************************************************************** +// +// The following define the offsets of the registers and memories accessed via +// base address register one on the CS4281 part. +// +//**************************************************************************** + +//**************************************************************************** +// +// The following defines are for the flags in the PCI device ID/vendor ID +// register. +// +//**************************************************************************** +#define PDV_VENID_MASK 0x0000FFFFL +#define PDV_DEVID_MASK 0xFFFF0000L +#define PDV_VENID_SHIFT 0L +#define PDV_DEVID_SHIFT 16L +#define VENID_CIRRUS_LOGIC 0x1013L +#define DEVID_CS4281 0x6005L + +//**************************************************************************** +// +// The following defines are for the flags in the PCI status and command +// register. +// +//**************************************************************************** +#define PSC_IO_SPACE_ENABLE 0x00000001L +#define PSC_MEMORY_SPACE_ENABLE 0x00000002L +#define PSC_BUS_MASTER_ENABLE 0x00000004L +#define PSC_SPECIAL_CYCLES 0x00000008L +#define PSC_MWI_ENABLE 0x00000010L +#define PSC_VGA_PALETTE_SNOOP 0x00000020L +#define PSC_PARITY_RESPONSE 0x00000040L +#define PSC_WAIT_CONTROL 0x00000080L +#define PSC_SERR_ENABLE 0x00000100L +#define PSC_FAST_B2B_ENABLE 0x00000200L +#define PSC_UDF_MASK 0x007F0000L +#define PSC_FAST_B2B_CAPABLE 0x00800000L +#define PSC_PARITY_ERROR_DETECTED 0x01000000L +#define PSC_DEVSEL_TIMING_MASK 0x06000000L +#define PSC_TARGET_ABORT_SIGNALLED 0x08000000L +#define PSC_RECEIVED_TARGET_ABORT 0x10000000L +#define PSC_RECEIVED_MASTER_ABORT 0x20000000L +#define PSC_SIGNALLED_SERR 0x40000000L +#define PSC_DETECTED_PARITY_ERROR 0x80000000L +#define PSC_UDF_SHIFT 16L +#define PSC_DEVSEL_TIMING_SHIFT 25L + +//**************************************************************************** +// +// The following defines are for the flags in the PCI class/revision ID +// register. +// +//**************************************************************************** +#define PCR_REVID_MASK 0x000000FFL +#define PCR_INTERFACE_MASK 0x0000FF00L +#define PCR_SUBCLASS_MASK 0x00FF0000L +#define PCR_CLASS_MASK 0xFF000000L +#define PCR_REVID_SHIFT 0L +#define PCR_INTERFACE_SHIFT 8L +#define PCR_SUBCLASS_SHIFT 16L +#define PCR_CLASS_SHIFT 24L + +//**************************************************************************** +// +// The following defines are for the flags in the PCI latency timer register. +// +//**************************************************************************** +#define PLT_CACHE_LINE_SIZE_MASK 0x000000FFL +#define PLT_LATENCY_TIMER_MASK 0x0000FF00L +#define PLT_HEADER_TYPE_MASK 0x00FF0000L +#define PLT_BIST_MASK 0xFF000000L +#define PLT_CACHE_LINE_SIZE_SHIFT 0L +#define PLT_LATENCY_TIMER_SHIFT 8L +#define PLT_HEADER_TYPE_SHIFT 16L +#define PLT_BIST_SHIFT 24L + +//**************************************************************************** +// +// The following defines are for the flags in the PCI base address registers. +// +//**************************************************************************** +#define PBAR_MEMORY_SPACE_INDICATOR 0x00000001L +#define PBAR_LOCATION_TYPE_MASK 0x00000006L +#define PBAR_NOT_PREFETCHABLE 0x00000008L +#define PBAR_ADDRESS_MASK 0xFFFFFFF0L +#define PBAR_LOCATION_TYPE_SHIFT 1L + +//**************************************************************************** +// +// The following defines are for the flags in the PCI subsystem ID/subsystem +// vendor ID register. +// +//**************************************************************************** +#define PSS_SUBSYSTEM_VENDOR_ID_MASK 0x0000FFFFL +#define PSS_SUBSYSTEM_ID_MASK 0xFFFF0000L +#define PSS_SUBSYSTEM_VENDOR_ID_SHIFT 0L +#define PSS_SUBSYSTEM_ID_SHIFT 16L + +//**************************************************************************** +// +// The following defines are for the flags in the PCI interrupt register. +// +//**************************************************************************** +#define PI_LINE_MASK 0x000000FFL +#define PI_PIN_MASK 0x0000FF00L +#define PI_MIN_GRANT_MASK 0x00FF0000L +#define PI_MAX_LATENCY_MASK 0xFF000000L +#define PI_LINE_SHIFT 0L +#define PI_PIN_SHIFT 8L +#define PI_MIN_GRANT_SHIFT 16L +#define PI_MAX_LATENCY_SHIFT 24L + +//**************************************************************************** +// +// The following defines are for the flags in the host interrupt status +// register. +// +//**************************************************************************** +#define HISR_HVOLMASK 0x00000003L +#define HISR_VDNI 0x00000001L +#define HISR_VUPI 0x00000002L +#define HISR_GP1I 0x00000004L +#define HISR_GP3I 0x00000008L +#define HISR_GPSI 0x00000010L +#define HISR_GPPI 0x00000020L +#define HISR_DMAI 0x00040000L +#define HISR_FIFOI 0x00100000L +#define HISR_HVOL 0x00200000L +#define HISR_MIDI 0x00400000L +#define HISR_SBINT 0x00800000L +#define HISR_INTENA 0x80000000L +#define HISR_DMA_MASK 0x00000F00L +#define HISR_FIFO_MASK 0x0000F000L +#define HISR_DMA_SHIFT 8L +#define HISR_FIFO_SHIFT 12L +#define HISR_FIFO0 0x00001000L +#define HISR_FIFO1 0x00002000L +#define HISR_FIFO2 0x00004000L +#define HISR_FIFO3 0x00008000L +#define HISR_DMA0 0x00000100L +#define HISR_DMA1 0x00000200L +#define HISR_DMA2 0x00000400L +#define HISR_DMA3 0x00000800L +#define HISR_RESERVED 0x40000000L + +//**************************************************************************** +// +// The following defines are for the flags in the host interrupt control +// register. +// +//**************************************************************************** +#define HICR_IEV 0x00000001L +#define HICR_CHGM 0x00000002L + +//**************************************************************************** +// +// The following defines are for the flags in the DMA Mode Register n +// (DMRn) +// +//**************************************************************************** +#define DMRn_TR_MASK 0x0000000CL +#define DMRn_TR_SHIFT 2L +#define DMRn_AUTO 0x00000010L +#define DMRn_TR_READ 0x00000008L +#define DMRn_TR_WRITE 0x00000004L +#define DMRn_TYPE_MASK 0x000000C0L +#define DMRn_TYPE_SHIFT 6L +#define DMRn_SIZE8 0x00010000L +#define DMRn_MONO 0x00020000L +#define DMRn_BEND 0x00040000L +#define DMRn_USIGN 0x00080000L +#define DMRn_SIZE20 0x00100000L +#define DMRn_SWAPC 0x00400000L +#define DMRn_CBC 0x01000000L +#define DMRn_TBC 0x02000000L +#define DMRn_POLL 0x10000000L +#define DMRn_DMA 0x20000000L +#define DMRn_FSEL_MASK 0xC0000000L +#define DMRn_FSEL_SHIFT 30L +#define DMRn_FSEL0 0x00000000L +#define DMRn_FSEL1 0x40000000L +#define DMRn_FSEL2 0x80000000L +#define DMRn_FSEL3 0xC0000000L + +//**************************************************************************** +// +// The following defines are for the flags in the DMA Command Register n +// (DCRn) +// +//**************************************************************************** +#define DCRn_HTCIE 0x00020000L +#define DCRn_TCIE 0x00010000L +#define DCRn_MSK 0x00000001L + +//**************************************************************************** +// +// The following defines are for the flags in the FIFO Control +// register n.(FCRn) +// +//**************************************************************************** +#define FCRn_OF_MASK 0x0000007FL +#define FCRn_OF_SHIFT 0L +#define FCRn_SZ_MASK 0x00007F00L +#define FCRn_SZ_SHIFT 8L +#define FCRn_LS_MASK 0x001F0000L +#define FCRn_LS_SHIFT 16L +#define FCRn_RS_MASK 0x1F000000L +#define FCRn_RS_SHIFT 24L +#define FCRn_FEN 0x80000000L +#define FCRn_PSH 0x20000000L +#define FCRn_DACZ 0x40000000L + +//**************************************************************************** +// +// The following defines are for the flags in the serial port Power Management +// control register.(SPMC) +// +//**************************************************************************** +#define SPMC_RSTN 0x00000001L +#define SPMC_ASYN 0x00000002L +#define SPMC_WUP1 0x00000004L +#define SPMC_WUP2 0x00000008L +#define SPMC_ASDI2E 0x00000100L +#define SPMC_ESSPD 0x00000200L +#define SPMC_GISPEN 0x00004000L +#define SPMC_GIPPEN 0x00008000L + +//**************************************************************************** +// +// The following defines are for the flags in the Configuration Load register. +// (CFLR) +// +//**************************************************************************** +#define CFLR_CLOCK_SOURCE_MASK 0x00000003L +#define CFLR_CLOCK_SOURCE_AC97 0x00000001L + +#define CFLR_CB0_MASK 0x000000FFL +#define CFLR_CB1_MASK 0x0000FF00L +#define CFLR_CB2_MASK 0x00FF0000L +#define CFLR_CB3_MASK 0xFF000000L +#define CFLR_CB0_SHIFT 0L +#define CFLR_CB1_SHIFT 8L +#define CFLR_CB2_SHIFT 16L +#define CFLR_CB3_SHIFT 24L + +#define IOTCR_DMA0 0x00000000L +#define IOTCR_DMA1 0x00000400L +#define IOTCR_DMA2 0x00000800L +#define IOTCR_DMA3 0x00000C00L +#define IOTCR_CCLS 0x00000100L +#define IOTCR_PCPCI 0x00000200L +#define IOTCR_DDMA 0x00000300L + +#define SBWBS_WBB 0x00000080L + +//**************************************************************************** +// +// The following defines are for the flags in the SRC Slot Assignment Register +// (SRCSA) +// +//**************************************************************************** +#define SRCSA_PLSS_MASK 0x0000001FL +#define SRCSA_PLSS_SHIFT 0L +#define SRCSA_PRSS_MASK 0x00001F00L +#define SRCSA_PRSS_SHIFT 8L +#define SRCSA_CLSS_MASK 0x001F0000L +#define SRCSA_CLSS_SHIFT 16L +#define SRCSA_CRSS_MASK 0x1F000000L +#define SRCSA_CRSS_SHIFT 24L + +//**************************************************************************** +// +// The following defines are for the flags in the Sound System Power Management +// register.(SSPM) +// +//**************************************************************************** +#define SSPM_FPDN 0x00000080L +#define SSPM_MIXEN 0x00000040L +#define SSPM_CSRCEN 0x00000020L +#define SSPM_PSRCEN 0x00000010L +#define SSPM_JSEN 0x00000008L +#define SSPM_ACLEN 0x00000004L +#define SSPM_FMEN 0x00000002L + +//**************************************************************************** +// +// The following defines are for the flags in the Sound System Control +// Register. (SSCR) +// +//**************************************************************************** +#define SSCR_SB 0x00000004L +#define SSCR_HVC 0x00000008L +#define SSCR_LPFIFO 0x00000040L +#define SSCR_LPSRC 0x00000080L +#define SSCR_XLPSRC 0x00000100L +#define SSCR_MVMD 0x00010000L +#define SSCR_MVAD 0x00020000L +#define SSCR_MVLD 0x00040000L +#define SSCR_MVCS 0x00080000L + +//**************************************************************************** +// +// The following defines are for the flags in the Clock Control Register 1. +// (CLKCR1) +// +//**************************************************************************** +#define CLKCR1_DLLSS_MASK 0x0000000CL +#define CLKCR1_DLLSS_SHIFT 2L +#define CLKCR1_DLLP 0x00000010L +#define CLKCR1_SWCE 0x00000020L +#define CLKCR1_DLLOS 0x00000040L +#define CLKCR1_CKRA 0x00010000L +#define CLKCR1_CKRN 0x00020000L +#define CLKCR1_DLLRDY 0x01000000L +#define CLKCR1_CLKON 0x02000000L + +//**************************************************************************** +// +// The following defines are for the flags in the Sound Blaster Read Buffer +// Status.(SBRBS) +// +//**************************************************************************** +#define SBRBS_RD_MASK 0x0000007FL +#define SBRBS_RD_SHIFT 0L +#define SBRBS_RBF 0x00000080L + +//**************************************************************************** +// +// The following defines are for the flags in the serial port master control +// register.(SERMC) +// +//**************************************************************************** +#define SERMC_MSPE 0x00000001L +#define SERMC_PTC_MASK 0x0000000EL +#define SERMC_PTC_SHIFT 1L +#define SERMC_PTC_AC97 0x00000002L +#define SERMC_PLB 0x00000010L +#define SERMC_PXLB 0x00000020L +#define SERMC_LOFV 0x00080000L +#define SERMC_SLB 0x00100000L +#define SERMC_SXLB 0x00200000L +#define SERMC_ODSEN1 0x01000000L +#define SERMC_ODSEN2 0x02000000L + +//**************************************************************************** +// +// The following defines are for the flags in the General Purpose I/O Register. +// (GPIOR) +// +//**************************************************************************** +#define GPIOR_VDNS 0x00000001L +#define GPIOR_VUPS 0x00000002L +#define GPIOR_GP1S 0x00000004L +#define GPIOR_GP3S 0x00000008L +#define GPIOR_GPSS 0x00000010L +#define GPIOR_GPPS 0x00000020L +#define GPIOR_GP1D 0x00000400L +#define GPIOR_GP3D 0x00000800L +#define GPIOR_VDNLT 0x00010000L +#define GPIOR_VDNPO 0x00020000L +#define GPIOR_VDNST 0x00040000L +#define GPIOR_VDNW 0x00080000L +#define GPIOR_VUPLT 0x00100000L +#define GPIOR_VUPPO 0x00200000L +#define GPIOR_VUPST 0x00400000L +#define GPIOR_VUPW 0x00800000L +#define GPIOR_GP1OE 0x01000000L +#define GPIOR_GP1PT 0x02000000L +#define GPIOR_GP1ST 0x04000000L +#define GPIOR_GP1W 0x08000000L +#define GPIOR_GP3OE 0x10000000L +#define GPIOR_GP3PT 0x20000000L +#define GPIOR_GP3ST 0x40000000L +#define GPIOR_GP3W 0x80000000L + +//**************************************************************************** +// +// The following defines are for the flags in the clock control register 1. +// +//**************************************************************************** +#define CLKCR1_PLLSS_MASK 0x0000000CL +#define CLKCR1_PLLSS_SERIAL 0x00000000L +#define CLKCR1_PLLSS_CRYSTAL 0x00000004L +#define CLKCR1_PLLSS_PCI 0x00000008L +#define CLKCR1_PLLSS_RESERVED 0x0000000CL +#define CLKCR1_PLLP 0x00000010L +#define CLKCR1_SWCE 0x00000020L +#define CLKCR1_PLLOS 0x00000040L + +//**************************************************************************** +// +// The following defines are for the flags in the feature reporting register. +// +//**************************************************************************** +#define FRR_FAB_MASK 0x00000003L +#define FRR_MASK_MASK 0x0000001CL +#define FRR_ID_MASK 0x00003000L +#define FRR_FAB_SHIFT 0L +#define FRR_MASK_SHIFT 2L +#define FRR_ID_SHIFT 12L + +//**************************************************************************** +// +// The following defines are for the flags in the serial port 1 configuration +// register. +// +//**************************************************************************** +#define SERC1_VALUE 0x00000003L +#define SERC1_SO1EN 0x00000001L +#define SERC1_SO1F_MASK 0x0000000EL +#define SERC1_SO1F_CS423X 0x00000000L +#define SERC1_SO1F_AC97 0x00000002L +#define SERC1_SO1F_DAC 0x00000004L +#define SERC1_SO1F_SPDIF 0x00000006L + +//**************************************************************************** +// +// The following defines are for the flags in the serial port 2 configuration +// register. +// +//**************************************************************************** +#define SERC2_VALUE 0x00000003L +#define SERC2_SI1EN 0x00000001L +#define SERC2_SI1F_MASK 0x0000000EL +#define SERC2_SI1F_CS423X 0x00000000L +#define SERC2_SI1F_AC97 0x00000002L +#define SERC2_SI1F_ADC 0x00000004L +#define SERC2_SI1F_SPDIF 0x00000006L + +//**************************************************************************** +// +// The following defines are for the flags in the AC97 control register. +// +//**************************************************************************** +#define ACCTL_ESYN 0x00000002L +#define ACCTL_VFRM 0x00000004L +#define ACCTL_DCV 0x00000008L +#define ACCTL_CRW 0x00000010L +#define ACCTL_TC 0x00000040L + +//**************************************************************************** +// +// The following defines are for the flags in the AC97 status register. +// +//**************************************************************************** +#define ACSTS_CRDY 0x00000001L +#define ACSTS_VSTS 0x00000002L + +//**************************************************************************** +// +// The following defines are for the flags in the AC97 output slot valid +// register. +// +//**************************************************************************** +#define ACOSV_SLV3 0x00000001L +#define ACOSV_SLV4 0x00000002L +#define ACOSV_SLV5 0x00000004L +#define ACOSV_SLV6 0x00000008L +#define ACOSV_SLV7 0x00000010L +#define ACOSV_SLV8 0x00000020L +#define ACOSV_SLV9 0x00000040L +#define ACOSV_SLV10 0x00000080L +#define ACOSV_SLV11 0x00000100L +#define ACOSV_SLV12 0x00000200L + +//**************************************************************************** +// +// The following defines are for the flags in the AC97 command address +// register. +// +//**************************************************************************** +#define ACCAD_CI_MASK 0x0000007FL +#define ACCAD_CI_SHIFT 0L + +//**************************************************************************** +// +// The following defines are for the flags in the AC97 command data register. +// +//**************************************************************************** +#define ACCDA_CD_MASK 0x0000FFFFL +#define ACCDA_CD_SHIFT 0L + +//**************************************************************************** +// +// The following defines are for the flags in the AC97 input slot valid +// register. +// +//**************************************************************************** +#define ACISV_ISV3 0x00000001L +#define ACISV_ISV4 0x00000002L +#define ACISV_ISV5 0x00000004L +#define ACISV_ISV6 0x00000008L +#define ACISV_ISV7 0x00000010L +#define ACISV_ISV8 0x00000020L +#define ACISV_ISV9 0x00000040L +#define ACISV_ISV10 0x00000080L +#define ACISV_ISV11 0x00000100L +#define ACISV_ISV12 0x00000200L + +//**************************************************************************** +// +// The following defines are for the flags in the AC97 status address +// register. +// +//**************************************************************************** +#define ACSAD_SI_MASK 0x0000007FL +#define ACSAD_SI_SHIFT 0L + +//**************************************************************************** +// +// The following defines are for the flags in the AC97 status data register. +// +//**************************************************************************** +#define ACSDA_SD_MASK 0x0000FFFFL +#define ACSDA_SD_SHIFT 0L + +//**************************************************************************** +// +// The following defines are for the flags in the I/O trap address and control +// registers (all 12). +// +//**************************************************************************** +#define IOTAC_SA_MASK 0x0000FFFFL +#define IOTAC_MSK_MASK 0x000F0000L +#define IOTAC_IODC_MASK 0x06000000L +#define IOTAC_IODC_16_BIT 0x00000000L +#define IOTAC_IODC_10_BIT 0x02000000L +#define IOTAC_IODC_12_BIT 0x04000000L +#define IOTAC_WSPI 0x08000000L +#define IOTAC_RSPI 0x10000000L +#define IOTAC_WSE 0x20000000L +#define IOTAC_WE 0x40000000L +#define IOTAC_RE 0x80000000L +#define IOTAC_SA_SHIFT 0L +#define IOTAC_MSK_SHIFT 16L + +//**************************************************************************** +// +// The following defines are for the flags in the PC/PCI master enable +// register. +// +//**************************************************************************** +#define PCPCIEN_EN 0x00000001L + +//**************************************************************************** +// +// The following defines are for the flags in the joystick poll/trigger +// register. +// +//**************************************************************************** +#define JSPT_CAX 0x00000001L +#define JSPT_CAY 0x00000002L +#define JSPT_CBX 0x00000004L +#define JSPT_CBY 0x00000008L +#define JSPT_BA1 0x00000010L +#define JSPT_BA2 0x00000020L +#define JSPT_BB1 0x00000040L +#define JSPT_BB2 0x00000080L + +//**************************************************************************** +// +// The following defines are for the flags in the joystick control register. +// The TBF bit has been moved from MIDSR register to JSCTL register bit 8. +// +//**************************************************************************** +#define JSCTL_SP_MASK 0x00000003L +#define JSCTL_SP_SLOW 0x00000000L +#define JSCTL_SP_MEDIUM_SLOW 0x00000001L +#define JSCTL_SP_MEDIUM_FAST 0x00000002L +#define JSCTL_SP_FAST 0x00000003L +#define JSCTL_ARE 0x00000004L +#define JSCTL_TBF 0x00000100L + + +//**************************************************************************** +// +// The following defines are for the flags in the MIDI control register. +// +//**************************************************************************** +#define MIDCR_TXE 0x00000001L +#define MIDCR_RXE 0x00000002L +#define MIDCR_RIE 0x00000004L +#define MIDCR_TIE 0x00000008L +#define MIDCR_MLB 0x00000010L +#define MIDCR_MRST 0x00000020L + +//**************************************************************************** +// +// The following defines are for the flags in the MIDI status register. +// +//**************************************************************************** +#define MIDSR_RBE 0x00000080L +#define MIDSR_RDA 0x00008000L + +//**************************************************************************** +// +// The following defines are for the flags in the MIDI write port register. +// +//**************************************************************************** +#define MIDWP_MWD_MASK 0x000000FFL +#define MIDWP_MWD_SHIFT 0L + +//**************************************************************************** +// +// The following defines are for the flags in the MIDI read port register. +// +//**************************************************************************** +#define MIDRP_MRD_MASK 0x000000FFL +#define MIDRP_MRD_SHIFT 0L + +//**************************************************************************** +// +// The following defines are for the flags in the configuration interface +// register. +// +//**************************************************************************** +#define CFGI_CLK 0x00000001L +#define CFGI_DOUT 0x00000002L +#define CFGI_DIN_EEN 0x00000004L +#define CFGI_EELD 0x00000008L + +//**************************************************************************** +// +// The following defines are for the flags in the subsystem ID and vendor ID +// register. +// +//**************************************************************************** +#define SSVID_VID_MASK 0x0000FFFFL +#define SSVID_SID_MASK 0xFFFF0000L +#define SSVID_VID_SHIFT 0L +#define SSVID_SID_SHIFT 16L + +//**************************************************************************** +// +// The following defines are for the flags in the GPIO pin interface register. +// +//**************************************************************************** +#define GPIOR_VOLDN 0x00000001L +#define GPIOR_VOLUP 0x00000002L +#define GPIOR_SI2D 0x00000004L +#define GPIOR_SI2OE 0x00000008L + +//**************************************************************************** +// +// The following defines are for the flags in the AC97 status register 2. +// +//**************************************************************************** +#define ACSTS2_CRDY 0x00000001L +#define ACSTS2_VSTS 0x00000002L + +//**************************************************************************** +// +// The following defines are for the flags in the AC97 input slot valid +// register 2. +// +//**************************************************************************** +#define ACISV2_ISV3 0x00000001L +#define ACISV2_ISV4 0x00000002L +#define ACISV2_ISV5 0x00000004L +#define ACISV2_ISV6 0x00000008L +#define ACISV2_ISV7 0x00000010L +#define ACISV2_ISV8 0x00000020L +#define ACISV2_ISV9 0x00000040L +#define ACISV2_ISV10 0x00000080L +#define ACISV2_ISV11 0x00000100L +#define ACISV2_ISV12 0x00000200L + +//**************************************************************************** +// +// The following defines are for the flags in the AC97 status address +// register 2. +// +//**************************************************************************** +#define ACSAD2_SI_MASK 0x0000007FL +#define ACSAD2_SI_SHIFT 0L + +//**************************************************************************** +// +// The following defines are for the flags in the AC97 status data register 2. +// +//**************************************************************************** +#define ACSDA2_SD_MASK 0x0000FFFFL +#define ACSDA2_SD_SHIFT 0L + +//**************************************************************************** +// +// The following defines are for the flags in the I/O trap control register. +// +//**************************************************************************** +#define IOTCR_ITD 0x00000001L +#define IOTCR_HRV 0x00000002L +#define IOTCR_SRV 0x00000004L +#define IOTCR_DTI 0x00000008L +#define IOTCR_DFI 0x00000010L +#define IOTCR_DDP 0x00000020L +#define IOTCR_JTE 0x00000040L +#define IOTCR_PPE 0x00000080L + +//**************************************************************************** +// +// The following defines are for the flags in the I/O trap address and control +// registers for Hardware Master Volume. +// +//**************************************************************************** +#define IOTGP_SA_MASK 0x0000FFFFL +#define IOTGP_MSK_MASK 0x000F0000L +#define IOTGP_IODC_MASK 0x06000000L +#define IOTGP_IODC_16_BIT 0x00000000L +#define IOTGP_IODC_10_BIT 0x02000000L +#define IOTGP_IODC_12_BIT 0x04000000L +#define IOTGP_WSPI 0x08000000L +#define IOTGP_RSPI 0x10000000L +#define IOTGP_WSE 0x20000000L +#define IOTGP_WE 0x40000000L +#define IOTGP_RE 0x80000000L +#define IOTGP_SA_SHIFT 0L +#define IOTGP_MSK_SHIFT 16L + +//**************************************************************************** +// +// The following defines are for the flags in the I/O trap address and control +// registers for Sound Blaster +// +//**************************************************************************** +#define IOTSB_SA_MASK 0x0000FFFFL +#define IOTSB_MSK_MASK 0x000F0000L +#define IOTSB_IODC_MASK 0x06000000L +#define IOTSB_IODC_16_BIT 0x00000000L +#define IOTSB_IODC_10_BIT 0x02000000L +#define IOTSB_IODC_12_BIT 0x04000000L +#define IOTSB_WSPI 0x08000000L +#define IOTSB_RSPI 0x10000000L +#define IOTSB_WSE 0x20000000L +#define IOTSB_WE 0x40000000L +#define IOTSB_RE 0x80000000L +#define IOTSB_SA_SHIFT 0L +#define IOTSB_MSK_SHIFT 16L + +//**************************************************************************** +// +// The following defines are for the flags in the I/O trap address and control +// registers for FM. +// +//**************************************************************************** +#define IOTFM_SA_MASK 0x0000FFFFL +#define IOTFM_MSK_MASK 0x000F0000L +#define IOTFM_IODC_MASK 0x06000000L +#define IOTFM_IODC_16_BIT 0x00000000L +#define IOTFM_IODC_10_BIT 0x02000000L +#define IOTFM_IODC_12_BIT 0x04000000L +#define IOTFM_WSPI 0x08000000L +#define IOTFM_RSPI 0x10000000L +#define IOTFM_WSE 0x20000000L +#define IOTFM_WE 0x40000000L +#define IOTFM_RE 0x80000000L +#define IOTFM_SA_SHIFT 0L +#define IOTFM_MSK_SHIFT 16L + +//**************************************************************************** +// +// The following defines are for the flags in the PC/PCI request register. +// +//**************************************************************************** +#define PCPRR_RDC_MASK 0x00000007L +#define PCPRR_REQ 0x00008000L +#define PCPRR_RDC_SHIFT 0L + +//**************************************************************************** +// +// The following defines are for the flags in the PC/PCI grant register. +// +//**************************************************************************** +#define PCPGR_GDC_MASK 0x00000007L +#define PCPGR_VL 0x00008000L +#define PCPGR_GDC_SHIFT 0L + +//**************************************************************************** +// +// The following defines are for the flags in the PC/PCI Control Register. +// +//**************************************************************************** +#define PCPCR_EN 0x00000001L + +//**************************************************************************** +// +// The following defines are for the flags in the debug index register. +// +//**************************************************************************** +#define DREG_REGID_MASK 0x0000007FL +#define DREG_DEBUG 0x00000080L +#define DREG_RGBK_MASK 0x00000700L +#define DREG_TRAP 0x00000800L +#if !defined(NO_CS4612) +#if !defined(NO_CS4615) +#define DREG_TRAPX 0x00001000L +#endif +#endif +#define DREG_REGID_SHIFT 0L +#define DREG_RGBK_SHIFT 8L +#define DREG_RGBK_REGID_MASK 0x0000077FL +#define DREG_REGID_R0 0x00000010L +#define DREG_REGID_R1 0x00000011L +#define DREG_REGID_R2 0x00000012L +#define DREG_REGID_R3 0x00000013L +#define DREG_REGID_R4 0x00000014L +#define DREG_REGID_R5 0x00000015L +#define DREG_REGID_R6 0x00000016L +#define DREG_REGID_R7 0x00000017L +#define DREG_REGID_R8 0x00000018L +#define DREG_REGID_R9 0x00000019L +#define DREG_REGID_RA 0x0000001AL +#define DREG_REGID_RB 0x0000001BL +#define DREG_REGID_RC 0x0000001CL +#define DREG_REGID_RD 0x0000001DL +#define DREG_REGID_RE 0x0000001EL +#define DREG_REGID_RF 0x0000001FL +#define DREG_REGID_RA_BUS_LOW 0x00000020L +#define DREG_REGID_RA_BUS_HIGH 0x00000038L +#define DREG_REGID_YBUS_LOW 0x00000050L +#define DREG_REGID_YBUS_HIGH 0x00000058L +#define DREG_REGID_TRAP_0 0x00000100L +#define DREG_REGID_TRAP_1 0x00000101L +#define DREG_REGID_TRAP_2 0x00000102L +#define DREG_REGID_TRAP_3 0x00000103L +#define DREG_REGID_TRAP_4 0x00000104L +#define DREG_REGID_TRAP_5 0x00000105L +#define DREG_REGID_TRAP_6 0x00000106L +#define DREG_REGID_TRAP_7 0x00000107L +#define DREG_REGID_INDIRECT_ADDRESS 0x0000010EL +#define DREG_REGID_TOP_OF_STACK 0x0000010FL +#if !defined(NO_CS4612) +#if !defined(NO_CS4615) +#define DREG_REGID_TRAP_8 0x00000110L +#define DREG_REGID_TRAP_9 0x00000111L +#define DREG_REGID_TRAP_10 0x00000112L +#define DREG_REGID_TRAP_11 0x00000113L +#define DREG_REGID_TRAP_12 0x00000114L +#define DREG_REGID_TRAP_13 0x00000115L +#define DREG_REGID_TRAP_14 0x00000116L +#define DREG_REGID_TRAP_15 0x00000117L +#define DREG_REGID_TRAP_16 0x00000118L +#define DREG_REGID_TRAP_17 0x00000119L +#define DREG_REGID_TRAP_18 0x0000011AL +#define DREG_REGID_TRAP_19 0x0000011BL +#define DREG_REGID_TRAP_20 0x0000011CL +#define DREG_REGID_TRAP_21 0x0000011DL +#define DREG_REGID_TRAP_22 0x0000011EL +#define DREG_REGID_TRAP_23 0x0000011FL +#endif +#endif +#define DREG_REGID_RSA0_LOW 0x00000200L +#define DREG_REGID_RSA0_HIGH 0x00000201L +#define DREG_REGID_RSA1_LOW 0x00000202L +#define DREG_REGID_RSA1_HIGH 0x00000203L +#define DREG_REGID_RSA2 0x00000204L +#define DREG_REGID_RSA3 0x00000205L +#define DREG_REGID_RSI0_LOW 0x00000206L +#define DREG_REGID_RSI0_HIGH 0x00000207L +#define DREG_REGID_RSI1 0x00000208L +#define DREG_REGID_RSI2 0x00000209L +#define DREG_REGID_SAGUSTATUS 0x0000020AL +#define DREG_REGID_RSCONFIG01_LOW 0x0000020BL +#define DREG_REGID_RSCONFIG01_HIGH 0x0000020CL +#define DREG_REGID_RSCONFIG23_LOW 0x0000020DL +#define DREG_REGID_RSCONFIG23_HIGH 0x0000020EL +#define DREG_REGID_RSDMA01E 0x0000020FL +#define DREG_REGID_RSDMA23E 0x00000210L +#define DREG_REGID_RSD0_LOW 0x00000211L +#define DREG_REGID_RSD0_HIGH 0x00000212L +#define DREG_REGID_RSD1_LOW 0x00000213L +#define DREG_REGID_RSD1_HIGH 0x00000214L +#define DREG_REGID_RSD2_LOW 0x00000215L +#define DREG_REGID_RSD2_HIGH 0x00000216L +#define DREG_REGID_RSD3_LOW 0x00000217L +#define DREG_REGID_RSD3_HIGH 0x00000218L +#define DREG_REGID_SRAR_HIGH 0x0000021AL +#define DREG_REGID_SRAR_LOW 0x0000021BL +#define DREG_REGID_DMA_STATE 0x0000021CL +#define DREG_REGID_CURRENT_DMA_STREAM 0x0000021DL +#define DREG_REGID_NEXT_DMA_STREAM 0x0000021EL +#define DREG_REGID_CPU_STATUS 0x00000300L +#define DREG_REGID_MAC_MODE 0x00000301L +#define DREG_REGID_STACK_AND_REPEAT 0x00000302L +#define DREG_REGID_INDEX0 0x00000304L +#define DREG_REGID_INDEX1 0x00000305L +#define DREG_REGID_DMA_STATE_0_3 0x00000400L +#define DREG_REGID_DMA_STATE_4_7 0x00000404L +#define DREG_REGID_DMA_STATE_8_11 0x00000408L +#define DREG_REGID_DMA_STATE_12_15 0x0000040CL +#define DREG_REGID_DMA_STATE_16_19 0x00000410L +#define DREG_REGID_DMA_STATE_20_23 0x00000414L +#define DREG_REGID_DMA_STATE_24_27 0x00000418L +#define DREG_REGID_DMA_STATE_28_31 0x0000041CL +#define DREG_REGID_DMA_STATE_32_35 0x00000420L +#define DREG_REGID_DMA_STATE_36_39 0x00000424L +#define DREG_REGID_DMA_STATE_40_43 0x00000428L +#define DREG_REGID_DMA_STATE_44_47 0x0000042CL +#define DREG_REGID_DMA_STATE_48_51 0x00000430L +#define DREG_REGID_DMA_STATE_52_55 0x00000434L +#define DREG_REGID_DMA_STATE_56_59 0x00000438L +#define DREG_REGID_DMA_STATE_60_63 0x0000043CL +#define DREG_REGID_DMA_STATE_64_67 0x00000440L +#define DREG_REGID_DMA_STATE_68_71 0x00000444L +#define DREG_REGID_DMA_STATE_72_75 0x00000448L +#define DREG_REGID_DMA_STATE_76_79 0x0000044CL +#define DREG_REGID_DMA_STATE_80_83 0x00000450L +#define DREG_REGID_DMA_STATE_84_87 0x00000454L +#define DREG_REGID_DMA_STATE_88_91 0x00000458L +#define DREG_REGID_DMA_STATE_92_95 0x0000045CL +#define DREG_REGID_TRAP_SELECT 0x00000500L +#define DREG_REGID_TRAP_WRITE_0 0x00000500L +#define DREG_REGID_TRAP_WRITE_1 0x00000501L +#define DREG_REGID_TRAP_WRITE_2 0x00000502L +#define DREG_REGID_TRAP_WRITE_3 0x00000503L +#define DREG_REGID_TRAP_WRITE_4 0x00000504L +#define DREG_REGID_TRAP_WRITE_5 0x00000505L +#define DREG_REGID_TRAP_WRITE_6 0x00000506L +#define DREG_REGID_TRAP_WRITE_7 0x00000507L +#if !defined(NO_CS4612) +#if !defined(NO_CS4615) +#define DREG_REGID_TRAP_WRITE_8 0x00000510L +#define DREG_REGID_TRAP_WRITE_9 0x00000511L +#define DREG_REGID_TRAP_WRITE_10 0x00000512L +#define DREG_REGID_TRAP_WRITE_11 0x00000513L +#define DREG_REGID_TRAP_WRITE_12 0x00000514L +#define DREG_REGID_TRAP_WRITE_13 0x00000515L +#define DREG_REGID_TRAP_WRITE_14 0x00000516L +#define DREG_REGID_TRAP_WRITE_15 0x00000517L +#define DREG_REGID_TRAP_WRITE_16 0x00000518L +#define DREG_REGID_TRAP_WRITE_17 0x00000519L +#define DREG_REGID_TRAP_WRITE_18 0x0000051AL +#define DREG_REGID_TRAP_WRITE_19 0x0000051BL +#define DREG_REGID_TRAP_WRITE_20 0x0000051CL +#define DREG_REGID_TRAP_WRITE_21 0x0000051DL +#define DREG_REGID_TRAP_WRITE_22 0x0000051EL +#define DREG_REGID_TRAP_WRITE_23 0x0000051FL +#endif +#endif +#define DREG_REGID_MAC0_ACC0_LOW 0x00000600L +#define DREG_REGID_MAC0_ACC1_LOW 0x00000601L +#define DREG_REGID_MAC0_ACC2_LOW 0x00000602L +#define DREG_REGID_MAC0_ACC3_LOW 0x00000603L +#define DREG_REGID_MAC1_ACC0_LOW 0x00000604L +#define DREG_REGID_MAC1_ACC1_LOW 0x00000605L +#define DREG_REGID_MAC1_ACC2_LOW 0x00000606L +#define DREG_REGID_MAC1_ACC3_LOW 0x00000607L +#define DREG_REGID_MAC0_ACC0_MID 0x00000608L +#define DREG_REGID_MAC0_ACC1_MID 0x00000609L +#define DREG_REGID_MAC0_ACC2_MID 0x0000060AL +#define DREG_REGID_MAC0_ACC3_MID 0x0000060BL +#define DREG_REGID_MAC1_ACC0_MID 0x0000060CL +#define DREG_REGID_MAC1_ACC1_MID 0x0000060DL +#define DREG_REGID_MAC1_ACC2_MID 0x0000060EL +#define DREG_REGID_MAC1_ACC3_MID 0x0000060FL +#define DREG_REGID_MAC0_ACC0_HIGH 0x00000610L +#define DREG_REGID_MAC0_ACC1_HIGH 0x00000611L +#define DREG_REGID_MAC0_ACC2_HIGH 0x00000612L +#define DREG_REGID_MAC0_ACC3_HIGH 0x00000613L +#define DREG_REGID_MAC1_ACC0_HIGH 0x00000614L +#define DREG_REGID_MAC1_ACC1_HIGH 0x00000615L +#define DREG_REGID_MAC1_ACC2_HIGH 0x00000616L +#define DREG_REGID_MAC1_ACC3_HIGH 0x00000617L +#define DREG_REGID_RSHOUT_LOW 0x00000620L +#define DREG_REGID_RSHOUT_MID 0x00000628L +#define DREG_REGID_RSHOUT_HIGH 0x00000630L + +//**************************************************************************** +// +// The following defines are for the flags in the AC97 S/PDIF Control register. +// +//**************************************************************************** +#define SPDIF_CONTROL_SPDIF_EN 0x00008000L +#define SPDIF_CONTROL_VAL 0x00004000L +#define SPDIF_CONTROL_COPY 0x00000004L +#define SPDIF_CONTROL_CC0 0x00000010L +#define SPDIF_CONTROL_CC1 0x00000020L +#define SPDIF_CONTROL_CC2 0x00000040L +#define SPDIF_CONTROL_CC3 0x00000080L +#define SPDIF_CONTROL_CC4 0x00000100L +#define SPDIF_CONTROL_CC5 0x00000200L +#define SPDIF_CONTROL_CC6 0x00000400L +#define SPDIF_CONTROL_L 0x00000800L + +#endif // _H_HWDEFS diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/cs46xx.c linux/drivers/sound/cs46xx.c --- v2.4.0-test8/linux/drivers/sound/cs46xx.c Tue Aug 29 14:09:15 2000 +++ linux/drivers/sound/cs46xx.c Sun Sep 17 09:45:05 2000 @@ -100,12 +100,6 @@ /* maxinum number of AC97 codecs connected, AC97 2.0 defined 4 */ #define NR_AC97 2 -/* minor number of /dev/dspW */ -#define SND_DEV_DSP8 1 - -/* minor number of /dev/dspW */ -#define SND_DEV_DSP16 1 - static const unsigned sample_size[] = { 1, 2, 2, 4 }; static const unsigned sample_shift[] = { 0, 1, 1, 2 }; @@ -2485,7 +2479,7 @@ void (*active)(struct cs_card *, int); }; -static struct cs_card_type __init cards[]={ +static struct cs_card_type __initdata cards[]={ {0x1489, 0x7001, "Genius Soundmaker 128 value", amp_none, NULL}, {0x5053, 0x3357, "Voyetra", amp_voyetra, NULL}, /* MI6020/21 use the same chipset as the Thinkpads, maybe needed */ @@ -2494,7 +2488,7 @@ {PCI_VENDOR_ID_IBM, 0x0132, "Thinkpad 570", amp_none, clkrun_hack}, {PCI_VENDOR_ID_IBM, 0x0153, "Thinkpad 600X/A20/T20", amp_none, clkrun_hack}, {PCI_VENDOR_ID_IBM, 0x1010, "Thinkpad 600E (unsupported)", NULL, NULL}, - {0, 0, NULL, NULL} + {0, 0, NULL, NULL, NULL} }; static int __init cs_install(struct pci_dev *pci_dev) diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/dev_table.c linux/drivers/sound/dev_table.c --- v2.4.0-test8/linux/drivers/sound/dev_table.c Sun Apr 2 15:45:06 2000 +++ linux/drivers/sound/dev_table.c Mon Sep 25 12:32:54 2000 @@ -16,8 +16,6 @@ #define _DEV_TABLE_C_ #include "sound_config.h" -int softoss_dev = 0; - int sound_install_audiodrv(int vers, char *name, struct audio_driver *driver, int driver_size, int flags, unsigned int format_mask, void *devc, int dma1, int dma2) diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/dmasound/awacs_defs.h linux/drivers/sound/dmasound/awacs_defs.h --- v2.4.0-test8/linux/drivers/sound/dmasound/awacs_defs.h Mon Jul 12 16:21:25 1999 +++ linux/drivers/sound/dmasound/awacs_defs.h Sun Sep 17 09:48:05 2000 @@ -62,6 +62,11 @@ #define MASK_ADDR_VOLC MASK_ADDR4 /* Volume Control C -- Speaker */ #define MASK_ADDR_VOLSPK MASK_ADDR4 +/* additional registers of screamer */ +#define MASK_ADDR5 (0x5 << 12) /* Expanded Data Mode Address 5 */ +#define MASK_ADDR6 (0x6 << 12) /* Expanded Data Mode Address 6 */ +#define MASK_ADDR7 (0x7 << 12) /* Expanded Data Mode Address 7 */ + /* Address 0 Bit Masks & Macros */ /* ------- - --- ----- - ------ */ #define MASK_GAINRIGHT (0xf) /* Gain Right Mask */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/dmasound/dmasound_awacs.c linux/drivers/sound/dmasound/dmasound_awacs.c --- v2.4.0-test8/linux/drivers/sound/dmasound/dmasound_awacs.c Tue Jun 20 07:52:36 2000 +++ linux/drivers/sound/dmasound/dmasound_awacs.c Sun Sep 17 09:48:05 2000 @@ -17,8 +17,12 @@ #include #include #include +#ifdef CONFIG_ADB_CUDA #include +#endif +#ifdef CONFIG_ADB_PMU #include +#endif #include #include @@ -45,6 +49,9 @@ static char awacs_name[64]; static int awacs_revision; +int awacs_is_screamer = 0; +int awacs_device_id = 0; +int awacs_has_iic = 0; #define AWACS_BURGUNDY 100 /* fake revision # for burgundy */ /* @@ -60,7 +67,7 @@ * Cached values of AWACS registers (we can't read them). * Except on the burgundy. XXX */ -int awacs_reg[5]; +int awacs_reg[8]; #define HAS_16BIT_TABLES #undef HAS_8BIT_TABLES @@ -1303,6 +1310,11 @@ awacs_write(awacs_reg[1] | MASK_ADDR1); awacs_write(awacs_reg[2] | MASK_ADDR2); awacs_write(awacs_reg[4] | MASK_ADDR4); + if (awacs_is_screamer) { + awacs_write(awacs_reg[5] + MASK_ADDR5); + awacs_write(awacs_reg[6] + MASK_ADDR6); + awacs_write(awacs_reg[7] + MASK_ADDR7); + } out_le32(&awacs->byteswap, dmasound.hard.format != AFMT_S16_BE); enable_irq(awacs_irq); enable_irq(awacs_tx_irq); @@ -1551,6 +1563,7 @@ if (sys_ctrler != SYS_CTRLER_CUDA) return; +#ifdef CONFIG_ADB_CUDA /* turn on headphones */ cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC, 0x8a, 4, 0); @@ -1570,6 +1583,7 @@ cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC, 0x8a, 1, 0x29); while (!req.complete) cuda_poll(); +#endif /* CONFIG_ADB_CUDA */ } @@ -1974,6 +1988,13 @@ awacs_subframe = *prop; if (device_is_compatible(sound, "burgundy")) awacs_revision = AWACS_BURGUNDY; + /* This should be verified on older screamers */ + if (device_is_compatible(sound, "screamer")) + awacs_is_screamer = 1; + prop = (unsigned int *)get_property(sound, "device-id", 0); + if (prop != 0) + awacs_device_id = *prop; + awacs_has_iic = (find_devices("perch") != NULL); /* look for a property saying what sample rates are available */ @@ -2029,10 +2050,12 @@ #ifdef CONFIG_PMAC_PBOOK if (machine_is_compatible("PowerBook1,1") || machine_is_compatible("AAPL,PowerBook1998")) { + pmu_suspend(); feature_set(np, FEATURE_Sound_CLK_enable); feature_set(np, FEATURE_Sound_power); /* Shorter delay will not work */ mdelay(1000); + pmu_resume(); } #endif awacs_tx_cmds = (volatile struct dbdma_cmd *) @@ -2050,16 +2073,28 @@ awacs_reg[0] = MASK_MUX_CD; - awacs_reg[1] = MASK_LOOPTHRU | MASK_PAROUT; + /* FIXME: Only machines with external SRS module need MASK_PAROUT */ + awacs_reg[1] = MASK_LOOPTHRU; + if (awacs_has_iic || awacs_device_id == 0x5 || /*awacs_device_id == 0x8 + || */awacs_device_id == 0xb) + awacs_reg[1] |= MASK_PAROUT; /* get default volume from nvram */ vol = (~nvram_read_byte(0x1308) & 7) << 1; awacs_reg[2] = vol + (vol << 6); awacs_reg[4] = vol + (vol << 6); + awacs_reg[5] = 0; + awacs_reg[6] = 0; + awacs_reg[7] = 0; out_le32(&awacs->control, 0x11); awacs_write(awacs_reg[0] + MASK_ADDR0); awacs_write(awacs_reg[1] + MASK_ADDR1); awacs_write(awacs_reg[2] + MASK_ADDR2); awacs_write(awacs_reg[4] + MASK_ADDR4); + if (awacs_is_screamer) { + awacs_write(awacs_reg[5] + MASK_ADDR5); + awacs_write(awacs_reg[6] + MASK_ADDR6); + awacs_write(awacs_reg[7] + MASK_ADDR7); + } /* Initialize recent versions of the awacs */ if (awacs_revision == 0) { @@ -2118,7 +2153,15 @@ break; } } - /* enable CD sound input */ + /* + * Enable CD sound input. + * The relevant bits for writing to this byte are 0x8f. + * I haven't found out what the 0x80 bit does. + * For the 0xf bits, writing 3 or 7 enables the CD + * input, any other value disables it. Values + * 1, 3, 5, 7 enable the microphone. Values 0, 2, + * 4, 6, 8 - f enable the input from the modem. + */ if (macio_base) out_8(macio_base + 0x37, 3); } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/emu10k1/audio.c linux/drivers/sound/emu10k1/audio.c --- v2.4.0-test8/linux/drivers/sound/emu10k1/audio.c Tue Aug 29 14:09:15 2000 +++ linux/drivers/sound/emu10k1/audio.c Thu Sep 21 13:25:09 2000 @@ -363,6 +363,7 @@ if (get_user(val, (int *) arg)) return -EFAULT; + DPD(2, "val is %d\n", val); if (val > 0) { @@ -418,6 +419,7 @@ if (get_user(val, (int *) arg)) return -EFAULT; + DPD(2, " val is %d\n", val); if (file->f_mode & FMODE_READ) { @@ -464,6 +466,7 @@ if (get_user(val, (int *) arg)) return -EFAULT; + DPD(2, " val is %d\n", val); if (val > 0) { @@ -527,6 +530,7 @@ if (get_user(val, (int *) arg)) return -EFAULT; + DPD(2, " val is %d\n", val); if (val != AFMT_QUERY) { diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/emu10k1/ecard.h linux/drivers/sound/emu10k1/ecard.h --- v2.4.0-test8/linux/drivers/sound/emu10k1/ecard.h Mon Aug 14 08:32:48 2000 +++ linux/drivers/sound/emu10k1/ecard.h Fri Sep 22 14:21:17 2000 @@ -29,6 +29,7 @@ #include "8010.h" #include "hwaccess.h" #include +#include /* In A1 Silicon, these bits are in the HC register */ #define HOOKN_BIT (1L << 12) diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/emu10k1/emu_wrapper.h linux/drivers/sound/emu10k1/emu_wrapper.h --- v2.4.0-test8/linux/drivers/sound/emu10k1/emu_wrapper.h Mon Aug 14 08:32:48 2000 +++ linux/drivers/sound/emu10k1/emu_wrapper.h Sun Sep 17 09:45:06 2000 @@ -5,9 +5,4 @@ #define PCI_SET_DMA_MASK(pdev,mask) (((pdev)->dma_mask) = (mask)) -#ifndef PCI_GET_DRIVER_DATA - #define PCI_GET_DRIVER_DATA(pdev) ((pdev)->driver_data) - #define PCI_SET_DRIVER_DATA(pdev,data) (((pdev)->driver_data) = (data)) -#endif /* PCI_GET_DRIVER_DATA */ - #endif diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/emu10k1/main.c linux/drivers/sound/emu10k1/main.c --- v2.4.0-test8/linux/drivers/sound/emu10k1/main.c Mon Aug 14 08:32:48 2000 +++ linux/drivers/sound/emu10k1/main.c Thu Sep 21 13:25:09 2000 @@ -121,14 +121,14 @@ /* stereo voice */ card->waveout.send_a[1] = 0x00; - card->waveout.send_b[1] = 0xff; - card->waveout.send_c[1] = 0x00; + card->waveout.send_b[1] = 0x00; + card->waveout.send_c[1] = 0xff; card->waveout.send_d[1] = 0x00; card->waveout.send_routing[1] = 0xd01c; card->waveout.send_a[2] = 0x00; - card->waveout.send_b[2] = 0x00; - card->waveout.send_c[2] = 0xff; + card->waveout.send_b[2] = 0xff; + card->waveout.send_c[2] = 0x00; card->waveout.send_d[2] = 0x00; card->waveout.send_routing[2] = 0xd01c; @@ -641,7 +641,7 @@ return -ENODEV; } - PCI_SET_DRIVER_DATA(pci_dev, card); + pci_set_drvdata(pci_dev, card); PCI_SET_DMA_MASK(pci_dev, EMU10K1_DMA_MASK); card->irq = pci_dev->irq; @@ -736,7 +736,7 @@ static void __devexit emu10k1_remove(struct pci_dev *pci_dev) { - struct emu10k1_card *card = PCI_GET_DRIVER_DATA(pci_dev); + struct emu10k1_card *card = pci_get_drvdata(pci_dev); midi_exit(card); emu10k1_exit(card); @@ -755,7 +755,7 @@ kfree(card); - return; + pci_set_drvdata(pci_dev, NULL); } MODULE_AUTHOR("Bertrand Lee, Cai Ying. (Email to: emu10k1-devel@opensource.creative.com)"); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/emu10k1/midi.c linux/drivers/sound/emu10k1/midi.c --- v2.4.0-test8/linux/drivers/sound/emu10k1/midi.c Mon Aug 14 08:32:48 2000 +++ linux/drivers/sound/emu10k1/midi.c Thu Sep 21 13:25:09 2000 @@ -43,7 +43,7 @@ #include "cardmi.h" #include "midi.h" -static spinlock_t midi_spinlock = SPIN_LOCK_UNLOCKED; +static spinlock_t midi_spinlock __attribute((unused)) = SPIN_LOCK_UNLOCKED; static void init_midi_hdr(struct midi_hdr *midihdr) { diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/emu10k1/mixer.c linux/drivers/sound/emu10k1/mixer.c --- v2.4.0-test8/linux/drivers/sound/emu10k1/mixer.c Tue Aug 29 14:09:15 2000 +++ linux/drivers/sound/emu10k1/mixer.c Thu Sep 21 13:25:09 2000 @@ -1040,6 +1040,7 @@ if (get_user(val, (int *) arg)) return -EFAULT; + i = hweight32(val); if (i == 0) return 0; /* val = mixer_recmask(s); */ @@ -1065,6 +1066,7 @@ return -EINVAL; if (get_user(val, (int *) arg)) return -EFAULT; + if (emu10k1_mixer_wrch(card, i, val)) return -EINVAL; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/es1370.c linux/drivers/sound/es1370.c --- v2.4.0-test8/linux/drivers/sound/es1370.c Tue Aug 29 14:09:15 2000 +++ linux/drivers/sound/es1370.c Mon Sep 18 14:57:01 2000 @@ -2593,7 +2593,7 @@ } set_fs(fs); /* store it in the driver field */ - pcidev->driver_data = s; + pci_set_drvdata(pcidev, s); pcidev->dma_mask = 0xffffffff; /* put it into driver list */ list_add_tail(&s->devs, &devs); @@ -2620,7 +2620,7 @@ static void __devinit es1370_remove(struct pci_dev *dev) { - struct es1370_state *s = (struct es1370_state *)dev->driver_data; + struct es1370_state *s = pci_get_drvdata(dev); if (!s) return; @@ -2635,7 +2635,7 @@ unregister_sound_dsp(s->dev_dac); unregister_sound_midi(s->dev_midi); kfree(s); - dev->driver_data = NULL; + pci_set_drvdata(dev, NULL); } static struct pci_device_id id_table[] __devinitdata = { diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/es1371.c linux/drivers/sound/es1371.c --- v2.4.0-test8/linux/drivers/sound/es1371.c Tue Aug 29 14:09:15 2000 +++ linux/drivers/sound/es1371.c Fri Sep 22 17:24:45 2000 @@ -2859,7 +2859,7 @@ /* turn on S/PDIF output driver if requested */ outl(cssr, s->io+ES1371_REG_STATUS); /* store it in the driver field */ - pcidev->driver_data = s; + pci_set_drvdata(pcidev, s); pcidev->dma_mask = 0xffffffff; /* put it into driver list */ list_add_tail(&s->devs, &devs); @@ -2886,7 +2886,7 @@ static void __devinit es1371_remove(struct pci_dev *dev) { - struct es1371_state *s = (struct es1371_state *)dev->driver_data; + struct es1371_state *s = pci_get_drvdata(dev); if (!s) return; @@ -2905,7 +2905,7 @@ unregister_sound_dsp(s->dev_dac); unregister_sound_midi(s->dev_midi); kfree(s); - dev->driver_data = NULL; + pci_set_drvdata(dev, NULL); } static struct pci_device_id id_table[] __devinitdata = { diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/esssolo1.c linux/drivers/sound/esssolo1.c --- v2.4.0-test8/linux/drivers/sound/esssolo1.c Tue Aug 29 14:09:15 2000 +++ linux/drivers/sound/esssolo1.c Wed Sep 27 13:53:57 2000 @@ -2085,12 +2085,11 @@ return -ERESTARTSYS; down(&s->open_sem); } - if (check_region(s->sbbase, FMSYNTH_EXTENT)) { + if (!request_region(s->sbbase, FMSYNTH_EXTENT, "ESS Solo1")) { up(&s->open_sem); printk(KERN_ERR "solo1: FM synth io ports in use, opl3 loaded?\n"); return -EBUSY; } - request_region(s->sbbase, FMSYNTH_EXTENT, "ESS Solo1"); /* init the stuff */ outb(1, s->sbbase); outb(0x20, s->sbbase+1); /* enable waveforms */ @@ -2305,7 +2304,7 @@ if (setup_solo1(s)) goto err; /* store it in the driver field */ - pcidev->driver_data = s; + pci_set_drvdata(pcidev, s); pcidev->dma_mask = dma_mask; /* put it into driver list */ list_add_tail(&s->devs, &devs); @@ -2342,7 +2341,7 @@ static void __devinit solo1_remove(struct pci_dev *dev) { - struct solo1_state *s = (struct solo1_state *)dev->driver_data; + struct solo1_state *s = pci_get_drvdata(dev); if (!s) return; @@ -2363,7 +2362,7 @@ unregister_sound_midi(s->dev_midi); unregister_sound_special(s->dev_dmfm); kfree(s); - dev->driver_data = NULL; + pci_set_drvdata(dev, NULL); } static struct pci_device_id id_table[] __devinitdata = { diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/gus_card.c linux/drivers/sound/gus_card.c --- v2.4.0-test8/linux/drivers/sound/gus_card.c Fri Aug 11 08:26:43 2000 +++ linux/drivers/sound/gus_card.c Sun Sep 17 09:45:05 2000 @@ -198,7 +198,9 @@ } #endif +#ifdef CONFIG_SOUND_GUS16 static int gus16 = 0; +#endif #ifdef CONFIG_SOUND_GUSMAX static int no_wave_dma = 0;/* Set if no dma is to be used for the wave table (GF1 chip) */ @@ -223,12 +225,12 @@ MODULE_PARM(dma, "i"); MODULE_PARM(dma16, "i"); MODULE_PARM(type, "i"); -MODULE_PARM(gus16, "i"); #ifdef CONFIG_SOUND_GUSMAX MODULE_PARM(no_wave_dma, "i"); #endif #ifdef CONFIG_SOUND_GUS16 MODULE_PARM(db16, "i"); +MODULE_PARM(gus16, "i"); #endif static int __init init_gus(void) diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/mad16.c linux/drivers/sound/mad16.c --- v2.4.0-test8/linux/drivers/sound/mad16.c Fri Aug 11 08:26:43 2000 +++ linux/drivers/sound/mad16.c Wed Sep 27 13:53:56 2000 @@ -66,6 +66,7 @@ * Paul Grayson Added support for Midi on later Mozart cards. * 25-Nov-1999 * Christoph Hellwig Adapted to module_init/module_exit. + * Arnaldo C. de Melo got rid of attach_uart401 21-Sep-2000 */ #include @@ -714,28 +715,6 @@ request_region(hw_config->io_base, 4, "MAD16 WSS config"); } -static void __init attach_mad16_mpu(struct address_info *hw_config) -{ -#ifdef CONFIG_MAD16_OLDCARD - - if (mad_read(MC1_PORT) & 0x20) - hw_config->io_base = 0x240; - else - hw_config->io_base = 0x220; - - hw_config->name = "Mad16/Mozart"; - sb_dsp_init(hw_config, THIS_MODULE); - return; -#endif - - if (!already_initialized) - return; - - hw_config->driver_use_1 = SB_MIDI_ONLY; - hw_config->name = "Mad16/Mozart"; - attach_uart401(hw_config, THIS_MODULE); -} - static int __init probe_mad16_mpu(struct address_info *hw_config) { static int mpu_attached = 0; @@ -791,7 +770,17 @@ mad_write(MC3_PORT, tmp | 0x04); hw_config->driver_use_1 = SB_MIDI_ONLY; - return sb_dsp_detect(hw_config, 0, 0, NULL); + if (!sb_dsp_detect(hw_config, 0, 0, NULL)) + return 0; + + if (mad_read(MC1_PORT) & 0x20) + hw_config->io_base = 0x240; + else + hw_config->io_base = 0x220; + + hw_config->name = "Mad16/Mozart"; + sb_dsp_init(hw_config, THIS_MODULE); + return 1; #else /* assuming all later Mozart cards are identified as * either 82C928 or Mozart. If so, following code attempts @@ -845,8 +834,7 @@ } mad_write(MC8_PORT, tmp); /* write MPU port parameters */ - - return probe_uart401(hw_config); + goto probe_401; #endif } tmp = mad_read(MC6_PORT) & 0x83; @@ -888,8 +876,12 @@ } } mad_write(MC6_PORT, tmp); /* Write MPU401 config */ - - return probe_uart401(hw_config); +#ifndef CONFIG_MAD16_OLDCARD +probe_401: +#endif + hw_config->driver_use_1 = SB_MIDI_ONLY; + hw_config->name = "Mad16/Mozart"; + return probe_uart401(hw_config, THIS_MODULE); } static void __exit unload_mad16(struct address_info *hw_config) @@ -1090,10 +1082,6 @@ attach_mad16(&cfg); found_mpu = probe_mad16_mpu(&cfg_mpu); - - if (found_mpu) - attach_mad16_mpu(&cfg_mpu); - return 0; } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/mpu401.h linux/drivers/sound/mpu401.h --- v2.4.0-test8/linux/drivers/sound/mpu401.h Fri Aug 11 08:26:43 2000 +++ linux/drivers/sound/mpu401.h Wed Sep 27 13:53:56 2000 @@ -6,8 +6,7 @@ */ /* From uart401.c */ -int probe_uart401 (struct address_info *hw_config); -void attach_uart401 (struct address_info *hw_config, struct module *owner); +int probe_uart401 (struct address_info *hw_config, struct module *owner); void unload_uart401 (struct address_info *hw_config); void uart401intr (int irq, void *dev_id, struct pt_regs * dummy); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/msnd_pinnacle.c linux/drivers/sound/msnd_pinnacle.c --- v2.4.0-test8/linux/drivers/sound/msnd_pinnacle.c Mon Aug 7 21:01:35 2000 +++ linux/drivers/sound/msnd_pinnacle.c Mon Sep 25 12:32:54 2000 @@ -1610,10 +1610,6 @@ static int fifosize __initdata = DEFFIFOSIZE; static int calibrate_signal __initdata; -/* If we're a module, this is just init_module */ - -int init_module(void) - #else /* not a module */ static int write_ndelay __initdata = -1; @@ -1692,14 +1688,10 @@ #endif static int calibrate_signal __initdata = CONFIG_MSND_CALSIGNAL; +#endif /* MODULE */ -#ifdef MSND_CLASSIC -int __init msnd_classic_init(void) -#else -int __init msnd_pinnacle_init(void) -#endif /* MSND_CLASSIC */ -#endif /* MODULE */ +static int __init msnd_init(void) { int err; #ifndef MSND_CLASSIC @@ -1875,11 +1867,12 @@ return 0; } -#ifdef MODULE -void cleanup_module(void) +static void __exit msdn_cleanup(void) { unload_multisound(); msnd_fifo_free(&dev.DAPF); msnd_fifo_free(&dev.DARF); } -#endif + +module_init(msnd_init); +module_exit(msdn_cleanup); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/opl3.c linux/drivers/sound/opl3.c --- v2.4.0-test8/linux/drivers/sound/opl3.c Fri Aug 11 08:26:43 2000 +++ linux/drivers/sound/opl3.c Sun Sep 17 09:45:06 2000 @@ -15,6 +15,8 @@ * Thomas Sailer ioctl code reworked (vmalloc/vfree removed) * Alan Cox modularisation, fixed sound_mem allocs. * Christoph Hellwig Adapted to module_init/module_exit + * Arnaldo C. de Melo get rid of check_region, use request_region for + * OPL4, release it on exit, some cleanups. * * Status * Believed to work. Badly needs rewriting a bit to support multiple @@ -172,6 +174,15 @@ "structure \n "); return 0; } + + memset(devc, 0, sizeof(*devc)); + strcpy(devc->fm_info.name, "OPL2"); + + if (!request_region(ioaddr, 4, devc->fm_info.name)) { + printk(KERN_WARNING "opl3: I/O port 0x%x already in use\n", ioaddr); + goto cleanup_devc; + } + devc->osp = osp; devc->base = ioaddr; @@ -187,7 +198,7 @@ signature != 0x0f) { MDB(printk(KERN_INFO "OPL3 not detected %x\n", signature)); - return 0; + goto cleanup_region; } if (signature == 0x06) /* OPL2 */ @@ -214,7 +225,7 @@ detected_model = 4; } - if (!check_region(ioaddr - 8, 2)) /* OPL4 port is free */ + if (request_region(ioaddr - 8, 2, "OPL4")) /* OPL4 port was free */ { int tmp; @@ -232,7 +243,10 @@ udelay(10); } else + { /* release OPL4 port */ + release_region(ioaddr - 8, 2); detected_model = 3; + } } opl3_command(ioaddr + 2, OPL3_MODE_REGISTER, 0); } @@ -246,6 +260,12 @@ * Melodic mode. */ return 1; +cleanup_region: + release_region(ioaddr, 4); +cleanup_devc: + kfree(devc); + devc = NULL; + return 0; } static int opl3_kill_note (int devno, int voice, int note, int velocity) @@ -1099,12 +1119,7 @@ return -1; } - memset((char *) devc, 0x00, sizeof(*devc)); - devc->osp = osp; - devc->base = ioaddr; - devc->nr_voice = 9; - strcpy(devc->fm_info.name, "OPL2"); devc->fm_info.device = 0; devc->fm_info.synth_type = SYNTH_TYPE_FM; @@ -1191,18 +1206,12 @@ if (io != -1) /* User loading pure OPL3 module */ { - if (check_region(io, 4)) - { - printk(KERN_WARNING "opl3: I/O port 0x%x already in use\n", io); - return 0; - } if (!opl3_detect(io, NULL)) { return -ENODEV; } - me = opl3_init(io, NULL, THIS_MODULE); - request_region(io, 4, devc->fm_info.name); + me = opl3_init(io, NULL, THIS_MODULE); } return 0; @@ -1212,8 +1221,11 @@ { if (devc && io != -1) { - if(devc->base) + if (devc->base) { release_region(devc->base,4); + if (devc->is_opl4) + release_region(devc->base - 8, 2); + } kfree(devc); devc = NULL; sound_unload_synthdev(me); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/opl3sa.c linux/drivers/sound/opl3sa.c --- v2.4.0-test8/linux/drivers/sound/opl3sa.c Fri Aug 11 08:26:43 2000 +++ linux/drivers/sound/opl3sa.c Wed Sep 27 13:53:56 2000 @@ -14,6 +14,7 @@ * Changes: * Alan Cox Modularisation * Christoph Hellwig Adapted to module_init/module_exit + * Arnaldo C. de Melo got rid of attach_uart401 * * FIXME: * Check for install of mpu etc is wrong, should check result of the mss stuff @@ -176,12 +177,6 @@ } -static void __init attach_opl3sa_mpu(struct address_info *hw_config) -{ - hw_config->name = "OPL3-SA (MPU401)"; - attach_uart401(hw_config, THIS_MODULE); -} - static int __init probe_opl3sa_mpu(struct address_info *hw_config) { unsigned char conf; @@ -197,11 +192,6 @@ DDB(printk("OPL3-SA: MPU mode already initialized\n")); return 0; } - if (check_region(hw_config->io_base, 4)) - { - printk(KERN_ERR "OPL3-SA: MPU I/O port conflict (%x)\n", hw_config->io_base); - return 0; - } if (hw_config->irq > 10) { printk(KERN_ERR "OPL3-SA: Bad MPU IRQ %d\n", hw_config->irq); @@ -236,8 +226,9 @@ opl3sa_write(0x03, conf); mpu_initialized = 1; + hw_config->name = "OPL3-SA (MPU401)"; - return probe_uart401(hw_config); + return probe_uart401(hw_config, THIS_MODULE); } static void __exit unload_opl3sa_wss(struct address_info *hw_config) @@ -310,9 +301,6 @@ found_mpu=probe_opl3sa_mpu(&cfg_mpu); attach_opl3sa_wss(&cfg); - if(found_mpu) - attach_opl3sa_mpu(&cfg_mpu); - return 0; } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/pss.c linux/drivers/sound/pss.c --- v2.4.0-test8/linux/drivers/sound/pss.c Fri Aug 11 08:26:43 2000 +++ linux/drivers/sound/pss.c Mon Sep 18 15:02:02 2000 @@ -24,8 +24,32 @@ * To probe_pss_mss added test for initialize AD1848 * 98-05-28: Vladimir Michl * Fixed computation of mixer volumes + * 04-05-1999: Anthony Barbachan + * Added code that allows the user to enable his cdrom and/or + * joystick through the module parameters pss_cdrom_port and + * pss_enable_joystick. pss_cdrom_port takes a port address as its + * argument. pss_enable_joystick takes either a 0 or a non-0 as its + * argument. + * 04-06-1999: Anthony Barbachan + * Separated some code into new functions for easier reuse. + * Cleaned up and streamlined new code. Added code to allow a user + * to only use this driver for enabling non-sound components + * through the new module parameter pss_no_sound (flag). Added + * code that would allow a user to decide whether the driver should + * reset the configured hardware settings for the PSS board through + * the module parameter pss_keep_settings (flag). This flag will + * allow a user to free up resources in use by this card if needbe, + * furthermore it allows him to use this driver to just enable the + * emulations and then be unloaded as it is no longer needed. Both + * new settings are only available to this driver if compiled as a + * module. The default settings of all new parameters are set to + * load the driver as it did in previous versions. + * 04-07-1999: Anthony Barbachan + * Added module parameter pss_firmware to allow the user to tell + * the driver where the fireware file is located. The default + * setting is the previous hardcoded setting "/etc/sound/pss_synth". * 00-03-03: Christoph Hellwig - * Adapted to module_init/module_exit + * Adapted to module_init/module_exit */ @@ -84,6 +108,7 @@ #define NO_WSS_MIXER -1 #include "coproc.h" + #include "pss_boot.h" /* If compiled into kernel, it enable or disable pss mixer */ @@ -116,6 +141,8 @@ static int pss_initialized = 0; static int nonstandard_microcode = 0; +static int pss_cdrom_port = -1; /* Parameter for the PSS cdrom port */ +static int pss_enable_joystick = 0;/* Parameter for enabling the joystick */ static void pss_write(pss_confdata *devc, int data) { @@ -574,6 +601,49 @@ ioctl: pss_mixer_ioctl }; +void disable_all_emulations(void) +{ + outw(0x0000, REG(CONF_PSS)); /* 0x0400 enables joystick */ + outw(0x0000, REG(CONF_WSS)); + outw(0x0000, REG(CONF_SB)); + outw(0x0000, REG(CONF_MIDI)); + outw(0x0000, REG(CONF_CDROM)); +} + +void configure_nonsound_components(void) +{ + /* Configure Joystick port */ + + if(pss_enable_joystick) + { + outw(0x0400, REG(CONF_PSS)); /* 0x0400 enables joystick */ + printk(KERN_INFO "PSS: joystick enabled.\n"); + } + else + { + printk(KERN_INFO "PSS: joystick port not enabled.\n"); + } + + /* Configure CDROM port */ + + if(pss_cdrom_port == -1) /* If cdrom port enablation wasn't requested */ + { + printk(KERN_INFO "PSS: CDROM port not enabled.\n"); + } + else if(check_region(pss_cdrom_port, 2)) + { + printk(KERN_ERR "PSS: CDROM I/O port conflict.\n"); + } + else if(!set_io_base(devc, CONF_CDROM, pss_cdrom_port)) + { + printk(KERN_ERR "PSS: CDROM I/O port could not be set.\n"); + } + else /* CDROM port successfully configured */ + { + printk(KERN_INFO "PSS: CDROM I/O port set to 0x%x.\n", pss_cdrom_port); + } +} + void attach_pss(struct address_info *hw_config) { unsigned short id; @@ -594,13 +664,10 @@ id = inw(REG(PSS_ID)) & 0x00ff; /* - * Disable all emulations. Will be enabled later (if required). + * Disable all emulations. Will be enabled later (if required). */ - outw(0x0000, REG(CONF_PSS)); /* 0x0400 enables joystick */ - outw(0x0000, REG(CONF_WSS)); - outw(0x0000, REG(CONF_SB)); - outw(0x0000, REG(CONF_MIDI)); - outw(0x0000, REG(CONF_CDROM)); + + disable_all_emulations(); #if YOU_REALLY_WANT_TO_ALLOCATE_THESE_RESOURCES if (sound_alloc_dma(hw_config->dma, "PSS")) @@ -620,6 +687,7 @@ } #endif + configure_nonsound_components(); pss_initialized = 1; sprintf(tmp, "ECHO-PSS Rev. %d", id); conf_printf(tmp, hw_config); @@ -1028,6 +1096,9 @@ static int mss_dma __initdata = -1; static int mpu_io __initdata = -1; static int mpu_irq __initdata = -1; +static int pss_no_sound __initdata = 0; /* Just configure non-sound components */ +static int pss_keep_settings = 1; /* Keep hardware settings at module exit */ +static char *pss_firmware = "/etc/sound/pss_synth"; MODULE_PARM(pss_io, "i"); MODULE_PARM_DESC(pss_io, "Set i/o base of PSS card (probably 0x220 or 0x240)"); @@ -1041,6 +1112,16 @@ MODULE_PARM_DESC(mpu_io, "Set MIDI i/o base (0x330 or other. Address must be on 4 location boundaries and must be from 0x100 to 0xFFC)"); MODULE_PARM(mpu_irq, "i"); MODULE_PARM_DESC(mpu_irq, "Set MIDI IRQ (3, 5, 7, 9, 10, 11, 12)"); +MODULE_PARM(pss_cdrom_port, "i"); +MODULE_PARM_DESC(pss_cdrom_port, "Set the PSS CDROM port i/o base (0x340 or other)"); +MODULE_PARM(pss_enable_joystick, "i"); +MODULE_PARM_DESC(pss_enable_joystick, "Enables the PSS joystick port (1 to enable, 0 to disable)"); +MODULE_PARM(pss_no_sound, "i"); +MODULE_PARM_DESC(pss_no_sound, "Configure sound compoents (0 - no, 1 - yes)"); +MODULE_PARM(pss_keep_settings, "i"); +MODULE_PARM_DESC(pss_keep_settings, "Keep hardware setting at driver unloading (0 - no, 1 - yes)"); +MODULE_PARM(pss_firmware, "s"); +MODULE_PARM_DESC(pss_firmware, "Location of the firmware file (default - /etc/sound/pss_synth)"); MODULE_PARM(pss_mixer, "b"); MODULE_PARM_DESC(pss_mixer, "Enable (1) or disable (0) PSS mixer (controlling of output volume, bass, treble, synth volume). The mixer is not available on all PSS cards."); MODULE_AUTHOR("Hannu Savolainen, Vladimir Michl"); @@ -1055,6 +1136,19 @@ static int __init init_pss(void) { + + if(pss_no_sound) /* If configuring only nonsound components */ + { + cfg.io_base = pss_io; + if(!probe_pss(&cfg)) + return -ENODEV; + printk(KERN_INFO "ECHO-PSS Rev. %d\n", inw(REG(PSS_ID)) & 0x00ff); + printk(KERN_INFO "PSS: loading in no sound mode.\n"); + disable_all_emulations(); + configure_nonsound_components(); + return 0; + } + cfg.io_base = pss_io; cfg2.io_base = mss_io; @@ -1071,7 +1165,7 @@ if (!pss_synth) { fw_load = 1; - pss_synthLen = mod_firmware_load("/etc/sound/pss_synth", (void *) &pss_synth); + pss_synthLen = mod_firmware_load(pss_firmware, (void *) &pss_synth); } if (!probe_pss(&cfg)) return -ENODEV; @@ -1093,13 +1187,22 @@ static void __exit cleanup_pss(void) { - if (fw_load && pss_synth) - vfree(pss_synth); - if (pssmss) - unload_pss_mss(&cfg2); - if (pssmpu) - unload_pss_mpu(&cfg_mpu); - unload_pss(&cfg); + if(!pss_no_sound) + { + if(fw_load && pss_synth) + vfree(pss_synth); + if(pssmss) + unload_pss_mss(&cfg2); + if(pssmpu) + unload_pss_mpu(&cfg_mpu); + unload_pss(&cfg); + } + + if(!pss_keep_settings) /* Keep hardware settings if asked */ + { + disable_all_emulations(); + printk(KERN_INFO "Resetting PSS sound card configurations.\n"); + } } module_init(init_pss); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/sb.h linux/drivers/sound/sb.h --- v2.4.0-test8/linux/drivers/sound/sb.h Fri Aug 11 08:26:43 2000 +++ linux/drivers/sound/sb.h Wed Sep 27 13:53:56 2000 @@ -178,8 +178,7 @@ /* From sb_common.c */ void sb_dsp_disable_midi(int port); void sb_dsp_disable_recording(int port); -void attach_sbmpu (struct address_info *hw_config, struct module *owner); -int probe_sbmpu (struct address_info *hw_config); +int probe_sbmpu (struct address_info *hw_config, struct module *owner); void unload_sbmpu (struct address_info *hw_config); void unload_sb16(struct address_info *hw_info); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/sb_card.c linux/drivers/sound/sb_card.c --- v2.4.0-test8/linux/drivers/sound/sb_card.c Mon Aug 21 09:44:05 2000 +++ linux/drivers/sound/sb_card.c Wed Sep 27 13:53:56 2000 @@ -47,6 +47,9 @@ * * 12-08-2000 Added Creative SB32 PnP (CTL009F). * Kasatenko Ivan Alex. + * + * 21-09-2000 Got rid of attach_sbmpu + * Arnaldo Carvalho de Melo */ #include @@ -524,7 +527,7 @@ return(NULL); /* Cards with separate OPL3 device (ALS, CMI, etc.) - * This is just to activate the device... */ + * This is just to activate the device so the OPL module can use it */ if(sb_isapnp_list[slot].opl_vendor || sb_isapnp_list[slot].opl_function) { if((opl_dev[card] = isapnp_find_dev(bus, sb_isapnp_list[slot].opl_vendor, sb_isapnp_list[slot].opl_function, NULL))) { int ret = opl_dev[card]->prepare(opl_dev[card]); @@ -607,7 +610,7 @@ return 0; } -int __init sb_isapnp_probe(struct address_info *hw_config, struct address_info *mpu_config, int card) +static int __init sb_isapnp_probe(struct address_info *hw_config, struct address_info *mpu_config, int card) { static int first = 1; int i; @@ -647,7 +650,7 @@ static int __init init_sb(void) { - int card, max = multiple ? SB_CARDS_MAX : 1; + int card, max = (multiple && isapnp) ? SB_CARDS_MAX : 1; printk(KERN_INFO "Soundblaster audio driver Copyright (C) by Hannu Savolainen 1993-1996\n"); @@ -658,9 +661,15 @@ * single driver! */ if(isapnp && (sb_isapnp_probe(&cfg[card], &cfg_mpu[card], card) < 0) ) { if(!sb_cards_num) { + /* Found no ISAPnP cards, so check for a non-pnp + * card and set the detection loop for 1 cycle + */ printk(KERN_NOTICE "sb: No ISAPnP cards found, trying standard ones...\n"); isapnp = 0; + max = 1; } else + /* found all the ISAPnP cards so exit the + * detection loop. */ break; } #endif @@ -674,8 +683,21 @@ cfg[card].card_subtype = type; - if (!probe_sb(&cfg[card])) - return -ENODEV; + if (!probe_sb(&cfg[card])) { + /* if one or more cards already registered, don't + * return an error but print a warning. Note, this + * should never really happen unless the hardware + * or ISAPnP screwed up. */ + if (sb_cards_num) { + printk(KERN_WARNING "sb.c: There was a " \ + "problem probing one of your SoundBlaster " \ + "ISAPnP soundcards. Continuing.\n"); + card--; + sb_cards_num--; + continue; + } else + return -ENODEV; + } attach_sb_card(&cfg[card]); if(cfg[card].slots[0]==-1) @@ -683,10 +705,8 @@ if (!isapnp) cfg_mpu[card].io_base = mpu_io; - if (probe_sbmpu(&cfg_mpu[card])) + if (probe_sbmpu(&cfg_mpu[card], THIS_MODULE)) sbmpu[card] = 1; - if (sbmpu[card]) - attach_sbmpu(&cfg_mpu[card], THIS_MODULE); } if(isapnp) diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/sb_common.c linux/drivers/sound/sb_common.c --- v2.4.0-test8/linux/drivers/sound/sb_common.c Fri Aug 11 08:26:43 2000 +++ linux/drivers/sound/sb_common.c Wed Sep 27 13:53:56 2000 @@ -19,6 +19,8 @@ * 2000/01/18 - separated sb_card and sb_common - * Jeff Garzik * + * 2000/09/18 - got rid of attach_uart401 + * Arnaldo Carvalho de Melo */ #include @@ -1190,24 +1192,10 @@ return 1; } -void attach_sbmpu(struct address_info *hw_config, struct module *owner) -{ - if (last_sb->model == MDL_ESS) { -#if defined(CONFIG_SOUND_MPU401) - attach_mpu401(hw_config, owner); - if (last_sb->irq == -hw_config->irq) { - last_sb->midi_irq_cookie=(void *)hw_config->slots[1]; - } -#endif - return; - } - attach_uart401(hw_config, THIS_MODULE); - last_sb->midi_irq_cookie=midi_devs[hw_config->slots[4]]->devc; -} - -int probe_sbmpu(struct address_info *hw_config) +int probe_sbmpu(struct address_info *hw_config, struct module *owner) { sb_devc *devc = last_devc; + int ret; if (last_devc == NULL) return 0; @@ -1239,15 +1227,15 @@ return 0; hw_config->name = "ESS1xxx MPU"; devc->midi_irq_cookie = -1; - return probe_mpu401(hw_config); + if (!probe_mpu401(hw_config)) + return 0; + attach_mpu401(hw_config, owner); + if (last_sb->irq == -hw_config->irq) + last_sb->midi_irq_cookie=(void *)hw_config->slots[1]; + return 1; } #endif - if (check_region(hw_config->io_base, 4)) - { - printk(KERN_ERR "sbmpu: I/O port conflict (%x)\n", hw_config->io_base); - return 0; - } switch (devc->model) { case MDL_SB16: @@ -1277,7 +1265,11 @@ default: return 0; } - return probe_uart401(hw_config); + + ret = probe_uart401(hw_config, owner); + if (ret) + last_sb->midi_irq_cookie=midi_devs[hw_config->slots[4]]->devc; + return ret; } void unload_sbmpu(struct address_info *hw_config) @@ -1296,7 +1288,6 @@ EXPORT_SYMBOL(sb_dsp_unload); EXPORT_SYMBOL(sb_dsp_disable_midi); EXPORT_SYMBOL(sb_be_quiet); -EXPORT_SYMBOL(attach_sbmpu); EXPORT_SYMBOL(probe_sbmpu); EXPORT_SYMBOL(unload_sbmpu); EXPORT_SYMBOL(smw_free); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/sequencer.c linux/drivers/sound/sequencer.c --- v2.4.0-test8/linux/drivers/sound/sequencer.c Fri Aug 11 08:26:44 2000 +++ linux/drivers/sound/sequencer.c Mon Sep 25 12:32:54 2000 @@ -18,9 +18,6 @@ #define SEQUENCER_C #include "sound_config.h" -#include "softoss.h" - -int (*softsynthp) (int cmd, int parm1, int parm2, unsigned long parm3) = NULL; #include "midi_ctrl.h" @@ -170,10 +167,7 @@ if (data == 0xfe) /* Ignore active sensing */ return; - if (softsynthp != NULL) - tstamp = softsynthp(SSYN_GETTIME, 0, 0, 0); - else - tstamp = jiffies - seq_time; + tstamp = jiffies - seq_time; if (tstamp != prev_input_time) { @@ -195,8 +189,6 @@ if (seq_mode == SEQ_2) this_time = tmr->get_time(tmr_no); - else if (softsynthp != NULL) - this_time = softsynthp(SSYN_GETTIME, 0, 0, 0); else this_time = jiffies - seq_time; @@ -659,10 +651,7 @@ prev_event_time = time; seq_playing = 1; - if (softsynthp != NULL) - softsynthp(SSYN_REQUEST, time, 0, 0); - else - request_sound_timer(time); + request_sound_timer(time); if ((SEQ_MAX_QUEUE - qlen) >= output_threshold) wake_up(&seq_sleeper); @@ -671,13 +660,7 @@ break; case TMR_START: - if (softsynthp != NULL) - { - softsynthp(SSYN_START, 0, 0, 0); - seq_time = 0; - } - else - seq_time = jiffies; + seq_time = jiffies; prev_input_time = 0; prev_event_time = 0; break; @@ -785,10 +768,7 @@ time = *delay; prev_event_time = time; - if (softsynthp != NULL) - softsynthp(SSYN_REQUEST, time, 0, 0); - else - request_sound_timer(time); + request_sound_timer(time); if ((SEQ_MAX_QUEUE - qlen) >= output_threshold) wake_up(&seq_sleeper); @@ -809,14 +789,9 @@ case SEQ_SYNCTIMER: /* * Reset timer */ - if (softsynthp != NULL) - seq_time = 0; - else - seq_time = jiffies; + seq_time = jiffies; prev_input_time = 0; prev_event_time = 0; - if (softsynthp != NULL) - softsynthp(SSYN_START, 0, 0, 0); break; case SEQ_MIDIPUTC: /* @@ -838,10 +813,7 @@ */ seq_playing = 1; - if (softsynthp != NULL) - softsynthp(SSYN_REQUEST, -1, 0, 0); - else - request_sound_timer(-1); + request_sound_timer(-1); return 2; } else @@ -1085,15 +1057,10 @@ } } - if (softsynthp != NULL) - seq_time = 0; - else - seq_time = jiffies; + seq_time = jiffies; prev_input_time = 0; prev_event_time = 0; - if (softsynthp != NULL) - softsynthp(SSYN_START, 0, 0, 0); if (seq_mode == SEQ_1 && (mode == OPEN_READ || mode == OPEN_READWRITE)) { @@ -1280,10 +1247,7 @@ int chn; unsigned long flags; - if (softsynthp != NULL) - softsynthp(SSYN_STOP, 0, 0, 0); - else - sound_stop_timer(); + sound_stop_timer(); seq_time = jiffies; prev_input_time = 0; @@ -1449,10 +1413,7 @@ case SNDCTL_SEQ_GETTIME: if (seq_mode == SEQ_2) return tmr->ioctl(tmr_no, cmd, arg); - if (softsynthp != NULL) - val = softsynthp(SSYN_GETTIME, 0, 0, 0); - else - val = jiffies - seq_time; + val = jiffies - seq_time; break; case SNDCTL_SEQ_CTRLRATE: diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/sequencer_syms.c linux/drivers/sound/sequencer_syms.c --- v2.4.0-test8/linux/drivers/sound/sequencer_syms.c Thu Feb 24 22:12:57 2000 +++ linux/drivers/sound/sequencer_syms.c Mon Sep 25 12:32:54 2000 @@ -23,10 +23,6 @@ EXPORT_SYMBOL(sound_timer_syncinterval); EXPORT_SYMBOL(reprogram_timer); -#include "softoss.h" - -EXPORT_SYMBOL(softsynthp); - /* Tuning */ #define _SEQUENCER_C_ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/softoss.c linux/drivers/sound/softoss.c --- v2.4.0-test8/linux/drivers/sound/softoss.c Fri Aug 11 08:26:44 2000 +++ linux/drivers/sound/softoss.c Wed Dec 31 16:00:00 1969 @@ -1,1532 +0,0 @@ -/* - * sound/softoss.c - * - * Software based MIDI synthsesizer driver. - * - * - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - * - * - * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) - * Christoph Hellwig : adapted to module_init/module_exit - */ - -#include -#include -#include - -/* - * When POLLED_MODE is defined, the resampling loop is run using a timer - * callback routine. Normally the resampling loop is executed inside - * audio buffer interrupt handler which doesn't work with single mode DMA. - */ -#define SOFTSYN_MAIN -#undef POLLED_MODE -#define HANDLE_LFO - -#define ENVELOPE_SCALE 8 -#define NO_SAMPLE 0xffff - -#include "sound_config.h" -#include "softoss.h" -#include - -int softsynth_disabled = 0; - -static volatile int intr_pending = 0; - -#ifdef POLLED_MODE - -static struct timer_list poll_timer = { - NULL, NULL, 0, 0, softsyn_poll -}; - -#else -#endif - -#ifdef HANDLE_LFO -/* - * LFO table. Playback at 128 Hz gives 1 Hz LFO frequency. - */ -static int tremolo_table[128] = -{ - 0, 39, 158, 355, 630, 982, 1411, 1915, - 2494, 3146, 3869, 4662, 5522, 6448, 7438, 8489, - 9598, 10762, 11980, 13248, 14563, 15922, 17321, 18758, - 20228, 21729, 23256, 24806, 26375, 27960, 29556, 31160, - 32768, 34376, 35980, 37576, 39161, 40730, 42280, 43807, - 45308, 46778, 48215, 49614, 50973, 52288, 53556, 54774, - 55938, 57047, 58098, 59088, 60014, 60874, 61667, 62390, - 63042, 63621, 64125, 64554, 64906, 65181, 65378, 65497, - 65536, 65497, 65378, 65181, 64906, 64554, 64125, 63621, - 63042, 62390, 61667, 60874, 60014, 59087, 58098, 57047, - 55938, 54774, 53556, 52288, 50973, 49614, 48215, 46778, - 45308, 43807, 42280, 40730, 39161, 37576, 35980, 34376, - 32768, 31160, 29556, 27960, 26375, 24806, 23256, 21729, - 20228, 18758, 17321, 15922, 14563, 13248, 11980, 10762, - 9598, 8489, 7438, 6448, 5522, 4662, 3869, 3146, - 2494, 1915, 1411, 982, 630, 355, 158, 39 -}; - -static int vibrato_table[128] = -{ - 0, 1608, 3212, 4808, 6393, 7962, 9512, 11039, - 12540, 14010, 15447, 16846, 18205, 19520, 20788, 22006, - 23170, 24279, 25330, 26320, 27246, 28106, 28899, 29622, - 30274, 30853, 31357, 31786, 32138, 32413, 32610, 32729, - 32768, 32729, 32610, 32413, 32138, 31786, 31357, 30853, - 30274, 29622, 28899, 28106, 27246, 26320, 25330, 24279, - 23170, 22006, 20788, 19520, 18205, 16846, 15447, 14010, - 12540, 11039, 9512, 7962, 6393, 4808, 3212, 1608, - 0, -1608, -3212, -4808, -6393, -7962, -9512, -11039, - -12540, -14010, -15447, -16846, -18205, -19520, -20788, -22006, - -23170, -24279, -25330, -26320, -27246, -28106, -28899, -29622, - -30274, -30853, -31357, -31786, -32138, -32413, -32610, -32729, - -32768, -32729, -32610, -32413, -32138, -31786, -31357, -30853, - -30274, -29622, -28899, -28106, -27246, -26320, -25330, -24279, - -23170, -22006, -20788, -19520, -18205, -16846, -15447, -14010, - -12540, -11039, -9512, -7962, -6393, -4808, -3212, -1608 -}; - -#endif - -static unsigned long last_resample_jiffies; -static unsigned long resample_counter; - -extern int *sound_osp; - -static volatile int is_running = 0; -static int softsynth_loaded = 0; - -static struct synth_info softsyn_info = { - "SoftOSS", 0, SYNTH_TYPE_SAMPLE, SAMPLE_TYPE_GUS, 0, 16, 0, MAX_PATCH -}; - -static struct softsyn_devc sdev_info = { - 0 -}; - -softsyn_devc *devc = &sdev_info; /* used in softoss_rs.c */ - -static struct voice_alloc_info *voice_alloc; - -static int softsyn_open(int synthdev, int mode); -static void init_voice(softsyn_devc * devc, int voice); -static void compute_step(int voice); - -static volatile int tmr_running = 0; -static int voice_limit = 24; - - -static void set_max_voices(int nr) -{ - int i; - - if (nr < 4) - nr = 4; - - if (nr > voice_limit) - nr = voice_limit; - - voice_alloc->max_voice = devc->maxvoice = nr; - devc->afterscale = 5; - - for (i = 31; i > 0; i--) - if (nr & (1 << i)) - { - devc->afterscale = i + 1; - return; - } -} - -static void update_vibrato(int voice) -{ - voice_info *v = &softoss_voices[voice]; - -#ifdef HANDLE_LFO - int x; - - x = vibrato_table[v->vibrato_phase >> 8]; - v->vibrato_phase = (v->vibrato_phase + v->vibrato_step) & 0x7fff; - - x = (x * v->vibrato_depth) >> 15; - v->vibrato_level = (x * 600) >> 8; - - compute_step(voice); -#else - v->vibrato_level = 0; -#endif -} - -#ifdef HANDLE_LFO -static void update_tremolo(int voice) -{ - voice_info *v = &softoss_voices[voice]; - int x; - - x = tremolo_table[v->tremolo_phase >> 8]; - v->tremolo_phase = (v->tremolo_phase + v->tremolo_step) & 0x7fff; - - v->tremolo_level = (x * v->tremolo_depth) >> 20; -} -#endif - -static void start_vibrato(int voice) -{ - voice_info *v = &softoss_voices[voice]; - int rate; - - if (!v->vibrato_depth) - return; - - rate = v->vibrato_rate * 6 * 128; - v->vibrato_step = (rate * devc->control_rate) / devc->speed; - - devc->vibratomap |= (1 << voice); /* Enable vibrato */ -} - -static void start_tremolo(int voice) -{ - voice_info *v = &softoss_voices[voice]; - int rate; - - if (!v->tremolo_depth) - return; - - rate = v->tremolo_rate * 6 * 128; - v->tremolo_step = (rate * devc->control_rate) / devc->speed; - - devc->tremolomap |= (1 << voice); /* Enable tremolo */ -} - -static void update_volume(int voice) -{ - voice_info *v = &softoss_voices[voice]; - unsigned int vol; - - /* - * Compute plain volume - */ - - vol = (v->velocity * v->expression_vol * v->main_vol) >> 12; - -#ifdef HANDLE_LFO - /* - * Handle LFO - */ - - if (devc->tremolomap & (1 << voice)) - { - int t; - - t = 32768 - v->tremolo_level; - vol = (vol * t) >> 15; - update_tremolo(voice); - } -#endif - /* - * Envelope - */ - - if (v->mode & WAVE_ENVELOPES && !v->percussive_voice) - vol = (vol * (v->envelope_vol >> 16)) >> 19; - else - vol >>= 4; - - /* - * Handle panning - */ - - if (v->panning < 0) /* Pan left */ - v->rightvol = (vol * (128 + v->panning)) / 128; - else - v->rightvol = vol; - - if (v->panning > 0) /* Pan right */ - v->leftvol = (vol * (128 - v->panning)) / 128; - else - v->leftvol = vol; -} - -static void step_envelope(int voice, int do_release, int velocity) -{ - voice_info *v = &softoss_voices[voice]; - int r, rate, time, dif; - unsigned int vol; - unsigned long flags; - - save_flags(flags); - cli(); - - if (!voice_active[voice] || v->sample == NULL) - { - restore_flags(flags); - return; - } - if (!do_release) - { - if (v->mode & WAVE_SUSTAIN_ON && v->envelope_phase == 2) - { - /* Stop envelope until note off */ - v->envelope_volstep = 0; - v->envelope_time = 0x7fffffff; - if (v->mode & WAVE_VIBRATO) - start_vibrato(voice); - if (v->mode & WAVE_TREMOLO) - start_tremolo(voice); - restore_flags(flags); - return; - } - } - if (do_release) - v->envelope_phase = 3; - else - v->envelope_phase++; - - if (v->envelope_phase >= 5) /* Finished */ - { - init_voice(devc, voice); - restore_flags(flags); - return; - } - vol = v->envelope_target = v->sample->env_offset[v->envelope_phase] << 22; - - - rate = v->sample->env_rate[v->envelope_phase]; - r = 3 - ((rate >> 6) & 0x3); - r *= 3; - r = (int) (rate & 0x3f) << r; - rate = (((r * 44100) / devc->speed) * devc->control_rate) << 8; - - if (rate < (1 << 20)) /* Avoid infinitely "releasing" voices */ - rate = 1 << 20; - - dif = (v->envelope_vol - vol); - if (dif < 0) - dif *= -1; - if (dif < rate * 2) /* Too close */ - { - step_envelope(voice, 0, 60); - restore_flags(flags); - return; - } - - if (vol > v->envelope_vol) - { - v->envelope_volstep = rate; - time = (vol - v->envelope_vol) / rate; - } - else - { - v->envelope_volstep = -rate; - time = (v->envelope_vol - vol) / rate; - } - - time--; - if (time <= 0) - time = 1; - v->envelope_time = time; - restore_flags(flags); -} - -static void step_envelope_lfo(int voice) -{ - voice_info *v = &softoss_voices[voice]; - - /* - * Update pitch (vibrato) LFO - */ - - if (devc->vibratomap & (1 << voice)) - update_vibrato(voice); - - /* - * Update envelope - */ - - if (v->mode & WAVE_ENVELOPES) - { - v->envelope_vol += v->envelope_volstep; - /* Overshoot protection */ - if (v->envelope_vol < 0) - { - v->envelope_vol = v->envelope_target; - v->envelope_volstep = 0; - } - if (v->envelope_time-- <= 0) - { - v->envelope_vol = v->envelope_target; - step_envelope(voice, 0, 60); - } - } -} - -static void compute_step(int voice) -{ - voice_info *v = &softoss_voices[voice]; - - /* - * Since the pitch bender may have been set before playing the note, we - * have to calculate the bending now. - */ - - v->current_freq = compute_finetune(v->orig_freq, - v->bender, - v->bender_range, - v->vibrato_level); - v->step = (((v->current_freq << 9) + (devc->speed >> 1)) / devc->speed); - - if (v->mode & WAVE_LOOP_BACK) - v->step *= -1; /* Reversed playback */ -} - -static void init_voice(softsyn_devc * devc, int voice) -{ - voice_info *v = &softoss_voices[voice]; - unsigned long flags; - - save_flags(flags); - cli(); - voice_active[voice] = 0; - devc->vibratomap &= ~(1 << voice); - devc->tremolomap &= ~(1 << voice); - v->mode = 0; - v->wave = NULL; - v->sample = NULL; - v->ptr = 0; - v->step = 0; - v->startloop = 0; - v->startbackloop = 0; - v->endloop = 0; - v->looplen = 0; - v->bender = 0; - v->bender_range = 200; - v->panning = 0; - v->main_vol = 127; - v->expression_vol = 127; - v->patch_vol = 127; - v->percussive_voice = 0; - v->sustain_mode = 0; - v->envelope_phase = 1; - v->envelope_vol = 1 << 24; - v->envelope_volstep = 256; - v->envelope_time = 0; - v->vibrato_phase = 0; - v->vibrato_step = 0; - v->vibrato_level = 0; - v->vibrato_rate = 0; - v->vibrato_depth = 0; - v->tremolo_phase = 0; - v->tremolo_step = 0; - v->tremolo_level = 0; - v->tremolo_rate = 0; - v->tremolo_depth = 0; - voice_alloc->map[voice] = 0; - voice_alloc->alloc_times[voice] = 0; - restore_flags(flags); -} - -static void reset_samples(softsyn_devc * devc) -{ - int i; - - for (i = 0; i < MAX_VOICE; i++) - voice_active[i] = 0; - for (i = 0; i < devc->maxvoice; i++) - { - init_voice(devc, i); - softoss_voices[i].instr = 0; - } - - devc->ram_used = 0; - - for (i = 0; i < MAX_PATCH; i++) - devc->programs[i] = NO_SAMPLE; - - for (i = 0; i < devc->nrsamples; i++) - { - vfree(devc->samples[i]); - vfree(devc->wave[i]); - devc->samples[i] = NULL; - devc->wave[i] = NULL; - } - devc->nrsamples = 0; -} - -static void init_engine(softsyn_devc * devc) -{ - int i, fz, srate, sz = devc->channels; - - set_max_voices(devc->default_max_voices); - voice_alloc->timestamp = 0; - - if (devc->bits == 16) - sz *= 2; - - fz = devc->fragsize / sz; /* Samples per fragment */ - devc->samples_per_fragment = fz; - - devc->usecs = 0; - devc->usecs_per_frag = (1000000 * fz) / devc->speed; - - for (i = 0; i < devc->maxvoice; i++) - { - init_voice(devc, i); - softoss_voices[i].instr = 0; - } - devc->engine_state = ES_STOPPED; - - /* - * Initialize delay - */ - - for (i = 0; i < DELAY_SIZE; i++) - left_delay[i] = right_delay[i] = 0; - delayp = 0; - srate = (devc->speed / 10000); /* 1 to 4 */ - if (srate <= 0) - srate = 1; - devc->delay_size = (DELAY_SIZE * srate) / 4; - if (devc->delay_size == 0 || devc->delay_size > DELAY_SIZE) - devc->delay_size = DELAY_SIZE; -} - -void softsyn_control_loop(void) -{ - int voice; - - /* - * Recompute envlope, LFO, etc. - */ - for (voice = 0; voice < devc->maxvoice; voice++) - { - if (voice_active[voice]) - { - update_volume(voice); - step_envelope_lfo(voice); - } - else - voice_alloc->map[voice] = 0; - } -} - -static void start_engine(softsyn_devc * devc); - -static void do_resample(int dummy) -{ - struct dma_buffparms *dmap = audio_devs[devc->audiodev]->dmap_out; - struct voice_info *vinfo; - unsigned long flags, jif; - - int voice, loops; - short *buf; - - if (softsynth_disabled) - return; - - save_flags(flags); - cli(); - - if (is_running) - { - printk(KERN_WARNING "SoftOSS: Playback overrun\n"); - restore_flags(flags); - return; - } - jif = jiffies; - if (jif == last_resample_jiffies) - { - if (resample_counter++ > 50) - { - for (voice = 0; voice < devc->maxvoice; voice++) - init_voice(devc, voice); - voice_limit--; - resample_counter = 0; - printk(KERN_WARNING "SoftOSS: CPU overload. Limiting # of voices to %d\n", voice_limit); - - if (voice_limit < 10) - { - voice_limit = 10; - devc->speed = (devc->speed * 2) / 3; - - printk(KERN_WARNING "SoftOSS: Dropping sampling rate and stopping the device.\n"); - softsynth_disabled = 1; - } - } - } - else - { - last_resample_jiffies = jif; - resample_counter = 0; - } - - /* is_running = 1; */ - - if (dmap->qlen > devc->max_playahead) - { - printk(KERN_WARNING "SoftOSS: audio buffers full\n"); - is_running = 0; - restore_flags(flags); - return; - } - /* - * First verify that all active voices are valid (do this just once per block). - */ - - for (voice = 0; voice < devc->maxvoice; voice++) - { - if (voice_active[voice]) - { - int ptr; - - vinfo = &softoss_voices[voice]; - ptr = vinfo->ptr >> 9; - - if (vinfo->wave == NULL || ptr < 0 || ptr > vinfo->sample->len) - init_voice(devc, voice); - else if (!(vinfo->mode & WAVE_LOOPING) && (vinfo->ptr + vinfo->step) > vinfo->endloop) - voice_active[voice] = 0; - } - } - - /* - * Start the resampling process - */ - - loops = devc->samples_per_fragment; - buf = (short *) (dmap->raw_buf + (dmap->qtail * dmap->fragment_size)); - - softsynth_resample_loop(buf, loops); /* In Xsoftsynth_rs.c */ - - dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; - dmap->qlen++; - dmap->user_counter += dmap->fragment_size; - - devc->usecs += devc->usecs_per_frag; - - if (tmr_running) - sound_timer_interrupt(); - /* - * Execute timer - */ - - if (!tmr_running) - { - if (devc->usecs >= devc->next_event_usecs) - { - devc->next_event_usecs = ~0; - sequencer_timer(0); - } - } - - is_running = 0; - restore_flags(flags); -} - -static void delayed_resample(int dummy) -{ - struct dma_buffparms *dmap = audio_devs[devc->audiodev]->dmap_out; - int n = 0; - - if (is_running) - return; - - while (devc->engine_state != ES_STOPPED && dmap->qlen < devc->max_playahead && n++ < 2) - do_resample(0); - intr_pending = 0; -} - -#ifdef POLLED_MODE -static void softsyn_poll(unsigned long dummy) -{ - delayed_resample(0); - - if (devc->engine_state != ES_STOPPED) - { - poll_timer.expires = jiffies+1; - add_timer(&poll_timer); - } -} - -#else -static void softsyn_callback(int dev, int parm) -{ - delayed_resample(0); -} -#endif - -static void start_engine(softsyn_devc * devc) -{ - struct dma_buffparms *dmap; - int trig, n; - mm_segment_t fs; - - if (!devc->audio_opened) - if (softsyn_open(devc->synthdev, 0) < 0) - return; - - if (devc->audiodev >= num_audiodevs) - return; - - dmap = audio_devs[devc->audiodev]->dmap_out; - - devc->usecs = 0; - devc->next_event_usecs = ~0; - devc->control_rate = 64; - devc->control_counter = 0; - - if (devc->engine_state == ES_STOPPED) - { - n = trig = 0; - fs = get_fs(); - set_fs(get_ds()); - dma_ioctl(devc->audiodev, SNDCTL_DSP_SETTRIGGER, (caddr_t)&trig); -#ifdef POLLED_MODE - poll_timer.expires = jiffies+1; - add_timer(&poll_timer); - /* Start polling */ -#else - dmap->audio_callback = softsyn_callback; - dmap->qhead = dmap->qtail = dmap->qlen = 0; -#endif - while (dmap->qlen < devc->max_playahead && n++ < 2) - do_resample(0); - devc->engine_state = ES_STARTED; - last_resample_jiffies = jiffies; - resample_counter = 0; - trig = PCM_ENABLE_OUTPUT; - if (dma_ioctl(devc->audiodev, SNDCTL_DSP_SETTRIGGER, (caddr_t)&trig) < 0) - printk(KERN_ERR "SoftOSS: Trigger failed\n"); - set_fs(fs); - } -} - -static void stop_engine(softsyn_devc * devc) -{ -} - -static void request_engine(softsyn_devc * devc, int ticks) -{ - if (ticks < 0) /* Relative time */ - devc->next_event_usecs = devc->usecs - ticks * (1000000 / HZ); - else - devc->next_event_usecs = ticks * (1000000 / HZ); -} - -/* - * Softsync hook serves mode1 (timing) calls made by sequencer.c - */ - -static int softsynth_hook(int cmd, int parm1, int parm2, unsigned long parm3) -{ - switch (cmd) - { - case SSYN_START: - start_engine(devc); - break; - - case SSYN_STOP: - stop_engine(devc); - break; - - case SSYN_REQUEST: - request_engine(devc, parm1); - break; - - case SSYN_GETTIME: - return devc->usecs / (1000000 / HZ); - break; - - default: - printk(KERN_WARNING "SoftOSS: Unknown request %d\n", cmd); - } - return 0; -} - -static int softsyn_ioctl(int dev, unsigned int cmd, caddr_t arg) -{ - switch (cmd) - { - case SNDCTL_SYNTH_INFO: - softsyn_info.nr_voices = devc->maxvoice; - if (copy_to_user(arg, &softsyn_info, sizeof(softsyn_info))) - return -EFAULT; - return 0; - - case SNDCTL_SEQ_RESETSAMPLES: - stop_engine(devc); - reset_samples(devc); - return 0; - - case SNDCTL_SYNTH_MEMAVL: - return devc->ram_size - devc->ram_used; - - default: - return -EINVAL; - } -} - -static int softsyn_kill_note(int devno, int voice, int note, int velocity) -{ - if (voice < 0 || voice > devc->maxvoice) - return 0; - voice_alloc->map[voice] = 0xffff; /* Releasing */ - - if (softoss_voices[voice].sustain_mode & 1) /* Sustain controller on */ - { - softoss_voices[voice].sustain_mode = 3; /* Note off pending */ - return 0; - } - if (velocity > 127 || softoss_voices[voice].mode & WAVE_FAST_RELEASE) - { - init_voice(devc, voice); /* Mark it inactive */ - return 0; - } - if (softoss_voices[voice].mode & WAVE_ENVELOPES) - step_envelope(voice, 1, velocity); /* Enter sustain phase */ - else - init_voice(devc, voice); /* Mark it inactive */ - return 0; -} - -static int softsyn_set_instr(int dev, int voice, int instr) -{ - if (voice < 0 || voice > devc->maxvoice) - return 0; - - if (instr < 0 || instr > MAX_PATCH) - { - printk(KERN_ERR "SoftOSS: Invalid instrument number %d\n", instr); - return 0; - } - softoss_voices[voice].instr = instr; - return 0; -} - -static int softsyn_start_note(int dev, int voice, int note, int volume) -{ - int instr = 0; - int best_sample, best_delta, delta_freq, selected; - unsigned long note_freq, freq, base_note, flags; - voice_info *v = &softoss_voices[voice]; - - struct patch_info *sample; - - if (voice < 0 || voice > devc->maxvoice) - return 0; - - if (volume == 0) /* Actually note off */ - softsyn_kill_note(dev, voice, note, volume); - - save_flags(flags); - cli(); - - if (note == 255) - { /* Just volume update */ - v->velocity = volume; - if (voice_active[voice]) - update_volume(voice); - restore_flags(flags); - return 0; - } - voice_active[voice] = 0; /* Stop the voice for a while */ - devc->vibratomap &= ~(1 << voice); - devc->tremolomap &= ~(1 << voice); - - instr = v->instr; - if (instr < 0 || instr > MAX_PATCH || devc->programs[instr] == NO_SAMPLE) - { - printk(KERN_WARNING "SoftOSS: Undefined MIDI instrument %d\n", instr); - restore_flags(flags); - return 0; - } - instr = devc->programs[instr]; - - if (instr < 0 || instr >= devc->nrsamples) - { - printk(KERN_WARNING "SoftOSS: Corrupted MIDI instrument %d (%d)\n", v->instr, instr); - restore_flags(flags); - return 0; - } - note_freq = note_to_freq(note); - - selected = -1; - - best_sample = instr; - best_delta = 1000000; - - while (instr != NO_SAMPLE && instr >= 0 && selected == -1) - { - delta_freq = note_freq - devc->samples[instr]->base_note; - - if (delta_freq < 0) - delta_freq = -delta_freq; - if (delta_freq < best_delta) - { - best_sample = instr; - best_delta = delta_freq; - } - if (devc->samples[instr]->low_note <= note_freq && - note_freq <= devc->samples[instr]->high_note) - { - selected = instr; - } - else instr = devc->samples[instr]->key; /* Link to next sample */ - - if (instr < 0 || instr >= devc->nrsamples) - instr = NO_SAMPLE; - } - - if (selected == -1) - instr = best_sample; - else - instr = selected; - - if (instr < 0 || instr == NO_SAMPLE || instr > devc->nrsamples) - { - printk(KERN_WARNING "SoftOSS: Unresolved MIDI instrument %d\n", v->instr); - restore_flags(flags); - return 0; - } - sample = devc->samples[instr]; - v->sample = sample; - - if (v->percussive_voice) /* No key tracking */ - v->orig_freq = sample->base_freq; /* Fixed pitch */ - else - { - base_note = sample->base_note / 100; - note_freq /= 100; - - freq = sample->base_freq * note_freq / base_note; - v->orig_freq = freq; - } - - if (!(sample->mode & WAVE_LOOPING)) - sample->loop_end = sample->len; - - v->wave = devc->wave[instr]; - if (volume < 0) - volume = 0; - else if (volume > 127) - volume = 127; - v->ptr = 0; - v->startloop = sample->loop_start * 512; - v->startbackloop = 0; - v->endloop = sample->loop_end * 512; - v->looplen = (sample->loop_end - sample->loop_start) * 512; - v->leftvol = 64; - v->rightvol = 64; - v->patch_vol = sample->volume; - v->velocity = volume; - v->mode = sample->mode; - v->vibrato_phase = 0; - v->vibrato_step = 0; - v->vibrato_level = 0; - v->vibrato_rate = 0; - v->vibrato_depth = 0; - v->tremolo_phase = 0; - v->tremolo_step = 0; - v->tremolo_level = 0; - v->tremolo_rate = 0; - v->tremolo_depth = 0; - - if (!(v->mode & WAVE_LOOPING)) - v->mode &= ~(WAVE_BIDIR_LOOP | WAVE_LOOP_BACK); - else if (v->mode & WAVE_LOOP_BACK) - { - v->ptr = sample->len; - v->startbackloop = v->startloop; - } - if (v->mode & WAVE_VIBRATO) - { - v->vibrato_rate = sample->vibrato_rate; - v->vibrato_depth = sample->vibrato_depth; - } - if (v->mode & WAVE_TREMOLO) - { - v->tremolo_rate = sample->tremolo_rate; - v->tremolo_depth = sample->tremolo_depth; - } - if (v->mode & WAVE_ENVELOPES) - { - v->envelope_phase = -1; - v->envelope_vol = 0; - step_envelope(voice, 0, 60); - } - update_volume(voice); - compute_step(voice); - - voice_active[voice] = 1; /* Mark it active */ - restore_flags(flags); - return 0; -} - -static int softsyn_open(int synthdev, int mode) -{ - int err; - extern int softoss_dev; - int frags = 0x7fff0007; /* fragment size of 128 bytes */ - mm_segment_t fs; - - if (devc->audio_opened) /* Already opened */ - return 0; - - softsynth_disabled = 0; - devc->finfo.f_mode = FMODE_WRITE; - devc->finfo.f_flags = 0; - - if (softoss_dev >= num_audiodevs) - softoss_dev = num_audiodevs - 1; - - if (softoss_dev < 0) - softoss_dev = 0; - if (softoss_dev >= num_audiodevs) - return -ENXIO; - devc->audiodev = softoss_dev; - - if (!(audio_devs[devc->audiodev]->format_mask & AFMT_S16_LE)) - { -/* printk(KERN_ERR "SoftOSS: The audio device doesn't support 16 bits\n"); */ - return -ENXIO; - } - if ((err = audio_open((devc->audiodev << 4) | SND_DEV_DSP16, &devc->finfo)) < 0) - return err; - - devc->speed = audio_devs[devc->audiodev]->d->set_speed( - devc->audiodev, devc->speed); - devc->channels = audio_devs[devc->audiodev]->d->set_channels( - devc->audiodev, devc->channels); - devc->bits = audio_devs[devc->audiodev]->d->set_bits( - devc->audiodev, devc->bits); - - - DDB(printk("SoftOSS: Using audio dev %d, speed %d, bits %d, channels %d\n", devc->audiodev, devc->speed, devc->bits, devc->channels)); - fs = get_fs(); - set_fs(get_ds()); - dma_ioctl(devc->audiodev, SNDCTL_DSP_SETFRAGMENT, (caddr_t) & frags); - dma_ioctl(devc->audiodev, SNDCTL_DSP_GETBLKSIZE, (caddr_t) & devc->fragsize); - set_fs(fs); - - if (devc->bits != 16 || devc->channels != 2) - { - audio_release((devc->audiodev << 4) | SND_DEV_DSP16, &devc->finfo); -/* printk("SoftOSS: A 16 bit stereo sound card is required\n");*/ - return -EINVAL; - } - if (devc->max_playahead >= audio_devs[devc->audiodev]->dmap_out->nbufs) - devc->max_playahead = audio_devs[devc->audiodev]->dmap_out->nbufs; - - DDB(printk("SoftOSS: Using %d fragments of %d bytes\n", devc->max_playahead, devc->fragsize)); - - init_engine(devc); - devc->audio_opened = 1; - devc->sequencer_mode = mode; - return 0; -} - -static void softsyn_close(int synthdev) -{ - mm_segment_t fs; - - devc->engine_state = ES_STOPPED; -#ifdef POLLED_MODE - del_timer(&poll_timer); -#endif - fs = get_fs(); - set_fs(get_ds()); - dma_ioctl(devc->audiodev, SNDCTL_DSP_RESET, 0); - set_fs(fs); - if (devc->audio_opened) - audio_release((devc->audiodev << 4) | SND_DEV_DSP16, &devc->finfo); - devc->audio_opened = 0; -} - -static void softsyn_hw_control(int dev, unsigned char *event_rec) -{ - int voice, cmd; - unsigned short p1, p2; - unsigned int plong; - - cmd = event_rec[2]; - voice = event_rec[3]; - p1 = *(unsigned short *) &event_rec[4]; - p2 = *(unsigned short *) &event_rec[6]; - plong = *(unsigned int *) &event_rec[4]; - - switch (cmd) - { - - case _GUS_NUMVOICES: - set_max_voices(p1); - break; - - default:; - } -} - -static int softsyn_load_patch(int dev, int format, const char *addr, - int offs, int count, int pmgr_flag) -{ - struct patch_info *patch = NULL; - - int i, p, instr; - long sizeof_patch; - int memlen, adj; - unsigned short data; - short *wave = NULL; - - sizeof_patch = (long) &patch->data[0] - (long) patch; /* Header size */ - - if (format != GUS_PATCH) - { -/* printk(KERN_ERR "SoftOSS: Invalid patch format (key) 0x%x\n", format);*/ - return -EINVAL; - } - if (count < sizeof_patch) - { -/* printk(KERN_ERR "SoftOSS: Patch header too short\n");*/ - return -EINVAL; - } - count -= sizeof_patch; - - if (devc->nrsamples >= MAX_SAMPLE) - { -/* printk(KERN_ERR "SoftOSS: Sample table full\n");*/ - return -ENOBUFS; - } - - /* - * Copy the header from user space but ignore the first bytes which have - * been transferred already. - */ - - patch = vmalloc(sizeof(*patch)); - - if (patch == NULL) - { -/* printk(KERN_ERR "SoftOSS: Out of memory\n");*/ - return -ENOMEM; - } - if(copy_from_user(&((char *) patch)[offs], &(addr)[offs], sizeof_patch - offs)) - return -EFAULT; - - if (patch->mode & WAVE_ROM) - { - vfree(patch); - return -EINVAL; - } - instr = patch->instr_no; - - if (instr < 0 || instr > MAX_PATCH) - { -/* printk(KERN_ERR "SoftOSS: Invalid patch number %d\n", instr);*/ - vfree(patch); - return -EINVAL; - } - if (count < patch->len) - { -/* printk(KERN_ERR "SoftOSS: Patch record too short (%d<%d)\n", count, (int) patch->len);*/ - patch->len = count; - } - if (patch->len <= 0 || patch->len > (devc->ram_size - devc->ram_used)) - { -/* printk(KERN_ERR "SoftOSS: Invalid sample length %d\n", (int) patch->len); */ - vfree(patch); - return -EINVAL; - } - if (patch->mode & WAVE_LOOPING) - { - if (patch->loop_start < 0 || patch->loop_start >= patch->len) - { -/* printk(KERN_ERR "SoftOSS: Invalid loop start %d\n", patch->loop_start);*/ - vfree(patch); - return -EINVAL; - } - if (patch->loop_end < patch->loop_start || patch->loop_end > patch->len) - { -/* printk(KERN_ERR "SoftOSS: Invalid loop start or end point (%d, %d)\n", patch->loop_start, patch->loop_end);*/ - vfree(patch); - return -EINVAL; - } - } - /* - * Next load the wave data to memory - */ - - memlen = patch->len; - adj = 1; - - if (!(patch->mode & WAVE_16_BITS)) - memlen *= 2; - else - adj = 2; - - wave = vmalloc(memlen); - - if (wave == NULL) - { -/* printk(KERN_ERR "SoftOSS: Can't allocate %d bytes of mem for a sample\n", memlen);*/ - vfree(patch); - return -ENOMEM; - } - p = 0; - for (i = 0; i < memlen / 2; i++) /* Handle words */ - { - unsigned char tmp; - data = 0; - if (patch->mode & WAVE_16_BITS) - { - get_user(*(unsigned char *) &tmp, (unsigned char *) &((addr)[sizeof_patch + p++])); /* Get lsb */ - data = tmp; - get_user(*(unsigned char *) &tmp, (unsigned char *) &((addr)[sizeof_patch + p++])); /* Get msb */ - if (patch->mode & WAVE_UNSIGNED) - tmp ^= 0x80; /* Convert to signed */ - data |= (tmp << 8); - } - else - { - get_user(*(unsigned char *) &tmp, (unsigned char *) &((addr)[sizeof_patch + p++])); - if (patch->mode & WAVE_UNSIGNED) - tmp ^= 0x80; /* Convert to signed */ - data = (tmp << 8); /* Convert to 16 bits */ - } - wave[i] = (short) data; - } - - devc->ram_used += patch->len; - - /* - * Convert pointers to 16 bit indexes - */ - patch->len /= adj; - patch->loop_start /= adj; - patch->loop_end /= adj; - - /* - * Finally link the loaded patch to the chain - */ - - patch->key = devc->programs[instr]; - devc->programs[instr] = devc->nrsamples; - devc->wave[devc->nrsamples] = (short *) wave; - devc->samples[devc->nrsamples++] = patch; - - return 0; -} - -static void softsyn_panning(int dev, int voice, int pan) -{ - if (voice < 0 || voice > devc->maxvoice) - return; - - if (pan < -128) - pan = -128; - if (pan > 127) - pan = 127; - - softoss_voices[voice].panning = pan; - if (voice_active[voice]) - update_volume(voice); -} - -static void softsyn_volume_method(int dev, int mode) -{ -} - -static void softsyn_aftertouch(int dev, int voice, int pressure) -{ - if (voice < 0 || voice > devc->maxvoice) - return; - - if (voice_active[voice]) - update_volume(voice); -} - -static void softsyn_controller(int dev, int voice, int ctrl_num, int value) -{ - unsigned long flags; - - if (voice < 0 || voice > devc->maxvoice) - return; - save_flags(flags); - cli(); - - switch (ctrl_num) - { - case CTRL_PITCH_BENDER: - softoss_voices[voice].bender = value; - if (voice_active[voice]) - compute_step(voice); /* Update pitch */ - break; - - - case CTRL_PITCH_BENDER_RANGE: - softoss_voices[voice].bender_range = value; - break; - - case CTL_EXPRESSION: - value /= 128; - case CTRL_EXPRESSION: - softoss_voices[voice].expression_vol = value; - if (voice_active[voice]) - update_volume(voice); - break; - - case CTL_PAN: - softsyn_panning(dev, voice, (value * 2) - 128); - break; - - case CTL_MAIN_VOLUME: - value = (value * 100) / 16383; - - case CTRL_MAIN_VOLUME: - softoss_voices[voice].main_vol = value; - if (voice_active[voice]) - update_volume(voice); - break; - - default: - break; - } - restore_flags(flags); -} - -static void softsyn_bender(int dev, int voice, int value) -{ - if (voice < 0 || voice > devc->maxvoice) - return; - - softoss_voices[voice].bender = value - 8192; - if (voice_active[voice]) - compute_step(voice); /* Update pitch */ -} - -static int softsyn_alloc_voice(int dev, int chn, int note, struct voice_alloc_info *alloc) -{ - int i, p, best = -1, best_time = 0x7fffffff; - - p = alloc->ptr; - - /* - * First look for a completely stopped voice - */ - - for (i = 0; i < alloc->max_voice; i++) - { - if (alloc->map[p] == 0) - { - alloc->ptr = p; - voice_active[p] = 0; - return p; - } - if (alloc->alloc_times[p] < best_time) - { - best = p; - best_time = alloc->alloc_times[p]; - } - p = (p + 1) % alloc->max_voice; - } - - /* - * Then look for a releasing voice - */ - - for (i = 0; i < alloc->max_voice; i++) - { - if (alloc->map[p] == 0xffff) - { - alloc->ptr = p; - voice_active[p] = 0; - return p; - } - p = (p + 1) % alloc->max_voice; - } - - if (best >= 0) - p = best; - - alloc->ptr = p; - voice_active[p] = 0; - return p; -} - -static void softsyn_setup_voice(int dev, int voice, int chn) -{ - unsigned long flags; - - struct channel_info *info = &synth_devs[dev]->chn_info[chn]; - - save_flags(flags); - cli(); - - /* init_voice(devc, voice); */ - softsyn_set_instr(dev, voice, info->pgm_num); - - softoss_voices[voice].expression_vol = info->controllers[CTL_EXPRESSION]; /* Just MSB */ - softoss_voices[voice].main_vol = (info->controllers[CTL_MAIN_VOLUME] * 100) / (unsigned) 128; - softsyn_panning(dev, voice, (info->controllers[CTL_PAN] * 2) - 128); - softoss_voices[voice].bender = 0; /* info->bender_value; */ - softoss_voices[voice].bender_range = info->bender_range; - - if (chn == 9) - softoss_voices[voice].percussive_voice = 1; - restore_flags(flags); -} - -static void softsyn_reset(int devno) -{ - int i; - unsigned long flags; - - save_flags(flags); - cli(); - - for (i = 0; i < devc->maxvoice; i++) - init_voice(devc, i); - restore_flags(flags); -} - -static struct synth_operations softsyn_operations = -{ - owner: THIS_MODULE, - id: "SoftOSS", - info: &softsyn_info, - midi_dev: 0, - synth_type: SYNTH_TYPE_SAMPLE, - synth_subtype: 0, - open: softsyn_open, - close: softsyn_close, - ioctl: softsyn_ioctl, - kill_note: softsyn_kill_note, - start_note: softsyn_start_note, - set_instr: softsyn_set_instr, - reset: softsyn_reset, - hw_control: softsyn_hw_control, - load_patch: softsyn_load_patch, - aftertouch: softsyn_aftertouch, - controller: softsyn_controller, - panning: softsyn_panning, - volume_method: softsyn_volume_method, - bender: softsyn_bender, - alloc_voice: softsyn_alloc_voice, - setup_voice: softsyn_setup_voice -}; - -/* - * Timer stuff (for /dev/music). - */ - -static unsigned int soft_tmr_start(int dev, unsigned int usecs) -{ - tmr_running = 1; - start_engine(devc); - return devc->usecs_per_frag; -} - -static void soft_tmr_disable(int dev) -{ - stop_engine(devc); - tmr_running = 0; -} - -static void soft_tmr_restart(int dev) -{ - tmr_running = 1; -} - -static struct sound_lowlev_timer soft_tmr = -{ - 0, - 9999, - soft_tmr_start, - soft_tmr_disable, - soft_tmr_restart -}; - -static int __init probe_softsyn(struct address_info *hw_config) -{ - int i; - - if (softsynth_loaded) - return 0; - - devc->ram_size = 8 * 1024 * 1024; - devc->ram_used = 0; - devc->nrsamples = 0; - for (i = 0; i < MAX_PATCH; i++) - { - devc->programs[i] = NO_SAMPLE; - devc->wave[i] = NULL; - } - - devc->maxvoice = DEFAULT_VOICES; - - devc->audiodev = 0; - devc->audio_opened = 0; - devc->channels = 2; - devc->bits = 16; - devc->max_playahead = 32; - -#ifdef CONFIG_SOFTOSS_RATE - devc->speed = CONFIG_SOFTOSS_RATE; -#else - devc->speed = 32000; -#endif - -#ifdef CONFIG_SOFTOSS_VOICES - devc->default_max_voices = CONFIG_SOFTOSS_VOICES; -#else - devc->default_max_voices = 32; -#endif - softsynth_loaded = 1; - return 1; -} - -static void __init attach_softsyn_card(struct address_info *hw_config) -{ - voice_alloc = &softsyn_operations.alloc; - synth_devs[devc->synthdev = num_synths++] = &softsyn_operations; - sequencer_init(); - sound_timer_init(&soft_tmr, "SoftOSS"); - devc->timerdev = num_sound_timers; - softsynthp = softsynth_hook; - -#ifndef POLLED_MODE -#endif -} - -static void __exit unload_softsyn(struct address_info *hw_config) -{ - if (!softsynth_loaded) - return; - softsynthp = NULL; - softsynth_loaded = 0; - reset_samples(devc); -} - -static struct address_info cfg; - -static int __init init_softoss(void) -{ - printk(KERN_INFO "SoftOSS driver Copyright (C) by Hannu Savolainen 1993-1997\n"); - if (!probe_softsyn(&cfg)) - return -ENODEV; - attach_softsyn_card(&cfg); - - return 0; -} - -static void __exit cleanup_softoss(void) -{ - unload_softsyn(&cfg); - sound_unload_synthdev(devc->synthdev); - sound_unload_timerdev(devc->timerdev); -} - -module_init(init_softoss); -module_exit(cleanup_softoss); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/softoss.h linux/drivers/sound/softoss.h --- v2.4.0-test8/linux/drivers/sound/softoss.h Thu Feb 19 14:46:15 1998 +++ linux/drivers/sound/softoss.h Wed Dec 31 16:00:00 1969 @@ -1,161 +0,0 @@ -/* - * softoss.h - Definitions for Software MIDI Synthesizer. - */ -/* - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - */ - - -/* - * Sequencer mode1 timer calls made by sequencer.c - */ -extern int (*softsynthp) (int cmd, int parm1, int parm2, unsigned long parm3); - -#define SSYN_START 1 -#define SSYN_REQUEST 2 /* parm1 = time */ -#define SSYN_STOP 3 -#define SSYN_GETTIME 4 /* Returns number of ticks since reset */ - -#define MAX_PATCH 256 -#define MAX_SAMPLE 512 -#define MAX_VOICE 32 -#define DEFAULT_VOICES 16 - -typedef struct voice_info -{ -/* - * Don't change anything in the beginning of this struct. These fields are used - * by the resampling loop which may have been written in assembly for some - * architectures. Any change may make the resampling code incompatible - */ - int instr; - short *wave; - struct patch_info *sample; - - unsigned int ptr; int step; /* Pointer to the wave data and pointer increment */ - - int mode; - int startloop, startbackloop, endloop, looplen; - - unsigned int leftvol, rightvol; -/***** Don't change anything above this */ - - volatile unsigned long orig_freq, current_freq; - volatile int bender, bender_range, panning; - volatile int main_vol, expression_vol, patch_vol, velocity; - -/* Envelope parameters */ - - int envelope_phase; - volatile int envelope_vol; - volatile int envelope_volstep; - int envelope_time; /* Number of remaining envelope steps */ - unsigned int envelope_target; - int percussive_voice; - int sustain_mode; /* 0=off, 1=sustain on, 2=sustain on+key released */ - -/* Vibrato */ - int vibrato_rate; - int vibrato_depth; - int vibrato_phase; - int vibrato_step; - int vibrato_level; - -/* Tremolo */ - int tremolo_rate; - int tremolo_depth; - int tremolo_phase; - int tremolo_step; - int tremolo_level; -} voice_info; - -extern voice_info softoss_voices[MAX_VOICE]; /* Voice spesific info */ - -typedef struct softsyn_devc -{ -/* - * Don't change anything in the beginning of this struct. These fields are used - * by the resampling loop which may have been written in assembly for some - * architectures. Any change may make the resampling code incompatible - */ - int maxvoice; /* # of voices to be processed */ - int afterscale; - int delay_size; - int control_rate, control_counter; -/***** Don't change anything above this */ - - int ram_size; - int ram_used; - - int synthdev; - int timerdev; - int sequencer_mode; -/* - * Audio parameters - */ - - int audiodev; - int audio_opened; - int speed; - int channels; - int bits; - int default_max_voices; - int max_playahead; - struct file finfo; - int fragsize; - int samples_per_fragment; - -/* - * Sample storage - */ - int nrsamples; - struct patch_info *samples[MAX_SAMPLE]; - short *wave[MAX_SAMPLE]; - -/* - * Programs - */ - int programs[MAX_PATCH]; - -/* - * Timer parameters - */ - volatile unsigned long usecs; - volatile unsigned long usecs_per_frag; - volatile unsigned long next_event_usecs; - -/* - * Engine state - */ - - volatile int engine_state; -#define ES_STOPPED 0 -#define ES_STARTED 1 - - /* Voice spesific bitmaps */ - volatile int tremolomap; - volatile int vibratomap; - -} softsyn_devc; - -void softsynth_resample_loop(short *buf, int loops); -extern void softsyn_control_loop(void); - -#define DELAY_SIZE 4096 - -#ifdef SOFTSYN_MAIN - short voice_active[MAX_VOICE] = {0}; - voice_info softoss_voices[MAX_VOICE] = {{0}}; /* Voice spesific info */ - int left_delay[DELAY_SIZE]={0}, right_delay[DELAY_SIZE]={0}; - int delayp=0; -#else - extern softsyn_devc *devc; - - extern int left_delay[DELAY_SIZE], right_delay[DELAY_SIZE]; - extern int delayp; - extern short voice_active[MAX_VOICE]; -#endif diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/softoss_rs.c linux/drivers/sound/softoss_rs.c --- v2.4.0-test8/linux/drivers/sound/softoss_rs.c Mon Feb 28 07:18:20 2000 +++ linux/drivers/sound/softoss_rs.c Wed Dec 31 16:00:00 1969 @@ -1,127 +0,0 @@ - -/* - * sound/softoss_rs.c - * - * Software based MIDI synthsesizer driver, the actual mixing loop. - * Keep the loop as simple as possible to make it easier to rewrite this - * routine in assembly. - * - * - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - */ -#include "sound_config.h" -#include "softoss.h" - -void softsynth_resample_loop(short *buf, int loops) -{ - int iloop, voice; - volatile voice_info *v; - -#ifdef OSS_BIG_ENDIAN - unsigned char *cbuf = (unsigned char *) buf; - -#endif - - for (iloop = 0; iloop < loops; iloop++) - { /* Mix one sample */ - int accum, left = 0, right = 0; - int ix, position; - - for (voice = 0; voice < devc->maxvoice; voice++) - { - if (voice_active[voice]) - { /* Compute voice */ - v = &softoss_voices[voice]; -#ifdef SOFTOSS_TEST - ix = iloop << 3; - position = v->ptr; -#else - ix = (position = v->ptr) >> 9; -#endif - /* Interpolation (resolution of 512 steps) */ - { - int fract = v->ptr & 0x1ff; /* 9 bits */ - - /* This method works with less arithmetic operations */ - register int v1 = v->wave[ix]; - accum = v1 + ((((v->wave[ix + 1] - v1)) * (fract)) >> 9); - } - - left += (accum * v->leftvol); - right += (accum * v->rightvol); - - /* Update sample pointer */ - position += v->step; - if (position <= v->endloop) - v->ptr = position; - else if (v->mode & WAVE_LOOPING) - { - if (v->mode & WAVE_BIDIR_LOOP) - { v->mode ^= WAVE_LOOP_BACK; /* Turn around */ - v->step *= -1; - } - else - { - position -= v->looplen; - v->ptr = position; - } - } - /* else leave the voice looping the current sample */ - - if (v->mode & WAVE_LOOP_BACK && position < v->startloop) - { - if (v->mode & WAVE_BIDIR_LOOP) - { v->mode ^= WAVE_LOOP_BACK; /* Turn around */ - v->step *= -1; - } - else - { - position += v->looplen; - v->ptr = position; - } - } - } /* Compute voice */ - } -#if 1 /* Delay */ - left += left_delay[delayp]; - right += right_delay[delayp]; - - left_delay[delayp] = right >> 2; - right_delay[delayp] = left >> 2; - delayp = (delayp + 1) % devc->delay_size; -#endif - -#define AFTERSCALE devc->afterscale; - - left >>= AFTERSCALE; - right >>= AFTERSCALE; - - if (left > 32767) - left = 32767; - if (left < -32768) - left = -32768; - if (right > 32767) - right = 32767; - if (right < -32768) - right = -32768; - -#ifdef OSS_BIG_ENDIAN - *cbuf++ = left & 0xff; - *cbuf++ = (left >> 8) & 0xff; - *cbuf++ = right & 0xff; - *cbuf++ = (right >> 8) & 0xff; -#else - *buf++ = left; - *buf++ = right; -#endif - if (devc->control_counter++ >= devc->control_rate) - { - devc->control_counter = 0; - softsyn_control_loop(); - } - } /* Mix one sample */ -} diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/sonicvibes.c linux/drivers/sound/sonicvibes.c --- v2.4.0-test8/linux/drivers/sound/sonicvibes.c Tue Aug 29 14:09:15 2000 +++ linux/drivers/sound/sonicvibes.c Mon Sep 18 14:57:01 2000 @@ -2589,7 +2589,7 @@ } set_fs(fs); /* store it in the driver field */ - pcidev->driver_data = s; + pci_set_drvdata(pcidev, s); pcidev->dma_mask = 0x00ffffff; /* put it into driver list */ list_add_tail(&s->devs, &devs); @@ -2624,7 +2624,7 @@ static void __devinit sv_remove(struct pci_dev *dev) { - struct sv_state *s = (struct sv_state *)dev->driver_data; + struct sv_state *s = pci_get_drvdata(dev); if (!s) return; @@ -2646,7 +2646,7 @@ unregister_sound_midi(s->dev_midi); unregister_sound_special(s->dev_dmfm); kfree(s); - dev->driver_data = NULL; + pci_set_drvdata(dev, NULL); } static struct pci_device_id id_table[] __devinitdata = { diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/sound_core.c linux/drivers/sound/sound_core.c --- v2.4.0-test8/linux/drivers/sound/sound_core.c Mon Aug 28 15:03:42 2000 +++ linux/drivers/sound/sound_core.c Mon Sep 25 12:32:54 2000 @@ -36,6 +36,7 @@ #include #include +#include #include #include #include @@ -62,9 +63,6 @@ #ifdef CONFIG_SOUND_MSNDPIN extern int msnd_pinnacle_init(void); #endif -#ifdef CONFIG_SOUND_CMPCI -extern int init_cmpci(void); -#endif /* * Low level list operator. Scan the ordered list, find a hole and @@ -545,12 +543,11 @@ extern int mod_firmware_load(const char *, char **); EXPORT_SYMBOL(mod_firmware_load); -#ifdef MODULE MODULE_DESCRIPTION("Core sound module"); MODULE_AUTHOR("Alan Cox"); -void cleanup_module(void) +static void __exit cleanup_soundcore(void) { /* We have nothing to really do here - we know the lists must be empty */ @@ -558,10 +555,7 @@ devfs_unregister (devfs_handle); } -int init_module(void) -#else -int soundcore_init(void) -#endif +static int __init init_soundcore(void) { if(devfs_register_chrdev(SOUND_MAJOR, "sound", &soundcore_fops)==-1) { @@ -569,20 +563,9 @@ return -EBUSY; } devfs_handle = devfs_mk_dir (NULL, "sound", NULL); - /* - * Now init non OSS drivers - */ -#ifdef CONFIG_SOUND_CMPCI - init_cmpci(); -#endif -#ifdef CONFIG_SOUND_MSNDCLAS - msnd_classic_init(); -#endif -#ifdef CONFIG_SOUND_MSNDPIN - msnd_pinnacle_init(); -#endif -#ifdef CONFIG_SOUND_VWSND - init_vwsnd(); -#endif + return 0; } + +module_init(init_soundcore); +module_exit(cleanup_soundcore); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/sound_syms.c linux/drivers/sound/sound_syms.c --- v2.4.0-test8/linux/drivers/sound/sound_syms.c Fri Aug 11 08:26:44 2000 +++ linux/drivers/sound/sound_syms.c Mon Sep 25 12:32:54 2000 @@ -49,8 +49,5 @@ EXPORT_SYMBOL(conf_printf); EXPORT_SYMBOL(conf_printf2); -extern int softoss_dev; -EXPORT_SYMBOL(softoss_dev); - MODULE_DESCRIPTION("OSS Sound subsystem"); MODULE_AUTHOR("Hannu Savolainen, et al."); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/sound_timer.c linux/drivers/sound/sound_timer.c --- v2.4.0-test8/linux/drivers/sound/sound_timer.c Fri Aug 11 08:26:44 2000 +++ linux/drivers/sound/sound_timer.c Sun Oct 1 20:35:16 2000 @@ -16,7 +16,7 @@ #include "sound_config.h" -static volatile int initialized = 0, opened = 0, tmr_running = 0; +static volatile int initialized, opened, tmr_running; static volatile time_t tmr_offs, tmr_ctr; static volatile unsigned long ticks_offs; static volatile int curr_tempo, curr_timebase; @@ -25,7 +25,7 @@ static unsigned long prev_event_time; static volatile unsigned long usecs_per_tmr; /* Length of the current interval */ -static struct sound_lowlev_timer *tmr = NULL; +static struct sound_lowlev_timer *tmr; static unsigned long tmr2ticks(int tmr_value) { diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/soundcard.c linux/drivers/sound/soundcard.c --- v2.4.0-test8/linux/drivers/sound/soundcard.c Fri Aug 11 08:26:44 2000 +++ linux/drivers/sound/soundcard.c Mon Sep 25 12:32:54 2000 @@ -25,6 +25,7 @@ #include #include "sound_config.h" +#include #include #include #include @@ -51,8 +52,6 @@ #define valid_dma(n) ((n) >= 0 && (n) < MAX_DMA_CHANNELS && (n) != 4) #endif -static int chrdev_registered = 0; - /* * Table for permanently allocated memory (used when unloading the module) */ @@ -267,6 +266,7 @@ DEB(printk("sound_release(dev=%d)\n", dev)); switch (dev & 0x0f) { case SND_DEV_CTL: + dev >>= 4; if (mixer_devs[dev]->owner) __MOD_DEC_USE_COUNT (mixer_devs[dev]->owner); break; @@ -582,34 +582,6 @@ } } -#ifdef MODULE -static void -#else -void -#endif -soundcard_init(void) -{ - /* drag in sound_syms.o */ - { - extern char sound_syms_symbol; - sound_syms_symbol = 0; - } - -#ifndef MODULE - create_special_devices(); - chrdev_registered = 1; -#endif - - soundcard_register_devfs(1); /* register after we know # of devices */ -} - -#ifdef MODULE - -static void destroy_special_devices(void) -{ - unregister_sound_special(1); - unregister_sound_special(8); -} static int dmabuf = 0; static int dmabug = 0; @@ -617,14 +589,21 @@ MODULE_PARM(dmabuf, "i"); MODULE_PARM(dmabug, "i"); -int init_module(void) +static int __init oss_init(void) { int err; + + /* drag in sound_syms.o */ + { + extern char sound_syms_symbol; + sound_syms_symbol = 0; + } #ifdef CONFIG_PCI if(dmabug) isa_dma_bridge_buggy = dmabug; #endif + err = create_special_devices(); if (err) { printk(KERN_ERR "sound: driver already loaded/included in kernel\n"); @@ -634,8 +613,7 @@ /* Protecting the innocent */ sound_dmap_flag = (dmabuf > 0 ? 1 : 0); - chrdev_registered = 1; - soundcard_init(); + soundcard_register_devfs(1); if (sound_nblocks >= 1024) printk(KERN_ERR "Sound warning: Deallocation table was too small.\n"); @@ -643,7 +621,7 @@ return 0; } -void cleanup_module(void) +static void __exit oss_cleanup(void) { int i; @@ -651,8 +629,9 @@ return; soundcard_register_devfs (0); - if (chrdev_registered) - destroy_special_devices(); + + unregister_sound_special(1); + unregister_sound_special(8); sound_stop_timer(); @@ -668,7 +647,10 @@ vfree(sound_mem_blocks[i]); } -#endif + +module_init(oss_init); +module_exit(oss_cleanup); + int sound_alloc_dma(int chn, char *deviceID) { diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/trident.c linux/drivers/sound/trident.c --- v2.4.0-test8/linux/drivers/sound/trident.c Tue Aug 29 14:09:15 2000 +++ linux/drivers/sound/trident.c Mon Sep 18 14:57:01 2000 @@ -2484,7 +2484,7 @@ /* edited by HMSEO for GT sound*/ } - pci_dev->driver_data = card; + pci_set_drvdata(pci_dev, card); pci_dev->dma_mask = TRIDENT_DMA_MASK; /* Enable Address Engine Interrupts */ @@ -2496,7 +2496,7 @@ static void __exit trident_remove(struct pci_dev *pci_dev) { int i; - struct trident_card *card = pci_dev->driver_data; + struct trident_card *card = pci_get_drvdata(pci_dev); /* Kill interrupts, and SP/DIF */ trident_disable_loop_interrupts(card); @@ -2514,6 +2514,8 @@ unregister_sound_dsp(card->dev_audio); kfree(card); + + pci_set_drvdata(pci_dev, NULL); } MODULE_AUTHOR("Alan Cox, Aaron Holtzman, Ollie Lho, Ching Ling Lee"); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/trix.c linux/drivers/sound/trix.c --- v2.4.0-test8/linux/drivers/sound/trix.c Fri Aug 11 08:26:44 2000 +++ linux/drivers/sound/trix.c Wed Sep 27 13:53:56 2000 @@ -14,6 +14,7 @@ * Changes * Alan Cox Modularisation, cleanup. * Christoph Hellwig Adapted to module_init/module_exit + * Arnaldo C. de Melo Got rid of attach_uart401 */ #include @@ -337,12 +338,6 @@ sb_be_quiet = old_quiet; } -static void __init attach_trix_mpu(struct address_info *hw_config) -{ - hw_config->name = "AudioTrix Pro"; - attach_uart401(hw_config, THIS_MODULE); -} - static int __init probe_trix_mpu(struct address_info *hw_config) { unsigned char conf; @@ -365,11 +360,6 @@ DDB(printk("Trix: MPU mode already initialized\n")); return 0; } - if (check_region(hw_config->io_base, 4)) - { - printk(KERN_ERR "AudioTrix: MPU I/O port conflict (%x)\n", hw_config->io_base); - return 0; - } if (hw_config->irq > 9) { printk(KERN_ERR "AudioTrix: Bad MPU IRQ %d\n", hw_config->irq); @@ -401,7 +391,8 @@ conf |= irq_bits[hw_config->irq] << 4; trix_write(0x19, (trix_read(0x19) & 0x83) | conf); mpu_initialized = 1; - return probe_uart401(hw_config); + hw_config->name = "AudioTrix Pro"; + return probe_uart401(hw_config, THIS_MODULE); } static void __exit unload_trix_wss(struct address_info *hw_config) @@ -510,11 +501,8 @@ attach_trix_sb(&cfg2); } - if (cfg_mpu.io_base != -1) { + if (cfg_mpu.io_base != -1) mpu = probe_trix_mpu(&cfg_mpu); - if (mpu) - attach_trix_mpu(&cfg_mpu); - } return 0; } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/uart401.c linux/drivers/sound/uart401.c --- v2.4.0-test8/linux/drivers/sound/uart401.c Fri Aug 11 08:26:44 2000 +++ linux/drivers/sound/uart401.c Wed Sep 27 13:53:57 2000 @@ -15,6 +15,7 @@ * interrupt allocation. Protect against bogus unload * Fixed to allow IRQ > 15 * Christoph Hellwig Adapted to module_init/module_exit + * Arnaldo C. de Melo got rid of check_region * * Status: * Untested @@ -40,8 +41,6 @@ } uart401_devc; -static uart401_devc *detected_devc = NULL; - #define DATAPORT (devc->base) #define COMDPORT (devc->base+1) #define STATPORT (devc->base+1) @@ -241,95 +240,6 @@ restore_flags(flags); } -void attach_uart401(struct address_info *hw_config, struct module *owner) -{ - uart401_devc *devc; - char *name = "MPU-401 (UART) MIDI"; - - - if (hw_config->name) - name = hw_config->name; - - if (detected_devc == NULL) - return; - - - devc = (uart401_devc *) kmalloc(sizeof(uart401_devc), GFP_KERNEL); - if (devc == NULL) - { - printk(KERN_WARNING "uart401: Can't allocate memory\n"); - return; - } - memcpy((char *) devc, (char *) detected_devc, sizeof(uart401_devc)); - detected_devc = NULL; - - devc->irq = hw_config->irq; - if (devc->irq < 0) - { - devc->share_irq = 1; - devc->irq *= -1; - } - else - devc->share_irq = 0; - - if (!devc->share_irq) - { - if (request_irq(devc->irq, uart401intr, 0, "MPU-401 UART", devc) < 0) - { - printk(KERN_WARNING "uart401: Failed to allocate IRQ%d\n", devc->irq); - devc->share_irq = 1; - } - } - devc->my_dev = sound_alloc_mididev(); - - request_region(hw_config->io_base, 4, "MPU-401 UART"); - enter_uart_mode(devc); - - if (devc->my_dev == -1) - { - printk(KERN_INFO "uart401: Too many midi devices detected\n"); - kfree(devc); - return; - } - conf_printf(name, hw_config); - - std_midi_synth.midi_dev = devc->my_dev; - midi_devs[devc->my_dev] = (struct midi_operations *)kmalloc(sizeof(struct midi_operations), GFP_KERNEL); - if (midi_devs[devc->my_dev] == NULL) - { - printk(KERN_ERR "uart401: Failed to allocate memory\n"); - sound_unload_mididev(devc->my_dev); - kfree(devc); - devc=NULL; - return; - } - memcpy((char *) midi_devs[devc->my_dev], (char *) &uart401_operations, - sizeof(struct midi_operations)); - - if (owner) - midi_devs[devc->my_dev]->owner = owner; - - midi_devs[devc->my_dev]->devc = devc; - midi_devs[devc->my_dev]->converter = (struct synth_operations *)kmalloc(sizeof(struct synth_operations), GFP_KERNEL); - if (midi_devs[devc->my_dev]->converter == NULL) - { - printk(KERN_WARNING "uart401: Failed to allocate memory\n"); - kfree(midi_devs[devc->my_dev]); - kfree(devc); - sound_unload_mididev(devc->my_dev); - devc=NULL; - return; - } - memcpy((char *) midi_devs[devc->my_dev]->converter, (char *) &std_midi_synth, - sizeof(struct synth_operations)); - - strcpy(midi_devs[devc->my_dev]->info.name, name); - midi_devs[devc->my_dev]->converter->id = "UART401"; - hw_config->slots[4] = devc->my_dev; - sequencer_init(); - devc->opened = 0; -} - static int reset_uart401(uart401_devc * devc) { int ok, timeout, n; @@ -379,21 +289,28 @@ return ok; } -int probe_uart401(struct address_info *hw_config) +int probe_uart401(struct address_info *hw_config, struct module *owner) { + uart401_devc *devc; + char *name = "MPU-401 (UART) MIDI"; int ok = 0; unsigned long flags; - static uart401_devc hw_info; - uart401_devc *devc = &hw_info; DDB(printk("Entered probe_uart401()\n")); /* Default to "not found" */ hw_config->slots[4] = -1; - detected_devc = NULL; - if (check_region(hw_config->io_base, 4)) + if (!request_region(hw_config->io_base, 4, "MPU-401 UART")) { + printk(KERN_INFO "uart401: could not request_region(%d, 4)\n", hw_config->io_base); return 0; + } + + devc = kmalloc(sizeof(uart401_devc), GFP_KERNEL); + if (!devc) { + printk(KERN_WARNING "uart401: Can't allocate memory\n"); + goto cleanup_region; + } devc->base = hw_config->io_base; devc->irq = hw_config->irq; @@ -409,10 +326,67 @@ ok = reset_uart401(devc); restore_flags(flags); - if (ok) - detected_devc = devc; + if (!ok) + goto cleanup_devc; - return ok; + if (hw_config->name) + name = hw_config->name; + + if (devc->irq < 0) { + devc->share_irq = 1; + devc->irq *= -1; + } else + devc->share_irq = 0; + + if (!devc->share_irq) + if (request_irq(devc->irq, uart401intr, 0, "MPU-401 UART", devc) < 0) { + printk(KERN_WARNING "uart401: Failed to allocate IRQ%d\n", devc->irq); + devc->share_irq = 1; + } + devc->my_dev = sound_alloc_mididev(); + enter_uart_mode(devc); + + if (devc->my_dev == -1) { + printk(KERN_INFO "uart401: Too many midi devices detected\n"); + goto cleanup_irq; + } + conf_printf(name, hw_config); + std_midi_synth.midi_dev = devc->my_dev; + midi_devs[devc->my_dev] = kmalloc(sizeof(struct midi_operations), GFP_KERNEL); + if (!midi_devs[devc->my_dev]) { + printk(KERN_ERR "uart401: Failed to allocate memory\n"); + goto cleanup_unload_mididev; + } + memcpy(midi_devs[devc->my_dev], &uart401_operations, sizeof(struct midi_operations)); + + if (owner) + midi_devs[devc->my_dev]->owner = owner; + + midi_devs[devc->my_dev]->devc = devc; + midi_devs[devc->my_dev]->converter = kmalloc(sizeof(struct synth_operations), GFP_KERNEL); + if (!midi_devs[devc->my_dev]->converter) { + printk(KERN_WARNING "uart401: Failed to allocate memory\n"); + goto cleanup_midi_devs; + } + memcpy(midi_devs[devc->my_dev]->converter, &std_midi_synth, sizeof(struct synth_operations)); + strcpy(midi_devs[devc->my_dev]->info.name, name); + midi_devs[devc->my_dev]->converter->id = "UART401"; + hw_config->slots[4] = devc->my_dev; + sequencer_init(); + devc->opened = 0; + return 1; +cleanup_midi_devs: + kfree(midi_devs[devc->my_dev]); +cleanup_unload_mididev: + sound_unload_mididev(devc->my_dev); +cleanup_irq: + if (!devc->share_irq) + free_irq(devc->irq, devc); +cleanup_devc: + kfree(devc); +cleanup_region: + release_region(hw_config->io_base, 4); + return 0; } void unload_uart401(struct address_info *hw_config) @@ -446,7 +420,6 @@ sound_unload_mididev(hw_config->slots[4]); } -EXPORT_SYMBOL(attach_uart401); EXPORT_SYMBOL(probe_uart401); EXPORT_SYMBOL(unload_uart401); EXPORT_SYMBOL(uart401intr); @@ -469,9 +442,8 @@ to others */ if (cfg_mpu.io_base != -1 && cfg_mpu.irq != -1) { printk(KERN_INFO "MPU-401 UART driver Copyright (C) Hannu Savolainen 1993-1997"); - if (probe_uart401(&cfg_mpu) == 0) + if (!probe_uart401(&cfg_mpu, THIS_MODULE)) return -ENODEV; - attach_uart401(&cfg_mpu, THIS_MODULE); } return 0; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/uart6850.c linux/drivers/sound/uart6850.c --- v2.4.0-test8/linux/drivers/sound/uart6850.c Fri Aug 11 08:26:44 2000 +++ linux/drivers/sound/uart6850.c Sun Sep 17 09:45:07 2000 @@ -13,8 +13,11 @@ * Alan Cox: Updated for new modular code. Removed snd_* irq handling. Now * uses native linux resources * Christoph Hellwig: Adapted to module_init/module_exit + * Jeff Garzik: Made it work again, in theory + * FIXME: If the request_irq() succeeds, the probe succeeds. Ug. + * + * Status: Testing required (no shit -jgarzik) * - * Status: Testing required * */ @@ -64,12 +67,11 @@ #define UART_RESET 0x95 #define UART_MODE_ON 0x03 -static int uart6850_opened = 0; +static int uart6850_opened; static int uart6850_irq; -static int uart6850_detected = 0; +static int uart6850_detected; static int my_dev; -static int reset_uart6850(void); static void (*midi_input_intr) (int dev, unsigned char data); static void poll_uart6850(unsigned long dummy); @@ -251,6 +253,9 @@ int ok, timeout; unsigned long flags; + if (!uart6850_detected) + return; + if ((my_dev = sound_alloc_mididev()) == -1) { printk(KERN_INFO "uart6850: Too many midi devices detected\n"); @@ -260,11 +265,6 @@ uart6850_osp = hw_config->osp; uart6850_irq = hw_config->irq; - if (!uart6850_detected) - { - sound_unload_mididev(my_dev); - return; - } save_flags(flags); cli(); @@ -283,7 +283,7 @@ sequencer_init(); } -static int reset_uart6850(void) +static inline int reset_uart6850(void) { uart6850_read(); return 1; /* @@ -291,10 +291,9 @@ */ } - static int __init probe_uart6850(struct address_info *hw_config) { - int ok = 0; + int ok; uart6850_osp = hw_config->osp; uart6850_base = hw_config->io_base; @@ -334,6 +333,7 @@ if (probe_uart6850(&cfg_mpu)) return -ENODEV; + attach_uart6850(&cfg_mpu); return 0; } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/vidc.c linux/drivers/sound/vidc.c --- v2.4.0-test8/linux/drivers/sound/vidc.c Fri Aug 11 08:26:44 2000 +++ linux/drivers/sound/vidc.c Wed Sep 27 13:39:23 2000 @@ -1,9 +1,13 @@ /* - * drivers/sound/vidc.c + * linux/drivers/sound/vidc.c * - * VIDC20 audio driver. + * Copyright (C) 1997-2000 by Russell King * - * Copyright (C) 1997-2000 by 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. + * + * VIDC20 audio driver. * * The VIDC20 sound hardware consists of the VIDC20 itself, a DAC and a DMA * engine. The DMA transfers fixed-format (16-bit little-endian linear) @@ -13,7 +17,6 @@ * We currently support a mixer device, but it is currently non-functional. */ -#include #include #include #include @@ -21,7 +24,7 @@ #include #include #include -#include +#include #include #include @@ -79,7 +82,6 @@ static void (*old_mksound)(unsigned int hz, unsigned int ticks); extern void (*kd_mksound)(unsigned int hz, unsigned int ticks); extern void vidc_update_filler(int bits, int channels); -extern int softoss_dev; static void vidc_mksound(unsigned int hz, unsigned int ticks) @@ -287,10 +289,10 @@ struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; unsigned long flags; - save_flags_cli(flags); + local_irq_save(flags); dma_start = buf - (unsigned long)dmap->raw_buf_phys + (unsigned long)dmap->raw_buf; dma_count = total_count; - restore_flags(flags); + local_irq_restore(flags); } static void @@ -345,7 +347,7 @@ if (!(adev->flags & DMA_ACTIVE)) { unsigned long flags; - save_flags_cli(flags); + local_irq_save(flags); /* prevent recusion */ adev->flags |= DMA_ACTIVE; @@ -354,7 +356,7 @@ vidc_sound_dma_irq(0, NULL, NULL); outb(DMA_CR_E | 0x10, IOMD_SD0CR); - restore_flags(flags); + local_irq_restore(flags); } } } @@ -471,9 +473,6 @@ vidc_adev = adev; vidc_mixer_set(SOUND_MIXER_VOLUME, (85 | 85 << 8)); -#if defined(CONFIG_SOUND_SOFTOSS) || defined(CONFIG_SOUND_SOFTOSS_MODULE) - softoss_dev = adev; -#endif return; irq_failed: diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/vidc.h linux/drivers/sound/vidc.h --- v2.4.0-test8/linux/drivers/sound/vidc.h Thu Feb 24 22:44:47 2000 +++ linux/drivers/sound/vidc.h Mon Sep 18 15:15:22 2000 @@ -1,9 +1,13 @@ /* - * drivers/sound/vidc.h + * linux/drivers/sound/vidc.h * - * VIDC sound function prototypes + * Copyright (C) 1997 Russell King * - * Copyright (C) 1997 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. + * + * VIDC sound function prototypes */ /* vidc.c */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/vidc_fill.S linux/drivers/sound/vidc_fill.S --- v2.4.0-test8/linux/drivers/sound/vidc_fill.S Thu Feb 24 22:44:47 2000 +++ linux/drivers/sound/vidc_fill.S Mon Sep 18 15:15:22 2000 @@ -1,15 +1,19 @@ /* - * sound/vidc_fill.S + * linux/drivers/sound/vidc_fill.S * - * Filler routines for DMA buffers + * Copyright (C) 1997 Russell King * - * Copyright (C) 1997 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. + * + * Filler routines for DMA buffers */ #define __ASSEMBLY__ #include #include #include -#include +#include .text diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/vwsnd.c linux/drivers/sound/vwsnd.c --- v2.4.0-test8/linux/drivers/sound/vwsnd.c Tue Aug 29 14:09:15 2000 +++ linux/drivers/sound/vwsnd.c Mon Sep 25 12:32:54 2000 @@ -138,6 +138,8 @@ */ #include +#include + #include #include #include @@ -3452,12 +3454,10 @@ CO_IRQ(CO_APIC_LI_AUDIO) /* irq */ }; -#ifdef MODULE - MODULE_DESCRIPTION("SGI Visual Workstation sound module"); MODULE_AUTHOR("Bob Miller "); -extern int init_module(void) +static int __init init_vwsnd(void) { int err; @@ -3472,23 +3472,15 @@ return 0; } -extern void cleanup_module(void) +static void __exit cleanup_vwsnd(void) { DBGX("sound::vwsnd::cleanup_module()\n"); unload_vwsnd(&the_hw_config); } -#else - -extern void init_vwsnd(void) -{ - DBGX("sound::vwsnd::init_vwsnd()\n"); - if (probe_vwsnd(&the_hw_config)) - (void) attach_vwsnd(&the_hw_config); -} - -#endif /* !MODULE */ +module_init(init_vwsnd); +module_exit(cleanup_vwsnd); /* * Local variables: diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/waveartist.c linux/drivers/sound/waveartist.c --- v2.4.0-test8/linux/drivers/sound/waveartist.c Tue Aug 29 14:09:15 2000 +++ linux/drivers/sound/waveartist.c Mon Sep 18 15:15:22 2000 @@ -38,7 +38,6 @@ #include #include -#include #include #include #include diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/wf_midi.c linux/drivers/sound/wf_midi.c --- v2.4.0-test8/linux/drivers/sound/wf_midi.c Fri Aug 11 08:26:44 2000 +++ linux/drivers/sound/wf_midi.c Sun Sep 17 09:45:07 2000 @@ -781,8 +781,7 @@ return 0; } -static int __init detect_wf_mpu (int irq, int io_base) - +int __init detect_wf_mpu (int irq, int io_base) { if (check_region (io_base, 2)) { printk (KERN_WARNING "WF-MPU: I/O port %x already in use.\n", diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/ymf_sb.c linux/drivers/sound/ymf_sb.c --- v2.4.0-test8/linux/drivers/sound/ymf_sb.c Fri Aug 11 08:26:44 2000 +++ linux/drivers/sound/ymf_sb.c Wed Sep 27 13:53:57 2000 @@ -40,6 +40,9 @@ in 724hwmcode.h. * fixed wrong legacy_io setting on YMF744/YMF754 . + Thu Sep 21 05:32:51 BRT 2000 0.0.5 + * got rid of attach_uart401 and attach_sbmpu + Arnaldo Carvalho de Melo */ #include @@ -217,17 +220,15 @@ #define PFX "ymf_sb: " -#define YMFSB_VERSION "0.0.4" +#define YMFSB_VERSION "0.0.5" #define YMFSB_CARD_NAME "YMF7xx Legacy Audio driver " YMFSB_VERSION #ifdef SUPPORT_UART401_MIDI #if 0 # define ymf7xxsb_probe_midi probe_uart401 -# define ymf7xxsb_attach_midi attach_uart401 # define ymf7xxsb_unload_midi unload_uart401 #else # define ymf7xxsb_probe_midi probe_sbmpu -# define ymf7xxsb_attach_midi attach_sbmpu # define ymf7xxsb_unload_midi unload_sbmpu #endif #endif @@ -771,14 +772,13 @@ /* register legacy MIDI */ if ( mpu_io > 0 && 0) { - if (!ymf7xxsb_probe_midi (&mpu_data[cards])) { + if (!ymf7xxsb_probe_midi (&mpu_data[cards], THIS_MODULE)) { printk (KERN_ERR PFX "MIDI probe @ 0x%X failed, aborting\n", mpu_io); ymf7xxsb_unload_sb (&sb_data[cards], 0); return -ENODEV; } - ymf7xxsb_attach_midi (&mpu_data[cards], THIS_MODULE); } #endif diff -u --recursive --new-file v2.4.0-test8/linux/drivers/telephony/Makefile linux/drivers/telephony/Makefile --- v2.4.0-test8/linux/drivers/telephony/Makefile Wed Dec 29 17:13:59 1999 +++ linux/drivers/telephony/Makefile Sun Sep 17 09:45:07 2000 @@ -1,35 +1,29 @@ # -# Makefile for the kernel miscellaneous drivers. +# Makefile for drivers/telephony # # 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 inherited from the -# parent makes.. -SUB_DIRS := +SUB_DIRS := MOD_SUB_DIRS := $(SUB_DIRS) ALL_SUB_DIRS := $(SUB_DIRS) -L_TARGET := telephony.a -MX_OBJS := -M_OBJS := - -ifeq ($(CONFIG_PHONE),y) - LX_OBJS += phonedev.o -else - ifeq ($(CONFIG_PHONE),m) - MX_OBJS += phonedev.o - endif -endif - -ifeq ($(CONFIG_PHONE_IXJ),y) - L_OBJS += ixj.o -else - ifeq ($(CONFIG_PHONE_IXJ),m) - M_OBJS += ixj.o - endif -endif +obj-y := +obj-n := +obj-m := +obj- := +export-objs := phonedev.o + +obj-$(CONFIG_PHONE) += phonedev.o +obj-$(CONFIG_PHONE_IXJ) += ixj.o + +O_TARGET := telephony.o +O_OBJS := $(filter-out $(export-objs), $(obj-y)) +OX_OBJS := $(filter $(export-objs), $(obj-y)) +M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) +MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) include $(TOPDIR)/Rules.make + diff -u --recursive --new-file v2.4.0-test8/linux/drivers/telephony/ixj.c linux/drivers/telephony/ixj.c --- v2.4.0-test8/linux/drivers/telephony/ixj.c Wed Jul 12 21:58:43 2000 +++ linux/drivers/telephony/ixj.c Tue Sep 19 08:31:53 2000 @@ -1,10 +1,10 @@ -/* +/**************************************************************************** * ixj.c * * Device Driver for the Internet PhoneJACK and * Internet LineJACK Telephony Cards. * - * (c) Copyright 1999 Quicknet Technologies, Inc. + * (c) Copyright 1999-2000 Quicknet Technologies, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -12,29 +12,41 @@ * 2 of the License, or (at your option) any later version. * * Author: Ed Okerson, - * + * * Contributors: Greg Herlein, * David W. Erhart, * John Sellers, * Mike Preston, - * + * * Fixes: - * - * 2.3.x port : Alan Cox - * - * More information about the hardware related to this driver can be found + * Marc Boucher, + * + * More information about the hardware related to this driver can be found * at our website: http://www.quicknet.net * - */ + * IN NO EVENT SHALL QUICKNET TECHNOLOGIES, INC. BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT + * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF QUICKNET + * TECHNOLOGIES, INC.HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * QUICKNET TECHNOLOGIES, INC. SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND QUICKNET TECHNOLOGIES, INC. HAS NO OBLIGATION + * TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + ***************************************************************************/ -static char ixj_c_rcsid[] = "$Id: ixj.c,v 3.4 1999/12/16 22:18:36 root Exp root $"; +static char ixj_c_rcsid[] = "$Id: ixj.c,v 3.31 2000/04/14 19:24:47 jaugenst Exp $"; +static char ixj_c_revision[] = "$Revision: 3.31 $"; //#define PERFMON_STATS #define IXJDEBUG 0 #define MAXRINGS 5 -#include #include +#include + #include #include #include /* printk() */ @@ -50,7 +62,6 @@ #include #include #include -#include #include #include @@ -102,14 +113,17 @@ static void ixj_write_frame(int board); static void ixj_init_timer(void); static void ixj_add_timer(void); -static void ixj_del_timer(void); static void ixj_timeout(unsigned long ptr); static int read_filters(int board); static int LineMonitor(int board); static int ixj_fasync(int fd, struct file *, int mode); +static int ixj_set_port(int board, int arg); +static int ixj_set_pots(int board, int arg); static int ixj_hookstate(int board); static int ixj_record_start(int board); static void ixj_record_stop(int board); +static void set_rec_volume(int board, int volume); +static void ixj_vad(int board, int arg); static int ixj_play_start(int board); static void ixj_play_stop(int board); static int ixj_set_tone_on(unsigned short arg, int board); @@ -126,6 +140,7 @@ static char daa_int_read(int board); static int daa_set_mode(int board, int mode); static int ixj_linetest(int board); +static int ixj_daa_write(int board); static int ixj_daa_cid_read(int board); static void DAA_Coeff_US(int board); static void DAA_Coeff_UK(int board); @@ -136,12 +151,18 @@ static int ixj_init_filter(int board, IXJ_FILTER * jf); static int ixj_init_tone(int board, IXJ_TONE * ti); static int ixj_build_cadence(int board, IXJ_CADENCE * cp); +static int ixj_build_filter_cadence(int board, IXJ_FILTER_CADENCE * cp); // Serial Control Interface funtions static int SCI_Control(int board, int control); static int SCI_Prepare(int board); static int SCI_WaitHighSCI(int board); static int SCI_WaitLowSCI(int board); static DWORD PCIEE_GetSerialNumber(WORD wAddress); +static int ixj_PCcontrol_wait(int board); +static void ixj_write_cid(int board); +static void ixj_write_cid_bit(int board, int bit); +static int set_base_frame(int board, int size); +static int set_play_codec(int board, int rate); /************************************************************************ CT8020/CT8021 Host Programmers Model @@ -162,12 +183,19 @@ ixj[board].hsr.bytes.low = inb_p(ixj[board].DSPbase + 8); ixj[board].hsr.bytes.high = inb_p(ixj[board].DSPbase + 9); } + extern __inline__ int IsControlReady(int board) { ixj_read_HSR(board); return ixj[board].hsr.bits.controlrdy ? 1 : 0; } +extern __inline__ int IsPCControlReady(int board) +{ + ixj[board].pccr1.byte = inb_p(ixj[board].XILINXbase + 3); + return ixj[board].pccr1.bits.crr ? 1 : 0; +} + extern __inline__ int IsStatusReady(int board) { ixj_read_HSR(board); @@ -177,21 +205,54 @@ extern __inline__ int IsRxReady(int board) { ixj_read_HSR(board); +#ifdef PERFMON_STATS + ++ixj[board].rxreadycheck; +#endif return ixj[board].hsr.bits.rxrdy ? 1 : 0; } extern __inline__ int IsTxReady(int board) { ixj_read_HSR(board); +#ifdef PERFMON_STATS + ++ixj[board].txreadycheck; +#endif return ixj[board].hsr.bits.txrdy ? 1 : 0; } +extern __inline__ void set_play_volume(int board, int volume) +{ + ixj_WriteDSPCommand(0xCF02, board); + ixj_WriteDSPCommand(volume, board); +} + +extern __inline__ int get_play_volume(int board) +{ + ixj_WriteDSPCommand(0xCF00, board); + return ixj[board].ssr.high << 8 | ixj[board].ssr.low; +} + extern __inline__ BYTE SLIC_GetState(int board) { IXJ *j = &ixj[board]; - j->pld_slicr.byte = inb_p(j->XILINXbase + 0x01); - + if (j->cardtype == 600) { + j->pccr1.byte = 0; + j->psccr.bits.dev = 3; + j->psccr.bits.rw = 1; + outw_p(j->psccr.byte << 8, j->XILINXbase + 0x00); + ixj_PCcontrol_wait(board); + j->pslic.byte = inw_p(j->XILINXbase + 0x00) & 0xFF; + ixj_PCcontrol_wait(board); + if (j->pslic.bits.powerdown) + return PLD_SLIC_STATE_OC; + else if (!j->pslic.bits.ring0 && !j->pslic.bits.ring1) + return PLD_SLIC_STATE_ACTIVE; + else + return PLD_SLIC_STATE_RINGING; + } else { + j->pld_slicr.byte = inb_p(j->XILINXbase + 0x01); + } return j->pld_slicr.bits.state; } @@ -200,78 +261,122 @@ BOOL fRetVal = FALSE; IXJ *j = &ixj[board]; - // Set the C1, C2, C3 & B2EN signals. - switch (byState) { - case PLD_SLIC_STATE_OC: - j->pld_slicw.bits.c1 = 0; - j->pld_slicw.bits.c2 = 0; - j->pld_slicw.bits.c3 = 0; - j->pld_slicw.bits.b2en = 0; - outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01); - fRetVal = TRUE; - break; - case PLD_SLIC_STATE_RINGING: - j->pld_slicw.bits.c1 = 1; - j->pld_slicw.bits.c2 = 0; - j->pld_slicw.bits.c3 = 0; - j->pld_slicw.bits.b2en = 1; - outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01); - fRetVal = TRUE; - break; - case PLD_SLIC_STATE_ACTIVE: - j->pld_slicw.bits.c1 = 0; - j->pld_slicw.bits.c2 = 1; - j->pld_slicw.bits.c3 = 0; - j->pld_slicw.bits.b2en = 0; - outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01); - fRetVal = TRUE; - break; - case PLD_SLIC_STATE_OHT: // On-hook transmit + if (j->cardtype == 600) { + if (j->flags.pcmciasct) { + switch (byState) { + case PLD_SLIC_STATE_TIPOPEN: + case PLD_SLIC_STATE_OC: + j->pslic.bits.powerdown = 1; + j->pslic.bits.ring0 = j->pslic.bits.ring1 = 0; + fRetVal = TRUE; + break; + case PLD_SLIC_STATE_RINGING: + if (j->readers || j->writers) { + j->pslic.bits.powerdown = 0; + j->pslic.bits.ring0 = 1; + j->pslic.bits.ring1 = 0; + fRetVal = TRUE; + } + break; + case PLD_SLIC_STATE_OHT: // On-hook transmit - j->pld_slicw.bits.c1 = 1; - j->pld_slicw.bits.c2 = 1; - j->pld_slicw.bits.c3 = 0; - j->pld_slicw.bits.b2en = 0; - outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01); - fRetVal = TRUE; - break; - case PLD_SLIC_STATE_TIPOPEN: - j->pld_slicw.bits.c1 = 0; - j->pld_slicw.bits.c2 = 0; - j->pld_slicw.bits.c3 = 1; - j->pld_slicw.bits.b2en = 0; - outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01); - fRetVal = TRUE; - break; - case PLD_SLIC_STATE_STANDBY: - j->pld_slicw.bits.c1 = 1; - j->pld_slicw.bits.c2 = 0; - j->pld_slicw.bits.c3 = 1; - j->pld_slicw.bits.b2en = 1; - outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01); - fRetVal = TRUE; - break; - case PLD_SLIC_STATE_APR: // Active polarity reversal + case PLD_SLIC_STATE_STANDBY: + case PLD_SLIC_STATE_ACTIVE: + if (j->readers || j->writers) { + j->pslic.bits.powerdown = 0; + } else { + j->pslic.bits.powerdown = 1; + } + j->pslic.bits.ring0 = j->pslic.bits.ring1 = 0; + fRetVal = TRUE; + break; + case PLD_SLIC_STATE_APR: // Active polarity reversal - j->pld_slicw.bits.c1 = 0; - j->pld_slicw.bits.c2 = 1; - j->pld_slicw.bits.c3 = 1; - j->pld_slicw.bits.b2en = 0; - outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01); - fRetVal = TRUE; - break; - case PLD_SLIC_STATE_OHTPR: // OHT polarity reversal + case PLD_SLIC_STATE_OHTPR: // OHT polarity reversal - j->pld_slicw.bits.c1 = 1; - j->pld_slicw.bits.c2 = 1; - j->pld_slicw.bits.c3 = 1; - j->pld_slicw.bits.b2en = 0; - outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01); - fRetVal = TRUE; - break; - default: - fRetVal = FALSE; - break; + default: + fRetVal = FALSE; + break; + } + j->psccr.bits.dev = 3; + j->psccr.bits.rw = 0; + outw_p(j->psccr.byte << 8 | j->pslic.byte, j->XILINXbase + 0x00); + ixj_PCcontrol_wait(board); + } + } else { + // Set the C1, C2, C3 & B2EN signals. + switch (byState) { + case PLD_SLIC_STATE_OC: + j->pld_slicw.bits.c1 = 0; + j->pld_slicw.bits.c2 = 0; + j->pld_slicw.bits.c3 = 0; + j->pld_slicw.bits.b2en = 0; + outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01); + fRetVal = TRUE; + break; + case PLD_SLIC_STATE_RINGING: + j->pld_slicw.bits.c1 = 1; + j->pld_slicw.bits.c2 = 0; + j->pld_slicw.bits.c3 = 0; + j->pld_slicw.bits.b2en = 1; + outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01); + fRetVal = TRUE; + break; + case PLD_SLIC_STATE_ACTIVE: + j->pld_slicw.bits.c1 = 0; + j->pld_slicw.bits.c2 = 1; + j->pld_slicw.bits.c3 = 0; + j->pld_slicw.bits.b2en = 0; + outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01); + fRetVal = TRUE; + break; + case PLD_SLIC_STATE_OHT: // On-hook transmit + + j->pld_slicw.bits.c1 = 1; + j->pld_slicw.bits.c2 = 1; + j->pld_slicw.bits.c3 = 0; + j->pld_slicw.bits.b2en = 0; + outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01); + fRetVal = TRUE; + break; + case PLD_SLIC_STATE_TIPOPEN: + j->pld_slicw.bits.c1 = 0; + j->pld_slicw.bits.c2 = 0; + j->pld_slicw.bits.c3 = 1; + j->pld_slicw.bits.b2en = 0; + outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01); + fRetVal = TRUE; + break; + case PLD_SLIC_STATE_STANDBY: + j->pld_slicw.bits.c1 = 1; + j->pld_slicw.bits.c2 = 0; + j->pld_slicw.bits.c3 = 1; + j->pld_slicw.bits.b2en = 1; + outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01); + fRetVal = TRUE; + break; + case PLD_SLIC_STATE_APR: // Active polarity reversal + + j->pld_slicw.bits.c1 = 0; + j->pld_slicw.bits.c2 = 1; + j->pld_slicw.bits.c3 = 1; + j->pld_slicw.bits.b2en = 0; + outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01); + fRetVal = TRUE; + break; + case PLD_SLIC_STATE_OHTPR: // OHT polarity reversal + + j->pld_slicw.bits.c1 = 1; + j->pld_slicw.bits.c2 = 1; + j->pld_slicw.bits.c3 = 1; + j->pld_slicw.bits.b2en = 0; + outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01); + fRetVal = TRUE; + break; + default: + fRetVal = FALSE; + break; + } } return fRetVal; @@ -363,51 +468,42 @@ add_timer(&ixj_timer); } -static void ixj_del_timer(void) -{ - del_timer(&ixj_timer); -} - static void ixj_tone_timeout(int board) { IXJ *j = &ixj[board]; IXJ_TONE ti; - + j->tone_state++; if (j->tone_state == 3) { j->tone_state = 0; if (j->cadence_t) { j->tone_cadence_state++; - if (j->tone_cadence_state >= j->cadence_t->elements_used) - { - switch (j->cadence_t->termination) - { - case PLAY_ONCE: - ixj_cpt_stop(board); - break; - case REPEAT_LAST_ELEMENT: - j->tone_cadence_state--; - ixj_play_tone(board, j->cadence_t->ce[j->tone_cadence_state].index); - break; - case REPEAT_ALL: - j->tone_cadence_state = 0; - if (j->cadence_t->ce[j->tone_cadence_state].freq0) - { - ti.tone_index = j->cadence_t->ce[j->tone_cadence_state].index; - ti.freq0 = j->cadence_t->ce[j->tone_cadence_state].freq0; - ti.gain0 = j->cadence_t->ce[j->tone_cadence_state].gain0; - ti.freq1 = j->cadence_t->ce[j->tone_cadence_state].freq1; - ti.gain1 = j->cadence_t->ce[j->tone_cadence_state].gain1; - ixj_init_tone(board, &ti); - } - ixj_set_tone_on(j->cadence_t->ce[0].tone_on_time, board); - ixj_set_tone_off(j->cadence_t->ce[0].tone_off_time, board); - ixj_play_tone(board, j->cadence_t->ce[0].index); - break; + if (j->tone_cadence_state >= j->cadence_t->elements_used) { + switch (j->cadence_t->termination) { + case PLAY_ONCE: + ixj_cpt_stop(board); + break; + case REPEAT_LAST_ELEMENT: + j->tone_cadence_state--; + ixj_play_tone(board, j->cadence_t->ce[j->tone_cadence_state].index); + break; + case REPEAT_ALL: + j->tone_cadence_state = 0; + if (j->cadence_t->ce[j->tone_cadence_state].freq0) { + ti.tone_index = j->cadence_t->ce[j->tone_cadence_state].index; + ti.freq0 = j->cadence_t->ce[j->tone_cadence_state].freq0; + ti.gain0 = j->cadence_t->ce[j->tone_cadence_state].gain0; + ti.freq1 = j->cadence_t->ce[j->tone_cadence_state].freq1; + ti.gain1 = j->cadence_t->ce[j->tone_cadence_state].gain1; + ixj_init_tone(board, &ti); + } + ixj_set_tone_on(j->cadence_t->ce[0].tone_on_time, board); + ixj_set_tone_off(j->cadence_t->ce[0].tone_off_time, board); + ixj_play_tone(board, j->cadence_t->ce[0].index); + break; } } else { - if (j->cadence_t->ce[j->tone_cadence_state].gain0) - { + if (j->cadence_t->ce[j->tone_cadence_state].gain0) { ti.tone_index = j->cadence_t->ce[j->tone_cadence_state].index; ti.freq0 = j->cadence_t->ce[j->tone_cadence_state].freq0; ti.gain0 = j->cadence_t->ce[j->tone_cadence_state].gain0; @@ -423,49 +519,49 @@ } } +extern __inline__ void ixj_kill_fasync(int board, int dir) +{ + kill_fasync(&ixj[board].async_queue, SIGIO, dir); // Send apps notice of change + +} static void ixj_timeout(unsigned long ptr) { int board; unsigned long jifon; IXJ *j; - for (board = 0; board < IXJMAX; board++) - { + for (board = 0; board < IXJMAX; board++) { j = &ixj[board]; - if (j->DSPbase) - { + if (j->DSPbase) { #ifdef PERFMON_STATS j->timerchecks++; #endif - if (j->tone_state) - { - if (!ixj_hookstate(board)) - { + if (j->tone_state) { + if (!ixj_hookstate(board)) { ixj_cpt_stop(board); - if (j->m_hook) - { + if (j->m_hook) { j->m_hook = 0; j->ex.bits.hookstate = 1; - kill_fasync(&j->async_queue, SIGIO, POLL_IN); // Send apps notice of change + ixj_kill_fasync(board, POLL_IN); } - goto timer_end; + continue; } if (j->tone_state == 1) jifon = (hertz * j->tone_on_time * 25 / 100000); else jifon = (hertz * j->tone_on_time * 25 / 100000) + (hertz * j->tone_off_time * 25 / 100000); - if (jiffies < j->tone_start_jif + jifon) { + if (time_before(jiffies, j->tone_start_jif + jifon)) { if (j->tone_state == 1) { ixj_play_tone(board, j->tone_index); if (j->dsp.low == 0x20) { - goto timer_end; + continue; } } else { ixj_play_tone(board, 0); if (j->dsp.low == 0x20) { - goto timer_end; + continue; } } } else { @@ -476,13 +572,13 @@ if (j->flags.busytone) { ixj_busytone(board); if (j->dsp.low == 0x20) { - goto timer_end; + continue; } } if (j->flags.ringback) { ixj_ringback(board); if (j->dsp.low == 0x20) { - goto timer_end; + continue; } } if (!j->tone_state) { @@ -499,7 +595,7 @@ if (IsRxReady(board)) { ixj_read_frame(board); } - if (IsTxReady(board)) { + if (IsTxReady(board) && !j->flags.cidplay) { ixj_write_frame(board); } } @@ -509,6 +605,11 @@ ixj_ring_off(board); } else { if (jiffies - j->ring_cadence_jif >= (hertz/2)) { + if (j->flags.cidring && !j->flags.cidsent) { + j->flags.cidsent = 1; + ixj_write_cid(board); + j->flags.cidring = 0; + } j->ring_cadence_t--; if (j->ring_cadence_t == -1) j->ring_cadence_t = 15; @@ -518,16 +619,15 @@ ixj_ring_on(board); } else { ixj_ring_off(board); + j->flags.cidring = 1; } - goto timer_end; + continue; } } if (!j->flags.ringing) { if (ixj_hookstate(board)) { - if (j->dsp.low == 0x21 && - j->pld_slicr.bits.state != PLD_SLIC_STATE_ACTIVE) - // Internet LineJACK - { + if (j->dsp.low != 0x20 && + SLIC_GetState(board) != PLD_SLIC_STATE_ACTIVE) { SLIC_SetState(PLD_SLIC_STATE_ACTIVE, board); } LineMonitor(board); @@ -536,12 +636,12 @@ j->proc_load = j->ssr.high << 8 | j->ssr.low; if (!j->m_hook) { j->m_hook = j->ex.bits.hookstate = 1; - kill_fasync(&j->async_queue, SIGIO, POLL_IN); // Send apps notice of change + ixj_kill_fasync(board, POLL_IN); } } else { - if (j->dsp.low == 0x21 && - j->pld_slicr.bits.state == PLD_SLIC_STATE_ACTIVE) - // Internet LineJACK + if (j->dsp.low != 0x20 && + SLIC_GetState(board) == PLD_SLIC_STATE_ACTIVE) + // Internet LineJACK { SLIC_SetState(PLD_SLIC_STATE_STANDBY, board); } @@ -551,14 +651,14 @@ if (j->m_hook) { j->m_hook = 0; j->ex.bits.hookstate = 1; - kill_fasync(&j->async_queue, SIGIO, POLL_IN); // Send apps notice of change + ixj_kill_fasync(board, POLL_IN); } } } - if (j->cardtype == 300) { + if (j->cardtype == 300 && !j->flags.incheck) { if (j->flags.pstn_present) { j->pld_scrr.byte = inb_p(j->XILINXbase); - if (jiffies >= j->pstn_sleeptil && j->pld_scrr.bits.daaflag) { + if (j->pld_scrr.bits.daaflag) { daa_int_read(board); if (j->m_DAAShadowRegs.XOP_REGS.XOP.xr0.bitreg.RING) { if (!j->flags.pstn_ringing) { @@ -567,22 +667,38 @@ daa_set_mode(board, SOP_PU_RINGING); } } - if (j->m_DAAShadowRegs.XOP_REGS.XOP.xr0.bitreg.VDD_OK) { + if (time_after(jiffies, j->pstn_sleeptil) && j->m_DAAShadowRegs.XOP_REGS.XOP.xr0.bitreg.VDD_OK) { j->pstn_winkstart = 0; + j->pstn_ring_stop = 0; + ixj[board].pld_scrw.bits.led1 = 1; if (j->flags.pstn_ringing && !j->pstn_envelope) { + if (j->daa_mode != SOP_PU_RINGING) { + j->flags.pstn_ringing = 0; + } else { + ixj[board].pld_scrw.bits.led2 = 0; + j->pstn_envelope = 1; + j->pstn_ring_start = jiffies; + j->pstn_ring_stop = 0; + } j->ex.bits.pstn_ring = 0; - j->pstn_envelope = 1; - j->pstn_ring_start = jiffies; } + outb_p(ixj[board].pld_scrw.byte, ixj[board].XILINXbase); } else { - if (j->flags.pstn_ringing && j->pstn_envelope && - jiffies > j->pstn_ring_start + ((hertz * 15) / 10)) { - j->ex.bits.pstn_ring = 1; - j->pstn_envelope = 0; + ixj[board].pld_scrw.bits.led1 = 0; + ixj[board].pld_scrw.bits.led2 = 1; + outb_p(ixj[board].pld_scrw.byte, ixj[board].XILINXbase); + if (j->flags.pstn_ringing && j->pstn_envelope) { + if(!j->pstn_ring_stop) { + j->pstn_ring_stop = jiffies; + } else if (time_after(jiffies, j->pstn_ring_stop + ((hertz * 5) / 100))){ + j->pstn_ring_stop = 0; + j->ex.bits.pstn_ring = 1; + j->pstn_envelope = 0; + } } else if (j->daa_mode == SOP_PU_CONVERSATION) { if (!j->pstn_winkstart) { j->pstn_winkstart = jiffies; - } else if (jiffies > j->pstn_winkstart + (hertz * j->winktime / 1000)) { + } else if (time_after(jiffies, j->pstn_winkstart + (hertz * j->winktime / 1000))) { daa_set_mode(board, SOP_PU_SLEEP); j->pstn_winkstart = 0; j->ex.bits.pstn_wink = 1; @@ -619,13 +735,23 @@ j->ex.bits.caller_id = 0; } if (!j->m_DAAShadowRegs.XOP_REGS.XOP.xr0.bitreg.VDD_OK) { + ixj[board].pld_scrw.bits.led1 = 0; + ixj[board].pld_scrw.bits.led2 = 1; + outb_p(ixj[board].pld_scrw.byte, ixj[board].XILINXbase); if (j->flags.pstn_ringing && j->pstn_envelope) { - j->ex.bits.pstn_ring = 1; - j->pstn_envelope = 0; + if(!j->pstn_ring_stop) { + j->pstn_ring_stop = jiffies; + } else if (time_after(jiffies, j->pstn_ring_stop + ((hertz * 5) / 100))){ + j->pstn_ring_stop = 0; + j->ex.bits.pstn_ring = 1; + j->pstn_envelope = 0; + } + ixj[board].pld_scrw.bits.led1 = 0; + outb_p(ixj[board].pld_scrw.byte, ixj[board].XILINXbase); } else if (j->daa_mode == SOP_PU_CONVERSATION) { if (!j->pstn_winkstart) { j->pstn_winkstart = jiffies; - } else if (jiffies > j->pstn_winkstart + (hertz * 320 / 1000)) { + } else if (time_after(jiffies, j->pstn_winkstart + (hertz * j->winktime / 1000))) { daa_set_mode(board, SOP_PU_SLEEP); j->pstn_winkstart = 0; j->ex.bits.pstn_wink = 1; @@ -635,18 +761,15 @@ } } } - if ((j->ex.bits.f0 || j->ex.bits.f1 || j->ex.bits.f2 || j->ex.bits.f3) - && j->filter_cadence) { - } if (j->ex.bytes) { wake_up_interruptible(&j->poll_q); // Wake any blocked selects - kill_fasync(&j->async_queue, SIGIO, POLL_IN); // Send apps notice of change + + ixj_kill_fasync(board, POLL_IN); } } else { break; } } -timer_end: ixj_add_timer(); } @@ -663,6 +786,19 @@ return 0; } +static int ixj_PCcontrol_wait(int board) +{ + unsigned long jif; + + jif = jiffies; + while (!IsPCControlReady(board)) { + if (jiffies - jif > (60 * (hertz / 100))) { + return -1; + } + } + return 0; +} + int ixj_WriteDSPCommand(unsigned short cmd, int board) { BYTES bytes; @@ -708,7 +844,7 @@ extern __inline__ void LED_SetState(int state, int board) { - if (ixj[board].dsp.low == 0x21) { + if (ixj[board].cardtype == 300) { ixj[board].pld_scrw.bits.led1 = state & 0x1 ? 1 : 0; ixj[board].pld_scrw.bits.led2 = state & 0x2 ? 1 : 0; ixj[board].pld_scrw.bits.led3 = state & 0x4 ? 1 : 0; @@ -746,12 +882,19 @@ case PORT_POTS: j->port = PORT_POTS; switch (j->cardtype) { + case 600: + if (j->flags.pcmciasct == 1) + SLIC_SetState(PLD_SLIC_STATE_ACTIVE, board); + else + return 11; + break; case 500: j->pld_slicw.pcib.mic = 0; j->pld_slicw.pcib.spk = 0; outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01); break; case 300: + ixj_set_pots(board, 0); if (ixj_WriteDSPCommand(0xC528, board)) /* Write CODEC config to Software Control Register */ return 2; @@ -789,12 +932,21 @@ case PORT_SPEAKER: j->port = PORT_SPEAKER; switch (j->cardtype) { + case 600: + if (j->flags.pcmciasct) { + SLIC_SetState(PLD_SLIC_STATE_OC, board); +// while(SLIC_GetState(board) != PLD_SLIC_STATE_OC) { + // SLIC_SetState(PLD_SLIC_STATE_OC,board); + // } + } + break; case 500: j->pld_slicw.pcib.mic = 1; j->pld_slicw.pcib.spk = 1; outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01); break; case 300: + ixj_set_pots(board, 0); break; case 100: j->gpio.bytes.high = 0x0B; @@ -859,8 +1011,7 @@ j->gpio.bits.gpio2 = 1; j->gpio.bits.gpio5 = 0; ixj_WriteDSPCommand(j->gpio.word, board); /* send the ring signal */ - } else // Internet LineJACK, Internet PhoneJACK Lite or - // Internet PhoneJACK PCI + } else // Internet LineJACK, Internet PhoneJACK Lite or Internet PhoneJACK PCI { if (ixjdebug > 0) printk(KERN_INFO "IXJ Ring On /dev/phone%d\n", board); @@ -869,6 +1020,212 @@ } } +static int ixj_pcmcia_cable_check(int board) +{ + IXJ *j = &ixj[board]; + + j->pccr1.byte = inb_p(j->XILINXbase + 0x03); + if (!j->flags.pcmciastate) { + j->pccr2.byte = inb_p(j->XILINXbase + 0x02); + if (j->pccr1.bits.drf || j->pccr2.bits.rstc) { + j->flags.pcmciastate = 4; + return 0; + } + if (j->pccr1.bits.ed) { + j->pccr1.bits.ed = 0; + j->psccr.bits.dev = 3; + j->psccr.bits.rw = 1; + outw_p(j->psccr.byte << 8, j->XILINXbase + 0x00); + ixj_PCcontrol_wait(board); + j->pslic.byte = inw_p(j->XILINXbase + 0x00) & 0xFF; + j->pslic.bits.led2 = j->pslic.bits.det ? 1 : 0; + j->psccr.bits.dev = 3; + j->psccr.bits.rw = 0; + outw_p(j->psccr.byte << 8 | j->pslic.byte, j->XILINXbase + 0x00); + ixj_PCcontrol_wait(board); + return j->pslic.bits.led2 ? 1 : 0; + } else if (j->flags.pcmciasct) { + return j->r_hook; + } else { + return 1; + } + } else if (j->flags.pcmciastate == 4) { + if (!j->pccr1.bits.drf) { + j->flags.pcmciastate = 3; + } + return 0; + } else if (j->flags.pcmciastate == 3) { + j->pccr2.bits.pwr = 0; + j->pccr2.bits.rstc = 1; + outb_p(j->pccr2.byte, j->XILINXbase + 0x02); + j->checkwait = jiffies + hertz * 2; + j->flags.incheck = 1; + j->flags.pcmciastate = 2; + return 0; + } else if (j->flags.pcmciastate == 2) { + if (j->flags.incheck) { + if (time_before(jiffies, j->checkwait)) { + return 0; + } else { + j->flags.incheck = 0; + } + } + j->pccr2.bits.pwr = 0; + j->pccr2.bits.rstc = 0; + outb_p(j->pccr2.byte, j->XILINXbase + 0x02); + j->flags.pcmciastate = 1; + return 0; + } else if (j->flags.pcmciastate == 1) { + j->flags.pcmciastate = 0; + if (!j->pccr1.bits.drf) { + j->psccr.bits.dev = 3; + j->psccr.bits.rw = 1; + outb_p(j->psccr.byte, j->XILINXbase + 0x01); + ixj_PCcontrol_wait(board); + j->flags.pcmciascp = 1; // Set Cable Present Flag + + j->flags.pcmciasct = (inw_p(j->XILINXbase + 0x00) >> 8) & 0x03; // Get Cable Type + + if (j->flags.pcmciasct == 3) { + j->flags.pcmciastate = 4; + return 0; + } else if (j->flags.pcmciasct == 0) { + j->pccr2.bits.pwr = 1; + j->pccr2.bits.rstc = 0; + outb_p(j->pccr2.byte, j->XILINXbase + 0x02); + j->port = PORT_SPEAKER; + } else { + j->port = PORT_POTS; + } + j->sic1.bits.cpd = 0; // Chip Power Down + + j->sic1.bits.mpd = 0; // MIC Bias Power Down + + j->sic1.bits.hpd = 0; // Handset Bias Power Down + + j->sic1.bits.lpd = 0; // Line Bias Power Down + + j->sic1.bits.spd = 1; // Speaker Drive Power Down + + j->psccr.bits.addr = 1; // R/W Smart Cable Register Address + + j->psccr.bits.rw = 0; // Read / Write flag + + j->psccr.bits.dev = 0; + outb(j->sic1.byte, j->XILINXbase + 0x00); + outb(j->psccr.byte, j->XILINXbase + 0x01); + ixj_PCcontrol_wait(board); + j->sic2.bits.al = 0; // Analog Loopback DAC analog -> ADC analog + + j->sic2.bits.dl2 = 0; // Digital Loopback DAC -> ADC one bit + + j->sic2.bits.dl1 = 0; // Digital Loopback ADC -> DAC one bit + + j->sic2.bits.pll = 0; // 1 = div 10, 0 = div 5 + + j->sic2.bits.hpd = 0; // HPF disable + + j->psccr.bits.addr = 2; // R/W Smart Cable Register Address + + j->psccr.bits.rw = 0; // Read / Write flag + + j->psccr.bits.dev = 0; + outb(j->sic2.byte, j->XILINXbase + 0x00); + outb(j->psccr.byte, j->XILINXbase + 0x01); + ixj_PCcontrol_wait(board); + j->psccr.bits.addr = 3; // R/W Smart Cable Register Address + + j->psccr.bits.rw = 0; // Read / Write flag + + j->psccr.bits.dev = 0; + outb(0x00, j->XILINXbase + 0x00); // PLL Divide N1 + + outb(j->psccr.byte, j->XILINXbase + 0x01); + ixj_PCcontrol_wait(board); + j->psccr.bits.addr = 4; // R/W Smart Cable Register Address + + j->psccr.bits.rw = 0; // Read / Write flag + + j->psccr.bits.dev = 0; + outb(0x09, j->XILINXbase + 0x00); // PLL Multiply M1 + + outb(j->psccr.byte, j->XILINXbase + 0x01); + ixj_PCcontrol_wait(board); + j->sirxg.bits.lig = 1; // Line In Gain + + j->sirxg.bits.lim = 1; // Line In Mute + + j->sirxg.bits.mcg = 0; // MIC In Gain // was 3 + + j->sirxg.bits.mcm = 0; // MIC In Mute + + j->sirxg.bits.him = 0; // Handset In Mute + + j->sirxg.bits.iir = 1; // IIR + + j->psccr.bits.addr = 5; // R/W Smart Cable Register Address + + j->psccr.bits.rw = 0; // Read / Write flag + + j->psccr.bits.dev = 0; + outb(j->sirxg.byte, j->XILINXbase + 0x00); + outb(j->psccr.byte, j->XILINXbase + 0x01); + ixj_PCcontrol_wait(board); + j->siadc.bits.hom = 0; // Handset Out Mute + + j->siadc.bits.lom = 0; // Line Out Mute + + j->siadc.bits.rxg = 23; //(0xC000 - 0x41C8) / 0x4EF; // RX PGA Gain + + j->psccr.bits.addr = 6; // R/W Smart Cable Register Address + + j->psccr.bits.rw = 0; // Read / Write flag + + j->psccr.bits.dev = 0; + outb(j->siadc.byte, j->XILINXbase + 0x00); + outb(j->psccr.byte, j->XILINXbase + 0x01); + ixj_PCcontrol_wait(board); + j->sidac.bits.srm = 1; // Speaker Right Mute + + j->sidac.bits.slm = 1; // Speaker Left Mute + + j->sidac.bits.txg = (0xC000 - 0x45E4) / 0x5D3; // TX PGA Gain + + j->psccr.bits.addr = 7; // R/W Smart Cable Register Address + + j->psccr.bits.rw = 0; // Read / Write flag + + j->psccr.bits.dev = 0; + outb(j->sidac.byte, j->XILINXbase + 0x00); + outb(j->psccr.byte, j->XILINXbase + 0x01); + ixj_PCcontrol_wait(board); + j->siaatt.bits.sot = 0; + j->psccr.bits.addr = 9; // R/W Smart Cable Register Address + + j->psccr.bits.rw = 0; // Read / Write flag + + j->psccr.bits.dev = 0; + outb(j->siaatt.byte, j->XILINXbase + 0x00); + outb(j->psccr.byte, j->XILINXbase + 0x01); + ixj_PCcontrol_wait(board); + + if (j->flags.pcmciasct == 1 && !j->readers && !j->writers) { + j->psccr.byte = j->pslic.byte = 0; + j->pslic.bits.powerdown = 1; + j->psccr.bits.dev = 3; + j->psccr.bits.rw = 0; + outw_p(j->psccr.byte << 8 | j->pslic.byte, j->XILINXbase + 0x00); + ixj_PCcontrol_wait(board); + } + } + return 0; + } else { + j->flags.pcmciascp = 0; + return 0; + } + return 0; +} + static int ixj_hookstate(int board) { unsigned long det; @@ -885,15 +1242,12 @@ case 500: SLIC_GetState(board); if (j->pld_slicr.bits.state == PLD_SLIC_STATE_ACTIVE || - j->pld_slicr.bits.state == PLD_SLIC_STATE_STANDBY) - { - if (j->flags.ringing) - { - if(!in_interrupt()) - { + j->pld_slicr.bits.state == PLD_SLIC_STATE_STANDBY) { + if (j->flags.ringing) { + if (!in_interrupt()) { det = jiffies + (hertz / 50); while (time_before(jiffies, det)) { - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); } } @@ -909,13 +1263,17 @@ fOffHook = j->pld_slicr.bits.det ? 1 : 0; } break; + case 600: + fOffHook = ixj_pcmcia_cable_check(board); + break; } if (j->r_hook != fOffHook) { j->r_hook = fOffHook; if (j->port != PORT_POTS) { j->ex.bits.hookstate = 1; - kill_fasync(&j->async_queue, SIGIO, POLL_IN); // Send apps notice of change - + ixj_kill_fasync(board, POLL_IN); + } else if (!fOffHook) { + j->flash_end = jiffies + (hertz / 10 * 6); } } if (j->port == PORT_PSTN && j->daa_mode == SOP_PU_CONVERSATION) @@ -927,7 +1285,10 @@ if (j->port == PORT_HANDSET) fOffHook |= 2; - return fOffHook; + if (fOffHook && time_before(jiffies, j->flash_end)) + return 0; + else + return fOffHook; } static void ixj_ring_off(board) @@ -949,7 +1310,7 @@ if (ixjdebug > 0) printk(KERN_INFO "IXJ Ring Off\n"); - SLIC_SetState(PLD_SLIC_STATE_STANDBY, board); + SLIC_SetState(PLD_SLIC_STATE_STANDBY, board); SLIC_GetState(board); } @@ -997,9 +1358,9 @@ j->flags.ringing = 0; return 1; } - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); - if(signal_pending(current)) + if (signal_pending(current)) break; } jif = jiffies + (3 * hertz); @@ -1008,9 +1369,9 @@ if (ixj_hookstate(board) & 1) { det = jiffies + (hertz / 100); while (time_before(jiffies, det)) { - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); - if(signal_pending(current)) + if (signal_pending(current)) break; } if (ixj_hookstate(board) & 1) { @@ -1018,9 +1379,9 @@ return 1; } } - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); - if(signal_pending(current)) + if (signal_pending(current)) break; } } @@ -1031,39 +1392,70 @@ int ixj_open(struct phone_device *p, struct file *file_p) { - IXJ *j = &ixj[p->board]; + IXJ *j = file_p->private_data = &ixj[p->board]; if (!j->DSPbase) return -ENODEV; - if (file_p->f_mode & FMODE_READ) - j->readers++; - if (file_p->f_mode & FMODE_WRITE) - j->writers++; + if (file_p->f_mode & FMODE_READ) { + if(!j->readers) { + j->readers++; + } else { + return -EBUSY; + } + } + + if (file_p->f_mode & FMODE_WRITE) { + if(!j->writers) { + j->writers++; + } else { + if (file_p->f_mode & FMODE_READ){ + j->readers--; + } + return -EBUSY; + } + } + + if (j->cardtype == 600) { + j->pslic.bits.powerdown = 0; + j->psccr.bits.dev = 3; + j->psccr.bits.rw = 0; + outw_p(j->psccr.byte << 8 | j->pslic.byte, j->XILINXbase + 0x00); + ixj_PCcontrol_wait(p->board); + } + MOD_INC_USE_COUNT; if (ixjdebug > 0) -// printk(KERN_INFO "Opening board %d\n", NUM(inode->i_rdev)); printk(KERN_INFO "Opening board %d\n", p->board); + j->framesread = j->frameswritten = 0; return 0; } int ixj_release(struct inode *inode, struct file *file_p) { IXJ_TONE ti; - int board = NUM(inode->i_rdev); - IXJ *j = &ixj[board]; +// int board = NUM(inode->i_rdev); + IXJ *j = file_p->private_data; + int board = j->p.board; +// IXJ *j = &ixj[board]; if (ixjdebug > 0) printk(KERN_INFO "Closing board %d\n", NUM(inode->i_rdev)); - lock_kernel(); daa_set_mode(board, SOP_PU_SLEEP); - ixj_set_port(board, PORT_POTS); + if (j->cardtype == 600) + ixj_set_port(board, PORT_SPEAKER); + else + ixj_set_port(board, PORT_POTS); aec_stop(board); ixj_play_stop(board); ixj_record_stop(board); + set_play_volume(board, 0x100); + set_rec_volume(board, 0x100); + ixj_ring_off(board); + // Restore the tone table to default settings. ti.tone_index = 10; ti.gain0 = 1; ti.freq0 = hz941; @@ -1172,6 +1564,10 @@ idle(board); +// if(j->cardtype == 600) { // && j->flags.pcmciasct == 1 && j->readers == 1 && j->writers == 1) { + SLIC_SetState(PLD_SLIC_STATE_OC, board); +// } + if (file_p->f_mode & FMODE_READ) j->readers--; if (file_p->f_mode & FMODE_WRITE) @@ -1189,15 +1585,24 @@ } j->rec_codec = j->play_codec = 0; j->rec_frame_size = j->play_frame_size = 0; + j->flags.cidsent = j->flags.cidring = 0; ixj_fasync(-1, file_p, 0); // remove from list of async notification - unlock_kernel(); + if(j->cardtype == 300 && !j->readers && !j->writers) { + ixj_set_port(board, PORT_PSTN); + ixj_set_pots(board, 1); + } + ixj_WriteDSPCommand(0x0FE3, board); // Put the DSP in 1/5 power mode. + + file_p->private_data = NULL; + MOD_DEC_USE_COUNT; return 0; } static int read_filters(int board) { unsigned short fc, cnt; + int var; IXJ *j = &ixj[board]; if (ixj_WriteDSPCommand(0x5144, board)) @@ -1209,6 +1614,11 @@ j->frame_count = fc; + if (j->dtmf_proc) + return 1; + + var = 10; + for (cnt = 0; cnt < 4; cnt++) { if (ixj_WriteDSPCommand(0x5154 + cnt, board)) return -1; @@ -1217,8 +1627,108 @@ return -1; j->filter_hist[cnt] = j->ssr.high << 8 | j->ssr.low; - if ((j->filter_hist[cnt] & 1 && !(j->filter_hist[cnt] & 2)) || - (j->filter_hist[cnt] & 2 && !(j->filter_hist[cnt] & 1))) { + + if (j->cadence_f[cnt].enable) { + if (j->filter_hist[cnt] & 3 && !(j->filter_hist[cnt] & 12)) { + if (j->cadence_f[cnt].state == 0) { + j->cadence_f[cnt].state = 1; + j->cadence_f[cnt].on1min = jiffies + (j->cadence_f[cnt].on1 * hertz * (100 - var) / 10000); + j->cadence_f[cnt].on1dot = jiffies + (j->cadence_f[cnt].on1 * hertz * (100) / 10000); + j->cadence_f[cnt].on1max = jiffies + (j->cadence_f[cnt].on1 * hertz * (100 + var) / 10000); + } else if (j->cadence_f[cnt].state == 2 && + (time_after(jiffies, j->cadence_f[cnt].off1min) && + time_before(jiffies, j->cadence_f[cnt].off1max))) { + if (j->cadence_f[cnt].on2) { + j->cadence_f[cnt].state = 3; + j->cadence_f[cnt].on2min = jiffies + (j->cadence_f[cnt].on2 * hertz * (100 - var) / 10000); + j->cadence_f[cnt].on2dot = jiffies + (j->cadence_f[cnt].on2 * hertz * (100) / 10000); + j->cadence_f[cnt].on2max = jiffies + (j->cadence_f[cnt].on2 * hertz * (100 + var) / 10000); + } else { + j->cadence_f[cnt].state = 6; + } + } else if (j->cadence_f[cnt].state == 4 && + (time_after(jiffies, j->cadence_f[cnt].off2min) && + time_before(jiffies, j->cadence_f[cnt].off2max))) { + if (j->cadence_f[cnt].on2) { + j->cadence_f[cnt].state = 5; + j->cadence_f[cnt].on3min = jiffies + (j->cadence_f[cnt].on3 * hertz * (100 - var) / 10000); + j->cadence_f[cnt].on3dot = jiffies + (j->cadence_f[cnt].on3 * hertz * (100) / 10000); + j->cadence_f[cnt].on3max = jiffies + (j->cadence_f[cnt].on3 * hertz * (100 + var) / 10000); + } else { + j->cadence_f[cnt].state = 6; + } + } else { + j->cadence_f[cnt].state = 0; + } + } else if (j->filter_hist[cnt] & 12 && !(j->filter_hist[cnt] & 3)) { + if (j->cadence_f[cnt].state == 1 && + (time_after(jiffies, j->cadence_f[cnt].on1min) && + time_before(jiffies, j->cadence_f[cnt].on1max))) { + j->cadence_f[cnt].state = 2; + j->cadence_f[cnt].off1min = jiffies + (j->cadence_f[cnt].off1 * hertz * (100 - var) / 10000); + j->cadence_f[cnt].off1max = jiffies + (j->cadence_f[cnt].off1 * hertz * (100 + var) / 10000); + } else if (j->cadence_f[cnt].state == 3 && + (time_after(jiffies, j->cadence_f[cnt].on2min) && + time_before(jiffies, j->cadence_f[cnt].on2max))) { + j->cadence_f[cnt].state = 4; + j->cadence_f[cnt].off2min = jiffies + (j->cadence_f[cnt].off2 * hertz * (100 - var) / 10000); + j->cadence_f[cnt].off2max = jiffies + (j->cadence_f[cnt].off2 * hertz * (100 + var) / 10000); + } else if (j->cadence_f[cnt].state == 5 && + (time_after(jiffies, j->cadence_f[cnt].on3min) && + time_before(jiffies, j->cadence_f[cnt].on3max))) { + j->cadence_f[cnt].state = 6; + j->cadence_f[cnt].off3min = jiffies + (j->cadence_f[cnt].off3 * hertz * (100 - var) / 10000); + j->cadence_f[cnt].off3max = jiffies + (j->cadence_f[cnt].off3 * hertz * (100 + var) / 10000); + } else { + j->cadence_f[cnt].state = 0; + } + } else { + switch(j->cadence_f[cnt].state) { + case 1: + if(time_after(jiffies, j->cadence_f[cnt].on1dot) && + !j->cadence_f[cnt].off1 && + !j->cadence_f[cnt].on2 && !j->cadence_f[cnt].off2 && + !j->cadence_f[cnt].on3 && !j->cadence_f[cnt].off3) { + j->cadence_f[cnt].state = 6; + } + break; + case 3: + if(time_after(jiffies, j->cadence_f[cnt].on2dot) && + !j->cadence_f[cnt].off2 && + !j->cadence_f[cnt].on3 && !j->cadence_f[cnt].off3) { + j->cadence_f[cnt].state = 6; + } + break; + case 5: + if(time_after(jiffies, j->cadence_f[cnt].on3dot) && + !j->cadence_f[cnt].off3) { + j->cadence_f[cnt].state = 6; + } + break; + } + } + } + if (j->cadence_f[cnt].state == 6) { + j->cadence_f[cnt].state = 0; + if (j->cadence_f[cnt].enable == 1) + j->cadence_f[cnt].enable = 0; + switch (cnt) { + case 0: + j->ex.bits.fc0 = 1; + break; + case 1: + j->ex.bits.fc1 = 1; + break; + case 2: + j->ex.bits.fc2 = 1; + break; + case 3: + j->ex.bits.fc3 = 1; + break; + } + } + if (j->filter_en[cnt] && ((j->filter_hist[cnt] & 3 && !(j->filter_hist[cnt] & 12)) || + (j->filter_hist[cnt] & 12 && !(j->filter_hist[cnt] & 3)))) { switch (cnt) { case 0: j->ex.bits.f0 = 1; @@ -1259,11 +1769,16 @@ } if (j->dtmf_state && !j->dtmf.bits.dtmf_valid) // && j->dtmf_wp != j->dtmf_rp) { - j->dtmfbuffer[j->dtmf_wp] = j->dtmf_current; - j->dtmf_wp++; - if (j->dtmf_wp == 79) - j->dtmf_wp = 0; - j->ex.bits.dtmf_ready = 1; + if(!j->flags.cidplay) { + j->dtmfbuffer[j->dtmf_wp] = j->dtmf_current; + j->dtmf_wp++; + if (j->dtmf_wp == 79) + j->dtmf_wp = 0; + j->ex.bits.dtmf_ready = 1; + } + else if(j->dtmf_current == 25 || j->dtmf_current == 31) { + j->flags.cidcw_ack = 1; + } j->dtmf_state = 0; } j->dtmf_proc = 0; @@ -1277,39 +1792,54 @@ IXJ *j = &ixj[NUM(file_p->f_dentry->d_inode->i_rdev)]; DECLARE_WAITQUEUE(wait, current); + if (j->flags.inread) + return -EALREADY; + + j->flags.inread = 1; + add_wait_queue(&j->read_q, &wait); - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); mb(); while (!j->read_buffer_ready || (j->dtmf_state && j->flags.dtmf_oob)) { ++j->read_wait; + if(j->tone_state) { + j->flags.inread = 0; + return -EAGAIN; + } if (file_p->f_flags & O_NONBLOCK) { - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); remove_wait_queue(&j->read_q, &wait); + j->flags.inread = 0; return -EAGAIN; } if (!ixj_hookstate(NUM(file_p->f_dentry->d_inode->i_rdev))) { - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); remove_wait_queue(&j->read_q, &wait); + j->flags.inread = 0; return 0; } interruptible_sleep_on(&j->read_q); if (signal_pending(current)) { - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); remove_wait_queue(&j->read_q, &wait); + j->flags.inread = 0; return -EINTR; } } remove_wait_queue(&j->read_q, &wait); - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); /* Don't ever copy more than the user asks */ i = copy_to_user(buf, j->read_buffer, min(length, j->read_buffer_size)); j->read_buffer_ready = 0; - if (i) + if (i) { + j->flags.inread = 0; return -EFAULT; - else + } else { + j->flags.inread = 0; return min(length, j->read_buffer_size); + } } ssize_t ixj_enhanced_read(struct file * file_p, char *buf, size_t length, @@ -1337,50 +1867,62 @@ return read_retval; } -ssize_t ixj_write(struct file * file_p, const char *buf, size_t count, loff_t * ppos) +ssize_t ixj_write(struct file *file_p, const char *buf, size_t count, loff_t * ppos) { unsigned long i = *ppos; - int board = NUM(file_p->f_dentry->d_inode->i_rdev); - IXJ *j = &ixj[board]; + IXJ *j = file_p->private_data; DECLARE_WAITQUEUE(wait, current); - add_wait_queue(&j->read_q, &wait); - current->state = TASK_INTERRUPTIBLE; + if (j->flags.inwrite) + return -EALREADY; + + j->flags.inwrite = 1; + + add_wait_queue(&j->write_q, &wait); + set_current_state(TASK_INTERRUPTIBLE); mb(); while (!j->write_buffers_empty) { ++j->write_wait; + if(j->tone_state) { + j->flags.inwrite = 0; + return -EAGAIN; + } if (file_p->f_flags & O_NONBLOCK) { - current->state = TASK_RUNNING; - remove_wait_queue(&j->read_q, &wait); + set_current_state(TASK_RUNNING); + remove_wait_queue(&j->write_q, &wait); + j->flags.inwrite = 0; return -EAGAIN; } if (!ixj_hookstate(NUM(file_p->f_dentry->d_inode->i_rdev))) { - current->state = TASK_RUNNING; - remove_wait_queue(&j->read_q, &wait); + set_current_state(TASK_RUNNING); + remove_wait_queue(&j->write_q, &wait); + j->flags.inwrite = 0; return 0; } interruptible_sleep_on(&j->write_q); if (signal_pending(current)) { - current->state = TASK_RUNNING; - remove_wait_queue(&j->read_q, &wait); + set_current_state(TASK_RUNNING); + remove_wait_queue(&j->write_q, &wait); + j->flags.inwrite = 0; return -EINTR; } } - current->state = TASK_RUNNING; - remove_wait_queue(&j->read_q, &wait); + set_current_state(TASK_RUNNING); + remove_wait_queue(&j->write_q, &wait); if (j->write_buffer_wp + count >= j->write_buffer_end) j->write_buffer_wp = j->write_buffer; i = copy_from_user(j->write_buffer_wp, buf, min(count, j->write_buffer_size)); - if (i) + if (i) { + j->flags.inwrite = 0; return -EFAULT; - + } + j->flags.inwrite = 0; return min(count, j->write_buffer_size); } -ssize_t ixj_enhanced_write(struct file * file_p, const char *buf, size_t count, - loff_t * ppos) +ssize_t ixj_enhanced_write(struct file * file_p, const char *buf, size_t count, loff_t * ppos) { int pre_retval; ssize_t write_retval = 0; @@ -1437,9 +1979,7 @@ *(j->read_buffer + cnt) = inb_p(j->DSPbase + 0x0E); *(j->read_buffer + cnt + 1) = inb_p(j->DSPbase + 0x0F); } -#ifdef PERFMON_STATS ++j->framesread; -#endif if (j->intercom != -1) { if (IsTxReady(j->intercom)) { for (cnt = 0; cnt < j->rec_frame_size * 2; cnt += 2) { @@ -1456,9 +1996,7 @@ outb_p(*(j->read_buffer + cnt), ixj[j->intercom].DSPbase + 0x0C); outb_p(*(j->read_buffer + cnt + 1), ixj[j->intercom].DSPbase + 0x0D); } -#ifdef PERFMON_STATS ++ixj[j->intercom].frameswritten; -#endif } } else { j->read_buffer_ready = 1; @@ -1466,12 +2004,472 @@ wake_up_interruptible(&j->poll_q); // Wake any blocked selects - kill_fasync(&j->async_queue, SIGIO, POLL_IN); // Send apps notice of frame + ixj_kill_fasync(board, POLL_OUT); + } + } +} + +static short fsk[][6][20] = +{ + { + { + 0, 17846, 29934, 32364, 24351, 8481, -10126, -25465, -32587, -29196, + -16384, 1715, 19260, 30591, 32051, 23170, 6813, -11743, -26509, -32722 + }, + { + -28377, -14876, 3425, 20621, 31163, 31650, 21925, 5126, -13328, -27481, + -32767, -27481, -13328, 5126, 21925, 31650, 31163, 20621, 3425, -14876 + }, + { + -28377, -32722, -26509, -11743, 6813, 23170, 32051, 30591, 19260, 1715, + -16384, -29196, -32587, -25465, -10126, 8481, 24351, 32364, 29934, 17846 + }, + { + 0, -17846, -29934, -32364, -24351, -8481, 10126, 25465, 32587, 29196, + 16384, -1715, -19260, -30591, -32051, -23170, -6813, 11743, 26509, 32722 + }, + { + 28377, 14876, -3425, -20621, -31163, -31650, -21925, -5126, 13328, 27481, + 32767, 27481, 13328, -5126, -21925, -31650, -31163, -20621, -3425, 14876 + }, + { + 28377, 32722, 26509, 11743, -6813, -23170, -32051, -30591, -19260, -1715, + 16384, 29196, 32587, 25465, 10126, -8481, -24351, -32364, -29934, -17846 + } + }, + { + { + 0, 10126, 19260, 26509, 31163, 32767, 31163, 26509, 19260, 10126, + 0, -10126, -19260, -26509, -31163, -32767, -31163, -26509, -19260, -10126 + }, + { + -28377, -21925, -13328, -3425, 6813, 16384, 24351, 29934, 32587, 32051, + 28377, 21925, 13328, 3425, -6813, -16384, -24351, -29934, -32587, -32051 + }, + { + -28377, -32051, -32587, -29934, -24351, -16384, -6813, 3425, 13328, 21925, + 28377, 32051, 32587, 29934, 24351, 16384, 6813, -3425, -13328, -21925 + }, + { + 0, -10126, -19260, -26509, -31163, -32767, -31163, -26509, -19260, -10126, + 0, 10126, 19260, 26509, 31163, 32767, 31163, 26509, 19260, 10126 + }, + { + 28377, 21925, 13328, 3425, -6813, -16383, -24351, -29934, -32587, -32051, + -28377, -21925, -13328, -3425, 6813, 16383, 24351, 29934, 32587, 32051 + }, + { + 28377, 32051, 32587, 29934, 24351, 16384, 6813, -3425, -13328, -21925, + -28377, -32051, -32587, -29934, -24351, -16384, -6813, 3425, 13328, 21925 + } + } +}; + + +static void ixj_write_cid_bit(int board, int bit) +{ + int dly; + IXJ_WORD dat; + IXJ *j = &ixj[board]; + + while (j->fskcnt < 20) { + if (!IsTxReady(board)) { + dly = 0; + while (!IsTxReady(board)) { + if (dly++ > 5) { + dly = 0; + // break; + // printk("CID delay\n"); + } + udelay(10); + } + } + dat.word = j->fskdata[j->fskdcnt++] = + fsk[bit][j->fskz][j->fskcnt]; + outb_p(dat.bytes.low, j->DSPbase + 0x0C); + outb_p(dat.bytes.high, j->DSPbase + 0x0D); + j->fskcnt += 3; + } + j->fskcnt %= 20; + + if (!bit) + j->fskz++; + if (j->fskz >= 6) + j->fskz = 0; + +} + +static void ixj_write_cid_byte(int board, char byte) +{ + IXJ_CBYTE cb; + +// printk("Writing CID data %x - %c\n", byte, byte); + cb.cbyte = byte; + ixj_write_cid_bit(board, 0); + ixj_write_cid_bit(board, cb.cbits.b0 ? 1 : 0); + ixj_write_cid_bit(board, cb.cbits.b1 ? 1 : 0); + ixj_write_cid_bit(board, cb.cbits.b2 ? 1 : 0); + ixj_write_cid_bit(board, cb.cbits.b3 ? 1 : 0); + ixj_write_cid_bit(board, cb.cbits.b4 ? 1 : 0); + ixj_write_cid_bit(board, cb.cbits.b5 ? 1 : 0); + ixj_write_cid_bit(board, cb.cbits.b6 ? 1 : 0); + ixj_write_cid_bit(board, cb.cbits.b7 ? 1 : 0); + ixj_write_cid_bit(board, 1); +} + +static void ixj_write_cid_seize(int board) +{ + int cnt; + + for (cnt = 0; cnt < 150; cnt++) { + ixj_write_cid_bit(board, 0); + ixj_write_cid_bit(board, 1); + } + for (cnt = 0; cnt < 180; cnt++) { + ixj_write_cid_bit(board, 1); + } +} + +static void ixj_write_cidcw_seize(int board) +{ + int cnt; + + for (cnt = 0; cnt < 80; cnt++) { + ixj_write_cid_bit(board, 1); + } +} + +static int ixj_write_cid_string(int board, char *s, int checksum) +{ + int cnt; + + for (cnt = 0; cnt < strlen(s); cnt++) { + ixj_write_cid_byte(board, s[cnt]); + checksum = (checksum + s[cnt]); + } + return checksum; +} +static void ixj_pad_fsk(int board, int pad) +{ + int cnt, dly; + IXJ *j = &ixj[board]; + + for (cnt = 0; cnt < pad; cnt++) { + if (!IsTxReady(board)) { + dly = 0; + while (!IsTxReady(board)) { + if (dly++ > 5) { + dly = 0; + } + udelay(10); + } + } + outb_p(0x00, j->DSPbase + 0x0C); + outb_p(0x00, j->DSPbase + 0x0D); + } + for (cnt = 0; cnt < 720; cnt++) { + if (!IsTxReady(board)) { + dly = 0; + while (!IsTxReady(board)) { + if (dly++ > 5) { + dly = 0; + } + udelay(10); + } } + outb_p(0x00, j->DSPbase + 0x0C); + outb_p(0x00, j->DSPbase + 0x0D); } } +static void ixj_write_cid(int board) +{ + IXJ *j = &ixj[board]; + + char sdmf1[50]; + char sdmf2[50]; + char sdmf3[80]; + char mdmflen, len1, len2, len3; + int pad; + + int checksum = 0; + + if (ixj[board].dsp.low == 0x20) + return; + + ixj[board].fskz = ixj[board].fskphase = ixj[board].fskcnt = + ixj[board].fskdcnt = 0; + + ixj[board].flags.cidplay = 1; + + strcpy(sdmf1, j->cid_send.month); + strcat(sdmf1, j->cid_send.day); + strcat(sdmf1, j->cid_send.hour); + strcat(sdmf1, j->cid_send.min); + strcpy(sdmf2, j->cid_send.number); + strcpy(sdmf3, j->cid_send.name); + + len1 = strlen(sdmf1); + len2 = strlen(sdmf2); + len3 = strlen(sdmf3); + mdmflen = len1 + len2 + len3 + 6; + + printk("CID Lengths = %d %d %d %d\n", len1, len2, len3, mdmflen); + + set_base_frame(board, 30); + set_play_codec(board, LINEAR16); + + if (ixj[board].port == PORT_POTS) + if(!j->r_hook) + SLIC_SetState(PLD_SLIC_STATE_OHT, board); + + set_play_volume(board, 0x1B); + ixj_play_start(board); + ixj_write_cid_seize(board); + + ixj_write_cid_byte(board, 0x80); + checksum = 0x80; + ixj_write_cid_byte(board, mdmflen); + checksum = checksum + mdmflen; + + ixj_write_cid_byte(board, 0x01); + checksum = checksum + 0x01; + ixj_write_cid_byte(board, len1); + checksum = checksum + len1; + checksum = ixj_write_cid_string(board, sdmf1, checksum); + + ixj_write_cid_byte(board, 0x02); + checksum = checksum + 0x02; + ixj_write_cid_byte(board, len2); + checksum = checksum + len2; + checksum = ixj_write_cid_string(board, sdmf2, checksum); + + ixj_write_cid_byte(board, 0x07); + checksum = checksum + 0x07; + ixj_write_cid_byte(board, len3); + checksum = checksum + len3; + checksum = ixj_write_cid_string(board, sdmf3, checksum); + + checksum %= 256; + checksum ^= 0xFF; + checksum += 1; + printk("14Checksum = %d\n", checksum); + + ixj_write_cid_byte(board, (char) checksum); + + pad = j->fskdcnt % 240; + if (pad) { + pad = 240 - pad; + } + ixj_pad_fsk(board, pad); + SLIC_SetState(PLD_SLIC_STATE_STANDBY, board); + ixj[board].flags.cidplay = 0; + ixj_play_stop(board); +} + +static void ixj_write_cidcw(int board) +{ + IXJ_TONE ti; + + IXJ *j = &ixj[board]; + + char sdmf1[50]; + char sdmf2[50]; + char sdmf3[80]; + char mdmflen, len1, len2, len3; + int pad; + + int checksum = 0; + + if (ixj[board].dsp.low == 0x20) + return; + + ixj[board].fskz = ixj[board].fskphase = ixj[board].fskcnt = ixj[board].fskdcnt = 0; + + ixj[board].flags.cidplay = 1; + + ti.tone_index = 23; + ti.gain0 = 1; + ti.freq0 = hz440; + ti.gain1 = 0; + ti.freq1 = 0; + ixj_init_tone(board, &ti); + + ti.tone_index = 24; + ti.gain0 = 1; + ti.freq0 = hz2130; + ti.gain1 = 0; + ti.freq1 = hz2750; + ixj_init_tone(board, &ti); + + ixj_set_tone_on(1200, board); + ixj_play_tone(board, 23); + + while(j->tone_state) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(1); + } + + ixj_set_tone_on(320, board); + ixj_play_tone(board, 24); + + while(j->tone_state) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(1); + } + + j->cidcw_wait = jiffies + (200 * hertz / 100000); + + while(!j->flags.cidcw_ack && time_before(jiffies, j->cidcw_wait)) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(1); + } + + if(!j->flags.cidcw_ack) { + return; + } + + strcpy(sdmf1, j->cid_send.month); + strcat(sdmf1, j->cid_send.day); + strcat(sdmf1, j->cid_send.hour); + strcat(sdmf1, j->cid_send.min); + strcpy(sdmf2, j->cid_send.number); + strcpy(sdmf3, j->cid_send.name); + + len1 = strlen(sdmf1); + len2 = strlen(sdmf2); + len3 = strlen(sdmf3); + mdmflen = len1 + len2 + len3 + 6; + + printk("CID Lengths = %d %d %d %d\n", len1, len2, len3, mdmflen); + + j->cid_play_codec = j->play_codec; + ixj_play_stop(board); + + switch(j->baseframe.low) { + case 0xA0: + j->cid_base_frame_size = 20; + break; + case 0x50: + j->cid_base_frame_size = 10; + break; + default: + j->cid_base_frame_size = 30; + break; + } + set_base_frame(board, 30); + set_play_codec(board, LINEAR16); + + set_play_volume(board, 0x1B); + ixj_play_start(board); + ixj_write_cidcw_seize(board); + + ixj_write_cid_byte(board, 0x80); + checksum = 0x80; + ixj_write_cid_byte(board, mdmflen); + checksum = checksum + mdmflen; + + ixj_write_cid_byte(board, 0x01); + checksum = checksum + 0x01; + ixj_write_cid_byte(board, len1); + checksum = checksum + len1; + checksum = ixj_write_cid_string(board, sdmf1, checksum); + + ixj_write_cid_byte(board, 0x02); + checksum = checksum + 0x02; + ixj_write_cid_byte(board, len2); + checksum = checksum + len2; + checksum = ixj_write_cid_string(board, sdmf2, checksum); + + ixj_write_cid_byte(board, 0x07); + checksum = checksum + 0x07; + ixj_write_cid_byte(board, len3); + checksum = checksum + len3; + checksum = ixj_write_cid_string(board, sdmf3, checksum); + + checksum %= 256; + checksum ^= 0xFF; + checksum += 1; + printk("14Checksum = %d\n", checksum); + + ixj_write_cid_byte(board, (char) checksum); + + pad = j->fskdcnt % 240; + if (pad) { + pad = 240 - pad; + } + ixj_pad_fsk(board, pad); + ixj[board].flags.cidplay = 0; + ixj_play_stop(board); + + set_base_frame(board, j->cid_base_frame_size); + set_play_codec(board, j->cid_play_codec); +} + +static void ixj_write_vmwi(int board, int msg) +{ + IXJ *j = &ixj[board]; + + char mdmflen; + int pad; + + int checksum = 0; + + if (ixj[board].dsp.low == 0x20) + return; + + ixj[board].fskz = ixj[board].fskphase = ixj[board].fskcnt = ixj[board].fskdcnt = 0; + + ixj[board].flags.cidplay = 1; + + mdmflen = 3; + + set_base_frame(board, 30); + set_play_codec(board, LINEAR16); + + if (ixj[board].port == PORT_POTS) + SLIC_SetState(PLD_SLIC_STATE_OHT, board); + + set_play_volume(board, 0x1B); + ixj_play_start(board); + ixj_write_cid_seize(board); + + ixj_write_cid_byte(board, 0x82); + checksum = 0x82; + ixj_write_cid_byte(board, mdmflen); + checksum = checksum + mdmflen; + + ixj_write_cid_byte(board, 0x0B); + checksum = checksum + 0x0B; + ixj_write_cid_byte(board, 1); + checksum = checksum + 1; + + if(msg) { + ixj_write_cid_byte(board, 0xFF); + checksum = checksum + 0xFF; + } + else { + ixj_write_cid_byte(board, 0x00); + checksum = checksum + 0x00; + } + + checksum %= 256; + checksum ^= 0xFF; + checksum += 1; + + ixj_write_cid_byte(board, (char) checksum); + + pad = j->fskdcnt % 240; + if (pad) { + pad = 240 - pad; + } + ixj_pad_fsk(board, pad); + SLIC_SetState(PLD_SLIC_STATE_STANDBY, board); + ixj[board].flags.cidplay = 0; + ixj_play_stop(board); +} + static void ixj_write_frame(int board) { int cnt, frame_count, dly; @@ -1547,14 +2545,12 @@ j->write_buffer_rp = j->write_buffer; } j->write_buffers_empty++; - wake_up_interruptible(&(j->write_q)); // Wake any blocked writers + wake_up_interruptible(&j->write_q); // Wake any blocked writers wake_up_interruptible(&j->poll_q); // Wake any blocked selects - kill_fasync(&j->async_queue, SIGIO, POLL_IN); // Send apps notice of empty buffer -#ifdef PERFMON_STATS + ixj_kill_fasync(board, POLL_OUT); ++j->frameswritten; -#endif } } else { j->drybuffer++; @@ -1787,6 +2783,12 @@ unsigned short cmd = 0x0000; IXJ *j = &ixj[board]; + if (j->read_buffer) { + ixj_record_stop(board); + } + j->flags.recording = 1; + ixj_WriteDSPCommand(0x0FE0, board); // Put the DSP in full power mode. + if (!j->rec_mode) { switch (j->rec_codec) { case G723_63: @@ -1885,10 +2887,26 @@ { IXJ *j = &ixj[board]; + if (j->read_buffer) { + kfree(j->read_buffer); + j->read_buffer = NULL; + j->read_buffer_size = 0; + } if (j->rec_mode > -1) { ixj_WriteDSPCommand(0x5120, board); j->rec_mode = -1; } + j->flags.recording = 0; + if (!j->flags.playing) + ixj_WriteDSPCommand(0x0FE3, board); // Put the DSP in 1/5 power mode. + +} +static void ixj_vad(int board, int arg) +{ + if (arg) + ixj_WriteDSPCommand(0x513F, board); + else + ixj_WriteDSPCommand(0x513E, board); } static void set_rec_depth(int board, int depth) @@ -1906,13 +2924,23 @@ ixj_WriteDSPCommand(volume, board); } +static int get_rec_volume(int board) +{ + ixj_WriteDSPCommand(0xCF03, board); + return ixj[board].ssr.high << 8 | ixj[board].ssr.low; +} + static int get_rec_level(int board) { + int retval; + IXJ *j = &ixj[board]; ixj_WriteDSPCommand(0xCF88, board); - return j->ssr.high << 8 | j->ssr.low; + retval = j->ssr.high << 8 | j->ssr.low; + retval = (retval * 256) / 240; + return retval; } static void ixj_aec_start(int board, int level) @@ -1921,7 +2949,7 @@ j->aec_level = level; if (!level) { - ixj_WriteDSPCommand(0xB002, board); + aec_stop(board); } else { if (j->rec_codec == G729 || j->play_codec == G729) { ixj_WriteDSPCommand(0xE022, board); // Move AEC filter buffer @@ -1933,26 +2961,41 @@ ixj_WriteDSPCommand(0xE013, board); // Advanced AEC C1 switch (level) { - case 1: + case AEC_LOW: ixj_WriteDSPCommand(0x0000, board); // Advanced AEC C2 = off ixj_WriteDSPCommand(0xE011, board); ixj_WriteDSPCommand(0xFFFF, board); break; - case 2: + case AEC_MED: ixj_WriteDSPCommand(0x0600, board); // Advanced AEC C2 = on medium ixj_WriteDSPCommand(0xE011, board); ixj_WriteDSPCommand(0x0080, board); break; - case 3: + case AEC_HIGH: ixj_WriteDSPCommand(0x0C00, board); // Advanced AEC C2 = on high ixj_WriteDSPCommand(0xE011, board); ixj_WriteDSPCommand(0x0080, board); break; + + case AEC_AUTO: + ixj_WriteDSPCommand(0x0002, board); // Attenuation scaling factor of 2 + + ixj_WriteDSPCommand(0xE011, board); + ixj_WriteDSPCommand(0x0100, board); // Higher Threshold Floor + + ixj_WriteDSPCommand(0xE012, board); // Set Train and Lock + + ixj_WriteDSPCommand(0x0023, board); + + ixj_WriteDSPCommand(0xE014, board); + ixj_WriteDSPCommand(0x0003, board); // Lock threashold at 3dB + + break; } } } @@ -2140,6 +3183,12 @@ unsigned short cmd = 0x0000; IXJ *j = &ixj[board]; + if (j->write_buffer) { + ixj_play_stop(board); + } + j->flags.playing = 1; + ixj_WriteDSPCommand(0x0FE0, board); // Put the DSP in full power mode. + j->flags.play_first_frame = 1; j->drybuffer = 0; @@ -2175,12 +3224,10 @@ if (ixj_WriteDSPCommand(cmd, board)) return -1; } + j->write_buffer = kmalloc(j->play_frame_size * 2, GFP_ATOMIC); if (!j->write_buffer) { - j->write_buffer = kmalloc(j->play_frame_size * 2, GFP_ATOMIC); - if (!j->write_buffer) { - printk("Write buffer allocation for ixj board %d failed!\n", board); - return -ENOMEM; - } + printk("Write buffer allocation for ixj board %d failed!\n", board); + return -ENOMEM; } j->write_buffers_empty = 2; j->write_buffer_size = j->play_frame_size * 2; @@ -2242,11 +3289,20 @@ { IXJ *j = &ixj[board]; + if (j->write_buffer) { + kfree(j->write_buffer); + j->write_buffer = NULL; + j->write_buffer_size = 0; + } if (j->play_mode > -1) { - ixj_WriteDSPCommand(0x5221, board); // Stop playback + ixj_WriteDSPCommand(0x5221, board); // Stop playback and flush buffers. 8022 reference page 9-40 j->play_mode = -1; } + j->flags.playing = 0; + if (!j->flags.recording) + ixj_WriteDSPCommand(0x0FE3, board); // Put the DSP in 1/5 power mode. + } extern __inline__ void set_play_depth(int board, int depth) @@ -2258,16 +3314,15 @@ ixj_WriteDSPCommand(0x5280 + depth, board); } -extern __inline__ void set_play_volume(int board, int volume) -{ - ixj_WriteDSPCommand(0xCF02, board); - ixj_WriteDSPCommand(volume, board); -} - extern __inline__ int get_play_level(int board) { - ixj_WriteDSPCommand(0xCF8F, board); + int retval; + + ixj_WriteDSPCommand(0xCF8F, board); // 8022 Reference page 9-38 return ixj[board].ssr.high << 8 | ixj[board].ssr.low; + retval = ixj[board].ssr.high << 8 | ixj[board].ssr.low; + retval = (retval * 256) / 240; + return retval; } static unsigned int ixj_poll(struct file *file_p, poll_table * wait) @@ -2476,6 +3531,8 @@ break; } + j->m_DAAShadowRegs.SOP_REGS.SOP.cr4.reg = reg; + switch (j->m_DAAShadowRegs.SOP_REGS.SOP.cr4.bitreg.AGX) { case 0: j->m_DAAShadowRegs.SOP_REGS.SOP.cr4.bitreg.AGR_Z = 0; @@ -2645,7 +3702,7 @@ } pIn += 5, pOut += 4; } - memset(&j->cid, 0, sizeof(IXJ_CID)); + memset(&j->cid, 0, sizeof(PHONE_CID)); pOut = j->m_DAAShadowRegs.CAO_REGS.CAO.CallerID; pOut += 4; strncpy(j->cid.month, pOut, 2); @@ -2721,7 +3778,6 @@ // ALIS-A part. // - BYTES bytes; IXJ *j = &ixj[board]; @@ -2730,6 +3786,19 @@ switch (mode) { case SOP_PU_SLEEP: + if(j->daa_mode == SOP_PU_CONVERSATION) + { + j->pld_scrw.bits.daafsyncen = 0; // Turn off DAA Frame Sync + + outb_p(j->pld_scrw.byte, j->XILINXbase); + j->pld_slicw.bits.rly2 = 0; + outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01); + bytes.high = 0x10; + bytes.low = j->m_DAAShadowRegs.SOP_REGS.SOP.cr0.reg; + daa_load(&bytes, board); + if (!SCI_Prepare(board)) + return 0; + } j->pld_scrw.bits.daafsyncen = 0; // Turn off DAA Frame Sync outb_p(j->pld_scrw.byte, j->XILINXbase); @@ -2740,10 +3809,15 @@ daa_load(&bytes, board); if (!SCI_Prepare(board)) return 0; + j->daa_mode = SOP_PU_SLEEP; j->flags.pstn_ringing = 0; - j->pstn_sleeptil = jiffies + (hertz * 3); - break; + j->ex.bits.pstn_ring = 0; + j->pstn_sleeptil = jiffies + (hertz / 2); + wake_up_interruptible(&j->read_q); // Wake any blocked readers + wake_up_interruptible(&j->write_q); // Wake any blocked writers + wake_up_interruptible(&j->poll_q); // Wake any blocked selects + break; case SOP_PU_RINGING: j->pld_scrw.bits.daafsyncen = 0; // Turn off DAA Frame Sync @@ -3281,14 +4355,11 @@ int ixj_set_tone_off(unsigned short arg, int board) { ixj[board].tone_off_time = arg; - if (ixj_WriteDSPCommand(0x6E05, board)) // Set Tone Off Period return -1; - if (ixj_WriteDSPCommand(arg, board)) return -1; - return 0; } @@ -3297,7 +4368,6 @@ if (ixj_WriteDSPCommand(0x6E06, board)) // Get Tone On Period return -1; - return 0; } @@ -3306,7 +4376,6 @@ if (ixj_WriteDSPCommand(0x6E07, board)) // Get Tone Off Period return -1; - return 0; } @@ -3315,7 +4384,6 @@ ixj[board].flags.ringback = 0; ixj[board].flags.dialtone = 0; ixj[board].flags.busytone = 1; - ixj_set_tone_on(0x07D0, board); ixj_set_tone_off(0x07D0, board); ixj_play_tone(board, 27); @@ -3326,13 +4394,11 @@ ixj[board].flags.ringback = 0; ixj[board].flags.dialtone = 1; ixj[board].flags.busytone = 0; - if (ixj[board].dsp.low == 0x20) { return; } else { ixj_set_tone_on(0xFFFF, board); ixj_set_tone_off(0x0000, board); - ixj_play_tone(board, 25); } } @@ -3340,28 +4406,24 @@ static void ixj_cpt_stop(board) { IXJ *j = &ixj[board]; - - j->flags.dialtone = 0; - j->flags.busytone = 0; - j->flags.ringback = 0; - - ixj_set_tone_on(0x0001, board); - ixj_set_tone_off(0x0000, board); - - ixj_play_tone(board, 0); - - j->tone_state = 0; - - ixj_del_timer(); - if (j->cadence_t) { - if (j->cadence_t->ce) { - kfree(j->cadence_t->ce); + if(j->tone_state) + { + j->flags.dialtone = 0; + j->flags.busytone = 0; + j->flags.ringback = 0; + ixj_set_tone_on(0x0001, board); + ixj_set_tone_off(0x0000, board); + ixj_play_tone(board, 0); + j->tone_state = 0; + if (j->cadence_t) { + if (j->cadence_t->ce) { + kfree(j->cadence_t->ce); + } + kfree(j->cadence_t); + j->cadence_t = NULL; } - kfree(j->cadence_t); - j->cadence_t = NULL; } - ixj_add_timer(); - if (j->dsp.low == 0x20 || (j->play_mode == -1 && j->rec_mode == -1)) + if (j->play_mode == -1 && j->rec_mode == -1) idle(board); if (j->play_mode != -1) ixj_play_start(board); @@ -3374,7 +4436,6 @@ ixj[board].flags.busytone = 0; ixj[board].flags.dialtone = 0; ixj[board].flags.ringback = 1; - ixj_set_tone_on(0x0FA0, board); ixj_set_tone_off(0x2EE0, board); ixj_play_tone(board, 26); @@ -3391,28 +4452,29 @@ IXJ_CADENCE_ELEMENT *lcep; IXJ_TONE ti; IXJ *j = &ixj[board]; - lcp = kmalloc(sizeof(IXJ_CADENCE), GFP_KERNEL); if (lcp == NULL) return -ENOMEM; - if (copy_from_user(lcp, (char *) cp, sizeof(IXJ_CADENCE))) + { + kfree(lcp); return -EFAULT; - + } lcep = kmalloc(sizeof(IXJ_CADENCE_ELEMENT) * lcp->elements_used, GFP_KERNEL); if (lcep == NULL) { kfree(lcp); return -ENOMEM; } if (copy_from_user(lcep, lcp->ce, sizeof(IXJ_CADENCE_ELEMENT) * lcp->elements_used)) - return -EFAULT; - - if(j->cadence_t) { + kfree(lcep); + kfree(lcp); + return -EFAULT; + } + if (j->cadence_t) { kfree(j->cadence_t->ce); kfree(j->cadence_t); } - lcp->ce = (void *) lcep; j->cadence_t = lcp; j->tone_cadence_state = 0; @@ -3427,16 +4489,50 @@ ixj_init_tone(board, &ti); } ixj_play_tone(board, lcp->ce[0].index); - return 1; } +static int ixj_build_filter_cadence(int board, IXJ_FILTER_CADENCE * cp) +{ + IXJ_FILTER_CADENCE *lcp; + IXJ *j = &ixj[board]; + lcp = kmalloc(sizeof(IXJ_CADENCE), GFP_KERNEL); + if (lcp == NULL) + return -ENOMEM; + if (copy_from_user(lcp, (char *) cp, sizeof(IXJ_FILTER_CADENCE))) + return -EFAULT; + if (lcp->filter > 4) + return -1; + j->cadence_f[lcp->filter].state = 0; + j->cadence_f[lcp->filter].enable = lcp->enable; + j->filter_en[lcp->filter] = j->cadence_f[lcp->filter].en_filter = lcp->en_filter; + j->cadence_f[lcp->filter].on1 = lcp->on1; + j->cadence_f[lcp->filter].on1min = 0; + j->cadence_f[lcp->filter].on1max = 0; + j->cadence_f[lcp->filter].off1 = lcp->off1; + j->cadence_f[lcp->filter].off1min = 0; + j->cadence_f[lcp->filter].off1max = 0; + j->cadence_f[lcp->filter].on2 = lcp->on2; + j->cadence_f[lcp->filter].on2min = 0; + j->cadence_f[lcp->filter].on2max = 0; + j->cadence_f[lcp->filter].off2 = lcp->off2; + j->cadence_f[lcp->filter].off2min = 0; + j->cadence_f[lcp->filter].off2max = 0; + j->cadence_f[lcp->filter].on3 = lcp->on3; + j->cadence_f[lcp->filter].on3min = 0; + j->cadence_f[lcp->filter].on3max = 0; + j->cadence_f[lcp->filter].off3 = lcp->off3; + j->cadence_f[lcp->filter].off3min = 0; + j->cadence_f[lcp->filter].off3max = 0; + kfree(lcp); + return 0; +} + static void add_caps(int board) { IXJ *j = &ixj[board]; j->caps = 0; - - j->caplist[j->caps].cap = vendor; + j->caplist[j->caps].cap = PHONE_VENDOR_QUICKNET; strcpy(j->caplist[j->caps].desc, "Quicknet Technologies, Inc. (www.quicknet.net)"); j->caplist[j->caps].captype = vendor; j->caplist[j->caps].handle = j->caps++; @@ -3532,10 +4628,9 @@ int cnt; IXJ *j = &ixj[board]; int retval = 0; - for (cnt = 0; cnt < j->caps; cnt++) { - if (pcreq->captype == j->caplist[cnt].captype && - pcreq->cap == j->caplist[cnt].cap) { + if (pcreq->captype == j->caplist[cnt].captype + && pcreq->cap == j->caplist[cnt].cap) { retval = 1; break; } @@ -3543,8 +4638,7 @@ return retval; } -int ixj_ioctl(struct inode *inode, struct file *file_p, - unsigned int cmd, unsigned long arg) +int ixj_ioctl(struct inode *inode, struct file *file_p, unsigned int cmd, unsigned long arg) { IXJ_TONE ti; IXJ_FILTER jf; @@ -3552,16 +4646,13 @@ int board = NUM(inode->i_rdev); IXJ *j = &ixj[NUM(inode->i_rdev)]; int retval = 0; - if (ixjdebug > 1) printk(KERN_DEBUG "phone%d ioctl, cmd: 0x%x, arg: 0x%lx\n", minor, cmd, arg); if (minor >= IXJMAX) return -ENODEV; - /* * Check ioctls only root can use. */ - if (!capable(CAP_SYS_ADMIN)) { switch (cmd) { case IXJCTL_TESTRAM: @@ -3580,10 +4671,33 @@ case IXJCTL_SERIAL: retval = j->serial; break; + case IXJCTL_VERSION: + if (copy_to_user((char *) arg, ixj_c_revision, strlen(ixj_c_revision))) + return -EFAULT; + break; case PHONE_RING_CADENCE: j->ring_cadence = arg; break; + case IXJCTL_CIDCW: + if(arg) { + copy_from_user(&j->cid_send, (char *)arg, sizeof(PHONE_CID)); + } + else { + memset(&j->cid_send, 0, sizeof(PHONE_CID)); + } + ixj_write_cidcw(board); + break; + /* Binary compatbility */ + case OLD_PHONE_RING_START: + arg = 0; + /* Fall through */ case PHONE_RING_START: + if(arg) { + copy_from_user(&j->cid_send, (char *)arg, sizeof(PHONE_CID)); + } + else { + memset(&j->cid_send, 0, sizeof(PHONE_CID)); + } ixj_ring_start(board); break; case PHONE_RING_STOP: @@ -3595,7 +4709,19 @@ break; case PHONE_EXCEPTION: retval = j->ex.bytes; - j->ex.bytes &= 0x03; + j->ex.bits.flash = 0; + j->ex.bits.pstn_ring = 0; + j->ex.bits.caller_id = 0; + j->ex.bits.pstn_wink = 0; + j->ex.bits.f0 = 0; + j->ex.bits.f1 = 0; + j->ex.bits.f2 = 0; + j->ex.bits.f3 = 0; + j->ex.bits.fc0 = 0; + j->ex.bits.fc1 = 0; + j->ex.bits.fc2 = 0; + j->ex.bits.fc3 = 0; + j->ex.bits.reserved = 0; break; case PHONE_HOOKSTATE: j->ex.bits.hookstate = 0; @@ -3610,6 +4736,9 @@ case PHONE_REC_CODEC: retval = set_rec_codec(board, arg); break; + case PHONE_VAD: + ixj_vad(board, arg); + break; case PHONE_REC_START: ixj_record_start(board); break; @@ -3620,7 +4749,13 @@ set_rec_depth(board, arg); break; case PHONE_REC_VOLUME: - set_rec_volume(board, arg); + if(arg == -1) { + retval = get_rec_volume(board); + } + else { + set_rec_volume(board, arg); + retval = arg; + } break; case PHONE_REC_LEVEL: retval = get_rec_level(board); @@ -3638,7 +4773,7 @@ retval = set_play_codec(board, arg); break; case PHONE_PLAY_START: - ixj_play_start(board); + retval = ixj_play_start(board); break; case PHONE_PLAY_STOP: ixj_play_stop(board); @@ -3647,7 +4782,13 @@ set_play_depth(board, arg); break; case PHONE_PLAY_VOLUME: - set_play_volume(board, arg); + if(arg == -1) { + retval = get_play_volume(board); + } + else { + set_play_volume(board, arg); + retval = arg; + } break; case PHONE_PLAY_LEVEL: retval = get_play_level(board); @@ -3828,41 +4969,45 @@ switch (arg) { case DAA_US: DAA_Coeff_US(board); - ixj_daa_write(board); + retval = ixj_daa_write(board); break; case DAA_UK: DAA_Coeff_UK(board); - ixj_daa_write(board); + retval = ixj_daa_write(board); break; case DAA_FRANCE: DAA_Coeff_France(board); - ixj_daa_write(board); + retval = ixj_daa_write(board); break; case DAA_GERMANY: DAA_Coeff_Germany(board); - ixj_daa_write(board); + retval = ixj_daa_write(board); break; case DAA_AUSTRALIA: DAA_Coeff_Australia(board); - ixj_daa_write(board); + retval = ixj_daa_write(board); break; case DAA_JAPAN: DAA_Coeff_Japan(board); - ixj_daa_write(board); + retval = ixj_daa_write(board); break; default: + retval = 1; break; } + j->country = arg; break; case IXJCTL_DAA_AGAIN: ixj_daa_cr4(board, arg | 0x02); break; case IXJCTL_PSTN_LINETEST: - case PHONE_PSTN_LINETEST: retval = ixj_linetest(board); break; + case IXJCTL_VMWI: + ixj_write_vmwi(board, arg); + break; case IXJCTL_CID: - if (copy_to_user((char *) arg, &j->cid, sizeof(IXJ_CID))) + if (copy_to_user((char *) arg, &j->cid, sizeof(PHONE_CID))) return -EFAULT; j->ex.bits.caller_id = 0; break; @@ -3883,7 +5028,7 @@ break; case PHONE_CAPABILITIES_LIST: if (copy_to_user((char *) arg, j->caplist, sizeof(struct phone_capability) * j->caps)) - return -EFAULT; + return -EFAULT; break; case PHONE_CAPABILITIES_CHECK: retval = capabilities_check(board, (struct phone_capability *) arg); @@ -3896,7 +5041,7 @@ j->ex.bits.pstn_ring = 0; break; case IXJCTL_SET_FILTER: - if (copy_from_user(&jf, (char *) arg, sizeof(ti))) + if (copy_from_user(&jf, (char *) arg, sizeof(jf))) return -EFAULT; retval = ixj_init_filter(board, &jf); break; @@ -3910,6 +5055,9 @@ case IXJCTL_TONE_CADENCE: retval = ixj_build_cadence(board, (IXJ_CADENCE *) arg); break; + case IXJCTL_FILTER_CADENCE: + retval = ixj_build_filter_cadence(board, (IXJ_FILTER_CADENCE *) arg); + break; case IXJCTL_INTERCOM_STOP: ixj[board].intercom = -1; ixj[arg].intercom = -1; @@ -3948,7 +5096,7 @@ poll: ixj_poll, ioctl: ixj_ioctl, release: ixj_release, - fasync: ixj_fasync, + fasync: ixj_fasync }; static int ixj_linetest(int board) @@ -3956,8 +5104,9 @@ unsigned long jifwait; IXJ *j = &ixj[board]; + j->flags.incheck = 1; // Testing if (!j->flags.pots_correct) { - j->flags.pots_correct = 1; // Testing + j->flags.pots_correct = 1; daa_int_read(board); //Clear DAA Interrupt flags // @@ -3988,7 +5137,7 @@ daa_set_mode(board, SOP_PU_CONVERSATION); jifwait = jiffies + hertz; while (time_before(jiffies, jifwait)) { - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); } daa_int_read(board); @@ -4009,23 +5158,23 @@ } } } - if (!j->flags.pstn_present) { - j->pld_slicw.bits.rly3 = 0; - outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01); - daa_set_mode(board, SOP_PU_CONVERSATION); - jifwait = jiffies + hertz; - while (time_before(jiffies, jifwait)) { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); - } - daa_int_read(board); - daa_set_mode(board, SOP_PU_SLEEP); - if (j->m_DAAShadowRegs.XOP_REGS.XOP.xr0.bitreg.VDD_OK) { - j->flags.pstn_present = 1; - } else { - j->flags.pstn_present = 0; - } +// if (!j->flags.pstn_present) { + j->pld_slicw.bits.rly3 = 0; + outb_p(j->pld_slicw.byte, j->XILINXbase + 0x01); + daa_set_mode(board, SOP_PU_CONVERSATION); + jifwait = jiffies + hertz; + while (time_before(jiffies, jifwait)) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(1); + } + daa_int_read(board); + daa_set_mode(board, SOP_PU_SLEEP); + if (j->m_DAAShadowRegs.XOP_REGS.XOP.xr0.bitreg.VDD_OK) { + j->flags.pstn_present = 1; + } else { + j->flags.pstn_present = 0; } +// } if (j->flags.pstn_present) { if (j->flags.pots_correct) { LED_SetState(0xA, board); @@ -4039,6 +5188,7 @@ LED_SetState(0x5, board); } } + j->flags.incheck = 0; // Testing return j->flags.pstn_present; } @@ -4046,59 +5196,44 @@ { unsigned short cmd; unsigned long jif; + int cnt; BYTES bytes; IXJ *j = &ixj[board]; - /* - * First initialise the queues - */ - + init_waitqueue_head(&j->poll_q); init_waitqueue_head(&j->read_q); init_waitqueue_head(&j->write_q); - init_waitqueue_head(&j->poll_q); - - /* - * Now we can probe - */ - if (ixjdebug > 0) printk(KERN_INFO "Write IDLE to Software Control Register\n"); + ixj_WriteDSPCommand(0x0FE0, board); // Put the DSP in full power mode. if (ixj_WriteDSPCommand(0x0000, board)) /* Write IDLE to Software Control Register */ return -1; - // The read values of the SSR should be 0x00 for the IDLE command if (j->ssr.low || j->ssr.high) return -1; - if (ixjdebug > 0) printk(KERN_INFO "Get Device ID Code\n"); - if (ixj_WriteDSPCommand(0x3400, board)) /* Get Device ID Code */ return -1; - j->dsp.low = j->ssr.low; j->dsp.high = j->ssr.high; - if (ixjdebug > 0) printk(KERN_INFO "Get Device Version Code\n"); - if (ixj_WriteDSPCommand(0x3800, board)) /* Get Device Version Code */ return -1; - j->ver.low = j->ssr.low; j->ver.high = j->ssr.high; - if (!j->cardtype) { if (j->dsp.low == 0x21) { - j->XILINXbase = j->DSPbase + 0x10; +// j->XILINXbase = j->DSPbase + 0x10; bytes.high = bytes.low = inb_p(j->XILINXbase + 0x02); outb_p(bytes.low ^ 0xFF, j->XILINXbase + 0x02); - // Test for Internet LineJACK or Internet PhoneJACK Lite +// Test for Internet LineJACK or Internet PhoneJACK Lite bytes.low = inb_p(j->XILINXbase + 0x02); if (bytes.low == bytes.high) // Register is read only on - // Internet PhoneJack Lite - { + // Internet PhoneJack Lite + { j->cardtype = 400; // Internet PhoneJACK Lite if (check_region(j->XILINXbase, 4)) { @@ -4158,18 +5293,18 @@ j->pld_slicw.pcib.e1 = 1; outb_p(j->pld_slicw.byte, j->XILINXbase); break; + case 600: //Internet PhoneCARD + + break; } } if (j->dsp.low == 0x20 || j->cardtype == 400 || j->cardtype == 500) { if (ixjdebug > 0) printk(KERN_INFO "Write CODEC config to Software Control Register\n"); - if (ixj_WriteDSPCommand(0xC462, board)) /* Write CODEC config to Software Control Register */ return -1; - if (ixjdebug > 0) printk(KERN_INFO "Write CODEC timing to Software Control Register\n"); - if (j->cardtype == 100) { cmd = 0x9FF2; } else { @@ -4180,17 +5315,17 @@ } else { if (set_base_frame(board, 30) != 30) return -1; - + if (ixjdebug > 0) + printk(KERN_INFO "Write CODEC config to Software Control Register\n"); + if (j->cardtype == 600) { + if (ixj_WriteDSPCommand(0xC528, board)) /* Write CODEC config to Software Control Register */ + return -1; + } if (j->cardtype == 300) { - if (ixjdebug > 0) - printk(KERN_INFO "Write CODEC config to Software Control Register\n"); - if (ixj_WriteDSPCommand(0xC528, board)) /* Write CODEC config to Software Control Register */ return -1; - if (ixjdebug > 0) printk(KERN_INFO "Turn on the PLD Clock at 8Khz\n"); - j->pld_clock.byte = 0; outb_p(j->pld_clock.byte, j->XILINXbase + 0x04); } @@ -4199,9 +5334,8 @@ if (j->dsp.low == 0x20) { if (ixjdebug > 0) printk(KERN_INFO "Configure GPIO pins\n"); - j->gpio.bytes.high = 0x09; - /* bytes.low = 0xEF; 0xF7 */ +/* bytes.low = 0xEF; 0xF7 */ j->gpio.bits.gpio1 = 1; j->gpio.bits.gpio2 = 1; j->gpio.bits.gpio3 = 0; @@ -4210,10 +5344,8 @@ j->gpio.bits.gpio6 = 1; j->gpio.bits.gpio7 = 1; ixj_WriteDSPCommand(ixj[board].gpio.word, board); /* Set GPIO pin directions */ - if (ixjdebug > 0) printk(KERN_INFO "Enable SLIC\n"); - j->gpio.bytes.high = 0x0B; j->gpio.bytes.low = 0x00; j->gpio.bits.gpio1 = 0; @@ -4226,45 +5358,38 @@ LED_SetState(0x1, board); jif = jiffies + (hertz / 10); while (time_before(jiffies, jif)) { - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); } LED_SetState(0x2, board); jif = jiffies + (hertz / 10); while (time_before(jiffies, jif)) { - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); } LED_SetState(0x4, board); jif = jiffies + (hertz / 10); while (time_before(jiffies, jif)) { - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); } LED_SetState(0x8, board); jif = jiffies + (hertz / 10); while (time_before(jiffies, jif)) { - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); } LED_SetState(0x0, board); - daa_get_version(board); - if (ixjdebug > 0) printk("Loading DAA Coefficients\n"); - DAA_Coeff_US(board); if (!ixj_daa_write(board)) printk("DAA write failed on board %d\n", board); - ixj_daa_cid_reset(board); - j->flags.pots_correct = 0; j->flags.pstn_present = 0; - ixj_linetest(board); - if (j->flags.pots_correct) { j->pld_scrw.bits.daafsyncen = 0; // Turn off DAA Frame Sync @@ -4275,9 +5400,10 @@ SLIC_SetState(PLD_SLIC_STATE_STANDBY, board); j->port = PORT_POTS; } + ixj_set_port(board, PORT_PSTN); + ixj_set_pots(board, 1); if (ixjdebug > 0) printk(KERN_INFO "Enable Mixer\n"); - ixj_mixer(0x0000, board); //Master Volume Left unmute 0db ixj_mixer(0x0100, board); //Master Volume Right unmute 0db @@ -4301,43 +5427,43 @@ ixj_mixer(0x1800, board); //ADC Source select } else { - j->port = PORT_POTS; - SLIC_SetState(PLD_SLIC_STATE_STANDBY, board); + if (j->cardtype == 600) { + ixj_WriteDSPCommand(0xCF07, board); + ixj_WriteDSPCommand(0x00B0, board); + ixj_set_port(board, PORT_SPEAKER); + } else { + ixj_set_port(board, PORT_POTS); + SLIC_SetState(PLD_SLIC_STATE_STANDBY, board); + } } } j->intercom = -1; j->framesread = j->frameswritten = 0; + j->read_wait = j->write_wait = 0; j->rxreadycheck = j->txreadycheck = 0; - + set_play_volume(board, 0x100); + set_rec_volume(board, 0x100); if (ixj_WriteDSPCommand(0x0000, board)) /* Write IDLE to Software Control Register */ return -1; - - // The read values of the SSR should be 0x00 for the IDLE command +// The read values of the SSR should be 0x00 for the IDLE command if (j->ssr.low || j->ssr.high) return -1; - if (ixjdebug > 0) printk(KERN_INFO "Enable Line Monitor\n"); - if (ixjdebug > 0) printk(KERN_INFO "Set Line Monitor to Asyncronous Mode\n"); - if (ixj_WriteDSPCommand(0x7E01, board)) // Asynchronous Line Monitor return -1; - if (ixjdebug > 0) printk(KERN_INFO "Enable DTMF Detectors\n"); - if (ixj_WriteDSPCommand(0x5151, board)) // Enable DTMF detection return -1; - if (ixj_WriteDSPCommand(0x6E01, board)) // Set Asyncronous Tone Generation return -1; - set_rec_depth(board, 2); // Set Record Channel Limit to 2 frames set_play_depth(board, 2); // Set Playback Channel Limit to 2 frames @@ -4345,7 +5471,6 @@ j->ex.bits.dtmf_ready = 0; j->dtmf_state = 0; j->dtmf_wp = ixj[board].dtmf_rp = 0; - j->rec_mode = ixj[board].play_mode = -1; j->flags.ringing = 0; j->maxrings = MAXRINGS; @@ -4353,25 +5478,600 @@ j->drybuffer = 0; j->winktime = 320; j->flags.dtmf_oob = 0; - + for (cnt = 0; cnt < 4; cnt++) + j->cadence_f[cnt].enable = 0; /* must be a device on the specified address */ + ixj_WriteDSPCommand(0x0FE3, board); // Put the DSP in 1/5 power mode. /* Register with the Telephony for Linux subsystem */ j->p.f_op = &ixj_fops; j->p.open = ixj_open; + j->p.board = board; phone_register_device(&j->p, PHONE_UNIT_ANY); - add_caps(board); + return 0; +} + +int ixj_get_status_proc(char *buf) +{ + int len; + int cnt; + IXJ *j; + len = 0; + len += sprintf(buf + len, "\n%s", ixj_c_rcsid); + len += sprintf(buf + len, "\n%s", ixj_h_rcsid); + len += sprintf(buf + len, "\n%s", ixjuser_h_rcsid); + for (cnt = 0; cnt < IXJMAX; cnt++) { + j = &ixj[cnt]; + if (j->DSPbase) { + len += sprintf(buf + len, "\nCard Num %d", cnt); + len += sprintf(buf + len, "\nDSP Base Address 0x%4.4x", j->DSPbase); + if (j->cardtype != 100) + len += sprintf(buf + len, "\nXILINX Base Address 0x%4.4x", j->XILINXbase); + len += sprintf(buf + len, "\nDSP Type %2.2x%2.2x", j->dsp.high, j->dsp.low); + len += sprintf(buf + len, "\nDSP Version %2.2x.%2.2x", j->ver.high, j->ver.low); + len += sprintf(buf + len, "\nSerial Number %8.8x", j->serial); + switch (j->cardtype) { + case (100): + len += sprintf(buf + len, "\nCard Type = Internet PhoneJACK"); + break; + case (300): + len += sprintf(buf + len, "\nCard Type = Internet LineJACK"); + if (j->flags.g729_loaded) + len += sprintf(buf + len, " w/G.729 A/B"); + len += sprintf(buf + len, " Country = %d", j->country); + break; + case (400): + len += sprintf(buf + len, "\nCard Type = Internet PhoneJACK Lite"); + if (j->flags.g729_loaded) + len += sprintf(buf + len, " w/G.729 A/B"); + break; + case (500): + len += sprintf(buf + len, "\nCard Type = Internet PhoneJACK PCI"); + if (j->flags.g729_loaded) + len += sprintf(buf + len, " w/G.729 A/B"); + break; + case (600): + len += sprintf(buf + len, "\nCard Type = Internet PhoneCARD"); + if (j->flags.g729_loaded) + len += sprintf(buf + len, " w/G.729 A/B"); + len += sprintf(buf + len, "\nSmart Cable %spresent", j->pccr1.bits.drf ? "not " : ""); + if (!j->pccr1.bits.drf) + len += sprintf(buf + len, "\nSmart Cable type %d", j->flags.pcmciasct); + len += sprintf(buf + len, "\nSmart Cable state %d", j->flags.pcmciastate); + break; + default: + len += sprintf(buf + len, "\nCard Type = %d", j->cardtype); + break; + } + len += sprintf(buf + len, "\nReaders %d", j->readers); + len += sprintf(buf + len, "\nWriters %d", j->writers); + len += sprintf(buf + len, "\nFSK words %d", ixj[2].fskdcnt); + len += sprintf(buf + len, "\nCapabilities %d", j->caps); + if (j->dsp.low != 0x20) + len += sprintf(buf + len, "\nDSP Processor load %d", j->proc_load); + if (j->flags.cidsent) + len += sprintf(buf + len, "\nCaller ID data sent"); + else + len += sprintf(buf + len, "\nCaller ID data not sent"); + + len += sprintf(buf + len, "\nCaller ID Date %s%s", j->cid_send.month, j->cid_send.day); + len += sprintf(buf + len, "\nCaller ID Time %s%s", j->cid_send.hour, j->cid_send.min); + len += sprintf(buf + len, "\nCaller ID Name %s", j->cid_send.name); + len += sprintf(buf + len, "\nCaller ID Number %s", j->cid_send.number); + + len += sprintf(buf + len, "\nPlay CODEC "); + switch (j->play_codec) { + case G723_63: + len += sprintf(buf + len, "G.723.1 6.3"); + break; + case G723_53: + len += sprintf(buf + len, "G.723.1 5.3"); + break; + case TS85: + len += sprintf(buf + len, "TrueSpeech 8.5"); + break; + case TS48: + len += sprintf(buf + len, "TrueSpeech 4.8"); + break; + case TS41: + len += sprintf(buf + len, "TrueSpeech 4.1"); + break; + case G728: + len += sprintf(buf + len, "G.728"); + break; + case G729: + len += sprintf(buf + len, "G.729"); + break; + case ULAW: + len += sprintf(buf + len, "uLaw"); + break; + case ALAW: + len += sprintf(buf + len, "aLaw"); + break; + case LINEAR16: + len += sprintf(buf + len, "16 bit Linear"); + break; + case LINEAR8: + len += sprintf(buf + len, "8 bit Linear"); + break; + case WSS: + len += sprintf(buf + len, "Windows Sound System"); + break; + default: + len += sprintf(buf + len, "NO CODEC CHOSEN"); + break; + } + len += sprintf(buf + len, "\nRecord CODEC "); + switch (j->rec_codec) { + case G723_63: + len += sprintf(buf + len, "G.723.1 6.3"); + break; + case G723_53: + len += sprintf(buf + len, "G.723.1 5.3"); + break; + case TS85: + len += sprintf(buf + len, "TrueSpeech 8.5"); + break; + case TS48: + len += sprintf(buf + len, "TrueSpeech 4.8"); + break; + case TS41: + len += sprintf(buf + len, "TrueSpeech 4.1"); + break; + case G728: + len += sprintf(buf + len, "G.728"); + break; + case G729: + len += sprintf(buf + len, "G.729"); + break; + case ULAW: + len += sprintf(buf + len, "uLaw"); + break; + case ALAW: + len += sprintf(buf + len, "aLaw"); + break; + case LINEAR16: + len += sprintf(buf + len, "16 bit Linear"); + break; + case LINEAR8: + len += sprintf(buf + len, "8 bit Linear"); + break; + case WSS: + len += sprintf(buf + len, "Windows Sound System"); + break; + default: + len += sprintf(buf + len, "NO CODEC CHOSEN"); + break; + } + switch (j->aec_level) { + case AEC_OFF: + len += sprintf(buf + len, "\n AEC OFF"); + break; + case AEC_LOW: + len += sprintf(buf + len, "\n AEC LOW"); + break; + case AEC_MED: + len += sprintf(buf + len, "\n AEC MED"); + break; + case AEC_HIGH: + len += sprintf(buf + len, "\n AEC HIGH"); + break; + } + len += sprintf(buf + len, "\nHook state %d", j->r_hook); // ixj_hookstate(cnt)); + + if (j->cardtype == 300) { + len += sprintf(buf + len, "\nPOTS Correct %d", j->flags.pots_correct); + len += sprintf(buf + len, "\nPSTN Present %d", j->flags.pstn_present); + len += sprintf(buf + len, "\nPOTS to PSTN %d", j->flags.pots_pstn); + len += sprintf(buf + len, "\nPSTN sleeptil %ld - jiffies %ld", j->pstn_sleeptil, jiffies); + switch (j->daa_mode) { + case SOP_PU_SLEEP: + len += sprintf(buf + len, "\nDAA PSTN On Hook"); + break; + case SOP_PU_RINGING: + len += sprintf(buf + len, "\nDAA PSTN Ringing"); + break; + case SOP_PU_CONVERSATION: + len += sprintf(buf + len, "\nDAA PSTN Off Hook"); + break; + case SOP_PU_PULSEDIALING: + len += sprintf(buf + len, "\nDAA PSTN Pulse Dialing"); + break; + } + } + switch (j->port) { + case PORT_POTS: + len += sprintf(buf + len, "\nPort POTS"); + break; + case PORT_PSTN: + len += sprintf(buf + len, "\nPort PSTN"); + break; + case PORT_SPEAKER: + len += sprintf(buf + len, "\nPort SPEAKER/MIC"); + break; + case PORT_HANDSET: + len += sprintf(buf + len, "\nPort HANDSET"); + break; + } + if (j->dsp.low == 0x21 || j->dsp.low == 0x22) { + len += sprintf(buf + len, "\nSLIC state "); + switch (SLIC_GetState(cnt)) { + case PLD_SLIC_STATE_OC: + len += sprintf(buf + len, "OC"); + break; + case PLD_SLIC_STATE_RINGING: + len += sprintf(buf + len, "RINGING"); + break; + case PLD_SLIC_STATE_ACTIVE: + len += sprintf(buf + len, "ACTIVE"); + break; + case PLD_SLIC_STATE_OHT: // On-hook transmit + + len += sprintf(buf + len, "OHT"); + break; + case PLD_SLIC_STATE_TIPOPEN: + len += sprintf(buf + len, "TIPOPEN"); + break; + case PLD_SLIC_STATE_STANDBY: + len += sprintf(buf + len, "STANDBY"); + break; + case PLD_SLIC_STATE_APR: // Active polarity reversal + + len += sprintf(buf + len, "APR"); + break; + case PLD_SLIC_STATE_OHTPR: // OHT polarity reversal + + len += sprintf(buf + len, "OHTPR"); + break; + default: + len += sprintf(buf + len, "%d", SLIC_GetState(cnt)); + break; + } + } +#ifdef PERFMON_STATS + len += sprintf(buf + len, "\nTimer Checks %ld", j->timerchecks); + len += sprintf(buf + len, "\nRX Ready Checks %ld", j->rxreadycheck); + len += sprintf(buf + len, "\nTX Ready Checks %ld", j->txreadycheck); + len += sprintf(buf + len, "\nBase Frame %2.2x.%2.2x", j->baseframe.high, j->baseframe.low); + len += sprintf(buf + len, "\nFrames Read %ld", j->framesread); + len += sprintf(buf + len, "\nFrames Written %ld", j->frameswritten); + len += sprintf(buf + len, "\nDry Buffer %ld", j->drybuffer); + len += sprintf(buf + len, "\nRead Waits %ld", j->read_wait); + len += sprintf(buf + len, "\nWrite Waits %ld", j->write_wait); +#endif + len += sprintf(buf + len, "\n"); + } + } + return len; +} +int ixj_get_status_proc_fsk(char *buf) +{ + int len; + len = 0; + if (ixj[2].fskdcnt) { + memcpy(buf, &ixj[2].fskdata, (ixj[2].fskdcnt) * 2); + len += ixj[2].fskdcnt * 2; + } + return len; +} + +static int ixj_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = ixj_get_status_proc(page); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + return len; +} +static int ixj_read_proc_fsk(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = ixj_get_status_proc_fsk(page); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + return len; +} + +MODULE_DESCRIPTION("Internet Phone/Internet LineJack module - www.quicknet.net"); +MODULE_AUTHOR("Ed Okerson "); +#ifdef CONFIG_PCMCIA +#ifdef PCMCIA_DEBUG +static int pc_debug = PCMCIA_DEBUG; +MODULE_PARM(pc_debug, "i"); +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) +#else +#define DEBUG(n, args...) +#endif +typedef struct ixj_info_t { + int ndev; + dev_node_t node; + struct ixj *port; +} ixj_info_t; +static dev_link_t *ixj_attach(void); +static void ixj_detach(dev_link_t *); +static void ixj_config(dev_link_t * link); +static void ixj_cs_release(u_long arg); +static int ixj_event(event_t event, int priority, event_callback_args_t * args); +static dev_info_t dev_info = "ixj_cs"; +static dev_link_t *dev_list = NULL; +static void cs_error(client_handle_t handle, int func, int ret) +{ + error_info_t err = + { + func, ret + }; + CardServices(ReportError, handle, &err); +} + +static dev_link_t *ixj_attach(void) +{ + client_reg_t client_reg; + dev_link_t *link; + int ret; + DEBUG(0, "ixj_attach()\n"); + /* Create new ixj device */ + link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); + memset(link, 0, sizeof(struct dev_link_t)); + link->release.function = &ixj_cs_release; + link->release.data = (u_long) link; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + link->io.Attributes2 = IO_DATA_PATH_WIDTH_8; + link->io.IOAddrLines = 3; + link->conf.Vcc = 50; + link->conf.IntType = INT_MEMORY_AND_IO; + link->priv = kmalloc(sizeof(struct ixj_info_t), GFP_KERNEL); + memset(link->priv, 0, sizeof(struct ixj_info_t)); + /* Register with Card Services */ + link->next = dev_list; + dev_list = link; + client_reg.dev_info = &dev_info; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.EventMask = + CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | + CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | + CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; + client_reg.event_handler = &ixj_event; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + ret = CardServices(RegisterClient, &link->handle, &client_reg); + if (ret != CS_SUCCESS) { + cs_error(link->handle, RegisterClient, ret); + ixj_detach(link); + return NULL; + } + return link; +} + +static void ixj_detach(dev_link_t * link) +{ + dev_link_t **linkp; + long flags; + int ret; + DEBUG(0, "ixj_detach(0x%p)\n", link); + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) + break; + if (*linkp == NULL) + return; + save_flags(flags); + cli(); + if (link->state & DEV_RELEASE_PENDING) { + del_timer(&link->release); + link->state &= ~DEV_RELEASE_PENDING; + } + restore_flags(flags); + if (link->state & DEV_CONFIG) + ixj_cs_release((u_long) link); + if (link->handle) { + ret = CardServices(DeregisterClient, link->handle); + if (ret != CS_SUCCESS) + cs_error(link->handle, DeregisterClient, ret); + } + /* Unlink device structure, free bits */ + *linkp = link->next; + kfree_s(link->priv, sizeof(ixj_info_t)); + kfree_s(link, sizeof(struct dev_link_t)); +} + +#define CS_CHECK(fn, args...) \ +while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed + +#define CFG_CHECK(fn, args...) \ +if (CardServices(fn, args) != 0) goto next_entry + +void ixj_get_serial(dev_link_t * link, IXJ * j) +{ + client_handle_t handle; + tuple_t tuple; + u_short buf[128]; + char *str; + int last_ret, last_fn, i, place; + handle = link->handle; + DEBUG(0, "ixj_get_serial(0x%p)\n", link); + tuple.TupleData = (cisdata_t *) buf; + tuple.TupleOffset = 0; + tuple.TupleDataMax = 80; + tuple.Attributes = 0; + tuple.DesiredTuple = CISTPL_VERS_1; + CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(GetTupleData, handle, &tuple); + str = (char *) buf; + printk("PCMCIA Version %d.%d\n", str[0], str[1]); + str += 2; + printk("%s", str); + str = str + strlen(str) + 1; + printk(" %s", str); + str = str + strlen(str) + 1; + place = 1; + for (i = strlen(str) - 1; i >= 0; i--) { + switch (str[i]) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + j->serial += (str[i] - 48) * place; + break; + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + j->serial += (str[i] - 55) * place; + break; + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + j->serial += (str[i] - 87) * place; + break; + } + place = place * 0x10; + } + str = str + strlen(str) + 1; + printk(" version %s\n", str); + cs_failed: + return; +} + +void ixj_config(dev_link_t * link) +{ + client_handle_t handle; + ixj_info_t *info; + tuple_t tuple; + u_short buf[128]; + cisparse_t parse; + config_info_t conf; + cistpl_cftable_entry_t *cfg = &parse.cftable_entry; + cistpl_cftable_entry_t dflt = + { + 0 + }; + int last_ret, last_fn; + handle = link->handle; + info = link->priv; + DEBUG(0, "ixj_config(0x%p)\n", link); + tuple.TupleData = (cisdata_t *) buf; + tuple.TupleOffset = 0; + tuple.TupleDataMax = 255; + tuple.Attributes = 0; + tuple.DesiredTuple = CISTPL_CONFIG; + CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(GetTupleData, handle, &tuple); + CS_CHECK(ParseTuple, handle, &tuple, &parse); + link->conf.ConfigBase = parse.config.base; + link->conf.Present = parse.config.rmask[0]; + link->state |= DEV_CONFIG; + CS_CHECK(GetConfigurationInfo, handle, &conf); + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + tuple.Attributes = 0; + CS_CHECK(GetFirstTuple, handle, &tuple); + while (1) { + CFG_CHECK(GetTupleData, handle, &tuple); + CFG_CHECK(ParseTuple, handle, &tuple, &parse); + if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { + cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; + link->conf.ConfigIndex = cfg->index; + link->io.BasePort1 = io->win[0].base; + link->io.NumPorts1 = io->win[0].len; + if (io->nwin == 2) { + link->io.BasePort2 = io->win[1].base; + link->io.NumPorts2 = io->win[1].len; + } + CFG_CHECK(RequestIO, link->handle, &link->io); + /* If we've got this far, we're done */ + break; + } + next_entry: + if (cfg->flags & CISTPL_CFTABLE_DEFAULT) + dflt = *cfg; + CS_CHECK(GetNextTuple, handle, &tuple); + } + + CS_CHECK(RequestConfiguration, handle, &link->conf); + ixj[0].DSPbase = link->io.BasePort1; + ixj[0].XILINXbase = link->io.BasePort1 + 0x10; + ixj[0].cardtype = 600; + ixj_selfprobe(0); + info->ndev = 1; + info->node.major = PHONE_MAJOR; + link->dev = &info->node; + ixj_get_serial(link, &ixj[0]); + link->state &= ~DEV_CONFIG_PENDING; + return; + cs_failed: + cs_error(link->handle, last_fn, last_ret); + ixj_cs_release((u_long) link); +} + +void ixj_cs_release(u_long arg) +{ + dev_link_t *link = (dev_link_t *) arg; + ixj_info_t *info = link->priv; + DEBUG(0, "ixj_cs_release(0x%p)\n", link); + info->ndev = 0; + link->dev = NULL; + CardServices(ReleaseConfiguration, link->handle); + CardServices(ReleaseIO, link->handle, &link->io); + link->state &= ~DEV_CONFIG; +} + +int ixj_event(event_t event, int priority, event_callback_args_t * args) +{ + dev_link_t *link = args->client_data; + DEBUG(1, "ixj_event(0x%06x)\n", event); + switch (event) { + case CS_EVENT_CARD_REMOVAL: + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) { + link->release.expires = RUN_AT(HZ / 20); + link->state |= DEV_RELEASE_PENDING; + add_timer(&link->release); + } + break; + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + ixj_config(link); + break; + case CS_EVENT_PM_SUSPEND: + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + if (link->state & DEV_CONFIG) + CardServices(ReleaseConfiguration, link->handle); + break; + case CS_EVENT_PM_RESUME: + link->state &= ~DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_CARD_RESET: + if (DEV_OK(link)) + CardServices(RequestConfiguration, link->handle, &link->conf); + break; + } return 0; } +#endif // PCMCIA + static void cleanup(void) { int cnt; - del_timer(&ixj_timer); -// if (ixj_major) - // unregister_chrdev(ixj_major, "ixj"); for (cnt = 0; cnt < IXJMAX; cnt++) { if (ixj[cnt].cardtype == 300) { ixj[cnt].pld_scrw.bits.daafsyncen = 0; // Turn off DAA Frame Sync @@ -4382,7 +6082,6 @@ ixj[cnt].pld_slicw.bits.rly3 = 0; outb_p(ixj[cnt].pld_slicw.byte, ixj[cnt].XILINXbase + 0x01); LED_SetState(0x0, cnt); - release_region(ixj[cnt].XILINXbase, 8); } if (ixj[cnt].cardtype == 400 || ixj[cnt].cardtype == 500) { @@ -4400,16 +6099,22 @@ if (ixj[cnt].dev) ixj[cnt].dev->deactivate(ixj[cnt].dev); #endif +#ifdef CONFIG_PCMCIA + DEBUG(0, "ixj_cs: unloading\n"); + unregister_pcmcia_driver(&dev_info); + while (dev_list != NULL) + ixj_detach(dev_list); +#endif } + remove_proc_entry ("ixj", NULL); + remove_proc_entry ("ixjfsk", NULL); } - // Typedefs typedef struct { BYTE length; DWORD bits; } DATABLOCK; - static void PCIEE_WriteBit(WORD wEEPROMAddress, BYTE lastLCC, BYTE byData) { lastLCC = lastLCC & 0xfb; @@ -4422,7 +6127,6 @@ byData = byData << 1; lastLCC = lastLCC & 0xfe; - udelay(1000); outb(lastLCC, wEEPROMAddress); //after delay, SK falling edge @@ -4447,11 +6151,8 @@ WORD wEEPROMAddress = wAddress + 3; DWORD i; BYTE byResult; - *pwResult = 0; - lastLCC = inb(wEEPROMAddress); - lastLCC = lastLCC | 0x02; lastLCC = lastLCC & 0xfe; outb(lastLCC, wEEPROMAddress); // CS hi, SK lo @@ -4461,7 +6162,6 @@ PCIEE_WriteBit(wEEPROMAddress, lastLCC, 1); PCIEE_WriteBit(wEEPROMAddress, lastLCC, 1); PCIEE_WriteBit(wEEPROMAddress, lastLCC, 0); - for (i = 0; i < 8; i++) { PCIEE_WriteBit(wEEPROMAddress, lastLCC, wLoc & 0x80 ? 1 : 0); wLoc <<= 1; @@ -4483,45 +6183,58 @@ static DWORD PCIEE_GetSerialNumber(WORD wAddress) { WORD wLo, wHi; - if (PCIEE_ReadWord(wAddress, 62, &wLo)) return 0; - if (PCIEE_ReadWord(wAddress, 63, &wHi)) return 0; - return (((DWORD) wHi << 16) | wLo); } -static int dspio[IXJMAX + 1] = {0,}; -static int xio[IXJMAX + 1] = {0,}; - -MODULE_DESCRIPTION("Internet PhoneJACK/Internet LineJACK module - www.quicknet.net"); -MODULE_AUTHOR("Ed Okerson "); +#ifndef CONFIG_PCMCIA +#ifndef CONFIG_ISAPNP +static int dspio[IXJMAX + 1] = +{ + 0, +}; +static int xio[IXJMAX + 1] = +{ + 0, +}; MODULE_PARM(dspio, "1-" __MODULE_STRING(IXJMAX) "i"); MODULE_PARM(xio, "1-" __MODULE_STRING(IXJMAX) "i"); +#endif +#endif -#ifdef MODULE - -void cleanup_module(void) +void ixj_exit(void) { cleanup(); } -int init_module(void) -#else int __init ixj_init(void) -#endif { int result; - - int func = 0x110, i = 0; + int i = 0; int cnt = 0; int probe = 0; +#ifdef CONFIG_ISAPNP + int func = 0x110; struct pci_dev *dev = NULL, *old_dev = NULL; +#endif +#ifdef CONFIG_PCI struct pci_dev *pci = NULL; - +#endif +#ifdef CONFIG_PCMCIA + servinfo_t serv; + DEBUG(0, "%s\n", version); + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_NOTICE "ixj_cs: Card Services release does not match!\n"); + return -1; + } + register_pcmcia_driver(&dev_info, &ixj_attach, &ixj_detach); + probe = 0; +#else #ifdef CONFIG_ISAPNP while (1) { do { @@ -4530,7 +6243,6 @@ ISAPNP_FUNCTION(func), old_dev); if (!dev) break; - printk("preparing %x\n", func); result = dev->prepare(dev); if (result < 0) { printk("preparing failed %d \n", result); @@ -4548,7 +6260,6 @@ ixj[cnt].DSPbase = dev->resource[0].start; /* get real port */ if (func != 0x110) ixj[cnt].XILINXbase = dev->resource[1].start; /* get real port */ - result = check_region(ixj[cnt].DSPbase, 16); if (result) { printk(KERN_INFO "ixj: can't get I/O address 0x%x\n", ixj[cnt].DSPbase); @@ -4568,13 +6279,21 @@ break; } probe = ixj_selfprobe(cnt); - ixj[cnt].serial = dev->bus->serial; ixj[cnt].dev = dev; - printk(KERN_INFO "ixj: found card at 0x%x\n", ixj[cnt].DSPbase); + switch (func) { + case 0x110: + printk(KERN_INFO "ixj: found Internet PhoneJACK at 0x%x\n", ixj[cnt].DSPbase); + break; + case 0x310: + printk(KERN_INFO "ixj: found Internet LineJACK at 0x%x\n", ixj[cnt].DSPbase); + break; + case 0x410: + printk(KERN_INFO "ixj: found Internet PhoneJACK Lite at 0x%x\n", ixj[cnt].DSPbase); + break; + } cnt++; } while (dev); - if (func == 0x410) break; if (func == 0x310) @@ -4585,11 +6304,10 @@ } #else //CONFIG_ISAPNP /* Use passed parameters for older kernels without PnP */ - - for (cnt = 0; cnt < IXJMAX; cnt++) { - if (dspio[cnt]) { - ixj[cnt].DSPbase = dspio[cnt]; - ixj[cnt].XILINXbase = xio[cnt]; + for (i = 0; i < IXJMAX; i++) { + if (dspio[i]) { + ixj[cnt].DSPbase = dspio[i]; + ixj[cnt].XILINXbase = xio[i]; ixj[cnt].cardtype = 0; result = check_region(ixj[cnt].DSPbase, 16); if (result) { @@ -4600,9 +6318,11 @@ request_region(ixj[cnt].DSPbase, 16, "ixj DSP"); probe = ixj_selfprobe(cnt); ixj[cnt].dev = NULL; + cnt++; } } -#endif +#endif // !CONFIG_ISAPNP +#endif // CONFIG_PCMCIA #ifdef CONFIG_PCI if (pci_present()) { for (i = 0; i < IXJMAX - cnt; i++) { @@ -4615,7 +6335,6 @@ ixj[cnt].DSPbase = pci_resource_start(pci, 0); ixj[cnt].XILINXbase = ixj[cnt].DSPbase + 0x10; ixj[cnt].serial = (PCIEE_GetSerialNumber)pci_resource_start(pci, 2); - result = check_region(ixj[cnt].DSPbase, 16); if (result) { printk(KERN_INFO "ixj: can't get I/O address 0x%x\n", ixj[cnt].DSPbase); @@ -4625,32 +6344,38 @@ request_region(ixj[cnt].DSPbase, 16, "ixj DSP"); ixj[cnt].cardtype = 500; probe = ixj_selfprobe(cnt); + if (probe) + printk(KERN_INFO "ixj: found Internet PhoneJACK PCI at 0x%x\n", ixj[cnt].DSPbase); cnt++; } } } #endif printk("%s\n", ixj_c_rcsid); - + create_proc_read_entry ("ixj", 0, NULL, ixj_read_proc, NULL); + create_proc_read_entry ("ixjfsk", 0, NULL, ixj_read_proc_fsk, NULL); ixj_init_timer(); - ixj_add_timer(); + ixj_add_timer(); return probe; } +module_init(ixj_init); +module_exit(ixj_exit); + static void DAA_Coeff_US(int board) { IXJ *j = &ixj[board]; - int i; + j->daa_country = DAA_US; //----------------------------------------------- // CAO for (i = 0; i < ALISDAA_CALLERID_SIZE; i++) { j->m_DAAShadowRegs.CAO_REGS.CAO.CallerID[i] = 0; } - // Bytes for IM-filter part 1 (04): 0E,32,E2,2F,C2,5A,C0,00 - j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[7] = 0x0E; +// Bytes for IM-filter part 1 (04): 0E,32,E2,2F,C2,5A,C0,00 + j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[7] = 0x0E; j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[6] = 0x32; j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[5] = 0xE2; j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[4] = 0x2F; @@ -4658,7 +6383,6 @@ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[2] = 0x5A; j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[1] = 0xC0; j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[0] = 0x00; - // Bytes for IM-filter part 2 (05): 72,85,00,0E,2B,3A,D0,08 j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[7] = 0x72; j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[6] = 0x85; @@ -4668,7 +6392,6 @@ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[2] = 0x3A; j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[1] = 0xD0; j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[0] = 0x08; - // Bytes for FRX-filter (08): 03,8F,48,F2,8F,48,70,08 j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[7] = 0x03; j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[6] = 0x8F; @@ -4678,7 +6401,6 @@ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[2] = 0x48; j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[1] = 0x70; j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[0] = 0x08; - // Bytes for FRR-filter (07): 04,8F,38,7F,9B,EA,B0,08 j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[7] = 0x04; j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[6] = 0x8F; @@ -4688,19 +6410,16 @@ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[2] = 0xEA; j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[1] = 0xB0; j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[0] = 0x08; - // Bytes for AX-filter (0A): 16,55,DD,CA j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[3] = 0x16; j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[2] = 0x55; j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[1] = 0xDD; j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[0] = 0xCA; - // Bytes for AR-filter (09): 52,D3,11,42 j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[3] = 0x52; j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[2] = 0xD3; j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[1] = 0x11; j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[0] = 0x42; - // Bytes for TH-filter part 1 (00): 00,42,48,81,B3,80,00,98 j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[7] = 0x00; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[6] = 0x42; @@ -4710,7 +6429,6 @@ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[2] = 0x80; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[1] = 0x00; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[0] = 0x98; - // Bytes for TH-filter part 2 (01): 02,F2,33,A0,68,AB,8A,AD j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[7] = 0x02; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[6] = 0xF2; @@ -4720,7 +6438,6 @@ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[2] = 0xAB; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[1] = 0x8A; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[0] = 0xAD; - // Bytes for TH-filter part 3 (02): 00,88,DA,54,A4,BA,2D,BB j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[7] = 0x00; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[6] = 0x88; @@ -4730,7 +6447,6 @@ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[2] = 0xBA; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[1] = 0x2D; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[0] = 0xBB; - // ; (10K, 0.68uF) // // Bytes for Ringing part 1 (03):1B,3B,9B,BA,D4,1C,B3,23 @@ -4742,7 +6458,6 @@ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[2] = 0x1C; j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[1] = 0xB3; j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[0] = 0x23; - // Bytes for Ringing part 2 (06):13,42,A6,BA,D4,73,CA,D5 j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[7] = 0x13; j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[6] = 0x42; @@ -4752,14 +6467,12 @@ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[2] = 0x73; j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[1] = 0xCA; j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[0] = 0xD5; - // // Levelmetering Ringing (0D):B2,45,0F,8E j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[3] = 0xB2; j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[2] = 0x45; j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[1] = 0x0F; j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[0] = 0x8E; - // Caller ID 1st Tone (0E):CA,0E,CA,09,99,99,99,99 j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[7] = 0xCA; j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[6] = 0x0E; @@ -4769,7 +6482,6 @@ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[2] = 0x99; j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[1] = 0x99; j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[0] = 0x99; - // Caller ID 2nd Tone (0F):FD,B5,BA,07,DA,00,00,00 j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[7] = 0xFD; j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[6] = 0xB5; @@ -4779,64 +6491,52 @@ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[2] = 0x00; j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[1] = 0x00; j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[0] = 0x00; - // // ;CR Registers // Config. Reg. 0 (filters) (cr0):FE ; CLK gen. by crystal - j->m_DAAShadowRegs.SOP_REGS.SOP.cr0.reg = 0xFE; - + j->m_DAAShadowRegs.SOP_REGS.SOP.cr0.reg = 0xFF; // Config. Reg. 1 (dialing) (cr1):05 j->m_DAAShadowRegs.SOP_REGS.SOP.cr1.reg = 0x05; - // Config. Reg. 2 (caller ID) (cr2):04 j->m_DAAShadowRegs.SOP_REGS.SOP.cr2.reg = 0x04; - // Config. Reg. 3 (testloops) (cr3):03 ; SEL Bit==0, HP-disabled j->m_DAAShadowRegs.SOP_REGS.SOP.cr3.reg = 0x03; - // Config. Reg. 4 (analog gain) (cr4):01 j->m_DAAShadowRegs.SOP_REGS.SOP.cr4.reg = 0x02; //0x01; - -// Config. Reg. 5 (Version) (cr5):02 + // Config. Reg. 5 (Version) (cr5):02 // Config. Reg. 6 (Reserved) (cr6):00 // Config. Reg. 7 (Reserved) (cr7):00 // - -// ;xr Registers + // ;xr Registers // Ext. Reg. 0 (Interrupt Reg.) (xr0):02 + j->m_DAAShadowRegs.XOP_xr0_W.reg = 0x02; // SO_1 set to '1' because it is inverted. + // Ext. Reg. 1 (Interrupt enable) (xr1):1C // Cadence, RING, Caller ID, VDD_OK -// Ext. Reg. 1 (Interrupt enable) (xr1):1C // Cadence, RING, Caller ID, VDD_OK j->m_DAAShadowRegs.XOP_REGS.XOP.xr1.reg = 0x3C; - // Ext. Reg. 2 (Cadence Time Out) (xr2):7D j->m_DAAShadowRegs.XOP_REGS.XOP.xr2.reg = 0x7D; - // Ext. Reg. 3 (DC Char) (xr3):32 ; B-Filter Off == 1 j->m_DAAShadowRegs.XOP_REGS.XOP.xr3.reg = 0x12; //0x32; + // Ext. Reg. 4 (Cadence) (xr4):00 -// Ext. Reg. 4 (Cadence) (xr4):00 j->m_DAAShadowRegs.XOP_REGS.XOP.xr4.reg = 0x00; - // Ext. Reg. 5 (Ring timer) (xr5):22 j->m_DAAShadowRegs.XOP_REGS.XOP.xr5.reg = 0x22; - // Ext. Reg. 6 (Power State) (xr6):00 j->m_DAAShadowRegs.XOP_xr6_W.reg = 0x00; - // Ext. Reg. 7 (Vdd) (xr7):40 j->m_DAAShadowRegs.XOP_REGS.XOP.xr7.reg = 0x40; // 0x40 ??? Should it be 0x00? - -// + // // DTMF Tone 1 (0B): 11,B3,5A,2C ; 697 Hz // 12,33,5A,C3 ; 770 Hz // 13,3C,5B,32 ; 852 Hz // 1D,1B,5C,CC ; 941 Hz + j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[3] = 0x11; j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[2] = 0xB3; j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[1] = 0x5A; j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[0] = 0x2C; - // DTMF Tone 2 (0C): 32,32,52,B3 ; 1209 Hz // EC,1D,52,22 ; 1336 Hz // AA,AC,51,D2 ; 1477 Hz @@ -4845,23 +6545,22 @@ j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[2] = 0x32; j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[1] = 0x52; j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[0] = 0xB3; - } static void DAA_Coeff_UK(int board) { IXJ *j = &ixj[board]; - int i; + j->daa_country = DAA_UK; //----------------------------------------------- // CAO for (i = 0; i < ALISDAA_CALLERID_SIZE; i++) { j->m_DAAShadowRegs.CAO_REGS.CAO.CallerID[i] = 0; } - // Bytes for IM-filter part 1 (04): 00,C2,BB,A8,CB,81,A0,00 - j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[7] = 0x00; +// Bytes for IM-filter part 1 (04): 00,C2,BB,A8,CB,81,A0,00 + j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[7] = 0x00; j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[6] = 0xC2; j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[5] = 0xBB; j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[4] = 0xA8; @@ -4869,8 +6568,7 @@ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[2] = 0x81; j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[1] = 0xA0; j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[0] = 0x00; - - // Bytes for IM-filter part 2 (05): 40,00,00,0A,A4,33,E0,08 +// Bytes for IM-filter part 2 (05): 40,00,00,0A,A4,33,E0,08 j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[7] = 0x40; j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[6] = 0x00; j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[5] = 0x00; @@ -4879,7 +6577,6 @@ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[2] = 0x33; j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[1] = 0xE0; j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[0] = 0x08; - // Bytes for FRX-filter (08): 07,9B,ED,24,B2,A2,A0,08 j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[7] = 0x07; j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[6] = 0x9B; @@ -4889,7 +6586,6 @@ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[2] = 0xA2; j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[1] = 0xA0; j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[0] = 0x08; - // Bytes for FRR-filter (07): 0F,92,F2,B2,87,D2,30,08 j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[7] = 0x0F; j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[6] = 0x92; @@ -4899,19 +6595,16 @@ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[2] = 0xD2; j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[1] = 0x30; j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[0] = 0x08; - // Bytes for AX-filter (0A): 1B,A5,DD,CA j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[3] = 0x1B; j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[2] = 0xA5; j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[1] = 0xDD; j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[0] = 0xCA; - // Bytes for AR-filter (09): E2,27,10,D6 j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[3] = 0xE2; j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[2] = 0x27; j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[1] = 0x10; j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[0] = 0xD6; - // Bytes for TH-filter part 1 (00): 80,2D,38,8B,D0,00,00,98 j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[7] = 0x80; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[6] = 0x2D; @@ -4921,7 +6614,6 @@ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[2] = 0x00; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[1] = 0x00; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[0] = 0x98; - // Bytes for TH-filter part 2 (01): 02,5A,53,F0,0B,5F,84,D4 j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[7] = 0x02; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[6] = 0x5A; @@ -4931,7 +6623,6 @@ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[2] = 0x5F; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[1] = 0x84; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[0] = 0xD4; - // Bytes for TH-filter part 3 (02): 00,88,6A,A4,8F,52,F5,32 j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[7] = 0x00; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[6] = 0x88; @@ -4941,10 +6632,8 @@ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[2] = 0x52; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[1] = 0xF5; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[0] = 0x32; - // ; idle - -// Bytes for Ringing part 1 (03):1B,3C,93,3A,22,12,A3,23 + // Bytes for Ringing part 1 (03):1B,3C,93,3A,22,12,A3,23 j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[7] = 0x1B; j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[6] = 0x3C; j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[5] = 0x93; @@ -4953,7 +6642,6 @@ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[2] = 0x12; j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[1] = 0xA3; j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[0] = 0x23; - // Bytes for Ringing part 2 (06):12,A2,A6,BA,22,7A,0A,D5 j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[7] = 0x12; j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[6] = 0xA2; @@ -4963,13 +6651,11 @@ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[2] = 0x7A; j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[1] = 0x0A; j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[0] = 0xD5; - // Levelmetering Ringing (0D):AA,35,0F,8E ; 25Hz 30V less possible? j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[3] = 0xAA; j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[2] = 0x35; j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[1] = 0x0F; j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[0] = 0x8E; - // Caller ID 1st Tone (0E):CA,0E,CA,09,99,99,99,99 j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[7] = 0xCA; j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[6] = 0x0E; @@ -4979,7 +6665,6 @@ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[2] = 0x99; j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[1] = 0x99; j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[0] = 0x99; - // Caller ID 2nd Tone (0F):FD,B5,BA,07,DA,00,00,00 j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[7] = 0xFD; j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[6] = 0xB5; @@ -4989,61 +6674,49 @@ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[2] = 0x00; j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[1] = 0x00; j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[0] = 0x00; - // ;CR Registers // Config. Reg. 0 (filters) (cr0):FF - j->m_DAAShadowRegs.SOP_REGS.SOP.cr0.reg = 0xFF; //0xFE; - + j->m_DAAShadowRegs.SOP_REGS.SOP.cr0.reg = 0xFE; // Config. Reg. 1 (dialing) (cr1):05 j->m_DAAShadowRegs.SOP_REGS.SOP.cr1.reg = 0x05; - // Config. Reg. 2 (caller ID) (cr2):04 j->m_DAAShadowRegs.SOP_REGS.SOP.cr2.reg = 0x04; - // Config. Reg. 3 (testloops) (cr3):00 ; j->m_DAAShadowRegs.SOP_REGS.SOP.cr3.reg = 0x00; - // Config. Reg. 4 (analog gain) (cr4):01 j->m_DAAShadowRegs.SOP_REGS.SOP.cr4.reg = 0x02; //0x01; - -// Config. Reg. 5 (Version) (cr5):02 + // Config. Reg. 5 (Version) (cr5):02 // Config. Reg. 6 (Reserved) (cr6):00 // Config. Reg. 7 (Reserved) (cr7):00 - -// ;xr Registers + // ;xr Registers // Ext. Reg. 0 (Interrupt Reg.) (xr0):02 + j->m_DAAShadowRegs.XOP_xr0_W.reg = 0x02; // SO_1 set to '1' because it is inverted. + // Ext. Reg. 1 (Interrupt enable) (xr1):1C -// Ext. Reg. 1 (Interrupt enable) (xr1):1C j->m_DAAShadowRegs.XOP_REGS.XOP.xr1.reg = 0x1C; // RING, Caller ID, VDD_OK + // Ext. Reg. 2 (Cadence Time Out) (xr2):7D -// Ext. Reg. 2 (Cadence Time Out) (xr2):7D j->m_DAAShadowRegs.XOP_REGS.XOP.xr2.reg = 0x7D; - // Ext. Reg. 3 (DC Char) (xr3):36 ; j->m_DAAShadowRegs.XOP_REGS.XOP.xr3.reg = 0x36; - // Ext. Reg. 4 (Cadence) (xr4):00 j->m_DAAShadowRegs.XOP_REGS.XOP.xr4.reg = 0x00; - // Ext. Reg. 5 (Ring timer) (xr5):22 j->m_DAAShadowRegs.XOP_REGS.XOP.xr5.reg = 0x22; - // Ext. Reg. 6 (Power State) (xr6):00 j->m_DAAShadowRegs.XOP_xr6_W.reg = 0x00; - // Ext. Reg. 7 (Vdd) (xr7):46 j->m_DAAShadowRegs.XOP_REGS.XOP.xr7.reg = 0x46; // 0x46 ??? Should it be 0x00? - -// DTMF Tone 1 (0B): 11,B3,5A,2C ; 697 Hz + // DTMF Tone 1 (0B): 11,B3,5A,2C ; 697 Hz // 12,33,5A,C3 ; 770 Hz // 13,3C,5B,32 ; 852 Hz // 1D,1B,5C,CC ; 941 Hz + j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[3] = 0x11; j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[2] = 0xB3; j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[1] = 0x5A; j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[0] = 0x2C; - // DTMF Tone 2 (0C): 32,32,52,B3 ; 1209 Hz // EC,1D,52,22 ; 1336 Hz // AA,AC,51,D2 ; 1477 Hz @@ -5052,24 +6725,23 @@ j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[2] = 0x32; j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[1] = 0x52; j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[0] = 0xB3; - } static void DAA_Coeff_France(int board) { IXJ *j = &ixj[board]; - int i; + j->daa_country = DAA_FRANCE; //----------------------------------------------- // CAO for (i = 0; i < ALISDAA_CALLERID_SIZE; i++) { j->m_DAAShadowRegs.CAO_REGS.CAO.CallerID[i] = 0; } - // Bytes for IM-filter part 1 (04): 02,A2,43,2C,22,AF,A0,00 - j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[7] = 0x02; +// Bytes for IM-filter part 1 (04): 02,A2,43,2C,22,AF,A0,00 + j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[7] = 0x02; j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[6] = 0xA2; j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[5] = 0x43; j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[4] = 0x2C; @@ -5077,7 +6749,6 @@ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[2] = 0xAF; j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[1] = 0xA0; j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[0] = 0x00; - // Bytes for IM-filter part 2 (05): 67,CE,00,0C,22,33,E0,08 j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[7] = 0x67; j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[6] = 0xCE; @@ -5087,7 +6758,6 @@ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[2] = 0x33; j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[1] = 0xE0; j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[0] = 0x08; - // Bytes for FRX-filter (08): 07,9A,28,F6,23,4A,B0,08 j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[7] = 0x07; j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[6] = 0x9A; @@ -5097,7 +6767,6 @@ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[2] = 0x4A; j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[1] = 0xB0; j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[0] = 0x08; - // Bytes for FRR-filter (07): 03,8F,F9,2F,9E,FA,20,08 j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[7] = 0x03; j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[6] = 0x8F; @@ -5107,19 +6776,16 @@ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[2] = 0xFA; j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[1] = 0x20; j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[0] = 0x08; - // Bytes for AX-filter (0A): 16,B5,DD,CA j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[3] = 0x16; j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[2] = 0xB5; j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[1] = 0xDD; j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[0] = 0xCA; - // Bytes for AR-filter (09): 52,C7,10,D6 j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[3] = 0xE2; j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[2] = 0xC7; j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[1] = 0x10; j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[0] = 0xD6; - // Bytes for TH-filter part 1 (00): 00,42,48,81,A6,80,00,98 j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[7] = 0x00; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[6] = 0x42; @@ -5129,7 +6795,6 @@ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[2] = 0x80; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[1] = 0x00; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[0] = 0x98; - // Bytes for TH-filter part 2 (01): 02,AC,2A,30,78,AC,8A,2C j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[7] = 0x02; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[6] = 0xAC; @@ -5139,7 +6804,6 @@ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[2] = 0xAC; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[1] = 0x8A; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[0] = 0x2C; - // Bytes for TH-filter part 3 (02): 00,88,DA,A5,22,BA,2C,45 j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[7] = 0x00; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[6] = 0x88; @@ -5149,10 +6813,8 @@ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[2] = 0xBA; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[1] = 0x2C; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[0] = 0x45; - // ; idle - -// Bytes for Ringing part 1 (03):1B,3C,93,3A,22,12,A3,23 + // Bytes for Ringing part 1 (03):1B,3C,93,3A,22,12,A3,23 j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[7] = 0x1B; j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[6] = 0x3C; j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[5] = 0x93; @@ -5161,7 +6823,6 @@ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[2] = 0x12; j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[1] = 0xA3; j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[0] = 0x23; - // Bytes for Ringing part 2 (06):12,A2,A6,BA,22,7A,0A,D5 j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[7] = 0x12; j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[6] = 0xA2; @@ -5171,13 +6832,11 @@ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[2] = 0x7A; j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[1] = 0x0A; j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[0] = 0xD5; - // Levelmetering Ringing (0D):32,45,B5,84 ; 50Hz 20V j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[3] = 0x32; j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[2] = 0x45; j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[1] = 0xB5; j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[0] = 0x84; - // Caller ID 1st Tone (0E):CA,0E,CA,09,99,99,99,99 j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[7] = 0xCA; j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[6] = 0x0E; @@ -5187,7 +6846,6 @@ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[2] = 0x99; j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[1] = 0x99; j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[0] = 0x99; - // Caller ID 2nd Tone (0F):FD,B5,BA,07,DA,00,00,00 j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[7] = 0xFD; j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[6] = 0xB5; @@ -5197,61 +6855,49 @@ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[2] = 0x00; j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[1] = 0x00; j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[0] = 0x00; - // ;CR Registers // Config. Reg. 0 (filters) (cr0):FF - j->m_DAAShadowRegs.SOP_REGS.SOP.cr0.reg = 0xFF; - + j->m_DAAShadowRegs.SOP_REGS.SOP.cr0.reg = 0xFE; // Config. Reg. 1 (dialing) (cr1):05 j->m_DAAShadowRegs.SOP_REGS.SOP.cr1.reg = 0x05; - // Config. Reg. 2 (caller ID) (cr2):04 j->m_DAAShadowRegs.SOP_REGS.SOP.cr2.reg = 0x04; - // Config. Reg. 3 (testloops) (cr3):00 ; j->m_DAAShadowRegs.SOP_REGS.SOP.cr3.reg = 0x00; - // Config. Reg. 4 (analog gain) (cr4):01 j->m_DAAShadowRegs.SOP_REGS.SOP.cr4.reg = 0x02; //0x01; - -// Config. Reg. 5 (Version) (cr5):02 + // Config. Reg. 5 (Version) (cr5):02 // Config. Reg. 6 (Reserved) (cr6):00 // Config. Reg. 7 (Reserved) (cr7):00 - -// ;xr Registers + // ;xr Registers // Ext. Reg. 0 (Interrupt Reg.) (xr0):02 + j->m_DAAShadowRegs.XOP_xr0_W.reg = 0x02; // SO_1 set to '1' because it is inverted. + // Ext. Reg. 1 (Interrupt enable) (xr1):1C -// Ext. Reg. 1 (Interrupt enable) (xr1):1C j->m_DAAShadowRegs.XOP_REGS.XOP.xr1.reg = 0x1C; // RING, Caller ID, VDD_OK + // Ext. Reg. 2 (Cadence Time Out) (xr2):7D -// Ext. Reg. 2 (Cadence Time Out) (xr2):7D j->m_DAAShadowRegs.XOP_REGS.XOP.xr2.reg = 0x7D; - // Ext. Reg. 3 (DC Char) (xr3):36 ; j->m_DAAShadowRegs.XOP_REGS.XOP.xr3.reg = 0x36; - // Ext. Reg. 4 (Cadence) (xr4):00 j->m_DAAShadowRegs.XOP_REGS.XOP.xr4.reg = 0x00; - // Ext. Reg. 5 (Ring timer) (xr5):22 j->m_DAAShadowRegs.XOP_REGS.XOP.xr5.reg = 0x22; - // Ext. Reg. 6 (Power State) (xr6):00 j->m_DAAShadowRegs.XOP_xr6_W.reg = 0x00; - // Ext. Reg. 7 (Vdd) (xr7):46 j->m_DAAShadowRegs.XOP_REGS.XOP.xr7.reg = 0x46; // 0x46 ??? Should it be 0x00? - -// DTMF Tone 1 (0B): 11,B3,5A,2C ; 697 Hz + // DTMF Tone 1 (0B): 11,B3,5A,2C ; 697 Hz // 12,33,5A,C3 ; 770 Hz // 13,3C,5B,32 ; 852 Hz // 1D,1B,5C,CC ; 941 Hz + j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[3] = 0x11; j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[2] = 0xB3; j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[1] = 0x5A; j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[0] = 0x2C; - // DTMF Tone 2 (0C): 32,32,52,B3 ; 1209 Hz // EC,1D,52,22 ; 1336 Hz // AA,AC,51,D2 ; 1477 Hz @@ -5260,24 +6906,23 @@ j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[2] = 0x32; j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[1] = 0x52; j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[0] = 0xB3; - } static void DAA_Coeff_Germany(int board) { IXJ *j = &ixj[board]; - int i; + j->daa_country = DAA_GERMANY; //----------------------------------------------- // CAO for (i = 0; i < ALISDAA_CALLERID_SIZE; i++) { j->m_DAAShadowRegs.CAO_REGS.CAO.CallerID[i] = 0; } - // Bytes for IM-filter part 1 (04): 00,CE,BB,B8,D2,81,B0,00 - j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[7] = 0x00; +// Bytes for IM-filter part 1 (04): 00,CE,BB,B8,D2,81,B0,00 + j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[7] = 0x00; j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[6] = 0xCE; j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[5] = 0xBB; j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[4] = 0xB8; @@ -5285,7 +6930,6 @@ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[2] = 0x81; j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[1] = 0xB0; j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[0] = 0x00; - // Bytes for IM-filter part 2 (05): 45,8F,00,0C,D2,3A,D0,08 j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[7] = 0x45; j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[6] = 0x8F; @@ -5295,7 +6939,6 @@ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[2] = 0x3A; j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[1] = 0xD0; j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[0] = 0x08; - // Bytes for FRX-filter (08): 07,AA,E2,34,24,89,20,08 j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[7] = 0x07; j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[6] = 0xAA; @@ -5305,7 +6948,6 @@ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[2] = 0x89; j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[1] = 0x20; j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[0] = 0x08; - // Bytes for FRR-filter (07): 02,87,FA,37,9A,CA,B0,08 j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[7] = 0x02; j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[6] = 0x87; @@ -5315,19 +6957,16 @@ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[2] = 0xCA; j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[1] = 0xB0; j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[0] = 0x08; - // Bytes for AX-filter (0A): 72,D5,DD,CA j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[3] = 0x72; j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[2] = 0xD5; j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[1] = 0xDD; j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[0] = 0xCA; - // Bytes for AR-filter (09): 72,42,13,4B j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[3] = 0x72; j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[2] = 0x42; j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[1] = 0x13; j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[0] = 0x4B; - // Bytes for TH-filter part 1 (00): 80,52,48,81,AD,80,00,98 j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[7] = 0x80; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[6] = 0x52; @@ -5337,7 +6976,6 @@ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[2] = 0x80; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[1] = 0x00; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[0] = 0x98; - // Bytes for TH-filter part 2 (01): 02,42,5A,20,E8,1A,81,27 j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[7] = 0x02; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[6] = 0x42; @@ -5347,7 +6985,6 @@ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[2] = 0x1A; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[1] = 0x81; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[0] = 0x27; - // Bytes for TH-filter part 3 (02): 00,88,63,26,BD,4B,A3,C2 j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[7] = 0x00; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[6] = 0x88; @@ -5357,10 +6994,8 @@ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[2] = 0x4B; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[1] = 0xA3; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[0] = 0xC2; - // ; (10K, 0.68uF) - -// Bytes for Ringing part 1 (03):1B,3B,9B,BA,D4,1C,B3,23 + // Bytes for Ringing part 1 (03):1B,3B,9B,BA,D4,1C,B3,23 j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[7] = 0x1B; j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[6] = 0x3B; j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[5] = 0x9B; @@ -5369,7 +7004,6 @@ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[2] = 0x1C; j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[1] = 0xB3; j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[0] = 0x23; - // Bytes for Ringing part 2 (06):13,42,A6,BA,D4,73,CA,D5 j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[7] = 0x13; j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[6] = 0x42; @@ -5379,13 +7013,11 @@ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[2] = 0x73; j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[1] = 0xCA; j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[0] = 0xD5; - // Levelmetering Ringing (0D):B2,45,0F,8E j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[3] = 0xB2; j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[2] = 0x45; j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[1] = 0x0F; j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[0] = 0x8E; - // Caller ID 1st Tone (0E):CA,0E,CA,09,99,99,99,99 j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[7] = 0xCA; j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[6] = 0x0E; @@ -5395,7 +7027,6 @@ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[2] = 0x99; j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[1] = 0x99; j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[0] = 0x99; - // Caller ID 2nd Tone (0F):FD,B5,BA,07,DA,00,00,00 j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[7] = 0xFD; j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[6] = 0xB5; @@ -5405,61 +7036,49 @@ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[2] = 0x00; j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[1] = 0x00; j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[0] = 0x00; - // ;CR Registers // Config. Reg. 0 (filters) (cr0):FF ; all Filters enabled, CLK from ext. source - j->m_DAAShadowRegs.SOP_REGS.SOP.cr0.reg = 0xFF; - + j->m_DAAShadowRegs.SOP_REGS.SOP.cr0.reg = 0xFE; // Config. Reg. 1 (dialing) (cr1):05 ; Manual Ring, Ring metering enabled j->m_DAAShadowRegs.SOP_REGS.SOP.cr1.reg = 0x05; - // Config. Reg. 2 (caller ID) (cr2):04 ; Analog Gain 0dB, FSC internal j->m_DAAShadowRegs.SOP_REGS.SOP.cr2.reg = 0x04; - // Config. Reg. 3 (testloops) (cr3):00 ; SEL Bit==0, HP-enabled j->m_DAAShadowRegs.SOP_REGS.SOP.cr3.reg = 0x00; - // Config. Reg. 4 (analog gain) (cr4):01 j->m_DAAShadowRegs.SOP_REGS.SOP.cr4.reg = 0x02; //0x01; - -// Config. Reg. 5 (Version) (cr5):02 + // Config. Reg. 5 (Version) (cr5):02 // Config. Reg. 6 (Reserved) (cr6):00 // Config. Reg. 7 (Reserved) (cr7):00 - -// ;xr Registers + // ;xr Registers // Ext. Reg. 0 (Interrupt Reg.) (xr0):02 + j->m_DAAShadowRegs.XOP_xr0_W.reg = 0x02; // SO_1 set to '1' because it is inverted. + // Ext. Reg. 1 (Interrupt enable) (xr1):1C ; Ring, CID, VDDOK Interrupts enabled -// Ext. Reg. 1 (Interrupt enable) (xr1):1C ; Ring, CID, VDDOK Interrupts enabled j->m_DAAShadowRegs.XOP_REGS.XOP.xr1.reg = 0x1C; // RING, Caller ID, VDD_OK + // Ext. Reg. 2 (Cadence Time Out) (xr2):7D -// Ext. Reg. 2 (Cadence Time Out) (xr2):7D j->m_DAAShadowRegs.XOP_REGS.XOP.xr2.reg = 0x7D; - // Ext. Reg. 3 (DC Char) (xr3):32 ; B-Filter Off==1, U0=3.5V, R=200Ohm j->m_DAAShadowRegs.XOP_REGS.XOP.xr3.reg = 0x32; - // Ext. Reg. 4 (Cadence) (xr4):00 j->m_DAAShadowRegs.XOP_REGS.XOP.xr4.reg = 0x00; - // Ext. Reg. 5 (Ring timer) (xr5):22 j->m_DAAShadowRegs.XOP_REGS.XOP.xr5.reg = 0x22; - // Ext. Reg. 6 (Power State) (xr6):00 j->m_DAAShadowRegs.XOP_xr6_W.reg = 0x00; - // Ext. Reg. 7 (Vdd) (xr7):40 ; VDD=4.25 V j->m_DAAShadowRegs.XOP_REGS.XOP.xr7.reg = 0x40; // 0x40 ??? Should it be 0x00? - -// DTMF Tone 1 (0B): 11,B3,5A,2C ; 697 Hz + // DTMF Tone 1 (0B): 11,B3,5A,2C ; 697 Hz // 12,33,5A,C3 ; 770 Hz // 13,3C,5B,32 ; 852 Hz // 1D,1B,5C,CC ; 941 Hz + j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[3] = 0x11; j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[2] = 0xB3; j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[1] = 0x5A; j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[0] = 0x2C; - // DTMF Tone 2 (0C): 32,32,52,B3 ; 1209 Hz // EC,1D,52,22 ; 1336 Hz // AA,AC,51,D2 ; 1477 Hz @@ -5468,24 +7087,23 @@ j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[2] = 0x32; j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[1] = 0x52; j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[0] = 0xB3; - } static void DAA_Coeff_Australia(int board) { IXJ *j = &ixj[board]; - int i; + j->daa_country = DAA_AUSTRALIA; //----------------------------------------------- // CAO for (i = 0; i < ALISDAA_CALLERID_SIZE; i++) { j->m_DAAShadowRegs.CAO_REGS.CAO.CallerID[i] = 0; } - // Bytes for IM-filter part 1 (04): 00,A3,AA,28,B3,82,D0,00 - j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[7] = 0x00; +// Bytes for IM-filter part 1 (04): 00,A3,AA,28,B3,82,D0,00 + j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[7] = 0x00; j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[6] = 0xA3; j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[5] = 0xAA; j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[4] = 0x28; @@ -5493,7 +7111,6 @@ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[2] = 0x82; j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[1] = 0xD0; j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[0] = 0x00; - // Bytes for IM-filter part 2 (05): 70,96,00,09,32,6B,C0,08 j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[7] = 0x70; j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[6] = 0x96; @@ -5503,7 +7120,6 @@ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[2] = 0x6B; j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[1] = 0xC0; j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[0] = 0x08; - // Bytes for FRX-filter (08): 07,96,E2,34,32,9B,30,08 j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[7] = 0x07; j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[6] = 0x96; @@ -5513,7 +7129,6 @@ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[2] = 0x9B; j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[1] = 0x30; j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[0] = 0x08; - // Bytes for FRR-filter (07): 0F,9A,E9,2F,22,CC,A0,08 j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[7] = 0x0F; j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[6] = 0x9A; @@ -5523,19 +7138,16 @@ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[2] = 0xCC; j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[1] = 0xA0; j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[0] = 0x08; - // Bytes for AX-filter (0A): CB,45,DD,CA j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[3] = 0xCB; j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[2] = 0x45; j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[1] = 0xDD; j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[0] = 0xCA; - // Bytes for AR-filter (09): 1B,67,10,D6 j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[3] = 0x1B; j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[2] = 0x67; j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[1] = 0x10; j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[0] = 0xD6; - // Bytes for TH-filter part 1 (00): 80,52,48,81,AF,80,00,98 j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[7] = 0x80; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[6] = 0x52; @@ -5545,7 +7157,6 @@ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[2] = 0x80; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[1] = 0x00; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[0] = 0x98; - // Bytes for TH-filter part 2 (01): 02,DB,52,B0,38,01,82,AC j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[7] = 0x02; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[6] = 0xDB; @@ -5555,7 +7166,6 @@ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[2] = 0x01; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[1] = 0x82; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[0] = 0xAC; - // Bytes for TH-filter part 3 (02): 00,88,4A,3E,2C,3B,24,46 j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[7] = 0x00; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[6] = 0x88; @@ -5565,10 +7175,8 @@ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[2] = 0x3B; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[1] = 0x24; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[0] = 0x46; - // ; idle - -// Bytes for Ringing part 1 (03):1B,3C,93,3A,22,12,A3,23 + // Bytes for Ringing part 1 (03):1B,3C,93,3A,22,12,A3,23 j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[7] = 0x1B; j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[6] = 0x3C; j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[5] = 0x93; @@ -5577,7 +7185,6 @@ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[2] = 0x12; j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[1] = 0xA3; j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[0] = 0x23; - // Bytes for Ringing part 2 (06):12,A2,A6,BA,22,7A,0A,D5 j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[7] = 0x12; j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[6] = 0xA2; @@ -5587,13 +7194,11 @@ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[2] = 0x7A; j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[1] = 0x0A; j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[0] = 0xD5; - // Levelmetering Ringing (0D):32,45,B5,84 ; 50Hz 20V j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[3] = 0x32; j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[2] = 0x45; j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[1] = 0xB5; j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[0] = 0x84; - // Caller ID 1st Tone (0E):CA,0E,CA,09,99,99,99,99 j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[7] = 0xCA; j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[6] = 0x0E; @@ -5603,7 +7208,6 @@ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[2] = 0x99; j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[1] = 0x99; j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[0] = 0x99; - // Caller ID 2nd Tone (0F):FD,B5,BA,07,DA,00,00,00 j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[7] = 0xFD; j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[6] = 0xB5; @@ -5613,61 +7217,49 @@ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[2] = 0x00; j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[1] = 0x00; j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[0] = 0x00; - // ;CR Registers // Config. Reg. 0 (filters) (cr0):FF j->m_DAAShadowRegs.SOP_REGS.SOP.cr0.reg = 0xFF; - // Config. Reg. 1 (dialing) (cr1):05 j->m_DAAShadowRegs.SOP_REGS.SOP.cr1.reg = 0x05; - // Config. Reg. 2 (caller ID) (cr2):04 j->m_DAAShadowRegs.SOP_REGS.SOP.cr2.reg = 0x04; - // Config. Reg. 3 (testloops) (cr3):00 ; j->m_DAAShadowRegs.SOP_REGS.SOP.cr3.reg = 0x00; - // Config. Reg. 4 (analog gain) (cr4):01 j->m_DAAShadowRegs.SOP_REGS.SOP.cr4.reg = 0x02; //0x01; - -// Config. Reg. 5 (Version) (cr5):02 + // Config. Reg. 5 (Version) (cr5):02 // Config. Reg. 6 (Reserved) (cr6):00 // Config. Reg. 7 (Reserved) (cr7):00 - -// ;xr Registers + // ;xr Registers // Ext. Reg. 0 (Interrupt Reg.) (xr0):02 + j->m_DAAShadowRegs.XOP_xr0_W.reg = 0x02; // SO_1 set to '1' because it is inverted. + // Ext. Reg. 1 (Interrupt enable) (xr1):1C -// Ext. Reg. 1 (Interrupt enable) (xr1):1C j->m_DAAShadowRegs.XOP_REGS.XOP.xr1.reg = 0x1C; // RING, Caller ID, VDD_OK + // Ext. Reg. 2 (Cadence Time Out) (xr2):7D -// Ext. Reg. 2 (Cadence Time Out) (xr2):7D j->m_DAAShadowRegs.XOP_REGS.XOP.xr2.reg = 0x7D; - // Ext. Reg. 3 (DC Char) (xr3):2B ; j->m_DAAShadowRegs.XOP_REGS.XOP.xr3.reg = 0x2B; - // Ext. Reg. 4 (Cadence) (xr4):00 j->m_DAAShadowRegs.XOP_REGS.XOP.xr4.reg = 0x00; - // Ext. Reg. 5 (Ring timer) (xr5):22 j->m_DAAShadowRegs.XOP_REGS.XOP.xr5.reg = 0x22; - // Ext. Reg. 6 (Power State) (xr6):00 j->m_DAAShadowRegs.XOP_xr6_W.reg = 0x00; - // Ext. Reg. 7 (Vdd) (xr7):40 j->m_DAAShadowRegs.XOP_REGS.XOP.xr7.reg = 0x40; // 0x40 ??? Should it be 0x00? - -// DTMF Tone 1 (0B): 11,B3,5A,2C ; 697 Hz + // DTMF Tone 1 (0B): 11,B3,5A,2C ; 697 Hz // 12,33,5A,C3 ; 770 Hz // 13,3C,5B,32 ; 852 Hz // 1D,1B,5C,CC ; 941 Hz + j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[3] = 0x11; j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[2] = 0xB3; j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[1] = 0x5A; j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[0] = 0x2C; - // DTMF Tone 2 (0C): 32,32,52,B3 ; 1209 Hz // EC,1D,52,22 ; 1336 Hz // AA,AC,51,D2 ; 1477 Hz @@ -5676,23 +7268,22 @@ j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[2] = 0x32; j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[1] = 0x52; j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[0] = 0xB3; - } static void DAA_Coeff_Japan(int board) { IXJ *j = &ixj[board]; - int i; + j->daa_country = DAA_JAPAN; //----------------------------------------------- // CAO for (i = 0; i < ALISDAA_CALLERID_SIZE; i++) { j->m_DAAShadowRegs.CAO_REGS.CAO.CallerID[i] = 0; } - // Bytes for IM-filter part 1 (04): 06,BD,E2,2D,BA,F9,A0,00 - j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[7] = 0x06; +// Bytes for IM-filter part 1 (04): 06,BD,E2,2D,BA,F9,A0,00 + j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[7] = 0x06; j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[6] = 0xBD; j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[5] = 0xE2; j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[4] = 0x2D; @@ -5700,7 +7291,6 @@ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[2] = 0xF9; j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[1] = 0xA0; j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_1[0] = 0x00; - // Bytes for IM-filter part 2 (05): 6F,F7,00,0E,34,33,E0,08 j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[7] = 0x6F; j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[6] = 0xF7; @@ -5710,7 +7300,6 @@ j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[2] = 0x33; j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[1] = 0xE0; j->m_DAAShadowRegs.COP_REGS.COP.IMFilterCoeff_2[0] = 0x08; - // Bytes for FRX-filter (08): 02,8F,68,77,9C,58,F0,08 j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[7] = 0x02; j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[6] = 0x8F; @@ -5720,7 +7309,6 @@ j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[2] = 0x58; j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[1] = 0xF0; j->m_DAAShadowRegs.COP_REGS.COP.FRXFilterCoeff[0] = 0x08; - // Bytes for FRR-filter (07): 03,8F,38,73,87,EA,20,08 j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[7] = 0x03; j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[6] = 0x8F; @@ -5730,19 +7318,16 @@ j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[2] = 0xEA; j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[1] = 0x20; j->m_DAAShadowRegs.COP_REGS.COP.FRRFilterCoeff[0] = 0x08; - // Bytes for AX-filter (0A): 51,C5,DD,CA j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[3] = 0x51; j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[2] = 0xC5; j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[1] = 0xDD; j->m_DAAShadowRegs.COP_REGS.COP.AXFilterCoeff[0] = 0xCA; - // Bytes for AR-filter (09): 25,A7,10,D6 j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[3] = 0x25; j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[2] = 0xA7; j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[1] = 0x10; j->m_DAAShadowRegs.COP_REGS.COP.ARFilterCoeff[0] = 0xD6; - // Bytes for TH-filter part 1 (00): 00,42,48,81,AE,80,00,98 j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[7] = 0x00; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[6] = 0x42; @@ -5752,7 +7337,6 @@ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[2] = 0x80; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[1] = 0x00; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_1[0] = 0x98; - // Bytes for TH-filter part 2 (01): 02,AB,2A,20,99,5B,89,28 j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[7] = 0x02; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[6] = 0xAB; @@ -5762,7 +7346,6 @@ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[2] = 0x5B; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[1] = 0x89; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_2[0] = 0x28; - // Bytes for TH-filter part 3 (02): 00,88,DA,25,34,C5,4C,BA j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[7] = 0x00; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[6] = 0x88; @@ -5772,10 +7355,8 @@ j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[2] = 0xC5; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[1] = 0x4C; j->m_DAAShadowRegs.COP_REGS.COP.THFilterCoeff_3[0] = 0xBA; - // ; idle - -// Bytes for Ringing part 1 (03):1B,3C,93,3A,22,12,A3,23 + // Bytes for Ringing part 1 (03):1B,3C,93,3A,22,12,A3,23 j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[7] = 0x1B; j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[6] = 0x3C; j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[5] = 0x93; @@ -5784,7 +7365,6 @@ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[2] = 0x12; j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[1] = 0xA3; j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[0] = 0x23; - // Bytes for Ringing part 2 (06):12,A2,A6,BA,22,7A,0A,D5 j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[7] = 0x12; j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[6] = 0xA2; @@ -5794,13 +7374,11 @@ j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[2] = 0x7A; j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[1] = 0x0A; j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[0] = 0xD5; - // Levelmetering Ringing (0D):AA,35,0F,8E ; 25Hz 30V ????????? j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[3] = 0xAA; j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[2] = 0x35; j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[1] = 0x0F; j->m_DAAShadowRegs.COP_REGS.COP.LevelmeteringRinging[0] = 0x8E; - // Caller ID 1st Tone (0E):CA,0E,CA,09,99,99,99,99 j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[7] = 0xCA; j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[6] = 0x0E; @@ -5810,7 +7388,6 @@ j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[2] = 0x99; j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[1] = 0x99; j->m_DAAShadowRegs.COP_REGS.COP.CallerID1stTone[0] = 0x99; - // Caller ID 2nd Tone (0F):FD,B5,BA,07,DA,00,00,00 j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[7] = 0xFD; j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[6] = 0xB5; @@ -5820,76 +7397,62 @@ j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[2] = 0x00; j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[1] = 0x00; j->m_DAAShadowRegs.COP_REGS.COP.CallerID2ndTone[0] = 0x00; - // ;CR Registers // Config. Reg. 0 (filters) (cr0):FF - j->m_DAAShadowRegs.SOP_REGS.SOP.cr0.reg = 0xFF; - + j->m_DAAShadowRegs.SOP_REGS.SOP.cr0.reg = 0xFE; // Config. Reg. 1 (dialing) (cr1):05 j->m_DAAShadowRegs.SOP_REGS.SOP.cr1.reg = 0x05; - // Config. Reg. 2 (caller ID) (cr2):04 j->m_DAAShadowRegs.SOP_REGS.SOP.cr2.reg = 0x04; - // Config. Reg. 3 (testloops) (cr3):00 ; j->m_DAAShadowRegs.SOP_REGS.SOP.cr3.reg = 0x00; - // Config. Reg. 4 (analog gain) (cr4):01 j->m_DAAShadowRegs.SOP_REGS.SOP.cr4.reg = 0x02; //0x01; - -// Config. Reg. 5 (Version) (cr5):02 + // Config. Reg. 5 (Version) (cr5):02 // Config. Reg. 6 (Reserved) (cr6):00 // Config. Reg. 7 (Reserved) (cr7):00 - -// ;xr Registers + // ;xr Registers // Ext. Reg. 0 (Interrupt Reg.) (xr0):02 + j->m_DAAShadowRegs.XOP_xr0_W.reg = 0x02; // SO_1 set to '1' because it is inverted. + // Ext. Reg. 1 (Interrupt enable) (xr1):1C -// Ext. Reg. 1 (Interrupt enable) (xr1):1C j->m_DAAShadowRegs.XOP_REGS.XOP.xr1.reg = 0x1C; // RING, Caller ID, VDD_OK + // Ext. Reg. 2 (Cadence Time Out) (xr2):7D -// Ext. Reg. 2 (Cadence Time Out) (xr2):7D j->m_DAAShadowRegs.XOP_REGS.XOP.xr2.reg = 0x7D; - // Ext. Reg. 3 (DC Char) (xr3):22 ; j->m_DAAShadowRegs.XOP_REGS.XOP.xr3.reg = 0x22; - // Ext. Reg. 4 (Cadence) (xr4):00 j->m_DAAShadowRegs.XOP_REGS.XOP.xr4.reg = 0x00; - // Ext. Reg. 5 (Ring timer) (xr5):22 j->m_DAAShadowRegs.XOP_REGS.XOP.xr5.reg = 0x22; - // Ext. Reg. 6 (Power State) (xr6):00 j->m_DAAShadowRegs.XOP_xr6_W.reg = 0x00; - // Ext. Reg. 7 (Vdd) (xr7):40 j->m_DAAShadowRegs.XOP_REGS.XOP.xr7.reg = 0x40; // 0x40 ??? Should it be 0x00? - -// DTMF Tone 1 (0B): 11,B3,5A,2C ; 697 Hz + // DTMF Tone 1 (0B): 11,B3,5A,2C ; 697 Hz // 12,33,5A,C3 ; 770 Hz // 13,3C,5B,32 ; 852 Hz // 1D,1B,5C,CC ; 941 Hz + j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[3] = 0x11; j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[2] = 0xB3; j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[1] = 0x5A; j->m_DAAShadowRegs.COP_REGS.COP.Tone1Coeff[0] = 0x2C; - // DTMF Tone 2 (0C): 32,32,52,B3 ; 1209 Hz // EC,1D,52,22 ; 1336 Hz // AA,AC,51,D2 ; 1477 Hz // 9B,3B,51,25 ; 1633 Hz - j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[3] = 0x32; j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[2] = 0x32; j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[1] = 0x52; j->m_DAAShadowRegs.COP_REGS.COP.Tone2Coeff[0] = 0xB3; - } static s16 tone_table[][19] = { - { // f20_50[] + { // f20_50[] 11 32538, // A1 = 1.985962 -32325, // A2 = -0.986511 -343, // B2 = -0.010493 @@ -5910,7 +7473,7 @@ 21, // 21/32 in-band to broad-band ratio 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5 }, - { // f133_200[] + { // f133_200[] 12 32072, // A1 = 1.95752 -31896, // A2 = -0.973419 -435, // B2 = -0.013294 @@ -5931,7 +7494,7 @@ 21, // 21/32 in-band to broad-band ratio 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5 }, - { // 300.txt + { // 300.txt 13 31769, // A1 = -1.939026 -32584, // A2 = 0.994385 -475, // B2 = -0.014522 @@ -5952,7 +7515,7 @@ 21, // 21/32 in-band to broad-band ratio 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5 }, - { // f300_420[] + { // f300_420[] 14 30750, // A1 = 1.876892 -31212, // A2 = -0.952515 -804, // B2 = -0.024541 @@ -5973,7 +7536,7 @@ 21, // 21/32 in-band to broad-band ratio 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5 }, - { // 330.txt + { // 330.txt 15 31613, // A1 = -1.929565 -32646, // A2 = 0.996277 -185, // B2 = -0.005657 @@ -5994,7 +7557,7 @@ 21, // 21/32 in-band to broad-band ratio 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5 }, - { // f300_425[] + { // f300_425[] 16 30741, // A1 = 1.876282 -31475, // A2 = -0.960541 -703, // B2 = -0.021484 @@ -6015,7 +7578,7 @@ 21, // 21/32 in-band to broad-band ratio 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5 }, - { // f330_440[] + { // f330_440[] 17 30627, // A1 = 1.869324 -31338, // A2 = -0.95636 -843, // B2 = -0.025749 @@ -6036,7 +7599,7 @@ 21, // 21/32 in-band to broad-band ratio 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5 }, - { // 340.txt + { // 340.txt 18 31546, // A1 = -1.925476 -32646, // A2 = 0.996277 -445, // B2 = -0.013588 @@ -6057,7 +7620,7 @@ 21, // 21/32 in-band to broad-band ratio 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5 }, - { // f350_400[] + { // f350_400[] 19 31006, // A1 = 1.892517 -32029, // A2 = -0.977448 -461, // B2 = -0.014096 @@ -7421,21 +8984,19 @@ 159, // Minimum in-band energy threshold 21, // 21/32 in-band to broad-band ratio 0x0FF5 // shift-mask 0x0FF (look at 16 half-frames) bit count = 5 - },}; - + }, +}; static int ixj_init_filter(int board, IXJ_FILTER * jf) { unsigned short cmd; int cnt, max; IXJ *j = &ixj[board]; - if (jf->filter > 3) { return -1; } if (ixj_WriteDSPCommand(0x5154 + jf->filter, board)) // Select Filter return -1; - if (!jf->enable) { if (ixj_WriteDSPCommand(0x5152, board)) // Disable Filter @@ -7446,7 +9007,6 @@ if (ixj_WriteDSPCommand(0x5153, board)) // Enable Filter return -1; - // Select the filter (f0 - f3) to use. if (ixj_WriteDSPCommand(0x5154 + jf->filter, board)) return -1; @@ -7463,7 +9023,6 @@ // frequency we want. if (ixj_WriteDSPCommand(0x5170 + jf->filter, board)) return -1; - if (j->ver.low != 0x12) { cmd = 0x515B; max = 19; @@ -7473,23 +9032,12 @@ } if (ixj_WriteDSPCommand(cmd, board)) return -1; - for (cnt = 0; cnt < max; cnt++) { - if (ixj_WriteDSPCommand(tone_table[jf->freq][cnt], board)) + if (ixj_WriteDSPCommand(tone_table[jf->freq - 12][cnt], board)) return -1; } -/* if(j->ver.low != 0x12) - { - if(ixj_WriteDSPCommand(7, board)) - return -1; - if(ixj_WriteDSPCommand(159, board)) - return -1; - if(ixj_WriteDSPCommand(21, board)) - return -1; - if(ixj_WriteDSPCommand(0x0FF5, board)) - return -1; - } */ } + j->filter_en[jf->filter] = jf->enable; return 0; } @@ -7497,7 +9045,6 @@ { int freq0, freq1; unsigned short data; - if (ti->freq0) { freq0 = ti->freq0; } else { @@ -7510,18 +9057,15 @@ freq1 = 0x7FFF; } -// if(ti->tone_index > 12 && ti->tone_index < 28) + if(ti->tone_index > 12 && ti->tone_index < 28) { if (ixj_WriteDSPCommand(0x6800 + ti->tone_index, board)) return -1; - if (ixj_WriteDSPCommand(0x6000 + (ti->gain0 << 4) + ti->gain1, board)) return -1; - data = freq0; if (ixj_WriteDSPCommand(data, board)) return -1; - data = freq1; if (ixj_WriteDSPCommand(data, board)) return -1; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/telephony/ixj.h linux/drivers/telephony/ixj.h --- v2.4.0-test8/linux/drivers/telephony/ixj.h Wed Dec 29 17:13:59 1999 +++ linux/drivers/telephony/ixj.h Mon Sep 18 15:02:03 2000 @@ -1,4 +1,4 @@ -/* +/****************************************************************************** * ixj.h * * Device Driver for the Internet PhoneJACK and @@ -22,9 +22,20 @@ * at our website: http://www.quicknet.net * * Fixes: - * Linux 2.3 port, Alan Cox - */ -static char ixj_h_rcsid[] = "$Id: ixj.h,v 3.4 1999/12/16 22:18:36 root Exp root $"; + * + * IN NO EVENT SHALL QUICKNET TECHNOLOGIES, INC. BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT + * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF QUICKNET + * TECHNOLOGIES, INC.HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * QUICKNET TECHNOLOGIES, INC. SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND QUICKNET TECHNOLOGIES, INC. HAS NO OBLIGATION + * TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + *****************************************************************************/ +static char ixj_h_rcsid[] = "$Id: ixj.h,v 3.14 2000/03/30 22:06:48 eokerson Exp $"; #ifndef _I386_TYPES_H #include @@ -61,6 +72,27 @@ unsigned char high; } BYTES; +typedef union { + BYTES bytes; + short word; +} IXJ_WORD; + +typedef struct{ + unsigned int b0:1; + unsigned int b1:1; + unsigned int b2:1; + unsigned int b3:1; + unsigned int b4:1; + unsigned int b5:1; + unsigned int b6:1; + unsigned int b7:1; +} IXJ_CBITS; + +typedef union{ + IXJ_CBITS cbits; + char cbyte; +} IXJ_CBYTE; + int ixj_WriteDSPCommand(unsigned short, int board); /****************************************************************************** @@ -328,6 +360,199 @@ /****************************************************************************** * +* These structures deal with the control logic on the Internet PhoneCARD +* +******************************************************************************/ +typedef struct { + unsigned int x0:4; // unused bits + + unsigned int ed:1; // Event Detect + + unsigned int drf:1; // Smart Cable Removal Flag 1=no cable + + unsigned int dspf:1; // DSP Flag 1=DSP Ready + + unsigned int crr:1; // Control Register Ready + +} COMMAND_REG1; + +typedef union { + COMMAND_REG1 bits; + unsigned char byte; +} PCMCIA_CR1; + +typedef struct { + unsigned int x0:4; // unused bits + + unsigned int rstc:1; // Smart Cable Reset + + unsigned int pwr:1; // Smart Cable Power + + unsigned int x1:2; // unused bits + +} COMMAND_REG2; + +typedef union { + COMMAND_REG2 bits; + unsigned char byte; +} PCMCIA_CR2; + +typedef struct { + unsigned int addr:5; // R/W Smart Cable Register Address + + unsigned int rw:1; // Read / Write flag + + unsigned int dev:2; // 2 bit Smart Cable Device Address + +} CONTROL_REG; + +typedef union { + CONTROL_REG bits; + unsigned char byte; +} PCMCIA_SCCR; + +typedef struct { + unsigned int hsw:1; + unsigned int det:1; + unsigned int led2:1; + unsigned int led1:1; + unsigned int ring1:1; + unsigned int ring0:1; + unsigned int x:1; + unsigned int powerdown:1; +} PCMCIA_SLIC_REG; + +typedef union { + PCMCIA_SLIC_REG bits; + unsigned char byte; +} PCMCIA_SLIC; + +typedef struct { + unsigned int cpd:1; // Chip Power Down + + unsigned int mpd:1; // MIC Bias Power Down + + unsigned int hpd:1; // Handset Drive Power Down + + unsigned int lpd:1; // Line Drive Power Down + + unsigned int spd:1; // Speaker Drive Power Down + + unsigned int x:2; // unused bits + + unsigned int sr:1; // Software Reset + +} Si3CONTROL1; + +typedef union { + Si3CONTROL1 bits; + unsigned char byte; +} Si3C1; + +typedef struct { + unsigned int al:1; // Analog Loopback DAC analog -> ADC analog + + unsigned int dl2:1; // Digital Loopback DAC -> ADC one bit + + unsigned int dl1:1; // Digital Loopback ADC -> DAC one bit + + unsigned int pll:1; // 1 = div 10, 0 = div 5 + + unsigned int hpd:1; // HPF disable + + unsigned int x:3; // unused bits + +} Si3CONTROL2; + +typedef union { + Si3CONTROL2 bits; + unsigned char byte; +} Si3C2; + +typedef struct { + unsigned int iir:1; // 1 enables IIR, 0 enables FIR + + unsigned int him:1; // Handset Input Mute + + unsigned int mcm:1; // MIC In Mute + + unsigned int mcg:2; // MIC In Gain + + unsigned int lim:1; // Line In Mute + + unsigned int lig:2; // Line In Gain + +} Si3RXGAIN; + +typedef union { + Si3RXGAIN bits; + unsigned char byte; +} Si3RXG; + +typedef struct { + unsigned int hom:1; // Handset Out Mute + + unsigned int lom:1; // Line Out Mute + + unsigned int rxg:5; // RX PGA Gain + + unsigned int x:1; // unused bit + +} Si3ADCVOLUME; + +typedef union { + Si3ADCVOLUME bits; + unsigned char byte; +} Si3ADC; + +typedef struct { + unsigned int srm:1; // Speaker Right Mute + + unsigned int slm:1; // Speaker Left Mute + + unsigned int txg:5; // TX PGA Gain + + unsigned int x:1; // unused bit + +} Si3DACVOLUME; + +typedef union { + Si3DACVOLUME bits; + unsigned char byte; +} Si3DAC; + +typedef struct { + unsigned int x:5; // unused bit + + unsigned int losc:1; // Line Out Short Circuit + + unsigned int srsc:1; // Speaker Right Short Circuit + + unsigned int slsc:1; // Speaker Left Short Circuit + +} Si3STATUSREPORT; + +typedef union { + Si3STATUSREPORT bits; + unsigned char byte; +} Si3STAT; + +typedef struct { + unsigned int sot:2; // Speaker Out Attenuation + + unsigned int lot:2; // Line Out Attenuation + + unsigned int x:4; // unused bits + +} Si3ANALOGATTN; + +typedef union { + Si3ANALOGATTN bits; + unsigned char byte; +} Si3AATT; + +/****************************************************************************** +* * These structures deal with the DAA on the Internet LineJACK * ******************************************************************************/ @@ -855,10 +1080,49 @@ }; typedef struct { + char enable; + char en_filter; + unsigned int filter; + unsigned int state; // State 0 when cadence has not started. + + unsigned int on1; // State 1 + + unsigned long on1min; // State 1 - 10% + jiffies + unsigned long on1dot; // State 1 + jiffies + + unsigned long on1max; // State 1 + 10% + jiffies + + unsigned int off1; // State 2 + + unsigned long off1min; + unsigned long off1max; + unsigned int on2; // State 3 + + unsigned long on2min; + unsigned long on2dot; + unsigned long on2max; + unsigned int off2; // State 4 + + unsigned long off2min; + unsigned long off2max; + unsigned int on3; // State 5 + + unsigned long on3min; + unsigned long on3dot; + unsigned long on3max; + unsigned int off3; // State 6 + + unsigned long off3min; + unsigned long off3max; +} IXJ_CADENCE_F; + +typedef struct { unsigned int busytone:1; unsigned int dialtone:1; unsigned int ringback:1; unsigned int ringing:1; + unsigned int playing:1; + unsigned int recording:1; unsigned int cringing:1; unsigned int play_first_frame:1; unsigned int pstn_present:1; @@ -869,6 +1133,28 @@ unsigned int ts85_loaded:1; unsigned int dtmf_oob:1; // DTMF Out-Of-Band + unsigned int pcmciascp:1; // Smart Cable Present + + unsigned int pcmciasct:2; // Smart Cable Type + + unsigned int pcmciastate:3; // Smart Cable Init State + + unsigned int inwrite:1; // Currently writing + + unsigned int inread:1; // Currently reading + + unsigned int incheck:1; // Currently checking the smart cable + + unsigned int cidplay:1; // Currently playing Caller ID + + unsigned int cidring:1; // This is the ring for Caller ID + + unsigned int cidsent:1; // Caller ID has been sent + + unsigned int cidcw_ack:1; // Caller ID CW ACK (from CPE) + + unsigned int x:6; // unsed bits + } IXJ_FLAGS; /****************************************************************************** @@ -885,15 +1171,19 @@ unsigned int serial; struct phone_capability caplist[30]; unsigned int caps; + unsigned int country; struct pci_dev *dev; unsigned int cardtype; unsigned int rec_codec; char rec_mode; unsigned int play_codec; + unsigned int cid_play_codec; char play_mode; IXJ_FLAGS flags; unsigned int rec_frame_size; unsigned int play_frame_size; + unsigned int cid_base_frame_size; + unsigned long cidcw_wait; int aec_level; int readers, writers; wait_queue_head_t poll_q; @@ -920,6 +1210,7 @@ char maxrings; IXJ_CADENCE *cadence_t; int tone_cadence_state; + IXJ_CADENCE_F cadence_f[4]; DTMF dtmf; CPTF cptf; BYTES dsp; @@ -934,30 +1225,50 @@ PLD_SLICW pld_slicw; PLD_SLICR pld_slicr; PLD_CLOCK pld_clock; + PCMCIA_CR1 pccr1; + PCMCIA_CR2 pccr2; + PCMCIA_SCCR psccr; + PCMCIA_SLIC pslic; + char pscdd; + Si3C1 sic1; + Si3C2 sic2; + Si3RXG sirxg; + Si3ADC siadc; + Si3DAC sidac; + Si3STAT sistat; + Si3AATT siaatt; MIX mix; unsigned short ring_cadence; int ring_cadence_t; unsigned long ring_cadence_jif; + unsigned long checkwait; int intercom; int m_hook; int r_hook; char pstn_envelope; char pstn_cid_intr; + unsigned char fskz; + unsigned char fskphase; + unsigned char fskcnt; unsigned pstn_cid_recieved; - IXJ_CID cid; + PHONE_CID cid; + PHONE_CID cid_send; unsigned long pstn_ring_start; + unsigned long pstn_ring_stop; unsigned long pstn_winkstart; unsigned int winktime; + unsigned long flash_end; char port; union telephony_exception ex; char daa_mode; + char daa_country; unsigned long pstn_sleeptil; DAA_REGS m_DAAShadowRegs; Proc_Info_Type Info_read; Proc_Info_Type Info_write; unsigned short frame_count; - unsigned int filter_cadence; unsigned int filter_hist[4]; + unsigned char filter_en[4]; unsigned short proc_load; unsigned long framesread; unsigned long frameswritten; @@ -966,6 +1277,8 @@ unsigned long timerchecks; unsigned long txreadycheck; unsigned long rxreadycheck; + short fskdata[8000]; + int fskdcnt; } IXJ; typedef int (*IXJ_REGFUNC) (IXJ * j, unsigned long arg); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/telephony/phonedev.c linux/drivers/telephony/phonedev.c --- v2.4.0-test8/linux/drivers/telephony/phonedev.c Mon Jul 24 17:04:12 2000 +++ linux/drivers/telephony/phonedev.c Tue Sep 19 08:31:53 2000 @@ -14,7 +14,6 @@ * phone_register_device now works with unit!=PHONE_UNIT_ANY */ -#include #include #include #include @@ -24,6 +23,7 @@ #include #include #include +#include #include #include @@ -143,40 +143,29 @@ * Board init functions */ -extern int ixj_init(void); /* * Initialise Telephony for linux */ -int telephony_init(void) +static int __init telephony_init(void) { printk(KERN_INFO "Linux telephony interface: v1.00\n"); if (register_chrdev(PHONE_MAJOR, "telephony", &phone_fops)) { printk("phonedev: unable to get major %d\n", PHONE_MAJOR); return -EIO; } - /* - * Init kernel installed drivers - */ -#ifdef CONFIG_PHONE_IXJ - ixj_init(); -#endif - return 0; -} -#ifdef MODULE -int init_module(void) -{ - return telephony_init(); + return 0; } -void cleanup_module(void) +static void __exit telephony_exit(void) { unregister_chrdev(PHONE_MAJOR, "telephony"); } -#endif +module_init(telephony_init); +module_exit(telephony_exit); EXPORT_SYMBOL(phone_register_device); EXPORT_SYMBOL(phone_unregister_device); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/usb/Config.in linux/drivers/usb/Config.in --- v2.4.0-test8/linux/drivers/usb/Config.in Tue Aug 22 15:20:52 2000 +++ linux/drivers/usb/Config.in Mon Sep 18 15:23:30 2000 @@ -72,6 +72,7 @@ dep_tristate ' USB Diamond Rio500 support (EXPERIMENTAL)' CONFIG_USB_RIO500 $CONFIG_USB dep_tristate ' D-Link USB FM radio support (EXPERIMENTAL)' CONFIG_USB_DSBR $CONFIG_USB $CONFIG_VIDEO_DEV dep_tristate ' USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB + dep_tristate ' NetChip 1080-based USB Host-to-Host Link (EXPERIMENTAL)' CONFIG_USB_NET1080 $CONFIG_USB $CONFIG_NET fi comment 'USB Human Interface Devices (HID)' diff -u --recursive --new-file v2.4.0-test8/linux/drivers/usb/Makefile linux/drivers/usb/Makefile --- v2.4.0-test8/linux/drivers/usb/Makefile Mon Aug 28 16:59:14 2000 +++ linux/drivers/usb/Makefile Wed Sep 27 13:53:56 2000 @@ -6,7 +6,6 @@ SUB_DIRS := MOD_SUB_DIRS := $(SUB_DIRS) -MOD_IN_SUB_DIRS := $(SUB_DIRS) ALL_SUB_DIRS := $(SUB_DIRS) serial storage # The target object and module list name. @@ -65,6 +64,7 @@ obj-$(CONFIG_USB_DSBR) += dsbr100.o obj-$(CONFIG_USB_MICROTEK) += microtek.o obj-$(CONFIG_USB_BLUETOOTH) += bluetooth.o +obj-$(CONFIG_USB_NET1080) += net1080.o # Object files in subdirectories @@ -73,7 +73,7 @@ obj-y += serial/usb-serial.o else ifeq ($(CONFIG_USB_SERIAL),m) - MOD_IN_SUB_DIRS += serial + MOD_SUB_DIRS += serial endif endif @@ -82,7 +82,7 @@ obj-y += storage/storage.o else ifeq ($(CONFIG_USB_STORAGE),m) - MOD_IN_SUB_DIRS += storage + MOD_SUB_DIRS += storage endif endif @@ -98,10 +98,6 @@ obj-m := $(filter-out $(obj-y), $(obj-m)) int-m := $(filter-out $(int-y), $(int-m)) - -# Take multi-part drivers out of obj-y and put components in. - -obj-y := $(filter-out $(list-multi), $(obj-y)) $(int-y) # Translate to Rules.make lists. diff -u --recursive --new-file v2.4.0-test8/linux/drivers/usb/acm.c linux/drivers/usb/acm.c --- v2.4.0-test8/linux/drivers/usb/acm.c Thu Jul 27 18:36:54 2000 +++ linux/drivers/usb/acm.c Mon Sep 18 15:23:30 2000 @@ -49,7 +49,7 @@ #include #include #include -#define DEBUG +#undef DEBUG #include /* @@ -559,9 +559,11 @@ FILL_BULK_URB(&acm->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress), buf += ctrlsize, readsize, acm_read_bulk, acm); + acm->readurb.transfer_flags |= USB_NO_FSBR; FILL_BULK_URB(&acm->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress), buf += readsize, acm->writesize, acm_write_bulk, acm); + acm->writeurb.transfer_flags |= USB_NO_FSBR; printk(KERN_INFO "ttyACM%d: USB ACM device\n", minor); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/usb/dabusb.h linux/drivers/usb/dabusb.h --- v2.4.0-test8/linux/drivers/usb/dabusb.h Mon Jun 19 13:42:41 2000 +++ linux/drivers/usb/dabusb.h Tue Oct 3 09:24:40 2000 @@ -23,7 +23,7 @@ wait_queue_head_t wait; wait_queue_head_t remove_ok; spinlock_t lock; - volatile atomic_t pending_io; + atomic_t pending_io; driver_state_t state; int remove_pending; int got_mem; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/usb/dc2xx.c linux/drivers/usb/dc2xx.c --- v2.4.0-test8/linux/drivers/usb/dc2xx.c Tue Aug 22 11:48:54 2000 +++ linux/drivers/usb/dc2xx.c Mon Sep 25 16:18:55 2000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999-2000 by David Brownell + * Copyright (C) 1999-2000 by David Brownell * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -90,6 +90,7 @@ /* These have the same application level protocol */ { 0x040a, 0x0120 }, // Kodak DC-240 { 0x040a, 0x0130 }, // Kodak DC-280 + { 0x040a, 0x0132 }, // Kodak DC-3400 /* These have a different application level protocol which * is part of the Flashpoint "DigitaOS". That supports some @@ -498,7 +499,7 @@ } -MODULE_AUTHOR("David Brownell, david-b@pacbell.net"); +MODULE_AUTHOR("David Brownell, "); MODULE_DESCRIPTION("USB Camera Driver for Kodak DC-2xx series cameras"); module_init (usb_dc2xx_init); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/usb/devices.c linux/drivers/usb/devices.c --- v2.4.0-test8/linux/drivers/usb/devices.c Mon Jul 24 19:04:33 2000 +++ linux/drivers/usb/devices.c Mon Sep 25 15:25:29 2000 @@ -496,8 +496,10 @@ lock_kernel(); if (!st) { st = kmalloc(sizeof(struct usb_device_status), GFP_KERNEL); - if (!st) + if (!st) { + unlock_kernel(); return POLLIN; + } /* * need to prevent the module from being unloaded, since * proc_unregister does not call the release method and diff -u --recursive --new-file v2.4.0-test8/linux/drivers/usb/devio.c linux/drivers/usb/devio.c --- v2.4.0-test8/linux/drivers/usb/devio.c Tue Aug 29 14:09:15 2000 +++ linux/drivers/usb/devio.c Wed Sep 27 13:53:57 2000 @@ -55,113 +55,6 @@ urb_t urb; }; -/* - * my own sync control and bulk methods. Here to experiment - * and because the kernel ones set the process to TASK_UNINTERRUPTIBLE. - */ - -struct sync { - wait_queue_head_t wait; -}; - -static void sync_completed(purb_t urb) -{ - struct sync *s = (struct sync *)urb->context; - - wake_up(&s->wait); -} - -static int do_sync(purb_t urb, int timeout) -{ - DECLARE_WAITQUEUE(wait, current); - unsigned long tm; - signed long tmdiff; - struct sync s; - int ret; - - tm = jiffies+timeout; - init_waitqueue_head(&s.wait); - add_wait_queue(&s.wait, &wait); - urb->context = &s; - urb->complete = sync_completed; - set_current_state(TASK_INTERRUPTIBLE); - if ((ret = usb_submit_urb(urb))) - goto out; - while (urb->status == -EINPROGRESS) { - tmdiff = tm - jiffies; - if (tmdiff <= 0) { - ret = -ETIMEDOUT; - goto out; - } - if (signal_pending(current)) { - ret = -EINTR; - goto out; - } - schedule_timeout(tmdiff); - } - ret = urb->status; - out: - set_current_state(TASK_RUNNING); - usb_unlink_urb(urb); - remove_wait_queue(&s.wait, &wait); - return ret; -} - -static int my_usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, - __u16 value, __u16 index, void *data, __u16 size, int timeout) -{ - urb_t *urb; - int ret; - - if (!(urb = usb_alloc_urb(0))) - return -ENOMEM; - if (!(urb->setup_packet = kmalloc(8, GFP_KERNEL))) { - usb_free_urb(urb); - return -ENOMEM; - } - urb->setup_packet[0] = requesttype; - urb->setup_packet[1] = request; - urb->setup_packet[2] = value; - urb->setup_packet[3] = value >> 8; - urb->setup_packet[4] = index; - urb->setup_packet[5] = index >> 8; - urb->setup_packet[6] = size; - urb->setup_packet[7] = size >> 8; - urb->dev = dev; - urb->pipe = pipe; - urb->transfer_buffer = data; - urb->transfer_buffer_length = size; - ret = do_sync(urb, timeout); - //if (ret >= 0) - // ret = urb->status; - if (ret >= 0) - ret = urb->actual_length; - kfree(urb->setup_packet); - usb_free_urb(urb); - return ret; -} - -static int my_usb_bulk_msg(struct usb_device *dev, unsigned int pipe, - void *data, int len, int *actual_length, int timeout) -{ - urb_t *urb; - int ret; - - if (!(urb = usb_alloc_urb(0))) - return -ENOMEM; - urb->dev = dev; - urb->pipe = pipe; - urb->transfer_buffer = data; - urb->transfer_buffer_length = len; - ret = do_sync(urb, timeout); - //if (ret >= 0) - // ret = urb->status; - if (ret >= 0 && actual_length != NULL) - *actual_length = urb->actual_length; - usb_free_urb(urb); - return ret; -} - static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig) { switch (orig) { @@ -289,6 +182,8 @@ { if (as->urb.transfer_buffer) kfree(as->urb.transfer_buffer); + if (as->urb.setup_packet) + kfree(as->urb.setup_packet); kfree(as); } @@ -536,6 +431,28 @@ } #endif +static int check_ctrlrecip(struct dev_state *ps, unsigned int recip, unsigned int index) +{ + int ret; + + switch (recip & USB_RECIP_MASK) { + case USB_RECIP_ENDPOINT: + if ((ret = findintfep(ps->dev, index & 0xff)) < 0) + return ret; + if ((ret = checkintf(ps, ret))) + return ret; + break; + + case USB_RECIP_INTERFACE: + if ((ret = findintfif(ps->dev, index & 0xff)) < 0) + return ret; + if ((ret = checkintf(ps, ret))) + return ret; + break; + } + return 0; +} + /* * file operations */ @@ -609,21 +526,8 @@ if (copy_from_user(&ctrl, (void *)arg, sizeof(ctrl))) return -EFAULT; - switch (ctrl.requesttype & 0x1f) { - case USB_RECIP_ENDPOINT: - if ((ret = findintfep(ps->dev, ctrl.index & 0xff)) < 0) - return ret; - if ((ret = checkintf(ps, ret))) - return ret; - break; - - case USB_RECIP_INTERFACE: - if ((ret = findintfif(ps->dev, ctrl.index & 0xff)) < 0) - return ret; - if ((ret = checkintf(ps, ret))) - return ret; - break; - } + if ((ret = check_ctrlrecip(ps, ctrl.requesttype, ctrl.index))) + return ret; if (ctrl.length > PAGE_SIZE) return -EINVAL; if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL))) @@ -634,7 +538,7 @@ free_page((unsigned long)tbuf); return -EINVAL; } - i = my_usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.request, ctrl.requesttype, + i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.request, ctrl.requesttype, ctrl.value, ctrl.index, tbuf, ctrl.length, tmo); if ((i > 0) && ctrl.length) { if (copy_to_user(ctrl.data, tbuf, ctrl.length)) @@ -645,7 +549,7 @@ if (copy_from_user(tbuf, ctrl.data, ctrl.length)) return -EFAULT; } - i = my_usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.request, ctrl.requesttype, + i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.request, ctrl.requesttype, ctrl.value, ctrl.index, tbuf, ctrl.length, tmo); } free_page((unsigned long)tbuf); @@ -688,7 +592,7 @@ free_page((unsigned long)tbuf); return -EINVAL; } - i = my_usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo); + i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo); if (!i && len2) { if (copy_to_user(bulk.data, tbuf, len2)) return -EFAULT; @@ -698,7 +602,7 @@ if (copy_from_user(tbuf, bulk.data, len1)) return -EFAULT; } - i = my_usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo); + i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo); } free_page((unsigned long)tbuf); if (i < 0) { @@ -840,23 +744,61 @@ { struct usbdevfs_urb uurb; struct usbdevfs_iso_packet_desc *isopkt = NULL; + struct usb_endpoint_descriptor *ep_desc; struct async *as; + devrequest *dr = NULL; unsigned int u, totlen, isofrmlen; int ret; if (copy_from_user(&uurb, arg, sizeof(uurb))) return -EFAULT; - if (uurb.flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_DISABLE_SPD)) + if (uurb.flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_DISABLE_SPD|USBDEVFS_URB_QUEUE_BULK)) return -EINVAL; if (!uurb.buffer) return -EINVAL; if (uurb.signr != 0 && (uurb.signr < SIGRTMIN || uurb.signr > SIGRTMAX)) return -EINVAL; - if ((ret = findintfep(ps->dev, uurb.endpoint)) < 0) - return ret; - if ((ret = checkintf(ps, ret))) - return ret; + if (!(uurb.type == USBDEVFS_URB_TYPE_CONTROL && (uurb.endpoint & ~USB_ENDPOINT_DIR_MASK) == 0)) { + if ((ret = findintfep(ps->dev, uurb.endpoint)) < 0) + return ret; + if ((ret = checkintf(ps, ret))) + return ret; + } switch(uurb.type) { + case USBDEVFS_URB_TYPE_CONTROL: + if ((uurb.endpoint & ~USB_ENDPOINT_DIR_MASK) != 0) { + if (!(ep_desc = usb_epnum_to_ep_desc(ps->dev, uurb.endpoint))) + return -ENOENT; + if ((ep_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_CONTROL) + return -EINVAL; + } + /* min 8 byte setup packet, max arbitrary */ + if (uurb.buffer_length < 8 || uurb.buffer_length > PAGE_SIZE) + return -EINVAL; + if (!(dr = kmalloc(sizeof(devrequest), GFP_KERNEL))) + return -ENOMEM; + if (copy_from_user(dr, (unsigned char*)uurb.buffer, 8)) { + kfree(dr); + return -EFAULT; + } + if (uurb.buffer_length < (le16_to_cpup(&dr->length) + 8)) { + kfree(dr); + return -EINVAL; + } + if ((ret = check_ctrlrecip(ps, dr->requesttype, le16_to_cpup(&dr->index)))) { + kfree(dr); + return ret; + } + uurb.endpoint = (uurb.endpoint & ~USB_ENDPOINT_DIR_MASK) | (dr->requesttype & USB_ENDPOINT_DIR_MASK); + uurb.number_of_packets = 0; + uurb.buffer_length = le16_to_cpup(&dr->length); + uurb.buffer += 8; + if (!access_ok((uurb.endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb.buffer, uurb.buffer_length)) { + kfree(dr); + return -EFAULT; + } + break; + case USBDEVFS_URB_TYPE_BULK: uurb.number_of_packets = 0; if (uurb.buffer_length > 16384) @@ -896,11 +838,15 @@ if (!(as = alloc_async(uurb.number_of_packets))) { if (isopkt) kfree(isopkt); + if (dr) + kfree(dr); return -ENOMEM; } if (!(as->urb.transfer_buffer = kmalloc(uurb.buffer_length, GFP_KERNEL))) { if (isopkt) kfree(isopkt); + if (dr) + kfree(dr); free_async(as); return -ENOMEM; } @@ -909,6 +855,7 @@ as->urb.pipe = (uurb.type << 30) | __create_pipe(ps->dev, uurb.endpoint & 0xf) | (uurb.endpoint & USB_DIR_IN); as->urb.transfer_flags = uurb.flags; as->urb.transfer_buffer_length = uurb.buffer_length; + as->urb.setup_packet = (unsigned char*)dr; as->urb.start_frame = uurb.start_frame; as->urb.number_of_packets = uurb.number_of_packets; as->urb.context = as; @@ -963,20 +910,23 @@ if (copy_to_user(as->userbuffer, as->urb.transfer_buffer, as->urb.transfer_buffer_length)) return -EFAULT; if (put_user(as->urb.status, - &((struct usbdevfs_urb *)as->userurb)->status) || - __put_user(as->urb.actual_length, - &((struct usbdevfs_urb *)as->userurb)->actual_length) || - __put_user(as->urb.error_count, - &((struct usbdevfs_urb *)as->userurb)->error_count)) + &((struct usbdevfs_urb *)as->userurb)->status)) + return -EFAULT; + if (put_user(as->urb.actual_length, + &((struct usbdevfs_urb *)as->userurb)->actual_length)) + return -EFAULT; + if (put_user(as->urb.error_count, + &((struct usbdevfs_urb *)as->userurb)->error_count)) return -EFAULT; if (!(usb_pipeisoc(as->urb.pipe))) return 0; for (i = 0; i < as->urb.number_of_packets; i++) { if (put_user(as->urb.iso_frame_desc[i].actual_length, - &((struct usbdevfs_urb *)as->userurb)->iso_frame_desc[i].actual_length) || - __put_user(as->urb.iso_frame_desc[i].status, - &((struct usbdevfs_urb *)as->userurb)->iso_frame_desc[i].status)) + &((struct usbdevfs_urb *)as->userurb)->iso_frame_desc[i].actual_length)) + return -EFAULT; + if (put_user(as->urb.iso_frame_desc[i].status, + &((struct usbdevfs_urb *)as->userurb)->iso_frame_desc[i].status)) return -EFAULT; } return 0; @@ -1090,7 +1040,7 @@ kfree (buf); return -EFAULT; } else - memset (arg, 0, size); + memset (buf, 0, size); } /* ioctl to device */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/usb/hid.c linux/drivers/usb/hid.c --- v2.4.0-test8/linux/drivers/usb/hid.c Tue Aug 22 09:06:31 2000 +++ linux/drivers/usb/hid.c Mon Oct 2 14:20:39 2000 @@ -1,5 +1,5 @@ /* - * $Id: hid.c,v 1.14 2000/08/14 21:05:26 vojtech Exp $ + * $Id: hid.c,v 1.16 2000/09/18 21:38:55 vojtech Exp $ * * Copyright (c) 1999 Andreas Gal * Copyright (c) 2000 Vojtech Pavlik @@ -924,6 +924,8 @@ usage->code = find_next_zero_bit(bit, max + 1, usage->code); } + if (usage->code > max) return; + if (usage->type == EV_ABS) { int a = field->logical_minimum; int b = field->logical_maximum; @@ -936,7 +938,7 @@ if (usage->hat) { int i; - for (i = usage->code; i < usage->code + 2; i++) { + for (i = usage->code; i < usage->code + 2 && i <= max; i++) { input->absmax[i] = 1; input->absmin[i] = -1; input->absfuzz[i] = 0; @@ -1229,6 +1231,7 @@ hid->urbout.transfer_buffer_length = hid->out[hid->outtail].dr.length; hid->urbout.transfer_buffer = hid->out[hid->outtail].buffer; hid->urbout.setup_packet = (void *) &(hid->out[hid->outtail].dr); + hid->urbout.dev = hid->dev; if (usb_submit_urb(&hid->urbout)) { err("usb_submit_urb(out) failed"); @@ -1286,7 +1289,9 @@ if (hid->open++) return 0; - if (usb_submit_urb(&hid->urb)) + hid->urb.dev = hid->dev; + + if (usb_submit_urb(&hid->urb)) return -EIO; return 0; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/usb/hub.c linux/drivers/usb/hub.c --- v2.4.0-test8/linux/drivers/usb/hub.c Tue Sep 5 13:41:53 2000 +++ linux/drivers/usb/hub.c Thu Sep 28 13:20:48 2000 @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -76,30 +77,32 @@ data, sizeof(struct usb_hub_status), HZ); } -/* - * A irq handler returns non-zero to indicate to - * the low-level driver that it wants to be re-activated, - * or zero to say "I'm done". - */ static void hub_irq(struct urb *urb) { struct usb_hub *hub = (struct usb_hub *)urb->context; unsigned long flags; + /* Cause a hub reset after 10 consecutive errors */ if (urb->status) { - if (urb->status != -ENOENT) - dbg("nonzero status in irq %d", urb->status); + if (urb->status == -ENOENT) + return; - return; + dbg("nonzero status in irq %d", urb->status); + + if ((++hub->nerrors < 10) || hub->error) + return; + + hub->error = urb->status; } + hub->nerrors = 0; + /* Something happened, let khubd figure it out */ if (waitqueue_active(&khubd_wait)) { /* Add the hub to the event queue */ spin_lock_irqsave(&hub_event_lock, flags); - if (hub->event_list.next == &hub->event_list) { + if (list_empty(&hub->event_list)) { list_add(&hub->event_list, &hub_event_list); - /* Wake up khubd */ wake_up(&khubd_wait); } spin_unlock_irqrestore(&hub_event_lock, flags); @@ -114,40 +117,43 @@ dbg("enabling power on all ports"); for (i = 0; i < hub->nports; i++) usb_set_port_feature(hub->dev, i + 1, USB_PORT_FEAT_POWER); + + /* Wait for power to be enabled */ + wait_ms(hub->descriptor->bPwrOn2PwrGood * 2); } -static int usb_hub_configure(struct usb_hub *hub) +static int usb_hub_configure(struct usb_hub *hub, struct usb_endpoint_descriptor *endpoint) { struct usb_device *dev = hub->dev; - unsigned char buffer[HUB_DESCRIPTOR_MAX_SIZE], *bitmap; - struct usb_hub_descriptor *descriptor; - struct usb_descriptor_header *header; - struct usb_hub_status *hubsts; - int i, ret; + struct usb_hub_status hubstatus; + char portstr[USB_MAXCHILDREN + 1]; + unsigned int pipe; + int i, maxp, ret; + + hub->descriptor = kmalloc(HUB_DESCRIPTOR_MAX_SIZE, GFP_KERNEL); + if (!hub->descriptor) { + err("Unable to kmalloc %d bytes for hub descriptor", HUB_DESCRIPTOR_MAX_SIZE); + return -1; + } /* Request the entire hub descriptor. */ - header = (struct usb_descriptor_header *)buffer; - ret = usb_get_hub_descriptor(dev, buffer, sizeof(buffer)); - /* is large enough for a hub with 127 ports; + ret = usb_get_hub_descriptor(dev, hub->descriptor, HUB_DESCRIPTOR_MAX_SIZE); + /* descriptor> is large enough for a hub with 127 ports; * the hub can/will return fewer bytes here. */ if (ret < 0) { err("Unable to get hub descriptor (err = %d)", ret); return -1; } - bitmap = kmalloc(header->bLength, GFP_KERNEL); - if (!bitmap) { - err("Unable to kmalloc %d bytes for bitmap", header->bLength); - return -1; - } - - memcpy (bitmap, buffer, header->bLength); - descriptor = (struct usb_hub_descriptor *)bitmap; - - hub->nports = dev->maxchild = descriptor->bNbrPorts; + hub->nports = dev->maxchild = hub->descriptor->bNbrPorts; info("%d port%s detected", hub->nports, (hub->nports == 1) ? "" : "s"); - switch (descriptor->wHubCharacteristics & HUB_CHAR_LPSM) { + if (hub->descriptor->wHubCharacteristics & HUB_CHAR_COMPOUND) + dbg("part of a compound device"); + else + dbg("standalone hub"); + + switch (hub->descriptor->wHubCharacteristics & HUB_CHAR_LPSM) { case 0x00: dbg("ganged power switching"); break; @@ -160,12 +166,7 @@ break; } - if (descriptor->wHubCharacteristics & HUB_CHAR_COMPOUND) - dbg("part of a compound device"); - else - dbg("standalone hub"); - - switch (descriptor->wHubCharacteristics & HUB_CHAR_OCPM) { + switch (hub->descriptor->wHubCharacteristics & HUB_CHAR_OCPM) { case 0x00: dbg("global over-current protection"); break; @@ -178,28 +179,52 @@ break; } - dbg("power on to power good time: %dms", descriptor->bPwrOn2PwrGood * 2); - dbg("hub controller current requirement: %dmA", descriptor->bHubContrCurrent); + dbg("power on to power good time: %dms", hub->descriptor->bPwrOn2PwrGood * 2); + dbg("hub controller current requirement: %dmA", hub->descriptor->bHubContrCurrent); for (i = 0; i < dev->maxchild; i++) - dbg("port %d is%s removable", i + 1, - bitmap[7 + ((i + 1)/8)] & (1 << ((i + 1) % 8)) - ? " not" : ""); + portstr[i] = hub->descriptor->bitmap[((i + 1) / 8)] & (1 << ((i + 1) % 8)) ? 'F' : 'R'; + portstr[dev->maxchild] = 0; - kfree(bitmap); + dbg("port removable status: %s", portstr); - ret = usb_get_hub_status(dev, buffer); + ret = usb_get_hub_status(dev, &hubstatus); if (ret < 0) { err("Unable to get hub status (err = %d)", ret); return -1; } - hubsts = (struct usb_hub_status *)buffer; + le16_to_cpus(&hubstatus.wHubStatus); + dbg("local power source is %s", - (le16_to_cpu(hubsts->wHubStatus) & HUB_STATUS_LOCAL_POWER) ? "lost (inactive)" : "good"); + (hubstatus.wHubStatus & HUB_STATUS_LOCAL_POWER) ? "lost (inactive)" : "good"); dbg("%sover-current condition exists", - (le16_to_cpu(hubsts->wHubStatus) & HUB_STATUS_OVERCURRENT) ? "" : "no "); + (hubstatus.wHubStatus & HUB_STATUS_OVERCURRENT) ? "" : "no "); + + /* Start the interrupt endpoint */ + pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); + maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); + + if (maxp > sizeof(hub->buffer)) + maxp = sizeof(hub->buffer); + + hub->urb = usb_alloc_urb(0); + if (!hub->urb) { + err("couldn't allocate interrupt urb"); + return -1; + } + + FILL_INT_URB(hub->urb, dev, pipe, hub->buffer, maxp, hub_irq, + hub, endpoint->bInterval); + ret = usb_submit_urb(hub->urb); + if (ret) { + err("usb_submit_urb failed (%d)", ret); + return -1; + } + + /* Wake up khubd */ + wake_up(&khubd_wait); usb_hub_power_on(hub); @@ -212,8 +237,6 @@ struct usb_endpoint_descriptor *endpoint; struct usb_hub *hub; unsigned long flags; - unsigned int pipe; - int maxp, ret; interface = &dev->actconfig->interface[i].altsetting[0]; @@ -265,34 +288,11 @@ list_add(&hub->hub_list, &hub_list); spin_unlock_irqrestore(&hub_event_lock, flags); - if (usb_hub_configure(hub) >= 0) { - pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); - maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); - - if (maxp > sizeof(hub->buffer)) - maxp = sizeof(hub->buffer); - - hub->urb = usb_alloc_urb(0); - if (!hub->urb) { - err("couldn't allocate interrupt urb"); - goto fail; - } - - FILL_INT_URB(hub->urb, dev, pipe, hub->buffer, maxp, hub_irq, - hub, endpoint->bInterval); - ret = usb_submit_urb(hub->urb); - if (ret) { - err("usb_submit_urb failed (%d)", ret); - goto fail; - } - - /* Wake up khubd */ - wake_up(&khubd_wait); - } + if (usb_hub_configure(hub, endpoint) >= 0) + return hub; - return hub; + err("hub configuration failed"); -fail: /* free hub, but first clean up its list. */ spin_lock_irqsave(&hub_event_lock, flags); @@ -330,11 +330,16 @@ hub->urb = NULL; } + if (hub->descriptor) { + kfree(hub->descriptor); + hub->descriptor = NULL; + } + /* Free the memory */ kfree(hub); } -static int hub_ioctl (struct usb_device *hub, unsigned int code, void *user_data) +static int hub_ioctl(struct usb_device *hub, unsigned int code, void *user_data) { /* assert ifno == 0 (part of hub spec) */ switch (code) { @@ -343,19 +348,19 @@ unsigned long flags; int i; - spin_lock_irqsave (&hub_event_lock, flags); + spin_lock_irqsave(&hub_event_lock, flags); if (hub->devnum <= 0) info->nports = 0; else { info->nports = hub->maxchild; for (i = 0; i < info->nports; i++) { - if (hub->children [i] == NULL) - info->port [i] = 0; + if (hub->children[i] == NULL) + info->port[i] = 0; else - info->port [i] = hub->children [i]->devnum; + info->port[i] = hub->children[i]->devnum; } } - spin_unlock_irqrestore (&hub_event_lock, flags); + spin_unlock_irqrestore(&hub_event_lock, flags); return info->nports + 1; } @@ -365,121 +370,260 @@ } } -static void usb_hub_port_connect_change(struct usb_device *hub, int port) +static int usb_hub_reset(struct usb_hub *hub) { - struct usb_device *usb; - struct usb_port_status portsts; - unsigned short portstatus, portchange; - int ret, tries; - - wait_ms(100); + struct usb_device *dev = hub->dev; + int i; - ret = usb_get_port_status(hub, port + 1, &portsts); - if (ret < 0) { - err("get_port_status(%d) failed (err = %d)", port + 1, ret); - return; + /* Disconnect any attached devices */ + for (i = 0; i < hub->nports; i++) { + if (dev->children[i]) + usb_disconnect(&dev->children[i]); } - portstatus = le16_to_cpu(portsts.wPortStatus); - portchange = le16_to_cpu(portsts.wPortChange); - dbg("portstatus %x, change %x, %s", portstatus, portchange, - portstatus&(1<urb) + usb_unlink_urb(hub->urb); + else + return -1; - /* Clear the connection change status */ - usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_C_CONNECTION); + if (usb_reset_device(dev)) + return -1; - /* Disconnect any existing devices under this port */ - if (((!(portstatus & USB_PORT_STAT_CONNECTION)) && - (!(portstatus & USB_PORT_STAT_ENABLE)))|| (hub->children[port])) { - usb_disconnect(&hub->children[port]); - /* Return now if nothing is connected */ - if (!(portstatus & USB_PORT_STAT_CONNECTION)) - return; + if (usb_submit_urb(hub->urb)) + return -1; + + usb_hub_power_on(hub); + + return 0; +} + +static void usb_hub_disconnect(struct usb_device *dev) +{ + struct usb_device *parent = dev->parent; + int i; + + /* Find the device pointer to disconnect */ + if (parent) { + for (i = 0; i < parent->maxchild; i++) { + if (parent->children[i] == dev) { + usb_disconnect(&parent->children[i]); + return; + } + } } - wait_ms(400); - down(&usb_address0_sem); + err("cannot disconnect hub %d", dev->devnum); +} -#define MAX_TRIES 5 - /* Reset the port */ - for (tries = 0; tries < MAX_TRIES ; tries++) { - usb_set_port_feature(hub, port + 1, USB_PORT_FEAT_RESET); - wait_ms(200); +#define HUB_RESET_TRIES 5 +#define HUB_PROBE_TRIES 2 +#define HUB_SHORT_RESET_TIME 10 +#define HUB_LONG_RESET_TIME 200 +#define HUB_RESET_TIMEOUT 500 + +static int usb_hub_port_wait_reset(struct usb_device *hub, int port, + struct usb_device *dev, unsigned int delay) +{ + int delay_time, ret; + struct usb_port_status portsts; + unsigned short portchange, portstatus; + + for (delay_time = 0; delay_time < HUB_RESET_TIMEOUT; delay_time += delay) { + /* wait to give the device a chance to reset */ + wait_ms(delay); + /* read and decode port status */ ret = usb_get_port_status(hub, port + 1, &portsts); if (ret < 0) { err("get_port_status(%d) failed (err = %d)", port + 1, ret); - goto out; + return -1; } portstatus = le16_to_cpu(portsts.wPortStatus); portchange = le16_to_cpu(portsts.wPortChange); - dbg("portstatus %x, change %x, %s", portstatus ,portchange, - portstatus&(1<slow = (portstatus & USB_PORT_STAT_LOW_SPEED) ? 1 : 0; + return 0; + } - wait_ms(200); + /* switch to the long delay after two short delay failures */ + if (delay_time >= 2 * HUB_SHORT_RESET_TIME) + delay = HUB_LONG_RESET_TIME; + + dbg("port %d of hub %d not reset yet, waiting %dms", port + 1, + hub->devnum, delay); } - if (tries >= MAX_TRIES) { - err("Cannot enable port %i after %i retries, disabling port.", port+1, MAX_TRIES); - err("Maybe the USB cable is bad?"); - goto out; + return -1; +} + +static int usb_hub_port_reset(struct usb_device *hub, int port, + struct usb_device *dev, unsigned int delay) +{ + int i; + + /* Reset the port */ + for (i = 0; i < HUB_RESET_TRIES; i++) { + usb_set_port_feature(hub, port + 1, USB_PORT_FEAT_RESET); + + /* return success if the port reset OK */ + if (!usb_hub_port_wait_reset(hub, port, dev, delay)) { + usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_C_RESET); + return 0; + } + + dbg("port %d of hub %d not enabled, trying reset again...", + port + 1, hub->devnum); + delay = HUB_LONG_RESET_TIME; } - usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_C_RESET); + err("Cannot enable port %i of hub %d, disabling port.", + port + 1, hub->devnum); + err("Maybe the USB cable is bad?"); + + return -1; +} + +void usb_hub_port_disable(struct usb_device *hub, int port) +{ + int ret; + + ret = usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_ENABLE); + if (ret) + err("cannot disable port %d of hub %d (err = %d)", + port + 1, hub->devnum, ret); +} + +static void usb_hub_port_connect_change(struct usb_device *hub, int port, + struct usb_port_status *portsts) +{ + struct usb_device *dev; + unsigned short portstatus, portchange; + unsigned int delay = HUB_SHORT_RESET_TIME; + int i; + char *portstr, *tempstr; + + portstatus = le16_to_cpu(portsts->wPortStatus); + portchange = le16_to_cpu(portsts->wPortChange); + dbg("port %d, portstatus %x, change %x, %s", port + 1, portstatus, + portchange, portstatus & (1 << USB_PORT_FEAT_LOWSPEED) ? "1.5 Mb/s" : "12 Mb/s"); + + /* Clear the connection change status */ + usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_C_CONNECTION); - /* Allocate a new device struct for it */ - usb = usb_alloc_dev(hub, hub->bus); - if (!usb) { - err("couldn't allocate usb_device"); - goto out; + /* Disconnect any existing devices under this port */ + if (hub->children[port]) + usb_disconnect(&hub->children[port]); + + /* Return now if nothing is connected */ + if (!(portstatus & USB_PORT_STAT_CONNECTION)) { + if (portstatus & USB_PORT_STAT_ENABLE) + usb_hub_port_disable(hub, port); + + return; } - usb->slow = (portstatus & USB_PORT_STAT_LOW_SPEED) ? 1 : 0; + down(&usb_address0_sem); - hub->children[port] = usb; + tempstr = kmalloc(1024, GFP_KERNEL); + portstr = kmalloc(1024, GFP_KERNEL); + if (portstr) + portstr[0] = 0; + + for (i = 0; i < HUB_PROBE_TRIES; i++) { + struct usb_device *pdev, *cdev; + + /* Allocate a new device struct */ + dev = usb_alloc_dev(hub, hub->bus); + if (!dev) { + err("couldn't allocate usb_device"); + break; + } - /* Find a new device ID for it */ - usb_connect(usb); + hub->children[port] = dev; - /* Run it through the hoops (find a driver, etc) */ - ret = usb_new_device(usb); - if (ret) { - /* Try resetting the device. Windows does this and it */ - /* gets some devices working correctly */ - usb_set_port_feature(hub, port + 1, USB_PORT_FEAT_RESET); + /* Reset the device */ + if (usb_hub_port_reset(hub, port, dev, delay)) { + usb_free_dev(dev); + break; + } - ret = usb_new_device(usb); - if (ret) { - usb_disconnect(&hub->children[port]); + /* Find a new device ID for it */ + usb_connect(dev); - /* Woops, disable the port */ - dbg("hub: disabling port %d", port + 1); - usb_clear_port_feature(hub, port + 1, - USB_PORT_FEAT_ENABLE); + /* Create a readable topology string */ + cdev = dev; + pdev = dev->parent; + if (portstr && tempstr) { + while (pdev) { + int port; + + for (port = 0; port < pdev->maxchild; port++) + if (pdev->children[port] == cdev) + break; + + strcpy(tempstr, portstr); + if (!strlen(tempstr)) + sprintf(portstr, "%d", port + 1); + else + sprintf(portstr, "%d/%s", port + 1, tempstr); + + cdev = pdev; + pdev = pdev->parent; + } } + + if (portstr) + info("USB new device connect on bus%d/%s, assigned device number %d", + dev->bus->busnum, portstr, dev->devnum); + else + info("USB new device connect on bus%d, assigned device number %d", + dev->bus->busnum, dev->devnum); + + if (portstr) + kfree(portstr); + if (tempstr) + kfree(tempstr); + + /* Run it through the hoops (find a driver, etc) */ + if (!usb_new_device(dev)) { + up(&usb_address0_sem); + return; + } + + /* Free the configuration if there was an error */ + usb_free_dev(dev); + + /* Switch to a long reset time */ + delay = HUB_LONG_RESET_TIME; } -out: + hub->children[port] = NULL; + usb_hub_port_disable(hub, port); up(&usb_address0_sem); } static void usb_hub_events(void) { unsigned long flags; - int i; struct list_head *tmp; struct usb_device *dev; struct usb_hub *hub; struct usb_hub_status hubsts; unsigned short hubstatus, hubchange; + int i, ret; /* * We restart the list everytime to avoid a deadlock with @@ -504,12 +648,26 @@ spin_unlock_irqrestore(&hub_event_lock, flags); + if (hub->error) { + dbg("resetting hub %d for error %d", dev->devnum, hub->error); + + if (usb_hub_reset(hub)) { + err("error resetting hub %d - disconnecting", dev->devnum); + usb_hub_disconnect(dev); + continue; + } + + hub->nerrors = 0; + hub->error = 0; + } + for (i = 0; i < hub->nports; i++) { struct usb_port_status portsts; unsigned short portstatus, portchange; - if (usb_get_port_status(dev, i + 1, &portsts) < 0) { - err("get_port_status failed"); + ret = usb_get_port_status(dev, i + 1, &portsts); + if (ret < 0) { + err("get_port_status failed (err = %d)", ret); continue; } @@ -519,27 +677,27 @@ if (portchange & USB_PORT_STAT_C_CONNECTION) { dbg("port %d connection change", i + 1); - usb_hub_port_connect_change(dev, i); - } - - if (portchange & USB_PORT_STAT_C_ENABLE) { + usb_hub_port_connect_change(dev, i, &portsts); + } else if (portchange & USB_PORT_STAT_C_ENABLE) { dbg("port %d enable change, status %x", i + 1, portstatus); usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_ENABLE); - // EM interference sometimes causes bad shielded USB devices to - // be shutdown by the hub, this hack enables them again. - // Works at least with mouse driver. + /* + * EM interference sometimes causes bad shielded USB devices to + * be shutdown by the hub, this hack enables them again. + * Works at least with mouse driver. + */ if (!(portstatus & USB_PORT_STAT_ENABLE) && (portstatus & USB_PORT_STAT_CONNECTION) && (dev->children[i])) { err("already running port %i disabled by hub (EMI?), re-enabling...", i + 1); - usb_hub_port_connect_change(dev, i); + usb_hub_port_connect_change(dev, i, &portsts); } } - if (portstatus & USB_PORT_STAT_SUSPEND) { + if (portchange & USB_PORT_STAT_C_SUSPEND) { dbg("port %d suspend change", i + 1); - usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_SUSPEND); + usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_SUSPEND); } if (portchange & USB_PORT_STAT_C_OVERCURRENT) { @@ -555,9 +713,9 @@ } /* end for i */ /* deal with hub status changes */ - if (usb_get_hub_status(dev, &hubsts) < 0) { + if (usb_get_hub_status(dev, &hubsts) < 0) err("get_hub_status failed"); - } else { + else { hubstatus = le16_to_cpup(&hubsts.wHubStatus); hubchange = le16_to_cpup(&hubsts.wHubChange); if (hubchange & HUB_CHANGE_LOCAL_POWER) { @@ -566,7 +724,7 @@ } if (hubchange & HUB_CHANGE_OVERCURRENT) { dbg("hub overcurrent change"); - wait_ms(500); //Cool down + wait_ms(500); /* Cool down */ usb_clear_hub_feature(dev, C_HUB_OVER_CURRENT); usb_hub_power_on(hub); } @@ -660,7 +818,7 @@ } /* - * Hub resources are freed for us by usb_deregister. It + * Hub resources are freed for us by usb_deregister. It calls * usb_driver_purge on every device which in turn calls that * devices disconnect function if it is using this driver. * The hub_disconnect function takes care of releasing the @@ -701,23 +859,23 @@ down(&usb_address0_sem); /* Send a reset to the device */ - usb_set_port_feature(parent, port + 1, USB_PORT_FEAT_RESET); - - wait_ms(200); - - usb_clear_port_feature(parent, port + 1, USB_PORT_FEAT_C_RESET); + if (usb_hub_port_reset(parent, port, dev, HUB_SHORT_RESET_TIME)) { + usb_hub_port_disable(parent, port); + up(&usb_address0_sem); + return(-ENODEV); + } /* Reprogram the Address */ ret = usb_set_address(dev); if (ret < 0) { err("USB device not accepting new address (error=%d)", ret); - clear_bit(dev->devnum, &dev->bus->devmap.devicemap); - dev->devnum = -1; + usb_hub_port_disable(parent, port); up(&usb_address0_sem); return ret; } - wait_ms(10); /* Let the SET_ADDRESS settle */ + /* Let the SET_ADDRESS settle */ + wait_ms(10); up(&usb_address0_sem); @@ -768,30 +926,23 @@ usb_set_maxpacket(dev); return 1; - } else { - ret = usb_set_configuration(dev, - dev->actconfig->bConfigurationValue); - if (ret < 0) { - err("failed to set active configuration (error=%d)", - ret); - return ret; - } + } - for (i = 0; i < dev->actconfig->bNumInterfaces; i++) { - struct usb_interface *intf = - &dev->actconfig->interface[i]; - struct usb_interface_descriptor *as = - &intf->altsetting[intf->act_altsetting]; + ret = usb_set_configuration(dev, dev->actconfig->bConfigurationValue); + if (ret < 0) { + err("failed to set active configuration (error=%d)", ret); + return ret; + } - ret = usb_set_interface(dev, as->bInterfaceNumber, - as->bAlternateSetting); - if (ret < 0) { - err("failed to set active alternate setting for interface %d (error=%d)", i, ret); - return ret; - } - } + for (i = 0; i < dev->actconfig->bNumInterfaces; i++) { + struct usb_interface *intf = &dev->actconfig->interface[i]; + struct usb_interface_descriptor *as = &intf->altsetting[intf->act_altsetting]; - return 0; + ret = usb_set_interface(dev, as->bInterfaceNumber, as->bAlternateSetting); + if (ret < 0) { + err("failed to set active alternate setting for interface %d (error=%d)", i, ret); + return ret; + } } return 0; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/usb/hub.h linux/drivers/usb/hub.h --- v2.4.0-test8/linux/drivers/usb/hub.h Mon Jun 19 13:42:41 2000 +++ linux/drivers/usb/hub.h Tue Sep 19 15:33:36 2000 @@ -82,47 +82,32 @@ __u16 wHubCharacteristics; __u8 bPwrOn2PwrGood; __u8 bHubContrCurrent; + /* DeviceRemovable and PortPwrCtrlMask want to be variable-length bitmaps that hold max 256 entries, but for now they're ignored */ + __u8 bitmap[0]; } __attribute__ ((packed)); struct usb_device; -typedef enum { - USB_PORT_UNPOWERED = 0, /* Default state */ - USB_PORT_POWERED, /* When we've put power to it */ - USB_PORT_ENABLED, /* When it's been enabled */ - USB_PORT_DISABLED, /* If it's been disabled */ - USB_PORT_ADMINDISABLED, /* Forced down */ -} usb_hub_port_state; - -struct usb_hub_port { - usb_hub_port_state cstate; /* Configuration state */ - - struct usb_device *child; /* Device attached to this port */ - - struct usb_hub *parent; /* Parent hub */ -}; - struct usb_hub { - /* Device structure */ struct usb_device *dev; - /* Interrupt polling pipe */ - struct urb *urb; + struct urb *urb; /* Interrupt polling pipe */ char buffer[USB_MAXCHILDREN / 8]; - /* List of hubs */ + int error; + int nerrors; + struct list_head hub_list; - /* Temporary event list */ struct list_head event_list; /* Number of ports on the hub */ int nports; - struct usb_hub_port ports[0]; /* Dynamically allocated */ + struct usb_hub_descriptor *descriptor; }; #endif diff -u --recursive --new-file v2.4.0-test8/linux/drivers/usb/microtek.c linux/drivers/usb/microtek.c --- v2.4.0-test8/linux/drivers/usb/microtek.c Thu Sep 7 08:42:37 2000 +++ linux/drivers/usb/microtek.c Mon Sep 18 17:31:14 2000 @@ -98,10 +98,12 @@ * 20000603 Version 0.2.1 * 20000620 minor cosmetic changes * 20000620 Version 0.2.2 - * 20000822 Hopefully fixed deadlock in mts_remove_nolock() - * 20000822 Fixed minor race in mts_transfer_cleanup() - * 20000822 Fixed deadlock on submission error in queuecommand - * 20000822 Version 0.2.3 + * 20000822 Hopefully fixed deadlock in mts_remove_nolock() + * 20000822 Fixed minor race in mts_transfer_cleanup() + * 20000822 Fixed deadlock on submission error in queuecommand + * 20000822 Version 0.2.3 + * 20000913 Reduced module size if debugging is off + * 20000913 Version 0.2.4 */ #include @@ -151,7 +153,7 @@ /* Internal driver stuff */ -#define MTS_VERSION "0.2.3" +#define MTS_VERSION "0.2.4" #define MTS_NAME "microtek usb (rev " MTS_VERSION "): " #define MTS_WARNING(x...) \ @@ -198,6 +200,8 @@ MTS_DEBUG_INT();\ } while (0) +#ifdef MTS_DO_DEBUG + static inline void mts_debug_dump(struct mts_desc* desc) { MTS_DEBUG("desc at 0x%x: halted = %x%x, toggle = %x%x\n", (int)desc,(int)desc->usb_dev->halted[1],(int)desc->usb_dev->halted[0], @@ -292,6 +296,23 @@ srb->cmnd[0], srb->cmnd[1], srb->cmnd[2], srb->cmnd[3], srb->cmnd[4], srb->cmnd[5], srb->cmnd[6], srb->cmnd[7], srb->cmnd[8], srb->cmnd[9]); } + +#else + +static inline void mts_show_command(Scsi_Cmnd *srb) +{ + while (0) {} +} + +static inline void mts_debug_dump(struct mts_desc* desc) +{ + while (0) {} +} + +#endif + + + static inline int mts_is_aborting(struct mts_desc* desc) { return (atomic_read(&desc->context.do_abort)); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/usb/net1080.c linux/drivers/usb/net1080.c --- v2.4.0-test8/linux/drivers/usb/net1080.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/net1080.c Tue Sep 19 08:31:53 2000 @@ -0,0 +1,1099 @@ +/* + * NetChip 1080 Driver (USB Host-to-Host Link) + * Copyright (C) 2000 by David Brownell + */ + +/* + * This talks to the NetChip 1080, which can appear in "network cables" + * and other designs. This driver interoperates with the Win32 network + * drivers from NetChip, using the NetChip reference design. + * + * The IP-over-USB protocol here may be of interest. Embedded devices + * could implement it at the cost of two bulk endpoints, and whatever + * other system resources the desired IP-based applications need. + * Some Linux palmtops could support that today. + * + * STATUS: + * + * 13-sept-2000 experimental, new + * + * This doesn't yet do any network hotplugging, and there's no matching + * ifup policy script ... it should arrange bridging with "brctl", and + * should handle static and dynamic ("pump") setups. + * + * RX/TX queue sizes currently fixed at one due to URB unlink problems. + * + *-------------------------------------------------------------------------*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEBUG // error path messages +// #define VERBOSE // more; success messages +#define USE_TTL // timeout our reads + +#if !defined (DEBUG) && defined (CONFIG_USB_DEBUG) +# define DEBUG +#endif +#include + + +static const struct product { + char *name; + u16 idVendor; + u16 idProduct; +} products [] = { + { "NetChip TurboCONNECT", 0x0525, 0x1080 }, // reference + // Belkin, ... + { 0, 0, 0 }, // END +}; + +static u8 node_id [ETH_ALEN]; + + +/*------------------------------------------------------------------------- + * + * NetChip protocol: ethernet framing, and only use bulk endpoints (01/81; + * not mailboxes 02/82 or status interrupt 83). Expects Ethernet bridging. + * Odd USB length == always short read. + * - nc_header + * - payload, in Ethernet framing (14 byte header etc) + * - (optional padding byte, if needed so length is odd) + * - nc_trailer + */ + +struct nc_header { + u16 hdr_len; // sizeof nc_header (LE, all) + u16 packet_len; // packet size + u16 packet_id; // detects dropped packets +#define NC_MIN_HEADER 6 + + // all else is optional, and must start with: + // u16 vendorId; // from usb-if + // u16 productId; +}; + +#define NC_PAD_BYTE ((unsigned char)0xAC) + +struct nc_trailer { + u16 packet_id; +}; + +// packetsize == f(mtu setting), with upper limit +#define NC_MAX_PACKET(mtu) (sizeof (struct nc_header) \ + + (mtu) \ + + 1 \ + + sizeof (struct nc_trailer)) + +// zero means no timeout; else, how long a 64 byte bulk +// read may be queued before HW flushes it. +#define NC_READ_TTL ((u8)255) // ms + + +/*-------------------------------------------------------------------------*/ + +// list of all devices we manage +static DECLARE_MUTEX (net1080_mutex); +static LIST_HEAD (net1080_list); + + +// Nineteen USB 1.1 max size bulk transactions per frame, max. +#if 0 +#define RX_QLEN 4 +#define TX_QLEN 4 + +#else +// unlink_urbs() has probs on OHCI without test8-pre patches. +#define RX_QLEN 1 +#define TX_QLEN 1 +#endif + +enum skb_state { + illegal = 0, + tx_start, tx_done, + rx_start, rx_done, rx_cleanup +}; + +struct skb_data { // skb->cb is one of these + struct urb *urb; + struct net1080 *dev; + enum skb_state state; + size_t length; +}; + + +struct net1080 { + // housekeeping + struct usb_device *udev; + const struct product *prod_info; + struct semaphore mutex; + struct list_head dev_list; + wait_queue_head_t *wait; + + // protocol/interface state + struct net_device net; + struct net_device_stats stats; + u16 packet_id; + + // various kinds of pending driver work + struct sk_buff_head rxq; + struct sk_buff_head txq; + struct sk_buff_head done; + struct tasklet_struct bh; +}; + +#define mutex_lock(x) down(x) +#define mutex_unlock(x) up(x) + +static void defer_bh (struct net1080 *dev, struct sk_buff *skb) +{ + unsigned long flags; + + skb_unlink (skb); + spin_lock_irqsave (&dev->done.lock, flags); + __skb_queue_tail (&dev->done, skb); + if (dev->done.qlen == 1) + tasklet_schedule (&dev->bh); + spin_unlock_irqrestore (&dev->done.lock, flags); +} + +/*------------------------------------------------------------------------- + * + * We ignore most registers and EEPROM contents. + */ + +#define REG_USBCTL ((u8)0x04) +#define REG_TTL ((u8)0x10) +#define REG_STATUS ((u8)0x11) + +/* + * Vendor specific requests to read/write data + */ + +#define REQUEST_REGISTER ((u8)0x10) +#define REQUEST_EEPROM ((u8)0x11) + +#define CONTROL_TIMEOUT (500) /* msec */ + +static int +vendor_read (struct net1080 *dev, u8 req, u8 regnum, u16 *retval_ptr) +{ + int status = usb_control_msg (dev->udev, + usb_rcvctrlpipe (dev->udev, 0), + req, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, regnum, + retval_ptr, sizeof *retval_ptr, + CONTROL_TIMEOUT); + if (status > 0) + status = 0; + if (!status) + le16_to_cpus (retval_ptr); + return status; +} + +static inline int +register_read (struct net1080 *dev, u8 regnum, u16 *retval_ptr) +{ + return vendor_read (dev, REQUEST_REGISTER, regnum, retval_ptr); +} + +// without retval, this can become fully async (usable in_interrupt) +static void +vendor_write (struct net1080 *dev, u8 req, u8 regnum, u16 value) +{ + usb_control_msg (dev->udev, + usb_sndctrlpipe (dev->udev, 0), + req, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, regnum, + 0, 0, // data is in setup packet + CONTROL_TIMEOUT); +} + +static inline void +register_write (struct net1080 *dev, u8 regnum, u16 value) +{ + vendor_write (dev, REQUEST_REGISTER, regnum, value); +} + + +#if 0 +static void dump_registers (struct net1080 *dev) +{ + u8 reg; + u16 value; + + dbg ("%s registers:", dev->net.name); + for (reg = 0; reg < 0x20; reg++) { + int retval; + + // reading some registers is trouble + if (reg >= 0x08 && reg <= 0xf) + continue; + if (reg >= 0x12 && reg <= 0x1e) + continue; + + retval = register_read (dev, reg, &value); + if (retval < 0) + dbg ("%s reg [0x%x] ==> error %d", + dev->net.name, reg, retval); + else + dbg ("%s reg [0x%x] = 0x%x", + dev->net.name, reg, value); + } +} +#endif + + +/*------------------------------------------------------------------------- + * + * Control register + */ + +#define USBCTL_WRITABLE_MASK 0x1f0f +// bits 15-13 reserved, r/o +#define USBCTL_ENABLE_LANG (1 << 12) +#define USBCTL_ENABLE_MFGR (1 << 11) +#define USBCTL_ENABLE_PROD (1 << 10) +#define USBCTL_ENABLE_SERIAL (1 << 9) +#define USBCTL_ENABLE_DEFAULTS (1 << 8) +// bits 7-4 reserved, r/o +#define USBCTL_FLUSH_OTHER (1 << 3) +#define USBCTL_FLUSH_THIS (1 << 2) +#define USBCTL_DISCONN_OTHER (1 << 1) +#define USBCTL_DISCONN_THIS (1 << 0) + +#ifdef DEBUG +static void dump_usbctl (struct net1080 *dev, u16 usbctl) +{ + dbg ("%s: USB %d dev %d usbctl 0x%x:%s%s%s%s%s;" + " this%s%s;" + " other%s%s; r/o 0x%x", + dev->net.name, + dev->udev->bus->busnum, dev->udev->devnum, + usbctl, + (usbctl & USBCTL_ENABLE_LANG) ? " lang" : "", + (usbctl & USBCTL_ENABLE_MFGR) ? " mfgr" : "", + (usbctl & USBCTL_ENABLE_PROD) ? " prod" : "", + (usbctl & USBCTL_ENABLE_SERIAL) ? " serial" : "", + (usbctl & USBCTL_ENABLE_DEFAULTS) ? " defaults" : "", + + (usbctl & USBCTL_FLUSH_OTHER) ? " FLUSH" : "", + (usbctl & USBCTL_DISCONN_OTHER) ? " DIS" : "", + (usbctl & USBCTL_FLUSH_THIS) ? " FLUSH" : "", + (usbctl & USBCTL_DISCONN_THIS) ? " DIS" : "", + usbctl & ~USBCTL_WRITABLE_MASK + ); +} +#else +static inline void dump_usbctl (struct net1080 *dev, u16 usbctl) {} +#endif + +/*------------------------------------------------------------------------- + * + * Status register + */ + +#define STATUS_PORT_A (1 << 15) + +#define STATUS_CONN_OTHER (1 << 14) +#define STATUS_SUSPEND_OTHER (1 << 13) +#define STATUS_MAILBOX_OTHER (1 << 12) +#define STATUS_PACKETS_OTHER(n) (((n) >> 8) && 0x03) + +#define STATUS_CONN_THIS (1 << 6) +#define STATUS_SUSPEND_THIS (1 << 5) +#define STATUS_MAILBOX_THIS (1 << 4) +#define STATUS_PACKETS_THIS(n) (((n) >> 0) && 0x03) + +#define STATUS_UNSPEC_MASK 0x0c8c +#define STATUS_NOISE_MASK ((u16)~(0x0303|STATUS_UNSPEC_MASK)) + + +#ifdef DEBUG +static void dump_status (struct net1080 *dev, u16 status) +{ + dbg ("%s: USB %d dev %d status 0x%x:" + " this (%c) PKT=%d%s%s%s;" + " other PKT=%d%s%s%s; unspec 0x%x", + dev->net.name, + dev->udev->bus->busnum, dev->udev->devnum, + status, + + // XXX the packet counts don't seem right + // (1 at reset, not 0); maybe UNSPEC too + + (status & STATUS_PORT_A) ? 'A' : 'B', + STATUS_PACKETS_THIS (status), + (status & STATUS_CONN_THIS) ? " CON" : "", + (status & STATUS_SUSPEND_THIS) ? " SUS" : "", + (status & STATUS_MAILBOX_THIS) ? " MBOX" : "", + + STATUS_PACKETS_OTHER (status), + (status & STATUS_CONN_OTHER) ? " CON" : "", + (status & STATUS_SUSPEND_OTHER) ? " SUS" : "", + (status & STATUS_MAILBOX_OTHER) ? " MBOX" : "", + + status & STATUS_UNSPEC_MASK + ); +} +#else +static inline void dump_status (struct net1080 *dev, u16 status) {} +#endif + +/*------------------------------------------------------------------------- + * + * TTL register + */ + +#define TTL_THIS(ttl) (0x00ff & ttl) +#define TTL_OTHER(ttl) (0x00ff & (ttl >> 8)) +#define MK_TTL(this,other) ((u16)(((other)<<8)|(0x00ff&(this)))) + +#ifdef DEBUG +static void dump_ttl (struct net1080 *dev, u16 ttl) +{ + dbg ("%s: USB %d dev %d ttl 0x%x this = %d, other = %d", + dev->net.name, + dev->udev->bus->busnum, dev->udev->devnum, + ttl, + + TTL_THIS (ttl), + TTL_OTHER (ttl) + ); +} +#else +static inline void dump_ttl (struct net1080 *dev, u16 ttl) {} +#endif + +#define RUN_CONTEXT (in_irq () ? "in_irq" \ + : (in_interrupt () ? "in_interrupt" : "can sleep")) + +/*-------------------------------------------------------------------------*/ + +// ensure that the device is in a known state before using it. + +// preconditions: +// caller owns the device mutex +// caller has a process context + +static int net1080_reset (struct net1080 *dev) +{ + u16 usbctl, status, ttl; + int retval; + + if ((retval = register_read (dev, REG_STATUS, &status)) < 0) { + dbg ("can't read dev %d status: %d", dev->udev->devnum, retval); + goto done; + } + dump_status (dev, status); + + if ((retval = register_read (dev, REG_USBCTL, &usbctl)) < 0) { + dbg ("can't read USBCTL, %d", retval); + goto done; + } + dump_usbctl (dev, usbctl); + + register_write (dev, REG_USBCTL, + USBCTL_FLUSH_THIS | USBCTL_FLUSH_OTHER); + + if ((retval = register_read (dev, REG_TTL, &ttl)) < 0) { + dbg ("can't read TTL, %d", retval); + goto done; + } + dump_ttl (dev, ttl); + +#ifdef USE_TTL + // Have the chip flush reads that seem to be starving for read + // bandwidth ... or we're otherwise reading. Note, Win32 drivers + // may change our read TTL for us. + + register_write (dev, REG_TTL, + MK_TTL (NC_READ_TTL, TTL_OTHER (ttl)) ); + dbg ("%s: assigned TTL, %d ms", dev->net.name, NC_READ_TTL); +#endif + + info ("%s: %s, port %c on USB %d dev %d, peer %sconnected", + dev->net.name, dev->prod_info->name, + (status & STATUS_PORT_A) ? 'A' : 'B', + dev->udev->bus->busnum, + dev->udev->devnum, + (status & STATUS_CONN_OTHER) ? "" : "dis" + ); + retval = 0; + +done: + return retval; +} + + +/*------------------------------------------------------------------------- + * + * Network Device Driver support (peer link to USB Host) + * + --------------------------------------------------------------------------*/ + +static int net1080_change_mtu (struct net_device *net, int new_mtu) +{ + if ((new_mtu < 0) || NC_MAX_PACKET (new_mtu) > 8191) + return -EINVAL; + net->mtu = new_mtu; + return 0; +} + +/*-------------------------------------------------------------------------*/ + +static struct net_device_stats *net1080_get_stats (struct net_device *net) +{ + return &((struct net1080 *) net->priv)->stats; +} + +/*-------------------------------------------------------------------------*/ + +static void rx_complete (struct urb *urb); + +static void rx_submit (struct net1080 *dev, struct urb *urb, int flags) +{ + struct sk_buff *skb; + struct skb_data *entry; + int retval = 0; + unsigned long lockflags; + + if ((skb = alloc_skb (NC_MAX_PACKET (dev->net.mtu), flags)) == 0) { + err ("no rx skb"); + tasklet_schedule (&dev->bh); + usb_free_urb (urb); + return; + } + + entry = (struct skb_data *) skb->cb; + entry->urb = urb; + entry->dev = dev; + entry->state = rx_start; + entry->length = 0; + + FILL_BULK_URB (urb, dev->udev, usb_rcvbulkpipe (dev->udev, 1), + skb->data, skb->truesize, rx_complete, skb); + urb->transfer_flags |= USB_QUEUE_BULK; + + spin_lock_irqsave (&dev->rxq.lock, lockflags); + if (!netif_queue_stopped (&dev->net)) { + if ((retval = usb_submit_urb (urb)) != 0) { + err ("%s rx submit, %d", dev->net.name, retval); + tasklet_schedule (&dev->bh); + } else { + __skb_queue_tail (&dev->rxq, skb); + } + } else { + dbg ("rx: stopped"); + retval = -ENOLINK; + } + spin_unlock_irqrestore (&dev->rxq.lock, lockflags); + if (retval) { + dev_kfree_skb_any (skb); + usb_free_urb (urb); + } +} + + +/*-------------------------------------------------------------------------*/ + +static void rx_complete (struct urb *urb) +{ + struct sk_buff *skb = (struct sk_buff *) urb->context; + struct skb_data *entry = (struct skb_data *) skb->cb; + struct net1080 *dev = entry->dev; + int urb_status = urb->status; + + urb->dev = 0; + skb->len = urb->actual_length; + entry->state = rx_done; + entry->urb = 0; + + if ((urb->transfer_flags & USB_ASYNC_UNLINK) != 0 + || netif_queue_stopped (&dev->net)) { + dbg ("rx ... shutting down"); + usb_free_urb (urb); + urb = 0; + } + + switch (urb_status) { + // success + case 0: + if (skb->len & 0x01) + break; + entry->state = rx_cleanup; + dev->stats.rx_errors++; + dev->stats.rx_length_errors++; + dbg ("even rx len %d", skb->len); + break; + + // hardware-reported interface shutdown ... which we + // typically see before khubd calls disconnect() + case -ETIMEDOUT: // usb-ohci + case -EILSEQ: // *uhci ... "crc"/timeout error + // netif_device_detach (&dev->net); + // FALLTHROUGH + + // software-driven interface shutdown + case -ECONNRESET: + entry->state = rx_cleanup; + usb_free_urb (urb); + urb = 0; + dbg ("%s ... shutdown rx (%d)", dev->net.name, urb_status); + break; + + // data overrun ... flush fifo? + case -EOVERFLOW: + dev->stats.rx_over_errors++; + // FALLTHROUGH + + default: + entry->state = rx_cleanup; + dev->stats.rx_errors++; + err ("%s rx: status %d", dev->net.name, urb_status); + break; + } + defer_bh (dev, skb); + + if (urb) { + if (!netif_queue_stopped (&dev->net)) { + rx_submit (dev, urb, GFP_ATOMIC); + return; + } else + usb_free_urb (urb); + } +#ifdef VERBOSE + dbg ("no read resubmitted"); +#endif VERBOSE +} + +/*-------------------------------------------------------------------------*/ + +// unlink pending rx/tx; completion handlers do all other cleanup + +static int unlink_urbs (struct sk_buff_head *q) +{ + unsigned long flags; + struct sk_buff *skb; + struct skb_data *entry; + int retval; + int count = 0; + + spin_lock_irqsave (&q->lock, flags); + for (skb = q->next; skb != (struct sk_buff *) q; skb = skb->next) { + entry = (struct skb_data *) skb->cb; + entry->urb->transfer_flags |= USB_ASYNC_UNLINK; + retval = usb_unlink_urb (entry->urb); + if (retval < 0) + dbg ("unlink urb err, %d", retval); + else + count++; + } + spin_unlock_irqrestore (&q->lock, flags); + return count; +} + + +/*-------------------------------------------------------------------------*/ + +// precondition: never called in_interrupt + +static int net1080_stop (struct net_device *net) +{ + struct net1080 *dev = (struct net1080 *) net->priv; + int temp; + DECLARE_WAIT_QUEUE_HEAD (unlink_wakeup); + DECLARE_WAITQUEUE (wait, current); + + mutex_lock (&dev->mutex); + + dbg ("%s stop stats: rx/tx %ld/%ld, errs %ld/%ld", net->name, + dev->stats.rx_packets, dev->stats.tx_packets, + dev->stats.rx_errors, dev->stats.tx_errors + ); + + netif_stop_queue(net); + + // ensure there are no more active urbs + add_wait_queue (&unlink_wakeup, &wait); + dev->wait = &unlink_wakeup; + temp = unlink_urbs (&dev->txq) + unlink_urbs (&dev->rxq); + + // maybe wait for deletions to finish. + if (temp) { + current->state = TASK_UNINTERRUPTIBLE; + schedule (); + dbg ("waited for %d urb completions", temp); + } + dev->wait = 0; + remove_wait_queue (&unlink_wakeup, &wait); + + mutex_unlock (&dev->mutex); + MOD_DEC_USE_COUNT; + return 0; +} + +/*-------------------------------------------------------------------------*/ + +// posts a read, and enables write queing + +// precondition: never called in_interrupt + +static int net1080_open (struct net_device *net) +{ + struct net1080 *dev = (struct net1080 *) net->priv; + int retval; + u16 status; + int i; + + MOD_INC_USE_COUNT; + mutex_lock (&dev->mutex); + + // insist peer be connected -- is this the best place? + if ((retval = register_read (dev, REG_STATUS, &status)) != 0) { + dbg ("%s open: status read failed - %d", net->name, retval); + goto done; + } + if ((status & STATUS_CONN_OTHER) != STATUS_CONN_OTHER) { + retval = -ENOLINK; + dbg ("%s open: peer not connected", net->name); + goto done; + } + + MOD_INC_USE_COUNT; + netif_start_queue (net); + for (i = 0; i < RX_QLEN; i++) + rx_submit (dev, usb_alloc_urb (0), GFP_KERNEL); + + dbg ("%s open: started queueing (rx %d, tx %d)", + net->name, RX_QLEN, TX_QLEN); +done: + mutex_unlock (&dev->mutex); + MOD_DEC_USE_COUNT; + return retval; +} + +/*-------------------------------------------------------------------------*/ + +static void tx_complete (struct urb *urb) +{ + struct sk_buff *skb = (struct sk_buff *) urb->context; + struct skb_data *entry = (struct skb_data *) skb->cb; + struct net1080 *dev = entry->dev; + + urb->dev = 0; + entry->state = tx_done; + defer_bh (dev, skb); + netif_wake_queue (&dev->net); +} + +/*-------------------------------------------------------------------------*/ + +static struct sk_buff *fixup_skb (struct sk_buff *skb) +{ + int padlen; + struct sk_buff *skb2; + + padlen = ((skb->len + sizeof (struct nc_header) + + sizeof (struct nc_trailer)) & 0x01) ? 0 : 1; + if (!skb_cloned (skb)) { + int headroom = skb_headroom (skb); + int tailroom = skb_tailroom (skb); + + if ((padlen + sizeof (struct nc_trailer)) <= tailroom + && sizeof (struct nc_header) <= headroom) + return skb; + + if ((sizeof (struct nc_header) + padlen + + sizeof (struct nc_trailer)) < + (headroom + tailroom)) { + skb->data = memmove (skb->head + + sizeof (struct nc_header), + skb->data, skb->len); + skb->tail = skb->data + skb->len; + return skb; + } + } + skb2 = skb_copy_expand (skb, + sizeof (struct nc_header), + sizeof (struct nc_trailer) + padlen, + in_interrupt () ? GFP_ATOMIC : GFP_KERNEL); + dev_kfree_skb_any (skb); + return skb2; +} + +/*-------------------------------------------------------------------------*/ + +static int net1080_start_xmit (struct sk_buff *skb, struct net_device *net) +{ + struct net1080 *dev = (struct net1080 *) net->priv; + int length = skb->len; + int retval = 0; + struct urb *urb = 0; + struct skb_data *entry; + struct nc_header *header; + struct nc_trailer *trailer; + unsigned long flags; + + if ((skb = fixup_skb (skb)) == 0) { + dbg ("can't fixup skb"); + goto drop; + } + if ((urb = usb_alloc_urb (0)) == 0) { + dbg ("no urb"); + goto drop; + } + + entry = (struct skb_data *) skb->cb; + entry->urb = urb; + entry->dev = dev; + entry->state = tx_start; + entry->length = length; + + header = (struct nc_header *) skb_push (skb, sizeof *header); + header->hdr_len = cpu_to_le16 (sizeof (*header)); + header->packet_len = cpu_to_le16 (length); + if (!((skb->len + sizeof *trailer) & 0x01)) + *skb_put (skb, 1) = NC_PAD_BYTE; + trailer = (struct nc_trailer *) skb_put (skb, sizeof *trailer); + + FILL_BULK_URB (urb, dev->udev, + usb_sndbulkpipe (dev->udev, 1), + skb->data, skb->len, tx_complete, skb); + urb->transfer_flags |= USB_QUEUE_BULK; + // FIXME urb->timeout = ...; + + spin_lock_irqsave (&dev->txq.lock, flags); + if (!netif_queue_stopped (&dev->net)) { + header->packet_id = cpu_to_le16 (dev->packet_id++); + put_unaligned (header->packet_id, &trailer->packet_id); + + netif_stop_queue (net); + if ((retval = usb_submit_urb (urb)) != 0) { + netif_start_queue (net); + dbg ("%s tx: submit urb err %d", net->name, retval); + } else { + net->trans_start = jiffies; + __skb_queue_tail (&dev->txq, skb); + if (dev->txq.qlen < TX_QLEN) + netif_start_queue (net); + } + } else + retval = -ENOLINK; + spin_unlock_irqrestore (&dev->txq.lock, flags); + + if (retval) { + dbg ("drop"); +drop: + dev->stats.tx_dropped++; + dev_kfree_skb_any (skb); + usb_free_urb (urb); +#ifdef VERBOSE + } else { + dbg ("%s: tx %p len %d", net->name, skb, length); +#endif + } + return retval; +} + + +/*-------------------------------------------------------------------------*/ + +static void rx_process (struct net1080 *dev, struct sk_buff *skb) +{ + struct nc_header *header; + struct nc_trailer *trailer; + + header = (struct nc_header *) skb->data; + le16_to_cpus (&header->hdr_len); + le16_to_cpus (&header->packet_len); + if (header->hdr_len < NC_MIN_HEADER) { + dev->stats.rx_frame_errors++; + dbg ("header too short, %d", header->hdr_len); + goto error; + } else if (header->hdr_len != sizeof *header) { + // out of band data for us? + dbg ("header OOB, %d bytes", header->hdr_len - NC_MIN_HEADER); + // switch (vendor/product ids) { ... } + } + skb_pull (skb, header->hdr_len); + + trailer = (struct nc_trailer *) + (skb->data + skb->len - sizeof *trailer); + skb_trim (skb, skb->len - sizeof *trailer); + + if ((header->packet_len & 0x01) == 0) { + if (skb->data [header->packet_len] != NC_PAD_BYTE) { + dev->stats.rx_frame_errors++; + dbg ("bad pad"); + goto error; + } + skb_trim (skb, skb->len - 1); + } + if (skb->len != header->packet_len) { + dev->stats.rx_length_errors++; + dbg ("bad packet len %d (expected %d)", + skb->len, header->packet_len); + goto error; + } + if (header->packet_id != get_unaligned (&trailer->packet_id)) { + dev->stats.rx_fifo_errors++; + dbg ("(2+ dropped) rx packet_id mismatch 0x%x 0x%x", + header->packet_id, trailer->packet_id); + goto error; + } + + if (skb->len) { + skb->dev = &dev->net; + skb->protocol = eth_type_trans (skb, &dev->net); + dev->stats.rx_packets++; + dev->stats.rx_bytes += skb->len; + +#ifdef VERBOSE + dbg ("%s: rx %p len %d, type 0x%x, id 0x%x", + dev->net.name, skb, skb->len, skb->protocol, + le16_to_cpu (header->packet_id)); +#endif + netif_rx (skb); + } else { + dbg ("drop"); +error: + dev->stats.rx_errors++; + dev_kfree_skb (skb); + } +} + +/*-------------------------------------------------------------------------*/ + +// tasklet + +// We can have a state machine in this tasklet monitor the link state, +// using async control messaging and calling attach/detach routines. + +// But then some listener ought to respond to the changes; do those +// network attach/detach notifications get to userland somehow, such +// as by calling "ifup usb0" and "ifdown usb0"? + +static void net1080_bh (unsigned long param) +{ + struct net1080 *dev = (struct net1080 *) param; + struct sk_buff *skb; + struct skb_data *entry; + + while ((skb = skb_dequeue (&dev->done))) { + entry = (struct skb_data *) skb->cb; + switch (entry->state) { + case rx_done: + rx_process (dev, skb); + continue; + case tx_done: + if (entry->urb->status) { + // can this statistic become more specific? + dev->stats.tx_errors++; + dbg ("%s tx: err %d", dev->net.name, + entry->urb->status); + } else { + dev->stats.tx_packets++; + dev->stats.tx_bytes += entry->length; + } + // FALLTHROUGH: + case rx_cleanup: + usb_free_urb (entry->urb); + dev_kfree_skb (skb); + continue; + default: + dbg ("%s: bogus skb state %d", + dev->net.name, entry->state); + } + } + + // waiting for all pending urbs to complete? + if (dev->wait) { + if ((dev->txq.qlen + dev->rxq.qlen + dev->done.qlen) == 0) { + wake_up (dev->wait); + } + + // or are we maybe short a few urbs? + } else if (!netif_queue_stopped (&dev->net)) { + if (dev->rxq.qlen < TX_QLEN) { + struct urb *urb; + int i; + for (i = 0; i < 3 && dev->rxq.qlen < TX_QLEN; i++) { + if ((urb = usb_alloc_urb (0)) != 0) + rx_submit (dev, urb, GFP_ATOMIC); + } + dbg ("%s: rxqlen now %d", + dev->net.name, dev->rxq.qlen); + } + } +} + +/*------------------------------------------------------------------------- + * + * USB Device Driver support + * + --------------------------------------------------------------------------*/ + +// precondition: never called in_interrupt + +static void net1080_disconnect (struct usb_device *udev, void *ptr) +{ + struct net1080 *dev = (struct net1080 *) ptr; + + info ("%s: USB %d dev %d, %s, disconnected", + dev->net.name, + udev->bus->busnum, udev->devnum, + dev->prod_info->name); + + unregister_netdev (&dev->net); + + mutex_lock (&net1080_mutex); + mutex_lock (&dev->mutex); + list_del (&dev->dev_list); + mutex_unlock (&net1080_mutex); + +#ifdef DEBUG + memset (dev, 0x55, sizeof *dev); +#endif + kfree (dev); + usb_dec_dev_use (udev); +} + + +/*-------------------------------------------------------------------------*/ + +// precondition: never called in_interrupt + +static void *net1080_probe (struct usb_device *udev, unsigned ifnum) +{ + int i; + struct net1080 *dev; + struct net_device *net; + struct usb_interface_descriptor *interface; + int retval; + + for (i = 0; products [i].idVendor != 0; i++) { + if (products [i].idVendor != udev->descriptor.idVendor) + continue; + if (products [i].idProduct != udev->descriptor.idProduct) + continue; + break; + } + if (products [i].idVendor == 0) + return 0; + + // sanity check; expect dedicated interface/devices for now. + interface = &udev->actconfig->interface [ifnum].altsetting[0]; + if (udev->descriptor.bNumConfigurations != 1 + || udev->config[0].bNumInterfaces != 1 + || udev->config[0].bNumInterfaces != 1 + || interface->bInterfaceClass != USB_CLASS_VENDOR_SPEC + || interface->bNumEndpoints != 5 + ) { + dbg ("Bogus config info"); + return 0; + } + + // set up our own records + if (!(dev = kmalloc (sizeof *dev, GFP_KERNEL))) { + dbg ("can't kmalloc dev"); + return 0; + } + memset (dev, 0, sizeof *dev); + + init_MUTEX_LOCKED (&dev->mutex); + usb_inc_dev_use (udev); + dev->udev = udev; + dev->prod_info = &products [i]; + INIT_LIST_HEAD (&dev->dev_list); + skb_queue_head_init (&dev->rxq); + skb_queue_head_init (&dev->txq); + skb_queue_head_init (&dev->done); + dev->bh.func = net1080_bh; + dev->bh.data = (unsigned long) dev; + + // set up network interface records + net = &dev->net; + net->priv = dev; + strcpy (net->name, "usb%d"); + memcpy (net->dev_addr, node_id, sizeof node_id); + + ether_setup (net); + // net->flags |= IFF_POINTOPOINT; + + net->change_mtu = net1080_change_mtu; + net->get_stats = net1080_get_stats; + net->hard_start_xmit = net1080_start_xmit; + net->open = net1080_open; + net->stop = net1080_stop; + + register_netdev (&dev->net); + + // ... talk to the device + // dump_registers (dev); + + if ((retval = net1080_reset (dev)) < 0) { + err ("%s: init reset fail on USB %d dev %d - %d", + dev->net.name, udev->bus->busnum, udev->devnum, retval); + mutex_unlock (&dev->mutex); + net1080_disconnect (udev, dev); + return 0; + } + + // ok, it's ready to go. + mutex_lock (&net1080_mutex); + list_add (&dev->dev_list, &net1080_list); + mutex_unlock (&dev->mutex); + + // start as if the link is up + netif_device_attach (&dev->net); + + mutex_unlock (&net1080_mutex); + + return dev; +} + + +/*-------------------------------------------------------------------------*/ + +static struct usb_driver net1080_driver = { + name: "net1080", + probe: net1080_probe, + disconnect: net1080_disconnect, +}; + +/*-------------------------------------------------------------------------*/ + +static int __init net1080_init (void) +{ + // compiler should optimize this out + if (sizeof (((struct sk_buff *)0)->cb) < sizeof (struct skb_data)) + BUG (); + + if (usb_register (&net1080_driver) < 0) + return -1; + + get_random_bytes (node_id, sizeof node_id); + node_id [0] &= 0x7f; + + return 0; +} +module_init (net1080_init); + +static void __exit net1080_exit (void) +{ + usb_deregister (&net1080_driver); +} +module_exit (net1080_exit); + +MODULE_AUTHOR ("David Brownell "); +MODULE_DESCRIPTION ("NetChip 1080 Driver (USB Host-to-Host Link)"); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/usb/ov511.c linux/drivers/usb/ov511.c --- v2.4.0-test8/linux/drivers/usb/ov511.c Mon Aug 7 21:01:36 2000 +++ linux/drivers/usb/ov511.c Tue Sep 19 11:37:59 2000 @@ -30,7 +30,7 @@ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -static const char version[] = "1.20"; +static const char version[] = "1.25"; #define __NO_VERSION__ @@ -59,11 +59,9 @@ #define MAX_FRAME_SIZE (640 * 480 * 3) #define MAX_DATA_SIZE (MAX_FRAME_SIZE + sizeof(struct timeval)) -#define DEFAULT_WIDTH 640 -#define DEFAULT_HEIGHT 480 - #define GET_SEGSIZE(p) ((p) == VIDEO_PALETTE_GREY ? 256 : 384) -#define GET_DEPTH(p) ((p) == VIDEO_PALETTE_GREY ? 8 : ((p) == VIDEO_PALETTE_YUV422 ? 8 : 24)) +#define GET_DEPTH(p) ((p) == VIDEO_PALETTE_GREY ? 8 : \ + ((p) == VIDEO_PALETTE_YUV422 ? 16 : 24)) /* PARAMETER VARIABLES: */ static int autoadjust = 1; /* CCD dynamically changes exposure, etc... */ @@ -107,6 +105,13 @@ /* Prevent apps from timing out if frame is not done in time */ static int retry_sync = 0; +/* Enable compression. This is for experimentation only; compressed images + * still cannot be decoded yet. */ +static int compress = 0; + +/* Display test pattern - doesn't work yet either */ +static int testpat = 0; + MODULE_PARM(autoadjust, "i"); MODULE_PARM_DESC(autoadjust, "CCD dynamically changes exposure"); MODULE_PARM(debug, "i"); @@ -122,21 +127,28 @@ MODULE_PARM(aperture, "i"); MODULE_PARM_DESC(aperture, "Read the OV7610/7620 specs"); MODULE_PARM(force_rgb, "i"); -MODULE_PARM_DESC(force_rgb, "Read RBG instead of BGR"); +MODULE_PARM_DESC(force_rgb, "Read RGB instead of BGR"); MODULE_PARM(buf_timeout, "i"); MODULE_PARM_DESC(buf_timeout, "Number of seconds before buffer deallocation"); MODULE_PARM(cams, "i"); MODULE_PARM_DESC(cams, "Number of simultaneous cameras"); MODULE_PARM(retry_sync, "i"); MODULE_PARM_DESC(retry_sync, "Prevent apps from timing out"); +MODULE_PARM(compress, "i"); +MODULE_PARM_DESC(compress, "Turn on compression (not functional yet)"); +MODULE_PARM(testpat, "i"); +MODULE_PARM_DESC(testpat, "Replace image with vertical bar testpattern (only partially working)"); -MODULE_AUTHOR("Mark McClelland & Bret Wallach & Orion Sky Lawlor & Kevin Moore & Charl P. Botha & Claudio Matsuoka "); +MODULE_AUTHOR("Mark McClelland & Bret Wallach & Orion Sky Lawlor & Kevin Moore & Charl P. Botha & Claudio Matsuoka "); MODULE_DESCRIPTION("OV511 USB Camera Driver"); char kernel_version[] = UTS_RELEASE; static struct usb_driver ov511_driver; +/* I know, I know, global variables suck. This is only a temporary hack */ +int output_offset; + /********************************************************************** * List of known OV511-based cameras **********************************************************************/ @@ -645,7 +657,7 @@ static void ov511_dump_i2c_regs(struct usb_device *dev) { PDEBUG(3, "I2C REGS"); - ov511_dump_i2c_range(dev, 0x00, 0x38); + ov511_dump_i2c_range(dev, 0x00, 0x7C); } #if 0 @@ -673,7 +685,7 @@ PDEBUG(1, "I2C REGS"); ov511_dump_reg_range(dev, 0x40, 0x49); PDEBUG(1, "SYSTEM CONTROL REGS"); - ov511_dump_reg_range(dev, 0x50, 0x53); + ov511_dump_reg_range(dev, 0x50, 0x55); ov511_dump_reg_range(dev, 0x5e, 0x5f); PDEBUG(1, "OmniCE REGS"); ov511_dump_reg_range(dev, 0x70, 0x79); @@ -797,15 +809,22 @@ if (ov511_i2c_write(dev, OV7610_REG_COM_B, ret & 0xfe) < 0) return -EIO; #endif - if (ov511->sensor == SEN_OV7610 || ov511->sensor == SEN_OV7620AE) - if(ov511_i2c_write(dev, OV7610_REG_SAT, p->colour >> 8) < 0) + if (ov511->sensor == SEN_OV7610 || ov511->sensor == SEN_OV7620AE + || ov511->sensor == SEN_OV6620) + if (ov511_i2c_write(dev, OV7610_REG_SAT, p->colour >> 8) < 0) return -EIO; - if (ov511->sensor == SEN_OV7610) { - if(ov511_i2c_write(dev, OV7610_REG_CNT, p->contrast >> 8) < 0) + if (ov511->sensor == SEN_OV7610 || ov511->sensor == SEN_OV6620) { + if (ov511_i2c_write(dev, OV7610_REG_CNT, p->contrast >> 8) < 0) return -EIO; - if(ov511_i2c_write(dev, OV7610_REG_BRT, p->brightness >> 8) < 0) + if (ov511_i2c_write(dev, OV7610_REG_RED, 0xFF - (p->hue >> 8)) < 0) + return -EIO; + + if (ov511_i2c_write(dev, OV7610_REG_BLUE, p->hue >> 8) < 0) + return -EIO; + + if (ov511_i2c_write(dev, OV7610_REG_BRT, p->brightness >> 8) < 0) return -EIO; } else if ((ov511->sensor == SEN_OV7620) || (ov511->sensor == SEN_OV7620AE)) { @@ -816,7 +835,7 @@ PDEBUG(1, "con=%d brt=%d", ov511_i2c_read(dev, OV7610_REG_CNT), ov511_i2c_read(dev, OV7610_REG_BRT)); - if(ov511_i2c_write(dev, OV7610_REG_CNT, p->contrast >> 8) < 0) + if (ov511_i2c_write(dev, OV7610_REG_CNT, p->contrast >> 8) < 0) return -EIO; #endif } @@ -838,16 +857,19 @@ if (ov511_stop(dev) < 0) return -EIO; - if((ret = ov511_i2c_read(dev, OV7610_REG_SAT)) < 0) return -EIO; + if ((ret = ov511_i2c_read(dev, OV7610_REG_SAT)) < 0) return -EIO; p->colour = ret << 8; - if((ret = ov511_i2c_read(dev, OV7610_REG_CNT)) < 0) return -EIO; + if ((ret = ov511_i2c_read(dev, OV7610_REG_CNT)) < 0) return -EIO; p->contrast = ret << 8; - if((ret = ov511_i2c_read(dev, OV7610_REG_BRT)) < 0) return -EIO; + if ((ret = ov511_i2c_read(dev, OV7610_REG_BRT)) < 0) return -EIO; p->brightness = ret << 8; - p->hue = 0x8000; + /* This may not be the best way to do it */ + if ((ret = ov511_i2c_read(dev, OV7610_REG_BLUE)) < 0) return -EIO; + p->hue = ret << 8; + p->whiteness = 105 << 8; /* Can we get these from frame[0]? -claudio? */ @@ -860,20 +882,23 @@ return 0; } -/* FIXME: 176x144, 160x140 */ /* LNCNT values fixed by Lawrence Glaister */ static struct mode_list mlist[] = { - /* W H C PXCNT LNCNT PXDIV LNDIV M420 COMA COMC COML */ - { 640, 480, 0, 0x4f, 0x3b, 0x00, 0x00, 0x03, 0x24, 0x04, 0x9e }, - { 640, 480, 1, 0x4f, 0x3b, 0x00, 0x00, 0x03, 0x24, 0x04, 0x9e }, - { 320, 240, 0, 0x27, 0x1d, 0x00, 0x00, 0x03, 0x04, 0x24, 0x1e }, - { 320, 240, 1, 0x27, 0x1d, 0x00, 0x00, 0x03, 0x04, 0x24, 0x1e }, - { 352, 288, 0, 0x2b, 0x25, 0x00, 0x00, 0x03, 0x04, 0x04, 0x1e }, - { 352, 288, 1, 0x2b, 0x25, 0x00, 0x00, 0x03, 0x04, 0x04, 0x1e }, - { 384, 288, 0, 0x2f, 0x25, 0x00, 0x00, 0x03, 0x04, 0x04, 0x1e }, - { 384, 288, 1, 0x2f, 0x25, 0x00, 0x00, 0x03, 0x04, 0x04, 0x1e }, - { 448, 336, 0, 0x37, 0x29, 0x00, 0x00, 0x03, 0x04, 0x04, 0x1e }, - { 448, 336, 1 ,0x37, 0x29, 0x00, 0x00, 0x03, 0x04, 0x04, 0x1e }, + /* W H C PXCNT LNCNT PXDIV LNDIV M420 COMA COML */ + { 640, 480, 0, 0x4f, 0x3b, 0x00, 0x00, 0x03, 0x24, 0x9e }, + { 640, 480, 1, 0x4f, 0x3b, 0x00, 0x00, 0x03, 0x24, 0x9e }, + { 320, 240, 0, 0x27, 0x1d, 0x00, 0x00, 0x03, 0x04, 0x1e }, + { 320, 240, 1, 0x27, 0x1d, 0x00, 0x00, 0x03, 0x04, 0x1e }, + { 352, 288, 0, 0x2b, 0x25, 0x00, 0x00, 0x03, 0x04, 0x1e }, + { 352, 288, 1, 0x2b, 0x25, 0x00, 0x00, 0x03, 0x04, 0x1e }, + { 384, 288, 0, 0x2f, 0x25, 0x00, 0x00, 0x03, 0x04, 0x1e }, + { 384, 288, 1, 0x2f, 0x25, 0x00, 0x00, 0x03, 0x04, 0x1e }, + { 448, 336, 0, 0x37, 0x29, 0x00, 0x00, 0x03, 0x04, 0x1e }, + { 448, 336, 1, 0x37, 0x29, 0x00, 0x00, 0x03, 0x04, 0x1e }, + { 176, 144, 0, 0x15, 0x12, 0x00, 0x00, 0x03, 0x04, 0x1e }, + { 176, 144, 1, 0x15, 0x12, 0x00, 0x00, 0x03, 0x04, 0x1e }, + { 160, 120, 0, 0x13, 0x0e, 0x00, 0x00, 0x03, 0x04, 0x1e }, + { 160, 120, 1, 0x13, 0x0e, 0x00, 0x00, 0x03, 0x04, 0x1e }, { 0, 0 } }; @@ -883,7 +908,8 @@ { int i; struct usb_device *dev = ov511->dev; - int hwsbase = 0, hwebase = 0; + int hwsbase, hwebase, vwsbase, vwebase, hwsize, vwsize; + int hwscale = 0, vwscale = 0; PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d", width, height, mode, sub_flag); @@ -895,7 +921,7 @@ ov511_reg_write(dev, 0x16, 0x00); if (ov511->sensor == SEN_OV7610 || ov511->sensor == SEN_OV7620AE) { - /* these aren't valid on the OV7620 */ + /* these aren't valid on the OV6620/OV7620 */ ov511_i2c_write(dev, 0x0e, 0x44); } ov511_i2c_write(dev, 0x13, autoadjust ? 0x21 : 0x20); @@ -907,7 +933,7 @@ ov511_reg_write(dev, 0x16, 0x01); if (ov511->sensor == SEN_OV7610 || ov511->sensor == SEN_OV7620AE) { - /* not valid on the OV7620 */ + /* not valid on the OV6620/OV7620 */ ov511_i2c_write(dev, 0x0e, 0x04); } ov511_i2c_write(dev, 0x13, autoadjust ? 0x01 : 0x00); @@ -923,27 +949,64 @@ case SEN_OV7620AE: hwsbase = 0x38; hwebase = 0x3a; + vwsbase = vwebase = 0x05; + break; + case SEN_OV6620: + hwsbase = 0x38; + hwebase = 0x39; + vwsbase = 0x03; + vwebase = 0x04; break; case SEN_OV7620: hwsbase = 0x2c; hwebase = 0x2d; + vwsbase = vwebase = 0x05; break; default: - hwsbase = 0; - hwebase = 0; - break; + err("Invalid sensor"); + return -EINVAL; + } + + /* Bit 5 of COM C register varies with sensor */ + if (ov511->sensor == SEN_OV6620) { + if (width > 176 && height > 144) { /* CIF */ + ov511_i2c_write(dev, 0x14, 0x04); + hwscale = 1; + vwscale = 1; /* The datasheet says 0; it's wrong */ + hwsize = 352; + vwsize = 288; + } else { /* QCIF */ + ov511_i2c_write(dev, 0x14, 0x24); + hwsize = 176; + vwsize = 144; + } + } + else { + if (width > 320 && height > 240) { /* VGA */ + ov511_i2c_write(dev, 0x14, 0x04); + hwscale = 2; + vwscale = 1; + hwsize = 640; + vwsize = 480; + } else { /* QVGA */ + ov511_i2c_write(dev, 0x14, 0x24); + hwscale = 1; + hwsize = 320; + vwsize = 240; + } } + /* FIXME! - This needs to be changed to support 160x120 and 6620!!! */ if (sub_flag) { - ov511_i2c_write(dev, 0x17, hwsbase+(ov511->subx>>2)); - ov511_i2c_write(dev, 0x18, hwebase+((ov511->subx+ov511->subw)>>2)); - ov511_i2c_write(dev, 0x19, 0x5+(ov511->suby>>1)); - ov511_i2c_write(dev, 0x1a, 0x5+((ov511->suby+ov511->subh)>>1)); + ov511_i2c_write(dev, 0x17, hwsbase+(ov511->subx>>hwscale)); + ov511_i2c_write(dev, 0x18, hwebase+((ov511->subx+ov511->subw)>>hwscale)); + ov511_i2c_write(dev, 0x19, vwsbase+(ov511->suby>>vwscale)); + ov511_i2c_write(dev, 0x1a, vwebase+((ov511->suby+ov511->subh)>>vwscale)); } else { ov511_i2c_write(dev, 0x17, hwsbase); - ov511_i2c_write(dev, 0x18, hwebase + (640>>2)); - ov511_i2c_write(dev, 0x19, 0x5); - ov511_i2c_write(dev, 0x1a, 5 + (480>>1)); + ov511_i2c_write(dev, 0x18, hwebase + (hwsize>>hwscale)); + ov511_i2c_write(dev, 0x19, vwsbase); + ov511_i2c_write(dev, 0x1a, vwebase + (vwsize>>vwscale)); } for (i = 0; mlist[i].width; i++) { @@ -981,17 +1044,22 @@ #ifdef OV511_GBR422 ov511_i2c_write(dev, 0x12, mlist[i].common_A | 0x08); #else - ov511_i2c_write(dev, 0x12, mlist[i].common_A); + ov511_i2c_write(dev, 0x12, mlist[i].common_A | (testpat?0x02:0x00)); #endif - ov511_i2c_write(dev, 0x14, mlist[i].common_C); - /* 7620 doesn't have register 0x35, so play it safe */ - if (ov511->sensor != SEN_OV7620) + /* 7620/6620 don't have register 0x35, so play it safe */ + if (ov511->sensor == SEN_OV7610 || + ov511->sensor == SEN_OV7620AE) ov511_i2c_write(dev, 0x35, mlist[i].common_L); break; } + if (compress) { + ov511_reg_write(dev, 0x78, 0x03); // Turn on Y compression + ov511_reg_write(dev, 0x79, 0x00); // Disable LUTs + } + if (ov511_restart(ov511->dev) < 0) return -EIO; @@ -1028,6 +1096,16 @@ * * To avoid floating point arithmetic, the color conversion * coefficients are scaled into 16.16 fixed-point integers. + * They were determined as follows: + * + * double brightness = 1.0; (0->black; 1->full scale) + * double saturation = 1.0; (0->greyscale; 1->full color) + * double fixScale = brightness * 256 * 256; + * int rvScale = (int)(1.402 * saturation * fixScale); + * int guScale = (int)(-0.344136 * saturation * fixScale); + * int gvScale = (int)(-0.714136 * saturation * fixScale); + * int buScale = (int)(1.772 * saturation * fixScale); + * int yScale = (int)(fixScale); */ /* LIMIT: convert a 16.16 fixed-point value to a byte, with clipping. */ @@ -1037,14 +1115,11 @@ ov511_move_420_block(int yTL, int yTR, int yBL, int yBR, int u, int v, int rowPixels, unsigned char * rgb) { - const double brightness = 1.0; /* 0->black; 1->full scale */ - const double saturation = 1.0; /* 0->greyscale; 1->full color */ - const double fixScale = brightness * 256 * 256; - const int rvScale = (int)(1.402 * saturation * fixScale); - const int guScale = (int)(-0.344136 * saturation * fixScale); - const int gvScale = (int)(-0.714136 * saturation * fixScale); - const int buScale = (int)(1.772 * saturation * fixScale); - const int yScale = (int)(fixScale); + const int rvScale = 91881; + const int guScale = -22553; + const int gvScale = -46801; + const int buScale = 116129; + const int yScale = 65536; int r, g, b; g = guScale * u + gvScale * v; @@ -1104,6 +1179,9 @@ #undef OV511_DUMPPIX +/* #define this and OV511_DUMPPIX to disable parsing of UV data */ +#undef OV511_FORCE_MONO + #ifdef OV511_GBR422 static void ov511_parse_data_rgb24(unsigned char *pIn0, unsigned char *pOut0, @@ -1234,6 +1312,8 @@ } } #else + +#ifndef OV511_FORCE_MONO /* Just dump pix data straight out for debug */ int i, j; @@ -1246,95 +1326,124 @@ } pOut0 += (iWidth - WDIV) * 3; } +#else + +#if 1 + /* This converts the Y data to "black-and-white" RGB data */ + /* Useful for experimenting with compression */ + int k, l, m; + unsigned char *pIn, *pOut, *pOut1; + + pIn = pIn0 + 128; + pOut = pOut0 + iOutY; + for (k = 0; k < 4; k++) { + pOut1 = pOut; + for (l = 0; l < 8; l++) { + for (m = 0; m < 8; m++) { + *pOut1++ = *pIn; + *pOut1++ = *pIn; + *pOut1++ = *pIn++; + } + pOut1 += (iWidth - 8) * 3; + } + pOut += 8 * 3; + } +#else + /* This will dump the Y channel data stream as-is */ + int count; + unsigned char *pIn, *pOut; + + pIn = pIn0 + 128; + pOut = pOut0 + output_offset; + for (count = 0; count < 256; count++) { + *pOut++ = *pIn; + *pOut++ = *pIn; + *pOut++ = *pIn++; + output_offset += 3; + } +#endif + +#endif + #endif } #endif +/* This converts YUV420 segments to YUYV */ static void ov511_parse_data_yuv422(unsigned char *pIn0, unsigned char *pOut0, - int iOutY, int iOutUV, int iHalf, int iWidth) + int iOutY, int iOutUV, int iWidth) { int k, l, m; - unsigned char *pIn; - unsigned char *pOut, *pOut1; + unsigned char *pIn, *pOut, *pOut1; - /* Just copy the Y's if in the first stripe */ - if (!iHalf) { - pIn = pIn0 + 128; - pOut = pOut0 + iOutY; - for (k = 0; k < 4; k++) { - pOut1 = pOut; - for (l = 0; l < 8; l++) { - for (m = 0; m < 8; m++) { - *pOut1++ = (*pIn++) & 0xF0; - } - pOut1 += iWidth - 8; + pIn = pIn0 + 128; + pOut = pOut0 + iOutY; + for (k = 0; k < 4; k++) { + pOut1 = pOut; + for (l = 0; l < 8; l++) { + for (m = 0; m < 8; m++) { + *pOut1 = (*pIn++); + pOut1 += 2; } - pOut += 8; + pOut1 += (iWidth - 8) * 2; } + pOut += 8 * 2; } - /* Use the first half of VUs to calculate value */ pIn = pIn0; - pOut = pOut0 + iOutUV; - for (l = 0; l < 4; l++) { + pOut = pOut0 + iOutUV + 1; + for (l = 0; l < 8; l++) { for (m=0; m<8; m++) { - unsigned char *p00 = pOut; - unsigned char *p01 = pOut+1; - unsigned char *p10 = pOut+iWidth; - unsigned char *p11 = pOut+iWidth+1; - int v = *(pIn+64) - 128; - int u = *pIn++ - 128; - int uv = ((u >> 4) & 0x0C) + (v >> 6); - - *p00 |= uv; - *p01 |= uv; - *p10 |= uv; - *p11 |= uv; - - pOut += 2; + int v = *(pIn+64); + int u = *pIn++; + + *pOut = u; + *(pOut+2) = v; + *(pOut+iWidth) = u; + *(pOut+iWidth+2) = v; + pOut += 4; } - pOut += (iWidth*2 - 16); + pOut += (iWidth*4 - 32); } +} - /* Just copy the other UV rows */ - for (l = 0; l < 4; l++) { - for (m = 0; m < 8; m++) { - int v = *(pIn + 64) - 128; - int u = (*pIn++) - 128; - int uv = ((u >> 4) & 0x0C) + (v >> 6); - *(pOut) = uv; - pOut += 2; - } - pOut += (iWidth*2 - 16); +static void +ov511_parse_data_yuv420(unsigned char *pIn0, unsigned char *pOut0, + int iOutY, int iOutUV, int iWidth, int iHeight) +{ + int k, l, m; + unsigned char *pIn; + unsigned char *pOut, *pOut1; + unsigned a = iWidth * iHeight; + unsigned w = iWidth / 2; + + pIn = pIn0; + pOut = pOut0 + iOutUV + a; + for (k = 0; k < 8; k++) { + pOut1 = pOut; + for (l = 0; l < 8; l++) *pOut1++ = *pIn++; + pOut += w; } - /* Calculate values if it's the second half */ - if (iHalf) { - pIn = pIn0 + 128; - pOut = pOut0 + iOutY; - for (k = 0; k < 4; k++) { - pOut1 = pOut; - for (l=0; l<4; l++) { - for (m=0; m<4; m++) { - int y10 = *(pIn+8); - int y00 = *pIn++; - int y11 = *(pIn+8); - int y01 = *pIn++; - int uv = *pOut1; + pIn = pIn0 + 64; + pOut = pOut0 + iOutUV + a + a/4; + for (k = 0; k < 8; k++) { + pOut1 = pOut; + for (l = 0; l < 8; l++) *pOut1++ = *pIn++; + pOut += w; + } - *pOut1 = (y00 & 0xF0) | uv; - *(pOut1+1) = (y01 & 0xF0) | uv; - *(pOut1+iWidth) = (y10 & 0xF0) | uv; - *(pOut1+iWidth+1) = (y11 & 0xF0) | uv; - - pOut1 += 2; - } - pOut1 += (iWidth*2 - 8); - pIn += 8; - } - pOut += 8; + pIn = pIn0 + 128; + pOut = pOut0 + iOutY; + for (k = 0; k < 4; k++) { + pOut1 = pOut; + for (l = 0; l < 8; l++) { + for (m = 0; m < 8; m++) + *pOut1++ =*pIn++; + pOut1 += iWidth - 8; } + pOut += 8; } } @@ -1553,6 +1662,8 @@ /* Frame start */ PDEBUG(4, "Frame start, framenum = %d", ov511->curframe); + output_offset = 0; + /* Check to see if it's a snapshot frame */ /* FIXME?? Should the snapshot reset go here? Performance? */ if (cdata[8] & 0x02) { @@ -1633,8 +1744,12 @@ iY & 1, frame->width); break; case VIDEO_PALETTE_YUV422: - ov511_parse_data_yuv422(pData, pOut, iOutY, iOutUV, - iY & 1, frame->width); + case VIDEO_PALETTE_YUYV: + ov511_parse_data_yuv422(pData, pOut, iOutY, iOutUV, frame->width); + break; + case VIDEO_PALETTE_YUV420: + ov511_parse_data_yuv420 (pData, pOut, iOutYP, iUV*HDIV*frame->width/2 + jUV*WDIV/4, + frame->width, frame->height); break; case VIDEO_PALETTE_YUV422P: ov511_parse_data_yuv422p (pData, pOut, iOutYP, iOutUVP/2, @@ -1674,7 +1789,7 @@ return; if (!ov511->streaming) { - PDEBUG(2, "hmmm... not streaming, but got interrupt"); + PDEBUG(4, "hmmm... not streaming, but got interrupt"); return; } @@ -1794,7 +1909,6 @@ static int ov511_new_frame(struct usb_ov511 *ov511, int framenum) { struct ov511_frame *frame; - int width, height; PDEBUG(4, "ov511->curframe = %d, framenum = %d", ov511->curframe, framenum); @@ -1810,11 +1924,9 @@ return 0; frame = &ov511->frame[framenum]; - width = frame->width; - height = frame->height; - PDEBUG (4, "framenum = %d, width = %d, height = %d", framenum, width, - height); + PDEBUG (4, "framenum = %d, width = %d, height = %d", framenum, + frame->width, frame->height); frame->grabstate = FRAME_GRABBING; frame->scanstate = STATE_SCANNING; @@ -1824,15 +1936,15 @@ ov511->curframe = framenum; /* Make sure it's not too big */ - if (width > DEFAULT_WIDTH) - width = DEFAULT_WIDTH; + if (frame->width > ov511->maxwidth) + frame->width = ov511->maxwidth; - width &= ~7L; /* Multiple of 8 */ + frame->width &= ~7L; /* Multiple of 8 */ - if (height > DEFAULT_HEIGHT) - height = DEFAULT_HEIGHT; + if (frame->height > ov511->maxheight) + frame->height = ov511->maxheight; - width &= ~3L; /* Multiple of 4 */ + frame->height &= ~3L; /* Multiple of 4 */ return 0; } @@ -2006,22 +2118,24 @@ PDEBUG(4, "ov511_close"); - down(&ov511->lock); - ov511->user--; + down(&ov511->lock); + ov511->user--; ov511_stop_isoc(ov511); - ov511_dealloc(ov511, 0); + if (ov511->dev) + ov511_dealloc(ov511, 0); + up(&ov511->lock); if (!ov511->dev) { + ov511_dealloc(ov511, 1); video_unregister_device(&ov511->vdev); kfree(ov511); ov511 = NULL; } MOD_DEC_USE_COUNT; - } static int ov511_init_done(struct video_device *dev) @@ -2058,8 +2172,8 @@ b.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE; b.channels = 1; b.audios = 0; - b.maxwidth = DEFAULT_WIDTH; - b.maxheight = DEFAULT_HEIGHT; + b.maxwidth = ov511->maxwidth; + b.maxheight = ov511->maxheight; b.minwidth = 32; b.minheight = 16; @@ -2126,6 +2240,8 @@ if (p.palette != VIDEO_PALETTE_GREY && p.palette != VIDEO_PALETTE_RGB24 && p.palette != VIDEO_PALETTE_YUV422 && + p.palette != VIDEO_PALETTE_YUYV && + p.palette != VIDEO_PALETTE_YUV420 && p.palette != VIDEO_PALETTE_YUV422P) return -EINVAL; @@ -2198,9 +2314,9 @@ return -EINVAL; if (vw.clipcount) return -EINVAL; - if (vw.height != DEFAULT_HEIGHT) + if (vw.height != ov511->maxheight) return -EINVAL; - if (vw.width != DEFAULT_WIDTH) + if (vw.width != ov511->maxwidth) return -EINVAL; #endif @@ -2268,6 +2384,8 @@ if (vm.format != VIDEO_PALETTE_RGB24 && vm.format != VIDEO_PALETTE_YUV422 && + vm.format != VIDEO_PALETTE_YUYV && + vm.format != VIDEO_PALETTE_YUV420 && vm.format != VIDEO_PALETTE_YUV422P && vm.format != VIDEO_PALETTE_GREY) return -EINVAL; @@ -2275,7 +2393,7 @@ if ((vm.frame != 0) && (vm.frame != 1)) return -EINVAL; - if (vm.width > DEFAULT_WIDTH || vm.height > DEFAULT_HEIGHT) + if (vm.width > ov511->maxwidth || vm.height > ov511->maxheight) return -EINVAL; if (ov511->frame[vm.frame].grabstate == FRAME_GRABBING) @@ -2392,14 +2510,14 @@ return 0; } case VIDIOCKEY: - return 0; + return 0; case VIDIOCCAPTURE: return -EINVAL; case VIDIOCSFBUF: return -EINVAL; case VIDIOCGTUNER: case VIDIOCSTUNER: - return -EINVAL; + return -EINVAL; case VIDIOCGFREQ: case VIDIOCSFREQ: return -EINVAL; @@ -2599,12 +2717,9 @@ { OV511_I2C_BUS, 0x16, 0x06 }, { OV511_I2C_BUS, 0x28, 0x24 }, { OV511_I2C_BUS, 0x2b, 0xac }, - { OV511_I2C_BUS, 0x05, 0x00 }, - { OV511_I2C_BUS, 0x06, 0x00 }, { OV511_I2C_BUS, 0x12, 0x00 }, { OV511_I2C_BUS, 0x38, 0x81 }, { OV511_I2C_BUS, 0x28, 0x24 }, /* 0c */ - { OV511_I2C_BUS, 0x05, 0x00 }, { OV511_I2C_BUS, 0x0f, 0x85 }, /* lg's setting */ { OV511_I2C_BUS, 0x15, 0x01 }, { OV511_I2C_BUS, 0x20, 0x1c }, @@ -2612,7 +2727,6 @@ { OV511_I2C_BUS, 0x24, 0x10 }, { OV511_I2C_BUS, 0x25, 0x8a }, { OV511_I2C_BUS, 0x27, 0xc2 }, - { OV511_I2C_BUS, 0x29, 0x03 }, /* 91 */ { OV511_I2C_BUS, 0x2a, 0x04 }, { OV511_I2C_BUS, 0x2c, 0xfe }, { OV511_I2C_BUS, 0x30, 0x71 }, @@ -2634,14 +2748,12 @@ { OV511_I2C_BUS, 0x2b, 0xac }, { OV511_I2C_BUS, 0x12, 0x00 }, { OV511_I2C_BUS, 0x28, 0x24 }, - { OV511_I2C_BUS, 0x05, 0x00 }, { OV511_I2C_BUS, 0x0f, 0x85 }, /* lg's setting */ { OV511_I2C_BUS, 0x15, 0x01 }, { OV511_I2C_BUS, 0x23, 0x00 }, { OV511_I2C_BUS, 0x24, 0x10 }, { OV511_I2C_BUS, 0x25, 0x8a }, { OV511_I2C_BUS, 0x27, 0xe2 }, - { OV511_I2C_BUS, 0x29, 0x03 }, { OV511_I2C_BUS, 0x2a, 0x00 }, { OV511_I2C_BUS, 0x2c, 0xfe }, { OV511_I2C_BUS, 0x30, 0x71 }, @@ -2658,24 +2770,23 @@ PDEBUG (4, "starting configuration"); - if(ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE, - OV7610_I2C_WRITE_ID) < 0) + /* This looks redundant, but is necessary for WebCam 3 */ + if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE, + OV7610_I2C_WRITE_ID) < 0) return -1; - if(ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ, - OV7610_I2C_READ_ID) < 0) + if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ, + OV7610_I2C_READ_ID) < 0) return -1; if (ov511_reset(dev, OV511_RESET_NOREGS) < 0) return -1; - + /* Reset the 76xx */ if (ov511_i2c_write(dev, 0x12, 0x80) < 0) return -1; -#if 1 /* Maybe this will fix detection problems? MM */ /* Wait for it to initialize */ schedule_timeout (1 + 150 * HZ / 1000); -#endif for (i = 0, success = 0; i < i2c_detect_tries && !success; i++) { if ((ov511_i2c_read(dev, OV7610_REG_ID_HIGH) == 0x7F) && @@ -2693,12 +2804,34 @@ } if (success) { - PDEBUG(1, "I2C synced in %d attempt(s)", i); + PDEBUG(1, "I2C synced in %d attempt(s) (method 1)", i); } else { - err("Failed to read sensor ID. You might not have an OV76xx,"); - err("or it may be not responding. Report this to"); - err("mmcclelland@delphi.com"); - return -1; + /* Reset the 76xx */ + if (ov511_i2c_write(dev, 0x12, 0x80) < 0) return -1; + + /* Wait for it to initialize */ + schedule_timeout (1 + 150 * HZ / 1000); + + i = 0; + success = 0; + while (i <= i2c_detect_tries) { + if ((ov511_i2c_read(dev, OV7610_REG_ID_HIGH) == 0x7F) && + (ov511_i2c_read(dev, OV7610_REG_ID_LOW) == 0xA2)) { + success = 1; + break; + } else { + i++; + } + } + + if ((i == i2c_detect_tries) && (success == 0)) { + err("Failed to read sensor ID. You might not have an OV7610/20,"); + err("or it may be not responding. Report this to"); + err("mwm@i.am"); + return -1; + } else { + PDEBUG(1, "I2C synced in %d attempt(s) (method 2)", i+1); + } } /* Detect sensor if user didn't use override param */ @@ -2736,6 +2869,128 @@ return -1; } + /* Set sensor-specific vars */ + ov511->maxwidth = 640; + ov511->maxheight = 480; + + if (aperture < 0) { /* go with the default */ + if (ov511_i2c_write(dev, 0x26, 0xa2) < 0) return -1; + } else if (aperture <= 0xf) { /* user overrode default */ + if (ov511_i2c_write(dev, 0x26, (aperture << 4) + 2) < 0) + return -1; + } else { + err("Invalid setting for aperture; legal value: 0 - 15"); + return -1; + } + + if (autoadjust) { + if (ov511_i2c_write(dev, 0x13, 0x01) < 0) return -1; + if (ov511_i2c_write(dev, 0x2d, + ov511->sensor==SEN_OV7620?0x91:0x93) < 0) return -1; + } else { + if (ov511_i2c_write(dev, 0x13, 0x00) < 0) return -1; + if (ov511_i2c_write(dev, 0x2d, + ov511->sensor==SEN_OV7620?0x81:0x83) < 0) return -1; + ov511_i2c_write(dev, 0x28, ov511_i2c_read(dev, 0x28) | 8); + } + + return 0; +} + +static int ov6xx0_configure(struct usb_ov511 *ov511) +{ + struct usb_device *dev = ov511->dev; + int i, success, rc; + + static struct ov511_regvals aRegvalsNorm6x20[] = { + { OV511_I2C_BUS, 0x12, 0x80 }, /* reset */ + { OV511_I2C_BUS, 0x11, 0x01 }, + { OV511_I2C_BUS, 0x03, 0xd0 }, + { OV511_I2C_BUS, 0x05, 0x7f }, + { OV511_I2C_BUS, 0x07, 0xa8 }, + { OV511_I2C_BUS, 0x0c, 0x24 }, + { OV511_I2C_BUS, 0x0d, 0x24 }, + { OV511_I2C_BUS, 0x10, 0xff }, /* ? */ + { OV511_I2C_BUS, 0x14, 0x04 }, + { OV511_I2C_BUS, 0x16, 0x06 }, /* ? */ + { OV511_I2C_BUS, 0x19, 0x04 }, + { OV511_I2C_BUS, 0x1a, 0x93 }, + { OV511_I2C_BUS, 0x20, 0x28 }, + { OV511_I2C_BUS, 0x27, 0xa2 }, + { OV511_I2C_BUS, 0x28, 0x24 }, + { OV511_I2C_BUS, 0x2a, 0x04 }, /* 84? */ + { OV511_I2C_BUS, 0x2b, 0xac }, /* a8? */ + { OV511_I2C_BUS, 0x2d, 0x95 }, + { OV511_I2C_BUS, 0x33, 0x28 }, + { OV511_I2C_BUS, 0x34, 0xc7 }, + { OV511_I2C_BUS, 0x38, 0x8b }, + { OV511_I2C_BUS, 0x3c, 0x5c }, + { OV511_I2C_BUS, 0x3d, 0x80 }, + { OV511_I2C_BUS, 0x3f, 0x00 }, + { OV511_I2C_BUS, 0x4a, 0x80 }, /* undocumented */ + { OV511_I2C_BUS, 0x4b, 0x80 }, /* undocumented */ + { OV511_I2C_BUS, 0x4d, 0xd2 }, + { OV511_I2C_BUS, 0x4e, 0xc1 }, + { OV511_I2C_BUS, 0x4f, 0x04 }, + { OV511_DONE_BUS, 0x0, 0x00 }, + }; + + PDEBUG (4, "starting sensor configuration"); + + /* Reset the 6xx0 */ + if (ov511_i2c_write(dev, 0x12, 0x80) < 0) return -1; + + /* Wait for it to initialize */ + schedule_timeout (1 + 150 * HZ / 1000); + + for (i = 0, success = 0; i < i2c_detect_tries && !success; i++) { + if ((ov511_i2c_read(dev, OV7610_REG_ID_HIGH) == 0x7F) && + (ov511_i2c_read(dev, OV7610_REG_ID_LOW) == 0xA2)) { + success = 1; + continue; + } + + /* Reset the 6xx0 */ + if (ov511_i2c_write(dev, 0x12, 0x80) < 0) return -1; + /* Wait for it to initialize */ + schedule_timeout (1 + 150 * HZ / 1000); + /* Dummy read to sync I2C */ + if (ov511_i2c_read(dev, 0x00) < 0) return -1; + } + + if (success) { + PDEBUG(1, "I2C synced in %d attempt(s)", i); + } else { + err("Failed to read sensor ID. You might not have an OV6xx0,"); + err("or it may be not responding. Report this to"); + err("mwm@i.am"); + return -1; + } + + /* Detect sensor if user didn't use override param */ + if (sensor == 0) { + rc = ov511_i2c_read(dev, OV7610_REG_COM_I); + + if (rc < 0) { + err("Error detecting sensor type"); + return -1; + } else { + info("Sensor is an OV6xx0 (version %d)", rc & 3); + ov511->sensor = SEN_OV6620; + } + } else { /* sensor != 0; user overrode detection */ + ov511->sensor = sensor; + info("Sensor set to type %d", ov511->sensor); + } + + /* Set sensor-specific vars */ + ov511->maxwidth = 352; + ov511->maxheight = 288; + + PDEBUG(4, "Writing 6x20 registers"); + if (ov511_write_regvals(dev, aRegvalsNorm6x20)) + return -1; + if (aperture < 0) { /* go with the default */ if (ov511_i2c_write(dev, 0x26, 0xa2) < 0) return -1; } else if (aperture <= 0xf) { /* user overrode default */ @@ -2781,10 +3036,10 @@ { OV511_REG_BUS, OV511_REG_DRAM_ENABLE_FLOW_CONTROL, 0x01 }, { OV511_REG_BUS, OV511_REG_SYSTEM_SNAPSHOT, 0x02 }, { OV511_REG_BUS, OV511_REG_SYSTEM_SNAPSHOT, 0x00 }, - { OV511_REG_BUS, OV511_REG_FIFO_BITMASK, 0x1f }, /* 0f */ - { OV511_REG_BUS, OV511_OMNICE_PREDICTION_HORIZ_Y, 0x3f }, - { OV511_REG_BUS, OV511_OMNICE_PREDICTION_HORIZ_UV, 0x3f }, - { OV511_REG_BUS, OV511_OMNICE_PREDICTION_VERT_Y, 0x01 }, + { OV511_REG_BUS, OV511_REG_FIFO_BITMASK, 0x1f }, + { OV511_REG_BUS, OV511_OMNICE_PREDICTION_HORIZ_Y, 0x08 }, + { OV511_REG_BUS, OV511_OMNICE_PREDICTION_HORIZ_UV, 0x01 }, + { OV511_REG_BUS, OV511_OMNICE_PREDICTION_VERT_Y, 0x08 }, { OV511_REG_BUS, OV511_OMNICE_PREDICTION_VERT_UV, 0x01 }, { OV511_REG_BUS, OV511_OMNICE_QUANTIZATION_HORIZ_Y, 0x01 }, { OV511_REG_BUS, OV511_OMNICE_QUANTIZATION_HORIZ_UV, 0x01 }, @@ -2814,11 +3069,52 @@ ov511->snap_enabled = snapshot; + /* Test for 76xx */ + if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE, + OV7610_I2C_WRITE_ID) < 0) + goto error; + + if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ, + OV7610_I2C_READ_ID) < 0) + goto error; + + if (ov511_reset(dev, OV511_RESET_NOREGS) < 0) + goto error; + + if (ov511_i2c_write(dev, 0x12, 0x80) < 0) { + /* Test for 6xx0 */ + if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_WRITE, + OV6xx0_I2C_WRITE_ID) < 0) + goto error; + + if (ov511_reg_write(dev, OV511_REG_I2C_SLAVE_ID_READ, + OV6xx0_I2C_READ_ID) < 0) + goto error; + + if (ov511_reset(dev, OV511_RESET_NOREGS) < 0) + goto error; + + if (ov511_i2c_write(dev, 0x12, 0x80) < 0) { + err("Can't determine sensor slave IDs"); + goto error; + } + + if(ov6xx0_configure(ov511) < 0) { + err("failed to configure OV6xx0"); + goto error; + } + } else { + if(ov76xx_configure(ov511) < 0) { + err("failed to configure OV76xx"); + goto error; + } + } + /* Set default sizes in case IOCTL (VIDIOCMCAPTURE) is not used * (using read() instead). */ for (i = 0; i < OV511_NUMFRAMES; i++) { - ov511->frame[i].width = DEFAULT_WIDTH; - ov511->frame[i].height = DEFAULT_HEIGHT; + ov511->frame[i].width = ov511->maxwidth; + ov511->frame[i].height = ov511->maxheight; ov511->frame[i].depth = 24; ov511->frame[i].bytes_read = 0; ov511->frame[i].segment = 0; @@ -2826,14 +3122,8 @@ ov511->frame[i].segsize = GET_SEGSIZE(ov511->frame[i].format); } - /* Initialize to DEFAULT_WIDTH, DEFAULT_HEIGHT, YUV4:2:0 */ - - if(ov76xx_configure(ov511) < 0) { - err("failed to configure OV76xx"); - goto error; - } - - if (ov511_mode_init_regs(ov511, DEFAULT_WIDTH, DEFAULT_HEIGHT, + /* Initialize to max width/height, RGB24 */ + if (ov511_mode_init_regs(ov511, ov511->maxwidth, ov511->maxheight, VIDEO_PALETTE_RGB24, 0) < 0) goto error; @@ -2869,10 +3159,12 @@ interface = &dev->actconfig->interface[ifnum].altsetting[0]; /* Is it an OV511/OV511+? */ - if (dev->descriptor.idVendor != 0x05a9) + if (dev->descriptor.idVendor != 0x05a9 + && dev->descriptor.idVendor != 0x0813) return NULL; if (dev->descriptor.idProduct != 0x0511 - && dev->descriptor.idProduct != 0xA511) + && dev->descriptor.idProduct != 0xA511 + && dev->descriptor.idProduct != 0x0002) return NULL; /* Checking vendor/product should be enough, but what the hell */ @@ -2903,6 +3195,15 @@ info("USB OV511+ camera found"); ov511->bridge = BRG_OV511PLUS; break; + case 0x0002: + if (dev->descriptor.idVendor != 0x0813) + goto error; + info("Intel Play Me2Cam (OV511+) found"); + ov511->bridge = BRG_OV511PLUS; + break; + default: + err("Unknown product ID"); + goto error; } ov511->customid = ov511_reg_read(dev, OV511_REG_SYSTEM_CUSTOM_ID); @@ -2929,7 +3230,7 @@ if (clist[i].id == -1) { err("Camera type (%d) not recognized", ov511->customid); - err("Please contact mmcclelland@delphi.com to request"); + err("Please contact mwm@i.am to request"); err("support for your camera."); } @@ -2969,14 +3270,14 @@ MOD_INC_USE_COUNT; + PDEBUG(3, ""); + /* We don't want people trying to open up the device */ if (!ov511->user) video_unregister_device(&ov511->vdev); + else + PDEBUG(3, "Device open...deferring video_unregister_device"); - usb_driver_release_interface(&ov511_driver, - &ov511->dev->actconfig->interface[ov511->iface]); - - ov511->dev = NULL; for (n = 0; n < OV511_NUMFRAMES; n++) ov511->frame[n].grabstate = FRAME_ERROR; @@ -3001,15 +3302,17 @@ } } + usb_driver_release_interface(&ov511_driver, + &ov511->dev->actconfig->interface[ov511->iface]); + ov511->dev = NULL; + #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) destroy_proc_ov511_cam(ov511); #endif - /* FIXME - is this correct/safe? Should we acquire ov511->lock? */ - ov511_dealloc(ov511, 1); - /* Free the memory */ if (ov511 && !ov511->user) { + ov511_dealloc(ov511, 1); kfree(ov511); ov511 = NULL; } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/usb/ov511.h linux/drivers/usb/ov511.h --- v2.4.0-test8/linux/drivers/usb/ov511.h Tue Jul 11 10:46:38 2000 +++ linux/drivers/usb/ov511.h Tue Sep 19 11:37:59 2000 @@ -183,6 +183,9 @@ // FIXME - these can vary between specific models #define OV7610_I2C_WRITE_ID 0x42 #define OV7610_I2C_READ_ID 0x43 +#define OV6xx0_I2C_WRITE_ID 0xC0 +#define OV6xx0_I2C_READ_ID 0xC1 + #define OV511_I2C_CLOCK_PRESCALER 0x03 /* Prototypes */ @@ -203,6 +206,7 @@ SEN_OV7610, SEN_OV7620, SEN_OV7620AE, + SEN_OV6620, }; enum { @@ -254,7 +258,7 @@ int hdrheight; /* Height */ int sub_flag; /* Sub-capture mode for this frame? */ - int format; /* Format for this frame */ + unsigned int format; /* Format for this frame */ int segsize; /* How big is each segment from the camera? */ volatile int grabstate; /* State of grabbing */ @@ -285,6 +289,10 @@ int desc; unsigned char iface; + /* Determined by sensor type */ + int maxwidth; + int maxheight; + int brightness; int colour; int contrast; @@ -356,7 +364,6 @@ u8 lndv; /* line divisor */ u8 m420; u8 common_A; - u8 common_C; u8 common_L; }; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/usb/pegasus.c linux/drivers/usb/pegasus.c --- v2.4.0-test8/linux/drivers/usb/pegasus.c Tue Aug 22 15:23:13 2000 +++ linux/drivers/usb/pegasus.c Mon Oct 2 14:20:39 2000 @@ -13,6 +13,12 @@ ** from top-halves. ** v0.4.0 Control messages remained unurbified are now URBs. ** Now we can touch the HW at any time. +** v0.4.9 Control urbs again use process context to wait. Argh... +** Some long standing bugs (start_net) fixed. Also nasty +** trick with resubmiting control urb from interrupt +** context used. Please let me know how it behaves. +** Pegasus II support added since this version. +** TODO: suppressing HCD warnings spewage on disconnect. */ /* @@ -42,20 +48,65 @@ #include -static const char *version = __FILE__ ": v0.4.3 2000/08/22 (C) 1999-2000 Petko Manolov (petkan@dce.bg)\n"; +static const char *version = __FILE__ ": v0.4.9 2000/09/14 (C) 1999-2000 Petko Manolov (petkan@dce.bg)"; -#define PEGASUS_USE_WAITQ +#define PEGASUS_USE_INTR +#define PEGASUS_II 0x80000000 +#define HAS_HOME_PNA 0x40000000 + #define PEGASUS_MTU 1500 #define PEGASUS_MAX_MTU 1536 + #define EPROM_WRITE 0x01 #define EPROM_READ 0x02 +#define EPROM_DONE 0x04 +#define EPROM_WR_ENABLE 0x10 +#define EPROM_LOAD 0x20 + +#define MII_BMCR 0x00 +#define MII_BMSR 0x01 +#define BMSR_MEDIA 0x7808 +#define MII_ANLPA 0x05 +#define ANLPA_100TX_FD 0x0100 +#define ANLPA_100TX_HD 0x0080 +#define ANLPA_10T_FD 0x0040 +#define ANLPA_10T_HD 0x0020 +#define PHY_DONE 0x80 +#define PHY_READ 0x40 +#define PHY_WRITE 0x20 +#define DEFAULT_GPIO_RESET 0x24 +#define LINKSYS_GPIO_RESET 0x24 +#define DEFAULT_GPIO_SET 0x26 + +#define PEGASUS_PRESENT 1 +#define PEGASUS_RUNNING 2 +#define CTRL_URB_RUNNING 4 +#define CTRL_URB_SLEEP 8 +#define ETH_REGS_CHANGE 0x40000000 +#define ETH_REGS_CHANGED 0x80000000 + +#define RX_MULTICAST 2 +#define RX_PROMISCUOUS 4 + +#define REG_TIMEOUT (HZ) #define PEGASUS_TX_TIMEOUT (HZ*10) -#define PEGASUS_CTRL_TIMEOUT (HZ*5) -#define PEGASUS_CTRL_WAIT (1<<31) -#define PEGASUS_RUNNING 1 + +#ifdef PEGASUS_USE_INTR + #define INTR_IVAL 0x80 +#else + #define INTR_IVAL 0 +#endif + +#define TX_UNDERRUN 0x80 +#define EXCESSIVE_COL 0x40 +#define LATE_COL 0x20 +#define NO_CARRIER 0x10 +#define LOSS_CARRIER 0x08 +#define JABBER_TIMEOUT 0x04 + #define PEGASUS_REQT_READ 0xc0 #define PEGASUS_REQT_WRITE 0x40 #define PEGASUS_REQ_GET_REGS 0xf0 @@ -64,12 +115,12 @@ #define NUM_CTRL_URBS 0x10 #define ALIGN(x) x __attribute__((aligned(L1_CACHE_BYTES))) - enum pegasus_registers { EthCtrl0 = 0, EthCtrl1 = 1, EthCtrl2 = 2, EthID = 0x10, + Reg1d = 0x1d, EpromOffset = 0x20, EpromData = 0x21, /* 0x21 low, 0x22 high byte */ EpromCtrl = 0x23, @@ -80,348 +131,445 @@ EthTxStat0 = 0x2b, EthTxStat1 = 0x2c, EthRxStat = 0x2d, + Reg7b = 0x7b, Gpio0 = 0x7e, Gpio1 = 0x7f, + Reg81 = 0x81, }; -struct pegasus; -struct ctrl_urb_pool { - struct pegasus *pegasus; - struct urb urb; - devrequest dr; - __u8 busy; -}; - - -struct pegasus { +typedef struct pegasus { struct usb_device *usb; struct net_device *net; struct net_device_stats stats; - int flags; - struct urb rx_urb, tx_urb, intr_urb; - struct ctrl_urb_pool ALIGN(ctrl[NUM_CTRL_URBS]); + unsigned flags; + unsigned features; + struct urb ctrl_urb, rx_urb, tx_urb, intr_urb; + devrequest dr; wait_queue_head_t ctrl_wait; struct semaphore ctrl_sem; unsigned char ALIGN(rx_buff[PEGASUS_MAX_MTU]); unsigned char ALIGN(tx_buff[PEGASUS_MAX_MTU]); unsigned char ALIGN(intr_buff[8]); -}; + __u8 eth_regs[4]; + __u8 phy; + __u8 gpio_res; +} pegasus_t; struct usb_eth_dev { char *name; __u16 vendor; __u16 device; - void *private; + __u32 private; /* LSB is gpio reset value */ }; static int loopback = 0; +static int mode = 0; static int multicast_filter_limit = 32; MODULE_AUTHOR("Petko Manolov "); MODULE_DESCRIPTION("ADMtek AN986 Pegasus USB Ethernet driver"); MODULE_PARM(loopback, "i"); +MODULE_PARM(mode, "i"); MODULE_PARM_DESC(loopback, "Enable MAC loopback mode (bit 0)"); +MODULE_PARM_DESC(mode, "Enable HomePNA mode (bit 0) - default = MII mode = 0"); static struct usb_eth_dev usb_dev_id[] = { - {"Billionton USB-100", 0x08dd, 0x0986, NULL}, - {"Corega FEter USB-TX", 0x7aa, 0x0004, NULL}, - {"MELCO/BUFFALO LUA-TX", 0x0411, 0x0001, NULL}, - {"D-Link DSB-650TX", 0x2001, 0x4001, NULL}, - {"D-Link DSB-650TX", 0x2001, 0x4002, NULL}, - {"D-Link DSB-650TX(PNA)", 0x2001, 0x4003, NULL}, - {"D-Link DSB-650", 0x2001, 0xabc1, NULL}, - {"D-Link DU-E10", 0x07b8, 0xabc1, NULL}, - {"D-Link DU-E100", 0x07b8, 0x4002, NULL}, - {"Linksys USB10TX", 0x066b, 0x2202, NULL}, - {"Linksys USB100TX", 0x066b, 0x2203, NULL}, - {"Linksys USB100TX", 0x066b, 0x2204, NULL}, - {"Linksys USB Ethernet Adapter", 0x066b, 0x2206, NULL}, - {"SMC 202 USB Ethernet", 0x0707, 0x0200, NULL}, - {"ADMtek AN986 \"Pegasus\" USB Ethernet (eval board)", 0x07a6, 0x0986, NULL}, - {"Accton USB 10/100 Ethernet Adapter", 0x083a, 0x1046, NULL}, - {"IO DATA USB ET/TX", 0x04bb, 0x0904, NULL}, - {"LANEED USB Ethernet LD-USB/TX", 0x056e, 0x4002, NULL}, - {"SOHOware NUB100 Ethernet", 0x15e8, 0x9100, NULL}, - {NULL, 0, 0, NULL} + {"Billionton USB-100", 0x08dd, 0x0986, DEFAULT_GPIO_RESET}, + {"Corega FEter USB-TX", 0x7aa, 0x0004, DEFAULT_GPIO_RESET}, + {"MELCO/BUFFALO LUA-TX", 0x0411, 0x0001, DEFAULT_GPIO_RESET}, + {"D-Link DSB-650TX", 0x2001, 0x4001, LINKSYS_GPIO_RESET}, + {"D-Link DSB-650TX", 0x2001, 0x4002, LINKSYS_GPIO_RESET}, + {"D-Link DSB-650TX(PNA)", 0x2001, 0x4003, DEFAULT_GPIO_RESET}, + {"D-Link DSB-650", 0x2001, 0xabc1, DEFAULT_GPIO_RESET}, + {"D-Link DU-E10", 0x07b8, 0xabc1, DEFAULT_GPIO_RESET}, + {"D-Link DU-E100", 0x07b8, 0x4002, DEFAULT_GPIO_RESET}, + {"Linksys USB10TX", 0x066b, 0x2202, LINKSYS_GPIO_RESET}, + {"Linksys USB100TX", 0x066b, 0x2203, LINKSYS_GPIO_RESET}, + {"Linksys USB100TX", 0x066b, 0x2204, LINKSYS_GPIO_RESET}, + {"Linksys USB Ethernet Adapter", 0x066b, 0x2206, LINKSYS_GPIO_RESET}, + {"SMC 202 USB Ethernet", 0x0707, 0x0200, DEFAULT_GPIO_RESET}, + {"ADMtek AN986 \"Pegasus\" USB Ethernet (eval board)", 0x07a6, 0x0986, + HAS_HOME_PNA | DEFAULT_GPIO_RESET}, + {"Accton USB 10/100 Ethernet Adapter", 0x083a, 0x1046, + DEFAULT_GPIO_RESET}, + {"IO DATA USB ET/TX", 0x04bb, 0x0904, DEFAULT_GPIO_RESET}, + {"LANEED USB Ethernet LD-USB/TX", 0x056e, 0x4002, DEFAULT_GPIO_RESET}, + {"SOHOware NUB100 Ethernet", 0x15e8, 0x9100, DEFAULT_GPIO_RESET}, + {"ADMtek ADM8511 \"Pegasus II\" USB Ethernet", 0x07a6, 0x8511, + PEGASUS_II | DEFAULT_GPIO_RESET}, + {NULL, 0, 0, 0} }; -static void pegasus_unlink_ctrl_urbs( struct pegasus *pegasus ) +static int update_eth_regs_async( pegasus_t * ); +/* Aargh!!! I _really_ hate such tweaks */ +static void ctrl_callback( urb_t *urb ) { - int i; + pegasus_t *pegasus = urb->context; + + if ( !pegasus ) + return; - for ( i=0; i < NUM_CTRL_URBS; i++ ) { - if ( pegasus->ctrl[i].urb.status == -EINPROGRESS ) - usb_unlink_urb( &pegasus->ctrl[i].urb ); + switch ( urb->status ) { + case USB_ST_NOERROR: + if ( pegasus->flags & ETH_REGS_CHANGE ) { + pegasus->flags &= ~ETH_REGS_CHANGE; + pegasus->flags |= ETH_REGS_CHANGED; + update_eth_regs_async( pegasus ); + return; + } + break; + case USB_ST_URB_PENDING: + return; + case USB_ST_URB_KILLED: + break; + default: + warn( __FUNCTION__ " status %d", urb->status); + } + pegasus->flags &= ~ETH_REGS_CHANGED; + if ( pegasus->flags & CTRL_URB_SLEEP ) { + pegasus->flags &= ~CTRL_URB_SLEEP; + wake_up_interruptible( &pegasus->ctrl_wait ); } } -static int pegasus_find_ctrl_urb( struct pegasus *pegasus ) +static int get_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data) { - int i=0; - - while( i < NUM_CTRL_URBS && (pegasus->ctrl[i].busy == 1 || - (pegasus->ctrl[i].urb.status == -EINPROGRESS)) ) - i++; + int ret; - return i; -} - - -static void pegasus_ctrl_end( urb_t *urb ) -{ - struct ctrl_urb_pool *ctrl = urb->context; - struct pegasus *pegasus = ctrl->pegasus; + if ( pegasus->flags & ETH_REGS_CHANGED ) { + pegasus->flags |= CTRL_URB_SLEEP; + interruptible_sleep_on( &pegasus->ctrl_wait ); + } + pegasus->dr.requesttype = PEGASUS_REQT_READ; + pegasus->dr.request = PEGASUS_REQ_GET_REGS; + pegasus->dr.value = 0; + pegasus->dr.index = cpu_to_le16p(&indx); + pegasus->dr.length = + pegasus->ctrl_urb.transfer_buffer_length = cpu_to_le16p(&size); + FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb, + usb_rcvctrlpipe(pegasus->usb,0), + (char *)&pegasus->dr, + data, size, ctrl_callback, pegasus ); - if ( !pegasus ) - return; + if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) { + err( __FUNCTION__ " BAD CTRLs %d", ret); + return ret; + } + pegasus->flags |= CTRL_URB_SLEEP; + interruptible_sleep_on( &pegasus->ctrl_wait ); - if ( urb->status ) - warn("ctrl_urb end status %d", urb->status); - ctrl->busy = 0; -#ifdef PEGASUS_USE_WAITQ - wake_up_interruptible( &pegasus->ctrl_wait ); -#endif + return ret; } -static int pegasus_get_registers( struct pegasus *pegasus, __u16 indx, __u16 size, void *data ) +static int set_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data) { - int ret, i; - struct ctrl_urb_pool *ctrl; - - if ( (i = pegasus_find_ctrl_urb( pegasus )) == NUM_CTRL_URBS ) { - return -1; - } + int ret; - ctrl = &pegasus->ctrl[i]; - ctrl->busy = 1; - ctrl->pegasus = pegasus; - - ctrl->dr.requesttype = PEGASUS_REQT_READ; - ctrl->dr.request = PEGASUS_REQ_GET_REGS; - ctrl->dr.value = 0; - ctrl->dr.index = cpu_to_le16p(&indx); - ctrl->dr.length = - ctrl->urb.transfer_buffer_length = cpu_to_le16p(&size); + if ( pegasus->flags & ETH_REGS_CHANGED ) { + pegasus->flags |= CTRL_URB_SLEEP ; + interruptible_sleep_on( &pegasus->ctrl_wait ); + } + pegasus->dr.requesttype = PEGASUS_REQT_WRITE; + pegasus->dr.request = PEGASUS_REQ_SET_REGS; + pegasus->dr.value = 0; + pegasus->dr.index = cpu_to_le16p( &indx ); + pegasus->dr.length = + pegasus->ctrl_urb.transfer_buffer_length = cpu_to_le16p( &size ); - FILL_CONTROL_URB( &ctrl->urb, pegasus->usb, - usb_rcvctrlpipe(pegasus->usb,0), - (char *)&ctrl->dr, - data, size, pegasus_ctrl_end, ctrl ); + FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb, + usb_sndctrlpipe(pegasus->usb,0), + (char *)&pegasus->dr, + data, size, ctrl_callback, pegasus ); - if ( (ret = usb_submit_urb( &ctrl->urb )) ) - err( __FUNCTION__ " BAD CTRLs %d", ret); -#ifdef PEGASUS_USE_WAITQ + if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) { + err( __FUNCTION__ " BAD CTRL %d", ret); + return ret; + } + pegasus->flags |= CTRL_URB_SLEEP; interruptible_sleep_on( &pegasus->ctrl_wait ); -#endif + return ret; } -static int pegasus_set_registers( struct pegasus *pegasus, __u16 indx, __u16 size, void *data ) +static int set_register( pegasus_t *pegasus, __u16 indx, __u8 data ) { - int ret, i; - struct ctrl_urb_pool *ctrl; - - if ( (i = pegasus_find_ctrl_urb( pegasus )) == NUM_CTRL_URBS ) { - return -1; - } + int ret; - ctrl = &pegasus->ctrl[i]; - ctrl->busy = 1; - ctrl->pegasus = pegasus; - - ctrl->dr.requesttype = PEGASUS_REQT_WRITE; - ctrl->dr.request = PEGASUS_REQ_SET_REGS; - ctrl->dr.value = 0; - ctrl->dr.index = cpu_to_le16p( &indx ); - ctrl->dr.length = - ctrl->urb.transfer_buffer_length = cpu_to_le16p( &size ); + if ( pegasus->flags & ETH_REGS_CHANGED ) { + pegasus->flags |= CTRL_URB_SLEEP; + interruptible_sleep_on( &pegasus->ctrl_wait ); + } + pegasus->dr.requesttype = PEGASUS_REQT_WRITE; + pegasus->dr.request = PEGASUS_REQ_SET_REG; + pegasus->dr.value = data; + pegasus->dr.index = cpu_to_le16p( &indx ); + pegasus->dr.length = pegasus->ctrl_urb.transfer_buffer_length = 1; - FILL_CONTROL_URB( &ctrl->urb, pegasus->usb, + FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb, usb_sndctrlpipe(pegasus->usb,0), - (char *)&ctrl->dr, - data, size, pegasus_ctrl_end, ctrl ); + (char *)&pegasus->dr, + &data, 1, ctrl_callback, pegasus ); - if ( (ret = usb_submit_urb( &ctrl->urb )) ) + if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) { err( __FUNCTION__ " BAD CTRL %d", ret); -#ifdef PEGASUS_USE_WAITQ + return ret; + } + pegasus->flags |= CTRL_URB_SLEEP; interruptible_sleep_on( &pegasus->ctrl_wait ); -#endif + return ret; } -static int pegasus_set_register( struct pegasus *pegasus, __u16 indx,__u8 data ) +static int update_eth_regs_async( pegasus_t *pegasus ) { - int ret, i; - struct ctrl_urb_pool *ctrl; - - if ( (i = pegasus_find_ctrl_urb( pegasus )) == NUM_CTRL_URBS ) { - return -1; - } - - ctrl = &pegasus->ctrl[i]; - ctrl->busy = 1; - ctrl->pegasus = pegasus; + int ret; - ctrl->dr.requesttype = PEGASUS_REQT_WRITE; - ctrl->dr.request = PEGASUS_REQ_SET_REG; - ctrl->dr.value = cpu_to_le16p( &data ); - ctrl->dr.index = cpu_to_le16p( &indx ); - ctrl->dr.length = ctrl->urb.transfer_buffer_length = 1; + pegasus->dr.requesttype = PEGASUS_REQT_WRITE; + pegasus->dr.request = PEGASUS_REQ_SET_REGS; + pegasus->dr.value = 0; + pegasus->dr.index = EthCtrl0; + pegasus->dr.length = + pegasus->ctrl_urb.transfer_buffer_length = 3; - FILL_CONTROL_URB( &ctrl->urb, pegasus->usb, + FILL_CONTROL_URB( &pegasus->ctrl_urb, pegasus->usb, usb_sndctrlpipe(pegasus->usb,0), - (char *)&ctrl->dr, - &data, 1, pegasus_ctrl_end, ctrl ); + (char *)&pegasus->dr, + pegasus->eth_regs, 3, ctrl_callback, pegasus ); + + if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) + err( __FUNCTION__ " BAD CTRL %d, flags %x",ret,pegasus->flags ); - if ( (ret = usb_submit_urb( &ctrl->urb )) ) - err( __FUNCTION__ " BAD CTRL %d", ret); -#ifdef PEGASUS_USE_WAITQ - interruptible_sleep_on( &pegasus->ctrl_wait ); -#endif return ret; } -static int pegasus_read_phy_word(struct pegasus *pegasus, __u8 index, __u16 *regdata) +static int read_phy_word( pegasus_t *pegasus, __u8 phy, __u8 indx, __u16 *regd ) { - int i; - __u8 data[4] = { 1, 0, 0, 0x40 + index }; + int i; + __u8 data[4] = { phy, 0, 0, indx }; - pegasus_set_registers(pegasus, PhyAddr, 4, data); - for (i = 0; i < 100; i++) { - pegasus_get_registers(pegasus, PhyData, 3, data); - if (data[2] & 0x80) { - *regdata = *(__u16 *)(data); - return 0; - } + set_register( pegasus, PhyCtrl, 0 ); + set_registers( pegasus, PhyAddr, sizeof(data), data ); + set_register( pegasus, PhyCtrl, (indx | PHY_READ) ); + for (i = 0; i < REG_TIMEOUT; i++) { + get_registers(pegasus, PhyCtrl, 1, data); + if ( data[0] & PHY_DONE ) + break; } - warn("read_phy_word() failed"); + if ( i < REG_TIMEOUT ) { + get_registers( pegasus, PhyData, 2, regd ); + return 0; + } + warn( __FUNCTION__ " failed" ); return 1; } -static int pegasus_write_phy_word(struct pegasus *pegasus, __u8 index, __u16 regdata) +static int write_phy_word( pegasus_t *pegasus, __u8 phy, __u8 indx, __u16 regd ) { - int i; - __u8 data[4] = { 1, regdata, regdata >> 8, 0x20 + index }; - - pegasus_set_registers(pegasus, PhyAddr, 4, data); - for (i = 0; i < 100; i++) { - pegasus_get_registers(pegasus, PhyCtrl, 1, data); - if (data[0] & 0x80) - return 0; + int i; + __u8 data[4] = { phy, 0, 0, indx }; + + *(data + 1) = cpu_to_le16p( ®d ); + set_register( pegasus, PhyCtrl, 0 ); + set_registers( pegasus, PhyAddr, 4, data ); + set_register( pegasus, PhyCtrl, (indx | PHY_WRITE) ); + for (i = 0; i < REG_TIMEOUT; i++) { + get_registers(pegasus, PhyCtrl, 1, data); + if ( data[0] & PHY_DONE ) + break; } - warn("write_phy_word() failed"); + if ( i < REG_TIMEOUT ) + return 0; + warn( __FUNCTION__ " failed" ); return 1; } -static int pegasus_rw_eprom_word(struct pegasus *pegasus, __u8 index, __u16 *retdata, __u8 direction) +static int read_eprom_word( pegasus_t *pegasus, __u8 index, __u16 *retdata ) { - int i; - __u8 data[4] = { index, 0, 0, direction }; + int i, tmp; - pegasus_set_registers(pegasus, EpromOffset, 4, data); - for (i = 0; i < 100; i++) { - pegasus_get_registers(pegasus, EpromCtrl, 1, data); - if (data[0] & 4) { - pegasus_get_registers(pegasus, EpromData, 2, data); - *retdata = *(__u16 *)data; - return 0; - } + set_register( pegasus, EpromCtrl, 0 ); + set_register( pegasus, EpromOffset, index ); + set_register( pegasus, EpromCtrl, EPROM_READ); + for ( i=0; i < REG_TIMEOUT; i++ ) { + get_registers( pegasus, EpromCtrl, 1, &tmp ); + if ( tmp & EPROM_DONE ) + break; } - warn("pegasus_rw_eprom_word() failed"); - - return 1; + if ( i < REG_TIMEOUT ) { + get_registers( pegasus, EpromData, 2, retdata ); + return 0; + } + warn( __FUNCTION__ " failed" ); + + return -1; +} + + +static inline void enable_eprom_write( pegasus_t *pegasus ) +{ + __u8 tmp; + + get_registers( pegasus, EthCtrl2, 1, &tmp ); + set_register( pegasus, EthCtrl2, tmp | EPROM_WR_ENABLE ); +} + + +static inline void disable_eprom_write( pegasus_t *pegasus ) +{ + __u8 tmp; + + get_registers( pegasus, EthCtrl2, 1, &tmp ); + set_register( pegasus, EpromCtrl, 0 ); + set_register( pegasus, EthCtrl2, tmp & ~EPROM_WR_ENABLE ); +} + + +static int write_eprom_word( pegasus_t *pegasus, __u8 index, __u16 data ) +{ + int i, tmp; + __u8 d[4] = {0x3f, 0, 0, EPROM_WRITE}; + + set_registers( pegasus, EpromOffset, 4, d ); + enable_eprom_write( pegasus ); + set_register( pegasus, EpromOffset, index ); + set_registers( pegasus, EpromData, 2, &data ); + set_register( pegasus, EpromCtrl, EPROM_WRITE ); + + for ( i=0; i < REG_TIMEOUT; i++ ) { + get_registers( pegasus, EpromCtrl, 1, &tmp ); + if ( tmp & EPROM_DONE ) + break; + } + disable_eprom_write( pegasus ); + if ( i < REG_TIMEOUT ) + return 0; + warn( __FUNCTION__ " failed" ); + return -1; } -static int pegasus_get_node_id(struct pegasus *pegasus, __u8 *id) +static void set_intr_interval( pegasus_t *pegasus ) +{ + __u16 d; + __u8 tmp; + + read_eprom_word( pegasus, 4, &d ); + ((__u8 *)&d)[1] = INTR_IVAL; + write_eprom_word( pegasus, 4, d ); + get_registers( pegasus, EthCtrl2, 1, &tmp ); + set_register( pegasus, EthCtrl2, tmp | EPROM_LOAD ); + udelay( 10000 ); + set_register( pegasus, EthCtrl2, tmp ); +#ifdef PEGASUS_DUMP_EEPROM + { int i; + for ( i=0; i < 0x40; i++ ) { + read_eprom_word( pegasus, i, &d ); + printk( "eepromword %02x-%04x, ", i, d ); + } + printk( "\n" ); + } +#endif +} + + +static inline int get_node_id( pegasus_t *pegasus, __u8 *id ) { int i; + for (i = 0; i < 3; i++) - if (pegasus_rw_eprom_word(pegasus, i, (__u16 *)&id[i*2], EPROM_READ)) + if ( read_eprom_word( pegasus, i, (__u16 *)&id[i*2]) ) return 1; return 0; } -static int pegasus_reset_mac(struct pegasus *pegasus) +static inline int reset_mac( pegasus_t *pegasus ) { - __u8 data = 0x8; - int i; + __u8 data = 0x8; + int i; - pegasus_set_register(pegasus, EthCtrl1, data); - for (i = 0; i < 100; i++) { - pegasus_get_registers(pegasus, EthCtrl1, 1, &data); + set_register(pegasus, EthCtrl1, data); + for (i = 0; i < REG_TIMEOUT; i++) { + get_registers(pegasus, EthCtrl1, 1, &data); if (~data & 0x08) { if (loopback & 1) - return 0; - pegasus_set_register(pegasus, Gpio0, 0x24); - pegasus_set_register(pegasus, Gpio0, 0x27); - return 0; + break; + if ( mode && (pegasus->features & HAS_HOME_PNA) ) + set_register( pegasus, Gpio1, 0x34 ); + else + set_register( pegasus, Gpio1, 0x26 ); + set_register( pegasus, Gpio0, pegasus->features ); + set_register( pegasus, Gpio0, DEFAULT_GPIO_SET ); + break; } } - - return 1; + if ( i == REG_TIMEOUT ) + return 1; + return 0; } -static int pegasus_start_net(struct net_device *dev, struct usb_device *usb) +static int start_net( struct net_device *dev, struct usb_device *usb ) { - __u16 partmedia, temp; - __u8 node_id[6]; - __u8 data[4]; - struct pegasus *pegasus = dev->priv; + __u16 linkpart, bmsr; + __u8 node_id[6]; + __u8 data[4]; + pegasus_t *pegasus = dev->priv; - if (pegasus_get_node_id(pegasus, node_id)) + if ( get_node_id(pegasus, node_id) ) return 1; - pegasus_set_registers(pegasus, EthID, 6, node_id); - memcpy(dev->dev_addr, node_id, 6); - if (pegasus_read_phy_word(pegasus, 1, &temp)) + set_registers( pegasus, EthID, sizeof(node_id), node_id ); + memcpy( dev->dev_addr, node_id, sizeof(node_id) ); + if ( read_phy_word(pegasus, pegasus->phy, MII_BMSR, &bmsr) ) return 2; - - if ((~temp & 4) && !loopback) { - warn("%s: link NOT established (0x%x) - check the cable.", - dev->name, temp); - } - - if (pegasus_read_phy_word(pegasus, 5, &partmedia)) + if ( !(bmsr & 0x20) && !loopback ) + warn( "%s: link NOT established (0x%x) - check the cable.", + dev->name, bmsr ); + if ( read_phy_word(pegasus, pegasus->phy, MII_ANLPA, &linkpart) ) return 4; - - if ((partmedia & 0x1f) != 1) { - warn("party FAIL %x", partmedia); - } + if ( !(linkpart & 1) ) + warn( "link partner stat %x", linkpart ); data[0] = 0xc9; - data[1] = (partmedia & 0x100) ? 0x30 : ((partmedia & 0x80) ? 0x10 : 0); + data[1] = 0; + if ( linkpart & (ANLPA_100TX_FD | ANLPA_10T_FD) ) + data[1] |= 0x20; /* set full duplex */ + if ( linkpart & (ANLPA_100TX_FD | ANLPA_100TX_HD) ) + data[1] |= 0x10; /* set 100 Mbps */ + if ( mode ) + data[1] = 0; data[2] = (loopback & 1) ? 0x09 : 0x01; - pegasus_set_registers(pegasus, EthCtrl0, 3, data); + *(unsigned *)pegasus->eth_regs = *(unsigned *)data; + + set_registers( pegasus, EthCtrl0, 3, data ); return 0; } -static void pegasus_read_bulk_callback( struct urb *urb ) +static void read_bulk_callback( struct urb *urb ) { - struct pegasus *pegasus = urb->context; - struct net_device *net; /* = pegasus->net;*/ + pegasus_t *pegasus = urb->context; + struct net_device *net; int count = urb->actual_length, res; - int rx_status; /*= *(int *)(pegasus->rx_buff + count - 4);*/ + int rx_status; struct sk_buff *skb; __u16 pkt_len; @@ -436,26 +584,26 @@ goto goon; } - if (!count) - goto goon; -#if 0 - if (rx_status & 0x00010000) + if ( !count ) goto goon; -#endif - if (rx_status & 0x000e0000) { + + if ( rx_status & 0x000e0000 ) { dbg("%s: error receiving packet %x", net->name, rx_status & 0xe0000); pegasus->stats.rx_errors++; - if(rx_status & 0x060000) pegasus->stats.rx_length_errors++; - if(rx_status & 0x080000) pegasus->stats.rx_crc_errors++; - if(rx_status & 0x100000) pegasus->stats.rx_frame_errors++; + if ( rx_status & 0x060000 ) + pegasus->stats.rx_length_errors++; + if ( rx_status & 0x080000 ) + pegasus->stats.rx_crc_errors++; + if ( rx_status & 0x100000 ) + pegasus->stats.rx_frame_errors++; goto goon; } pkt_len = (rx_status & 0xfff) - 8; - if(!(skb = dev_alloc_skb(pkt_len+2))) + if ( !(skb = dev_alloc_skb(pkt_len+2)) ) goto goon; skb->dev = net; @@ -469,36 +617,60 @@ pegasus->stats.rx_bytes += pkt_len; goon: + pegasus->rx_urb.dev = pegasus->usb; if ( (res = usb_submit_urb(&pegasus->rx_urb)) ) - warn("(prb)failed rx_urb %d", res); + warn( __FUNCTION__ " failed submint rx_urb %d", res); } -static void pegasus_irq_callback( urb_t *urb ) +static void write_bulk_callback( struct urb *urb ) { - __u8 *d = urb->transfer_buffer; + pegasus_t *pegasus = urb->context; + if ( !pegasus || !(pegasus->flags & PEGASUS_RUNNING) ) + return; + if ( urb->status ) + info("%s: TX status %d", pegasus->net->name, urb->status); - if ( d[0] ) - dbg("txst0=0x%2x", d[0]); + netif_wake_queue(pegasus->net); } -static void pegasus_write_bulk_callback(struct urb *urb) +static void intr_callback( struct urb *urb ) { - struct pegasus *pegasus = urb->context; + pegasus_t *pegasus = urb->context; + struct net_device *net; + __u8 *d; if ( !pegasus ) return; - - if (urb->status) - info("%s: TX status %d", pegasus->net->name, urb->status); - netif_wake_queue(pegasus->net); + d = urb->transfer_buffer; + net = pegasus->net; + if ( d[0] & 0xfc ) { + pegasus->stats.tx_errors++; + if ( d[0] & TX_UNDERRUN ) + pegasus->stats.tx_fifo_errors++; + if ( d[0] & (EXCESSIVE_COL | JABBER_TIMEOUT) ) + pegasus->stats.tx_aborted_errors++; + if ( d[0] & LATE_COL ) + pegasus->stats.tx_window_errors++; + if ( d[0] & (NO_CARRIER | LOSS_CARRIER) ) + pegasus->stats.tx_carrier_errors++; + } + switch ( urb->status ) { + case USB_ST_NOERROR: + break; + case USB_ST_URB_KILLED: + break; + default: + info("intr status %d", urb->status); + } } -static void pegasus_tx_timeout(struct net_device *net) + +static void pegasus_tx_timeout( struct net_device *net ) { - struct pegasus *pegasus = net->priv; + pegasus_t *pegasus = net->priv; if ( !pegasus ) return; @@ -512,11 +684,11 @@ } -static int pegasus_start_xmit(struct sk_buff *skb, struct net_device *net) +static int pegasus_start_xmit( struct sk_buff *skb, struct net_device *net ) { - struct pegasus *pegasus = net->priv; - int count = ((skb->len+2) & 0x3f) ? skb->len+2 : skb->len+3; - int res; + pegasus_t *pegasus = net->priv; + int count = ((skb->len+2) & 0x3f) ? skb->len+2 : skb->len+3; + int res; netif_stop_queue(net); if ( !(pegasus->flags & PEGASUS_RUNNING) ) @@ -527,6 +699,7 @@ pegasus->tx_urb.transfer_buffer_length = count; pegasus->tx_urb.transfer_flags |= USB_ASYNC_UNLINK; + pegasus->tx_urb.dev = pegasus->usb; if ((res = usb_submit_urb(&pegasus->tx_urb))) { warn("failed tx_urb %d", res); pegasus->stats.tx_errors++; @@ -543,77 +716,76 @@ } -static struct net_device_stats *pegasus_netdev_stats(struct net_device *dev) +static struct net_device_stats *pegasus_netdev_stats( struct net_device *dev ) { - return &((struct pegasus *)dev->priv)->stats; + return &((pegasus_t *)dev->priv)->stats; } -static inline void pegasus_stop_net( struct pegasus *pegasus ) +static inline void stop_net( pegasus_t *pegasus ) { - int tmp; + int tmp=0; - pegasus_get_registers( pegasus, EthCtrl0, 1, &tmp ); - pegasus_set_register( pegasus, EthCtrl0, tmp & 0x3f ); + set_registers( pegasus, EthCtrl0, 2, &tmp ); } static int pegasus_open(struct net_device *net) { - struct pegasus *pegasus = (struct pegasus *)net->priv; - int res; + pegasus_t *pegasus = (pegasus_t *)net->priv; + int res; - if ((res = pegasus_start_net(net, pegasus->usb))) { + if ((res = start_net(net, pegasus->usb))) { err("can't start_net() - %d", res); return -EIO; } - - if ((res = usb_submit_urb(&pegasus->rx_urb))) - warn("(open)failed rx_urb %d", res); - - if ((res = usb_submit_urb(&pegasus->intr_urb))) - warn("(open)failed intr_urb %d", res); - - netif_start_queue(net); + pegasus->rx_urb.dev = pegasus->usb; + if ( (res = usb_submit_urb(&pegasus->rx_urb)) ) + warn( __FUNCTION__ " failed rx_urb %d", res ); +#ifdef PEGASUS_USE_INTR + pegasus->intr_urb.dev = pegasus->usb; + if ( (res = usb_submit_urb(&pegasus->intr_urb)) ) + warn( __FUNCTION__ " failed intr_urb %d", res); +#endif + netif_start_queue( net ); pegasus->flags |= PEGASUS_RUNNING; return 0; } -static int pegasus_close(struct net_device *net) +static int pegasus_close( struct net_device *net ) { - struct pegasus *pegasus = net->priv; + pegasus_t *pegasus = net->priv; + stop_net( pegasus ); pegasus->flags &= ~PEGASUS_RUNNING; - pegasus_stop_net( pegasus ); - netif_stop_queue(net); - usb_unlink_urb(&pegasus->rx_urb); - usb_unlink_urb(&pegasus->tx_urb); - usb_unlink_urb(&pegasus->intr_urb); - pegasus_unlink_ctrl_urbs( pegasus ); + usb_unlink_urb( &pegasus->rx_urb ); + usb_unlink_urb( &pegasus->tx_urb ); + usb_unlink_urb( &pegasus->ctrl_urb ); + usb_unlink_urb( &pegasus->intr_urb ); return 0; } -static int pegasus_ioctl(struct net_device *net, struct ifreq *rq, int cmd) +static int pegasus_ioctl( struct net_device *net, struct ifreq *rq, int cmd ) { __u16 *data = (__u16 *)&rq->ifr_data; - struct pegasus *pegasus = net->priv; + pegasus_t *pegasus = net->priv; switch(cmd) { case SIOCDEVPRIVATE: - data[0] = 1; + data[0] = pegasus->phy; case SIOCDEVPRIVATE+1: - pegasus_read_phy_word(pegasus, data[1] & 0x1f, &data[3]); + read_phy_word(pegasus, data[0], data[1]&0x1f, &data[3]); return 0; case SIOCDEVPRIVATE+2: - if (!capable(CAP_NET_ADMIN)) + if ( !capable(CAP_NET_ADMIN) ) return -EPERM; - pegasus_write_phy_word(pegasus, data[1] & 0x1f, data[2]); + write_phy_word(pegasus, pegasus->phy, data[1] & 0x1f, data[2]); return 0; default: return -EOPNOTSUPP; @@ -621,36 +793,29 @@ } -static void pegasus_set_rx_mode(struct net_device *net) +static void pegasus_set_multicast( struct net_device *net ) { -#ifndef PEGASUS_USE_WAITQ - struct pegasus *pegasus = net->priv; - __u8 tmp; -#endif + pegasus_t *pegasus = net->priv; netif_stop_queue(net); if (net->flags & IFF_PROMISC) { -#ifndef PEGASUS_USE_WAITQ - pegasus_get_registers(pegasus, EthCtrl2, 1, &tmp); - pegasus_set_register(pegasus, EthCtrl2, tmp | 4); -#endif + pegasus->eth_regs[EthCtrl2] |= RX_PROMISCUOUS; info("%s: Promiscuous mode enabled", net->name); } else if ((net->mc_count > multicast_filter_limit) || (net->flags & IFF_ALLMULTI)) { -#ifndef PEGASUS_USE_WAITQ - pegasus_set_register(pegasus, EthCtrl0, 0xfa); - pegasus_set_register(pegasus, EthCtrl2, 0); -#endif + pegasus->eth_regs[EthCtrl0] |= RX_MULTICAST; + pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS; info("%s set allmulti", net->name); } else { -#ifndef PEGASUS_USE_WAITQ - pegasus_get_registers(pegasus, EthCtrl2, 1, &tmp); - pegasus_set_register(pegasus, EthCtrl2, tmp & ~4); -#endif + pegasus->eth_regs[EthCtrl0] &= ~RX_MULTICAST; + pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS; info("%s: set Rx mode", net->name); } + pegasus->flags |= ETH_REGS_CHANGE; + ctrl_callback( &pegasus->ctrl_urb ); + netif_wake_queue(net); } @@ -669,10 +834,38 @@ } -static void * pegasus_probe(struct usb_device *dev, unsigned int ifnum) +static __u8 mii_phy_probe( pegasus_t *pegasus ) +{ + int i; + __u16 tmp; + + for ( i=0; i < 32; i++ ) { + read_phy_word( pegasus, i, MII_BMSR, &tmp ); + if ( tmp == 0 || tmp == 0xffff || (tmp & BMSR_MEDIA) == 0 ) + continue; + else + return i; + } + + return 0; +} + + +static inline void setup_pegasus_II( pegasus_t *pegasus ) +{ + set_register( pegasus, Reg1d, 0 ); + set_register( pegasus, Reg7b, 2 ); + if ( pegasus->features & HAS_HOME_PNA ) + set_register( pegasus, Reg81, 6 ); + else + set_register( pegasus, Reg81, 2 ); +} + + +static void * pegasus_probe( struct usb_device *dev, unsigned int ifnum ) { struct net_device *net; - struct pegasus *pegasus; + pegasus_t *pegasus; int dev_indx; if ( (dev_indx = check_device_ids(dev->descriptor.idVendor, dev->descriptor.idProduct)) == -1 ) { @@ -698,34 +891,50 @@ net->tx_timeout = pegasus_tx_timeout; net->do_ioctl = pegasus_ioctl; net->hard_start_xmit = pegasus_start_xmit; - net->set_multicast_list = pegasus_set_rx_mode; + net->set_multicast_list = pegasus_set_multicast; net->get_stats = pegasus_netdev_stats; net->mtu = PEGASUS_MTU; init_MUTEX( &pegasus-> ctrl_sem ); init_waitqueue_head( &pegasus->ctrl_wait ); + usb_inc_dev_use (dev); pegasus->usb = dev; pegasus->net = net; FILL_BULK_URB( &pegasus->rx_urb, dev, usb_rcvbulkpipe(dev, 1), pegasus->rx_buff, PEGASUS_MAX_MTU, - pegasus_read_bulk_callback, pegasus ); + read_bulk_callback, pegasus ); FILL_BULK_URB( &pegasus->tx_urb, dev, usb_sndbulkpipe(dev, 2), pegasus->tx_buff, PEGASUS_MAX_MTU, - pegasus_write_bulk_callback, pegasus ); + write_bulk_callback, pegasus ); FILL_INT_URB( &pegasus->intr_urb, dev, usb_rcvintpipe(dev, 3), - pegasus->intr_buff, 8, pegasus_irq_callback, - pegasus, 128 ); + pegasus->intr_buff, 8, intr_callback, + pegasus, INTR_IVAL ); - if (pegasus_reset_mac(pegasus)) { + pegasus->features = usb_dev_id[dev_indx].private; + if ( reset_mac(pegasus) ) { err("can't reset MAC"); + unregister_netdev( pegasus->net ); kfree(pegasus); pegasus = NULL; return NULL; } - - info( "%s: %s\n", net->name, usb_dev_id[dev_indx].name ); + + if ( pegasus->features & PEGASUS_II ) { + info( "setup Pegasus II specific registers" ); + setup_pegasus_II( pegasus ); + } + + pegasus->phy = mii_phy_probe( pegasus ); + if ( !pegasus->phy ) { + warn( "can't locate MII phy, using default" ); + pegasus->phy = 1; + } + + set_intr_interval( pegasus ); + + info( "%s: %s", net->name, usb_dev_id[dev_indx].name ); MOD_INC_USE_COUNT; @@ -733,24 +942,22 @@ } -static void pegasus_disconnect(struct usb_device *dev, void *ptr) +static void pegasus_disconnect( struct usb_device *dev, void *ptr ) { struct pegasus *pegasus = ptr; - if (!pegasus) { + if ( !pegasus ) { warn("unregistering non-existant device"); return; } + stop_net( pegasus ); pegasus->flags &= ~PEGASUS_RUNNING; - unregister_netdev(pegasus->net); - - usb_unlink_urb(&pegasus->rx_urb); - usb_unlink_urb(&pegasus->tx_urb); - usb_unlink_urb(&pegasus->intr_urb); - pegasus_unlink_ctrl_urbs( pegasus ); + netif_stop_queue( pegasus->net ); + unregister_netdev( pegasus->net ); - kfree(pegasus); + usb_dec_dev_use (pegasus->usb); + kfree( pegasus ); pegasus = NULL; MOD_DEC_USE_COUNT; @@ -766,13 +973,13 @@ int __init pegasus_init(void) { info( "%s", version ); - return usb_register(&pegasus_driver); + return usb_register( &pegasus_driver ); } void __exit pegasus_exit(void) { - usb_deregister(&pegasus_driver); + usb_deregister( &pegasus_driver ); } -module_init(pegasus_init); -module_exit(pegasus_exit); +module_init( pegasus_init ); +module_exit( pegasus_exit ); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/usb/scanner.c linux/drivers/usb/scanner.c --- v2.4.0-test8/linux/drivers/usb/scanner.c Mon Jun 19 13:42:42 2000 +++ linux/drivers/usb/scanner.c Tue Sep 19 17:47:06 2000 @@ -199,6 +199,14 @@ * - Fixed HP S20 ID's...again..sigh. Thanks to Ruud * Linders . * + * 0.4.4 + * - Added addtional Mustek ID's (BearPaw 1200, 600 CU, 1200 USB, + * and 1200 UB. Thanks to Henning Meier-Geinitz . + * - Added the Vuego Scan Brisa 340U ID's. Apparently this scanner is + * marketed by Acer Peripherals as a cheap 300 dpi model. Thanks to + * David Gundersen . + * - Added the Epson Expression1600 ID's. Thanks to Karl Heinz + * Kremer . * * TODO * diff -u --recursive --new-file v2.4.0-test8/linux/drivers/usb/scanner.h linux/drivers/usb/scanner.h --- v2.4.0-test8/linux/drivers/usb/scanner.h Mon Jun 19 13:42:42 2000 +++ linux/drivers/usb/scanner.h Tue Sep 19 17:47:06 2000 @@ -106,6 +106,7 @@ /* Acer */ { 0x04a5, 0x2060 }, /* Prisa Acerscan 620U & 640U (!) */ { 0x04a5, 0x2040 }, /* Prisa AcerScan 620U (!) */ + { 0x04a5, 0x2022 }, /* Vuego Scan Brisa 340U */ /* Agfa */ { 0x06bd, 0x0001 }, /* SnapScan 1212U */ { 0x06bd, 0x2061 }, /* Another SnapScan 1212U (?) */ @@ -120,6 +121,7 @@ { 0x03f0, 0x0105 }, /* 4200C */ { 0x03f0, 0x0102 }, /* PhotoSmart S20 */ { 0x03f0, 0x0401 }, /* 5200C */ + { 0x03f0, 0x0701 }, /* 5300C */ { 0x03f0, 0x0201 }, /* 6200C */ { 0x03f0, 0x0601 }, /* 6300C */ /* iVina */ @@ -134,6 +136,10 @@ { 0x05da, 0x80ac }, /* ScanMaker V6UL - SpicyU */ /* Mustek */ { 0x055f, 0x0001 }, /* 1200 CU */ + { 0x0400, 0x1000 }, /* BearPaw 1200 */ + { 0x055f, 0x0002 }, /* 600 CU */ + { 0x055f, 0x0003 }, /* 1200 USB */ + { 0x055f, 0x0006 }, /* 1200 UB */ /* Primax/Colorado */ { 0x0461, 0x0300 }, /* G2-300 #1 */ { 0x0461, 0x0380 }, /* G2-600 #1 */ @@ -151,15 +157,19 @@ { 0x04b8, 0x0101 }, /* Perfection 636U and 636Photo */ { 0x04b8, 0x0103 }, /* Perfection 610 */ { 0x04b8, 0x0104 }, /* Perfection 1200U and 1200Photo */ + { 0x04b8, 0x0107 }, /* Expression 1600 */ /* Umax */ { 0x1606, 0x0010 }, /* Astra 1220U */ { 0x1606, 0x0002 }, /* Astra 1236U */ { 0x1606, 0x0030 }, /* Astra 2000U */ { 0x1606, 0x0230 }, /* Astra 2200U */ /* Visioneer */ - { 0x04a7, 0x0221 }, /* OneTouch 5300 */ - { 0x04a7, 0x0221 }, /* OneTouch 7600 duplicate ID (!) */ - { 0x04a7, 0x0231 }, /* 6100 */ + { 0x04a7, 0x0221 }, /* OneTouch 5300 USB */ + { 0x04a7, 0x0211 }, /* OneTouch 7600 USB */ + { 0x04a7, 0x0231 }, /* 6100 USB */ + { 0x04a7, 0x0311 }, /* 6200 EPP/USB */ + { 0x04a7, 0x0321 }, /* OneTouch 8100 EPP/USB */ + { 0x04a7, 0x0331 }, /* OneTouch 8600 EPP/USB */ }; /* Forward declarations */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/usb/serial/ftdi_sio.c linux/drivers/usb/serial/ftdi_sio.c --- v2.4.0-test8/linux/drivers/usb/serial/ftdi_sio.c Tue Sep 5 13:42:52 2000 +++ linux/drivers/usb/serial/ftdi_sio.c Mon Sep 18 15:23:25 2000 @@ -12,6 +12,9 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (09/11/2000) gkh + * Removed DEBUG #ifdefs with call to usb_serial_debug_data + * * (07/19/2000) gkh * Added module_init and module_exit functions to handle the fact that this * driver is a loadable module now. @@ -331,26 +334,9 @@ first_byte = port->write_urb->transfer_buffer; *first_byte = 1 | ((count-data_offset) << 2) ; -#ifdef CONFIG_USB_SERIAL_DEBUG dbg("Bytes: %d, Control Byte: 0o%03o",count, first_byte[0]); - - if (count) { - int i; - printk (KERN_DEBUG __FILE__ ": data written - length = %d, data = ", count); - for (i = 0; i < count; ++i) { - printk ( "0x%02x ", first_byte[i]); - if (first_byte[i] > ' ' && first_byte[i] < '~') { - printk( "%c ", first_byte[i]); - } else { - printk( " "); - } - } - - - printk ( "\n"); - } - -#endif + usb_serial_debug_data (__FILE__, __FUNCTION__, count, first_byte); + /* send the data out the bulk port */ port->write_urb->transfer_buffer_length = count; @@ -429,23 +415,11 @@ return; } -#ifdef CONFIG_USB_SERIAL_DEBUG if (urb->actual_length > 2) { - printk (KERN_DEBUG __FILE__ ": data read - length = %d, data = ", urb->actual_length); - for (i = 0; i < urb->actual_length; ++i) { - printk ( "0x%.2x ", data[i]); - if (data[i] > ' ' && data[i] < '~') { - printk( "%c ", data[i]); - } else { - printk( " "); - } - } - printk ( "\n"); + usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data); } else { dbg("Just status"); } -#endif - if (urb->actual_length > data_offset) { for (i = data_offset ; i < urb->actual_length ; ++i) { diff -u --recursive --new-file v2.4.0-test8/linux/drivers/usb/serial/usb-serial.h linux/drivers/usb/serial/usb-serial.h --- v2.4.0-test8/linux/drivers/usb/serial/usb-serial.h Tue Sep 5 13:19:08 2000 +++ linux/drivers/usb/serial/usb-serial.h Mon Sep 18 15:23:25 2000 @@ -11,6 +11,10 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (09/11/2000) gkh + * Added usb_serial_debug_data function to help get rid of #DEBUG in the + * drivers. + * * (08/28/2000) gkh * Added port_lock to port structure. * @@ -204,6 +208,18 @@ return port->serial; } + +static inline void usb_serial_debug_data (const char *file, const char *function, int size, const unsigned char *data) +{ +#ifdef CONFIG_USB_SERIAL_DEBUG + int i; + printk (KERN_DEBUG "%s: %s - length = %d, data = ", file, function, size); + for (i = 0; i < size; ++i) { + printk ("%.2x ", data[i]); + } + printk ("\n"); +#endif +} #endif /* ifdef __LINUX_USB_SERIAL_H */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/usb/serial/usbserial.c linux/drivers/usb/serial/usbserial.c --- v2.4.0-test8/linux/drivers/usb/serial/usbserial.c Tue Sep 5 13:19:08 2000 +++ linux/drivers/usb/serial/usbserial.c Mon Sep 18 15:23:25 2000 @@ -15,6 +15,9 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (09/11/2000) gkh + * Removed DEBUG #ifdefs with call to usb_serial_debug_data + * * (08/28/2000) gkh * Added port_lock to port structure. * Added locks for SMP safeness to generic driver @@ -766,16 +769,7 @@ spin_lock_irqsave (&port->port_lock, flags); count = (count > port->bulk_out_size) ? port->bulk_out_size : count; -#ifdef DEBUG - { - int i; - printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ " - length = %d, data = ", count); - for (i = 0; i < count; ++i) { - printk ("%.2x ", buf[i]); - } - printk ("\n"); - } -#endif + usb_serial_debug_data (__FILE__, __FUNCTION__, count, buf); if (from_user) { copy_from_user(port->write_urb->transfer_buffer, buf, count); @@ -854,15 +848,7 @@ return; } -#ifdef DEBUG - if (urb->actual_length) { - printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ "- length = %d, data = ", urb->actual_length); - for (i = 0; i < urb->actual_length; ++i) { - printk ("%.2x ", data[i]); - } - printk ("\n"); - } -#endif + usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data); tty = port->tty; if (urb->actual_length) { diff -u --recursive --new-file v2.4.0-test8/linux/drivers/usb/serial/visor.c linux/drivers/usb/serial/visor.c --- v2.4.0-test8/linux/drivers/usb/serial/visor.c Tue Sep 5 13:42:52 2000 +++ linux/drivers/usb/serial/visor.c Mon Sep 18 15:23:25 2000 @@ -11,6 +11,17 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (09/11/2000) gkh + * Got rid of always calling kmalloc for every urb we wrote out to the + * device. + * Added visor_read_callback so we can keep track of bytes in and out for + * those people who like to know the speed of their device. + * Removed DEBUG #ifdefs with call to usb_serial_debug_data + * + * (09/06/2000) gkh + * Fixed oops in visor_exit. Need to uncomment usb_unlink_urb call _after_ + * the host controller drivers set urb->dev = NULL when the urb is finished. + * * (08/28/2000) gkh * Added locks for SMP safeness. * @@ -71,6 +82,7 @@ #include "visor.h" +#define MIN(a,b) (((a)<(b))?(a):(b)) /* function prototypes for a handspring visor */ static int visor_open (struct usb_serial_port *port, struct file *filp); @@ -82,7 +94,8 @@ static void visor_shutdown (struct usb_serial *serial); static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg); static void visor_set_termios (struct usb_serial_port *port, struct termios *old_termios); -static void visor_write_bulk_callback (struct urb *urb); +static void visor_write_bulk_callback (struct urb *urb); +static void visor_read_bulk_callback (struct urb *urb); /* All of the device info needed for the Handspring Visor */ static __u16 handspring_vendor_id = HANDSPRING_VENDOR_ID; @@ -108,12 +121,17 @@ set_termios: visor_set_termios, write: visor_write, write_bulk_callback: visor_write_bulk_callback, + read_bulk_callback: visor_read_bulk_callback, }; -#define NUM_URBS 24 +#define NUM_URBS 24 +#define URB_TRANSFER_BUFFER_SIZE 64 static struct urb *write_urb_pool[NUM_URBS]; static spinlock_t write_urb_pool_lock; +static int bytes_in; +static int bytes_out; + /****************************************************************************** * Handspring Visor specific driver functions @@ -134,6 +152,8 @@ if (!port->active) { port->active = 1; + bytes_in = 0; + bytes_out = 0; /*Start reading from the device*/ if (usb_submit_urb(port->read_urb)) @@ -181,78 +201,79 @@ usb_unlink_urb (port->read_urb); port->active = 0; port->open_count = 0; - } + } spin_unlock_irqrestore (&port->port_lock, flags); + + /* Uncomment the following line if you want to see some statistics in your syslog */ + /* info ("Bytes In = %d Bytes Out = %d", bytes_in, bytes_out); */ } static int visor_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count) { struct usb_serial *serial = port->serial; - struct urb *urb = NULL; - unsigned char *buffer = NULL; + struct urb *urb; + const unsigned char *current_position = buf; + unsigned long flags; int status; int i; - unsigned long flags; + int bytes_sent = 0; + int transfer_size; dbg(__FUNCTION__ " - port %d", port->number); - if (count == 0) { - dbg(__FUNCTION__ " - write request of 0 bytes"); - return 0; - } - - /* try to find a free urb in our list of them */ - spin_lock_irqsave (&write_urb_pool_lock, flags); - for (i = 0; i < NUM_URBS; ++i) { - if (write_urb_pool[i]->status != -EINPROGRESS) { - urb = write_urb_pool[i]; - break; + usb_serial_debug_data (__FILE__, __FUNCTION__, count, buf); + + while (count > 0) { + /* try to find a free urb in our list of them */ + urb = NULL; + spin_lock_irqsave (&write_urb_pool_lock, flags); + for (i = 0; i < NUM_URBS; ++i) { + if (write_urb_pool[i]->status != -EINPROGRESS) { + urb = write_urb_pool[i]; + break; + } } + spin_unlock_irqrestore (&write_urb_pool_lock, flags); + if (urb == NULL) { + dbg (__FUNCTION__ " - no more free urbs"); + goto exit; + } + if (urb->transfer_buffer == NULL) { + urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL); + if (urb->transfer_buffer == NULL) { + err(__FUNCTION__" no more kernel memory..."); + goto exit; + } + } + + transfer_size = MIN (count, URB_TRANSFER_BUFFER_SIZE); + if (from_user) + copy_from_user (urb->transfer_buffer, current_position, transfer_size); + else + memcpy (urb->transfer_buffer, current_position, transfer_size); + + count = (count > port->bulk_out_size) ? port->bulk_out_size : count; + + /* build up our urb */ + FILL_BULK_URB (urb, serial->dev, usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress), + urb->transfer_buffer, transfer_size, visor_write_bulk_callback, port); + urb->transfer_flags |= USB_QUEUE_BULK; + + /* send it down the pipe */ + status = usb_submit_urb(urb); + if (status) + dbg(__FUNCTION__ " - usb_submit_urb(write bulk) failed with status = %d", status); + + current_position += transfer_size; + bytes_sent += transfer_size; + count -= transfer_size; + bytes_out += transfer_size; } - spin_unlock_irqrestore (&write_urb_pool_lock, flags); - if (urb == NULL) { - dbg (__FUNCTION__ " - no free urbs"); - return 0; - } - - count = (count > port->bulk_out_size) ? port->bulk_out_size : count; - -#ifdef DEBUG - printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ " - length = %d, data = ", count); - for (i = 0; i < count; ++i) { - printk ("%.2x ", buf[i]); - } - printk ("\n"); -#endif - if (urb->transfer_buffer != NULL) - kfree(urb->transfer_buffer); - buffer = kmalloc (count, GFP_KERNEL); - if (buffer == NULL) { - err(__FUNCTION__" no more kernel memory..."); - return 0; - } - - if (from_user) { - copy_from_user(buffer, buf, count); - } - else { - memcpy (buffer, buf, count); - } - - /* build up our urb */ - FILL_BULK_URB (urb, serial->dev, usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress), - buffer, count, visor_write_bulk_callback, port); - urb->transfer_flags |= USB_QUEUE_BULK; - - /* send it down the pipe */ - status = usb_submit_urb(urb); - if (status) - dbg(__FUNCTION__ " - usb_submit_urb(write bulk) failed with status = %d", status); - - return (count); +exit: + return bytes_sent; } @@ -277,6 +298,41 @@ } +static void visor_read_bulk_callback (struct urb *urb) +{ + struct usb_serial_port *port = (struct usb_serial_port *)urb->context; + struct tty_struct *tty; + unsigned char *data = urb->transfer_buffer; + int i; + + if (port_paranoia_check (port, __FUNCTION__)) + return; + + dbg(__FUNCTION__ " - port %d", port->number); + + if (urb->status) { + dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status); + return; + } + + usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data); + + tty = port->tty; + if (urb->actual_length) { + for (i = 0; i < urb->actual_length ; ++i) { + tty_insert_flip_char(tty, data[i], 0); + } + tty_flip_buffer_push(tty); + bytes_in += urb->actual_length; + } + + /* Continue trying to always read */ + if (usb_submit_urb(urb)) + dbg(__FUNCTION__ " - failed resubmitting read urb"); + return; +} + + static void visor_throttle (struct usb_serial_port *port) { unsigned long flags; @@ -372,7 +428,7 @@ kfree (transfer_buffer); /* continue on with initialization */ - return (0); + return 0; } @@ -466,20 +522,27 @@ static int __init visor_init (void) { + struct urb *urb; int i; usb_serial_register (&handspring_device); - /* create our write urb pool */ + /* create our write urb pool and transfer buffers */ spin_lock_init (&write_urb_pool_lock); for (i = 0; i < NUM_URBS; ++i) { - struct urb *urb = usb_alloc_urb(0); + urb = usb_alloc_urb(0); + write_urb_pool[i] = urb; if (urb == NULL) { err("No more urbs???"); continue; } + urb->transfer_buffer = NULL; - write_urb_pool[i] = urb; + urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL); + if (!urb->transfer_buffer) { + err (__FUNCTION__ " - out of memory for urb buffers."); + continue; + } } return 0; @@ -496,10 +559,15 @@ spin_lock_irqsave (&write_urb_pool_lock, flags); for (i = 0; i < NUM_URBS; ++i) { - usb_unlink_urb(write_urb_pool[i]); - if (write_urb_pool[i]->transfer_buffer) - kfree(write_urb_pool[i]->transfer_buffer); - usb_free_urb (write_urb_pool[i]); + if (write_urb_pool[i]) { + /* FIXME - uncomment the following usb_unlink_urb call when + * the host controllers get fixed to set urb->dev = NULL after + * the urb is finished. Otherwise this call oopses. */ + /* usb_unlink_urb(write_urb_pool[i]); */ + if (write_urb_pool[i]->transfer_buffer) + kfree(write_urb_pool[i]->transfer_buffer); + usb_free_urb (write_urb_pool[i]); + } } spin_unlock_irqrestore (&write_urb_pool_lock, flags); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/usb/serial/whiteheat.c linux/drivers/usb/serial/whiteheat.c --- v2.4.0-test8/linux/drivers/usb/serial/whiteheat.c Thu Sep 7 08:36:40 2000 +++ linux/drivers/usb/serial/whiteheat.c Mon Sep 18 15:23:25 2000 @@ -11,6 +11,9 @@ * * See Documentation/usb/usb-serial.txt for more information on using this driver * + * (09/11/2000) gkh + * Removed DEBUG #ifdefs with call to usb_serial_debug_data + * * (07/19/2000) gkh * Added module_init and module_exit functions to handle the fact that this * driver is a loadable module now. @@ -130,11 +133,6 @@ *****************************************************************************/ static void command_port_write_callback (struct urb *urb) { -#ifdef DEBUG - int i; - unsigned char *data = urb->transfer_buffer; -#endif - dbg (__FUNCTION__); if (urb->status) { @@ -142,15 +140,7 @@ return; } -#ifdef DEBUG - if (urb->actual_length) { - printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ " - length = %d, data = ", urb->actual_length); - for (i = 0; i < urb->actual_length; ++i) { - printk ("%.2x ", data[i]); - } - printk ("\n"); - } -#endif + usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, urb->transfer_buffer); return; } @@ -160,9 +150,6 @@ { struct whiteheat_private *info = (struct whiteheat_private *)urb->context; unsigned char *data = urb->transfer_buffer; -#ifdef DEBUG - int i; -#endif dbg (__FUNCTION__); @@ -171,15 +158,7 @@ return; } -#ifdef DEBUG - if (urb->actual_length) { - printk (KERN_DEBUG __FILE__ ": " __FUNCTION__ " - length = %d, data = ", urb->actual_length); - for (i = 0; i < urb->actual_length; ++i) { - printk ("%.2x ", data[i]); - } - printk ("\n"); - } -#endif + usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data); /* right now, if the command is COMMAND_COMPLETE, just flip the bit saying the command finished */ /* in the future we're going to have to pay attention to the actual command that completed */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/usb/storage/Makefile linux/drivers/usb/storage/Makefile --- v2.4.0-test8/linux/drivers/usb/storage/Makefile Mon Aug 28 16:59:14 2000 +++ linux/drivers/usb/storage/Makefile Fri Sep 8 16:39:12 2000 @@ -21,7 +21,7 @@ usb-storage-obj-$(CONFIG_USB_STORAGE_DPCM) += dpcm.o usb-storage-objs := scsiglue.o protocol.o transport.o usb.o \ - $(usb-storage-obj-y) + initializers.o $(usb-storage-obj-y) # Extract lists of the multi-part drivers. # The 'int-*' lists are the intermediate files used to build the multi's. diff -u --recursive --new-file v2.4.0-test8/linux/drivers/usb/storage/debug.c linux/drivers/usb/storage/debug.c --- v2.4.0-test8/linux/drivers/usb/storage/debug.c Mon Aug 28 16:59:14 2000 +++ linux/drivers/usb/storage/debug.c Fri Sep 8 16:39:12 2000 @@ -1,7 +1,7 @@ /* Driver for USB Mass Storage compliant devices * Debugging Functions Source Code File * - * $Id: debug.c,v 1.3 2000/08/25 00:13:51 mdharm Exp $ + * $Id: debug.c,v 1.4 2000/09/04 02:12:47 groovyjava Exp $ * * Current development and maintenance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) @@ -206,5 +206,162 @@ sg[i].address[14], sg[i].address[15]); } +} + +void usb_stor_show_sense( + unsigned char key, + unsigned char asc, + unsigned char ascq) { + + char *keys[] = { + "No Sense", + "Recovered Error", + "Not Ready", + "Medium Error", + "Hardware Error", + "Illegal Request", + "Unit Attention", + "Data Protect", + "Blank Check", + "Vendor Specific", + "Copy Aborted", + "Aborted Command", + "(Obsolete)", + "Volume Overflow", + "Miscompare" + }; + + unsigned short qual = asc; + + char *what = 0; + char *keystr = 0; + + qual <<= 8; + qual |= ascq; + + if (key>0x0E) + keystr = "(Unknown Key)"; + else + keystr = keys[key]; + + switch (qual) { + + case 0x0000: what="no additional sense information"; break; + case 0x0001: what="filemark detected"; break; + case 0x0002: what="end of partition/medium detected"; break; + case 0x0003: what="setmark detected"; break; + case 0x0004: what="beginning of partition/medium detected"; break; + case 0x0005: what="end of data detected"; break; + case 0x0006: what="I/O process terminated"; break; + case 0x0011: what="audio play operation in progress"; break; + case 0x0012: what="audio play operation paused"; break; + case 0x0013: what="audio play operation stopped due to error"; break; + case 0x0014: what="audio play operation successfully completed"; break; + case 0x0015: what="no current audio status to return"; break; + case 0x0016: what="operation in progress"; break; + case 0x0017: what="cleaning requested"; break; + case 0x0100: what="no index/sector signal"; break; + case 0x0200: what="no seek complete"; break; + case 0x0300: what="peripheral device write fault"; break; + case 0x0301: what="no write current"; break; + case 0x0302: what="excessive write errors"; break; + case 0x0400: what="LUN not ready, cause not reportable"; break; + case 0x0401: what="LUN in process of becoming ready"; break; + case 0x0402: what="LUN not ready, initializing cmd. required"; break; + case 0x0403: what="LUN not ready, manual intervention required"; break; + case 0x0404: what="LUN not ready, format in progress"; break; + case 0x0405: what="LUN not ready, rebuild in progress"; break; + case 0x0406: what="LUN not ready, recalculation in progress"; break; + case 0x0407: what="LUN not ready, operation in progress"; break; + case 0x0408: what="LUN not ready, long write in progress"; break; + case 0x0500: what="LUN doesn't respond to selection"; break; + case 0x0A00: what="error log overflow"; break; + case 0x0C04: what="compression check miscompare error"; break; + case 0x0C05: what="data expansion occurred during compression"; break; + case 0x0C06: what="block not compressible"; break; + case 0x1102: what="error too long to correct"; break; + case 0x1106: what="CIRC unrecovered error"; break; + case 0x1107: what="data resynchronization error"; break; + case 0x110D: what="decompression CRC error"; break; + case 0x110E: what="can't decompress using declared algorithm"; break; + case 0x110F: what="error reading UPC/EAN number"; break; + case 0x1110: what="error reading ISRC number"; break; + case 0x1200: what="address mark not found for ID field"; break; + case 0x1300: what="address mark not found for data field"; break; + case 0x1403: what="end of data not found"; break; + case 0x1404: what="block sequence error"; break; + case 0x1600: what="data sync mark error"; break; + case 0x1601: what="data sync error: data rewritten"; break; + case 0x1602: what="data sync error: recommend rewrite"; break; + case 0x1603: what="data sync error: data auto-reallocated"; break; + case 0x1604: what="data sync error: recommend reassignment"; break; + case 0x1900: what="defect list error"; break; + case 0x1901: what="defect list not available"; break; + case 0x1902: what="defect list error in primary list"; break; + case 0x1903: what="defect list error in grown list"; break; + case 0x1C00: what="defect list not found"; break; + case 0x2400: what="invalid field in CDB"; break; + case 0x2703: what="associated write protect"; break; + case 0x2903: what="bus device reset function occurred"; break; + case 0x2904: what="device internal reset"; break; + case 0x2B00: what="copy can't execute since host can't disconnect"; + break; + case 0x2C00: what="command sequence error"; break; + case 0x2C03: what="current program area is not empty"; break; + case 0x2C04: what="current program area is empty"; break; + case 0x2F00: what="commands cleared by another initiator"; break; + case 0x3001: what="can't read medium: unknown format"; break; + case 0x3002: what="can't read medium: incompatible format"; break; + case 0x3003: what="cleaning cartridge installed"; break; + case 0x3004: what="can't write medium: unknown format"; break; + case 0x3005: what="can't write medium: incompatible format"; break; + case 0x3006: what="can't format medium: incompatible medium"; break; + case 0x3007: what="cleaning failure"; break; + case 0x3008: what="can't write: application code mismatch"; break; + case 0x3009: what="current session not fixated for append"; break; + case 0x3201: what="defect list update failure"; break; + case 0x3400: what="enclosure failure"; break; + case 0x3500: what="enclosure services failure"; break; + case 0x3502: what="enclosure services unavailable"; break; + case 0x3503: what="enclosure services transfer failure"; break; + case 0x3504: what="enclosure services transfer refused"; break; + case 0x3B0F: what="end of medium reached"; break; + case 0x3F02: what="changed operating definition"; break; + case 0x4100: what="data path failure (should use 40 NN)"; break; + case 0x4A00: what="command phase error"; break; + case 0x4B00: what="data phase error"; break; + case 0x5100: what="erase failure"; break; + case 0x5200: what="cartridge fault"; break; + case 0x6300: what="end of user area encountered on this track"; break; + case 0x6600: what="automatic document feeder cover up"; break; + case 0x6601: what="automatic document feeder lift up"; break; + case 0x6602: what="document jam in auto doc feeder"; break; + case 0x6603: what="document miss feed auto in doc feeder"; break; + case 0x6700: what="configuration failure"; break; + case 0x6701: what="configuration of incapable LUN's failed"; break; + case 0x6702: what="add logical unit failed"; break; + case 0x6706: what="attachment of logical unit failed"; break; + case 0x6707: what="creation of logical unit failed"; break; + case 0x6900: what="data loss on logical unit"; break; + case 0x6E00: what="command to logical unit failed"; break; + case 0x7100: what="decompression exception long algorithm ID"; break; + case 0x7204: what="empty or partially written reserved track"; break; + case 0x7300: what="CD control error"; break; + + default: + if (asc==0x40) { + US_DEBUGP("%s: diagnostic failure on component" + " %02X\n", keystr, ascq); + return; + } + if (asc==0x70) { + US_DEBUGP("%s: decompression exception short" + " algorithm ID of %02X\n", keystr, ascq); + return; + } + what = "(unknown ASC/ASCQ)"; + } + + US_DEBUGP("%s: %s\n", keystr, what); } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/usb/storage/debug.h linux/drivers/usb/storage/debug.h --- v2.4.0-test8/linux/drivers/usb/storage/debug.h Mon Aug 28 16:59:14 2000 +++ linux/drivers/usb/storage/debug.h Mon Oct 2 11:02:34 2000 @@ -1,7 +1,7 @@ /* Driver for USB Mass Storage compliant devices * Debugging Functions Header File * - * $Id: debug.h,v 1.4 2000/08/25 00:13:51 mdharm Exp $ + * $Id: debug.h,v 1.5 2000/09/04 02:12:47 groovyjava Exp $ * * Current development and maintenance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) @@ -55,6 +55,8 @@ #ifdef CONFIG_USB_STORAGE_DEBUG void usb_stor_show_command(Scsi_Cmnd *srb); void usb_stor_print_Scsi_Cmnd( Scsi_Cmnd* cmd ); +void usb_stor_show_sense( unsigned char key, + unsigned char asc, unsigned char ascq ); #define US_DEBUGP(x...) printk( KERN_DEBUG USB_STORAGE ## x ) #define US_DEBUGPX(x...) printk( ## x ) #define US_DEBUG(x) x diff -u --recursive --new-file v2.4.0-test8/linux/drivers/usb/storage/freecom.c linux/drivers/usb/storage/freecom.c --- v2.4.0-test8/linux/drivers/usb/storage/freecom.c Tue Sep 5 12:56:51 2000 +++ linux/drivers/usb/storage/freecom.c Mon Oct 2 11:54:51 2000 @@ -1,6 +1,6 @@ /* Driver for Freecom USB/IDE adaptor * - * $Id: freecom.c,v 1.7 2000/08/25 00:13:51 mdharm Exp $ + * $Id: freecom.c,v 1.12 2000/09/22 01:16:17 mdharm Exp $ * * Freecom v0.1: * @@ -33,6 +33,7 @@ #include "usb.h" #include "debug.h" #include "freecom.h" +#include "linux/hdreg.h" static void pdump (void *, int); @@ -54,6 +55,18 @@ __u8 Timeout; /* Timeout in seconds. */ __u32 Count; /* Number of bytes to transfer. */ __u8 Pad[58]; +} __attribute__ ((packed)); + +struct freecom_ide_out { + __u8 Type; /* Type + IDE register. */ + __u8 Pad; + __u16 Value; /* Value to write. */ + __u8 Pad2[60]; +}; + +struct freecom_ide_in { + __u8 Type; /* Type | IDE register. */ + __u8 Pad[63]; }; struct freecom_status { @@ -63,17 +76,182 @@ __u8 Pad[60]; }; +/* Freecom stuffs the interrupt status in the INDEX_STAT bit of the ide + * register. */ +#define FCM_INT_STATUS INDEX_STAT + /* These are the packet types. The low bit indicates that this command * should wait for an interrupt. */ #define FCM_PACKET_ATAPI 0x21 +#define FCM_PACKET_STATUS 0x20 /* Receive data from the IDE interface. The ATAPI packet has already * waited, so the data should be immediately available. */ -#define FCM_PACKET_INPUT 0x90 +#define FCM_PACKET_INPUT 0x81 + +/* Send data to the IDE interface. */ +#define FCM_PACKET_OUTPUT 0x01 + +/* Write a value to an ide register. Or the ide register to write after + * munging the addres a bit. */ +#define FCM_PACKET_IDE_WRITE 0x40 +#define FCM_PACKET_IDE_READ 0xC0 /* All packets (except for status) are 64 bytes long. */ #define FCM_PACKET_LENGTH 64 +/* + * Transfer an entire SCSI command's worth of data payload over the bulk + * pipe. + * + * Note that this uses us_transfer_partial to achieve it's goals -- this + * function simply determines if we're going to use scatter-gather or not, + * and acts appropriately. For now, it also re-interprets the error codes. + */ +static void us_transfer_freecom(Scsi_Cmnd *srb, struct us_data* us, int transfer_amount) +{ + int i; + int result = -1; + struct scatterlist *sg; + unsigned int total_transferred = 0; + + /* was someone foolish enough to request more data than available + * buffer space? */ + if (transfer_amount > srb->request_bufflen) + transfer_amount = srb->request_bufflen; + + /* are we scatter-gathering? */ + if (srb->use_sg) { + + /* loop over all the scatter gather structures and + * make the appropriate requests for each, until done + */ + sg = (struct scatterlist *) srb->request_buffer; + for (i = 0; i < srb->use_sg; i++) { + + /* transfer the lesser of the next buffer or the + * remaining data */ + if (transfer_amount - total_transferred >= + sg[i].length) { + result = us_transfer_partial(us, sg[i].address, + sg[i].length); + total_transferred += sg[i].length; + } else + result = us_transfer_partial(us, sg[i].address, + transfer_amount - total_transferred); + + /* if we get an error, end the loop here */ + if (result) + break; + } + } + else + /* no scatter-gather, just make the request */ + result = us_transfer_partial(us, srb->request_buffer, + transfer_amount); + + /* return the result in the data structure itself */ + srb->result = result; +} + + +/* Write a value to an ide register. */ +static int +freecom_ide_write (struct us_data *us, int reg, int value) +{ + freecom_udata_t extra = (freecom_udata_t) us->extra; + struct freecom_ide_out *ideout = + (struct freecom_ide_out *) extra->buffer; + int opipe; + int result, partial; + + printk (KERN_DEBUG "IDE out 0x%02x <- 0x%02x\n", reg, value); + + /* Get handles for both transports. */ + opipe = usb_sndbulkpipe (us->pusb_dev, us->ep_out); + + if (reg < 0 || reg > 8) + return USB_STOR_TRANSPORT_ERROR; + if (reg < 8) + reg |= 0x20; + else + reg = 0x0e; + + ideout->Type = FCM_PACKET_IDE_WRITE | reg; + ideout->Pad = 0; + ideout->Value = cpu_to_le16 (value); + memset (ideout->Pad2, 0, sizeof (ideout->Pad2)); + + result = usb_stor_bulk_msg (us, ideout, opipe, + FCM_PACKET_LENGTH, &partial); + if (result != 0) { + if (result == -ENOENT) + return US_BULK_TRANSFER_ABORTED; + else + return USB_STOR_TRANSPORT_ERROR; + } + + return USB_STOR_TRANSPORT_GOOD; +} + +/* Read a value from an ide register. */ +static int +freecom_ide_read (struct us_data *us, int reg, int *value) +{ + freecom_udata_t extra = (freecom_udata_t) us->extra; + struct freecom_ide_in *idein = + (struct freecom_ide_in *) extra->buffer; + __u8 *buffer = extra->buffer; + int ipipe, opipe; + int result, partial; + int desired_length; + + /* Get handles for both transports. */ + opipe = usb_sndbulkpipe (us->pusb_dev, us->ep_out); + ipipe = usb_rcvbulkpipe (us->pusb_dev, us->ep_in); + + if (reg < 0 || reg > 8) + return USB_STOR_TRANSPORT_ERROR; + if (reg < 8) + reg |= 0x10; + else + reg = 0x0e; + + idein->Type = FCM_PACKET_IDE_READ | reg; + memset (idein->Pad, 0, sizeof (idein->Pad)); + + result = usb_stor_bulk_msg (us, idein, opipe, + FCM_PACKET_LENGTH, &partial); + if (result != 0) { + if (result == -ENOENT) + return US_BULK_TRANSFER_ABORTED; + else + return USB_STOR_TRANSPORT_ERROR; + } + + desired_length = 1; + if (reg == 0x10) + desired_length = 2; + + result = usb_stor_bulk_msg (us, buffer, ipipe, + desired_length, &partial); + if (result != 0) { + if (result == -ENOENT) + return US_BULK_TRANSFER_ABORTED; + else + return USB_STOR_TRANSPORT_ERROR; + } + + if (desired_length == 1) + *value = buffer[0]; + else + *value = le16_to_cpu (*(__u16 *) buffer); + + printk (KERN_DEBUG "IDE in 0x%02x -> 0x%02x\n", reg, *value); + + return USB_STOR_TRANSPORT_GOOD; +} + static int freecom_readdata (Scsi_Cmnd *srb, struct us_data *us, int ipipe, int opipe, int count) @@ -83,6 +261,7 @@ (struct freecom_xfer_wrap *) extra->buffer; int result, partial; int offset; + int this_read; __u8 *buffer = extra->buffer; fxfr->Type = FCM_PACKET_INPUT | 0x00; @@ -111,6 +290,9 @@ result, partial); /* Now transfer all of our blocks. */ + printk (KERN_DEBUG "Start of read\n"); + us_transfer_freecom(srb, us, count); +#if 0 if (srb->use_sg) { US_DEBUGP ("Need to implement scatter-gather\n"); return USB_STOR_TRANSPORT_ERROR; @@ -118,6 +300,14 @@ offset = 0; while (offset < count) { +#if 0 + this_read = count - offset; + if (this_read > 64) + this_read = 64; +#else + this_read = 64; +#endif + printk (KERN_DEBUG "Start of read\n"); /* Use the given buffer directly, but only if there * is space for an entire packet. */ @@ -125,7 +315,7 @@ if (offset + 64 <= srb->request_bufflen) { result = usb_stor_bulk_msg ( us, srb->request_buffer+offset, - ipipe, 64, &partial); + ipipe, this_read, &partial); printk (KERN_DEBUG "Read111 = %d, %d\n", result, partial); pdump (srb->request_buffer+offset, @@ -133,7 +323,7 @@ } else { result = usb_stor_bulk_msg ( us, buffer, - ipipe, 64, &partial); + ipipe, this_read, &partial); printk (KERN_DEBUG "Read112 = %d, %d\n", result, partial); memcpy (srb->request_buffer+offset, @@ -156,14 +346,118 @@ return USB_STOR_TRANSPORT_ERROR; } - offset += 64; + offset += this_read; } } +#endif printk (KERN_DEBUG "freecom_readdata done!\n"); return USB_STOR_TRANSPORT_GOOD; } +static int +freecom_writedata (Scsi_Cmnd *srb, struct us_data *us, + int ipipe, int opipe, int count) +{ + freecom_udata_t extra = (freecom_udata_t) us->extra; + struct freecom_xfer_wrap *fxfr = + (struct freecom_xfer_wrap *) extra->buffer; + int result, partial; + int offset; + int this_write; + __u8 *buffer = extra->buffer; + + fxfr->Type = FCM_PACKET_OUTPUT | 0x00; + fxfr->Timeout = 0; /* Short timeout for debugging. */ + fxfr->Count = cpu_to_le32 (count); + memset (fxfr->Pad, 0, sizeof (fxfr->Pad)); + + printk (KERN_DEBUG "Write data Freecom! (c=%d)\n", count); + + /* Issue the transfer command. */ + result = usb_stor_bulk_msg (us, fxfr, opipe, + FCM_PACKET_LENGTH, &partial); + if (result != 0) { + US_DEBUGP ("Freecom writedata xpot failure: r=%d, p=%d\n", + result, partial); + + /* -ENOENT -- we canceled this transfer */ + if (result == -ENOENT) { + US_DEBUGP("us_transfer_partial(): transfer aborted\n"); + return US_BULK_TRANSFER_ABORTED; + } + + return USB_STOR_TRANSPORT_ERROR; + } + printk (KERN_DEBUG "Done issuing write request: %d %d\n", + result, partial); + + /* Now transfer all of our blocks. */ + printk (KERN_DEBUG "Start of write\n"); + us_transfer_freecom(srb, us, count); +#if 0 + if (srb->use_sg) { + US_DEBUGP ("Need to implement scatter-gather\n"); + return USB_STOR_TRANSPORT_ERROR; + } else { + offset = 0; + + while (offset < count) { +#if 1 + this_write = count - offset; + if (this_write > 64) + this_write = 64; +#else + this_write = 64; +#endif + + printk (KERN_DEBUG "Start of write\n"); + /* Use the given buffer directly, but only if there + * is space for an entire packet. */ + + if (offset + 64 <= srb->request_bufflen) { + result = usb_stor_bulk_msg ( + us, srb->request_buffer+offset, + opipe, this_write, &partial); + printk (KERN_DEBUG "Write111 = %d, %d\n", + result, partial); + pdump (srb->request_buffer+offset, + partial); + } else { + result = usb_stor_bulk_msg ( + us, buffer, + opipe, this_write, &partial); + printk (KERN_DEBUG "Write112 = %d, %d\n", + result, partial); + memcpy (buffer, + srb->request_buffer+offset, + srb->request_bufflen - offset); + pdump (srb->request_buffer+offset, + srb->request_bufflen - offset); + } + + if (result != 0) { + US_DEBUGP ("Freecom writeblock r=%d, p=%d\n", + result, partial); + + /* -ENOENT -- we canceled this transfer */ + if (result == -ENOENT) { + US_DEBUGP("us_transfer_partial(): transfer aborted\n"); + return US_BULK_TRANSFER_ABORTED; + } + + return USB_STOR_TRANSPORT_ERROR; + } + + offset += this_write; + } + } +#endif + + printk (KERN_DEBUG "freecom_writedata done!\n"); + return USB_STOR_TRANSPORT_GOOD; +} + /* * Transport for the Freecom USB/IDE adaptor. * @@ -178,17 +472,6 @@ int length; freecom_udata_t extra; - /* Allocate a buffer for us. The upper usb transport code will - * free this for us when cleaning up. */ - if (us->extra == NULL) { - us->extra = kmalloc (sizeof (struct freecom_udata), - GFP_KERNEL); - if (us->extra == NULL) { - printk (KERN_WARNING USB_STORAGE "Out of memory\n"); - return USB_STOR_TRANSPORT_ERROR; - } - } - extra = (freecom_udata_t) us->extra; fcb = (struct freecom_cb_wrap *) extra->buffer; @@ -208,7 +491,7 @@ #endif /* The ATAPI Command always goes out first. */ - fcb->Type = FCM_PACKET_ATAPI; + fcb->Type = FCM_PACKET_ATAPI | 0x00; fcb->Timeout = 0; memcpy (fcb->Atapi, srb->cmnd, 12); memset (fcb->Filler, 0, sizeof (fcb->Filler)); @@ -247,10 +530,54 @@ } pdump ((void *) fst, partial); + + /* while we haven't recieved the IRQ */ + while (!(fst->Status & 0x2)) { + /* send a command to re-fetch the status */ + US_DEBUGP("Re-attempting to get status...\n"); + + fcb->Type = FCM_PACKET_STATUS; + fcb->Timeout = 0; + memset (fcb->Atapi, 0, 12); + memset (fcb->Filler, 0, sizeof (fcb->Filler)); + + /* Send it out. */ + result = usb_stor_bulk_msg (us, fcb, opipe, + FCM_PACKET_LENGTH, &partial); + + /* The Freecom device will only fail if there is something wrong in + * USB land. It returns the status in its own registers, which + * come back in the bulk pipe. */ + if (result != 0) { + US_DEBUGP ("freecom xport failure: r=%d, p=%d\n", + result, partial); + + /* -ENOENT -- we canceled this transfer */ + if (result == -ENOENT) { + US_DEBUGP("us_transfer_partial(): transfer aborted\n"); + return US_BULK_TRANSFER_ABORTED; + } + + return USB_STOR_TRANSPORT_ERROR; + } + + /* actually get the status info */ + result = usb_stor_bulk_msg (us, fst, ipipe, + FCM_PACKET_LENGTH, &partial); + printk (KERN_DEBUG "bar Status result %d %d\n", result, partial); + /* -ENOENT -- we canceled this transfer */ + if (result == -ENOENT) { + US_DEBUGP("us_transfer_partial(): transfer aborted\n"); + return US_BULK_TRANSFER_ABORTED; + } + + pdump ((void *) fst, partial); + } + if (partial != 4 || result != 0) { return USB_STOR_TRANSPORT_ERROR; } - if ((fst->Reason & 1) != 0) { + if ((fst->Status & 1) != 0) { printk (KERN_DEBUG "operation failed\n"); return USB_STOR_TRANSPORT_FAILED; } @@ -274,9 +601,70 @@ switch (us->srb->sc_data_direction) { case SCSI_DATA_READ: + /* Make sure that the status indicates that the device + * wants data as well. */ + if ((fst->Status & DRQ_STAT) == 0 || (fst->Reason & 3) != 2) { + printk (KERN_DEBUG "SCSI wants data, drive doesn't have any\n"); + return USB_STOR_TRANSPORT_FAILED; + } result = freecom_readdata (srb, us, ipipe, opipe, length); if (result != USB_STOR_TRANSPORT_GOOD) return result; + + printk (KERN_DEBUG "FCM: Waiting for status\n"); + result = usb_stor_bulk_msg (us, fst, ipipe, + FCM_PACKET_LENGTH, &partial); + pdump ((void *) fst, partial); + if (result == -ENOENT) { + US_DEBUGP ("freecom_transport: transfer aborted\n"); + return US_BULK_TRANSFER_ABORTED; + } + if (partial != 4 || result != 0) + return USB_STOR_TRANSPORT_ERROR; + if ((fst->Status & ERR_STAT) != 0) { + printk (KERN_DEBUG "operation failed\n"); + return USB_STOR_TRANSPORT_FAILED; + } + if ((fst->Reason & 3) != 3) { + printk (KERN_DEBUG "Drive seems still hungry\n"); + return USB_STOR_TRANSPORT_FAILED; + } + printk (KERN_DEBUG "Transfer happy\n"); + break; + + case SCSI_DATA_WRITE: + /* Make sure the status indicates that the device wants to + * send us data. */ + /* !!IMPLEMENT!! */ + result = freecom_writedata (srb, us, ipipe, opipe, length); + if (result != USB_STOR_TRANSPORT_GOOD) + return result; + +#if 1 + printk (KERN_DEBUG "FCM: Waiting for status\n"); + result = usb_stor_bulk_msg (us, fst, ipipe, + FCM_PACKET_LENGTH, &partial); + if (result == -ENOENT) { + US_DEBUGP ("freecom_transport: transfer aborted\n"); + return US_BULK_TRANSFER_ABORTED; + } + if (partial != 4 || result != 0) + return USB_STOR_TRANSPORT_ERROR; + if ((fst->Status & ERR_STAT) != 0) { + printk (KERN_DEBUG "operation failed\n"); + return USB_STOR_TRANSPORT_FAILED; + } + if ((fst->Reason & 3) != 3) { + printk (KERN_DEBUG "Drive seems still hungry\n"); + return USB_STOR_TRANSPORT_FAILED; + } +#endif + printk (KERN_DEBUG "Transfer happy\n"); + break; + + + case SCSI_DATA_NONE: + /* Easy, do nothing. */ break; default: @@ -310,6 +698,69 @@ srb->sc_data_direction); return USB_STOR_TRANSPORT_ERROR; +} + +int +freecom_init (struct us_data *us) +{ + int result, value; + int counter; + char buffer[33]; + + /* Allocate a buffer for us. The upper usb transport code will + * free this for us when cleaning up. */ + if (us->extra == NULL) { + us->extra = kmalloc (sizeof (struct freecom_udata), + GFP_KERNEL); + if (us->extra == NULL) { + printk (KERN_WARNING USB_STORAGE "Out of memory\n"); + return USB_STOR_TRANSPORT_ERROR; + } + } + + result = usb_stor_control_msg(us, usb_rcvctrlpipe(us->pusb_dev, 0), + 0x4c, 0xc0, 0x4346, 0x0, buffer, 0x20); + buffer[32] = '\0'; + US_DEBUGP("String returned from FC init is: %s\n", buffer); + + result = freecom_ide_write (us, 0x06, 0xA0); + if (result != USB_STOR_TRANSPORT_GOOD) + return result; + result = freecom_ide_write (us, 0x01, 0x00); + if (result != USB_STOR_TRANSPORT_GOOD) + return result; + + counter = 50; + do { + result = freecom_ide_read (us, 0x07, &value); + if (result != USB_STOR_TRANSPORT_GOOD) + return result; + if (counter-- < 0) { + printk (KERN_WARNING USB_STORAGE "Timeout in freecom"); + return USB_STOR_TRANSPORT_ERROR; + } + } while ((value & 0x80) != 0); + + result = freecom_ide_write (us, 0x07, 0x08); + if (result != USB_STOR_TRANSPORT_GOOD) + return result; + + counter = 50; + do { + result = freecom_ide_read (us, 0x07, &value); + if (result != USB_STOR_TRANSPORT_GOOD) + return result; + if (counter-- < 0) { + printk (KERN_WARNING USB_STORAGE "Timeout in freecom"); + return USB_STOR_TRANSPORT_ERROR; + } + } while ((value & 0x80) != 0); + + result = freecom_ide_write (us, 0x08, 0x08); + if (result != USB_STOR_TRANSPORT_GOOD) + return result; + + return USB_STOR_TRANSPORT_GOOD; } int usb_stor_freecom_reset(struct us_data *us) diff -u --recursive --new-file v2.4.0-test8/linux/drivers/usb/storage/freecom.h linux/drivers/usb/storage/freecom.h --- v2.4.0-test8/linux/drivers/usb/storage/freecom.h Mon Aug 28 16:59:14 2000 +++ linux/drivers/usb/storage/freecom.h Fri Sep 8 16:39:12 2000 @@ -1,6 +1,6 @@ /* Driver for Freecom USB/IDE adaptor * - * $Id: freecom.h,v 1.3 2000/08/25 00:13:51 mdharm Exp $ + * $Id: freecom.h,v 1.4 2000/08/29 14:49:15 dlbrown Exp $ * * Freecom v0.1: * @@ -31,5 +31,6 @@ extern int freecom_transport(Scsi_Cmnd *srb, struct us_data *us); extern int usb_stor_freecom_reset(struct us_data *us); +extern int freecom_init (struct us_data *us); #endif diff -u --recursive --new-file v2.4.0-test8/linux/drivers/usb/storage/initializers.c linux/drivers/usb/storage/initializers.c --- v2.4.0-test8/linux/drivers/usb/storage/initializers.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/storage/initializers.c Fri Sep 8 16:39:12 2000 @@ -0,0 +1,60 @@ +/* Special Initializers for certain USB Mass Storage devices + * + * $Id: initializers.c,v 1.2 2000/09/06 22:35:57 mdharm Exp $ + * + * Current development and maintenance by: + * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) + * + * This driver is based on the 'USB Mass Storage Class' document. This + * describes in detail the protocol used to communicate with such + * devices. Clearly, the designers had SCSI and ATAPI commands in + * mind when they created this document. The commands are all very + * similar to commands in the SCSI-II and ATAPI specifications. + * + * It is important to note that in a number of cases this class + * exhibits class-specific exemptions from the USB specification. + * Notably the usage of NAK, STALL and ACK differs from the norm, in + * that they are used to communicate wait, failed and OK on commands. + * + * Also, for certain devices, the interrupt endpoint is used to convey + * status of a command. + * + * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more + * information about this driver. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "initializers.h" +#include "debug.h" + +/* This places the Shuttle/SCM USB<->SCSI bridge devices in multi-target + * mode */ +int usb_stor_euscsi_init(struct us_data *us) +{ + unsigned char data = 0x1; + int result; + + US_DEBUGP("Attempting to init eUSCSI bridge...\n"); + result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev, 0), + 0x0C, USB_RECIP_INTERFACE | USB_TYPE_VENDOR, + 0x01, 0x0, &data, 0x1, 5*HZ); + US_DEBUGP("-- result is %d\n", result); + US_DEBUGP("-- data afterwards is %d\n", data); + + return 0; +} + + diff -u --recursive --new-file v2.4.0-test8/linux/drivers/usb/storage/initializers.h linux/drivers/usb/storage/initializers.h --- v2.4.0-test8/linux/drivers/usb/storage/initializers.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/storage/initializers.h Mon Oct 2 11:02:34 2000 @@ -0,0 +1,44 @@ +/* Header file for Special Initializers for certain USB Mass Storage devices + * + * $Id: initializers.h,v 1.1 2000/08/29 23:07:02 mdharm Exp $ + * + * Current development and maintenance by: + * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) + * + * This driver is based on the 'USB Mass Storage Class' document. This + * describes in detail the protocol used to communicate with such + * devices. Clearly, the designers had SCSI and ATAPI commands in + * mind when they created this document. The commands are all very + * similar to commands in the SCSI-II and ATAPI specifications. + * + * It is important to note that in a number of cases this class + * exhibits class-specific exemptions from the USB specification. + * Notably the usage of NAK, STALL and ACK differs from the norm, in + * that they are used to communicate wait, failed and OK on commands. + * + * Also, for certain devices, the interrupt endpoint is used to convey + * status of a command. + * + * Please see http://www.one-eyed-alien.net/~mdharm/linux-usb for more + * information about this driver. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "usb.h" + +/* This places the Shuttle/SCM USB<->SCSI bridge devices in multi-target + * mode */ +int usb_stor_euscsi_init(struct us_data *us); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/usb/storage/protocol.c linux/drivers/usb/storage/protocol.c --- v2.4.0-test8/linux/drivers/usb/storage/protocol.c Mon Aug 28 16:59:14 2000 +++ linux/drivers/usb/storage/protocol.c Fri Sep 8 16:39:12 2000 @@ -1,6 +1,6 @@ /* Driver for USB Mass Storage compliant devices * - * $Id: protocol.c,v 1.5 2000/08/25 00:13:51 mdharm Exp $ + * $Id: protocol.c,v 1.6 2000/09/01 22:03:55 mdharm Exp $ * * Current development and maintenance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) @@ -170,7 +170,7 @@ usb_stor_invoke_transport(srb, us); /* Fix the MODE_SENSE data if we translated the command */ - if ((old_cmnd == MODE_SENSE) && (srb->result == GOOD)) + if ((old_cmnd == MODE_SENSE) && (status_byte(srb->result) == GOOD)) usb_stor_scsiSense10to6(srb); /* fix the INQUIRY data if necessary */ @@ -265,7 +265,7 @@ usb_stor_invoke_transport(srb, us); /* Fix the MODE_SENSE data if we translated the command */ - if ((old_cmnd == MODE_SENSE) && (srb->result == GOOD)) + if ((old_cmnd == MODE_SENSE) && (status_byte(srb->result) == GOOD)) usb_stor_scsiSense10to6(srb); /* Fix the data for an INQUIRY, if necessary */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/usb/storage/scsiglue.c linux/drivers/usb/storage/scsiglue.c --- v2.4.0-test8/linux/drivers/usb/storage/scsiglue.c Mon Aug 28 16:59:14 2000 +++ linux/drivers/usb/storage/scsiglue.c Mon Oct 2 12:07:51 2000 @@ -1,7 +1,7 @@ /* Driver for USB Mass Storage compliant devices * SCSI layer glue code * - * $Id: scsiglue.c,v 1.9 2000/08/25 00:13:51 mdharm Exp $ + * $Id: scsiglue.c,v 1.13 2000/09/28 21:54:30 mdharm Exp $ * * Current development and maintenance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) @@ -112,7 +112,7 @@ { struct us_data *us = (struct us_data *)psh->hostdata[0]; - US_DEBUGP("us_release() called for host %s\n", us->htmplt.name); + US_DEBUGP("release() called for host %s\n", us->htmplt.name); /* Kill the control threads * @@ -124,9 +124,7 @@ wake_up(&(us->wqh)); down(&(us->notify)); - /* free the data structure we were using */ - US_DEBUGP("-- freeing URB\n"); - kfree(us->current_urb); + /* remove the pointer to the data structure we were using */ (struct us_data*)psh->hostdata[0] = NULL; /* we always have a successful release */ @@ -189,12 +187,6 @@ return SUCCESS; } - /* This is a sanity check that we should never hit */ - if (in_interrupt()) { - printk(KERN_ERR "usb-storage: command_abort() called from an interrupt!!! BAD!!! BAD!! BAD!!\n"); - return FAILED; - } - /* if we have an urb pending, let's wake the control thread up */ if (us->current_urb->status == -EINPROGRESS) { /* cancel the URB */ @@ -213,18 +205,62 @@ return FAILED; } -/* FIXME: this doesn't do anything right now */ +/* This invokes the transport reset mechanism to reset the state of the + * device */ +static int device_reset( Scsi_Cmnd *srb ) +{ + struct us_data *us = (struct us_data *)srb->host->hostdata[0]; + + US_DEBUGP("device_reset() called\n" ); + return us->transport_reset(us); +} + +/* This resets the device port, and simulates the device + * disconnect/reconnect for all drivers which have claimed other + * interfaces. */ static int bus_reset( Scsi_Cmnd *srb ) { - // struct us_data *us = (struct us_data *)srb->host->hostdata[0]; + struct us_data *us = (struct us_data *)srb->host->hostdata[0]; + int i; - printk(KERN_CRIT "usb-storage: bus_reset() requested but not implemented\n" ); - US_DEBUGP("Bus reset requested\n"); - // us->transport_reset(us); - return FAILED; + /* we use the usb_reset_device() function to handle this for us */ + US_DEBUGP("bus_reset() called\n"); + + /* attempt to reset the port */ + if (usb_reset_device(us->pusb_dev) < 0) + return FAILED; + + /* FIXME: This needs to lock out driver probing while it's working + * or we can have race conditions */ + for (i = 0; i < us->pusb_dev->actconfig->bNumInterfaces; i++) { + struct usb_interface *intf = + &us->pusb_dev->actconfig->interface[i]; + + /* if this is an unclaimed interface, skip it */ + if (!intf->driver) { + continue; + } + + US_DEBUGP("Examinging driver %s...", intf->driver->name); + /* skip interfaces which we've claimed */ + if (intf->driver == &usb_storage_driver) { + US_DEBUGPX("skipping ourselves.\n"); + continue; + } + + /* simulate a disconnect and reconnect for all interfaces */ + US_DEBUGPX("simulating disconnect/reconnect.\n"); + down(&intf->driver->serialize); + intf->driver->disconnect(us->pusb_dev, intf->private_data); + intf->driver->probe(us->pusb_dev, i); + up(&intf->driver->serialize); + } + + US_DEBUGP("bus_reset() complete\n"); + return SUCCESS; } -/* FIXME: This doesn't actually reset anything */ +/* FIXME: This doesn't do anything right now */ static int host_reset( Scsi_Cmnd *srb ) { printk(KERN_CRIT "usb-storage: host_reset() requested but not implemented\n" ); @@ -261,9 +297,11 @@ us = us->next; } + /* release our lock on the data structures */ + up(&us_list_semaphore); + /* if we couldn't find it, we return an error */ if (!us) { - up(&us_list_semaphore); return -ESRCH; } @@ -282,9 +320,6 @@ /* show the GUID of the device */ SPRINTF(" GUID: " GUID_FORMAT "\n", GUID_ARGS(us->guid)); - /* release our lock on the data structures */ - up(&us_list_semaphore); - /* * Calculate start of next buffer, and return value. */ @@ -313,7 +348,7 @@ queuecommand: queuecommand, eh_abort_handler: command_abort, - eh_device_reset_handler:bus_reset, + eh_device_reset_handler:device_reset, eh_bus_reset_handler: bus_reset, eh_host_reset_handler: host_reset, diff -u --recursive --new-file v2.4.0-test8/linux/drivers/usb/storage/shuttle_usbat.c linux/drivers/usb/storage/shuttle_usbat.c --- v2.4.0-test8/linux/drivers/usb/storage/shuttle_usbat.c Mon Aug 28 16:59:14 2000 +++ linux/drivers/usb/storage/shuttle_usbat.c Sun Oct 1 19:42:40 2000 @@ -1,18 +1,6 @@ /* Driver for SCM Microsystems USB-ATAPI cable * - * $Id: shuttle_usbat.c,v 1.4 2000/08/25 00:13:51 mdharm Exp $ - * - * SCM driver v0.2: - * - * Removed any reference to maxlen for bulk transfers. - * Changed scm_bulk_transport to allow for transfers without commands. - * Changed hp8200e transport to use the request_bufflen field in the - * SCSI command for the length of the transfer, rather than calculating - * it ourselves based on the command. - * - * SCM driver v0.1: - * - * First release - hp8200e. + * $Id: shuttle_usbat.c,v 1.10 2000/09/24 00:03:08 groovyjava Exp $ * * Current development and maintenance by: * (c) 2000 Robert Baruch (autophile@dol.net) @@ -30,8 +18,8 @@ * as well. This driver is only guaranteed to work with the ATAPI * translation. * - * The only peripherals that I know of (as of 14 Jul 2000) that uses this - * device is the Hewlett-Packard 8200e CD-Writer Plus. + * The only peripheral that I know of (as of 8 Sep 2000) that uses this + * device is the Hewlett-Packard 8200e/8210e CD-Writer Plus. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -64,10 +52,12 @@ extern int usb_stor_bulk_msg(struct us_data *us, void *data, int pipe, unsigned int len, unsigned int *act_len); -#define short_pack(b1,b2) ( ((u16)(b1)) | ( ((u16)(b2))<<8 ) ) +#define short_pack(LSB,MSB) ( ((u16)(LSB)) | ( ((u16)(MSB))<<8 ) ) #define LSB_of(s) ((s)&0xFF) #define MSB_of(s) ((s)>>8) +int transferred = 0; + /* * Send a control message and wait for the response. * @@ -98,16 +88,6 @@ int result; - // If data is going to be sent or received with the URB, - // then allocate a buffer for it. If data is to be sent, - // copy the data into the buffer. -/* - if (xfer_len > 0) { - buffer = kmalloc(xfer_len, GFP_KERNEL); - if (!(command[0] & USB_DIR_IN)) - memcpy(buffer, xfer_data, xfer_len); - } -*/ // Send the URB to the device and wait for a response. /* Why are request and request type reversed in this call? */ @@ -117,16 +97,6 @@ xfer_data, xfer_len); - // If data was sent or received with the URB, free the buffer we - // allocated earlier, but not before reading the data out of the - // buffer if we wanted to receive data. -/* - if (xfer_len > 0) { - if (command[0] & USB_DIR_IN) - memcpy(xfer_data, buffer, xfer_len); - kfree(buffer); - } -*/ // Check the return code for the command. if (result < 0) { @@ -192,7 +162,7 @@ if (result == -EPIPE) { US_DEBUGP("usbat_raw_bulk():" " output pipe stalled\n"); - return USB_STOR_TRANSPORT_FAILED; + return US_BULK_TRANSFER_SHORT; } /* the catch-all case */ @@ -206,7 +176,8 @@ return US_BULK_TRANSFER_SHORT; } - US_DEBUGP("Transfered %d of %d bytes\n", act_len, len); + US_DEBUGP("Transferred %s %d of %d bytes\n", + direction==SCSI_DATA_READ ? "in" : "out", act_len, len); return US_BULK_TRANSFER_GOOD; } @@ -225,68 +196,18 @@ int result = USB_STOR_TRANSPORT_GOOD; int transferred = 0; - unsigned char execute[8] = { - 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; int i; struct scatterlist *sg; - char string[64]; - int pipe; -/* - if (command_len != 0) { - - // Fix up the command's data length - - command[6] = len&0xFF; - command[7] = (len>>8)&0xFF; - - - - result = usbat_send_control(us, - execute, - command, - command_len); - - if (result != USB_STOR_TRANSPORT_GOOD) - return result; - } -*/ if (len==0) return USB_STOR_TRANSPORT_GOOD; - /* transfer the data payload for the command, if there is any */ - if (command_len != 0) direction = (command[0]&0x80) ? SCSI_DATA_READ : SCSI_DATA_WRITE; - if (direction == SCSI_DATA_WRITE) { - - /* Debug-print the first 48 bytes of the write transfer */ - - if (!use_sg) { - string[0] = 0; - for (i=0; ipusb_dev,0), @@ -324,8 +242,6 @@ content, 1); - // result = usbat_send_control(us, command, content, 1); - return result; } @@ -335,9 +251,6 @@ unsigned char content) { int result; - unsigned char command[8] = { - 0x40, access|0x01, reg, content, 0x00, 0x00, 0x00, 0x00 - }; result = usbat_send_control(us, usb_sndctrlpipe(us->pusb_dev,0), @@ -348,8 +261,6 @@ NULL, 0); - // result = usbat_send_control(us, command, NULL, 0); - return result; } @@ -376,8 +287,6 @@ command, 8); - // result = usbat_bulk_transport(us, command, 8, 0, NULL, 0, 0); - return result; } @@ -409,9 +318,6 @@ result = usbat_bulk_transport(us, NULL, 0, SCSI_DATA_READ, content, len, use_sg); - // result = usbat_bulk_transport(us, - // command, 8, 0, content, len, use_sg); - return result; } @@ -420,40 +326,47 @@ * an error condition. */ -int usbat_wait_not_busy(struct us_data *us) { +int usbat_wait_not_busy(struct us_data *us, int minutes) { int i; int result; unsigned char status; /* Synchronizing cache on a CDR could take a heck of a long time, - but probably not more than 15 minutes or so */ + * but probably not more than 10 minutes or so. On the other hand, + * doing a full blank on a CDRW at speed 1 will take about 75 + * minutes! + */ + + for (i=0; i<1200+minutes*60; i++) { - for (i=0; i<500; i++) { result = usbat_read(us, USBAT_ATA, 0x17, &status); - US_DEBUGP("SCM: Write ATA data status is %02X\n", status); + if (result!=USB_STOR_TRANSPORT_GOOD) return result; if (status&0x01) // check condition return USB_STOR_TRANSPORT_FAILED; if (status&0x20) // device fault return USB_STOR_TRANSPORT_FAILED; - if ((status&0x80)!=0x80) // not busy - break; - if (i<5) - wait_ms(100); - else if (i<20) - wait_ms(500); - else if (i<49) - wait_ms(1000); - else if (i<499) - wait_ms(2000); - } - if (i==500) - return USB_STOR_TRANSPORT_FAILED; + if ((status&0x80)!=0x80) { // not busy + US_DEBUGP("Waited not busy for %d steps\n", i); + return USB_STOR_TRANSPORT_GOOD; + } - return USB_STOR_TRANSPORT_GOOD; + if (i<500) + wait_ms(10); // 5 seconds + else if (i<700) + wait_ms(50); // 10 seconds + else if (i<1200) + wait_ms(100); // 50 seconds + else + wait_ms(1000); // X minutes + } + + US_DEBUGP("Waited not busy for %d minutes, timing out.\n", + minutes); + return USB_STOR_TRANSPORT_FAILED; } int usbat_write_block(struct us_data *us, @@ -461,7 +374,8 @@ unsigned char reg, unsigned char *content, unsigned short len, - int use_sg) { + int use_sg, + int minutes) { int result; unsigned char command[8] = { @@ -487,115 +401,157 @@ if (result != USB_STOR_TRANSPORT_GOOD) return result; - // result = usbat_bulk_transport(us, - // command, 8, 0, content, len, use_sg); - - return usbat_wait_not_busy(us); + return usbat_wait_not_busy(us, minutes); } -int usbat_write_block_test(struct us_data *us, +int usbat_rw_block_test(struct us_data *us, unsigned char access, unsigned char *registers, unsigned char *data_out, unsigned short num_registers, unsigned char data_reg, unsigned char status_reg, - unsigned char qualifier, unsigned char timeout, + unsigned char qualifier, + int direction, unsigned char *content, unsigned short len, - int use_sg) { + int use_sg, + int minutes) { int result; // Not really sure the 0x07, 0x17, 0xfc, 0xe7 is necessary here, - // but that's what came out of the trace. + // but that's what came out of the trace every single time. unsigned char command[16] = { 0x40, access|0x07, 0x07, 0x17, 0xfc, 0xe7, LSB_of(num_registers*2), MSB_of(num_registers*2), - 0x40, access|0x05, data_reg, status_reg, - qualifier, timeout, LSB_of(len), MSB_of(len) + (direction==SCSI_DATA_WRITE ? 0x40 : 0xC0), + access|(direction==SCSI_DATA_WRITE ? 0x05 : 0x04), + data_reg, status_reg, + timeout, qualifier, LSB_of(len), MSB_of(len) }; + int i; unsigned char data[num_registers*2]; - int transferred; - struct scatterlist *sg; - char string[64]; + unsigned char status; for (i=0; ipusb_dev,0), - 0x80, - 0x40, - 0, - 0, - command, - 16); - - if (result != USB_STOR_TRANSPORT_GOOD) - return result; + for (i=0; i<20; i++) { - result = usbat_bulk_transport(us, - NULL, 0, SCSI_DATA_WRITE, data, num_registers*2, 0); + /* + * The first time we send the full command, which consists + * of downloading the SCSI command followed by downloading + * the data via a write-and-test. Any other time we only + * send the command to download the data -- the SCSI command + * is still 'active' in some sense in the device. + * + * We're only going to try sending the data 10 times. After + * that, we just return a failure. + */ + + result = usbat_send_control(us, + usb_sndctrlpipe(us->pusb_dev,0), + 0x80, + 0x40, + 0, + 0, + (i==0 ? command : command+8), + (i==0 ? 16 : 8)); - // result = usbat_bulk_transport(us, - // command, 16, 0, data, num_registers*2, 0); + if (result != USB_STOR_TRANSPORT_GOOD) + return result; - if (result!=USB_STOR_TRANSPORT_GOOD) - return result; + if (i==0) { - // transferred = 0; + result = usbat_bulk_transport(us, + NULL, 0, SCSI_DATA_WRITE, + data, num_registers*2, 0); - US_DEBUGP("Transfer out %d bytes, sg buffers %d\n", - len, use_sg); + if (result!=USB_STOR_TRANSPORT_GOOD) + return result; - result = usbat_bulk_transport(us, - NULL, 0, SCSI_DATA_WRITE, content, len, use_sg); + } -/* - if (!use_sg) { - // Debug-print the first 48 bytes of the transfer + //US_DEBUGP("Transfer %s %d bytes, sg buffers %d\n", + // direction == SCSI_DATA_WRITE ? "out" : "in", + // len, use_sg); + + result = usbat_bulk_transport(us, + NULL, 0, direction, content, len, use_sg); + + /* + * If we get a stall on the bulk download, we'll retry + * the bulk download -- but not the SCSI command because + * in some sense the SCSI command is still 'active' and + * waiting for the data. Don't ask me why this should be; + * I'm only following what the Windoze driver did. + * + * Note that a stall for the test-and-read/write command means + * that the test failed. In this case we're testing to make + * sure that the device is error-free + * (i.e. bit 0 -- CHK -- of status is 0). The most likely + * hypothesis is that the USBAT chip somehow knows what + * the device will accept, but doesn't give the device any + * data until all data is received. Thus, the device would + * still be waiting for the first byte of data if a stall + * occurs, even if the stall implies that some data was + * transferred. + */ + + if (result == US_BULK_TRANSFER_SHORT) { + + /* + * If we're reading and we stalled, then clear + * the bulk output pipe only the first time. + */ + + if (direction==SCSI_DATA_READ && i==0) + usb_clear_halt(us->pusb_dev, + usb_sndbulkpipe(us->pusb_dev, + us->ep_out)); + /* + * Read status: is the device angry, or just busy? + */ + + result = usbat_read(us, USBAT_ATA, + direction==SCSI_DATA_WRITE ? 0x17 : 0x0E, + &status); - string[0] = 0; - for (i=0; i sg[i].length ? - sg[i].length : len-transferred); - if (result!=US_BULK_TRANSFER_GOOD) - break; - transferred += sg[i].length; - } } -*/ - if (result!=USB_STOR_TRANSPORT_GOOD) - return result; - return usbat_wait_not_busy(us); + US_DEBUGP("Bummer! %s bulk data 20 times failed.\n", + direction==SCSI_DATA_WRITE ? "Writing" : "Reading"); + + return USB_STOR_TRANSPORT_FAILED; } +/* + * Write data to multiple registers at once. Not meant for large + * transfers of data! + */ + int usbat_multiple_write(struct us_data *us, unsigned char access, unsigned char *registers, @@ -630,21 +586,15 @@ result = usbat_bulk_transport(us, NULL, 0, SCSI_DATA_WRITE, data, num_registers*2, 0); - // result = usbat_bulk_transport(us, cmd, 8, 0, - // data, num_registers*2, 0); - if (result!=USB_STOR_TRANSPORT_GOOD) return result; - return usbat_wait_not_busy(us); + return usbat_wait_not_busy(us, 0); } int usbat_read_user_io(struct us_data *us, unsigned char *data_flags) { - unsigned char command[8] = { - 0xC0, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; int result; result = usbat_send_control(us, @@ -656,8 +606,6 @@ data_flags, 1); - // result = usbat_send_control(us, command, data_flags, 1); - return result; } @@ -665,9 +613,6 @@ unsigned char enable_flags, unsigned char data_flags) { - unsigned char command[8] = { - 0x40, 0x82, enable_flags, data_flags, 0x00, 0x00, 0x00, 0x00 - }; int result; result = usbat_send_control(us, @@ -679,8 +624,138 @@ NULL, 0); - // result = usbat_send_control(us, command, NULL, 0); + return result; +} + +/* + * Squeeze a potentially huge (> 65535 byte) read10 command into + * a little ( <= 65535 byte) ATAPI pipe + */ + +int usbat_handle_read10(struct us_data *us, + unsigned char *registers, + unsigned char *data, + Scsi_Cmnd *srb) { + + int result = USB_STOR_TRANSPORT_GOOD; + unsigned char *buffer; + unsigned int len; + unsigned int sector; + unsigned int amount; + struct scatterlist *sg = NULL; + int sg_segment = 0; + int sg_offset = 0; + + US_DEBUGP("handle_read10: transfersize %d\n", + srb->transfersize); + + if (srb->request_bufflen < 0x10000) { + + result = usbat_rw_block_test(us, USBAT_ATA, + registers, data, 19, + 0x10, 0x17, 0xFD, 0x30, + SCSI_DATA_READ, + srb->request_buffer, + srb->request_bufflen, srb->use_sg, 1); + + return result; + } + + /* + * Since we're requesting more data than we can handle in + * a single read command (max is 64k-1), we will perform + * multiple reads, but each read must be in multiples of + * a sector. Luckily the sector size is in srb->transfersize + * (see linux/drivers/scsi/sr.c). + */ + + if (data[7+0] == GPCMD_READ_CD) { + len = short_pack(data[7+9], data[7+8]); + len <<= 16; + len |= data[7+7]; + srb->transfersize = srb->request_bufflen/len; + } + + + len = (65535/srb->transfersize) * srb->transfersize; + US_DEBUGP("Max read is %d bytes\n", len); + buffer = kmalloc(len, GFP_KERNEL); + if (buffer == NULL) // bloody hell! + return USB_STOR_TRANSPORT_FAILED; + sector = short_pack(data[7+3], data[7+2]); + sector <<= 16; + sector |= short_pack(data[7+5], data[7+4]); + transferred = 0; + + if (srb->use_sg) { + sg = (struct scatterlist *)srb->request_buffer; + sg_segment = 0; // for keeping track of where we are in + sg_offset = 0; // the scatter/gather list + } + + while (transferred != srb->request_bufflen) { + + if (len > srb->request_bufflen - transferred) + len = srb->request_bufflen - transferred; + + data[3] = len&0xFF; // (cylL) = expected length (L) + data[4] = (len>>8)&0xFF; // (cylH) = expected length (H) + + // Fix up the SCSI command sector and num sectors + + data[7+2] = MSB_of(sector>>16); // SCSI command sector + data[7+3] = LSB_of(sector>>16); + data[7+4] = MSB_of(sector&0xFFFF); + data[7+5] = LSB_of(sector&0xFFFF); + if (data[7+0] == GPCMD_READ_CD) + data[7+6] = 0; + data[7+7] = MSB_of(len / srb->transfersize); // SCSI command + data[7+8] = LSB_of(len / srb->transfersize); // num sectors + + result = usbat_rw_block_test(us, USBAT_ATA, + registers, data, 19, + 0x10, 0x17, 0xFD, 0x30, + SCSI_DATA_READ, + buffer, + len, 0, 1); + + if (result != USB_STOR_TRANSPORT_GOOD) + break; + + // Transfer the received data into the srb buffer + + if (!srb->use_sg) { + memcpy(srb->request_buffer+transferred, buffer, len); + } else { + amount = 0; + while (amount= + sg[sg_segment].length-sg_offset) { + memcpy(sg[sg_segment].address + sg_offset, + buffer + amount, + sg[sg_segment].length - sg_offset); + amount += + sg[sg_segment].length-sg_offset; + sg_segment++; + sg_offset=0; + } else { + memcpy(sg[sg_segment].address + sg_offset, + buffer + amount, + len - amount); + sg_offset += (len - amount); + amount = len; + } + } + } + // Update the amount transferred and the sector number + + transferred += len; + sector += len / srb->transfersize; + + } // while transferred != srb->request_bufflen + + kfree(buffer); return result; } @@ -870,102 +945,8 @@ int i; char string[64]; - /* This table tells us: - X = command not supported - L = return length in cmnd[4] (8 bits). - H = return length in cmnd[7] and cmnd[8] (16 bits). - D = return length in cmnd[6] to cmnd[9] (32 bits). - B = return length/blocksize in cmnd[6] to cmnd[8]. - T = return length in cmnd[6] to cmnd[8] (24 bits). - 0-9 = fixed return length - W = 24 bytes - h = return length/2048 in cmnd[7-8]. - */ - - static char *lengths = - - /* 0123456789ABCDEF 0123456789ABCDEF */ - - "0XXL0XXXXXXXXXXX" "XXLXXXXXXXX0XX0X" /* 00-1F */ - "XXXXX8XXhXH0XXX0" "XXXXX0XXXXXXXXXX" /* 20-3F */ - "XXHHL0X0XXH0XX0X" "XHH00HXX0TH0H0XX" /* 40-5F */ - "XXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXX" /* 60-7F */ - "XXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXX" /* 80-9F */ - "X0XXX0XXDXDXXXXX" "XXXXXXXXX000XHBX" /* A0-BF */ - "XXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXX" /* C0-DF */ - "XDXXXXXXXXXXXXXX" "XXW00HXXXXXXXXXX"; /* E0-FF */ - -/* if (us->flags & US_FL_NEED_INIT) { - US_DEBUGP("8200e: initializing\n"); - init_8200e(us); - us->flags &= ~US_FL_NEED_INIT; - } */ - len = srb->request_bufflen; -/* if (srb->sc_data_direction == SCSI_DATA_WRITE) - len = srb->request_bufflen; - else { - - switch (lengths[srb->cmnd[0]]) { - - case 'L': - len = srb->cmnd[4]; - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - len = lengths[srb->cmnd[0]]-'0'; - break; - case 'H': - len = (((unsigned int)srb->cmnd[7])<<8) | srb->cmnd[8]; - break; - case 'h': - len = (((unsigned int)srb->cmnd[7])<<8) | srb->cmnd[8]; - len <<= 11; // *2048 - break; - case 'T': - len = (((unsigned int)srb->cmnd[6])<<16) | - (((unsigned int)srb->cmnd[7])<<8) | - srb->cmnd[8]; - break; - case 'D': - len = (((unsigned int)srb->cmnd[6])<<24) | - (((unsigned int)srb->cmnd[7])<<16) | - (((unsigned int)srb->cmnd[8])<<8) | - srb->cmnd[9]; - break; - case 'W': - len = 24; - break; - case 'B': - // Let's try using the command structure's - // request_bufflen here - len = srb->request_bufflen; - break; - default: - US_DEBUGP("Error: UNSUPPORTED COMMAND %02X\n", - srb->cmnd[0]); - return USB_STOR_TRANSPORT_ERROR; - } - } */ - - if (len > 0xFFFF) { - US_DEBUGP("Error: len = %08X... what do I do now?\n", - len); - return USB_STOR_TRANSPORT_ERROR; - } - - // US_DEBUGP("XXXXXXXXXXXXXXXX req_bufflen %d, len %d, bufflen %d\n", - // srb->request_bufflen, len, srb->bufflen); - /* Send A0 (ATA PACKET COMMAND). Note: I guess we're never going to get any of the ATA commands... just ATA Packet Commands. @@ -986,20 +967,41 @@ data[5] = 0xB0; // (device sel) = slave data[6] = 0xA0; // (command) = ATA PACKET COMMAND - if (srb->sc_data_direction == SCSI_DATA_WRITE) { + for (i=7; i<19; i++) { + registers[i] = 0x10; + data[i] = (i-7 >= srb->cmd_len) ? 0 : srb->cmnd[i-7]; + } - for (i=7; i<19; i++) { - registers[i] = 0x10; - data[i] = (i-7 >= srb->cmd_len) ? 0 : srb->cmnd[i-7]; - } + if (srb->cmnd[0] == TEST_UNIT_READY) + transferred = 0; + + if (srb->sc_data_direction == SCSI_DATA_WRITE) { - result = usbat_write_block_test(us, USBAT_ATA, + result = usbat_rw_block_test(us, USBAT_ATA, registers, data, 19, 0x10, 0x17, 0xFD, 0x30, + SCSI_DATA_WRITE, srb->request_buffer, - len, srb->use_sg); + len, srb->use_sg, 10); + + if (result == USB_STOR_TRANSPORT_GOOD) { + transferred += len; + US_DEBUGP("Wrote %08X bytes\n", transferred); + } return result; + + } else if (srb->cmnd[0] == READ_10 || + srb->cmnd[0] == GPCMD_READ_CD) { + + return usbat_handle_read10(us, registers, data, srb); + + } + + if (len > 0xFFFF) { + US_DEBUGP("Error: len = %08X... what do I do now?\n", + len); + return USB_STOR_TRANSPORT_ERROR; } if ( (result = usbat_multiple_write(us, @@ -1010,8 +1012,15 @@ // Write the 12-byte command header. + // If the command is BLANK then set the timer for 75 minutes. + // Otherwise set it for 10 minutes. + + // NOTE: THE 8200 DOCUMENTATION STATES THAT BLANKING A CDRW + // AT SPEED 4 IS UNRELIABLE!!! + if ( (result = usbat_write_block(us, - USBAT_ATA, 0x10, srb->cmnd, 12, 0)) != + USBAT_ATA, 0x10, srb->cmnd, 12, 0, + srb->cmnd[0]==GPCMD_BLANK ? 75 : 10)) != USB_STOR_TRANSPORT_GOOD) { return result; } @@ -1060,8 +1069,6 @@ US_DEBUGP("%s\n", string); } } - - // US_DEBUGP("Command result %d\n", result); return result; } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/usb/storage/shuttle_usbat.h linux/drivers/usb/storage/shuttle_usbat.h --- v2.4.0-test8/linux/drivers/usb/storage/shuttle_usbat.h Mon Aug 28 16:59:14 2000 +++ linux/drivers/usb/storage/shuttle_usbat.h Sun Oct 1 19:42:40 2000 @@ -1,7 +1,7 @@ /* Driver for SCM Microsystems USB-ATAPI cable * Header File * - * $Id: shuttle_usbat.h,v 1.4 2000/08/25 00:13:51 mdharm Exp $ + * $Id: shuttle_usbat.h,v 1.5 2000/09/17 14:44:52 groovyjava Exp $ * * Current development and maintenance by: * (c) 2000 Robert Baruch (autophile@dol.net) @@ -63,7 +63,7 @@ int use_sg); extern int usbat_write_block(struct us_data *us, unsigned char access, unsigned char reg, unsigned char *content, unsigned short len, - int use_sg); + int use_sg, int minutes); extern int usbat_multiple_write(struct us_data *us, unsigned char access, unsigned char *registers, unsigned char *data_out, unsigned short num_registers); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/usb/storage/transport.c linux/drivers/usb/storage/transport.c --- v2.4.0-test8/linux/drivers/usb/storage/transport.c Mon Aug 28 16:59:14 2000 +++ linux/drivers/usb/storage/transport.c Sun Oct 1 19:42:40 2000 @@ -1,6 +1,6 @@ /* Driver for USB Mass Storage compliant devices * - * $Id: transport.c,v 1.18 2000/08/25 00:13:51 mdharm Exp $ + * $Id: transport.c,v 1.27 2000/09/28 21:54:30 mdharm Exp $ * * Current development and maintenance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) @@ -43,6 +43,8 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include #include "transport.h" #include "protocol.h" #include "usb.h" @@ -680,7 +682,7 @@ need_auto_sense = 1; } if (result == USB_STOR_TRANSPORT_ERROR) { - /* FIXME: we need to invoke a transport reset here */ + us->transport_reset(us); US_DEBUGP("-- transport indicates transport failure\n"); need_auto_sense = 0; srb->result = DID_ERROR << 16; @@ -742,8 +744,15 @@ /* issue the auto-sense command */ temp_result = us->transport(us->srb, us); if (temp_result != USB_STOR_TRANSPORT_GOOD) { - /* FIXME: we need to invoke a transport reset here */ US_DEBUGP("-- auto-sense failure\n"); + + /* we skip the reset if this happens to be a + * multi-target device, since failure of an + * auto-sense is perfectly valid + */ + if (!(us->flags & US_FL_SCM_MULT_TARG)) { + us->transport_reset(us); + } srb->result = DID_ERROR << 16; return; } @@ -754,9 +763,15 @@ srb->sense_buffer[2] & 0xf, srb->sense_buffer[12], srb->sense_buffer[13]); +#ifdef CONFIG_USB_STORAGE_DEBUG + usb_stor_show_sense( + srb->sense_buffer[2] & 0xf, + srb->sense_buffer[12], + srb->sense_buffer[13]); +#endif /* set the result so the higher layers expect this data */ - srb->result = CHECK_CONDITION; + srb->result = CHECK_CONDITION << 1; /* we're done here, let's clean up */ srb->request_buffer = old_request_buffer; @@ -767,15 +782,15 @@ /* If things are really okay, then let's show that */ if ((srb->sense_buffer[2] & 0xf) == 0x0) - srb->result = GOOD; + srb->result = GOOD << 1; } else /* if (need_auto_sense) */ - srb->result = GOOD; + srb->result = GOOD << 1; /* Regardless of auto-sense, if we _know_ we have an error * condition, show that in the result code */ if (result == USB_STOR_TRANSPORT_FAILED) - srb->result = CHECK_CONDITION; + srb->result = CHECK_CONDITION << 1; /* If we think we're good, then make sure the sense data shows it. * This is necessary because the auto-sense for some devices always @@ -822,6 +837,9 @@ { int result; + /* Set up for status notification */ + us->ip_wanted = 1; + /* COMMAND STAGE */ /* let's send the command via the control pipe */ result = usb_stor_control_msg(us, usb_sndctrlpipe(us->pusb_dev,0), @@ -832,6 +850,9 @@ /* check the return code for the command */ US_DEBUGP("Call to usb_stor_control_msg() returned %d\n", result); if (result < 0) { + /* Reset flag for status notification */ + us->ip_wanted = 0; + /* if the command was aborted, indicate that */ if (result == -ENOENT) return USB_STOR_TRANSPORT_ABORTED; @@ -850,9 +871,6 @@ return USB_STOR_TRANSPORT_ERROR; } - /* Set up for status notification */ - us->ip_wanted = 1; - /* DATA STAGE */ /* transfer the data payload for this command, if one exists*/ if (us_transfer_length(srb)) { @@ -860,8 +878,12 @@ US_DEBUGP("CBI data stage result is 0x%x\n", srb->result); /* if it was aborted, we need to indicate that */ - if (srb->result == USB_STOR_TRANSPORT_ABORTED) + if (srb->result == USB_STOR_TRANSPORT_ABORTED) { + /* we need to reset the state of this semaphore */ + down(&(us->ip_waitq)); + return USB_STOR_TRANSPORT_ABORTED; + } } /* STATUS STAGE */ @@ -1038,7 +1060,7 @@ /* send it to out endpoint */ US_DEBUGP("Bulk command S 0x%x T 0x%x Trg %d LUN %d L %d F %d CL %d\n", le32_to_cpu(bcb.Signature), bcb.Tag, - (bcb.Lun >> 4), (bcb.Lun & 0xFF), + (bcb.Lun >> 4), (bcb.Lun & 0x0F), bcb.DataTransferLength, bcb.Flags, bcb.Length); result = usb_stor_bulk_msg(us, &bcb, pipe, US_BULK_CB_WRAP_LEN, &partial); @@ -1137,8 +1159,9 @@ return USB_STOR_TRANSPORT_FAILED; case US_BULK_STAT_PHASE: - /* phase error */ - usb_stor_Bulk_reset(us); + /* phase error -- note that a transport reset will be + * invoked by the invoke_transport() function + */ return USB_STOR_TRANSPORT_ERROR; } @@ -1167,8 +1190,15 @@ USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, us->ifnum, cmd, sizeof(cmd), HZ*5); + if (result < 0) { + US_DEBUGP("CB[I] soft reset failed %d\n", result); + return FAILED; + } + /* long wait for reset */ + set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ*6); + set_current_state(TASK_RUNNING); US_DEBUGP("CB_reset: clearing endpoint halt\n"); clear_halt(us->pusb_dev, @@ -1177,7 +1207,8 @@ usb_rcvbulkpipe(us->pusb_dev, us->ep_out)); US_DEBUGP("CB_reset done\n"); - return 0; + /* return a result code based on the result of the control message */ + return SUCCESS; } /* This issues a Bulk-only Reset to the device in question, including @@ -1195,16 +1226,20 @@ USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, us->ifnum, NULL, 0, HZ*5); - if (result < 0) - US_DEBUGP("Bulk hard reset failed %d\n", result); + if (result < 0) { + US_DEBUGP("Bulk soft reset failed %d\n", result); + return FAILED; + } + + /* long wait for reset */ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ*6); + set_current_state(TASK_RUNNING); clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_in)); clear_halt(us->pusb_dev, usb_sndbulkpipe(us->pusb_dev, us->ep_out)); - - /* long wait for reset */ - schedule_timeout(HZ*6); - - return result; + US_DEBUGP("Bulk soft reset completed\n"); + return SUCCESS; } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/usb/storage/transport.h linux/drivers/usb/storage/transport.h --- v2.4.0-test8/linux/drivers/usb/storage/transport.h Mon Aug 28 16:59:14 2000 +++ linux/drivers/usb/storage/transport.h Mon Oct 2 11:02:34 2000 @@ -1,7 +1,7 @@ /* Driver for USB Mass Storage compliant devices * Transport Functions Header File * - * $Id: transport.h,v 1.11 2000/08/25 00:13:51 mdharm Exp $ + * $Id: transport.h,v 1.12 2000/09/08 21:20:06 mdharm Exp $ * * Current development and maintenance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) @@ -41,8 +41,8 @@ #ifndef _TRANSPORT_H_ #define _TRANSPORT_H_ -#include #include +#include #include "usb.h" #include "scsi.h" diff -u --recursive --new-file v2.4.0-test8/linux/drivers/usb/storage/usb.c linux/drivers/usb/storage/usb.c --- v2.4.0-test8/linux/drivers/usb/storage/usb.c Tue Sep 5 12:56:51 2000 +++ linux/drivers/usb/storage/usb.c Sun Oct 1 19:42:40 2000 @@ -1,6 +1,6 @@ /* Driver for USB Mass Storage compliant devices * - * $Id: usb.c,v 1.33 2000/08/25 00:13:51 mdharm Exp $ + * $Id: usb.c,v 1.46 2000/09/25 23:25:12 mdharm Exp $ * * Current development and maintenance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) @@ -49,6 +49,7 @@ #include "transport.h" #include "protocol.h" #include "debug.h" +#include "initializers.h" #ifdef CONFIG_USB_STORAGE_HP8200e #include "shuttle_usbat.h" #endif @@ -94,7 +95,7 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum); static void storage_disconnect(struct usb_device *dev, void *ptr); -static struct usb_driver storage_driver = { +struct usb_driver usb_storage_driver = { name: "usb-storage", probe: storage_probe, disconnect: storage_disconnect, @@ -206,7 +207,7 @@ */ if (us->srb->sc_data_direction == SCSI_DATA_UNKNOWN) { US_DEBUGP("UNKNOWN data direction\n"); - us->srb->result = DID_ERROR; + us->srb->result = DID_ERROR << 16; set_current_state(TASK_INTERRUPTIBLE); us->srb->scsi_done(us->srb); us->srb = NULL; @@ -242,7 +243,7 @@ /* handle those devices which can't do a START_STOP */ if ((us->srb->cmnd[0] == START_STOP) && (us->flags & US_FL_START_STOP)) { - us->srb->result = GOOD; + us->srb->result = GOOD << 1; set_current_state(TASK_INTERRUPTIBLE); us->srb->scsi_done(us->srb); @@ -264,12 +265,12 @@ memcpy(us->srb->request_buffer, usb_stor_sense_notready, sizeof(usb_stor_sense_notready)); - us->srb->result = GOOD; + us->srb->result = GOOD << 1; } else { memcpy(us->srb->sense_buffer, usb_stor_sense_notready, sizeof(usb_stor_sense_notready)); - us->srb->result = CHECK_CONDITION; + us->srb->result = CHECK_CONDITION << 1; } } else { /* !us->pusb_dev */ /* we've got a command, let's do it! */ @@ -328,46 +329,34 @@ * restriction. However, if the flag is not present, then you * are free to use as many characters as you like. */ - -int euscsi_init(struct us_data *us) -{ - unsigned char bar = 0x1; - int result; - - US_DEBUGP("Attempting to init eUSCSI bridge...\n"); - result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev, 0), - 0x0C, USB_RECIP_INTERFACE | USB_TYPE_VENDOR, - 0x01, 0x0, &bar, 0x1, 5*HZ); - US_DEBUGP("-- result is %d\n", result); - US_DEBUGP("-- bar afterwards is %d\n", bar); -} - static struct us_unusual_dev us_unusual_dev_list[] = { + { 0x03ee, 0x0000, 0x0000, 0x0245, + "Mitsumi", + "CD-R/RW Drive", + US_SC_8020, US_PR_CBI, NULL, 0}, + { 0x03f0, 0x0107, 0x0200, 0x0200, "HP", "CD-Writer+", - US_SC_8070, US_PR_CB, NULL, - 0}, + US_SC_8070, US_PR_CB, NULL, 0}, #ifdef CONFIG_USB_STORAGE_HP8200e { 0x03f0, 0x0207, 0x0001, 0x0001, "HP", "CD-Writer+ 8200e", - US_SC_8070, US_PR_SCM_ATAPI, init_8200e, - US_FL_SINGLE_LUN}, + US_SC_8070, US_PR_SCM_ATAPI, init_8200e, 0}, #endif { 0x04e6, 0x0001, 0x0200, 0x0200, "Matshita", "LS-120", - US_SC_8020, US_PR_CB, NULL, - US_FL_SINGLE_LUN}, + US_SC_8020, US_PR_CB, NULL, 0}, { 0x04e6, 0x0002, 0x0100, 0x0100, "Shuttle", "eUSCSI Bridge", - US_SC_SCSI, US_PR_BULK, euscsi_init, + US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init, US_FL_SCM_MULT_TARG }, #ifdef CONFIG_USB_STORAGE_SDDR09 @@ -392,39 +381,42 @@ US_SC_SCSI, US_PR_CB, NULL, US_FL_SINGLE_LUN}, + { 0x04e6, 0x0007, 0x0100, 0x0200, + "Sony", + "Hifd", + US_SC_SCSI, US_PR_CB, NULL, + US_FL_SINGLE_LUN}, + { 0x04e6, 0x0009, 0x0200, 0x0200, "Shuttle", - "ATA/ATAPI Bridge", - US_SC_8020, US_PR_CB, NULL, - US_FL_SINGLE_LUN}, + "eUSB ATA/ATAPI Adapter", + US_SC_8020, US_PR_CB, NULL, 0}, - { 0x04e6, 0x000A, 0x0200, 0x0200, + { 0x04e6, 0x000a, 0x0200, 0x0200, "Shuttle", - "Compact Flash Reader", - US_SC_8020, US_PR_CB, NULL, - US_FL_SINGLE_LUN}, + "eUSB CompactFlash Adapter", + US_SC_8020, US_PR_CB, NULL, 0}, { 0x04e6, 0x000B, 0x0100, 0x0100, "Shuttle", "eUSCSI Bridge", - US_SC_SCSI, US_PR_BULK, euscsi_init, + US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init, US_FL_SCM_MULT_TARG }, { 0x04e6, 0x000C, 0x0100, 0x0100, "Shuttle", "eUSCSI Bridge", - US_SC_SCSI, US_PR_BULK, euscsi_init, + US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init, US_FL_SCM_MULT_TARG }, { 0x04e6, 0x0101, 0x0200, 0x0200, "Shuttle", "CD-RW Device", - US_SC_8020, US_PR_CB, NULL, - US_FL_SINGLE_LUN}, + US_SC_8020, US_PR_CB, NULL, 0}, - { 0x054c, 0x0010, 0x0210, 0x0210, + { 0x054c, 0x0010, 0x0106, 0x0210, "Sony", - "DSC-S30/S70", + "DSC-S30/S70/505V/F505", US_SC_SCSI, US_PR_CB, NULL, US_FL_SINGLE_LUN | US_FL_START_STOP | US_FL_MODE_XLATE }, @@ -449,26 +441,35 @@ { 0x059f, 0xa601, 0x0200, 0x0200, "LaCie", "USB Hard Disk", - US_SC_RBC, US_PR_CB, NULL, - 0 }, + US_SC_RBC, US_PR_CB, NULL, 0 }, { 0x05ab, 0x0031, 0x0100, 0x0100, "In-System", - "USB/IDE Bridge", - US_SC_8070, US_PR_BULK, NULL, - 0 }, + "USB/IDE Bridge (ATAPI ONLY!)", + US_SC_8070, US_PR_BULK, NULL, 0 }, - { 0x0693, 0x0005, 0x0100, 0x0100, - "Hagiwara", - "Flashgate", - US_SC_SCSI, US_PR_BULK, NULL, - 0 }, + { 0x0644, 0x0000, 0x0100, 0x0100, + "TEAC", + "Floppy Drive", + US_SC_UFI, US_PR_CB, NULL, 0 }, + +#ifdef CONFIG_USB_STORAGE_SDDR09 + { 0x066b, 0x0105, 0x0100, 0x0100, + "Olympus", + "Camedia MAUSB-2", + US_SC_SCSI, US_PR_EUSB_SDDR09, NULL, + US_FL_SINGLE_LUN | US_FL_START_STOP }, +#endif { 0x0693, 0x0002, 0x0100, 0x0100, "Hagiwara", "FlashGate SmartMedia", - US_SC_SCSI, US_PR_BULK, NULL, - 0 }, + US_SC_SCSI, US_PR_BULK, NULL, 0 }, + + { 0x0693, 0x0005, 0x0100, 0x0100, + "Hagiwara", + "Flashgate", + US_SC_SCSI, US_PR_BULK, NULL, 0 }, { 0x0781, 0x0001, 0x0200, 0x0200, "Sandisk", @@ -493,20 +494,20 @@ { 0x07af, 0x0004, 0x0100, 0x0100, "Microtech", "USB-SCSI-DB25", - US_SC_SCSI, US_PR_BULK, euscsi_init, + US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init, US_FL_SCM_MULT_TARG }, #ifdef CONFIG_USB_STORAGE_FREECOM { 0x07ab, 0xfc01, 0x0921, 0x0921, "Freecom", "USB-IDE", - US_SC_8070, US_PR_FREECOM, NULL, US_FL_SINGLE_LUN }, + US_SC_QIC, US_PR_FREECOM, freecom_init, 0}, #endif { 0x07af, 0x0005, 0x0100, 0x0100, "Microtech", "USB-SCSI-HD50", - US_SC_SCSI, US_PR_BULK, euscsi_init, + US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init, US_FL_SCM_MULT_TARG }, #ifdef CONFIG_USB_STORAGE_DPCM @@ -613,7 +614,9 @@ unsigned int flags; struct us_unusual_dev *unusual_dev; struct us_data *ss = NULL; +#ifdef CONFIG_USB_STORAGE_SDDR09 int result; +#endif /* these are temporary copies -- we test on these, then put them * in the us-data structure @@ -716,6 +719,7 @@ } /* At this point, we're committed to using the device */ + usb_inc_dev_use(dev); /* clear the GUID and fetch the strings */ GUID_CLEAR(guid); @@ -740,9 +744,6 @@ dev->descriptor.idProduct, "0"); } - /* lock access to the data structures */ - down(&us_list_semaphore); - /* * Now check if we have seen this GUID before * We're looking for a device with a matching GUID that isn't @@ -775,8 +776,14 @@ if ((ss->protocol == US_PR_CBI) && usb_stor_allocate_irq(ss)) return NULL; - /* Re-Initialize the device if it needs it */ + /* allocate the URB we're going to use */ + ss->current_urb = usb_alloc_urb(0); + if (!ss->current_urb) { + kfree(ss); + return NULL; + } + /* Re-Initialize the device if it needs it */ if (unusual_dev && unusual_dev->initFunction) (unusual_dev->initFunction)(ss); @@ -787,7 +794,6 @@ if ((ss = (struct us_data *)kmalloc(sizeof(struct us_data), GFP_KERNEL)) == NULL) { printk(KERN_WARNING USB_STORAGE "Out of memory\n"); - up(&us_list_semaphore); return NULL; } memset(ss, 0, sizeof(struct us_data)); @@ -892,7 +898,7 @@ ss->transport_name = "EUSB/SDDR09"; ss->transport = sddr09_transport; ss->transport_reset = usb_stor_CB_reset; - ss->max_lun = 1; + ss->max_lun = 0; break; #endif @@ -916,7 +922,6 @@ default: ss->transport_name = "Unknown"; - up(&us_list_semaphore); kfree(ss->current_urb); kfree(ss); return NULL; @@ -937,16 +942,19 @@ case US_SC_8020: ss->protocol_name = "8020i"; ss->proto_handler = usb_stor_ATAPI_command; + ss->max_lun = 0; break; case US_SC_QIC: ss->protocol_name = "QIC-157"; ss->proto_handler = usb_stor_qic157_command; + ss->max_lun = 0; break; case US_SC_8070: ss->protocol_name = "8070i"; ss->proto_handler = usb_stor_ATAPI_command; + ss->max_lun = 0; break; case US_SC_SCSI: @@ -961,7 +969,6 @@ default: ss->protocol_name = "Unknown"; - up(&us_list_semaphore); kfree(ss->current_urb); kfree(ss); return NULL; @@ -994,7 +1001,7 @@ /* Just before we start our control thread, initialize * the device if it needs initialization */ if (unusual_dev && unusual_dev->initFunction) - (unusual_dev->initFunction)(ss); + unusual_dev->initFunction(ss); /* start up our control thread */ ss->pid = kernel_thread(usb_stor_control_thread, ss, @@ -1014,13 +1021,16 @@ ss->htmplt.module = THIS_MODULE; scsi_register_module(MODULE_SCSI_HA, &(ss->htmplt)); + /* lock access to the data structures */ + down(&us_list_semaphore); + /* put us in the list */ ss->next = us_list; us_list = ss; - } - /* release the data structure lock */ - up(&us_list_semaphore); + /* release the data structure lock */ + up(&us_list_semaphore); + } printk(KERN_DEBUG "WARNING: USB Mass Storage data integrity not assured\n"); @@ -1051,18 +1061,26 @@ /* release the IRQ, if we have one */ down(&(ss->irq_urb_sem)); if (ss->irq_urb) { - US_DEBUGP("-- releasing irq handle\n"); + US_DEBUGP("-- releasing irq URB\n"); result = usb_unlink_urb(ss->irq_urb); - ss->irq_urb = NULL; US_DEBUGP("-- usb_unlink_urb() returned %d\n", result); usb_free_urb(ss->irq_urb); + ss->irq_urb = NULL; } up(&(ss->irq_urb_sem)); + /* free up the main URB for this device */ + US_DEBUGP("-- releasing main URB\n"); + result = usb_unlink_urb(ss->current_urb); + US_DEBUGP("-- usb_unlink_urb() returned %d\n", result); + usb_free_urb(ss->current_urb); + ss->current_urb = NULL; + /* mark the device as gone */ + usb_dec_dev_use(ss->pusb_dev); ss->pusb_dev = NULL; - /* lock access to the device data structure */ + /* unlock access to the device data structure */ up(&(ss->dev_semaphore)); } @@ -1078,7 +1096,7 @@ my_host_number = 0; /* register the driver, return -1 if error */ - if (usb_register(&storage_driver) < 0) + if (usb_register(&usb_storage_driver) < 0) return -1; /* we're all set */ @@ -1096,46 +1114,47 @@ * This eliminates races with probes and disconnects */ US_DEBUGP("-- calling usb_deregister()\n"); - usb_deregister(&storage_driver) ; + usb_deregister(&usb_storage_driver) ; - /* lock access to the data structures */ - down(&us_list_semaphore); - /* While there are still virtual hosts, unregister them - * - * Note that the us_release() routine will destroy the local data - * structure. So we have to peel these off the top of the list - * and keep updating the head pointer as we go. + * Note that it's important to do this completely before removing + * the structures because of possible races with the /proc + * interface + */ + for (next = us_list; next; next = next->next) { + US_DEBUGP("-- calling scsi_unregister_module()\n"); + scsi_unregister_module(MODULE_SCSI_HA, &(next->htmplt)); + } + + /* While there are still structures, free them. Note that we are + * now race-free, since these structures can no longer be accessed + * from either the SCSI command layer or the /proc interface */ while (us_list) { /* keep track of where the next one is */ next = us_list->next; - US_DEBUGP("-- calling scsi_unregister_module()\n"); - scsi_unregister_module(MODULE_SCSI_HA, &(us_list->htmplt)); - - /* Now that scsi_unregister_module is done with the host - * template, we can free the us_data structure (the host - * template is inline in this structure). */ - /* If there's extra data in the us_data structure then * free that first */ - if (us_list->extra) { - if (us_list->extra_destructor) - (*us_list->extra_destructor)( - us_list->extra); + /* call the destructor routine, if it exists */ + if (us_list->extra_destructor) { + US_DEBUGP("-- calling extra_destructor()\n"); + us_list->extra_destructor(us_list->extra); + } + + /* destroy the extra data */ + US_DEBUGP("-- freeing the data structure\n"); kfree(us_list->extra); } + + /* free the structure itself */ kfree (us_list); /* advance the list pointer */ us_list = next; } - - /* unlock the data structures */ - up(&us_list_semaphore); } -module_init(usb_stor_init) ; -module_exit(usb_stor_exit) ; +module_init(usb_stor_init); +module_exit(usb_stor_exit); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/usb/storage/usb.h linux/drivers/usb/storage/usb.h --- v2.4.0-test8/linux/drivers/usb/storage/usb.h Mon Aug 28 16:59:14 2000 +++ linux/drivers/usb/storage/usb.h Mon Oct 2 11:02:34 2000 @@ -1,7 +1,7 @@ /* Driver for USB Mass Storage compliant devices * Main Header File * - * $Id: usb.h,v 1.8 2000/08/25 00:13:51 mdharm Exp $ + * $Id: usb.h,v 1.9 2000/09/25 23:25:12 mdharm Exp $ * * Current development and maintenance by: * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) @@ -112,6 +112,7 @@ typedef int (*trans_cmnd)(Scsi_Cmnd*, struct us_data*); typedef int (*trans_reset)(struct us_data*); typedef void (*proto_cmnd)(Scsi_Cmnd*, struct us_data*); +typedef void (*extra_data_destructor)(void *); /* extra data destructor */ /* we allocate one of these for every device that we remember */ struct us_data { @@ -178,16 +179,17 @@ struct semaphore queue_exclusion; /* to protect data structs */ struct us_unusual_dev *unusual_dev; /* If unusual device */ void *extra; /* Any extra data */ - void (*extra_destructor)(void *); /* extra data destructor */ + extra_data_destructor extra_destructor;/* extra data destructor */ }; /* The list of structures and the protective lock for them */ extern struct us_data *us_list; extern struct semaphore us_list_semaphore; -/* Function to fill an inquiry response. See usb.c for details */ +/* The structure which defines our driver */ +struct usb_driver usb_storage_driver; +/* Function to fill an inquiry response. See usb.c for details */ extern void fill_inquiry_response(struct us_data *us, unsigned char *data, unsigned int data_len); - #endif diff -u --recursive --new-file v2.4.0-test8/linux/drivers/usb/uhci.c linux/drivers/usb/uhci.c --- v2.4.0-test8/linux/drivers/usb/uhci.c Thu Sep 7 08:39:00 2000 +++ linux/drivers/usb/uhci.c Tue Sep 19 17:47:06 2000 @@ -493,8 +493,6 @@ urb->hcpriv = urbp; - usb_inc_dev_use(urb->dev); - return urbp; } @@ -556,8 +554,6 @@ urb->hcpriv = NULL; kmem_cache_free(uhci_up_cachep, urbp); - usb_dec_dev_use(urb->dev); - unlock: spin_unlock_irqrestore(&urb->lock, flags); } @@ -572,7 +568,7 @@ spin_lock_irqsave(&uhci->framelist_lock, flags); - if (!urbp->fsbr) { + if ((!(urb->transfer_flags & USB_NO_FSBR)) && (!urbp->fsbr)) { urbp->fsbr = 1; if (!uhci->fsbr++) uhci->skel_term_qh.link = virt_to_bus(&uhci->skel_hs_control_qh) | UHCI_PTR_QH; @@ -591,7 +587,7 @@ spin_lock_irqsave(&uhci->framelist_lock, flags); - if (urbp->fsbr) { + if ((!(urb->transfer_flags & USB_NO_FSBR)) && urbp->fsbr) { urbp->fsbr = 0; if (!--uhci->fsbr) uhci->skel_term_qh.link = UHCI_PTR_TERM; @@ -739,8 +735,6 @@ uhci_add_urb_list(uhci, urb); - usb_inc_dev_use(urb->dev); - return -EINPROGRESS; } @@ -1316,10 +1310,13 @@ if (u && !(urb->transfer_flags & USB_QUEUE_BULK)) return -ENXIO; + usb_inc_dev_use(urb->dev); spin_lock_irqsave(&urb->lock, flags); if (!uhci_alloc_urb_priv(urb)) { spin_unlock_irqrestore(&urb->lock, flags); + usb_dec_dev_use(urb->dev); + return -ENOMEM; } @@ -1329,17 +1326,16 @@ break; case PIPE_INTERRUPT: if (urb->bandwidth == 0) { /* not yet checked/allocated */ - bustime = usb_check_bandwidth (urb->dev, urb); + bustime = usb_check_bandwidth(urb->dev, urb); if (bustime < 0) ret = bustime; else { ret = uhci_submit_interrupt(urb); if (ret == -EINPROGRESS) - usb_claim_bandwidth (urb->dev, urb, bustime, 0); + usb_claim_bandwidth(urb->dev, urb, bustime, 0); } - } else { /* bandwidth is already set */ + } else /* bandwidth is already set */ ret = uhci_submit_interrupt(urb); - } break; case PIPE_BULK: ret = uhci_submit_bulk(urb, u); @@ -1350,7 +1346,7 @@ ret = -EINVAL; break; } - bustime = usb_check_bandwidth (urb->dev, urb); + bustime = usb_check_bandwidth(urb->dev, urb); if (bustime < 0) { ret = bustime; break; @@ -1358,10 +1354,9 @@ ret = uhci_submit_isochronous(urb); if (ret == -EINPROGRESS) - usb_claim_bandwidth (urb->dev, urb, bustime, 1); - } else { /* bandwidth is already set */ + usb_claim_bandwidth(urb->dev, urb, bustime, 1); + } else /* bandwidth is already set */ ret = uhci_submit_isochronous(urb); - } break; } @@ -1371,8 +1366,10 @@ if (ret == -EINPROGRESS) ret = 0; - else + else { uhci_unlink_generic(urb); + usb_dec_dev_use(urb->dev); + } return ret; } @@ -1384,6 +1381,7 @@ */ static void uhci_transfer_result(struct urb *urb) { + struct usb_device *dev = urb->dev; struct urb *turb; int proceed = 0, is_ring = 0; int ret = -EINVAL; @@ -1420,22 +1418,23 @@ /* Release bandwidth for Interrupt or Isoc. transfers */ /* Spinlock needed ? */ if (urb->bandwidth) - usb_release_bandwidth (urb->dev, urb, 1); + usb_release_bandwidth(urb->dev, urb, 1); uhci_unlink_generic(urb); break; case PIPE_INTERRUPT: /* Interrupts are an exception */ - urb->complete(urb); - if (urb->interval) + if (urb->interval) { + urb->complete(urb); uhci_reset_interrupt(urb); - else { - /* Release bandwidth for Interrupt or Isoc. transfers */ - /* Spinlock needed ? */ - if (urb->bandwidth) - usb_release_bandwidth (urb->dev, urb, 0); - uhci_unlink_generic(urb); + return; } - return; /* <-- Note the return */ + + /* Release bandwidth for Interrupt or Isoc. transfers */ + /* Spinlock needed ? */ + if (urb->bandwidth) + usb_release_bandwidth(urb->dev, urb, 0); + uhci_unlink_generic(urb); + break; } if (urb->next) { @@ -1453,7 +1452,7 @@ is_ring = 1; } - if (urb->complete && (!proceed || (urb->transfer_flags & USB_URB_EARLY_COMPLETE))) { + if (urb->complete && !proceed) { urb->complete(urb); if (!proceed && is_ring) uhci_submit_urb(urb); @@ -1468,9 +1467,12 @@ turb = turb->next; } while (turb && turb != urb->next); - if (urb->complete && !(urb->transfer_flags & USB_URB_EARLY_COMPLETE)) + if (urb->complete) urb->complete(urb); } + + /* We decrement the usage count after we're done with everything */ + usb_dec_dev_use(dev); } static int uhci_unlink_generic(struct urb *urb) @@ -1494,6 +1496,8 @@ uhci_destroy_urb_priv(urb); + urb->dev = NULL; + return 0; } @@ -1520,10 +1524,10 @@ if (urb->bandwidth) { switch (usb_pipetype(urb->pipe)) { case PIPE_INTERRUPT: - usb_release_bandwidth (urb->dev, urb, 0); + usb_release_bandwidth(urb->dev, urb, 0); break; case PIPE_ISOCHRONOUS: - usb_release_bandwidth (urb->dev, urb, 1); + usb_release_bandwidth(urb->dev, urb, 1); break; default: break; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/usb/usb-core.c linux/drivers/usb/usb-core.c --- v2.4.0-test8/linux/drivers/usb/usb-core.c Thu Sep 7 08:39:00 2000 +++ linux/drivers/usb/usb-core.c Mon Sep 18 15:23:30 2000 @@ -12,7 +12,6 @@ #include #include -#include #include #include @@ -25,13 +24,6 @@ int usb_major_init(void); void usb_major_cleanup(void); - -/* - * HCI drivers - */ - -int uhci_init(void); -int ohci_hcd_init(void); /* * Cleanup diff -u --recursive --new-file v2.4.0-test8/linux/drivers/usb/usb-ohci.c linux/drivers/usb/usb-ohci.c --- v2.4.0-test8/linux/drivers/usb/usb-ohci.c Thu Sep 7 08:39:00 2000 +++ linux/drivers/usb/usb-ohci.c Tue Oct 3 09:24:40 2000 @@ -2,6 +2,7 @@ * URB OHCI HCD (Host Controller Driver) for USB. * * (C) Copyright 1999 Roman Weissgaerber + * (C) Copyright 2000 David Brownell * * [ Initialisation is based on Linus' ] * [ uhci code and gregs ohci fragments ] @@ -11,6 +12,14 @@ * * History: * + * 2000/09/26 fixed races in removing the private portion of the urb + * 2000/09/07 disable bulk and control lists when unlinking the last + * endpoint descriptor in order to avoid unrecoverable errors on + * the Lucent chips. + * 2000/08/29 use bandwidth claiming hooks (thanks Randy!), fix some + * urb unlink probs, indentation fixes + * 2000/08/11 various oops fixes mostly affecting iso and cleanup from + * device unplugs. * 2000/06/28 use PCI hotplug framework, for better power management * and for Cardbus support (David Brownell) * 2000/earlier: fixes for NEC/Lucent chips; suspend/resume handling @@ -73,8 +82,9 @@ /* For initializing controller (mask in an HCFS mode too) */ #define OHCI_CONTROL_INIT \ - (OHCI_CTRL_CBSR & 0x3) \ - | OHCI_CTRL_BLE | OHCI_CTRL_CLE | OHCI_CTRL_IE | OHCI_CTRL_PLE + (OHCI_CTRL_CBSR & 0x3) | OHCI_CTRL_IE | OHCI_CTRL_PLE + +#define OHCI_UNLINK_TIMEOUT (HZ / 10) static LIST_HEAD (ohci_hcd_list); static spinlock_t usb_ed_lock = SPIN_LOCK_UNLOCKED; @@ -83,23 +93,55 @@ * URB support functions *-------------------------------------------------------------------------*/ -/* free the private part of an URB */ - -static void urb_rm_priv (urb_t * urb) +/* free HCD-private data associated with this URB */ + +static void urb_free_priv (urb_priv_t * urb_priv) { - urb_priv_t * urb_priv = urb->hcpriv; int i; - - if (!urb_priv) return; - + for (i = 0; i < urb_priv->length; i++) { if (urb_priv->td [i]) { OHCI_FREE (urb_priv->td [i]); } } - kfree (urb->hcpriv); - urb->hcpriv = NULL; + kfree (urb_priv); +} + +static void urb_rm_priv_locked (urb_t * urb) +{ + urb_priv_t * urb_priv = urb->hcpriv; + + if (urb_priv) { + urb->hcpriv = NULL; + + /* Release int/iso bandwidth */ + if (urb->bandwidth) { + switch (usb_pipetype(urb->pipe)) { + case PIPE_INTERRUPT: + usb_release_bandwidth (urb->dev, urb, 0); + break; + case PIPE_ISOCHRONOUS: + usb_release_bandwidth (urb->dev, urb, 1); + break; + default: + break; + } + } + + urb_free_priv (urb_priv); + usb_dec_dev_use (urb->dev); + urb->dev = NULL; + } +} + +static void urb_rm_priv (urb_t * urb) +{ + unsigned long flags; + + spin_lock_irqsave (&usb_ed_lock, flags); + urb_rm_priv_locked (urb); + spin_unlock_irqrestore (&usb_ed_lock, flags); } /*-------------------------------------------------------------------------*/ @@ -347,15 +389,15 @@ unsigned long flags; int i; + if (!urb_priv) + return -1; /* urb already unlinked */ + /* just to be sure */ if (!urb->complete) { urb_rm_priv (urb); - usb_dec_dev_use (urb->dev); return -1; } - if (!urb_priv) return -1; /* urb already unlinked */ - #ifdef DEBUG urb_print (urb, "RET", usb_pipeout (urb->pipe)); #endif @@ -389,7 +431,6 @@ } else { /* unlink URB, call complete */ urb_rm_priv (urb); - usb_dec_dev_use (urb->dev); urb->complete (urb); } break; @@ -397,7 +438,6 @@ case PIPE_BULK: case PIPE_CONTROL: /* unlink URB, call complete */ urb_rm_priv (urb); - usb_dec_dev_use (urb->dev); urb->complete (urb); break; } @@ -416,9 +456,10 @@ unsigned int pipe = urb->pipe; int i, size = 0; unsigned long flags; + int bustime = 0; if (!urb->dev || !urb->dev->bus) - return -EINVAL; + return -ENODEV; if (urb->hcpriv) /* urb already in use */ return -EINVAL; @@ -433,7 +474,7 @@ urb_print (urb, "SUB", usb_pipein (pipe)); #endif - /* a request to the virtual root hub */ + /* handle a request to the virtual root hub */ if (usb_pipedevice (pipe) == ohci->rh.devnum) return rh_submit_urb (urb); @@ -457,6 +498,10 @@ break; case PIPE_ISOCHRONOUS: /* number of packets from URB */ size = urb->number_of_packets; + if (size <= 0) { + usb_dec_dev_use (urb->dev); + return -EINVAL; + } for (i = 0; i < urb->number_of_packets; i++) { urb->iso_frame_desc[i].actual_length = 0; urb->iso_frame_desc[i].status = -EXDEV; @@ -468,11 +513,10 @@ break; case PIPE_INTERRUPT: /* one TD */ size = 1; - break; } - /* allocate the private part or the URB */ + /* allocate the private part of the URB */ urb_priv = kmalloc (sizeof (urb_priv_t) + size * sizeof (td_t *), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); if (!urb_priv) { @@ -482,43 +526,59 @@ memset (urb_priv, 0, sizeof (urb_priv_t) + size * sizeof (td_t *)); /* fill the private part of the URB */ - urb->hcpriv = urb_priv; urb_priv->length = size; - urb_priv->td_cnt = 0; - urb_priv->state = 0; urb_priv->ed = ed; - + /* allocate the TDs */ for (i = 0; i < size; i++) { OHCI_ALLOC (urb_priv->td[i], sizeof (td_t)); if (!urb_priv->td[i]) { + urb_free_priv (urb_priv); usb_dec_dev_use (urb->dev); - urb_rm_priv (urb); return -ENOMEM; } } - spin_lock_irqsave (&usb_ed_lock, flags); + if (ed->state == ED_NEW || (ed->state & ED_DEL)) { - urb_rm_priv(urb); + urb_free_priv (urb_priv); usb_dec_dev_use (urb->dev); - spin_unlock_irqrestore(&usb_ed_lock, flags); return -EINVAL; } - /* for ISOC transfers calculate start frame index */ - if (urb->transfer_flags & USB_ISO_ASAP) { - urb->start_frame = ((ed->state == ED_OPER)? (ed->last_iso + 1): - (le16_to_cpu (ohci->hcca.frame_no) + 10)) & 0xffff; - } - urb->status = USB_ST_URB_PENDING; + /* allocate and claim bandwidth if needed; ISO + * needs start frame index if it was't provided. + */ + switch (usb_pipetype (pipe)) { + case PIPE_ISOCHRONOUS: + if (urb->transfer_flags & USB_ISO_ASAP) { + urb->start_frame = ((ed->state == ED_OPER) + ? (ed->last_iso + 1) + : (le16_to_cpu (ohci->hcca.frame_no) + 10)) & 0xffff; + } + /* FALLTHROUGH */ + case PIPE_INTERRUPT: + if (urb->bandwidth == 0) { + bustime = usb_check_bandwidth (urb->dev, urb); + } + if (bustime < 0) { + urb_free_priv (urb_priv); + usb_dec_dev_use (urb->dev); + return bustime; + } + usb_claim_bandwidth (urb->dev, urb, bustime, usb_pipeisoc (urb->pipe)); + } + + spin_lock_irqsave (&usb_ed_lock, flags); urb->actual_length = 0; - - if (ed->state != ED_OPER) /* link the ed into a chain if is not already */ + urb->hcpriv = urb_priv; + urb->status = USB_ST_URB_PENDING; + + /* link the ed into a chain if is not already */ + if (ed->state != ED_OPER) ep_link (ohci, ed); - - urb->status = USB_ST_URB_PENDING; - td_submit_urb (urb); /* fill the TDs and link it to the ed */ + /* fill the TDs and link it to the ed */ + td_submit_urb (urb); spin_unlock_irqrestore (&usb_ed_lock, flags); return 0; @@ -528,7 +588,7 @@ /* deactivate all TDs and remove the private part of the URB */ /* interrupt callers must use async unlink mode */ - + static int sohci_unlink_urb (urb_t * urb) { unsigned long flags; @@ -545,16 +605,14 @@ #ifdef DEBUG urb_print (urb, "UNLINK", 1); #endif - - if (usb_pipedevice (urb->pipe) == ohci->rh.devnum) { - usb_dec_dev_use(urb->dev); - return rh_unlink_urb (urb); /* a request to the virtual root hub */ - } - if (urb->hcpriv) { - /* URB active? */ - if (urb->status == USB_ST_URB_PENDING && !ohci->disabled) { - urb_priv_t * urb_priv = urb->hcpriv; + /* handle a request to the virtual root hub */ + if (usb_pipedevice (urb->pipe) == ohci->rh.devnum) + return rh_unlink_urb (urb); + + if (urb->hcpriv && (urb->status == USB_ST_URB_PENDING)) { + if (!ohci->disabled) { + urb_priv_t * urb_priv; /* interrupt code may not sleep; it must use * async status return to unlink pending urbs. @@ -566,40 +624,50 @@ return -EWOULDBLOCK; } - /* flag the urb and its TDs for deletion in some * upcoming SF interrupt delete list processing */ - urb_priv->state = URB_DEL; - spin_lock_irqsave (&usb_ed_lock, flags); + urb_priv = urb->hcpriv; + + if (!urb_priv || (urb_priv->state == URB_DEL)) { + spin_unlock_irqrestore (&usb_ed_lock, flags); + return 0; + } + + urb_priv->state = URB_DEL; ep_rm_ed (urb->dev, urb_priv->ed); urb_priv->ed->state |= ED_URB_DEL; - spin_unlock_irqrestore (&usb_ed_lock, flags); if (!(urb->transfer_flags & USB_ASYNC_UNLINK)) { DECLARE_WAIT_QUEUE_HEAD (unlink_wakeup); DECLARE_WAITQUEUE (wait, current); + int timeout = OHCI_UNLINK_TIMEOUT; - usb_dec_dev_use (urb->dev); - /* wait until all TDs are deleted */ add_wait_queue (&unlink_wakeup, &wait); urb_priv->wait = &unlink_wakeup; - current->state = TASK_UNINTERRUPTIBLE; - schedule (); + spin_unlock_irqrestore (&usb_ed_lock, flags); + + /* wait until all TDs are deleted */ + set_current_state(TASK_UNINTERRUPTIBLE); + while (timeout && (urb->status == USB_ST_URB_PENDING)) + timeout = schedule_timeout (timeout); remove_wait_queue (&unlink_wakeup, &wait); - urb->status = -ENOENT; - urb_priv->wait = 0; + if (urb->status == USB_ST_URB_PENDING) { + err ("unlink URB timeout"); + return -ETIMEDOUT; + } } else { /* usb_dec_dev_use done in dl_del_list() */ urb->status = -EINPROGRESS; + spin_unlock_irqrestore (&usb_ed_lock, flags); } } else { - usb_dec_dev_use (urb->dev); urb_rm_priv (urb); - if (urb->complete && (urb->transfer_flags & USB_ASYNC_UNLINK)) { - urb->complete (urb); - urb->status = 0; + if (urb->transfer_flags & USB_ASYNC_UNLINK) { + urb->status = -ECONNRESET; + if (urb->complete) + urb->complete (urb); } else urb->status = -ENOENT; } @@ -683,14 +751,19 @@ } else if (!in_interrupt ()) { DECLARE_WAIT_QUEUE_HEAD (freedev_wakeup); DECLARE_WAITQUEUE (wait, current); + int timeout = OHCI_UNLINK_TIMEOUT; /* SF interrupt handler calls dl_del_list */ add_wait_queue (&freedev_wakeup, &wait); dev->wait = &freedev_wakeup; - current->state = TASK_UNINTERRUPTIBLE; - schedule (); + set_current_state(TASK_UNINTERRUPTIBLE); + while (timeout && dev->ed_cnt) + timeout = schedule_timeout (timeout); remove_wait_queue (&freedev_wakeup, &wait); - + if (dev->ed_cnt) { + err ("free device %d timeout", usb_dev->devnum); + return -ETIMEDOUT; + } } else { /* likely some interface's driver has a refcount bug */ err ("bus %s devnum %d deletion in interrupt", @@ -790,7 +863,7 @@ ed->state = ED_OPER; switch (ed->type) { - case CTRL: + case PIPE_CONTROL: ed->hwNextED = 0; if (ohci->ed_controltail == NULL) { writel (virt_to_bus (ed), &ohci->regs->ed_controlhead); @@ -798,10 +871,15 @@ ohci->ed_controltail->hwNextED = cpu_to_le32 (virt_to_bus (ed)); } ed->ed_prev = ohci->ed_controltail; + if (!ohci->ed_controltail && !ohci->ed_rm_list[0] && + !ohci->ed_rm_list[1]) { + ohci->hc_control |= OHCI_CTRL_CLE; + writel (ohci->hc_control, &ohci->regs->control); + } ohci->ed_controltail = edi; break; - case BULK: + case PIPE_BULK: ed->hwNextED = 0; if (ohci->ed_bulktail == NULL) { writel (virt_to_bus (ed), &ohci->regs->ed_bulkhead); @@ -809,10 +887,15 @@ ohci->ed_bulktail->hwNextED = cpu_to_le32 (virt_to_bus (ed)); } ed->ed_prev = ohci->ed_bulktail; + if (!ohci->ed_bulktail && !ohci->ed_rm_list[0] && + !ohci->ed_rm_list[1]) { + ohci->hc_control |= OHCI_CTRL_BLE; + writel (ohci->hc_control, &ohci->regs->control); + } ohci->ed_bulktail = edi; break; - case INT: + case PIPE_INTERRUPT: load = ed->int_load; interval = ep_2_n_interval (ed->int_period); ed->int_interval = interval; @@ -833,7 +916,7 @@ #endif break; - case ISO: + case PIPE_ISOCHRONOUS: ed->hwNextED = 0; ed->int_interval = 1; if (ohci->ed_isotail != NULL) { @@ -873,24 +956,33 @@ int inter; int interval; __u32 * ed_p; - - + + ed->hwINFO |= cpu_to_le32 (OHCI_ED_SKIP); + switch (ed->type) { - case CTRL: + case PIPE_CONTROL: if (ed->ed_prev == NULL) { + if (!ed->hwNextED) { + ohci->hc_control &= ~OHCI_CTRL_CLE; + writel (ohci->hc_control, &ohci->regs->control); + } writel (le32_to_cpup (&ed->hwNextED), &ohci->regs->ed_controlhead); } else { ed->ed_prev->hwNextED = ed->hwNextED; } - if(ohci->ed_controltail == ed) { + if (ohci->ed_controltail == ed) { ohci->ed_controltail = ed->ed_prev; } else { ((ed_t *) bus_to_virt (le32_to_cpup (&ed->hwNextED)))->ed_prev = ed->ed_prev; } break; - case BULK: + case PIPE_BULK: if (ed->ed_prev == NULL) { + if (!ed->hwNextED) { + ohci->hc_control &= ~OHCI_CTRL_BLE; + writel (ohci->hc_control, &ohci->regs->control); + } writel (le32_to_cpup (&ed->hwNextED), &ohci->regs->ed_bulkhead); } else { ed->ed_prev->hwNextED = ed->hwNextED; @@ -902,7 +994,7 @@ } break; - case INT: + case PIPE_INTERRUPT: int_branch = ed->int_branch; interval = ed->int_interval; @@ -924,7 +1016,7 @@ #endif break; - case ISO: + case PIPE_ISOCHRONOUS: if (ohci->ed_isotail == ed) ohci->ed_isotail = ed->ed_prev; if (ed->hwNextED != 0) @@ -969,16 +1061,17 @@ td_t * td; ed_t * ed_ret; volatile ed_t * ed; + unsigned long flags; - spin_lock (&usb_ed_lock); + spin_lock_irqsave (&usb_ed_lock, flags); ed = ed_ret = &(usb_to_ohci (usb_dev)->ed[(usb_pipeendpoint (pipe) << 1) | (usb_pipecontrol (pipe)? 0: usb_pipeout (pipe))]); if ((ed->state & ED_DEL) || (ed->state & ED_URB_DEL)) { /* pending delete request */ - spin_unlock (&usb_ed_lock); + spin_unlock_irqrestore (&usb_ed_lock, flags); return NULL; } @@ -987,7 +1080,7 @@ OHCI_ALLOC (td, sizeof (*td)); /* dummy td; end of td list for ed */ if (!td) { /* out of memory */ - spin_unlock (&usb_ed_lock); + spin_unlock_irqrestore (&usb_ed_lock, flags); return NULL; } ed->hwTailP = cpu_to_le32 (virt_to_bus (td)); @@ -1006,12 +1099,12 @@ | usb_pipeslow (pipe) << 13 | usb_maxpacket (usb_dev, pipe, usb_pipeout (pipe)) << 16); - if (ed->type == INT && ed->state == ED_UNLINK) { + if (ed->type == PIPE_INTERRUPT && ed->state == ED_UNLINK) { ed->int_period = interval; ed->int_load = load; } - spin_unlock(&usb_ed_lock); + spin_unlock_irqrestore (&usb_ed_lock, flags); return ed_ret; } @@ -1029,28 +1122,29 @@ if ((ed->state & ED_DEL) || (ed->state & ED_URB_DEL)) return; - ed->hwINFO |= cpu_to_le32 (OHCI_ED_SKIP); + ed->hwINFO |= cpu_to_le32 (OHCI_ED_SKIP); if (!ohci->disabled) { - /* enable SOF interrupt */ - writel (OHCI_INTR_SF, &ohci->regs->intrstatus); - writel (OHCI_INTR_SF, &ohci->regs->intrenable); + switch (ed->type) { + case PIPE_CONTROL: /* stop control list */ + ohci->hc_control &= ~OHCI_CTRL_CLE; + writel (ohci->hc_control, &ohci->regs->control); + break; + case PIPE_BULK: /* stop bulk list */ + ohci->hc_control &= ~OHCI_CTRL_BLE; + writel (ohci->hc_control, &ohci->regs->control); + break; + } } frame = le16_to_cpu (ohci->hcca.frame_no) & 0x1; ed->ed_rm_list = ohci->ed_rm_list[frame]; ohci->ed_rm_list[frame] = ed; - if (ohci->disabled) - return; - - switch (ed->type) { - case CTRL: /* stop CTRL list */ - writel (ohci->hc_control &= ~OHCI_CTRL_CLE, &ohci->regs->control); - break; - case BULK: /* stop BULK list */ - writel (ohci->hc_control &= ~OHCI_CTRL_BLE, &ohci->regs->control); - break; + if (!ohci->disabled) { + /* enable SOF interrupt */ + writel (OHCI_INTR_SF, &ohci->regs->intrstatus); + writel (OHCI_INTR_SF, &ohci->regs->intrenable); } } @@ -1072,25 +1166,30 @@ td_pt = urb_priv->td [index]; /* fill the old dummy TD */ - td = urb_priv->td [index] = (td_t *) bus_to_virt (le32_to_cpup (&urb_priv->ed->hwTailP) & 0xfffffff0); + td = urb_priv->td [index] = (td_t *) + bus_to_virt (le32_to_cpup (&urb_priv->ed->hwTailP) & 0xfffffff0); td->ed = urb_priv->ed; + td->next_dl_td = NULL; td->index = index; td->urb = urb; td->hwINFO = cpu_to_le32 (info); - if ((td->ed->type & 3) == PIPE_ISOCHRONOUS) { - td->hwCBP = cpu_to_le32 (((!data || !len)? - 0 : virt_to_bus (data)) & 0xFFFFF000); + if ((td->ed->type) == PIPE_ISOCHRONOUS) { + td->hwCBP = cpu_to_le32 (((!data || !len) + ? 0 + : virt_to_bus (data)) & 0xFFFFF000); td->ed->last_iso = info & 0xffff; } else { - td->hwCBP = cpu_to_le32 (((!data || !len)? 0 : virt_to_bus (data))); + td->hwCBP = cpu_to_le32 (((!data || !len) + ? 0 + : virt_to_bus (data))); } - td->hwBE = cpu_to_le32 ((!data || !len )? 0: virt_to_bus (data + len - 1)); + td->hwBE = cpu_to_le32 ((!data || !len ) + ? 0 + : virt_to_bus (data + len - 1)); td->hwNextTD = cpu_to_le32 (virt_to_bus (td_pt)); td->hwPSW [0] = cpu_to_le16 ((virt_to_bus (data) & 0x0FFF) | 0xE000); td_pt->hwNextTD = 0; td->ed->hwTailP = td->hwNextTD; - - td->next_dl_td = NULL; //td_pt; } /*-------------------------------------------------------------------------*/ @@ -1215,6 +1314,27 @@ } } +/* handle an urb that is being unlinked */ + +static void dl_del_urb (urb_t * urb) +{ + wait_queue_head_t * wait_head = ((urb_priv_t *)(urb->hcpriv))->wait; + + urb_rm_priv_locked (urb); + + if (urb->transfer_flags & USB_ASYNC_UNLINK) { + urb->status = -ECONNRESET; + if (urb->complete) + urb->complete (urb); + } else { + urb->status = -ENOENT; + + /* unblock sohci_unlink_urb */ + if (wait_head) + wake_up (wait_head); + } +} + /*-------------------------------------------------------------------------*/ /* replies to the request have to be on a FIFO basis so @@ -1276,6 +1396,7 @@ int ctrl = 0, bulk = 0; spin_lock_irqsave (&usb_ed_lock, flags); + for (ed = ohci->ed_rm_list[frame]; ed != NULL; ed = ed->ed_rm_list) { tdTailP = bus_to_virt (le32_to_cpup (&ed->hwTailP) & 0xfffffff0); @@ -1290,22 +1411,13 @@ td_next = bus_to_virt (le32_to_cpup (&td->hwNextTD) & 0xfffffff0); if ((urb_priv->state == URB_DEL) || (ed->state & ED_DEL)) { tdINFO = le32_to_cpup (&td->hwINFO); - if (TD_CC_GET (tdINFO) < 0xE) dl_transfer_length (td); + if (TD_CC_GET (tdINFO) < 0xE) + dl_transfer_length (td); *td_p = td->hwNextTD | (*td_p & cpu_to_le32 (0x3)); - /* URB is done; clean up */ - if (++(urb_priv->td_cnt) == urb_priv->length) { - void *condition = urb_priv->wait; - urb_rm_priv (urb); - if (urb->transfer_flags & USB_ASYNC_UNLINK) { - usb_dec_dev_use (urb->dev); - urb->status = -ECONNRESET; - urb->complete (urb); - } else if (condition) { - /* unblock sohci_unlink_urb */ - wake_up (condition); - } - } + /* URB is done; clean up */ + if (++(urb_priv->td_cnt) == urb_priv->length) + dl_del_urb (urb); } else { td_p = &td->hwNextTD; } @@ -1317,31 +1429,54 @@ ed->hwINFO = cpu_to_le32 (OHCI_ED_SKIP); ed->state = ED_NEW; /* if all eds are removed wake up sohci_free_dev */ - if (!--dev->ed_cnt && dev->wait) - wake_up (dev->wait); - } - else { + if (!--dev->ed_cnt) { + wait_queue_head_t *wait_head = dev->wait; + + dev->wait = 0; + if (wait_head) + wake_up (wait_head); + } + } else { ed->state &= ~ED_URB_DEL; - ed->hwINFO &= ~cpu_to_le32 (OHCI_ED_SKIP); + tdHeadP = bus_to_virt (le32_to_cpup (&ed->hwHeadP) & 0xfffffff0); + + if (tdHeadP == tdTailP) { + if (ed->state == ED_OPER) + ep_unlink(ohci, ed); + OHCI_FREE (tdTailP); + ed->hwINFO = cpu_to_le32 (OHCI_ED_SKIP); + ed->state = ED_NEW; + --(usb_to_ohci (ohci->dev[edINFO & 0x7F]))->ed_cnt; + } else + ed->hwINFO &= ~cpu_to_le32 (OHCI_ED_SKIP); } - - if ((ed->type & 3) == CTRL) ctrl |= 1; - if ((ed->type & 3) == BULK) bulk |= 1; + + switch (ed->type) { + case PIPE_CONTROL: + ctrl = 1; + break; + case PIPE_BULK: + bulk = 1; + break; + } } - /* maybe reenable CTRL and BULK lists */ + /* maybe reenable control and bulk lists */ if (!ohci->disabled) { - if (ctrl) /* reset CTRL list */ + if (ctrl) /* reset control list */ writel (0, &ohci->regs->ed_controlcurrent); - if (bulk) /* reset BULK list */ + if (bulk) /* reset bulk list */ writel (0, &ohci->regs->ed_bulkcurrent); if (!ohci->ed_rm_list[!frame]) { - ohci->hc_control |= OHCI_CTRL_CLE | OHCI_CTRL_BLE; + if (ohci->ed_controltail) + ohci->hc_control |= OHCI_CTRL_CLE; + if (ohci->ed_bulktail) + ohci->hc_control |= OHCI_CTRL_BLE; writel (ohci->hc_control, &ohci->regs->control); } } - ohci->ed_rm_list[frame] = NULL; + ohci->ed_rm_list[frame] = NULL; spin_unlock_irqrestore (&usb_ed_lock, flags); } @@ -1375,17 +1510,25 @@ /* error code of transfer */ cc = TD_CC_GET (tdINFO); - if( cc == TD_CC_STALL) usb_endpoint_halt(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)); + if (cc == TD_CC_STALL) + usb_endpoint_halt(urb->dev, + usb_pipeendpoint(urb->pipe), + usb_pipeout(urb->pipe)); - if (!(urb->transfer_flags & USB_DISABLE_SPD) && (cc == TD_DATAUNDERRUN)) - cc = TD_CC_NOERROR; + if (!(urb->transfer_flags & USB_DISABLE_SPD) + && (cc == TD_DATAUNDERRUN)) + cc = TD_CC_NOERROR; + if (++(urb_priv->td_cnt) == urb_priv->length) { - if (urb_priv->state != URB_DEL && !(ed->state & ED_DEL) && ed->state != ED_NEW) { + if ((ed->state & (ED_OPER | ED_UNLINK)) + && (urb_priv->state != URB_DEL)) { urb->status = cc_to_error[cc]; sohci_return_urb (urb); } else { - urb_rm_priv (urb); - } + spin_lock_irqsave (&usb_ed_lock, flags); + dl_del_urb (urb); + spin_unlock_irqrestore (&usb_ed_lock, flags); + } } spin_lock_irqsave (&usb_ed_lock, flags); @@ -1393,13 +1536,13 @@ edHeadP = le32_to_cpup (&ed->hwHeadP) & 0xfffffff0; edTailP = le32_to_cpup (&ed->hwTailP); - if((edHeadP == edTailP) && (ed->state == ED_OPER)) - ep_unlink (ohci, ed); /* unlink eds if they are not busy */ - - } - spin_unlock_irqrestore (&usb_ed_lock, flags); + /* unlink eds if they are not busy */ + if ((edHeadP == edTailP) && (ed->state == ED_OPER)) + ep_unlink (ohci, ed); + } + spin_unlock_irqrestore (&usb_ed_lock, flags); - td_list = td_list_next; + td_list = td_list_next; } } @@ -1530,7 +1673,7 @@ /* ignore timers firing during PM suspend, etc */ if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER) - return; + goto out; if(ohci->rh.send) { len = rh_send_irq (ohci, urb->transfer_buffer, urb->transfer_buffer_length); @@ -1539,9 +1682,11 @@ #ifdef DEBUG urb_print (urb, "RET-t(rh)", usb_pipeout (urb->pipe)); #endif - if (urb->complete) urb->complete (urb); + if (urb->complete) + urb->complete (urb); } - } + } + out: rh_init_int_timer (urb); } @@ -1594,7 +1739,6 @@ __u16 wLength; if (usb_pipeint(pipe)) { - ohci->rh.urb = urb; ohci->rh.send = 1; ohci->rh.interval = urb->interval; @@ -1765,9 +1909,11 @@ urb_print (urb, "RET(rh)", usb_pipeout (urb->pipe)); #endif + urb->hcpriv = NULL; + usb_dec_dev_use (usb_dev); + urb->dev = NULL; if (urb->complete) urb->complete (urb); - usb_dec_dev_use (urb->dev); return 0; } @@ -1780,6 +1926,17 @@ if (ohci->rh.urb == urb) { ohci->rh.send = 0; del_timer (&ohci->rh.rh_int_timer); + ohci->rh.urb = NULL; + + urb->hcpriv = NULL; + usb_dec_dev_use(urb->dev); + urb->dev = NULL; + if (urb->transfer_flags & USB_ASYNC_UNLINK) { + urb->status = -ECONNRESET; + if (urb->complete) + urb->complete (urb); + } else + urb->status = -ENOENT; } return 0; } @@ -2290,6 +2447,12 @@ ohci->disabled = 0; ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER; + if (!ohci->ed_rm_list[0] & !ohci->ed_rm_list[1]) { + if (ohci->ed_controltail) + ohci->hc_control |= OHCI_CTRL_CLE; + if (ohci->ed_bulktail) + ohci->hc_control |= OHCI_CTRL_BLE; + } writel (ohci->hc_control, &ohci->regs->control); #ifdef CONFIG_PMAC_PBOOK enable_irq (ohci->irq); @@ -2386,7 +2549,6 @@ return ret; } - /*-------------------------------------------------------------------------*/ static void __exit ohci_hcd_cleanup (void) @@ -2401,6 +2563,5 @@ module_exit (ohci_hcd_cleanup); - -MODULE_AUTHOR ("Roman Weissgaerber "); +MODULE_AUTHOR ("Roman Weissgaerber , David Brownell"); MODULE_DESCRIPTION ("USB OHCI Host Controller Driver"); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/usb/usb-ohci.h linux/drivers/usb/usb-ohci.h --- v2.4.0-test8/linux/drivers/usb/usb-ohci.h Sun Aug 13 15:59:10 2000 +++ linux/drivers/usb/usb-ohci.h Tue Oct 3 09:24:40 2000 @@ -1,10 +1,10 @@ - /* +/* * URB OHCI HCD (Host Controller Driver) for USB. * - *(C) Copyright 1999 Roman Weissgaerber + * (C) Copyright 1999 Roman Weissgaerber + * (C) Copyright 2000 David Brownell * * usb-ohci.h - * */ @@ -40,7 +40,7 @@ #define ED_UNLINK 0x01 #define ED_OPER 0x02 #define ED_DEL 0x04 -#define ED_URB_DEL 0x08 +#define ED_URB_DEL 0x08 /* usb_ohci_ed */ typedef struct ed { @@ -107,7 +107,7 @@ __u32 hwBE; /* Memory Buffer End Pointer */ __u16 hwPSW[MAXPSW]; - __u8 type; + __u8 unused; __u8 index; struct ed * ed; struct td * next_dl_td; @@ -115,18 +115,6 @@ } td_t; -/* TD types */ -#define BULK 0x03 -#define INT 0x01 -#define CTRL 0x02 -#define ISO 0x00 - -#define SEND 0x01 -#define ST_ADDR 0x02 -#define ADD_LEN 0x04 -#define DEL 0x08 - - #define OHCI_ED_SKIP (1 << 14) /* @@ -347,7 +335,7 @@ __u16 length; // number of tds associated with this request __u16 td_cnt; // number of tds already serviced int state; - void * wait; + wait_queue_head_t * wait; td_t * td[0]; // list pointer to all corresponding TDs associated with this request } urb_priv_t; @@ -372,8 +360,8 @@ struct list_head ohci_hcd_list; /* list of all ohci_hcd */ struct ohci * next; // chain of uhci device contexts - struct list_head urb_list; // list of all pending urbs - spinlock_t urb_list_lock; // lock to keep consistency + // struct list_head urb_list; // list of all pending urbs + // spinlock_t urb_list_lock; // lock to keep consistency int ohci_int_load[32]; /* load of the 32 Interrupt Chains (for load balancing)*/ ed_t * ed_rm_list[2]; /* lists of all endpoints to be removed */ @@ -398,7 +386,7 @@ struct ohci_device { ed_t ed[NUM_EDS]; int ed_cnt; - void * wait; + wait_queue_head_t * wait; }; // #define ohci_to_usb(ohci) ((ohci)->usb) @@ -418,7 +406,7 @@ static int rh_unlink_urb(urb_t * urb); static int rh_init_int_timer(urb_t * urb); -#ifdef DEBUG +#ifdef OHCI_VERBOSE_DEBUG #define OHCI_FREE(x) kfree(x); printk("OHCI FREE: %d: %4x\n", -- __ohci_free_cnt, (unsigned int) x) #define OHCI_ALLOC(x,size) (x) = kmalloc(size, in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); printk("OHCI ALLO: %d: %4x\n", ++ __ohci_free_cnt,(unsigned int) x) static int __ohci_free_cnt = 0; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/usb/usb-uhci.c linux/drivers/usb/usb-uhci.c --- v2.4.0-test8/linux/drivers/usb/usb-uhci.c Thu Sep 7 08:39:00 2000 +++ linux/drivers/usb/usb-uhci.c Tue Oct 3 09:24:40 2000 @@ -12,7 +12,7 @@ * (C) Copyright 1999 Johannes Erdfelt * (C) Copyright 1999 Randy Dunlap * - * $Id: usb-uhci.c,v 1.237 2000/08/08 14:58:17 acher Exp $ + * $Id: usb-uhci.c,v 1.239 2000/09/19 20:15:12 acher Exp $ */ #include @@ -48,7 +48,7 @@ /* This enables an extra UHCI slab for memory debugging */ #define DEBUG_SLAB -#define VERSTR "$Revision: 1.237 $ time " __TIME__ " " __DATE__ +#define VERSTR "$Revision: 1.239 $ time " __TIME__ " " __DATE__ #include #include "usb-uhci.h" @@ -141,6 +141,9 @@ { int flags; + if (urb->transfer_flags & USB_NO_FSBR) + return; + spin_lock_irqsave (&s->qh_lock, flags); s->chain_end->hw.qh.head&=~UHCI_PTR_TERM; mb(); @@ -153,8 +156,10 @@ { int flags; - spin_lock_irqsave (&s->qh_lock, flags); + if (urb->transfer_flags & USB_NO_FSBR) + return; + spin_lock_irqsave (&s->qh_lock, flags); if (((urb_priv_t*)urb->hcpriv)->use_loop) { s->loop_usage--; @@ -1029,12 +1034,30 @@ } } /*-------------------------------------------------------------------*/ +// Release bandwidth for Interrupt or Isoc. transfers +_static void uhci_release_bandwidth(urb_t *urb) +{ + if (urb->bandwidth) { + switch (usb_pipetype(urb->pipe)) { + case PIPE_INTERRUPT: + usb_release_bandwidth (urb->dev, urb, 0); + break; + case PIPE_ISOCHRONOUS: + usb_release_bandwidth (urb->dev, urb, 1); + break; + default: + break; + } + } +} +/*-------------------------------------------------------------------*/ // unlinks an urb by dequeuing its qh, waits some frames and forgets it _static int uhci_unlink_urb_sync (uhci_t *s, urb_t *urb) { uhci_desc_t *qh; urb_priv_t *urb_priv; unsigned long flags=0; + struct usb_device *usb_dev; spin_lock_irqsave (&s->urb_list_lock, flags); @@ -1050,6 +1073,7 @@ if (!in_interrupt()) spin_unlock(&urb->lock); + uhci_release_bandwidth(urb); spin_unlock_irqrestore (&s->urb_list_lock, flags); urb->status = -ENOENT; // mark urb as killed @@ -1080,11 +1104,13 @@ #else kfree (urb->hcpriv); #endif + usb_dev = urb->dev; if (urb->complete) { dbg("unlink_urb: calling completion"); + urb->dev = NULL; urb->complete ((struct urb *) urb); } - usb_dec_dev_use (urb->dev); + usb_dec_dev_use (usb_dev); } else { if (!in_interrupt()) @@ -1148,6 +1174,7 @@ if (urb->complete) { spin_unlock(&s->urb_list_lock); + urb->dev = NULL; urb->complete ((struct urb *) urb); spin_lock(&s->urb_list_lock); } @@ -1242,6 +1269,7 @@ if (!in_interrupt()) spin_lock(&urb->lock); + uhci_release_bandwidth(urb); ret = uhci_unlink_urb_async(s, urb); if (!in_interrupt()) @@ -1543,6 +1571,7 @@ int ret = 0; unsigned long flags; urb_t *bulk_urb=NULL; + int bustime; if (!urb->dev || !urb->dev->bus) return -ENODEV; @@ -1612,11 +1641,39 @@ else { spin_unlock_irqrestore (&s->urb_list_lock, flags); switch (usb_pipetype (urb->pipe)) { - case PIPE_ISOCHRONOUS: - ret = uhci_submit_iso_urb (urb); + case PIPE_ISOCHRONOUS: + if (urb->bandwidth == 0) { /* not yet checked/allocated */ + if (urb->number_of_packets <= 0) { + ret = -EINVAL; + break; + } + + bustime = usb_check_bandwidth (urb->dev, urb); + if (bustime < 0) { + ret = bustime; + break; + } + + ret = uhci_submit_iso_urb(urb); + if (ret == 0) + usb_claim_bandwidth (urb->dev, urb, bustime, 1); + } else { /* bandwidth is already set */ + ret = uhci_submit_iso_urb(urb); + } break; case PIPE_INTERRUPT: - ret = uhci_submit_int_urb (urb); + if (urb->bandwidth == 0) { /* not yet checked/allocated */ + bustime = usb_check_bandwidth (urb->dev, urb); + if (bustime < 0) + ret = bustime; + else { + ret = uhci_submit_int_urb(urb); + if (ret == 0) + usb_claim_bandwidth (urb->dev, urb, bustime, 0); + } + } else { /* bandwidth is already set */ + ret = uhci_submit_int_urb(urb); + } break; case PIPE_CONTROL: ret = uhci_submit_control_urb (urb); @@ -2029,6 +2086,7 @@ urb->actual_length = len; urb->status = stat; + urb->dev=NULL; if (urb->complete) urb->complete (urb); return 0; @@ -2431,7 +2489,6 @@ int ret = 0; urb_t *urb; - urb=list_entry (p, urb_t, urb_list); //dbg("process_urb: found queued urb: %p", urb); @@ -2455,6 +2512,17 @@ if (urb->status != -EINPROGRESS) { int proceed = 0; + struct usb_device *usb_dev; + + usb_dev=urb->dev; + + /* Release bandwidth for Interrupt or Iso transfers */ + if (urb->bandwidth) { + if (usb_pipetype(urb->pipe)==PIPE_ISOCHRONOUS) + usb_release_bandwidth (urb->dev, urb, 1); + else if (usb_pipetype(urb->pipe)==PIPE_INTERRUPT && urb->interval) + usb_release_bandwidth (urb->dev, urb, 0); + } dbg("dequeued urb: %p", urb); dequeue_urb (s, urb); @@ -2488,9 +2556,12 @@ // In case you need the current URB status for your completion handler (before resubmit) if (urb->complete && (!proceed )) { dbg("process_transfer: calling early completion"); + urb->dev = NULL; urb->complete ((struct urb *) urb); - if (!proceed && is_ring && (urb->status != -ENOENT)) + if (!proceed && is_ring && (urb->status != -ENOENT)) { + urb->dev=usb_dev; uhci_submit_urb (urb); + } } if (proceed && urb->next) { @@ -2506,11 +2577,13 @@ if (urb->complete) { dbg("process_transfer: calling completion"); + urb->dev=NULL; urb->complete ((struct urb *) urb); } } - - usb_dec_dev_use (urb->dev); + + urb->dev=NULL; // Just in case no completion was called + usb_dec_dev_use (usb_dev); spin_unlock(&urb->lock); spin_lock(&s->urb_list_lock); } @@ -2842,6 +2915,7 @@ if(!urb_priv_kmem) { err("kmem_cache_create for urb_priv_t failed (out of memory)"); + kmem_cache_destroy(uhci_desc_kmem); return -ENOMEM; } #endif @@ -2876,6 +2950,15 @@ i++; } +#ifdef DEBUG_SLAB + if (retval < 0 ) { + if (kmem_cache_destroy(urb_priv_kmem)) + err("urb_priv_kmem remained"); + if (kmem_cache_destroy(uhci_desc_kmem)) + err("uhci_desc_kmem remained"); + } +#endif + return retval; } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/usb/usb.c linux/drivers/usb/usb.c --- v2.4.0-test8/linux/drivers/usb/usb.c Tue Sep 5 13:41:53 2000 +++ linux/drivers/usb/usb.c Tue Oct 3 09:24:40 2000 @@ -25,19 +25,7 @@ #include #include #include /* for in_interrupt() */ - - -#if defined(CONFIG_KMOD) && defined(CONFIG_HOTPLUG) #include -#include -#include - -#define __KERNEL_SYSCALLS__ -#include - -/* waitpid() call glue uses this */ -static int errno; -#endif #ifdef CONFIG_USB_DEBUG @@ -47,6 +35,11 @@ #endif #include +#define DEVNUM_ROUND_ROBIN /***** OPTION *****/ +#ifdef DEVNUM_ROUND_ROBIN +static int devnum_next = 1; +#endif + static const int usb_bandwidth_option = #ifdef CONFIG_USB_BANDWIDTH 1; @@ -187,6 +180,19 @@ return NULL; } +struct usb_endpoint_descriptor *usb_epnum_to_ep_desc(struct usb_device *dev, unsigned epnum) +{ + int i, j, k; + + for (i = 0; i < dev->actconfig->bNumInterfaces; i++) + for (j = 0; j < dev->actconfig->interface[i].num_altsetting; j++) + for (k = 0; k < dev->actconfig->interface[i].altsetting[j].bNumEndpoints; k++) + if (epnum == dev->actconfig->interface[i].altsetting[j].endpoint[k].bEndpointAddress) + return &dev->actconfig->interface[i].altsetting[j].endpoint[k]; + + return NULL; +} + /* * usb_calc_bus_time: * @@ -284,7 +290,7 @@ dev->bus->bandwidth_int_reqs++; urb->bandwidth = bustime; - dbg("bw_alloc increased by %d to %d for %d requesters", + dbg("bandwidth alloc increased by %d to %d for %d requesters", bustime, dev->bus->bandwidth_allocated, dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs); @@ -303,7 +309,7 @@ else dev->bus->bandwidth_int_reqs--; - dbg("bw_alloc reduced by %d to %d for %d requesters", + dbg("bandwidth alloc reduced by %d to %d for %d requesters", urb->bandwidth, dev->bus->bandwidth_allocated, dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs); @@ -504,40 +510,6 @@ * (normally /sbin/hotplug) when USB devices get added or removed. */ -static int exec_helper (void *arg) -{ - void **params = (void **) arg; - char *path = (char *) params [0]; - char **argv = (char **) params [1]; - char **envp = (char **) params [2]; - return exec_usermodehelper (path, argv, envp); -} - -int call_usermodehelper (char *path, char **argv, char **envp) -{ - void *params [3] = { path, argv, envp }; - int pid, pid2, retval; - mm_segment_t fs; - - if ((pid = kernel_thread (exec_helper, (void *) params, 0)) < 0) { - err ("failed fork of %s, errno = %d", argv [0], -pid); - return -1; - } - - /* set signal mask? */ - fs = get_fs (); - set_fs (KERNEL_DS); /* retval is in kernel space. */ - pid2 = waitpid (pid, &retval, __WCLONE); /* "errno" gets assigned */ - set_fs (fs); - /* restore signal mask? */ - - if (pid2 != pid) { - err ("waitpid(%d) failed, returned %d\n", pid, pid2); - return -1; - } - return retval; -} - static int to_bcd (char *buf, __u16 *bcdValue) { int retval = 0; @@ -700,7 +672,8 @@ value = call_usermodehelper (argv [0], argv, envp); kfree (buf); kfree (envp); - dbg ("kusbd policy returned 0x%x", value); + if (value != 0) + dbg ("kusbd policy returned 0x%x", value); } #else @@ -737,7 +710,7 @@ dbg("unhandled interfaces on device"); if (!claimed) { - warn("USB device %d (prod/vend 0x%x/0x%x) is not claimed by any active driver.", + warn("USB device %d (vend/prod 0x%x/0x%x) is not claimed by any active driver.", dev->devnum, dev->descriptor.idVendor, dev->descriptor.idProduct); @@ -1237,7 +1210,7 @@ config->interface = (struct usb_interface *) kmalloc(config->bNumInterfaces * sizeof(struct usb_interface), GFP_KERNEL); - dbg("kmalloc IF %p, numif %i",config->interface,config->bNumInterfaces); + dbg("kmalloc IF %p, numif %i", config->interface, config->bNumInterfaces); if (!config->interface) { err("out of memory"); return -1; @@ -1455,8 +1428,6 @@ info("USB disconnect on device %d", dev->devnum); - call_policy ("remove", dev); - if (dev->actconfig) { for (i = 0; i < dev->actconfig->bNumInterfaces; i++) { struct usb_interface *interface = &dev->actconfig->interface[i]; @@ -1477,6 +1448,9 @@ usb_disconnect(child); } + /* Let policy agent unload modules etc */ + call_policy ("remove", dev); + /* Free the device number and remove the /proc/bus/usb entry */ if (dev->devnum > 0) { clear_bit(dev->devnum, &dev->bus->devmap.devicemap); @@ -1498,10 +1472,22 @@ int devnum; // FIXME needs locking for SMP!! /* why? this is called only from the hub thread, - * which hopefully doesn't run on multiple CPU's simulatenously 8-) + * which hopefully doesn't run on multiple CPU's simultaneously 8-) */ dev->descriptor.bMaxPacketSize0 = 8; /* Start off at 8 bytes */ +#ifndef DEVNUM_ROUND_ROBIN devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, 1); +#else /* round_robin alloc of devnums */ + /* Try to allocate the next devnum beginning at devnum_next. */ + devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, devnum_next); + if (devnum >= 128) + devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, 1); + + devnum_next = devnum + 1; + if (devnum_next >= 128) + devnum_next = 1; +#endif /* round_robin alloc of devnums */ + if (devnum < 128) { set_bit(devnum, dev->bus->devmap.devicemap); dev->devnum = devnum; @@ -1898,8 +1884,6 @@ { int err; - info("USB new device connect, assigned device number %d", dev->devnum); - /* USB v1.1 5.5.3 */ /* We read the first 8 bytes from the device descriptor to get to */ /* the bMaxPacketSize0 field. Then we set the maximum packet size */ @@ -1909,7 +1893,8 @@ err = usb_set_address(dev); if (err < 0) { - err("USB device not accepting new address (error=%d)", err); + err("USB device not accepting new address=%d (error=%d)", + dev->devnum, err); clear_bit(dev->devnum, &dev->bus->devmap.devicemap); dev->devnum = -1; return 1; @@ -1922,7 +1907,7 @@ if (err < 0) err("USB device not responding, giving up (error=%d)", err); else - err("USB device descriptor short read (expected %i, got %i)",8,err); + err("USB device descriptor short read (expected %i, got %i)", 8, err); clear_bit(dev->devnum, &dev->bus->devmap.devicemap); dev->devnum = -1; return 1; @@ -1935,7 +1920,8 @@ if (err < 0) err("unable to get device descriptor (error=%d)", err); else - err("USB device descriptor short read (expected %i, got %i)", sizeof(dev->descriptor), err); + err("USB device descriptor short read (expected %i, got %i)", + sizeof(dev->descriptor), err); clear_bit(dev->devnum, &dev->bus->devmap.devicemap); dev->devnum = -1; @@ -1944,7 +1930,8 @@ err = usb_get_configuration(dev); if (err < 0) { - err("unable to get configuration (error=%d)", err); + err("unable to get device %d configuration (error=%d)", + dev->devnum, err); usb_destroy_configuration(dev); clear_bit(dev->devnum, &dev->bus->devmap.devicemap); dev->devnum = -1; @@ -1954,7 +1941,8 @@ /* we set the default configuration here */ err = usb_set_configuration(dev, dev->config[0].bConfigurationValue); if (err) { - err("failed to set default configuration (error=%d)", err); + err("failed to set device %d default configuration (error=%d)", + dev->devnum, err); clear_bit(dev->devnum, &dev->bus->devmap.devicemap); dev->devnum = -1; return 1; @@ -2048,6 +2036,7 @@ * then these symbols need to be exported for the modules to use. */ EXPORT_SYMBOL(usb_ifnum_to_if); +EXPORT_SYMBOL(usb_epnum_to_ep_desc); EXPORT_SYMBOL(usb_register); EXPORT_SYMBOL(usb_deregister); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/video/Config.in linux/drivers/video/Config.in --- v2.4.0-test8/linux/drivers/video/Config.in Wed Aug 9 14:11:11 2000 +++ linux/drivers/video/Config.in Mon Sep 18 15:15:22 2000 @@ -30,7 +30,7 @@ if [ "$CONFIG_ARCH_ACORN" = "y" ]; then bool ' Acorn VIDC support' CONFIG_FB_ACORN fi - tristate ' Cyber2000 support' CONFIG_FB_CYBER2000 + dep_tristate ' Cyber2000 support' CONFIG_FB_CYBER2000 $CONFIG_PCI if [ "$CONFIG_ARCH_SA1100" = "y" ]; then bool ' SA-1100 LCD support' CONFIG_FB_SA1100 fi diff -u --recursive --new-file v2.4.0-test8/linux/drivers/video/Makefile linux/drivers/video/Makefile --- v2.4.0-test8/linux/drivers/video/Makefile Sun Aug 6 11:23:41 2000 +++ linux/drivers/video/Makefile Sun Sep 17 09:48:04 2000 @@ -46,7 +46,10 @@ # Add fbmon.o back into obj-$(CONFIG_FB) in 2.5.x obj-$(CONFIG_FB) += fbmem.o fbcmap.o modedb.o fbcon.o fonts.o +# Only include macmodes.o if we have FB support and are PPC +ifeq ($(CONFIG_FB),y) obj-$(CONFIG_PPC) += macmodes.o +endif obj-$(CONFIG_FB_ACORN) += acornfb.o obj-$(CONFIG_FB_AMIGA) += amifb.o diff -u --recursive --new-file v2.4.0-test8/linux/drivers/video/acornfb.c linux/drivers/video/acornfb.c --- v2.4.0-test8/linux/drivers/video/acornfb.c Sun Aug 13 10:04:17 2000 +++ linux/drivers/video/acornfb.c Mon Sep 18 15:15:22 2000 @@ -1,7 +1,11 @@ /* - * linux/drivers/video/acornfb.c + * linux/drivers/video/acornfb.c * - * Copyright (C) 1998-2000 Russell King + * Copyright (C) 1998-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. * * Frame buffer code for Acorn platforms * @@ -97,6 +101,8 @@ #ifdef HAS_VIDC +#define MAX_SIZE 480*1024 + /* CTL VIDC Actual * 24.000 0 8.000 * 25.175 0 8.392 @@ -335,6 +341,8 @@ #ifdef HAS_VIDC20 #include +#define MAX_SIZE 2*1024*1024 + /* VIDC20 has a different set of rules from the VIDC: * hcr : must be multiple of 4 * hswr : must be even @@ -1561,7 +1569,7 @@ if (current_par.montype == -1 || current_par.montype > NR_MONTYPES) current_par.montype = 4; - if (current_par.montype > 0) { + if (current_par.montype >= 0) { fb_info.monspecs = monspecs[current_par.montype]; fb_info.monspecs.dpms = current_par.dpms; } @@ -1603,8 +1611,13 @@ } else if (current_par.dram_size) size = current_par.dram_size; else - size = (init_var.xres * init_var.yres * - init_var.bits_per_pixel) / 8; + size = MAX_SIZE; + + /* + * Limit maximum screen size. + */ + if (size > MAX_SIZE) + size = MAX_SIZE; size = PAGE_ALIGN(size); @@ -1640,13 +1653,6 @@ } #endif #if defined(HAS_VIDC) -#define MAX_SIZE 480*1024 - /* - * Limit maximum screen size. - */ - if (size > MAX_SIZE) - size = MAX_SIZE; - /* * Free unused pages */ @@ -1661,17 +1667,41 @@ * find it, then we can't restore it if we change * the resolution, so we disable this feature. */ - rc = fb_find_mode(&init_var, &fb_info, NULL, modedb, - sizeof(modedb) / sizeof(*modedb), - &acornfb_default_mode, DEFAULT_BPP); + do { + rc = fb_find_mode(&init_var, &fb_info, NULL, modedb, + sizeof(modedb) / sizeof(*modedb), + &acornfb_default_mode, DEFAULT_BPP); + /* + * If we found an exact match, all ok. + */ + if (rc == 1) + break; + + rc = fb_find_mode(&init_var, &fb_info, NULL, NULL, 0, + &acornfb_default_mode, DEFAULT_BPP); + /* + * If we found an exact match, all ok. + */ + if (rc == 1) + break; + + rc = fb_find_mode(&init_var, &fb_info, NULL, modedb, + sizeof(modedb) / sizeof(*modedb), + &acornfb_default_mode, DEFAULT_BPP); + if (rc) + break; + + rc = fb_find_mode(&init_var, &fb_info, NULL, NULL, 0, + &acornfb_default_mode, DEFAULT_BPP); + } while (0); /* * If we didn't find an exact match, try the * generic database. */ - if (rc != 1 && fb_find_mode(&init_var, &fb_info, NULL, NULL, 0, - &acornfb_default_mode, DEFAULT_BPP)) { + if (rc == 0) { printk("Acornfb: no valid mode found\n"); + return -EINVAL; } h_sync = 1953125000 / init_var.pixclock; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/video/acornfb.h linux/drivers/video/acornfb.h --- v2.4.0-test8/linux/drivers/video/acornfb.h Fri May 12 11:21:20 2000 +++ linux/drivers/video/acornfb.h Mon Sep 18 15:15:22 2000 @@ -1,16 +1,20 @@ /* - * linux/drivers/video/acornfb.h + * linux/drivers/video/acornfb.h * - * Copyright (C) 1998,1999 Russell King + * Copyright (C) 1998,1999 Russell King * - * Frame buffer code for Acorn platforms + * 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. + * + * Frame buffer code for Acorn platforms */ #if defined(HAS_VIDC20) -#include +#include #define VIDC_PALETTE_SIZE 256 #define VIDC_NAME "VIDC20" #elif defined(HAS_VIDC) -#include +#include #define VIDC_PALETTE_SIZE 16 #define VIDC_NAME "VIDC" #endif diff -u --recursive --new-file v2.4.0-test8/linux/drivers/video/aty.h linux/drivers/video/aty.h --- v2.4.0-test8/linux/drivers/video/aty.h Tue Jun 20 14:14:51 2000 +++ linux/drivers/video/aty.h Sun Sep 17 09:48:04 2000 @@ -461,6 +461,7 @@ #define VERTEX_2_SECONDARY_T 0x0738 /* Dword offset 1_CE */ #define VERTEX_2_SECONDARY_W 0x073C /* Dword offset 1_CF */ +#define GTC_3D_RESET_DELAY 3 /* 3D engine reset delay in ms */ /* CRTC control values (mostly CRTC_GEN_CNTL) */ @@ -747,7 +748,8 @@ #define GI_CHIP_ID 0x4749 /* RAGE PRO, BGA, PCI33 only */ #define GP_CHIP_ID 0x4750 /* RAGE PRO, PQFP, PCI33, full 3D */ #define GQ_CHIP_ID 0x4751 /* RAGE PRO, PQFP, PCI33, limited 3D */ -#define LN_CHIP_ID 0x4c4d /* RAGE Mobility AGP */ +#define LM_CHIP_ID 0x4c4d /* RAGE Mobility PCI */ +#define LN_CHIP_ID 0x4c4e /* RAGE Mobility AGP */ /* Mach64 major ASIC revisions */ @@ -998,5 +1000,12 @@ #define LCD_LT_GIO 0x07 #define LCD_POWER_MANAGEMENT 0x08 #define LCD_ZVGPIO 0x09 +#define LCD_MISC_CNTL 0x14 + +/* Values in LCD_MISC_CNTL */ +#define BIAS_MOD_LEVEL_MASK 0x0000ff00 +#define BIAS_MOD_LEVEL_SHIFT 8 +#define BLMOD_EN 0x00010000 +#define BIASMOD_EN 0x00020000 #endif /* REGMACH64_H */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/video/aty128.h linux/drivers/video/aty128.h --- v2.4.0-test8/linux/drivers/video/aty128.h Tue Jun 20 14:14:51 2000 +++ linux/drivers/video/aty128.h Sun Sep 17 09:48:04 2000 @@ -43,6 +43,7 @@ #define OVR_CLR 0x0230 #define OVR_WID_LEFT_RIGHT 0x0234 #define OVR_WID_TOP_BOTTOM 0x0238 +#define LVDS_GEN_CNTL 0x02d0 #define DDA_CONFIG 0x02e0 #define DDA_ON_OFF 0x02e4 #define VGA_DDA_CONFIG 0x02e8 @@ -267,7 +268,8 @@ #define DAC_BLANKING 0x00000004 #define DAC_RANGE_CNTL 0x00000003 #define DAC_RANGE_CNTL 0x00000003 -#define PALETTE_ACCESS_CNTL 0x00000020 +#define DAC_PALETTE_ACCESS_CNTL 0x00000020 +#define DAC_PDWN 0x00008000 /* GEN_RESET_CNTL bit constants */ #define SOFT_RESET_GUI 0x00000001 @@ -339,5 +341,12 @@ #define DP_SRC_RECT 0x00000200 #define DP_SRC_HOST 0x00000300 #define DP_SRC_HOST_BYTEALIGN 0x00000400 + +/* LVDS_GEN_CNTL constants */ +#define LVDS_BL_MOD_LEVEL_MASK 0x0000ff00 +#define LVDS_BL_MOD_LEVEL_SHIFT 8 +#define LVDS_BL_MOD_EN 0x00010000 +#define LVDS_DIGION 0x00040000 +#define LVDS_BLON 0x00080000 #endif /* REG_RAGE128_H */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/video/aty128fb.c linux/drivers/video/aty128fb.c --- v2.4.0-test8/linux/drivers/video/aty128fb.c Wed Jul 26 11:08:40 2000 +++ linux/drivers/video/aty128fb.c Sun Sep 17 09:48:04 2000 @@ -55,6 +55,15 @@ #endif #endif +#ifdef CONFIG_ADB_PMU +#include +#include +#endif + +#ifdef CONFIG_PMAC_BACKLIGHT +#include +#endif + #ifdef CONFIG_FB_COMPAT_XPMAC #include #endif @@ -211,13 +220,8 @@ #endif #ifdef CONFIG_PPC -#ifdef CONFIG_NVRAM_NOT_DEFINED -static int default_vmode __initdata = VMODE_640_480_60; +static int default_vmode __initdata = VMODE_1024_768_60; static int default_cmode __initdata = CMODE_8; -#else -static int default_vmode __initdata = VMODE_NVRAM; -static int default_cmode __initdata = CMODE_NVRAM; -#endif #endif #ifdef CONFIG_MTRR @@ -419,6 +423,15 @@ fb_rasterimg: aty128fb_rasterimg, }; +#ifdef CONFIG_PMAC_BACKLIGHT +static int aty128_set_backlight_enable(int on, int level, void* data); +static int aty128_set_backlight_level(int level, void* data); + +static struct backlight_controller aty128_backlight_controller = { + aty128_set_backlight_enable, + aty128_set_backlight_level +}; +#endif /* CONFIG_PMAC_BACKLIGHT */ /* * Functions to read from/write to the mmio registers @@ -1712,15 +1725,8 @@ if (!mac_find_mode(&var, &info->fb_info, mode_option, 8)) var = default_var; } else { -#ifdef CONFIG_NVRAM - if (default_vmode == VMODE_NVRAM) - default_vmode = nvram_read_byte(NV_VMODE); - - if (default_cmode == CMODE_NVRAM) - default_cmode = nvram_read_byte(NV_CMODE); -#endif if (default_vmode <= 0 || default_vmode > VMODE_MAX) - default_vmode = VMODE_640_480_60; + default_vmode = VMODE_1024_768_60; if (default_cmode < CMODE_8 || default_cmode > CMODE_32) default_cmode = CMODE_8; @@ -1772,6 +1778,12 @@ if (register_framebuffer(&info->fb_info) < 0) return 0; +#ifdef CONFIG_PMAC_BACKLIGHT + /* Could be extended to Rage128Pro LVDS output too */ + if (info->chip_gen == rage_M3) + register_backlight_controller(&aty128_backlight_controller, info, "ati"); +#endif /* CONFIG_PMAC_BACKLIGHT */ + printk(KERN_INFO "fb%d: %s frame buffer device on %s\n", GET_FB_IDX(info->fb_info.node), aty128fb_name, name); @@ -1916,6 +1928,11 @@ } #endif /* CONFIG_MTRR */ +#ifdef CONFIG_FB_COMPAT_XPMAC + if (!console_fb_info) + console_fb_info = &info->fb_info; +#endif + return 0; err_out: @@ -2136,6 +2153,11 @@ struct fb_info_aty128 *info = (struct fb_info_aty128 *)fb; u8 state = 0; +#ifdef CONFIG_PMAC_BACKLIGHT + if ((_machine == _MACH_Pmac) && blank) + set_backlight_enable(0); +#endif /* CONFIG_PMAC_BACKLIGHT */ + if (blank & VESA_VSYNC_SUSPEND) state |= 2; if (blank & VESA_HSYNC_SUSPEND) @@ -2144,6 +2166,11 @@ state |= 4; aty_st_8(CRTC_EXT_CNTL+1, state); + +#ifdef CONFIG_PMAC_BACKLIGHT + if ((_machine == _MACH_Pmac) && !blank) + set_backlight_enable(1); +#endif /* CONFIG_PMAC_BACKLIGHT */ } @@ -2199,7 +2226,7 @@ int i; if (info->chip_gen == rage_M3) - aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & ~PALETTE_ACCESS_CNTL); + aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & ~DAC_PALETTE_ACCESS_CNTL); for (i=16; i<256; i++) { aty_st_8(PALETTE_INDEX, i); @@ -2208,7 +2235,7 @@ } if (info->chip_gen == rage_M3) { - aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | PALETTE_ACCESS_CNTL); + aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | DAC_PALETTE_ACCESS_CNTL); for (i=16; i<256; i++) { aty_st_8(PALETTE_INDEX, i); @@ -2221,7 +2248,7 @@ /* initialize palette */ if (info->chip_gen == rage_M3) - aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & ~PALETTE_ACCESS_CNTL); + aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & ~DAC_PALETTE_ACCESS_CNTL); if (info->current_par.crtc.bpp == 16) aty_st_8(PALETTE_INDEX, (regno << 3)); @@ -2230,7 +2257,7 @@ col = (red << 16) | (green << 8) | blue; aty_st_le32(PALETTE_DATA, col); if (info->chip_gen == rage_M3) { - aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | PALETTE_ACCESS_CNTL); + aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | DAC_PALETTE_ACCESS_CNTL); if (info->current_par.crtc.bpp == 16) aty_st_8(PALETTE_INDEX, (regno << 3)); else @@ -2282,6 +2309,38 @@ } } + +#ifdef CONFIG_PMAC_BACKLIGHT +static int backlight_conv[] = { + 0xff, 0xc0, 0xb5, 0xaa, 0x9f, 0x94, 0x89, 0x7e, + 0x73, 0x68, 0x5d, 0x52, 0x47, 0x3c, 0x31, 0x24 +}; + +static int +aty128_set_backlight_enable(int on, int level, void* data) +{ + struct fb_info_aty128 *info = (struct fb_info_aty128 *)data; + unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL); + + reg |= LVDS_BL_MOD_EN | LVDS_BLON; + if (on && level > BACKLIGHT_OFF) { + reg &= ~LVDS_BL_MOD_LEVEL_MASK; + reg |= (backlight_conv[level] << LVDS_BL_MOD_LEVEL_SHIFT); + } else { + reg &= ~LVDS_BL_MOD_LEVEL_MASK; + reg |= (backlight_conv[0] << LVDS_BL_MOD_LEVEL_SHIFT); + } + aty_st_le32(LVDS_GEN_CNTL, reg); + + return 0; +} + +static int +aty128_set_backlight_level(int level, void* data) +{ + return aty128_set_backlight_enable(1, level, data); +} +#endif /* CONFIG_PMAC_BACKLIGHT */ /* * Accelerated functions diff -u --recursive --new-file v2.4.0-test8/linux/drivers/video/atyfb.c linux/drivers/video/atyfb.c --- v2.4.0-test8/linux/drivers/video/atyfb.c Tue Aug 29 14:09:15 2000 +++ linux/drivers/video/atyfb.c Sun Sep 17 09:48:05 2000 @@ -20,6 +20,8 @@ * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive for * more details. + * + * Many thanks to Nitya from ATI devrel for support and patience ! */ /****************************************************************************** @@ -73,6 +75,10 @@ #ifdef CONFIG_NVRAM #include #endif +#ifdef CONFIG_PMAC_BACKLIGHT +#include +#endif + #ifdef __sparc__ #include #include @@ -286,6 +292,15 @@ static struct fb_info_aty* first_display = NULL; #endif +#ifdef CONFIG_PMAC_BACKLIGHT +static int aty_set_backlight_enable(int on, int level, void* data); +static int aty_set_backlight_level(int level, void* data); + +static struct backlight_controller aty_backlight_controller = { + aty_set_backlight_enable, + aty_set_backlight_level +}; +#endif /* CONFIG_PMAC_BACKLIGHT */ /* * Frame buffer device API @@ -556,6 +571,8 @@ { 0x4749, 0x4749, "3D RAGE PRO (BGA, PCI)" }, { 0x4750, 0x4750, "3D RAGE PRO (PQFP, PCI)" }, { 0x4751, 0x4751, "3D RAGE PRO (PQFP, PCI, limited 3D)" }, + { 0x4c4d, 0x4c4d, "3D RAGE Mobility (PCI)" }, + { 0x4c4e, 0x4c4e, "3D RAGE Mobility (AGP)" }, }; static const char *aty_gx_ram[8] __initdata = { @@ -567,48 +584,51 @@ }; -static inline u32 aty_ld_le32(unsigned int regindex, +static inline u32 aty_ld_le32(int regindex, const struct fb_info_aty *info) { -#if defined(__powerpc__) - unsigned long temp; - u32 val; + /* Hack for bloc 1, should be cleanly optimized by compiler */ + if (regindex >= 0x400) + regindex -= 0x800; - temp = info->ati_regbase; - asm volatile("lwbrx %0,%1,%2;eieio" : "=r"(val) : "b" (regindex), "r" (temp)); - return val; -#elif defined(__mc68000__) +#if defined(__mc68000__) return le32_to_cpu(*((volatile u32 *)(info->ati_regbase+regindex))); #else return readl (info->ati_regbase + regindex); #endif } -static inline void aty_st_le32(unsigned int regindex, u32 val, +static inline void aty_st_le32(int regindex, u32 val, const struct fb_info_aty *info) { -#if defined(__powerpc__) - unsigned long temp; + /* Hack for bloc 1, should be cleanly optimized by compiler */ + if (regindex >= 0x400) + regindex -= 0x800; - temp = info->ati_regbase; - asm volatile("stwbrx %0,%1,%2;eieio" : : "r" (val), "b" (regindex), "r" (temp) : - "memory"); -#elif defined(__mc68000__) +#if defined(__mc68000__) *((volatile u32 *)(info->ati_regbase+regindex)) = cpu_to_le32(val); #else writel (val, info->ati_regbase + regindex); #endif } -static inline u8 aty_ld_8(unsigned int regindex, +static inline u8 aty_ld_8(int regindex, const struct fb_info_aty *info) { + /* Hack for bloc 1, should be cleanly optimized by compiler */ + if (regindex >= 0x400) + regindex -= 0x800; + return readb (info->ati_regbase + regindex); } -static inline void aty_st_8(unsigned int regindex, u8 val, +static inline void aty_st_8(int regindex, u8 val, const struct fb_info_aty *info) { + /* Hack for bloc 1, should be cleanly optimized by compiler */ + if (regindex >= 0x400) + regindex -= 0x800; + writeb (val, info->ati_regbase + regindex); } @@ -675,6 +695,16 @@ BUS_FIFO_ERR_ACK, info); } +static void reset_GTC_3D_engine(const struct fb_info_aty *info) +{ + aty_st_le32(SCALE_3D_CNTL, 0xc0, info); + mdelay(GTC_3D_RESET_DELAY); + aty_st_le32(SETUP_CNTL, 0x00, info); + mdelay(GTC_3D_RESET_DELAY); + aty_st_le32(SCALE_3D_CNTL, 0x00, info); + mdelay(GTC_3D_RESET_DELAY); +} + static void init_engine(const struct atyfb_par *par, struct fb_info_aty *info) { u32 pitch_value; @@ -688,6 +718,13 @@ pitch_value = pitch_value * 3; } + /* On GTC (RagePro), we need to reset the 3D engine before */ + if (Gx == LB_CHIP_ID || Gx == LD_CHIP_ID || Gx == LI_CHIP_ID || + Gx == LP_CHIP_ID || Gx == GB_CHIP_ID || Gx == GD_CHIP_ID || + Gx == GI_CHIP_ID || Gx == GP_CHIP_ID || Gx == GQ_CHIP_ID || + Gx == LM_CHIP_ID || Gx == LN_CHIP_ID) + reset_GTC_3D_engine(info); + /* Reset engine, enable, and clear any engine errors */ reset_engine(info); /* Ensure that vga page pointers are set to zero - the upper */ @@ -2494,6 +2531,9 @@ } else if ((Gx == VT_CHIP_ID) || (Gx == VU_CHIP_ID)) { aty_st_le32(DAC_CNTL, 0x87010184, info); aty_st_le32(BUS_CNTL, 0x680000f9, info); + } else if ((Gx == LN_CHIP_ID) || (Gx == LM_CHIP_ID)) { + aty_st_le32(DAC_CNTL, 0x80010102, info); + aty_st_le32(BUS_CNTL, 0x7b33a040, info); } else { /* GT */ aty_st_le32(DAC_CNTL, 0x86010102, info); @@ -3375,6 +3415,10 @@ /* Rage LT */ pll = 230; mclk = 63; + } else if ((Gx == LN_CHIP_ID) || (Gx == LM_CHIP_ID)) { + /* Rage mobility M1 */ + pll = 230; + mclk = 50; } else { /* other RAGE */ pll = 135; @@ -3545,13 +3589,15 @@ info->fb_info.blank = &atyfbcon_blank; info->fb_info.flags = FBINFO_FLAG_DEFAULT; -#ifdef CONFIG_PPC +#ifdef CONFIG_PMAC_BACKLIGHT if (Gx == LI_CHIP_ID && machine_is_compatible("PowerBook1,1")) { /* these bits let the 101 powerbook wake up from sleep -- paulus */ aty_st_lcd(LCD_POWER_MANAGEMENT, aty_ld_lcd(LCD_POWER_MANAGEMENT, info) | (USE_F32KHZ | TRISTATE_MEM_EN), info); } -#endif /* CONFIG_PPC */ + if ((Gx == LN_CHIP_ID) || (Gx == LM_CHIP_ID)) + register_backlight_controller(&aty_backlight_controller, info, "ati"); +#endif /* CONFIG_PMAC_BACKLIGHT */ #ifdef MODULE var = default_var; @@ -3580,6 +3626,9 @@ default_vmode = VMODE_1024_768_60; else if (machine_is_compatible("iMac")) default_vmode = VMODE_1024_768_75; + else if (machine_is_compatible("PowerBook2,1")) + /* iBook with 800x600 LCD */ + default_vmode = VMODE_800_600_60; else default_vmode = VMODE_640_480_67; sense = read_aty_sense(info); @@ -4216,10 +4265,10 @@ struct fb_info_aty *info = (struct fb_info_aty *)fb; u8 gen_cntl; -#ifdef CONFIG_ADB_PMU +#ifdef CONFIG_PMAC_BACKLIGHT if ((_machine == _MACH_Pmac) && blank) - pmu_enable_backlight(0); -#endif + set_backlight_enable(0); +#endif /* CONFIG_PMAC_BACKLIGHT */ gen_cntl = aty_ld_8(CRTC_GEN_CNTL, info); if (blank > 0) @@ -4241,10 +4290,10 @@ gen_cntl &= ~(0x4c); aty_st_8(CRTC_GEN_CNTL, gen_cntl, info); -#ifdef CONFIG_ADB_PMU +#ifdef CONFIG_PMAC_BACKLIGHT if ((_machine == _MACH_Pmac) && !blank) - pmu_enable_backlight(1); -#endif + set_backlight_enable(1); +#endif /* CONFIG_PMAC_BACKLIGHT */ } @@ -4954,6 +5003,40 @@ return result; } #endif /* CONFIG_PMAC_PBOOK */ + +#ifdef CONFIG_PMAC_BACKLIGHT +static int backlight_conv[] = { + 0x00, 0x3f, 0x4c, 0x59, 0x66, 0x73, 0x80, 0x8d, + 0x9a, 0xa7, 0xb4, 0xc1, 0xcf, 0xdc, 0xe9, 0xff +}; + +static int +aty_set_backlight_enable(int on, int level, void* data) +{ + struct fb_info_aty *info = (struct fb_info_aty *)data; + unsigned int reg = aty_ld_lcd(LCD_MISC_CNTL, info); + + reg |= (BLMOD_EN | BIASMOD_EN); + if (on && level > BACKLIGHT_OFF) { + reg &= ~BIAS_MOD_LEVEL_MASK; + reg |= (backlight_conv[level] << BIAS_MOD_LEVEL_SHIFT); + } else { + reg &= ~BIAS_MOD_LEVEL_MASK; + reg |= (backlight_conv[0] << BIAS_MOD_LEVEL_SHIFT); + } + aty_st_lcd(LCD_MISC_CNTL, reg, info); + + return 0; +} + +static int +aty_set_backlight_level(int level, void* data) +{ + return aty_set_backlight_enable(1, level, data); +} + +#endif /* CONFIG_PMAC_BACKLIGHT */ + #ifdef MODULE int __init init_module(void) diff -u --recursive --new-file v2.4.0-test8/linux/drivers/video/chipsfb.c linux/drivers/video/chipsfb.c --- v2.4.0-test8/linux/drivers/video/chipsfb.c Fri Aug 4 18:06:34 2000 +++ linux/drivers/video/chipsfb.c Sun Sep 17 09:48:05 2000 @@ -35,6 +35,9 @@ #include #include #include +#ifdef CONFIG_PMAC_BACKLIGHT +#include +#endif #include #include @@ -245,7 +248,9 @@ // used to disable backlight only for blank > 1, but it seems // useful at blank = 1 too (saves battery, extends backlight life) if (blank) { - pmu_enable_backlight(0); +#ifdef CONFIG_PMAC_BACKLIGHT + set_backlight_enable(0); +#endif /* CONFIG_PMAC_BACKLIGHT */ /* get the palette from the chip */ for (i = 0; i < 256; ++i) { out_8(p->io_base + 0x3c7, i); @@ -262,7 +267,9 @@ out_8(p->io_base + 0x3c9, 0); } } else { - pmu_enable_backlight(1); +#ifdef CONFIG_PMAC_BACKLIGHT + set_backlight_enable(1); +#endif /* CONFIG_PMAC_BACKLIGHT */ for (i = 0; i < 256; ++i) { out_8(p->io_base + 0x3c8, i); udelay(1); @@ -673,8 +680,10 @@ /* Clear the entire framebuffer */ memset(p->frame_buffer, 0, 0x100000); +#ifdef CONFIG_PMAC_BACKLIGHT /* turn on the backlight */ - pmu_enable_backlight(1); + set_backlight_enable(1); +#endif /* CONFIG_PMAC_BACKLIGHT */ init_chips(p); } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/video/controlfb.c linux/drivers/video/controlfb.c --- v2.4.0-test8/linux/drivers/video/controlfb.c Fri Aug 4 18:06:34 2000 +++ linux/drivers/video/controlfb.c Sun Sep 17 09:48:05 2000 @@ -122,6 +122,8 @@ struct fb_info *info); static int control_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info); +static int control_mmap(struct fb_info *info, struct file *file, + struct vm_area_struct *vma); static int controlfb_getcolreg(u_int regno, u_int *red, u_int *green, @@ -171,6 +173,7 @@ fb_get_cmap: control_get_cmap, fb_set_cmap: control_set_cmap, fb_pan_display: control_pan_display, + fb_mmap: control_mmap, }; @@ -327,6 +330,48 @@ return 0; } +/* Private mmap since we want to have a different caching on the framebuffer + * for controlfb. + * Note there's no locking in here; it's done in fb_mmap() in fbmem.c. + */ +static int control_mmap(struct fb_info *info, struct file *file, + struct vm_area_struct *vma) +{ + struct fb_ops *fb = info->fbops; + struct fb_fix_screeninfo fix; + struct fb_var_screeninfo var; + unsigned long off, start; + u32 len; + + fb->fb_get_fix(&fix, PROC_CONSOLE(info), info); + off = vma->vm_pgoff << PAGE_SHIFT; + + /* frame buffer memory */ + start = fix.smem_start; + len = PAGE_ALIGN((start & ~PAGE_MASK)+fix.smem_len); + if (off >= len) { + /* memory mapped io */ + off -= len; + fb->fb_get_var(&var, PROC_CONSOLE(info), info); + if (var.accel_flags) + return -EINVAL; + start = fix.mmio_start; + len = PAGE_ALIGN((start & ~PAGE_MASK)+fix.mmio_len); + pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE|_PAGE_GUARDED; + } else { + /* framebuffer */ + pgprot_val(vma->vm_page_prot) |= _PAGE_WRITETHRU; + } + start &= PAGE_MASK; + vma->vm_pgoff = off >> PAGE_SHIFT; + if (io_remap_page_range(vma->vm_start, off, + vma->vm_end - vma->vm_start, vma->vm_page_prot)) + return -EAGAIN; + + return 0; +} + + /******************** End of controlfb_ops implementation ********************/ /* (new one that is) */ @@ -466,11 +511,6 @@ } } -#ifdef CONFIG_FB_COMPAT_XPMAC -extern struct vc_mode display_info; -extern struct fb_info *console_fb_info; -#endif /* CONFIG_FB_COMPAT_XPMAC */ - static inline int control_vram_reqd(int video_mode, int color_mode) { return (control_reg_init[video_mode-1]->vres @@ -483,12 +523,14 @@ struct adb_request req; int i; +#ifdef CONFIG_ADB_CUDA for (i = 0; i < 3; ++i) { cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC, 0x50, i + 1, params[i]); while (!req.complete) cuda_poll(); } +#endif } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/video/cyber2000fb.c linux/drivers/video/cyber2000fb.c --- v2.4.0-test8/linux/drivers/video/cyber2000fb.c Sun Aug 6 11:25:46 2000 +++ linux/drivers/video/cyber2000fb.c Mon Sep 18 15:15:22 2000 @@ -1,7 +1,11 @@ /* - * Linux/drivers/video/cyber2000fb.c + * linux/drivers/video/cyber2000fb.c * - * Copyright (C) 1998-2000 Russell King + * Copyright (C) 1998-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. * * Integraphics CyberPro 2000, 2010 and 5000 frame buffer device * @@ -268,9 +272,9 @@ if (regno >= NR_PALETTE) return 1; - red >>= 10; - green >>= 10; - blue >>= 10; + red >>= 8; + green >>= 8; + blue >>= 8; cfb->palette[regno].red = red; cfb->palette[regno].green = green; @@ -706,6 +710,7 @@ int err; hw->width = var->xres_virtual; + hw->palette_ctrl = 0x06; switch (var->bits_per_pixel) { #ifdef FBCON_HAS_CFB8 @@ -713,7 +718,6 @@ hw->pixformat = PIXFORMAT_8BPP; hw->visualid = VISUALID_256; hw->pitch = hw->width >> 3; - hw->palette_ctrl = 0x04; break; #endif #ifdef FBCON_HAS_CFB16 @@ -722,14 +726,14 @@ hw->pixformat = PIXFORMAT_16BPP; hw->visualid = VISUALID_64K; hw->pitch = hw->width >> 2; - hw->palette_ctrl = 0x14; + hw->palette_ctrl |= 0x10; break; #endif case 15:/* DIRECTCOLOUR, 32k */ hw->pixformat = PIXFORMAT_16BPP; hw->visualid = VISUALID_32K; hw->pitch = hw->width >> 2; - hw->palette_ctrl = 0x14; + hw->palette_ctrl |= 0x10; break; #endif @@ -739,7 +743,7 @@ hw->visualid = VISUALID_16M; hw->width *= 3; hw->pitch = hw->width >> 3; - hw->palette_ctrl = 0x14; + hw->palette_ctrl |= 0x10; break; #endif default: diff -u --recursive --new-file v2.4.0-test8/linux/drivers/video/cyber2000fb.h linux/drivers/video/cyber2000fb.h --- v2.4.0-test8/linux/drivers/video/cyber2000fb.h Tue Jun 20 14:14:51 2000 +++ linux/drivers/video/cyber2000fb.h Mon Sep 18 15:15:22 2000 @@ -1,5 +1,11 @@ /* - * linux/drivers/video/cyber2000fb.h + * linux/drivers/video/cyber2000fb.h + * + * Copyright (C) 1998-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. * * Integraphics Cyber2000 frame buffer device */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/video/fbcon.c linux/drivers/video/fbcon.c --- v2.4.0-test8/linux/drivers/video/fbcon.c Mon Jul 24 18:24:26 2000 +++ linux/drivers/video/fbcon.c Sun Oct 1 20:35:16 2000 @@ -143,7 +143,7 @@ * if dispsw->cursor is NULL, use Atari alike software cursor */ -static int cursor_drawn = 0; +static int cursor_drawn; #define CURSOR_DRAW_DELAY (1) @@ -154,8 +154,8 @@ #define MAC_CURSOR_BLINK_RATE (32) #define DEFAULT_CURSOR_BLINK_RATE (20) -static int vbl_cursor_cnt = 0; -static int cursor_on = 0; +static int vbl_cursor_cnt; +static int cursor_on; static int cursor_blink_rate; static inline void cursor_undrawn(void) @@ -218,7 +218,7 @@ /* * On the Macintoy, there may or may not be a working VBL int. We need to probe */ -static int vbl_detected = 0; +static int vbl_detected; static void fbcon_vbl_detect(int irq, void *dummy, struct pt_regs *fp) { diff -u --recursive --new-file v2.4.0-test8/linux/drivers/video/fbmem.c linux/drivers/video/fbmem.c --- v2.4.0-test8/linux/drivers/video/fbmem.c Sun Aug 6 11:25:46 2000 +++ linux/drivers/video/fbmem.c Sun Oct 1 20:35:16 2000 @@ -286,10 +286,10 @@ struct fb_info *registered_fb[FB_MAX]; -int num_registered_fb = 0; +int num_registered_fb; extern int fbcon_softback_size; -static int first_fb_vc = 0; +static int first_fb_vc; static int last_fb_vc = MAX_NR_CONSOLES-1; static int fbcon_is_default = 1; diff -u --recursive --new-file v2.4.0-test8/linux/drivers/video/matrox/matroxfb_base.c linux/drivers/video/matrox/matroxfb_base.c --- v2.4.0-test8/linux/drivers/video/matrox/matroxfb_base.c Tue Aug 29 14:09:15 2000 +++ linux/drivers/video/matrox/matroxfb_base.c Sun Oct 1 20:35:16 2000 @@ -1286,43 +1286,43 @@ }; /* initialized by setup, see explanation at end of file (search for MODULE_PARM_DESC) */ -static unsigned int mem = 0; /* "matrox:mem:xxxxxM" */ +static unsigned int mem; /* "matrox:mem:xxxxxM" */ static int option_precise_width = 1; /* cannot be changed, option_precise_width==0 must imply noaccel */ -static int inv24 = 0; /* "matrox:inv24" */ +static int inv24; /* "matrox:inv24" */ static int cross4MB = -1; /* "matrox:cross4MB" */ -static int disabled = 0; /* "matrox:disabled" */ -static int noaccel = 0; /* "matrox:noaccel" */ -static int nopan = 0; /* "matrox:nopan" */ -static int no_pci_retry = 0; /* "matrox:nopciretry" */ -static int novga = 0; /* "matrox:novga" */ -static int nobios = 0; /* "matrox:nobios" */ +static int disabled; /* "matrox:disabled" */ +static int noaccel; /* "matrox:noaccel" */ +static int nopan; /* "matrox:nopan" */ +static int no_pci_retry; /* "matrox:nopciretry" */ +static int novga; /* "matrox:novga" */ +static int nobios; /* "matrox:nobios" */ static int noinit = 1; /* "matrox:init" */ -static int inverse = 0; /* "matrox:inverse" */ +static int inverse; /* "matrox:inverse" */ static int hwcursor = 1; /* "matrox:nohwcursor" */ static int blink = 1; /* "matrox:noblink" */ -static int sgram = 0; /* "matrox:sgram" */ +static int sgram; /* "matrox:sgram" */ #ifdef CONFIG_MTRR static int mtrr = 1; /* "matrox:nomtrr" */ #endif -static int grayscale = 0; /* "matrox:grayscale" */ -static unsigned int fastfont = 0; /* "matrox:fastfont:xxxxx" */ +static int grayscale; /* "matrox:grayscale" */ +static unsigned int fastfont; /* "matrox:fastfont:xxxxx" */ static int dev = -1; /* "matrox:dev:xxxxx" */ static unsigned int vesa = ~0; /* "matrox:vesa:xxxxx" */ static int depth = -1; /* "matrox:depth:xxxxx" */ -static unsigned int xres = 0; /* "matrox:xres:xxxxx" */ -static unsigned int yres = 0; /* "matrox:yres:xxxxx" */ +static unsigned int xres; /* "matrox:xres:xxxxx" */ +static unsigned int yres; /* "matrox:yres:xxxxx" */ static unsigned int upper = ~0; /* "matrox:upper:xxxxx" */ static unsigned int lower = ~0; /* "matrox:lower:xxxxx" */ -static unsigned int vslen = 0; /* "matrox:vslen:xxxxx" */ +static unsigned int vslen; /* "matrox:vslen:xxxxx" */ static unsigned int left = ~0; /* "matrox:left:xxxxx" */ static unsigned int right = ~0; /* "matrox:right:xxxxx" */ -static unsigned int hslen = 0; /* "matrox:hslen:xxxxx" */ -static unsigned int pixclock = 0; /* "matrox:pixclock:xxxxx" */ +static unsigned int hslen; /* "matrox:hslen:xxxxx" */ +static unsigned int pixclock; /* "matrox:pixclock:xxxxx" */ static int sync = -1; /* "matrox:sync:xxxxx" */ -static unsigned int fv = 0; /* "matrox:fv:xxxxx" */ -static unsigned int fh = 0; /* "matrox:fh:xxxxxk" */ -static unsigned int maxclk = 0; /* "matrox:maxclk:xxxxM" */ -static int dfp = 0; /* "matrox:dfp */ +static unsigned int fv; /* "matrox:fv:xxxxx" */ +static unsigned int fh; /* "matrox:fh:xxxxxk" */ +static unsigned int maxclk; /* "matrox:maxclk:xxxxM" */ +static int dfp; /* "matrox:dfp */ static int memtype = -1; /* "matrox:memtype:xxx" */ static char fontname[64]; /* "matrox:font:xxxxx" */ diff -u --recursive --new-file v2.4.0-test8/linux/drivers/video/offb.c linux/drivers/video/offb.c --- v2.4.0-test8/linux/drivers/video/offb.c Fri Aug 4 18:06:34 2000 +++ linux/drivers/video/offb.c Sun Sep 17 09:48:05 2000 @@ -43,6 +43,15 @@ static int currcon = 0; +/* Supported palette hacks */ +enum { + cmap_unknown, + cmap_m64, /* ATI Mach64 */ + cmap_r128, /* ATI Rage128 */ + cmap_M3A, /* ATI Rage Mobility M3 Head A */ + cmap_M3B /* ATI Rage Mobility M3 Head B */ +}; + struct fb_info_offb { struct fb_info info; struct fb_fix_screeninfo fix; @@ -51,7 +60,7 @@ struct { u_char red, green, blue, pad; } palette[256]; volatile unsigned char *cmap_adr; volatile unsigned char *cmap_data; - int is_rage_128; + int cmap_type; union { #ifdef FBCON_HAS_CFB16 u16 cfb16[16]; @@ -408,21 +417,27 @@ fix->type = FB_TYPE_PACKED_PIXELS; fix->type_aux = 0; - info->is_rage_128 = 0; + info->cmap_type = cmap_unknown; if (depth == 8) { /* XXX kludge for ati */ - if (strncmp(name, "ATY,Rage128", 11) == 0) { - if (dp) { + if (dp && !strncmp(name, "ATY,Rage128", 11)) { unsigned long regbase = dp->addrs[2].address; - info->cmap_adr = ioremap(regbase, 0x1FFF) + 0x00b0; - info->cmap_data = info->cmap_adr + 4; - info->is_rage_128 = 1; - } - } else if (strncmp(name, "ATY,", 4) == 0) { + info->cmap_adr = ioremap(regbase, 0x1FFF); + info->cmap_type = cmap_r128; + } else if (dp && !strncmp(name, "ATY,RageM3pA", 12)) { + unsigned long regbase = dp->parent->addrs[2].address; + info->cmap_adr = ioremap(regbase, 0x1FFF); + info->cmap_type = cmap_M3A; + } else if (dp && !strncmp(name, "ATY,RageM3pB", 12)) { + unsigned long regbase = dp->parent->addrs[2].address; + info->cmap_adr = ioremap(regbase, 0x1FFF); + info->cmap_type = cmap_M3B; + } else if (!strncmp(name, "ATY,", 4)) { unsigned long base = address & 0xff000000UL; info->cmap_adr = ioremap(base + 0x7ff000, 0x1000) + 0xcc0; info->cmap_data = info->cmap_adr + 1; + info->cmap_type = cmap_m64; } fix->visual = info->cmap_adr ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_STATIC_PSEUDOCOLOR; @@ -580,7 +595,7 @@ display_info.cmap_data_address = 0; display_info.disp_reg_address = 0; /* XXX kludge for ati */ - if (strncmp(name, "ATY,", 4) == 0) { + if (info->cmap_type == cmap_m64) { unsigned long base = address & 0xff000000UL; display_info.disp_reg_address = base + 0x7ffc00; display_info.cmap_adr_address = base + 0x7ffcc0; @@ -628,11 +643,32 @@ if (blank) for (i = 0; i < 256; i++) { - *info2->cmap_adr = i; - mach_eieio(); - for (j = 0; j < 3; j++) { - *info2->cmap_data = 0; - mach_eieio(); + switch(info2->cmap_type) { + case cmap_m64: + *info2->cmap_adr = i; + mach_eieio(); + for (j = 0; j < 3; j++) { + *info2->cmap_data = 0; + mach_eieio(); + } + break; + case cmap_M3A: + /* Clear PALETTE_ACCESS_CNTL in DAC_CNTL */ + out_le32((unsigned *)(info2->cmap_adr + 0x58), + in_le32((unsigned *)(info2->cmap_adr + 0x58)) & ~0x20); + case cmap_r128: + /* Set palette index & data */ + out_8(info2->cmap_adr + 0xb0, i); + out_le32((unsigned *)(info2->cmap_adr + 0xb4), 0); + break; + case cmap_M3B: + /* Set PALETTE_ACCESS_CNTL in DAC_CNTL */ + out_le32((unsigned *)(info2->cmap_adr + 0x58), + in_le32((unsigned *)(info2->cmap_adr + 0x58)) | 0x20); + /* Set palette index & data */ + out_8(info2->cmap_adr + 0xb0, i); + out_le32((unsigned *)(info2->cmap_adr + 0xb4), 0); + break; } } else @@ -682,18 +718,36 @@ info2->palette[regno].green = green; info2->palette[regno].blue = blue; - *info2->cmap_adr = regno;/* On some chipsets, add << 3 in 15 bits */ - mach_eieio(); - if (info2->is_rage_128) { - out_le32((unsigned int *)info2->cmap_data, - (red << 16 | green << 8 | blue)); - } else { + switch(info2->cmap_type) { + case cmap_m64: + *info2->cmap_adr = regno; + mach_eieio(); *info2->cmap_data = red; - mach_eieio(); - *info2->cmap_data = green; - mach_eieio(); - *info2->cmap_data = blue; - mach_eieio(); + mach_eieio(); + *info2->cmap_data = green; + mach_eieio(); + *info2->cmap_data = blue; + mach_eieio(); + break; + case cmap_M3A: + /* Clear PALETTE_ACCESS_CNTL in DAC_CNTL */ + out_le32((unsigned *)(info2->cmap_adr + 0x58), + in_le32((unsigned *)(info2->cmap_adr + 0x58)) & ~0x20); + case cmap_r128: + /* Set palette index & data */ + out_8(info2->cmap_adr + 0xb0, regno); + out_le32((unsigned *)(info2->cmap_adr + 0xb4), + (red << 16 | green << 8 | blue)); + break; + case cmap_M3B: + /* Set PALETTE_ACCESS_CNTL in DAC_CNTL */ + out_le32((unsigned *)(info2->cmap_adr + 0x58), + in_le32((unsigned *)(info2->cmap_adr + 0x58)) | 0x20); + /* Set palette index & data */ + out_8(info2->cmap_adr + 0xb0, regno); + out_le32((unsigned *)(info2->cmap_adr + 0xb4), + (red << 16 | green << 8 | blue)); + break; } if (regno < 16) diff -u --recursive --new-file v2.4.0-test8/linux/drivers/video/riva/fbdev.c linux/drivers/video/riva/fbdev.c --- v2.4.0-test8/linux/drivers/video/riva/fbdev.c Mon Jul 31 11:21:37 2000 +++ linux/drivers/video/riva/fbdev.c Mon Sep 18 14:57:01 2000 @@ -582,7 +582,7 @@ riva_boards = riva_board_list_add(riva_boards, rinfo); - pd->driver_data = rinfo; + pci_set_drvdata (pd, rinfo); printk ("PCI Riva NV%d framebuffer ver %s (%s, %dMB @ 0x%lX)\n", rinfo->riva.Architecture, @@ -610,7 +610,7 @@ static void __devexit rivafb_remove_one (struct pci_dev *pd) { - struct rivafb_info *board = pd->driver_data; + struct rivafb_info *board = pci_get_drvdata (pd); if (!board) return; @@ -630,6 +630,8 @@ board->base1_region_size); kfree (board); + + pci_set_drvdata (pd, NULL); } diff -u --recursive --new-file v2.4.0-test8/linux/drivers/video/sa1100fb.c linux/drivers/video/sa1100fb.c --- v2.4.0-test8/linux/drivers/video/sa1100fb.c Sun Aug 13 09:54:15 2000 +++ linux/drivers/video/sa1100fb.c Mon Sep 18 15:15:22 2000 @@ -43,7 +43,17 @@ * * 2000/08/09: * XP860 support added - * Kunihiko IMAI + * Kunihiko IMAI + * + * 2000/08/19: + * Allows standard options to be passed on the kernel command line + * for most common passive displays. + * Mark Huang + * + * 2000/08/29: + * s/save_flags_cli/local_irq_save/ + * remove unneeded extra save_flags_cli in + * sa1100fb_enable_lcd_controller */ #include @@ -164,6 +174,7 @@ /* Shadows for LCD controller registers */ struct sa1100fb_lcd_reg { Address dbar1; + Address dbar2; Word lccr0; Word lccr1; Word lccr2; @@ -667,6 +678,16 @@ init_var.grayscale = 0; init_var.sync = 0; init_var.pixclock = 171521; + } else if (machine_is_cerf()) { + current_par.max_xres = 320; + current_par.max_yres = 240; + current_par.max_bpp = 8; + init_var.red.length = 4; + init_var.green.length = 4; + init_var.blue.length = 4; + init_var.grayscale = 0; + init_var.sync = 0; + init_var.pixclock = 171521; } else if (machine_is_bitsy()) { current_par.max_xres = 320; current_par.max_yres = 240; @@ -784,8 +805,8 @@ u_int required_pages; u_int extra_pages; u_int order; + struct page *page; char *allocated_region; - struct page *page; if (VideoMemRegion != NULL) return -EINVAL; @@ -885,10 +906,11 @@ DPRINTK("activating\n"); /* Disable interrupts and save status */ - save_flags_cli(flags); // disable the interrupts and save flags + local_irq_save(flags); // disable the interrupts and save flags /* Reset the LCD Controller's DMA address if it has changed */ lcd_shadow.dbar1 = (Address)current_par.p_palette_base; + lcd_shadow.dbar2 = (Address)(current_par.p_screen_base + (current_par.xres * current_par.yres * current_par.bits_per_pixel / 8 / 2)); DPRINTK("Configuring xres = %d, yres = %d\n",var->xres, var->yres); @@ -945,6 +967,22 @@ LCCR3_OutEnH + LCCR3_PixFlEdg + LCCR3_VrtSnchH + LCCR3_HorSnchH + LCCR3_ACBsCntOff + LCCR3_ACBsDiv(2) + LCCR3_PixClkDiv(44); + } else if (machine_is_cerf()) { + DPRINTK("Configuring Cerf LCD\n"); + lcd_shadow.lccr0 = + LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + + LCCR0_LDM + LCCR0_BAM + LCCR0_ERM + LCCR0_Pas + + LCCR0_LtlEnd + LCCR0_DMADel(0); + lcd_shadow.lccr1 = + LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(6) + + LCCR1_BegLnDel(61) + LCCR1_EndLnDel(9); + lcd_shadow.lccr2 = + LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(1) + + LCCR2_BegFrmDel(3) + LCCR2_EndFrmDel(0); + lcd_shadow.lccr3 = + LCCR3_OutEnH + LCCR3_PixFlEdg + LCCR3_VrtSnchH + + LCCR3_HorSnchH + LCCR3_ACBsCntOff + + LCCR3_ACBsDiv(2) + LCCR3_PixClkDiv(38); } else if (machine_is_lart()) { DPRINTK("Configuring LART LCD\n"); lcd_shadow.lccr0 = @@ -1034,13 +1072,14 @@ } /* Restore interrupt status */ - restore_flags(flags); + local_irq_restore(flags); if (( LCCR0 != lcd_shadow.lccr0 ) || ( LCCR1 != lcd_shadow.lccr1 ) || ( LCCR2 != lcd_shadow.lccr2 ) || ( LCCR3 != lcd_shadow.lccr3 ) || - ( DBAR1 != lcd_shadow.dbar1 )) + ( DBAR1 != lcd_shadow.dbar1 ) || + ( DBAR2 != lcd_shadow.dbar2 )) { sa1100fb_enable_lcd_controller(); } @@ -1064,6 +1103,27 @@ if (controller_state == LCD_MODE_DISABLE_BEFORE_ENABLE) { DPRINTK("sa1100fb_inter_handler: re-enabling LCD controller\n"); sa1100fb_enable_lcd_controller(); + } else { + /* + * Second half of sa1100fb_disable_lcd_controller() + */ + if (machine_is_assabet()) { +#ifdef CONFIG_SA1100_ASSABET + BCR_clear(BCR_LCD_ON); +#endif + } else if (machine_is_bitsy()) { +#ifdef CONFIG_SA1100_BITSY + if (current_par.controller_state != LCD_MODE_DISABLE_BEFORE_ENABLE) + clr_bitsy_egpio(EGPIO_BITSY_LCD_ON | EGPIO_BITSY_LCD_PCI | EGPIO_BITSY_LCD_5V_ON | EGPIO_BITSY_LVDD_ON); +#endif + } else if (machine_is_penny()) { +#ifdef CONFIG_SA1100_PENNY + FpgaLcdCS1 = 0x000; /* LCD Backlight to 0% */ + FpgaPortI &= ~LCD_ON; /* Turn off LCD Backlight */ +#endif + } else if (machine_is_tifon()) { + GPCR = GPIO_GPIO(24); /* turn off display */ + } } } LCSR = 0; /* Clear LCD Status Register */ @@ -1087,29 +1147,10 @@ return; } - if (machine_is_assabet()) { -#ifdef CONFIG_SA1100_ASSABET - BCR_clear(BCR_LCD_ON); -#endif - } else if (machine_is_bitsy()) { -#ifdef CONFIG_SA1100_BITSY - if (current_par.controller_state != LCD_MODE_DISABLE_BEFORE_ENABLE) - clr_bitsy_egpio(EGPIO_BITSY_LCD_ON | EGPIO_BITSY_LCD_PCI | EGPIO_BITSY_LCD_5V_ON | EGPIO_BITSY_LVDD_ON); -#endif - } else if (machine_is_penny()) { -#ifdef CONFIG_SA1100_PENNY - FpgaLcdCS1 = 0x000; /* LCD Backlight to 0% */ - FpgaPortI &= ~LCD_ON; /* Turn off LCD Backlight */ -#endif - } else if (machine_is_tifon()) { - GPCR = GPIO_GPIO(24); /* turn off display */ - } - LCSR = 0; /* Clear LCD Status Register */ LCCR0 &= ~(LCCR0_LDM); /* Enable LCD Disable Done Interrupt */ enable_irq(IRQ_LCD); /* Enable LCD IRQ */ LCCR0 &= ~(LCCR0_LEN); /* Disable LCD Controller */ - } /* @@ -1122,7 +1163,7 @@ { u_long flags; - save_flags_cli(flags); + local_irq_save(flags); /* Disable controller before changing parameters */ if (current_par.controller_state == LCD_MODE_ENABLED) { @@ -1135,14 +1176,20 @@ current_par.v_palette_base[0] &= 0x0FFF; current_par.v_palette_base[0] |= SA1100_PALETTE_MODE_VAL(current_par.bits_per_pixel); - /* disable the interrupts and save flags */ - save_flags_cli(flags); + /* Enable GPIO<9:2> for LCD usage if dual-scan */ + if (lcd_shadow.lccr0 & LCCR0_SDS) { + GPDR |= 0x3fc; + GAFR |= 0x3fc; + } - DBAR1 = lcd_shadow.dbar1; + /* Sequence from 11.7.10 */ LCCR3 = lcd_shadow.lccr3; LCCR2 = lcd_shadow.lccr2; LCCR1 = lcd_shadow.lccr1; - LCCR0 = lcd_shadow.lccr0; + LCCR0 = lcd_shadow.lccr0 & ~LCCR0_LEN; + DBAR1 = lcd_shadow.dbar1; + DBAR2 = lcd_shadow.dbar2; + LCCR0 |= LCCR0_LEN; if (machine_is_assabet()) { #ifdef CONFIG_SA1100_ASSABET @@ -1172,7 +1219,7 @@ } /* Restore interrupt status */ - restore_flags(flags); + local_irq_restore(flags); } /* @@ -1263,6 +1310,9 @@ } else if (machine_is_bitsy()) { GPDR = (GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12 | GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9 | GPIO_LDD8); GAFR |= (GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12 | GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9 | GPIO_LDD8); + } else if (machine_is_cerf()) { + GPDR |= 0x3fc; + GAFR |= 0x3fc; } else if (machine_is_penny()) { #ifdef CONFIG_SA1100_PENNY GPDR |= GPIO_GPDR_GFX; /* GPIO Data Direction register for LCD data bits 8-11 */ @@ -1286,3 +1336,35 @@ return 0; } + +int __init sa1100fb_setup(char *options) +{ + char *this_opt; + + if (!options || !*options) + return 0; + + for (this_opt = strtok(options, ","); this_opt; + this_opt = strtok(NULL, ",")) { + + if (!strncmp(this_opt, "bpp:", 4)) + current_par.max_bpp = simple_strtoul(this_opt+4, NULL, 0); + + if (!strncmp(this_opt, "lccr0:", 6)) + lcd_shadow.lccr0 = simple_strtoul(this_opt+6, NULL, 0); + if (!strncmp(this_opt, "lccr1:", 6)) { + lcd_shadow.lccr1 = simple_strtoul(this_opt+6, NULL, 0); + current_par.max_xres = (lcd_shadow.lccr1 & 0x3ff) + 16; + } + if (!strncmp(this_opt, "lccr2:", 6)) { + lcd_shadow.lccr2 = simple_strtoul(this_opt+6, NULL, 0); + current_par.max_yres = (lcd_shadow.lccr0 & LCCR0_SDS) ? + ((lcd_shadow.lccr2 & 0x3ff) + 1) * 2 : + ((lcd_shadow.lccr2 & 0x3ff) + 1); + } + if (!strncmp(this_opt, "lccr3:", 6)) + lcd_shadow.lccr3 = simple_strtoul(this_opt+6, NULL, 0); + } + return 0; +} + diff -u --recursive --new-file v2.4.0-test8/linux/drivers/video/sisfb.c linux/drivers/video/sisfb.c --- v2.4.0-test8/linux/drivers/video/sisfb.c Mon Aug 28 21:25:25 2000 +++ linux/drivers/video/sisfb.c Mon Sep 18 14:57:01 2000 @@ -356,8 +356,6 @@ 0x0B, 0x0C, 0x0D, 0x0F, 0x10 }; -#ifdef CONFIG_FB_SIS_LINUXBIOS - #define Monitor1Sense 0x20 unsigned char SRegsInit[] = { @@ -371,6 +369,8 @@ 0x8e, 0x40, 0x00, 0x00, 0x08, 0x00, 0xff, 0xff }; +#ifdef CONFIG_FB_SIS_LINUXBIOS + unsigned char SRegs[] = { 0x03, 0x01, 0x0F, 0x00, 0x0E, 0xA1, 0x02, 0x13, 0x3F, 0x86, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, @@ -1440,7 +1440,6 @@ static u16 get_modeID_length(unsigned long ROMAddr, u16 ModeNo) { - unsigned char ModeID; u16 modeidlength; u16 usModeIDOffset; unsigned short PreviousWord,CurrentWord; @@ -2804,7 +2803,6 @@ u16 cr30flag, cr31flag; unsigned long ROMAddr = rom_vbase; u16 BaseAddr = (u16) ivideo.vga_base; - u_short i; P3c4 = BaseAddr + 0x14; P3d4 = BaseAddr + 0x24; @@ -3420,7 +3418,6 @@ struct board *b; int pdev_valid = 0; unsigned char jTemp; - u32 cmd; outb(0x77, 0x80); @@ -3448,10 +3445,8 @@ return -1; #ifdef CONFIG_FB_SIS_LINUXBIOS - pci_read_config_dword(pdev, PCI_COMMAND, &cmd); - cmd |= PCI_COMMAND_IO; - cmd |= PCI_COMMAND_MEMORY; - pci_write_config_dword(pdev, PCI_COMMAND, cmd); + if (pci_enable_device(pdev)) + return -EIO; #endif ivideo.video_base = pci_resource_start(pdev, 0); diff -u --recursive --new-file v2.4.0-test8/linux/drivers/video/valkyriefb.c linux/drivers/video/valkyriefb.c --- v2.4.0-test8/linux/drivers/video/valkyriefb.c Fri Aug 4 18:06:34 2000 +++ linux/drivers/video/valkyriefb.c Sun Sep 17 09:48:05 2000 @@ -425,12 +425,14 @@ struct adb_request req; int i; +#ifdef CONFIG_ADB_CUDA for (i = 0; i < 3; ++i) { cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC, 0x50, i + 1, params[i]); while (!req.complete) cuda_poll(); } +#endif } static void __init init_valkyrie(struct fb_info_valkyrie *p) diff -u --recursive --new-file v2.4.0-test8/linux/fs/Config.in linux/fs/Config.in --- v2.4.0-test8/linux/fs/Config.in Mon Aug 14 13:31:10 2000 +++ linux/fs/Config.in Mon Sep 25 13:14:53 2000 @@ -76,7 +76,7 @@ dep_tristate 'Coda file system support (advanced network fs)' CONFIG_CODA_FS $CONFIG_INET dep_tristate 'NFS file system support' CONFIG_NFS_FS $CONFIG_INET - dep_mbool ' Provide NFSv3 client support (EXPERIMENTAL)' CONFIG_NFS_V3 $CONFIG_NFS_FS + dep_mbool ' Provide NFSv3 client support' CONFIG_NFS_V3 $CONFIG_NFS_FS dep_bool ' Root file system on NFS' CONFIG_ROOT_NFS $CONFIG_NFS_FS $CONFIG_IP_PNP dep_tristate 'NFS server support' CONFIG_NFSD $CONFIG_INET @@ -100,8 +100,11 @@ dep_tristate 'SMB file system support (to mount Windows shares etc.)' CONFIG_SMB_FS $CONFIG_INET if [ "$CONFIG_SMB_FS" != "n" ]; then - string 'Default Remote NLS Option' CONFIG_SMB_NLS_REMOTE "" - fi + bool ' Use a default NLS' CONFIG_SMB_NLS_DEFAULT + if [ "$CONFIG_SMB_NLS_DEFAULT" = "y" ]; then + string ' Default Remote NLS Option' CONFIG_SMB_NLS_REMOTE "cp437" + fi + fi if [ "$CONFIG_IPX" != "n" -o "$CONFIG_INET" != "n" ]; then tristate 'NCP file system support (to mount NetWare volumes)' CONFIG_NCP_FS source fs/ncpfs/Config.in diff -u --recursive --new-file v2.4.0-test8/linux/fs/Makefile linux/fs/Makefile --- v2.4.0-test8/linux/fs/Makefile Mon Aug 28 21:27:39 2000 +++ linux/fs/Makefile Mon Oct 2 11:54:11 2000 @@ -1,348 +1,91 @@ # # Makefile for the Linux filesystems. # -# Note! Dependencies are done automagically by 'make dep', which also -# removes any old dependencies. DON'T put your own dependencies here -# unless it's something special (not a .c file). -# -# Note 2! The CFLAGS definitions are now in the main makefile. +# 14 Sep 2000, Christoph Hellwig +# Rewritten to use lists instead of if-statements. +# -FILESYSTEMS = $(join $(SUB_DIRS),$(SUB_DIRS:%=/%.o)) O_TARGET := fs.o -O_OBJS = open.o read_write.o devices.o file_table.o buffer.o \ + +export-objs := filesystems.o +mod-subdirs := nls + +obj-y := open.o read_write.o devices.o file_table.o buffer.o \ super.o block_dev.o stat.o exec.o pipe.o namei.o fcntl.o \ ioctl.o readdir.o select.o fifo.o locks.o \ - dcache.o inode.o attr.o bad_inode.o file.o iobuf.o \ - $(BINFMTS) $(FILESYSTEMS) -OX_OBJS := filesystems.o - -ALL_SUB_DIRS := coda minix ext2 fat msdos vfat proc isofs nfs umsdos ntfs \ - hpfs sysv smbfs ncpfs ufs efs affs romfs autofs hfs lockd \ - nfsd nls devpts devfs adfs partitions qnx4 udf bfs cramfs \ - openpromfs autofs4 ramfs jffs - -SUB_DIRS := + dcache.o inode.o attr.o bad_inode.o file.o iobuf.o dnotify.o \ + filesystems.o ifeq ($(CONFIG_QUOTA),y) -O_OBJS += dquot.o +obj-y += dquot.o else -O_OBJS += noquot.o -endif - -ifdef CONFIG_PROC_FS -SUB_DIRS += proc +obj-y += noquot.o endif -SUB_DIRS += partitions +subdir-$(CONFIG_PROC_FS) += proc +subdir-y += partitions # Do not add any filesystems before this line +subdir-$(CONFIG_EXT2_FS) += ext2 +subdir-$(CONFIG_CRAMFS) += cramfs +subdir-$(CONFIG_RAMFS) += ramfs +subdir-$(CONFIG_CODA_FS) += coda +subdir-$(CONFIG_MINIX_FS) += minix +subdir-$(CONFIG_FAT_FS) += fat +subdir-$(CONFIG_MSDOS_FS) += msdos +subdir-$(CONFIG_VFAT_FS) += vfat +subdir-$(CONFIG_BFS_FS) += bfs +subdir-$(CONFIG_ISO9660_FS) += isofs +subdir-$(CONFIG_DEVFS_FS) += devfs +subdir-$(CONFIG_HFS_FS) += hfs +subdir-$(CONFIG_NFS_FS) += nfs +subdir-$(CONFIG_NFSD) += nfsd +subdir-$(CONFIG_LOCKD) += lockd +subdir-$(CONFIG_NLS) += nls +subdir-$(CONFIG_UMSDOS_FS) += umsdos +subdir-$(CONFIG_SYSV_FS) += sysv +subdir-$(CONFIG_SMB_FS) += smbfs +subdir-$(CONFIG_NCP_FS) += ncpfs +subdir-$(CONFIG_HPFS_FS) += hpfs +subdir-$(CONFIG_NTFS_FS) += ntfs +subdir-$(CONFIG_UFS_FS) += ufs +subdir-$(CONFIG_EFS_FS) += efs +subdir-$(CONFIG_JFFS_FS) += jffs +subdir-$(CONFIG_AFFS_FS) += affs +subdir-$(CONFIG_ROMFS_FS) += romfs +subdir-$(CONFIG_QNX4FS_FS) += qnx4 +subdir-$(CONFIG_UDF_FS) += udf +subdir-$(CONFIG_AUTOFS_FS) += autofs +subdir-$(CONFIG_AUTOFS4_FS) += autofs4 +subdir-$(CONFIG_ADFS_FS) += adfs +subdir-$(CONFIG_DEVPTS_FS) += devpts +subdir-$(CONFIG_SUN_OPENPROMFS) += openpromfs + + +obj-$(CONFIG_BINFMT_AOUT) += binfmt_aout.o +obj-$(CONFIG_BINFMT_EM86) += binfmt_em86.o +obj-$(CONFIG_BINFMT_MISC) += binfmt_misc.o -ifeq ($(CONFIG_EXT2_FS),y) -SUB_DIRS += ext2 -else - ifeq ($(CONFIG_EXT2_FS),m) - MOD_SUB_DIRS += ext2 - endif -endif - -ifeq ($(CONFIG_CRAMFS),y) -SUB_DIRS += cramfs -else - ifeq ($(CONFIG_CRAMFS),m) - MOD_SUB_DIRS += cramfs - endif -endif - -ifeq ($(CONFIG_RAMFS),y) -SUB_DIRS += ramfs -else - ifeq ($(CONFIG_RAMFS),m) - MOD_SUB_DIRS += ramfs - endif -endif - -ifeq ($(CONFIG_CODA_FS),y) -SUB_DIRS += coda -else - ifeq ($(CONFIG_CODA_FS),m) - MOD_SUB_DIRS += coda - endif -endif - -ifeq ($(CONFIG_MINIX_FS),y) -SUB_DIRS += minix -else - ifeq ($(CONFIG_MINIX_FS),m) - MOD_SUB_DIRS += minix - endif -endif - -ifeq ($(CONFIG_FAT_FS),y) -SUB_DIRS += fat -else - ifeq ($(CONFIG_FAT_FS),m) - MOD_SUB_DIRS += fat - endif -endif - -ifeq ($(CONFIG_MSDOS_FS),y) -SUB_DIRS += msdos -else - ifeq ($(CONFIG_MSDOS_FS),m) - MOD_SUB_DIRS += msdos - endif -endif - -ifeq ($(CONFIG_VFAT_FS),y) -SUB_DIRS += vfat -else - ifeq ($(CONFIG_VFAT_FS),m) - MOD_SUB_DIRS += vfat - endif -endif - -ifeq ($(CONFIG_BFS_FS),y) -SUB_DIRS += bfs -else - ifeq ($(CONFIG_BFS_FS),m) - MOD_SUB_DIRS += bfs - endif -endif - -ifeq ($(CONFIG_ISO9660_FS),y) -SUB_DIRS += isofs -else - ifeq ($(CONFIG_ISO9660_FS),m) - MOD_SUB_DIRS += isofs - endif -endif - -ifdef CONFIG_DEVFS_FS -SUB_DIRS += devfs -endif - -ifeq ($(CONFIG_HFS_FS),y) -SUB_DIRS += hfs -else - ifeq ($(CONFIG_HFS_FS),m) - MOD_SUB_DIRS += hfs - endif -endif - -ifeq ($(CONFIG_NFS_FS),y) -SUB_DIRS += nfs -else - ifeq ($(CONFIG_NFS_FS),m) - MOD_SUB_DIRS += nfs - endif -endif - -ifeq ($(CONFIG_NFSD),y) -CONFIG_LOCKD := y -SUB_DIRS += nfsd -else - ifeq ($(CONFIG_NFSD),m) - MOD_SUB_DIRS += nfsd - endif -endif - -ifeq ($(CONFIG_LOCKD),y) -SUB_DIRS += lockd -else - ifeq ($(CONFIG_LOCKD),m) - MOD_SUB_DIRS := lockd $(MOD_SUB_DIRS) - endif -endif - -# Since CONFIG_NLS might be set to y while there are modules -# to be build in the nls/ directory, we need to enter the nls -# directory every time, but with different rules. -ifeq ($(CONFIG_NLS),y) -SUB_DIRS += nls -MOD_IN_SUB_DIRS += nls -else - ifeq ($(CONFIG_NLS),m) - MOD_SUB_DIRS += nls - endif -endif - -ifeq ($(CONFIG_UMSDOS_FS),y) -SUB_DIRS += umsdos -else - ifeq ($(CONFIG_UMSDOS_FS),m) - MOD_SUB_DIRS += umsdos - endif -endif - -ifeq ($(CONFIG_SYSV_FS),y) -SUB_DIRS += sysv -else - ifeq ($(CONFIG_SYSV_FS),m) - MOD_SUB_DIRS += sysv - endif -endif - -ifeq ($(CONFIG_SMB_FS),y) -SUB_DIRS += smbfs -else - ifeq ($(CONFIG_SMB_FS),m) - MOD_SUB_DIRS += smbfs - endif -endif - -ifeq ($(CONFIG_NCP_FS),y) -SUB_DIRS += ncpfs -else - ifeq ($(CONFIG_NCP_FS),m) - MOD_SUB_DIRS += ncpfs - endif -endif - -ifeq ($(CONFIG_HPFS_FS),y) -SUB_DIRS += hpfs -else - ifeq ($(CONFIG_HPFS_FS),m) - MOD_SUB_DIRS += hpfs - endif -endif - -ifeq ($(CONFIG_NTFS_FS),y) -SUB_DIRS += ntfs -else - ifeq ($(CONFIG_NTFS_FS),m) - MOD_SUB_DIRS += ntfs - endif -endif - -ifeq ($(CONFIG_UFS_FS),y) -SUB_DIRS += ufs -else - ifeq ($(CONFIG_UFS_FS),m) - MOD_SUB_DIRS += ufs - endif -endif - -ifeq ($(CONFIG_EFS_FS),y) -SUB_DIRS += efs -else - ifeq ($(CONFIG_EFS_FS),m) - MOD_SUB_DIRS += efs - endif -endif - -ifeq ($(CONFIG_JFFS_FS),y) -SUB_DIRS += jffs -else - ifeq ($(CONFIG_JFFS_FS),m) - MOD_SUB_DIRS += jffs - endif -endif - -ifeq ($(CONFIG_AFFS_FS),y) -SUB_DIRS += affs -else - ifeq ($(CONFIG_AFFS_FS),m) - MOD_SUB_DIRS += affs - endif -endif - -ifeq ($(CONFIG_ROMFS_FS),y) -SUB_DIRS += romfs -else - ifeq ($(CONFIG_ROMFS_FS),m) - MOD_SUB_DIRS += romfs - endif -endif - -ifeq ($(CONFIG_QNX4FS_FS),y) -SUB_DIRS += qnx4 -else - ifeq ($(CONFIG_QNX4FS_FS),m) - MOD_SUB_DIRS += qnx4 - endif -endif - -ifeq ($(CONFIG_UDF_FS),y) -SUB_DIRS += udf -else - ifeq ($(CONFIG_UDF_FS),m) - MOD_SUB_DIRS += udf - endif -endif - -ifeq ($(CONFIG_AUTOFS_FS),y) -SUB_DIRS += autofs -else - ifeq ($(CONFIG_AUTOFS_FS),m) - MOD_SUB_DIRS += autofs - endif -endif - -ifeq ($(CONFIG_AUTOFS4_FS),y) -SUB_DIRS += autofs4 -else - ifeq ($(CONFIG_AUTOFS4_FS),m) - MOD_SUB_DIRS += autofs4 - endif -endif - -ifeq ($(CONFIG_ADFS_FS),y) -SUB_DIRS += adfs -else - ifeq ($(CONFIG_ADFS_FS),m) - MOD_SUB_DIRS += adfs - endif -endif - -ifeq ($(CONFIG_DEVPTS_FS),y) -SUB_DIRS += devpts -else - ifeq ($(CONFIG_DEVPTS_FS),m) - MOD_SUB_DIRS += devpts - endif -endif +# binfmt_script is always there +obj-y += binfmt_script.o -ifeq ($(CONFIG_SUN_OPENPROMFS),y) -SUB_DIRS += openpromfs -else - ifeq ($(CONFIG_SUN_OPENPROMFS),m) - MOD_SUB_DIRS += openpromfs - endif -endif +obj-$(CONFIG_BINFMT_ELF) += binfmt_elf.o -ifeq ($(CONFIG_BINFMT_AOUT),y) -BINFMTS += binfmt_aout.o -else - ifeq ($(CONFIG_BINFMT_AOUT),m) - M_OBJS += binfmt_aout.o - endif -endif +# persistent filesystems +obj-y += $(join $(subdir-y),$(subdir-y:%=/%.o)) -ifeq ($(CONFIG_BINFMT_EM86),y) -BINFMTS += binfmt_em86.o -else - ifeq ($(CONFIG_BINFMT_EM86),m) - M_OBJS += binfmt_em86.o - endif -endif -ifeq ($(CONFIG_BINFMT_MISC),y) -BINFMTS += binfmt_misc.o -else - ifeq ($(CONFIG_BINFMT_MISC),m) - M_OBJS += binfmt_misc.o - endif -endif +# Subdirectories that should be entered when MAKING_MODULES=1, even if set to 'y'. +both-m := $(filter $(mod-subdirs), $(subdir-y)) -# binfmt_script is always there -BINFMTS += binfmt_script.o +# 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))) -ifeq ($(CONFIG_BINFMT_ELF),y) -BINFMTS += binfmt_elf.o -else - ifeq ($(CONFIG_BINFMT_ELF),m) - M_OBJS += binfmt_elf.o - endif -endif +SUB_DIRS := $(subdir-y) +MOD_SUB_DIRS := $(sort $(subdir-m) $(both-m)) +ALL_SUB_DIRS := $(sort $(subdir-y) $(subdir-m) $(subdir-n) $(subdir-)) include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.0-test8/linux/fs/adfs/adfs.h linux/fs/adfs/adfs.h --- v2.4.0-test8/linux/fs/adfs/adfs.h Wed Jul 5 21:38:44 2000 +++ linux/fs/adfs/adfs.h Mon Sep 18 15:14:06 2000 @@ -97,6 +97,7 @@ /* dir_*.c */ extern struct inode_operations adfs_dir_inode_operations; extern struct file_operations adfs_dir_operations; +extern struct dentry_operations adfs_dentry_operations; extern struct adfs_dir_ops adfs_f_dir_ops; extern struct adfs_dir_ops adfs_fplus_dir_ops; diff -u --recursive --new-file v2.4.0-test8/linux/fs/adfs/dir.c linux/fs/adfs/dir.c --- v2.4.0-test8/linux/fs/adfs/dir.c Fri Aug 11 14:29:02 2000 +++ linux/fs/adfs/dir.c Mon Sep 18 15:14:06 2000 @@ -1,9 +1,13 @@ /* - * linux/fs/adfs/dir.c + * linux/fs/adfs/dir.c * - * Copyright (C) 1999-2000 Russell King + * Copyright (C) 1999-2000 Russell King * - * Common directory handling for ADFS + * 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. + * + * Common directory handling for ADFS */ #include #include diff -u --recursive --new-file v2.4.0-test8/linux/fs/adfs/dir_f.c linux/fs/adfs/dir_f.c --- v2.4.0-test8/linux/fs/adfs/dir_f.c Tue Sep 5 14:07:29 2000 +++ linux/fs/adfs/dir_f.c Mon Sep 18 15:14:06 2000 @@ -3,7 +3,11 @@ * * Copyright (C) 1997-1999 Russell King * - * E and F format directory handling + * 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. + * + * E and F format directory handling */ #include #include diff -u --recursive --new-file v2.4.0-test8/linux/fs/adfs/dir_f.h linux/fs/adfs/dir_f.h --- v2.4.0-test8/linux/fs/adfs/dir_f.h Sun Feb 6 17:45:25 2000 +++ linux/fs/adfs/dir_f.h Mon Sep 18 15:14:06 2000 @@ -1,9 +1,13 @@ /* - * linux/fs/adfs/dir_f.h + * linux/fs/adfs/dir_f.h * - * Copyright (C) 1999 Russell King + * Copyright (C) 1999 Russell King * - * Structures of directories on the F format disk + * 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. + * + * Structures of directories on the F format disk */ #ifndef ADFS_DIR_F_H #define ADFS_DIR_F_H diff -u --recursive --new-file v2.4.0-test8/linux/fs/adfs/dir_fplus.c linux/fs/adfs/dir_fplus.c --- v2.4.0-test8/linux/fs/adfs/dir_fplus.c Wed Jun 21 10:10:02 2000 +++ linux/fs/adfs/dir_fplus.c Mon Sep 18 15:14:06 2000 @@ -1,7 +1,11 @@ /* * linux/fs/adfs/dir_fplus.c * - * Copyright (C) 1997-1999 Russell King + * Copyright (C) 1997-1999 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 diff -u --recursive --new-file v2.4.0-test8/linux/fs/adfs/dir_fplus.h linux/fs/adfs/dir_fplus.h --- v2.4.0-test8/linux/fs/adfs/dir_fplus.h Sun Feb 6 17:45:25 2000 +++ linux/fs/adfs/dir_fplus.h Mon Sep 18 15:14:06 2000 @@ -1,9 +1,13 @@ /* - * linux/fs/adfs/dir_fplus.h + * linux/fs/adfs/dir_fplus.h * - * Copyright (C) 1999 Russell King + * Copyright (C) 1999 Russell King * - * Structures of directories on the F+ format disk + * 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. + * + * Structures of directories on the F+ format disk */ #define ADFS_FPLUS_NAME_LEN 255 diff -u --recursive --new-file v2.4.0-test8/linux/fs/adfs/file.c linux/fs/adfs/file.c --- v2.4.0-test8/linux/fs/adfs/file.c Wed Jun 21 10:10:02 2000 +++ linux/fs/adfs/file.c Wed Sep 27 13:41:33 2000 @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include diff -u --recursive --new-file v2.4.0-test8/linux/fs/adfs/inode.c linux/fs/adfs/inode.c --- v2.4.0-test8/linux/fs/adfs/inode.c Sat Jul 8 19:26:12 2000 +++ linux/fs/adfs/inode.c Mon Sep 18 15:14:06 2000 @@ -1,7 +1,11 @@ /* * linux/fs/adfs/inode.c * - * Copyright (C) 1997-1999 Russell King + * Copyright (C) 1997-1999 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 diff -u --recursive --new-file v2.4.0-test8/linux/fs/adfs/map.c linux/fs/adfs/map.c --- v2.4.0-test8/linux/fs/adfs/map.c Wed Jun 21 10:10:02 2000 +++ linux/fs/adfs/map.c Mon Sep 18 15:14:06 2000 @@ -1,7 +1,11 @@ /* * linux/fs/adfs/map.c * - * Copyright (C) 1997-1999 Russell King + * Copyright (C) 1997-1999 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 diff -u --recursive --new-file v2.4.0-test8/linux/fs/adfs/super.c linux/fs/adfs/super.c --- v2.4.0-test8/linux/fs/adfs/super.c Wed Jun 21 10:10:02 2000 +++ linux/fs/adfs/super.c Mon Sep 18 15:14:06 2000 @@ -1,7 +1,11 @@ /* * linux/fs/adfs/super.c * - * Copyright (C) 1997-1999 Russell King + * Copyright (C) 1997-1999 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 @@ -425,7 +429,8 @@ kfree(sb->u.adfs_sb.s_map); adfs_error(sb, "get root inode failed\n"); goto error; - } + } else + sb->s_root->d_op = &adfs_dentry_operations; return sb; error_free_bh: diff -u --recursive --new-file v2.4.0-test8/linux/fs/attr.c linux/fs/attr.c --- v2.4.0-test8/linux/fs/attr.c Mon May 8 14:31:13 2000 +++ linux/fs/attr.c Fri Sep 22 14:21:18 2000 @@ -9,6 +9,8 @@ #include #include #include +#include +#include /* Taken over from the old code... */ @@ -79,6 +81,28 @@ mark_inode_dirty(inode); } +static int setattr_mask(unsigned int ia_valid) +{ + unsigned long dn_mask = 0; + + if (ia_valid & ATTR_UID) + dn_mask |= DN_ATTRIB; + if (ia_valid & ATTR_GID) + dn_mask |= DN_ATTRIB; + if (ia_valid & ATTR_SIZE) + dn_mask |= DN_MODIFY; + /* both times implies a utime(s) call */ + if ((ia_valid & (ATTR_ATIME|ATTR_MTIME)) == (ATTR_ATIME|ATTR_MTIME)) + dn_mask |= DN_ATTRIB; + else if (ia_valid & ATTR_ATIME) + dn_mask |= DN_ACCESS; + else if (ia_valid & ATTR_MTIME) + dn_mask |= DN_MODIFY; + if (ia_valid & ATTR_MODE) + dn_mask |= DN_ATTRIB; + return dn_mask; +} + int notify_change(struct dentry * dentry, struct iattr * attr) { struct inode *inode = dentry->d_inode; @@ -101,5 +125,10 @@ inode_setattr(inode, attr); } unlock_kernel(); + if (!error) { + unsigned long dn_mask = setattr_mask(ia_valid); + if (dn_mask) + inode_dir_notify(dentry->d_parent->d_inode, dn_mask); + } return error; } diff -u --recursive --new-file v2.4.0-test8/linux/fs/bfs/inode.c linux/fs/bfs/inode.c --- v2.4.0-test8/linux/fs/bfs/inode.c Tue Sep 5 14:07:29 2000 +++ linux/fs/bfs/inode.c Sun Sep 17 09:51:57 2000 @@ -197,7 +197,7 @@ buf->f_bfree = buf->f_bavail = s->su_freeb; buf->f_files = s->su_lasti + 1 - BFS_ROOT_INO; buf->f_ffree = s->su_freei; - buf->f_fsid.val[0] = s->s_dev; + buf->f_fsid.val[0] = kdev_t_to_nr(s->s_dev); buf->f_namelen = BFS_NAMELEN; return 0; } diff -u --recursive --new-file v2.4.0-test8/linux/fs/block_dev.c linux/fs/block_dev.c --- v2.4.0-test8/linux/fs/block_dev.c Tue Sep 5 14:07:31 2000 +++ linux/fs/block_dev.c Sun Oct 1 20:35:16 2000 @@ -30,17 +30,17 @@ ssize_t block, blocks; loff_t offset; ssize_t chars; - ssize_t written = 0; + ssize_t written; struct buffer_head * bhlist[NBUF]; size_t size; - kdev_t dev; + kdev_t dev = inode->i_rdev; struct buffer_head * bh, *bufferlist[NBUF]; register char * p; - write_error = buffercount = 0; - dev = inode->i_rdev; - if ( is_read_only( inode->i_rdev )) + if (is_read_only(dev)) return -EPERM; + + written = write_error = buffercount = 0; blocksize = BLOCK_SIZE; if (blksize_size[MAJOR(dev)] && blksize_size[MAJOR(dev)][MINOR(dev)]) blocksize = blksize_size[MAJOR(dev)][MINOR(dev)]; @@ -311,6 +311,39 @@ } /* + * private llseek: + * for a block special file file->f_dentry->d_inode->i_size is zero + * so we compute the size by hand (just as in block_read/write above) + */ +static loff_t block_llseek(struct file *file, loff_t offset, int origin) +{ + long long retval; + kdev_t dev; + + switch (origin) { + case 2: + dev = file->f_dentry->d_inode->i_rdev; + if (blk_size[MAJOR(dev)]) + offset += (loff_t) blk_size[MAJOR(dev)][MINOR(dev)] << BLOCK_SIZE_BITS; + /* else? return -EINVAL? */ + break; + case 1: + offset += file->f_pos; + } + retval = -EINVAL; + if (offset >= 0) { + if (offset != file->f_pos) { + file->f_pos = offset; + file->f_reada = 0; + file->f_version = ++event; + } + retval = offset; + } + return retval; +} + + +/* * Filp may be NULL when we are called by an msync of a vma * since the vma has no handle. */ @@ -435,9 +468,7 @@ static struct { const char *name; struct block_device_operations *bdops; -} blkdevs[MAX_BLKDEV] = { - { NULL, NULL }, -}; +} blkdevs[MAX_BLKDEV]; int get_blkdev_list(char * p) { @@ -612,7 +643,7 @@ int blkdev_open(struct inode * inode, struct file * filp) { - int ret = -ENODEV; + int ret = -ENXIO; struct block_device *bdev = inode->i_bdev; down(&bdev->bd_sem); lock_kernel(); @@ -678,6 +709,7 @@ struct file_operations def_blk_fops = { open: blkdev_open, release: blkdev_close, + llseek: block_llseek, read: block_read, write: block_write, fsync: block_fsync, diff -u --recursive --new-file v2.4.0-test8/linux/fs/buffer.c linux/fs/buffer.c --- v2.4.0-test8/linux/fs/buffer.c Wed Sep 6 08:29:45 2000 +++ linux/fs/buffer.c Mon Oct 2 12:03:34 2000 @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -409,8 +410,9 @@ */ #define _hashfn(dev,block) \ ((((dev)<<(bh_hash_shift - 6)) ^ ((dev)<<(bh_hash_shift - 9))) ^ \ - (((block)<<(bh_hash_shift - 6)) ^ ((block) >> 13) ^ ((block) << (bh_hash_shift - 12)))) -#define hash(dev,block) hash_table[(_hashfn(dev,block) & bh_hash_mask)] + (((block)<<(bh_hash_shift - 6)) ^ ((block) >> 13) ^ \ + ((block) << (bh_hash_shift - 12)))) +#define hash(dev,block) hash_table[(_hashfn(HASHDEV(dev),block) & bh_hash_mask)] static __inline__ void __hash_link(struct buffer_head *bh, struct buffer_head **head) { @@ -856,23 +858,35 @@ /* -1 -> no need to flush 0 -> async flush 1 -> sync flush (wait for I/O completation) */ -static int balance_dirty_state(kdev_t dev) +int balance_dirty_state(kdev_t dev) { unsigned long dirty, tot, hard_dirty_limit, soft_dirty_limit; + int shortage; dirty = size_buffers_type[BUF_DIRTY] >> PAGE_SHIFT; tot = nr_free_buffer_pages(); - tot -= size_buffers_type[BUF_PROTECTED] >> PAGE_SHIFT; dirty *= 200; soft_dirty_limit = tot * bdf_prm.b_un.nfract; hard_dirty_limit = soft_dirty_limit * 2; + /* First, check for the "real" dirty limit. */ if (dirty > soft_dirty_limit) { if (dirty > hard_dirty_limit) return 1; return 0; } + + /* + * If we are about to get low on free pages and + * cleaning the inactive_dirty pages would help + * fix this, wake up bdflush. + */ + shortage = free_shortage(); + if (shortage && nr_inactive_dirty_pages > shortage && + nr_inactive_dirty_pages > freepages.high) + return 0; + return -1; } @@ -1380,6 +1394,19 @@ } /* + * NOTE! All mapped/uptodate combinations are valid: + * + * Mapped Uptodate Meaning + * + * No No "unknown" - must do get_block() + * No Yes "hole" - zero-filled + * Yes No "allocated" - allocated on disk, not read in + * Yes Yes "valid" - allocated and up-to-date in memory. + * + * "Dirty" is valid only with the last case (mapped+uptodate). + */ + +/* * block_write_full_page() is SMP-safe - currently it's still * being called with the kernel lock held, but the code is ready. */ @@ -1471,6 +1498,10 @@ goto out; if (buffer_new(bh)) { unmap_underlying_metadata(bh); + if (Page_Uptodate(page)) { + set_bit(BH_Uptodate, &bh->b_state); + continue; + } if (block_end > to) memset(kaddr+to, 0, block_end-to); if (block_start < from) @@ -1480,6 +1511,10 @@ continue; } } + if (Page_Uptodate(page)) { + set_bit(BH_Uptodate, &bh->b_state); + continue; + } if (!buffer_uptodate(bh) && (block_start < from || block_end > to)) { ll_rw_block(READ, 1, &bh); @@ -1574,8 +1609,10 @@ continue; if (!buffer_mapped(bh)) { - if (iblock < lblock) - get_block(inode, iblock, bh, 0); + if (iblock < lblock) { + if (get_block(inode, iblock, bh, 0)) + continue; + } if (!buffer_mapped(bh)) { if (!kaddr) kaddr = kmap(page); @@ -1758,17 +1795,27 @@ pos += blocksize; } + err = 0; + if (!buffer_mapped(bh)) { + /* Hole? Nothing to do */ + if (buffer_uptodate(bh)) + goto unlock; + get_block(inode, iblock, bh, 0); + /* Still unmapped? Nothing to do */ + if (!buffer_mapped(bh)) + goto unlock; + } + + /* Ok, it's mapped. Make sure it's up-to-date */ + if (Page_Uptodate(page)) + set_bit(BH_Uptodate, &bh->b_state); + + bh->b_end_io = end_buffer_io_sync; if (!buffer_uptodate(bh)) { - err = 0; - if (!buffer_mapped(bh)) { - get_block(inode, iblock, bh, 0); - if (!buffer_mapped(bh)) - goto unlock; - } err = -EIO; - bh->b_end_io = end_buffer_io_sync; ll_rw_block(READ, 1, &bh); wait_on_buffer(bh); + /* Uhhuh. Read error. Complain and punt. */ if (!buffer_uptodate(bh)) goto unlock; } @@ -2152,6 +2199,7 @@ page = alloc_page(GFP_BUFFER); if (!page) goto out; + LockPage(page); bh = create_buffers(page, size, 0); if (!bh) goto no_buffer_head; @@ -2184,10 +2232,12 @@ page->buffers = bh; page->flags &= ~(1 << PG_referenced); lru_cache_add(page); + UnlockPage(page); atomic_inc(&buffermem_pages); return 1; no_buffer_head: + UnlockPage(page); page_cache_release(page); out: return 0; @@ -2244,7 +2294,9 @@ { struct buffer_head * tmp, * bh = page->buffers; int index = BUFSIZE_INDEX(bh->b_size); + int loop = 0; +cleaned_buffers_try_again: spin_lock(&lru_list_lock); write_lock(&hash_table_lock); spin_lock(&free_list[index].lock); @@ -2290,8 +2342,14 @@ spin_unlock(&free_list[index].lock); write_unlock(&hash_table_lock); spin_unlock(&lru_list_lock); - if (wait) + if (wait) { sync_page_buffers(bh, wait); + /* We waited synchronously, so we can free the buffers. */ + if (wait > 1 && !loop) { + loop = 1; + goto cleaned_buffers_try_again; + } + } return 0; } @@ -2609,6 +2667,8 @@ CHECK_EMERGENCY_SYNC flushed = flush_dirty_buffers(0); + if (free_shortage()) + flushed += page_launder(GFP_BUFFER, 0); /* If wakeup_bdflush will wakeup us after our bdflush_done wakeup, then @@ -2619,14 +2679,16 @@ (as we would be sleeping) and so it would deadlock in SMP. */ __set_current_state(TASK_INTERRUPTIBLE); - wake_up(&bdflush_done); + wake_up_all(&bdflush_done); /* * If there are still a lot of dirty buffers around, * skip the sleep and flush some more. Otherwise, we * go to sleep waiting a wakeup. */ - if (!flushed || balance_dirty_state(NODEV) < 0) + if (!flushed || balance_dirty_state(NODEV) < 0) { + run_task_queue(&tq_disk); schedule(); + } /* Remember to mark us as running otherwise the next schedule will block. */ __set_current_state(TASK_RUNNING); diff -u --recursive --new-file v2.4.0-test8/linux/fs/coda/cache.c linux/fs/coda/cache.c --- v2.4.0-test8/linux/fs/coda/cache.c Wed Jul 5 11:30:59 2000 +++ linux/fs/coda/cache.c Thu Sep 21 09:59:46 2000 @@ -24,168 +24,60 @@ #include #include -/* create a new acl cache entry and enlist it */ -static struct coda_cache *coda_cache_create(struct inode *inode) +/* replace or extend an acl cache hit */ +void coda_cache_enter(struct inode *inode, int mask) { struct coda_inode_info *cii = ITOC(inode); - struct coda_sb_info *sbi = coda_sbp(inode->i_sb); - struct coda_cache *cc = NULL; - ENTRY; - - if ( !sbi || !cii ) { - printk("coda_cache_create: NULL sbi or cii!\n"); - return NULL; - } - - CODA_ALLOC(cc, struct coda_cache *, sizeof(*cc)); - - if ( !cc ) { - printk("Out of memory in coda_cache_create!\n"); - return NULL; - } - - coda_load_creds(&cc->cc_cred); - cc->cc_mask = 0; - - INIT_LIST_HEAD(&cc->cc_cclist); - INIT_LIST_HEAD(&cc->cc_cnlist); - list_add(&cc->cc_cclist, &sbi->sbi_cchead); - list_add(&cc->cc_cnlist, &cii->c_cnhead); - - return cc; -} + ENTRY; -/* destroy an acl cache entry */ -static void coda_cache_destroy(struct coda_cache *el) -{ - ENTRY; - if (list_empty(&el->cc_cclist) || list_empty(&el->cc_cnlist)) { - printk("coda_cache_destroy: loose entry!"); - return; - } - list_del(&el->cc_cclist); - list_del(&el->cc_cnlist); - CODA_FREE(el, sizeof(struct coda_cache)); + if ( !coda_cred_ok(&cii->c_cached_cred) ) { + coda_load_creds(&cii->c_cached_cred); + cii->c_cached_perm = mask; + } else + cii->c_cached_perm |= mask; } -/* see if there is a match for the current - credentials already */ -static struct coda_cache * coda_cache_find(struct inode *inode) +/* remove cached acl from an inode */ +void coda_cache_clear_inode(struct inode *inode) { struct coda_inode_info *cii = ITOC(inode); - struct list_head *le; - struct coda_cache *cc = NULL; - - list_for_each(le, &cii->c_cnhead) - { - /* compare name and creds */ - cc = list_entry(le, struct coda_cache, cc_cnlist); - if ( !coda_cred_ok(&cc->cc_cred) ) - continue; - CDEBUG(D_CACHE, "HIT for ino %ld\n", inode->i_ino ); - return cc; /* cache hit */ - } - return NULL; -} - -/* create or extend an acl cache hit */ -void coda_cache_enter(struct inode *inode, int mask) -{ - struct coda_cache *cc; - - cc = coda_cache_find(inode); - - if (!cc) - cc = coda_cache_create(inode); - if (cc) - cc->cc_mask |= mask; + ENTRY; + cii->c_cached_perm = 0; } -/* remove all cached acl matches from an inode */ -void coda_cache_clear_inode(struct inode *inode) +/* remove all acl caches for a principal (or all principals when cred == NULL)*/ +void coda_cache_clear_all(struct super_block *sb, struct coda_cred *cred) { - struct list_head *le; - struct coda_inode_info *cii; - struct coda_cache *cc; - ENTRY; + struct coda_sb_info *sbi; + struct coda_inode_info *cii; + struct list_head *tmp; - if ( !inode ) { - CDEBUG(D_CACHE, "coda_cache_clear_inode: NULL inode\n"); - return; - } - cii = ITOC(inode); - - le = cii->c_cnhead.next; - while ( le != &cii->c_cnhead ) { - cc = list_entry(le, struct coda_cache, cc_cnlist); - le = le->next; - coda_cache_destroy(cc); - } -} + ENTRY; + sbi = coda_sbp(sb); + if (!sbi) BUG(); -/* remove all acl caches */ -void coda_cache_clear_all(struct super_block *sb) -{ - struct list_head *le; - struct coda_cache *cc; - struct coda_sb_info *sbi = coda_sbp(sb); - - if ( !sbi ) { - printk("coda_cache_clear_all: NULL sbi\n"); - return; - } - - le = sbi->sbi_cchead.next; - while ( le != &sbi->sbi_cchead ) { - cc = list_entry(le, struct coda_cache, cc_cclist); - le = le->next; - coda_cache_destroy(cc); - } -} + list_for_each(tmp, &sbi->sbi_cihead) + { + cii = list_entry(tmp, struct coda_inode_info, c_cilist); + if ( cii->c_magic != CODA_CNODE_MAGIC ) BUG(); -/* remove all acl caches for a principal */ -void coda_cache_clear_cred(struct super_block *sb, struct coda_cred *cred) -{ - struct list_head *le; - struct coda_cache *cc; - struct coda_sb_info *sbi = coda_sbp(sb); - - if ( !sbi ) { - printk("coda_cache_clear_all: NULL sbi\n"); - return; - } - - le = sbi->sbi_cchead.next; - while ( le != &sbi->sbi_cchead ) { - cc = list_entry(le, struct coda_cache, cc_cclist); - le = le->next; - if ( coda_cred_eq(&cc->cc_cred, cred)) - coda_cache_destroy(cc); + if (!cred || coda_cred_eq(cred, &cii->c_cached_cred)) + cii->c_cached_perm = 0; } } -/* check if the mask has been matched against the acl - already */ +/* check if the mask has been matched against the acl already */ int coda_cache_check(struct inode *inode, int mask) { struct coda_inode_info *cii = ITOC(inode); - struct list_head *le; - struct coda_cache *cc = NULL; + int hit; - list_for_each(le, &cii->c_cnhead) - { - /* compare name and creds */ - cc = list_entry(le, struct coda_cache, cc_cnlist); - if ( (cc->cc_mask & mask) != mask ) - continue; - if ( !coda_cred_ok(&cc->cc_cred) ) - continue; - CDEBUG(D_CACHE, "HIT for ino %ld\n", inode->i_ino ); - return 1; /* cache hit */ - } - CDEBUG(D_CACHE, "MISS for ino %ld\n", inode->i_ino ); - return 0; + hit = ((mask & cii->c_cached_perm) == mask) && + coda_cred_ok(&cii->c_cached_cred); + + CDEBUG(D_CACHE, "%s for ino %ld\n", hit ? "HIT" : "MISS", inode->i_ino); + return hit; } diff -u --recursive --new-file v2.4.0-test8/linux/fs/coda/cnode.c linux/fs/coda/cnode.c --- v2.4.0-test8/linux/fs/coda/cnode.c Wed Jun 21 10:10:02 2000 +++ linux/fs/coda/cnode.c Thu Sep 21 09:59:46 2000 @@ -59,7 +59,6 @@ struct coda_vattr * attr) { struct inode *inode; - struct coda_sb_info *sbi= coda_sbp(sb); struct coda_inode_info *cii; ino_t ino = attr->va_fileid; @@ -71,50 +70,26 @@ /* check if the inode is already initialized */ cii = ITOC(inode); - if (cii->c_magic == CODA_CNODE_MAGIC) { + if (cii->c_fid.Volume != 0 || cii->c_fid.Vnode != 0 || cii->c_fid.Unique != 0) { /* see if it is the right one (might have an inode collision) */ - if ( !coda_fideq(fid, &cii->c_fid) ) { + if ( !coda_fideq(fid, &cii->c_fid) ) { printk("coda_iget: initialized inode old %s new %s!\n", coda_f2s(&cii->c_fid), coda_f2s2(fid)); iput(inode); return ERR_PTR(-ENOENT); } - /* replace the attributes, type might have changed */ - coda_fill_inode(inode, attr); + /* we will still replace the attributes, type might have changed */ goto out; } /* new, empty inode found... initializing */ /* Initialize the Coda inode info structure */ - memset(cii, 0, (int) sizeof(struct coda_inode_info)); - cii->c_magic = CODA_CNODE_MAGIC; cii->c_fid = *fid; - cii->c_flags = 0; cii->c_vnode = inode; - INIT_LIST_HEAD(&(cii->c_cnhead)); - INIT_LIST_HEAD(&(cii->c_volrootlist)); - coda_fill_inode(inode, attr); - - /* check if it is a weird fid (hashed fid != ino), f.i mountpoints - repair object, expanded local-global conflict trees, etc. - */ - if ( coda_f2i(fid) == ino ) - goto out; - - /* check if we expected this weird fid */ - if ( !coda_fid_is_weird(fid) ) { - printk("Coda: unknown weird fid: ino %ld, fid %s." - "Tell Peter.\n", (long)ino, coda_f2s(&cii->c_fid)); - goto out; - } - - /* add the inode to a global list so we can find it back later */ - list_add(&cii->c_volrootlist, &sbi->sbi_volroothead); - CDEBUG(D_CNODE, "Added %ld, %s to volroothead\n", - (long)ino, coda_f2s(&cii->c_fid)); out: + coda_fill_inode(inode, attr); return inode; } @@ -161,22 +136,14 @@ void coda_replace_fid(struct inode *inode, struct ViceFid *oldfid, struct ViceFid *newfid) { - struct coda_inode_info *cnp; - struct coda_sb_info *sbi= coda_sbp(inode->i_sb); + struct coda_inode_info *cii; - cnp = ITOC(inode); - - if ( ! coda_fideq(&cnp->c_fid, oldfid) ) - printk("What? oldfid != cnp->c_fid. Call 911.\n"); - - cnp->c_fid = *newfid; + cii = ITOC(inode); - list_del(&cnp->c_volrootlist); - INIT_LIST_HEAD(&cnp->c_volrootlist); - if ( coda_fid_is_weird(newfid) ) - list_add(&cnp->c_volrootlist, &sbi->sbi_volroothead); + if ( ! coda_fideq(&cii->c_fid, oldfid) ) + printk("What? oldfid != cii->c_fid. Call 911.\n"); - return; + cii->c_fid = *newfid; } @@ -197,24 +164,18 @@ return NULL; } - if ( !fid ) { - printk("coda_fid_to_inode: no fid!\n"); - return NULL; - } CDEBUG(D_INODE, "%s\n", coda_f2s(fid)); + /* weird fids cannot be hashed, have to look for them the hard way */ if ( coda_fid_is_weird(fid) ) { - struct list_head *lh, *le; struct coda_sb_info *sbi = coda_sbp(sb); - le = lh = &sbi->sbi_volroothead; + struct list_head *le; - while ( (le = le->next) != lh ) { - cii = list_entry(le, struct coda_inode_info, - c_volrootlist); - /* paranoia check, should never trigger */ - if ( cii->c_magic != CODA_CNODE_MAGIC ) - printk("coda_fid_to_inode: Bad magic in inode %x.\n", cii->c_magic); + list_for_each(le, &sbi->sbi_cihead) + { + cii = list_entry(le, struct coda_inode_info, c_cilist); + if ( cii->c_magic != CODA_CNODE_MAGIC ) BUG(); CDEBUG(D_DOWNCALL, "iterating, now doing %s, ino %ld\n", coda_f2s(&cii->c_fid), cii->c_vnode->i_ino); @@ -240,26 +201,19 @@ /* check if this inode is linked to a cnode */ cii = ITOC(inode); - if ( cii->c_magic != CODA_CNODE_MAGIC ) { - CDEBUG(D_INODE, "uninitialized inode. Return.\n"); - goto bad_inode; - } - /* make sure fid is the one we want */ - if ( !coda_fideq(fid, &(cii->c_fid)) ) { + /* make sure this is the one we want */ + if ( coda_fideq(fid, &cii->c_fid) ) { + CDEBUG(D_INODE, "found %ld\n", inode->i_ino); + return inode; + } + #if 0 - printk("coda_fid2inode: bad cnode (ino %ld, fid %s)", nr, - coda_f2s(fid)); + printk("coda_fid2inode: bad cnode (ino %ld, fid %s)", nr, coda_f2s(fid)); #endif - goto bad_inode; - } - - CDEBUG(D_INODE, "found %ld\n", inode->i_ino); - return inode; + iput(inode); + return NULL; -bad_inode: - iput(inode); - return NULL; } /* the CONTROL inode is made without asking attributes from Venus */ @@ -271,7 +225,7 @@ if ( *inode ) { (*inode)->i_op = &coda_ioctl_inode_operations; (*inode)->i_fop = &coda_ioctl_operations; - (*inode)->i_mode = 00444; + (*inode)->i_mode = 0444; error = 0; } else { error = -ENOMEM; diff -u --recursive --new-file v2.4.0-test8/linux/fs/coda/coda_linux.c linux/fs/coda/coda_linux.c --- v2.4.0-test8/linux/fs/coda/coda_linux.c Thu Feb 10 12:16:58 2000 +++ linux/fs/coda/coda_linux.c Tue Sep 19 15:08:59 2000 @@ -23,7 +23,6 @@ #include #include #include -#include /* initialize the debugging variables */ int coda_debug = 0; @@ -71,12 +70,6 @@ } } -/* is this a volume root FID */ -int coda_fid_is_volroot(struct ViceFid *fid) -{ - return ( (fid->Vnode == 1) && (fid->Unique == 1 ) ); -} - int coda_fid_is_weird(struct ViceFid *fid) { /* volume roots */ diff -u --recursive --new-file v2.4.0-test8/linux/fs/coda/dir.c linux/fs/coda/dir.c --- v2.4.0-test8/linux/fs/coda/dir.c Fri Aug 11 14:29:02 2000 +++ linux/fs/coda/dir.c Tue Sep 19 15:08:59 2000 @@ -170,12 +170,13 @@ ENTRY; coda_vfs_stat.permission++; - coda_permission_stat.count++; if ( mask == 0 ) return 0; - if ( coda_access_cache == 1 ) { + if ( coda_access_cache ) { + coda_permission_stat.count++; + if ( coda_cache_check(inode, mask) ) { coda_permission_stat.hit_count++; return 0; @@ -472,6 +473,7 @@ const char *new_name = new_dentry->d_name.name; int old_length = old_dentry->d_name.len; int new_length = new_dentry->d_name.len; + int link_adjust = 0; int error; ENTRY; @@ -488,16 +490,16 @@ if ( !error ) { if ( new_dentry->d_inode ) { - if ( S_ISDIR(new_dentry->d_inode->i_mode) ) { - old_dir->i_nlink--; - new_dir->i_nlink++; - } - coda_flag_inode(new_dentry->d_inode, C_VATTR); - } + if ( S_ISDIR(new_dentry->d_inode->i_mode) ) + link_adjust = 1; - /* coda_flag_inode(old_dir, C_VATTR); */ - /* coda_flag_inode(new_dir, C_VATTR); */ - old_dir->i_mtime = new_dir->i_mtime = CURRENT_TIME; + coda_dir_changed(old_dir, -link_adjust); + coda_dir_changed(new_dir, link_adjust); + coda_flag_inode(new_dentry->d_inode, C_VATTR); + } else { + coda_flag_inode(old_dir, C_VATTR); + coda_flag_inode(new_dir, C_VATTR); + } } CDEBUG(D_INODE, "result %d\n", error); @@ -578,6 +580,7 @@ unsigned short flags = f->f_flags & (~O_EXCL); unsigned short coda_flags = coda_flags_to_cflags(flags); struct coda_cred *cred; + struct coda_inode_info *cii; lock_kernel(); ENTRY; @@ -617,8 +620,11 @@ } i->i_mapping = cont_inode->i_mapping; - CDEBUG(D_FILE, "result %d, coda i->i_count is %d for ino %ld\n", - error, atomic_read(&i->i_count), i->i_ino); + cii = ITOC(i); + cii->c_contcount++; + + CDEBUG(D_FILE, "result %d, coda i->i_count is %d, cii->contcount is %d for ino %ld\n", + error, atomic_read(&i->i_count), cii->c_contcount, i->i_ino); CDEBUG(D_FILE, "cache ino: %ld, count %d, ops %p\n", cont_inode->i_ino, atomic_read(&cont_inode->i_count), cont_inode->i_op); @@ -634,6 +640,7 @@ unsigned short flags = (f->f_flags) & (~O_EXCL); unsigned short cflags = coda_flags_to_cflags(flags); struct coda_cred *cred; + struct coda_inode_info *cii; lock_kernel(); ENTRY; @@ -644,10 +651,16 @@ if (i->i_mapping != &i->i_data) container = (struct inode *)i->i_mapping->host; - CDEBUG(D_FILE, "RELEASE coda (ino %ld, ct %d) cache (ino %ld, ct %d)\n", - i->i_ino, atomic_read(&i->i_count), + cii = ITOC(i); + CDEBUG(D_FILE, "RELEASE coda (ino %ld, ct %d, cc %d) cache (ino %ld, ct %d)\n", + i->i_ino, atomic_read(&i->i_count), cii->c_contcount, (container ? container->i_ino : 0), (container ? atomic_read(&container->i_count) : -99)); + + if (--cii->c_contcount == 0 && container) { + i->i_mapping = &i->i_data; + iput(container); + } error = venus_release(i->i_sb, coda_i2f(i), cflags, cred); diff -u --recursive --new-file v2.4.0-test8/linux/fs/coda/file.c linux/fs/coda/file.c --- v2.4.0-test8/linux/fs/coda/file.c Thu Jun 29 16:20:07 2000 +++ linux/fs/coda/file.c Tue Sep 19 15:08:59 2000 @@ -23,18 +23,21 @@ #include #include #include -#include #include static ssize_t coda_file_write(struct file *file,const char *buf,size_t count,loff_t *ppos) { struct inode *inode = file->f_dentry->d_inode; + struct inode *container = (struct inode*)inode->i_mapping->host; ssize_t n; + down(&container->i_sem); + n = generic_file_write(file, buf, count, ppos); + inode->i_size = container->i_size; - inode->i_size = ((struct inode*)inode->i_mapping->host)->i_size; + up(&container->i_sem); return n; } @@ -63,7 +66,7 @@ result = file_fsync(NULL, &cont_dentry, datasync); up(&cont_dentry.d_inode->i_sem); - if ( result == 0 ) { + if ( result == 0 && datasync == 0 ) { lock_kernel(); result = venus_fsync(inode->i_sb, coda_i2f(inode)); unlock_kernel(); diff -u --recursive --new-file v2.4.0-test8/linux/fs/coda/inode.c linux/fs/coda/inode.c --- v2.4.0-test8/linux/fs/coda/inode.c Wed Jun 21 10:10:02 2000 +++ linux/fs/coda/inode.c Thu Sep 21 09:59:46 2000 @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -48,6 +49,47 @@ statfs: coda_statfs, }; +static int get_device_index(struct coda_mount_data *data) +{ + struct file *file; + struct inode *inode; + int idx; + + if(data == NULL) { + printk("coda_read_super: Bad mount data\n"); + return -1; + } + + if(data->version != CODA_MOUNT_VERSION) { + printk("coda_read_super: Bad mount version\n"); + return -1; + } + + file = fget(data->fd); + inode = NULL; + if(file) + inode = file->f_dentry->d_inode; + + if(!inode || !S_ISCHR(inode->i_mode) || + MAJOR(inode->i_rdev) != CODA_PSDEV_MAJOR) { + if(file) + fput(file); + + printk("coda_read_super: Bad file\n"); + return -1; + } + + idx = MINOR(inode->i_rdev); + fput(file); + + if(idx < 0 || idx >= MAX_CODADEVS) { + printk("coda_read_super: Bad minor number\n"); + return -1; + } + + return idx; +} + static struct super_block * coda_read_super(struct super_block *sb, void *data, int silent) { @@ -57,23 +99,41 @@ ViceFid fid; kdev_t dev = sb->s_dev; int error; - + int idx; ENTRY; - vc = &coda_upc_comm; - sbi = &coda_super_info; + idx = get_device_index((struct coda_mount_data *) data); + + /* Ignore errors in data, for backward compatibility */ + if(idx == -1) + idx = 0; + + printk(KERN_INFO "coda_read_super: device index: %i\n", idx); + + vc = &coda_comms[idx]; + if (!vc->vc_inuse) { + printk("coda_read_super: No pseudo device\n"); + EXIT; + return NULL; + } + + if ( vc->vc_sb ) { + printk("coda_read_super: Device already mounted\n"); + EXIT; + return NULL; + } - if ( sbi->sbi_sb ) { - printk("Already mounted\n"); + sbi = kmalloc(sizeof(struct coda_sb_info), GFP_KERNEL); + if(!sbi) { EXIT; return NULL; } + vc->vc_sb = sb; + sbi->sbi_sb = sb; - sbi->sbi_psdev = psdev; sbi->sbi_vcomm = vc; - INIT_LIST_HEAD(&(sbi->sbi_cchead)); - INIT_LIST_HEAD(&(sbi->sbi_volroothead)); + INIT_LIST_HEAD(&sbi->sbi_cihead); sb->u.generic_sbp = sbi; sb->s_blocksize = 1024; /* XXXXX what do we put here?? */ @@ -100,7 +160,6 @@ printk("coda_read_super: rootinode is %ld dev %d\n", root->i_ino, root->i_dev); - sbi->sbi_root = root; sb->s_root = d_alloc_root(root); EXIT; return sb; @@ -108,9 +167,9 @@ error: EXIT; if (sbi) { - sbi->sbi_vcomm = NULL; - sbi->sbi_root = NULL; - sbi->sbi_sb = NULL; + kfree(sbi); + if(vc) + vc->vc_sb = NULL; } if (root) { iput(root); @@ -120,15 +179,16 @@ static void coda_put_super(struct super_block *sb) { - struct coda_sb_info *sb_info; + struct coda_sb_info *sbi; ENTRY; - coda_cache_clear_all(sb); - sb_info = coda_sbp(sb); - coda_super_info.sbi_sb = NULL; + sbi = coda_sbp(sb); + sbi->sbi_vcomm->vc_sb = NULL; + list_del_init(&sbi->sbi_cihead); + printk("Coda: Bye bye.\n"); - memset(sb_info, 0, sizeof(* sb_info)); + kfree(sbi); EXIT; } @@ -136,11 +196,21 @@ /* all filling in of inodes postponed until lookup */ static void coda_read_inode(struct inode *inode) { + struct coda_sb_info *sbi = coda_sbp(inode->i_sb); struct coda_inode_info *cii; ENTRY; + + if (!sbi) BUG(); + cii = ITOC(inode); - cii->c_magic = 0; - return; + if (cii->c_magic == CODA_CNODE_MAGIC) { + printk("coda_read_inode: initialized inode"); + return; + } + + memset(cii, 0, sizeof(struct coda_inode_info)); + list_add(&cii->c_cilist, &sbi->sbi_cihead); + cii->c_magic = CODA_CNODE_MAGIC; } static void coda_clear_inode(struct inode *inode) @@ -152,15 +222,13 @@ CDEBUG(D_SUPER, " inode->ino: %ld, count: %d\n", inode->i_ino, atomic_read(&inode->i_count)); - if ( inode->i_ino == CTL_INO || cii->c_magic != CODA_CNODE_MAGIC ) - goto out; + if ( cii->c_magic != CODA_CNODE_MAGIC ) + return; - lock_kernel(); + list_del_init(&cii->c_cilist); - if ( !list_empty(&cii->c_volrootlist) ) { - list_del(&cii->c_volrootlist); - INIT_LIST_HEAD(&cii->c_volrootlist); - } + if ( inode->i_ino == CTL_INO ) + goto out; if ( inode->i_mapping != &inode->i_data ) { open_inode = (struct inode *)inode->i_mapping->host; @@ -170,12 +238,11 @@ iput(open_inode); } - coda_cache_clear_inode(inode); - unlock_kernel(); - CDEBUG(D_DOWNCALL, "clearing inode: %ld, %x\n", inode->i_ino, cii->c_flags); + coda_cache_clear_inode(inode); out: inode->u.coda_i.c_magic = 0; + memset(&inode->u.coda_i.c_fid, 0, sizeof(struct ViceFid)); EXIT; } @@ -237,9 +304,4 @@ /* init_coda: used by filesystems.c to register coda */ DECLARE_FSTYPE( coda_fs_type, "coda", coda_read_super, 0); - -int init_coda_fs(void) -{ - return register_filesystem(&coda_fs_type); -} diff -u --recursive --new-file v2.4.0-test8/linux/fs/coda/pioctl.c linux/fs/coda/pioctl.c --- v2.4.0-test8/linux/fs/coda/pioctl.c Wed Jul 26 09:09:39 2000 +++ linux/fs/coda/pioctl.c Tue Sep 19 15:08:59 2000 @@ -23,13 +23,12 @@ #include #include #include -#include #include /* pioctl ops */ static int coda_ioctl_permission(struct inode *inode, int mask); static int coda_pioctl(struct inode * inode, struct file * filp, - unsigned int cmd, unsigned long arg); + unsigned int cmd, unsigned long user_data); /* exported from this file */ struct inode_operations coda_ioctl_inode_operations = @@ -52,7 +51,7 @@ } static int coda_pioctl(struct inode * inode, struct file * filp, - unsigned int cmd, unsigned long user_data) + unsigned int cmd, unsigned long user_data) { struct nameidata nd; int error; diff -u --recursive --new-file v2.4.0-test8/linux/fs/coda/psdev.c linux/fs/coda/psdev.c --- v2.4.0-test8/linux/fs/coda/psdev.c Wed Jul 12 21:58:43 2000 +++ linux/fs/coda/psdev.c Tue Sep 19 15:08:59 2000 @@ -46,21 +46,19 @@ #include #include #include -#include #include /* * Coda stuff */ extern struct file_system_type coda_fs_type; -extern int init_coda_fs(void); /* statistics */ int coda_hard = 0; /* allows signals during upcalls */ unsigned long coda_timeout = 30; /* .. secs, then signals will dequeue */ -struct coda_sb_info coda_super_info; -struct venus_comm coda_upc_comm; + +struct venus_comm coda_comms[MAX_CODADEVS]; /* * Device operations @@ -68,7 +66,7 @@ static unsigned int coda_psdev_poll(struct file *file, poll_table * wait) { - struct venus_comm *vcp = &coda_upc_comm; + struct venus_comm *vcp = (struct venus_comm *) file->private_data; unsigned int mask = POLLOUT | POLLWRNORM; poll_wait(file, &vcp->vc_waitq, wait); @@ -101,7 +99,7 @@ static ssize_t coda_psdev_write(struct file *file, const char *buf, size_t nbytes, loff_t *off) { - struct venus_comm *vcp = &coda_upc_comm; + struct venus_comm *vcp = (struct venus_comm *) file->private_data; struct upc_req *req = NULL; struct upc_req *tmp; struct list_head *lh; @@ -109,8 +107,6 @@ ssize_t retval = 0, count = 0; int error; - if ( !coda_upc_comm.vc_inuse ) - return -EIO; /* Peek at the opcode, uniquefier */ if (copy_from_user(&hdr, buf, 2 * sizeof(u_long))) return -EFAULT; @@ -123,7 +119,7 @@ union outputArgs *dcbuf; int size = sizeof(*dcbuf); - sb = coda_super_info.sbi_sb; + sb = vcp->vc_sb; if ( !sb ) { CDEBUG(D_PSDEV, "coda_psdev_write: downcall, no SB!\n"); count = nbytes; @@ -221,7 +217,7 @@ size_t nbytes, loff_t *off) { DECLARE_WAITQUEUE(wait, current); - struct venus_comm *vcp = &coda_upc_comm; + struct venus_comm *vcp = (struct venus_comm *) file->private_data; struct upc_req *req; ssize_t retval = 0, count = 0; @@ -245,7 +241,7 @@ schedule(); } - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); remove_wait_queue(&vcp->vc_waitq, &wait); if (retval) @@ -285,21 +281,32 @@ return (count ? count : retval); } - static int coda_psdev_open(struct inode * inode, struct file * file) { - struct venus_comm *vcp = &coda_upc_comm; + struct venus_comm *vcp; + int idx; ENTRY; - - /* first opener, initialize */ + lock_kernel(); + idx = MINOR(inode->i_rdev); + if(idx >= MAX_CODADEVS) + return -ENODEV; + + vcp = &coda_comms[idx]; + if(vcp->vc_inuse) + return -EBUSY; + if (!vcp->vc_inuse++) { - INIT_LIST_HEAD(&vcp->vc_pending); - INIT_LIST_HEAD(&vcp->vc_processing); - vcp->vc_seq = 0; + INIT_LIST_HEAD(&vcp->vc_pending); + INIT_LIST_HEAD(&vcp->vc_processing); + init_waitqueue_head(&vcp->vc_waitq); + vcp->vc_sb = 0; + vcp->vc_seq = 0; } + + file->private_data = vcp; - CDEBUG(D_PSDEV, "inuse: %d\n", vcp->vc_inuse); + CDEBUG(D_PSDEV, "device %i - inuse: %d\n", idx, vcp->vc_inuse); EXIT; unlock_kernel(); @@ -309,7 +316,7 @@ static int coda_psdev_release(struct inode * inode, struct file * file) { - struct venus_comm *vcp = &coda_upc_comm; + struct venus_comm *vcp = (struct venus_comm *) file->private_data; struct upc_req *req; struct list_head *lh, *next; ENTRY; @@ -369,29 +376,9 @@ release: coda_psdev_release, }; - - -int __init init_coda(void) -{ - int status; - printk(KERN_INFO "Coda Kernel/Venus communications, v4.6.0, braam@cs.cmu.edu\n"); - - status = init_coda_psdev(); - if ( status ) { - printk("Problem (%d) in init_coda_psdev\n", status); - return status; - } - - status = init_coda_fs(); - if (status) { - printk("coda: failed in init_coda_fs!\n"); - } - return status; -} - static devfs_handle_t devfs_handle = NULL; -int init_coda_psdev(void) +static int init_coda_psdev(void) { if(devfs_register_chrdev(CODA_PSDEV_MAJOR,"coda_psdev", &coda_psdev_fops)) { @@ -404,9 +391,6 @@ CODA_PSDEV_MAJOR, 0, S_IFCHR | S_IRUSR | S_IWUSR, &coda_psdev_fops, NULL); - memset(&coda_upc_comm, 0, sizeof(coda_upc_comm)); - memset(&coda_super_info, 0, sizeof(coda_super_info)); - init_waitqueue_head(&coda_upc_comm.vc_waitq); coda_sysctl_init(); @@ -414,36 +398,35 @@ } -#ifdef MODULE - MODULE_AUTHOR("Peter J. Braam "); -int init_module(void) +static int __init init_coda(void) { int status; - printk(KERN_INFO "Coda Kernel/Venus communications (module), v5.0-pre1, braam@cs.cmu.edu.\n"); + printk(KERN_INFO "Coda Kernel/Venus communications, v5.3.9, coda@cs.cmu.edu\n"); + status = init_coda_psdev(); if ( status ) { printk("Problem (%d) in init_coda_psdev\n", status); return status; } - - status = init_coda_fs(); + + status = register_filesystem(&coda_fs_type); if (status) { printk("coda: failed in init_coda_fs!\n"); } return status; } - -void cleanup_module(void) +static void __exit exit_coda(void) { int err; ENTRY; - if ( (err = unregister_filesystem(&coda_fs_type)) != 0 ) { + err = unregister_filesystem(&coda_fs_type); + if ( err != 0 ) { printk("coda: failed to unregister filesystem\n"); } devfs_unregister (devfs_handle); @@ -451,5 +434,5 @@ coda_sysctl_clean(); } -#endif - +module_init(init_coda); +module_exit(exit_coda); diff -u --recursive --new-file v2.4.0-test8/linux/fs/coda/symlink.c linux/fs/coda/symlink.c --- v2.4.0-test8/linux/fs/coda/symlink.c Wed Jul 5 11:31:01 2000 +++ linux/fs/coda/symlink.c Tue Sep 19 15:08:59 2000 @@ -20,7 +20,6 @@ #include #include #include -#include #include static int coda_symlink_filler(struct file *file, struct page *page) diff -u --recursive --new-file v2.4.0-test8/linux/fs/coda/sysctl.c linux/fs/coda/sysctl.c --- v2.4.0-test8/linux/fs/coda/sysctl.c Wed Jun 21 10:10:02 2000 +++ linux/fs/coda/sysctl.c Tue Sep 19 15:08:59 2000 @@ -76,9 +76,9 @@ /* keep this in sync with coda.h! */ char *coda_upcall_names[] = { "totals ", /* 0 */ - "noop ", /* 1 */ + "- ", /* 1 */ "root ", /* 2 */ - "sync ", /* 3 */ + "open_by_fd ", /* 3 */ "open ", /* 4 */ "close ", /* 5 */ "ioctl ", /* 6 */ @@ -96,7 +96,7 @@ "symlink ", /* 18 */ "readlink ", /* 19 */ "fsync ", /* 20 */ - "inactive ", /* 21 */ + "- ", /* 21 */ "vget ", /* 22 */ "signal ", /* 23 */ "replace ", /* 24 */ @@ -104,13 +104,12 @@ "purgeuser ", /* 26 */ "zapfile ", /* 27 */ "zapdir ", /* 28 */ - "noop2 ", /* 29 */ + "- ", /* 29 */ "purgefid ", /* 30 */ "open_by_path", /* 31 */ "resolve ", /* 32 */ "reintegrate ", /* 33 */ - "statfs ", /* 34 */ - "make_cinode " /* 35 */ + "statfs " /* 34 */ }; diff -u --recursive --new-file v2.4.0-test8/linux/fs/coda/upcall.c linux/fs/coda/upcall.c --- v2.4.0-test8/linux/fs/coda/upcall.c Sun Sep 3 11:46:40 2000 +++ linux/fs/coda/upcall.c Tue Sep 19 15:08:59 2000 @@ -543,7 +543,8 @@ goto exit; } - error = coda_upcall(coda_sbp(sb), insize, &outsize, inp); + error = coda_upcall(coda_sbp(sb), SIZE(ioctl) + data->vi.in_size, + &outsize, inp); if (error) { printk("coda_pioctl: Venus returns: %d for %s\n", @@ -607,7 +608,8 @@ * */ -static inline unsigned long coda_waitfor_upcall(struct upc_req *vmp) +static inline unsigned long coda_waitfor_upcall(struct upc_req *vmp, + struct venus_comm *vcommp) { DECLARE_WAITQUEUE(wait, current); struct timeval begin = { 0, 0 }, end = { 0, 0 }; @@ -625,7 +627,7 @@ set_current_state(TASK_UNINTERRUPTIBLE); /* venus died */ - if ( !coda_upc_comm.vc_inuse ) + if ( !vcommp->vc_inuse ) break; /* got a reply */ @@ -645,7 +647,7 @@ schedule(); } remove_wait_queue(&vmp->uc_sleep, &wait); - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); if (coda_upcall_timestamping && begin.tv_sec != 0) { do_gettimeofday(&end); @@ -685,9 +687,9 @@ struct upc_req *req; int error = 0; -ENTRY; + ENTRY; - vcommp = &coda_upc_comm; + vcommp = sbi->sbi_vcomm; if ( !vcommp->vc_inuse ) { printk("No pseudo device in upcall comms at %p\n", vcommp); return -ENXIO; @@ -724,7 +726,7 @@ * ENODEV. */ /* Go to sleep. Wake up on signals only after the timeout. */ - runtime = coda_waitfor_upcall(req); + runtime = coda_waitfor_upcall(req, vcommp); coda_upcall_stats(((union inputArgs *)buffer)->ih.opcode, runtime); CDEBUG(D_TIMING, "opc: %d time: %ld uniq: %d size: %d\n", @@ -738,11 +740,6 @@ if (req->uc_flags & REQ_WRITE) { out = (union outputArgs *)req->uc_data; /* here we map positive Venus errors to kernel errors */ - if ( out->oh.result < 0 ) { - printk("Tell Peter: Venus returns negative error %ld, for oc %ld!\n", - out->oh.result, out->oh.opcode); - out->oh.result = EINTR; - } error = -out->oh.result; CDEBUG(D_UPCALL, "upcall: (u,o,r) (%ld, %ld, %ld) out at %p\n", @@ -855,7 +852,7 @@ case CODA_FLUSH : { clstats(CODA_FLUSH); CDEBUG(D_DOWNCALL, "CODA_FLUSH\n"); - coda_cache_clear_all(sb); + coda_cache_clear_all(sb, NULL); shrink_dcache_sb(sb); coda_flag_inode(sb->s_root->d_inode, C_FLUSH); return(0); @@ -869,7 +866,7 @@ return 0; } clstats(CODA_PURGEUSER); - coda_cache_clear_cred(sb, cred); + coda_cache_clear_all(sb, cred); return(0); } diff -u --recursive --new-file v2.4.0-test8/linux/fs/cramfs/uncompress.c linux/fs/cramfs/uncompress.c --- v2.4.0-test8/linux/fs/cramfs/uncompress.c Wed Apr 12 09:47:29 2000 +++ linux/fs/cramfs/uncompress.c Sun Oct 1 20:35:16 2000 @@ -20,7 +20,7 @@ #include "inflate/zlib.h" static z_stream stream; -static int initialized = 0; +static int initialized; /* Returns length of decompressed data. */ int cramfs_uncompress_block(void *dst, int dstlen, void *src, int srclen) diff -u --recursive --new-file v2.4.0-test8/linux/fs/dcache.c linux/fs/dcache.c --- v2.4.0-test8/linux/fs/dcache.c Fri Aug 11 19:14:46 2000 +++ linux/fs/dcache.c Sun Oct 1 19:55:17 2000 @@ -551,20 +551,29 @@ * ... * 6 - base-level: try to shrink a bit. */ -int shrink_dcache_memory(int priority, unsigned int gfp_mask) +void shrink_dcache_memory(int priority, unsigned int gfp_mask) { int count = 0; + + /* + * Nasty deadlock avoidance. + * + * ext2_new_block->getblk->GFP->shrink_dcache_memory->prune_dcache-> + * prune_one_dentry->dput->dentry_iput->iput->inode->i_sb->s_op-> + * put_inode->ext2_discard_prealloc->ext2_free_blocks->lock_super-> + * DEADLOCK. + * + * We should make sure we don't hold the superblock lock over + * block allocations, but for now: + */ + if (!(gfp_mask & __GFP_IO)) + return; + if (priority) count = dentry_stat.nr_unused / priority; + prune_dcache(count); - /* FIXME: kmem_cache_shrink here should tell us - the number of pages freed, and it should - work in a __GFP_DMA/__GFP_HIGHMEM behaviour - to free only the interesting pages in - function of the needs of the current allocation. */ kmem_cache_shrink(dentry_cache); - - return 0; } #define NAME_ALLOC_LEN(len) ((len+16) & ~15) @@ -1248,7 +1257,7 @@ panic("Cannot create buffer head SLAB cache"); names_cachep = kmem_cache_create("names_cache", - PAGE_SIZE, 0, + PATH_MAX + 1, 0, SLAB_HWCACHE_ALIGN, NULL, NULL); if (!names_cachep) panic("Cannot create names SLAB cache"); diff -u --recursive --new-file v2.4.0-test8/linux/fs/devices.c linux/fs/devices.c --- v2.4.0-test8/linux/fs/devices.c Fri Jul 28 12:39:00 2000 +++ linux/fs/devices.c Sun Oct 1 20:35:16 2000 @@ -36,9 +36,7 @@ }; static rwlock_t chrdevs_lock = RW_LOCK_UNLOCKED; -static struct device_struct chrdevs[MAX_CHRDEV] = { - { NULL, NULL }, -}; +static struct device_struct chrdevs[MAX_CHRDEV]; extern int get_blkdev_list(char *); diff -u --recursive --new-file v2.4.0-test8/linux/fs/dnotify.c linux/fs/dnotify.c --- v2.4.0-test8/linux/fs/dnotify.c Wed Dec 31 16:00:00 1969 +++ linux/fs/dnotify.c Fri Sep 22 14:21:18 2000 @@ -0,0 +1,140 @@ +/* + * Directory notifications for Linux. + * + * Copyright (C) 2000 Stephen Rothwell + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ +#include +#include +#include +#include +#include +#include + +extern void send_sigio(struct fown_struct *fown, int fd, int band); + +int dir_notify_enable = 1; + +static rwlock_t dn_lock = RW_LOCK_UNLOCKED; +static kmem_cache_t *dn_cache; + +static void redo_inode_mask(struct inode *inode) +{ + unsigned long new_mask; + struct dnotify_struct *dn; + + new_mask = 0; + for (dn = inode->i_dnotify; dn != NULL; dn = dn->dn_next) + new_mask |= dn->dn_mask & ~DN_MULTISHOT; + inode->i_dnotify_mask = new_mask; +} + +int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg) +{ + struct dnotify_struct *dn = NULL; + struct dnotify_struct *odn; + struct dnotify_struct **prev; + struct inode *inode; + int turning_off = (arg & ~DN_MULTISHOT) == 0; + + if (!turning_off && !dir_notify_enable) + return -EINVAL; + inode = filp->f_dentry->d_inode; + if (!S_ISDIR(inode->i_mode)) + return -ENOTDIR; + if (!turning_off) { + dn = kmem_cache_alloc(dn_cache, SLAB_KERNEL); + if (dn == NULL) + return -ENOMEM; + } + write_lock(&dn_lock); + prev = &inode->i_dnotify; + for (odn = *prev; odn != NULL; prev = &odn->dn_next, odn = *prev) + if (odn->dn_filp == filp) + break; + if (odn != NULL) { + if (turning_off) { + *prev = odn->dn_next; + redo_inode_mask(inode); + dn = odn; + goto out_free; + } + odn->dn_fd = fd; + odn->dn_mask |= arg; + inode->i_dnotify_mask |= arg & ~DN_MULTISHOT; + goto out_free; + } + if (turning_off) + goto out; + filp->f_owner.pid = current->pid; + filp->f_owner.uid = current->uid; + filp->f_owner.euid = current->euid; + dn->dn_magic = DNOTIFY_MAGIC; + dn->dn_mask = arg; + dn->dn_fd = fd; + dn->dn_filp = filp; + inode->i_dnotify_mask |= arg & ~DN_MULTISHOT; + dn->dn_next = inode->i_dnotify; + inode->i_dnotify = dn; +out: + write_unlock(&dn_lock); + return 0; +out_free: + kmem_cache_free(dn_cache, dn); + goto out; +} + +void __inode_dir_notify(struct inode *inode, unsigned long event) +{ + struct dnotify_struct * dn; + struct dnotify_struct **prev; + struct fown_struct * fown; + int changed = 0; + + write_lock(&dn_lock); + prev = &inode->i_dnotify; + while ((dn = *prev) != NULL) { + if ((dn->dn_mask & event) == 0) { + prev = &dn->dn_next; + continue; + } + if (dn->dn_magic != DNOTIFY_MAGIC) { + printk(KERN_ERR "__inode_dir_notify: bad magic " + "number in dnotify_struct!\n"); + return; + } + fown = &dn->dn_filp->f_owner; + if (fown->pid) + send_sigio(fown, dn->dn_fd, POLL_MSG); + if (dn->dn_mask & DN_MULTISHOT) + prev = &dn->dn_next; + else { + *prev = dn->dn_next; + changed = 1; + kmem_cache_free(dn_cache, dn); + } + } + if (changed) + redo_inode_mask(inode); + write_unlock(&dn_lock); +} + +static int __init dnotify_init(void) +{ + dn_cache = kmem_cache_create("dnotify cache", + sizeof(struct dnotify_struct), 0, 0, NULL, NULL); + if (!dn_cache) + panic("cannot create dnotify slab cache"); + return 0; +} + +module_init(dnotify_init) diff -u --recursive --new-file v2.4.0-test8/linux/fs/dquot.c linux/fs/dquot.c --- v2.4.0-test8/linux/fs/dquot.c Tue Sep 5 13:59:18 2000 +++ linux/fs/dquot.c Wed Sep 27 14:12:08 2000 @@ -1285,12 +1285,15 @@ blocks = isize_to_blocks(inode->i_size, BLOCK_SIZE_BITS); else blocks = (inode->i_blocks >> 1); - for (cnt = 0; cnt < MAXQUOTAS; cnt++) + for (cnt = 0; cnt < MAXQUOTAS; cnt++) { + if (!transfer_to[cnt]) + continue; if (check_idq(transfer_to[cnt], 1) == NO_QUOTA || check_bdq(transfer_to[cnt], blocks, 0) == NO_QUOTA) { cnt = MAXQUOTAS; goto put_all; } + } if ((error = notify_change(dentry, iattr))) goto put_all; diff -u --recursive --new-file v2.4.0-test8/linux/fs/ext2/balloc.c linux/fs/ext2/balloc.c --- v2.4.0-test8/linux/fs/ext2/balloc.c Tue Sep 5 14:07:29 2000 +++ linux/fs/ext2/balloc.c Wed Sep 27 13:41:33 2000 @@ -13,6 +13,7 @@ #include #include +#include #include #include diff -u --recursive --new-file v2.4.0-test8/linux/fs/ext2/bitmap.c linux/fs/ext2/bitmap.c --- v2.4.0-test8/linux/fs/ext2/bitmap.c Thu Dec 2 15:24:49 1999 +++ linux/fs/ext2/bitmap.c Wed Sep 27 13:41:33 2000 @@ -8,7 +8,7 @@ */ #include - +#include static int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0}; diff -u --recursive --new-file v2.4.0-test8/linux/fs/ext2/dir.c linux/fs/ext2/dir.c --- v2.4.0-test8/linux/fs/ext2/dir.c Fri Aug 11 14:29:01 2000 +++ linux/fs/ext2/dir.c Wed Sep 27 13:41:33 2000 @@ -19,6 +19,7 @@ */ #include +#include static unsigned char ext2_filetype_table[] = { DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK diff -u --recursive --new-file v2.4.0-test8/linux/fs/ext2/file.c linux/fs/ext2/file.c --- v2.4.0-test8/linux/fs/ext2/file.c Thu Jul 27 19:27:34 2000 +++ linux/fs/ext2/file.c Wed Sep 27 13:41:33 2000 @@ -19,6 +19,7 @@ */ #include +#include #include static loff_t ext2_file_lseek(struct file *, loff_t, int); diff -u --recursive --new-file v2.4.0-test8/linux/fs/ext2/fsync.c linux/fs/ext2/fsync.c --- v2.4.0-test8/linux/fs/ext2/fsync.c Thu Jun 29 15:53:57 2000 +++ linux/fs/ext2/fsync.c Wed Sep 27 13:41:33 2000 @@ -23,6 +23,7 @@ */ #include +#include #include #include diff -u --recursive --new-file v2.4.0-test8/linux/fs/ext2/ialloc.c linux/fs/ext2/ialloc.c --- v2.4.0-test8/linux/fs/ext2/ialloc.c Tue Sep 5 14:07:29 2000 +++ linux/fs/ext2/ialloc.c Wed Sep 27 13:41:33 2000 @@ -14,6 +14,7 @@ #include #include +#include #include #include diff -u --recursive --new-file v2.4.0-test8/linux/fs/ext2/inode.c linux/fs/ext2/inode.c --- v2.4.0-test8/linux/fs/ext2/inode.c Tue Sep 5 19:01:29 2000 +++ linux/fs/ext2/inode.c Wed Sep 27 13:41:33 2000 @@ -23,6 +23,7 @@ */ #include +#include #include #include #include diff -u --recursive --new-file v2.4.0-test8/linux/fs/ext2/ioctl.c linux/fs/ext2/ioctl.c --- v2.4.0-test8/linux/fs/ext2/ioctl.c Thu Aug 3 17:07:34 2000 +++ linux/fs/ext2/ioctl.c Wed Sep 27 13:41:33 2000 @@ -8,6 +8,7 @@ */ #include +#include #include #include diff -u --recursive --new-file v2.4.0-test8/linux/fs/ext2/namei.c linux/fs/ext2/namei.c --- v2.4.0-test8/linux/fs/ext2/namei.c Tue Sep 5 14:07:29 2000 +++ linux/fs/ext2/namei.c Wed Sep 27 13:41:33 2000 @@ -19,6 +19,7 @@ */ #include +#include #include #include diff -u --recursive --new-file v2.4.0-test8/linux/fs/ext2/super.c linux/fs/ext2/super.c --- v2.4.0-test8/linux/fs/ext2/super.c Tue Sep 5 14:07:29 2000 +++ linux/fs/ext2/super.c Wed Sep 27 13:41:33 2000 @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -167,7 +168,7 @@ else if (!strcmp (this_char, "errors")) { if (!value || !*value) { printk ("EXT2-fs: the errors option requires " - "an argument"); + "an argument\n"); return 0; } if (!strcmp (value, "continue")) { diff -u --recursive --new-file v2.4.0-test8/linux/fs/ext2/symlink.c linux/fs/ext2/symlink.c --- v2.4.0-test8/linux/fs/ext2/symlink.c Fri Apr 7 13:38:00 2000 +++ linux/fs/ext2/symlink.c Wed Sep 27 13:41:33 2000 @@ -18,6 +18,7 @@ */ #include +#include static int ext2_readlink(struct dentry *dentry, char *buffer, int buflen) { diff -u --recursive --new-file v2.4.0-test8/linux/fs/fcntl.c linux/fs/fcntl.c --- v2.4.0-test8/linux/fs/fcntl.c Sat Aug 12 19:48:04 2000 +++ linux/fs/fcntl.c Fri Sep 22 14:21:18 2000 @@ -4,8 +4,10 @@ * Copyright (C) 1991, 1992 Linus Torvalds */ +#include #include #include +#include #include #include @@ -14,6 +16,8 @@ #include extern int sock_fcntl (struct file *, unsigned int cmd, unsigned long arg); +extern int fcntl_setlease(unsigned int fd, struct file *filp, long arg); +extern int fcntl_getlease(struct file *filp); /* Expand files. Return <0 on error; 0 nothing done; 1 files expanded, * we may have blocked. @@ -195,6 +199,7 @@ static int setfl(int fd, struct file * filp, unsigned long arg) { struct inode * inode = filp->f_dentry->d_inode; + int error; /* * In the case of an append-only file, O_APPEND @@ -205,8 +210,11 @@ /* Did FASYNC state change? */ if ((arg ^ filp->f_flags) & FASYNC) { - if (filp->f_op && filp->f_op->fasync) - filp->f_op->fasync(fd, filp, (arg & FASYNC) != 0); + if (filp->f_op && filp->f_op->fasync) { + error = filp->f_op->fasync(fd, filp, (arg & FASYNC) != 0); + if (error < 0) + return error; + } } /* required for strict SunOS emulation */ @@ -221,11 +229,10 @@ static long do_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg, struct file * filp) { - long err = 0; + long err = -EINVAL; switch (cmd) { case F_DUPFD: - err = -EINVAL; if (arg < NR_OPEN) { get_file(filp); err = dupfd(filp, arg); @@ -235,20 +242,21 @@ err = get_close_on_exec(fd); break; case F_SETFD: + err = 0; set_close_on_exec(fd, arg&1); break; case F_GETFL: err = filp->f_flags; break; case F_SETFL: + lock_kernel(); err = setfl(fd, filp, arg); + unlock_kernel(); break; case F_GETLK: err = fcntl_getlk(fd, (struct flock *) arg); break; case F_SETLK: - err = fcntl_setlk(fd, cmd, (struct flock *) arg); - break; case F_SETLKW: err = fcntl_setlk(fd, cmd, (struct flock *) arg); break; @@ -263,11 +271,14 @@ err = filp->f_owner.pid; break; case F_SETOWN: + lock_kernel(); filp->f_owner.pid = arg; filp->f_owner.uid = current->uid; filp->f_owner.euid = current->euid; + err = 0; if (S_ISSOCK (filp->f_dentry->d_inode->i_mode)) err = sock_fcntl (filp, F_SETOWN, arg); + unlock_kernel(); break; case F_GETSIG: err = filp->f_owner.signum; @@ -275,12 +286,20 @@ case F_SETSIG: /* arg == 0 restores default behaviour. */ if (arg < 0 || arg > _NSIG) { - err = -EINVAL; break; } err = 0; filp->f_owner.signum = arg; break; + case F_GETLEASE: + err = fcntl_getlease(filp); + break; + case F_SETLEASE: + err = fcntl_setlease(fd, filp, arg); + break; + case F_NOTIFY: + err = fcntl_dirnotify(fd, filp, arg); + break; default: /* sockets need a few special fcntls. */ err = -EINVAL; @@ -301,9 +320,7 @@ if (!filp) goto out; - lock_kernel(); err = do_fcntl(fd, cmd, arg, filp); - unlock_kernel(); fput(filp); out: @@ -356,7 +373,7 @@ static void send_sigio_to_task(struct task_struct *p, struct fown_struct *fown, - struct fasync_struct *fa, + int fd, int reason) { if ((fown->euid != 0) && @@ -384,7 +401,7 @@ si.si_band = ~0L; else si.si_band = band_table[reason - POLL_IN]; - si.si_fd = fa->fa_fd; + si.si_fd = fd; if (!send_sig_info(fown->signum, &si, p)) break; /* fall-through: fall back on the old plain SIGIO signal */ @@ -393,15 +410,14 @@ } } -static void send_sigio(struct fown_struct *fown, struct fasync_struct *fa, - int band) +void send_sigio(struct fown_struct *fown, int fd, int band) { struct task_struct * p; int pid = fown->pid; read_lock(&tasklist_lock); if ( (pid > 0) && (p = find_task_by_pid(pid)) ) { - send_sigio_to_task(p, fown, fa, band); + send_sigio_to_task(p, fown, fd, band); goto out; } for_each_task(p) { @@ -410,18 +426,20 @@ match = -p->pgrp; if (pid != match) continue; - send_sigio_to_task(p, fown, fa, band); + send_sigio_to_task(p, fown, fd, band); } out: read_unlock(&tasklist_lock); } +static rwlock_t fasync_lock = RW_LOCK_UNLOCKED; +static kmem_cache_t *fasync_cache; + /* * fasync_helper() is used by some character device drivers (mainly mice) * to set up the fasync queue. It returns negative on error, 0 if it did * no changes and positive if it added/deleted the entry. */ -static rwlock_t fasync_lock = RW_LOCK_UNLOCKED; int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp) { struct fasync_struct *fa, **fp; @@ -429,7 +447,7 @@ int result = 0; if (on) { - new = kmalloc(sizeof(struct fasync_struct), GFP_KERNEL); + new = kmem_cache_alloc(fasync_cache, SLAB_KERNEL); if (!new) return -ENOMEM; } @@ -438,10 +456,10 @@ if (fa->fa_file == filp) { if(on) { fa->fa_fd = fd; - kfree(new); + kmem_cache_free(fasync_cache, new); } else { *fp = fa->fa_next; - kfree(fa); + kmem_cache_free(fasync_cache, fa); result = 1; } goto out; @@ -466,7 +484,7 @@ while (fa) { struct fown_struct * fown; if (fa->magic != FASYNC_MAGIC) { - printk("kill_fasync: bad magic number in " + printk(KERN_ERR "kill_fasync: bad magic number in " "fasync_struct!\n"); return; } @@ -475,7 +493,7 @@ queued signum: SIGURG has its own default signalling mechanism. */ if (fown->pid && !(sig == SIGURG && fown->signum == 0)) - send_sigio(fown, fa, band); + send_sigio(fown, fa->fa_fd, band); fa = fa->fa_next; } } @@ -486,3 +504,14 @@ __kill_fasync(*fp, sig, band); read_unlock(&fasync_lock); } + +static int __init fasync_init(void) +{ + fasync_cache = kmem_cache_create("fasync cache", + sizeof(struct fasync_struct), 0, 0, NULL, NULL); + if (!fasync_cache) + panic("cannot create fasync slab cache"); + return 0; +} + +module_init(fasync_init) diff -u --recursive --new-file v2.4.0-test8/linux/fs/file_table.c linux/fs/file_table.c --- v2.4.0-test8/linux/fs/file_table.c Thu Jul 27 16:47:16 2000 +++ linux/fs/file_table.c Tue Sep 19 08:31:53 2000 @@ -98,48 +98,35 @@ return 0; } -/* - * Called when retiring the last use of a file pointer. - */ -static void __fput(struct file *filp) +void fput(struct file * file) { - struct dentry * dentry = filp->f_dentry; - struct vfsmount * mnt = filp->f_vfsmnt; + struct dentry * dentry = file->f_dentry; + struct vfsmount * mnt = file->f_vfsmnt; struct inode * inode = dentry->d_inode; - if (filp->f_op && filp->f_op->release) - filp->f_op->release(inode, filp); - fops_put(filp->f_op); - filp->f_dentry = NULL; - filp->f_vfsmnt = NULL; - if (filp->f_mode & FMODE_WRITE) - put_write_access(inode); - dput(dentry); - if (mnt) - mntput(mnt); -} - -static void _fput(struct file *file) -{ - locks_remove_flock(file); - __fput(file); - - file_list_lock(); - list_del(&file->f_list); - list_add(&file->f_list, &free_list); - files_stat.nr_free_files++; - file_list_unlock(); -} - -void fput(struct file * file) -{ - if (atomic_dec_and_test(&file->f_count)) - _fput(file); + if (atomic_dec_and_test(&file->f_count)) { + locks_remove_flock(file); + if (file->f_op && file->f_op->release) + file->f_op->release(inode, file); + fops_put(file->f_op); + file->f_dentry = NULL; + file->f_vfsmnt = NULL; + if (file->f_mode & FMODE_WRITE) + put_write_access(inode); + dput(dentry); + if (mnt) + mntput(mnt); + file_list_lock(); + list_del(&file->f_list); + list_add(&file->f_list, &free_list); + files_stat.nr_free_files++; + file_list_unlock(); + } } struct file * fget(unsigned int fd) { - struct file * file = NULL; + struct file * file; struct files_struct *files = current->files; read_lock(&files->file_lock); diff -u --recursive --new-file v2.4.0-test8/linux/fs/filesystems.c linux/fs/filesystems.c --- v2.4.0-test8/linux/fs/filesystems.c Sat Sep 2 11:33:30 2000 +++ linux/fs/filesystems.c Mon Sep 25 17:05:01 2000 @@ -21,10 +21,6 @@ #include #include -#ifdef CONFIG_CODA_FS -extern int init_coda(void); -#endif - #ifdef CONFIG_DEVPTS_FS extern int init_devpts_fs(void); #endif @@ -35,10 +31,6 @@ #ifdef CONFIG_NFS_FS init_nfs_fs(); -#endif - -#ifdef CONFIG_CODA_FS - init_coda(); #endif #ifdef CONFIG_DEVPTS_FS diff -u --recursive --new-file v2.4.0-test8/linux/fs/inode.c linux/fs/inode.c --- v2.4.0-test8/linux/fs/inode.c Thu Aug 17 11:27:25 2000 +++ linux/fs/inode.c Sun Oct 1 20:35:16 2000 @@ -71,7 +71,7 @@ int nr_inodes; int nr_unused; int dummy[5]; -} inodes_stat = {0, 0,}; +} inodes_stat; static kmem_cache_t * inode_cachep; @@ -454,21 +454,25 @@ dispose_list(freeable); } -int shrink_icache_memory(int priority, int gfp_mask) +void shrink_icache_memory(int priority, int gfp_mask) { int count = 0; - + + /* + * Nasty deadlock avoidance.. + * + * We may hold various FS locks, and we don't + * want to recurse into the FS that called us + * in clear_inode() and friends.. + */ + if (!(gfp_mask & __GFP_IO)) + return; + if (priority) count = inodes_stat.nr_unused / priority; + prune_icache(count); - /* FIXME: kmem_cache_shrink here should tell us - the number of pages freed, and it should - work in a __GFP_DMA/__GFP_HIGHMEM behaviour - to free only the interesting pages in - function of the needs of the current allocation. */ kmem_cache_shrink(inode_cachep); - - return 0; } /* @@ -509,9 +513,9 @@ */ static void clean_inode(struct inode *inode) { - static struct address_space_operations empty_aops = {}; - static struct inode_operations empty_iops = {}; - static struct file_operations empty_fops = {}; + static struct address_space_operations empty_aops; + static struct inode_operations empty_iops; + static struct file_operations empty_fops; memset(&inode->u, 0, sizeof(inode->u)); inode->i_sock = 0; inode->i_op = &empty_iops; diff -u --recursive --new-file v2.4.0-test8/linux/fs/lockd/clntlock.c linux/fs/lockd/clntlock.c --- v2.4.0-test8/linux/fs/lockd/clntlock.c Thu Jun 29 14:06:47 2000 +++ linux/fs/lockd/clntlock.c Fri Sep 22 14:21:18 2000 @@ -168,6 +168,7 @@ * reclaim is in progress */ lock_kernel(); lockd_up(); + down(&file_lock_sem); /* First, reclaim all locks that have been granted previously. */ restart: @@ -185,6 +186,7 @@ } tmp = tmp->next; } + up(&file_lock_sem); host->h_reclaiming = 0; wake_up(&host->h_gracewait); diff -u --recursive --new-file v2.4.0-test8/linux/fs/lockd/clntproc.c linux/fs/lockd/clntproc.c --- v2.4.0-test8/linux/fs/lockd/clntproc.c Wed Jun 21 12:43:38 2000 +++ linux/fs/lockd/clntproc.c Thu Sep 21 13:38:58 2000 @@ -47,7 +47,6 @@ struct nlm_args *argp = &req->a_args; struct nlm_lock *lock = &argp->lock; - memset(argp, 0, sizeof(*argp)); nlmclnt_next_cookie(&argp->cookie); argp->state = nsm_local_state; memcpy(&lock->fh, NFS_FH(fl->fl_file->f_dentry), sizeof(struct nfs_fh)); @@ -55,7 +54,7 @@ lock->oh.data = req->a_owner; lock->oh.len = sprintf(req->a_owner, "%d@%s", current->pid, system_utsname.nodename); - lock->fl = *fl; + locks_copy_lock(&lock->fl, fl); } /* @@ -157,7 +156,9 @@ call->a_flags = RPC_TASK_ASYNC; } else { spin_unlock_irqrestore(¤t->sigmask_lock, flags); - call->a_flags = 0; + memset(call, 0, sizeof(*call)); + locks_init_lock(&call->a_args.lock.fl); + locks_init_lock(&call->a_res.lock.fl); } call->a_host = host; @@ -214,8 +215,12 @@ while (!signalled()) { call = (struct nlm_rqst *) kmalloc(sizeof(struct nlm_rqst), GFP_KERNEL); - if (call) + if (call) { + memset(call, 0, sizeof(*call)); + locks_init_lock(&call->a_args.lock.fl); + locks_init_lock(&call->a_res.lock.fl); return call; + } printk("nlmclnt_alloc_call: failed, waiting for memory\n"); current->state = TASK_INTERRUPTIBLE; schedule_timeout(5*HZ); @@ -389,7 +394,7 @@ * Report the conflicting lock back to the application. * FIXME: Is it OK to report the pid back as well? */ - memcpy(fl, &req->a_res.lock.fl, sizeof(*fl)); + locks_copy_lock(fl, &req->a_res.lock.fl); /* fl->fl_pid = 0; */ } else { return nlm_stat_to_errno(req->a_res.status); @@ -476,6 +481,9 @@ int status; req = &reqst; + memset(req, 0, sizeof(*req)); + locks_init_lock(&req->a_args.lock.fl); + locks_init_lock(&req->a_res.lock.fl); req->a_host = host; req->a_flags = 0; diff -u --recursive --new-file v2.4.0-test8/linux/fs/lockd/host.c linux/fs/lockd/host.c --- v2.4.0-test8/linux/fs/lockd/host.c Wed Jun 21 12:43:38 2000 +++ linux/fs/lockd/host.c Sun Oct 1 20:35:16 2000 @@ -29,8 +29,8 @@ #define NLM_HOST_ADDR(sv) (&(sv)->s_nlmclnt->cl_xprt->addr) static struct nlm_host * nlm_hosts[NLM_HOST_NRHASH]; -static unsigned long next_gc = 0; -static int nrhosts = 0; +static unsigned long next_gc; +static int nrhosts; static DECLARE_MUTEX(nlm_host_sema); diff -u --recursive --new-file v2.4.0-test8/linux/fs/lockd/svc.c linux/fs/lockd/svc.c --- v2.4.0-test8/linux/fs/lockd/svc.c Fri Jun 23 21:12:53 2000 +++ linux/fs/lockd/svc.c Sun Oct 1 20:35:16 2000 @@ -39,12 +39,12 @@ #define ALLOWED_SIGS (sigmask(SIGKILL)) extern struct svc_program nlmsvc_program; -struct nlmsvc_binding * nlmsvc_ops = NULL; +struct nlmsvc_binding * nlmsvc_ops; static DECLARE_MUTEX(nlmsvc_sema); -static unsigned int nlmsvc_users = 0; -static pid_t nlmsvc_pid = 0; -unsigned long nlmsvc_grace_period = 0; -unsigned long nlmsvc_timeout = 0; +static unsigned int nlmsvc_users; +static pid_t nlmsvc_pid; +unsigned long nlmsvc_grace_period; +unsigned long nlmsvc_timeout; static DECLARE_MUTEX_LOCKED(lockd_start); static DECLARE_WAIT_QUEUE_HEAD(lockd_exit); @@ -53,7 +53,7 @@ * Currently the following can be set only at insmod time. * Ideally, they would be accessible through the sysctl interface. */ -unsigned long nlm_grace_period = 0; +unsigned long nlm_grace_period; unsigned long nlm_timeout = LOCKD_DFLT_TIMEO; /* diff -u --recursive --new-file v2.4.0-test8/linux/fs/lockd/svclock.c linux/fs/lockd/svclock.c --- v2.4.0-test8/linux/fs/lockd/svclock.c Thu Jun 29 14:06:47 2000 +++ linux/fs/lockd/svclock.c Thu Sep 21 13:38:58 2000 @@ -170,6 +170,8 @@ if (!(block = (struct nlm_block *) kmalloc(sizeof(*block), GFP_KERNEL))) goto failed; memset(block, 0, sizeof(*block)); + locks_init_lock(&block->b_call.a_args.lock.fl); + locks_init_lock(&block->b_call.a_res.lock.fl); /* Set notifier function for VFS, and init args */ lock->fl.fl_notify = nlmsvc_notify_blocked; @@ -347,7 +349,7 @@ /* Append to list of blocked */ nlmsvc_insert_block(block, NLM_NEVER); - if (!list_empty(&block->b_call.a_args.lock.fl.fl_block)) { + if (list_empty(&block->b_call.a_args.lock.fl.fl_list)) { /* Now add block to block list of the conflicting lock if we haven't done so. */ dprintk("lockd: blocking on this lock.\n"); diff -u --recursive --new-file v2.4.0-test8/linux/fs/lockd/svcshare.c linux/fs/lockd/svcshare.c --- v2.4.0-test8/linux/fs/lockd/svcshare.c Tue Jun 1 23:25:47 1999 +++ linux/fs/lockd/svcshare.c Thu Sep 21 13:38:58 2000 @@ -54,7 +54,6 @@ share->s_owner.len = oh->len; share->s_next = file->f_shares; file->f_shares = share; - file->f_count += 1; update: share->s_access = argp->fsm_access; diff -u --recursive --new-file v2.4.0-test8/linux/fs/lockd/xdr.c linux/fs/lockd/xdr.c --- v2.4.0-test8/linux/fs/lockd/xdr.c Wed Jul 5 22:15:27 2000 +++ linux/fs/lockd/xdr.c Thu Sep 21 13:38:58 2000 @@ -129,7 +129,7 @@ || !(p = nlm_decode_oh(p, &lock->oh))) return NULL; - memset(fl, 0, sizeof(*fl)); + locks_init_lock(fl); fl->fl_owner = current->files; fl->fl_pid = ntohl(*p++); fl->fl_flags = FL_POSIX; @@ -314,6 +314,7 @@ int len; memset(lock, 0, sizeof(*lock)); + locks_init_lock(&lock->fl); lock->fl.fl_pid = ~(u32) 0; if (!(p = nlm_decode_cookie(p, &argp->cookie)) @@ -430,6 +431,7 @@ s32 start, len, end; memset(&resp->lock, 0, sizeof(resp->lock)); + locks_init_lock(fl); excl = ntohl(*p++); fl->fl_pid = ntohl(*p++); if (!(p = nlm_decode_oh(p, &resp->lock.oh))) diff -u --recursive --new-file v2.4.0-test8/linux/fs/lockd/xdr4.c linux/fs/lockd/xdr4.c --- v2.4.0-test8/linux/fs/lockd/xdr4.c Mon Apr 10 23:02:45 2000 +++ linux/fs/lockd/xdr4.c Thu Sep 21 13:38:59 2000 @@ -131,7 +131,7 @@ || !(p = nlm4_decode_oh(p, &lock->oh))) return NULL; - memset(fl, 0, sizeof(*fl)); + locks_init_lock(fl); fl->fl_owner = current->files; fl->fl_pid = ntohl(*p++); fl->fl_flags = FL_POSIX; @@ -322,6 +322,7 @@ int len; memset(lock, 0, sizeof(*lock)); + locks_init_lock(&lock->fl); lock->fl.fl_pid = ~(u32) 0; if (!(p = nlm4_decode_cookie(p, &argp->cookie)) @@ -438,6 +439,7 @@ s64 start, end, len; memset(&resp->lock, 0, sizeof(resp->lock)); + locks_init_lock(fl); excl = ntohl(*p++); fl->fl_pid = ntohl(*p++); if (!(p = nlm4_decode_oh(p, &resp->lock.oh))) diff -u --recursive --new-file v2.4.0-test8/linux/fs/locks.c linux/fs/locks.c --- v2.4.0-test8/linux/fs/locks.c Tue Aug 29 12:41:12 2000 +++ linux/fs/locks.c Sun Oct 1 19:45:29 2000 @@ -1,3 +1,4 @@ +#define MSNFS /* HACK HACK */ /* * linux/fs/locks.c * @@ -108,25 +109,44 @@ * Use generic list implementation from . * Sped up posix_locks_deadlock by only considering blocked locks. * Matthew Wilcox , March, 2000. + * + * Leases and LOCK_MAND + * Matthew Wilcox , June, 2000. + * Stephen Rothwell , June, 2000. */ #include #include #include #include +#include +#include +#include #include +DECLARE_MUTEX(file_lock_sem); + +#define acquire_fl_sem() down(&file_lock_sem) +#define release_fl_sem() up(&file_lock_sem) + +int leases_enable = 1; +int lease_break_time = 45; + LIST_HEAD(file_lock_list); static LIST_HEAD(blocked_list); static kmem_cache_t *filelock_cache; /* Allocate an empty lock structure. */ -static struct file_lock *locks_alloc_lock(void) +static struct file_lock *locks_alloc_lock(int account) { struct file_lock *fl; + if (account && current->locks >= current->rlim[RLIMIT_LOCKS].rlim_cur) + return NULL; fl = kmem_cache_alloc(filelock_cache, SLAB_KERNEL); + if (fl) + current->locks++; return fl; } @@ -137,19 +157,38 @@ BUG(); return; } - + current->locks--; if (waitqueue_active(&fl->fl_wait)) panic("Attempting to free lock with active wait queue"); if (!list_empty(&fl->fl_block)) panic("Attempting to free lock with active block list"); - if (!list_empty(&fl->fl_link)) + if (!list_empty(&fl->fl_link) || !list_empty(&fl->fl_list)) panic("Attempting to free lock on active lock list"); kmem_cache_free(filelock_cache, fl); } +void locks_init_lock(struct file_lock *fl) +{ + INIT_LIST_HEAD(&fl->fl_link); + INIT_LIST_HEAD(&fl->fl_block); + INIT_LIST_HEAD(&fl->fl_list); + init_waitqueue_head(&fl->fl_wait); + fl->fl_next = NULL; + fl->fl_fasync = NULL; + fl->fl_owner = 0; + fl->fl_pid = 0; + fl->fl_file = NULL; + fl->fl_flags = 0; + fl->fl_type = 0; + fl->fl_start = fl->fl_end = 0; + fl->fl_notify = NULL; + fl->fl_insert = NULL; + fl->fl_remove = NULL; +} + /* * Initialises the fields of the file lock which are invariant for * free file_locks. @@ -162,16 +201,13 @@ SLAB_CTOR_CONSTRUCTOR) return; - lock->fl_next = NULL; - INIT_LIST_HEAD(&lock->fl_link); - INIT_LIST_HEAD(&lock->fl_block); - init_waitqueue_head(&lock->fl_wait); + locks_init_lock(lock); } /* * Initialize a new lock from an existing file_lock structure. */ -static void locks_copy_lock(struct file_lock *new, struct file_lock *fl) +void locks_copy_lock(struct file_lock *new, struct file_lock *fl) { new->fl_owner = fl->fl_owner; new->fl_pid = fl->fl_pid; @@ -189,7 +225,7 @@ /* Fill in a file_lock structure with an appropriate FLOCK lock. */ static struct file_lock *flock_make_lock(struct file *filp, unsigned int type) { - struct file_lock *fl = locks_alloc_lock(); + struct file_lock *fl = locks_alloc_lock(1); if (fl == NULL) return NULL; @@ -207,6 +243,20 @@ return fl; } +static int assign_type(struct file_lock *fl, int type) +{ + switch (type) { + case F_RDLCK: + case F_WRLCK: + case F_UNLCK: + fl->fl_type = type; + break; + default: + return -EINVAL; + } + return 0; +} + /* Verify a "struct flock" and copy it to a "struct file_lock" as a POSIX * style lock. */ @@ -234,6 +284,8 @@ fl->fl_end = start + l->l_len - 1; if (l->l_len > 0 && fl->fl_end < 0) return (0); + if (fl->fl_end > OFFT_OFFSET_MAX) + return 0; fl->fl_start = start; /* we record the absolute position */ if (l->l_len == 0) fl->fl_end = OFFSET_MAX; @@ -246,17 +298,7 @@ fl->fl_insert = NULL; fl->fl_remove = NULL; - switch (l->l_type) { - case F_RDLCK: - case F_WRLCK: - case F_UNLCK: - fl->fl_type = l->l_type; - break; - default: - return (0); - } - - return (1); + return (assign_type(fl, l->l_type) == 0); } #if BITS_PER_LONG == 32 @@ -310,6 +352,32 @@ } #endif +/* Allocate a file_lock initialised to this type of lease */ +static int lease_alloc(struct file *filp, int type, struct file_lock **flp) +{ + struct file_lock *fl = locks_alloc_lock(1); + if (fl == NULL) + return -ENOMEM; + + fl->fl_owner = current->files; + fl->fl_pid = current->pid; + + fl->fl_file = filp; + fl->fl_flags = FL_LEASE; + if (assign_type(fl, type) != 0) { + locks_free_lock(fl); + return -EINVAL; + } + fl->fl_start = 0; + fl->fl_end = OFFSET_MAX; + fl->fl_notify = NULL; + fl->fl_insert = NULL; + fl->fl_remove = NULL; + + *flp = fl; + return 0; +} + /* Check if two locks overlap each other. */ static inline int locks_overlap(struct file_lock *fl1, struct file_lock *fl2) @@ -335,10 +403,11 @@ */ static void locks_delete_block(struct file_lock *waiter) { - list_del(&waiter->fl_block); - INIT_LIST_HEAD(&waiter->fl_block); + list_del(&waiter->fl_list); + INIT_LIST_HEAD(&waiter->fl_list); list_del(&waiter->fl_link); INIT_LIST_HEAD(&waiter->fl_link); + waiter->fl_next = NULL; } /* Insert waiter into blocker's block list. @@ -349,15 +418,15 @@ static void locks_insert_block(struct file_lock *blocker, struct file_lock *waiter) { - if (!list_empty(&waiter->fl_block)) { + if (!list_empty(&waiter->fl_list)) { printk(KERN_ERR "locks_insert_block: removing duplicated lock " "(pid=%d %Ld-%Ld type=%d)\n", waiter->fl_pid, waiter->fl_start, waiter->fl_end, waiter->fl_type); locks_delete_block(waiter); } - list_add_tail(&waiter->fl_block, &blocker->fl_block); - list_add(&waiter->fl_link, &blocked_list); + list_add_tail(&waiter->fl_list, &blocker->fl_block); waiter->fl_next = blocker; + list_add(&waiter->fl_link, &blocked_list); } /* Wake up processes blocked waiting for blocker. @@ -367,7 +436,7 @@ static void locks_wake_up_blocks(struct file_lock *blocker, unsigned int wait) { while (!list_empty(&blocker->fl_block)) { - struct file_lock *waiter = list_entry(blocker->fl_block.next, struct file_lock, fl_block); + struct file_lock *waiter = list_entry(blocker->fl_block.next, struct file_lock, fl_list); /* N.B. Is it possible for the notify function to block?? */ if (waiter->fl_notify) waiter->fl_notify(waiter); @@ -402,10 +471,10 @@ fl->fl_insert(fl); } -/* Delete a lock and free it. - * First remove our lock from the active lock lists. Then call - * locks_wake_up_blocks() to wake up processes that are blocked - * waiting for this lock. Finally free the lock structure. +/* Delete a lock and then free it. + * Remove our lock from the lock lists, wake up processes that are blocked + * waiting for this lock, notify the FS that the lock has been cleared and + * finally free the lock. */ static void locks_delete_lock(struct file_lock **thisfl_p, unsigned int wait) { @@ -418,6 +487,12 @@ list_del(&fl->fl_link); INIT_LIST_HEAD(&fl->fl_link); + fasync_helper(0, fl->fl_file, 0, &fl->fl_fasync); + if (fl->fl_fasync != NULL){ + printk("locks_delete_lock: fasync == %p\n", fl->fl_fasync); + fl->fl_fasync = NULL; + } + if (fl->fl_remove) fl->fl_remove(fl); @@ -431,17 +506,14 @@ } /* Determine if lock sys_fl blocks lock caller_fl. Common functionality - * checks for overlapping locks and shared/exclusive status. + * checks for shared/exclusive status of overlapping locks. */ static int locks_conflict(struct file_lock *caller_fl, struct file_lock *sys_fl) { - if (!locks_overlap(caller_fl, sys_fl)) - return (0); - switch (caller_fl->fl_type) { case F_RDLCK: return (sys_fl->fl_type == F_WRLCK); - + case F_WRLCK: return (1); @@ -465,6 +537,10 @@ locks_same_owner(caller_fl, sys_fl)) return (0); + /* Check whether they overlap */ + if (!locks_overlap(caller_fl, sys_fl)) + return 0; + return (locks_conflict(caller_fl, sys_fl)); } @@ -479,21 +555,66 @@ if (!(sys_fl->fl_flags & FL_FLOCK) || (caller_fl->fl_file == sys_fl->fl_file)) return (0); +#ifdef MSNFS + if ((caller_fl->fl_type & LOCK_MAND) || (sys_fl->fl_type & LOCK_MAND)) + return 0; +#endif return (locks_conflict(caller_fl, sys_fl)); } +int interruptible_sleep_on_locked(wait_queue_head_t *fl_wait, struct semaphore *sem, int timeout) +{ + int result = 0; + wait_queue_t wait; + init_waitqueue_entry(&wait, current); + + __add_wait_queue(fl_wait, &wait); + current->state = TASK_INTERRUPTIBLE; + up(sem); + if (timeout == 0) + schedule(); + else + result = schedule_timeout(timeout); + if (signal_pending(current)) + result = -ERESTARTSYS; + down(sem); + remove_wait_queue(fl_wait, &wait); + current->state = TASK_RUNNING; + return result; +} + +static int locks_block_on(struct file_lock *blocker, struct file_lock *waiter) +{ + int result; + locks_insert_block(blocker, waiter); + result = interruptible_sleep_on_locked(&waiter->fl_wait, &file_lock_sem, 0); + locks_delete_block(waiter); + return result; +} + +static int locks_block_on_timeout(struct file_lock *blocker, struct file_lock *waiter, int time) +{ + int result; + locks_insert_block(blocker, waiter); + result = interruptible_sleep_on_locked(&waiter->fl_wait, &file_lock_sem, time); + locks_delete_block(waiter); + return result; +} + struct file_lock * posix_test_lock(struct file *filp, struct file_lock *fl) { struct file_lock *cfl; + acquire_fl_sem(); for (cfl = filp->f_dentry->d_inode->i_flock; cfl; cfl = cfl->fl_next) { if (!(cfl->fl_flags & FL_POSIX)) continue; if (posix_locks_conflict(cfl, fl)) break; } + release_fl_sem(); return (cfl); } @@ -528,9 +649,8 @@ next_task: if (caller_owner == blocked_owner && caller_pid == blocked_pid) return 1; - while (tmp != &blocked_list) { + list_for_each(tmp, &blocked_list) { struct file_lock *fl = list_entry(tmp, struct file_lock, fl_link); - tmp = tmp->next; if ((fl->fl_owner == blocked_owner) && (fl->fl_pid == blocked_pid)) { fl = fl->fl_next; @@ -550,14 +670,14 @@ /* * Search the lock list for this inode for any POSIX locks. */ - lock_kernel(); + acquire_fl_sem(); for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { if (!(fl->fl_flags & FL_POSIX)) continue; if (fl->fl_owner != owner) break; } - unlock_kernel(); + release_fl_sem(); return fl ? -EAGAIN : 0; } @@ -566,7 +686,7 @@ size_t count) { struct file_lock *fl; - struct file_lock *new_fl = locks_alloc_lock(); + struct file_lock *new_fl = locks_alloc_lock(0); int error; new_fl->fl_owner = current->files; @@ -578,36 +698,29 @@ new_fl->fl_end = offset + count - 1; error = 0; - lock_kernel(); + acquire_fl_sem(); repeat: /* Search the lock list for this inode for locks that conflict with * the proposed read/write. */ - for (fl = inode->i_flock; ; fl = fl->fl_next) { - error = 0; - if (!fl) - break; + for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { if (!(fl->fl_flags & FL_POSIX)) continue; - /* Block for writes against a "read" lock, - * and both reads and writes against a "write" lock. - */ + if (fl->fl_start > new_fl->fl_end) + break; if (posix_locks_conflict(new_fl, fl)) { error = -EAGAIN; if (filp && (filp->f_flags & O_NONBLOCK)) break; - error = -ERESTARTSYS; - if (signal_pending(current)) - break; error = -EDEADLK; if (posix_locks_deadlock(new_fl, fl)) break; - - locks_insert_block(fl, new_fl); - interruptible_sleep_on(&new_fl->fl_wait); - locks_delete_block(new_fl); - + + error = locks_block_on(fl, new_fl); + if (error != 0) + break; + /* * If we've been sleeping someone might have * changed the permissions behind our back. @@ -617,14 +730,14 @@ goto repeat; } } - unlock_kernel(); locks_free_lock(new_fl); + release_fl_sem(); return error; } -/* Try to create a FLOCK lock on filp. We always insert new FLOCK locks at - * the head of the list, but that's secret knowledge known only to the next - * two functions. +/* Try to create a FLOCK lock on filp. We always insert new FLOCK locks + * at the head of the list, but that's secret knowledge known only to + * flock_lock_file and posix_lock_file. */ static int flock_lock_file(struct file *filp, unsigned int lock_type, unsigned int wait) @@ -643,7 +756,7 @@ error = -ENOLCK; new_fl = flock_make_lock(filp, lock_type); if (!new_fl) - goto out; + return error; } error = 0; @@ -659,7 +772,7 @@ } before = &fl->fl_next; } - /* change means that we are changing the type of an existing lock, or + /* change means that we are changing the type of an existing lock, * or else unlocking it. */ if (change) { @@ -675,10 +788,6 @@ goto out; repeat: - /* Check signals each time we start */ - error = -ERESTARTSYS; - if (signal_pending(current)) - goto out; for (fl = inode->i_flock; (fl != NULL) && (fl->fl_flags & FL_FLOCK); fl = fl->fl_next) { if (!flock_locks_conflict(new_fl, fl)) @@ -686,9 +795,9 @@ error = -EAGAIN; if (!wait) goto out; - locks_insert_block(fl, new_fl); - interruptible_sleep_on(&new_fl->fl_wait); - locks_delete_block(new_fl); + error = locks_block_on(fl, new_fl); + if (error != 0) + goto out; goto repeat; } locks_insert_lock(&inode->i_flock, new_fl); @@ -701,7 +810,13 @@ return error; } -/* Add a POSIX style lock to a file. +/** + * posix_lock_file: + * @filp: The file to apply the lock to + * @caller: The lock to be applied + * @wait: 1 to retry automatically, 0 to return -EAGAIN + * + * Add a POSIX style lock to a file. * We merge adjacent locks whenever possible. POSIX locks are sorted by owner * task, then by starting address * @@ -728,12 +843,13 @@ * We may need two file_lock structures for this operation, * so we get them in advance to avoid races. */ - new_fl = locks_alloc_lock(); - new_fl2 = locks_alloc_lock(); + new_fl = locks_alloc_lock(0); + new_fl2 = locks_alloc_lock(0); error = -ENOLCK; /* "no luck" */ if (!(new_fl && new_fl2)) goto out; + acquire_fl_sem(); if (caller->fl_type != F_UNLCK) { repeat: for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { @@ -747,12 +863,10 @@ error = -EDEADLK; if (posix_locks_deadlock(caller, fl)) goto out; - error = -ERESTARTSYS; - if (signal_pending(current)) + + error = locks_block_on(fl, caller); + if (error != 0) goto out; - locks_insert_block(fl, caller); - interruptible_sleep_on(&caller->fl_wait); - locks_delete_block(caller); goto repeat; } } @@ -880,6 +994,7 @@ locks_wake_up_blocks(left, 0); } out: + release_fl_sem(); /* * Free any unused locks. */ @@ -891,6 +1006,10 @@ } static inline int flock_translate_cmd(int cmd) { +#ifdef MSNFS + if (cmd & LOCK_MAND) + return cmd & (LOCK_MAND | LOCK_RW); +#endif switch (cmd &~ LOCK_NB) { case LOCK_SH: return F_RDLCK; @@ -902,8 +1021,270 @@ return -EINVAL; } -/* flock() system call entry point. Apply a FL_FLOCK style lock to - * an open file descriptor. +/** + * __get_lease - revoke all outstanding leases on file + * @inode: the inode of the file to return + * @mode: the open mode (read or write) + * + * get_lease (inlined for speed) has checked there already + * is a lease on this file. Leases are broken on a call to open() + * or truncate(). This function can sleep unless you + * specified %O_NONBLOCK to your open(). + */ +int __get_lease(struct inode *inode, unsigned int mode) +{ + int error = 0, future; + struct file_lock *new_fl, *flock; + struct file_lock *fl; + int alloc_err; + + alloc_err = lease_alloc(NULL, 0, &new_fl); + + acquire_fl_sem(); + flock = inode->i_flock; + if (flock->fl_type & F_INPROGRESS) { + if ((mode & O_NONBLOCK) + || (flock->fl_owner == current->files)) { + error = -EWOULDBLOCK; + goto out; + } + if (alloc_err != 0) { + error = alloc_err; + goto out; + } + do { + error = locks_block_on(flock, new_fl); + if (error != 0) + goto out; + flock = inode->i_flock; + if (!(flock && (flock->fl_flags & FL_LEASE))) + goto out; + } while (flock->fl_type & F_INPROGRESS); + } + + if (mode & FMODE_WRITE) { + /* If we want write access, we have to revoke any lease. */ + future = F_UNLCK | F_INPROGRESS; + } else if (flock->fl_type & F_WRLCK) { + /* Downgrade the exclusive lease to a read-only lease. */ + future = F_RDLCK | F_INPROGRESS; + } else { + /* the existing lease was read-only, so we can read too. */ + goto out; + } + + if (alloc_err && (flock->fl_owner != current->files)) { + error = alloc_err; + goto out; + } + + fl = flock; + do { + fl->fl_type = future; + fl = fl->fl_next; + } while (fl != NULL && (fl->fl_flags & FL_LEASE)); + + kill_fasync(&flock->fl_fasync, SIGIO, POLL_MSG); + + if ((mode & O_NONBLOCK) || (flock->fl_owner == current->files)) { + error = -EWOULDBLOCK; + goto out; + } + + if (lease_break_time > 0) + error = lease_break_time * HZ; + else + error = 0; +restart: + error = locks_block_on_timeout(flock, new_fl, error); + if (error == 0) { + /* We timed out. Unilaterally break the lease. */ + locks_delete_lock(&inode->i_flock, 0); + printk(KERN_WARNING "lease timed out\n"); + } else if (error > 0) { + flock = inode->i_flock; + if (flock && (flock->fl_flags & FL_LEASE)) + goto restart; + error = 0; + } + +out: + release_fl_sem(); + if (!alloc_err) + locks_free_lock(new_fl); + return error; +} + +/** + * lease_get_mtime + * @inode: the inode + * + * This is to force NFS clients to flush their caches for files with + * exclusive leases. The justification is that if someone has an + * exclusive lease, then they could be modifiying it. + */ +time_t lease_get_mtime(struct inode *inode) +{ + struct file_lock *flock = inode->i_flock; + if (flock && (flock->fl_flags & FL_LEASE) && (flock->fl_type & F_WRLCK)) + return CURRENT_TIME; + return inode->i_mtime; +} + +/** + * fcntl_getlease - Enquire what lease is currently active + * @filp: the file + * + * The value returned by this function will be one of + * + * %F_RDLCK to indicate a read-only (type II) lease is held. + * + * %F_WRLCK to indicate an exclusive lease is held. + * + * XXX: sfr & i disagree over whether F_INPROGRESS + * should be returned to userspace. + */ +int fcntl_getlease(struct file *filp) +{ + struct file_lock *fl; + + fl = filp->f_dentry->d_inode->i_flock; + if ((fl == NULL) || ((fl->fl_flags & FL_LEASE) == 0)) + return F_UNLCK; + return fl->fl_type & ~F_INPROGRESS; +} + +/* We already had a lease on this file; just change its type */ +static int lease_modify(struct file_lock **before, int arg, int fd, struct file *filp) +{ + struct file_lock *fl = *before; + int error = assign_type(fl, arg); + if (error < 0) + goto out; + + locks_wake_up_blocks(fl, 0); + + if (arg == F_UNLCK) { + filp->f_owner.pid = 0; + filp->f_owner.uid = 0; + filp->f_owner.euid = 0; + filp->f_owner.signum = 0; + locks_delete_lock(before, 0); + fasync_helper(fd, filp, 0, &fl->fl_fasync); + } + +out: + return error; +} + +/** + * fcntl_setlease - sets a lease on an open file + * @fd: open file descriptor + * @filp: file pointer + * @arg: type of lease to obtain + * + * Call this fcntl to establish a lease on the file. + * Note that you also need to call %F_SETSIG to + * receive a signal when the lease is broken. + */ +int fcntl_setlease(unsigned int fd, struct file *filp, long arg) +{ + struct file_lock *fl, **before, **my_before = NULL; + struct dentry *dentry; + struct inode *inode; + int error, rdlease_count = 0, wrlease_count = 0; + + dentry = filp->f_dentry; + inode = dentry->d_inode; + + if ((current->fsuid != inode->i_uid) && !capable(CAP_LEASE)) + return -EACCES; + if (!S_ISREG(inode->i_mode)) + return -EINVAL; + + /* + * FIXME: What about F_RDLCK and files open for writing? + */ + if ((arg == F_WRLCK) + && ((atomic_read(&dentry->d_count) > 1) + || (atomic_read(&inode->i_count) > 1))) + return -EAGAIN; + + before = &inode->i_flock; + + acquire_fl_sem(); + + while ((fl = *before) != NULL) { + if (fl->fl_flags != FL_LEASE) + break; + if (fl->fl_file == filp) + my_before = before; + else if (fl->fl_type & F_WRLCK) + wrlease_count++; + else + rdlease_count++; + before = &fl->fl_next; + } + + if ((arg == F_RDLCK && (wrlease_count > 0)) || + (arg == F_WRLCK && ((rdlease_count + wrlease_count) > 0))) { + error = -EAGAIN; + goto out_unlock; + } + + if (my_before != NULL) { + error = lease_modify(my_before, arg, fd, filp); + goto out_unlock; + } + + if (arg == F_UNLCK) { + error = 0; + goto out_unlock; + } + + if (!leases_enable) { + error = -EINVAL; + goto out_unlock; + } + + error = lease_alloc(filp, arg, &fl); + if (error) + goto out_unlock; + + error = fasync_helper(fd, filp, 1, &fl->fl_fasync); + if (error < 0) { + locks_free_lock(fl); + goto out_unlock; + } + fl->fl_next = *before; + *before = fl; + list_add(&fl->fl_link, &file_lock_list); + filp->f_owner.pid = current->pid; + filp->f_owner.uid = current->uid; + filp->f_owner.euid = current->euid; +out_unlock: + release_fl_sem(); + return error; +} + +/** + * sys_flock: - flock() system call. + * @fd: the file descriptor to lock. + * @cmd: the type of lock to apply. + * + * Apply a %FL_FLOCK style lock to an open file descriptor. + * The @cmd can be one of + * + * %LOCK_SH -- a shared lock. + * + * %LOCK_EX -- an exclusive lock. + * + * %LOCK_UN -- remove an existing lock. + * + * %LOCK_MAND -- a `mandatory' flock. This exists to emulate Windows Share Modes. + * + * %LOCK_MAND can be combined with %LOCK_READ or %LOCK_WRITE to allow other + * processes read and write access respectively. */ asmlinkage long sys_flock(unsigned int fd, unsigned int cmd) { @@ -921,13 +1302,17 @@ type = error; error = -EBADF; - if ((type != F_UNLCK) && !(filp->f_mode & 3)) + if ((type != F_UNLCK) +#ifdef MSNFS + && !(type & LOCK_MAND) +#endif + && !(filp->f_mode & 3)) goto out_putf; - lock_kernel(); + acquire_fl_sem(); error = flock_lock_file(filp, type, (cmd & (LOCK_UN | LOCK_NB)) ? 0 : 1); - unlock_kernel(); + release_fl_sem(); out_putf: fput(filp); @@ -941,7 +1326,7 @@ int fcntl_getlk(unsigned int fd, struct flock *l) { struct file *filp; - struct file_lock *fl, *file_lock = locks_alloc_lock(); + struct file_lock *fl, file_lock; struct flock flock; int error; @@ -958,20 +1343,20 @@ goto out; error = -EINVAL; - if (!flock_to_posix_lock(filp, file_lock, &flock)) + if (!flock_to_posix_lock(filp, &file_lock, &flock)) goto out_putf; if (filp->f_op->lock) { - error = filp->f_op->lock(filp, F_GETLK, file_lock); + error = filp->f_op->lock(filp, F_GETLK, &file_lock); if (error < 0) goto out_putf; else if (error == LOCK_USE_CLNT) /* Bypass for NFS with no locking - 2.0.36 compat */ - fl = posix_test_lock(filp, file_lock); + fl = posix_test_lock(filp, &file_lock); else - fl = (file_lock->fl_type == F_UNLCK ? NULL : file_lock); + fl = (file_lock.fl_type == F_UNLCK ? NULL : &file_lock); } else { - fl = posix_test_lock(filp, file_lock); + fl = posix_test_lock(filp, &file_lock); } flock.l_type = F_UNLCK; @@ -1002,7 +1387,6 @@ out_putf: fput(filp); out: - locks_free_lock(file_lock); return error; } @@ -1012,7 +1396,7 @@ int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l) { struct file *filp; - struct file_lock *file_lock = locks_alloc_lock(); + struct file_lock *file_lock = locks_alloc_lock(0); struct flock flock; struct inode *inode; int error; @@ -1107,7 +1491,7 @@ int fcntl_getlk64(unsigned int fd, struct flock64 *l) { struct file *filp; - struct file_lock *fl, *file_lock = locks_alloc_lock(); + struct file_lock *fl, file_lock; struct flock64 flock; int error; @@ -1124,20 +1508,20 @@ goto out; error = -EINVAL; - if (!flock64_to_posix_lock(filp, file_lock, &flock)) + if (!flock64_to_posix_lock(filp, &file_lock, &flock)) goto out_putf; if (filp->f_op->lock) { - error = filp->f_op->lock(filp, F_GETLK, file_lock); + error = filp->f_op->lock(filp, F_GETLK, &file_lock); if (error < 0) goto out_putf; else if (error == LOCK_USE_CLNT) /* Bypass for NFS with no locking - 2.0.36 compat */ - fl = posix_test_lock(filp, file_lock); + fl = posix_test_lock(filp, &file_lock); else - fl = (file_lock->fl_type == F_UNLCK ? NULL : file_lock); + fl = (file_lock.fl_type == F_UNLCK ? NULL : &file_lock); } else { - fl = posix_test_lock(filp, file_lock); + fl = posix_test_lock(filp, &file_lock); } flock.l_type = F_UNLCK; @@ -1156,7 +1540,6 @@ out_putf: fput(filp); out: - locks_free_lock(file_lock); return error; } @@ -1166,7 +1549,7 @@ int fcntl_setlk64(unsigned int fd, unsigned int cmd, struct flock64 *l) { struct file *filp; - struct file_lock *file_lock = locks_alloc_lock(); + struct file_lock *file_lock = locks_alloc_lock(0); struct flock64 flock; struct inode *inode; int error; @@ -1262,17 +1645,16 @@ */ return; } - lock_kernel(); -repeat: + acquire_fl_sem(); before = &inode->i_flock; while ((fl = *before) != NULL) { if ((fl->fl_flags & FL_POSIX) && fl->fl_owner == owner) { locks_delete_lock(before, 0); - goto repeat; + continue; } before = &fl->fl_next; } - unlock_kernel(); + release_fl_sem(); } /* @@ -1281,76 +1663,104 @@ void locks_remove_flock(struct file *filp) { struct inode * inode = filp->f_dentry->d_inode; - struct file_lock file_lock, *fl; + struct file_lock *fl; struct file_lock **before; + if (!inode->i_flock) return; - lock_kernel(); -repeat: + acquire_fl_sem(); before = &inode->i_flock; + while ((fl = *before) != NULL) { - if ((fl->fl_flags & FL_FLOCK) && fl->fl_file == filp) { - int (*lock)(struct file *, int, struct file_lock *); - lock = NULL; - if (filp->f_op) - lock = filp->f_op->lock; - if (lock) { - file_lock = *fl; - file_lock.fl_type = F_UNLCK; - } + if ((fl->fl_flags & (FL_FLOCK|FL_LEASE)) + && (fl->fl_file == filp)) { locks_delete_lock(before, 0); - if (lock) { - lock(filp, F_SETLK, &file_lock); - /* List may have changed: */ - goto repeat; - } continue; - } + } before = &fl->fl_next; } - unlock_kernel(); + release_fl_sem(); } -/* The following two are for the benefit of lockd. +/** + * posix_block_lock - blocks waiting for a file lock + * @blocker: the lock which is blocking + * @waiter: the lock which conflicts and has to wait + * + * lockd needs to block waiting for locks. */ void posix_block_lock(struct file_lock *blocker, struct file_lock *waiter) { - lock_kernel(); + acquire_fl_sem(); locks_insert_block(blocker, waiter); - unlock_kernel(); + release_fl_sem(); } +/** + * posix_unblock_lock - stop waiting for a file lock + * @waiter: the lock which was waiting + * + * lockd needs to block waiting for locks. + */ void posix_unblock_lock(struct file_lock *waiter) { - locks_delete_block(waiter); - return; + acquire_fl_sem(); + if (!list_empty(&waiter->fl_list)) { + locks_delete_block(waiter); + wake_up(&waiter->fl_wait); + } + release_fl_sem(); } static void lock_get_status(char* out, struct file_lock *fl, int id, char *pfx) { - struct inode *inode; + struct inode *inode = NULL; - inode = fl->fl_file->f_dentry->d_inode; + if (fl->fl_file != NULL) + inode = fl->fl_file->f_dentry->d_inode; out += sprintf(out, "%d:%s ", id, pfx); if (fl->fl_flags & FL_POSIX) { out += sprintf(out, "%6s %s ", (fl->fl_flags & FL_ACCESS) ? "ACCESS" : "POSIX ", + (inode == NULL) ? "*NOINODE*" : (IS_MANDLOCK(inode) && (inode->i_mode & (S_IXGRP | S_ISGID)) == S_ISGID) ? "MANDATORY" : "ADVISORY "); + } else if (fl->fl_flags & FL_FLOCK) { +#ifdef MSNFS + if (fl->fl_type & LOCK_MAND) { + out += sprintf(out, "FLOCK MSNFS "); + } else +#endif + out += sprintf(out, "FLOCK ADVISORY "); + } else if (fl->fl_flags & FL_LEASE) { + out += sprintf(out, "LEASE MANDATORY "); + } else { + out += sprintf(out, "UNKNOWN UNKNOWN "); } - else { - out += sprintf(out, "FLOCK ADVISORY "); - } - out += sprintf(out, "%s ", (fl->fl_type == F_RDLCK) ? "READ " : "WRITE"); - out += sprintf(out, "%d %s:%ld %Ld %Ld ", +#ifdef MSNFS + if (fl->fl_type & LOCK_MAND) { + out += sprintf(out, "%s ", + (fl->fl_type & LOCK_READ) + ? (fl->fl_type & LOCK_WRITE) ? "RW " : "READ " + : (fl->fl_type & LOCK_WRITE) ? "WRITE" : "NONE "); + } else +#endif + out += sprintf(out, "%s ", + (fl->fl_type & F_WRLCK) ? "WRITE" : "READ "); + out += sprintf(out, "%d %s:%ld ", fl->fl_pid, - kdevname(inode->i_dev), inode->i_ino, - (long long)fl->fl_start, (long long)fl->fl_end); + inode ? kdevname(inode->i_dev) : "", + inode ? inode->i_ino : 0); + out += sprintf(out, "%Ld ", fl->fl_start); + if (fl->fl_end == OFFSET_MAX) + out += sprintf(out, "EOF "); + else + out += sprintf(out, "%Ld ", fl->fl_end); sprintf(out, "%08lx %08lx %08lx %08lx %08lx\n", (long)fl, (long)fl->fl_link.prev, (long)fl->fl_link.next, (long)fl->fl_next, (long)fl->fl_block.next); @@ -1378,6 +1788,14 @@ *pos += len; } +/** + * get_locks_status - reports lock usage in /proc/locks + * @buffer: address in userspace to write into + * @start: ? + * @offset: how far we are through the buffer + * @length: how much to read + */ + int get_locks_status(char *buffer, char **start, off_t offset, int length) { struct list_head *tmp; @@ -1385,7 +1803,7 @@ off_t pos = 0; int i = 0; - lock_kernel(); + acquire_fl_sem(); list_for_each(tmp, &file_lock_list) { struct list_head *btmp; struct file_lock *fl = list_entry(tmp, struct file_lock, fl_link); @@ -1397,7 +1815,7 @@ list_for_each(btmp, &fl->fl_block) { struct file_lock *bfl = list_entry(btmp, - struct file_lock, fl_block); + struct file_lock, fl_list); lock_get_status(q, bfl, i, " ->"); move_lock_status(&q, &pos, offset); @@ -1406,12 +1824,88 @@ } } done: - unlock_kernel(); + release_fl_sem(); *start = buffer; if(q-buffer < length) return (q-buffer); return length; } + +#ifdef MSNFS +/** + * lock_may_read - checks that the region is free of locks + * @inode: the inode that is being read + * @start: the first byte to read + * @len: the number of bytes to read + * + * Emulates Windows locking requirements. Whole-file + * mandatory locks (share modes) can prohibit a read and + * byte-range POSIX locks can prohibit a read if they overlap. + * + * N.B. this function is only ever called + * from knfsd and ownership of locks is never checked. + */ +int lock_may_read(struct inode *inode, loff_t start, unsigned long len) +{ + struct file_lock *fl; + int result = 1; + acquire_fl_sem(); + for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { + if (fl->fl_flags == FL_POSIX) { + if (fl->fl_type == F_RDLCK) + continue; + if ((fl->fl_end < start) || (fl->fl_start > (start + len))) + continue; + } else if (fl->fl_flags == FL_FLOCK) { + if (!(fl->fl_type & LOCK_MAND)) + continue; + if (fl->fl_type & LOCK_READ) + continue; + } else + continue; + result = 0; + break; + } + release_fl_sem(); + return result; +} + +/** + * lock_may_write - checks that the region is free of locks + * @inode: the inode that is being written + * @start: the first byte to write + * @len: the number of bytes to write + * + * Emulates Windows locking requirements. Whole-file + * mandatory locks (share modes) can prohibit a write and + * byte-range POSIX locks can prohibit a write if they overlap. + * + * N.B. this function is only ever called + * from knfsd and ownership of locks is never checked. + */ +int lock_may_write(struct inode *inode, loff_t start, unsigned long len) +{ + struct file_lock *fl; + int result = 1; + acquire_fl_sem(); + for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { + if (fl->fl_flags == FL_POSIX) { + if ((fl->fl_end < start) || (fl->fl_start > (start + len))) + continue; + } else if (fl->fl_flags == FL_FLOCK) { + if (!(fl->fl_type & LOCK_MAND)) + continue; + if (fl->fl_type & LOCK_WRITE) + continue; + } else + continue; + result = 0; + break; + } + release_fl_sem(); + return result; +} +#endif static int __init filelock_init(void) { diff -u --recursive --new-file v2.4.0-test8/linux/fs/minix/Makefile linux/fs/minix/Makefile --- v2.4.0-test8/linux/fs/minix/Makefile Thu Feb 10 12:16:58 2000 +++ linux/fs/minix/Makefile Wed Sep 27 19:23:40 2000 @@ -8,7 +8,7 @@ # Note 2! The CFLAGS definitions are now in the main makefile. O_TARGET := minix.o -O_OBJS := bitmap.o truncate.o namei.o inode.o file.o dir.o fsync.o +O_OBJS := bitmap.o itree_v1.o itree_v2.o namei.o inode.o file.o dir.o M_OBJS := $(O_TARGET) include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.0-test8/linux/fs/minix/bitmap.c linux/fs/minix/bitmap.c --- v2.4.0-test8/linux/fs/minix/bitmap.c Tue Sep 5 14:07:30 2000 +++ linux/fs/minix/bitmap.c Wed Sep 27 19:23:40 2000 @@ -83,8 +83,6 @@ if (!minix_test_and_clear_bit(bit,bh->b_data)) printk("free_block (%s:%d): bit already cleared\n", kdevname(sb->s_dev), block); - else - DQUOT_FREE_BLOCK(sb, inode, 1); mark_buffer_dirty(bh); return; } @@ -100,9 +98,6 @@ return 0; } repeat: - if(DQUOT_ALLOC_BLOCK(sb, inode, 1)) - return -EDQUOT; - j = 8192; bh = NULL; for (i = 0; i < sb->u.minix_sb.s_zmap_blocks; i++) { @@ -114,7 +109,6 @@ return 0; if (minix_test_and_set_bit(j,bh->b_data)) { printk("new_block: bit already set"); - DQUOT_FREE_BLOCK(sb, inode, 1); goto repeat; } mark_buffer_dirty(bh); @@ -215,9 +209,6 @@ return; } - DQUOT_FREE_INODE(inode->i_sb, inode); - DQUOT_DROP(inode); - bh = inode->i_sb->u.minix_sb.s_imap[ino >> 13]; minix_clear_inode(inode); clear_inode(inode); @@ -276,14 +267,6 @@ mark_inode_dirty(inode); unlock_super(sb); - if(DQUOT_ALLOC_INODE(sb, inode)) { - sb->dq_op->drop(inode); - inode->i_nlink = 0; - iput(inode); - *error = -EDQUOT; - return NULL; - } - *error = 0; return inode; } diff -u --recursive --new-file v2.4.0-test8/linux/fs/minix/file.c linux/fs/minix/file.c --- v2.4.0-test8/linux/fs/minix/file.c Sat Feb 26 20:33:06 2000 +++ linux/fs/minix/file.c Wed Sep 27 19:23:40 2000 @@ -13,6 +13,8 @@ * We have mostly NULLs here: the current defaults are OK for * the minix filesystem. */ +static int minix_sync_file(struct file *, struct dentry *, int); + struct file_operations minix_file_operations = { read: generic_file_read, write: generic_file_write, @@ -23,3 +25,15 @@ struct inode_operations minix_file_inode_operations = { truncate: minix_truncate, }; + +static int minix_sync_file(struct file * file, + struct dentry *dentry, + int datasync) +{ + struct inode *inode = dentry->d_inode; + + if (INODE_VERSION(inode) == MINIX_V1) + return V1_minix_sync_file(inode); + else + return V2_minix_sync_file(inode); +} diff -u --recursive --new-file v2.4.0-test8/linux/fs/minix/fsync.c linux/fs/minix/fsync.c --- v2.4.0-test8/linux/fs/minix/fsync.c Thu Jun 29 16:01:11 2000 +++ linux/fs/minix/fsync.c Wed Dec 31 16:00:00 1969 @@ -1,344 +0,0 @@ -/* - * linux/fs/minix/fsync.c - * - * Copyright (C) 1993 Stephen Tweedie (sct@dcs.ed.ac.uk) - * from - * Copyright (C) 1991, 1992 Linus Torvalds - * - * Copyright (C) 1996 Gertjan van Wingerde (gertjan@cs.vu.nl) - * Minix V2 fs support - * - * minix fsync primitive - */ - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#define blocksize BLOCK_SIZE - -/* - * The functions for minix V1 fs file synchronization. - */ -static int V1_sync_block (struct inode * inode, unsigned short * block, int wait) -{ - struct buffer_head * bh; - unsigned short tmp; - - if (!*block) - return 0; - tmp = *block; - bh = get_hash_table(inode->i_dev, *block, blocksize); - if (!bh) - return 0; - if (*block != tmp) { - brelse (bh); - return 1; - } - if (wait && buffer_req(bh) && !buffer_uptodate(bh)) { - brelse(bh); - return -1; - } - if (wait || !buffer_uptodate(bh) || !buffer_dirty(bh)) - { - brelse(bh); - return 0; - } - ll_rw_block(WRITE, 1, &bh); - atomic_dec(&bh->b_count); - return 0; -} - -static int V1_sync_iblock (struct inode * inode, unsigned short * iblock, - struct buffer_head **bh, int wait) -{ - int rc; - unsigned short tmp; - - *bh = NULL; - tmp = *iblock; - if (!tmp) - return 0; - rc = V1_sync_block (inode, iblock, wait); - if (rc) - return rc; - *bh = bread(inode->i_dev, tmp, blocksize); - if (tmp != *iblock) { - brelse(*bh); - *bh = NULL; - return 1; - } - if (!*bh) - return -1; - return 0; -} - -static int V1_sync_direct(struct inode *inode, int wait) -{ - int i; - int rc, err = 0; - - for (i = 0; i < 7; i++) { - rc = V1_sync_block (inode, - (unsigned short *) inode->u.minix_i.u.i1_data + i, wait); - if (rc > 0) - break; - if (rc) - err = rc; - } - return err; -} - -static int V1_sync_indirect(struct inode *inode, unsigned short *iblock, int wait) -{ - int i; - struct buffer_head * ind_bh; - int rc, err = 0; - - rc = V1_sync_iblock (inode, iblock, &ind_bh, wait); - if (rc || !ind_bh) - return rc; - - for (i = 0; i < 512; i++) { - rc = V1_sync_block (inode, - ((unsigned short *) ind_bh->b_data) + i, - wait); - if (rc > 0) - break; - if (rc) - err = rc; - } - brelse(ind_bh); - return err; -} - -static int V1_sync_dindirect(struct inode *inode, unsigned short *diblock, - int wait) -{ - int i; - struct buffer_head * dind_bh; - int rc, err = 0; - - rc = V1_sync_iblock (inode, diblock, &dind_bh, wait); - if (rc || !dind_bh) - return rc; - - for (i = 0; i < 512; i++) { - rc = V1_sync_indirect (inode, - ((unsigned short *) dind_bh->b_data) + i, - wait); - if (rc > 0) - break; - if (rc) - err = rc; - } - brelse(dind_bh); - return err; -} - -static int V1_minix_sync_file(struct inode * inode, struct file * file) -{ - int wait, err = 0; - - lock_kernel(); - for (wait=0; wait<=1; wait++) - { - err |= V1_sync_direct(inode, wait); - err |= V1_sync_indirect(inode, inode->u.minix_i.u.i1_data + 7, wait); - err |= V1_sync_dindirect(inode, inode->u.minix_i.u.i1_data + 8, wait); - } - err |= minix_sync_inode (inode); - unlock_kernel(); - return (err < 0) ? -EIO : 0; -} - -/* - * The functions for minix V2 fs file synchronization. - */ -static int V2_sync_block (struct inode * inode, unsigned long * block, int wait) -{ - struct buffer_head * bh; - unsigned long tmp; - - if (!*block) - return 0; - tmp = *block; - bh = get_hash_table(inode->i_dev, *block, blocksize); - if (!bh) - return 0; - if (*block != tmp) { - brelse (bh); - return 1; - } - if (wait && buffer_req(bh) && !buffer_uptodate(bh)) { - brelse(bh); - return -1; - } - if (wait || !buffer_uptodate(bh) || !buffer_dirty(bh)) - { - brelse(bh); - return 0; - } - ll_rw_block(WRITE, 1, &bh); - atomic_dec(&bh->b_count); - return 0; -} - -static int V2_sync_iblock (struct inode * inode, unsigned long * iblock, - struct buffer_head **bh, int wait) -{ - int rc; - unsigned long tmp; - - *bh = NULL; - tmp = *iblock; - if (!tmp) - return 0; - rc = V2_sync_block (inode, iblock, wait); - if (rc) - return rc; - *bh = bread(inode->i_dev, tmp, blocksize); - if (tmp != *iblock) { - brelse(*bh); - *bh = NULL; - return 1; - } - if (!*bh) - return -1; - return 0; -} - -static int V2_sync_direct(struct inode *inode, int wait) -{ - int i; - int rc, err = 0; - - for (i = 0; i < 7; i++) { - rc = V2_sync_block (inode, - (unsigned long *)inode->u.minix_i.u.i2_data + i, wait); - if (rc > 0) - break; - if (rc) - err = rc; - } - return err; -} - -static int V2_sync_indirect(struct inode *inode, unsigned long *iblock, int wait) -{ - int i; - struct buffer_head * ind_bh; - int rc, err = 0; - - rc = V2_sync_iblock (inode, iblock, &ind_bh, wait); - if (rc || !ind_bh) - return rc; - - for (i = 0; i < 256; i++) { - rc = V2_sync_block (inode, - ((unsigned long *) ind_bh->b_data) + i, - wait); - if (rc > 0) - break; - if (rc) - err = rc; - } - brelse(ind_bh); - return err; -} - -static int V2_sync_dindirect(struct inode *inode, unsigned long *diblock, - int wait) -{ - int i; - struct buffer_head * dind_bh; - int rc, err = 0; - - rc = V2_sync_iblock (inode, diblock, &dind_bh, wait); - if (rc || !dind_bh) - return rc; - - for (i = 0; i < 256; i++) { - rc = V2_sync_indirect (inode, - ((unsigned long *) dind_bh->b_data) + i, - wait); - if (rc > 0) - break; - if (rc) - err = rc; - } - brelse(dind_bh); - return err; -} - -static int V2_sync_tindirect(struct inode *inode, unsigned long *tiblock, - int wait) -{ - int i; - struct buffer_head * tind_bh; - int rc, err = 0; - - rc = V2_sync_iblock (inode, tiblock, &tind_bh, wait); - if (rc || !tind_bh) - return rc; - - for (i = 0; i < 256; i++) { - rc = V2_sync_dindirect (inode, - ((unsigned long *) tind_bh->b_data) + i, - wait); - if (rc > 0) - break; - if (rc) - err = rc; - } - brelse(tind_bh); - return err; -} - -static int V2_minix_sync_file(struct inode * inode, struct file * file) -{ - int wait, err = 0; - - lock_kernel(); - for (wait=0; wait<=1; wait++) - { - err |= V2_sync_direct(inode, wait); - err |= V2_sync_indirect(inode, - (unsigned long *) inode->u.minix_i.u.i2_data + 7, wait); - err |= V2_sync_dindirect(inode, - (unsigned long *) inode->u.minix_i.u.i2_data + 8, wait); - err |= V2_sync_tindirect(inode, - (unsigned long *) inode->u.minix_i.u.i2_data + 9, wait); - } - err |= minix_sync_inode (inode); - unlock_kernel(); - return (err < 0) ? -EIO : 0; -} - -/* - * The function which is called for file synchronization. File may be - * NULL - */ - -int minix_sync_file(struct file * file, struct dentry *dentry, int datasync) -{ - struct inode *inode = dentry->d_inode; - - if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || - S_ISLNK(inode->i_mode))) - return -EINVAL; - - if (INODE_VERSION(inode) == MINIX_V1) - return V1_minix_sync_file(inode, file); - else - return V2_minix_sync_file(inode, file); -} diff -u --recursive --new-file v2.4.0-test8/linux/fs/minix/inode.c linux/fs/minix/inode.c --- v2.4.0-test8/linux/fs/minix/inode.c Tue Sep 5 14:07:30 2000 +++ linux/fs/minix/inode.c Wed Sep 27 19:23:40 2000 @@ -348,573 +348,13 @@ return 0; } -/* - * The minix V1 fs bmap functions. - */ -#define V1_inode_bmap(inode,nr) (((unsigned short *)(inode)->u.minix_i.u.i1_data)[(nr)]) - -static int V1_block_bmap(struct buffer_head * bh, int nr) -{ - int tmp; - - if (!bh) - return 0; - tmp = ((unsigned short *) bh->b_data)[nr]; - brelse(bh); - return tmp; -} - -static int V1_minix_block_map(struct inode * inode, long block) -{ - int i, ret; - - ret = 0; - lock_kernel(); - if (block < 0) { - printk("minix_bmap: block<0"); - goto out; - } - if (block >= (inode->i_sb->u.minix_sb.s_max_size/BLOCK_SIZE)) { - printk("minix_bmap: block>big"); - goto out; - } - if (block < 7) { - ret = V1_inode_bmap(inode,block); - goto out; - } - block -= 7; - if (block < 512) { - i = V1_inode_bmap(inode,7); - if (!i) - goto out; - ret = V1_block_bmap(bread(inode->i_dev, i, - BLOCK_SIZE), block); - goto out; - } - block -= 512; - i = V1_inode_bmap(inode,8); - if (!i) - goto out; - i = V1_block_bmap(bread(inode->i_dev,i,BLOCK_SIZE),block>>9); - if (!i) - goto out; - ret = V1_block_bmap(bread(inode->i_dev, i, BLOCK_SIZE), - block & 511); -out: - unlock_kernel(); - return ret; -} - -/* - * The minix V2 fs bmap functions. - */ -#define V2_inode_bmap(inode,nr) (((unsigned int *)(inode)->u.minix_i.u.i2_data)[(nr)]) -static int V2_block_bmap(struct buffer_head * bh, int nr) -{ - int tmp; - - if (!bh) - return 0; - tmp = ((unsigned int *) bh->b_data)[nr]; - brelse(bh); - return tmp; -} - -static int V2_minix_block_map(struct inode * inode, int block) -{ - int i, ret; - - ret = 0; - lock_kernel(); - if (block < 0) { - printk("minix_bmap: block<0"); - goto out; - } - if (block >= (inode->i_sb->u.minix_sb.s_max_size/BLOCK_SIZE)) { - printk("minix_bmap: block>big"); - goto out; - } - if (block < 7) { - ret = V2_inode_bmap(inode,block); - goto out; - } - block -= 7; - if (block < 256) { - i = V2_inode_bmap(inode, 7); - if (!i) - goto out; - ret = V2_block_bmap(bread(inode->i_dev, i, - BLOCK_SIZE), block); - goto out; - } - block -= 256; - if (block < (256 * 256)) { - i = V2_inode_bmap(inode, 8); - if (!i) - goto out; - i = V2_block_bmap(bread(inode->i_dev, i, BLOCK_SIZE), - block >> 8); - if (!i) - goto out; - ret = V2_block_bmap(bread(inode->i_dev, i, BLOCK_SIZE), - block & 255); - goto out; - } - block -= (256 * 256); - i = V2_inode_bmap(inode, 9); - if (!i) - goto out; - i = V2_block_bmap(bread(inode->i_dev, i, BLOCK_SIZE), - block >> 16); - if (!i) - goto out; - i = V2_block_bmap(bread(inode->i_dev, i, BLOCK_SIZE), - (block >> 8) & 255); - if (!i) - goto out; - ret = V2_block_bmap(bread(inode->i_dev, i, BLOCK_SIZE), - block & 255); -out: - unlock_kernel(); - return ret; -} - -/* - * The minix V1 fs getblk functions. - */ -static struct buffer_head * V1_inode_getblk(struct inode * inode, int nr, - int new_block, int *err, - int metadata, int *phys, int *new) -{ - int tmp; - unsigned short *p; - struct buffer_head * result; - - p = inode->u.minix_i.u.i1_data + nr; -repeat: - tmp = *p; - if (tmp) { - if (metadata) { - result = getblk(inode->i_dev, tmp, BLOCK_SIZE); - if (tmp == *p) - return result; - brelse(result); - goto repeat; - } else { - *phys = tmp; - return NULL; - } - } - - tmp = minix_new_block(inode); - if (!tmp) { - *err = -ENOSPC; - return NULL; - } - if (metadata) { - result = getblk(inode->i_dev, tmp, BLOCK_SIZE); - if (*p) { - minix_free_block(inode, tmp); - brelse(result); - goto repeat; - } - memset(result->b_data, 0, BLOCK_SIZE); - mark_buffer_uptodate(result, 1); - mark_buffer_dirty(result); - } else { - if (*p) { - /* - * Nobody is allowed to change block allocation - * state from under us: - */ - BUG(); - minix_free_block(inode, tmp); - goto repeat; - } - *phys = tmp; - result = NULL; - *err = 0; - *new = 1; - } - *p = tmp; - - inode->i_ctime = CURRENT_TIME; - mark_inode_dirty(inode); - return result; -} - -static struct buffer_head * V1_block_getblk(struct inode * inode, - struct buffer_head * bh, int nr, int new_block, int *err, - int metadata, int *phys, int *new) -{ - int tmp; - unsigned short *p; - struct buffer_head * result; - - result = NULL; - if (!bh) - goto out; - if (!buffer_uptodate(bh)) { - ll_rw_block(READ, 1, &bh); - wait_on_buffer(bh); - if (!buffer_uptodate(bh)) - goto out; - } - p = nr + (unsigned short *) bh->b_data; -repeat: - tmp = *p; - if (tmp) { - if (metadata) { - result = getblk(bh->b_dev, tmp, BLOCK_SIZE); - if (tmp == *p) - goto out; - brelse(result); - goto repeat; - } else { - *phys = tmp; - goto out; - } - } - - tmp = minix_new_block(inode); - if (!tmp) - goto out; - if (metadata) { - result = getblk(bh->b_dev, tmp, BLOCK_SIZE); - if (*p) { - minix_free_block(inode, tmp); - brelse(result); - goto repeat; - } - memset(result->b_data, 0, BLOCK_SIZE); - mark_buffer_uptodate(result, 1); - mark_buffer_dirty(result); - } else { - *phys = tmp; - *new = 1; - } - if (*p) { - minix_free_block(inode, tmp); - brelse(result); - goto repeat; - } - - *p = tmp; - mark_buffer_dirty(bh); - *err = 0; -out: - brelse(bh); - return result; -} - -static int V1_get_block(struct inode * inode, long block, - struct buffer_head *bh_result, int create) -{ - int ret, err, new, phys, ptr; - struct buffer_head *bh; - - if (!create) { - phys = V1_minix_block_map(inode, block); - if (phys) { - bh_result->b_dev = inode->i_dev; - bh_result->b_blocknr = phys; - bh_result->b_state |= (1UL << BH_Mapped); - } - return 0; - } - - err = -EIO; - new = 0; - ret = 0; - bh = NULL; - - lock_kernel(); - if (block < 0) - goto abort_negative; - if (block >= inode->i_sb->u.minix_sb.s_max_size/BLOCK_SIZE) - goto abort_too_big; - - err = 0; - ptr = block; - /* - * ok, these macros clean the logic up a bit and make - * it much more readable: - */ -#define GET_INODE_DATABLOCK(x) \ - V1_inode_getblk(inode, x, block, &err, 0, &phys, &new) -#define GET_INODE_PTR(x) \ - V1_inode_getblk(inode, x, block, &err, 1, NULL, NULL) -#define GET_INDIRECT_DATABLOCK(x) \ - V1_block_getblk(inode, bh, x, block, &err, 0, &phys, &new) -#define GET_INDIRECT_PTR(x) \ - V1_block_getblk(inode, bh, x, block, &err, 1, NULL, NULL) - - if (ptr < 7) { - bh = GET_INODE_DATABLOCK(ptr); - goto out; - } - ptr -= 7; - if (ptr < 512) { - bh = GET_INODE_PTR(7); - goto get_indirect; - } - ptr -= 512; - bh = GET_INODE_PTR(8); - bh = GET_INDIRECT_PTR((ptr >> 9) & 511); -get_indirect: - bh = GET_INDIRECT_DATABLOCK(ptr & 511); - -#undef GET_INODE_DATABLOCK -#undef GET_INODE_PTR -#undef GET_INDIRECT_DATABLOCK -#undef GET_INDIRECT_PTR - -out: - if (err) - goto abort; - bh_result->b_dev = inode->i_dev; - bh_result->b_blocknr = phys; - bh_result->b_state |= (1UL << BH_Mapped); - if (new) - bh_result->b_state |= (1UL << BH_New); -abort: - unlock_kernel(); - return err; - -abort_negative: - printk("minix_getblk: block<0"); - goto abort; - -abort_too_big: - printk("minix_getblk: block>big"); - goto abort; -} - -/* - * The minix V2 fs getblk functions. - */ -static struct buffer_head * V2_inode_getblk(struct inode * inode, int nr, - int new_block, int *err, - int metadata, int *phys, int *new) -{ - int tmp; - unsigned int *p; - struct buffer_head * result; - - p = (unsigned int *) inode->u.minix_i.u.i2_data + nr; -repeat: - tmp = *p; - if (tmp) { - if (metadata) { - result = getblk(inode->i_dev, tmp, BLOCK_SIZE); - if (tmp == *p) - return result; - brelse(result); - goto repeat; - } else { - *phys = tmp; - return NULL; - } - } - - tmp = minix_new_block(inode); - if (!tmp) { - *err = -ENOSPC; - return NULL; - } - if (metadata) { - result = getblk(inode->i_dev, tmp, BLOCK_SIZE); - if (*p) { - minix_free_block(inode, tmp); - brelse(result); - goto repeat; - } - memset(result->b_data, 0, BLOCK_SIZE); - mark_buffer_uptodate(result, 1); - mark_buffer_dirty(result); - } else { - if (*p) { - /* - * Nobody is allowed to change block allocation - * state from under us: - */ - BUG(); - minix_free_block(inode, tmp); - goto repeat; - } - *phys = tmp; - result = NULL; - *err = 0; - *new = 1; - } - *p = tmp; - - inode->i_ctime = CURRENT_TIME; - mark_inode_dirty(inode); - return result; -} - -static struct buffer_head * V2_block_getblk(struct inode * inode, - struct buffer_head * bh, int nr, int new_block, int *err, - int metadata, int *phys, int *new) -{ - int tmp; - unsigned int *p; - struct buffer_head * result; - - result = NULL; - if (!bh) - goto out; - if (!buffer_uptodate(bh)) { - ll_rw_block(READ, 1, &bh); - wait_on_buffer(bh); - if (!buffer_uptodate(bh)) - goto out; - } - p = nr + (unsigned int *) bh->b_data; -repeat: - tmp = *p; - if (tmp) { - if (metadata) { - result = getblk(bh->b_dev, tmp, BLOCK_SIZE); - if (tmp == *p) - goto out; - brelse(result); - goto repeat; - } else { - *phys = tmp; - goto out; - } - } - - tmp = minix_new_block(inode); - if (!tmp) - goto out; - if (metadata) { - result = getblk(bh->b_dev, tmp, BLOCK_SIZE); - if (*p) { - minix_free_block(inode, tmp); - brelse(result); - goto repeat; - } - memset(result->b_data, 0, BLOCK_SIZE); - mark_buffer_uptodate(result, 1); - mark_buffer_dirty(result); - } else { - *phys = tmp; - *new = 1; - } - if (*p) { - minix_free_block(inode, tmp); - brelse(result); - goto repeat; - } - - *p = tmp; - mark_buffer_dirty(bh); - *err = 0; -out: - brelse(bh); - return result; -} - -static int V2_get_block(struct inode * inode, long block, - struct buffer_head *bh_result, int create) -{ - int ret, err, new, phys, ptr; - struct buffer_head * bh; - - if (!create) { - phys = V2_minix_block_map(inode, block); - if (phys) { - bh_result->b_dev = inode->i_dev; - bh_result->b_blocknr = phys; - bh_result->b_state |= (1UL << BH_Mapped); - } - return 0; - } - - err = -EIO; - new = 0; - ret = 0; - bh = NULL; - - lock_kernel(); - if (block < 0) - goto abort_negative; - if (block >= inode->i_sb->u.minix_sb.s_max_size/BLOCK_SIZE) - goto abort_too_big; - - err = 0; - ptr = block; - /* - * ok, these macros clean the logic up a bit and make - * it much more readable: - */ -#define GET_INODE_DATABLOCK(x) \ - V2_inode_getblk(inode, x, block, &err, 0, &phys, &new) -#define GET_INODE_PTR(x) \ - V2_inode_getblk(inode, x, block, &err, 1, NULL, NULL) -#define GET_INDIRECT_DATABLOCK(x) \ - V2_block_getblk(inode, bh, x, block, &err, 0, &phys, &new) -#define GET_INDIRECT_PTR(x) \ - V2_block_getblk(inode, bh, x, block, &err, 1, NULL, NULL) - - if (ptr < 7) { - bh = GET_INODE_DATABLOCK(ptr); - goto out; - } - ptr -= 7; - if (ptr < 256) { - bh = GET_INODE_PTR(7); - goto get_indirect; - } - ptr -= 256; - if (ptr < 256*256) { - bh = GET_INODE_PTR(8); - goto get_double; - } - ptr -= 256*256; - bh = GET_INODE_PTR(9); - bh = GET_INDIRECT_PTR((ptr >> 16) & 255); -get_double: - bh = GET_INDIRECT_PTR((ptr >> 8) & 255); -get_indirect: - bh = GET_INDIRECT_DATABLOCK(ptr & 255); - -#undef GET_INODE_DATABLOCK -#undef GET_INODE_PTR -#undef GET_INDIRECT_DATABLOCK -#undef GET_INDIRECT_PTR - -out: - if (err) - goto abort; - bh_result->b_dev = inode->i_dev; - bh_result->b_blocknr = phys; - bh_result->b_state |= (1UL << BH_Mapped); - if (new) - bh_result->b_state |= (1UL << BH_New); -abort: - unlock_kernel(); - return err; - -abort_negative: - printk("minix_getblk: block<0"); - goto abort; - -abort_too_big: - printk("minix_getblk: block>big"); - goto abort; -} - static int minix_get_block(struct inode *inode, long block, struct buffer_head *bh_result, int create) { if (INODE_VERSION(inode) == MINIX_V1) - return V1_get_block(inode, block, bh_result, create); + return V1_minix_get_block(inode, block, bh_result, create); else - return V2_get_block(inode, block, bh_result, create); + return V2_minix_get_block(inode, block, bh_result, create); } /* @@ -1214,6 +654,17 @@ err = -1; brelse (bh); return err; +} + +/* + * The function that is called for file truncation. + */ +void minix_truncate(struct inode * inode) +{ + if (INODE_VERSION(inode) == MINIX_V1) + V1_minix_truncate(inode); + else + V2_minix_truncate(inode); } static DECLARE_FSTYPE_DEV(minix_fs_type,"minix",minix_read_super); diff -u --recursive --new-file v2.4.0-test8/linux/fs/minix/itree_common.c linux/fs/minix/itree_common.c --- v2.4.0-test8/linux/fs/minix/itree_common.c Wed Dec 31 16:00:00 1969 +++ linux/fs/minix/itree_common.c Wed Sep 27 19:23:40 2000 @@ -0,0 +1,417 @@ +/* Generic part */ + +typedef struct { + block_t *p; + block_t key; + struct buffer_head *bh; +} Indirect; + +static inline void add_chain(Indirect *p, struct buffer_head *bh, block_t *v) +{ + p->key = *(p->p = v); + p->bh = bh; +} + +static inline int verify_chain(Indirect *from, Indirect *to) +{ + while (from <= to && from->key == *from->p) + from++; + return (from > to); +} + +static inline block_t *block_end(struct buffer_head *bh) +{ + return (block_t *)((char*)bh->b_data + BLOCK_SIZE); +} + +static inline Indirect *get_branch(struct inode *inode, + int depth, + int *offsets, + Indirect chain[DEPTH], + int *err) +{ + kdev_t dev = inode->i_dev; + Indirect *p = chain; + struct buffer_head *bh; + + *err = 0; + /* i_data is not going away, no lock needed */ + add_chain (chain, NULL, i_data(inode) + *offsets); + if (!p->key) + goto no_block; + while (--depth) { + bh = bread(dev, block_to_cpu(p->key), BLOCK_SIZE); + if (!bh) + goto failure; + /* Reader: pointers */ + if (!verify_chain(chain, p)) + goto changed; + add_chain(++p, bh, (block_t *)bh->b_data + *++offsets); + /* Reader: end */ + if (!p->key) + goto no_block; + } + return NULL; + +changed: + *err = -EAGAIN; + goto no_block; +failure: + *err = -EIO; +no_block: + return p; +} + +static int alloc_branch(struct inode *inode, + int num, + int *offsets, + Indirect *branch) +{ + int n = 0; + int i; + int parent = minix_new_block(inode); + + branch[0].key = cpu_to_block(parent); + if (parent) for (n = 1; n < num; n++) { + struct buffer_head *bh; + /* Allocate the next block */ + int nr = minix_new_block(inode); + if (!nr) + break; + branch[n].key = cpu_to_block(nr); + bh = getblk(inode->i_dev, parent, BLOCK_SIZE); + if (!buffer_uptodate(bh)) + wait_on_buffer(bh); + memset(bh->b_data, 0, BLOCK_SIZE); + branch[n].bh = bh; + branch[n].p = (block_t*) bh->b_data + offsets[n]; + *branch[n].p = branch[n].key; + mark_buffer_uptodate(bh, 1); + mark_buffer_dirty(bh); + parent = nr; + } + if (n == num) + return 0; + + /* Allocation failed, free what we already allocated */ + for (i = 1; i < n; i++) + bforget(branch[i].bh); + for (i = 0; i < n; i++) + minix_free_block(inode, block_to_cpu(branch[i].key)); + return -ENOSPC; +} + +static inline int splice_branch(struct inode *inode, + Indirect chain[DEPTH], + Indirect *where, + int num) +{ + int i; + + /* Verify that place we are splicing to is still there and vacant */ + + /* Writer: pointers */ + if (!verify_chain(chain, where-1) || *where->p) + /* Writer: end */ + goto changed; + + /* That's it */ + + *where->p = where->key; + + /* Writer: end */ + + /* We are done with atomic stuff, now do the rest of housekeeping */ + + inode->i_ctime = CURRENT_TIME; + + /* had we spliced it onto indirect block? */ + if (where->bh) + mark_buffer_dirty(where->bh); + + mark_inode_dirty(inode); + return 0; + +changed: + for (i = 1; i < num; i++) + bforget(where[i].bh); + for (i = 0; i < num; i++) + minix_free_block(inode, block_to_cpu(where[i].key)); + return -EAGAIN; +} + +static inline int get_block(struct inode * inode, long block, + struct buffer_head *bh_result, int create) +{ + int err = -EIO; + int offsets[DEPTH]; + Indirect chain[DEPTH]; + Indirect *partial; + int left; + int depth = block_to_path(inode, block, offsets); + + if (depth == 0) + goto out; + + lock_kernel(); +reread: + partial = get_branch(inode, depth, offsets, chain, &err); + + /* Simplest case - block found, no allocation needed */ + if (!partial) { +got_it: + bh_result->b_dev = inode->i_dev; + bh_result->b_blocknr = block_to_cpu(chain[depth-1].key); + bh_result->b_state |= (1UL << BH_Mapped); + /* Clean up and exit */ + partial = chain+depth-1; /* the whole chain */ + goto cleanup; + } + + /* Next simple case - plain lookup or failed read of indirect block */ + if (!create || err == -EIO) { +cleanup: + while (partial > chain) { + brelse(partial->bh); + partial--; + } + unlock_kernel(); +out: + return err; + } + + /* + * Indirect block might be removed by truncate while we were + * reading it. Handling of that case (forget what we've got and + * reread) is taken out of the main path. + */ + if (err == -EAGAIN) + goto changed; + + left = (chain + depth) - partial; + err = alloc_branch(inode, left, offsets+(partial-chain), partial); + if (err) + goto cleanup; + + if (splice_branch(inode, chain, partial, left) < 0) + goto changed; + + bh_result->b_state |= (1UL << BH_New); + goto got_it; + +changed: + while (partial > chain) { + bforget(partial->bh); + partial--; + } + goto reread; +} + +static inline int all_zeroes(block_t *p, block_t *q) +{ + while (p < q) + if (*p++) + return 0; + return 1; +} + +static Indirect *find_shared(struct inode *inode, + int depth, + int offsets[DEPTH], + Indirect chain[DEPTH], + block_t *top) +{ + Indirect *partial, *p; + int k, err; + + *top = 0; + for (k = depth; k > 1 && !offsets[k-1]; k--) + ; + partial = get_branch(inode, k, offsets, chain, &err); + /* Writer: pointers */ + if (!partial) + partial = chain + k-1; + if (!partial->key && *partial->p) + /* Writer: end */ + goto no_top; + for (p=partial;p>chain && all_zeroes((block_t*)p->bh->b_data,p->p);p--) + ; + if (p == chain + k - 1 && p > chain) { + p->p--; + } else { + *top = *p->p; + *p->p = 0; + } + /* Writer: end */ + + while(partial > p) + { + brelse(partial->bh); + partial--; + } +no_top: + return partial; +} + +static inline void free_data(struct inode *inode, block_t *p, block_t *q) +{ + unsigned long nr; + + for ( ; p < q ; p++) { + nr = block_to_cpu(*p); + if (nr) { + *p = 0; + minix_free_block(inode, nr); + } + } +} + +static void free_branches(struct inode *inode, block_t *p, block_t *q, int depth) +{ + struct buffer_head * bh; + unsigned long nr; + + if (depth--) { + for ( ; p < q ; p++) { + nr = block_to_cpu(*p); + if (!nr) + continue; + *p = 0; + bh = bread (inode->i_dev, nr, BLOCK_SIZE); + if (!bh) + continue; + free_branches(inode, (block_t*)bh->b_data, + block_end(bh), depth); + bforget(bh); + minix_free_block(inode, nr); + mark_inode_dirty(inode); + } + } else + free_data(inode, p, q); +} + +static inline void truncate (struct inode * inode) +{ + block_t *idata = i_data(inode); + int offsets[DEPTH]; + Indirect chain[DEPTH]; + Indirect *partial; + block_t nr = 0; + int n; + int first_whole; + long iblock; + + iblock = (inode->i_size + BLOCK_SIZE-1) >> 10; + block_truncate_page(inode->i_mapping, inode->i_size, get_block); + + n = block_to_path(inode, iblock, offsets); + if (!n) + return; + + if (n == 1) { + free_data(inode, idata+offsets[0], idata + DIRECT); + first_whole = 0; + goto do_indirects; + } + + first_whole = offsets[0] + 1 - DIRECT; + partial = find_shared(inode, n, offsets, chain, &nr); + if (nr) { + if (partial == chain) + mark_inode_dirty(inode); + else + mark_buffer_dirty(partial->bh); + free_branches(inode, &nr, &nr+1, (chain+n-1) - partial); + } + /* Clear the ends of indirect blocks on the shared branch */ + while (partial > chain) { + free_branches(inode, partial->p + 1, block_end(partial->bh), + (chain+n-1) - partial); + mark_buffer_dirty(partial->bh); + brelse (partial->bh); + partial--; + } +do_indirects: + /* Kill the remaining (whole) subtrees */ + while (first_whole < DEPTH-1) { + nr = idata[DIRECT+first_whole]; + if (nr) { + idata[DIRECT+first_whole] = 0; + mark_inode_dirty(inode); + free_branches(inode, &nr, &nr+1, first_whole+1); + } + first_whole++; + } + inode->i_mtime = inode->i_ctime = CURRENT_TIME; + mark_inode_dirty(inode); +} + +static int sync_block (struct inode * inode, block_t block, int wait) +{ + struct buffer_head * bh; + + if (!block) + return 0; + bh = get_hash_table(inode->i_dev, block_to_cpu(block), BLOCK_SIZE); + if (!bh) + return 0; + if (wait && buffer_req(bh) && !buffer_uptodate(bh)) { + brelse(bh); + return -1; + } + if (wait || !buffer_uptodate(bh) || !buffer_dirty(bh)) + { + brelse(bh); + return 0; + } + ll_rw_block(WRITE, 1, &bh); + atomic_dec(&bh->b_count); + return 0; +} + +static int sync_indirect(struct inode *inode, block_t iblock, int depth, + int wait) +{ + struct buffer_head * ind_bh = NULL; + int rc, err = 0; + + if (!iblock) + return 0; + + rc = sync_block (inode, iblock, wait); + if (rc) + return rc; + + ind_bh = bread(inode->i_dev, block_to_cpu(iblock), BLOCK_SIZE); + if (!ind_bh) + return -1; + + if (--depth) { + block_t *p = (block_t*)ind_bh->b_data; + block_t *end = block_end(ind_bh); + while (p < end) { + rc = sync_indirect (inode, *p++, depth, wait); + if (rc > 0) + break; + if (rc) + err = rc; + } + } + brelse(ind_bh); + return err; +} + +static inline int sync_file(struct inode * inode) +{ + int wait, err = 0, i; + block_t *idata = i_data(inode); + + lock_kernel(); + err = generic_buffer_fdatasync(inode, 0, ~0UL); + for (wait=0; wait<=1; wait++) + for (i=1; i +#include +#include +#include + +enum {DEPTH = 3, DIRECT = 7}; /* Only double indirect */ + +typedef u16 block_t; /* 16 bit, host order */ + +static inline unsigned long block_to_cpu(block_t n) +{ + return n; +} + +static inline block_t cpu_to_block(unsigned long n) +{ + return n; +} + +static inline block_t *i_data(struct inode *inode) +{ + return (block_t *)inode->u.minix_i.u.i1_data; +} + +static int block_to_path(struct inode * inode, long block, int offsets[DEPTH]) +{ + int n = 0; + + if (block < 0) { + printk("minix_bmap: block<0"); + } else if (block >= (inode->i_sb->u.minix_sb.s_max_size/BLOCK_SIZE)) { + printk("minix_bmap: block>big"); + } else if (block < 7) { + offsets[n++] = block; + } else if ((block -= 7) < 512) { + offsets[n++] = 7; + offsets[n++] = block; + } else { + block -= 512; + offsets[n++] = 8; + offsets[n++] = block>>9; + offsets[n++] = block & 511; + } + return n; +} + +#include "itree_common.c" + +int V1_minix_get_block(struct inode * inode, long block, + struct buffer_head *bh_result, int create) +{ + return get_block(inode, block, bh_result, create); +} + +void V1_minix_truncate(struct inode * inode) +{ + truncate(inode); +} + +int V1_minix_sync_file(struct inode * inode) +{ + return sync_file(inode); +} diff -u --recursive --new-file v2.4.0-test8/linux/fs/minix/itree_v2.c linux/fs/minix/itree_v2.c --- v2.4.0-test8/linux/fs/minix/itree_v2.c Wed Dec 31 16:00:00 1969 +++ linux/fs/minix/itree_v2.c Wed Sep 27 19:23:40 2000 @@ -0,0 +1,68 @@ +#include +#include +#include +#include + +enum {DIRECT = 7, DEPTH = 4}; /* Have triple indirect */ + +typedef u32 block_t; /* 32 bit, host order */ + +static inline unsigned long block_to_cpu(block_t n) +{ + return n; +} + +static inline block_t cpu_to_block(unsigned long n) +{ + return n; +} + +static inline block_t *i_data(struct inode *inode) +{ + return (block_t *)inode->u.minix_i.u.i2_data; +} + +static int block_to_path(struct inode * inode, long block, int offsets[DEPTH]) +{ + int n = 0; + + if (block < 0) { + printk("minix_bmap: block<0"); + } else if (block >= (inode->i_sb->u.minix_sb.s_max_size/BLOCK_SIZE)) { + printk("minix_bmap: block>big"); + } else if (block < 7) { + offsets[n++] = block; + } else if ((block -= 7) < 256) { + offsets[n++] = 7; + offsets[n++] = block; + } else if ((block -= 256) < 256*256) { + offsets[n++] = 8; + offsets[n++] = block>>8; + offsets[n++] = block & 255; + } else { + block -= 256*256; + offsets[n++] = 9; + offsets[n++] = block>>16; + offsets[n++] = (block>>8) & 255; + offsets[n++] = block & 255; + } + return n; +} + +#include "itree_common.c" + +int V2_minix_get_block(struct inode * inode, long block, + struct buffer_head *bh_result, int create) +{ + return get_block(inode, block, bh_result, create); +} + +void V2_minix_truncate(struct inode * inode) +{ + truncate(inode); +} + +int V2_minix_sync_file(struct inode * inode) +{ + return sync_file(inode); +} diff -u --recursive --new-file v2.4.0-test8/linux/fs/minix/namei.c linux/fs/minix/namei.c --- v2.4.0-test8/linux/fs/minix/namei.c Tue Sep 5 14:07:30 2000 +++ linux/fs/minix/namei.c Wed Sep 27 19:23:40 2000 @@ -389,7 +389,6 @@ if (!bh) goto end_rmdir; inode = dentry->d_inode; - DQUOT_INIT(inode); if (!empty_dir(inode)) { retval = -ENOTEMPTY; @@ -424,7 +423,6 @@ retval = -ENOENT; inode = dentry->d_inode; - DQUOT_INIT(inode); bh = minix_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de); if (!bh || de->inode != inode->i_ino) @@ -557,8 +555,6 @@ if (!new_inode) { brelse(new_bh); new_bh = NULL; - } else { - DQUOT_INIT(new_inode); } } if (S_ISDIR(old_inode->i_mode)) { diff -u --recursive --new-file v2.4.0-test8/linux/fs/minix/truncate.c linux/fs/minix/truncate.c --- v2.4.0-test8/linux/fs/minix/truncate.c Tue Sep 5 14:07:30 2000 +++ linux/fs/minix/truncate.c Wed Dec 31 16:00:00 1969 @@ -1,420 +0,0 @@ -/* - * linux/fs/truncate.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - * - * Copyright (C) 1996 Gertjan van Wingerde (gertjan@cs.vu.nl) - * Minix V2 fs support. - */ - -#include -#include -#include -#include -#include - -#define DIRECT_BLOCK ((inode->i_size + 1023) >> 10) -#define INDIRECT_BLOCK(offset) (DIRECT_BLOCK-offset) -#define V1_DINDIRECT_BLOCK(offset) ((DIRECT_BLOCK-offset)>>9) -#define V2_DINDIRECT_BLOCK(offset) ((DIRECT_BLOCK-offset)>>8) -#define TINDIRECT_BLOCK(offset) ((DIRECT_BLOCK-(offset))>>8) - -/* - * Truncate has the most races in the whole filesystem: coding it is - * a pain in the a**, especially as I don't do any locking. - * - * The code may look a bit weird, but that's just because I've tried to - * handle things like file-size changes in a somewhat graceful manner. - * Anyway, truncating a file at the same time somebody else writes to it - * is likely to result in pretty weird behaviour... - * - * The new code handles normal truncates (size = 0) as well as the more - * general case (size = XXX). I hope. - */ - -#define DATA_BUFFER_USED(bh) \ - (atomic_read(&bh->b_count) > 1 || buffer_locked(bh)) - -/* - * The functions for minix V1 fs truncation. - */ -static int V1_trunc_direct(struct inode * inode) -{ - unsigned short * p; - struct buffer_head * bh; - int i, tmp; - int retry = 0; - -repeat: - for (i = DIRECT_BLOCK ; i < 7 ; i++) { - p = i + inode->u.minix_i.u.i1_data; - if (!(tmp = *p)) - continue; - bh = get_hash_table(inode->i_dev,tmp,BLOCK_SIZE); - if (i < DIRECT_BLOCK) { - brelse(bh); - goto repeat; - } - if ((bh && DATA_BUFFER_USED(bh)) || tmp != *p) { - retry = 1; - brelse(bh); - continue; - } - *p = 0; - mark_inode_dirty(inode); - bforget(bh); - minix_free_block(inode,tmp); - } - return retry; -} - -static int V1_trunc_indirect(struct inode * inode, int offset, unsigned short * p) -{ - struct buffer_head * bh; - int i, tmp; - struct buffer_head * ind_bh; - unsigned short * ind; - int retry = 0; - - tmp = *p; - if (!tmp) - return 0; - ind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE); - if (tmp != *p) { - brelse(ind_bh); - return 1; - } - if (!ind_bh) { - *p = 0; - return 0; - } -repeat: - for (i = INDIRECT_BLOCK(offset) ; i < 512 ; i++) { - if (i < 0) - i = 0; - if (i < INDIRECT_BLOCK(offset)) - goto repeat; - ind = i+(unsigned short *) ind_bh->b_data; - tmp = *ind; - if (!tmp) - continue; - bh = get_hash_table(inode->i_dev,tmp,BLOCK_SIZE); - if (i < INDIRECT_BLOCK(offset)) { - brelse(bh); - goto repeat; - } - if ((bh && DATA_BUFFER_USED(bh)) || tmp != *ind) { - retry = 1; - brelse(bh); - continue; - } - *ind = 0; - mark_buffer_dirty(ind_bh); - bforget(bh); - minix_free_block(inode,tmp); - } - ind = (unsigned short *) ind_bh->b_data; - for (i = 0; i < 512; i++) - if (*(ind++)) - break; - if (i >= 512) { - if (atomic_read(&ind_bh->b_count) != 1) - retry = 1; - else { - tmp = *p; - *p = 0; - minix_free_block(inode,tmp); - } - } - brelse(ind_bh); - return retry; -} - -static int V1_trunc_dindirect(struct inode * inode, int offset, unsigned short *p) -{ - int i, tmp; - struct buffer_head * dind_bh; - unsigned short * dind; - int retry = 0; - - if (!(tmp = *p)) - return 0; - dind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE); - if (tmp != *p) { - brelse(dind_bh); - return 1; - } - if (!dind_bh) { - *p = 0; - return 0; - } -repeat: - for (i = V1_DINDIRECT_BLOCK(offset) ; i < 512 ; i ++) { - if (i < 0) - i = 0; - if (i < V1_DINDIRECT_BLOCK(offset)) - goto repeat; - dind = i+(unsigned short *) dind_bh->b_data; - retry |= V1_trunc_indirect(inode,offset+(i<<9),dind); - mark_buffer_dirty(dind_bh); - } - dind = (unsigned short *) dind_bh->b_data; - for (i = 0; i < 512; i++) - if (*(dind++)) - break; - if (i >= 512) { - if (atomic_read(&dind_bh->b_count) != 1) - retry = 1; - else { - tmp = *p; - *p = 0; - mark_inode_dirty(inode); - minix_free_block(inode,tmp); - } - } - brelse(dind_bh); - return retry; -} - -static void V1_minix_truncate(struct inode * inode) -{ - int retry; - - if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || - S_ISLNK(inode->i_mode))) - return; - while (1) { - retry = V1_trunc_direct(inode); - retry |= V1_trunc_indirect(inode, 7, inode->u.minix_i.u.i1_data + 7); - retry |= V1_trunc_dindirect(inode, 7+512, inode->u.minix_i.u.i1_data + 8); - if (!retry) - break; - current->counter = 0; - schedule(); - } - inode->i_mtime = inode->i_ctime = CURRENT_TIME; - mark_inode_dirty(inode); -} - -/* - * The functions for minix V2 fs truncation. - */ -static int V2_trunc_direct(struct inode * inode) -{ - unsigned long * p; - struct buffer_head * bh; - int i, tmp; - int retry = 0; - -repeat: - for (i = DIRECT_BLOCK ; i < 7 ; i++) { - p = (unsigned long *) inode->u.minix_i.u.i2_data + i; - if (!(tmp = *p)) - continue; - bh = get_hash_table(inode->i_dev,tmp,BLOCK_SIZE); - if (i < DIRECT_BLOCK) { - brelse(bh); - goto repeat; - } - if ((bh && DATA_BUFFER_USED(bh)) || tmp != *p) { - retry = 1; - brelse(bh); - continue; - } - *p = 0; - mark_inode_dirty(inode); - bforget(bh); - minix_free_block(inode,tmp); - } - return retry; -} - -static int V2_trunc_indirect(struct inode * inode, int offset, unsigned long * p) -{ - struct buffer_head * bh; - int i, tmp; - struct buffer_head * ind_bh; - unsigned long * ind; - int retry = 0; - - tmp = *p; - if (!tmp) - return 0; - ind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE); - if (tmp != *p) { - brelse(ind_bh); - return 1; - } - if (!ind_bh) { - *p = 0; - return 0; - } -repeat: - for (i = INDIRECT_BLOCK(offset) ; i < 256 ; i++) { - if (i < 0) - i = 0; - if (i < INDIRECT_BLOCK(offset)) - goto repeat; - ind = i+(unsigned long *) ind_bh->b_data; - tmp = *ind; - if (!tmp) - continue; - bh = get_hash_table(inode->i_dev,tmp,BLOCK_SIZE); - if (i < INDIRECT_BLOCK(offset)) { - brelse(bh); - goto repeat; - } - if ((bh && DATA_BUFFER_USED(bh)) || tmp != *ind) { - retry = 1; - brelse(bh); - continue; - } - *ind = 0; - mark_buffer_dirty(ind_bh); - bforget(bh); - minix_free_block(inode,tmp); - } - ind = (unsigned long *) ind_bh->b_data; - for (i = 0; i < 256; i++) - if (*(ind++)) - break; - if (i >= 256) { - if (atomic_read(&ind_bh->b_count) != 1) - retry = 1; - else { - tmp = *p; - *p = 0; - minix_free_block(inode,tmp); - } - } - brelse(ind_bh); - return retry; -} - -static int V2_trunc_dindirect(struct inode * inode, int offset, unsigned long *p) -{ - int i, tmp; - struct buffer_head * dind_bh; - unsigned long * dind; - int retry = 0; - - if (!(tmp = *p)) - return 0; - dind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE); - if (tmp != *p) { - brelse(dind_bh); - return 1; - } - if (!dind_bh) { - *p = 0; - return 0; - } -repeat: - for (i = V2_DINDIRECT_BLOCK(offset) ; i < 256 ; i ++) { - if (i < 0) - i = 0; - if (i < V2_DINDIRECT_BLOCK(offset)) - goto repeat; - dind = i+(unsigned long *) dind_bh->b_data; - retry |= V2_trunc_indirect(inode,offset+(i<<8),dind); - mark_buffer_dirty(dind_bh); - } - dind = (unsigned long *) dind_bh->b_data; - for (i = 0; i < 256; i++) - if (*(dind++)) - break; - if (i >= 256) { - if (atomic_read(&dind_bh->b_count) != 1) - retry = 1; - else { - tmp = *p; - *p = 0; - mark_inode_dirty(inode); - minix_free_block(inode,tmp); - } - } - brelse(dind_bh); - return retry; -} - -static int V2_trunc_tindirect(struct inode * inode, int offset, unsigned long * p) -{ - int i, tmp; - struct buffer_head * tind_bh; - unsigned long * tind; - int retry = 0; - - if (!(tmp = *p)) - return 0; - tind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE); - if (tmp != *p) { - brelse(tind_bh); - return 1; - } - if (!tind_bh) { - *p = 0; - return 0; - } -repeat: - for (i = TINDIRECT_BLOCK(offset) ; i < 256 ; i ++) { - if (i < 0) - i = 0; - if (i < TINDIRECT_BLOCK(offset)) - goto repeat; - tind = i+(unsigned long *) tind_bh->b_data; - retry |= V2_trunc_dindirect(inode,offset+(i<<8),tind); - mark_buffer_dirty(tind_bh); - } - tind = (unsigned long *) tind_bh->b_data; - for (i = 0; i < 256; i++) - if (*(tind++)) - break; - if (i >= 256) { - if (atomic_read(&tind_bh->b_count) != 1) - retry = 1; - else { - tmp = *p; - *p = 0; - mark_inode_dirty(inode); - minix_free_block(inode,tmp); - } - } - brelse(tind_bh); - return retry; -} - -static void V2_minix_truncate(struct inode * inode) -{ - int retry; - - if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || - S_ISLNK(inode->i_mode))) - return; - while (1) { - retry = V2_trunc_direct(inode); - retry |= V2_trunc_indirect(inode,7, - (unsigned long *) inode->u.minix_i.u.i2_data + 7); - retry |= V2_trunc_dindirect(inode, 7+256, - (unsigned long *) inode->u.minix_i.u.i2_data + 8); - retry |= V2_trunc_tindirect(inode, 7+256+256*256, - (unsigned long *) inode->u.minix_i.u.i2_data + 9); - if (!retry) - break; - run_task_queue(&tq_disk); - current->policy |= SCHED_YIELD; - schedule(); - } - inode->i_mtime = inode->i_ctime = CURRENT_TIME; - mark_inode_dirty(inode); -} - -/* - * The function that is called for file truncation. - */ -void minix_truncate(struct inode * inode) -{ - if (INODE_VERSION(inode) == MINIX_V1) - V1_minix_truncate(inode); - else - V2_minix_truncate(inode); -} diff -u --recursive --new-file v2.4.0-test8/linux/fs/namei.c linux/fs/namei.c --- v2.4.0-test8/linux/fs/namei.c Sun Sep 3 22:49:25 2000 +++ linux/fs/namei.c Fri Sep 22 14:21:18 2000 @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -107,7 +108,7 @@ static inline int do_getname(const char *filename, char *page) { int retval; - unsigned long len = PAGE_SIZE; + unsigned long len = PATH_MAX + 1; if ((unsigned long) filename >= TASK_SIZE) { if (!segment_eq(get_fs(), KERNEL_DS)) @@ -180,7 +181,7 @@ /* read and search access */ if ((mask == S_IROTH) || - (S_ISDIR(mode) && !(mask & ~(S_IROTH | S_IXOTH)))) + (S_ISDIR(inode->i_mode) && !(mask & ~(S_IROTH | S_IXOTH)))) if (capable(CAP_DAC_READ_SEARCH)) return 0; @@ -683,7 +684,7 @@ } /* SMP-safe */ -int path_init(const char *name,unsigned int flags,struct nameidata *nd) +int path_init(const char *name, unsigned int flags, struct nameidata *nd) { nd->last_type = LAST_ROOT; /* if there are only slashes... */ nd->flags = flags; @@ -912,6 +913,8 @@ unlock_kernel(); exit_lock: up(&dir->i_zombie); + if (!error) + inode_dir_notify(dir, DN_CREATE); return error; } @@ -1066,6 +1069,13 @@ goto exit; } + /* + * Ensure there are no outstanding leases on the file. + */ + error = get_lease(inode, flag); + if (error) + goto exit; + if (flag & O_TRUNC) { error = get_write_access(inode); if (error) @@ -1183,6 +1193,8 @@ unlock_kernel(); exit_lock: up(&dir->i_zombie); + if (!error) + inode_dir_notify(dir, DN_CREATE); return error; } @@ -1250,6 +1262,8 @@ exit_lock: up(&dir->i_zombie); + if (!error) + inode_dir_notify(dir, DN_CREATE); return error; } @@ -1338,8 +1352,10 @@ dentry->d_inode->i_flags |= S_DEAD; } double_up(&dir->i_zombie, &dentry->d_inode->i_zombie); - if (!error) + if (!error) { + inode_dir_notify(dir, DN_DELETE); d_delete(dentry); + } dput(dentry); return error; @@ -1406,6 +1422,8 @@ } } up(&dir->i_zombie); + if (!error) + inode_dir_notify(dir, DN_DELETE); return error; } @@ -1472,6 +1490,8 @@ exit_lock: up(&dir->i_zombie); + if (!error) + inode_dir_notify(dir, DN_CREATE); return error; } @@ -1544,6 +1564,8 @@ exit_lock: up(&dir->i_zombie); + if (!error) + inode_dir_notify(dir, DN_CREATE); return error; } @@ -1749,10 +1771,20 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { + int error; if (S_ISDIR(old_dentry->d_inode->i_mode)) - return vfs_rename_dir(old_dir,old_dentry,new_dir,new_dentry); + error = vfs_rename_dir(old_dir,old_dentry,new_dir,new_dentry); else - return vfs_rename_other(old_dir,old_dentry,new_dir,new_dentry); + error = vfs_rename_other(old_dir,old_dentry,new_dir,new_dentry); + if (!error) { + if (old_dir == new_dir) + inode_dir_notify(old_dir, DN_RENAME); + else { + inode_dir_notify(old_dir, DN_DELETE); + inode_dir_notify(new_dir, DN_CREATE); + } + } + return error; } static inline int do_rename(const char * oldname, const char * newname) diff -u --recursive --new-file v2.4.0-test8/linux/fs/ncpfs/file.c linux/fs/ncpfs/file.c --- v2.4.0-test8/linux/fs/ncpfs/file.c Wed Jul 5 11:56:28 2000 +++ linux/fs/ncpfs/file.c Fri Sep 15 14:26:23 2000 @@ -256,7 +256,7 @@ } if (ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle, - pos, to_write, buf, &written_this_time) != 0) { + pos, to_write, bouncebuffer, &written_this_time) != 0) { errno = -EIO; break; } diff -u --recursive --new-file v2.4.0-test8/linux/fs/nfs/dir.c linux/fs/nfs/dir.c --- v2.4.0-test8/linux/fs/nfs/dir.c Tue Sep 5 14:02:41 2000 +++ linux/fs/nfs/dir.c Mon Sep 11 08:38:25 2000 @@ -809,14 +809,9 @@ dentry->d_parent->d_name.name, dentry->d_name.name, atomic_read(&dentry->d_count)); - /* - * Note that a silly-renamed file can be deleted once it's - * no longer in use -- it's just an ordinary file now. - */ - if (atomic_read(&dentry->d_count) == 1) { - dentry->d_flags &= ~DCACHE_NFSFS_RENAMED; + if (atomic_read(&dentry->d_count) == 1) goto out; /* No need to silly rename. */ - } + #ifdef NFS_PARANOIA if (!dentry->d_inode) @@ -900,12 +895,21 @@ #endif goto out; } + + /* If the dentry was sillyrenamed, we simply call d_delete() */ + if (dentry->d_flags & DCACHE_NFSFS_RENAMED) { + error = 0; + goto out_delete; + } + nfs_zap_caches(dir_i); if (inode) NFS_CACHEINV(inode); error = NFS_PROTO(dir_i)->remove(dir, &dentry->d_name); if (error < 0) goto out; + + out_delete: /* * Free the inode */ diff -u --recursive --new-file v2.4.0-test8/linux/fs/nfs/file.c linux/fs/nfs/file.c --- v2.4.0-test8/linux/fs/nfs/file.c Thu Jun 29 16:02:40 2000 +++ linux/fs/nfs/file.c Mon Sep 18 15:18:56 2000 @@ -291,10 +291,13 @@ status = 0; /* - * Make sure we re-validate anything we've got cached. + * Make sure we clear the cache whenever we try to get the lock. * This makes locking act as a cache coherency point. */ out_ok: - NFS_CACHEINV(inode); + if ((cmd == F_SETLK || cmd == F_SETLKW) && fl->fl_type != F_UNLCK) { + nfs_wb_all(inode); /* we may have slept */ + nfs_zap_caches(inode); + } return status; } diff -u --recursive --new-file v2.4.0-test8/linux/fs/nfs/inode.c linux/fs/nfs/inode.c --- v2.4.0-test8/linux/fs/nfs/inode.c Mon Aug 21 13:00:25 2000 +++ linux/fs/nfs/inode.c Mon Sep 25 13:13:53 2000 @@ -353,6 +353,7 @@ clnt->cl_intr = (data->flags & NFS_MOUNT_INTR)? 1 : 0; clnt->cl_softrtry = (data->flags & NFS_MOUNT_SOFT)? 1 : 0; + clnt->cl_droppriv = (data->flags & NFS_MOUNT_BROKEN_SUID) ? 1 : 0; clnt->cl_chatty = 1; server->client = clnt; diff -u --recursive --new-file v2.4.0-test8/linux/fs/nfs/nfs3proc.c linux/fs/nfs/nfs3proc.c --- v2.4.0-test8/linux/fs/nfs/nfs3proc.c Tue Sep 5 14:02:41 2000 +++ linux/fs/nfs/nfs3proc.c Mon Sep 11 08:38:25 2000 @@ -279,6 +279,7 @@ arg->fh = NFS_FH(dir); arg->name = name->name; arg->len = name->len; + res->valid = 0; msg->rpc_proc = NFS3PROC_REMOVE; msg->rpc_argp = arg; msg->rpc_resp = res; @@ -288,10 +289,13 @@ static void nfs3_proc_unlink_done(struct dentry *dir, struct rpc_message *msg) { - struct nfs_fattr *dir_attr = (struct nfs_fattr*)msg->rpc_resp; + struct nfs_fattr *dir_attr; - nfs_refresh_inode(dir->d_inode, dir_attr); - kfree(msg->rpc_argp); + if (msg->rpc_argp) { + dir_attr = (struct nfs_fattr*)msg->rpc_resp; + nfs_refresh_inode(dir->d_inode, dir_attr); + kfree(msg->rpc_argp); + } } static int diff -u --recursive --new-file v2.4.0-test8/linux/fs/nfs/nfsroot.c linux/fs/nfs/nfsroot.c --- v2.4.0-test8/linux/fs/nfs/nfsroot.c Fri Apr 21 13:36:40 2000 +++ linux/fs/nfs/nfsroot.c Mon Sep 25 13:13:53 2000 @@ -157,6 +157,7 @@ #endif { "udp", ~NFS_MOUNT_TCP, 0 }, { "tcp", ~NFS_MOUNT_TCP, NFS_MOUNT_TCP }, + { "broken_suid",~NFS_MOUNT_BROKEN_SUID, NFS_MOUNT_BROKEN_SUID }, { NULL, 0, 0 } }; diff -u --recursive --new-file v2.4.0-test8/linux/fs/nfs/proc.c linux/fs/nfs/proc.c --- v2.4.0-test8/linux/fs/nfs/proc.c Tue Sep 5 14:02:41 2000 +++ linux/fs/nfs/proc.c Mon Sep 11 08:38:25 2000 @@ -251,8 +251,10 @@ static void nfs_proc_unlink_done(struct dentry *dir, struct rpc_message *msg) { - NFS_CACHEINV(dir->d_inode); - kfree(msg->rpc_argp); + if (msg->rpc_argp) { + NFS_CACHEINV(dir->d_inode); + kfree(msg->rpc_argp); + } } static int diff -u --recursive --new-file v2.4.0-test8/linux/fs/nfs/unlink.c linux/fs/nfs/unlink.c --- v2.4.0-test8/linux/fs/nfs/unlink.c Tue Sep 5 14:02:41 2000 +++ linux/fs/nfs/unlink.c Sun Oct 1 20:35:16 2000 @@ -23,7 +23,7 @@ unsigned int count; }; -static struct nfs_unlinkdata *nfs_deletes = NULL; +static struct nfs_unlinkdata *nfs_deletes; static struct rpc_wait_queue nfs_delete_queue = RPC_INIT_WAITQ("nfs_delete_queue"); /** @@ -121,8 +121,11 @@ { struct nfs_unlinkdata *data = (struct nfs_unlinkdata *)task->tk_calldata; struct dentry *dir = data->dir; - struct inode *dir_i = dir->d_inode; + struct inode *dir_i; + if (!dir) + return; + dir_i = dir->d_inode; nfs_zap_caches(dir_i); NFS_PROTO(dir_i)->unlink_done(dir, &task->tk_msg); rpcauth_releasecred(task->tk_auth, data->cred); @@ -206,6 +209,7 @@ return; data->count++; nfs_copy_dname(dentry, data); + dentry->d_flags &= ~DCACHE_NFSFS_RENAMED; if (data->task.tk_rpcwait == &nfs_delete_queue) rpc_wake_up_task(&data->task); nfs_put_unlinkdata(data); diff -u --recursive --new-file v2.4.0-test8/linux/fs/nfsd/export.c linux/fs/nfsd/export.c --- v2.4.0-test8/linux/fs/nfsd/export.c Mon Jun 26 11:44:15 2000 +++ linux/fs/nfsd/export.c Sun Oct 1 20:35:16 2000 @@ -1,3 +1,4 @@ +#define MSNFS /* HACK HACK */ /* * linux/fs/nfsd/export.c * @@ -56,12 +57,12 @@ struct svc_client * h_client; }; static struct svc_clnthash * clnt_hash[CLIENT_HASHMAX]; -static svc_client * clients = NULL; -static int initialized = 0; +static svc_client * clients; +static int initialized; -static int hash_lock = 0; -static int want_lock = 0; -static int hash_count = 0; +static int hash_lock; +static int want_lock; +static int hash_count; static DECLARE_WAIT_QUEUE_HEAD( hash_wait ); @@ -556,6 +557,9 @@ { NFSEXP_CROSSMNT, {"nohide", ""}}, { NFSEXP_NOSUBTREECHECK, {"no_subtree_check", ""}}, { NFSEXP_NOAUTHNLM, {"insecure_locks", ""}}, +#ifdef NSMFS + { NFSEXP_MSNFS, {"msnfs", ""}}, +#endif { 0, {"", ""}} }; diff -u --recursive --new-file v2.4.0-test8/linux/fs/nfsd/nfs3proc.c linux/fs/nfsd/nfs3proc.c --- v2.4.0-test8/linux/fs/nfsd/nfs3proc.c Fri Jun 23 21:22:12 2000 +++ linux/fs/nfsd/nfs3proc.c Wed Sep 27 13:41:33 2000 @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include diff -u --recursive --new-file v2.4.0-test8/linux/fs/nfsd/nfs3xdr.c linux/fs/nfsd/nfs3xdr.c --- v2.4.0-test8/linux/fs/nfsd/nfs3xdr.c Fri Aug 11 14:29:02 2000 +++ linux/fs/nfsd/nfs3xdr.c Fri Sep 22 14:21:18 2000 @@ -193,7 +193,7 @@ p = xdr_encode_hyper(p, (u64) inode->i_dev); p = xdr_encode_hyper(p, (u64) inode->i_ino); p = encode_time3(p, inode->i_atime); - p = encode_time3(p, inode->i_mtime); + p = encode_time3(p, lease_get_mtime(inode)); p = encode_time3(p, inode->i_ctime); return p; diff -u --recursive --new-file v2.4.0-test8/linux/fs/nfsd/nfsctl.c linux/fs/nfsd/nfsctl.c --- v2.4.0-test8/linux/fs/nfsd/nfsctl.c Mon Aug 28 21:27:39 2000 +++ linux/fs/nfsd/nfsctl.c Sun Oct 1 20:35:16 2000 @@ -46,7 +46,7 @@ static int nfsctl_ugidupdate(struct nfsctl_ugidmap *data); #endif -static int initialized = 0; +static int initialized; int exp_procfs_exports(char *buffer, char **start, off_t offset, int length, int *eof, void *data); diff -u --recursive --new-file v2.4.0-test8/linux/fs/nfsd/nfsfh.c linux/fs/nfsd/nfsfh.c --- v2.4.0-test8/linux/fs/nfsd/nfsfh.c Fri Aug 11 14:29:02 2000 +++ linux/fs/nfsd/nfsfh.c Wed Sep 27 13:54:30 2000 @@ -405,7 +405,7 @@ || !S_ISDIR(dentry->d_inode->i_mode)) { goto err_dentry; } - if ((!dentry->d_flags & DCACHE_NFSD_DISCONNECTED)) + if (!(dentry->d_flags & DCACHE_NFSD_DISCONNECTED)) found = 1; tmp = splice(result, dentry); err = PTR_ERR(tmp); diff -u --recursive --new-file v2.4.0-test8/linux/fs/nfsd/nfssvc.c linux/fs/nfsd/nfssvc.c --- v2.4.0-test8/linux/fs/nfsd/nfssvc.c Fri Sep 1 14:33:04 2000 +++ linux/fs/nfsd/nfssvc.c Sun Oct 1 20:35:16 2000 @@ -41,9 +41,9 @@ extern struct svc_program nfsd_program; static void nfsd(struct svc_rqst *rqstp); -struct timeval nfssvc_boot = { 0, 0 }; -static struct svc_serv *nfsd_serv = NULL; -static int nfsd_busy = 0; +struct timeval nfssvc_boot; +static struct svc_serv *nfsd_serv; +static int nfsd_busy; static unsigned long nfsd_last_call; struct nfsd_list { @@ -154,6 +154,8 @@ current->pgrp = 1; sprintf(current->comm, "nfsd"); current->fs->umask = 0; + + current->rlim[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY; nfsdstats.th_cnt++; /* Let svc_process check client's authentication. */ diff -u --recursive --new-file v2.4.0-test8/linux/fs/nfsd/nfsxdr.c linux/fs/nfsd/nfsxdr.c --- v2.4.0-test8/linux/fs/nfsd/nfsxdr.c Fri Aug 11 14:29:02 2000 +++ linux/fs/nfsd/nfsxdr.c Fri Sep 22 14:21:19 2000 @@ -155,7 +155,7 @@ *p++ = htonl((u32) inode->i_ino); *p++ = htonl((u32) inode->i_atime); *p++ = 0; - *p++ = htonl((u32) inode->i_mtime); + *p++ = htonl((u32) lease_get_mtime(inode)); *p++ = 0; *p++ = htonl((u32) inode->i_ctime); *p++ = 0; diff -u --recursive --new-file v2.4.0-test8/linux/fs/nfsd/vfs.c linux/fs/nfsd/vfs.c --- v2.4.0-test8/linux/fs/nfsd/vfs.c Mon Aug 28 21:27:39 2000 +++ linux/fs/nfsd/vfs.c Sun Sep 24 17:10:45 2000 @@ -1,3 +1,4 @@ +#define MSNFS /* HACK HACK */ /* * linux/fs/nfsd/vfs.c * @@ -249,6 +250,15 @@ if (err) goto out; } + + /* + * If we are changing the size of the file, then + * we need to break all leases. + */ + err = get_lease(inode, FMODE_WRITE); + if (err) + goto out_nfserr; + err = get_write_access(inode); if (err) goto out_nfserr; @@ -443,6 +453,14 @@ if (!inode->i_fop) goto out; + /* + * Check to see if there are any leases on this file. + * This may block while leases are broken. + */ + err = get_lease(inode, (access & MAY_WRITE) ? FMODE_WRITE : 0); + if (err) + goto out_nfserr; + if ((access & MAY_WRITE) && (err = get_write_access(inode)) != 0) goto out_nfserr; @@ -451,11 +469,11 @@ atomic_set(&filp->f_count, 1); filp->f_dentry = dentry; if (access & MAY_WRITE) { - filp->f_flags = O_WRONLY; + filp->f_flags = O_WRONLY|O_LARGEFILE; filp->f_mode = FMODE_WRITE; DQUOT_INIT(inode); } else { - filp->f_flags = O_RDONLY; + filp->f_flags = O_RDONLY|O_LARGEFILE; filp->f_mode = FMODE_READ; } @@ -577,6 +595,11 @@ err = nfserr_perm; if (!file.f_op->read) goto out_close; +#ifdef MSNFS + if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) && + (!lock_may_read(file.f_dentry->d_inode, offset, *count))) + goto out_close; +#endif /* Get readahead parameters */ ra = nfsd_get_raparms(fhp->fh_export->ex_dev, fhp->fh_dentry->d_inode->i_ino); @@ -643,6 +666,11 @@ err = nfserr_perm; if (!file.f_op->write) goto out_close; +#ifdef MSNFS + if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) && + (!lock_may_write(file.f_dentry->d_inode, offset, cnt))) + goto out_close; +#endif dentry = file.f_dentry; inode = dentry->d_inode; @@ -1250,6 +1278,13 @@ goto out_dput_old; +#ifdef MSNFS + if ((ffhp->fh_export->ex_flags & NFSEXP_MSNFS) && + ((atomic_read(&odentry->d_count) > 1) + || (atomic_read(&ndentry->d_count) > 1))) { + err = nfserr_perm; + } else +#endif err = vfs_rename(fdir, odentry, tdir, ndentry); if (!err && EX_ISSYNC(tfhp->fh_export)) { nfsd_sync_dir(tdentry); @@ -1311,6 +1346,12 @@ } if (type != S_IFDIR) { /* It's UNLINK */ +#ifdef MSNFS + if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) && + (atomic_read(&rdentry->d_count) > 1)) { + err = nfserr_perm; + } else +#endif err = vfs_unlink(dirp, rdentry); } else { /* It's RMDIR */ err = vfs_rmdir(dirp, rdentry); diff -u --recursive --new-file v2.4.0-test8/linux/fs/open.c linux/fs/open.c --- v2.4.0-test8/linux/fs/open.c Fri Aug 11 15:16:21 2000 +++ linux/fs/open.c Sun Oct 1 20:32:01 2000 @@ -10,11 +10,14 @@ #include #include #include +#include #include #include #include +#define special_file(m) (S_ISCHR(m)||S_ISBLK(m)||S_ISFIFO(m)||S_ISSOCK(m)) + int vfs_statfs(struct super_block *sb, struct statfs *buf) { int retval = -ENODEV; @@ -115,6 +118,13 @@ if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) goto dput_and_out; + /* + * Make sure that there are no leases. + */ + error = get_lease(inode, FMODE_WRITE); + if (error) + goto dput_and_out; + error = get_write_access(inode); if (error) goto dput_and_out; @@ -314,7 +324,8 @@ if (!res) { res = permission(nd.dentry->d_inode, mode); /* SuS v2 requires we report a read only fs too */ - if(!res && (mode & S_IWOTH) && IS_RDONLY(nd.dentry->d_inode)) + if(!res && (mode & S_IWOTH) && IS_RDONLY(nd.dentry->d_inode) + && !special_file(nd.dentry->d_inode->i_mode)) res = -EROFS; path_release(&nd); } @@ -790,6 +801,7 @@ retval = filp->f_op->flush(filp); unlock_kernel(); } + fcntl_dirnotify(0, filp, 0); locks_remove_posix(filp, id); fput(filp); return retval; diff -u --recursive --new-file v2.4.0-test8/linux/fs/partitions/acorn.c linux/fs/partitions/acorn.c --- v2.4.0-test8/linux/fs/partitions/acorn.c Wed Aug 9 14:11:11 2000 +++ linux/fs/partitions/acorn.c Mon Sep 18 15:15:26 2000 @@ -1,12 +1,17 @@ /* - * linux/arch/arm/drivers/block/adfspart.c + * linux/fs/partitions/acorn.c * - * Copyright (c) 1996-2000 Russell King. + * Copyright (c) 1996-2000 Russell King. * - * Scan ADFS partitions on hard disk drives. + * 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. + * + * Scan ADFS partitions on hard disk drives. */ #include #include +#include #include #include #include diff -u --recursive --new-file v2.4.0-test8/linux/fs/partitions/check.c linux/fs/partitions/check.c --- v2.4.0-test8/linux/fs/partitions/check.c Mon Aug 28 21:29:17 2000 +++ linux/fs/partitions/check.c Wed Sep 27 13:39:23 2000 @@ -146,6 +146,16 @@ sprintf(buf, "%s/c%dd%dp%d", maj, ctlr, disk, part); return buf; } + if (hd->major >= COMPAQ_CISS_MAJOR && hd->major <= COMPAQ_CISS_MAJOR+7) { + int ctlr = hd->major - COMPAQ_CISS_MAJOR; + int disk = minor >> hd->minor_shift; + int part = minor & (( 1 << hd->minor_shift) - 1); + if (part == 0) + sprintf(buf, "%s/c%dd%d", maj, ctlr, disk); + else + sprintf(buf, "%s/c%dd%dp%d", maj, ctlr, disk, part); + return buf; + } if (hd->major >= DAC960_MAJOR && hd->major <= DAC960_MAJOR+7) { int ctlr = hd->major - DAC960_MAJOR; int disk = minor >> hd->minor_shift; @@ -177,7 +187,8 @@ #ifdef CONFIG_DEVFS_FS printk(" p%d", (minor & ((1 << hd->minor_shift) - 1))); #else - if (hd->major >= COMPAQ_SMART2_MAJOR+0 && hd->major <= COMPAQ_SMART2_MAJOR+7) + if ((hd->major >= COMPAQ_SMART2_MAJOR+0 && hd->major <= COMPAQ_SMART2_MAJOR+7) || + (hd->major >= COMPAQ_CISS_MAJOR+0 && hd->major <= COMPAQ_CISS_MAJOR+7)) printk(" p%d", (minor & ((1 << hd->minor_shift) - 1))); else printk(" %s", disk_name(hd, minor, buf)); @@ -438,9 +449,6 @@ else #endif rd_load(); -#endif -#ifdef CONFIG_BLK_DEV_MD - md_run_setup(); #endif return 0; } diff -u --recursive --new-file v2.4.0-test8/linux/fs/partitions/mac.c linux/fs/partitions/mac.c --- v2.4.0-test8/linux/fs/partitions/mac.c Wed Feb 9 19:43:53 2000 +++ linux/fs/partitions/mac.c Sun Sep 17 09:51:57 2000 @@ -21,7 +21,7 @@ #include "mac.h" #ifdef CONFIG_PPC -extern void note_bootable_part(kdev_t dev, int part); +extern void note_bootable_part(kdev_t dev, int part, int goodness); #endif /* @@ -67,7 +67,7 @@ brelse(bh); dev_pos = secsize; if ((bh = bread(dev, secsize/dev_bsize, dev_bsize)) == 0) { - printk("%s: error reading partition table\n", + printk("%s: error reading Mac partition table\n", kdevname(dev)); return -1; } @@ -77,6 +77,7 @@ brelse(bh); return 0; /* not a MacOS disk */ } + printk(" [mac]"); blocks_in_map = be32_to_cpu(part->map_count); for (blk = 1; blk <= blocks_in_map; ++blk) { pos = blk * secsize; @@ -114,7 +115,8 @@ goodness++; if (strcasecmp(part->type, "Apple_UNIX_SVR2") == 0 - || strcasecmp(part->type, "Linux_PPC") == 0) { + || (strnicmp(part->type, "Linux", 5) == 0 + && strcasecmp(part->type, "Linux_swap") != 0)) { int i, l; goodness++; @@ -143,7 +145,7 @@ } #ifdef CONFIG_PPC if (found_root_goodness) - note_bootable_part(dev, found_root); + note_bootable_part(dev, found_root, found_root_goodness); #endif brelse(bh); printk("\n"); diff -u --recursive --new-file v2.4.0-test8/linux/fs/proc/generic.c linux/fs/proc/generic.c --- v2.4.0-test8/linux/fs/proc/generic.c Fri Aug 11 14:29:01 2000 +++ linux/fs/proc/generic.c Sun Oct 1 20:35:16 2000 @@ -190,7 +190,7 @@ return 0; } -static unsigned char proc_alloc_map[PROC_NDYNAMIC / 8] = {0}; +static unsigned char proc_alloc_map[PROC_NDYNAMIC / 8]; static int make_inode_number(void) { diff -u --recursive --new-file v2.4.0-test8/linux/fs/proc/proc_misc.c linux/fs/proc/proc_misc.c --- v2.4.0-test8/linux/fs/proc/proc_misc.c Mon Aug 28 21:29:17 2000 +++ linux/fs/proc/proc_misc.c Sun Sep 17 10:13:25 2000 @@ -156,22 +156,30 @@ * have been updated. */ len += sprintf(page+len, - "MemTotal: %8lu kB\n" - "MemFree: %8lu kB\n" - "MemShared: %8lu kB\n" - "Buffers: %8lu kB\n" - "Cached: %8u kB\n" - "HighTotal: %8lu kB\n" - "HighFree: %8lu kB\n" - "LowTotal: %8lu kB\n" - "LowFree: %8lu kB\n" - "SwapTotal: %8lu kB\n" - "SwapFree: %8lu kB\n", + "MemTotal: %8lu kB\n" + "MemFree: %8lu kB\n" + "MemShared: %8lu kB\n" + "Buffers: %8lu kB\n" + "Cached: %8u kB\n" + "Active: %8u kB\n" + "Inact_dirty: %8u kB\n" + "Inact_clean: %8u kB\n" + "Inact_target: %8lu kB\n" + "HighTotal: %8lu kB\n" + "HighFree: %8lu kB\n" + "LowTotal: %8lu kB\n" + "LowFree: %8lu kB\n" + "SwapTotal: %8lu kB\n" + "SwapFree: %8lu kB\n", K(i.totalram), K(i.freeram), K(i.sharedram), K(i.bufferram), K(atomic_read(&page_cache_size)), + K(nr_active_pages), + K(nr_inactive_dirty_pages), + K(nr_inactive_clean_pages()), + K(inactive_target), K(i.totalhigh), K(i.freehigh), K(i.totalram-i.totalhigh), @@ -328,14 +336,14 @@ for (major = 0; major < DK_MAX_MAJOR; major++) { for (disk = 0; disk < DK_MAX_DISK; disk++) { - int active = kstat.dk_drive_rio[major][disk] + + int active = kstat.dk_drive[major][disk] + kstat.dk_drive_rblk[major][disk] + - kstat.dk_drive_wio[major][disk] + kstat.dk_drive_wblk[major][disk]; if (active) len += sprintf(page + len, - "(%u,%u):(%u,%u,%u,%u) ", + "(%u,%u):(%u,%u,%u,%u,%u) ", major, disk, + kstat.dk_drive[major][disk], kstat.dk_drive_rio[major][disk], kstat.dk_drive_rblk[major][disk], kstat.dk_drive_wio[major][disk], diff -u --recursive --new-file v2.4.0-test8/linux/fs/proc/procfs_syms.c linux/fs/proc/procfs_syms.c --- v2.4.0-test8/linux/fs/proc/procfs_syms.c Mon May 8 11:17:47 2000 +++ linux/fs/proc/procfs_syms.c Mon Sep 11 08:41:07 2000 @@ -28,7 +28,9 @@ if (!err) { proc_mnt = kern_mount(&proc_fs_type); err = PTR_ERR(proc_mnt); - if (!IS_ERR(proc_mnt)) + if (IS_ERR(proc_mnt)) + unregister_filesystem(&proc_fs_type); + else err = 0; } return err; diff -u --recursive --new-file v2.4.0-test8/linux/fs/ramfs/inode.c linux/fs/ramfs/inode.c --- v2.4.0-test8/linux/fs/ramfs/inode.c Sun Aug 6 11:43:18 2000 +++ linux/fs/ramfs/inode.c Sun Sep 17 09:51:57 2000 @@ -121,7 +121,7 @@ inode->i_size = 0; inode->i_blksize = PAGE_CACHE_SIZE; inode->i_blocks = 0; - inode->i_rdev = dev; + inode->i_rdev = to_kdev_t(dev); inode->i_nlink = 1; inode->i_op = NULL; inode->i_fop = NULL; diff -u --recursive --new-file v2.4.0-test8/linux/fs/read_write.c linux/fs/read_write.c --- v2.4.0-test8/linux/fs/read_write.c Tue Jun 20 07:52:36 2000 +++ linux/fs/read_write.c Fri Sep 22 14:21:19 2000 @@ -10,6 +10,7 @@ #include #include #include +#include #include @@ -132,6 +133,9 @@ ret = read(file, buf, count, &file->f_pos); } } + if (ret > 0) + inode_dir_notify(file->f_dentry->d_parent->d_inode, + DN_ACCESS); fput(file); } return ret; @@ -156,6 +160,9 @@ ret = write(file, buf, count, &file->f_pos); } } + if (ret > 0) + inode_dir_notify(file->f_dentry->d_parent->d_inode, + DN_MODIFY); fput(file); } return ret; @@ -257,6 +264,10 @@ if (iov != iovstack) kfree(iov); out_nofree: + /* VERIFY_WRITE actually means a read, as we write to user space */ + if ((ret + (type == VERIFY_WRITE)) > 0) + inode_dir_notify(file->f_dentry->d_parent->d_inode, + (type == VERIFY_WRITE) ? DN_MODIFY : DN_ACCESS); return ret; } @@ -327,6 +338,8 @@ if (pos < 0) goto out; ret = read(file, buf, count, &pos); + if (ret > 0) + inode_dir_notify(file->f_dentry->d_parent->d_inode, DN_ACCESS); out: fput(file); bad_file: @@ -357,6 +370,8 @@ goto out; ret = write(file, buf, count, &pos); + if (ret > 0) + inode_dir_notify(file->f_dentry->d_parent->d_inode, DN_MODIFY); out: fput(file); bad_file: diff -u --recursive --new-file v2.4.0-test8/linux/fs/smbfs/inode.c linux/fs/smbfs/inode.c --- v2.4.0-test8/linux/fs/smbfs/inode.c Mon Aug 28 12:50:58 2000 +++ linux/fs/smbfs/inode.c Tue Sep 19 11:33:06 2000 @@ -33,6 +33,13 @@ #include "smb_debug.h" #include "getopt.h" +/* Always pick a default string */ +#ifdef CONFIG_SMB_NLS_REMOTE +#define SMB_NLS_REMOTE CONFIG_SMB_NLS_REMOTE +#else +#define SMB_NLS_REMOTE "" +#endif + static void smb_delete_inode(struct inode *); static void smb_put_super(struct super_block *); static int smb_statfs(struct super_block *, struct statfs *); @@ -445,7 +452,7 @@ memset(mnt, 0, sizeof(struct smb_mount_data_kernel)); strncpy(mnt->codepage.local_name, CONFIG_NLS_DEFAULT, SMB_NLS_MAXNAMELEN); - strncpy(mnt->codepage.remote_name, CONFIG_SMB_NLS_REMOTE, + strncpy(mnt->codepage.remote_name, SMB_NLS_REMOTE, SMB_NLS_MAXNAMELEN); if (ver == SMB_MOUNT_OLDVERSION) { diff -u --recursive --new-file v2.4.0-test8/linux/fs/super.c linux/fs/super.c --- v2.4.0-test8/linux/fs/super.c Fri Aug 11 14:31:45 2000 +++ linux/fs/super.c Mon Sep 25 13:13:53 2000 @@ -483,6 +483,7 @@ { NFS_MOUNT_NOCTO, ",nocto", "" }, { NFS_MOUNT_NOAC, ",noac", "" }, { NFS_MOUNT_NONLM, ",nolock", ",lock" }, + { NFS_MOUNT_BROKEN_SUID, ",broken_suid", "" }, { 0, NULL, NULL } }; @@ -1303,20 +1304,21 @@ * information (or be NULL). * * NOTE! As pre-0.97 versions of mount() didn't use this setup, the - * flags have to have a special 16-bit magic number in the high word: - * 0xC0ED. If this magic word isn't present, the flags and data info - * aren't used, as the syscall assumes we are talking to an older - * version that didn't understand them. + * flags used to have a special 16-bit magic number in the high word: + * 0xC0ED. If this magic number is present, the high word is discarded. */ long do_mount(char * dev_name, char * dir_name, char *type_page, - unsigned long new_flags, void *data_page) + unsigned long flags, void *data_page) { struct file_system_type * fstype; struct nameidata nd; struct vfsmount *mnt = NULL; struct super_block *sb; int retval = 0; - unsigned long flags = 0; + + /* Discard magic */ + if ((flags & MS_MGC_MSK) == MS_MGC_VAL) + flags &= ~MS_MGC_MSK; /* Basic sanity checks */ @@ -1328,21 +1330,25 @@ /* OK, looks good, now let's see what do they want */ /* just change the flags? - capabilities are checked in do_remount() */ - if ((new_flags & (MS_MGC_MSK|MS_REMOUNT)) == (MS_MGC_VAL|MS_REMOUNT)) - return do_remount(dir_name, new_flags&~(MS_MGC_MSK|MS_REMOUNT), - (char *) data_page); - - if ((new_flags & MS_MGC_MSK) == MS_MGC_VAL) - flags = new_flags & ~MS_MGC_MSK; + if (flags & MS_REMOUNT) + return do_remount(dir_name, flags & ~MS_REMOUNT, + (char *) data_page); + + /* "mount --bind"? Equivalent to older "mount -t bind" */ + /* No capabilities? What if users do thousands of these? */ + if (flags & MS_BIND) + return do_loopback(dev_name, dir_name); /* For the rest we need the type */ if (!type_page || !memchr(type_page, 0, PAGE_SIZE)) return -EINVAL; +#if 0 /* Can be deleted again. Introduced in patch-2.3.99-pre6 */ /* loopback mount? This is special - requires fewer capabilities */ if (strcmp(type_page, "bind")==0) return do_loopback(dev_name, dir_name); +#endif /* for the rest we _really_ need capabilities... */ if (!capable(CAP_SYS_ADMIN)) @@ -1354,7 +1360,8 @@ return -ENODEV; /* ... and mountpoint. Do the lookup first to force automounting. */ - if (path_init(dir_name, LOOKUP_FOLLOW|LOOKUP_POSITIVE|LOOKUP_DIRECTORY, &nd)) + if (path_init(dir_name, + LOOKUP_FOLLOW|LOOKUP_POSITIVE|LOOKUP_DIRECTORY, &nd)) retval = path_walk(dir_name, &nd); if (retval) goto fs_out; @@ -1363,7 +1370,7 @@ if (fstype->fs_flags & FS_NOMOUNT) sb = ERR_PTR(-EINVAL); else if (fstype->fs_flags & FS_REQUIRES_DEV) - sb = get_sb_bdev(fstype, dev_name,flags, data_page); + sb = get_sb_bdev(fstype, dev_name, flags, data_page); else if (fstype->fs_flags & FS_SINGLE) sb = get_sb_single(fstype, flags, data_page); else @@ -1376,6 +1383,13 @@ /* Something was mounted here while we slept */ while(d_mountpoint(nd.dentry) && follow_down(&nd.mnt, &nd.dentry)) ; + + /* Refuse the same filesystem on the same mount point */ + retval = -EBUSY; + if (nd.mnt && nd.mnt->mnt_sb == sb + && nd.mnt->mnt_root == nd.dentry) + goto fail; + retval = -ENOENT; if (!nd.dentry->d_inode) goto fail; @@ -1403,7 +1417,7 @@ } asmlinkage long sys_mount(char * dev_name, char * dir_name, char * type, - unsigned long new_flags, void * data) + unsigned long flags, void * data) { int retval; unsigned long data_page; @@ -1423,14 +1437,18 @@ retval = copy_mount_options (dev_name, &dev_page); if (retval < 0) goto out2; + retval = copy_mount_options (data, &data_page); - if (retval >= 0) { - lock_kernel(); - retval = do_mount((char*)dev_page,dir_page,(char*)type_page, - new_flags, (void*)data_page); - unlock_kernel(); - free_page(data_page); - } + if (retval < 0) + goto out3; + + lock_kernel(); + retval = do_mount((char*)dev_page, dir_page, (char*)type_page, + flags, (void*)data_page); + unlock_kernel(); + free_page(data_page); + +out3: free_page(dev_page); out2: putname(dir_page); diff -u --recursive --new-file v2.4.0-test8/linux/fs/udf/ialloc.c linux/fs/udf/ialloc.c --- v2.4.0-test8/linux/fs/udf/ialloc.c Tue Sep 5 14:07:30 2000 +++ linux/fs/udf/ialloc.c Wed Sep 27 13:43:56 2000 @@ -119,10 +119,7 @@ inode->i_nlink = 1; inode->i_dev = sb->s_dev; inode->i_uid = current->fsuid; - if (test_opt (sb, GRPID)) - inode->i_gid = dir->i_gid; - else if (dir->i_mode & S_ISGID) - { + if (dir->i_mode & S_ISGID) { inode->i_gid = dir->i_gid; if (S_ISDIR(mode)) mode |= S_ISGID; diff -u --recursive --new-file v2.4.0-test8/linux/fs/ufs/ialloc.c linux/fs/ufs/ialloc.c --- v2.4.0-test8/linux/fs/ufs/ialloc.c Tue Sep 5 14:07:30 2000 +++ linux/fs/ufs/ialloc.c Tue Sep 19 08:01:35 2000 @@ -265,9 +265,7 @@ inode->i_nlink = 1; inode->i_dev = sb->s_dev; inode->i_uid = current->fsuid; - if (test_opt (sb, GRPID)) - inode->i_gid = dir->i_gid; - else if (dir->i_mode & S_ISGID) { + if (dir->i_mode & S_ISGID) { inode->i_gid = dir->i_gid; if (S_ISDIR(mode)) mode |= S_ISGID; diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-alpha/atomic.h linux/include/asm-alpha/atomic.h --- v2.4.0-test8/linux/include/asm-alpha/atomic.h Mon May 8 22:00:01 2000 +++ linux/include/asm-alpha/atomic.h Sun Sep 24 12:12:33 2000 @@ -1,8 +1,6 @@ #ifndef _ALPHA_ATOMIC_H #define _ALPHA_ATOMIC_H -#include - /* * Atomic operations that C can't guarantee us. Useful for * resource counting etc... @@ -11,11 +9,13 @@ * than regular operations. */ -#ifdef CONFIG_SMP + +/* + * Counter is volatile to make sure gcc doesn't try to be clever + * and move things around on us. We need to use _exactly_ the address + * the user gave us, not some alias that contains the same information. + */ typedef struct { volatile int counter; } atomic_t; -#else -typedef struct { int counter; } atomic_t; -#endif #define ATOMIC_INIT(i) ( (atomic_t) { (i) } ) @@ -23,19 +23,12 @@ #define atomic_set(v,i) ((v)->counter = (i)) /* - * Make sure gcc doesn't try to be clever and move things around - * on us. We need to use _exactly_ the address the user gave us, - * not some alias that contains the same information. - */ -#define __atomic_fool_gcc(x) (*(struct { int a[100]; } *)x) - -/* * To get proper branch prediction for the main line, we must branch * forward to code at the end of this object's .text section, then * branch back to restart the operation. */ -extern __inline__ void atomic_add(int i, atomic_t * v) +static __inline__ void atomic_add(int i, atomic_t * v) { unsigned long temp; __asm__ __volatile__( @@ -46,11 +39,11 @@ ".subsection 2\n" "2: br 1b\n" ".previous" - :"=&r" (temp), "=m" (__atomic_fool_gcc(v)) - :"Ir" (i), "m" (__atomic_fool_gcc(v))); + :"=&r" (temp), "=m" (v->counter) + :"Ir" (i), "m" (v->counter)); } -extern __inline__ void atomic_sub(int i, atomic_t * v) +static __inline__ void atomic_sub(int i, atomic_t * v) { unsigned long temp; __asm__ __volatile__( @@ -61,14 +54,14 @@ ".subsection 2\n" "2: br 1b\n" ".previous" - :"=&r" (temp), "=m" (__atomic_fool_gcc(v)) - :"Ir" (i), "m" (__atomic_fool_gcc(v))); + :"=&r" (temp), "=m" (v->counter) + :"Ir" (i), "m" (v->counter)); } /* * Same as above, but return the result value */ -extern __inline__ long atomic_add_return(int i, atomic_t * v) +static __inline__ long atomic_add_return(int i, atomic_t * v) { long temp, result; __asm__ __volatile__( @@ -81,12 +74,12 @@ ".subsection 2\n" "2: br 1b\n" ".previous" - :"=&r" (temp), "=m" (__atomic_fool_gcc(v)), "=&r" (result) - :"Ir" (i), "m" (__atomic_fool_gcc(v))); + :"=&r" (temp), "=m" (v->counter), "=&r" (result) + :"Ir" (i), "m" (v->counter) : "memory"); return result; } -extern __inline__ long atomic_sub_return(int i, atomic_t * v) +static __inline__ long atomic_sub_return(int i, atomic_t * v) { long temp, result; __asm__ __volatile__( @@ -99,8 +92,8 @@ ".subsection 2\n" "2: br 1b\n" ".previous" - :"=&r" (temp), "=m" (__atomic_fool_gcc(v)), "=&r" (result) - :"Ir" (i), "m" (__atomic_fool_gcc(v))); + :"=&r" (temp), "=m" (v->counter), "=&r" (result) + :"Ir" (i), "m" (v->counter) : "memory"); return result; } diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-alpha/bitops.h linux/include/asm-alpha/bitops.h --- v2.4.0-test8/linux/include/asm-alpha/bitops.h Mon Aug 28 21:21:57 2000 +++ linux/include/asm-alpha/bitops.h Tue Oct 3 09:24:41 2000 @@ -1,6 +1,9 @@ #ifndef _ALPHA_BITOPS_H #define _ALPHA_BITOPS_H +#include +#include + /* * Copyright 1994, Linus Torvalds. */ @@ -17,14 +20,19 @@ * bit 0 is the LSB of addr; bit 64 is the LSB of (addr+1). */ +#define BITOPS_NO_BRANCH + extern __inline__ void set_bit(unsigned long nr, volatile void * addr) { +#ifndef BITOPS_NO_BRANCH unsigned long oldbit; +#endif unsigned long temp; unsigned int * m = ((unsigned int *) addr) + (nr >> 5); +#ifndef BITOPS_NO_BRANCH __asm__ __volatile__( - "1: ldl_l %0,%1\n" + "1: ldl_l %0,%4\n" " and %0,%3,%2\n" " bne %2,2f\n" " xor %0,%3,%0\n" @@ -36,16 +44,57 @@ ".previous" :"=&r" (temp), "=m" (*m), "=&r" (oldbit) :"Ir" (1UL << (nr & 31)), "m" (*m)); +#else + __asm__ __volatile__( + "1: ldl_l %0,%3\n" + " bis %0,%2,%0\n" + " stl_c %0,%1\n" + " beq %0,2f\n" + ".subsection 2\n" + "2: br 1b\n" + ".previous" + :"=&r" (temp), "=m" (*m) + :"Ir" (1UL << (nr & 31)), "m" (*m)); +#endif } +/* + * WARNING: non atomic version. + */ +extern __inline__ void __set_bit(unsigned long nr, volatile void * addr) +{ + unsigned int * m = ((unsigned int *) addr) + (nr >> 5); + /* + * Asm and C produces the same thing so let + * the compiler to do its good work. + */ +#if 0 + int tmp; + + __asm__ __volatile__( + "ldl %0,%3\n\t" + "bis %0,%2,%0\n\t" + "stl %0,%1" + : "=&r" (tmp), "=m" (*m) + : "Ir" (1UL << (nr & 31)), "m" (*m)); +#else + *m |= 1UL << (nr & 31); +#endif +} + +#define smp_mb__before_clear_bit() smp_mb() +#define smp_mb__after_clear_bit() smp_mb() extern __inline__ void clear_bit(unsigned long nr, volatile void * addr) { +#ifndef BITOPS_NO_BRANCH unsigned long oldbit; +#endif unsigned long temp; unsigned int * m = ((unsigned int *) addr) + (nr >> 5); +#ifndef BITOPS_NO_BRANCH __asm__ __volatile__( - "1: ldl_l %0,%1\n" + "1: ldl_l %0,%4\n" " and %0,%3,%2\n" " beq %2,2f\n" " xor %0,%3,%0\n" @@ -57,6 +106,18 @@ ".previous" :"=&r" (temp), "=m" (*m), "=&r" (oldbit) :"Ir" (1UL << (nr & 31)), "m" (*m)); +#else + __asm__ __volatile__( + "1: ldl_l %0,%3\n" + " and %0,%2,%0\n" + " stl_c %0,%1\n" + " beq %0,2f\n" + ".subsection 2\n" + "2: br 1b\n" + ".previous" + :"=&r" (temp), "=m" (*m) + :"Ir" (~(1UL << (nr & 31))), "m" (*m)); +#endif } extern __inline__ void change_bit(unsigned long nr, volatile void * addr) @@ -65,12 +126,12 @@ unsigned int * m = ((unsigned int *) addr) + (nr >> 5); __asm__ __volatile__( - "1: ldl_l %0,%1\n" + "1: ldl_l %0,%3\n" " xor %0,%2,%0\n" " stl_c %0,%1\n" - " beq %0,3f\n" + " beq %0,2f\n" ".subsection 2\n" - "3: br 1b\n" + "2: br 1b\n" ".previous" :"=&r" (temp), "=m" (*m) :"Ir" (1UL << (nr & 31)), "m" (*m)); @@ -84,18 +145,43 @@ unsigned int * m = ((unsigned int *) addr) + (nr >> 5); __asm__ __volatile__( - "1: ldl_l %0,%1\n" + "1: ldl_l %0,%4\n" " and %0,%3,%2\n" " bne %2,2f\n" " xor %0,%3,%0\n" " stl_c %0,%1\n" " beq %0,3f\n" +#ifdef CONFIG_SMP " mb\n" +#endif "2:\n" ".subsection 2\n" "3: br 1b\n" ".previous" :"=&r" (temp), "=m" (*m), "=&r" (oldbit) + :"Ir" (1UL << (nr & 31)), "m" (*m) : "memory"); + + return oldbit != 0; +} + +/* + * WARNING: non atomic version. + */ +extern __inline__ int __test_and_set_bit(unsigned long nr, + volatile void * addr) +{ + unsigned long oldbit; + unsigned long temp; + unsigned int * m = ((unsigned int *) addr) + (nr >> 5); + + __asm__ __volatile__( + " ldl %0,%4\n" + " and %0,%3,%2\n" + " bne %2,1f\n" + " xor %0,%3,%0\n" + " stl %0,%1\n" + "1:\n" + :"=&r" (temp), "=m" (*m), "=&r" (oldbit) :"Ir" (1UL << (nr & 31)), "m" (*m)); return oldbit != 0; @@ -109,18 +195,43 @@ unsigned int * m = ((unsigned int *) addr) + (nr >> 5); __asm__ __volatile__( - "1: ldl_l %0,%1\n" + "1: ldl_l %0,%4\n" " and %0,%3,%2\n" " beq %2,2f\n" " xor %0,%3,%0\n" " stl_c %0,%1\n" " beq %0,3f\n" +#ifdef CONFIG_SMP " mb\n" +#endif "2:\n" ".subsection 2\n" "3: br 1b\n" ".previous" :"=&r" (temp), "=m" (*m), "=&r" (oldbit) + :"Ir" (1UL << (nr & 31)), "m" (*m) : "memory"); + + return oldbit != 0; +} + +/* + * WARNING: non atomic version. + */ +extern __inline__ int __test_and_clear_bit(unsigned long nr, + volatile void * addr) +{ + unsigned long oldbit; + unsigned long temp; + unsigned int * m = ((unsigned int *) addr) + (nr >> 5); + + __asm__ __volatile__( + " ldl %0,%4\n" + " and %0,%3,%2\n" + " beq %2,1f\n" + " xor %0,%3,%0\n" + " stl %0,%1\n" + "1:\n" + :"=&r" (temp), "=m" (*m), "=&r" (oldbit) :"Ir" (1UL << (nr & 31)), "m" (*m)); return oldbit != 0; @@ -134,17 +245,19 @@ unsigned int * m = ((unsigned int *) addr) + (nr >> 5); __asm__ __volatile__( - "1: ldl_l %0,%1\n" + "1: ldl_l %0,%4\n" " and %0,%3,%2\n" " xor %0,%3,%0\n" " stl_c %0,%1\n" " beq %0,3f\n" +#ifdef CONFIG_SMP " mb\n" +#endif ".subsection 2\n" "3: br 1b\n" ".previous" :"=&r" (temp), "=m" (*m), "=&r" (oldbit) - :"Ir" (1UL << (nr & 31)), "m" (*m)); + :"Ir" (1UL << (nr & 31)), "m" (*m) : "memory"); return oldbit != 0; } @@ -279,16 +392,16 @@ #ifdef __KERNEL__ -#define ext2_set_bit test_and_set_bit -#define ext2_clear_bit test_and_clear_bit +#define ext2_set_bit __test_and_set_bit +#define ext2_clear_bit __test_and_clear_bit #define ext2_test_bit test_bit #define ext2_find_first_zero_bit find_first_zero_bit #define ext2_find_next_zero_bit find_next_zero_bit /* Bitmap functions for the minix filesystem. */ -#define minix_test_and_set_bit(nr,addr) test_and_set_bit(nr,addr) -#define minix_set_bit(nr,addr) set_bit(nr,addr) -#define minix_test_and_clear_bit(nr,addr) test_and_clear_bit(nr,addr) +#define minix_test_and_set_bit(nr,addr) __test_and_set_bit(nr,addr) +#define minix_set_bit(nr,addr) __set_bit(nr,addr) +#define minix_test_and_clear_bit(nr,addr) __test_and_clear_bit(nr,addr) #define minix_test_bit(nr,addr) test_bit(nr,addr) #define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size) diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-alpha/elf.h linux/include/asm-alpha/elf.h --- v2.4.0-test8/linux/include/asm-alpha/elf.h Tue Jul 11 15:43:45 2000 +++ linux/include/asm-alpha/elf.h Fri Sep 22 14:07:43 2000 @@ -127,7 +127,7 @@ #ifdef __KERNEL__ #define SET_PERSONALITY(EX, IBCS2) \ - set_personality((EX).e_flags & EF_ALPHA_32BIT \ + set_personality(((EX).e_flags & EF_ALPHA_32BIT) \ ? PER_LINUX_32BIT : (IBCS2) ? PER_SVR4 : PER_LINUX) #endif diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-alpha/fcntl.h linux/include/asm-alpha/fcntl.h --- v2.4.0-test8/linux/include/asm-alpha/fcntl.h Fri Aug 11 14:37:49 2000 +++ linux/include/asm-alpha/fcntl.h Wed Sep 27 13:39:23 2000 @@ -48,13 +48,19 @@ #define F_EXLCK 16 /* or 3 */ #define F_SHLCK 32 /* or 4 */ +#define F_INPROGRESS 16 + /* operations for bsd flock(), also used by the kernel implementation */ #define LOCK_SH 1 /* shared lock */ #define LOCK_EX 2 /* exclusive lock */ #define LOCK_NB 4 /* or'd with one of the above to prevent blocking */ #define LOCK_UN 8 /* remove lock */ - +#define LOCK_MAND 32 /* This is a mandatory flock */ +#define LOCK_READ 64 /* ... Which allows concurrent read operations */ +#define LOCK_WRITE 128 /* ... Which allows concurrent write operations */ +#define LOCK_RW 192 /* ... Which allows concurrent read & write ops */ + struct flock { short l_type; short l_whence; @@ -66,5 +72,6 @@ #ifdef __KERNEL__ #define flock64 flock #endif +#define F_LINUX_SPECIFIC_BASE 1024 #endif diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-alpha/resource.h linux/include/asm-alpha/resource.h --- v2.4.0-test8/linux/include/asm-alpha/resource.h Thu Feb 17 09:35:07 2000 +++ linux/include/asm-alpha/resource.h Wed Sep 27 13:39:23 2000 @@ -15,8 +15,9 @@ #define RLIMIT_AS 7 /* address space limit(?) */ #define RLIMIT_NPROC 8 /* max number of processes */ #define RLIMIT_MEMLOCK 9 /* max locked-in-memory address space */ +#define RLIMIT_LOCKS 10 /* maximum file locks held */ -#define RLIM_NLIMITS 10 +#define RLIM_NLIMITS 11 /* * SuS says limits have to be unsigned. Fine, it's unsigned, but @@ -39,6 +40,7 @@ {LONG_MAX, LONG_MAX}, /* RLIMIT_AS */ \ {LONG_MAX, LONG_MAX}, /* RLIMIT_NPROC */ \ {LONG_MAX, LONG_MAX}, /* RLIMIT_MEMLOCK */ \ + {LONG_MAX, LONG_MAX}, /* RLIMIT_LOCKS */ \ } #endif /* __KERNEL__ */ diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-alpha/semaphore-helper.h linux/include/asm-alpha/semaphore-helper.h --- v2.4.0-test8/linux/include/asm-alpha/semaphore-helper.h Thu Feb 24 22:36:05 2000 +++ linux/include/asm-alpha/semaphore-helper.h Fri Sep 22 14:07:43 2000 @@ -37,7 +37,7 @@ ".subsection 2\n" "3: br 1b\n" ".previous" - : "=r"(ret), "=r"(tmp), "=m"(__atomic_fool_gcc(&sem->waking)) + : "=r"(ret), "=r"(tmp), "=m"(sem->waking.counter) : "0"(0)); return ret > 0; diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-alpha/spinlock.h linux/include/asm-alpha/spinlock.h --- v2.4.0-test8/linux/include/asm-alpha/spinlock.h Thu Feb 24 22:36:05 2000 +++ linux/include/asm-alpha/spinlock.h Fri Sep 22 14:07:43 2000 @@ -5,8 +5,8 @@ #include #include -#define DEBUG_SPINLOCK 1 -#define DEBUG_RWLOCK 1 +#define DEBUG_SPINLOCK 0 +#define DEBUG_RWLOCK 0 /* * Simple spin lock operations. There are two variants, one clears IRQ's @@ -38,9 +38,6 @@ #define spin_is_locked(x) ((x)->lock != 0) #define spin_unlock_wait(x) ({ do { barrier(); } while ((x)->lock); }) -typedef struct { unsigned long a[100]; } __dummy_lock_t; -#define __dummy_lock(lock) (*(__dummy_lock_t *)(lock)) - #if DEBUG_SPINLOCK extern void spin_unlock(spinlock_t * lock); extern void debug_spin_lock(spinlock_t * lock, const char *, int); @@ -83,8 +80,8 @@ " blbs %0,2b\n" " br 1b\n" ".previous" - : "=r" (tmp), "=m" (__dummy_lock(lock)) - : "m"(__dummy_lock(lock))); + : "=r" (tmp), "=m" (lock->lock) + : "m"(lock->lock) : "memory"); } #define spin_trylock(lock) (!test_and_set_bit(0,(lock))) @@ -119,9 +116,8 @@ " bne %1,6b\n" " br 1b\n" ".previous" - : "=m" (__dummy_lock(lock)), "=&r" (regx) - : "0" (__dummy_lock(lock)) - ); + : "=m" (*(volatile int *)lock), "=&r" (regx) + : "0" (*(volatile int *)lock) : "memory"); } static inline void read_lock(rwlock_t * lock) @@ -140,9 +136,8 @@ " blbs %1,6b\n" " br 1b\n" ".previous" - : "=m" (__dummy_lock(lock)), "=&r" (regx) - : "m" (__dummy_lock(lock)) - ); + : "=m" (*(volatile int *)lock), "=&r" (regx) + : "m" (*(volatile int *)lock) : "memory"); } #endif /* DEBUG_RWLOCK */ @@ -156,6 +151,7 @@ { long regx; __asm__ __volatile__( + " mb\n" "1: ldl_l %1,%0\n" " addl %1,2,%1\n" " stl_c %1,%0\n" @@ -163,8 +159,8 @@ ".subsection 2\n" "6: br 1b\n" ".previous" - : "=m" (__dummy_lock(lock)), "=&r" (regx) - : "m" (__dummy_lock(lock))); + : "=m" (*(volatile int *)lock), "=&r" (regx) + : "m" (*(volatile int *)lock) : "memory"); } #endif /* _ALPHA_SPINLOCK_H */ diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-alpha/system.h linux/include/asm-alpha/system.h --- v2.4.0-test8/linux/include/asm-alpha/system.h Mon Jun 26 11:26:56 2000 +++ linux/include/asm-alpha/system.h Sun Sep 24 12:12:33 2000 @@ -137,12 +137,19 @@ #define wmb() \ __asm__ __volatile__("wmb": : :"memory") +#ifdef CONFIG_SMP +#define smp_mb() mb() +#define smp_rmb() rmb() +#define smp_wmb() wmb() +#else +#define smp_mb() barrier() +#define smp_rmb() barrier() +#define smp_wmb() barrier() +#endif + #define set_mb(var, value) \ do { var = value; mb(); } while (0) -#define set_rmb(var, value) \ -do { var = value; rmb(); } while (0) - #define set_wmb(var, value) \ do { var = value; wmb(); } while (0) @@ -284,11 +291,11 @@ #define getipl() (rdps() & 7) #define setipl(ipl) ((void) swpipl(ipl)) -#define __cli() setipl(IPL_MAX) -#define __sti() setipl(IPL_MIN) +#define __cli() do { setipl(IPL_MAX); barrier(); } while(0) +#define __sti() do { barrier(); setipl(IPL_MIN); } while(0) #define __save_flags(flags) ((flags) = rdps()) -#define __save_and_cli(flags) ((flags) = swpipl(IPL_MAX)) -#define __restore_flags(flags) setipl(flags) +#define __save_and_cli(flags) do { (flags) = swpipl(IPL_MAX); barrier(); } while(0) +#define __restore_flags(flags) do { barrier(); setipl(flags); barrier(); } while(0) #define local_irq_save(flags) __save_and_cli(flags) #define local_irq_restore(flags) __restore_flags(flags) @@ -344,6 +351,8 @@ /* * Atomic exchange. + * Since it can be used to implement critical sections + * it must clobber "memory" (also for interrupts in UP). */ extern __inline__ unsigned long @@ -352,16 +361,18 @@ unsigned long dummy; __asm__ __volatile__( - "1: ldl_l %0,%2\n" + "1: ldl_l %0,%4\n" " bis $31,%3,%1\n" " stl_c %1,%2\n" " beq %1,2f\n" +#ifdef CONFIG_SMP " mb\n" +#endif ".subsection 2\n" "2: br 1b\n" ".previous" : "=&r" (val), "=&r" (dummy), "=m" (*m) - : "rI" (val), "m" (*m)); + : "rI" (val), "m" (*m) : "memory"); return val; } @@ -372,16 +383,18 @@ unsigned long dummy; __asm__ __volatile__( - "1: ldq_l %0,%2\n" + "1: ldq_l %0,%4\n" " bis $31,%3,%1\n" " stq_c %1,%2\n" " beq %1,2f\n" +#ifdef CONFIG_SMP " mb\n" +#endif ".subsection 2\n" "2: br 1b\n" ".previous" : "=&r" (val), "=&r" (dummy), "=m" (*m) - : "rI" (val), "m" (*m)); + : "rI" (val), "m" (*m) : "memory"); return val; } @@ -416,6 +429,11 @@ * Atomic compare and exchange. Compare OLD with MEM, if identical, * store NEW in MEM. Return the initial value in MEM. Success is * indicated by comparing RETURN with OLD. + * + * The memory barrier should be placed in SMP only when we actually + * make the change. If we don't change anything (so if the returned + * prev is equal to old) then we aren't acquiring anything new and + * we don't need any memory barrier as far I can tell. */ #define __HAVE_ARCH_CMPXCHG 1 @@ -426,18 +444,21 @@ unsigned long prev, cmp; __asm__ __volatile__( - "1: ldl_l %0,%2\n" + "1: ldl_l %0,%5\n" " cmpeq %0,%3,%1\n" " beq %1,2f\n" " mov %4,%1\n" " stl_c %1,%2\n" " beq %1,3f\n" - "2: mb\n" +#ifdef CONFIG_SMP + " mb\n" +#endif + "2:\n" ".subsection 2\n" "3: br 1b\n" ".previous" : "=&r"(prev), "=&r"(cmp), "=m"(*m) - : "r"((long) old), "r"(new), "m"(*m)); + : "r"((long) old), "r"(new), "m"(*m) : "memory"); return prev; } @@ -448,18 +469,21 @@ unsigned long prev, cmp; __asm__ __volatile__( - "1: ldq_l %0,%2\n" + "1: ldq_l %0,%5\n" " cmpeq %0,%3,%1\n" " beq %1,2f\n" " mov %4,%1\n" " stq_c %1,%2\n" " beq %1,3f\n" - "2: mb\n" +#ifdef CONFIG_SMP + " mb\n" +#endif + "2:\n" ".subsection 2\n" "3: br 1b\n" ".previous" : "=&r"(prev), "=&r"(cmp), "=m"(*m) - : "r"((long) old), "r"(new), "m"(*m)); + : "r"((long) old), "r"(new), "m"(*m) : "memory"); return prev; } diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-alpha/termios.h linux/include/asm-alpha/termios.h --- v2.4.0-test8/linux/include/asm-alpha/termios.h Wed Oct 27 17:04:51 1999 +++ linux/include/asm-alpha/termios.h Fri Sep 22 14:21:17 2000 @@ -71,6 +71,7 @@ #define N_SLIP 1 #define N_MOUSE 2 #define N_PPP 3 +#define N_STRIP 4 #define N_AX25 5 #define N_X25 6 /* X.25 async */ #define N_6PACK 7 diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-arc/dma.h linux/include/asm-arm/arch-arc/dma.h --- v2.4.0-test8/linux/include/asm-arm/arch-arc/dma.h Tue Jul 18 22:43:24 2000 +++ linux/include/asm-arm/arch-arc/dma.h Mon Sep 18 15:15:22 2000 @@ -1,13 +1,17 @@ /* - * linux/include/asm-arm/arch-arc/dma.h + * linux/include/asm-arm/arch-arc/dma.h * - * Copyright (C) 1996-1998 Russell King + * Copyright (C) 1996-1998 Russell King * - * Acorn Archimedes/A5000 architecture virtual DMA - * implementation + * 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. * - * Modifications: - * 04-04-1998 RMK Merged arc and a5k versions + * Acorn Archimedes/A5000 architecture virtual DMA + * implementation + * + * Modifications: + * 04-04-1998 RMK Merged arc and a5k versions */ #ifndef __ASM_ARCH_DMA_H #define __ASM_ARCH_DMA_H diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-arc/hardware.h linux/include/asm-arm/arch-arc/hardware.h --- v2.4.0-test8/linux/include/asm-arm/arch-arc/hardware.h Sun Aug 13 09:54:15 2000 +++ linux/include/asm-arm/arch-arc/hardware.h Mon Sep 18 15:15:22 2000 @@ -1,13 +1,17 @@ /* - * linux/include/asm-arm/arch-arc/hardware.h + * linux/include/asm-arm/arch-arc/hardware.h * - * Copyright (C) 1996-1999 Russell King. + * Copyright (C) 1996-1999 Russell King. * - * This file contains the hardware definitions of the - * Acorn Archimedes/A5000 machines. + * 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. * - * Modifications: - * 04-04-1998 PJB/RMK Merged arc and a5k versions + * This file contains the hardware definitions of the + * Acorn Archimedes/A5000 machines. + * + * Modifications: + * 04-04-1998 PJB/RMK Merged arc and a5k versions */ #ifndef __ASM_ARCH_HARDWARE_H #define __ASM_ARCH_HARDWARE_H @@ -22,7 +26,7 @@ */ #define HAS_IOC #define HAS_MEMC -#include +#include #define HAS_VIDC /* Hardware addresses of major areas. diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-arc/ide.h linux/include/asm-arm/arch-arc/ide.h --- v2.4.0-test8/linux/include/asm-arm/arch-arc/ide.h Sun Aug 13 09:54:15 2000 +++ linux/include/asm-arm/arch-arc/ide.h Mon Sep 18 15:15:22 2000 @@ -1,15 +1,19 @@ /* - * linux/include/asm-arm/arch-arc/ide.h + * linux/include/asm-arm/arch-arc/ide.h * - * Copyright (c) 1997,1998 Russell King + * Copyright (C) 1997,1998 Russell King * - * IDE definitions for the Acorn Archimedes/A5000 - * architecture + * 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. * - * Modifications: - * 04-04-1998 PJB Merged `arc' and `a5k' versions - * 01-07-1998 RMK Added new ide_ioregspec_t - * 29-07-1998 RMK Major re-work of IDE architecture specific code + * IDE definitions for the Acorn Archimedes/A5000 + * architecture + * + * Modifications: + * 04-04-1998 PJB Merged `arc' and `a5k' versions + * 01-07-1998 RMK Added new ide_ioregspec_t + * 29-07-1998 RMK Major re-work of IDE architecture specific code */ #include #include diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-arc/io.h linux/include/asm-arm/arch-arc/io.h --- v2.4.0-test8/linux/include/asm-arm/arch-arc/io.h Thu Feb 24 22:44:47 2000 +++ linux/include/asm-arm/arch-arc/io.h Mon Sep 18 15:15:22 2000 @@ -1,10 +1,14 @@ /* - * linux/include/asm-arm/arch-arc/io.h + * linux/include/asm-arm/arch-arc/io.h * - * Copyright (C) 1997 Russell King + * Copyright (C) 1997 Russell King * - * Modifications: - * 06-Dec-1997 RMK Created. + * 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. + * + * Modifications: + * 06-Dec-1997 RMK Created. */ #ifndef __ASM_ARM_ARCH_IO_H #define __ASM_ARM_ARCH_IO_H diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-arc/irq.h linux/include/asm-arm/arch-arc/irq.h --- v2.4.0-test8/linux/include/asm-arm/arch-arc/irq.h Sun Sep 3 11:19:11 2000 +++ linux/include/asm-arm/arch-arc/irq.h Mon Sep 18 15:15:22 2000 @@ -1,9 +1,13 @@ /* - * include/asm-arm/arch-arc/irq.h + * linux/include/asm-arm/arch-arc/irq.h * - * Copyright (C) 1996 Russell King + * Copyright (C) 1996 Russell King * - * Changelog: + * 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. + * + * Changelog: * 24-09-1996 RMK Created * 10-10-1996 RMK Brought up to date with arch-sa110eval * 22-10-1996 RMK Changed interrupt numbers & uses new inb/outb macros @@ -11,7 +15,7 @@ * 22-08-1998 RMK Restructured IRQ routines */ #include -#include +#include #ifdef CONFIG_ARCH_ARC #define a_clf() clf() @@ -168,7 +172,7 @@ } } - irq_mask[IRQ_KEYBOARDTX].noautoenable = 1; + irq_desc[IRQ_KEYBOARDTX].noautoenable = 1; init_FIQ(); } diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-arc/irqs.h linux/include/asm-arm/arch-arc/irqs.h --- v2.4.0-test8/linux/include/asm-arm/arch-arc/irqs.h Fri May 8 00:42:39 1998 +++ linux/include/asm-arm/arch-arc/irqs.h Mon Sep 18 15:15:22 2000 @@ -1,10 +1,14 @@ /* - * linux/include/asm-arm/arch-arc/irqs.h + * linux/include/asm-arm/arch-arc/irqs.h * - * Copyright (C) 1996 Russell King, Dave Gilbert + * Copyright (C) 1996 Russell King, Dave Gilbert * - * Modifications: - * 04-04-1998 PJB Merged arc and a5k versions + * 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. + * + * Modifications: + * 04-04-1998 PJB Merged arc and a5k versions */ #include diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-arc/keyboard.h linux/include/asm-arm/arch-arc/keyboard.h --- v2.4.0-test8/linux/include/asm-arm/arch-arc/keyboard.h Sat May 8 11:06:57 1999 +++ linux/include/asm-arm/arch-arc/keyboard.h Mon Sep 18 15:15:22 2000 @@ -1,10 +1,14 @@ /* - * linux/include/asm-arm/arch-arc/keyboard.h + * linux/include/asm-arm/arch-arc/keyboard.h * - * Keyboard driver definitions for Acorn Archimedes/A5000 - * architecture + * Copyright (C) 1998 Russell King * - * Copyright (C) 1998 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. + * + * Keyboard driver definitions for Acorn Archimedes/A5000 + * architecture */ #include diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-arc/memory.h linux/include/asm-arm/arch-arc/memory.h --- v2.4.0-test8/linux/include/asm-arm/arch-arc/memory.h Thu Oct 28 10:16:02 1999 +++ linux/include/asm-arm/arch-arc/memory.h Mon Sep 18 15:15:22 2000 @@ -1,7 +1,11 @@ /* - * linux/include/asm-arm/arch-arc/memory.h + * linux/include/asm-arm/arch-arc/memory.h * - * Copyright (c) 1996-1999 Russell King. + * Copyright (C) 1996-1999 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. * * Changelog: * 22-Nov-1996 RMK Created diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-arc/oldlatches.h linux/include/asm-arm/arch-arc/oldlatches.h --- v2.4.0-test8/linux/include/asm-arm/arch-arc/oldlatches.h Tue Jul 18 22:43:24 2000 +++ linux/include/asm-arm/arch-arc/oldlatches.h Mon Sep 18 15:15:22 2000 @@ -1,12 +1,14 @@ /* - * linux/include/asm-arm/arch-arc/oldlatches.h + * linux/include/asm-arm/arch-arc/oldlatches.h * - * Copyright (C) 1996 Russell King, Dave Gilbert + * Copyright (C) 1996 Russell King, Dave Gilbert * - * Dummy oldlatches.h + * 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. * - * Modifications: - * 04-04-1998 PJB/RMK Merged arc and a5k versions + * Modifications: + * 04-04-1998 PJB/RMK Merged arc and a5k versions */ #ifndef _ASM_ARCH_OLDLATCH_H #define _ASM_ARCH_OLDLATCH_H diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-arc/processor.h linux/include/asm-arm/arch-arc/processor.h --- v2.4.0-test8/linux/include/asm-arm/arch-arc/processor.h Wed Oct 20 16:29:08 1999 +++ linux/include/asm-arm/arch-arc/processor.h Mon Sep 18 15:15:22 2000 @@ -1,11 +1,15 @@ /* - * linux/include/asm-arm/arch-arc/processor.h + * linux/include/asm-arm/arch-arc/processor.h * - * Copyright (c) 1996-1999 Russell King. + * Copyright (c) 1996-1999 Russell King. * - * Changelog: - * 10-Sep-1996 RMK Created - * 21-Mar-1999 RMK Added asm/arch/memory.h + * 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. + * + * Changelog: + * 10-Sep-1996 RMK Created + * 21-Mar-1999 RMK Added asm/arch/memory.h */ #ifndef __ASM_ARCH_PROCESSOR_H diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-arc/serial.h linux/include/asm-arm/arch-arc/serial.h --- v2.4.0-test8/linux/include/asm-arm/arch-arc/serial.h Thu Jan 13 13:30:31 2000 +++ linux/include/asm-arm/arch-arc/serial.h Mon Sep 18 15:15:22 2000 @@ -1,11 +1,15 @@ /* - * linux/include/asm-arm/arch-arc/serial.h + * linux/include/asm-arm/arch-arc/serial.h * - * Copyright (c) 1996 Russell King. + * Copyright (C) 1996 Russell King. * - * Changelog: - * 15-10-1996 RMK Created - * 04-04-1998 PJB Merged `arc' and `a5k' architectures + * 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. + * + * Changelog: + * 15-10-1996 RMK Created + * 04-04-1998 PJB Merged `arc' and `a5k' architectures */ #ifndef __ASM_ARCH_SERIAL_H #define __ASM_ARCH_SERIAL_H diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-arc/system.h linux/include/asm-arm/arch-arc/system.h --- v2.4.0-test8/linux/include/asm-arm/arch-arc/system.h Mon Aug 14 13:09:07 2000 +++ linux/include/asm-arm/arch-arc/system.h Mon Sep 18 15:15:22 2000 @@ -1,7 +1,11 @@ /* - * linux/include/asm-arm/arch-arc/system.h + * linux/include/asm-arm/arch-arc/system.h * - * Copyright (c) 1996-1999 Russell King and Dave Gilbert + * Copyright (C) 1996-1999 Russell King and Dave Gilbert + * + * 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. */ static void arch_idle(void) diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-arc/time.h linux/include/asm-arm/arch-arc/time.h --- v2.4.0-test8/linux/include/asm-arm/arch-arc/time.h Sun Feb 6 17:45:25 2000 +++ linux/include/asm-arm/arch-arc/time.h Mon Sep 18 15:15:22 2000 @@ -1,12 +1,16 @@ /* - * linux/include/asm-arm/arch-arc/time.h + * linux/include/asm-arm/arch-arc/time.h * - * Copyright (c) 1996-2000 Russell King. + * Copyright (C) 1996-2000 Russell King. * - * Changelog: - * 24-Sep-1996 RMK Created - * 10-Oct-1996 RMK Brought up to date with arch-sa110eval - * 04-Dec-1997 RMK Updated for new arch/arm/time.c + * 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. + * + * Changelog: + * 24-Sep-1996 RMK Created + * 10-Oct-1996 RMK Brought up to date with arch-sa110eval + * 04-Dec-1997 RMK Updated for new arch/arm/time.c */ extern void ioctime_init(void); diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-arc/timex.h linux/include/asm-arm/arch-arc/timex.h --- v2.4.0-test8/linux/include/asm-arm/arch-arc/timex.h Sun Apr 12 11:42:15 1998 +++ linux/include/asm-arm/arch-arc/timex.h Mon Sep 18 15:15:22 2000 @@ -1,9 +1,13 @@ /* - * linux/include/asm-arm/arch-arc/timex.h + * linux/include/asm-arm/arch-arc/timex.h * - * Acorn Archimedes/A5000 architecture timex specifications + * Copyright (C) 1997, 1998 Russell King * - * Copyright (C) 1997, 1998 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. + * + * Acorn Archimedes/A5000 architecture timex specifications */ /* diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-arc/uncompress.h linux/include/asm-arm/arch-arc/uncompress.h --- v2.4.0-test8/linux/include/asm-arm/arch-arc/uncompress.h Sat May 8 11:06:57 1999 +++ linux/include/asm-arm/arch-arc/uncompress.h Mon Sep 18 15:15:22 2000 @@ -1,7 +1,11 @@ /* - * linux/include/asm-arm/arch-arc/uncompress.h + * linux/include/asm-arm/arch-arc/uncompress.h * - * Copyright (C) 1996 Russell King + * Copyright (C) 1996 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. */ #define VIDMEM ((char *)0x02000000) diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-cl7500/hardware.h linux/include/asm-arm/arch-cl7500/hardware.h --- v2.4.0-test8/linux/include/asm-arm/arch-cl7500/hardware.h Sun Aug 13 09:54:15 2000 +++ linux/include/asm-arm/arch-cl7500/hardware.h Mon Sep 18 15:15:22 2000 @@ -11,7 +11,7 @@ #define __ASM_ARCH_HARDWARE_H #include -#include +#include /* * What hardware must be present diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-cl7500/irq.h linux/include/asm-arm/arch-cl7500/irq.h --- v2.4.0-test8/linux/include/asm-arm/arch-cl7500/irq.h Tue Nov 23 22:23:11 1999 +++ linux/include/asm-arm/arch-cl7500/irq.h Mon Sep 18 15:15:22 2000 @@ -9,7 +9,7 @@ * 22-08-1998 RMK Restructured IRQ routines * 11-08-1999 PJB Created ARM7500 version, derived from RiscPC code */ -#include +#include static inline int fixup_irq(unsigned int irq) { diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-cl7500/system.h linux/include/asm-arm/arch-cl7500/system.h --- v2.4.0-test8/linux/include/asm-arm/arch-cl7500/system.h Tue Jul 18 22:43:25 2000 +++ linux/include/asm-arm/arch-cl7500/system.h Mon Sep 18 15:15:22 2000 @@ -6,7 +6,7 @@ #ifndef __ASM_ARCH_SYSTEM_H #define __ASM_ARCH_SYSTEM_H -#include +#include static void arch_idle(void) { diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-ebsa110/dma.h linux/include/asm-arm/arch-ebsa110/dma.h --- v2.4.0-test8/linux/include/asm-arm/arch-ebsa110/dma.h Tue Jul 18 22:43:25 2000 +++ linux/include/asm-arm/arch-ebsa110/dma.h Mon Sep 18 15:15:22 2000 @@ -1,9 +1,13 @@ /* - * linux/include/asm-arm/arch-ebsa110/dma.h + * linux/include/asm-arm/arch-ebsa110/dma.h * - * Architecture DMA routes + * Copyright (C) 1997,1998 Russell King * - * Copyright (C) 1997,1998 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. + * + * EBSA110 DMA definitions */ #ifndef __ASM_ARCH_DMA_H #define __ASM_ARCH_DMA_H diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-ebsa110/hardware.h linux/include/asm-arm/arch-ebsa110/hardware.h --- v2.4.0-test8/linux/include/asm-arm/arch-ebsa110/hardware.h Sun Aug 13 09:54:15 2000 +++ linux/include/asm-arm/arch-ebsa110/hardware.h Mon Sep 18 15:15:22 2000 @@ -1,7 +1,11 @@ /* - * linux/include/asm-arm/arch-ebsa110/hardware.h + * linux/include/asm-arm/arch-ebsa110/hardware.h * - * Copyright (C) 1996-2000 Russell King. + * Copyright (C) 1996-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. * * This file contains the hardware definitions of the EBSA-110. */ diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-ebsa110/io.h linux/include/asm-arm/arch-ebsa110/io.h --- v2.4.0-test8/linux/include/asm-arm/arch-ebsa110/io.h Thu Feb 24 22:44:47 2000 +++ linux/include/asm-arm/arch-ebsa110/io.h Mon Sep 18 15:15:23 2000 @@ -1,7 +1,11 @@ /* - * linux/include/asm-arm/arch-ebsa110/io.h + * linux/include/asm-arm/arch-ebsa110/io.h * - * Copyright (C) 1997,1998 Russell King + * Copyright (C) 1997,1998 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. * * Modifications: * 06-Dec-1997 RMK Created. diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-ebsa110/irq.h linux/include/asm-arm/arch-ebsa110/irq.h --- v2.4.0-test8/linux/include/asm-arm/arch-ebsa110/irq.h Sat May 8 11:06:57 1999 +++ linux/include/asm-arm/arch-ebsa110/irq.h Mon Sep 18 15:15:23 2000 @@ -1,9 +1,13 @@ /* - * include/asm-arm/arch-ebsa110/irq.h + * linux/include/asm-arm/arch-ebsa110/irq.h * - * Copyright (C) 1996-1998 Russell King + * Copyright (C) 1996-1998 Russell King * - * Changelog: + * 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. + * + * Changelog: * 22-08-1998 RMK Restructured IRQ routines */ diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-ebsa110/irqs.h linux/include/asm-arm/arch-ebsa110/irqs.h --- v2.4.0-test8/linux/include/asm-arm/arch-ebsa110/irqs.h Sun Sep 6 10:45:30 1998 +++ linux/include/asm-arm/arch-ebsa110/irqs.h Mon Sep 18 15:15:23 2000 @@ -1,7 +1,11 @@ /* - * linux/include/asm-arm/arch-ebsa110/irqs.h + * linux/include/asm-arm/arch-ebsa110/irqs.h * - * Copyright (C) 1996 Russell King + * Copyright (C) 1996 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. */ #define NR_IRQS 8 diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-ebsa110/memory.h linux/include/asm-arm/arch-ebsa110/memory.h --- v2.4.0-test8/linux/include/asm-arm/arch-ebsa110/memory.h Thu Oct 28 10:16:02 1999 +++ linux/include/asm-arm/arch-ebsa110/memory.h Mon Sep 18 15:15:23 2000 @@ -1,13 +1,17 @@ /* - * linux/include/asm-arm/arch-ebsa110/memory.h + * linux/include/asm-arm/arch-ebsa110/memory.h * - * Copyright (c) 1996-1999 Russell King. + * Copyright (C) 1996-1999 Russell King. * - * Changelog: - * 20-Oct-1996 RMK Created - * 31-Dec-1997 RMK Fixed definitions to reduce warnings - * 21-Mar-1999 RMK Renamed to memory.h - * RMK Moved TASK_SIZE and PAGE_OFFSET here + * 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. + * + * Changelog: + * 20-Oct-1996 RMK Created + * 31-Dec-1997 RMK Fixed definitions to reduce warnings + * 21-Mar-1999 RMK Renamed to memory.h + * RMK Moved TASK_SIZE and PAGE_OFFSET here */ #ifndef __ASM_ARCH_MEMORY_H #define __ASM_ARCH_MEMORY_H diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-ebsa110/processor.h linux/include/asm-arm/arch-ebsa110/processor.h --- v2.4.0-test8/linux/include/asm-arm/arch-ebsa110/processor.h Wed Oct 20 16:29:08 1999 +++ linux/include/asm-arm/arch-ebsa110/processor.h Mon Sep 18 15:15:23 2000 @@ -1,10 +1,14 @@ /* - * linux/include/asm-arm/arch-ebsa110/processor.h + * linux/include/asm-arm/arch-ebsa110/processor.h * - * Copyright (C) 1996-1999 Russell King + * Copyright (C) 1996-1999 Russell King * - * Changelog: - * 21-Mar-1999 RMK Added asm/arch/memory.h + * 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. + * + * Changelog: + * 21-Mar-1999 RMK Added asm/arch/memory.h */ #ifndef __ASM_ARCH_PROCESSOR_H diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-ebsa110/serial.h linux/include/asm-arm/arch-ebsa110/serial.h --- v2.4.0-test8/linux/include/asm-arm/arch-ebsa110/serial.h Tue Nov 23 22:23:11 1999 +++ linux/include/asm-arm/arch-ebsa110/serial.h Mon Sep 18 15:15:23 2000 @@ -1,10 +1,14 @@ /* - * linux/include/asm-arm/arch-ebsa110/serial.h + * linux/include/asm-arm/arch-ebsa110/serial.h * - * Copyright (c) 1996,1997,1998 Russell King. + * Copyright (C) 1996,1997,1998 Russell King. * - * Changelog: - * 15-10-1996 RMK Created + * 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. + * + * Changelog: + * 15-10-1996 RMK Created */ #ifndef __ASM_ARCH_SERIAL_H #define __ASM_ARCH_SERIAL_H diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-ebsa110/system.h linux/include/asm-arm/arch-ebsa110/system.h --- v2.4.0-test8/linux/include/asm-arm/arch-ebsa110/system.h Tue Jul 18 22:43:25 2000 +++ linux/include/asm-arm/arch-ebsa110/system.h Mon Sep 18 15:15:23 2000 @@ -1,14 +1,25 @@ /* - * linux/include/asm-arm/arch-ebsa110/system.h + * linux/include/asm-arm/arch-ebsa110/system.h * - * Copyright (c) 1996-1999 Russell King. + * Copyright (C) 1996-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. */ #ifndef __ASM_ARCH_SYSTEM_H #define __ASM_ARCH_SYSTEM_H /* - * This machine must never stop it MCLK. However, if we are - * idle for a long time, slow the processor clock to MCLK. + * EBSA110 idling methodology: + * + * We can not execute the "wait for interrupt" instruction since that + * will stop our MCLK signal (which provides the clock for the glue + * logic, and therefore the timer interrupt). + * + * Instead, we spin, waiting for either hlt_counter or need_resched + * to be set. If we have been spinning for 2cs, then we drop the + * core clock down to the memory clock. */ static void arch_idle(void) { @@ -19,7 +30,7 @@ do { if (current->need_resched || hlt_counter) goto slow_out; - } while (time_before(start_idle, jiffies + HZ/3)); + } while (time_before(jiffies, start_idle + HZ/50)); cpu_do_idle(IDLE_CLOCK_SLOW); diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-ebsa110/time.h linux/include/asm-arm/arch-ebsa110/time.h --- v2.4.0-test8/linux/include/asm-arm/arch-ebsa110/time.h Sun Sep 3 11:19:11 2000 +++ linux/include/asm-arm/arch-ebsa110/time.h Mon Sep 18 15:15:23 2000 @@ -1,7 +1,11 @@ /* - * linux/include/asm-arm/arch-ebsa110/time.h + * linux/include/asm-arm/arch-ebsa110/time.h * - * Copyright (c) 1996,1997,1998 Russell King. + * Copyright (C) 1996,1997,1998 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. * * No real time clock on the evalulation board! * diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-ebsa110/timex.h linux/include/asm-arm/arch-ebsa110/timex.h --- v2.4.0-test8/linux/include/asm-arm/arch-ebsa110/timex.h Sun Sep 6 10:45:30 1998 +++ linux/include/asm-arm/arch-ebsa110/timex.h Mon Sep 18 15:15:23 2000 @@ -1,9 +1,13 @@ /* - * linux/include/asm-arm/arch-ebsa110/timex.h + * linux/include/asm-arm/arch-ebsa110/timex.h * - * EBSA110 architecture timex specifications + * Copyright (C) 1997, 1998 Russell King * - * Copyright (C) 1997, 1998 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. + * + * EBSA110 architecture timex specifications */ /* diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-ebsa110/uncompress.h linux/include/asm-arm/arch-ebsa110/uncompress.h --- v2.4.0-test8/linux/include/asm-arm/arch-ebsa110/uncompress.h Sun Sep 6 10:45:30 1998 +++ linux/include/asm-arm/arch-ebsa110/uncompress.h Mon Sep 18 15:15:23 2000 @@ -1,7 +1,11 @@ /* - * linux/include/asm-arm/arch-ebsa110/uncompress.h + * linux/include/asm-arm/arch-ebsa110/uncompress.h * - * Copyright (C) 1996,1997,1998 Russell King + * Copyright (C) 1996,1997,1998 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. */ /* diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-ebsa110/vmalloc.h linux/include/asm-arm/arch-ebsa110/vmalloc.h --- v2.4.0-test8/linux/include/asm-arm/arch-ebsa110/vmalloc.h Mon Mar 27 10:46:29 2000 +++ linux/include/asm-arm/arch-ebsa110/vmalloc.h Mon Sep 18 15:15:23 2000 @@ -1,5 +1,11 @@ /* - * linux/include/asm-arm/arch-ebsa110/vmalloc.h + * linux/include/asm-arm/arch-ebsa110/vmalloc.h + * + * Copyright (C) 1998 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. */ /* diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-ebsa285/dma.h linux/include/asm-arm/arch-ebsa285/dma.h --- v2.4.0-test8/linux/include/asm-arm/arch-ebsa285/dma.h Sat May 8 11:06:57 1999 +++ linux/include/asm-arm/arch-ebsa285/dma.h Mon Sep 18 15:15:23 2000 @@ -1,10 +1,10 @@ /* - * linux/include/asm-arm/arch-ebsa285/dma.h + * linux/include/asm-arm/arch-ebsa285/dma.h * - * Architecture DMA routines + * Architecture DMA routines * - * Copyright (C) 1998,1999 Russell King - * Copyright (C) 1998,1999 Philip Blundell + * Copyright (C) 1998,1999 Russell King + * Copyright (C) 1998,1999 Philip Blundell */ #ifndef __ASM_ARCH_DMA_H #define __ASM_ARCH_DMA_H diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-ebsa285/hardware.h linux/include/asm-arm/arch-ebsa285/hardware.h --- v2.4.0-test8/linux/include/asm-arm/arch-ebsa285/hardware.h Sun Sep 3 11:19:11 2000 +++ linux/include/asm-arm/arch-ebsa285/hardware.h Mon Sep 18 15:15:23 2000 @@ -1,9 +1,13 @@ /* - * linux/include/asm-arm/arch-ebsa285/hardware.h + * linux/include/asm-arm/arch-ebsa285/hardware.h * - * Copyright (C) 1998-1999 Russell King. + * Copyright (C) 1998-1999 Russell King. * - * This file contains the hardware definitions of the EBSA-285. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This file contains the hardware definitions of the EBSA-285. */ #ifndef __ASM_ARCH_HARDWARE_H #define __ASM_ARCH_HARDWARE_H diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-ebsa285/ide.h linux/include/asm-arm/arch-ebsa285/ide.h --- v2.4.0-test8/linux/include/asm-arm/arch-ebsa285/ide.h Mon Jun 26 12:04:42 2000 +++ linux/include/asm-arm/arch-ebsa285/ide.h Mon Sep 18 15:15:23 2000 @@ -1,10 +1,14 @@ /* - * linux/include/asm-arm/arch-ebsa285/ide.h + * linux/include/asm-arm/arch-ebsa285/ide.h * - * Copyright (c) 1998 Russell King + * Copyright (C) 1998 Russell King * - * Modifications: - * 29-07-1998 RMK Major re-work of IDE architecture specific code + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Modifications: + * 29-07-1998 RMK Major re-work of IDE architecture specific code */ #include diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-ebsa285/io.h linux/include/asm-arm/arch-ebsa285/io.h --- v2.4.0-test8/linux/include/asm-arm/arch-ebsa285/io.h Thu Feb 24 22:44:47 2000 +++ linux/include/asm-arm/arch-ebsa285/io.h Mon Sep 18 15:15:23 2000 @@ -1,11 +1,15 @@ /* - * linux/include/asm-arm/arch-ebsa285/io.h + * linux/include/asm-arm/arch-ebsa285/io.h * - * Copyright (C) 1997-1999 Russell King + * Copyright (C) 1997-1999 Russell King * - * Modifications: - * 06-12-1997 RMK Created. - * 07-04-1999 RMK Major cleanup + * 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. + * + * Modifications: + * 06-12-1997 RMK Created. + * 07-04-1999 RMK Major cleanup */ #ifndef __ASM_ARM_ARCH_IO_H #define __ASM_ARM_ARCH_IO_H @@ -74,7 +78,7 @@ #define outw(v,p) __arch_putw(v,__io_pci(p)) #define outl(v,p) __arch_putl(v,__io_pci(p)) -#include +#include /* * ioremap support - validate a PCI memory address, diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-ebsa285/irq.h linux/include/asm-arm/arch-ebsa285/irq.h --- v2.4.0-test8/linux/include/asm-arm/arch-ebsa285/irq.h Sun Aug 13 09:54:15 2000 +++ linux/include/asm-arm/arch-ebsa285/irq.h Mon Sep 18 15:15:23 2000 @@ -1,17 +1,21 @@ /* - * include/asm-arm/arch-ebsa285/irq.h + * linux/include/asm-arm/arch-ebsa285/irq.h * - * Copyright (C) 1996-1998 Russell King + * Copyright (C) 1996-1998 Russell King * - * Changelog: - * 22-Aug-1998 RMK Restructured IRQ routines - * 03-Sep-1998 PJB Merged CATS support - * 20-Jan-1998 RMK Started merge of EBSA286, CATS and NetWinder - * 26-Jan-1999 PJB Don't use IACK on CATS - * 16-Mar-1999 RMK Added autodetect of ISA PICs + * 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. + * + * Changelog: + * 22-Aug-1998 RMK Restructured IRQ routines + * 03-Sep-1998 PJB Merged CATS support + * 20-Jan-1998 RMK Started merge of EBSA286, CATS and NetWinder + * 26-Jan-1999 PJB Don't use IACK on CATS + * 16-Mar-1999 RMK Added autodetect of ISA PICs */ #include -#include +#include #include #include diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-ebsa285/memory.h linux/include/asm-arm/arch-ebsa285/memory.h --- v2.4.0-test8/linux/include/asm-arm/arch-ebsa285/memory.h Sun Aug 13 09:54:15 2000 +++ linux/include/asm-arm/arch-ebsa285/memory.h Mon Sep 18 15:15:23 2000 @@ -1,14 +1,18 @@ /* - * linux/include/asm-arm/arch-ebsa285/memory.h + * linux/include/asm-arm/arch-ebsa285/memory.h * - * Copyright (c) 1996-1999 Russell King. + * Copyright (C) 1996-1999 Russell King. * - * Changelog: - * 20-Oct-1996 RMK Created - * 31-Dec-1997 RMK Fixed definitions to reduce warnings. - * 17-May-1998 DAG Added __virt_to_bus and __bus_to_virt functions. - * 21-Nov-1998 RMK Changed __virt_to_bus and __bus_to_virt to macros. - * 21-Mar-1999 RMK Added PAGE_OFFSET for co285 architecture. + * 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. + * + * Changelog: + * 20-Oct-1996 RMK Created + * 31-Dec-1997 RMK Fixed definitions to reduce warnings. + * 17-May-1998 DAG Added __virt_to_bus and __bus_to_virt functions. + * 21-Nov-1998 RMK Changed __virt_to_bus and __bus_to_virt to macros. + * 21-Mar-1999 RMK Added PAGE_OFFSET for co285 architecture. * Renamed to memory.h * Moved PAGE_OFFSET and TASK_SIZE here */ diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-ebsa285/processor.h linux/include/asm-arm/arch-ebsa285/processor.h --- v2.4.0-test8/linux/include/asm-arm/arch-ebsa285/processor.h Wed Oct 20 16:29:08 1999 +++ linux/include/asm-arm/arch-ebsa285/processor.h Mon Sep 18 15:15:23 2000 @@ -1,10 +1,14 @@ /* - * linux/include/asm-arm/arch-ebsa110/processor.h + * linux/include/asm-arm/arch-ebsa110/processor.h * - * Copyright (C) 1996-1999 Russell King + * Copyright (C) 1996-1999 Russell King * - * Changelog: - * 21-Mar-1999 RMK Added asm/arch/memory.h + * 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. + * + * Changelog: + * 21-Mar-1999 RMK Added asm/arch/memory.h */ #ifndef __ASM_ARCH_PROCESSOR_H diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-ebsa285/serial.h linux/include/asm-arm/arch-ebsa285/serial.h --- v2.4.0-test8/linux/include/asm-arm/arch-ebsa285/serial.h Tue Nov 23 22:23:11 1999 +++ linux/include/asm-arm/arch-ebsa285/serial.h Mon Sep 18 15:15:23 2000 @@ -1,11 +1,15 @@ /* - * linux/include/asm-arm/arch-ebsa285/serial.h + * linux/include/asm-arm/arch-ebsa285/serial.h * - * Copyright (c) 1996,1997,1998 Russell King. + * Copyright (C) 1996,1997,1998 Russell King. * - * Changelog: - * 15-10-1996 RMK Created - * 25-05-1998 PJB CATS support + * 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. + * + * Changelog: + * 15-10-1996 RMK Created + * 25-05-1998 PJB CATS support */ #ifndef __ASM_ARCH_SERIAL_H #define __ASM_ARCH_SERIAL_H diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-ebsa285/system.h linux/include/asm-arm/arch-ebsa285/system.h --- v2.4.0-test8/linux/include/asm-arm/arch-ebsa285/system.h Sun Aug 13 09:54:15 2000 +++ linux/include/asm-arm/arch-ebsa285/system.h Mon Sep 18 15:15:23 2000 @@ -1,9 +1,13 @@ /* - * linux/include/asm-arm/arch-ebsa285/system.h + * linux/include/asm-arm/arch-ebsa285/system.h * - * Copyright (c) 1996-1999 Russell King. + * Copyright (C) 1996-1999 Russell King. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. */ -#include +#include #include #include #include @@ -19,7 +23,7 @@ if (current->need_resched || hlt_counter) goto slow_out; cpu_do_idle(IDLE_WAIT_FAST); - } while (time_before(start_idle, jiffies + HZ/3)); + } while (time_before(jiffies, start_idle + HZ/50)); cpu_do_idle(IDLE_CLOCK_SLOW); diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-ebsa285/time.h linux/include/asm-arm/arch-ebsa285/time.h --- v2.4.0-test8/linux/include/asm-arm/arch-ebsa285/time.h Sun Aug 13 09:54:15 2000 +++ linux/include/asm-arm/arch-ebsa285/time.h Mon Sep 18 15:15:23 2000 @@ -1,8 +1,8 @@ /* - * linux/include/asm-arm/arch-ebsa285/time.h + * linux/include/asm-arm/arch-ebsa285/time.h * - * Copyright (c) 1998 Russell King. - * Copyright (c) 1998 Phil Blundell + * Copyright (C) 1998 Russell King. + * Copyright (C) 1998 Phil Blundell * * CATS has a real-time clock, though the evaluation board doesn't. * @@ -19,7 +19,7 @@ #include -#include +#include #include #include diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-ebsa285/timex.h linux/include/asm-arm/arch-ebsa285/timex.h --- v2.4.0-test8/linux/include/asm-arm/arch-ebsa285/timex.h Tue Apr 25 16:54:38 2000 +++ linux/include/asm-arm/arch-ebsa285/timex.h Mon Sep 18 15:15:23 2000 @@ -1,9 +1,13 @@ /* - * linux/include/asm-arm/arch-ebsa285/timex.h + * linux/include/asm-arm/arch-ebsa285/timex.h * - * EBSA285 architecture timex specifications + * Copyright (C) 1998 Russell King * - * Copyright (C) 1998 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. + * + * EBSA285 architecture timex specifications */ /* diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-ebsa285/uncompress.h linux/include/asm-arm/arch-ebsa285/uncompress.h --- v2.4.0-test8/linux/include/asm-arm/arch-ebsa285/uncompress.h Sun Sep 3 11:19:11 2000 +++ linux/include/asm-arm/arch-ebsa285/uncompress.h Mon Sep 18 15:15:23 2000 @@ -1,7 +1,11 @@ /* - * linux/include/asm-arm/arch-ebsa285/uncompress.h + * linux/include/asm-arm/arch-ebsa285/uncompress.h * - * Copyright (C) 1996-1999 Russell King + * Copyright (C) 1996-1999 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 diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-ebsa285/vmalloc.h linux/include/asm-arm/arch-ebsa285/vmalloc.h --- v2.4.0-test8/linux/include/asm-arm/arch-ebsa285/vmalloc.h Mon Mar 27 10:46:29 2000 +++ linux/include/asm-arm/arch-ebsa285/vmalloc.h Mon Sep 18 15:15:23 2000 @@ -1,5 +1,9 @@ /* - * linux/include/asm-arm/arch-ebsa285/vmalloc.h + * linux/include/asm-arm/arch-ebsa285/vmalloc.h + * + * 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. */ /* diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-nexuspci/dma.h linux/include/asm-arm/arch-nexuspci/dma.h --- v2.4.0-test8/linux/include/asm-arm/arch-nexuspci/dma.h Tue Jul 18 22:43:25 2000 +++ linux/include/asm-arm/arch-nexuspci/dma.h Mon Sep 18 15:15:23 2000 @@ -7,6 +7,13 @@ */ /* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +/* * This is the maximum DMA address that can be DMAd to. */ #define MAX_DMA_ADDRESS 0xffffffff diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-nexuspci/hardware.h linux/include/asm-arm/arch-nexuspci/hardware.h --- v2.4.0-test8/linux/include/asm-arm/arch-nexuspci/hardware.h Sun Sep 3 11:19:11 2000 +++ linux/include/asm-arm/arch-nexuspci/hardware.h Mon Sep 18 15:15:23 2000 @@ -5,6 +5,14 @@ * * This file contains the hardware definitions of the FTV PCI card. */ + +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + #ifndef __ASM_ARCH_HARDWARE_H #define __ASM_ARCH_HARDWARE_H diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-nexuspci/irq.h linux/include/asm-arm/arch-nexuspci/irq.h --- v2.4.0-test8/linux/include/asm-arm/arch-nexuspci/irq.h Mon Feb 28 14:16:37 2000 +++ linux/include/asm-arm/arch-nexuspci/irq.h Mon Sep 18 15:15:23 2000 @@ -4,6 +4,13 @@ * Copyright (C) 1998, 1999, 2000 Philip Blundell */ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + #include #define fixup_irq(x) (x) diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-nexuspci/irqs.h linux/include/asm-arm/arch-nexuspci/irqs.h --- v2.4.0-test8/linux/include/asm-arm/arch-nexuspci/irqs.h Mon Feb 28 14:16:37 2000 +++ linux/include/asm-arm/arch-nexuspci/irqs.h Mon Sep 18 15:15:23 2000 @@ -4,9 +4,18 @@ * Copyright (C) 1997, 1998, 2000 Philip Blundell */ -/* The hardware is capable of routing any interrupt source (except the - DUART) to either IRQ or FIQ. We ignore FIQ and use IRQ exclusively - for simplicity. */ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +/* + * The hardware is capable of routing any interrupt source (except the + * DUART) to either IRQ or FIQ. We ignore FIQ and use IRQ exclusively + * for simplicity. + */ #define IRQ_DUART 0 #define IRQ_PLX 1 diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-nexuspci/system.h linux/include/asm-arm/arch-nexuspci/system.h --- v2.4.0-test8/linux/include/asm-arm/arch-nexuspci/system.h Tue Jul 18 22:43:25 2000 +++ linux/include/asm-arm/arch-nexuspci/system.h Mon Sep 18 15:15:23 2000 @@ -3,6 +3,14 @@ * * Copyright (c) 1996, 97, 98, 99, 2000 FutureTV Labs Ltd. */ + +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + #ifndef __ASM_ARCH_SYSTEM_H #define __ASM_ARCH_SYSTEM_H diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-nexuspci/time.h linux/include/asm-arm/arch-nexuspci/time.h --- v2.4.0-test8/linux/include/asm-arm/arch-nexuspci/time.h Sun Sep 3 11:19:11 2000 +++ linux/include/asm-arm/arch-nexuspci/time.h Mon Sep 18 15:15:23 2000 @@ -7,6 +7,13 @@ * SCC chip. */ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { static int count = 25; diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-nexuspci/uncompress.h linux/include/asm-arm/arch-nexuspci/uncompress.h --- v2.4.0-test8/linux/include/asm-arm/arch-nexuspci/uncompress.h Sun Sep 3 11:19:11 2000 +++ linux/include/asm-arm/arch-nexuspci/uncompress.h Mon Sep 18 15:15:23 2000 @@ -4,6 +4,13 @@ * Copyright (C) 1998, 1999, 2000 Philip Blundell */ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + #include #include diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-rpc/acornfb.h linux/include/asm-arm/arch-rpc/acornfb.h --- v2.4.0-test8/linux/include/asm-arm/arch-rpc/acornfb.h Wed Oct 20 16:29:08 1999 +++ linux/include/asm-arm/arch-rpc/acornfb.h Mon Sep 18 15:15:23 2000 @@ -1,9 +1,13 @@ /* - * linux/include/asm-arm/arch-rpc/acornfb.h + * linux/include/asm-arm/arch-rpc/acornfb.h * - * (C) 1999 Russell King + * Copyright (C) 1999 Russell King * - * AcornFB architecture specific code + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * AcornFB architecture specific code */ #define acornfb_valid_pixrate(rate) (1) diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-rpc/dma.h linux/include/asm-arm/arch-rpc/dma.h --- v2.4.0-test8/linux/include/asm-arm/arch-rpc/dma.h Tue Jul 18 22:43:25 2000 +++ linux/include/asm-arm/arch-rpc/dma.h Mon Sep 18 15:15:23 2000 @@ -1,5 +1,11 @@ /* - * linux/include/asm-arm/arch-rpc/dma.h + * linux/include/asm-arm/arch-rpc/dma.h + * + * Copyright (C) 1997 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. */ #ifndef __ASM_ARCH_DMA_H #define __ASM_ARCH_DMA_H diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-rpc/hardware.h linux/include/asm-arm/arch-rpc/hardware.h --- v2.4.0-test8/linux/include/asm-arm/arch-rpc/hardware.h Sun Aug 13 09:54:15 2000 +++ linux/include/asm-arm/arch-rpc/hardware.h Mon Sep 18 15:15:23 2000 @@ -1,9 +1,13 @@ /* - * linux/include/asm-arm/arch-rpc/hardware.h + * linux/include/asm-arm/arch-rpc/hardware.h * - * Copyright (C) 1996-1999 Russell King. + * Copyright (C) 1996-1999 Russell King. * - * This file contains the hardware definitions of the RiscPC series machines. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This file contains the hardware definitions of the RiscPC series machines. */ #ifndef __ASM_ARCH_HARDWARE_H #define __ASM_ARCH_HARDWARE_H diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-rpc/ide.h linux/include/asm-arm/arch-rpc/ide.h --- v2.4.0-test8/linux/include/asm-arm/arch-rpc/ide.h Mon Jun 26 12:04:42 2000 +++ linux/include/asm-arm/arch-rpc/ide.h Mon Sep 18 15:15:23 2000 @@ -1,10 +1,14 @@ /* - * linux/include/asm-arm/arch-rpc/ide.h + * linux/include/asm-arm/arch-rpc/ide.h * - * Copyright (c) 1997 Russell King + * Copyright (C) 1997 Russell King * - * Modifications: - * 29-07-1998 RMK Major re-work of IDE architecture specific code + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Modifications: + * 29-07-1998 RMK Major re-work of IDE architecture specific code */ #include diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-rpc/io.h linux/include/asm-arm/arch-rpc/io.h --- v2.4.0-test8/linux/include/asm-arm/arch-rpc/io.h Thu Feb 24 22:44:47 2000 +++ linux/include/asm-arm/arch-rpc/io.h Mon Sep 18 15:15:23 2000 @@ -1,7 +1,11 @@ /* - * linux/include/asm-arm/arch-rpc/io.h + * linux/include/asm-arm/arch-rpc/io.h * - * Copyright (C) 1997 Russell King + * Copyright (C) 1997 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. * * Modifications: * 06-Dec-1997 RMK Created. diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-rpc/irq.h linux/include/asm-arm/arch-rpc/irq.h --- v2.4.0-test8/linux/include/asm-arm/arch-rpc/irq.h Sun Sep 3 11:19:11 2000 +++ linux/include/asm-arm/arch-rpc/irq.h Mon Sep 18 15:15:23 2000 @@ -1,13 +1,17 @@ /* - * include/asm-arm/arch-rpc/irq.h + * linux/include/asm-arm/arch-rpc/irq.h * - * Copyright (C) 1996 Russell King + * Copyright (C) 1996 Russell King * - * Changelog: + * 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. + * + * Changelog: * 10-10-1996 RMK Brought up to date with arch-sa110eval * 22-08-1998 RMK Restructured IRQ routines */ -#include +#include #define fixup_irq(x) (x) diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-rpc/irqs.h linux/include/asm-arm/arch-rpc/irqs.h --- v2.4.0-test8/linux/include/asm-arm/arch-rpc/irqs.h Sun Sep 6 10:45:30 1998 +++ linux/include/asm-arm/arch-rpc/irqs.h Mon Sep 18 15:15:23 2000 @@ -1,7 +1,11 @@ /* - * linux/include/asm-arm/arch-rpc/irqs.h + * linux/include/asm-arm/arch-rpc/irqs.h * - * Copyright (C) 1996 Russell King + * Copyright (C) 1996 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. */ #define IRQ_PRINTER 0 diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-rpc/keyboard.h linux/include/asm-arm/arch-rpc/keyboard.h --- v2.4.0-test8/linux/include/asm-arm/arch-rpc/keyboard.h Sat May 8 11:06:57 1999 +++ linux/include/asm-arm/arch-rpc/keyboard.h Mon Sep 18 15:15:23 2000 @@ -1,11 +1,14 @@ /* - * linux/include/asm-arm/arch-rpc/keyboard.h + * linux/include/asm-arm/arch-rpc/keyboard.h * - * Keyboard driver definitions for RiscPC architecture + * Copyright (C) 1998 Russell King * - * (C) 1998 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. + * + * Keyboard driver definitions for RiscPC architecture */ - #include #define NR_SCANCODES 128 diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-rpc/memory.h linux/include/asm-arm/arch-rpc/memory.h --- v2.4.0-test8/linux/include/asm-arm/arch-rpc/memory.h Thu Oct 28 10:16:02 1999 +++ linux/include/asm-arm/arch-rpc/memory.h Mon Sep 18 15:15:23 2000 @@ -1,15 +1,19 @@ /* - * linux/include/asm-arm/arch-rpc/memory.h + * linux/include/asm-arm/arch-rpc/memory.h * - * Copyright (c) 1996,1997,1998 Russell King. + * Copyright (C) 1996,1997,1998 Russell King. * - * Changelog: - * 20-Oct-1996 RMK Created - * 31-Dec-1997 RMK Fixed definitions to reduce warnings - * 11-Jan-1998 RMK Uninlined to reduce hits on cache - * 08-Feb-1998 RMK Added __virt_to_bus and __bus_to_virt - * 21-Mar-1999 RMK Renamed to memory.h - * RMK Added TASK_SIZE and PAGE_OFFSET + * 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. + * + * Changelog: + * 20-Oct-1996 RMK Created + * 31-Dec-1997 RMK Fixed definitions to reduce warnings + * 11-Jan-1998 RMK Uninlined to reduce hits on cache + * 08-Feb-1998 RMK Added __virt_to_bus and __bus_to_virt + * 21-Mar-1999 RMK Renamed to memory.h + * RMK Added TASK_SIZE and PAGE_OFFSET */ #ifndef __ASM_ARCH_MMU_H #define __ASM_ARCH_MMU_H diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-rpc/processor.h linux/include/asm-arm/arch-rpc/processor.h --- v2.4.0-test8/linux/include/asm-arm/arch-rpc/processor.h Wed Oct 20 16:29:08 1999 +++ linux/include/asm-arm/arch-rpc/processor.h Mon Sep 18 15:15:23 2000 @@ -1,11 +1,15 @@ /* - * linux/include/asm-arm/arch-rpc/processor.h + * linux/include/asm-arm/arch-rpc/processor.h * - * Copyright (c) 1996-1999 Russell King. + * Copyright (C) 1996-1999 Russell King. * - * Changelog: - * 10-Sep-1996 RMK Created - * 21-Mar-1999 RMK Added asm/arch/memory.h + * 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. + * + * Changelog: + * 10-Sep-1996 RMK Created + * 21-Mar-1999 RMK Added asm/arch/memory.h */ #ifndef __ASM_ARCH_PROCESSOR_H diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-rpc/serial.h linux/include/asm-arm/arch-rpc/serial.h --- v2.4.0-test8/linux/include/asm-arm/arch-rpc/serial.h Tue Nov 23 22:23:11 1999 +++ linux/include/asm-arm/arch-rpc/serial.h Mon Sep 18 15:15:23 2000 @@ -1,10 +1,14 @@ /* - * linux/include/asm-arm/arch-rpc/serial.h + * linux/include/asm-arm/arch-rpc/serial.h * - * Copyright (c) 1996 Russell King. + * Copyright (C) 1996 Russell King. * - * Changelog: - * 15-10-1996 RMK Created + * 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. + * + * Changelog: + * 15-10-1996 RMK Created */ #ifndef __ASM_ARCH_SERIAL_H #define __ASM_ARCH_SERIAL_H diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-rpc/system.h linux/include/asm-arm/arch-rpc/system.h --- v2.4.0-test8/linux/include/asm-arm/arch-rpc/system.h Tue Jul 18 22:43:25 2000 +++ linux/include/asm-arm/arch-rpc/system.h Mon Sep 18 15:15:23 2000 @@ -1,10 +1,14 @@ /* - * linux/include/asm-arm/arch-rpc/system.h + * linux/include/asm-arm/arch-rpc/system.h * - * Copyright (c) 1996-1999 Russell King. + * Copyright (C) 1996-1999 Russell King. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. */ #include -#include +#include #include static void arch_idle(void) @@ -17,7 +21,7 @@ if (current->need_resched || hlt_counter) goto slow_out; cpu_do_idle(IDLE_WAIT_FAST); - } while (time_before(start_idle, jiffies + HZ/3)); + } while (time_before(jiffies, start_idle + HZ/50)); cpu_do_idle(IDLE_CLOCK_SLOW); diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-rpc/time.h linux/include/asm-arm/arch-rpc/time.h --- v2.4.0-test8/linux/include/asm-arm/arch-rpc/time.h Sun Feb 6 17:45:25 2000 +++ linux/include/asm-arm/arch-rpc/time.h Mon Sep 18 15:15:23 2000 @@ -1,12 +1,16 @@ /* - * linux/include/asm-arm/arch-rpc/time.h + * linux/include/asm-arm/arch-rpc/time.h * - * Copyright (c) 1996-2000 Russell King. + * Copyright (C) 1996-2000 Russell King. * - * Changelog: - * 24-Sep-1996 RMK Created - * 10-Oct-1996 RMK Brought up to date with arch-sa110eval - * 04-Dec-1997 RMK Updated for new arch/arm/time.c + * 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. + * + * Changelog: + * 24-Sep-1996 RMK Created + * 10-Oct-1996 RMK Brought up to date with arch-sa110eval + * 04-Dec-1997 RMK Updated for new arch/arm/time.c */ extern void ioctime_init(void); diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-rpc/timex.h linux/include/asm-arm/arch-rpc/timex.h --- v2.4.0-test8/linux/include/asm-arm/arch-rpc/timex.h Tue Jan 20 16:39:42 1998 +++ linux/include/asm-arm/arch-rpc/timex.h Mon Sep 18 15:15:23 2000 @@ -1,9 +1,13 @@ /* - * linux/include/asm-arm/arch-rpc/timex.h + * linux/include/asm-arm/arch-rpc/timex.h * - * RiscPC architecture timex specifications + * Copyright (C) 1997, 1998 Russell King * - * Copyright (C) 1997, 1998 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. + * + * RiscPC architecture timex specifications */ /* diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-rpc/uncompress.h linux/include/asm-arm/arch-rpc/uncompress.h --- v2.4.0-test8/linux/include/asm-arm/arch-rpc/uncompress.h Sat May 8 11:06:57 1999 +++ linux/include/asm-arm/arch-rpc/uncompress.h Mon Sep 18 15:15:23 2000 @@ -1,7 +1,11 @@ /* - * linux/include/asm-arm/arch-a5k/uncompress.h + * linux/include/asm-arm/arch-rpc/uncompress.h * - * Copyright (C) 1996 Russell King + * Copyright (C) 1996 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. */ #define VIDMEM ((char *)SCREEN_START) diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-rpc/vmalloc.h linux/include/asm-arm/arch-rpc/vmalloc.h --- v2.4.0-test8/linux/include/asm-arm/arch-rpc/vmalloc.h Tue Apr 25 16:54:38 2000 +++ linux/include/asm-arm/arch-rpc/vmalloc.h Mon Sep 18 15:15:23 2000 @@ -1,5 +1,11 @@ /* - * linux/include/asm-arm/arch-rpc/vmalloc.h + * linux/include/asm-arm/arch-rpc/vmalloc.h + * + * Copyright (C) 1997 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. */ /* diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-sa1100/SA-1100.h linux/include/asm-arm/arch-sa1100/SA-1100.h --- v2.4.0-test8/linux/include/asm-arm/arch-sa1100/SA-1100.h Tue Jul 18 22:43:25 2000 +++ linux/include/asm-arm/arch-sa1100/SA-1100.h Mon Sep 18 15:15:23 2000 @@ -2417,8 +2417,8 @@ (0xF << FShft (DDAR_DS)) #define DDAR_DA Fld (24, 8) /* Device Address */ #define DDAR_DevAdd(Add) /* Device Address */ \ - ((Add) & 0xF0000000 | \ - ((Add) & 0X003FFFFC) << (FShft (DDAR_DA) - 2)) + (((Add) & 0xF0000000) | \ + (((Add) & 0X003FFFFC) << (FShft (DDAR_DA) - 2))) #define DDAR_Ser0UDCWr /* Ser. port 0 UDC Write */ \ (DDAR_DevWr + DDAR_Brst8 + DDAR_8BitDev + \ DDAR_Ser0UDCTr + DDAR_DevAdd (_Ser0UDCDR)) diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-sa1100/assabet.h linux/include/asm-arm/arch-sa1100/assabet.h --- v2.4.0-test8/linux/include/asm-arm/arch-sa1100/assabet.h Mon Jun 19 17:59:35 2000 +++ linux/include/asm-arm/arch-sa1100/assabet.h Mon Sep 18 15:15:23 2000 @@ -28,7 +28,7 @@ /* Board Control Register */ -#define BCR_BASE 0xdc000000 +#define BCR_BASE 0xf1000000 #define BCR (*(volatile unsigned int *)(BCR_BASE)) #define BCR_DB1110 (0x00A07410) @@ -105,8 +105,8 @@ #define NEPONSET_USAR_IRQ MISC_IRQ1 #define NEPONSET_CPLD_BASE (0x10000000) -#define Nep_p2v( x ) ((x) - NEPONSET_CPLD_BASE + 0xd4000000) -#define Nep_v2p( x ) ((x) - 0xd4000000 + NEPONSET_CPLD_BASE) +#define Nep_p2v( x ) ((x) - NEPONSET_CPLD_BASE + 0xf0000000) +#define Nep_v2p( x ) ((x) - 0xf0000000 + NEPONSET_CPLD_BASE) #define _IRR 0x10000024 /* Interrupt Reason Register */ #define _AUD_CTL 0x100000c0 /* Audio controls (RW) */ diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-sa1100/bitsy.h linux/include/asm-arm/arch-sa1100/bitsy.h --- v2.4.0-test8/linux/include/asm-arm/arch-sa1100/bitsy.h Tue Jul 18 22:43:25 2000 +++ linux/include/asm-arm/arch-sa1100/bitsy.h Mon Sep 18 15:15:23 2000 @@ -38,6 +38,7 @@ #define EGPIO_BITSY_LVDD_ON (1 << 15) /* enable 9V and -6.5V to LCD. */ #ifndef __ASSEMBLY__ +#define BITSY_EGPIO (*(volatile int *)0xf0000000) extern void clr_bitsy_egpio(unsigned long x); extern void set_bitsy_egpio(unsigned long x); #endif diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-sa1100/cerf.h linux/include/asm-arm/arch-sa1100/cerf.h --- v2.4.0-test8/linux/include/asm-arm/arch-sa1100/cerf.h Sun Aug 13 09:54:15 2000 +++ linux/include/asm-arm/arch-sa1100/cerf.h Mon Sep 18 15:15:23 2000 @@ -12,5 +12,8 @@ #define IRQ_GPIO_CF_BVD2 IRQ_GPIO19 #define IRQ_GPIO_CF_BVD1 IRQ_GPIO20 +#define GPIO_UCB1200_IRQ GPIO_GPIO (18) +#define IRQ_GPIO_UCB1200_IRQ IRQ_GPIO18 + #endif diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-sa1100/hardware.h linux/include/asm-arm/arch-sa1100/hardware.h --- v2.4.0-test8/linux/include/asm-arm/arch-sa1100/hardware.h Sun Aug 13 09:54:15 2000 +++ linux/include/asm-arm/arch-sa1100/hardware.h Mon Sep 18 15:15:23 2000 @@ -13,17 +13,28 @@ #define __ASM_ARCH_HARDWARE_H #include +#include + /* Flushing areas */ #define FLUSH_BASE_PHYS 0xe0000000 /* SA1100 zero bank */ -#define FLUSH_BASE 0xdf000000 -#define FLUSH_BASE_MINICACHE 0xdf800000 +#define FLUSH_BASE 0xf5000000 +#define FLUSH_BASE_MINICACHE 0xf5800000 #define UNCACHEABLE_ADDR 0xfa050000 /* - * We requires absolute addresses i.e. (0xe00000 + 0x3f8) for in*()/out*() - * macros to be useful for all cases. + * Those are statically mapped PCMCIA IO space for designs using it as a + * generic IO bus, typically with ISA parts, hardwired IDE interfaces, etc. + * The actual PCMCIA code is mapping required IO region at run time. + */ +#define PCMCIA_IO_0_BASE 0xf6000000 +#define PCMCIA_IO_1_BASE 0xf7000000 + + +/* + * We requires absolute addresses i.e. (PCMCIA_IO_0_BASE + 0x3f8) for + * in*()/out*() macros to be usable for all cases. */ #define PCIO_BASE 0 @@ -37,8 +48,6 @@ * 90000000 fa000000 * a0000000 fc000000 * b0000000 fe000000 - * - * Nb: PCMCIA is mapped from 0xe0000000 to f7ffffff in mm-sa1100.c */ #define VIO_BASE 0xf8000000 /* virtual start of IO space */ @@ -89,20 +98,24 @@ #include "bitsy.h" #endif -#if defined(CONFIG_SA1100_GRAPHICSCLIENT) || defined(CONFIG_SA1100_THINCLIENT) +#if defined(CONFIG_SA1100_THINCLIENT) #include "thinclient.h" #endif +#if defined(CONFIG_SA1100_GRAPHICSCLIENT) +#include "graphicsclient.h" +#endif + #ifdef CONFIG_SA1101 /* * We have mapped the sa1101 depending on the value of SA1101_BASE. - * It then appears from 0xdc000000. + * It then appears from 0xf4000000. */ -#define SA1101_p2v( x ) ((x) - SA1101_BASE + 0xdc000000) -#define SA1101_v2p( x ) ((x) - 0xdc000000 + SA1101_BASE) +#define SA1101_p2v( x ) ((x) - SA1101_BASE + 0xf4000000) +#define SA1101_v2p( x ) ((x) - 0xf4000000 + SA1101_BASE) #include "SA-1101.h" @@ -111,8 +124,8 @@ #ifdef CONFIG_SA1111 -#define SA1111_p2v( x ) ((x) - SA1111_BASE + 0xd8000000) -#define SA1111_v2p( x ) ((x) - 0xd8000000 + SA1111_BASE) +#define SA1111_p2v( x ) ((x) - SA1111_BASE + 0xf4000000) +#define SA1111_v2p( x ) ((x) - 0xf4000000 + SA1111_BASE) #include "SA-1111.h" diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-sa1100/ide.h linux/include/asm-arm/arch-sa1100/ide.h --- v2.4.0-test8/linux/include/asm-arm/arch-sa1100/ide.h Sun Aug 13 09:54:15 2000 +++ linux/include/asm-arm/arch-sa1100/ide.h Mon Sep 18 15:15:23 2000 @@ -3,14 +3,22 @@ * * Copyright (c) 1998 Hugo Fiennes & Nicolas Pitre * + * 18-aug-2000: Cleanup by Erik Mouw (J.A.K.Mouw@its.tudelft.nl) + * Get rid of the special ide_init_hwif_ports() functions + * and make a generalised function that can be used by all + * architectures. */ #include - #include #include #include + +#define PCMCIA_IO_0_BASE 0xe0000000 +#define PCMCIA_IO_1_BASE 0xe4000000 + + /* * Set up a hw structure for a specified data port, control port and IRQ. * This should follow whatever the default interface uses. @@ -20,47 +28,33 @@ { ide_ioreg_t reg; int i; - int ioshift = 0; - + int regincr = 1; + /* The Empeg board has the first two address lines unused */ if (machine_is_empeg()) - ioshift = 2; - + regincr = 1 << 2; + + /* The LART doesn't use A0 for IDE */ + if (machine_is_lart()) + regincr = 1 << 1; + memset(hw, 0, sizeof(*hw)); - reg = (ide_ioreg_t) (data_port << ioshift); + reg = (ide_ioreg_t)data_port; + for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { hw->io_ports[i] = reg; - reg += (1 << ioshift); + reg += regincr; } - hw->io_ports[IDE_CONTROL_OFFSET] = - (ide_ioreg_t) (ctrl_port << ioshift); + hw->io_ports[IDE_CONTROL_OFFSET] = (ide_ioreg_t) ctrl_port; if (irq) *irq = 0; } -/* - * Special case for the empeg board which has the first two - * address lines unused - */ -static __inline__ void -empeg_ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port) -{ - ide_ioreg_t reg; - int i; - memset(hw, 0, sizeof(*hw)); - reg = (ide_ioreg_t) (0xe0000000 + (data_port << 2)); - for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { - hw->io_ports[i] = reg; - reg += (1 << 2); - } - hw->io_ports[IDE_CONTROL_OFFSET] = - (ide_ioreg_t) (0xe0000000 + (ctrl_port << 2)); -} /* * This registers the standard ports for this architecture with the IDE @@ -92,10 +86,10 @@ /* MAC 23/4/1999, swap these round so that the left hand hard disk is hda when viewed from the front. This doesn't match the silkscreen however. */ - empeg_ide_init_hwif_ports(&hw,0x10,0x1e); + ide_init_hwif_ports(&hw, PCMCIA_IO_0_BASE + 0x40, PCMCIA_IO_0_BASE + 0x78, NULL); hw.irq = EMPEG_IRQ_IDE2; ide_register_hw(&hw, NULL); - empeg_ide_init_hwif_ports(&hw,0x00,0x0e); + ide_init_hwif_ports(&hw, PCMCIA_IO_0_BASE + 0x00, PCMCIA_IO_0_BASE + 0x38, NULL); hw.irq = ,EMPEG_IRQ_IDE1; ide_register_hw(&hw, NULL); #endif @@ -112,7 +106,7 @@ /* set the pcmcia interface timing */ MECR = 0x00060006; - ide_init_hwif_ports(&hw, 0xe00001f0, 0xe00003f6, NULL); + ide_init_hwif_ports(&hw, PCMCIA_IO_0_BASE + 0x1f0, PCMCIA_IO_0_BASE + 0x3f6, NULL); hw.irq = IRQ_GPIO7; ide_register_hw(&hw, NULL); #endif @@ -129,8 +123,7 @@ MECR = 0x00060006; /* init the interface */ -/* ide_init_hwif_ports(&hw, 0xe00000000, 0xe00001000, NULL); */ - ide_init_hwif_ports(&hw, 0xe00001000, 0xe00000000, NULL); + ide_init_hwif_ports(&hw, PCMCIA_IO_0_BASE + 0x0000, PCMCIA_IO_0_BASE + 0x1000, NULL); hw.irq = IRQ_GPIO1; ide_register_hw(&hw, NULL); #endif diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-sa1100/memory.h linux/include/asm-arm/arch-sa1100/memory.h --- v2.4.0-test8/linux/include/asm-arm/arch-sa1100/memory.h Thu Jan 13 13:30:31 2000 +++ linux/include/asm-arm/arch-sa1100/memory.h Mon Sep 18 15:15:23 2000 @@ -24,22 +24,22 @@ */ #define PHYS_OFFSET (0xc0000000UL) - -#define __virt_to_phys__is_a_macro -#define __phys_to_virt__is_a_macro - /* - * The following gives a maximum memory size of 128MB (32MB in each bank). + * We take advantage of the fact that physical and virtual address can be the + * same. The NUMA code is handling the large holes that might exist between + * all memory banks. */ -#define __virt_to_phys(x) (((x) & 0xf9ffffff) | ((x) & 0x06000000) << 2) -#define __phys_to_virt(x) (((x) & 0xe7ffffff) | ((x) & 0x18000000) >> 2) +#define __virt_to_phys__is_a_macro +#define __phys_to_virt__is_a_macro +#define __virt_to_phys(x) (x) +#define __phys_to_virt(x) (x) /* * Virtual view <-> DMA view memory address translations * virt_to_bus: Used to translate the virtual address to an - * address suitable to be passed to set_dma_addr + * address suitable to be passed to set_dma_addr * bus_to_virt: Used to convert an address for DMA operations - * to an address that the kernel can use. + * to an address that the kernel can use. * * On the SA1100, bus addresses are equivalent to physical addresses. */ diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-sa1100/mmzone.h linux/include/asm-arm/arch-sa1100/mmzone.h --- v2.4.0-test8/linux/include/asm-arm/arch-sa1100/mmzone.h Wed Aug 9 13:46:01 2000 +++ linux/include/asm-arm/arch-sa1100/mmzone.h Mon Sep 18 15:15:23 2000 @@ -11,6 +11,14 @@ * * Of course, all this isn't mandatory for SA1100 implementations with only * one used memory bank. For those, simply undefine CONFIG_DISCONTIGMEM. + * + * The nodes are matched with the physical memory bank addresses which are + * incidentally the same as virtual addresses. + * + * node 0: 0xc0000000 - 0xc7ffffff + * node 1: 0xc8000000 - 0xcfffffff + * node 2: 0xd0000000 - 0xd7ffffff + * node 3: 0xd8000000 - 0xdfffffff */ @@ -20,18 +28,6 @@ extern pg_data_t sa1100_node_data[]; /* - * 32MB max in each bank, must fit with __virt_to_phys() & __phys_to_virt() - */ -#define NODE_MAX_MEM_SHIFT 25 -#define NODE_MAX_MEM_SIZE (1<> NODE_MAX_MEM_SHIFT) - -/* * Return a pointer to the node data for node n. */ #define NODE_DATA(nid) (&sa1100_node_data[nid]) @@ -42,11 +38,10 @@ #define NODE_MEM_MAP(nid) (NODE_DATA(nid)->node_mem_map) /* - * Given a mem_map_t, LOCAL_MAP_BASE finds the owning node for the - * physical page and returns the kaddr for the mem_map of that node. + * Given a kernel address, find the home node of the underlying memory. */ -#define LOCAL_MAP_BASE(page) \ - NODE_MEM_MAP(KVADDR_TO_NID((unsigned long)(page))) +#define KVADDR_TO_NID(addr) \ + (((unsigned long)(addr) & 0x18000000) >> 27) /* * Given a kaddr, ADDR_TO_MAPBASE finds the owning node of the memory @@ -56,28 +51,22 @@ NODE_MEM_MAP(KVADDR_TO_NID((unsigned long)(kaddr))) /* - * Given a kaddr, LOCAL_BASE_ADDR finds the owning node of the memory - * and returns the kaddr corresponding to first physical page in the - * node's mem_map. - */ -#define LOCAL_BASE_ADDR(kaddr) ((unsigned long)(kaddr) & ~(NODE_MAX_MEM_SIZE-1)) - -/* * Given a kaddr, LOCAL_MEM_MAP finds the owning node of the memory * and returns the index corresponding to the appropriate page in the * node's mem_map. */ #define LOCAL_MAP_NR(kvaddr) \ - (((unsigned long)(kvaddr)-LOCAL_BASE_ADDR((kvaddr))) >> PAGE_SHIFT) + (((unsigned long)(kvaddr) & 0x07ffffff) >> PAGE_SHIFT) -/* - * With discontigmem, the conceptual mem_map array starts from PAGE_OFFSET. - * Given a kaddr, MAP_NR returns the appropriate global mem_map index so - * it matches the corresponding node's local mem_map. - */ -#define MAP_NR(kaddr) (LOCAL_MAP_NR((kaddr)) + \ - (((unsigned long)ADDR_TO_MAPBASE((kaddr)) - PAGE_OFFSET) / \ - sizeof(mem_map_t))) +/* + * Given a kaddr, virt_to_page returns a pointer to the corresponding + * mem_map entry. + */ +#define virt_to_page(kaddr) \ + (ADDR_TO_MAPBASE(kaddr) + LOCAL_MAP_NR(kaddr)) + +/* + * Didn't find the best way to validate a page pointer yet... + */ -#define virt_to_page(kaddr) (mem_map + MAP_NR(kaddr)) -#define VALID_PAGE(page) ((page - mem_map) < max_mapnr) +#define VALID_PAGE(page) (1) diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-sa1100/system.h linux/include/asm-arm/arch-sa1100/system.h --- v2.4.0-test8/linux/include/asm-arm/arch-sa1100/system.h Tue Jul 18 22:43:25 2000 +++ linux/include/asm-arm/arch-sa1100/system.h Mon Sep 18 15:15:23 2000 @@ -5,13 +5,10 @@ */ #include -static void arch_idle(void) +static inline void arch_idle(void) { - while (!current->need_resched && !hlt_counter) { - cpu_do_idle(IDLE_CLOCK_SLOW); - cpu_do_idle(IDLE_WAIT_FAST); - cpu_do_idle(IDLE_CLOCK_FAST); - } + while (!current->need_resched && !hlt_counter) + cpu_do_idle(0); } #ifdef CONFIG_SA1100_VICTOR diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-sa1100/thinclient.h linux/include/asm-arm/arch-sa1100/thinclient.h --- v2.4.0-test8/linux/include/asm-arm/arch-sa1100/thinclient.h Tue Jul 18 22:43:25 2000 +++ linux/include/asm-arm/arch-sa1100/thinclient.h Mon Sep 18 15:15:23 2000 @@ -13,8 +13,8 @@ #define ADS_CPLD_BASE (0x10000000) -#define ADS_p2v( x ) ((x) - ADS_CPLD_BASE + 0xdc000000) -#define ADS_v2p( x ) ((x) - 0xdc000000 + ADS_CPLD_BASE) +#define ADS_p2v( x ) ((x) - ADS_CPLD_BASE + 0xf0000000) +#define ADS_v2p( x ) ((x) - 0xf0000000 + ADS_CPLD_BASE) /* Parallel Port */ diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-sa1100/vmalloc.h linux/include/asm-arm/arch-sa1100/vmalloc.h --- v2.4.0-test8/linux/include/asm-arm/arch-sa1100/vmalloc.h Mon Mar 27 10:46:29 2000 +++ linux/include/asm-arm/arch-sa1100/vmalloc.h Mon Sep 18 15:15:23 2000 @@ -13,4 +13,4 @@ #define VMALLOC_OFFSET (8*1024*1024) #define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) #define VMALLOC_VMADDR(x) ((unsigned long)(x)) -#define VMALLOC_END (PAGE_OFFSET + 0x10000000) +#define VMALLOC_END (0xe8000000) diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-shark/hardware.h linux/include/asm-arm/arch-shark/hardware.h --- v2.4.0-test8/linux/include/asm-arm/arch-shark/hardware.h Mon Jun 26 12:04:42 2000 +++ linux/include/asm-arm/arch-shark/hardware.h Mon Sep 18 15:15:23 2000 @@ -20,7 +20,7 @@ /* * RAM definitions */ -#define FLUSH_BASE_PHYS 0x60000000 +#define FLUSH_BASE_PHYS 0x80000000 #else @@ -28,22 +28,26 @@ #endif -#define IO_SIZE 0x10000000 +#define IO_SIZE 0x08000000 #define IO_START 0x40000000 +#define ROMCARD_SIZE 0x08000000 +#define ROMCARD_START 0x10000000 #define FLUSH_BASE 0xdf000000 #define PCIO_BASE 0xe0000000 /* defines for the Framebuffer */ -#define FB_BASE 0xd0000000 #define FB_START 0x06000000 -#define FB_SIZE 0x00200000 /* Registers for Framebuffer */ -#define FBREG_BASE (FB_BASE + FB_SIZE) -#define FBREG_START 0x06800000 -#define FBREG_SIZE 0x000c0000 +/*#define FBREG_START 0x06800000*/ + +#define UNCACHEABLE_ADDR 0xdf010000 + +#define SEQUOIA_LED_GREEN (1<<6) +#define SEQUOIA_LED_AMBER (1<<5) +#define SEQUOIA_LED_BACK (1<<7) #endif diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-shark/io.h linux/include/asm-arm/arch-shark/io.h --- v2.4.0-test8/linux/include/asm-arm/arch-shark/io.h Mon Mar 27 10:46:29 2000 +++ linux/include/asm-arm/arch-shark/io.h Mon Sep 18 15:15:23 2000 @@ -11,6 +11,8 @@ #ifndef __ASM_ARM_ARCH_IO_H #define __ASM_ARM_ARCH_IO_H +#define __arch_ioremap(off,size,nocache) __ioremap(off,size,0) + #define IO_SPACE_LIMIT 0xffffffff /* diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-shark/keyboard.h linux/include/asm-arm/arch-shark/keyboard.h --- v2.4.0-test8/linux/include/asm-arm/arch-shark/keyboard.h Sun Aug 13 09:54:15 2000 +++ linux/include/asm-arm/arch-shark/keyboard.h Mon Sep 18 15:15:23 2000 @@ -1,8 +1,8 @@ /* - * linux/include/asm-arm/arch-ebsa285/keyboard.h - * - * Keyboard driver definitions for EBSA285 architecture - * + * linux/include/asm-arm/arch-shark/keyboard.h + * by Alexander.Schulz@stud.uni-karlsruhe.de + * + * Derived from linux/include/asm-arm/arch-ebsa285/keyboard.h * (C) 1998 Russell King * (C) 1998 Phil Blundell */ @@ -24,45 +24,12 @@ #define NR_SCANCODES 128 -#define kbd_setkeycode(sc,kc) \ - ({ \ - int __ret; \ - if (have_isa_bridge) \ - __ret = pckbd_setkeycode(sc,kc);\ - else \ - __ret = -EINVAL; \ - __ret; \ - }) - -#define kbd_getkeycode(sc) \ - ({ \ - int __ret; \ - if (have_isa_bridge) \ - __ret = pckbd_getkeycode(sc); \ - else \ - __ret = -EINVAL; \ - __ret; \ - }) - -#define kbd_translate(sc, kcp, rm) \ - ({ \ - pckbd_translate(sc, kcp, rm); \ - }) - +#define kbd_setkeycode(sc,kc) pckbd_setkeycode(sc,kc) +#define kbd_getkeycode(sc) pckbd_getkeycode(sc) +#define kbd_translate(sc, kcp, rm) pckbd_translate(sc, kcp, rm) #define kbd_unexpected_up pckbd_unexpected_up - -#define kbd_leds(leds) \ - do { \ - if (have_isa_bridge) \ - pckbd_leds(leds); \ - } while (0) - -#define kbd_init_hw() \ - do { \ - if (have_isa_bridge) \ - pckbd_init_hw(); \ - } while (0) - +#define kbd_leds(leds) pckbd_leds(leds) +#define kbd_init_hw() pckbd_init_hw() #define kbd_sysrq_xlate pckbd_sysrq_xlate #define kbd_disable_irq() diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-shark/system.h linux/include/asm-arm/arch-shark/system.h --- v2.4.0-test8/linux/include/asm-arm/arch-shark/system.h Tue Jul 18 22:43:25 2000 +++ linux/include/asm-arm/arch-shark/system.h Mon Sep 18 15:15:23 2000 @@ -6,12 +6,19 @@ #ifndef __ASM_ARCH_SYSTEM_H #define __ASM_ARCH_SYSTEM_H +#include + static void arch_reset(char mode) { - /* - * loop endlessly - */ + short temp; cli(); + /* Reset the Machine via pc[3] of the sequoia chipset */ + outw(0x09,0x24); + temp=inw(0x26); + temp = temp | (1<<3) | (1<<10); + outw(0x09,0x24); + outw(temp,0x26); + } static void arch_idle(void) diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-shark/time.h linux/include/asm-arm/arch-shark/time.h --- v2.4.0-test8/linux/include/asm-arm/arch-shark/time.h Mon Jun 19 17:59:35 2000 +++ linux/include/asm-arm/arch-shark/time.h Mon Sep 18 15:15:23 2000 @@ -43,15 +43,6 @@ } } -static struct irqaction timerirq = { - timer_interrupt, - SA_INTERRUPT, - 0, - "timer", - NULL, - NULL -}; - /* * Set up timer interrupt, and return the current time in seconds. */ @@ -88,5 +79,7 @@ xtime.tv_sec = mktime(r_time.tm_year+epoch, r_time.tm_mon+1, r_time.tm_mday, r_time.tm_hour, r_time.tm_min, r_time.tm_sec); - setup_arm_irq(IRQ_TIMER, &timerirq); + timer_irq.handler = timer_interrupt; + timer_irq.flags = SA_INTERRUPT; /* FIXME: really? */ + setup_arm_irq(IRQ_TIMER, &timer_irq); } diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-shark/vmalloc.h linux/include/asm-arm/arch-shark/vmalloc.h --- v2.4.0-test8/linux/include/asm-arm/arch-shark/vmalloc.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-shark/vmalloc.h Mon Sep 18 15:15:23 2000 @@ -0,0 +1,17 @@ +/* + * linux/include/asm-arm/arch-rpc/vmalloc.h + */ + +/* + * Just any arbitrary offset to the start of the vmalloc VM area: the + * current 8MB value just means that there will be a 8MB "hole" after the + * physical memory until the kernel virtual memory starts. That means that + * any out-of-bounds memory accesses will hopefully be caught. + * The vmalloc() routines leaves a hole of 4kB between each vmalloced + * area for the same reason. ;) + */ +#define VMALLOC_OFFSET (8*1024*1024) +#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) +#define VMALLOC_VMADDR(x) ((unsigned long)(x)) +#define VMALLOC_END (PAGE_OFFSET + 0x10000000) + diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-tbox/dma.h linux/include/asm-arm/arch-tbox/dma.h --- v2.4.0-test8/linux/include/asm-arm/arch-tbox/dma.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-tbox/dma.h Mon Sep 18 15:15:23 2000 @@ -0,0 +1,37 @@ +/* + * linux/include/asm-arm/arch-tbox/dma.h + * + * Architecture DMA routines. We have to contend with the bizarre DMA + * machine built into the Tbox hardware. + * + * Copyright (C) 1998 Philip Blundell + */ + +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +/* + * DMA channel definitions. Some of these are physically strange but + * we sort it out inside dma.c so the user never has to care. The + * exception is the double-buffering which we can't really abstract + * away sensibly. + */ +#define DMA_VIDEO 0 +#define DMA_MPEG_B 1 +#define DMA_AUDIO_B 2 +#define DMA_ASHRX_B 3 +#define DMA_ASHTX 4 +#define DMA_MPEG 5 +#define DMA_AUDIO 6 +#define DMA_ASHRX 7 + +#define MAX_DMA_CHANNELS 0 /* XXX */ + +/* + * This is the maximum DMA address that can be DMAd to. + */ +#define MAX_DMA_ADDRESS 0xffffffff diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-tbox/hardware.h linux/include/asm-arm/arch-tbox/hardware.h --- v2.4.0-test8/linux/include/asm-arm/arch-tbox/hardware.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-tbox/hardware.h Mon Sep 18 15:15:23 2000 @@ -0,0 +1,60 @@ +/* + * linux/include/asm-arm/arch-tbox/hardware.h + * + * Copyright (C) 1998, 1999, 2000 Philip Blundell + * Copyright (C) 2000 FutureTV Labs Ltd + * + * This file contains the hardware definitions of the Tbox + */ + +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef __ASM_ARCH_HARDWARE_H +#define __ASM_ARCH_HARDWARE_H + +/* Logical Physical + * 0xfff00000 0x00100000 I/O + * 0xfff00000 0x00100000 Expansion CS0 + * 0xfff10000 0x00110000 DMA + * 0xfff20000 0x00120000 C-Cube + * 0xfff30000 0x00130000 FPGA 1 + * 0xfff40000 0x00140000 UART 2 + * 0xfff50000 0x00150000 UART 1 + * 0xfff60000 0x00160000 CS8900 + * 0xfff70000 0x00170000 INTCONT + * 0xfff80000 0x00180000 RAMDAC + * 0xfff90000 0x00190000 Control 0 + * 0xfffa0000 0x001a0000 Control 1 + * 0xfffb0000 0x001b0000 Control 2 + * 0xfffc0000 0x001c0000 FPGA 2 + * 0xfffd0000 0x001d0000 INTRESET + * 0xfffe0000 0x001e0000 C-Cube DMA throttle + * 0xffff0000 0x001f0000 Expansion CS1 + * 0xffe00000 0x82000000 cache flush + */ + +/* + * Mapping areas + */ +#define IO_BASE 0xfff00000 +#define IO_START 0x00100000 +#define FLUSH_BASE 0xffe00000 + +#define INTCONT 0xfff70000 + +#define FPGA1CONT 0xffff3000 + +/* + * RAM definitions + */ +#define RAM_BASE 0x80000000 +#define FLUSH_BASE_PHYS 0x82000000 + +#define UNCACHEABLE_ADDR INTCONT + +#endif diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-tbox/ide.h linux/include/asm-arm/arch-tbox/ide.h --- v2.4.0-test8/linux/include/asm-arm/arch-tbox/ide.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-tbox/ide.h Mon Sep 18 15:15:23 2000 @@ -0,0 +1,3 @@ +/* + * linux/include/asm-arm/arch-tbox/ide.h + */ diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-tbox/io.h linux/include/asm-arm/arch-tbox/io.h --- v2.4.0-test8/linux/include/asm-arm/arch-tbox/io.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-tbox/io.h Mon Sep 18 15:15:23 2000 @@ -0,0 +1,55 @@ +/* + * linux/include/asm-arm/arch-tbox/io.h + * + * Copyright (C) 1996-1999 Russell King + * Copyright (C) 1998, 1999 Philip Blundell + * + */ +#ifndef __ASM_ARM_ARCH_IO_H +#define __ASM_ARM_ARCH_IO_H + +#define IO_SPACE_LIMIT 0xffffffff + +#define __io_pc(_x) ((_x) << 2) + +/* + * Generic virtual read/write + */ +#define __arch_getb(a) (*(volatile unsigned char *)(a)) +#define __arch_getl(a) (*(volatile unsigned long *)(a)) + +extern __inline__ unsigned int __arch_getw(unsigned long a) +{ + unsigned int value; + __asm__ __volatile__("ldr%?h %0, [%1, #0] @ getw" + : "=&r" (value) + : "r" (a)); + return value; +} + + +#define __arch_putb(v,a) (*(volatile unsigned char *)(a) = (v)) +#define __arch_putl(v,a) (*(volatile unsigned long *)(a) = (v)) + +extern __inline__ void __arch_putw(unsigned int value, unsigned long a) +{ + __asm__ __volatile__("str%?h %0, [%1, #0] @ putw" + : : "r" (value), "r" (a)); +} + +#define inb(p) __arch_getb(__io_pc(p)) +#define inw(p) __arch_getw(__io_pc(p)) +#define inl(p) __arch_getl(__io_pc(p)) + +#define outb(v,p) __arch_putb(v,__io_pc(p)) +#define outw(v,p) __arch_putw(v,__io_pc(p)) +#define outl(v,p) __arch_putl(v,__io_pc(p)) + +/* Idem, for devices on the upper byte lanes */ +#define inb_u(p) __arch_getb(__io_pc(p) + 2) +#define inw_u(p) __arch_getw(__io_pc(p) + 2) + +#define outb_u(v,p) __arch_putb(v,__io_pc(p) + 2) +#define outw_u(v,p) __arch_putw(v,__io_pc(p) + 2) + +#endif diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-tbox/irq.h linux/include/asm-arm/arch-tbox/irq.h --- v2.4.0-test8/linux/include/asm-arm/arch-tbox/irq.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-tbox/irq.h Mon Sep 18 15:15:23 2000 @@ -0,0 +1,50 @@ +/* + * include/asm-arm/arch-tbox/irq.h + * + * Copyright (C) 1998, 1999, 2000 Philip Blundell + */ + +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include + +#define fixup_irq(x) (x) + +extern unsigned long soft_irq_mask; + +static void tbox_mask_irq(unsigned int irq) +{ + __raw_writel(0, INTCONT + (irq << 2)); + soft_irq_mask &= ~(1<= 12 && i <= 13)) { + irq_desc[i].valid = 1; + irq_desc[i].probe_ok = 0; + irq_desc[i].mask_ack = tbox_mask_irq; + irq_desc[i].mask = tbox_mask_irq; + irq_desc[i].unmask = tbox_unmask_irq; + tbox_mask_irq(i); + } else { + irq_desc[i].valid = 0; + irq_desc[i].probe_ok = 0; + } + } +} diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-tbox/irqs.h linux/include/asm-arm/arch-tbox/irqs.h --- v2.4.0-test8/linux/include/asm-arm/arch-tbox/irqs.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-tbox/irqs.h Mon Sep 18 15:15:23 2000 @@ -0,0 +1,29 @@ +/* + * linux/include/asm-arm/arch-tbox/irqs.h + * + * Copyright (C) 1998, 2000 Philip Blundell + */ + +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#define IRQ_MPEGDMA 0 +#define IRQ_ASHTX 1 +#define IRQ_ASHRX 2 +#define IRQ_VSYNC 3 +#define IRQ_HSYNC 4 +#define IRQ_MPEG 5 +#define IRQ_UART2 6 +#define IRQ_UART1 7 +#define IRQ_ETHERNET 8 +#define IRQ_TIMER 9 +#define IRQ_AUDIODMA 10 +/* bit 11 used for video field ident */ +#define IRQ_EXPMODCS0 12 +#define IRQ_EXPMODCS1 13 + +#define irq_cannonicalize(i) (i) diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-tbox/keyboard.h linux/include/asm-arm/arch-tbox/keyboard.h --- v2.4.0-test8/linux/include/asm-arm/arch-tbox/keyboard.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-tbox/keyboard.h Mon Sep 18 15:15:23 2000 @@ -0,0 +1,29 @@ +/* + * linux/include/asm-arm/arch-tbox/keyboard.h + * + * Driver definitions for Tbox dummy keyboard. + * + * Copyright (C) 1998 Russell King + * Copyright (C) 1998 Philip Blundell + */ + +#define NR_SCANCODES 128 + +#define kbd_setkeycode(sc,kc) (-EINVAL) +#define kbd_getkeycode(sc) (-EINVAL) + +/* Prototype: int kbd_pretranslate(scancode, raw_mode) + * Returns : 0 to ignore scancode + */ +#define kbd_pretranslate(sc,rm) (1) + +/* Prototype: int kbd_translate(scancode, *keycode, *up_flag, raw_mode) + * Returns : 0 to ignore scancode, *keycode set to keycode, *up_flag + * set to 0200 if scancode indicates release + */ +#define kbd_translate(sc, kcp, rm) 0 +#define kbd_unexpected_up(kc) (0200) +#define kbd_leds(leds) do { } while (0) +#define kbd_init_hw() do { } while (0) +#define kbd_disable_irq() do { } while (0) +#define kbd_enable_irq() do { } while (0) diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-tbox/memory.h linux/include/asm-arm/arch-tbox/memory.h --- v2.4.0-test8/linux/include/asm-arm/arch-tbox/memory.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-tbox/memory.h Mon Sep 18 15:15:23 2000 @@ -0,0 +1,38 @@ +/* + * linux/include/asm-arm/arch-tbox/memory.h + * + * Copyright (c) 1996-1999 Russell King. + * Copyright (c) 1998-1999 Phil Blundell + */ +#ifndef __ASM_ARCH_MEMORY_H +#define __ASM_ARCH_MEMORY_H + +/* + * Task size: 3GB + */ +#define TASK_SIZE (0xc0000000UL) +#define TASK_SIZE_26 (0x04000000UL) + +/* + * Page offset: 3GB + */ +#define PAGE_OFFSET (0xc0000000UL) +#define PHYS_OFFSET (0x80000000UL) + +/* + * DRAM is contiguous + */ +#define __virt_to_phys(vpage) ((vpage) - PAGE_OFFSET + PHYS_OFFSET) +#define __phys_to_virt(ppage) ((ppage) + PAGE_OFFSET - PHYS_OFFSET) +#define __virt_to_phys__is_a_macro +#define __phys_to_virt__is_a_macro + +/* + * Bus view is the same as physical view + */ +#define __virt_to_bus__is_a_macro +#define __virt_to_bus(x) __virt_to_phys(x) +#define __bus_to_virt__is_a_macro +#define __bus_to_virt(x) __phys_to_virt(x) + +#endif diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-tbox/param.h linux/include/asm-arm/arch-tbox/param.h --- v2.4.0-test8/linux/include/asm-arm/arch-tbox/param.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-tbox/param.h Mon Sep 18 15:15:23 2000 @@ -0,0 +1 @@ +#define HZ 1000 diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-tbox/processor.h linux/include/asm-arm/arch-tbox/processor.h --- v2.4.0-test8/linux/include/asm-arm/arch-tbox/processor.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-tbox/processor.h Mon Sep 18 15:15:23 2000 @@ -0,0 +1,24 @@ +/* + * linux/include/asm-arm/arch-tbox/processor.h + * from linux/include/asm-arm/arch-ebsa110/processor.h + * + * Copyright (C) 1996,1997,1998 Russell King + */ + +#ifndef __ASM_ARCH_PROCESSOR_H +#define __ASM_ARCH_PROCESSOR_H + +/* + * Bus types + */ +#define EISA_bus 0 +#define EISA_bus__is_a_macro /* for versions in ksyms.c */ +#define MCA_bus 0 +#define MCA_bus__is_a_macro /* for versions in ksyms.c */ + +/* This decides where the kernel will search for a free chunk of vm + * space during mmap's. + */ +#define TASK_UNMAPPED_BASE (TASK_SIZE / 3) + +#endif diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-tbox/serial.h linux/include/asm-arm/arch-tbox/serial.h --- v2.4.0-test8/linux/include/asm-arm/arch-tbox/serial.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-tbox/serial.h Mon Sep 18 15:15:23 2000 @@ -0,0 +1,34 @@ +/* + * linux/include/asm-arm/arch-tbox/serial.h + * + * Copyright (c) 1996 Russell King. + * Copyright (c) 1998 Phil Blundell + * + * Changelog: + * 15-10-1996 RMK Created + * 09-06-1998 PJB tbox version + */ +#ifndef __ASM_ARCH_SERIAL_H +#define __ASM_ARCH_SERIAL_H + +/* + * This assumes you have a 1.8432 MHz clock for your UART. + * + * It'd be nice if someone built a serial card with a 24.576 MHz + * clock, since the 16550A is capable of handling a top speed of 1.5 + * megabits/second; but this requires the faster clock. + */ +#define BASE_BAUD (1843200 / 16) + +#define RS_TABLE_SIZE 2 + +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) + + /* UART CLK PORT IRQ FLAGS */ +#define STD_SERIAL_PORT_DEFNS \ + { 0, BASE_BAUD, 0xffff4000 >> 2, 6, STD_COM_FLAGS }, /* ttyS0 */ \ + { 0, BASE_BAUD, 0xffff5000 >> 2, 7, STD_COM_FLAGS }, /* ttyS1 */ + +#define EXTRA_SERIAL_PORT_DEFNS + +#endif diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-tbox/system.h linux/include/asm-arm/arch-tbox/system.h --- v2.4.0-test8/linux/include/asm-arm/arch-tbox/system.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-tbox/system.h Mon Sep 18 15:15:23 2000 @@ -0,0 +1,33 @@ +/* + * linux/include/asm-arm/arch-tbox/system.h + * + * Copyright (c) 1996-1999 Russell King. + */ +#ifndef __ASM_ARCH_SYSTEM_H +#define __ASM_ARCH_SYSTEM_H + +static void arch_idle(void) +{ + unsigned long start_idle; + + start_idle = jiffies; + + do { + if (current->need_resched || hlt_counter) + goto slow_out; + cpu_do_idle(IDLE_WAIT_FAST); + } while (time_before(jiffies, start_idle + HZ/50)); + + cpu_do_idle(IDLE_CLOCK_SLOW); + + while (!current->need_resched && !hlt_counter) { + cpu_do_idle(IDLE_WAIT_SLOW); + } + + cpu_do_idle(IDLE_CLOCK_FAST); +slow_out: +} + +#define arch_reset(mode) do { } while (0) + +#endif diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-tbox/time.h linux/include/asm-arm/arch-tbox/time.h --- v2.4.0-test8/linux/include/asm-arm/arch-tbox/time.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-tbox/time.h Mon Sep 18 15:15:23 2000 @@ -0,0 +1,36 @@ +/* + * linux/include/asm-arm/arch-tbox/time.h + * + * Copyright (c) 1997, 1999 Phil Blundell. + * Copyright (c) 2000 FutureTV Labs Ltd + * + * Tbox has no real-time clock -- we get millisecond ticks to update + * our soft copy. + */ + +#include +#include + +#define update_rtc() + +static void timer_interrupt (int irq, void *dev_id, struct pt_regs *regs) +{ + /* Clear irq */ + __raw_writel(1, FPGA1CONT + 0xc); + __raw_writel(0, FPGA1CONT + 0xc); + + do_timer(regs); +} + +extern __inline__ void setup_timer (void) +{ + /* + * Default the date to 1 Jan 1970 0:0:0 + * You will have to run a time daemon to set the + * clock correctly at bootup + */ + xtime.tv_sec = mktime(1970, 1, 1, 0, 0, 0); + + timer_irq.handler = timer_interrupt; + setup_arm_irq(IRQ_TIMER, &timer_irq); +} diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-tbox/timex.h linux/include/asm-arm/arch-tbox/timex.h --- v2.4.0-test8/linux/include/asm-arm/arch-tbox/timex.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-tbox/timex.h Mon Sep 18 15:15:23 2000 @@ -0,0 +1,8 @@ +/* + * linux/include/asm-arm/arch-tbox/timex.h + * + * Tbox timex specifications + * + * Copyright (C) 1999 Philip Blundell + */ + diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-tbox/uncompress.h linux/include/asm-arm/arch-tbox/uncompress.h --- v2.4.0-test8/linux/include/asm-arm/arch-tbox/uncompress.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-tbox/uncompress.h Mon Sep 18 15:15:23 2000 @@ -0,0 +1,42 @@ +/* + * linux/include/asm-arm/arch-nexuspci/uncompress.h + * from linux/include/asm-arm/arch-ebsa110/uncompress.h + * + * Copyright (C) 1996,1997,1998 Russell King + * Copyright (C) 1998, 1999 Phil Blundell + */ + +#include + +#define UARTBASE 0x00400000 + +/* + * This does not append a newline + */ +static void puts(const char *s) +{ + while (*s) + { + char c = *(s++); + while (!(__raw_readb(UARTBASE + 0x14) & 0x20)); + __raw_writeb(c, UARTBASE); + if (c == 10) { + while (!(__raw_readb(UARTBASE + 0x14) & 0x20)); + __raw_writeb(13, UARTBASE); + } + } +} + +/* + * nothing to do + */ +#define arch_decomp_setup() + +/* + * Stroke the watchdog so we don't get reset during decompression. + */ +#define arch_decomp_wdog() \ + do { \ + __raw_writel(1, 0xa00000); \ + __raw_writel(0, 0xa00000); \ + } while (0) diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/arch-tbox/vmalloc.h linux/include/asm-arm/arch-tbox/vmalloc.h --- v2.4.0-test8/linux/include/asm-arm/arch-tbox/vmalloc.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/arch-tbox/vmalloc.h Mon Sep 18 15:15:23 2000 @@ -0,0 +1,17 @@ +/* + * linux/include/asm-arm/arch-rpc/vmalloc.h + */ + +/* + * Just any arbitrary offset to the start of the vmalloc VM area: the + * current 8MB value just means that there will be a 8MB "hole" after the + * physical memory until the kernel virtual memory starts. That means that + * any out-of-bounds memory accesses will hopefully be caught. + * The vmalloc() routines leaves a hole of 4kB between each vmalloced + * area for the same reason. ;) + */ +#define VMALLOC_OFFSET (8*1024*1024) +#define VMALLOC_START (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) +#define VMALLOC_VMADDR(x) ((unsigned long)(x)) +#define VMALLOC_END (PAGE_OFFSET + 0x10000000) + diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/atomic.h linux/include/asm-arm/atomic.h --- v2.4.0-test8/linux/include/asm-arm/atomic.h Mon Jun 26 12:04:42 2000 +++ linux/include/asm-arm/atomic.h Mon Sep 18 15:15:23 2000 @@ -1,13 +1,17 @@ /* - * linux/include/asm-arm/atomic.h + * linux/include/asm-arm/atomic.h * - * Copyright (c) 1996 Russell King. + * Copyright (c) 1996 Russell King. * - * Changelog: - * 27-06-1996 RMK Created - * 13-04-1997 RMK Made functions atomic! - * 07-12-1997 RMK Upgraded for v2.1. - * 26-08-1998 PJB Added #ifdef __KERNEL__ + * 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. + * + * Changelog: + * 27-06-1996 RMK Created + * 13-04-1997 RMK Made functions atomic! + * 07-12-1997 RMK Upgraded for v2.1. + * 26-08-1998 PJB Added #ifdef __KERNEL__ */ #ifndef __ASM_ARM_ATOMIC_H #define __ASM_ARM_ATOMIC_H diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/bugs.h linux/include/asm-arm/bugs.h --- v2.4.0-test8/linux/include/asm-arm/bugs.h Mon Aug 30 18:15:21 1999 +++ linux/include/asm-arm/bugs.h Mon Sep 18 15:15:23 2000 @@ -1,7 +1,11 @@ /* - * include/asm-arm/bugs.h + * linux/include/asm-arm/bugs.h * * Copyright (C) 1995 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. */ #ifndef __ASM_BUGS_H #define __ASM_BUGS_H diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/cache.h linux/include/asm-arm/cache.h --- v2.4.0-test8/linux/include/asm-arm/cache.h Wed Oct 20 16:29:08 1999 +++ linux/include/asm-arm/cache.h Mon Sep 18 15:15:23 2000 @@ -1,5 +1,5 @@ /* - * linux/include/asm-arm/cache.h + * linux/include/asm-arm/cache.h */ #ifndef __ASMARM_CACHE_H #define __ASMARM_CACHE_H diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/checksum.h linux/include/asm-arm/checksum.h --- v2.4.0-test8/linux/include/asm-arm/checksum.h Mon Mar 27 10:46:29 2000 +++ linux/include/asm-arm/checksum.h Mon Sep 18 15:15:23 2000 @@ -1,5 +1,5 @@ /* - * linux/include/asm-arm/checksum.h + * linux/include/asm-arm/checksum.h * * IP checksum routines * diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/cpu-multi26.h linux/include/asm-arm/cpu-multi26.h --- v2.4.0-test8/linux/include/asm-arm/cpu-multi26.h Mon Jun 26 12:04:42 2000 +++ linux/include/asm-arm/cpu-multi26.h Mon Sep 18 15:15:23 2000 @@ -1,3 +1,12 @@ +/* + * linux/include/asm-arm/cpu-multi26.h + * + * Copyright (C) 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. + */ #ifndef __ASSEMBLY__ #include diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/cpu-multi32.h linux/include/asm-arm/cpu-multi32.h --- v2.4.0-test8/linux/include/asm-arm/cpu-multi32.h Mon Mar 27 10:46:29 2000 +++ linux/include/asm-arm/cpu-multi32.h Mon Sep 18 15:15:23 2000 @@ -1,3 +1,12 @@ +/* + * linux/include/asm-arm/cpu-multi32.h + * + * Copyright (C) 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. + */ #ifndef __ASSEMBLY__ #include @@ -27,79 +36,91 @@ */ void (*_proc_fin)(void); /* - * Processor architecture specific - */ - /* CACHE - * - * flush all caches - */ - void (*_flush_cache_all)(void); - /* - * flush a specific page or pages - */ - void (*_flush_cache_area)(unsigned long address, unsigned long end, int flags); - /* - * flush cache entry for an address - */ - void (*_flush_cache_entry)(unsigned long address); - /* - * clean a virtual address range from the - * D-cache without flushing the cache. - */ - void (*_clean_cache_area)(unsigned long start, unsigned long size); - /* - * flush a page to RAM - */ - void (*_flush_ram_page)(unsigned long page); - /* TLB - * - * flush all TLBs - */ - void (*_flush_tlb_all)(void); - /* - * flush a specific TLB - */ - void (*_flush_tlb_area)(unsigned long address, unsigned long end, int flags); - /* - * Set the page table - */ - void (*_set_pgd)(unsigned long pgd_phys); - /* - * Set a PMD (handling IMP bit 4) - */ - void (*_set_pmd)(pmd_t *pmdp, pmd_t pmd); - /* - * Set a PTE - */ - void (*_set_pte)(pte_t *ptep, pte_t pte); - /* * Special stuff for a reset */ volatile void (*reset)(unsigned long addr); /* - * flush an icached page - */ - void (*_flush_icache_area)(unsigned long start, unsigned long size); - /* - * write back dirty cached data - */ - void (*_cache_wback_area)(unsigned long start, unsigned long end); - /* - * purge cached data without (necessarily) writing it back - */ - void (*_cache_purge_area)(unsigned long start, unsigned long end); - /* - * flush a specific TLB - */ - void (*_flush_tlb_page)(unsigned long address, int flags); - /* * Idle the processor */ int (*_do_idle)(int mode); /* - * flush I cache for a page + * Processor architecture specific */ - void (*_flush_icache_page)(unsigned long address); + struct { /* CACHE */ + /* + * flush all caches + */ + void (*clean_invalidate_all)(void); + /* + * flush a specific page or pages + */ + void (*clean_invalidate_range)(unsigned long address, unsigned long end, int flags); + /* + * flush a page to RAM + */ + void (*_flush_ram_page)(void *virt_page); + } cache; + + struct { /* D-cache */ + /* + * invalidate the specified data range + */ + void (*invalidate_range)(unsigned long start, unsigned long end); + /* + * clean specified data range + */ + void (*clean_range)(unsigned long start, unsigned long end); + /* + * obsolete flush cache entry + */ + void (*clean_page)(void *virt_page); + /* + * clean a virtual address range from the + * D-cache without flushing the cache. + */ + void (*clean_entry)(unsigned long start); + } dcache; + + struct { /* I-cache */ + /* + * invalidate the I-cache for the specified range + */ + void (*invalidate_range)(unsigned long start, unsigned long end); + /* + * invalidate the I-cache for the specified virtual page + */ + void (*invalidate_page)(void *virt_page); + } icache; + + struct { /* TLB */ + /* + * flush all TLBs + */ + void (*invalidate_all)(void); + /* + * flush a specific TLB + */ + void (*invalidate_range)(unsigned long address, unsigned long end); + /* + * flush a specific TLB + */ + void (*invalidate_page)(unsigned long address, int flags); + } tlb; + + struct { /* PageTable */ + /* + * Set the page table + */ + void (*set_pgd)(unsigned long pgd_phys); + /* + * Set a PMD (handling IMP bit 4) + */ + void (*set_pmd)(pmd_t *pmdp, pmd_t pmd); + /* + * Set a PTE + */ + void (*set_pte)(pte_t *ptep, pte_t pte); + } pgtable; } processor; extern const struct processor arm6_processor_functions; @@ -110,24 +131,28 @@ #define cpu_check_bugs() processor._check_bugs() #define cpu_proc_init() processor._proc_init() #define cpu_proc_fin() processor._proc_fin() +#define cpu_reset(addr) processor.reset(addr) #define cpu_do_idle(mode) processor._do_idle(mode) -#define cpu_flush_cache_all() processor._flush_cache_all() -#define cpu_flush_cache_area(start,end,flags) processor._flush_cache_area(start,end,flags) -#define cpu_flush_cache_entry(addr) processor._flush_cache_entry(addr) -#define cpu_clean_cache_area(start,size) processor._clean_cache_area(start,size) -#define cpu_flush_ram_page(page) processor._flush_ram_page(page) -#define cpu_flush_tlb_all() processor._flush_tlb_all() -#define cpu_flush_tlb_area(start,end,flags) processor._flush_tlb_area(start,end,flags) -#define cpu_flush_tlb_page(addr,flags) processor._flush_tlb_page(addr,flags) -#define cpu_set_pgd(pgd) processor._set_pgd(pgd) -#define cpu_set_pmd(pmdp, pmd) processor._set_pmd(pmdp, pmd) -#define cpu_set_pte(ptep, pte) processor._set_pte(ptep, pte) -#define cpu_reset(addr) processor.reset(addr) -#define cpu_flush_icache_area(start,end) processor._flush_icache_area(start,end) -#define cpu_cache_wback_area(start,end) processor._cache_wback_area(start,end) -#define cpu_cache_purge_area(start,end) processor._cache_purge_area(start,end) -#define cpu_flush_icache_page(virt) processor._flush_icache_page(virt) +#define cpu_cache_clean_invalidate_all() processor.cache.clean_invalidate_all() +#define cpu_cache_clean_invalidate_range(s,e,f) processor.cache.clean_invalidate_range(s,e,f) +#define cpu_flush_ram_page(vp) processor.cache._flush_ram_page(vp) + +#define cpu_dcache_clean_page(vp) processor.dcache.clean_page(vp) +#define cpu_dcache_clean_entry(addr) processor.dcache.clean_entry(addr) +#define cpu_dcache_clean_range(s,e) processor.dcache.clean_range(s,e) +#define cpu_dcache_invalidate_range(s,e) processor.dcache.invalidate_range(s,e) + +#define cpu_icache_invalidate_range(s,e) processor.icache.invalidate_range(s,e) +#define cpu_icache_invalidate_page(vp) processor.icache.invalidate_page(vp) + +#define cpu_tlb_invalidate_all() processor.tlb.invalidate_all() +#define cpu_tlb_invalidate_range(s,e) processor.tlb.invalidate_range(s,e) +#define cpu_tlb_invalidate_page(vp,f) processor.tlb.invalidate_page(vp,f) + +#define cpu_set_pgd(pgd) processor.pgtable.set_pgd(pgd) +#define cpu_set_pmd(pmdp, pmd) processor.pgtable.set_pmd(pmdp, pmd) +#define cpu_set_pte(ptep, pte) processor.pgtable.set_pte(ptep, pte) #define cpu_switch_mm(pgd,tsk) cpu_set_pgd(__virt_to_phys((unsigned long)(pgd))) diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/cpu-single.h linux/include/asm-arm/cpu-single.h --- v2.4.0-test8/linux/include/asm-arm/cpu-single.h Mon Mar 27 10:46:29 2000 +++ linux/include/asm-arm/cpu-single.h Mon Sep 18 15:15:23 2000 @@ -1,4 +1,13 @@ /* + * linux/include/asm-arm/cpu-single.h + * + * Copyright (C) 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. + */ +/* * Single CPU */ #ifdef __STDC__ @@ -9,33 +18,36 @@ #define cpu_fn(name,x) __cpu_fn(name,x) /* - * If we are supporting multiple CPUs, then - * we must use a table of function pointers - * for this lot. Otherwise, we can optimise - * the table away. + * If we are supporting multiple CPUs, then we must use a table of + * function pointers for this lot. Otherwise, we can optimise the + * table away. */ #define cpu_data_abort cpu_fn(CPU_NAME,_data_abort) #define cpu_check_bugs cpu_fn(CPU_NAME,_check_bugs) #define cpu_proc_init cpu_fn(CPU_NAME,_proc_init) #define cpu_proc_fin cpu_fn(CPU_NAME,_proc_fin) +#define cpu_reset cpu_fn(CPU_NAME,_reset) #define cpu_do_idle cpu_fn(CPU_NAME,_do_idle) -#define cpu_flush_cache_all cpu_fn(CPU_NAME,_flush_cache_all) -#define cpu_flush_cache_area cpu_fn(CPU_NAME,_flush_cache_area) -#define cpu_flush_cache_entry cpu_fn(CPU_NAME,_flush_cache_entry) -#define cpu_clean_cache_area cpu_fn(CPU_NAME,_clean_cache_area) +#define cpu_cache_clean_invalidate_all cpu_fn(CPU_NAME,_cache_clean_invalidate_all) +#define cpu_cache_clean_invalidate_range cpu_fn(CPU_NAME,_cache_clean_invalidate_range) #define cpu_flush_ram_page cpu_fn(CPU_NAME,_flush_ram_page) -#define cpu_flush_tlb_all cpu_fn(CPU_NAME,_flush_tlb_all) -#define cpu_flush_tlb_area cpu_fn(CPU_NAME,_flush_tlb_area) -#define cpu_flush_tlb_page cpu_fn(CPU_NAME,_flush_tlb_page) + +#define cpu_dcache_invalidate_range cpu_fn(CPU_NAME,_dcache_invalidate_range) +#define cpu_dcache_clean_range cpu_fn(CPU_NAME,_dcache_clean_range) +#define cpu_dcache_clean_page cpu_fn(CPU_NAME,_dcache_clean_page) +#define cpu_dcache_clean_entry cpu_fn(CPU_NAME,_dcache_clean_entry) + +#define cpu_icache_invalidate_range cpu_fn(CPU_NAME,_icache_invalidate_range) +#define cpu_icache_invalidate_page cpu_fn(CPU_NAME,_icache_invalidate_page) + +#define cpu_tlb_invalidate_all cpu_fn(CPU_NAME,_tlb_invalidate_all) +#define cpu_tlb_invalidate_range cpu_fn(CPU_NAME,_tlb_invalidate_range) +#define cpu_tlb_invalidate_page cpu_fn(CPU_NAME,_tlb_invalidate_page) + #define cpu_set_pgd cpu_fn(CPU_NAME,_set_pgd) #define cpu_set_pmd cpu_fn(CPU_NAME,_set_pmd) #define cpu_set_pte cpu_fn(CPU_NAME,_set_pte) -#define cpu_reset cpu_fn(CPU_NAME,_reset) -#define cpu_flush_icache_area cpu_fn(CPU_NAME,_flush_icache_area) -#define cpu_cache_wback_area cpu_fn(CPU_NAME,_cache_wback_area) -#define cpu_cache_purge_area cpu_fn(CPU_NAME,_cache_purge_area) -#define cpu_flush_icache_page cpu_fn(CPU_NAME,_flush_icache_page) #ifndef __ASSEMBLY__ @@ -51,22 +63,26 @@ extern void cpu_proc_fin(void); extern int cpu_do_idle(int mode); -extern void cpu_flush_cache_all(void); -extern void cpu_flush_cache_area(unsigned long address, unsigned long end, int flags); -extern void cpu_flush_cache_entry(unsigned long address); -extern void cpu_clean_cache_area(unsigned long start, unsigned long size); -extern void cpu_flush_ram_page(unsigned long page); -extern void cpu_flush_tlb_all(void); -extern void cpu_flush_tlb_area(unsigned long address, unsigned long end, int flags); -extern void cpu_flush_tlb_page(unsigned long address, int flags); +extern void cpu_cache_clean_invalidate_all(void); +extern void cpu_cache_clean_invalidate_range(unsigned long address, unsigned long end, int flags); +extern void cpu_flush_ram_page(void *virt_page); + +extern void cpu_dcache_invalidate_range(unsigned long start, unsigned long end); +extern void cpu_dcache_clean_range(unsigned long start, unsigned long end); +extern void cpu_dcache_clean_page(void *virt_page); +extern void cpu_dcache_clean_entry(unsigned long address); + +extern void cpu_icache_invalidate_range(unsigned long start, unsigned long end); +extern void cpu_icache_invalidate_page(void *virt_page); + +extern void cpu_tlb_invalidate_all(void); +extern void cpu_tlb_invalidate_range(unsigned long address, unsigned long end); +extern void cpu_tlb_invalidate_page(unsigned long address, int flags); + extern void cpu_set_pgd(unsigned long pgd_phys); extern void cpu_set_pmd(pmd_t *pmdp, pmd_t pmd); extern void cpu_set_pte(pte_t *ptep, pte_t pte); extern volatile void cpu_reset(unsigned long addr); -extern void cpu_flush_icache_area(unsigned long start, unsigned long size); -extern void cpu_cache_wback_area(unsigned long start, unsigned long end); -extern void cpu_cache_purge_area(unsigned long start, unsigned long end); -extern void cpu_flush_icache_page(unsigned long virt); #define cpu_switch_mm(pgd,tsk) cpu_set_pgd(__virt_to_phys((unsigned long)(pgd))) diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/dec21285.h linux/include/asm-arm/dec21285.h --- v2.4.0-test8/linux/include/asm-arm/dec21285.h Tue Jul 18 22:43:25 2000 +++ linux/include/asm-arm/dec21285.h Wed Dec 31 16:00:00 1969 @@ -1,144 +0,0 @@ -/* - * include/asm-arm/dec21285.h - * - * Copyright (C) 1998 Russell King - * - * DC21285 registers - */ -#define DC21285_PCI_IACK 0x79000000 -#define DC21285_ARMCSR_BASE 0x42000000 -#define DC21285_PCI_TYPE_0_CONFIG 0x7b000000 -#define DC21285_PCI_TYPE_1_CONFIG 0x7a000000 -#define DC21285_OUTBOUND_WRITE_FLUSH 0x78000000 -#define DC21285_FLASH 0x41000000 -#define DC21285_PCI_IO 0x7c000000 -#define DC21285_PCI_MEM 0x80000000 - -#include -#ifndef __ASSEMBLY__ -#include -#define DC21285_IO(x) ((volatile unsigned long *)(ARMCSR_BASE+(x))) -#else -#define DC21285_IO(x) (x) -#endif - -#define CSR_PCICMD DC21285_IO(0x0004) -#define CSR_CLASSREV DC21285_IO(0x0008) -#define CSR_PCICACHELINESIZE DC21285_IO(0x000c) -#define CSR_PCICSRBASE DC21285_IO(0x0010) -#define CSR_PCICSRIOBASE DC21285_IO(0x0014) -#define CSR_PCISDRAMBASE DC21285_IO(0x0018) -#define CSR_PCIROMBASE DC21285_IO(0x0030) -#define CSR_MBOX0 DC21285_IO(0x0050) -#define CSR_MBOX1 DC21285_IO(0x0054) -#define CSR_MBOX2 DC21285_IO(0x0058) -#define CSR_MBOX3 DC21285_IO(0x005c) -#define CSR_DOORBELL DC21285_IO(0x0060) -#define CSR_DOORBELL_SETUP DC21285_IO(0x0064) -#define CSR_ROMWRITEREG DC21285_IO(0x0068) -#define CSR_CSRBASEMASK DC21285_IO(0x00f8) -#define CSR_CSRBASEOFFSET DC21285_IO(0x00fc) -#define CSR_SDRAMBASEMASK DC21285_IO(0x0100) -#define CSR_SDRAMBASEOFFSET DC21285_IO(0x0104) -#define CSR_ROMBASEMASK DC21285_IO(0x0108) -#define CSR_SDRAMTIMING DC21285_IO(0x010c) -#define CSR_SDRAMADDRSIZE0 DC21285_IO(0x0110) -#define CSR_SDRAMADDRSIZE1 DC21285_IO(0x0114) -#define CSR_SDRAMADDRSIZE2 DC21285_IO(0x0118) -#define CSR_SDRAMADDRSIZE3 DC21285_IO(0x011c) -#define CSR_I2O_INFREEHEAD DC21285_IO(0x0120) -#define CSR_I2O_INPOSTTAIL DC21285_IO(0x0124) -#define CSR_I2O_OUTPOSTHEAD DC21285_IO(0x0128) -#define CSR_I2O_OUTFREETAIL DC21285_IO(0x012c) -#define CSR_I2O_INFREECOUNT DC21285_IO(0x0130) -#define CSR_I2O_OUTPOSTCOUNT DC21285_IO(0x0134) -#define CSR_I2O_INPOSTCOUNT DC21285_IO(0x0138) -#define CSR_SA110_CNTL DC21285_IO(0x013c) -#define SA110_CNTL_INITCMPLETE (1 << 0) -#define SA110_CNTL_ASSERTSERR (1 << 1) -#define SA110_CNTL_RXSERR (1 << 3) -#define SA110_CNTL_SA110DRAMPARITY (1 << 4) -#define SA110_CNTL_PCISDRAMPARITY (1 << 5) -#define SA110_CNTL_DMASDRAMPARITY (1 << 6) -#define SA110_CNTL_DISCARDTIMER (1 << 8) -#define SA110_CNTL_PCINRESET (1 << 9) -#define SA110_CNTL_I2O_256 (0 << 10) -#define SA110_CNTL_I20_512 (1 << 10) -#define SA110_CNTL_I2O_1024 (2 << 10) -#define SA110_CNTL_I2O_2048 (3 << 10) -#define SA110_CNTL_I2O_4096 (4 << 10) -#define SA110_CNTL_I2O_8192 (5 << 10) -#define SA110_CNTL_I2O_16384 (6 << 10) -#define SA110_CNTL_I2O_32768 (7 << 10) -#define SA110_CNTL_WATCHDOG (1 << 13) -#define SA110_CNTL_ROMWIDTH_UNDEF (0 << 14) -#define SA110_CNTL_ROMWIDTH_16 (1 << 14) -#define SA110_CNTL_ROMWIDTH_32 (2 << 14) -#define SA110_CNTL_ROMWIDTH_8 (3 << 14) -#define SA110_CNTL_ROMACCESSTIME(x) ((x)<<16) -#define SA110_CNTL_ROMBURSTTIME(x) ((x)<<20) -#define SA110_CNTL_ROMTRISTATETIME(x) ((x)<<24) -#define SA110_CNTL_XCSDIR(x) ((x)<<28) -#define SA110_CNTL_PCICFN (1 << 31) - -/* - * footbridge_cfn_mode() is used when we want - * to check whether we are the central function - */ -#define __footbridge_cfn_mode() (*CSR_SA110_CNTL & SA110_CNTL_PCICFN) -#if defined(CONFIG_FOOTBRIDGE_HOST) && defined(CONFIG_FOOTBRIDGE_ADDIN) -#define footbridge_cfn_mode() __footbridge_cfn_mode() -#elif defined(CONFIG_FOOTBRIDGE_HOST) -#define footbridge_cfn_mode() (1) -#else -#define footbridge_cfn_mode() (0) -#endif - -#define CSR_PCIADDR_EXTN DC21285_IO(0x0140) -#define CSR_PREFETCHMEMRANGE DC21285_IO(0x0144) -#define CSR_XBUS_CYCLE DC21285_IO(0x0148) -#define CSR_XBUS_IOSTROBE DC21285_IO(0x014c) -#define CSR_DOORBELL_PCI DC21285_IO(0x0150) -#define CSR_DOORBELL_SA110 DC21285_IO(0x0154) -#define CSR_UARTDR DC21285_IO(0x0160) -#define CSR_RXSTAT DC21285_IO(0x0164) -#define CSR_H_UBRLCR DC21285_IO(0x0168) -#define CSR_M_UBRLCR DC21285_IO(0x016c) -#define CSR_L_UBRLCR DC21285_IO(0x0170) -#define CSR_UARTCON DC21285_IO(0x0174) -#define CSR_UARTFLG DC21285_IO(0x0178) -#define CSR_IRQ_STATUS DC21285_IO(0x0180) -#define CSR_IRQ_RAWSTATUS DC21285_IO(0x0184) -#define CSR_IRQ_ENABLE DC21285_IO(0x0188) -#define CSR_IRQ_DISABLE DC21285_IO(0x018c) -#define CSR_IRQ_SOFT DC21285_IO(0x0190) -#define CSR_FIQ_STATUS DC21285_IO(0x0280) -#define CSR_FIQ_RAWSTATUS DC21285_IO(0x0284) -#define CSR_FIQ_ENABLE DC21285_IO(0x0288) -#define CSR_FIQ_DISABLE DC21285_IO(0x028c) -#define CSR_FIQ_SOFT DC21285_IO(0x0290) -#define CSR_TIMER1_LOAD DC21285_IO(0x0300) -#define CSR_TIMER1_VALUE DC21285_IO(0x0304) -#define CSR_TIMER1_CNTL DC21285_IO(0x0308) -#define CSR_TIMER1_CLR DC21285_IO(0x030c) -#define CSR_TIMER2_LOAD DC21285_IO(0x0320) -#define CSR_TIMER2_VALUE DC21285_IO(0x0324) -#define CSR_TIMER2_CNTL DC21285_IO(0x0328) -#define CSR_TIMER2_CLR DC21285_IO(0x032c) -#define CSR_TIMER3_LOAD DC21285_IO(0x0340) -#define CSR_TIMER3_VALUE DC21285_IO(0x0344) -#define CSR_TIMER3_CNTL DC21285_IO(0x0348) -#define CSR_TIMER3_CLR DC21285_IO(0x034c) -#define CSR_TIMER4_LOAD DC21285_IO(0x0360) -#define CSR_TIMER4_VALUE DC21285_IO(0x0364) -#define CSR_TIMER4_CNTL DC21285_IO(0x0368) -#define CSR_TIMER4_CLR DC21285_IO(0x036c) - -#define TIMER_CNTL_ENABLE (1 << 7) -#define TIMER_CNTL_AUTORELOAD (1 << 6) -#define TIMER_CNTL_DIV1 (0) -#define TIMER_CNTL_DIV16 (1 << 2) -#define TIMER_CNTL_DIV256 (2 << 2) -#define TIMER_CNTL_CNTEXT (3 << 2) - - diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/dma.h linux/include/asm-arm/dma.h --- v2.4.0-test8/linux/include/asm-arm/dma.h Sun Sep 3 11:19:11 2000 +++ linux/include/asm-arm/dma.h Mon Sep 18 15:15:23 2000 @@ -22,11 +22,6 @@ #define DMA_MODE_CASCADE 2 #define DMA_AUTOINIT 4 -typedef struct { - unsigned long address; - unsigned long length; -} dmasg_t; - extern spinlock_t dma_spin_lock; extern __inline__ unsigned long claim_dma_lock(void) @@ -85,7 +80,7 @@ * especially since some DMA architectures don't update the * DMA address immediately, but defer it to the enable_dma(). */ -extern void set_dma_sg(dmach_t channel, dmasg_t *sg, int nr_sg); +extern void set_dma_sg(dmach_t channel, struct scatterlist *sg, int nr_sg); /* Set the DMA address for this channel * diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/fcntl.h linux/include/asm-arm/fcntl.h --- v2.4.0-test8/linux/include/asm-arm/fcntl.h Wed Jul 5 11:13:39 2000 +++ linux/include/asm-arm/fcntl.h Fri Sep 22 14:21:19 2000 @@ -51,6 +51,9 @@ #define F_EXLCK 4 /* or 3 */ #define F_SHLCK 8 /* or 4 */ +/* for leases */ +#define F_INPROGRESS 16 + /* operations for bsd flock(), also used by the kernel implementation */ #define LOCK_SH 1 /* shared lock */ #define LOCK_EX 2 /* exclusive lock */ @@ -58,6 +61,11 @@ blocking */ #define LOCK_UN 8 /* remove lock */ +#define LOCK_MAND 32 /* This is a mandatory flock */ +#define LOCK_READ 64 /* ... Which allows concurrent read operations */ +#define LOCK_WRITE 128 /* ... Which allows concurrent write operations */ +#define LOCK_RW 192 /* ... Which allows concurrent read & write ops */ + struct flock { short l_type; short l_whence; @@ -74,4 +82,5 @@ pid_t l_pid; }; +#define F_LINUX_SPECIFIC_BASE 1024 #endif diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/floppy.h linux/include/asm-arm/floppy.h --- v2.4.0-test8/linux/include/asm-arm/floppy.h Mon Jun 26 12:04:42 2000 +++ linux/include/asm-arm/floppy.h Mon Sep 18 15:15:23 2000 @@ -1,9 +1,13 @@ /* - * linux/include/asm-arm/floppy.h + * linux/include/asm-arm/floppy.h * - * (C) 1996-2000 Russell King + * Copyright (C) 1996-2000 Russell King * - * Note that we don't touch FLOPPY_DMA nor FLOPPY_IRQ here + * 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. + * + * Note that we don't touch FLOPPY_DMA nor FLOPPY_IRQ here */ #ifndef __ASM_ARM_FLOPPY_H #define __ASM_ARM_FLOPPY_H diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/hardware/dec21285.h linux/include/asm-arm/hardware/dec21285.h --- v2.4.0-test8/linux/include/asm-arm/hardware/dec21285.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/hardware/dec21285.h Mon Sep 18 15:15:23 2000 @@ -0,0 +1,148 @@ +/* + * linux/include/asm-arm/hardware/dec21285.h + * + * Copyright (C) 1998 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. + * + * DC21285 registers + */ +#define DC21285_PCI_IACK 0x79000000 +#define DC21285_ARMCSR_BASE 0x42000000 +#define DC21285_PCI_TYPE_0_CONFIG 0x7b000000 +#define DC21285_PCI_TYPE_1_CONFIG 0x7a000000 +#define DC21285_OUTBOUND_WRITE_FLUSH 0x78000000 +#define DC21285_FLASH 0x41000000 +#define DC21285_PCI_IO 0x7c000000 +#define DC21285_PCI_MEM 0x80000000 + +#include +#ifndef __ASSEMBLY__ +#include +#define DC21285_IO(x) ((volatile unsigned long *)(ARMCSR_BASE+(x))) +#else +#define DC21285_IO(x) (x) +#endif + +#define CSR_PCICMD DC21285_IO(0x0004) +#define CSR_CLASSREV DC21285_IO(0x0008) +#define CSR_PCICACHELINESIZE DC21285_IO(0x000c) +#define CSR_PCICSRBASE DC21285_IO(0x0010) +#define CSR_PCICSRIOBASE DC21285_IO(0x0014) +#define CSR_PCISDRAMBASE DC21285_IO(0x0018) +#define CSR_PCIROMBASE DC21285_IO(0x0030) +#define CSR_MBOX0 DC21285_IO(0x0050) +#define CSR_MBOX1 DC21285_IO(0x0054) +#define CSR_MBOX2 DC21285_IO(0x0058) +#define CSR_MBOX3 DC21285_IO(0x005c) +#define CSR_DOORBELL DC21285_IO(0x0060) +#define CSR_DOORBELL_SETUP DC21285_IO(0x0064) +#define CSR_ROMWRITEREG DC21285_IO(0x0068) +#define CSR_CSRBASEMASK DC21285_IO(0x00f8) +#define CSR_CSRBASEOFFSET DC21285_IO(0x00fc) +#define CSR_SDRAMBASEMASK DC21285_IO(0x0100) +#define CSR_SDRAMBASEOFFSET DC21285_IO(0x0104) +#define CSR_ROMBASEMASK DC21285_IO(0x0108) +#define CSR_SDRAMTIMING DC21285_IO(0x010c) +#define CSR_SDRAMADDRSIZE0 DC21285_IO(0x0110) +#define CSR_SDRAMADDRSIZE1 DC21285_IO(0x0114) +#define CSR_SDRAMADDRSIZE2 DC21285_IO(0x0118) +#define CSR_SDRAMADDRSIZE3 DC21285_IO(0x011c) +#define CSR_I2O_INFREEHEAD DC21285_IO(0x0120) +#define CSR_I2O_INPOSTTAIL DC21285_IO(0x0124) +#define CSR_I2O_OUTPOSTHEAD DC21285_IO(0x0128) +#define CSR_I2O_OUTFREETAIL DC21285_IO(0x012c) +#define CSR_I2O_INFREECOUNT DC21285_IO(0x0130) +#define CSR_I2O_OUTPOSTCOUNT DC21285_IO(0x0134) +#define CSR_I2O_INPOSTCOUNT DC21285_IO(0x0138) +#define CSR_SA110_CNTL DC21285_IO(0x013c) +#define SA110_CNTL_INITCMPLETE (1 << 0) +#define SA110_CNTL_ASSERTSERR (1 << 1) +#define SA110_CNTL_RXSERR (1 << 3) +#define SA110_CNTL_SA110DRAMPARITY (1 << 4) +#define SA110_CNTL_PCISDRAMPARITY (1 << 5) +#define SA110_CNTL_DMASDRAMPARITY (1 << 6) +#define SA110_CNTL_DISCARDTIMER (1 << 8) +#define SA110_CNTL_PCINRESET (1 << 9) +#define SA110_CNTL_I2O_256 (0 << 10) +#define SA110_CNTL_I20_512 (1 << 10) +#define SA110_CNTL_I2O_1024 (2 << 10) +#define SA110_CNTL_I2O_2048 (3 << 10) +#define SA110_CNTL_I2O_4096 (4 << 10) +#define SA110_CNTL_I2O_8192 (5 << 10) +#define SA110_CNTL_I2O_16384 (6 << 10) +#define SA110_CNTL_I2O_32768 (7 << 10) +#define SA110_CNTL_WATCHDOG (1 << 13) +#define SA110_CNTL_ROMWIDTH_UNDEF (0 << 14) +#define SA110_CNTL_ROMWIDTH_16 (1 << 14) +#define SA110_CNTL_ROMWIDTH_32 (2 << 14) +#define SA110_CNTL_ROMWIDTH_8 (3 << 14) +#define SA110_CNTL_ROMACCESSTIME(x) ((x)<<16) +#define SA110_CNTL_ROMBURSTTIME(x) ((x)<<20) +#define SA110_CNTL_ROMTRISTATETIME(x) ((x)<<24) +#define SA110_CNTL_XCSDIR(x) ((x)<<28) +#define SA110_CNTL_PCICFN (1 << 31) + +/* + * footbridge_cfn_mode() is used when we want + * to check whether we are the central function + */ +#define __footbridge_cfn_mode() (*CSR_SA110_CNTL & SA110_CNTL_PCICFN) +#if defined(CONFIG_FOOTBRIDGE_HOST) && defined(CONFIG_FOOTBRIDGE_ADDIN) +#define footbridge_cfn_mode() __footbridge_cfn_mode() +#elif defined(CONFIG_FOOTBRIDGE_HOST) +#define footbridge_cfn_mode() (1) +#else +#define footbridge_cfn_mode() (0) +#endif + +#define CSR_PCIADDR_EXTN DC21285_IO(0x0140) +#define CSR_PREFETCHMEMRANGE DC21285_IO(0x0144) +#define CSR_XBUS_CYCLE DC21285_IO(0x0148) +#define CSR_XBUS_IOSTROBE DC21285_IO(0x014c) +#define CSR_DOORBELL_PCI DC21285_IO(0x0150) +#define CSR_DOORBELL_SA110 DC21285_IO(0x0154) +#define CSR_UARTDR DC21285_IO(0x0160) +#define CSR_RXSTAT DC21285_IO(0x0164) +#define CSR_H_UBRLCR DC21285_IO(0x0168) +#define CSR_M_UBRLCR DC21285_IO(0x016c) +#define CSR_L_UBRLCR DC21285_IO(0x0170) +#define CSR_UARTCON DC21285_IO(0x0174) +#define CSR_UARTFLG DC21285_IO(0x0178) +#define CSR_IRQ_STATUS DC21285_IO(0x0180) +#define CSR_IRQ_RAWSTATUS DC21285_IO(0x0184) +#define CSR_IRQ_ENABLE DC21285_IO(0x0188) +#define CSR_IRQ_DISABLE DC21285_IO(0x018c) +#define CSR_IRQ_SOFT DC21285_IO(0x0190) +#define CSR_FIQ_STATUS DC21285_IO(0x0280) +#define CSR_FIQ_RAWSTATUS DC21285_IO(0x0284) +#define CSR_FIQ_ENABLE DC21285_IO(0x0288) +#define CSR_FIQ_DISABLE DC21285_IO(0x028c) +#define CSR_FIQ_SOFT DC21285_IO(0x0290) +#define CSR_TIMER1_LOAD DC21285_IO(0x0300) +#define CSR_TIMER1_VALUE DC21285_IO(0x0304) +#define CSR_TIMER1_CNTL DC21285_IO(0x0308) +#define CSR_TIMER1_CLR DC21285_IO(0x030c) +#define CSR_TIMER2_LOAD DC21285_IO(0x0320) +#define CSR_TIMER2_VALUE DC21285_IO(0x0324) +#define CSR_TIMER2_CNTL DC21285_IO(0x0328) +#define CSR_TIMER2_CLR DC21285_IO(0x032c) +#define CSR_TIMER3_LOAD DC21285_IO(0x0340) +#define CSR_TIMER3_VALUE DC21285_IO(0x0344) +#define CSR_TIMER3_CNTL DC21285_IO(0x0348) +#define CSR_TIMER3_CLR DC21285_IO(0x034c) +#define CSR_TIMER4_LOAD DC21285_IO(0x0360) +#define CSR_TIMER4_VALUE DC21285_IO(0x0364) +#define CSR_TIMER4_CNTL DC21285_IO(0x0368) +#define CSR_TIMER4_CLR DC21285_IO(0x036c) + +#define TIMER_CNTL_ENABLE (1 << 7) +#define TIMER_CNTL_AUTORELOAD (1 << 6) +#define TIMER_CNTL_DIV1 (0) +#define TIMER_CNTL_DIV16 (1 << 2) +#define TIMER_CNTL_DIV256 (2 << 2) +#define TIMER_CNTL_CNTEXT (3 << 2) + + diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/hardware/ioc.h linux/include/asm-arm/hardware/ioc.h --- v2.4.0-test8/linux/include/asm-arm/hardware/ioc.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/hardware/ioc.h Mon Sep 18 15:15:23 2000 @@ -0,0 +1,67 @@ +/* + * linux/include/asm-arm/hardware/ioc.h + * + * Copyright (C) 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. + * + * Use these macros to read/write the IOC. All it does is perform the actual + * read/write. + */ + +#ifndef IOC_CONTROL + +#ifndef __ASSEMBLY__ +#define __IOC(offset) (IOC_BASE + (offset >> 2)) +#else +#define __IOC(offset) offset +#endif + +#define IOC_CONTROL __IOC(0x00) +#define IOC_KARTTX __IOC(0x04) +#define IOC_KARTRX __IOC(0x04) + +#define IOC_IRQSTATA __IOC(0x10) +#define IOC_IRQREQA __IOC(0x14) +#define IOC_IRQCLRA __IOC(0x14) +#define IOC_IRQMASKA __IOC(0x18) + +#define IOC_IRQSTATB __IOC(0x20) +#define IOC_IRQREQB __IOC(0x24) +#define IOC_IRQMASKB __IOC(0x28) + +#define IOC_FIQSTAT __IOC(0x30) +#define IOC_FIQREQ __IOC(0x34) +#define IOC_FIQMASK __IOC(0x38) + +#define IOC_T0CNTL __IOC(0x40) +#define IOC_T0LTCHL __IOC(0x40) +#define IOC_T0CNTH __IOC(0x44) +#define IOC_T0LTCHH __IOC(0x44) +#define IOC_T0GO __IOC(0x48) +#define IOC_T0LATCH __IOC(0x4c) + +#define IOC_T1CNTL __IOC(0x50) +#define IOC_T1LTCHL __IOC(0x50) +#define IOC_T1CNTH __IOC(0x54) +#define IOC_T1LTCHH __IOC(0x54) +#define IOC_T1GO __IOC(0x58) +#define IOC_T1LATCH __IOC(0x5c) + +#define IOC_T2CNTL __IOC(0x60) +#define IOC_T2LTCHL __IOC(0x60) +#define IOC_T2CNTH __IOC(0x64) +#define IOC_T2LTCHH __IOC(0x64) +#define IOC_T2GO __IOC(0x68) +#define IOC_T2LATCH __IOC(0x6c) + +#define IOC_T3CNTL __IOC(0x70) +#define IOC_T3LTCHL __IOC(0x70) +#define IOC_T3CNTH __IOC(0x74) +#define IOC_T3LTCHH __IOC(0x74) +#define IOC_T3GO __IOC(0x78) +#define IOC_T3LATCH __IOC(0x7c) + +#endif diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/hardware/iomd.h linux/include/asm-arm/hardware/iomd.h --- v2.4.0-test8/linux/include/asm-arm/hardware/iomd.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/hardware/iomd.h Mon Sep 18 15:15:23 2000 @@ -0,0 +1,249 @@ +/* + * linux/include/asm-arm/iomd.h + * + * Copyright (C) 1999 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. + * + * This file contains information out the IOMD ASIC used in the + * Acorn RiscPC and subsequently integrated into the CLPS7500 chips. + */ +#include + +#ifndef __ASSEMBLY__ +#define __IOMD(offset) (IO_IOMD_BASE + (offset >> 2)) +#else +#define __IOMD(offset) offset +#endif + +#define IOMD_CONTROL __IOMD(0x000) +#define IOMD_KARTTX __IOMD(0x004) +#define IOMD_KARTRX __IOMD(0x004) +#define IOMD_KCTRL __IOMD(0x008) + +#ifdef CONFIG_ARCH_CLPS7500 +#define IOMD_IOLINES __IOMD(0x00C) +#endif + +#define IOMD_IRQSTATA __IOMD(0x010) +#define IOMD_IRQREQA __IOMD(0x014) +#define IOMD_IRQCLRA __IOMD(0x014) +#define IOMD_IRQMASKA __IOMD(0x018) + +#ifdef CONFIG_ARCH_CLPS7500 +#define IOMD_SUSMODE __IOMD(0x01C) +#endif + +#define IOMD_IRQSTATB __IOMD(0x020) +#define IOMD_IRQREQB __IOMD(0x024) +#define IOMD_IRQMASKB __IOMD(0x028) + +#define IOMD_FIQSTAT __IOMD(0x030) +#define IOMD_FIQREQ __IOMD(0x034) +#define IOMD_FIQMASK __IOMD(0x038) + +#ifdef CONFIG_ARCH_CLPS7500 +#define IOMD_CLKCTL __IOMD(0x03C) +#endif + +#define IOMD_T0CNTL __IOMD(0x040) +#define IOMD_T0LTCHL __IOMD(0x040) +#define IOMD_T0CNTH __IOMD(0x044) +#define IOMD_T0LTCHH __IOMD(0x044) +#define IOMD_T0GO __IOMD(0x048) +#define IOMD_T0LATCH __IOMD(0x04c) + +#define IOMD_T1CNTL __IOMD(0x050) +#define IOMD_T1LTCHL __IOMD(0x050) +#define IOMD_T1CNTH __IOMD(0x054) +#define IOMD_T1LTCHH __IOMD(0x054) +#define IOMD_T1GO __IOMD(0x058) +#define IOMD_T1LATCH __IOMD(0x05c) + +#ifdef CONFIG_ARCH_CLPS7500 +#define IOMD_IRQSTATC __IOMD(0x060) +#define IOMD_IRQREQC __IOMD(0x064) +#define IOMD_IRQMASKC __IOMD(0x068) + +#define IOMD_VIDMUX __IOMD(0x06c) + +#define IOMD_IRQSTATD __IOMD(0x070) +#define IOMD_IRQREQD __IOMD(0x074) +#define IOMD_IRQMASKD __IOMD(0x078) +#endif + +#define IOMD_ROMCR0 __IOMD(0x080) +#define IOMD_ROMCR1 __IOMD(0x084) +#ifdef CONFIG_ARCH_RPC +#define IOMD_DRAMCR __IOMD(0x088) +#endif +#define IOMD_REFCR __IOMD(0x08C) + +#define IOMD_FSIZE __IOMD(0x090) +#define IOMD_ID0 __IOMD(0x094) +#define IOMD_ID1 __IOMD(0x098) +#define IOMD_VERSION __IOMD(0x09C) + +#ifdef CONFIG_ARCH_RPC +#define IOMD_MOUSEX __IOMD(0x0A0) +#define IOMD_MOUSEY __IOMD(0x0A4) +#endif + +#ifdef CONFIG_ARCH_CLPS7500 +#define IOMD_MSEDAT __IOMD(0x0A8) +#define IOMD_MSECTL __IOMD(0x0Ac) +#endif + +#ifdef CONFIG_ARCH_RPC +#define IOMD_DMATCR __IOMD(0x0C0) +#endif +#define IOMD_IOTCR __IOMD(0x0C4) +#define IOMD_ECTCR __IOMD(0x0C8) +#ifdef CONFIG_ARCH_RPC +#define IOMD_DMAEXT __IOMD(0x0CC) +#endif +#ifdef CONFIG_ARCH_CLPS7500 +#define IOMD_ASTCR __IOMD(0x0CC) +#define IOMD_DRAMCR __IOMD(0x0D0) +#define IOMD_SELFREF __IOMD(0x0D4) +#define IOMD_ATODICR __IOMD(0x0E0) +#define IOMD_ATODSR __IOMD(0x0E4) +#define IOMD_ATODCC __IOMD(0x0E8) +#define IOMD_ATODCNT1 __IOMD(0x0EC) +#define IOMD_ATODCNT2 __IOMD(0x0F0) +#define IOMD_ATODCNT3 __IOMD(0x0F4) +#define IOMD_ATODCNT4 __IOMD(0x0F8) +#endif + +#ifdef CONFIG_ARCH_RPC +#define DMA_EXT_IO0 1 +#define DMA_EXT_IO1 2 +#define DMA_EXT_IO2 4 +#define DMA_EXT_IO3 8 + +#define IOMD_IO0CURA __IOMD(0x100) +#define IOMD_IO0ENDA __IOMD(0x104) +#define IOMD_IO0CURB __IOMD(0x108) +#define IOMD_IO0ENDB __IOMD(0x10C) +#define IOMD_IO0CR __IOMD(0x110) +#define IOMD_IO0ST __IOMD(0x114) + +#define IOMD_IO1CURA __IOMD(0x120) +#define IOMD_IO1ENDA __IOMD(0x124) +#define IOMD_IO1CURB __IOMD(0x128) +#define IOMD_IO1ENDB __IOMD(0x12C) +#define IOMD_IO1CR __IOMD(0x130) +#define IOMD_IO1ST __IOMD(0x134) + +#define IOMD_IO2CURA __IOMD(0x140) +#define IOMD_IO2ENDA __IOMD(0x144) +#define IOMD_IO2CURB __IOMD(0x148) +#define IOMD_IO2ENDB __IOMD(0x14C) +#define IOMD_IO2CR __IOMD(0x150) +#define IOMD_IO2ST __IOMD(0x154) + +#define IOMD_IO3CURA __IOMD(0x160) +#define IOMD_IO3ENDA __IOMD(0x164) +#define IOMD_IO3CURB __IOMD(0x168) +#define IOMD_IO3ENDB __IOMD(0x16C) +#define IOMD_IO3CR __IOMD(0x170) +#define IOMD_IO3ST __IOMD(0x174) +#endif + +#define IOMD_SD0CURA __IOMD(0x180) +#define IOMD_SD0ENDA __IOMD(0x184) +#define IOMD_SD0CURB __IOMD(0x188) +#define IOMD_SD0ENDB __IOMD(0x18C) +#define IOMD_SD0CR __IOMD(0x190) +#define IOMD_SD0ST __IOMD(0x194) + +#ifdef CONFIG_ARCH_RPC +#define IOMD_SD1CURA __IOMD(0x1A0) +#define IOMD_SD1ENDA __IOMD(0x1A4) +#define IOMD_SD1CURB __IOMD(0x1A8) +#define IOMD_SD1ENDB __IOMD(0x1AC) +#define IOMD_SD1CR __IOMD(0x1B0) +#define IOMD_SD1ST __IOMD(0x1B4) +#endif + +#define IOMD_CURSCUR __IOMD(0x1C0) +#define IOMD_CURSINIT __IOMD(0x1C4) + +#define IOMD_VIDCUR __IOMD(0x1D0) +#define IOMD_VIDEND __IOMD(0x1D4) +#define IOMD_VIDSTART __IOMD(0x1D8) +#define IOMD_VIDINIT __IOMD(0x1DC) +#define IOMD_VIDCR __IOMD(0x1E0) + +#define IOMD_DMASTAT __IOMD(0x1F0) +#define IOMD_DMAREQ __IOMD(0x1F4) +#define IOMD_DMAMASK __IOMD(0x1F8) + +#define DMA_END_S (1 << 31) +#define DMA_END_L (1 << 30) + +#define DMA_CR_C 0x80 +#define DMA_CR_D 0x40 +#define DMA_CR_E 0x20 + +#define DMA_ST_OFL 4 +#define DMA_ST_INT 2 +#define DMA_ST_AB 1 + +#ifndef IOC_CONTROL +/* + * IOC compatability + */ +#define IOC_CONTROL IOMD_CONTROL +#define IOC_IRQSTATA IOMD_IRQSTATA +#define IOC_IRQREQA IOMD_IRQREQA +#define IOC_IRQCLRA IOMD_IRQCLRA +#define IOC_IRQMASKA IOMD_IRQMASKA + +#define IOC_IRQSTATB IOMD_IRQSTATB +#define IOC_IRQREQB IOMD_IRQREQB +#define IOC_IRQMASKB IOMD_IRQMASKB + +#define IOC_FIQSTAT IOMD_FIQSTAT +#define IOC_FIQREQ IOMD_FIQREQ +#define IOC_FIQMASK IOMD_FIQMASK + +#define IOC_T0CNTL IOMD_T0CNTL +#define IOC_T0LTCHL IOMD_T0LTCHL +#define IOC_T0CNTH IOMD_T0CNTH +#define IOC_T0LTCHH IOMD_T0LTCHH +#define IOC_T0GO IOMD_T0GO +#define IOC_T0LATCH IOMD_T0LATCH + +#define IOC_T1CNTL IOMD_T1CNTL +#define IOC_T1LTCHL IOMD_T1LTCHL +#define IOC_T1CNTH IOMD_T1CNTH +#define IOC_T1LTCHH IOMD_T1LTCHH +#define IOC_T1GO IOMD_T1GO +#define IOC_T1LATCH IOMD_T1LATCH +#endif + +/* + * DMA (MEMC) compatability + */ +#define HALF_SAM vram_half_sam +#define VDMA_ALIGNMENT (HALF_SAM * 2) +#define VDMA_XFERSIZE (HALF_SAM) +#define VDMA_INIT IOMD_VIDINIT +#define VDMA_START IOMD_VIDSTART +#define VDMA_END IOMD_VIDEND + +#ifndef __ASSEMBLY__ +extern unsigned int vram_half_sam; +#define video_set_dma(start,end,offset) \ +do { \ + outl (SCREEN_START + start, VDMA_START); \ + outl (SCREEN_START + end - VDMA_XFERSIZE, VDMA_END); \ + if (offset >= end - VDMA_XFERSIZE) \ + offset |= 0x40000000; \ + outl (SCREEN_START + offset, VDMA_INIT); \ +} while (0) +#endif + diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/hardware/memc.h linux/include/asm-arm/hardware/memc.h --- v2.4.0-test8/linux/include/asm-arm/hardware/memc.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/hardware/memc.h Mon Sep 18 15:15:23 2000 @@ -0,0 +1,26 @@ +/* + * linux/include/asm-arm/hardware/memc.h + * + * Copyright (C) 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. + */ +#define VDMA_ALIGNMENT PAGE_SIZE +#define VDMA_XFERSIZE 16 +#define VDMA_INIT 0 +#define VDMA_START 1 +#define VDMA_END 2 + +#ifndef __ASSEMBLY__ +extern void memc_write(unsigned int reg, unsigned long val); + +#define video_set_dma(start,end,offset) \ +do { \ + memc_write (VDMA_START, (start >> 2)); \ + memc_write (VDMA_END, (end - VDMA_XFERSIZE) >> 2); \ + memc_write (VDMA_INIT, (offset >> 2)); \ +} while (0) + +#endif diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/hardware/pci_v3.h linux/include/asm-arm/hardware/pci_v3.h --- v2.4.0-test8/linux/include/asm-arm/hardware/pci_v3.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/hardware/pci_v3.h Mon Sep 18 15:15:23 2000 @@ -0,0 +1,148 @@ +/* + * linux/include/asm-arm/hardware/pci_v3.h + * + * Internal header file PCI V3 chip + * + * Copyright (C) ARM Limited + * Copyright (C) 2000 Deep Blue Solutions Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef ASM_ARM_HARDWARE_PCI_V3_H +#define ASM_ARM_HARDWARE_PCI_V3_H + +/* ------------------------------------------------------------------------------- + * V3 Local Bus to PCI Bridge definitions + * ------------------------------------------------------------------------------- + * Registers (these are taken from page 129 of the EPC User's Manual Rev 1.04 + * All V3 register names are prefaced by V3_ to avoid clashing with any other + * PCI definitions. Their names match the user's manual. + * + * I'm assuming that I20 is disabled. + * + */ +#define V3_PCI_VENDOR 0x00000000 +#define V3_PCI_DEVICE 0x00000002 +#define V3_PCI_CMD 0x00000004 +#define V3_PCI_STAT 0x00000006 +#define V3_PCI_CC_REV 0x00000008 +#define V3_PCI_HDR_CFG 0x0000000C +#define V3_PCI_IO_BASE 0x00000010 +#define V3_PCI_BASE0 0x00000014 +#define V3_PCI_BASE1 0x00000018 +#define V3_PCI_SUB_VENDOR 0x0000002C +#define V3_PCI_SUB_ID 0x0000002E +#define V3_PCI_ROM 0x00000030 +#define V3_PCI_BPARAM 0x0000003C +#define V3_PCI_MAP0 0x00000040 +#define V3_PCI_MAP1 0x00000044 +#define V3_PCI_INT_STAT 0x00000048 +#define V3_PCI_INT_CFG 0x0000004C +#define V3_LB_BASE0 0x00000054 +#define V3_LB_BASE1 0x00000058 +#define V3_LB_MAP0 0x0000005E +#define V3_LB_MAP1 0x00000062 +#define V3_LB_BASE2 0x00000064 +#define V3_LB_MAP2 0x00000066 +#define V3_LB_SIZE 0x00000068 +#define V3_LB_IO_BASE 0x0000006E +#define V3_FIFO_CFG 0x00000070 +#define V3_FIFO_PRIORITY 0x00000072 +#define V3_FIFO_STAT 0x00000074 +#define V3_LB_ISTAT 0x00000076 +#define V3_LB_IMASK 0x00000077 +#define V3_SYSTEM 0x00000078 +#define V3_LB_CFG 0x0000007A +#define V3_PCI_CFG 0x0000007C +#define V3_DMA_PCI_ADR0 0x00000080 +#define V3_DMA_PCI_ADR1 0x00000090 +#define V3_DMA_LOCAL_ADR0 0x00000084 +#define V3_DMA_LOCAL_ADR1 0x00000094 +#define V3_DMA_LENGTH0 0x00000088 +#define V3_DMA_LENGTH1 0x00000098 +#define V3_DMA_CSR0 0x0000008B +#define V3_DMA_CSR1 0x0000009B +#define V3_DMA_CTLB_ADR0 0x0000008C +#define V3_DMA_CTLB_ADR1 0x0000009C +#define V3_DMA_DELAY 0x000000E0 +#define V3_MAIL_DATA 0x000000C0 +#define V3_PCI_MAIL_IEWR 0x000000D0 +#define V3_PCI_MAIL_IERD 0x000000D2 +#define V3_LB_MAIL_IEWR 0x000000D4 +#define V3_LB_MAIL_IERD 0x000000D6 +#define V3_MAIL_WR_STAT 0x000000D8 +#define V3_MAIL_RD_STAT 0x000000DA +#define V3_QBA_MAP 0x000000DC + +/* PCI COMMAND REGISTER bits + */ +#define V3_COMMAND_M_FBB_EN BIT9 +#define V3_COMMAND_M_SERR_EN BIT8 +#define V3_COMMAND_M_PAR_EN BIT6 +#define V3_COMMAND_M_MASTER_EN BIT2 +#define V3_COMMAND_M_MEM_EN BIT1 +#define V3_COMMAND_M_IO_EN BIT0 + +/* SYSTEM REGISTER bits + */ +#define V3_SYSTEM_M_RST_OUT BIT15 +#define V3_SYSTEM_M_LOCK BIT14 + +/* PCI_CFG bits + */ +#define V3_PCI_CFG_M_RETRY_EN BIT10 +#define V3_PCI_CFG_M_AD_LOW1 BIT9 +#define V3_PCI_CFG_M_AD_LOW0 BIT8 + +/* PCI_BASE register bits (PCI -> Local Bus) + */ +#define V3_PCI_BASE_M_ADR_BASE 0xFFF00000 +#define V3_PCI_BASE_M_ADR_BASEL 0x000FFF00 +#define V3_PCI_BASE_M_PREFETCH BIT3 +#define V3_PCI_BASE_M_TYPE BIT2+BIT1 +#define V3_PCI_BASE_M_IO BIT0 + +/* PCI MAP register bits (PCI -> Local bus) + */ +#define V3_PCI_MAP_M_MAP_ADR 0xFFF00000 +#define V3_PCI_MAP_M_RD_POST_INH BIT15 +#define V3_PCI_MAP_M_ROM_SIZE BIT11+BIT10 +#define V3_PCI_MAP_M_SWAP BIT9+BIT8 +#define V3_PCI_MAP_M_ADR_SIZE 0x000000F0 +#define V3_PCI_MAP_M_REG_EN BIT1 +#define V3_PCI_MAP_M_ENABLE BIT0 + +/* 9 => 512M window size + */ +#define V3_PCI_MAP_M_ADR_SIZE_512M 0x00000090 +/* A => 1024M window size + */ +#define V3_PCI_MAP_M_ADR_SIZE_1024M 0x000000A0 + +/* LB_BASE register bits (Local bus -> PCI) + */ +#define V3_LB_BASE_M_MAP_ADR 0xFFF00000 +#define V3_LB_BASE_M_SWAP BIT9+BIT8 +#define V3_LB_BASE_M_ADR_SIZE 0x000000F0 +#define V3_LB_BASE_M_PREFETCH BIT3 +#define V3_LB_BASE_M_ENABLE BIT0 + +/* LB_MAP register bits (Local bus -> PCI) + */ +#define V3_LB_MAP_M_MAP_ADR 0xFFF0 +#define V3_LB_MAP_M_TYPE 0x000E +#define V3_LB_MAP_M_AD_LOW_EN BIT0 + +#endif diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/hardware/serial_amba.h linux/include/asm-arm/hardware/serial_amba.h --- v2.4.0-test8/linux/include/asm-arm/hardware/serial_amba.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-arm/hardware/serial_amba.h Mon Sep 18 15:15:23 2000 @@ -0,0 +1,91 @@ +/* + * linux/include/asm-arm/hardware/serial_amba.h + * + * Internal header file for AMBA serial ports + * + * Copyright (C) ARM Limited + * Copyright (C) 2000 Deep Blue Solutions Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef ASM_ARM_HARDWARE_SERIAL_AMBA_H +#define ASM_ARM_HARDWARE_SERIAL_AMBA_H + +/* ------------------------------------------------------------------------------- + * From AMBA UART (PL010) Block Specification (ARM-0001-CUST-DSPC-A03) + * ------------------------------------------------------------------------------- + * UART Register Offsets. + */ +#define AMBA_UARTDR 0x00 /* Data read or written from the interface. */ +#define AMBA_UARTRSR 0x04 /* Receive status register (Read). */ +#define AMBA_UARTECR 0x04 /* Error clear register (Write). */ +#define AMBA_UARTLCR_H 0x08 /* Line control register, high byte. */ +#define AMBA_UARTLCR_M 0x0C /* Line control register, middle byte. */ +#define AMBA_UARTLCR_L 0x10 /* Line control register, low byte. */ +#define AMBA_UARTCR 0x14 /* Control register. */ +#define AMBA_UARTFR 0x18 /* Flag register (Read only). */ +#define AMBA_UARTIIR 0x1C /* Interrupt indentification register (Read). */ +#define AMBA_UARTICR 0x1C /* Interrupt clear register (Write). */ +#define AMBA_UARTILPR 0x20 /* IrDA low power counter register. */ + +#define AMBA_UARTRSR_OE 0x08 +#define AMBA_UARTRSR_BE 0x04 +#define AMBA_UARTRSR_PE 0x02 +#define AMBA_UARTRSR_FE 0x01 + +#define AMBA_UARTFR_TXFF 0x20 +#define AMBA_UARTFR_RXFE 0x10 +#define AMBA_UARTFR_BUSY 0x08 +#define AMBA_UARTFR_DCD 0x04 +#define AMBA_UARTFR_DSR 0x02 +#define AMBA_UARTFR_CTS 0x01 +#define AMBA_UARTFR_TMSK (AMBA_UARTFR_TXFF + AMBA_UARTFR_BUSY) + +#define AMBA_UARTCR_RTIE 0x40 +#define AMBA_UARTCR_TIE 0x20 +#define AMBA_UARTCR_RIE 0x10 +#define AMBA_UARTCR_MSIE 0x08 +#define AMBA_UARTCR_IIRLP 0x04 +#define AMBA_UARTCR_SIREN 0x02 +#define AMBA_UARTCR_UARTEN 0x01 + +#define AMBA_UARTLCR_H_WLEN_8 0x60 +#define AMBA_UARTLCR_H_WLEN_7 0x40 +#define AMBA_UARTLCR_H_WLEN_6 0x20 +#define AMBA_UARTLCR_H_WLEN_5 0x00 +#define AMBA_UARTLCR_H_FEN 0x10 +#define AMBA_UARTLCR_H_STP2 0x08 +#define AMBA_UARTLCR_H_EPS 0x04 +#define AMBA_UARTLCR_H_PEN 0x02 +#define AMBA_UARTLCR_H_BRK 0x01 + +#define AMBA_UARTIIR_RTIS 0x08 +#define AMBA_UARTIIR_TIS 0x04 +#define AMBA_UARTIIR_RIS 0x02 +#define AMBA_UARTIIR_MIS 0x01 + +#define ARM_BAUD_460800 1 +#define ARM_BAUD_230400 3 +#define ARM_BAUD_115200 7 +#define ARM_BAUD_57600 15 +#define ARM_BAUD_38400 23 +#define ARM_BAUD_19200 47 +#define ARM_BAUD_14400 63 +#define ARM_BAUD_9600 95 +#define ARM_BAUD_4800 191 +#define ARM_BAUD_2400 383 +#define ARM_BAUD_1200 767 + +#endif diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/hardware.h linux/include/asm-arm/hardware.h --- v2.4.0-test8/linux/include/asm-arm/hardware.h Sun Aug 13 09:54:15 2000 +++ linux/include/asm-arm/hardware.h Mon Sep 18 15:15:23 2000 @@ -1,9 +1,13 @@ /* - * linux/include/asm-arm/hardware.h + * linux/include/asm-arm/hardware.h * - * Copyright (C) 1996 Russell King + * Copyright (C) 1996 Russell King * - * Common hardware definitions + * 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. + * + * Common hardware definitions */ #ifndef __ASM_HARDWARE_H diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/io.h linux/include/asm-arm/io.h --- v2.4.0-test8/linux/include/asm-arm/io.h Mon Jun 26 12:04:42 2000 +++ linux/include/asm-arm/io.h Mon Sep 18 15:15:23 2000 @@ -1,7 +1,11 @@ /* - * linux/include/asm-arm/io.h + * linux/include/asm-arm/io.h * - * Copyright (C) 1996-2000 Russell King + * Copyright (C) 1996-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. * * Modifications: * 16-Sep-1996 RMK Inlined the inx/outx functions & optimised for both @@ -19,7 +23,6 @@ #include #include #include -#include #define outb_p(val,port) outb((val),(port)) #define outw_p(val,port) outw((val),(port)) diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/ioc.h linux/include/asm-arm/ioc.h --- v2.4.0-test8/linux/include/asm-arm/ioc.h Wed Oct 20 16:29:08 1999 +++ linux/include/asm-arm/ioc.h Wed Dec 31 16:00:00 1969 @@ -1,59 +0,0 @@ -/* - * Use these macros to read/write the IOC. All it does is perform the actual - * read/write. - */ - -#ifndef IOC_CONTROL - -#ifndef __ASSEMBLY__ -#define __IOC(offset) (IOC_BASE + (offset >> 2)) -#else -#define __IOC(offset) offset -#endif - -#define IOC_CONTROL __IOC(0x00) -#define IOC_KARTTX __IOC(0x04) -#define IOC_KARTRX __IOC(0x04) - -#define IOC_IRQSTATA __IOC(0x10) -#define IOC_IRQREQA __IOC(0x14) -#define IOC_IRQCLRA __IOC(0x14) -#define IOC_IRQMASKA __IOC(0x18) - -#define IOC_IRQSTATB __IOC(0x20) -#define IOC_IRQREQB __IOC(0x24) -#define IOC_IRQMASKB __IOC(0x28) - -#define IOC_FIQSTAT __IOC(0x30) -#define IOC_FIQREQ __IOC(0x34) -#define IOC_FIQMASK __IOC(0x38) - -#define IOC_T0CNTL __IOC(0x40) -#define IOC_T0LTCHL __IOC(0x40) -#define IOC_T0CNTH __IOC(0x44) -#define IOC_T0LTCHH __IOC(0x44) -#define IOC_T0GO __IOC(0x48) -#define IOC_T0LATCH __IOC(0x4c) - -#define IOC_T1CNTL __IOC(0x50) -#define IOC_T1LTCHL __IOC(0x50) -#define IOC_T1CNTH __IOC(0x54) -#define IOC_T1LTCHH __IOC(0x54) -#define IOC_T1GO __IOC(0x58) -#define IOC_T1LATCH __IOC(0x5c) - -#define IOC_T2CNTL __IOC(0x60) -#define IOC_T2LTCHL __IOC(0x60) -#define IOC_T2CNTH __IOC(0x64) -#define IOC_T2LTCHH __IOC(0x64) -#define IOC_T2GO __IOC(0x68) -#define IOC_T2LATCH __IOC(0x6c) - -#define IOC_T3CNTL __IOC(0x70) -#define IOC_T3LTCHL __IOC(0x70) -#define IOC_T3CNTH __IOC(0x74) -#define IOC_T3LTCHH __IOC(0x74) -#define IOC_T3GO __IOC(0x78) -#define IOC_T3LATCH __IOC(0x7c) - -#endif diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/iomd.h linux/include/asm-arm/iomd.h --- v2.4.0-test8/linux/include/asm-arm/iomd.h Fri May 12 11:21:20 2000 +++ linux/include/asm-arm/iomd.h Wed Dec 31 16:00:00 1969 @@ -1,245 +0,0 @@ -/* - * linux/include/asm-arm/iomd.h - * - * Copyright (C) 1999 Russell King - * - * This file contains information out the IOMD ASIC used in the - * Acorn RiscPC and subsequently integrated into the CLPS7500 chips. - */ -#include - -#ifndef __ASSEMBLY__ -#define __IOMD(offset) (IO_IOMD_BASE + (offset >> 2)) -#else -#define __IOMD(offset) offset -#endif - -#define IOMD_CONTROL __IOMD(0x000) -#define IOMD_KARTTX __IOMD(0x004) -#define IOMD_KARTRX __IOMD(0x004) -#define IOMD_KCTRL __IOMD(0x008) - -#ifdef CONFIG_ARCH_CLPS7500 -#define IOMD_IOLINES __IOMD(0x00C) -#endif - -#define IOMD_IRQSTATA __IOMD(0x010) -#define IOMD_IRQREQA __IOMD(0x014) -#define IOMD_IRQCLRA __IOMD(0x014) -#define IOMD_IRQMASKA __IOMD(0x018) - -#ifdef CONFIG_ARCH_CLPS7500 -#define IOMD_SUSMODE __IOMD(0x01C) -#endif - -#define IOMD_IRQSTATB __IOMD(0x020) -#define IOMD_IRQREQB __IOMD(0x024) -#define IOMD_IRQMASKB __IOMD(0x028) - -#define IOMD_FIQSTAT __IOMD(0x030) -#define IOMD_FIQREQ __IOMD(0x034) -#define IOMD_FIQMASK __IOMD(0x038) - -#ifdef CONFIG_ARCH_CLPS7500 -#define IOMD_CLKCTL __IOMD(0x03C) -#endif - -#define IOMD_T0CNTL __IOMD(0x040) -#define IOMD_T0LTCHL __IOMD(0x040) -#define IOMD_T0CNTH __IOMD(0x044) -#define IOMD_T0LTCHH __IOMD(0x044) -#define IOMD_T0GO __IOMD(0x048) -#define IOMD_T0LATCH __IOMD(0x04c) - -#define IOMD_T1CNTL __IOMD(0x050) -#define IOMD_T1LTCHL __IOMD(0x050) -#define IOMD_T1CNTH __IOMD(0x054) -#define IOMD_T1LTCHH __IOMD(0x054) -#define IOMD_T1GO __IOMD(0x058) -#define IOMD_T1LATCH __IOMD(0x05c) - -#ifdef CONFIG_ARCH_CLPS7500 -#define IOMD_IRQSTATC __IOMD(0x060) -#define IOMD_IRQREQC __IOMD(0x064) -#define IOMD_IRQMASKC __IOMD(0x068) - -#define IOMD_VIDMUX __IOMD(0x06c) - -#define IOMD_IRQSTATD __IOMD(0x070) -#define IOMD_IRQREQD __IOMD(0x074) -#define IOMD_IRQMASKD __IOMD(0x078) -#endif - -#define IOMD_ROMCR0 __IOMD(0x080) -#define IOMD_ROMCR1 __IOMD(0x084) -#ifdef CONFIG_ARCH_RPC -#define IOMD_DRAMCR __IOMD(0x088) -#endif -#define IOMD_REFCR __IOMD(0x08C) - -#define IOMD_FSIZE __IOMD(0x090) -#define IOMD_ID0 __IOMD(0x094) -#define IOMD_ID1 __IOMD(0x098) -#define IOMD_VERSION __IOMD(0x09C) - -#ifdef CONFIG_ARCH_RPC -#define IOMD_MOUSEX __IOMD(0x0A0) -#define IOMD_MOUSEY __IOMD(0x0A4) -#endif - -#ifdef CONFIG_ARCH_CLPS7500 -#define IOMD_MSEDAT __IOMD(0x0A8) -#define IOMD_MSECTL __IOMD(0x0Ac) -#endif - -#ifdef CONFIG_ARCH_RPC -#define IOMD_DMATCR __IOMD(0x0C0) -#endif -#define IOMD_IOTCR __IOMD(0x0C4) -#define IOMD_ECTCR __IOMD(0x0C8) -#ifdef CONFIG_ARCH_RPC -#define IOMD_DMAEXT __IOMD(0x0CC) -#endif -#ifdef CONFIG_ARCH_CLPS7500 -#define IOMD_ASTCR __IOMD(0x0CC) -#define IOMD_DRAMCR __IOMD(0x0D0) -#define IOMD_SELFREF __IOMD(0x0D4) -#define IOMD_ATODICR __IOMD(0x0E0) -#define IOMD_ATODSR __IOMD(0x0E4) -#define IOMD_ATODCC __IOMD(0x0E8) -#define IOMD_ATODCNT1 __IOMD(0x0EC) -#define IOMD_ATODCNT2 __IOMD(0x0F0) -#define IOMD_ATODCNT3 __IOMD(0x0F4) -#define IOMD_ATODCNT4 __IOMD(0x0F8) -#endif - -#ifdef CONFIG_ARCH_RPC -#define DMA_EXT_IO0 1 -#define DMA_EXT_IO1 2 -#define DMA_EXT_IO2 4 -#define DMA_EXT_IO3 8 - -#define IOMD_IO0CURA __IOMD(0x100) -#define IOMD_IO0ENDA __IOMD(0x104) -#define IOMD_IO0CURB __IOMD(0x108) -#define IOMD_IO0ENDB __IOMD(0x10C) -#define IOMD_IO0CR __IOMD(0x110) -#define IOMD_IO0ST __IOMD(0x114) - -#define IOMD_IO1CURA __IOMD(0x120) -#define IOMD_IO1ENDA __IOMD(0x124) -#define IOMD_IO1CURB __IOMD(0x128) -#define IOMD_IO1ENDB __IOMD(0x12C) -#define IOMD_IO1CR __IOMD(0x130) -#define IOMD_IO1ST __IOMD(0x134) - -#define IOMD_IO2CURA __IOMD(0x140) -#define IOMD_IO2ENDA __IOMD(0x144) -#define IOMD_IO2CURB __IOMD(0x148) -#define IOMD_IO2ENDB __IOMD(0x14C) -#define IOMD_IO2CR __IOMD(0x150) -#define IOMD_IO2ST __IOMD(0x154) - -#define IOMD_IO3CURA __IOMD(0x160) -#define IOMD_IO3ENDA __IOMD(0x164) -#define IOMD_IO3CURB __IOMD(0x168) -#define IOMD_IO3ENDB __IOMD(0x16C) -#define IOMD_IO3CR __IOMD(0x170) -#define IOMD_IO3ST __IOMD(0x174) -#endif - -#define IOMD_SD0CURA __IOMD(0x180) -#define IOMD_SD0ENDA __IOMD(0x184) -#define IOMD_SD0CURB __IOMD(0x188) -#define IOMD_SD0ENDB __IOMD(0x18C) -#define IOMD_SD0CR __IOMD(0x190) -#define IOMD_SD0ST __IOMD(0x194) - -#ifdef CONFIG_ARCH_RPC -#define IOMD_SD1CURA __IOMD(0x1A0) -#define IOMD_SD1ENDA __IOMD(0x1A4) -#define IOMD_SD1CURB __IOMD(0x1A8) -#define IOMD_SD1ENDB __IOMD(0x1AC) -#define IOMD_SD1CR __IOMD(0x1B0) -#define IOMD_SD1ST __IOMD(0x1B4) -#endif - -#define IOMD_CURSCUR __IOMD(0x1C0) -#define IOMD_CURSINIT __IOMD(0x1C4) - -#define IOMD_VIDCUR __IOMD(0x1D0) -#define IOMD_VIDEND __IOMD(0x1D4) -#define IOMD_VIDSTART __IOMD(0x1D8) -#define IOMD_VIDINIT __IOMD(0x1DC) -#define IOMD_VIDCR __IOMD(0x1E0) - -#define IOMD_DMASTAT __IOMD(0x1F0) -#define IOMD_DMAREQ __IOMD(0x1F4) -#define IOMD_DMAMASK __IOMD(0x1F8) - -#define DMA_END_S (1 << 31) -#define DMA_END_L (1 << 30) - -#define DMA_CR_C 0x80 -#define DMA_CR_D 0x40 -#define DMA_CR_E 0x20 - -#define DMA_ST_OFL 4 -#define DMA_ST_INT 2 -#define DMA_ST_AB 1 - -#ifndef IOC_CONTROL -/* - * IOC compatability - */ -#define IOC_CONTROL IOMD_CONTROL -#define IOC_IRQSTATA IOMD_IRQSTATA -#define IOC_IRQREQA IOMD_IRQREQA -#define IOC_IRQCLRA IOMD_IRQCLRA -#define IOC_IRQMASKA IOMD_IRQMASKA - -#define IOC_IRQSTATB IOMD_IRQSTATB -#define IOC_IRQREQB IOMD_IRQREQB -#define IOC_IRQMASKB IOMD_IRQMASKB - -#define IOC_FIQSTAT IOMD_FIQSTAT -#define IOC_FIQREQ IOMD_FIQREQ -#define IOC_FIQMASK IOMD_FIQMASK - -#define IOC_T0CNTL IOMD_T0CNTL -#define IOC_T0LTCHL IOMD_T0LTCHL -#define IOC_T0CNTH IOMD_T0CNTH -#define IOC_T0LTCHH IOMD_T0LTCHH -#define IOC_T0GO IOMD_T0GO -#define IOC_T0LATCH IOMD_T0LATCH - -#define IOC_T1CNTL IOMD_T1CNTL -#define IOC_T1LTCHL IOMD_T1LTCHL -#define IOC_T1CNTH IOMD_T1CNTH -#define IOC_T1LTCHH IOMD_T1LTCHH -#define IOC_T1GO IOMD_T1GO -#define IOC_T1LATCH IOMD_T1LATCH -#endif - -/* - * DMA (MEMC) compatability - */ -#define HALF_SAM vram_half_sam -#define VDMA_ALIGNMENT (HALF_SAM * 2) -#define VDMA_XFERSIZE (HALF_SAM) -#define VDMA_INIT IOMD_VIDINIT -#define VDMA_START IOMD_VIDSTART -#define VDMA_END IOMD_VIDEND - -#ifndef __ASSEMBLY__ -extern unsigned int vram_half_sam; -#define video_set_dma(start,end,offset) \ -do { \ - outl (SCREEN_START + start, VDMA_START); \ - outl (SCREEN_START + end - VDMA_XFERSIZE, VDMA_END); \ - if (offset >= end - VDMA_XFERSIZE) \ - offset |= 0x40000000; \ - outl (SCREEN_START + offset, VDMA_INIT); \ -} while (0) -#endif - diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/keyboard.h linux/include/asm-arm/keyboard.h --- v2.4.0-test8/linux/include/asm-arm/keyboard.h Thu Dec 17 09:05:43 1998 +++ linux/include/asm-arm/keyboard.h Mon Sep 18 15:15:23 2000 @@ -1,9 +1,13 @@ /* - * linux/include/asm-arm/keyboard.h + * linux/include/asm-arm/keyboard.h * - * Keyboard driver definitions for ARM + * Copyright (C) 1998 Russell King * - * (C) 1998 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. + * + * Keyboard driver definitions for ARM */ #ifndef __ASM_ARM_KEYBOARD_H #define __ASM_ARM_KEYBOARD_H diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/leds.h linux/include/asm-arm/leds.h --- v2.4.0-test8/linux/include/asm-arm/leds.h Sun Aug 13 09:54:15 2000 +++ linux/include/asm-arm/leds.h Mon Sep 18 15:15:23 2000 @@ -1,11 +1,14 @@ /* - * include/asm-arm/leds.h + * linux/include/asm-arm/leds.h * - * Copyright (C) 1998 Russell King + * Copyright (C) 1998 Russell King * - * Event-driven interface for LEDs on machines + * 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. * - * Added led_start and led_stop- Alex Holden, 28th Dec 1998. + * Event-driven interface for LEDs on machines + * Added led_start and led_stop- Alex Holden, 28th Dec 1998. */ #ifndef ASM_ARM_LEDS_H #define ASM_ARM_LEDS_H diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/linux_logo.h linux/include/asm-arm/linux_logo.h --- v2.4.0-test8/linux/include/asm-arm/linux_logo.h Thu Dec 17 09:05:43 1998 +++ linux/include/asm-arm/linux_logo.h Mon Sep 18 15:15:23 2000 @@ -1,9 +1,13 @@ /* - * linux/include/asm-arm/linux_logo.h + * linux/include/asm-arm/linux_logo.h * - * Copyright (C) 1998 Russell King + * Copyright (C) 1998 Russell King * - * Linux console driver logo definitions for ARM + * 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. + * + * Linux console driver logo definitions for ARM */ #include diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/mach/arch.h linux/include/asm-arm/mach/arch.h --- v2.4.0-test8/linux/include/asm-arm/mach/arch.h Sun Sep 3 11:19:11 2000 +++ linux/include/asm-arm/mach/arch.h Mon Sep 18 15:15:23 2000 @@ -1,7 +1,11 @@ /* - * linux/include/asm-arm/mach/arch.h + * linux/include/asm-arm/mach/arch.h * - * Copyright (C) 2000 Russell King + * Copyright (C) 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. */ /* diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/mach/dma.h linux/include/asm-arm/mach/dma.h --- v2.4.0-test8/linux/include/asm-arm/mach/dma.h Sun Sep 3 11:19:11 2000 +++ linux/include/asm-arm/mach/dma.h Mon Sep 18 15:15:23 2000 @@ -1,10 +1,14 @@ /* - * linux/arch/arm/kernel/dma.h + * linux/include/asm-arm/mach/dma.h * - * Copyright (C) 1998-2000 Russell King + * Copyright (C) 1998-2000 Russell King * - * This header file describes the interface between the generic DMA handler - * (dma.c) and the architecture-specific DMA backends (dma-*.c) + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This header file describes the interface between the generic DMA handler + * (dma.c) and the architecture-specific DMA backends (dma-*.c) */ struct dma_struct; @@ -46,4 +50,6 @@ * Purpose : Initialise architecture specific DMA * Params : dma - pointer to array of DMA structures */ -void arch_dma_init(dma_t *dma); +extern void arch_dma_init(dma_t *dma); + +extern void isa_init_dma(dma_t *dma); diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/mach/map.h linux/include/asm-arm/mach/map.h --- v2.4.0-test8/linux/include/asm-arm/mach/map.h Sun Sep 3 11:19:11 2000 +++ linux/include/asm-arm/mach/map.h Mon Sep 18 15:15:23 2000 @@ -3,6 +3,10 @@ * * Copyright (C) 1999-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. + * * Page table mapping constructs and function prototypes */ struct map_desc { diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/mach/pci.h linux/include/asm-arm/mach/pci.h --- v2.4.0-test8/linux/include/asm-arm/mach/pci.h Sun Sep 3 11:19:11 2000 +++ linux/include/asm-arm/mach/pci.h Mon Sep 18 15:15:23 2000 @@ -1,5 +1,11 @@ /* - * linux/include/asm-arm/mach/pci.h + * linux/include/asm-arm/mach/pci.h + * + * Copyright (C) 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. */ #define MAX_NR_BUS 2 diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/memc.h linux/include/asm-arm/memc.h --- v2.4.0-test8/linux/include/asm-arm/memc.h Wed Oct 20 16:29:08 1999 +++ linux/include/asm-arm/memc.h Wed Dec 31 16:00:00 1969 @@ -1,17 +0,0 @@ -#define VDMA_ALIGNMENT PAGE_SIZE -#define VDMA_XFERSIZE 16 -#define VDMA_INIT 0 -#define VDMA_START 1 -#define VDMA_END 2 - -#ifndef __ASSEMBLY__ -extern void memc_write(unsigned int reg, unsigned long val); - -#define video_set_dma(start,end,offset) \ -do { \ - memc_write (VDMA_START, (start >> 2)); \ - memc_write (VDMA_END, (end - VDMA_XFERSIZE) >> 2); \ - memc_write (VDMA_INIT, (offset >> 2)); \ -} while (0) - -#endif diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/memory.h linux/include/asm-arm/memory.h --- v2.4.0-test8/linux/include/asm-arm/memory.h Mon Jun 26 12:04:42 2000 +++ linux/include/asm-arm/memory.h Mon Sep 18 15:15:24 2000 @@ -1,11 +1,15 @@ /* - * linux/include/asm-arm/memory.h + * linux/include/asm-arm/memory.h * - * Copyright (C) 2000 Russell King + * Copyright (C) 2000 Russell King * - * Note: this file should not be included by non-asm/.h files + * 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. * - * Modifications: + * Note: this file should not be included by non-asm/.h files + * + * Modifications: */ #ifndef __ASM_ARM_MEMORY_H #define __ASM_ARM_MEMORY_H diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/mmu_context.h linux/include/asm-arm/mmu_context.h --- v2.4.0-test8/linux/include/asm-arm/mmu_context.h Sun Sep 3 11:19:11 2000 +++ linux/include/asm-arm/mmu_context.h Mon Sep 18 15:15:24 2000 @@ -1,10 +1,14 @@ /* - * linux/include/asm-arm/mmu_context.h + * linux/include/asm-arm/mmu_context.h * - * Copyright (c) 1996 Russell King. + * Copyright (C) 1996 Russell King. * - * Changelog: - * 27-06-1996 RMK Created + * 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. + * + * Changelog: + * 27-06-1996 RMK Created */ #ifndef __ASM_ARM_MMU_CONTEXT_H #define __ASM_ARM_MMU_CONTEXT_H diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/mmzone.h linux/include/asm-arm/mmzone.h --- v2.4.0-test8/linux/include/asm-arm/mmzone.h Mon Jun 19 17:59:35 2000 +++ linux/include/asm-arm/mmzone.h Mon Sep 18 15:15:24 2000 @@ -1,9 +1,12 @@ /* - * linux/include/asm-arm/mmzone.h + * linux/include/asm-arm/mmzone.h * - * 1999-12-29 Nicolas Pitre Created + * 1999-12-29 Nicolas Pitre Created + * + * 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. */ - #ifndef __ASM_MMZONE_H #define __ASM_MMZONE_H diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/param.h linux/include/asm-arm/param.h --- v2.4.0-test8/linux/include/asm-arm/param.h Wed Oct 20 16:29:08 1999 +++ linux/include/asm-arm/param.h Mon Sep 18 15:15:24 2000 @@ -1,7 +1,11 @@ /* - * linux/include/asm-arm/param.h + * linux/include/asm-arm/param.h * - * Copyright (C) 1995-1999 Russell King + * Copyright (C) 1995-1999 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. */ #ifndef __ASM_PARAM_H #define __ASM_PARAM_H diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/parport.h linux/include/asm-arm/parport.h --- v2.4.0-test8/linux/include/asm-arm/parport.h Tue Mar 14 18:04:50 2000 +++ linux/include/asm-arm/parport.h Mon Sep 18 15:15:24 2000 @@ -1,7 +1,7 @@ /* - * parport.h: ARM-specific parport initialisation + * linux/include/asm-arm/parport.h: ARM-specific parport initialisation * - * Copyright (C) 1999, 2000 Tim Waugh + * Copyright (C) 1999, 2000 Tim Waugh * * This file should only be included by drivers/parport/parport_pc.c. */ diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/pgalloc.h linux/include/asm-arm/pgalloc.h --- v2.4.0-test8/linux/include/asm-arm/pgalloc.h Sun Sep 3 11:19:11 2000 +++ linux/include/asm-arm/pgalloc.h Mon Sep 18 15:15:24 2000 @@ -1,5 +1,11 @@ /* - * linux/include/asm-arm/pgalloc.h + * linux/include/asm-arm/pgalloc.h + * + * Copyright (C) 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. */ #ifndef _ASMARM_PGALLOC_H #define _ASMARM_PGALLOC_H @@ -49,7 +55,7 @@ if ((ret = pgd_quicklist) != NULL) { pgd_quicklist = (unsigned long *)__pgd_next(ret); ret[1] = ret[2]; - clean_cache_area(ret + 1, 4); + clean_dcache_entry(ret + 1); pgtable_cache_size--; } return (pgd_t *)ret; @@ -76,7 +82,7 @@ if((ret = pte_quicklist) != NULL) { pte_quicklist = (unsigned long *)__pte_next(ret); ret[0] = ret[1]; - clean_cache_area(ret, 4); + clean_dcache_entry(ret); pgtable_cache_size--; } return (pte_t *)ret; diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/pgtable.h linux/include/asm-arm/pgtable.h --- v2.4.0-test8/linux/include/asm-arm/pgtable.h Sun Aug 13 09:54:15 2000 +++ linux/include/asm-arm/pgtable.h Mon Sep 18 15:15:24 2000 @@ -1,5 +1,11 @@ /* - * linux/include/asm-arm/pgtable.h + * linux/include/asm-arm/pgtable.h + * + * Copyright (C) 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. */ #ifndef _ASMARM_PGTABLE_H #define _ASMARM_PGTABLE_H @@ -88,7 +94,7 @@ * which, if __va and __pa are expensive causes twice the expense for * zero gain. --rmk */ -#define pte_page(x) (mem_map + MAP_NR(__va(pte_val((x))))) +#define pte_page(x) (virt_to_page(__va(pte_val((x))))) #endif #define pmd_none(pmd) (!pmd_val(pmd)) @@ -172,6 +178,10 @@ #define module_map vmalloc #define module_unmap vfree + +/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */ +/* FIXME: this is not correct */ +#define kern_addr_valid(addr) (1) #define io_remap_page_range remap_page_range diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/posix_types.h linux/include/asm-arm/posix_types.h --- v2.4.0-test8/linux/include/asm-arm/posix_types.h Sat Jan 15 22:08:28 2000 +++ linux/include/asm-arm/posix_types.h Mon Sep 18 15:15:24 2000 @@ -1,10 +1,14 @@ /* - * linux/include/asm-arm/posix_types.h + * linux/include/asm-arm/posix_types.h * - * Copyright (c) 1996-1998 Russell King. + * Copyright (C) 1996-1998 Russell King. * - * Changelog: - * 27-06-1996 RMK Created + * 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. + * + * Changelog: + * 27-06-1996 RMK Created */ #ifndef __ARCH_ARM_POSIX_TYPES_H #define __ARCH_ARM_POSIX_TYPES_H diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/proc-armo/assembler.h linux/include/asm-arm/proc-armo/assembler.h --- v2.4.0-test8/linux/include/asm-arm/proc-armo/assembler.h Sun Sep 3 11:19:11 2000 +++ linux/include/asm-arm/proc-armo/assembler.h Mon Sep 18 15:15:24 2000 @@ -1,10 +1,14 @@ /* - * linux/asm-arm/proc-armo/assembler.h + * linux/asm-arm/proc-armo/assembler.h * - * Copyright (C) 1996 Russell King + * Copyright (C) 1996 Russell King * - * This file contains arm architecture specific defines - * for the different processors + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This file contains arm architecture specific defines + * for the different processors */ #define MODE_USR USR26_MODE #define MODE_FIQ FIQ26_MODE diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/proc-armo/cache.h linux/include/asm-arm/proc-armo/cache.h --- v2.4.0-test8/linux/include/asm-arm/proc-armo/cache.h Sun Sep 3 11:19:11 2000 +++ linux/include/asm-arm/proc-armo/cache.h Mon Sep 18 15:15:24 2000 @@ -1,5 +1,13 @@ /* - * Cache handling for 26-bit ARM processors. + * linux/include/asm-arm/proc-armo/cache.h + * + * Copyright (C) 1999-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. + * + * Cache handling for 26-bit ARM processors. */ #define flush_cache_all() do { } while (0) #define flush_cache_mm(mm) do { } while (0) @@ -74,6 +82,3 @@ if (mm == current->active_mm) processor._set_pgd(mm->pgd); } - -#define __flush_entry_to_ram(entry) - diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/proc-armo/io.h linux/include/asm-arm/proc-armo/io.h --- v2.4.0-test8/linux/include/asm-arm/proc-armo/io.h Sun Sep 6 10:45:30 1998 +++ linux/include/asm-arm/proc-armo/io.h Wed Dec 31 16:00:00 1969 @@ -1,8 +0,0 @@ -/* - * linux/include/asm-arm/proc-armo/io.h - */ - -/* Nothing to do */ -#define dma_cache_inv(_start,_size) do { } while (0) -#define dma_cache_wback(_start,_size) do { } while (0) -#define dma_cache_wback_inv(_start,_size) do { } while (0) diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/proc-armo/locks.h linux/include/asm-arm/proc-armo/locks.h --- v2.4.0-test8/linux/include/asm-arm/proc-armo/locks.h Sun Sep 3 11:19:11 2000 +++ linux/include/asm-arm/proc-armo/locks.h Mon Sep 18 15:15:24 2000 @@ -1,11 +1,14 @@ /* - * linux/include/asm-arm/proc-armo/locks.h + * linux/include/asm-arm/proc-armo/locks.h * - * Copyright (C) 2000 Russell King - * Fixes for 26 bit machines, (C) 2000 Dave Gilbert + * Copyright (C) 2000 Russell King + * Fixes for 26 bit machines, (C) 2000 Dave Gilbert * - * Interrupt safe locking assembler. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. * + * Interrupt safe locking assembler. */ #ifndef __ASM_PROC_LOCKS_H #define __ASM_PROC_LOCKS_H diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/proc-armo/page.h linux/include/asm-arm/proc-armo/page.h --- v2.4.0-test8/linux/include/asm-arm/proc-armo/page.h Wed Oct 20 16:29:08 1999 +++ linux/include/asm-arm/proc-armo/page.h Mon Sep 18 15:15:24 2000 @@ -1,7 +1,11 @@ /* - * linux/include/asm-arm/proc-armo/page.h + * linux/include/asm-arm/proc-armo/page.h * - * Copyright (C) 1995, 1996 Russell King + * Copyright (C) 1995, 1996 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. */ #ifndef __ASM_PROC_PAGE_H #define __ASM_PROC_PAGE_H diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/proc-armo/pgtable.h linux/include/asm-arm/proc-armo/pgtable.h --- v2.4.0-test8/linux/include/asm-arm/proc-armo/pgtable.h Thu Oct 28 10:16:02 1999 +++ linux/include/asm-arm/proc-armo/pgtable.h Mon Sep 18 15:15:24 2000 @@ -1,9 +1,13 @@ /* - * linux/include/asm-arm/proc-armo/pgtable.h + * linux/include/asm-arm/proc-armo/pgtable.h * - * Copyright (C) 1995-1999 Russell King + * Copyright (C) 1995-1999 Russell King * - * 18-Oct-1997 RMK Now two-level (32x32) + * 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. + * + * 18-Oct-1997 RMK Now two-level (32x32) */ #ifndef __ASM_PROC_PGTABLE_H #define __ASM_PROC_PGTABLE_H diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/proc-armo/processor.h linux/include/asm-arm/proc-armo/processor.h --- v2.4.0-test8/linux/include/asm-arm/proc-armo/processor.h Tue Nov 23 22:23:11 1999 +++ linux/include/asm-arm/proc-armo/processor.h Mon Sep 18 15:15:24 2000 @@ -1,16 +1,20 @@ /* - * linux/include/asm-arm/proc-armo/processor.h + * linux/include/asm-arm/proc-armo/processor.h * - * Copyright (c) 1996 Russell King. + * Copyright (C) 1996 Russell King. * - * Changelog: - * 27-06-1996 RMK Created - * 10-10-1996 RMK Brought up to date with SA110 - * 26-09-1996 RMK Added 'EXTRA_THREAD_STRUCT*' - * 28-09-1996 RMK Moved start_thread into the processor dependencies - * 11-01-1998 RMK Added new uaccess_t - * 09-09-1998 PJB Delete redundant `wp_works_ok' - * 30-05-1999 PJB Save sl across context switches + * 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. + * + * Changelog: + * 27-06-1996 RMK Created + * 10-10-1996 RMK Brought up to date with SA110 + * 26-09-1996 RMK Added 'EXTRA_THREAD_STRUCT*' + * 28-09-1996 RMK Moved start_thread into the processor dependencies + * 11-01-1998 RMK Added new uaccess_t + * 09-09-1998 PJB Delete redundant `wp_works_ok' + * 30-05-1999 PJB Save sl across context switches */ #ifndef __ASM_PROC_PROCESSOR_H #define __ASM_PROC_PROCESSOR_H diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/proc-armo/ptrace.h linux/include/asm-arm/proc-armo/ptrace.h --- v2.4.0-test8/linux/include/asm-arm/proc-armo/ptrace.h Wed Oct 20 16:29:08 1999 +++ linux/include/asm-arm/proc-armo/ptrace.h Mon Sep 18 15:15:24 2000 @@ -1,7 +1,11 @@ /* - * linux/include/asm-arm/proc-armo/ptrace.h + * linux/include/asm-arm/proc-armo/ptrace.h * - * Copyright (C) 1996-1999 Russell King + * Copyright (C) 1996-1999 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. */ #ifndef __ASM_PROC_PTRACE_H #define __ASM_PROC_PTRACE_H @@ -53,6 +57,8 @@ #define user_mode(regs) \ (processor_mode(regs) == USR26_MODE) + +#define thumb_mode(regs) (0) #define interrupts_enabled(regs) \ (!((regs)->ARM_pc & I_BIT)) diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/proc-armo/shmparam.h linux/include/asm-arm/proc-armo/shmparam.h --- v2.4.0-test8/linux/include/asm-arm/proc-armo/shmparam.h Wed Nov 3 11:31:09 1999 +++ linux/include/asm-arm/proc-armo/shmparam.h Mon Sep 18 15:15:24 2000 @@ -1,11 +1,14 @@ /* - * linux/include/asm-arm/proc-armo/shmparam.h + * linux/include/asm-arm/proc-armo/shmparam.h * - * Copyright (C) 1996 Russell King + * Copyright (C) 1996 Russell King * - * definitions for the shared process memory on the ARM3 + * 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. + * + * definitions for the shared process memory on the ARM3 */ - #ifndef __ASM_PROC_SHMPARAM_H #define __ASM_PROC_SHMPARAM_H diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/proc-armo/system.h linux/include/asm-arm/proc-armo/system.h --- v2.4.0-test8/linux/include/asm-arm/proc-armo/system.h Sun Aug 13 09:54:15 2000 +++ linux/include/asm-arm/proc-armo/system.h Mon Sep 18 15:15:24 2000 @@ -1,9 +1,12 @@ /* - * linux/include/asm-arm/proc-armo/system.h + * linux/include/asm-arm/proc-armo/system.h * - * Copyright (C) 1995, 1996 Russell King + * Copyright (C) 1995, 1996 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. */ - #ifndef __ASM_PROC_SYSTEM_H #define __ASM_PROC_SYSTEM_H diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/proc-armo/uaccess.h linux/include/asm-arm/proc-armo/uaccess.h --- v2.4.0-test8/linux/include/asm-arm/proc-armo/uaccess.h Wed Oct 20 16:29:08 1999 +++ linux/include/asm-arm/proc-armo/uaccess.h Mon Sep 18 15:15:24 2000 @@ -1,7 +1,11 @@ /* - * linux/include/asm-arm/proc-armo/segment.h + * linux/include/asm-arm/proc-armo/segment.h * - * Copyright (C) 1996 Russell King + * Copyright (C) 1996 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. */ /* diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/proc-armo/uncompress.h linux/include/asm-arm/proc-armo/uncompress.h --- v2.4.0-test8/linux/include/asm-arm/proc-armo/uncompress.h Tue Jan 20 16:39:43 1998 +++ linux/include/asm-arm/proc-armo/uncompress.h Mon Sep 18 15:15:24 2000 @@ -1,7 +1,11 @@ /* - * linux/include/asm-arm/proc-armo/uncompress.h + * linux/include/asm-arm/proc-armo/uncompress.h * - * (c) 1997 Russell King + * Copyright (C) 1997 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. */ #define proc_decomp_setup() diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/proc-armv/assembler.h linux/include/asm-arm/proc-armv/assembler.h --- v2.4.0-test8/linux/include/asm-arm/proc-armv/assembler.h Sun Sep 3 11:19:11 2000 +++ linux/include/asm-arm/proc-armv/assembler.h Mon Sep 18 15:15:24 2000 @@ -1,10 +1,14 @@ /* - * linux/asm-arm/proc-armv/assembler.h + * linux/asm-arm/proc-armv/assembler.h * - * Copyright (C) 1996-2000 Russell King + * Copyright (C) 1996-2000 Russell King * - * This file contains ARM processor specifics for - * the ARM6 and better processors. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This file contains ARM processor specifics for + * the ARM6 and better processors. */ #define MODE_USR USR_MODE #define MODE_FIQ FIQ_MODE diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/proc-armv/cache.h linux/include/asm-arm/proc-armv/cache.h --- v2.4.0-test8/linux/include/asm-arm/proc-armv/cache.h Sun Aug 6 11:43:18 2000 +++ linux/include/asm-arm/proc-armv/cache.h Mon Sep 18 15:15:24 2000 @@ -1,57 +1,98 @@ +/* + * linux/include/asm-arm/proc-armv/cache.h + * + * Copyright (C) 1999-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 /* - * Cache flushing... + * Cache handling for 32-bit ARM processors. + * + * Note that on ARM, we have a more accurate specification than that + * Linux's "flush". We therefore do not use "flush" here, but instead + * use: + * + * clean: the act of pushing dirty cache entries out to memory. + * invalidate: the act of discarding data held within the cache, + * whether it is dirty or not. + */ + +/* + * Generic I + D cache */ #define flush_cache_all() \ - cpu_flush_cache_all() + do { \ + cpu_cache_clean_invalidate_all(); \ + } while (0) +/* This is always called for current->mm */ #define flush_cache_mm(_mm) \ do { \ - if ((_mm) == current->mm) \ - cpu_flush_cache_all(); \ + if ((_mm) == current->active_mm) \ + cpu_cache_clean_invalidate_all(); \ } while (0) #define flush_cache_range(_mm,_start,_end) \ do { \ if ((_mm) == current->mm) \ - cpu_flush_cache_area((_start), (_end), 1); \ + cpu_cache_clean_invalidate_range((_start), (_end), 1); \ } while (0) #define flush_cache_page(_vma,_vmaddr) \ do { \ - if ((_vma)->vm_mm == current->mm) \ - cpu_flush_cache_area((_vmaddr), \ + if ((_vma)->vm_mm == current->mm) { \ + cpu_cache_clean_invalidate_range((_vmaddr), \ (_vmaddr) + PAGE_SIZE, \ ((_vma)->vm_flags & VM_EXEC)); \ + } \ } while (0) -#define clean_cache_range(_start,_end) \ - do { \ - unsigned long _s, _sz; \ - _s = (unsigned long)_start; \ - _sz = (unsigned long)_end - _s; \ - cpu_clean_cache_area(_s, _sz); \ - } while (0) +/* + * This flushes back any buffered write data. We have to clean the entries + * in the cache for this page. This does not invalidate either I or D caches. + */ +static __inline__ void flush_page_to_ram(struct page *page) +{ + cpu_flush_ram_page(page_address(page)); +} -#define clean_cache_area(_start,_size) \ +/* + * D cache only + */ + +#define invalidate_dcache_range(_s,_e) cpu_dcache_invalidate_range((_s),(_e)) +#define clean_dcache_range(_s,_e) cpu_dcache_clean_range((_s),(_e)) +#define flush_dcache_range(_s,_e) cpu_cache_clean_invalidate_range((_s),(_e),0) + +/* + * FIXME: We currently clean the dcache for this page. Should we + * also invalidate the Dcache? And what about the Icache? -- rmk + */ +#define flush_dcache_page(page) cpu_dcache_clean_page(page_address(page)) + +#define clean_dcache_entry(_s) cpu_dcache_clean_entry((unsigned long)(_s)) + +/* + * I cache only + */ +#define flush_icache_range(_s,_e) \ do { \ - unsigned long _s; \ - _s = (unsigned long)_start; \ - cpu_clean_cache_area(_s, _size); \ + cpu_icache_invalidate_range((_s), (_e)); \ } while (0) -#define flush_icache_range(_start,_end) \ - cpu_flush_icache_area((_start), (_end) - (_start)) - #define flush_icache_page(vma,pg) \ do { \ if ((vma)->vm_flags & PROT_EXEC) \ - cpu_flush_icache_page((unsigned long) page_address(pg)); \ + cpu_icache_invalidate_page(page_address(pg)); \ } while (0) /* - * We don't have a MEMC chip... + * Old ARM MEMC stuff. This supports the reversed mapping handling that + * we have on the older 26-bit machines. We don't have a MEMC chip, so... */ #define memc_update_all() do { } while (0) #define memc_update_mm(mm) do { } while (0) @@ -59,48 +100,57 @@ #define memc_clear(mm,physaddr) do { } while (0) /* - * This flushes back any buffered write data. We have to clean the entries - * in the cache for this page. This does not invalidate either I or D caches. - */ -static __inline__ void flush_page_to_ram(struct page *page) -{ - cpu_flush_ram_page((unsigned long) page_address(page)); -} - -/* You guys might need to do something here. -DaveM */ -#define flush_dcache_page(page) do { } while (0) - -/* - * TLB flushing: + * TLB flushing. * - * - flush_tlb_all() flushes all processes TLBs - * - flush_tlb_mm(mm) flushes the specified mm context TLB's - * - flush_tlb_page(vma, vmaddr) flushes one page - * - flush_tlb_range(mm, start, end) flushes a range of pages + * - flush_tlb_all() flushes all processes TLBs + * - flush_tlb_mm(mm) flushes the specified mm context TLB's + * - flush_tlb_page(vma, vmaddr) flushes TLB for specified page + * - flush_tlb_range(mm, start, end) flushes TLB for specified range of pages * * We drain the write buffer in here to ensure that the page tables in ram * are really up to date. It is more efficient to do this here... */ -#define flush_tlb_all() \ - cpu_flush_tlb_all() -#define flush_tlb_mm(_mm) \ - do { \ - if ((_mm) == current->mm) \ - cpu_flush_tlb_all(); \ - } while (0) - -#define flush_tlb_range(_mm,_start,_end) \ - do { \ - if ((_mm) == current->mm) \ - cpu_flush_tlb_area((_start), (_end), 1); \ - } while (0) - -#define flush_tlb_page(_vma,_vmaddr) \ - do { \ - if ((_vma)->vm_mm == current->mm) \ - cpu_flush_tlb_page((_vmaddr), \ - ((_vma)->vm_flags & VM_EXEC)); \ +/* + * Notes: + * current->active_mm is the currently active memory description. + * current->mm == NULL iff we are lazy. + */ +#define flush_tlb_all() \ + do { \ + cpu_tlb_invalidate_all(); \ } while (0) +/* + * Flush all user virtual address space translations described by `_mm'. + * + * Currently, this is always called for current->mm, which should be + * the same as current->active_mm. This is currently not be called for + * the lazy TLB case. + */ +#define flush_tlb_mm(_mm) \ + do { \ + if ((_mm) == current->active_mm) \ + cpu_tlb_invalidate_all(); \ + } while (0) + +/* + * Flush the specified range of user virtual address space translations. + * + * _mm may not be current->active_mm, but may not be NULL. + */ +#define flush_tlb_range(_mm,_start,_end) \ + do { \ + if ((_mm) == current->active_mm) \ + cpu_tlb_invalidate_range((_start), (_end)); \ + } while (0) +/* + * Flush the specified user virtual address space translation. + */ +#define flush_tlb_page(_vma,_page) \ + do { \ + if ((_vma)->vm_mm == current->active_mm) \ + cpu_tlb_invalidate_page((_page), \ + ((_vma)->vm_flags & VM_EXEC)); \ + } while (0) diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/proc-armv/domain.h linux/include/asm-arm/proc-armv/domain.h --- v2.4.0-test8/linux/include/asm-arm/proc-armv/domain.h Mon Aug 2 10:19:52 1999 +++ linux/include/asm-arm/proc-armv/domain.h Mon Sep 18 15:15:24 2000 @@ -1,7 +1,11 @@ /* - * linux/include/asm-arm/proc-armv/domain.h + * linux/include/asm-arm/proc-armv/domain.h * - * Copyright (C) 1999 Russell King. + * Copyright (C) 1999 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. */ #ifndef __ASM_PROC_DOMAIN_H #define __ASM_PROC_DOMAIN_H diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/proc-armv/io.h linux/include/asm-arm/proc-armv/io.h --- v2.4.0-test8/linux/include/asm-arm/proc-armv/io.h Mon Aug 30 18:15:21 1999 +++ linux/include/asm-arm/proc-armv/io.h Wed Dec 31 16:00:00 1969 @@ -1,35 +0,0 @@ -/* - * linux/include/asm-arm/proc-armv/io.h - */ - -/* - * The caches on some architectures aren't dma-coherent and have need to - * handle this in software. There are two types of operations that - * can be applied to dma buffers. - * - * - dma_cache_wback_inv(start, size) makes caches and RAM coherent by - * writing the content of the caches back to memory, if necessary. - * The function also invalidates the affected part of the caches as - * necessary before DMA transfers from outside to memory. - * - dma_cache_inv(start, size) invalidates the affected parts of the - * caches. Dirty lines of the caches may be written back or simply - * be discarded. This operation is necessary before dma operations - * to the memory. - * - dma_cache_wback(start, size) writes back any dirty lines but does - * not invalidate the cache. This can be used before DMA reads from - * memory, - */ - -#include - -#define dma_cache_inv(start, size) \ - do { cpu_cache_purge_area((unsigned long)(start), \ - ((unsigned long)(start)+(size))); } while (0) - -#define dma_cache_wback(start, size) \ - do { cpu_cache_wback_area((unsigned long)(start), \ - ((unsigned long)(start)+(size))); } while (0) - -#define dma_cache_wback_inv(start, size) \ - do { cpu_flush_cache_area((unsigned long)(start), \ - ((unsigned long)(start)+(size)), 0); } while (0) diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/proc-armv/locks.h linux/include/asm-arm/proc-armv/locks.h --- v2.4.0-test8/linux/include/asm-arm/proc-armv/locks.h Mon Jun 19 17:59:35 2000 +++ linux/include/asm-arm/proc-armv/locks.h Mon Sep 18 15:15:24 2000 @@ -1,9 +1,13 @@ /* - * linux/include/asm-arm/proc-armv/locks.h + * linux/include/asm-arm/proc-armv/locks.h * - * Copyright (C) 2000 Russell King + * Copyright (C) 2000 Russell King * - * Interrupt safe locking assembler. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Interrupt safe locking assembler. */ #ifndef __ASM_PROC_LOCKS_H #define __ASM_PROC_LOCKS_H diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/proc-armv/page.h linux/include/asm-arm/proc-armv/page.h --- v2.4.0-test8/linux/include/asm-arm/proc-armv/page.h Wed Oct 20 16:29:08 1999 +++ linux/include/asm-arm/proc-armv/page.h Mon Sep 18 15:15:24 2000 @@ -1,7 +1,11 @@ /* - * linux/include/asm-arm/proc-armv/page.h + * linux/include/asm-arm/proc-armv/page.h * - * Copyright (C) 1995, 1996 Russell King + * Copyright (C) 1995, 1996 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. */ #ifndef __ASM_PROC_PAGE_H #define __ASM_PROC_PAGE_H diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/proc-armv/pgtable.h linux/include/asm-arm/proc-armv/pgtable.h --- v2.4.0-test8/linux/include/asm-arm/proc-armv/pgtable.h Tue Apr 25 16:54:38 2000 +++ linux/include/asm-arm/proc-armv/pgtable.h Mon Sep 18 15:15:24 2000 @@ -1,11 +1,15 @@ /* - * linux/include/asm-arm/proc-armv/pgtable.h + * linux/include/asm-arm/proc-armv/pgtable.h * - * Copyright (C) 1995-1999 Russell King + * Copyright (C) 1995-1999 Russell King * - * 12-Jan-1997 RMK Altered flushing routines to use function pointers + * 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. + * + * 12-Jan-1997 RMK Altered flushing routines to use function pointers * now possible to combine ARM6, ARM7 and StrongARM versions. - * 17-Apr-1999 RMK Now pass an area size to clean_cache_area and + * 17-Apr-1999 RMK Now pass an area size to clean_cache_area and * flush_icache_area. */ #ifndef __ASM_PROC_PGTABLE_H diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/proc-armv/processor.h linux/include/asm-arm/proc-armv/processor.h --- v2.4.0-test8/linux/include/asm-arm/proc-armv/processor.h Tue Nov 23 22:23:11 1999 +++ linux/include/asm-arm/proc-armv/processor.h Mon Sep 18 15:15:24 2000 @@ -1,15 +1,19 @@ /* - * linux/include/asm-arm/proc-armv/processor.h + * linux/include/asm-arm/proc-armv/processor.h * - * Copyright (c) 1996-1999 Russell King. + * Copyright (C) 1996-1999 Russell King. * - * Changelog: - * 20-09-1996 RMK Created - * 26-09-1996 RMK Added 'EXTRA_THREAD_STRUCT*' - * 28-09-1996 RMK Moved start_thread into the processor dependencies - * 09-09-1998 PJB Delete redundant `wp_works_ok' - * 30-05-1999 PJB Save sl across context switches - * 31-07-1999 RMK Added 'domain' stuff + * 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. + * + * Changelog: + * 20-09-1996 RMK Created + * 26-09-1996 RMK Added 'EXTRA_THREAD_STRUCT*' + * 28-09-1996 RMK Moved start_thread into the processor dependencies + * 09-09-1998 PJB Delete redundant `wp_works_ok' + * 30-05-1999 PJB Save sl across context switches + * 31-07-1999 RMK Added 'domain' stuff */ #ifndef __ASM_PROC_PROCESSOR_H #define __ASM_PROC_PROCESSOR_H diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/proc-armv/ptrace.h linux/include/asm-arm/proc-armv/ptrace.h --- v2.4.0-test8/linux/include/asm-arm/proc-armv/ptrace.h Wed Oct 20 16:29:08 1999 +++ linux/include/asm-arm/proc-armv/ptrace.h Mon Sep 18 15:15:24 2000 @@ -1,7 +1,11 @@ /* - * linux/include/asm-arm/proc-armv/ptrace.h + * linux/include/asm-arm/proc-armv/ptrace.h * - * Copyright (C) 1996-1999 Russell King + * Copyright (C) 1996-1999 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. */ #ifndef __ASM_PROC_PTRACE_H #define __ASM_PROC_PTRACE_H @@ -18,6 +22,7 @@ #define UND_MODE 0x1b #define SYSTEM_MODE 0x1f #define MODE_MASK 0x1f +#define T_BIT 0x20 #define F_BIT 0x40 #define I_BIT 0x80 #define CC_V_BIT (1 << 28) @@ -58,6 +63,9 @@ #define user_mode(regs) \ (((regs)->ARM_cpsr & 0xf) == 0) + +#define thumb_mode(regs) \ + (((regs)->ARM_cpsr & T_BIT)) #define processor_mode(regs) \ ((regs)->ARM_cpsr & MODE_MASK) diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/proc-armv/shmparam.h linux/include/asm-arm/proc-armv/shmparam.h --- v2.4.0-test8/linux/include/asm-arm/proc-armv/shmparam.h Wed Nov 3 11:31:09 1999 +++ linux/include/asm-arm/proc-armv/shmparam.h Mon Sep 18 15:15:24 2000 @@ -1,12 +1,15 @@ /* - * linux/include/asm-arm/proc-armv/shmparam.h + * linux/include/asm-arm/proc-armv/shmparam.h * - * Copyright (C) 1996 Russell King + * Copyright (C) 1996 Russell King * - * definitions for the shared process memory on ARM v3 or v4 - * processors + * 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. + * + * definitions for the shared process memory on ARM v3 or v4 + * processors */ - #ifndef __ASM_PROC_SHMPARAM_H #define __ASM_PROC_SHMPARAM_H diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/proc-armv/system.h linux/include/asm-arm/proc-armv/system.h --- v2.4.0-test8/linux/include/asm-arm/proc-armv/system.h Sun Sep 3 11:19:11 2000 +++ linux/include/asm-arm/proc-armv/system.h Mon Sep 18 15:15:24 2000 @@ -1,9 +1,12 @@ /* - * linux/include/asm-arm/proc-armv/system.h + * linux/include/asm-arm/proc-armv/system.h * - * Copyright (C) 1996 Russell King + * Copyright (C) 1996 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. */ - #ifndef __ASM_PROC_SYSTEM_H #define __ASM_PROC_SYSTEM_H @@ -72,36 +75,6 @@ __asm__ __volatile__( \ "mrs %0, cpsr @ cli\n" \ " orr %0, %0, #128\n" \ -" msr cpsr_c, %0" \ - : "=r" (temp) \ - : \ - : "memory"); \ - }) - -/* - * Enable FIQs - */ -#define __stf() \ - ({ \ - unsigned long temp; \ - __asm__ __volatile__( \ - "mrs %0, cpsr @ stf\n" \ -" bic %0, %0, #64\n" \ -" msr cpsr_c, %0" \ - : "=r" (temp) \ - : \ - : "memory"); \ - }) - -/* - * Disable FIQs - */ -#define __clf() \ - ({ \ - unsigned long temp; \ - __asm__ __volatile__( \ - "mrs %0, cpsr @ clf\n" \ -" orr %0, %0, #64\n" \ " msr cpsr_c, %0" \ : "=r" (temp) \ : \ diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/proc-armv/uaccess.h linux/include/asm-arm/proc-armv/uaccess.h --- v2.4.0-test8/linux/include/asm-arm/proc-armv/uaccess.h Sun Aug 13 09:54:15 2000 +++ linux/include/asm-arm/proc-armv/uaccess.h Mon Sep 18 15:15:24 2000 @@ -1,7 +1,10 @@ /* - * linux/include/asm-arm/proc-armv/uaccess.h + * linux/include/asm-arm/proc-armv/uaccess.h + * + * 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 diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/proc-armv/uncompress.h linux/include/asm-arm/proc-armv/uncompress.h --- v2.4.0-test8/linux/include/asm-arm/proc-armv/uncompress.h Thu Jan 13 13:30:31 2000 +++ linux/include/asm-arm/proc-armv/uncompress.h Mon Sep 18 15:15:24 2000 @@ -1,7 +1,11 @@ /* - * linux/include/asm-arm/proc-armv/uncompress.h + * linux/include/asm-arm/proc-armv/uncompress.h * - * (c) 1997 Russell King + * Copyright (C) 1997 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. */ static inline void proc_decomp_setup (void) diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/proc-fns.h linux/include/asm-arm/proc-fns.h --- v2.4.0-test8/linux/include/asm-arm/proc-fns.h Fri May 12 11:21:20 2000 +++ linux/include/asm-arm/proc-fns.h Mon Sep 18 15:15:24 2000 @@ -1,7 +1,12 @@ /* - * linux/include/asm-arm/proc-fns.h + * linux/include/asm-arm/proc-fns.h * - * Copyright (C) 1997-1999 Russell King + * Copyright (C) 1997-1999 Russell King + * Copyright (C) 2000 Deep Blue Solutions Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. */ #ifndef __ASM_PROCFNS_H #define __ASM_PROCFNS_H @@ -39,28 +44,36 @@ # define CPU_NAME arm7 # endif # endif -# ifdef CONFIG_CPU_SA110 +# ifdef CONFIG_CPU_ARM720 # ifdef CPU_NAME # undef MULTI_CPU # define MULTI_CPU # else -# define CPU_NAME sa110 +# define CPU_NAME arm720 # endif # endif -# ifdef CONFIG_CPU_SA1100 +# ifdef CONFIG_CPU_ARM920 # ifdef CPU_NAME # undef MULTI_CPU # define MULTI_CPU # else -# define CPU_NAME sa1100 +# define CPU_NAME arm920 # endif # endif -# ifdef CONFIG_CPU_ARM720 +# ifdef CONFIG_CPU_SA110 # ifdef CPU_NAME # undef MULTI_CPU # define MULTI_CPU # else -# define CPU_NAME arm720 +# define CPU_NAME sa110 +# endif +# endif +# ifdef CONFIG_CPU_SA1100 +# ifdef CPU_NAME +# undef MULTI_CPU +# define MULTI_CPU +# else +# define CPU_NAME sa1100 # endif # endif #endif diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/processor.h linux/include/asm-arm/processor.h --- v2.4.0-test8/linux/include/asm-arm/processor.h Fri Jan 7 12:59:42 2000 +++ linux/include/asm-arm/processor.h Mon Sep 18 15:15:24 2000 @@ -1,7 +1,11 @@ /* - * include/asm-arm/processor.h + * linux/include/asm-arm/processor.h * - * Copyright (C) 1995 Russell King + * Copyright (C) 1995 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. */ #ifndef __ASM_ARM_PROCESSOR_H diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/procinfo.h linux/include/asm-arm/procinfo.h --- v2.4.0-test8/linux/include/asm-arm/procinfo.h Sun Mar 12 19:39:39 2000 +++ linux/include/asm-arm/procinfo.h Mon Sep 18 15:15:24 2000 @@ -1,7 +1,11 @@ /* - * linux/include/asm-arm/procinfo.h + * linux/include/asm-arm/procinfo.h * - * Copyright (C) 1996-1999 Russell King + * Copyright (C) 1996-1999 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. */ #ifndef __ASM_PROCINFO_H #define __ASM_PROCINFO_H diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/resource.h linux/include/asm-arm/resource.h --- v2.4.0-test8/linux/include/asm-arm/resource.h Sun Aug 13 09:54:15 2000 +++ linux/include/asm-arm/resource.h Fri Sep 22 14:21:19 2000 @@ -15,8 +15,9 @@ #define RLIMIT_NOFILE 7 /* max number of open files */ #define RLIMIT_MEMLOCK 8 /* max locked-in-memory address space */ #define RLIMIT_AS 9 /* address space limit */ +#define RLIMIT_LOCKS 10 /* maximum file locks held */ -#define RLIM_NLIMITS 10 +#define RLIM_NLIMITS 11 #ifdef __KERNEL__ @@ -36,6 +37,7 @@ { RLIM_INFINITY, RLIM_INFINITY }, \ { 0, 0 }, \ { INR_OPEN, INR_OPEN }, \ + { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ } diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/serial.h linux/include/asm-arm/serial.h --- v2.4.0-test8/linux/include/asm-arm/serial.h Tue Nov 23 22:23:11 1999 +++ linux/include/asm-arm/serial.h Mon Sep 18 15:15:24 2000 @@ -1,10 +1,14 @@ /* - * linux/include/asm-arm/serial.h + * linux/include/asm-arm/serial.h * - * Copyright (c) 1996 Russell King. + * Copyright (C) 1996 Russell King. * - * Changelog: - * 15-10-1996 RMK Created + * 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. + * + * Changelog: + * 15-10-1996 RMK Created */ #ifndef __ASM_SERIAL_H diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/setup.h linux/include/asm-arm/setup.h --- v2.4.0-test8/linux/include/asm-arm/setup.h Mon Jun 19 17:59:35 2000 +++ linux/include/asm-arm/setup.h Mon Sep 18 15:15:24 2000 @@ -1,11 +1,15 @@ /* - * include/asm/setup.h + * linux/include/asm/setup.h * - * Structure passed to kernel to tell it about the - * hardware it's running on. See linux/Documentation/arm/Setup - * for more info. + * Copyright (C) 1997-1999 Russell King * - * Copyright (C) 1997-1999 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. + * + * Structure passed to kernel to tell it about the + * hardware it's running on. See linux/Documentation/arm/Setup + * for more info. */ #ifndef __ASMARM_SETUP_H #define __ASMARM_SETUP_H diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-arm/timex.h linux/include/asm-arm/timex.h --- v2.4.0-test8/linux/include/asm-arm/timex.h Thu Jan 7 15:51:33 1999 +++ linux/include/asm-arm/timex.h Mon Sep 18 15:15:24 2000 @@ -1,9 +1,13 @@ /* - * linux/include/asm-arm/timex.h + * linux/include/asm-arm/timex.h * - * Architecture Specific TIME specifications + * Copyright (C) 1997,1998 Russell King * - * Copyright (C) 1997,1998 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. + * + * Architecture Specific TIME specifications */ #ifndef _ASMARM_TIMEX_H #define _ASMARM_TIMEX_H diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-i386/atomic.h linux/include/asm-i386/atomic.h --- v2.4.0-test8/linux/include/asm-i386/atomic.h Fri Sep 8 12:52:41 2000 +++ linux/include/asm-i386/atomic.h Mon Oct 2 11:01:17 2000 @@ -19,102 +19,96 @@ * on us. We need to use _exactly_ the address the user gave us, * not some alias that contains the same information. */ -#define __atomic_fool_gcc(x) (*(volatile struct { int a[100]; } *)x) - -#ifdef CONFIG_SMP typedef struct { volatile int counter; } atomic_t; -#else -typedef struct { int counter; } atomic_t; -#endif #define ATOMIC_INIT(i) { (i) } #define atomic_read(v) ((v)->counter) #define atomic_set(v,i) (((v)->counter) = (i)) -static __inline__ void atomic_add(int i, volatile atomic_t *v) +static __inline__ void atomic_add(int i, atomic_t *v) { __asm__ __volatile__( LOCK "addl %1,%0" - :"=m" (__atomic_fool_gcc(v)) - :"ir" (i), "m" (__atomic_fool_gcc(v))); + :"=m" (v->counter) + :"ir" (i), "m" (v->counter)); } -static __inline__ void atomic_sub(int i, volatile atomic_t *v) +static __inline__ void atomic_sub(int i, atomic_t *v) { __asm__ __volatile__( LOCK "subl %1,%0" - :"=m" (__atomic_fool_gcc(v)) - :"ir" (i), "m" (__atomic_fool_gcc(v))); + :"=m" (v->counter) + :"ir" (i), "m" (v->counter)); } -static __inline__ int atomic_sub_and_test(int i, volatile atomic_t *v) +static __inline__ int atomic_sub_and_test(int i, atomic_t *v) { unsigned char c; __asm__ __volatile__( LOCK "subl %2,%0; sete %1" - :"=m" (__atomic_fool_gcc(v)), "=qm" (c) - :"ir" (i), "m" (__atomic_fool_gcc(v))); + :"=m" (v->counter), "=qm" (c) + :"ir" (i), "m" (v->counter) : "memory"); return c; } -static __inline__ void atomic_inc(volatile atomic_t *v) +static __inline__ void atomic_inc(atomic_t *v) { __asm__ __volatile__( LOCK "incl %0" - :"=m" (__atomic_fool_gcc(v)) - :"m" (__atomic_fool_gcc(v))); + :"=m" (v->counter) + :"m" (v->counter)); } -static __inline__ void atomic_dec(volatile atomic_t *v) +static __inline__ void atomic_dec(atomic_t *v) { __asm__ __volatile__( LOCK "decl %0" - :"=m" (__atomic_fool_gcc(v)) - :"m" (__atomic_fool_gcc(v))); + :"=m" (v->counter) + :"m" (v->counter)); } -static __inline__ int atomic_dec_and_test(volatile atomic_t *v) +static __inline__ int atomic_dec_and_test(atomic_t *v) { unsigned char c; __asm__ __volatile__( LOCK "decl %0; sete %1" - :"=m" (__atomic_fool_gcc(v)), "=qm" (c) - :"m" (__atomic_fool_gcc(v))); + :"=m" (v->counter), "=qm" (c) + :"m" (v->counter) : "memory"); return c != 0; } -static __inline__ int atomic_inc_and_test(volatile atomic_t *v) +static __inline__ int atomic_inc_and_test(atomic_t *v) { unsigned char c; __asm__ __volatile__( LOCK "incl %0; sete %1" - :"=m" (__atomic_fool_gcc(v)), "=qm" (c) - :"m" (__atomic_fool_gcc(v))); + :"=m" (v->counter), "=qm" (c) + :"m" (v->counter) : "memory"); return c != 0; } -extern __inline__ int atomic_add_negative(int i, volatile atomic_t *v) +static __inline__ int atomic_add_negative(int i, atomic_t *v) { unsigned char c; __asm__ __volatile__( LOCK "addl %2,%0; sets %1" - :"=m" (__atomic_fool_gcc(v)), "=qm" (c) - :"ir" (i), "m" (__atomic_fool_gcc(v))); + :"=m" (v->counter), "=qm" (c) + :"ir" (i), "m" (v->counter) : "memory"); return c; } /* These are x86-specific, used by some header files */ #define atomic_clear_mask(mask, addr) \ __asm__ __volatile__(LOCK "andl %0,%1" \ -: : "r" (~(mask)),"m" (__atomic_fool_gcc(addr)) : "memory") +: : "r" (~(mask)),"m" (*addr) : "memory") #define atomic_set_mask(mask, addr) \ __asm__ __volatile__(LOCK "orl %0,%1" \ -: : "r" (mask),"m" (__atomic_fool_gcc(addr)) : "memory") +: : "r" (mask),"m" (*addr) : "memory") #endif diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-i386/bitops.h linux/include/asm-i386/bitops.h --- v2.4.0-test8/linux/include/asm-i386/bitops.h Fri Sep 8 12:52:41 2000 +++ linux/include/asm-i386/bitops.h Mon Oct 2 11:01:17 2000 @@ -21,29 +21,9 @@ #define LOCK_PREFIX "" #endif -/* - * Function prototypes to keep gcc -Wall happy - */ -extern void set_bit(int nr, volatile void * addr); -extern void clear_bit(int nr, volatile void * addr); -extern void change_bit(int nr, volatile void * addr); -extern int test_and_set_bit(int nr, volatile void * addr); -extern int test_and_clear_bit(int nr, volatile void * addr); -extern int test_and_change_bit(int nr, volatile void * addr); -extern int __constant_test_bit(int nr, const volatile void * addr); -extern int __test_bit(int nr, volatile void * addr); -extern int find_first_zero_bit(void * addr, unsigned size); -extern int find_next_zero_bit (void * addr, int size, int offset); -extern unsigned long ffz(unsigned long word); - -/* - * Some hacks to defeat gcc over-optimizations.. - */ -struct __dummy { unsigned long a[100]; }; -#define ADDR (*(volatile struct __dummy *) addr) -#define CONST_ADDR (*(volatile const struct __dummy *) addr) +#define ADDR (*(volatile long *) addr) -extern __inline__ void set_bit(int nr, volatile void * addr) +static __inline__ void set_bit(int nr, volatile void * addr) { __asm__ __volatile__( LOCK_PREFIX "btsl %1,%0" @@ -51,7 +31,21 @@ :"Ir" (nr)); } -extern __inline__ void clear_bit(int nr, volatile void * addr) +/* WARNING: non atomic and it can be reordered! */ +static __inline__ void __set_bit(int nr, volatile void * addr) +{ + __asm__( + "btsl %1,%0" + :"=m" (ADDR) + :"Ir" (nr)); +} + +/* + * clear_bit() doesn't provide any barrier for the compiler. + */ +#define smp_mb__before_clear_bit() barrier() +#define smp_mb__after_clear_bit() barrier() +static __inline__ void clear_bit(int nr, volatile void * addr) { __asm__ __volatile__( LOCK_PREFIX "btrl %1,%0" @@ -59,7 +53,7 @@ :"Ir" (nr)); } -extern __inline__ void change_bit(int nr, volatile void * addr) +static __inline__ void change_bit(int nr, volatile void * addr) { __asm__ __volatile__( LOCK_PREFIX "btcl %1,%0" @@ -67,48 +61,77 @@ :"Ir" (nr)); } -extern __inline__ int test_and_set_bit(int nr, volatile void * addr) +/* + * It will also imply a memory barrier, thus it must clobber memory + * to make sure to reload anything that was cached into registers + * outside _this_ critical section. + */ +static __inline__ int test_and_set_bit(int nr, volatile void * addr) { int oldbit; __asm__ __volatile__( LOCK_PREFIX "btsl %2,%1\n\tsbbl %0,%0" :"=r" (oldbit),"=m" (ADDR) + :"Ir" (nr) : "memory"); + return oldbit; +} + +/* WARNING: non atomic and it can be reordered! */ +static __inline__ int __test_and_set_bit(int nr, volatile void * addr) +{ + int oldbit; + + __asm__( + "btsl %2,%1\n\tsbbl %0,%0" + :"=r" (oldbit),"=m" (ADDR) :"Ir" (nr)); return oldbit; } -extern __inline__ int test_and_clear_bit(int nr, volatile void * addr) +static __inline__ int test_and_clear_bit(int nr, volatile void * addr) { int oldbit; __asm__ __volatile__( LOCK_PREFIX "btrl %2,%1\n\tsbbl %0,%0" :"=r" (oldbit),"=m" (ADDR) + :"Ir" (nr) : "memory"); + return oldbit; +} + +/* WARNING: non atomic and it can be reordered! */ +static __inline__ int __test_and_clear_bit(int nr, volatile void * addr) +{ + int oldbit; + + __asm__( + "btrl %2,%1\n\tsbbl %0,%0" + :"=r" (oldbit),"=m" (ADDR) :"Ir" (nr)); return oldbit; } -extern __inline__ int test_and_change_bit(int nr, volatile void * addr) +static __inline__ int test_and_change_bit(int nr, volatile void * addr) { int oldbit; __asm__ __volatile__( LOCK_PREFIX "btcl %2,%1\n\tsbbl %0,%0" :"=r" (oldbit),"=m" (ADDR) - :"Ir" (nr)); + :"Ir" (nr) : "memory"); return oldbit; } /* * This routine doesn't need to be atomic. */ -extern __inline__ int __constant_test_bit(int nr, const volatile void * addr) +static __inline__ int constant_test_bit(int nr, const volatile void * addr) { return ((1UL << (nr & 31)) & (((const volatile unsigned int *) addr)[nr >> 5])) != 0; } -extern __inline__ int __test_bit(int nr, volatile void * addr) +static __inline__ int variable_test_bit(int nr, volatile void * addr) { int oldbit; @@ -121,13 +144,13 @@ #define test_bit(nr,addr) \ (__builtin_constant_p(nr) ? \ - __constant_test_bit((nr),(addr)) : \ - __test_bit((nr),(addr))) + constant_test_bit((nr),(addr)) : \ + variable_test_bit((nr),(addr))) /* * Find-bit routines.. */ -extern __inline__ int find_first_zero_bit(void * addr, unsigned size) +static __inline__ int find_first_zero_bit(void * addr, unsigned size) { int d0, d1, d2; int res; @@ -151,7 +174,7 @@ return res; } -extern __inline__ int find_next_zero_bit (void * addr, int size, int offset) +static __inline__ int find_next_zero_bit (void * addr, int size, int offset) { unsigned long * p = ((unsigned long *) addr) + (offset >> 5); int set = 0, bit = offset & 31, res; @@ -182,7 +205,7 @@ * ffz = Find First Zero in word. Undefined if no zero exists, * so code should check against ~0UL first.. */ -extern __inline__ unsigned long ffz(unsigned long word) +static __inline__ unsigned long ffz(unsigned long word) { __asm__("bsfl %1,%0" :"=r" (word) @@ -198,7 +221,7 @@ * differs in spirit from the above ffz (man ffs). */ -extern __inline__ int ffs(int x) +static __inline__ int ffs(int x) { int r; @@ -222,16 +245,16 @@ #ifdef __KERNEL__ -#define ext2_set_bit test_and_set_bit -#define ext2_clear_bit test_and_clear_bit +#define ext2_set_bit __test_and_set_bit +#define ext2_clear_bit __test_and_clear_bit #define ext2_test_bit test_bit #define ext2_find_first_zero_bit find_first_zero_bit #define ext2_find_next_zero_bit find_next_zero_bit /* Bitmap functions for the minix filesystem. */ -#define minix_test_and_set_bit(nr,addr) test_and_set_bit(nr,addr) -#define minix_set_bit(nr,addr) set_bit(nr,addr) -#define minix_test_and_clear_bit(nr,addr) test_and_clear_bit(nr,addr) +#define minix_test_and_set_bit(nr,addr) __test_and_set_bit(nr,addr) +#define minix_set_bit(nr,addr) __set_bit(nr,addr) +#define minix_test_and_clear_bit(nr,addr) __test_and_clear_bit(nr,addr) #define minix_test_bit(nr,addr) test_bit(nr,addr) #define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size) diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-i386/fcntl.h linux/include/asm-i386/fcntl.h --- v2.4.0-test8/linux/include/asm-i386/fcntl.h Fri Aug 11 14:37:49 2000 +++ linux/include/asm-i386/fcntl.h Fri Sep 22 14:21:19 2000 @@ -51,6 +51,9 @@ #define F_EXLCK 4 /* or 3 */ #define F_SHLCK 8 /* or 4 */ +/* for leases */ +#define F_INPROGRESS 16 + /* operations for bsd flock(), also used by the kernel implementation */ #define LOCK_SH 1 /* shared lock */ #define LOCK_EX 2 /* exclusive lock */ @@ -58,6 +61,11 @@ blocking */ #define LOCK_UN 8 /* remove lock */ +#define LOCK_MAND 32 /* This is a mandatory flock */ +#define LOCK_READ 64 /* ... Which allows concurrent read operations */ +#define LOCK_WRITE 128 /* ... Which allows concurrent write operations */ +#define LOCK_RW 192 /* ... Which allows concurrent read & write ops */ + struct flock { short l_type; short l_whence; @@ -73,5 +81,7 @@ loff_t l_len; pid_t l_pid; }; + +#define F_LINUX_SPECIFIC_BASE 1024 #endif diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-i386/resource.h linux/include/asm-i386/resource.h --- v2.4.0-test8/linux/include/asm-i386/resource.h Thu Feb 17 09:35:07 2000 +++ linux/include/asm-i386/resource.h Fri Sep 22 14:21:19 2000 @@ -15,8 +15,9 @@ #define RLIMIT_NOFILE 7 /* max number of open files */ #define RLIMIT_MEMLOCK 8 /* max locked-in-memory address space */ #define RLIMIT_AS 9 /* address space limit */ +#define RLIMIT_LOCKS 10 /* maximum file locks held */ -#define RLIM_NLIMITS 10 +#define RLIM_NLIMITS 11 /* * SuS says limits have to be unsigned. @@ -38,6 +39,7 @@ { INR_OPEN, INR_OPEN }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ + { RLIM_INFINITY, RLIM_INFINITY }, \ } #endif /* __KERNEL__ */ diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-i386/rwlock.h linux/include/asm-i386/rwlock.h --- v2.4.0-test8/linux/include/asm-i386/rwlock.h Sat Nov 27 16:04:04 1999 +++ linux/include/asm-i386/rwlock.h Fri Sep 22 14:07:43 2000 @@ -17,9 +17,6 @@ #ifndef _ASM_I386_RWLOCK_H #define _ASM_I386_RWLOCK_H -typedef struct { unsigned long a[100]; } __dummy_lock_t; -#define __dummy_lock(lock) (*(__dummy_lock_t *)(lock)) - #define RW_LOCK_BIAS 0x01000000 #define RW_LOCK_BIAS_STR "0x01000000" @@ -44,7 +41,7 @@ "popl %%eax\n\t" \ "jmp 1b\n" \ ".previous" \ - :"=m" (__dummy_lock(rw))) + :"=m" (*(volatile int *)rw) : : "memory") #define __build_read_lock(rw, helper) do { \ if (__builtin_constant_p(rw)) \ @@ -74,7 +71,7 @@ "popl %%eax\n\t" \ "jmp 1b\n" \ ".previous" \ - :"=m" (__dummy_lock(rw))) + :"=m" (*(volatile int *)rw) : : "memory") #define __build_write_lock(rw, helper) do { \ if (__builtin_constant_p(rw)) \ diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-i386/semaphore.h linux/include/asm-i386/semaphore.h --- v2.4.0-test8/linux/include/asm-i386/semaphore.h Fri Sep 8 12:52:41 2000 +++ linux/include/asm-i386/semaphore.h Mon Oct 2 11:01:18 2000 @@ -64,7 +64,7 @@ #define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1) #define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name,0) -extern inline void sema_init (struct semaphore *sem, int val) +static inline void sema_init (struct semaphore *sem, int val) { /* * *sem = (struct semaphore)__SEMAPHORE_INITIALIZER((*sem),val); @@ -105,7 +105,7 @@ * "__down_failed" is a special asm handler that calls the C * routine that actually waits. See arch/i386/kernel/semaphore.c */ -extern inline void down(struct semaphore * sem) +static inline void down(struct semaphore * sem) { #if WAITQUEUE_DEBUG CHECK_MAGIC(sem->__magic); @@ -125,7 +125,7 @@ :"memory"); } -extern inline int down_interruptible(struct semaphore * sem) +static inline int down_interruptible(struct semaphore * sem) { int result; @@ -149,7 +149,7 @@ return result; } -extern inline int down_trylock(struct semaphore * sem) +static inline int down_trylock(struct semaphore * sem) { int result; @@ -179,7 +179,7 @@ * The default case (no contention) will result in NO * jumps for both down() and up(). */ -extern inline void up(struct semaphore * sem) +static inline void up(struct semaphore * sem) { #if WAITQUEUE_DEBUG CHECK_MAGIC(sem->__magic); @@ -252,7 +252,7 @@ #define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS-1) #define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,0) -extern inline void init_rwsem(struct rw_semaphore *sem) +static inline void init_rwsem(struct rw_semaphore *sem) { atomic_set(&sem->count, RW_LOCK_BIAS); sem->read_bias_granted = 0; @@ -271,7 +271,7 @@ extern struct rw_semaphore *FASTCALL(__down_write_failed(struct rw_semaphore *sem)); extern struct rw_semaphore *FASTCALL(__rwsem_wake(struct rw_semaphore *sem)); -extern inline void down_read(struct rw_semaphore *sem) +static inline void down_read(struct rw_semaphore *sem) { #if WAITQUEUE_DEBUG if (sem->__magic != (long)&sem->__magic) @@ -287,7 +287,7 @@ #endif } -extern inline void down_write(struct rw_semaphore *sem) +static inline void down_write(struct rw_semaphore *sem) { #if WAITQUEUE_DEBUG if (sem->__magic != (long)&sem->__magic) @@ -311,7 +311,7 @@ * case is when there was a writer waiting, and we've * bumped the count to 0: we must wake the writer up. */ -extern inline void __up_read(struct rw_semaphore *sem) +static inline void __up_read(struct rw_semaphore *sem) { __asm__ __volatile__( "# up_read\n\t" @@ -330,7 +330,7 @@ /* releasing the writer is easy -- just release it and * wake up any sleepers. */ -extern inline void __up_write(struct rw_semaphore *sem) +static inline void __up_write(struct rw_semaphore *sem) { __asm__ __volatile__( "# up_write\n\t" @@ -346,7 +346,7 @@ ); } -extern inline void up_read(struct rw_semaphore *sem) +static inline void up_read(struct rw_semaphore *sem) { #if WAITQUEUE_DEBUG if (sem->write_bias_granted) @@ -358,7 +358,7 @@ __up_read(sem); } -extern inline void up_write(struct rw_semaphore *sem) +static inline void up_write(struct rw_semaphore *sem) { #if WAITQUEUE_DEBUG if (sem->read_bias_granted) diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-i386/spinlock.h linux/include/asm-i386/spinlock.h --- v2.4.0-test8/linux/include/asm-i386/spinlock.h Fri Sep 8 12:52:41 2000 +++ linux/include/asm-i386/spinlock.h Mon Oct 2 11:01:17 2000 @@ -70,13 +70,12 @@ char oldval; __asm__ __volatile__( "xchgb %b0,%1" - :"=q" (oldval), "=m" (__dummy_lock(lock)) - :"0" (0) - :"memory"); + :"=q" (oldval), "=m" (lock->lock) + :"0" (0) : "memory"); return oldval > 0; } -extern inline void spin_lock(spinlock_t *lock) +static inline void spin_lock(spinlock_t *lock) { #if SPINLOCK_DEBUG __label__ here; @@ -88,11 +87,10 @@ #endif __asm__ __volatile__( spin_lock_string - :"=m" (__dummy_lock(lock)) - : :"memory"); + :"=m" (lock->lock) : : "memory"); } -extern inline void spin_unlock(spinlock_t *lock) +static inline void spin_unlock(spinlock_t *lock) { #if SPINLOCK_DEBUG if (lock->magic != SPINLOCK_MAGIC) @@ -102,8 +100,7 @@ #endif __asm__ __volatile__( spin_unlock_string - :"=m" (__dummy_lock(lock)) - : :"memory"); + :"=m" (lock->lock) : : "memory"); } /* @@ -146,7 +143,7 @@ */ /* the spinlock helpers are in arch/i386/kernel/semaphore.S */ -extern inline void read_lock(rwlock_t *rw) +static inline void read_lock(rwlock_t *rw) { #if SPINLOCK_DEBUG if (rw->magic != RWLOCK_MAGIC) @@ -155,7 +152,7 @@ __build_read_lock(rw, "__read_lock_failed"); } -extern inline void write_lock(rwlock_t *rw) +static inline void write_lock(rwlock_t *rw) { #if SPINLOCK_DEBUG if (rw->magic != RWLOCK_MAGIC) @@ -164,10 +161,10 @@ __build_write_lock(rw, "__write_lock_failed"); } -#define read_unlock(rw) asm volatile("lock ; incl %0" :"=m" (__dummy_lock(&(rw)->lock))) -#define write_unlock(rw) asm volatile("lock ; addl $" RW_LOCK_BIAS_STR ",%0":"=m" (__dummy_lock(&(rw)->lock))) +#define read_unlock(rw) asm volatile("lock ; incl %0" :"=m" ((rw)->lock) : : "memory") +#define write_unlock(rw) asm volatile("lock ; addl $" RW_LOCK_BIAS_STR ",%0":"=m" ((rw)->lock) : : "memory") -extern inline int write_trylock(rwlock_t *lock) +static inline int write_trylock(rwlock_t *lock) { atomic_t *count = (atomic_t *)lock; if (atomic_sub_and_test(RW_LOCK_BIAS, count)) diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-i386/system.h linux/include/asm-i386/system.h --- v2.4.0-test8/linux/include/asm-i386/system.h Fri Sep 8 12:52:41 2000 +++ linux/include/asm-i386/system.h Mon Oct 2 11:01:18 2000 @@ -278,11 +278,22 @@ #endif #define rmb() mb() #define wmb() __asm__ __volatile__ ("": : :"memory") + +#ifdef CONFIG_SMP +#define smp_mb() mb() +#define smp_rmb() rmb() +#define smp_wmb() wmb() +#else +#define smp_mb() barrier() +#define smp_rmb() barrier() +#define smp_wmb() barrier() +#endif + #define set_mb(var, value) do { xchg(&var, value); } while (0) #define set_wmb(var, value) do { var = value; wmb(); } while (0) /* interrupt control.. */ -#define __save_flags(x) __asm__ __volatile__("pushfl ; popl %0":"=g" (x): /* no input */ :"memory") +#define __save_flags(x) __asm__ __volatile__("pushfl ; popl %0":"=g" (x): /* no input */) #define __restore_flags(x) __asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory") #define __cli() __asm__ __volatile__("cli": : :"memory") #define __sti() __asm__ __volatile__("sti": : :"memory") @@ -291,9 +302,9 @@ /* For spinlocks etc */ #define local_irq_save(x) __asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (x): /* no input */ :"memory") -#define local_irq_restore(x) __asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory") -#define local_irq_disable() __asm__ __volatile__("cli": : :"memory") -#define local_irq_enable() __asm__ __volatile__("sti": : :"memory") +#define local_irq_restore(x) __restore_flags(x) +#define local_irq_disable() __cli() +#define local_irq_enable() __sti() #ifdef CONFIG_SMP diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-ia64/fcntl.h linux/include/asm-ia64/fcntl.h --- v2.4.0-test8/linux/include/asm-ia64/fcntl.h Wed Jul 5 11:13:39 2000 +++ linux/include/asm-ia64/fcntl.h Fri Sep 22 14:21:19 2000 @@ -55,6 +55,9 @@ #define F_EXLCK 4 /* or 3 */ #define F_SHLCK 8 /* or 4 */ +/* for leases */ +#define F_INPROGRESS 16 + /* operations for bsd flock(), also used by the kernel implementation */ #define LOCK_SH 1 /* shared lock */ #define LOCK_EX 2 /* exclusive lock */ @@ -62,6 +65,11 @@ blocking */ #define LOCK_UN 8 /* remove lock */ +#define LOCK_MAND 32 /* This is a mandatory flock */ +#define LOCK_READ 64 /* ... Which allows concurrent read operations */ +#define LOCK_WRITE 128 /* ... Which allows concurrent write operations */ +#define LOCK_RW 192 /* ... Which allows concurrent read & write ops */ + struct flock { short l_type; short l_whence; @@ -70,4 +78,5 @@ pid_t l_pid; }; +#define F_LINUX_SPECIFIC_BASE 1024 #endif /* _ASM_IA64_FCNTL_H */ diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-ia64/resource.h linux/include/asm-ia64/resource.h --- v2.4.0-test8/linux/include/asm-ia64/resource.h Sun Feb 6 18:42:40 2000 +++ linux/include/asm-ia64/resource.h Fri Sep 22 14:21:19 2000 @@ -18,8 +18,9 @@ #define RLIMIT_NOFILE 7 /* max number of open files */ #define RLIMIT_MEMLOCK 8 /* max locked-in-memory address space */ #define RLIMIT_AS 9 /* address space limit */ +#define RLIMIT_LOCKS 10 /* maximum file locks held */ -#define RLIM_NLIMITS 10 +#define RLIM_NLIMITS 11 /* * SuS says limits have to be unsigned. @@ -39,6 +40,7 @@ { RLIM_INFINITY, RLIM_INFINITY }, \ { 0, 0 }, \ { INR_OPEN, INR_OPEN }, \ + { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ } diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-m68k/fcntl.h linux/include/asm-m68k/fcntl.h --- v2.4.0-test8/linux/include/asm-m68k/fcntl.h Wed Jul 5 11:13:39 2000 +++ linux/include/asm-m68k/fcntl.h Fri Sep 22 14:21:20 2000 @@ -47,6 +47,9 @@ #define F_EXLCK 4 /* or 3 */ #define F_SHLCK 8 /* or 4 */ +/* for leases */ +#define F_INPROGRESS 16 + /* operations for bsd flock(), also used by the kernel implementation */ #define LOCK_SH 1 /* shared lock */ #define LOCK_EX 2 /* exclusive lock */ @@ -54,6 +57,11 @@ blocking */ #define LOCK_UN 8 /* remove lock */ +#define LOCK_MAND 32 /* This is a mandatory flock */ +#define LOCK_READ 64 /* ... Which allows concurrent read operations */ +#define LOCK_WRITE 128 /* ... Which allows concurrent write operations */ +#define LOCK_RW 192 /* ... Which allows concurrent read & write ops */ + struct flock { short l_type; short l_whence; @@ -62,4 +70,5 @@ pid_t l_pid; }; +#define F_LINUX_SPECIFIC_BASE 1024 #endif /* _M68K_FCNTL_H */ diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-m68k/resource.h linux/include/asm-m68k/resource.h --- v2.4.0-test8/linux/include/asm-m68k/resource.h Thu Feb 17 09:35:07 2000 +++ linux/include/asm-m68k/resource.h Fri Sep 22 14:21:20 2000 @@ -15,8 +15,9 @@ #define RLIMIT_NOFILE 7 /* max number of open files */ #define RLIMIT_MEMLOCK 8 /* max locked-in-memory address space*/ #define RLIMIT_AS 9 /* address space limit */ +#define RLIMIT_LOCKS 10 /* maximum file locks held */ -#define RLIM_NLIMITS 10 +#define RLIM_NLIMITS 11 /* * SuS says limits have to be unsigned. @@ -36,6 +37,7 @@ {LONG_MAX, LONG_MAX}, \ {0, 0}, \ {INR_OPEN, INR_OPEN}, \ + {LONG_MAX, LONG_MAX}, \ {LONG_MAX, LONG_MAX}, \ {LONG_MAX, LONG_MAX} \ } diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-mips/fcntl.h linux/include/asm-mips/fcntl.h --- v2.4.0-test8/linux/include/asm-mips/fcntl.h Wed Jul 5 11:13:39 2000 +++ linux/include/asm-mips/fcntl.h Fri Sep 22 14:21:20 2000 @@ -56,6 +56,9 @@ #define F_EXLCK 4 /* or 3 */ #define F_SHLCK 8 /* or 4 */ +/* for leases */ +#define F_INPROGRESS 16 + /* operations for bsd flock(), also used by the kernel implementation */ #define LOCK_SH 1 /* shared lock */ #define LOCK_EX 2 /* exclusive lock */ @@ -63,6 +66,11 @@ blocking */ #define LOCK_UN 8 /* remove lock */ +#define LOCK_MAND 32 /* This is a mandatory flock */ +#define LOCK_READ 64 /* ... Which allows concurrent read operations */ +#define LOCK_WRITE 128 /* ... Which allows concurrent write operations */ +#define LOCK_RW 192 /* ... Which allows concurrent read & write ops */ + typedef struct flock { short l_type; short l_whence; @@ -73,4 +81,5 @@ long pad[4]; /* ZZZZZZZZZZZZZZZZZZZZZZZZZZ */ } flock_t; +#define F_LINUX_SPECIFIC_BASE 1024 #endif /* __ASM_MIPS_FCNTL_H */ diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-mips/resource.h linux/include/asm-mips/resource.h --- v2.4.0-test8/linux/include/asm-mips/resource.h Sat May 13 08:31:25 2000 +++ linux/include/asm-mips/resource.h Fri Sep 22 14:21:20 2000 @@ -22,8 +22,9 @@ #define RLIMIT_RSS 7 /* max resident set size */ #define RLIMIT_NPROC 8 /* max number of processes */ #define RLIMIT_MEMLOCK 9 /* max locked-in-memory address space */ +#define RLIMIT_LOCKS 10 /* maximum file locks held */ -#define RLIM_NLIMITS 10 /* Number of limit flavors. */ +#define RLIM_NLIMITS 11 /* Number of limit flavors. */ /* * SuS says limits have to be unsigned. @@ -44,6 +45,7 @@ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { 0, 0 }, \ + { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ } diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-mips64/fcntl.h linux/include/asm-mips64/fcntl.h --- v2.4.0-test8/linux/include/asm-mips64/fcntl.h Wed Jul 5 11:13:39 2000 +++ linux/include/asm-mips64/fcntl.h Fri Sep 22 14:21:20 2000 @@ -56,6 +56,9 @@ #define F_EXLCK 4 /* or 3 */ #define F_SHLCK 8 /* or 4 */ +/* for leases */ +#define F_INPROGRESS 16 + /* operations for bsd flock(), also used by the kernel implementation */ #define LOCK_SH 1 /* shared lock */ #define LOCK_EX 2 /* exclusive lock */ @@ -63,6 +66,11 @@ blocking */ #define LOCK_UN 8 /* remove lock */ +#define LOCK_MAND 32 /* This is a mandatory flock */ +#define LOCK_READ 64 /* ... Which allows concurrent read operations */ +#define LOCK_WRITE 128 /* ... Which allows concurrent write operations */ +#define LOCK_RW 192 /* ... Which allows concurrent read & write ops */ + typedef struct flock { short l_type; short l_whence; @@ -73,4 +81,5 @@ long pad[4]; /* ZZZZZZZZZZZZZZZZZZZZZZZZZZ */ } flock_t; +#define F_LINUX_SPECIFIC_BASE 1024 #endif /* _ASM_FCNTL_H */ diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-mips64/resource.h linux/include/asm-mips64/resource.h --- v2.4.0-test8/linux/include/asm-mips64/resource.h Sun Jul 9 22:18:15 2000 +++ linux/include/asm-mips64/resource.h Fri Sep 22 14:21:20 2000 @@ -23,8 +23,9 @@ #define RLIMIT_RSS 7 /* max resident set size */ #define RLIMIT_NPROC 8 /* max number of processes */ #define RLIMIT_MEMLOCK 9 /* max locked-in-memory address space */ +#define RLIMIT_LOCKS 10 /* maximum file locks held */ -#define RLIM_NLIMITS 10 /* Number of limit flavors. */ +#define RLIM_NLIMITS 11 /* Number of limit flavors. */ /* * SuS says limits have to be unsigned. @@ -45,6 +46,7 @@ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { 0, 0 }, \ + { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ } diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-ppc/atomic.h linux/include/asm-ppc/atomic.h --- v2.4.0-test8/linux/include/asm-ppc/atomic.h Tue May 2 13:05:40 2000 +++ linux/include/asm-ppc/atomic.h Mon Oct 2 11:54:51 2000 @@ -5,13 +5,7 @@ #ifndef _ASM_PPC_ATOMIC_H_ #define _ASM_PPC_ATOMIC_H_ -#include - -#ifdef CONFIG_SMP typedef struct { volatile int counter; } atomic_t; -#else -typedef struct { int counter; } atomic_t; -#endif #define ATOMIC_INIT(i) { (i) } @@ -21,7 +15,7 @@ extern void atomic_clear_mask(unsigned long mask, unsigned long *addr); extern void atomic_set_mask(unsigned long mask, unsigned long *addr); -extern __inline__ int atomic_add_return(int a, atomic_t *v) +static __inline__ int atomic_add_return(int a, atomic_t *v) { int t; @@ -30,14 +24,14 @@ add %0,%2,%0\n\ stwcx. %0,0,%3\n\ bne- 1b" - : "=&r" (t), "=m" (*v) - : "r" (a), "r" (v), "m" (*v) + : "=&r" (t), "=m" (v->counter) + : "r" (a), "r" (v), "m" (v->counter) : "cc"); return t; } -extern __inline__ int atomic_sub_return(int a, atomic_t *v) +static __inline__ int atomic_sub_return(int a, atomic_t *v) { int t; @@ -46,14 +40,14 @@ subf %0,%2,%0\n\ stwcx. %0,0,%3\n\ bne- 1b" - : "=&r" (t), "=m" (*v) - : "r" (a), "r" (v), "m" (*v) + : "=&r" (t), "=m" (v->counter) + : "r" (a), "r" (v), "m" (v->counter) : "cc"); return t; } -extern __inline__ int atomic_inc_return(atomic_t *v) +static __inline__ int atomic_inc_return(atomic_t *v) { int t; @@ -62,14 +56,14 @@ addic %0,%0,1\n\ stwcx. %0,0,%2\n\ bne- 1b" - : "=&r" (t), "=m" (*v) - : "r" (v), "m" (*v) + : "=&r" (t), "=m" (v->counter) + : "r" (v), "m" (v->counter) : "cc"); return t; } -extern __inline__ int atomic_dec_return(atomic_t *v) +static __inline__ int atomic_dec_return(atomic_t *v) { int t; @@ -78,8 +72,8 @@ addic %0,%0,-1\n\ stwcx. %0,0,%2\n\ bne 1b" - : "=&r" (t), "=m" (*v) - : "r" (v), "m" (*v) + : "=&r" (t), "=m" (v->counter) + : "r" (v), "m" (v->counter) : "cc"); return t; diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-ppc/backlight.h linux/include/asm-ppc/backlight.h --- v2.4.0-test8/linux/include/asm-ppc/backlight.h Thu Jul 13 09:42:51 2000 +++ linux/include/asm-ppc/backlight.h Sun Sep 17 09:48:07 2000 @@ -25,4 +25,4 @@ extern int set_backlight_level(int level); extern int get_backlight_level(void); -#endif \ No newline at end of file +#endif diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-ppc/bitops.h linux/include/asm-ppc/bitops.h --- v2.4.0-test8/linux/include/asm-ppc/bitops.h Wed Jul 5 22:15:26 2000 +++ linux/include/asm-ppc/bitops.h Wed Sep 27 13:41:33 2000 @@ -9,17 +9,9 @@ #include #include -extern void set_bit(int nr, volatile void *addr); -extern void clear_bit(int nr, volatile void *addr); -extern void change_bit(int nr, volatile void *addr); -extern int test_and_set_bit(int nr, volatile void *addr); -extern int test_and_clear_bit(int nr, volatile void *addr); -extern int test_and_change_bit(int nr, volatile void *addr); - /* - * Arguably these bit operations don't imply any memory barrier or - * SMP ordering, but in fact a lot of drivers expect them to imply - * both, since they do on x86 cpus. + * The test_and_*_bit operations are taken to imply a memory barrier + * on SMP systems. */ #ifdef CONFIG_SMP #define SMP_WMB "eieio\n" @@ -36,58 +28,75 @@ * These used to be if'd out here because using : "cc" as a constraint * resulted in errors from egcs. Things may be OK with gcc-2.95. */ -extern __inline__ void set_bit(int nr, volatile void * addr) +static __inline__ void set_bit(int nr, volatile void * addr) { unsigned long old; unsigned long mask = 1 << (nr & 0x1f); unsigned long *p = ((unsigned long *)addr) + (nr >> 5); - __asm__ __volatile__(SMP_WMB "\ + __asm__ __volatile__("\ 1: lwarx %0,0,%3 or %0,%0,%2 stwcx. %0,0,%3 - bne 1b" - SMP_MB + bne- 1b" : "=&r" (old), "=m" (*p) : "r" (mask), "r" (p), "m" (*p) : "cc" ); } -extern __inline__ void clear_bit(int nr, volatile void *addr) +/* + * non-atomic version + */ +static __inline__ void __set_bit(int nr, volatile void *addr) +{ + unsigned long mask = 1 << (nr & 0x1f); + unsigned long *p = ((unsigned long *)addr) + (nr >> 5); + + *p |= mask; +} + +/* + * clear_bit doesn't imply a memory barrier + */ +#define smp_mb__before_clear_bit() smp_mb() +#define smp_mb__after_clear_bit() smp_mb() + +static __inline__ void clear_bit(int nr, volatile void *addr) { unsigned long old; unsigned long mask = 1 << (nr & 0x1f); unsigned long *p = ((unsigned long *)addr) + (nr >> 5); - __asm__ __volatile__(SMP_WMB "\ + __asm__ __volatile__("\ 1: lwarx %0,0,%3 andc %0,%0,%2 stwcx. %0,0,%3 - bne 1b" - SMP_MB + bne- 1b" : "=&r" (old), "=m" (*p) : "r" (mask), "r" (p), "m" (*p) : "cc"); } -extern __inline__ void change_bit(int nr, volatile void *addr) +static __inline__ void change_bit(int nr, volatile void *addr) { unsigned long old; unsigned long mask = 1 << (nr & 0x1f); unsigned long *p = ((unsigned long *)addr) + (nr >> 5); - __asm__ __volatile__(SMP_WMB "\ + __asm__ __volatile__("\ 1: lwarx %0,0,%3 xor %0,%0,%2 stwcx. %0,0,%3 - bne 1b" - SMP_MB + bne- 1b" : "=&r" (old), "=m" (*p) : "r" (mask), "r" (p), "m" (*p) : "cc"); } -extern __inline__ int test_and_set_bit(int nr, volatile void *addr) +/* + * test_and_*_bit do imply a memory barrier (?) + */ +static __inline__ int test_and_set_bit(int nr, volatile void *addr) { unsigned int old, t; unsigned int mask = 1 << (nr & 0x1f); @@ -101,12 +110,25 @@ SMP_MB : "=&r" (old), "=&r" (t), "=m" (*p) : "r" (mask), "r" (p), "m" (*p) - : "cc"); + : "cc", "memory"); + + return (old & mask) != 0; +} +/* + * non-atomic version + */ +static __inline__ int __test_and_set_bit(int nr, volatile void *addr) +{ + unsigned long mask = 1 << (nr & 0x1f); + unsigned long *p = ((unsigned long *)addr) + (nr >> 5); + unsigned long old = *p; + + *p = old | mask; return (old & mask) != 0; } -extern __inline__ int test_and_clear_bit(int nr, volatile void *addr) +static __inline__ int test_and_clear_bit(int nr, volatile void *addr) { unsigned int old, t; unsigned int mask = 1 << (nr & 0x1f); @@ -120,12 +142,25 @@ SMP_MB : "=&r" (old), "=&r" (t), "=m" (*p) : "r" (mask), "r" (p), "m" (*p) - : "cc"); + : "cc", "memory"); return (old & mask) != 0; } -extern __inline__ int test_and_change_bit(int nr, volatile void *addr) +/* + * non-atomic version + */ +static __inline__ int __test_and_clear_bit(int nr, volatile void *addr) +{ + unsigned long mask = 1 << (nr & 0x1f); + unsigned long *p = ((unsigned long *)addr) + (nr >> 5); + unsigned long old = *p; + + *p = old & ~mask; + return (old & mask) != 0; +} + +static __inline__ int test_and_change_bit(int nr, volatile void *addr) { unsigned int old, t; unsigned int mask = 1 << (nr & 0x1f); @@ -139,13 +174,22 @@ SMP_MB : "=&r" (old), "=&r" (t), "=m" (*p) : "r" (mask), "r" (p), "m" (*p) - : "cc"); + : "cc", "memory"); return (old & mask) != 0; } +#else /* __INLINE_BITOPS */ + +extern void set_bit(int nr, volatile void *addr); +extern void clear_bit(int nr, volatile void *addr); +extern void change_bit(int nr, volatile void *addr); +extern int test_and_set_bit(int nr, volatile void *addr); +extern int test_and_clear_bit(int nr, volatile void *addr); +extern int test_and_change_bit(int nr, volatile void *addr); + #endif /* __INLINE_BITOPS */ -extern __inline__ int test_bit(int nr, __const__ volatile void *addr) +static __inline__ int test_bit(int nr, __const__ volatile void *addr) { __const__ unsigned int *p = (__const__ unsigned int *) addr; @@ -153,7 +197,7 @@ } /* Return the bit position of the most significant 1 bit in a word */ -extern __inline__ int __ilog2(unsigned int x) +static __inline__ int __ilog2(unsigned int x) { int lz; @@ -161,7 +205,7 @@ return 31 - lz; } -extern __inline__ int ffz(unsigned int x) +static __inline__ int ffz(unsigned int x) { if ((x = ~x) == 0) return 32; @@ -175,7 +219,7 @@ * the libc and compiler builtin ffs routines, therefore * differs in spirit from the above ffz (man ffs). */ -extern __inline__ int ffs(int x) +static __inline__ int ffs(int x) { return __ilog2(x & -x) + 1; } @@ -198,7 +242,7 @@ #define find_first_zero_bit(addr, size) \ find_next_zero_bit((addr), (size), 0) -extern __inline__ unsigned long find_next_zero_bit(void * addr, +static __inline__ unsigned long find_next_zero_bit(void * addr, unsigned long size, unsigned long offset) { unsigned int * p = ((unsigned int *) addr) + (offset >> 5); @@ -230,6 +274,8 @@ tmp = *p; found_first: tmp |= ~0UL << size; + if (tmp == ~0UL) /* Are any bits zero? */ + return result + size; /* Nope. */ found_middle: return result + ffz(tmp); } @@ -238,42 +284,11 @@ #define _EXT2_HAVE_ASM_BITOPS_ #ifdef __KERNEL__ -/* - * test_and_{set,clear}_bit guarantee atomicity without - * disabling interrupts. - */ -#define ext2_set_bit(nr, addr) test_and_set_bit((nr) ^ 0x18, addr) -#define ext2_clear_bit(nr, addr) test_and_clear_bit((nr) ^ 0x18, addr) -#else -extern __inline__ int ext2_set_bit(int nr, void * addr) -{ - int mask; - unsigned char *ADDR = (unsigned char *) addr; - int oldbit; - - ADDR += nr >> 3; - mask = 1 << (nr & 0x07); - oldbit = (*ADDR & mask) ? 1 : 0; - *ADDR |= mask; - return oldbit; -} - -extern __inline__ int ext2_clear_bit(int nr, void * addr) -{ - int mask; - unsigned char *ADDR = (unsigned char *) addr; - int oldbit; - - ADDR += nr >> 3; - mask = 1 << (nr & 0x07); - oldbit = (*ADDR & mask) ? 1 : 0; - *ADDR = *ADDR & ~mask; - return oldbit; -} -#endif /* __KERNEL__ */ +#define ext2_set_bit(nr, addr) __test_and_set_bit((nr) ^ 0x18, addr) +#define ext2_clear_bit(nr, addr) __test_and_clear_bit((nr) ^ 0x18, addr) -extern __inline__ int ext2_test_bit(int nr, __const__ void * addr) +static __inline__ int ext2_test_bit(int nr, __const__ void * addr) { __const__ unsigned char *ADDR = (__const__ unsigned char *) addr; @@ -288,7 +303,7 @@ #define ext2_find_first_zero_bit(addr, size) \ ext2_find_next_zero_bit((addr), (size), 0) -extern __inline__ unsigned long ext2_find_next_zero_bit(void *addr, +static __inline__ unsigned long ext2_find_next_zero_bit(void *addr, unsigned long size, unsigned long offset) { unsigned int *p = ((unsigned int *) addr) + (offset >> 5); @@ -320,6 +335,8 @@ tmp = cpu_to_le32p(p); found_first: tmp |= ~0U << size; + if (tmp == ~0UL) /* Are any bits zero? */ + return result + size; /* Nope. */ found_middle: return result + ffz(tmp); } @@ -330,5 +347,7 @@ #define minix_test_and_clear_bit(nr,addr) ext2_clear_bit(nr,addr) #define minix_test_bit(nr,addr) ext2_test_bit(nr,addr) #define minix_find_first_zero_bit(addr,size) ext2_find_first_zero_bit(addr,size) + +#endif /* __KERNEL__ */ #endif /* _PPC_BITOPS_H */ diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-ppc/bootx.h linux/include/asm-ppc/bootx.h --- v2.4.0-test8/linux/include/asm-ppc/bootx.h Sat Nov 27 15:42:33 1999 +++ linux/include/asm-ppc/bootx.h Sun Sep 17 09:48:08 2000 @@ -133,4 +133,3 @@ #endif #endif - \ No newline at end of file diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-ppc/cpm_8260.h linux/include/asm-ppc/cpm_8260.h --- v2.4.0-test8/linux/include/asm-ppc/cpm_8260.h Mon May 15 14:53:31 2000 +++ linux/include/asm-ppc/cpm_8260.h Sun Sep 17 09:48:08 2000 @@ -85,6 +85,7 @@ #define CPM_DATAONLY_BASE ((uint)128) #define CPM_DATAONLY_SIZE ((uint)(16 * 1024) - CPM_DATAONLY_BASE) #define CPM_DP_NOSPACE ((uint)0x7fffffff) +#define CPM_FCC_SPECIAL_BASE ((uint)0x0000b000) /* The number of pages of host memory we allocate for CPM. This is * done early in kernel initialization to get physically contiguous @@ -97,8 +98,8 @@ * and dual port ram. */ extern cpm8260_t *cpmp; /* Pointer to comm processor */ -uint m8260_cpm_dpalloc(uint size); -uint m8260_cpm_hostalloc(uint size); +uint m8260_cpm_dpalloc(uint size, uint align); +uint m8260_cpm_hostalloc(uint size, uint align); void m8260_cpm_setbrg(uint brg, uint rate); void m8260_cpm_fastbrg(uint brg, uint rate, int div16); @@ -153,7 +154,7 @@ #define PROFF_REVNUM ((uint)0x8af0) #define PROFF_RAND ((uint)0x8af8) #define PROFF_I2C_BASE ((uint)0x8afc) -#define PROFF_IDMA4_BASE ((uint)0x89fe) +#define PROFF_IDMA4_BASE ((uint)0x8afe) /* The SMCs are relocated to any of the first eight DPRAM pages. * We will fix these at the first locations of DPRAM, until we @@ -403,40 +404,44 @@ #define SCCE_ENET_TXB ((ushort)0x0002) /* A buffer was transmitted */ #define SCCE_ENET_RXB ((ushort)0x0001) /* A buffer was received */ -/* SCC Mode Register (PMSR) as used by Ethernet. +/* SCC Mode Register (PSMR) as used by Ethernet. */ -#define SCC_PMSR_HBC ((ushort)0x8000) /* Enable heartbeat */ -#define SCC_PMSR_FC ((ushort)0x4000) /* Force collision */ -#define SCC_PMSR_RSH ((ushort)0x2000) /* Receive short frames */ -#define SCC_PMSR_IAM ((ushort)0x1000) /* Check individual hash */ -#define SCC_PMSR_ENCRC ((ushort)0x0800) /* Ethernet CRC mode */ -#define SCC_PMSR_PRO ((ushort)0x0200) /* Promiscuous mode */ -#define SCC_PMSR_BRO ((ushort)0x0100) /* Catch broadcast pkts */ -#define SCC_PMSR_SBT ((ushort)0x0080) /* Special backoff timer */ -#define SCC_PMSR_LPB ((ushort)0x0040) /* Set Loopback mode */ -#define SCC_PMSR_SIP ((ushort)0x0020) /* Sample Input Pins */ -#define SCC_PMSR_LCW ((ushort)0x0010) /* Late collision window */ -#define SCC_PMSR_NIB22 ((ushort)0x000a) /* Start frame search */ -#define SCC_PMSR_FDE ((ushort)0x0001) /* Full duplex enable */ +#define SCC_PSMR_HBC ((ushort)0x8000) /* Enable heartbeat */ +#define SCC_PSMR_FC ((ushort)0x4000) /* Force collision */ +#define SCC_PSMR_RSH ((ushort)0x2000) /* Receive short frames */ +#define SCC_PSMR_IAM ((ushort)0x1000) /* Check individual hash */ +#define SCC_PSMR_ENCRC ((ushort)0x0800) /* Ethernet CRC mode */ +#define SCC_PSMR_PRO ((ushort)0x0200) /* Promiscuous mode */ +#define SCC_PSMR_BRO ((ushort)0x0100) /* Catch broadcast pkts */ +#define SCC_PSMR_SBT ((ushort)0x0080) /* Special backoff timer */ +#define SCC_PSMR_LPB ((ushort)0x0040) /* Set Loopback mode */ +#define SCC_PSMR_SIP ((ushort)0x0020) /* Sample Input Pins */ +#define SCC_PSMR_LCW ((ushort)0x0010) /* Late collision window */ +#define SCC_PSMR_NIB22 ((ushort)0x000a) /* Start frame search */ +#define SCC_PSMR_FDE ((ushort)0x0001) /* Full duplex enable */ /* Buffer descriptor control/status used by Ethernet receive. -*/ + * Common to SCC and FCC. + */ #define BD_ENET_RX_EMPTY ((ushort)0x8000) #define BD_ENET_RX_WRAP ((ushort)0x2000) #define BD_ENET_RX_INTR ((ushort)0x1000) #define BD_ENET_RX_LAST ((ushort)0x0800) #define BD_ENET_RX_FIRST ((ushort)0x0400) #define BD_ENET_RX_MISS ((ushort)0x0100) +#define BD_ENET_RX_BC ((ushort)0x0080) /* FCC Only */ +#define BD_ENET_RX_MC ((ushort)0x0040) /* FCC Only */ #define BD_ENET_RX_LG ((ushort)0x0020) #define BD_ENET_RX_NO ((ushort)0x0010) #define BD_ENET_RX_SH ((ushort)0x0008) #define BD_ENET_RX_CR ((ushort)0x0004) #define BD_ENET_RX_OV ((ushort)0x0002) #define BD_ENET_RX_CL ((ushort)0x0001) -#define BD_ENET_RX_STATS ((ushort)0x013f) /* All status bits */ +#define BD_ENET_RX_STATS ((ushort)0x01ff) /* All status bits */ /* Buffer descriptor control/status used by Ethernet transmit. -*/ + * Common to SCC and FCC. + */ #define BD_ENET_TX_READY ((ushort)0x8000) #define BD_ENET_TX_PAD ((ushort)0x4000) #define BD_ENET_TX_WRAP ((ushort)0x2000) @@ -522,6 +527,152 @@ } scc_trans_t; #define BD_SCC_TX_LAST ((ushort)0x0800) + +/* How about some FCCs..... +*/ +#define FCC_GFMR_DIAG_NORM ((uint)0x00000000) +#define FCC_GFMR_DIAG_LE ((uint)0x40000000) +#define FCC_GFMR_DIAG_AE ((uint)0x80000000) +#define FCC_GFMR_DIAG_ALE ((uint)0xc0000000) +#define FCC_GFMR_TCI ((uint)0x20000000) +#define FCC_GFMR_TRX ((uint)0x10000000) +#define FCC_GFMR_TTX ((uint)0x08000000) +#define FCC_GFMR_TTX ((uint)0x08000000) +#define FCC_GFMR_CDP ((uint)0x04000000) +#define FCC_GFMR_CTSP ((uint)0x02000000) +#define FCC_GFMR_CDS ((uint)0x01000000) +#define FCC_GFMR_CTSS ((uint)0x00800000) +#define FCC_GFMR_SYNL_NONE ((uint)0x00000000) +#define FCC_GFMR_SYNL_AUTO ((uint)0x00004000) +#define FCC_GFMR_SYNL_8 ((uint)0x00008000) +#define FCC_GFMR_SYNL_16 ((uint)0x0000c000) +#define FCC_GFMR_RTSM ((uint)0x00002000) +#define FCC_GFMR_RENC_NRZ ((uint)0x00000000) +#define FCC_GFMR_RENC_NRZI ((uint)0x00000800) +#define FCC_GFMR_REVD ((uint)0x00000400) +#define FCC_GFMR_TENC_NRZ ((uint)0x00000000) +#define FCC_GFMR_TENC_NRZI ((uint)0x00000100) +#define FCC_GFMR_TCRC_16 ((uint)0x00000000) +#define FCC_GFMR_TCRC_32 ((uint)0x00000080) +#define FCC_GFMR_ENR ((uint)0x00000020) +#define FCC_GFMR_ENT ((uint)0x00000010) +#define FCC_GFMR_MODE_ENET ((uint)0x0000000c) +#define FCC_GFMR_MODE_ATM ((uint)0x0000000a) +#define FCC_GFMR_MODE_HDLC ((uint)0x00000000) + +/* Generic FCC parameter ram. +*/ +typedef struct fcc_param { + ushort fcc_riptr; /* Rx Internal temp pointer */ + ushort fcc_tiptr; /* Tx Internal temp pointer */ + ushort fcc_res1; + ushort fcc_mrblr; /* Max receive buffer length, mod 32 bytes */ + uint fcc_rstate; /* Upper byte is Func code, must be set */ + uint fcc_rbase; /* Receive BD base */ + ushort fcc_rbdstat; /* RxBD status */ + ushort fcc_rbdlen; /* RxBD down counter */ + uint fcc_rdptr; /* RxBD internal data pointer */ + uint fcc_tstate; /* Upper byte is Func code, must be set */ + uint fcc_tbase; /* Transmit BD base */ + ushort fcc_tbdstat; /* TxBD status */ + ushort fcc_tbdlen; /* TxBD down counter */ + uint fcc_tdptr; /* TxBD internal data pointer */ + uint fcc_rbptr; /* Rx BD Internal buf pointer */ + uint fcc_tbptr; /* Tx BD Internal buf pointer */ + uint fcc_rcrc; /* Rx temp CRC */ + uint fcc_res2; + uint fcc_tcrc; /* Tx temp CRC */ +} fccp_t; + + +/* Ethernet controller through FCC. +*/ +typedef struct fcc_enet { + fccp_t fen_genfcc; + uint fen_statbuf; /* Internal status buffer */ + uint fen_camptr; /* CAM address */ + uint fen_cmask; /* Constant mask for CRC */ + uint fen_cpres; /* Preset CRC */ + uint fen_crcec; /* CRC Error counter */ + uint fen_alec; /* alignment error counter */ + uint fen_disfc; /* discard frame counter */ + ushort fen_retlim; /* Retry limit */ + ushort fen_retcnt; /* Retry counter */ + ushort fen_pper; /* Persistence */ + ushort fen_boffcnt; /* backoff counter */ + uint fen_gaddrh; /* Group address filter, high 32-bits */ + uint fen_gaddrl; /* Group address filter, low 32-bits */ + ushort fen_tfcstat; /* out of sequence TxBD */ + ushort fen_tfclen; + uint fen_tfcptr; + ushort fen_mflr; /* Maximum frame length (1518) */ + ushort fen_paddrh; /* MAC address */ + ushort fen_paddrm; + ushort fen_paddrl; + ushort fen_ibdcount; /* Internal BD counter */ + ushort fen_idbstart; /* Internal BD start pointer */ + ushort fen_ibdend; /* Internal BD end pointer */ + ushort fen_txlen; /* Internal Tx frame length counter */ + uint fen_ibdbase[8]; /* Internal use */ + uint fen_iaddrh; /* Individual address filter */ + uint fen_iaddrl; + ushort fen_minflr; /* Minimum frame length (64) */ + ushort fen_taddrh; /* Filter transfer MAC address */ + ushort fen_taddrm; + ushort fen_taddrl; + ushort fen_padptr; /* Pointer to pad byte buffer */ + ushort fen_cftype; /* control frame type */ + ushort fen_cfrange; /* control frame range */ + ushort fen_maxb; /* maximum BD count */ + ushort fen_maxd1; /* Max DMA1 length (1520) */ + ushort fen_maxd2; /* Max DMA2 length (1520) */ + ushort fen_maxd; /* internal max DMA count */ + ushort fen_dmacnt; /* internal DMA counter */ + uint fen_octc; /* Total octect counter */ + uint fen_colc; /* Total collision counter */ + uint fen_broc; /* Total broadcast packet counter */ + uint fen_mulc; /* Total multicast packet count */ + uint fen_uspc; /* Total packets < 64 bytes */ + uint fen_frgc; /* Total packets < 64 bytes with errors */ + uint fen_ospc; /* Total packets > 1518 */ + uint fen_jbrc; /* Total packets > 1518 with errors */ + uint fen_p64c; /* Total packets == 64 bytes */ + uint fen_p65c; /* Total packets 64 < bytes <= 127 */ + uint fen_p128c; /* Total packets 127 < bytes <= 255 */ + uint fen_p256c; /* Total packets 256 < bytes <= 511 */ + uint fen_p512c; /* Total packets 512 < bytes <= 1023 */ + uint fen_p1024c; /* Total packets 1024 < bytes <= 1518 */ + uint fen_cambuf; /* Internal CAM buffer poiner */ + ushort fen_rfthr; /* Received frames threshold */ + ushort fen_rfcnt; /* Received frames count */ +} fcc_enet_t; + +/* FCC Event/Mask register as used by Ethernet. +*/ +#define FCC_ENET_GRA ((ushort)0x0080) /* Graceful stop complete */ +#define FCC_ENET_RXC ((ushort)0x0040) /* Control Frame Received */ +#define FCC_ENET_TXC ((ushort)0x0020) /* Out of seq. Tx sent */ +#define FCC_ENET_TXE ((ushort)0x0010) /* Transmit Error */ +#define FCC_ENET_RXF ((ushort)0x0008) /* Full frame received */ +#define FCC_ENET_BSY ((ushort)0x0004) /* Busy. Rx Frame dropped */ +#define FCC_ENET_TXB ((ushort)0x0002) /* A buffer was transmitted */ +#define FCC_ENET_RXB ((ushort)0x0001) /* A buffer was received */ + +/* FCC Mode Register (FPSMR) as used by Ethernet. +*/ +#define FCC_PSMR_HBC ((uint)0x80000000) /* Enable heartbeat */ +#define FCC_PSMR_FC ((uint)0x40000000) /* Force Collision */ +#define FCC_PSMR_SBT ((uint)0x20000000) /* Stop backoff timer */ +#define FCC_PSMR_LPB ((uint)0x10000000) /* Local protect. 1 = FDX */ +#define FCC_PSMR_LCW ((uint)0x08000000) /* Late collision select */ +#define FCC_PSMR_FDE ((uint)0x04000000) /* Full Duplex Enable */ +#define FCC_PSMR_MON ((uint)0x02000000) /* RMON Enable */ +#define FCC_PSMR_PRO ((uint)0x00400000) /* Promiscuous Enable */ +#define FCC_PSMR_FCE ((uint)0x00200000) /* Flow Control Enable */ +#define FCC_PSMR_RSH ((uint)0x00100000) /* Receive Short Frames */ +#define FCC_PSMR_CAM ((uint)0x00000400) /* CAM enable */ +#define FCC_PSMR_BRO ((uint)0x00000200) /* Broadcast pkt discard */ +#define FCC_PSMR_ENCRC ((uint)0x00000080) /* Use 32-bit CRC */ /* IIC parameter RAM. */ diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-ppc/fcntl.h linux/include/asm-ppc/fcntl.h --- v2.4.0-test8/linux/include/asm-ppc/fcntl.h Wed Jul 5 11:13:39 2000 +++ linux/include/asm-ppc/fcntl.h Fri Sep 22 14:21:20 2000 @@ -35,6 +35,10 @@ #define F_SETSIG 10 /* for sockets. */ #define F_GETSIG 11 /* for sockets. */ +#define F_GETLK64 12 /* using 'struct flock64' */ +#define F_SETLK64 13 +#define F_SETLKW64 14 + /* for F_[GET|SET]FL */ #define FD_CLOEXEC 1 /* actually anything with low bit set goes */ @@ -47,6 +51,9 @@ #define F_EXLCK 4 /* or 3 */ #define F_SHLCK 8 /* or 4 */ +/* for leases */ +#define F_INPROGRESS 16 + /* operations for bsd flock(), also used by the kernel implementation */ #define LOCK_SH 1 /* shared lock */ #define LOCK_EX 2 /* exclusive lock */ @@ -54,6 +61,11 @@ blocking */ #define LOCK_UN 8 /* remove lock */ +#define LOCK_MAND 32 /* This is a mandatory flock */ +#define LOCK_READ 64 /* ... Which allows concurrent read operations */ +#define LOCK_WRITE 128 /* ... Which allows concurrent write operations */ +#define LOCK_RW 192 /* ... Which allows concurrent read & write ops */ + #ifdef __KERNEL__ #define F_POSIX 1 #define F_FLOCK 2 @@ -68,4 +80,13 @@ pid_t l_pid; }; +struct flock64 { + short l_type; + short l_whence; + loff_t l_start; + loff_t l_len; + pid_t l_pid; +}; + +#define F_LINUX_SPECIFIC_BASE 1024 #endif diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-ppc/feature.h linux/include/asm-ppc/feature.h --- v2.4.0-test8/linux/include/asm-ppc/feature.h Thu Jul 13 09:42:51 2000 +++ linux/include/asm-ppc/feature.h Sun Sep 17 09:48:08 2000 @@ -7,7 +7,9 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 1998 Paul Mackerras. + * Copyright (C) 1998 Paul Mackerras & + * Ben. Herrenschmidt. + * * */ #ifndef __ASM_PPC_FEATURE_H @@ -75,6 +77,9 @@ * Additional functions related to Core99 machines */ extern void feature_set_gmac_power(struct device_node* device, int power); + + /* use constants in KeyLargo.h for the reset parameter */ +extern void feature_set_gmac_phy_reset(struct device_node* device, int reset); extern void feature_set_usb_power(struct device_node* device, int power); diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-ppc/hardirq.h linux/include/asm-ppc/hardirq.h --- v2.4.0-test8/linux/include/asm-ppc/hardirq.h Fri Aug 4 16:15:37 2000 +++ linux/include/asm-ppc/hardirq.h Sun Sep 17 09:48:08 2000 @@ -5,16 +5,23 @@ #include /* entry.S is sensitive to the offsets of these fields */ +/* The __last_jiffy_stamp field is needed to ensure that no decrementer + * interrupt is lost on SMP machines. Since on most CPUs it is in the same + * cache line as local_irq_count, it is cheap to access and is also used on UP + * for uniformity. + */ typedef struct { unsigned int __softirq_active; unsigned int __softirq_mask; unsigned int __local_irq_count; unsigned int __local_bh_count; unsigned int __syscall_count; + unsigned int __last_jiffy_stamp; } ____cacheline_aligned irq_cpustat_t; #include /* Standard mappings for irq_cpustat_t above */ +#define last_jiffy_stamp(cpu) __IRQ_STAT((cpu), __last_jiffy_stamp) /* * Are we in an interrupt context? Either doing bottom half * or hardware interrupt processing? diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-ppc/heathrow.h linux/include/asm-ppc/heathrow.h --- v2.4.0-test8/linux/include/asm-ppc/heathrow.h Thu Jul 13 09:42:51 2000 +++ linux/include/asm-ppc/heathrow.h Sun Sep 17 09:48:08 2000 @@ -44,4 +44,9 @@ #define HRW_BMAC_IO_ENABLE 0x60000000 /* two bits, not documented in OF */ #define HRW_BMAC_RESET 0x80000000 /* not documented in OF */ +/* We OR those features at boot on desktop G3s */ +#define HRW_DEFAULTS (HRW_SCCA_IO | HRW_SCCB_IO | HRW_SCC_ENABLE) + +/* Those seem to be different on paddington */ #define PADD_MODEM_POWER_N 0x00000001 /* modem power on paddington */ +#define PADD_RESET_SCC 0x02000000 /* check this please */ diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-ppc/highmem.h linux/include/asm-ppc/highmem.h --- v2.4.0-test8/linux/include/asm-ppc/highmem.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-ppc/highmem.h Sun Sep 17 09:48:08 2000 @@ -0,0 +1,121 @@ +/* + * highmem.h: virtual kernel memory mappings for high memory + * + * PowerPC version, stolen from the i386 version. + * + * Used in CONFIG_HIGHMEM systems for memory pages which + * are not addressable by direct kernel virtual adresses. + * + * Copyright (C) 1999 Gerhard Wichert, Siemens AG + * Gerhard.Wichert@pdb.siemens.de + * + * + * Redesigned the x86 32-bit VM architecture to deal with + * up to 16 Terrabyte physical memory. With current x86 CPUs + * we now support up to 64 Gigabytes physical RAM. + * + * Copyright (C) 1999 Ingo Molnar + */ + +#ifndef _ASM_HIGHMEM_H +#define _ASM_HIGHMEM_H + +#ifdef __KERNEL__ + +#include +#include +#include +#include + +/* undef for production */ +#define HIGHMEM_DEBUG 1 + +extern pte_t *kmap_pte; +extern pgprot_t kmap_prot; +extern pte_t *pkmap_page_table; + +extern void kmap_init(void) __init; + +/* + * Right now we initialize only a single pte table. It can be extended + * easily, subsequent pte tables have to be allocated in one physical + * chunk of RAM. + */ +#define PKMAP_BASE (0xfe000000UL) +#define LAST_PKMAP 1024 +#define LAST_PKMAP_MASK (LAST_PKMAP-1) +#define PKMAP_NR(virt) ((virt-PKMAP_BASE) >> PAGE_SHIFT) +#define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT)) + +#define KMAP_FIX_BEGIN (0xfe400000UL) + +extern unsigned long kmap_high(struct page *page); +extern void kunmap_high(struct page *page); + +extern inline unsigned long kmap(struct page *page) +{ + if (in_interrupt()) + BUG(); + if (page < highmem_start_page) + return (unsigned long) page_address(page); + return kmap_high(page); +} + +extern inline void kunmap(struct page *page) +{ + if (in_interrupt()) + BUG(); + if (page < highmem_start_page) + return; + kunmap_high(page); +} + +/* + * The use of kmap_atomic/kunmap_atomic is discouraged - kmap/kunmap + * gives a more generic (and caching) interface. But kmap_atomic can + * be used in IRQ contexts, so in some (very limited) cases we need + * it. + */ +extern inline unsigned long kmap_atomic(struct page *page, enum km_type type) +{ + unsigned int idx; + unsigned long vaddr; + + if (page < highmem_start_page) + return (unsigned long) page_address(page); + + idx = type + KM_TYPE_NR*smp_processor_id(); + vaddr = KMAP_FIX_BEGIN + idx * PAGE_SIZE; +#if HIGHMEM_DEBUG + if (!pte_none(*(kmap_pte+idx))) + BUG(); +#endif + set_pte(kmap_pte+idx, mk_pte(page, kmap_prot)); + flush_hash_page(0, vaddr); + + return vaddr; +} + +extern inline void kunmap_atomic(unsigned long vaddr, enum km_type type) +{ +#if HIGHMEM_DEBUG + unsigned int idx = type + KM_TYPE_NR*smp_processor_id(); + + if (vaddr < KMAP_FIX_BEGIN) // FIXME + return; + + if (vaddr != KMAP_FIX_BEGIN + idx * PAGE_SIZE) + BUG(); + + /* + * force other mappings to Oops if they'll try to access + * this pte without first remap it + */ + pte_clear(kmap_pte+idx); + flush_hash_page(0, vaddr); +#endif +} + +#endif /* __KERNEL__ */ + +#endif /* _ASM_HIGHMEM_H */ diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-ppc/ide.h linux/include/asm-ppc/ide.h --- v2.4.0-test8/linux/include/asm-ppc/ide.h Tue May 2 13:05:40 2000 +++ linux/include/asm-ppc/ide.h Sun Sep 17 09:48:08 2000 @@ -63,7 +63,6 @@ void ide_outsw(ide_ioreg_t port, void *buf, int ns); void ppc_generic_ide_fix_driveid(struct hd_driveid *id); -#if 0 #undef insw #define insw(port, buf, ns) do { \ ppc_ide_md.insw((port), (buf), (ns)); \ @@ -73,7 +72,6 @@ #define outsw(port, buf, ns) do { \ ppc_ide_md.outsw((port), (buf), (ns)); \ } while (0) -#endif #undef SUPPORT_SLOW_DATA_PORTS #define SUPPORT_SLOW_DATA_PORTS 0 diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-ppc/immap_8260.h linux/include/asm-ppc/immap_8260.h --- v2.4.0-test8/linux/include/asm-ppc/immap_8260.h Tue May 2 13:05:40 2000 +++ linux/include/asm-ppc/immap_8260.h Sun Sep 17 09:48:08 2000 @@ -241,10 +241,12 @@ char res1[2]; ushort fcc_fdsr; char res2[2]; - uint fcc_fcce; - uint fcc_fccm; + ushort fcc_fcce; + char res3[2]; + ushort fcc_fccm; + char res4[2]; u_char fcc_fccs; - char res3[3]; + char res5[3]; u_char fcc_ftirr_phy[4]; } fcc_t; diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-ppc/io.h linux/include/asm-ppc/io.h --- v2.4.0-test8/linux/include/asm-ppc/io.h Mon Jun 19 17:59:37 2000 +++ linux/include/asm-ppc/io.h Sun Sep 17 09:48:08 2000 @@ -25,12 +25,12 @@ #include #elif defined(CONFIG_8260) #include -#else +#else /* 4xx/8xx/8260 */ #ifdef CONFIG_APUS #define _IO_BASE 0 #define _ISA_MEM_BASE 0 #define PCI_DRAM_OFFSET 0 -#else +#else /* CONFIG_APUS */ extern unsigned long isa_io_base; extern unsigned long isa_mem_base; extern unsigned long pci_dram_offset; @@ -54,6 +54,14 @@ #define writel(b,addr) out_le32((volatile u32 *)(addr),(b)) #endif + +#define __raw_readb(addr) (*(volatile unsigned char *)(addr)) +#define __raw_readw(addr) (*(volatile unsigned short *)(addr)) +#define __raw_readl(addr) (*(volatile unsigned int *)(addr)) +#define __raw_writeb(v, addr) (*(volatile unsigned char *)(addr) = (v)) +#define __raw_writew(v, addr) (*(volatile unsigned short *)(addr) = (v)) +#define __raw_writel(v, addr) (*(volatile unsigned int *)(addr) = (v)) + /* * The insw/outsw/insl/outsl macros don't do byte-swapping. * They are only used in practice for transferring buffers which @@ -67,26 +75,76 @@ #define insl(port, buf, nl) _insl_ns((u32 *)((port)+_IO_BASE), (buf), (nl)) #define outsl(port, buf, nl) _outsl_ns((u32 *)((port)+_IO_BASE), (buf), (nl)) +#ifdef CONFIG_ALL_PPC +/* + * We have to handle possible machine checks here on powermacs + * and potentially some CHRPs -- paulus. + */ +#define __do_in_asm(name, op) \ +extern __inline__ unsigned int name(unsigned int port) \ +{ \ + unsigned int x; \ + __asm__ __volatile__( \ + op " %0,0,%1\n" \ + "1: sync\n" \ + "2:\n" \ + ".section .fixup,\"ax\"\n" \ + "3: li %0,-1\n" \ + " b 2b\n" \ + ".previous\n" \ + ".section __ex_table,\"ax\"\n" \ + " .align 2\n" \ + " .long 1b,3b\n" \ + ".previous" \ + : "=&r" (x) \ + : "r" (port + _IO_BASE)); \ + return x; \ +} + +#define __do_out_asm(name, op) \ +extern __inline__ void name(unsigned int val, unsigned int port) \ +{ \ + __asm__ __volatile__( \ + op " %0,0,%1\n" \ + "1: sync\n" \ + "2:\n" \ + ".section __ex_table,\"ax\"\n" \ + " .align 2\n" \ + " .long 1b,2b\n" \ + ".previous" \ + : : "r" (val), "r" (port + _IO_BASE)); \ +} + +__do_in_asm(inb, "lbzx") +__do_in_asm(inw, "lhbrx") +__do_in_asm(inl, "lwbrx") +__do_out_asm(outb, "stbx") +__do_out_asm(outw, "sthbrx") +__do_out_asm(outl, "stwbrx") + +#elif defined(CONFIG_APUS) #define inb(port) in_8((u8 *)((port)+_IO_BASE)) #define outb(val, port) out_8((u8 *)((port)+_IO_BASE), (val)) -#if defined(CONFIG_APUS) #define inw(port) in_be16((u16 *)((port)+_IO_BASE)) #define outw(val, port) out_be16((u16 *)((port)+_IO_BASE), (val)) #define inl(port) in_be32((u32 *)((port)+_IO_BASE)) #define outl(val, port) out_be32((u32 *)((port)+_IO_BASE), (val)) -#else + +#else /* not APUS or ALL_PPC */ +#define inb(port) in_8((u8 *)((port)+_IO_BASE)) +#define outb(val, port) out_8((u8 *)((port)+_IO_BASE), (val)) #define inw(port) in_le16((u16 *)((port)+_IO_BASE)) #define outw(val, port) out_le16((u16 *)((port)+_IO_BASE), (val)) #define inl(port) in_le32((u32 *)((port)+_IO_BASE)) #define outl(val, port) out_le32((u32 *)((port)+_IO_BASE), (val)) #endif -#define inb_p(port) in_8((u8 *)((port)+_IO_BASE)) -#define outb_p(val, port) out_8((u8 *)((port)+_IO_BASE), (val)) -#define inw_p(port) in_le16((u16 *)((port)+_IO_BASE)) -#define outw_p(val, port) out_le16((u16 *)((port)+_IO_BASE), (val)) -#define inl_p(port) in_le32((u32 *)((port)+_IO_BASE)) -#define outl_p(val, port) out_le32((u32 *)((port)+_IO_BASE), (val)) +#define inb_p(port) inb((port)) +#define outb_p(val, port) outb((val), (port)) +#define inw_p(port) inw((port)) +#define outw_p(val, port) outw((val), (port)) +#define inl_p(port) inl((port)) +#define outl_p(val, port) outl((val), (port)) extern void _insb(volatile u8 *port, void *buf, int ns); extern void _outsb(volatile u8 *port, const void *buf, int ns); @@ -123,6 +181,8 @@ */ extern void *__ioremap(unsigned long address, unsigned long size, unsigned long flags); +extern void *__ioremap_at(unsigned long phys, unsigned long size, + unsigned long flags); extern void *ioremap(unsigned long address, unsigned long size); #define ioremap_nocache(addr, size) ioremap((addr), (size)) extern void iounmap(void *addr); diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-ppc/irq.h linux/include/asm-ppc/irq.h --- v2.4.0-test8/linux/include/asm-ppc/irq.h Tue May 2 13:05:40 2000 +++ linux/include/asm-ppc/irq.h Sun Sep 17 09:48:08 2000 @@ -184,6 +184,9 @@ */ #define SIU_INT_SMC1 ((uint)0x04) #define SIU_INT_SMC2 ((uint)0x05) +#define SIU_INT_FCC1 ((uint)0x20) +#define SIU_INT_FCC2 ((uint)0x21) +#define SIU_INT_FCC3 ((uint)0x22) #define SIU_INT_SCC1 ((uint)0x28) #define SIU_INT_SCC2 ((uint)0x29) #define SIU_INT_SCC3 ((uint)0x2a) diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-ppc/keylargo.h linux/include/asm-ppc/keylargo.h --- v2.4.0-test8/linux/include/asm-ppc/keylargo.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-ppc/keylargo.h Sun Sep 17 09:48:08 2000 @@ -0,0 +1,103 @@ +/* + * keylargo.h: definitions for using the "KeyLargo" I/O controller chip. + * + */ + +/* offset from base for feature control registers */ +#define KEYLARGO_MBCR 0x34 /* Media bay control/status */ +#define KEYLARGO_FCR0 0x38 +#define KEYLARGO_FCR1 0x3c +#define KEYLARGO_FCR2 0x40 +#define KEYLARGO_FCR3 0x44 +#define KEYLARGO_FCR4 0x48 + +/* GPIO registers */ +#define KEYLARGO_GPIO_LEVELS0 0x50 +#define KEYLARGO_GPIO_LEVELS1 0x54 +#define KEYLARGO_GPIO_EXTINT_0 0x58 +#define KEYLARGO_GPIO_EXTINT_CNT 18 +#define KEYLARGO_GPIO_0 0x6A +#define KEYLARGO_GPIO_CNT 17 + +/* Specific GPIO regs */ +#define KL_GPIO_ETH_PHY_RESET (KEYLARGO_GPIO_0+0x10) +#define KL_GPIO_ETH_PHY_RESET_ASSERT 0x04 +#define KL_GPIO_ETH_PHY_RESET_RELEASE 0x05 +#define KL_GPIO_ETH_PHY_RESET_TRISTATE 0x00 +/* + * Bits in feature control register + */ +#define KL_MBCR_MBDEV_ENABLE 0x00001000 + +#define KL0_SCC_B_INTF_ENABLE 0x00000001 /* ??? */ +#define KL0_SCC_A_INTF_ENABLE 0x00000002 /* ??? */ +#define KL0_SCC_SLOWPCLK 0x00000004 +#define KL0_SCC_RESET 0x00000008 +#define KL0_SCCA_ENABLE 0x00000010 +#define KL0_SCCB_ENABLE 0x00000020 +#define KL0_SCC_CELL_ENABLE 0x00000040 +#define KL0_IRDA_ENABLE 0x00008000 +#define KL0_IRDA_CLK32_ENABLE 0x00010000 +#define KL0_IRDA_CLK19_ENABLE 0x00020000 +#define KL0_USB0_PAD_SUSPEND0 0x00040000 +#define KL0_USB0_PAD_SUSPEND1 0x00080000 +#define KL0_USB0_CELL_ENABLE 0x00100000 +#define KL0_USB1_PAD_SUSPEND0 0x00400000 +#define KL0_USB1_PAD_SUSPEND1 0x00800000 +#define KL0_USB1_CELL_ENABLE 0x01000000 +#define KL0_USB_REF_SUSPEND 0x10000000 + +#define KL0_SERIAL_ENABLE (KL0_SCC_B_INTF_ENABLE | \ + KL0_SCC_SLOWPCLK | \ + KL0_SCC_CELL_ENABLE | KL0_SCCA_ENABLE) + +#define KL1_AUDIO_SEL_22MCLK 0x00000002 +#define KL1_AUDIO_CLK_ENABLE_BIT 0x00000008 +#define KL1_AUDIO_CLK_OUT_ENABLE 0x00000020 /* Burgundy only ? */ +#define KL1_AUDIO_CELL_ENABLE 0x00000040 +#define KL1_AUDIO_CHOOSE 0x00000080 /* Burgundy only ? */ +#define KL1_I2S0_CELL_ENABLE 0x00000400 +#define KL1_I2S0_CLK_ENABLE_BIT 0x00001000 +#define KL1_I2S0_ENABLE 0x00002000 +#define KL1_I2S1_CELL_ENABLE 0x00020000 +#define KL1_I2S1_CLK_ENABLE_BIT 0x00080000 +#define KL1_I2S1_ENABLE 0x00100000 +#define KL1_EIDE0_ENABLE 0x00800000 +#define KL1_EIDE0_RESET_N 0x01000000 +#define KL1_EIDE1_ENABLE 0x04000000 +#define KL1_EIDE1_RESET_N 0x08000000 +#define KL1_UIDE_ENABLE 0x20000000 +#define KL1_UIDE_RESET_N 0x40000000 + +#define KL2_IOBUS_ENABLE 0x00000002 +#define KL2_SLEEP_STATE_BIT 0x00000100 +#define KL2_MPIC_ENABLE 0x00020000 +#define KL2_MODEM_POWER_N 0x02000000 +#define KL2_AIRPORT_RESET_N 0x08000000 /* Or power ? */ + +#define KL3_SHUTDOWN_PLL_TOTAL 0x00000001 +#define KL3_SHUTDOWN_PLLKW6 0x00000002 +#define KL3_SHUTDOWN_PLLKW4 0x00000004 +#define KL3_SHUTDOWN_PLLKW35 0x00000008 +#define KL3_SHUTDOWN_PLLKW12 0x00000010 +#define KL3_PLL_RESET 0x00000020 +#define KL3_SHUTDOWN_PLL2X 0x00000080 +#define KL3_CLK66_ENABLE 0x00000100 +#define KL3_CLK49_ENABLE 0x00000200 +#define KL3_CLK45_ENABLE 0x00000400 +#define KL3_CLK31_ENABLE 0x00000800 +#define KL3_TIMER_CLK18_ENABLE 0x00001000 +#define KL3_I2S1_CLK18_ENABLE 0x00002000 +#define KL3_I2S0_CLK18_ENABLE 0x00004000 +#define KL3_VIA_CLK16_ENABLE 0x00008000 +#define KL3_STOPPING33_ENABLED 0x00080000 + +/* Port 0,1 : bus 0, port 2,3 : bus 1 */ +#define KL4_SET_PORT_ENABLE(p) (0x00000008 << (p<<3)) +#define KL4_SET_PORT_RESUME(p) (0x00000004 << (p<<3)) +#define KL4_SET_PORT_CONNECT(p) (0x00000002 << (p<<3)) +#define KL4_SET_PORT_DISCONNECT(p) (0x00000001 << (p<<3)) +#define KL4_GET_PORT_RESUME(p) (0x00000040 << (p<<3)) +#define KL4_GET_PORT_CONNECT(p) (0x00000020 << (p<<3)) +#define KL4_GET_PORT_DISCONNECT(p) (0x00000010 << (p<<3)) + diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-ppc/kmap_types.h linux/include/asm-ppc/kmap_types.h --- v2.4.0-test8/linux/include/asm-ppc/kmap_types.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-ppc/kmap_types.h Sun Sep 17 09:48:08 2000 @@ -0,0 +1,10 @@ +#ifndef _ASM_KMAP_TYPES_H +#define _ASM_KMAP_TYPES_H + +enum km_type { + KM_BOUNCE_READ, + KM_BOUNCE_WRITE, + KM_TYPE_NR +}; + +#endif diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-ppc/machdep.h linux/include/asm-ppc/machdep.h --- v2.4.0-test8/linux/include/asm-ppc/machdep.h Tue Jul 18 23:02:09 2000 +++ linux/include/asm-ppc/machdep.h Sun Sep 17 09:48:08 2000 @@ -31,7 +31,7 @@ void (*power_off)(void); void (*halt)(void); - void (*time_init)(void); /* Optional, may be NULL */ + long (*time_init)(void); /* Optional, may be NULL */ int (*set_rtc_time)(unsigned long nowtime); unsigned long (*get_rtc_time)(void); void (*calibrate_decr)(void); @@ -75,7 +75,7 @@ void (*pcibios_fixup)(void); void (*pcibios_fixup_bus)(struct pci_bus *); - void* (*pci_dev_io_base)(unsigned char bus, unsigned char devfn); + void* (*pci_dev_io_base)(unsigned char bus, unsigned char devfn, int physical); void* (*pci_dev_mem_base)(unsigned char bus, unsigned char devfn); int (*pci_dev_root_bridge)(unsigned char bus, unsigned char devfn); diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-ppc/mbx.h linux/include/asm-ppc/mbx.h --- v2.4.0-test8/linux/include/asm-ppc/mbx.h Sat Nov 27 15:42:33 1999 +++ linux/include/asm-ppc/mbx.h Sun Sep 17 09:48:08 2000 @@ -25,6 +25,7 @@ unsigned int bi_busfreq; /* Bus Freq, in Hz */ unsigned int bi_clun; /* Boot device controller */ unsigned int bi_dlun; /* Boot device logical dev */ + unsigned int bi_baudrate; /* ...to be like everyone else */ } bd_t; /* Memory map for the MBX as configured by EPPC-Bug. We could reprogram diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-ppc/mman.h linux/include/asm-ppc/mman.h --- v2.4.0-test8/linux/include/asm-ppc/mman.h Tue Mar 21 10:49:32 2000 +++ linux/include/asm-ppc/mman.h Sun Sep 17 09:48:08 2000 @@ -22,8 +22,8 @@ #define MS_INVALIDATE 2 /* invalidate the caches */ #define MS_SYNC 4 /* synchronous memory sync */ -#define MCL_CURRENT 1 /* lock all current mappings */ -#define MCL_FUTURE 2 /* lock all future mappings */ +#define MCL_CURRENT 0x2000 /* lock all currently mapped pages */ +#define MCL_FUTURE 0x4000 /* lock all additions to address space */ #define MADV_NORMAL 0x0 /* default page-in behavior */ #define MADV_RANDOM 0x1 /* page-in minimum required */ diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-ppc/nvram.h linux/include/asm-ppc/nvram.h --- v2.4.0-test8/linux/include/asm-ppc/nvram.h Tue May 2 13:05:40 2000 +++ linux/include/asm-ppc/nvram.h Sun Sep 17 09:48:08 2000 @@ -38,6 +38,8 @@ pmac_nvram_NR /* MacOS Name Registry partition */ }; +#ifdef __KERNEL__ + /* Return partition offset in nvram */ extern int pmac_get_partition(int partition); @@ -45,15 +47,20 @@ extern u8 pmac_xpram_read(int xpaddr); extern void pmac_xpram_write(int xpaddr, u8 data); +#endif /* __KERNEL__ */ + /* Some offsets in XPRAM */ #define PMAC_XPRAM_MACHINE_LOC 0xe4 #define PMAC_XPRAM_SOUND_VOLUME 0x08 /* Machine location structure in XPRAM */ struct pmac_machine_location { - u32 latitude; /* 2+30 bit Fractional number */ - u32 longitude; /* 2+30 bit Fractional number */ - u32 delta; /* mix of GMT delta and DLS */ + unsigned int latitude; /* 2+30 bit Fractional number */ + unsigned int longitude; /* 2+30 bit Fractional number */ + unsigned int delta; /* mix of GMT delta and DLS */ }; + +/* /dev/nvram ioctls */ +#define PMAC_NVRAM_GET_OFFSET _IOWR('p', 0x40, int) /* Get NVRAM partition offset */ #endif diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-ppc/pci-bridge.h linux/include/asm-ppc/pci-bridge.h --- v2.4.0-test8/linux/include/asm-ppc/pci-bridge.h Thu Jul 13 09:42:51 2000 +++ linux/include/asm-ppc/pci-bridge.h Sun Sep 17 09:48:08 2000 @@ -15,8 +15,12 @@ /* This version handles the new Uni-N host bridge, the iobase is now * a per-device thing. I also added the memory base so PReP can * be fixed to return 0xc0000000 (I didn't actually implement it) + * + * pci_dev_io_base() returns either a virtual (ioremap'ed) address or + * a physical address. In-kernel clients will use logical while the + * sys_pciconfig_iobase syscall returns a physical one to userland. */ -void *pci_dev_io_base(unsigned char bus, unsigned char devfn); +void *pci_dev_io_base(unsigned char bus, unsigned char devfn, int physical); void *pci_dev_mem_base(unsigned char bus, unsigned char devfn); /* Returns the root-bridge number (Uni-N number) of a device */ @@ -33,7 +37,8 @@ struct bridge_data { volatile unsigned int *cfg_addr; volatile unsigned char *cfg_data; - void *io_base; + void *io_base; /* virtual */ + unsigned long io_base_phys; int bus_number; int max_bus; struct bridge_data *next; diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-ppc/pgtable.h linux/include/asm-ppc/pgtable.h --- v2.4.0-test8/linux/include/asm-ppc/pgtable.h Mon Aug 7 21:02:27 2000 +++ linux/include/asm-ppc/pgtable.h Sun Sep 17 09:48:08 2000 @@ -69,7 +69,7 @@ extern void flush_icache_range(unsigned long, unsigned long); extern void __flush_page_to_ram(unsigned long page_va); -#define flush_page_to_ram(page) __flush_page_to_ram((unsigned long) page_address(page)) +extern void flush_page_to_ram(struct page *page); #define flush_dcache_page(page) do { } while (0) diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-ppc/processor.h linux/include/asm-ppc/processor.h --- v2.4.0-test8/linux/include/asm-ppc/processor.h Mon Aug 7 21:02:27 2000 +++ linux/include/asm-ppc/processor.h Sun Sep 17 09:48:08 2000 @@ -287,6 +287,7 @@ #define SPRN_UPMC3 0x3AD /* User Performance Counter Register 3 */ #define SPRN_UPMC4 0x3AE /* User Performance Counter Register 4 */ #define SPRN_USIA 0x3AB /* User Sampled Instruction Address Register */ +#define SPRN_VRSAVE 0x100 /* Vector Register Save Register */ #define SPRN_XER 0x001 /* Fixed Point Exception Register */ #define SPRN_ZPR 0x3B0 /* Zone Protection Register */ diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-ppc/prom.h linux/include/asm-ppc/prom.h --- v2.4.0-test8/linux/include/asm-ppc/prom.h Thu Jul 13 09:42:51 2000 +++ linux/include/asm-ppc/prom.h Tue Sep 19 08:31:53 2000 @@ -7,11 +7,16 @@ #ifndef _PPC_PROM_H #define _PPC_PROM_H +#include + typedef void *phandle; typedef void *ihandle; extern char *prom_display_paths[]; extern unsigned int prom_num_displays; +#ifndef CONFIG_MACH_SPECIFIC +extern int have_of; +#endif struct address_range { unsigned int space; diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-ppc/resource.h linux/include/asm-ppc/resource.h --- v2.4.0-test8/linux/include/asm-ppc/resource.h Tue May 2 13:05:40 2000 +++ linux/include/asm-ppc/resource.h Fri Sep 22 14:21:21 2000 @@ -11,8 +11,9 @@ #define RLIMIT_NOFILE 7 /* max number of open files */ #define RLIMIT_MEMLOCK 8 /* max locked-in-memory address space */ #define RLIMIT_AS 9 /* address space limit(?) */ +#define RLIMIT_LOCKS 10 /* maximum file locks held */ -#define RLIM_NLIMITS 10 +#define RLIM_NLIMITS 11 #ifdef __KERNEL__ @@ -33,6 +34,7 @@ { RLIM_INFINITY, RLIM_INFINITY }, \ { 0, 0 }, \ { INR_OPEN, INR_OPEN }, \ + { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ } diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-ppc/serial.h linux/include/asm-ppc/serial.h --- v2.4.0-test8/linux/include/asm-ppc/serial.h Sat Nov 27 15:42:33 1999 +++ linux/include/asm-ppc/serial.h Sun Sep 17 09:48:08 2000 @@ -23,16 +23,6 @@ #define RS_TABLE_SIZE 4 #endif -#ifdef CONFIG_PMAC -/* - * Auto-probing will cause machine checks on powermacs. - */ -#define SERIAL_PORT_DFNS -#else -/* - * PReP, CHRP, etc. - */ - /* Standard COM flags (except for COM4, because of the 8514 problem) */ #ifdef CONFIG_SERIAL_DETECT_IRQ #define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ) @@ -136,5 +126,4 @@ HUB6_SERIAL_PORT_DFNS \ MCA_SERIAL_PORT_DFNS -#endif /* CONFIG_PMAC */ #endif /* CONFIG_GEMINI */ diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-ppc/smp.h linux/include/asm-ppc/smp.h --- v2.4.0-test8/linux/include/asm-ppc/smp.h Mon Jun 19 17:59:37 2000 +++ linux/include/asm-ppc/smp.h Sun Sep 17 09:48:08 2000 @@ -24,10 +24,11 @@ extern unsigned long smp_proc_in_lock[NR_CPUS]; -extern void smp_message_pass(int target, int msg, unsigned long data, int wait); extern void smp_store_cpu_info(int id); -extern void smp_message_recv(int); -void smp_send_tlb_invalidate(int); +extern void smp_send_tlb_invalidate(int); +extern void smp_send_xmon_break(int cpu); +struct pt_regs; +extern void smp_message_recv(int, struct pt_regs *); #define NO_PROC_ID 0xFF /* No processor magic marker */ #define PROC_CHANGE_PENALTY 20 diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-ppc/spinlock.h linux/include/asm-ppc/spinlock.h --- v2.4.0-test8/linux/include/asm-ppc/spinlock.h Sun Feb 13 10:47:01 2000 +++ linux/include/asm-ppc/spinlock.h Sun Sep 17 09:48:08 2000 @@ -41,6 +41,7 @@ } rwlock_t; #define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 } +#define rwlock_init(lp) do { *(lp) = RW_LOCK_UNLOCKED; } while(0) extern void _read_lock(rwlock_t *rw); extern void _read_unlock(rwlock_t *rw); diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-ppc/system.h linux/include/asm-ppc/system.h --- v2.4.0-test8/linux/include/asm-ppc/system.h Thu Aug 3 15:38:11 2000 +++ linux/include/asm-ppc/system.h Wed Sep 27 13:41:33 2000 @@ -36,6 +36,16 @@ #define set_mb(var, value) do { var = value; mb(); } while (0) #define set_wmb(var, value) do { var = value; wmb(); } while (0) +#ifdef CONFIG_SMP +#define smp_mb() mb() +#define smp_rmb() rmb() +#define smp_wmb() wmb() +#else +#define smp_mb() __asm__ __volatile__("": : :"memory") +#define smp_rmb() __asm__ __volatile__("": : :"memory") +#define smp_wmb() __asm__ __volatile__("": : :"memory") +#endif /* CONFIG_SMP */ + extern void xmon_irq(int, void *, struct pt_regs *); extern void xmon(struct pt_regs *excp); @@ -67,6 +77,7 @@ extern void cvt_df(double *from, float *to, unsigned long *fpscr); extern int call_rtas(const char *, int, int, unsigned long *, ...); extern int abs(int); +extern void cacheable_memzero(void *p, unsigned int nb); struct device_node; extern void note_scsi_host(struct device_node *, void *); @@ -114,16 +125,25 @@ #define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) -extern unsigned long xchg_u64(void *ptr, unsigned long val); -extern unsigned long xchg_u32(void *ptr, unsigned long val); +static __inline__ unsigned long +xchg_u32(volatile void *p, unsigned long val) +{ + unsigned long prev; + + __asm__ __volatile__ (" +1: lwarx %0,0,%2 + stwcx. %3,0,%2 + bne- 1b" + : "=&r" (prev), "=m" (*(volatile unsigned long *)p) + : "r" (p), "r" (val), "m" (*(volatile unsigned long *)p) + : "cc", "memory"); + + return prev; +} /* * This function doesn't exist, so you'll get a linker error * if something tries to do an invalid xchg(). - * - * This only works if the compiler isn't horribly bad at optimizing. - * gcc-2.5.8 reportedly can't handle this, but as that doesn't work - * too well on the alpha anyway.. */ extern void __xchg_called_with_bad_pointer(void); @@ -135,8 +155,10 @@ switch (size) { case 4: return (unsigned long )xchg_u32(ptr, x); +#if 0 /* xchg_u64 doesn't exist on 32-bit PPC */ case 8: return (unsigned long )xchg_u64(ptr, x); +#endif /* 0 */ } __xchg_called_with_bad_pointer(); return x; @@ -149,4 +171,56 @@ return (void *) xchg_u32(m, (unsigned long) val); } -#endif + +#define __HAVE_ARCH_CMPXCHG 1 + +static __inline__ unsigned long +__cmpxchg_u32(volatile int *p, int old, int new) +{ + int prev; + + __asm__ __volatile__ (" +1: lwarx %0,0,%2 + cmpw 0,%0,%3 + bne 2f + stwcx. %4,0,%2 + bne- 1b\n" +#ifdef CONFIG_SMP +" sync\n" +#endif /* CONFIG_SMP */ +"2:" + : "=&r" (prev), "=m" (*p) + : "r" (p), "r" (old), "r" (new), "m" (*p) + : "cc", "memory"); + + return prev; +} + +/* This function doesn't exist, so you'll get a linker error + if something tries to do an invalid cmpxchg(). */ +extern void __cmpxchg_called_with_bad_pointer(void); + +static __inline__ unsigned long +__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size) +{ + switch (size) { + case 4: + return __cmpxchg_u32(ptr, old, new); +#if 0 /* we don't have __cmpxchg_u64 on 32-bit PPC */ + case 8: + return __cmpxchg_u64(ptr, old, new); +#endif /* 0 */ + } + __cmpxchg_called_with_bad_pointer(); + return old; +} + +#define cmpxchg(ptr,o,n) \ + ({ \ + __typeof__(*(ptr)) _o_ = (o); \ + __typeof__(*(ptr)) _n_ = (n); \ + (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_, \ + (unsigned long)_n_, sizeof(*(ptr))); \ + }) + +#endif /* __PPC_SYSTEM_H */ diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-ppc/time.h linux/include/asm-ppc/time.h --- v2.4.0-test8/linux/include/asm-ppc/time.h Thu Jul 13 09:42:51 2000 +++ linux/include/asm-ppc/time.h Sun Sep 17 09:48:08 2000 @@ -12,11 +12,10 @@ #include /* time.c */ -extern unsigned decrementer_count; -extern unsigned count_period_num; -extern unsigned count_period_den; -extern unsigned long mktime(unsigned int, unsigned int, unsigned int, - unsigned int, unsigned int, unsigned int); +extern unsigned tb_ticks_per_jiffy; +extern unsigned tb_to_us; +extern unsigned tb_last_stamp; + extern void to_tm(int tim, struct rtc_time * tm); extern time_t last_rtc_update; @@ -37,6 +36,80 @@ #if defined(CONFIG_4xx) mtspr(SPRN_PIT, val); #else +#ifdef CONFIG_8xx_CPU6 + set_dec_cpu6(val); +#else mtspr(SPRN_DEC, val); #endif +#endif +} + +/* Accessor functions for the timebase (RTC on 601) registers. */ +/* If one day CONFIG_POWER is added just define __USE_RTC as 1 */ +#ifdef CONFIG_6xx +extern __inline__ int const __USE_RTC(void) { + return (mfspr(SPRN_PVR)>>16) == 1; +} +#else +#define __USE_RTC() 0 +#endif + +extern __inline__ unsigned long get_tbl(void) { + unsigned long tbl; + asm volatile("mftb %0" : "=r" (tbl)); + return tbl; +} + +extern __inline__ unsigned long get_rtcl(void) { + unsigned long rtcl; + asm volatile("mfrtcl %0" : "=r" (rtcl)); + return rtcl; } + +extern __inline__ unsigned get_native_tbl(void) { + if (__USE_RTC()) + return get_rtcl(); + else + return get_tbl(); +} + +/* On machines with RTC, this function can only be used safely + * after the timestamp and for 1 second. It is only used by gettimeofday + * however so it should not matter. + */ +extern __inline__ unsigned tb_ticks_since(unsigned tstamp) { + if (__USE_RTC()) { + int delta = get_rtcl() - tstamp; + return delta<0 ? delta + 1000000000 : delta; + } else { + return get_tbl() - tstamp; + } +} + +#if 0 +extern __inline__ unsigned long get_bin_rtcl(void) { + unsigned long rtcl, rtcu1, rtcu2; + asm volatile("\ +1: mfrtcu %0\n\ + mfrtcl %1\n\ + mfrtcu %2\n\ + cmpw %0,%2\n\ + bne- 1b\n" + : "=r" (rtcu1), "=r" (rtcl), "=r" (rtcu2) + : : "cr0"); + return rtcu2*1000000000+rtcl; +} + +extern __inline__ unsigned binary_tbl(void) { + if (__USE_RTC()) + return get_bin_rtcl(); + else + return get_tbl(); +} +#endif + +/* Use mulhwu to scale processor timebase to timeval */ +#define mulhwu(x,y) \ +({unsigned z; asm ("mulhwu %0,%1,%2" : "=r" (z) : "r" (x), "r" (y)); z;}) + +unsigned mulhwu_scale_factor(unsigned, unsigned); diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-ppc/uaccess.h linux/include/asm-ppc/uaccess.h --- v2.4.0-test8/linux/include/asm-ppc/uaccess.h Tue Aug 29 14:09:15 2000 +++ linux/include/asm-ppc/uaccess.h Sun Sep 17 09:48:08 2000 @@ -57,7 +57,7 @@ /* Returns 0 if exception not found and fixup otherwise. */ extern unsigned long search_exception_table(unsigned long); - +extern void sort_exception_table(void); /* * These are the main single-value transfer routines. They automatically @@ -131,10 +131,11 @@ ".section .fixup,\"ax\"\n" \ "3: li %0,%3\n" \ " b 2b\n" \ + ".previous\n" \ ".section __ex_table,\"a\"\n" \ " .align 2\n" \ " .long 1b,3b\n" \ - ".text" \ + ".previous" \ : "=r"(err) \ : "r"(x), "b"(addr), "i"(-EFAULT), "0"(err)) @@ -178,10 +179,11 @@ "3: li %0,%3\n" \ " li %1,0\n" \ " b 2b\n" \ + ".previous\n" \ ".section __ex_table,\"a\"\n" \ " .align 2\n" \ " .long 1b,3b\n" \ - ".text" \ + ".previous" \ : "=r"(err), "=r"(x) \ : "b"(addr), "i"(-EFAULT), "0"(err)) diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-ppc/uninorth.h linux/include/asm-ppc/uninorth.h --- v2.4.0-test8/linux/include/asm-ppc/uninorth.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-ppc/uninorth.h Sun Sep 17 09:48:08 2000 @@ -0,0 +1,83 @@ +/* + * uninorth.h: definitions for using the "UniNorth" host bridge chip + * from Apple. This chip is used on "Core99" machines + * + */ + + +/* + * Uni-N config space reg. definitions + * + * (Little endian) + */ + +/* Address ranges selection. This one should work with Bandit too */ +#define UNI_N_ADDR_SELECT 0x48 +#define UNI_N_ADDR_COARSE_MASK 0xffff0000 /* 256Mb regions at *0000000 */ +#define UNI_N_ADDR_FINE_MASK 0x0000ffff /* 16Mb regions at f*000000 */ + +/* AGP registers */ +#define UNI_N_CFG_GART_BASE 0x8c +#define UNI_N_CFG_AGP_BASE 0x90 +#define UNI_N_CFG_GART_CTRL 0x94 +#define UNI_N_CFG_INTERNAL_STATUS 0x98 + +/* UNI_N_CFG_GART_CTRL bits definitions */ +#define UNI_N_CFG_GART_INVAL 0x00000001 +#define UNI_N_CFG_GART_ENABLE 0x00000100 +#define UNI_N_CFG_GART_2xRESET 0x00010000 + + +/* + * Uni-N memory mapped reg. definitions + * + * Those registers are Big-Endian !! + * + * Their meaning come from either Darwin and/or from experiments I made with + * the bootrom, I'm not sure about their exact meaning yet + * + */ + +/* Version of the UniNorth chip */ +#define UNI_N_VERSION 0x0000 /* Known versions: 3,7 and 8 */ + +/* This register is used to enable/disable various parts */ +#define UNI_N_CLOCK_CNTL 0x0020 +#define UNI_N_CLOCK_CNTL_PCI 0x00000001 /* guess ? */ +#define UNI_N_CLOCK_CNTL_GMAC 0x00000002 +#define UNI_N_CLOCK_CNTL_FW 0x00000004 /* guess ? */ + +/* Power Management control ? (from Darwin) */ +#define UNI_N_POWER_MGT 0x0030 +#define UNI_N_POWER_MGT_NORMAL 0x00 +#define UNI_N_POWER_MGT_IDLE2 0x01 +#define UNI_N_POWER_MGT_SLEEP 0x02 + +/* This register is configured by Darwin depending on the UniN + * revision + */ +#define UNI_N_ARB_CTRL 0x0040 +#define UNI_N_ARB_CTRL_QACK_DELAY_SHIFT 15 +#define UNI_N_ARB_CTRL_QACK_DELAY_MASK 0x0e1f8000 +#define UNI_N_ARB_CTRL_QACK_DELAY 0x30 +#define UNI_N_ARB_CTRL_QACK_DELAY105 0x00 + +/* This one _might_ return the CPU number of the CPU reading it; + * the bootROM decides wether to boot or to sleep/spinloop depending + * on this register beeing 0 or not + */ +#define UNI_N_CPU_NUMBER 0x0050 + +/* This register appear to be read by the bootROM to decide what + * to do on a non-recoverable reset (powerup or wakeup) + */ +#define UNI_N_HWINIT_STATE 0x0070 +#define UNI_N_HWINIT_STATE_SLEEPING 0x01 +#define UNI_N_HWINIT_STATE_RUNNING 0x02 +/* This last bit appear to be used by the bootROM to know the second + * CPU has started and will enter it's sleep loop with IP=0 + */ +#define UNI_N_HWINIT_STATE_CPU1_FLAG 0x10000000 + + + diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-ppc/unistd.h linux/include/asm-ppc/unistd.h --- v2.4.0-test8/linux/include/asm-ppc/unistd.h Fri Aug 11 14:29:03 2000 +++ linux/include/asm-ppc/unistd.h Sun Sep 17 09:48:08 2000 @@ -201,10 +201,10 @@ #define __NR_stat64 195 #define __NR_lstat64 196 #define __NR_fstat64 197 -#define __NR_sys_pciconfig_read 198 -#define __NR_sys_pciconfig_write 199 -#define __NR_sys_pciconfig_iobase 200 -#define __NR_multiplexer 201 +#define __NR_pciconfig_read 198 +#define __NR_pciconfig_write 199 +#define __NR_pciconfig_iobase 200 +#define __NR_multiplexer 201 #define __NR_getdents64 202 #define __NR(n) #n diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-s390/fcntl.h linux/include/asm-s390/fcntl.h --- v2.4.0-test8/linux/include/asm-s390/fcntl.h Wed Jul 5 11:13:39 2000 +++ linux/include/asm-s390/fcntl.h Fri Sep 22 14:21:21 2000 @@ -54,6 +54,9 @@ #define F_EXLCK 4 /* or 3 */ #define F_SHLCK 8 /* or 4 */ +/* for leases */ +#define F_INPROGRESS 16 + /* operations for bsd flock(), also used by the kernel implementation */ #define LOCK_SH 1 /* shared lock */ #define LOCK_EX 2 /* exclusive lock */ @@ -61,6 +64,11 @@ blocking */ #define LOCK_UN 8 /* remove lock */ +#define LOCK_MAND 32 /* This is a mandatory flock */ +#define LOCK_READ 64 /* ... Which allows concurrent read operations */ +#define LOCK_WRITE 128 /* ... Which allows concurrent write operations */ +#define LOCK_RW 192 /* ... Which allows concurrent read & write ops */ + struct flock { short l_type; short l_whence; @@ -69,4 +77,5 @@ pid_t l_pid; }; +#define F_LINUX_SPECIFIC_BASE 1024 #endif diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-s390/resource.h linux/include/asm-s390/resource.h --- v2.4.0-test8/linux/include/asm-s390/resource.h Fri May 12 11:41:44 2000 +++ linux/include/asm-s390/resource.h Fri Sep 22 14:21:21 2000 @@ -23,8 +23,9 @@ #define RLIMIT_NOFILE 7 /* max number of open files */ #define RLIMIT_MEMLOCK 8 /* max locked-in-memory address space */ #define RLIMIT_AS 9 /* address space limit */ +#define RLIMIT_AS 10 /* maximum file locks held */ -#define RLIM_NLIMITS 10 +#define RLIM_NLIMITS 11 /* * SuS says limits have to be unsigned. @@ -44,6 +45,7 @@ { LONG_MAX, LONG_MAX }, \ { MAX_TASKS_PER_USER, MAX_TASKS_PER_USER }, \ { INR_OPEN, INR_OPEN }, \ + { LONG_MAX, LONG_MAX }, \ { LONG_MAX, LONG_MAX }, \ { LONG_MAX, LONG_MAX }, \ } diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-sh/atomic.h linux/include/asm-sh/atomic.h --- v2.4.0-test8/linux/include/asm-sh/atomic.h Tue Apr 25 16:53:13 2000 +++ linux/include/asm-sh/atomic.h Tue Oct 3 09:24:40 2000 @@ -7,13 +7,7 @@ * */ -#include - -#ifdef CONFIG_SMP typedef struct { volatile int counter; } atomic_t; -#else -typedef struct { int counter; } atomic_t; -#endif #define ATOMIC_INIT(i) ( (atomic_t) { (i) } ) @@ -23,19 +17,12 @@ #include /* - * Make sure gcc doesn't try to be clever and move things around - * on us. We need to use _exactly_ the address the user gave us, - * not some alias that contains the same information. - */ -#define __atomic_fool_gcc(x) (*(volatile struct { int a[100]; } *)x) - -/* * To get proper branch prediction for the main line, we must branch * forward to code at the end of this object's .text section, then * branch back to restart the operation. */ -extern __inline__ void atomic_add(int i, atomic_t * v) +static __inline__ void atomic_add(int i, atomic_t * v) { unsigned long flags; @@ -44,7 +31,7 @@ restore_flags(flags); } -extern __inline__ void atomic_sub(int i, atomic_t *v) +static __inline__ void atomic_sub(int i, atomic_t *v) { unsigned long flags; @@ -53,7 +40,7 @@ restore_flags(flags); } -extern __inline__ int atomic_add_return(int i, atomic_t * v) +static __inline__ int atomic_add_return(int i, atomic_t * v) { unsigned long temp, flags; @@ -66,7 +53,7 @@ return temp; } -extern __inline__ int atomic_sub_return(int i, atomic_t * v) +static __inline__ int atomic_sub_return(int i, atomic_t * v) { unsigned long temp, flags; @@ -88,7 +75,7 @@ #define atomic_inc(v) atomic_add(1,(v)) #define atomic_dec(v) atomic_sub(1,(v)) -extern __inline__ void atomic_clear_mask(unsigned int mask, atomic_t *v) +static __inline__ void atomic_clear_mask(unsigned int mask, atomic_t *v) { unsigned long flags; @@ -97,7 +84,7 @@ restore_flags(flags); } -extern __inline__ void atomic_set_mask(unsigned int mask, atomic_t *v) +static __inline__ void atomic_set_mask(unsigned int mask, atomic_t *v) { unsigned long flags; diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-sh/bitops.h linux/include/asm-sh/bitops.h --- v2.4.0-test8/linux/include/asm-sh/bitops.h Fri Jul 21 14:21:06 2000 +++ linux/include/asm-sh/bitops.h Mon Oct 2 11:57:34 2000 @@ -6,7 +6,7 @@ /* For __swab32 */ #include -extern __inline__ void set_bit(int nr, volatile void * addr) +static __inline__ void set_bit(int nr, volatile void * addr) { int mask; volatile unsigned int *a = addr; @@ -19,7 +19,12 @@ restore_flags(flags); } -extern __inline__ void clear_bit(int nr, volatile void * addr) +/* + * clear_bit() doesn't provide any barrier for the compiler. + */ +#define smp_mb__before_clear_bit() barrier() +#define smp_mb__after_clear_bit() barrier() +static __inline__ void clear_bit(int nr, volatile void * addr) { int mask; volatile unsigned int *a = addr; @@ -32,7 +37,7 @@ restore_flags(flags); } -extern __inline__ void change_bit(int nr, volatile void * addr) +static __inline__ void change_bit(int nr, volatile void * addr) { int mask; volatile unsigned int *a = addr; @@ -45,7 +50,7 @@ restore_flags(flags); } -extern __inline__ int test_and_set_bit(int nr, volatile void * addr) +static __inline__ int test_and_set_bit(int nr, volatile void * addr) { int mask, retval; volatile unsigned int *a = addr; @@ -61,7 +66,7 @@ return retval; } -extern __inline__ int test_and_clear_bit(int nr, volatile void * addr) +static __inline__ int test_and_clear_bit(int nr, volatile void * addr) { int mask, retval; volatile unsigned int *a = addr; @@ -77,7 +82,7 @@ return retval; } -extern __inline__ int test_and_change_bit(int nr, volatile void * addr) +static __inline__ int test_and_change_bit(int nr, volatile void * addr) { int mask, retval; volatile unsigned int *a = addr; @@ -94,12 +99,12 @@ } -extern __inline__ int test_bit(int nr, const volatile void *addr) +static __inline__ int test_bit(int nr, const volatile void *addr) { return 1UL & (((const volatile unsigned int *) addr)[nr >> 5] >> (nr & 31)); } -extern __inline__ unsigned long ffz(unsigned long word) +static __inline__ unsigned long ffz(unsigned long word) { unsigned long result; @@ -108,11 +113,12 @@ "bt/s 1b\n\t" " add #1, %0" : "=r" (result), "=r" (word) - : "0" (~0L), "1" (word)); + : "0" (~0L), "1" (word) + : "t"); return result; } -extern __inline__ int find_next_zero_bit(void *addr, int size, int offset) +static __inline__ int find_next_zero_bit(void *addr, int size, int offset) { unsigned long *p = ((unsigned long *) addr) + (offset >> 5); unsigned long result = offset & ~31UL; @@ -159,7 +165,7 @@ #define ext2_find_next_zero_bit(addr, size, offset) \ find_next_zero_bit((addr), (size), (offset)) #else -extern __inline__ int ext2_set_bit(int nr, volatile void * addr) +static __inline__ int ext2_set_bit(int nr, volatile void * addr) { int mask, retval; unsigned long flags; @@ -174,7 +180,7 @@ return retval; } -extern __inline__ int ext2_clear_bit(int nr, volatile void * addr) +static __inline__ int ext2_clear_bit(int nr, volatile void * addr) { int mask, retval; unsigned long flags; @@ -189,7 +195,7 @@ return retval; } -extern __inline__ int ext2_test_bit(int nr, const volatile void * addr) +static __inline__ int ext2_test_bit(int nr, const volatile void * addr) { int mask; const volatile unsigned char *ADDR = (const unsigned char *) addr; @@ -202,7 +208,7 @@ #define ext2_find_first_zero_bit(addr, size) \ ext2_find_next_zero_bit((addr), (size), 0) -extern __inline__ unsigned long ext2_find_next_zero_bit(void *addr, unsigned long size, unsigned long offset) +static __inline__ unsigned long ext2_find_next_zero_bit(void *addr, unsigned long size, unsigned long offset) { unsigned long *p = ((unsigned long *) addr) + (offset >> 5); unsigned long result = offset & ~31UL; diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-sh/checksum.h linux/include/asm-sh/checksum.h --- v2.4.0-test8/linux/include/asm-sh/checksum.h Sat Jul 22 07:42:06 2000 +++ linux/include/asm-sh/checksum.h Mon Oct 2 11:57:34 2000 @@ -82,7 +82,8 @@ "add %1, %0\n\t" "not %0, %0\n\t" : "=r" (sum), "=&r" (__dummy) - : "0" (sum)); + : "0" (sum) + : "t"); return sum; } @@ -115,7 +116,8 @@ are modified, we must also specify them as outputs, or gcc will assume they contain their original values. */ : "=r" (sum), "=r" (iph), "=r" (ihl), "=&r" (__dummy0), "=&z" (__dummy1) - : "1" (iph), "2" (ihl)); + : "1" (iph), "2" (ihl) + : "t"); return csum_fold(sum); } @@ -138,7 +140,8 @@ "movt %0\n\t" "add %1, %0" : "=r" (sum), "=r" (len_proto) - : "r" (daddr), "r" (saddr), "1" (len_proto), "0" (sum)); + : "r" (daddr), "r" (saddr), "1" (len_proto), "0" (sum) + : "t"); return sum; } @@ -197,7 +200,8 @@ "add %1, %0\n" : "=r" (sum), "=&r" (__dummy) : "r" (saddr), "r" (daddr), - "r" (htonl(len)), "r" (htonl(proto)), "0" (sum)); + "r" (htonl(len)), "r" (htonl(proto)), "0" (sum) + : "t"); return csum_fold(sum); } diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-sh/delay.h linux/include/asm-sh/delay.h --- v2.4.0-test8/linux/include/asm-sh/delay.h Wed Aug 9 13:59:04 2000 +++ linux/include/asm-sh/delay.h Mon Oct 2 11:57:34 2000 @@ -15,7 +15,8 @@ "bf/s 1b\n\t" " dt %0" : "=r" (loops) - : "0" (loops)); + : "0" (loops) + : "t"); } extern __inline__ void __udelay(unsigned long usecs, unsigned long lps) diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-sh/fcntl.h linux/include/asm-sh/fcntl.h --- v2.4.0-test8/linux/include/asm-sh/fcntl.h Wed Jul 5 11:13:39 2000 +++ linux/include/asm-sh/fcntl.h Mon Oct 2 11:57:34 2000 @@ -35,6 +35,10 @@ #define F_SETSIG 10 /* for sockets. */ #define F_GETSIG 11 /* for sockets. */ +#define F_GETLK64 12 /* using 'struct flock64' */ +#define F_SETLK64 13 +#define F_SETLKW64 14 + /* for F_[GET|SET]FL */ #define FD_CLOEXEC 1 /* actually anything with low bit set goes */ @@ -47,6 +51,9 @@ #define F_EXLCK 4 /* or 3 */ #define F_SHLCK 8 /* or 4 */ +/* for leases */ +#define F_INPROGRESS 16 + /* operations for bsd flock(), also used by the kernel implementation */ #define LOCK_SH 1 /* shared lock */ #define LOCK_EX 2 /* exclusive lock */ @@ -54,6 +61,11 @@ blocking */ #define LOCK_UN 8 /* remove lock */ +#define LOCK_MAND 32 /* This is a mandatory flock */ +#define LOCK_READ 64 /* ... Which allows concurrent read operations */ +#define LOCK_WRITE 128 /* ... Which allows concurrent write operations */ +#define LOCK_RW 192 /* ... Which allows concurrent read & write ops */ + struct flock { short l_type; short l_whence; @@ -62,5 +74,14 @@ pid_t l_pid; }; +struct flock64 { + short l_type; + short l_whence; + loff_t l_start; + loff_t l_len; + pid_t l_pid; +}; + +#define F_LINUX_SPECIFIC_BASE 1024 #endif /* __ASM_SH_FCNTL_H */ diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-sh/ide.h linux/include/asm-sh/ide.h --- v2.4.0-test8/linux/include/asm-sh/ide.h Wed Aug 9 13:59:04 2000 +++ linux/include/asm-sh/ide.h Mon Oct 2 11:57:34 2000 @@ -18,7 +18,8 @@ #include #ifndef MAX_HWIFS -#define MAX_HWIFS 1 +/* Should never have less than 2, ide-pci.c(ide_match_hwif) requires it */ +#define MAX_HWIFS 2 #endif #define ide__sti() __sti() diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-sh/io_hd64461.h linux/include/asm-sh/io_hd64461.h --- v2.4.0-test8/linux/include/asm-sh/io_hd64461.h Wed Aug 9 13:59:04 2000 +++ linux/include/asm-sh/io_hd64461.h Mon Oct 2 11:57:34 2000 @@ -62,6 +62,10 @@ # define __writew generic_writew # define __writel generic_writel +# define __isa_port2addr generic_isa_port2addr +# define __ioremap generic_ioremap +# define __iounmap generic_iounmap + #endif #endif /* _ASM_SH_IO_HD64461_H */ diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-sh/irq.h linux/include/asm-sh/irq.h --- v2.4.0-test8/linux/include/asm-sh/irq.h Wed Aug 9 13:59:04 2000 +++ linux/include/asm-sh/irq.h Mon Oct 2 11:57:34 2000 @@ -42,6 +42,7 @@ #if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) #define SCIF_ERI_IRQ 56 #define SCIF_RXI_IRQ 57 +#define SCIF_BRI_IRQ 58 #define SCIF_TXI_IRQ 59 #define SCIF_IPR_ADDR INTC_IPRE #define SCIF_IPR_POS 1 @@ -49,6 +50,7 @@ #define IRDA_ERI_IRQ 52 #define IRDA_RXI_IRQ 53 +#define IRDA_BRI_IRQ 54 #define IRDA_TXI_IRQ 55 #define IRDA_IPR_ADDR INTC_IPRE #define IRDA_IPR_POS 2 @@ -56,6 +58,7 @@ #elif defined(CONFIG_CPU_SUBTYPE_SH7750) #define SCIF_ERI_IRQ 40 #define SCIF_RXI_IRQ 41 +#define SCIF_BRI_IRQ 42 #define SCIF_TXI_IRQ 43 #define SCIF_IPR_ADDR INTC_IPRC #define SCIF_IPR_POS 1 diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-sh/page.h linux/include/asm-sh/page.h --- v2.4.0-test8/linux/include/asm-sh/page.h Wed Aug 9 13:46:01 2000 +++ linux/include/asm-sh/page.h Mon Oct 2 11:57:34 2000 @@ -9,7 +9,7 @@ [ P0/U0 (virtual) ] 0x00000000 <------ User space [ P1 (fixed) cached ] 0x80000000 <------ Kernel space [ P2 (fixed) non-cachable] 0xA0000000 <------ Physical access - [ P3 (virtual) cached] 0xC0000000 <------ not used + [ P3 (virtual) cached] 0xC0000000 <------ vmalloced area [ P4 control ] 0xE0000000 */ @@ -26,8 +26,14 @@ #define clear_page(page) memset((void *)(page), 0, PAGE_SIZE) #define copy_page(to,from) memcpy((void *)(to), (void *)(from), PAGE_SIZE) + +#if defined(__sh3__) #define clear_user_page(page, vaddr) clear_page(page) #define copy_user_page(to, from, vaddr) copy_page(to, from) +#elif defined(__SH4__) +extern void clear_user_page(void *to, unsigned long address); +extern void copy_user_page(void *to, void *from, unsigned long address); +#endif /* * These are used to make use of C type-checking.. @@ -62,7 +68,7 @@ #define __MEMORY_START CONFIG_MEMORY_START -#define PAGE_OFFSET (0x80000000) +#define PAGE_OFFSET (0x80000000UL) #define __pa(x) ((unsigned long)(x)-PAGE_OFFSET) #define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET)) #define virt_to_page(kaddr) (mem_map + ((__pa(kaddr)-__MEMORY_START) >> PAGE_SHIFT)) diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-sh/pci.h linux/include/asm-sh/pci.h --- v2.4.0-test8/linux/include/asm-sh/pci.h Wed Aug 9 13:59:04 2000 +++ linux/include/asm-sh/pci.h Mon Oct 2 11:57:34 2000 @@ -18,12 +18,12 @@ #define PCIBIOS_MIN_MEM 0x10000000 #endif -extern inline void pcibios_set_master(struct pci_dev *dev) +static inline void pcibios_set_master(struct pci_dev *dev) { /* No special bus mastering setup handling */ } -extern inline void pcibios_penalize_isa_irq(int irq) +static inline void pcibios_penalize_isa_irq(int irq) { /* We don't do dynamic PCI IRQ allocation */ } @@ -67,7 +67,7 @@ * Once the device is given the dma address, the device owns this memory * until either pci_unmap_single or pci_dma_sync_single is performed. */ -extern inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, +static inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size,int directoin) { return virt_to_bus(ptr); @@ -80,7 +80,7 @@ * After this call, reads by the cpu to the buffer are guarenteed to see * whatever the device wrote there. */ -extern inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, +static inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size,int direction) { /* Nothing to do */ @@ -101,7 +101,7 @@ * Device ownership issues as mentioned above for pci_map_single are * the same here. */ -extern inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, +static inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents,int direction) { return nents; @@ -111,7 +111,7 @@ * Again, cpu read rules concerning calls here are the same as for * pci_unmap_single() above. */ -extern inline void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, +static inline void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents,int direction) { /* Nothing to do */ @@ -126,7 +126,7 @@ * next point you give the PCI dma address back to the card, the * device again owns the buffer. */ -extern inline void pci_dma_sync_single(struct pci_dev *hwdev, +static inline void pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size,int direction) { @@ -139,7 +139,7 @@ * The same as pci_dma_sync_single but for a scatter-gather list, * same rules and usage. */ -extern inline void pci_dma_sync_sg(struct pci_dev *hwdev, +static inline void pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nelems,int direction) { diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-sh/pgtable.h linux/include/asm-sh/pgtable.h --- v2.4.0-test8/linux/include/asm-sh/pgtable.h Wed Aug 9 13:59:04 2000 +++ linux/include/asm-sh/pgtable.h Mon Oct 2 11:57:34 2000 @@ -92,45 +92,44 @@ #define VMALLOC_VMADDR(x) ((unsigned long)(x)) #define VMALLOC_END P4SEG -#define _PAGE_PRESENT 0x001 /* software: page is present */ -#define _PAGE_ACCESSED 0x002 /* software: page referenced */ +/* 0x001 WT-bit on SH-4, 0 on SH-3 */ +#define _PAGE_HW_SHARED 0x002 /* SH-bit : page is shared among processes */ #define _PAGE_DIRTY 0x004 /* D-bit : page changed */ #define _PAGE_CACHABLE 0x008 /* C-bit : cachable */ -/* 0x010 SZ-bit : size of page */ +/* 0x010 SZ0-bit : Size of page */ #define _PAGE_RW 0x020 /* PR0-bit : write access allowed */ #define _PAGE_USER 0x040 /* PR1-bit : user space access allowed */ -#define _PAGE_PROTNONE 0x080 /* software: if not present */ -/* 0x100 V-bit : page is valid */ -/* 0x200 can be used as software flag */ -/* 0x400 can be used as software flag */ -/* 0x800 can be used as software flag */ +/* 0x080 SZ1-bit : Size of page (on SH-4) */ +#define _PAGE_PRESENT 0x100 /* V-bit : page is valid */ +#define _PAGE_PROTNONE 0x200 /* software: if not present */ +#define _PAGE_ACCESSED 0x400 /* software: page referenced */ +#define _PAGE_U0_SHARED 0x800 /* software: page is shared in user space */ -#if defined(__sh3__) /* Mask which drop software flags */ -#define _PAGE_FLAGS_HARDWARE_MASK 0x1ffff06c -/* Flags defalult: SZ=1 (4k-byte), C=0 (non-cachable), SH=0 (not shared) */ -#define _PAGE_FLAGS_HARDWARE_DEFAULT 0x00000110 +#define _PAGE_FLAGS_HARDWARE_MASK 0x1ffff1ff +/* Hardware flags: SZ=1 (4k-byte) */ +#define _PAGE_FLAGS_HARD 0x00000010 + +#if defined(__sh3__) +#define _PAGE_SHARED _PAGE_HW_SHARED #elif defined(__SH4__) -/* Mask which drops software flags */ -#define _PAGE_FLAGS_HARDWARE_MASK 0x1ffff06c -/* Flags defalult: SZ=01 (4k-byte), C=0 (non-cachable), SH=0 (not shared), WT=0 */ -#define _PAGE_FLAGS_HARDWARE_DEFAULT 0x00000110 +#define _PAGE_SHARED _PAGE_U0_SHARED #endif #define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY) #define _KERNPG_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY) -#define _PAGE_CHG_MASK (PTE_MASK | _PAGE_ACCESSED | _PAGE_CACHABLE | _PAGE_DIRTY) +#define _PAGE_CHG_MASK (PTE_MASK | _PAGE_ACCESSED | _PAGE_CACHABLE | _PAGE_DIRTY | _PAGE_SHARED) -#define PAGE_NONE __pgprot(_PAGE_PROTNONE | _PAGE_CACHABLE |_PAGE_ACCESSED) -#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_CACHABLE |_PAGE_ACCESSED) -#define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_CACHABLE | _PAGE_ACCESSED) -#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_CACHABLE | _PAGE_ACCESSED) -#define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_CACHABLE | _PAGE_DIRTY | _PAGE_ACCESSED) -#define PAGE_KERNEL_RO __pgprot(_PAGE_PRESENT | _PAGE_CACHABLE | _PAGE_DIRTY | _PAGE_ACCESSED) +#define PAGE_NONE __pgprot(_PAGE_PROTNONE | _PAGE_CACHABLE |_PAGE_ACCESSED | _PAGE_FLAGS_HARD) +#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_CACHABLE |_PAGE_ACCESSED | _PAGE_SHARED | _PAGE_FLAGS_HARD) +#define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_CACHABLE | _PAGE_ACCESSED | _PAGE_FLAGS_HARD) +#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_CACHABLE | _PAGE_ACCESSED | _PAGE_FLAGS_HARD) +#define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_CACHABLE | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_HW_SHARED | _PAGE_FLAGS_HARD) +#define PAGE_KERNEL_RO __pgprot(_PAGE_PRESENT | _PAGE_CACHABLE | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_HW_SHARED | _PAGE_FLAGS_HARD) /* * As i386 and MIPS, SuperH can't do page protection for execute, and - * considers that the same are read. Also, write permissions imply + * considers that the same as a read. Also, write permissions imply * read permissions. This is the closest we can get.. */ @@ -184,6 +183,7 @@ extern inline int pte_dirty(pte_t pte){ return pte_val(pte) & _PAGE_DIRTY; } extern inline int pte_young(pte_t pte){ return pte_val(pte) & _PAGE_ACCESSED; } extern inline int pte_write(pte_t pte){ return pte_val(pte) & _PAGE_RW; } +extern inline int pte_shared(pte_t pte){ return pte_val(pte) & _PAGE_SHARED; } extern inline pte_t pte_rdprotect(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_USER)); return pte; } extern inline pte_t pte_exprotect(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_USER)); return pte; } @@ -244,11 +244,15 @@ unsigned long address, pte_t pte); /* Encode and de-code a swap entry */ -#define SWP_TYPE(x) (((x).val >> 1) & 0x3f) -#define SWP_OFFSET(x) ((x).val >> 8) -#define SWP_ENTRY(type, offset) ((swp_entry_t) { ((type) << 1) | ((offset) << 8) }) -#define pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) -#define swp_entry_to_pte(x) ((pte_t) { (x).val }) +/* + * NOTE: We should set ZEROs at the position of _PAGE_PRESENT + * and _PAGE_PROTONOE bits + */ +#define SWP_TYPE(x) ((x).val & 0xff) +#define SWP_OFFSET(x) ((x).val >> 10) +#define SWP_ENTRY(type, offset) ((swp_entry_t) { (type) | ((offset) << 10) }) +#define pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) +#define swp_entry_to_pte(x) ((pte_t) { (x).val }) #define module_map vmalloc #define module_unmap vfree diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-sh/resource.h linux/include/asm-sh/resource.h --- v2.4.0-test8/linux/include/asm-sh/resource.h Sun Mar 5 09:33:55 2000 +++ linux/include/asm-sh/resource.h Fri Sep 22 14:21:21 2000 @@ -15,8 +15,9 @@ #define RLIMIT_NOFILE 7 /* max number of open files */ #define RLIMIT_MEMLOCK 8 /* max locked-in-memory address space */ #define RLIMIT_AS 9 /* address space limit */ +#define RLIMIT_LOCKS 10 /* maximum file locks held */ -#define RLIM_NLIMITS 10 +#define RLIM_NLIMITS 11 #ifdef __KERNEL__ @@ -36,6 +37,7 @@ { RLIM_INFINITY, RLIM_INFINITY }, \ { 0, 0 }, \ { INR_OPEN, INR_OPEN }, \ + { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ { RLIM_INFINITY, RLIM_INFINITY }, \ } diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-sh/string.h linux/include/asm-sh/string.h --- v2.4.0-test8/linux/include/asm-sh/string.h Mon Mar 27 10:26:15 2000 +++ linux/include/asm-sh/string.h Mon Oct 2 11:57:34 2000 @@ -20,7 +20,7 @@ " add #1, %0\n\t" : "=r" (__dest), "=r" (__src), "=&z" (__dummy) : "0" (__dest), "1" (__src) - : "memory"); + : "memory", "t"); return __xdest; } @@ -46,7 +46,7 @@ "2:" : "=r" (__dest), "=r" (__src), "=&z" (__dummy) : "0" (__dest), "1" (__src), "r" (__src+__n) - : "memory"); + : "memory", "t"); return __xdest; } @@ -71,7 +71,8 @@ "sub %3, %2\n" "2:" : "=r" (__cs), "=r" (__ct), "=&r" (__res), "=&z" (__dummy) - : "0" (__cs), "1" (__ct)); + : "0" (__cs), "1" (__ct) + : "t"); return __res; } @@ -82,6 +83,9 @@ register int __res; unsigned long __dummy; + if (__n == 0) + return 0; + __asm__ __volatile__( "mov.b @%1+, %3\n" "1:\n\t" @@ -99,7 +103,8 @@ "sub %3, %2\n" "3:" :"=r" (__cs), "=r" (__ct), "=&r" (__res), "=&z" (__dummy) - : "0" (__cs), "1" (__ct), "r" (__cs+__n)); + : "0" (__cs), "1" (__ct), "r" (__cs+__n) + : "t"); return __res; } diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-sh/system.h linux/include/asm-sh/system.h --- v2.4.0-test8/linux/include/asm-sh/system.h Thu Aug 3 15:38:11 2000 +++ linux/include/asm-sh/system.h Mon Oct 2 11:57:34 2000 @@ -21,12 +21,12 @@ #define prepare_to_switch() do { } while(0) #define switch_to(prev,next,last) do { \ register struct task_struct *__last; \ - register unsigned long *__ts1 __asm__ ("$r1") = &prev->thread.sp; \ - register unsigned long *__ts2 __asm__ ("$r2") = &prev->thread.pc; \ - register unsigned long *__ts4 __asm__ ("$r4") = (unsigned long *)prev; \ - register unsigned long *__ts5 __asm__ ("$r5") = (unsigned long *)next; \ - register unsigned long *__ts6 __asm__ ("$r6") = &next->thread.sp; \ - register unsigned long __ts7 __asm__ ("$r7") = next->thread.pc; \ + register unsigned long *__ts1 __asm__ ("r1") = &prev->thread.sp; \ + register unsigned long *__ts2 __asm__ ("r2") = &prev->thread.pc; \ + register unsigned long *__ts4 __asm__ ("r4") = (unsigned long *)prev; \ + register unsigned long *__ts5 __asm__ ("r5") = (unsigned long *)next; \ + register unsigned long *__ts6 __asm__ ("r6") = &next->thread.sp; \ + register unsigned long __ts7 __asm__ ("r7") = next->thread.pc; \ __asm__ __volatile__ (".balign 4\n\t" \ "stc.l $gbr, @-$r15\n\t" \ "sts.l $pr, @-$r15\n\t" \ @@ -63,7 +63,7 @@ :"0" (prev), \ "r" (__ts1), "r" (__ts2), \ "r" (__ts4), "r" (__ts5), "r" (__ts6), "r" (__ts7) \ - :"r3"); \ + :"r3", "t"); \ last = __last; \ } while (0) #endif @@ -88,11 +88,22 @@ #define mb() __asm__ __volatile__ ("": : :"memory") #define rmb() mb() #define wmb() __asm__ __volatile__ ("": : :"memory") + +#ifdef CONFIG_SMP +#define smp_mb() mb() +#define smp_rmb() rmb() +#define smp_wmb() wmb() +#else +#define smp_mb() barrier() +#define smp_rmb() barrier() +#define smp_wmb() barrier() +#endif + #define set_mb(var, value) do { xchg(&var, value); } while (0) #define set_wmb(var, value) do { var = value; wmb(); } while (0) /* Interrupt Control */ -extern __inline__ void __sti(void) +static __inline__ void __sti(void) { unsigned long __dummy0, __dummy1; @@ -106,7 +117,7 @@ : "memory"); } -extern __inline__ void __cli(void) +static __inline__ void __cli(void) { unsigned long __dummy; __asm__ __volatile__("stc $sr, %0\n\t" @@ -205,7 +216,7 @@ #endif -extern __inline__ unsigned long xchg_u32(volatile int * m, unsigned long val) +static __inline__ unsigned long xchg_u32(volatile int * m, unsigned long val) { unsigned long flags, retval; @@ -216,7 +227,7 @@ return retval; } -extern __inline__ unsigned long xchg_u8(volatile unsigned char * m, unsigned long val) +static __inline__ unsigned long xchg_u8(volatile unsigned char * m, unsigned long val) { unsigned long flags, retval; diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-sh/uaccess.h linux/include/asm-sh/uaccess.h --- v2.4.0-test8/linux/include/asm-sh/uaccess.h Tue Aug 29 14:09:16 2000 +++ linux/include/asm-sh/uaccess.h Mon Oct 2 11:57:34 2000 @@ -45,11 +45,12 @@ * sum := addr + size; carry? --> flag = true; * if (sum >= addr_limit) flag = true; */ -#define __range_ok(addr,size) ({ \ - unsigned long flag,sum; \ - __asm__("clrt; addc %3, %1; movt %0; cmp/hi %4, %1; rotcl %0" \ - :"=&r" (flag), "=r" (sum) \ - :"1" (addr), "r" ((int)(size)), "r" (current->addr_limit.seg)); \ +#define __range_ok(addr,size) ({ \ + unsigned long flag,sum; \ + __asm__("clrt; addc %3, %1; movt %0; cmp/hi %4, %1; rotcl %0" \ + :"=&r" (flag), "=r" (sum) \ + :"1" (addr), "r" ((int)(size)), "r" (current->addr_limit.seg) \ + :"t"); \ flag; }) #define access_ok(type,addr,size) (__range_ok(addr,size) == 0) @@ -186,7 +187,8 @@ ".long 1b, 3b\n\t" \ ".previous" \ :"=&r" (__pu_err) \ - :"r" (__pu_val), "m" (__m(__pu_addr)), "i" (-EFAULT)); }) + :"r" (__pu_val), "m" (__m(__pu_addr)), "i" (-EFAULT) \ + :"memory"); }) extern void __put_user_unknown(void); @@ -224,7 +226,7 @@ ".previous" : "=r" (res), "=&z" (__dummy), "=r" (_f), "=r" (_t) : "2" (__from), "3" (__to), "0" (res) - : "memory"); + : "memory", "t"); return res; } @@ -284,7 +286,8 @@ " .long 1b,3b\n" ".previous" : "=r" (size), "=r" (__a) - : "0" (size), "1" (addr), "r" (0)); + : "0" (size), "1" (addr), "r" (0) + : "memory", "t"); return size; } @@ -330,7 +333,7 @@ : "=r" (res), "=&z" (__dummy), "=r" (_s), "=r" (_d) : "0" (__count), "2" (__src), "3" (__dest), "r" (__count), "i" (-EFAULT) - : "memory"); + : "memory", "t"); return res; } @@ -376,7 +379,8 @@ " .long 1b,3b\n" ".previous" : "=z" (res), "=&r" (__dummy) - : "0" (0), "r" (__s), "r" (__n), "i" (-EFAULT)); + : "0" (0), "r" (__s), "r" (__n), "i" (-EFAULT) + : "t"); return res; } diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-sh/unistd.h linux/include/asm-sh/unistd.h --- v2.4.0-test8/linux/include/asm-sh/unistd.h Fri Aug 11 14:29:03 2000 +++ linux/include/asm-sh/unistd.h Mon Oct 2 11:57:34 2000 @@ -230,6 +230,7 @@ #define __NR_mincore 218 #define __NR_madvise 219 #define __NR_getdents64 220 +#define __NR_fcntl64 221 /* user-visible error numbers are in the range -1 - -125: see */ @@ -249,7 +250,7 @@ #define _syscall0(type,name) \ type name(void) \ { \ -register long __sc0 __asm__ ("$r3") = __NR_##name; \ +register long __sc0 __asm__ ("r3") = __NR_##name; \ __asm__ __volatile__ ("trapa #0x10" \ : "=z" (__sc0) \ : "0" (__sc0) \ @@ -260,8 +261,8 @@ #define _syscall1(type,name,type1,arg1) \ type name(type1 arg1) \ { \ -register long __sc0 __asm__ ("$r3") = __NR_##name; \ -register long __sc4 __asm__ ("$r4") = (long) arg1; \ +register long __sc0 __asm__ ("r3") = __NR_##name; \ +register long __sc4 __asm__ ("r4") = (long) arg1; \ __asm__ __volatile__ ("trapa #0x11" \ : "=z" (__sc0) \ : "0" (__sc0), "r" (__sc4) \ @@ -272,9 +273,9 @@ #define _syscall2(type,name,type1,arg1,type2,arg2) \ type name(type1 arg1,type2 arg2) \ { \ -register long __sc0 __asm__ ("$r3") = __NR_##name; \ -register long __sc4 __asm__ ("$r4") = (long) arg1; \ -register long __sc5 __asm__ ("$r5") = (long) arg2; \ +register long __sc0 __asm__ ("r3") = __NR_##name; \ +register long __sc4 __asm__ ("r4") = (long) arg1; \ +register long __sc5 __asm__ ("r5") = (long) arg2; \ __asm__ __volatile__ ("trapa #0x12" \ : "=z" (__sc0) \ : "0" (__sc0), "r" (__sc4), "r" (__sc5) \ @@ -285,10 +286,10 @@ #define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \ type name(type1 arg1,type2 arg2,type3 arg3) \ { \ -register long __sc0 __asm__ ("$r3") = __NR_##name; \ -register long __sc4 __asm__ ("$r4") = (long) arg1; \ -register long __sc5 __asm__ ("$r5") = (long) arg2; \ -register long __sc6 __asm__ ("$r6") = (long) arg3; \ +register long __sc0 __asm__ ("r3") = __NR_##name; \ +register long __sc4 __asm__ ("r4") = (long) arg1; \ +register long __sc5 __asm__ ("r5") = (long) arg2; \ +register long __sc6 __asm__ ("r6") = (long) arg3; \ __asm__ __volatile__ ("trapa #0x13" \ : "=z" (__sc0) \ : "0" (__sc0), "r" (__sc4), "r" (__sc5), "r" (__sc6) \ @@ -299,11 +300,11 @@ #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4) \ { \ -register long __sc0 __asm__ ("$r3") = __NR_##name; \ -register long __sc4 __asm__ ("$r4") = (long) arg1; \ -register long __sc5 __asm__ ("$r5") = (long) arg2; \ -register long __sc6 __asm__ ("$r6") = (long) arg3; \ -register long __sc7 __asm__ ("$r7") = (long) arg4; \ +register long __sc0 __asm__ ("r3") = __NR_##name; \ +register long __sc4 __asm__ ("r4") = (long) arg1; \ +register long __sc5 __asm__ ("r5") = (long) arg2; \ +register long __sc6 __asm__ ("r6") = (long) arg3; \ +register long __sc7 __asm__ ("r7") = (long) arg4; \ __asm__ __volatile__ ("trapa #0x14" \ : "=z" (__sc0) \ : "0" (__sc0), "r" (__sc4), "r" (__sc5), "r" (__sc6), \ @@ -315,12 +316,12 @@ #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5) \ type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \ { \ -register long __sc3 __asm__ ("$r3") = __NR_##name; \ -register long __sc4 __asm__ ("$r4") = (long) arg1; \ -register long __sc5 __asm__ ("$r5") = (long) arg2; \ -register long __sc6 __asm__ ("$r6") = (long) arg3; \ -register long __sc7 __asm__ ("$r7") = (long) arg4; \ -register long __sc0 __asm__ ("$r0") = (long) arg5; \ +register long __sc3 __asm__ ("r3") = __NR_##name; \ +register long __sc4 __asm__ ("r4") = (long) arg1; \ +register long __sc5 __asm__ ("r5") = (long) arg2; \ +register long __sc6 __asm__ ("r6") = (long) arg3; \ +register long __sc7 __asm__ ("r7") = (long) arg4; \ +register long __sc0 __asm__ ("r0") = (long) arg5; \ __asm__ __volatile__ ("trapa #0x15" \ : "=z" (__sc0) \ : "0" (__sc0), "r" (__sc4), "r" (__sc5), "r" (__sc6), "r" (__sc7), \ @@ -345,7 +346,6 @@ */ #define __NR__exit __NR_exit static __inline__ _syscall0(int,pause) -static __inline__ _syscall1(int,setup,int,magic) static __inline__ _syscall0(int,sync) static __inline__ _syscall0(pid_t,setsid) static __inline__ _syscall3(int,write,int,fd,const char *,buf,off_t,count) diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-sparc/atomic.h linux/include/asm-sparc/atomic.h --- v2.4.0-test8/linux/include/asm-sparc/atomic.h Thu Sep 7 08:32:01 2000 +++ linux/include/asm-sparc/atomic.h Tue Oct 3 09:24:41 2000 @@ -8,19 +8,12 @@ #include -#ifdef CONFIG_SMP -/* This is a temporary measure. -DaveM */ typedef struct { volatile int counter; } atomic_t; -#define ATOMIC_INIT(i) { (i << 8) } -#else -typedef struct { int counter; } atomic_t; -#define ATOMIC_INIT(i) { (i) } -#endif #ifdef __KERNEL__ - #ifndef CONFIG_SMP +#define ATOMIC_INIT(i) { (i) } #define atomic_read(v) ((v)->counter) #define atomic_set(v, i) (((v)->counter) = i) @@ -38,6 +31,8 @@ * ---------------------------------------- * 31 8 7 0 */ + +#define ATOMIC_INIT(i) { (i << 8) } static __inline__ int atomic_read(atomic_t *v) { diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-sparc/bitops.h linux/include/asm-sparc/bitops.h --- v2.4.0-test8/linux/include/asm-sparc/bitops.h Sat Aug 12 12:08:50 2000 +++ linux/include/asm-sparc/bitops.h Tue Oct 3 09:24:41 2000 @@ -1,4 +1,4 @@ -/* $Id: bitops.h,v 1.60 2000/08/10 23:49:16 davem Exp $ +/* $Id: bitops.h,v 1.61 2000/09/23 02:11:22 davem Exp $ * bitops.h: Bit string operations on the Sparc. * * Copyright 1995 David S. Miller (davem@caip.rutgers.edu) @@ -155,6 +155,9 @@ } #endif /* __KERNEL__ */ + +#define smp_mb__before_clear_bit() do { } while(0) +#define smp_mb__after_clear_bit() do { } while(0) /* The following routine need not be atomic. */ extern __inline__ int test_bit(int nr, __const__ void *addr) diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-sparc/fcntl.h linux/include/asm-sparc/fcntl.h --- v2.4.0-test8/linux/include/asm-sparc/fcntl.h Sun Aug 13 12:01:54 2000 +++ linux/include/asm-sparc/fcntl.h Fri Sep 22 14:21:21 2000 @@ -50,6 +50,9 @@ #define F_EXLCK 4 /* or 3 */ #define F_SHLCK 8 /* or 4 */ +/* for leases */ +#define F_INPROGRESS 16 + /* operations for bsd flock(), also used by the kernel implementation */ #define LOCK_SH 1 /* shared lock */ #define LOCK_EX 2 /* exclusive lock */ @@ -57,6 +60,11 @@ blocking */ #define LOCK_UN 8 /* remove lock */ +#define LOCK_MAND 32 /* This is a mandatory flock */ +#define LOCK_READ 64 /* ... Which allows concurrent read operations */ +#define LOCK_WRITE 128 /* ... Which allows concurrent write operations */ +#define LOCK_RW 192 /* ... Which allows concurrent read & write ops */ + struct flock { short l_type; short l_whence; @@ -75,4 +83,5 @@ short __unused; }; +#define F_LINUX_SPECIFIC_BASE 1024 #endif diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-sparc/io.h linux/include/asm-sparc/io.h --- v2.4.0-test8/linux/include/asm-sparc/io.h Fri Apr 14 09:37:10 2000 +++ linux/include/asm-sparc/io.h Sun Sep 17 09:50:02 2000 @@ -1,5 +1,5 @@ /* - * $Id: io.h,v 1.27 2000/04/13 04:45:59 davem Exp $ + * $Id: io.h,v 1.28 2000/09/17 05:12:00 davem Exp $ */ #ifndef __SPARC_IO_H #define __SPARC_IO_H @@ -164,6 +164,8 @@ return (void *) dst; } +#ifdef __KERNEL__ + /* * Bus number may be embedded in the higher bits of the physical address. * This is why we have no bus number argument to ioremap(). @@ -199,5 +201,7 @@ #define dma_cache_inv(_start,_size) do { } while (0) #define dma_cache_wback(_start,_size) do { } while (0) #define dma_cache_wback_inv(_start,_size) do { } while (0) + +#endif #endif /* !(__SPARC_IO_H) */ diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-sparc/resource.h linux/include/asm-sparc/resource.h --- v2.4.0-test8/linux/include/asm-sparc/resource.h Thu Feb 17 09:35:07 2000 +++ linux/include/asm-sparc/resource.h Fri Sep 22 14:21:21 2000 @@ -21,8 +21,9 @@ #define RLIMIT_NPROC 7 /* max number of processes */ #define RLIMIT_MEMLOCK 8 /* max locked-in-memory address space */ #define RLIMIT_AS 9 /* address space limit */ +#define RLIMIT_LOCKS 10 /* maximum file locks held */ -#define RLIM_NLIMITS 10 +#define RLIM_NLIMITS 11 /* * SuS says limits have to be unsigned. @@ -41,6 +42,7 @@ { 0, RLIM_INFINITY}, \ {RLIM_INFINITY, RLIM_INFINITY}, \ {INR_OPEN, INR_OPEN}, {0, 0}, \ + {RLIM_INFINITY, RLIM_INFINITY}, \ {RLIM_INFINITY, RLIM_INFINITY}, \ {RLIM_INFINITY, RLIM_INFINITY} \ } diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-sparc/system.h linux/include/asm-sparc/system.h --- v2.4.0-test8/linux/include/asm-sparc/system.h Fri Aug 4 18:16:11 2000 +++ linux/include/asm-sparc/system.h Tue Oct 3 09:24:41 2000 @@ -1,4 +1,4 @@ -/* $Id: system.h,v 1.83 2000/08/04 05:35:55 davem Exp $ */ +/* $Id: system.h,v 1.84 2000/09/23 02:11:22 davem Exp $ */ #include #ifndef __SPARC_SYSTEM_H @@ -280,6 +280,9 @@ #define wmb() mb() #define set_mb(__var, __value) do { __var = __value; mb(); } while(0) #define set_wmb(__var, __value) set_mb(__var, __value) +#define smp_mb() __asm__ __volatile__("":::"memory"); +#define smp_rmb() __asm__ __volatile__("":::"memory"); +#define smp_wmb() __asm__ __volatile__("":::"memory"); #define nop() __asm__ __volatile__ ("nop"); diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-sparc64/atomic.h linux/include/asm-sparc64/atomic.h --- v2.4.0-test8/linux/include/asm-sparc64/atomic.h Thu Mar 16 11:40:17 2000 +++ linux/include/asm-sparc64/atomic.h Tue Oct 3 09:24:41 2000 @@ -8,7 +8,7 @@ #ifndef __ARCH_SPARC64_ATOMIC__ #define __ARCH_SPARC64_ATOMIC__ -typedef struct { int counter; } atomic_t; +typedef struct { volatile int counter; } atomic_t; #define ATOMIC_INIT(i) { (i) } #define atomic_read(v) ((v)->counter) diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-sparc64/bitops.h linux/include/asm-sparc64/bitops.h --- v2.4.0-test8/linux/include/asm-sparc64/bitops.h Sat Aug 12 12:08:50 2000 +++ linux/include/asm-sparc64/bitops.h Tue Oct 3 09:24:41 2000 @@ -1,4 +1,4 @@ -/* $Id: bitops.h,v 1.30 2000/08/10 23:49:16 davem Exp $ +/* $Id: bitops.h,v 1.31 2000/09/23 02:09:21 davem Exp $ * bitops.h: Bit string operations on the V9. * * Copyright 1996, 1997 David S. Miller (davem@caip.rutgers.edu) @@ -19,6 +19,9 @@ #define set_bit(nr,addr) ((void)__test_and_set_bit(nr,addr)) #define clear_bit(nr,addr) ((void)__test_and_clear_bit(nr,addr)) #define change_bit(nr,addr) ((void)__test_and_change_bit(nr,addr)) + +#define smp_mb__before_clear_bit() do { } while(0) +#define smp_mb__after_clear_bit() do { } while(0) extern __inline__ int test_bit(int nr, __const__ void *addr) { diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-sparc64/fcntl.h linux/include/asm-sparc64/fcntl.h --- v2.4.0-test8/linux/include/asm-sparc64/fcntl.h Sun Aug 13 12:01:54 2000 +++ linux/include/asm-sparc64/fcntl.h Fri Sep 22 14:21:21 2000 @@ -52,6 +52,9 @@ #define F_EXLCK 4 /* or 3 */ #define F_SHLCK 8 /* or 4 */ +/* for leases */ +#define F_INPROGRESS 16 + /* operations for bsd flock(), also used by the kernel implementation */ #define LOCK_SH 1 /* shared lock */ #define LOCK_EX 2 /* exclusive lock */ @@ -59,6 +62,11 @@ blocking */ #define LOCK_UN 8 /* remove lock */ +#define LOCK_MAND 32 /* This is a mandatory flock */ +#define LOCK_READ 64 /* ... Which allows concurrent read operations */ +#define LOCK_WRITE 128 /* ... Which allows concurrent write operations */ +#define LOCK_RW 192 /* ... Which allows concurrent read & write ops */ + struct flock { short l_type; short l_whence; @@ -83,4 +91,5 @@ #define flock64 flock #endif +#define F_LINUX_SPECIFIC_BASE 1024 #endif /* !(_SPARC64_FCNTL_H) */ diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-sparc64/io.h linux/include/asm-sparc64/io.h --- v2.4.0-test8/linux/include/asm-sparc64/io.h Fri Apr 14 09:37:10 2000 +++ linux/include/asm-sparc64/io.h Sun Sep 17 09:50:02 2000 @@ -1,4 +1,4 @@ -/* $Id: io.h,v 1.35 2000/04/13 04:45:59 davem Exp $ */ +/* $Id: io.h,v 1.36 2000/09/17 05:12:00 davem Exp $ */ #ifndef __SPARC64_IO_H #define __SPARC64_IO_H @@ -363,6 +363,8 @@ return retval; } +#ifdef __KERNEL__ + /* On sparc64 we have the whole physical IO address space accessible * using physically addressed loads and stores, so this does nothing. */ @@ -388,5 +390,7 @@ #define dma_cache_inv(_start,_size) do { } while (0) #define dma_cache_wback(_start,_size) do { } while (0) #define dma_cache_wback_inv(_start,_size) do { } while (0) + +#endif #endif /* !(__SPARC64_IO_H) */ diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-sparc64/resource.h linux/include/asm-sparc64/resource.h --- v2.4.0-test8/linux/include/asm-sparc64/resource.h Thu Feb 17 09:35:07 2000 +++ linux/include/asm-sparc64/resource.h Fri Sep 22 14:21:21 2000 @@ -21,8 +21,9 @@ #define RLIMIT_NPROC 7 /* max number of processes */ #define RLIMIT_MEMLOCK 8 /* max locked-in-memory address space */ #define RLIMIT_AS 9 /* address space limit */ +#define RLIMIT_LOCKS 10 /* maximum file locks held */ -#define RLIM_NLIMITS 10 +#define RLIM_NLIMITS 11 /* * SuS says limits have to be unsigned. @@ -40,6 +41,7 @@ { 0, RLIM_INFINITY}, \ {RLIM_INFINITY, RLIM_INFINITY}, \ {INR_OPEN, INR_OPEN}, {0, 0}, \ + {RLIM_INFINITY, RLIM_INFINITY}, \ {RLIM_INFINITY, RLIM_INFINITY}, \ {RLIM_INFINITY, RLIM_INFINITY} \ } diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-sparc64/smp.h linux/include/asm-sparc64/smp.h --- v2.4.0-test8/linux/include/asm-sparc64/smp.h Fri Aug 4 16:15:37 2000 +++ linux/include/asm-sparc64/smp.h Tue Oct 3 09:24:41 2000 @@ -9,6 +9,7 @@ #include #include #include +#include #ifndef __ASSEMBLY__ /* PROM provided per-processor information we need @@ -82,11 +83,7 @@ extern __inline__ int hard_smp_processor_id(void) { - extern int this_is_starfire; - if(this_is_starfire != 0) { - extern int starfire_hard_smp_processor_id(void); - return starfire_hard_smp_processor_id(); } else { unsigned long upaconfig; diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-sparc64/starfire.h linux/include/asm-sparc64/starfire.h --- v2.4.0-test8/linux/include/asm-sparc64/starfire.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-sparc64/starfire.h Tue Oct 3 09:24:41 2000 @@ -0,0 +1,21 @@ +/* $Id: starfire.h,v 1.1 2000/09/21 06:18:53 anton Exp $ + * starfire.h: Group all starfire specific code together. + * + * Copyright (C) 2000 Anton Blanchard (anton@linuxcare.com) + */ + +#ifndef _SPARC64_STARFIRE_H +#define _SPARC64_STARFIRE_H + +#ifndef __ASSEMBLY__ + +extern int this_is_starfire; + +extern void check_if_starfire(void); +extern void starfire_cpu_setup(void); +extern int starfire_hard_smp_processor_id(void); +extern void *starfire_hookup(int); +extern unsigned int starfire_translate(unsigned long imap, unsigned int upaid); + +#endif +#endif diff -u --recursive --new-file v2.4.0-test8/linux/include/asm-sparc64/system.h linux/include/asm-sparc64/system.h --- v2.4.0-test8/linux/include/asm-sparc64/system.h Fri Aug 4 18:16:11 2000 +++ linux/include/asm-sparc64/system.h Tue Oct 3 09:24:41 2000 @@ -1,4 +1,4 @@ -/* $Id: system.h,v 1.61 2000/08/04 05:35:55 davem Exp $ */ +/* $Id: system.h,v 1.62 2000/09/23 02:09:21 davem Exp $ */ #ifndef __SPARC64_SYSTEM_H #define __SPARC64_SYSTEM_H @@ -95,17 +95,27 @@ #endif -#define mb() __asm__ __volatile__ ("stbar" : : : "memory") - #define nop() __asm__ __volatile__ ("nop") #define membar(type) __asm__ __volatile__ ("membar " type : : : "memory"); -#define rmb() membar("#LoadLoad | #LoadStore") -#define wmb() membar("#StoreLoad | #StoreStore") +#define mb() \ + membar("#LoadLoad | #LoadStore | #StoreStore | #StoreLoad"); +#define rmb() membar("#LoadLoad") +#define wmb() membar("#StoreStore") #define set_mb(__var, __value) \ do { __var = __value; membar("#StoreLoad | #StoreStore"); } while(0) #define set_wmb(__var, __value) \ do { __var = __value; membar("#StoreStore"); } while(0) + +#ifdef CONFIG_SMP +#define smp_mb() mb() +#define smp_rmb() rmb() +#define smp_wmb() wmb() +#else +#define smp_mb() __asm__ __volatile__("":::"memory"); +#define smp_rmb() __asm__ __volatile__("":::"memory"); +#define smp_wmb() __asm__ __volatile__("":::"memory"); +#endif #define flushi(addr) __asm__ __volatile__ ("flush %0" : : "r" (addr) : "memory") diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/ac97_codec.h linux/include/linux/ac97_codec.h --- v2.4.0-test8/linux/include/linux/ac97_codec.h Tue Jun 20 07:52:36 2000 +++ linux/include/linux/ac97_codec.h Mon Oct 2 11:01:20 2000 @@ -142,6 +142,7 @@ char *name; int id; int dev_mixer; + int type; /* codec specific init/reset routines, used mainly for 4 or 6 channel support */ int (*codec_init) (struct ac97_codec *codec); @@ -158,7 +159,9 @@ int supported_mixers; int stereo_mixers; int record_sources; - + + int bit_resolution; + /* OSS mixer interface */ int (*read_mixer) (struct ac97_codec *codec, int oss_channel); void (*write_mixer)(struct ac97_codec *codec, int oss_channel, diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/adb.h linux/include/linux/adb.h --- v2.4.0-test8/linux/include/linux/adb.h Tue Oct 12 10:00:58 1999 +++ linux/include/linux/adb.h Sun Sep 17 09:48:05 2000 @@ -58,7 +58,6 @@ int (*probe)(void); int (*init)(void); int (*send_request)(struct adb_request *req, int sync); - /*int (*write)(struct adb_request *req);*/ int (*autopoll)(int devs); void (*poll)(void); int (*reset_bus)(void); @@ -83,6 +82,7 @@ int flags, int nbytes, ...); int adb_register(int default_id,int handler_id,struct adb_ids *ids, void (*handler)(unsigned char *, int, struct pt_regs *, int)); +int adb_unregister(int index); void adb_poll(void); void adb_input(unsigned char *, int, struct pt_regs *, int); int adb_reset_bus(void); diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/adfs_fs.h linux/include/linux/adfs_fs.h --- v2.4.0-test8/linux/include/linux/adfs_fs.h Fri Sep 8 12:52:55 2000 +++ linux/include/linux/adfs_fs.h Mon Oct 2 11:01:25 2000 @@ -46,7 +46,7 @@ * appear to be correct if the sector contains all zeros, so also check that * the disk size is non-zero!!! */ -extern inline int adfs_checkbblk(unsigned char *ptr) +static inline int adfs_checkbblk(unsigned char *ptr) { unsigned int result = 0; unsigned char *p = ptr + 511; diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/arcdevice.h linux/include/linux/arcdevice.h --- v2.4.0-test8/linux/include/linux/arcdevice.h Mon Jul 31 14:25:52 2000 +++ linux/include/linux/arcdevice.h Sun Sep 17 09:45:05 2000 @@ -340,7 +340,6 @@ void arcnet_raw_init(void); int com90xx_probe(struct net_device *dev); -void com20020pci_probe_all(void); #endif /* __KERNEL__ */ diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/atalk.h linux/include/linux/atalk.h --- v2.4.0-test8/linux/include/linux/atalk.h Fri Sep 8 12:52:42 2000 +++ linux/include/linux/atalk.h Mon Oct 2 11:01:18 2000 @@ -161,7 +161,7 @@ * Give a device find its atif control structure */ -extern __inline__ struct atalk_iface *atalk_find_dev(struct net_device *dev) +static inline struct atalk_iface *atalk_find_dev(struct net_device *dev) { return dev->atalk_ptr; } diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/blk.h linux/include/linux/blk.h --- v2.4.0-test8/linux/include/linux/blk.h Fri Sep 8 12:54:09 2000 +++ linux/include/linux/blk.h Mon Oct 2 11:02:34 2000 @@ -308,7 +308,7 @@ #elif (MAJOR_NR == I2O_MAJOR) #define DEVICE_NAME "I2O block" -#define DEVICE_REQUEST do_i2ob_request +#define DEVICE_REQUEST i2ob_request #define DEVICE_NR(device) (MINOR(device)>>4) #elif (MAJOR_NR == COMPAQ_SMART2_MAJOR) diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/brlock.h linux/include/linux/brlock.h --- v2.4.0-test8/linux/include/linux/brlock.h Fri Sep 8 12:52:42 2000 +++ linux/include/linux/brlock.h Mon Oct 2 11:01:18 2000 @@ -114,10 +114,23 @@ lock = &__br_write_locks[idx].lock; again: (*ctr)++; - rmb(); + mb(); if (spin_is_locked(lock)) { (*ctr)--; - rmb(); + wmb(); /* + * The release of the ctr must become visible + * to the other cpus eventually thus wmb(), + * we don't care if spin_is_locked is reordered + * before the releasing of the ctr. + * However IMHO this wmb() is superflous even in theory. + * It would not be superflous only if on the + * other CPUs doing a ldl_l instead of an ldl + * would make a difference and I don't think this is + * the case. + * I'd like to clarify this issue further + * but for now this is a slow path so adding the + * wmb() will keep us on the safe side. + */ while (spin_is_locked(lock)) barrier(); goto again; diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/byteorder/swab.h linux/include/linux/byteorder/swab.h --- v2.4.0-test8/linux/include/linux/byteorder/swab.h Tue Sep 1 10:50:11 1998 +++ linux/include/linux/byteorder/swab.h Tue Sep 19 17:56:31 2000 @@ -43,33 +43,33 @@ * provide defaults when no architecture-specific optimization is detected */ #ifndef __arch__swab16 -# define __arch__swab16(x) ___swab16(x) +# define __arch__swab16(x) ({ __u16 __tmp = (x) ; ___swab16(__tmp); }) #endif #ifndef __arch__swab32 -# define __arch__swab32(x) ___swab32(x) +# define __arch__swab32(x) ({ __u32 __tmp = (x) ; ___swab32(__tmp); }) #endif #ifndef __arch__swab64 -# define __arch__swab64(x) ___swab64(x) +# define __arch__swab64(x) ({ __u64 __tmp = (x) ; ___swab64(__tmp); }) #endif #ifndef __arch__swab16p -# define __arch__swab16p(x) __swab16(*(x)) +# define __arch__swab16p(x) __arch__swab16(*(x)) #endif #ifndef __arch__swab32p -# define __arch__swab32p(x) __swab32(*(x)) +# define __arch__swab32p(x) __arch__swab32(*(x)) #endif #ifndef __arch__swab64p -# define __arch__swab64p(x) __swab64(*(x)) +# define __arch__swab64p(x) __arch__swab64(*(x)) #endif #ifndef __arch__swab16s -# define __arch__swab16s(x) do { *(x) = __swab16p((x)); } while (0) +# define __arch__swab16s(x) do { *(x) = __arch__swab16p((x)); } while (0) #endif #ifndef __arch__swab32s -# define __arch__swab32s(x) do { *(x) = __swab32p((x)); } while (0) +# define __arch__swab32s(x) do { *(x) = __arch__swab32p((x)); } while (0) #endif #ifndef __arch__swab64s -# define __arch__swab64s(x) do { *(x) = __swab64p((x)); } while (0) +# define __arch__swab64s(x) do { *(x) = __arch__swab64p((x)); } while (0) #endif diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/capability.h linux/include/linux/capability.h --- v2.4.0-test8/linux/include/linux/capability.h Fri Sep 8 12:52:42 2000 +++ linux/include/linux/capability.h Mon Oct 2 11:01:19 2000 @@ -273,6 +273,10 @@ #define CAP_MKNOD 27 +/* Allow taking of leases on files */ + +#define CAP_LEASE 28 + #ifdef __KERNEL__ /* * Bounding set diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/cciss_ioctl.h linux/include/linux/cciss_ioctl.h --- v2.4.0-test8/linux/include/linux/cciss_ioctl.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/cciss_ioctl.h Fri Sep 22 17:11:37 2000 @@ -0,0 +1,186 @@ +#ifndef CCISS_IOCTLH +#define CCISS_IOCTLH + +#include +#include + +#define CCISS_IOC_MAGIC 'B' + + +typedef struct _cciss_pci_info_struct +{ + unsigned char bus; + unsigned char dev_fn; + __u32 board_id; +} cciss_pci_info_struct; + +typedef struct _cciss_coalint_struct +{ + __u32 delay; + __u32 count; +} cciss_coalint_struct; + +typedef char NodeName_type[16]; + +typedef __u32 Heartbeat_type; + +#define CISS_PARSCSIU2 0x0001 +#define CISS_PARCSCIU3 0x0002 +#define CISS_FIBRE1G 0x0100 +#define CISS_FIBRE2G 0x0200 +typedef __u32 BusTypes_type; + +typedef char FirmwareVer_type[4]; +typedef __u32 DriverVer_type; + + +#ifndef CCISS_CMD_H +// This defines are duplicated in cciss_cmd.h in the driver directory + +//general boundary defintions +#define SENSEINFOBYTES 32//note that this value may vary between host implementations + +//Command Status value +#define CMD_SUCCESS 0x0000 +#define CMD_TARGET_STATUS 0x0001 +#define CMD_DATA_UNDERRUN 0x0002 +#define CMD_DATA_OVERRUN 0x0003 +#define CMD_INVALID 0x0004 +#define CMD_PROTOCOL_ERR 0x0005 +#define CMD_HARDWARE_ERR 0x0006 +#define CMD_CONNECTION_LOST 0x0007 +#define CMD_ABORTED 0x0008 +#define CMD_ABORT_FAILED 0x0009 +#define CMD_UNSOLICITED_ABORT 0x000A +#define CMD_TIMEOUT 0x000B +#define CMD_UNABORTABLE 0x000C + +//transfer direction +#define XFER_NONE 0x00 +#define XFER_WRITE 0x01 +#define XFER_READ 0x02 +#define XFER_RSVD 0x03 + +//task attribute +#define ATTR_UNTAGGED 0x00 +#define ATTR_SIMPLE 0x04 +#define ATTR_HEADOFQUEUE 0x05 +#define ATTR_ORDERED 0x06 +#define ATTR_ACA 0x07 + +//cdb type +#define TYPE_CMD 0x00 +#define TYPE_MSG 0x01 + +// Type defs used in the following structs +#define BYTE __u8 +#define WORD __u16 +#define HWORD __u16 +#define DWORD __u32 + +#define CISS_MAX_LUN 16 + +#pragma pack(1) + +//Command List Structure +typedef union _SCSI3Addr_struct { + struct { + BYTE Bus:6; + BYTE Mode:2; // b00 + BYTE Dev; + } PeripDev; + struct { + BYTE DevMSB:6; + BYTE Mode:2; // b01 + BYTE DevLSB; + } LogDev; + struct { + BYTE Targ:6; + BYTE Mode:2; // b10 + BYTE Dev:5; + BYTE Bus:3; + } LogUnit; +} SCSI3Addr_struct; + +typedef struct _PhysDevAddr_struct { + DWORD TargetId:24; + DWORD Bus:6; + DWORD Mode:2; + SCSI3Addr_struct Target[2]; //2 level target device addr +} PhysDevAddr_struct; + +typedef struct _LogDevAddr_struct { + DWORD VolId:30; + DWORD Mode:2; + BYTE reserved[4]; +} LogDevAddr_struct; + +typedef union _LUNAddr_struct { + BYTE LunAddrBytes[8]; + SCSI3Addr_struct SCSI3Lun[4]; + PhysDevAddr_struct PhysDev; + LogDevAddr_struct LogDev; +} LUNAddr_struct; + +typedef struct _RequestBlock_struct { + BYTE CDBLen; + struct { + BYTE Type:3; + BYTE Attribute:3; + BYTE Direction:2; + } Type; + HWORD Timeout; + BYTE CDB[16]; +} RequestBlock_struct; + +typedef union _MoreErrInfo_struct{ + struct { + BYTE Reserved[3]; + BYTE Type; + DWORD ErrorInfo; + }Common_Info; + struct{ + BYTE Reserved[2]; + BYTE offense_size;//size of offending entry + BYTE offense_num; //byte # of offense 0-base + DWORD offense_value; + }Invalid_Cmd; +}MoreErrInfo_struct; +typedef struct _ErrorInfo_struct { + BYTE ScsiStatus; + BYTE SenseLen; + HWORD CommandStatus; + DWORD ResidualCnt; + MoreErrInfo_struct MoreErrInfo; + BYTE SenseInfo[SENSEINFOBYTES]; +} ErrorInfo_struct; + +#pragma pack() +#endif /* CCISS_CMD_H */ + +typedef struct _IOCTL_Command_struct { + LUNAddr_struct LUN_info; + RequestBlock_struct Request; + ErrorInfo_struct error_info; + WORD buf_size; /* size in bytes of the buf */ + BYTE *buf; +} IOCTL_Command_struct; + + +#define CCISS_GETPCIINFO _IOR(CCISS_IOC_MAGIC, 1, cciss_pci_info_struct) + +#define CCISS_GETINTINFO _IOR(CCISS_IOC_MAGIC, 2, cciss_coalint_struct) +#define CCISS_SETINTINFO _IOW(CCISS_IOC_MAGIC, 3, cciss_coalint_struct) + +#define CCISS_GETNODENAME _IOR(CCISS_IOC_MAGIC, 4, NodeName_type) +#define CCISS_SETNODENAME _IOW(CCISS_IOC_MAGIC, 5, NodeName_type) + +#define CCISS_GETHEARTBEAT _IOR(CCISS_IOC_MAGIC, 6, Heartbeat_type) +#define CCISS_GETBUSTYPES _IOR(CCISS_IOC_MAGIC, 7, BusTypes_type) +#define CCISS_GETFIRMVER _IOR(CCISS_IOC_MAGIC, 8, FirmwareVer_type) +#define CCISS_GETDRIVVER _IOR(CCISS_IOC_MAGIC, 9, DriverVer_type) +#define CCISS_REVALIDVOLS _IO(CCISS_IOC_MAGIC, 10) +#define CCISS_PASSTHRU _IOWR(CCISS_IOC_MAGIC, 11, IOCTL_Command_struct) + + +#endif diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/coda.h linux/include/linux/coda.h --- v2.4.0-test8/linux/include/linux/coda.h Wed Jun 21 10:10:02 2000 +++ linux/include/linux/coda.h Tue Sep 19 15:08:59 2000 @@ -284,7 +284,7 @@ */ #define CODA_ROOT 2 -#define CODA_SYNC 3 +#define CODA_OPEN_BY_FD 3 #define CODA_OPEN 4 #define CODA_CLOSE 5 #define CODA_IOCTL 6 @@ -298,11 +298,9 @@ #define CODA_RENAME 14 #define CODA_MKDIR 15 #define CODA_RMDIR 16 -#define CODA_READDIR 17 #define CODA_SYMLINK 18 #define CODA_READLINK 19 #define CODA_FSYNC 20 -#define CODA_INACTIVE 21 #define CODA_VGET 22 #define CODA_SIGNAL 23 #define CODA_REPLACE 24 /* DOWNCALL */ @@ -315,12 +313,9 @@ #define CODA_RESOLVE 32 #define CODA_REINTEGRATE 33 #define CODA_STATFS 34 -#define CODA_MAKE_CINODE 35 /* DOWNCALL */ -#define CODA_NCALLS 36 +#define CODA_NCALLS 35 -#define DOWNCALL(opcode) \ - ((opcode >= CODA_REPLACE && opcode <= CODA_PURGEFID) || \ - opcode == CODA_MAKE_CINODE) +#define DOWNCALL(opcode) (opcode >= CODA_REPLACE && opcode <= CODA_PURGEFID) #define VC_MAXDATASIZE 8192 #define VC_MAXMSGSIZE sizeof(union inputArgs)+sizeof(union outputArgs) +\ @@ -328,7 +323,7 @@ #define CIOC_KERNEL_VERSION _IOWR('c', 10, sizeof (int)) -#if 0 +#if 0 #define CODA_KERNEL_VERSION 0 /* don't care about kernel version number */ #define CODA_KERNEL_VERSION 1 /* The old venus 4.6 compatible interface */ #endif @@ -363,9 +358,6 @@ struct coda_in_hdr in; }; -/* coda_sync: */ -/* Nothing needed for coda_sync */ - /* coda_open: */ struct coda_open_in { struct coda_in_hdr ih; @@ -542,20 +534,6 @@ struct coda_out_hdr out; }; -/* coda_readdir: */ -struct coda_readdir_in { - struct coda_in_hdr ih; - ViceFid VFid; - int count; - int offset; -}; - -struct coda_readdir_out { - struct coda_out_hdr oh; - int size; - caddr_t data; /* Place holder for data. */ -}; - /* coda_symlink: NO_OUT */ struct coda_symlink_in { struct coda_in_hdr ih; @@ -592,12 +570,6 @@ struct coda_out_hdr out; }; -/* coda_inactive: NO_OUT */ -struct coda_inactive_in { - struct coda_in_hdr ih; - ViceFid VFid; -}; - /* coda_vget: */ struct coda_vget_in { struct coda_in_hdr ih; @@ -651,38 +623,24 @@ ViceFid CodaFid; }; -struct coda_make_cinode_out { +/* coda_replace: */ +/* CODA_REPLACE is a venus->kernel call */ +struct coda_replace_out { /* coda_replace is a venus->kernel call */ struct coda_out_hdr oh; - ViceFid CodaFid; - struct coda_vattr attr; - int fd; + ViceFid NewFid; + ViceFid OldFid; }; -/* coda_rdwr: */ -struct coda_rdwr_in { +/* coda_open_by_fd: */ +struct coda_open_by_fd_in { struct coda_in_hdr ih; - ViceFid VFid; - int rwflag; - int count; - int offset; - int ioflag; - caddr_t data; /* Place holder for data. */ + ViceFid VFid; + int flags; }; -struct coda_rdwr_out { +struct coda_open_by_fd_out { struct coda_out_hdr oh; - int rwflag; - int count; - caddr_t data; /* Place holder for data. */ -}; - - -/* coda_replace: */ -/* CODA_REPLACE is a venus->kernel call */ -struct coda_replace_out { /* coda_replace is a venus->kernel call */ - struct coda_out_hdr oh; - ViceFid NewFid; - ViceFid OldFid; + int fd; }; /* coda_open_by_path: */ @@ -729,13 +687,11 @@ struct coda_rename_in coda_rename; struct coda_mkdir_in coda_mkdir; struct coda_rmdir_in coda_rmdir; - struct coda_readdir_in coda_readdir; struct coda_symlink_in coda_symlink; struct coda_readlink_in coda_readlink; struct coda_fsync_in coda_fsync; - struct coda_inactive_in coda_inactive; struct coda_vget_in coda_vget; - struct coda_rdwr_in coda_rdwr; + struct coda_open_by_fd_in coda_open_by_fd; struct coda_open_by_path_in coda_open_by_path; struct coda_statfs_in coda_statfs; }; @@ -749,7 +705,6 @@ struct coda_lookup_out coda_lookup; struct coda_create_out coda_create; struct coda_mkdir_out coda_mkdir; - struct coda_readdir_out coda_readdir; struct coda_readlink_out coda_readlink; struct coda_vget_out coda_vget; struct coda_purgeuser_out coda_purgeuser; @@ -757,9 +712,8 @@ struct coda_zapdir_out coda_zapdir; struct coda_zapvnode_out coda_zapvnode; struct coda_purgefid_out coda_purgefid; - struct coda_rdwr_out coda_rdwr; struct coda_replace_out coda_replace; - struct coda_make_cinode_out coda_make_cinode; + struct coda_open_by_fd_out coda_open_by_fd; struct coda_open_by_path_out coda_open_by_path; struct coda_statfs_out coda_statfs; }; @@ -805,5 +759,15 @@ #define IS_CTL_FID(fidp) ((fidp)->Volume == CTL_VOL &&\ (fidp)->Vnode == CTL_VNO &&\ (fidp)->Unique == CTL_UNI) + +/* Data passed to mount */ + +#define CODA_MOUNT_VERSION 1 + +struct coda_mount_data { + int version; + int fd; /* Opened device */ +}; + #endif diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/coda_cache.h linux/include/linux/coda_cache.h --- v2.4.0-test8/linux/include/linux/coda_cache.h Wed Jun 21 10:10:02 2000 +++ linux/include/linux/coda_cache.h Tue Sep 19 15:08:59 2000 @@ -10,22 +10,10 @@ #ifndef _CFSNC_HEADER_ #define _CFSNC_HEADER_ -/* - * Structure for an element in the Coda Credential Cache. - */ - -struct coda_cache { - struct list_head cc_cclist; /* list of all cache entries */ - struct list_head cc_cnlist; /* list of cache entries/cnode */ - int cc_mask; - struct coda_cred cc_cred; -}; - /* credential cache */ void coda_cache_enter(struct inode *inode, int mask); void coda_cache_clear_inode(struct inode *); -void coda_cache_clear_all(struct super_block *sb); -void coda_cache_clear_cred(struct super_block *sb, struct coda_cred *cred); +void coda_cache_clear_all(struct super_block *sb, struct coda_cred *cred); int coda_cache_check(struct inode *inode, int mask); /* for downcalls and attributes and lookups */ diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/coda_fs_i.h linux/include/linux/coda_fs_i.h --- v2.4.0-test8/linux/include/linux/coda_fs_i.h Fri Sep 8 12:52:41 2000 +++ linux/include/linux/coda_fs_i.h Mon Oct 2 11:01:17 2000 @@ -20,9 +20,12 @@ struct coda_inode_info { struct ViceFid c_fid; /* Coda identifier */ u_short c_flags; /* flags (see below) */ - struct list_head c_cnhead; /* head of cache entries */ struct list_head c_volrootlist; /* list of volroot cnoddes */ - struct inode *c_vnode; /* inode associated with cnode */ + struct list_head c_cilist; /* list of all coda inodes */ + struct inode *c_vnode; /* inode associated with cnode */ + unsigned int c_contcount; /* refcount for container inode */ + struct coda_cred c_cached_cred; /* credentials of cached perms */ + unsigned int c_cached_perm; /* cached access permissions */ int c_magic; /* to verify the data structure */ }; diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/coda_linux.h linux/include/linux/coda_linux.h --- v2.4.0-test8/linux/include/linux/coda_linux.h Tue Jul 18 16:54:19 2000 +++ linux/include/linux/coda_linux.h Tue Sep 19 15:08:59 2000 @@ -40,6 +40,8 @@ int coda_permission(struct inode *inode, int mask); int coda_revalidate_inode(struct dentry *); int coda_notify_change(struct dentry *, struct iattr *); +int coda_pioctl(struct inode * inode, struct file * filp, + unsigned int cmd, unsigned long arg); /* global variables */ extern int coda_debug; @@ -103,20 +105,20 @@ #define CODA_ALLOC(ptr, cast, size) \ do { \ - if (size < 3000) { \ + if (size < PAGE_SIZE) { \ ptr = (cast)kmalloc((unsigned long) size, GFP_KERNEL); \ - CDEBUG(D_MALLOC, "kmalloced: %lx at %p.\n", (long)size, ptr);\ - } else { \ + CDEBUG(D_MALLOC, "kmalloced: %lx at %p.\n", (long)size, ptr); \ + } else { \ ptr = (cast)vmalloc((unsigned long) size); \ - CDEBUG(D_MALLOC, "vmalloced: %lx at %p .\n", (long)size, ptr);}\ + CDEBUG(D_MALLOC, "vmalloced: %lx at %p .\n", (long)size, ptr);} \ if (ptr == 0) { \ - printk("kernel malloc returns 0 at %s:%d\n", __FILE__, __LINE__); \ + printk("kernel malloc returns 0 at %s:%d\n", __FILE__, __LINE__); \ } \ - memset( ptr, 0, size ); \ + else memset( ptr, 0, size ); \ } while (0) -#define CODA_FREE(ptr,size) do {if (size < 3000) { kfree((ptr)); CDEBUG(D_MALLOC, "kfreed: %lx at %p.\n", (long) size, ptr); } else { vfree((ptr)); CDEBUG(D_MALLOC, "vfreed: %lx at %p.\n", (long) size, ptr);} } while (0) +#define CODA_FREE(ptr,size) do {if (size < PAGE_SIZE) { kfree((ptr)); CDEBUG(D_MALLOC, "kfreed: %lx at %p.\n", (long) size, ptr); } else { vfree((ptr)); CDEBUG(D_MALLOC, "vfreed: %lx at %p.\n", (long) size, ptr);} } while (0) /* inode to cnode access functions */ diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/coda_psdev.h linux/include/linux/coda_psdev.h --- v2.4.0-test8/linux/include/linux/coda_psdev.h Wed Jun 28 19:31:36 2000 +++ linux/include/linux/coda_psdev.h Tue Sep 19 15:08:59 2000 @@ -4,19 +4,13 @@ #define CODA_PSDEV_MAJOR 67 #define MAX_CODADEVS 5 /* how many do we allow */ -extern struct venus_comm coda_upc_comm; -extern struct coda_sb_info coda_super_info; #define CODA_SUPER_MAGIC 0x73757245 struct coda_sb_info { - struct inode * sbi_psdev; /* /dev/cfs? Venus/kernel device */ - int sbi_refct; struct venus_comm * sbi_vcomm; - struct inode * sbi_root; struct super_block *sbi_sb; - struct list_head sbi_cchead; - struct list_head sbi_volroothead; + struct list_head sbi_cihead; }; /* communication pending/processing queues */ @@ -26,6 +20,7 @@ struct list_head vc_pending; struct list_head vc_processing; int vc_inuse; + struct super_block *vc_sb; }; @@ -35,11 +30,6 @@ } - -extern void coda_psdev_detach(int unit); -extern int init_coda_psdev(void); - - /* upcalls */ int venus_rootfid(struct super_block *sb, ViceFid *fidp); int venus_getattr(struct super_block *sb, struct ViceFid *fid, @@ -112,6 +102,7 @@ } ; extern struct coda_upcallstats coda_callstats; +extern struct venus_comm coda_comms[]; static inline void clstats(int opcode) { diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/cuda.h linux/include/linux/cuda.h --- v2.4.0-test8/linux/include/linux/cuda.h Tue Oct 12 10:00:58 1999 +++ linux/include/linux/cuda.h Sun Sep 17 09:48:05 2000 @@ -28,7 +28,8 @@ #ifdef __KERNEL__ -void find_via_cuda(void); +extern int find_via_cuda(void); +extern int via_cuda_start(void); extern int cuda_request(struct adb_request *req, void (*done)(struct adb_request *), int nbytes, ...); extern void cuda_poll(void); diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/dcache.h linux/include/linux/dcache.h --- v2.4.0-test8/linux/include/linux/dcache.h Fri Sep 8 12:52:41 2000 +++ linux/include/linux/dcache.h Mon Oct 2 11:01:17 2000 @@ -163,11 +163,11 @@ #define shrink_dcache() prune_dcache(0) struct zone_struct; /* dcache memory management */ -extern int shrink_dcache_memory(int, unsigned int); +extern void shrink_dcache_memory(int, unsigned int); extern void prune_dcache(int); /* icache memory management (defined in linux/fs/inode.c) */ -extern int shrink_icache_memory(int, int); +extern void shrink_icache_memory(int, int); extern void prune_icache(int); /* only used at mount-time */ diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/devpts_fs.h linux/include/linux/devpts_fs.h --- v2.4.0-test8/linux/include/linux/devpts_fs.h Fri Sep 8 12:53:45 2000 +++ linux/include/linux/devpts_fs.h Mon Oct 2 11:01:50 2000 @@ -46,14 +46,14 @@ #endif #ifndef BUILDING_DEVPTS -extern inline void +static inline void devpts_pty_new(int line, kdev_t device) { if ( devpts_upcall_new ) return devpts_upcall_new(line,device); } -extern inline void +static inline void devpts_pty_kill(int line) { if ( devpts_upcall_kill ) @@ -63,10 +63,10 @@ #else /* No /dev/pts filesystem at all */ -extern inline void +static inline void devpts_pty_new(int line, kdev_t device) { } -extern inline void +static inline void devpts_pty_kill(int line) { } #endif diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/dnotify.h linux/include/linux/dnotify.h --- v2.4.0-test8/linux/include/linux/dnotify.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/dnotify.h Fri Sep 22 14:21:22 2000 @@ -0,0 +1,25 @@ +/* + * Directory notification for Linux + * + * Copyright 2000 (C) Stephen Rothwell + */ + +struct dnotify_struct { + struct dnotify_struct * dn_next; + int dn_magic; + unsigned long dn_mask; /* Events to be notified + see linux/fcntl.h */ + int dn_fd; + struct file * dn_filp; +}; + +#define DNOTIFY_MAGIC 0x444E4F54 + +extern void __inode_dir_notify(struct inode *, unsigned long); +extern int fcntl_dirnotify(int, struct file *, unsigned long); + +static inline void inode_dir_notify(struct inode *inode, unsigned long event) +{ + if ((inode)->i_dnotify_mask & (event)) + __inode_dir_notify(inode, event); +} diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/elf.h linux/include/linux/elf.h --- v2.4.0-test8/linux/include/linux/elf.h Fri Sep 8 12:53:16 2000 +++ linux/include/linux/elf.h Mon Oct 2 11:01:38 2000 @@ -72,6 +72,8 @@ #define EM_IA_64 50 /* HP/Intel IA-64 */ +#define EM_X8664 62 /* AMD x86-64 */ + /* * This is an interim value that we will use until the committee comes * up with a final number. diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/ext2_fs_sb.h linux/include/linux/ext2_fs_sb.h --- v2.4.0-test8/linux/include/linux/ext2_fs_sb.h Fri Sep 8 12:52:41 2000 +++ linux/include/linux/ext2_fs_sb.h Wed Sep 27 13:41:33 2000 @@ -16,8 +16,6 @@ #ifndef _LINUX_EXT2_FS_SB #define _LINUX_EXT2_FS_SB -#include - /* * The following is not needed anymore since the descriptors buffer * heads are now dynamically allocated diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/fcntl.h linux/include/linux/fcntl.h --- v2.4.0-test8/linux/include/linux/fcntl.h Fri Aug 11 15:08:03 2000 +++ linux/include/linux/fcntl.h Fri Sep 22 14:21:22 2000 @@ -3,4 +3,24 @@ #include +#define F_SETLEASE (F_LINUX_SPECIFIC_BASE+0) +#define F_GETLEASE (F_LINUX_SPECIFIC_BASE+1) + +/* + * Request nofications on a directory. + * See below for events that may be notified. + */ +#define F_NOTIFY (F_LINUX_SPECIFIC_BASE+2) + +/* + * Types of directory notifications that may be requested. + */ +#define DN_ACCESS 0x00000001 /* File accessed */ +#define DN_MODIFY 0x00000002 /* File modified */ +#define DN_CREATE 0x00000004 /* File created */ +#define DN_DELETE 0x00000008 /* File removed */ +#define DN_RENAME 0x00000010 /* File renamed */ +#define DN_ATTRIB 0x00000020 /* File changed attibutes */ +#define DN_MULTISHOT 0x80000000 /* Don't remove notifier */ + #endif diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/fs.h linux/include/linux/fs.h --- v2.4.0-test8/linux/include/linux/fs.h Fri Sep 8 12:52:42 2000 +++ linux/include/linux/fs.h Mon Oct 2 11:01:19 2000 @@ -54,6 +54,7 @@ }; extern struct files_stat_struct files_stat; extern int max_super_blocks, nr_super_blocks; +extern int leases_enable, dir_notify_enable, lease_break_time; #define NR_FILE 8192 /* this can well be larger on a larger system */ #define NR_RESERVED_FILES 10 /* reserved for root */ @@ -93,7 +94,7 @@ * as nfs_rename() will be cleaned up */ /* - * These are the fs-independent mount-flags: up to 16 flags are supported + * These are the fs-independent mount-flags: up to 32 flags are supported */ #define MS_RDONLY 1 /* Mount read-only */ #define MS_NOSUID 2 /* Ignore suid and sgid bits */ @@ -104,6 +105,7 @@ #define MS_MANDLOCK 64 /* Allow mandatory locks on an FS */ #define MS_NOATIME 1024 /* Do not update access times. */ #define MS_NODIRATIME 2048 /* Do not update directory access times */ +#define MS_BIND 4096 /* * Flags that can be altered by MS_REMOUNT @@ -409,6 +411,9 @@ struct pipe_inode_info *i_pipe; struct block_device *i_bdev; + unsigned long i_dnotify_mask; /* Directory notify events */ + struct dnotify_struct *i_dnotify; /* for directory notifications */ + unsigned long i_state; unsigned int i_flags; @@ -498,6 +503,7 @@ #define FL_BROKEN 4 /* broken flock() emulation */ #define FL_ACCESS 8 /* for processes suspended by mandatory locking */ #define FL_LOCKD 16 /* lock held by rpc.lockd */ +#define FL_LEASE 32 /* lease held on this file */ /* * The POSIX file lock owner is determined by @@ -512,6 +518,7 @@ struct file_lock *fl_next; /* singly linked list for this inode */ struct list_head fl_link; /* doubly linked list of all locks */ struct list_head fl_block; /* circular list of blocked processes */ + struct list_head fl_list; /* block list member */ fl_owner_t fl_owner; unsigned int fl_pid; wait_queue_head_t fl_wait; @@ -525,6 +532,8 @@ void (*fl_insert)(struct file_lock *); /* lock insertion callback */ void (*fl_remove)(struct file_lock *); /* lock removal callback */ + struct fasync_struct * fl_fasync; /* for lease break notifications */ + union { struct nfs_lock_info nfs_fl; } fl_u; @@ -538,6 +547,7 @@ #endif extern struct list_head file_lock_list; +extern struct semaphore file_lock_sem; #include @@ -548,12 +558,18 @@ extern int fcntl_setlk64(unsigned int, unsigned int, struct flock64 *); /* fs/locks.c */ +extern void locks_init_lock(struct file_lock *); +extern void locks_copy_lock(struct file_lock *, struct file_lock *); extern void locks_remove_posix(struct file *, fl_owner_t); extern void locks_remove_flock(struct file *); extern struct file_lock *posix_test_lock(struct file *, struct file_lock *); extern int posix_lock_file(struct file *, struct file_lock *, unsigned int); extern void posix_block_lock(struct file_lock *, struct file_lock *); extern void posix_unblock_lock(struct file_lock *); +extern int __get_lease(struct inode *inode, unsigned int flags); +extern time_t lease_get_mtime(struct inode *); +extern int lock_may_read(struct inode *, loff_t start, unsigned long count); +extern int lock_may_write(struct inode *, loff_t start, unsigned long count); struct fasync_struct { int magic; @@ -886,6 +902,12 @@ return 0; } +extern inline int get_lease(struct inode *inode, unsigned int mode) +{ + if (inode->i_flock && (inode->i_flock->fl_flags & FL_LEASE)) + return __get_lease(inode, mode); + return 0; +} /* fs/open.c */ diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/gameport.h linux/include/linux/gameport.h --- v2.4.0-test8/linux/include/linux/gameport.h Wed Jun 21 08:22:21 2000 +++ linux/include/linux/gameport.h Fri Sep 22 14:21:17 2000 @@ -29,6 +29,7 @@ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic */ +#include #include struct gameport; diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/hdlcdrv.h linux/include/linux/hdlcdrv.h --- v2.4.0-test8/linux/include/linux/hdlcdrv.h Tue Jul 11 11:12:24 2000 +++ linux/include/linux/hdlcdrv.h Fri Sep 22 14:21:17 2000 @@ -132,7 +132,7 @@ unsigned char buffer[HDLCDRV_BITBUFFER]; }; -extern inline void hdlcdrv_add_bitbuffer(struct hdlcdrv_bitbuffer *buf, +static inline void hdlcdrv_add_bitbuffer(struct hdlcdrv_bitbuffer *buf, unsigned int bit) { unsigned char new; @@ -147,7 +147,7 @@ } } -extern inline void hdlcdrv_add_bitbuffer_word(struct hdlcdrv_bitbuffer *buf, +static inline void hdlcdrv_add_bitbuffer_word(struct hdlcdrv_bitbuffer *buf, unsigned int bits) { buf->buffer[buf->wr] = bits & 0xff; @@ -250,7 +250,7 @@ /* -------------------------------------------------------------------- */ -extern inline int hdlcdrv_hbuf_full(struct hdlcdrv_hdlcbuffer *hb) +static inline int hdlcdrv_hbuf_full(struct hdlcdrv_hdlcbuffer *hb) { unsigned long flags; int ret; @@ -263,7 +263,7 @@ /* -------------------------------------------------------------------- */ -extern inline int hdlcdrv_hbuf_empty(struct hdlcdrv_hdlcbuffer *hb) +static inline int hdlcdrv_hbuf_empty(struct hdlcdrv_hdlcbuffer *hb) { unsigned long flags; int ret; @@ -276,7 +276,7 @@ /* -------------------------------------------------------------------- */ -extern inline unsigned short hdlcdrv_hbuf_get(struct hdlcdrv_hdlcbuffer *hb) +static inline unsigned short hdlcdrv_hbuf_get(struct hdlcdrv_hdlcbuffer *hb) { unsigned long flags; unsigned short val; @@ -296,7 +296,7 @@ /* -------------------------------------------------------------------- */ -extern inline void hdlcdrv_hbuf_put(struct hdlcdrv_hdlcbuffer *hb, +static inline void hdlcdrv_hbuf_put(struct hdlcdrv_hdlcbuffer *hb, unsigned short val) { unsigned newp; @@ -313,12 +313,12 @@ /* -------------------------------------------------------------------- */ -extern inline void hdlcdrv_putbits(struct hdlcdrv_state *s, unsigned int bits) +static inline void hdlcdrv_putbits(struct hdlcdrv_state *s, unsigned int bits) { hdlcdrv_hbuf_put(&s->hdlcrx.hbuf, bits); } -extern inline unsigned int hdlcdrv_getbits(struct hdlcdrv_state *s) +static inline unsigned int hdlcdrv_getbits(struct hdlcdrv_state *s) { unsigned int ret; @@ -336,19 +336,19 @@ return ret; } -extern inline void hdlcdrv_channelbit(struct hdlcdrv_state *s, unsigned int bit) +static inline void hdlcdrv_channelbit(struct hdlcdrv_state *s, unsigned int bit) { #ifdef HDLCDRV_DEBUG hdlcdrv_add_bitbuffer(&s->bitbuf_channel, bit); #endif /* HDLCDRV_DEBUG */ } -extern inline void hdlcdrv_setdcd(struct hdlcdrv_state *s, int dcd) +static inline void hdlcdrv_setdcd(struct hdlcdrv_state *s, int dcd) { s->hdlcrx.dcd = !!dcd; } -extern inline int hdlcdrv_ptt(struct hdlcdrv_state *s) +static inline int hdlcdrv_ptt(struct hdlcdrv_state *s) { return s->hdlctx.ptt || (s->hdlctx.calibrate > 0); } diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/hfs_fs.h linux/include/linux/hfs_fs.h --- v2.4.0-test8/linux/include/linux/hfs_fs.h Mon Mar 13 12:35:39 2000 +++ linux/include/linux/hfs_fs.h Fri Sep 22 14:21:17 2000 @@ -320,12 +320,12 @@ #define HFS_I(X) (&((X)->u.hfs_i)) #define HFS_SB(X) (&((X)->u.hfs_sb)) -extern __inline__ void hfs_nameout(struct inode *dir, struct hfs_name *out, +static inline void hfs_nameout(struct inode *dir, struct hfs_name *out, const char *in, int len) { HFS_SB(dir->i_sb)->s_nameout(out, in, len); } -extern __inline__ int hfs_namein(struct inode *dir, char *out, +static inline int hfs_namein(struct inode *dir, char *out, const struct hfs_name *in) { int len = HFS_SB(dir->i_sb)->s_namein(out, in); if (HFS_SB(dir->i_sb)->s_lowercase) { diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/hfs_sysdep.h linux/include/linux/hfs_sysdep.h --- v2.4.0-test8/linux/include/linux/hfs_sysdep.h Tue Sep 5 14:07:29 2000 +++ linux/include/linux/hfs_sysdep.h Fri Sep 22 14:21:17 2000 @@ -52,7 +52,7 @@ extern long int hfs_alloc; #endif -extern inline void *hfs_malloc(unsigned int size) { +static inline void *hfs_malloc(unsigned int size) { #if defined(DEBUG_ALL) || defined(DEBUG_MEM) hfs_warn("%ld bytes allocation at %s:%u\n", (hfs_alloc += size), __FILE__, __LINE__); @@ -60,7 +60,7 @@ return kmalloc(size, GFP_KERNEL); } -extern inline void hfs_free(void *ptr, unsigned int size) { +static inline void hfs_free(void *ptr, unsigned int size) { kfree(ptr); #if defined(DEBUG_ALL) || defined(DEBUG_MEM) hfs_warn("%ld bytes allocation at %s:%u\n", @@ -75,17 +75,17 @@ * not a good thing to do. instead, we depend upon tz_minuteswest * having the correct daylight savings correction. */ -extern inline hfs_u32 hfs_from_utc(hfs_s32 time) +static inline hfs_u32 hfs_from_utc(hfs_s32 time) { return time - sys_tz.tz_minuteswest*60; } -extern inline hfs_s32 hfs_to_utc(hfs_u32 time) +static inline hfs_s32 hfs_to_utc(hfs_u32 time) { return time + sys_tz.tz_minuteswest*60; } -extern inline hfs_u32 hfs_time(void) { +static inline hfs_u32 hfs_time(void) { return htonl(hfs_from_utc(CURRENT_TIME)+2082844800U); } @@ -95,19 +95,19 @@ */ typedef wait_queue_head_t hfs_wait_queue; -extern inline void hfs_init_waitqueue(hfs_wait_queue *queue) { +static inline void hfs_init_waitqueue(hfs_wait_queue *queue) { init_waitqueue_head(queue); } -extern inline void hfs_sleep_on(hfs_wait_queue *queue) { +static inline void hfs_sleep_on(hfs_wait_queue *queue) { sleep_on(queue); } -extern inline void hfs_wake_up(hfs_wait_queue *queue) { +static inline void hfs_wake_up(hfs_wait_queue *queue) { wake_up(queue); } -extern inline void hfs_relinquish(void) { +static inline void hfs_relinquish(void) { schedule(); } @@ -117,11 +117,11 @@ */ typedef struct super_block *hfs_sysmdb; -extern inline void hfs_mdb_dirty(hfs_sysmdb sys_mdb) { +static inline void hfs_mdb_dirty(hfs_sysmdb sys_mdb) { sys_mdb->s_dirt = 1; } -extern inline const char *hfs_mdb_name(hfs_sysmdb sys_mdb) { +static inline const char *hfs_mdb_name(hfs_sysmdb sys_mdb) { return kdevname(sys_mdb->s_dev); } @@ -141,19 +141,19 @@ /* In sysdep.c, since it needs HFS_SECTOR_SIZE */ extern hfs_buffer hfs_buffer_get(hfs_sysmdb, int, int); -extern inline int hfs_buffer_ok(hfs_buffer buffer) { +static inline int hfs_buffer_ok(hfs_buffer buffer) { return (buffer != NULL); } -extern inline void hfs_buffer_put(hfs_buffer buffer) { +static inline void hfs_buffer_put(hfs_buffer buffer) { brelse(buffer); } -extern inline void hfs_buffer_dirty(hfs_buffer buffer) { +static inline void hfs_buffer_dirty(hfs_buffer buffer) { mark_buffer_dirty(buffer); } -extern inline void hfs_buffer_sync(hfs_buffer buffer) { +static inline void hfs_buffer_sync(hfs_buffer buffer) { while (buffer_locked(buffer)) { wait_on_buffer(buffer); } @@ -163,7 +163,7 @@ } } -extern inline void *hfs_buffer_data(const hfs_buffer buffer) { +static inline void *hfs_buffer_data(const hfs_buffer buffer) { return buffer->b_data; } @@ -199,15 +199,15 @@ # error "Don't know if bytes are big- or little-endian!" #endif -extern inline int hfs_clear_bit(int bitnr, hfs_u32 *lword) { +static inline int hfs_clear_bit(int bitnr, hfs_u32 *lword) { return test_and_clear_bit(BITNR(bitnr), lword); } -extern inline int hfs_set_bit(int bitnr, hfs_u32 *lword) { +static inline int hfs_set_bit(int bitnr, hfs_u32 *lword) { return test_and_set_bit(BITNR(bitnr), lword); } -extern inline int hfs_test_bit(int bitnr, const hfs_u32 *lword) { +static inline int hfs_test_bit(int bitnr, const hfs_u32 *lword) { /* the kernel should declare the second arg of test_bit as const */ return test_bit(BITNR(bitnr), (void *)lword); } diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/highmem.h linux/include/linux/highmem.h --- v2.4.0-test8/linux/include/linux/highmem.h Fri Sep 8 12:52:42 2000 +++ linux/include/linux/highmem.h Mon Oct 2 11:01:19 2000 @@ -19,7 +19,7 @@ #else /* CONFIG_HIGHMEM */ -extern inline unsigned int nr_free_highpages(void) { return 0; } +static inline unsigned int nr_free_highpages(void) { return 0; } #define prepare_highmem_swapout(page) page #define replace_with_highmem(page) page diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/if_pppox.h linux/include/linux/if_pppox.h --- v2.4.0-test8/linux/include/linux/if_pppox.h Fri Sep 8 12:53:54 2000 +++ linux/include/linux/if_pppox.h Mon Oct 2 12:06:32 2000 @@ -130,7 +130,7 @@ extern struct ppp_channel_ops pppoe_chan_ops; -extern void pppox_proto_init(struct net_proto *np); +extern int pppox_proto_init(struct net_proto *np); #endif /* __KERNEL__ */ diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/inet.h linux/include/linux/inet.h --- v2.4.0-test8/linux/include/linux/inet.h Wed Jun 9 14:45:36 1999 +++ linux/include/linux/inet.h Mon Oct 2 14:14:29 2000 @@ -46,7 +46,6 @@ extern void inet_proto_init(struct net_proto *pro); extern char *in_ntoa(__u32 in); -extern char *in_ntoa2(__u32 in, char *buf); extern __u32 in_aton(const char *str); #endif diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/ixjuser.h linux/include/linux/ixjuser.h --- v2.4.0-test8/linux/include/linux/ixjuser.h Wed Dec 29 17:13:02 1999 +++ linux/include/linux/ixjuser.h Mon Sep 18 15:02:03 2000 @@ -1,7 +1,8 @@ -/* +/****************************************************************************** + * * ixjuser.h * - * User-space include file for the Internet PhoneJACK and + * Device Driver for the Internet PhoneJACK and * Internet LineJACK Telephony Cards. * * (c) Copyright 1999 Quicknet Technologies, Inc. @@ -22,31 +23,48 @@ * at our website: http://www.quicknet.net * * Fixes: - */ + * + * IN NO EVENT SHALL QUICKNET TECHNOLOGIES, INC. BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT + * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF QUICKNET + * TECHNOLOGIES, INC.HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * QUICKNET TECHNOLOGIES, INC. SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND QUICKNET TECHNOLOGIES, INC. HAS NO OBLIGATION + * TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + *****************************************************************************/ -static char ixjuser_h_rcsid[] = "$Id: ixjuser.h,v 3.4 1999/12/16 22:18:36 root Exp root $"; +static char ixjuser_h_rcsid[] = "$Id: ixjuser.h,v 3.11 2000/03/30 22:06:48 eokerson Exp $"; -#include +#include "telephony.h" -/*************************************************************************** - If you use the IXJCTL_TESTRAM command, the card must be power - cycled to reset the SRAM values before futher use. +/****************************************************************************** +* +* IOCTL's used for the Quicknet Cards +* +* If you use the IXJCTL_TESTRAM command, the card must be power cycled to +* reset the SRAM values before futher use. +* +******************************************************************************/ -***************************************************************************/ #define IXJCTL_DSP_RESET _IO ('q', 0xC0) -#define IXJCTL_RING PHONE_RING -#define IXJCTL_HOOKSTATE PHONE_HOOKSTATE +#define IXJCTL_RING PHONE_RING +#define IXJCTL_HOOKSTATE PHONE_HOOKSTATE #define IXJCTL_MAXRINGS PHONE_MAXRINGS -#define IXJCTL_RING_CADENCE PHONE_RING_CADENCE +#define IXJCTL_RING_CADENCE PHONE_RING_CADENCE #define IXJCTL_RING_START PHONE_RING_START #define IXJCTL_RING_STOP PHONE_RING_STOP #define IXJCTL_CARDTYPE _IOR ('q', 0xC1, int) -#define IXJCTL_SERIAL _IOR ('q', 0xC2, int) -#define IXJCTL_DSP_TYPE _IOR ('q', 0xC3, int) -#define IXJCTL_DSP_VERSION _IOR ('q', 0xC4, int) +#define IXJCTL_SERIAL _IOR ('q', 0xC2, int) +#define IXJCTL_DSP_TYPE _IOR ('q', 0xC3, int) +#define IXJCTL_DSP_VERSION _IOR ('q', 0xC4, int) +#define IXJCTL_VERSION _IOR ('q', 0xDA, char *) #define IXJCTL_DSP_IDLE _IO ('q', 0xC5) #define IXJCTL_TESTRAM _IO ('q', 0xC6) @@ -104,8 +122,22 @@ char enable; } IXJ_FILTER; +typedef struct { + char enable; + char en_filter; + unsigned int filter; + unsigned int on1; + unsigned int off1; + unsigned int on2; + unsigned int off2; + unsigned int on3; + unsigned int off3; +} IXJ_FILTER_CADENCE; + #define IXJCTL_SET_FILTER _IOW ('q', 0xC7, IXJ_FILTER *) #define IXJCTL_GET_FILTER_HIST _IOW ('q', 0xC8, int) +#define IXJCTL_FILTER_CADENCE _IOW ('q', 0xD6, IXJ_FILTER_CADENCE *) +#define IXJCTL_PLAY_CID _IO ('q', 0xD7) /****************************************************************************** * * This IOCTL allows you to reassign values in the tone index table. The @@ -222,7 +254,9 @@ hz1800 = 0x1405, hz1860 = 0xe0b, hz2100 = 0xf5f6, - hz2450 = 0xd3b3 + hz2130 = 0xf2f5, + hz2450 = 0xd3b3, + hz2750 = 0xb8e4 } IXJ_FREQ; typedef enum { @@ -344,6 +378,7 @@ #define AEC_LOW 1 #define AEC_MED 2 #define AEC_HIGH 3 +#define AEC_AUTO 4 /****************************************************************************** * * Call Progress Tones, DTMF, etc. @@ -533,16 +568,16 @@ /****************************************************************************** * -* The DAA Analog GAIN sets 2 parameters at one time, the receive gain (AGRR), +* The DAA Analog GAIN sets 2 parameters at one time, the recieve gain (AGRR), * and the transmit gain (AGX). OR together the components and pass them * as the parameter to IXJCTL_DAA_AGAIN. The default setting is both at 0dB. * ******************************************************************************/ #define IXJCTL_DAA_AGAIN _IOW ('q', 0xD2, int) -#define AGRR00DB 0x00 // Analog gain in receive direction 0dB -#define AGRR3_5DB 0x10 // Analog gain in receive direction 3.5dB -#define AGRR06DB 0x30 // Analog gain in receive direction 6dB +#define AGRR00DB 0x00 // Analog gain in recieve direction 0dB +#define AGRR3_5DB 0x10 // Analog gain in recieve direction 3.5dB +#define AGRR06DB 0x30 // Analog gain in recieve direction 6dB #define AGX00DB 0x00 // Analog gain in transmit direction 0dB #define AGX_6DB 0x04 // Analog gain in transmit direction -6dB @@ -551,18 +586,9 @@ #define IXJCTL_PSTN_LINETEST _IO ('q', 0xD3) -typedef struct { - char month[3]; - char day[3]; - char hour[3]; - char min[3]; - int numlen; - char number[11]; - int namelen; - char name[80]; -} IXJ_CID; - -#define IXJCTL_CID _IOR ('q', 0xD4, IXJ_CID *) +#define IXJCTL_CID _IOR ('q', 0xD4, PHONE_CID *) +#define IXJCTL_VMWI _IOR ('q', 0xD8, int) +#define IXJCTL_CIDCW _IOW ('q', 0xD9, PHONE_CID *) /****************************************************************************** * * The wink duration is tunable with this ioctl. The default wink duration diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/kernel.h linux/include/linux/kernel.h --- v2.4.0-test8/linux/include/linux/kernel.h Tue Jun 20 07:52:36 2000 +++ linux/include/linux/kernel.h Fri Sep 22 14:21:16 2000 @@ -9,6 +9,7 @@ #include #include +#include /* Optimization barrier */ /* The "volatile" is due to gcc bugs */ diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/kmod.h linux/include/linux/kmod.h --- v2.4.0-test8/linux/include/linux/kmod.h Fri Sep 8 12:52:41 2000 +++ linux/include/linux/kmod.h Mon Oct 2 11:01:18 2000 @@ -10,6 +10,7 @@ extern int exec_usermodehelper(char *program_path, char *argv[], char *envp[]); #ifdef CONFIG_HOTPLUG extern char hotplug_path []; +extern int call_usermodehelper(char *path, char *argv[], char *envp[]); #endif #else static inline int request_module(const char * name) { return -ENOSYS; } diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/locks.h linux/include/linux/locks.h --- v2.4.0-test8/linux/include/linux/locks.h Fri Sep 8 12:53:34 2000 +++ linux/include/linux/locks.h Mon Oct 2 11:01:39 2000 @@ -29,7 +29,9 @@ extern inline void unlock_buffer(struct buffer_head *bh) { clear_bit(BH_Lock, &bh->b_state); - wake_up(&bh->b_wait); + smp_mb__after_clear_bit(); + if (waitqueue_active(&bh->b_wait)) + wake_up(&bh->b_wait); } /* @@ -55,7 +57,12 @@ extern inline void unlock_super(struct super_block * sb) { sb->s_lock = 0; - wake_up(&sb->s_wait); + /* + * No need of any barrier, we're protected by + * the big kernel lock here... unfortunately :) + */ + if (waitqueue_active(&sb->s_wait)) + wake_up(&sb->s_wait); } #endif /* _LINUX_LOCKS_H */ diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/major.h linux/include/linux/major.h --- v2.4.0-test8/linux/include/linux/major.h Wed Aug 23 09:30:13 2000 +++ linux/include/linux/major.h Tue Oct 3 09:30:18 2000 @@ -108,6 +108,15 @@ #define SPECIALIX_NORMAL_MAJOR 75 #define SPECIALIX_CALLOUT_MAJOR 76 +#define COMPAQ_CISS_MAJOR 104 +#define COMPAQ_CISS_MAJOR1 105 +#define COMPAQ_CISS_MAJOR2 106 +#define COMPAQ_CISS_MAJOR3 107 +#define COMPAQ_CISS_MAJOR4 108 +#define COMPAQ_CISS_MAJOR5 109 +#define COMPAQ_CISS_MAJOR6 110 +#define COMPAQ_CISS_MAJOR7 111 + #define DASD_MAJOR 94 /* Official assignations from Peter */ #define MDISK_MAJOR 95 /* Official assignations from Peter */ @@ -134,11 +143,13 @@ #define USB_ACM_AUX_MAJOR 167 #define USB_CHAR_MAJOR 180 -#define TUN_MAJOR 195 - #define UNIX98_PTY_MASTER_MAJOR 128 #define UNIX98_PTY_MAJOR_COUNT 8 #define UNIX98_PTY_SLAVE_MAJOR (UNIX98_PTY_MASTER_MAJOR+UNIX98_PTY_MAJOR_COUNT) + +#define VXVM_MAJOR 199 /* VERITAS volume i/o driver */ +#define VXSPEC_MAJOR 200 /* VERITAS volume config driver */ +#define VXDMP_MAJOR 201 /* VERITAS volume multipath driver */ #define MSR_MAJOR 202 #define CPUID_MAJOR 203 diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/minix_fs.h linux/include/linux/minix_fs.h --- v2.4.0-test8/linux/include/linux/minix_fs.h Thu Jun 29 15:00:31 2000 +++ linux/include/linux/minix_fs.h Wed Sep 27 19:23:40 2000 @@ -99,9 +99,14 @@ extern struct buffer_head * minix_getblk(struct inode *, int, int); extern struct buffer_head * minix_bread(struct inode *, int, int); +extern void V1_minix_truncate(struct inode *); +extern void V2_minix_truncate(struct inode *); extern void minix_truncate(struct inode *); extern int minix_sync_inode(struct inode *); -extern int minix_sync_file(struct file *, struct dentry *, int); +extern int V1_minix_sync_file(struct inode *); +extern int V2_minix_sync_file(struct inode *); +extern int V1_minix_get_block(struct inode *, long, struct buffer_head *, int); +extern int V2_minix_get_block(struct inode *, long, struct buffer_head *, int); extern struct address_space_operations minix_aops; extern struct inode_operations minix_file_inode_operations; diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/miscdevice.h linux/include/linux/miscdevice.h --- v2.4.0-test8/linux/include/linux/miscdevice.h Fri Sep 8 12:52:44 2000 +++ linux/include/linux/miscdevice.h Mon Oct 2 11:01:19 2000 @@ -31,6 +31,8 @@ /* drivers/sgi/char/usema.c */ #define SGI_USEMACLONE 151 +#define TUN_MINOR 200 + extern int misc_init(void); struct miscdevice diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/mm.h linux/include/linux/mm.h --- v2.4.0-test8/linux/include/linux/mm.h Fri Sep 8 12:52:42 2000 +++ linux/include/linux/mm.h Mon Oct 2 11:01:19 2000 @@ -15,7 +15,9 @@ extern unsigned long num_physpages; extern void * high_memory; extern int page_cluster; -extern struct list_head lru_cache; +/* The inactive_clean lists are per zone. */ +extern struct list_head active_list; +extern struct list_head inactive_dirty_list; #include #include @@ -92,6 +94,7 @@ #define VM_RAND_READ 0x00010000 /* App will not benefit from clustered reads */ #define VM_DONTCOPY 0x00020000 /* Do not copy this vma on fork */ +#define VM_DONTEXPAND 0x00040000 /* Cannot expand with mremap() */ #define VM_STACK_FLAGS 0x00000177 @@ -149,6 +152,7 @@ atomic_t count; unsigned long flags; /* atomic flags, some possibly updated asynchronously */ struct list_head lru; + unsigned long age; wait_queue_head_t wait; struct page **pprev_hash; struct buffer_head * buffers; @@ -169,12 +173,12 @@ #define PG_uptodate 3 #define PG_dirty 4 #define PG_decr_after 5 -#define PG_unused_01 6 -#define PG__unused_02 7 +#define PG_active 6 +#define PG_inactive_dirty 7 #define PG_slab 8 #define PG_swap_cache 9 #define PG_skip 10 -#define PG_unused_03 11 +#define PG_inactive_clean 11 #define PG_highmem 12 /* bits 21-30 unused */ #define PG_reserved 31 @@ -190,15 +194,25 @@ #define PageLocked(page) test_bit(PG_locked, &(page)->flags) #define LockPage(page) set_bit(PG_locked, &(page)->flags) #define TryLockPage(page) test_and_set_bit(PG_locked, &(page)->flags) +/* + * The first mb is necessary to safely close the critical section opened by the + * TryLockPage(), the second mb is necessary to enforce ordering between + * the clear_bit and the read of the waitqueue (to avoid SMP races with a + * parallel wait_on_page). + */ #define UnlockPage(page) do { \ + smp_mb__before_clear_bit(); \ clear_bit(PG_locked, &(page)->flags); \ - wake_up(&page->wait); \ + smp_mb__after_clear_bit(); \ + if (waitqueue_active(&page->wait)) \ + wake_up(&page->wait); \ } while (0) #define PageError(page) test_bit(PG_error, &(page)->flags) #define SetPageError(page) set_bit(PG_error, &(page)->flags) #define ClearPageError(page) clear_bit(PG_error, &(page)->flags) #define PageReferenced(page) test_bit(PG_referenced, &(page)->flags) #define SetPageReferenced(page) set_bit(PG_referenced, &(page)->flags) +#define ClearPageReferenced(page) clear_bit(PG_referenced, &(page)->flags) #define PageTestandClearReferenced(page) test_and_clear_bit(PG_referenced, &(page)->flags) #define PageDecrAfter(page) test_bit(PG_decr_after, &(page)->flags) #define SetPageDecrAfter(page) set_bit(PG_decr_after, &(page)->flags) @@ -217,6 +231,18 @@ #define PageTestandClearSwapCache(page) test_and_clear_bit(PG_swap_cache, &(page)->flags) +#define PageActive(page) test_bit(PG_active, &(page)->flags) +#define SetPageActive(page) set_bit(PG_active, &(page)->flags) +#define ClearPageActive(page) clear_bit(PG_active, &(page)->flags) + +#define PageInactiveDirty(page) test_bit(PG_inactive_dirty, &(page)->flags) +#define SetPageInactiveDirty(page) set_bit(PG_inactive_dirty, &(page)->flags) +#define ClearPageInactiveDirty(page) clear_bit(PG_inactive_dirty, &(page)->flags) + +#define PageInactiveClean(page) test_bit(PG_inactive_clean, &(page)->flags) +#define SetPageInactiveClean(page) set_bit(PG_inactive_clean, &(page)->flags) +#define ClearPageInactiveClean(page) clear_bit(PG_inactive_clean, &(page)->flags) + #ifdef CONFIG_HIGHMEM #define PageHighMem(page) test_bit(PG_highmem, &(page)->flags) #else @@ -416,7 +442,6 @@ /* filemap.c */ extern void remove_inode_page(struct page *); extern unsigned long page_unuse(struct page *); -extern int shrink_mmap(int, int); extern void truncate_inode_pages(struct address_space *, loff_t); /* generic vm_area_ops exported for stackable file systems */ @@ -444,11 +469,11 @@ #define GFP_BUFFER (__GFP_HIGH | __GFP_WAIT) #define GFP_ATOMIC (__GFP_HIGH) -#define GFP_USER (__GFP_WAIT | __GFP_IO) -#define GFP_HIGHUSER (GFP_USER | __GFP_HIGHMEM) +#define GFP_USER ( __GFP_WAIT | __GFP_IO) +#define GFP_HIGHUSER ( __GFP_WAIT | __GFP_IO | __GFP_HIGHMEM) #define GFP_KERNEL (__GFP_HIGH | __GFP_WAIT | __GFP_IO) #define GFP_NFS (__GFP_HIGH | __GFP_WAIT | __GFP_IO) -#define GFP_KSWAPD (__GFP_IO) +#define GFP_KSWAPD ( __GFP_IO) /* Flag - indicates that the buffer will be suitable for DMA. Ignored on some platforms, used as appropriate on others */ diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/mmzone.h linux/include/linux/mmzone.h --- v2.4.0-test8/linux/include/linux/mmzone.h Fri Sep 8 12:52:41 2000 +++ linux/include/linux/mmzone.h Mon Oct 2 11:01:17 2000 @@ -28,13 +28,14 @@ spinlock_t lock; unsigned long offset; unsigned long free_pages; - char low_on_memory; - char zone_wake_kswapd; + unsigned long inactive_clean_pages; + unsigned long inactive_dirty_pages; unsigned long pages_min, pages_low, pages_high; /* * free areas of different sizes */ + struct list_head inactive_clean_list; free_area_t free_area[MAX_ORDER]; /* diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/module.h linux/include/linux/module.h --- v2.4.0-test8/linux/include/linux/module.h Fri Sep 8 12:52:41 2000 +++ linux/include/linux/module.h Mon Oct 2 11:01:17 2000 @@ -279,14 +279,6 @@ #define EXPORT_SYMBOL(var) #define EXPORT_SYMBOL_NOVERS(var) -#elif !defined(EXPORT_SYMTAB) - -/* If things weren't set up in the Makefiles to get EXPORT_SYMTAB defined, - then they weren't set up to run genksyms properly so MODVERSIONS breaks. */ -#define __EXPORT_SYMBOL(sym,str) error EXPORT_SYMTAB_not_defined -#define EXPORT_SYMBOL(var) error EXPORT_SYMTAB_not_defined -#define EXPORT_SYMBOL_NOVERS(var) error EXPORT_SYMTAB_not_defined - #else #define __EXPORT_SYMBOL(sym, str) \ diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/mount.h linux/include/linux/mount.h --- v2.4.0-test8/linux/include/linux/mount.h Mon Jul 24 17:04:13 2000 +++ linux/include/linux/mount.h Sun Sep 17 09:51:57 2000 @@ -27,8 +27,7 @@ struct list_head mnt_child; /* and going through their mnt_child */ atomic_t mnt_count; int mnt_flags; - - char *mnt_devname; /* Name of device e.g. /dev/dsk/hda1 */ + char *mnt_devname; /* Name of device e.g. /dev/dsk/hda1 */ struct list_head mnt_list; uid_t mnt_owner; }; diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/nfs_mount.h linux/include/linux/nfs_mount.h --- v2.4.0-test8/linux/include/linux/nfs_mount.h Fri Sep 8 12:53:21 2000 +++ linux/include/linux/nfs_mount.h Mon Oct 2 11:01:41 2000 @@ -52,6 +52,7 @@ #define NFS_MOUNT_VER3 0x0080 /* 3 */ #define NFS_MOUNT_KERBEROS 0x0100 /* 3 */ #define NFS_MOUNT_NONLM 0x0200 /* 3 */ +#define NFS_MOUNT_BROKEN_SUID 0x0400 /* 4 */ #define NFS_MOUNT_FLAGMASK 0xFFFF #endif diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/nfsd/export.h linux/include/linux/nfsd/export.h --- v2.4.0-test8/linux/include/linux/nfsd/export.h Fri Sep 8 12:53:25 2000 +++ linux/include/linux/nfsd/export.h Mon Oct 2 11:01:44 2000 @@ -38,7 +38,8 @@ #define NFSEXP_CROSSMNT 0x0200 #define NFSEXP_NOSUBTREECHECK 0x0400 #define NFSEXP_NOAUTHNLM 0x0800 /* Don't authenticate NLM requests - just trust */ -#define NFSEXP_ALLFLAGS 0x0FFF +#define NFSEXP_MSNFS 0x1000 /* do silly things that MS clients expect */ +#define NFSEXP_ALLFLAGS 0x1FFF #ifdef __KERNEL__ diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/pci.h linux/include/linux/pci.h --- v2.4.0-test8/linux/include/linux/pci.h Fri Sep 8 12:52:44 2000 +++ linux/include/linux/pci.h Mon Oct 2 12:06:32 2000 @@ -298,6 +298,16 @@ #define DEVICE_COUNT_DMA 2 #define DEVICE_COUNT_RESOURCE 12 +#define PCI_ANY_ID (~0) + +#define pci_present pcibios_present + +#define pci_for_each_dev(dev) \ + for(dev = pci_dev_g(pci_devices.next); dev != pci_dev_g(&pci_devices); dev = pci_dev_g(dev->global_list.next)) + +#define pci_for_each_dev_reverse(dev) \ + for(dev = pci_dev_g(pci_devices.prev); dev != pci_dev_g(&pci_devices); dev = pci_dev_g(dev->global_list.prev)) + /* * The pci_dev structure is used to describe both PCI and ISAPnP devices. */ @@ -429,6 +439,27 @@ unsigned long mem_start, mem_end; }; +struct pci_device_id { + unsigned int vendor, device; /* Vendor and device ID or PCI_ANY_ID */ + unsigned int subvendor, subdevice; /* Subsystem ID's or PCI_ANY_ID */ + unsigned int class, class_mask; /* (class,subclass,prog-if) triplet */ + unsigned long driver_data; /* Data private to the driver */ +}; + +struct pci_driver { + struct list_head node; + char *name; + const struct pci_device_id *id_table; /* NULL if wants all devices */ + int (*probe)(struct pci_dev *dev, const struct pci_device_id *id); /* New device inserted */ + void (*remove)(struct pci_dev *dev); /* Device removed (NULL if not a hot-plug capable driver) */ + void (*suspend)(struct pci_dev *dev); /* Device suspended */ + void (*resume)(struct pci_dev *dev); /* Device woken up */ +}; + + +/* these external functions are only available when PCI support is enabled */ +#ifdef CONFIG_PCI + void pcibios_init(void); void pcibios_fixup_bus(struct pci_bus *); int pcibios_enable_device(struct pci_dev *); @@ -444,7 +475,6 @@ /* Backward compatibility, don't use in new code! */ int pcibios_present(void); -#define pci_present pcibios_present int pcibios_read_config_byte (unsigned char bus, unsigned char dev_fn, unsigned char where, unsigned char *val); int pcibios_read_config_word (unsigned char bus, unsigned char dev_fn, @@ -488,8 +518,6 @@ struct pci_dev *pci_find_slot (unsigned int bus, unsigned int devfn); int pci_find_capability (struct pci_dev *dev, int cap); -#define PCI_ANY_ID (~0) - int pci_read_config_byte(struct pci_dev *dev, int where, u8 *val); int pci_read_config_word(struct pci_dev *dev, int where, u16 *val); int pci_read_config_dword(struct pci_dev *dev, int where, u32 *val); @@ -502,12 +530,6 @@ int pci_set_power_state(struct pci_dev *dev, int state); int pci_assign_resource(struct pci_dev *dev, int i); -#define pci_for_each_dev(dev) \ - for(dev = pci_dev_g(pci_devices.next); dev != pci_dev_g(&pci_devices); dev = pci_dev_g(dev->global_list.next)) - -#define pci_for_each_dev_reverse(dev) \ - for(dev = pci_dev_g(pci_devices.prev); dev != pci_dev_g(&pci_devices); dev = pci_dev_g(dev->global_list.prev)) - /* Helper functions for low-level code (drivers/pci/setup.c) */ int pci_claim_resource(struct pci_dev *, int); @@ -518,24 +540,6 @@ int (*)(struct pci_dev *, u8, u8)); /* New-style probing supporting hot-pluggable devices */ - -struct pci_device_id { - unsigned int vendor, device; /* Vendor and device ID or PCI_ANY_ID */ - unsigned int subvendor, subdevice; /* Subsystem ID's or PCI_ANY_ID */ - unsigned int class, class_mask; /* (class,subclass,prog-if) triplet */ - unsigned long driver_data; /* Data private to the driver */ -}; - -struct pci_driver { - struct list_head node; - char *name; - const struct pci_device_id *id_table; /* NULL if wants all devices */ - int (*probe)(struct pci_dev *dev, const struct pci_device_id *id); /* New device inserted */ - void (*remove)(struct pci_dev *dev); /* Device removed (NULL if not a hot-plug capable driver) */ - void (*suspend)(struct pci_dev *dev); /* Device suspended */ - void (*resume)(struct pci_dev *dev); /* Device woken up */ -}; - int pci_register_driver(struct pci_driver *); void pci_unregister_driver(struct pci_driver *); void pci_insert_device(struct pci_dev *, struct pci_bus *); @@ -543,6 +547,8 @@ struct pci_driver *pci_dev_driver(const struct pci_dev *); const struct pci_device_id *pci_match_device(const struct pci_device_id *ids, const struct pci_dev *dev); +#endif /* CONFIG_PCI */ + /* Include architecture-dependent settings and functions */ #include @@ -553,14 +559,14 @@ */ #ifndef CONFIG_PCI -extern inline int pcibios_present(void) { return 0; } -extern inline int pcibios_find_class (unsigned int class_code, unsigned short index, unsigned char *bus, unsigned char *dev_fn) +static inline int pcibios_present(void) { return 0; } +static inline int pcibios_find_class (unsigned int class_code, unsigned short index, unsigned char *bus, unsigned char *dev_fn) { return PCIBIOS_DEVICE_NOT_FOUND; } #define _PCI_NOP(o,s,t) \ - extern inline int pcibios_##o##_config_##s## (u8 bus, u8 dfn, u8 where, t val) \ + static inline int pcibios_##o##_config_##s## (u8 bus, u8 dfn, u8 where, t val) \ { return PCIBIOS_FUNC_NOT_SUPPORTED; } \ - extern inline int pci_##o##_config_##s## (struct pci_dev *dev, int where, t val) \ + static inline int pci_##o##_config_##s## (struct pci_dev *dev, int where, t val) \ { return PCIBIOS_FUNC_NOT_SUPPORTED; } #define _PCI_NOP_ALL(o,x) _PCI_NOP(o,byte,u8 x) \ _PCI_NOP(o,word,u16 x) \ @@ -568,27 +574,27 @@ _PCI_NOP_ALL(read, *) _PCI_NOP_ALL(write,) -extern inline struct pci_dev *pci_find_device(unsigned int vendor, unsigned int device, const struct pci_dev *from) +static inline struct pci_dev *pci_find_device(unsigned int vendor, unsigned int device, const struct pci_dev *from) { return NULL; } -extern inline struct pci_dev *pci_find_class(unsigned int class, const struct pci_dev *from) +static inline struct pci_dev *pci_find_class(unsigned int class, const struct pci_dev *from) { return NULL; } -extern inline struct pci_dev *pci_find_slot(unsigned int bus, unsigned int devfn) +static inline struct pci_dev *pci_find_slot(unsigned int bus, unsigned int devfn) { return NULL; } -extern inline struct pci_dev *pci_find_subsys(unsigned int vendor, unsigned int device, +static inline struct pci_dev *pci_find_subsys(unsigned int vendor, unsigned int device, unsigned int ss_vendor, unsigned int ss_device, const struct pci_dev *from) { return NULL; } -extern inline void pci_set_master(struct pci_dev *dev) { } -extern inline int pci_enable_device(struct pci_dev *dev) { return -EIO; } -extern inline int pci_module_init(struct pci_driver *drv) { return -ENODEV; } -extern inline int pci_assign_resource(struct pci_dev *dev, int i) { return -EBUSY;} -extern inline int pci_register_driver(struct pci_driver *drv) { return 0;} -extern inline void pci_unregister_driver(struct pci_driver *drv) { } -extern inline int scsi_to_pci_dma_dir(unsigned char scsi_dir) { return scsi_dir; } -extern inline int pci_find_capability (struct pci_dev *dev, int cap) {return 0; } +static inline void pci_set_master(struct pci_dev *dev) { } +static inline int pci_enable_device(struct pci_dev *dev) { return -EIO; } +static inline int pci_module_init(struct pci_driver *drv) { return -ENODEV; } +static inline int pci_assign_resource(struct pci_dev *dev, int i) { return -EBUSY;} +static inline int pci_register_driver(struct pci_driver *drv) { return 0;} +static inline void pci_unregister_driver(struct pci_driver *drv) { } +static inline int scsi_to_pci_dma_dir(unsigned char scsi_dir) { return scsi_dir; } +static inline int pci_find_capability (struct pci_dev *dev, int cap) {return 0; } #else @@ -598,7 +604,7 @@ * * This MUST stay in a header, as it checks for -DMODULE */ -extern inline int pci_module_init(struct pci_driver *drv) +static inline int pci_module_init(struct pci_driver *drv) { int rc = pci_register_driver (drv); @@ -635,6 +641,20 @@ \ (pci_resource_end((dev),(bar)) - \ pci_resource_start((dev),(bar)) + 1)) + +/* Similar to the helpers above, these manipulate per-pci_dev + * driver-specific data. Currently stored as pci_dev::driver_data, + * a void pointer, but it is not present on older kernels. + */ +static inline void *pci_get_drvdata (struct pci_dev *pdev) +{ + return pdev->driver_data; +} + +static inline void pci_set_drvdata (struct pci_dev *pdev, void *data) +{ + pdev->driver_data = data; +} /* * The world is not perfect and supplies us with broken PCI devices. diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/pci_ids.h linux/include/linux/pci_ids.h --- v2.4.0-test8/linux/include/linux/pci_ids.h Mon Aug 28 21:25:25 2000 +++ linux/include/linux/pci_ids.h Wed Sep 27 13:53:52 2000 @@ -131,6 +131,7 @@ #define PCI_DEVICE_ID_COMPAQ_NETEL100D 0xae40 #define PCI_DEVICE_ID_COMPAQ_NETEL100PI 0xae43 #define PCI_DEVICE_ID_COMPAQ_NETEL100I 0xb011 +#define PCI_DEVICE_ID_COMPAQ_CISS 0xb060 #define PCI_DEVICE_ID_COMPAQ_THUNDER 0xf130 #define PCI_DEVICE_ID_COMPAQ_NETFLEX3B 0xf150 @@ -463,6 +464,7 @@ #define PCI_DEVICE_ID_APPLE_BANDIT 0x0001 #define PCI_DEVICE_ID_APPLE_GC 0x0002 #define PCI_DEVICE_ID_APPLE_HYDRA 0x000e +#define PCI_DEVICE_ID_APPLE_UNINORTH 0x0020 #define PCI_VENDOR_ID_NEXGEN 0x1074 #define PCI_DEVICE_ID_NEXGEN_82C501 0x4e78 @@ -822,6 +824,11 @@ #define PCI_DEVICE_ID_SERVERWORKS_CMIC_HE 0x0011 #define PCI_DEVICE_ID_SERVERWORKS_CSB5 0x0201 +#define PCI_VENDOR_ID_SBE 0x1176 +#define PCI_DEVICE_ID_SBE_WANXL100 0x0301 +#define PCI_DEVICE_ID_SBE_WANXL200 0x0302 +#define PCI_DEVICE_ID_SBE_WANXL400 0x0104 + #define PCI_VENDOR_ID_TOSHIBA 0x1179 #define PCI_DEVICE_ID_TOSHIBA_601 0x0601 #define PCI_DEVICE_ID_TOSHIBA_TOPIC95 0x060a @@ -913,6 +920,10 @@ #define PCI_DEVICE_ID_CYCLOM_8Y_Hi 0x0105 #define PCI_DEVICE_ID_CYCLOM_Z_Lo 0x0200 #define PCI_DEVICE_ID_CYCLOM_Z_Hi 0x0201 +#define PCI_DEVICE_ID_PC300_RX_2 0x0300 +#define PCI_DEVICE_ID_PC300_RX_1 0x0301 +#define PCI_DEVICE_ID_PC300_TE_2 0x0310 +#define PCI_DEVICE_ID_PC300_TE_1 0x0311 #define PCI_VENDOR_ID_ESSENTIAL 0x120f #define PCI_DEVICE_ID_ESSENTIAL_ROADRUNNER 0x0001 @@ -1073,11 +1084,6 @@ #define PCI_DEVICE_ID_LAVA_QUAD_B 0x0202 /* 2x 16650, half of 4 port */ #define PCI_DEVICE_ID_LAVA_SSERIAL 0x0500 /* 1x 16550 */ #define PCI_DEVICE_ID_LAVA_PORT_650 0x0600 /* 1x 16650 */ - -#define PCI_VENDOR_ID_SYBA 0x1592 -#define PCI_DEVICE_ID_SYBA_2P_EPP 0x0782 -#define PCI_DEVICE_ID_SYBA_1P_ECP 0x0783 - #define PCI_DEVICE_ID_LAVA_PARALLEL 0x8000 #define PCI_DEVICE_ID_LAVA_DUAL_PAR_A 0x8002 /* The Lava Dual Parallel is */ #define PCI_DEVICE_ID_LAVA_DUAL_PAR_B 0x8003 /* two PCI devices on a card */ @@ -1103,6 +1109,10 @@ #define PCI_VENDOR_ID_AFAVLAB 0x14db #define PCI_DEVICE_ID_AFAVLAB_TK9902 0x2120 + +#define PCI_VENDOR_ID_SYBA 0x1592 +#define PCI_DEVICE_ID_SYBA_2P_EPP 0x0782 +#define PCI_DEVICE_ID_SYBA_1P_ECP 0x0783 #define PCI_VENDOR_ID_MORETON 0x15aa #define PCI_DEVICE_ID_RASTEL_2PORT 0x2000 diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/pmu.h linux/include/linux/pmu.h --- v2.4.0-test8/linux/include/linux/pmu.h Wed Feb 9 19:43:47 2000 +++ linux/include/linux/pmu.h Sun Sep 17 09:48:05 2000 @@ -10,6 +10,7 @@ /* * PMU commands */ +#define PMU_POWER_CTRL0 0x10 /* control power of some devices */ #define PMU_POWER_CTRL 0x11 /* control power of some devices */ #define PMU_ADB_CMD 0x20 /* send ADB packet */ #define PMU_ADB_POLL_OFF 0x21 /* disable ADB auto-poll */ @@ -26,15 +27,25 @@ #define PMU_INT_ACK 0x78 /* read interrupt bits */ #define PMU_SHUTDOWN 0x7e /* turn power off */ #define PMU_SLEEP 0x7f /* put CPU to sleep */ +#define PMU_POWER_EVENTS 0x8f /* Send power-event commands to PMU */ #define PMU_RESET 0xd0 /* reset CPU */ #define PMU_GET_BRIGHTBUTTON 0xd9 /* report brightness up/down pos */ #define PMU_GET_COVER 0xdc /* report cover open/closed */ +#define PMU_SYSTEM_READY 0xdf /* tell PMU we are awake */ + +/* Bits to use with the PMU_POWER_CTRL0 command */ +#define PMU_POW0_ON 0x80 /* OR this to power ON the device */ +#define PMU_POW0_OFF 0x00 /* leave bit 7 to 0 to power it OFF */ +#define PMU_POW0_HARD_DRIVE 0x04 /* Hard drive power (on wallstreet/lombard ?) */ /* Bits to use with the PMU_POWER_CTRL command */ #define PMU_POW_ON 0x80 /* OR this to power ON the device */ #define PMU_POW_OFF 0x00 /* leave bit 7 to 0 to power it OFF */ #define PMU_POW_BACKLIGHT 0x01 /* backlight power */ +#define PMU_POW_CHARGER 0x02 /* battery charger power */ #define PMU_POW_IRLED 0x04 /* IR led power (on wallstreet) */ +#define PMU_POW_MEDIABAY 0x08 /* media bay power (wallstreet/lombard ?) */ + /* Bits in PMU interrupt and interrupt mask bytes */ #define PMU_INT_ADB_AUTO 0x04 /* ADB autopoll, when PMU_INT_ADB */ @@ -54,6 +65,25 @@ PMU_KEYLARGO_BASED, /* Core99 motherboard (PMU99) */ }; +/* PMU PMU_POWER_EVENTS commands */ +enum { + PMU_PWR_GET_POWERUP_EVENTS = 0x00, + PMU_PWR_SET_POWERUP_EVENTS = 0x01, + PMU_PWR_CLR_POWERUP_EVENTS = 0x02, + PMU_PWR_GET_WAKEUP_EVENTS = 0x03, + PMU_PWR_SET_WAKEUP_EVENTS = 0x04, + PMU_PWR_CLR_WAKEUP_EVENTS = 0x05, +}; + +/* Power events wakeup bits */ +enum { + PMU_PWR_WAKEUP_KEY = 0x01, /* Wake on key press */ + PMU_PWR_WAKEUP_AC_INSERT = 0x02, /* Wake on AC adapter plug */ + PMU_PWR_WAKEUP_AC_CHANGE = 0x04, + PMU_PWR_WAKEUP_LID_OPEN = 0x08, + PMU_PWR_WAKEUP_RING = 0x10, +}; + /* * Ioctl commands for the /dev/pmu device */ @@ -61,34 +91,38 @@ /* no param */ #define PMU_IOC_SLEEP _IO('B', 0) -/* out param: u32* backlight value: 0 to 31 */ +/* out param: u32* backlight value: 0 to 15 */ #define PMU_IOC_GET_BACKLIGHT _IOR('B', 1, sizeof(__u32*)) -/* in param: u32 backlight value: 0 to 31 */ +/* in param: u32 backlight value: 0 to 15 */ #define PMU_IOC_SET_BACKLIGHT _IOW('B', 2, sizeof(__u32)) -/* out param: u32* backlight value: 0 to 31 */ +/* out param: u32* PMU model */ #define PMU_IOC_GET_MODEL _IOR('B', 3, sizeof(__u32*)) /* out param: u32* has_adb: 0 or 1 */ #define PMU_IOC_HAS_ADB _IOR('B', 4, sizeof(__u32*)) #ifdef __KERNEL__ -int find_via_pmu(void); -int via_pmu_init(void); +extern int find_via_pmu(void); +extern int via_pmu_start(void); -int pmu_request(struct adb_request *req, +extern int pmu_request(struct adb_request *req, void (*done)(struct adb_request *), int nbytes, ...); -void pmu_poll(void); -void pmu_enable_backlight(int on); -void pmu_set_brightness(int level); +extern void pmu_poll(void); + +/* For use before switching interrupts off for a long time; + * warning: not stackable + */ +extern void pmu_suspend(void); +extern void pmu_resume(void); -void pmu_enable_irled(int on); +extern void pmu_enable_irled(int on); -void pmu_restart(void); -void pmu_shutdown(void); +extern void pmu_restart(void); +extern void pmu_shutdown(void); -int pmu_present(void); -int pmu_get_model(void); +extern int pmu_present(void); +extern int pmu_get_model(void); #ifdef CONFIG_PMAC_PBOOK /* @@ -135,4 +169,4 @@ #endif /* CONFIG_PMAC_PBOOK */ -#endif /* __KERNEL */ +#endif /* __KERNEL__ */ diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/raid/md.h linux/include/linux/raid/md.h --- v2.4.0-test8/linux/include/linux/raid/md.h Fri Sep 8 12:52:55 2000 +++ linux/include/linux/raid/md.h Mon Oct 2 12:06:33 2000 @@ -82,7 +82,7 @@ extern int md_notify_reboot(struct notifier_block *this, unsigned long code, void *x); extern int md_error (kdev_t mddev, kdev_t rdev); -extern void md_run_setup(void); +extern int md_run_setup(void); extern void md_print_devices (void); diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/raid/md_compatible.h linux/include/linux/raid/md_compatible.h --- v2.4.0-test8/linux/include/linux/raid/md_compatible.h Fri Sep 8 12:52:42 2000 +++ linux/include/linux/raid/md_compatible.h Mon Oct 2 12:04:52 2000 @@ -77,11 +77,7 @@ /* 011 */ #define md_signal_pending signal_pending -/* 012 */ -extern inline void md_set_global_readahead(int * table) -{ - max_readahead[MD_MAJOR] = table; -} +/* 012 - md_set_global_readahead - nowhere used */ /* 013 */ #define md_mdelay(x) mdelay(x) diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/sched.h linux/include/linux/sched.h --- v2.4.0-test8/linux/include/linux/sched.h Fri Sep 8 12:52:42 2000 +++ linux/include/linux/sched.h Mon Oct 2 11:01:19 2000 @@ -298,6 +298,7 @@ * that's just fine.) */ struct list_head run_list; + unsigned long sleep_time; struct task_struct *next_task, *prev_task; struct mm_struct *active_mm; @@ -356,6 +357,7 @@ /* file system info */ int link_count; struct tty_struct *tty; /* NULL if no tty */ + unsigned int locks; /* How many file locks are being held */ /* ipc stuff */ struct sem_undo *semundo; struct sem_queue *semsleeping; @@ -818,6 +820,7 @@ static inline void del_from_runqueue(struct task_struct * p) { nr_running--; + p->sleep_time = jiffies; list_del(&p->run_list); p->run_list.next = NULL; } diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/signal.h linux/include/linux/signal.h --- v2.4.0-test8/linux/include/linux/signal.h Fri Sep 8 12:52:42 2000 +++ linux/include/linux/signal.h Mon Oct 2 11:01:19 2000 @@ -28,7 +28,7 @@ /* We don't use for these because there is no need to be atomic. */ -extern inline void sigaddset(sigset_t *set, int _sig) +static inline void sigaddset(sigset_t *set, int _sig) { unsigned long sig = _sig - 1; if (_NSIG_WORDS == 1) @@ -37,7 +37,7 @@ set->sig[sig / _NSIG_BPW] |= 1UL << (sig % _NSIG_BPW); } -extern inline void sigdelset(sigset_t *set, int _sig) +static inline void sigdelset(sigset_t *set, int _sig) { unsigned long sig = _sig - 1; if (_NSIG_WORDS == 1) @@ -46,7 +46,7 @@ set->sig[sig / _NSIG_BPW] &= ~(1UL << (sig % _NSIG_BPW)); } -extern inline int sigismember(sigset_t *set, int _sig) +static inline int sigismember(sigset_t *set, int _sig) { unsigned long sig = _sig - 1; if (_NSIG_WORDS == 1) @@ -55,7 +55,7 @@ return 1 & (set->sig[sig / _NSIG_BPW] >> (sig % _NSIG_BPW)); } -extern inline int sigfindinword(unsigned long word) +static inline int sigfindinword(unsigned long word) { return ffz(~word); } @@ -68,7 +68,7 @@ #include #define _SIG_SET_BINOP(name, op) \ -extern inline void name(sigset_t *r, const sigset_t *a, const sigset_t *b) \ +static inline void name(sigset_t *r, const sigset_t *a, const sigset_t *b) \ { \ unsigned long a0, a1, a2, a3, b0, b1, b2, b3; \ unsigned long i; \ @@ -119,7 +119,7 @@ #undef _sig_nand #define _SIG_SET_OP(name, op) \ -extern inline void name(sigset_t *set) \ +static inline void name(sigset_t *set) \ { \ unsigned long i; \ \ @@ -142,7 +142,7 @@ #undef _SIG_SET_OP #undef _sig_not -extern inline void sigemptyset(sigset_t *set) +static inline void sigemptyset(sigset_t *set) { switch (_NSIG_WORDS) { default: @@ -154,7 +154,7 @@ } } -extern inline void sigfillset(sigset_t *set) +static inline void sigfillset(sigset_t *set) { switch (_NSIG_WORDS) { default: @@ -170,22 +170,22 @@ /* Some extensions for manipulating the low 32 signals in particular. */ -extern inline void sigaddsetmask(sigset_t *set, unsigned long mask) +static inline void sigaddsetmask(sigset_t *set, unsigned long mask) { set->sig[0] |= mask; } -extern inline void sigdelsetmask(sigset_t *set, unsigned long mask) +static inline void sigdelsetmask(sigset_t *set, unsigned long mask) { set->sig[0] &= ~mask; } -extern inline int sigtestsetmask(sigset_t *set, unsigned long mask) +static inline int sigtestsetmask(sigset_t *set, unsigned long mask) { return (set->sig[0] & mask) != 0; } -extern inline void siginitset(sigset_t *set, unsigned long mask) +static inline void siginitset(sigset_t *set, unsigned long mask) { set->sig[0] = mask; switch (_NSIG_WORDS) { @@ -197,7 +197,7 @@ } } -extern inline void siginitsetinv(sigset_t *set, unsigned long mask) +static inline void siginitsetinv(sigset_t *set, unsigned long mask) { set->sig[0] = ~mask; switch (_NSIG_WORDS) { diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/slab.h linux/include/linux/slab.h --- v2.4.0-test8/linux/include/linux/slab.h Fri Sep 8 12:52:42 2000 +++ linux/include/linux/slab.h Mon Oct 2 11:54:51 2000 @@ -11,7 +11,6 @@ typedef struct kmem_cache_s kmem_cache_t; -#include #include #include @@ -75,14 +74,6 @@ extern kmem_cache_t *bh_cachep; extern kmem_cache_t *fs_cachep; extern kmem_cache_t *sigact_cachep; - -#ifdef CONFIG_SMP -extern unsigned long slab_cache_drain_mask; -extern void slab_drain_local_cache(void); -#else -#define slab_cache_drain_mask 0 -#define slab_drain_local_cache() do { } while (0) -#endif #endif /* __KERNEL__ */ diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/sunrpc/clnt.h linux/include/linux/sunrpc/clnt.h --- v2.4.0-test8/linux/include/linux/sunrpc/clnt.h Fri Sep 8 12:53:21 2000 +++ linux/include/linux/sunrpc/clnt.h Mon Oct 2 12:05:07 2000 @@ -45,6 +45,7 @@ cl_chatty : 1,/* be verbose */ cl_autobind : 1,/* use getport() */ cl_binding : 1,/* doing a getport() */ + cl_droppriv : 1,/* enable NFS suid hack */ cl_oneshot : 1,/* dispose after use */ cl_dead : 1;/* abandoned */ unsigned int cl_flags; /* misc client flags */ diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/swap.h linux/include/linux/swap.h --- v2.4.0-test8/linux/include/linux/swap.h Fri Sep 8 12:52:41 2000 +++ linux/include/linux/swap.h Mon Oct 2 11:28:38 2000 @@ -65,13 +65,16 @@ extern int nr_swap_pages; FASTCALL(unsigned int nr_free_pages(void)); +FASTCALL(unsigned int nr_inactive_clean_pages(void)); FASTCALL(unsigned int nr_free_buffer_pages(void)); -FASTCALL(unsigned int nr_free_highpages(void)); -extern int nr_lru_pages; +extern int nr_active_pages; +extern int nr_inactive_dirty_pages; extern atomic_t nr_async_pages; extern struct address_space swapper_space; extern atomic_t page_cache_size; extern atomic_t buffermem_pages; +extern spinlock_t pagecache_lock; +extern void __remove_inode_page(struct page *); /* Incomplete types for prototype declarations: */ struct task_struct; @@ -83,9 +86,30 @@ extern int shm_swap(int, int); /* linux/mm/swap.c */ +extern int memory_pressure; +extern void age_page_up(struct page *); +extern void age_page_up_nolock(struct page *); +extern void age_page_down(struct page *); +extern void age_page_down_nolock(struct page *); +extern void age_page_down_ageonly(struct page *); +extern void deactivate_page(struct page *); +extern void deactivate_page_nolock(struct page *); +extern void activate_page(struct page *); +extern void activate_page_nolock(struct page *); +extern void lru_cache_add(struct page *); +extern void __lru_cache_del(struct page *); +extern void lru_cache_del(struct page *); +extern void recalculate_vm_stats(void); extern void swap_setup(void); /* linux/mm/vmscan.c */ +extern struct page * reclaim_page(zone_t *); +extern wait_queue_head_t kswapd_wait; +extern wait_queue_head_t kreclaimd_wait; +extern int page_launder(int, int); +extern int free_shortage(void); +extern int inactive_shortage(void); +extern void wakeup_kswapd(int); extern int try_to_free_pages(unsigned int gfp_mask); /* linux/mm/page_io.c */ @@ -161,30 +185,102 @@ extern spinlock_t pagemap_lru_lock; /* - * Helper macros for lru_pages handling. + * Page aging defines. + * Since we do exponential decay of the page age, we + * can chose a fairly large maximum. */ -#define lru_cache_add(page) \ -do { \ - spin_lock(&pagemap_lru_lock); \ - list_add(&(page)->lru, &lru_cache); \ - nr_lru_pages++; \ - spin_unlock(&pagemap_lru_lock); \ -} while (0) - -#define __lru_cache_del(page) \ -do { \ - list_del(&(page)->lru); \ - nr_lru_pages--; \ -} while (0) - -#define lru_cache_del(page) \ -do { \ - if (!PageLocked(page)) \ - BUG(); \ - spin_lock(&pagemap_lru_lock); \ - __lru_cache_del(page); \ - spin_unlock(&pagemap_lru_lock); \ -} while (0) +#define PAGE_AGE_START 2 +#define PAGE_AGE_ADV 3 +#define PAGE_AGE_MAX 64 + +/* + * List add/del helper macros. These must be called + * with the pagemap_lru_lock held! + */ +#define DEBUG_ADD_PAGE \ + if (PageActive(page) || PageInactiveDirty(page) || \ + PageInactiveClean(page)) BUG(); + +#define ZERO_PAGE_BUG \ + if (page_count(page) == 0) BUG(); + +#define add_page_to_active_list(page) { \ + DEBUG_ADD_PAGE \ + ZERO_PAGE_BUG \ + SetPageActive(page); \ + list_add(&(page)->lru, &active_list); \ + nr_active_pages++; \ +} + +#define add_page_to_inactive_dirty_list(page) { \ + DEBUG_ADD_PAGE \ + ZERO_PAGE_BUG \ + SetPageInactiveDirty(page); \ + list_add(&(page)->lru, &inactive_dirty_list); \ + nr_inactive_dirty_pages++; \ + page->zone->inactive_dirty_pages++; \ +} + +#define add_page_to_inactive_clean_list(page) { \ + DEBUG_ADD_PAGE \ + ZERO_PAGE_BUG \ + SetPageInactiveClean(page); \ + list_add(&(page)->lru, &page->zone->inactive_clean_list); \ + page->zone->inactive_clean_pages++; \ +} + +#define del_page_from_active_list(page) { \ + list_del(&(page)->lru); \ + ClearPageActive(page); \ + nr_active_pages--; \ + DEBUG_ADD_PAGE \ + ZERO_PAGE_BUG \ +} + +#define del_page_from_inactive_dirty_list(page) { \ + list_del(&(page)->lru); \ + ClearPageInactiveDirty(page); \ + nr_inactive_dirty_pages--; \ + page->zone->inactive_dirty_pages--; \ + DEBUG_ADD_PAGE \ + ZERO_PAGE_BUG \ +} + +#define del_page_from_inactive_clean_list(page) { \ + list_del(&(page)->lru); \ + ClearPageInactiveClean(page); \ + page->zone->inactive_clean_pages--; \ + DEBUG_ADD_PAGE \ + ZERO_PAGE_BUG \ +} + +/* + * In mm/swap.c::recalculate_vm_stats(), we substract + * inactive_target from memory_pressure every second. + * This means that memory_pressure is smoothed over + * 64 (1 << INACTIVE_SHIFT) seconds. + */ +#define INACTIVE_SHIFT 6 +#define inactive_min(a,b) ((a) < (b) ? (a) : (b)) +#define inactive_target inactive_min((memory_pressure >> INACTIVE_SHIFT), \ + (num_physpages / 4)) + +/* + * Ugly ugly ugly HACK to make sure the inactive lists + * don't fill up with unfreeable ramdisk pages. We really + * want to fix the ramdisk driver to mark its pages as + * unfreeable instead of using dirty buffer magic, but the + * next code-change time is when 2.5 is forked... + */ +#ifndef _LINUX_KDEV_T_H +#include +#endif +#ifndef _LINUX_MAJOR_H +#include +#endif + +#define page_ramdisk(page) \ + (page->buffers && (MAJOR(page->buffers->b_dev) == RAMDISK_MAJOR)) extern spinlock_t swaplock; diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/sysctl.h linux/include/linux/sysctl.h --- v2.4.0-test8/linux/include/linux/sysctl.h Thu Aug 10 13:01:26 2000 +++ linux/include/linux/sysctl.h Fri Sep 22 14:21:22 2000 @@ -186,7 +186,8 @@ NET_CORE_MSG_COST=8, NET_CORE_MSG_BURST=9, NET_CORE_OPTMEM_MAX=10, - NET_CORE_HOT_LIST_LENGTH=11 + NET_CORE_HOT_LIST_LENGTH=11, + NET_CORE_DIVERT_VERSION=12 }; /* /proc/sys/net/ethernet */ @@ -512,7 +513,10 @@ FS_NRSUPER=9, /* int:current number of allocated super_blocks */ FS_MAXSUPER=10, /* int:maximum number of super_blocks that can be allocated */ FS_OVERFLOWUID=11, /* int: overflow UID */ - FS_OVERFLOWGID=12 /* int: overflow GID */ + FS_OVERFLOWGID=12, /* int: overflow GID */ + FS_LEASES=13, /* int: leases enabled */ + FS_DIR_NOTIFY=14, /* int: directory notification enabled */ + FS_LEASE_TIME=15, /* int: maximum time to wait for a lease break */ }; /* CTL_DEBUG names: */ @@ -522,7 +526,8 @@ DEV_CDROM=1, DEV_HWMON=2, DEV_PARPORT=3, - DEV_RAID=4 + DEV_RAID=4, + DEV_MAC_HID=5 }; /* /proc/sys/dev/cdrom */ @@ -571,6 +576,16 @@ /* /proc/sys/dev/parport/parport n/devices/device n */ enum { DEV_PARPORT_DEVICE_TIMESLICE=1, +}; + +/* /proc/sys/dev/mac_hid */ +enum { + DEV_MAC_HID_KEYBOARD_SENDS_LINUX_KEYCODES=1, + DEV_MAC_HID_KEYBOARD_LOCK_KEYCODES=2, + DEV_MAC_HID_MOUSE_BUTTON_EMULATION=3, + DEV_MAC_HID_MOUSE_BUTTON2_KEYCODE=4, + DEV_MAC_HID_MOUSE_BUTTON3_KEYCODE=5, + DEV_MAC_HID_ADB_MOUSE_SENDS_KEYCODES=6 }; #ifdef __KERNEL__ diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/tcp.h linux/include/linux/tcp.h --- v2.4.0-test8/linux/include/linux/tcp.h Fri Sep 8 12:52:42 2000 +++ linux/include/linux/tcp.h Mon Oct 2 11:01:18 2000 @@ -125,5 +125,63 @@ #define TCP_LINGER2 8 /* Life time of orphaned FIN-WAIT-2 state */ #define TCP_DEFER_ACCEPT 9 /* Wake up listener only when data arrive */ #define TCP_WINDOW_CLAMP 10 /* Bound advertised window */ +#define TCP_INFO 11 /* Information about this connection. */ + +#define TCPI_OPT_TIMESTAMPS 1 +#define TCPI_OPT_SACK 2 +#define TCPI_OPT_WSCALE 4 +#define TCPI_OPT_ECN 8 + +enum tcp_ca_state +{ + TCP_CA_Open = 0, +#define TCPF_CA_Open (1< - * Greg Herlein, + * Authors: Ed Okerson, + * Greg Herlein, * - * Contributors: Alan Cox, - * David Erhart, + * Contributors: Alan Cox, + * David W. Erhart, * * Version: 0.1.0 - December 19, 1999 * * Fixes: - */ + * + *****************************************************************************/ #ifndef TELEPHONY_H #define TELEPHONY_H -/* vendor identification numbers */ #define PHONE_VENDOR_IXJ 1 -#define PHONE_VENDOR_QUICKNET PHONE_IXJ +#define PHONE_VENDOR_QUICKNET PHONE_VENDOR_IXJ #define PHONE_VENDOR_VOICETRONIX 2 #define PHONE_VENDOR_ACULAB 3 #define PHONE_VENDOR_DIGI 4 @@ -43,7 +44,6 @@ * *****************************************************************************/ - /****************************************************************************** * * The capabilities ioctls can inform you of the capabilities of each phone @@ -81,11 +81,23 @@ #define PHONE_CAPABILITIES_LIST _IOR ('q', 0x81, struct phone_capability *) #define PHONE_CAPABILITIES_CHECK _IOW ('q', 0x82, struct phone_capability *) +typedef struct { + char month[3]; + char day[3]; + char hour[3]; + char min[3]; + int numlen; + char number[11]; + int namelen; + char name[80]; +} PHONE_CID; + #define PHONE_RING _IO ('q', 0x83) #define PHONE_HOOKSTATE _IO ('q', 0x84) #define PHONE_MAXRINGS _IOW ('q', 0x85, char) #define PHONE_RING_CADENCE _IOW ('q', 0x86, short) -#define PHONE_RING_START _IO ('q', 0x87) +#define OLD_PHONE_RING_START _IO ('q', 0x87) +#define PHONE_RING_START _IOW ('q', 0x87, PHONE_CID *) #define PHONE_RING_STOP _IO ('q', 0x88) #define USA_RING_CADENCE 0xC0C0 @@ -167,6 +179,23 @@ #define PHONE_QUERY_CODEC _IOWR ('q', 0xA7, struct phone_codec_data *) #define PHONE_PSTN_LINETEST _IO ('q', 0xA8) +/****************************************************************************** +* +* This controls the VAD/CNG functionality of G.723.1. The driver will +* always pass full size frames, any unused bytes will be padded with zeros, +* and frames passed to the driver should also be padded with zeros. The +* frame type is encoded in the least significant two bits of the first +* WORD of the frame as follows: +* +* bits 1-0 Frame Type Data Rate Significant Words +* 00 0 G.723.1 6.3 12 +* 01 1 G.723.1 5.3 10 +* 10 2 VAD/CNG 2 +* 11 3 Repeat last CNG 2 bits +* +******************************************************************************/ +#define PHONE_VAD _IOW ('q', 0xA9, int) + /****************************************************************************** * @@ -198,7 +227,12 @@ unsigned int f1:1; unsigned int f2:1; unsigned int f3:1; - unsigned int reserved:23; + unsigned int flash:1; + unsigned int fc0:1; + unsigned int fc1:1; + unsigned int fc2:1; + unsigned int fc3:1; + unsigned int reserved:18; }; union telephony_exception { diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/time.h linux/include/linux/time.h --- v2.4.0-test8/linux/include/linux/time.h Fri Sep 8 12:52:41 2000 +++ linux/include/linux/time.h Mon Oct 2 11:01:17 2000 @@ -45,7 +45,42 @@ value->tv_nsec = (jiffies % HZ) * (1000000000L / HZ); value->tv_sec = jiffies / HZ; } - + + +/* Converts Gregorian date to seconds since 1970-01-01 00:00:00. + * Assumes input in normal date format, i.e. 1980-12-31 23:59:59 + * => year=1980, mon=12, day=31, hour=23, min=59, sec=59. + * + * [For the Julian calendar (which was used in Russia before 1917, + * Britain & colonies before 1752, anywhere else before 1582, + * and is still in use by some communities) leave out the + * -year/100+year/400 terms, and add 10.] + * + * This algorithm was first published by Gauss (I think). + * + * WARNING: this function will overflow on 2106-02-07 06:28:16 on + * machines were long is 32-bit! (However, as time_t is signed, we + * will already get problems at other places on 2038-01-19 03:14:08) + */ +static inline unsigned long +mktime (unsigned int year, unsigned int mon, + unsigned int day, unsigned int hour, + unsigned int min, unsigned int sec) +{ + if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */ + mon += 12; /* Puts Feb last since it has leap day */ + year -= 1; + } + + return ((( + (unsigned long) (year/4 - year/100 + year/400 + 367*mon/12 + day) + + year*365 - 719499 + )*24 + hour /* now have hours */ + )*60 + min /* now have minutes */ + )*60 + sec; /* finally seconds */ +} + + struct timeval { time_t tv_sec; /* seconds */ suseconds_t tv_usec; /* microseconds */ diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/timex.h linux/include/linux/timex.h --- v2.4.0-test8/linux/include/linux/timex.h Fri Sep 8 12:52:41 2000 +++ linux/include/linux/timex.h Mon Oct 2 11:01:17 2000 @@ -51,6 +51,8 @@ #ifndef _LINUX_TIMEX_H #define _LINUX_TIMEX_H +#include + /* * The following defines establish the engineering parameters of the PLL * model. The HZ variable establishes the timer interrupt frequency, 100 Hz @@ -58,10 +60,20 @@ * OSF/1 kernel. The SHIFT_HZ define expresses the same value as the * nearest power of two in order to avoid hardware multiply operations. */ -#ifdef __alpha__ -# define SHIFT_HZ 10 /* log2(HZ) */ +#if HZ >= 24 && HZ < 48 +# define SHIFT_HZ 5 +#elif HZ >= 48 && HZ < 96 +# define SHIFT_HZ 6 +#elif HZ >= 96 && HZ < 192 +# define SHIFT_HZ 7 +#elif HZ >= 192 && HZ < 384 +# define SHIFT_HZ 8 +#elif HZ >= 384 && HZ < 768 +# define SHIFT_HZ 9 +#elif HZ >= 768 && HZ < 1536 +# define SHIFT_HZ 10 #else -# define SHIFT_HZ 7 /* log2(HZ) */ +# error You lose. #endif /* diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/toshiba.h linux/include/linux/toshiba.h --- v2.4.0-test8/linux/include/linux/toshiba.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/toshiba.h Mon Sep 18 15:02:03 2000 @@ -0,0 +1,36 @@ +/* toshiba.h -- Linux driver for accessing the SMM on Toshiba laptops + * + * Copyright (c) 1996-2000 Jonathan A. Buzzard (jonathan@buzzard.org.uk) + * + * Thanks to Juergen Heinzl for the pointers + * on making sure the structure is aligned and packed. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + */ + +#ifndef _LINUX_TOSHIBA_H +#define _LINUX_TOSHIBA_H + +#define TOSH_PROC "/proc/toshiba" +#define TOSH_DEVICE "/dev/toshiba" +#define TOSH_SMM _IOWR('t', 0x90, 24) + +typedef struct { + unsigned int eax; + unsigned int ebx __attribute__ ((packed)); + unsigned int ecx __attribute__ ((packed)); + unsigned int edx __attribute__ ((packed)); + unsigned int esi __attribute__ ((packed)); + unsigned int edi __attribute__ ((packed)); +} SMMRegisters; + +#endif diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/tqueue.h linux/include/linux/tqueue.h --- v2.4.0-test8/linux/include/linux/tqueue.h Fri Sep 8 12:52:41 2000 +++ linux/include/linux/tqueue.h Mon Oct 2 11:01:18 2000 @@ -114,7 +114,7 @@ f = p -> routine; save_p = p; p = p -> next; - mb(); + smp_mb(); save_p -> sync = 0; if (f) (*f)(arg); diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/usb.h linux/include/linux/usb.h --- v2.4.0-test8/linux/include/linux/usb.h Tue Aug 22 09:06:31 2000 +++ linux/include/linux/usb.h Mon Oct 2 11:02:34 2000 @@ -29,6 +29,7 @@ /* * USB recipients */ +#define USB_RECIP_MASK 0x1f #define USB_RECIP_DEVICE 0x00 #define USB_RECIP_INTERFACE 0x01 #define USB_RECIP_ENDPOINT 0x02 @@ -234,36 +235,36 @@ /* Endpoint descriptor */ struct usb_endpoint_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bEndpointAddress; - __u8 bmAttributes; - __u16 wMaxPacketSize; - __u8 bInterval; - __u8 bRefresh; - __u8 bSynchAddress; + __u8 bLength __attribute__ ((packed)); + __u8 bDescriptorType __attribute__ ((packed)); + __u8 bEndpointAddress __attribute__ ((packed)); + __u8 bmAttributes __attribute__ ((packed)); + __u16 wMaxPacketSize __attribute__ ((packed)); + __u8 bInterval __attribute__ ((packed)); + __u8 bRefresh __attribute__ ((packed)); + __u8 bSynchAddress __attribute__ ((packed)); unsigned char *extra; /* Extra descriptors */ int extralen; -} __attribute__ ((packed)); +}; /* Interface descriptor */ struct usb_interface_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bInterfaceNumber; - __u8 bAlternateSetting; - __u8 bNumEndpoints; - __u8 bInterfaceClass; - __u8 bInterfaceSubClass; - __u8 bInterfaceProtocol; - __u8 iInterface; + __u8 bLength __attribute__ ((packed)); + __u8 bDescriptorType __attribute__ ((packed)); + __u8 bInterfaceNumber __attribute__ ((packed)); + __u8 bAlternateSetting __attribute__ ((packed)); + __u8 bNumEndpoints __attribute__ ((packed)); + __u8 bInterfaceClass __attribute__ ((packed)); + __u8 bInterfaceSubClass __attribute__ ((packed)); + __u8 bInterfaceProtocol __attribute__ ((packed)); + __u8 iInterface __attribute__ ((packed)); struct usb_endpoint_descriptor *endpoint; unsigned char *extra; /* Extra descriptors */ int extralen; -} __attribute__ ((packed)); +}; struct usb_interface { struct usb_interface_descriptor *altsetting; @@ -278,20 +279,20 @@ /* Configuration descriptor information.. */ struct usb_config_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u16 wTotalLength; - __u8 bNumInterfaces; - __u8 bConfigurationValue; - __u8 iConfiguration; - __u8 bmAttributes; - __u8 MaxPower; + __u8 bLength __attribute__ ((packed)); + __u8 bDescriptorType __attribute__ ((packed)); + __u16 wTotalLength __attribute__ ((packed)); + __u8 bNumInterfaces __attribute__ ((packed)); + __u8 bConfigurationValue __attribute__ ((packed)); + __u8 iConfiguration __attribute__ ((packed)); + __u8 bmAttributes __attribute__ ((packed)); + __u8 MaxPower __attribute__ ((packed)); struct usb_interface *interface; unsigned char *extra; /* Extra descriptors */ int extralen; -} __attribute__ ((packed)); +}; /* String descriptor */ struct usb_string_descriptor { @@ -345,9 +346,9 @@ */ #define USB_DISABLE_SPD 0x0001 #define USB_ISO_ASAP 0x0002 -#define USB_URB_EARLY_COMPLETE 0x0004 #define USB_ASYNC_UNLINK 0x0008 #define USB_QUEUE_BULK 0x0010 +#define USB_NO_FSBR 0x0020 #define USB_TIMEOUT_KILLED 0x1000 // only set by HCD! typedef struct @@ -553,6 +554,7 @@ }; extern struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum); +extern struct usb_endpoint_descriptor *usb_epnum_to_ep_desc(struct usb_device *dev, unsigned epnum); extern int usb_register(struct usb_driver *); extern void usb_deregister(struct usb_driver *); @@ -775,13 +777,13 @@ #else /* CONFIG_USB_DEVICEFS */ -extern inline void usbdevfs_add_bus(struct usb_bus *bus) {} -extern inline void usbdevfs_remove_bus(struct usb_bus *bus) {} -extern inline void usbdevfs_add_device(struct usb_device *dev) {} -extern inline void usbdevfs_remove_device(struct usb_device *dev) {} +static inline void usbdevfs_add_bus(struct usb_bus *bus) {} +static inline void usbdevfs_remove_bus(struct usb_bus *bus) {} +static inline void usbdevfs_add_device(struct usb_device *dev) {} +static inline void usbdevfs_remove_device(struct usb_device *dev) {} -extern inline int usbdevfs_init(void) { return 0; } -extern inline void usbdevfs_cleanup(void) { } +static inline int usbdevfs_init(void) { return 0; } +static inline void usbdevfs_cleanup(void) { } #endif /* CONFIG_USB_DEVICEFS */ diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/usbdevice_fs.h linux/include/linux/usbdevice_fs.h --- v2.4.0-test8/linux/include/linux/usbdevice_fs.h Wed Jul 5 11:16:40 2000 +++ linux/include/linux/usbdevice_fs.h Mon Oct 2 11:02:52 2000 @@ -80,6 +80,7 @@ #define USBDEVFS_URB_DISABLE_SPD 1 #define USBDEVFS_URB_ISO_ASAP 2 +#define USBDEVFS_URB_QUEUE_BULK 0x10 #define USBDEVFS_URB_TYPE_ISO 0 #define USBDEVFS_URB_TYPE_INTERRUPT 1 diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/vmalloc.h linux/include/linux/vmalloc.h --- v2.4.0-test8/linux/include/linux/vmalloc.h Fri Sep 8 12:52:42 2000 +++ linux/include/linux/vmalloc.h Mon Oct 2 11:58:47 2000 @@ -26,9 +26,6 @@ extern int vmalloc_area_pages(unsigned long address, unsigned long size, int gfp_mask, pgprot_t prot); -extern struct vm_struct * vmlist; - - /* * Allocate any pages */ diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/vt_buffer.h linux/include/linux/vt_buffer.h --- v2.4.0-test8/linux/include/linux/vt_buffer.h Fri Sep 8 12:53:46 2000 +++ linux/include/linux/vt_buffer.h Mon Oct 2 11:01:50 2000 @@ -32,7 +32,7 @@ #endif #ifndef VT_BUF_HAVE_MEMSETW -extern inline void scr_memsetw(u16 *s, u16 c, unsigned int count) +static inline void scr_memsetw(u16 *s, u16 c, unsigned int count) { count /= 2; while (count--) @@ -41,7 +41,7 @@ #endif #ifndef VT_BUF_HAVE_MEMCPYW -extern inline void scr_memcpyw(u16 *d, const u16 *s, unsigned int count) +static inline void scr_memcpyw(u16 *d, const u16 *s, unsigned int count) { count /= 2; while (count--) @@ -50,7 +50,7 @@ #endif #ifndef VT_BUF_HAVE_MEMMOVEW -extern inline void scr_memmovew(u16 *d, const u16 *s, unsigned int count) +static inline void scr_memmovew(u16 *d, const u16 *s, unsigned int count) { if (d < s) scr_memcpyw(d, s, count); @@ -65,14 +65,14 @@ #endif #ifndef VT_BUF_HAVE_MEMCPYF -extern inline void scr_memcpyw_from(u16 *d, const u16 *s, unsigned int count) +static inline void scr_memcpyw_from(u16 *d, const u16 *s, unsigned int count) { count /= 2; while (count--) *d++ = scr_readw(s++); } -extern inline void scr_memcpyw_to(u16 *d, const u16 *s, unsigned int count) +static inline void scr_memcpyw_to(u16 *d, const u16 *s, unsigned int count) { count /= 2; while (count--) diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/wait.h linux/include/linux/wait.h --- v2.4.0-test8/linux/include/linux/wait.h Fri Sep 8 12:52:41 2000 +++ linux/include/linux/wait.h Mon Oct 2 11:01:17 2000 @@ -158,7 +158,7 @@ return !list_empty(&q->task_list); } -extern inline void __add_wait_queue(wait_queue_head_t *head, wait_queue_t *new) +static inline void __add_wait_queue(wait_queue_head_t *head, wait_queue_t *new) { #if WAITQUEUE_DEBUG if (!head || !new) @@ -174,7 +174,7 @@ /* * Used for wake-one threads: */ -extern inline void __add_wait_queue_tail(wait_queue_head_t *head, +static inline void __add_wait_queue_tail(wait_queue_head_t *head, wait_queue_t *new) { #if WAITQUEUE_DEBUG @@ -188,7 +188,7 @@ list_add_tail(&new->task_list, &head->task_list); } -extern inline void __remove_wait_queue(wait_queue_head_t *head, +static inline void __remove_wait_queue(wait_queue_head_t *head, wait_queue_t *old) { #if WAITQUEUE_DEBUG diff -u --recursive --new-file v2.4.0-test8/linux/include/linux/zftape.h linux/include/linux/zftape.h --- v2.4.0-test8/linux/include/linux/zftape.h Tue Nov 25 14:45:28 1997 +++ linux/include/linux/zftape.h Sun Sep 17 09:37:02 2000 @@ -56,7 +56,7 @@ extern int zft_init(void); -extern inline __s64 zft_div_blksz(__s64 value, __u32 blk_sz) +static inline __s64 zft_div_blksz(__s64 value, __u32 blk_sz) { if (blk_sz == 1) { return value; @@ -66,7 +66,7 @@ } } -extern inline __s64 zft_mul_blksz(__s64 value, __u32 blk_sz) +static inline __s64 zft_mul_blksz(__s64 value, __u32 blk_sz) { if (blk_sz == 1) { return value; diff -u --recursive --new-file v2.4.0-test8/linux/include/net/addrconf.h linux/include/net/addrconf.h --- v2.4.0-test8/linux/include/net/addrconf.h Mon Aug 23 10:01:02 1999 +++ linux/include/net/addrconf.h Sun Sep 17 10:03:43 2000 @@ -87,7 +87,7 @@ extern void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len); -extern __inline__ struct inet6_dev * +static inline struct inet6_dev * __in6_dev_get(struct net_device *dev) { return (struct inet6_dev *)dev->ip6_ptr; @@ -95,7 +95,7 @@ extern rwlock_t addrconf_lock; -extern __inline__ struct inet6_dev * +static inline struct inet6_dev * in6_dev_get(struct net_device *dev) { struct inet6_dev *idev = NULL; @@ -109,7 +109,7 @@ extern void in6_dev_finish_destroy(struct inet6_dev *idev); -extern __inline__ void +static inline void in6_dev_put(struct inet6_dev *idev) { if (atomic_dec_and_test(&idev->refcnt)) @@ -122,7 +122,7 @@ extern void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp); -extern __inline__ void in6_ifa_put(struct inet6_ifaddr *ifp) +static inline void in6_ifa_put(struct inet6_ifaddr *ifp) { if (atomic_dec_and_test(&ifp->refcnt)) inet6_ifa_finish_destroy(ifp); @@ -157,7 +157,7 @@ * compute link-local solicited-node multicast address */ -extern __inline__ void addrconf_addr_solict_mult_old(struct in6_addr *addr, +static inline void addrconf_addr_solict_mult_old(struct in6_addr *addr, struct in6_addr *solicited) { ipv6_addr_set(solicited, @@ -165,7 +165,7 @@ __constant_htonl(0x1), addr->s6_addr32[3]); } -extern __inline__ void addrconf_addr_solict_mult_new(struct in6_addr *addr, +static inline void addrconf_addr_solict_mult_new(struct in6_addr *addr, struct in6_addr *solicited) { ipv6_addr_set(solicited, @@ -175,21 +175,21 @@ } -extern __inline__ void ipv6_addr_all_nodes(struct in6_addr *addr) +static inline void ipv6_addr_all_nodes(struct in6_addr *addr) { ipv6_addr_set(addr, __constant_htonl(0xFF020000), 0, 0, __constant_htonl(0x1)); } -extern __inline__ void ipv6_addr_all_routers(struct in6_addr *addr) +static inline void ipv6_addr_all_routers(struct in6_addr *addr) { ipv6_addr_set(addr, __constant_htonl(0xFF020000), 0, 0, __constant_htonl(0x2)); } -extern __inline__ int ipv6_addr_is_multicast(struct in6_addr *addr) +static inline int ipv6_addr_is_multicast(struct in6_addr *addr) { return (addr->s6_addr32[0] & __constant_htonl(0xFF000000)) == __constant_htonl(0xFF000000); } diff -u --recursive --new-file v2.4.0-test8/linux/include/net/checksum.h linux/include/net/checksum.h --- v2.4.0-test8/linux/include/net/checksum.h Fri Sep 8 12:53:54 2000 +++ linux/include/net/checksum.h Mon Oct 2 12:06:33 2000 @@ -93,7 +93,7 @@ #endif #ifndef _HAVE_ARCH_COPY_AND_CSUM_FROM_USER -extern __inline__ +static inline unsigned int csum_and_copy_from_user (const char *src, char *dst, int len, int sum, int *err_ptr) { diff -u --recursive --new-file v2.4.0-test8/linux/include/net/dn_route.h linux/include/net/dn_route.h --- v2.4.0-test8/linux/include/net/dn_route.h Sat Jan 8 21:36:20 2000 +++ linux/include/net/dn_route.h Sun Sep 17 10:03:43 2000 @@ -91,12 +91,12 @@ #include #include -extern __inline__ void dn_rt_send(struct sk_buff *skb) +static inline void dn_rt_send(struct sk_buff *skb) { dev_queue_xmit(skb); } -extern __inline__ void dn_rt_finish_output(struct sk_buff *skb, char *dst) +static inline void dn_rt_finish_output(struct sk_buff *skb, char *dst) { struct net_device *dev = skb->dev; @@ -110,7 +110,7 @@ kfree_skb(skb); } -extern __inline__ void dn_nsp_send(struct sk_buff *skb) +static inline void dn_nsp_send(struct sk_buff *skb) { struct sock *sk = skb->sk; struct dn_scp *scp = &sk->protinfo.dn; diff -u --recursive --new-file v2.4.0-test8/linux/include/net/dsfield.h linux/include/net/dsfield.h --- v2.4.0-test8/linux/include/net/dsfield.h Tue Feb 8 18:23:13 2000 +++ linux/include/net/dsfield.h Mon Sep 18 15:04:13 2000 @@ -12,19 +12,19 @@ #include -extern __inline__ __u8 ipv4_get_dsfield(struct iphdr *iph) +static inline __u8 ipv4_get_dsfield(struct iphdr *iph) { return iph->tos; } -extern __inline__ __u8 ipv6_get_dsfield(struct ipv6hdr *ipv6h) +static inline __u8 ipv6_get_dsfield(struct ipv6hdr *ipv6h) { return ntohs(*(__u16 *) ipv6h) >> 4; } -extern __inline__ void ipv4_change_dsfield(struct iphdr *iph,__u8 mask, +static inline void ipv4_change_dsfield(struct iphdr *iph,__u8 mask, __u8 value) { __u32 check = ntohs(iph->check); @@ -40,7 +40,7 @@ } -extern __inline__ void ipv6_change_dsfield(struct ipv6hdr *ipv6h,__u8 mask, +static inline void ipv6_change_dsfield(struct ipv6hdr *ipv6h,__u8 mask, __u8 value) { __u16 tmp; @@ -53,7 +53,7 @@ #if 0 /* put this later into asm-i386 or such ... */ -extern __inline__ void ip_change_dsfield(struct iphdr *iph,__u16 dsfield) +static inline void ip_change_dsfield(struct iphdr *iph,__u16 dsfield) { __u16 check; diff -u --recursive --new-file v2.4.0-test8/linux/include/net/dst.h linux/include/net/dst.h --- v2.4.0-test8/linux/include/net/dst.h Fri Sep 8 12:53:54 2000 +++ linux/include/net/dst.h Mon Oct 2 12:06:32 2000 @@ -88,12 +88,12 @@ #ifdef __KERNEL__ -extern __inline__ void dst_hold(struct dst_entry * dst) +static inline void dst_hold(struct dst_entry * dst) { atomic_inc(&dst->__refcnt); } -extern __inline__ +static inline struct dst_entry * dst_clone(struct dst_entry * dst) { if (dst) @@ -101,7 +101,7 @@ return dst; } -extern __inline__ +static inline void dst_release(struct dst_entry * dst) { if (dst) @@ -112,7 +112,7 @@ extern void __dst_free(struct dst_entry * dst); extern void dst_destroy(struct dst_entry * dst); -extern __inline__ +static inline void dst_free(struct dst_entry * dst) { if (dst->obsolete > 1) @@ -124,27 +124,27 @@ __dst_free(dst); } -extern __inline__ void dst_confirm(struct dst_entry *dst) +static inline void dst_confirm(struct dst_entry *dst) { if (dst) neigh_confirm(dst->neighbour); } -extern __inline__ void dst_negative_advice(struct dst_entry **dst_p) +static inline void dst_negative_advice(struct dst_entry **dst_p) { struct dst_entry * dst = *dst_p; if (dst && dst->ops->negative_advice) *dst_p = dst->ops->negative_advice(dst); } -extern __inline__ void dst_link_failure(struct sk_buff *skb) +static inline void dst_link_failure(struct sk_buff *skb) { struct dst_entry * dst = skb->dst; if (dst && dst->ops && dst->ops->link_failure) dst->ops->link_failure(skb); } -extern __inline__ void dst_set_expires(struct dst_entry *dst, int timeout) +static inline void dst_set_expires(struct dst_entry *dst, int timeout) { unsigned long expires = jiffies + timeout; diff -u --recursive --new-file v2.4.0-test8/linux/include/net/if_inet6.h linux/include/net/if_inet6.h --- v2.4.0-test8/linux/include/net/if_inet6.h Thu Jun 22 07:23:26 2000 +++ linux/include/net/if_inet6.h Mon Sep 18 15:04:13 2000 @@ -108,7 +108,7 @@ extern struct ipv6_devconf ipv6_devconf; -extern __inline__ void ipv6_eth_mc_map(struct in6_addr *addr, char *buf) +static inline void ipv6_eth_mc_map(struct in6_addr *addr, char *buf) { /* * +-------+-------+-------+-------+-------+-------+ @@ -122,7 +122,7 @@ memcpy(buf + 2, &addr->s6_addr32[3], sizeof(__u32)); } -extern __inline__ void ipv6_tr_mc_map(struct in6_addr *addr, char *buf) +static inline void ipv6_tr_mc_map(struct in6_addr *addr, char *buf) { /* All nodes FF01::1, FF02::1, FF02::1:FFxx:xxxx */ diff -u --recursive --new-file v2.4.0-test8/linux/include/net/ip.h linux/include/net/ip.h --- v2.4.0-test8/linux/include/net/ip.h Fri Sep 8 12:53:54 2000 +++ linux/include/net/ip.h Mon Oct 2 12:06:33 2000 @@ -115,7 +115,7 @@ * multicast packets. */ -extern __inline__ void ip_tr_mc_map(u32 addr, char *buf) +static inline void ip_tr_mc_map(u32 addr, char *buf) { buf[0]=0xC0; buf[1]=0x00; @@ -159,7 +159,7 @@ extern int sysctl_ip_default_ttl; #ifdef CONFIG_INET -extern __inline__ int ip_send(struct sk_buff *skb) +static inline int ip_send(struct sk_buff *skb) { if (skb->len > skb->dst->pmtu) return ip_fragment(skb, ip_finish_output); @@ -169,7 +169,7 @@ /* The function in 2.2 was invalid, producing wrong result for * check=0xFEFF. It was noticed by Arthur Skawina _year_ ago. --ANK(000625) */ -extern __inline__ +static inline int ip_decrease_ttl(struct iphdr *iph) { u32 check = iph->check; @@ -178,7 +178,7 @@ return --iph->ttl; } -extern __inline__ +static inline int ip_dont_fragment(struct sock *sk, struct dst_entry *dst) { return (sk->protinfo.af_inet.pmtudisc == IP_PMTUDISC_DO || @@ -188,7 +188,7 @@ extern void __ip_select_ident(struct iphdr *iph, struct dst_entry *dst); -extern __inline__ void ip_select_ident(struct iphdr *iph, struct dst_entry *dst) +static inline void ip_select_ident(struct iphdr *iph, struct dst_entry *dst) { if (iph->frag_off&__constant_htons(IP_DF)) iph->id = 0; @@ -200,7 +200,7 @@ * Map a multicast IP onto multicast MAC for type ethernet. */ -extern __inline__ void ip_eth_mc_map(u32 addr, char *buf) +static inline void ip_eth_mc_map(u32 addr, char *buf) { addr=ntohl(addr); buf[0]=0x01; diff -u --recursive --new-file v2.4.0-test8/linux/include/net/ip6_fib.h linux/include/net/ip6_fib.h --- v2.4.0-test8/linux/include/net/ip6_fib.h Mon Aug 23 10:01:02 1999 +++ linux/include/net/ip6_fib.h Mon Sep 18 15:04:13 2000 @@ -96,7 +96,7 @@ extern struct fib6_walker_t fib6_walker_list; extern rwlock_t fib6_walker_lock; -extern __inline__ void fib6_walker_link(struct fib6_walker_t *w) +static inline void fib6_walker_link(struct fib6_walker_t *w) { write_lock_bh(&fib6_walker_lock); w->next = fib6_walker_list.next; @@ -106,7 +106,7 @@ write_unlock_bh(&fib6_walker_lock); } -extern __inline__ void fib6_walker_unlink(struct fib6_walker_t *w) +static inline void fib6_walker_unlink(struct fib6_walker_t *w) { write_lock_bh(&fib6_walker_lock); w->next->prev = w->prev; diff -u --recursive --new-file v2.4.0-test8/linux/include/net/ip6_route.h linux/include/net/ip6_route.h --- v2.4.0-test8/linux/include/net/ip6_route.h Mon Aug 23 10:01:02 1999 +++ linux/include/net/ip6_route.h Mon Sep 18 15:04:13 2000 @@ -94,7 +94,7 @@ * For UDP/RAW sockets this is done on udp_connect. */ -extern __inline__ void ip6_dst_store(struct sock *sk, struct dst_entry *dst, +static inline void ip6_dst_store(struct sock *sk, struct dst_entry *dst, struct in6_addr *daddr) { struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6; diff -u --recursive --new-file v2.4.0-test8/linux/include/net/ip_fib.h linux/include/net/ip_fib.h --- v2.4.0-test8/linux/include/net/ip_fib.h Mon Aug 23 10:01:02 1999 +++ linux/include/net/ip_fib.h Mon Sep 18 15:04:13 2000 @@ -140,19 +140,19 @@ extern struct fib_table *local_table; extern struct fib_table *main_table; -extern __inline__ struct fib_table *fib_get_table(int id) +static inline struct fib_table *fib_get_table(int id) { if (id != RT_TABLE_LOCAL) return main_table; return local_table; } -extern __inline__ struct fib_table *fib_new_table(int id) +static inline struct fib_table *fib_new_table(int id) { return fib_get_table(id); } -extern __inline__ int fib_lookup(const struct rt_key *key, struct fib_result *res) +static inline int fib_lookup(const struct rt_key *key, struct fib_result *res) { if (local_table->tb_lookup(local_table, key, res) && main_table->tb_lookup(main_table, key, res)) @@ -160,7 +160,7 @@ return 0; } -extern __inline__ void fib_select_default(const struct rt_key *key, struct fib_result *res) +static inline void fib_select_default(const struct rt_key *key, struct fib_result *res) { if (FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK) main_table->tb_select_default(main_table, key, res); @@ -175,7 +175,7 @@ extern struct fib_table *__fib_new_table(int id); extern void fib_rule_put(struct fib_rule *r); -extern __inline__ struct fib_table *fib_get_table(int id) +static inline struct fib_table *fib_get_table(int id) { if (id == 0) id = RT_TABLE_MAIN; @@ -183,7 +183,7 @@ return fib_tables[id]; } -extern __inline__ struct fib_table *fib_new_table(int id) +static inline struct fib_table *fib_new_table(int id) { if (id == 0) id = RT_TABLE_MAIN; @@ -241,7 +241,7 @@ extern void fib_rules_init(void); #endif -extern __inline__ void fib_combine_itag(u32 *itag, struct fib_result *res) +static inline void fib_combine_itag(u32 *itag, struct fib_result *res) { #ifdef CONFIG_NET_CLS_ROUTE #ifdef CONFIG_IP_MULTIPLE_TABLES @@ -259,13 +259,13 @@ extern void free_fib_info(struct fib_info *fi); -extern __inline__ void fib_info_put(struct fib_info *fi) +static inline void fib_info_put(struct fib_info *fi) { if (atomic_dec_and_test(&fi->fib_clntref)) free_fib_info(fi); } -extern __inline__ void fib_res_put(struct fib_result *res) +static inline void fib_res_put(struct fib_result *res) { if (res->fi) fib_info_put(res->fi); diff -u --recursive --new-file v2.4.0-test8/linux/include/net/ipv6.h linux/include/net/ipv6.h --- v2.4.0-test8/linux/include/net/ipv6.h Fri Sep 8 12:53:54 2000 +++ linux/include/net/ipv6.h Mon Oct 2 12:06:41 2000 @@ -4,7 +4,7 @@ * Authors: * Pedro Roque * - * $Id: ipv6.h,v 1.21 2000/07/07 22:29:42 davem Exp $ + * $Id: ipv6.h,v 1.22 2000/09/18 05:54:13 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -169,7 +169,7 @@ extern void ip6_flowlabel_init(void); extern void ip6_flowlabel_cleanup(void); -extern __inline__ void fl6_sock_release(struct ip6_flowlabel *fl) +static inline void fl6_sock_release(struct ip6_flowlabel *fl) { if (fl) atomic_dec(&fl->users); @@ -206,23 +206,23 @@ extern int ipv6_addr_type(struct in6_addr *addr); -extern __inline__ int ipv6_addr_scope(struct in6_addr *addr) +static inline int ipv6_addr_scope(struct in6_addr *addr) { return ipv6_addr_type(addr) & IPV6_ADDR_SCOPE_MASK; } -extern __inline__ int ipv6_addr_cmp(struct in6_addr *a1, struct in6_addr *a2) +static inline int ipv6_addr_cmp(struct in6_addr *a1, struct in6_addr *a2) { return memcmp((void *) a1, (void *) a2, sizeof(struct in6_addr)); } -extern __inline__ void ipv6_addr_copy(struct in6_addr *a1, struct in6_addr *a2) +static inline void ipv6_addr_copy(struct in6_addr *a1, struct in6_addr *a2) { memcpy((void *) a1, (void *) a2, sizeof(struct in6_addr)); } #ifndef __HAVE_ARCH_ADDR_SET -extern __inline__ void ipv6_addr_set(struct in6_addr *addr, +static inline void ipv6_addr_set(struct in6_addr *addr, __u32 w1, __u32 w2, __u32 w3, __u32 w4) { @@ -233,7 +233,7 @@ } #endif -extern __inline__ int ipv6_addr_any(struct in6_addr *a) +static inline int ipv6_addr_any(struct in6_addr *a) { return ((a->s6_addr32[0] | a->s6_addr32[1] | a->s6_addr32[2] | a->s6_addr32[3] ) == 0); diff -u --recursive --new-file v2.4.0-test8/linux/include/net/ndisc.h linux/include/net/ndisc.h --- v2.4.0-test8/linux/include/net/ndisc.h Fri Sep 8 12:53:54 2000 +++ linux/include/net/ndisc.h Mon Oct 2 12:06:41 2000 @@ -101,7 +101,7 @@ extern void igmp6_cleanup(void); -extern __inline__ struct neighbour * ndisc_get_neigh(struct net_device *dev, struct in6_addr *addr) +static inline struct neighbour * ndisc_get_neigh(struct net_device *dev, struct in6_addr *addr) { if (dev) diff -u --recursive --new-file v2.4.0-test8/linux/include/net/neighbour.h linux/include/net/neighbour.h --- v2.4.0-test8/linux/include/net/neighbour.h Fri Sep 8 12:53:53 2000 +++ linux/include/net/neighbour.h Mon Oct 2 12:06:32 2000 @@ -212,13 +212,13 @@ * Neighbour references */ -extern __inline__ void neigh_release(struct neighbour *neigh) +static inline void neigh_release(struct neighbour *neigh) { if (atomic_dec_and_test(&neigh->refcnt)) neigh_destroy(neigh); } -extern __inline__ struct neighbour * neigh_clone(struct neighbour *neigh) +static inline struct neighbour * neigh_clone(struct neighbour *neigh) { if (neigh) atomic_inc(&neigh->refcnt); @@ -227,23 +227,23 @@ #define neigh_hold(n) atomic_inc(&(n)->refcnt) -extern __inline__ void neigh_confirm(struct neighbour *neigh) +static inline void neigh_confirm(struct neighbour *neigh) { if (neigh) neigh->confirmed = jiffies; } -extern __inline__ int neigh_is_connected(struct neighbour *neigh) +static inline int neigh_is_connected(struct neighbour *neigh) { return neigh->nud_state&NUD_CONNECTED; } -extern __inline__ int neigh_is_valid(struct neighbour *neigh) +static inline int neigh_is_valid(struct neighbour *neigh) { return neigh->nud_state&NUD_VALID; } -extern __inline__ int neigh_event_send(struct neighbour *neigh, struct sk_buff *skb) +static inline int neigh_event_send(struct neighbour *neigh, struct sk_buff *skb) { neigh->used = jiffies; if (!(neigh->nud_state&(NUD_CONNECTED|NUD_DELAY|NUD_PROBE))) @@ -251,7 +251,7 @@ return 0; } -extern __inline__ struct neighbour * +static inline struct neighbour * __neigh_lookup(struct neigh_table *tbl, const void *pkey, struct net_device *dev, int creat) { struct neighbour *n = neigh_lookup(tbl, pkey, dev); @@ -263,7 +263,7 @@ return IS_ERR(n) ? NULL : n; } -extern __inline__ struct neighbour * +static inline struct neighbour * __neigh_lookup_errno(struct neigh_table *tbl, const void *pkey, struct net_device *dev) { diff -u --recursive --new-file v2.4.0-test8/linux/include/net/pkt_cls.h linux/include/net/pkt_cls.h --- v2.4.0-test8/linux/include/net/pkt_cls.h Fri Jan 7 18:11:45 2000 +++ linux/include/net/pkt_cls.h Mon Sep 18 15:04:13 2000 @@ -63,7 +63,7 @@ specific classifiers. */ -extern __inline__ int tc_classify(struct sk_buff *skb, struct tcf_proto *tp, struct tcf_result *res) +static inline int tc_classify(struct sk_buff *skb, struct tcf_proto *tp, struct tcf_result *res) { int err = 0; u32 protocol = skb->protocol; diff -u --recursive --new-file v2.4.0-test8/linux/include/net/pkt_sched.h linux/include/net/pkt_sched.h --- v2.4.0-test8/linux/include/net/pkt_sched.h Fri Sep 8 12:53:56 2000 +++ linux/include/net/pkt_sched.h Mon Oct 2 11:01:58 2000 @@ -104,32 +104,32 @@ int refcnt; }; -extern __inline__ void sch_tree_lock(struct Qdisc *q) +static inline void sch_tree_lock(struct Qdisc *q) { write_lock(&qdisc_tree_lock); spin_lock_bh(&q->dev->queue_lock); } -extern __inline__ void sch_tree_unlock(struct Qdisc *q) +static inline void sch_tree_unlock(struct Qdisc *q) { spin_unlock_bh(&q->dev->queue_lock); write_unlock(&qdisc_tree_lock); } -extern __inline__ void tcf_tree_lock(struct tcf_proto *tp) +static inline void tcf_tree_lock(struct tcf_proto *tp) { write_lock(&qdisc_tree_lock); spin_lock_bh(&tp->q->dev->queue_lock); } -extern __inline__ void tcf_tree_unlock(struct tcf_proto *tp) +static inline void tcf_tree_unlock(struct tcf_proto *tp) { spin_unlock_bh(&tp->q->dev->queue_lock); write_unlock(&qdisc_tree_lock); } -extern __inline__ unsigned long +static inline unsigned long cls_set_class(struct tcf_proto *tp, unsigned long *clp, unsigned long cl) { unsigned long old_cl; @@ -141,7 +141,7 @@ return old_cl; } -extern __inline__ unsigned long +static inline unsigned long __cls_set_class(unsigned long *clp, unsigned long cl) { unsigned long old_cl; @@ -401,7 +401,7 @@ extern int tcf_police_dump(struct sk_buff *skb, struct tcf_police *p); extern int tcf_police(struct sk_buff *skb, struct tcf_police *p); -extern __inline__ void tcf_police_release(struct tcf_police *p) +static inline void tcf_police_release(struct tcf_police *p) { if (p && --p->refcnt == 0) tcf_police_destroy(p); @@ -433,7 +433,7 @@ extern int qdisc_restart(struct net_device *dev); -extern __inline__ void qdisc_run(struct net_device *dev) +static inline void qdisc_run(struct net_device *dev) { while (!netif_queue_stopped(dev) && qdisc_restart(dev)<0) @@ -443,7 +443,7 @@ /* Calculate maximal size of packet seen by hard_start_xmit routine of this device. */ -extern __inline__ unsigned psched_mtu(struct net_device *dev) +static inline unsigned psched_mtu(struct net_device *dev) { unsigned mtu = dev->mtu; return dev->hard_header ? mtu + dev->hard_header_len : mtu; diff -u --recursive --new-file v2.4.0-test8/linux/include/net/profile.h linux/include/net/profile.h --- v2.4.0-test8/linux/include/net/profile.h Fri Sep 8 12:52:42 2000 +++ linux/include/net/profile.h Mon Oct 2 11:01:18 2000 @@ -31,12 +31,12 @@ #ifdef CONFIG_X86_TSC -extern __inline__ void net_profile_stamp(struct timeval *pstamp) +static inline void net_profile_stamp(struct timeval *pstamp) { rdtsc(pstamp->tv_usec, pstamp->tv_sec); } -extern __inline__ void net_profile_accumulate(struct timeval *entered, +static inline void net_profile_accumulate(struct timeval *entered, struct timeval *leaved, struct timeval *acc) { @@ -52,7 +52,7 @@ "0" (acc->tv_usec), "1" (acc->tv_sec)); } -extern __inline__ void net_profile_sub(struct timeval *sub, +static inline void net_profile_sub(struct timeval *sub, struct timeval *acc) { __asm__ __volatile__ ("subl %2,%0\n\t" @@ -62,7 +62,7 @@ "0" (acc->tv_usec), "1" (acc->tv_sec)); } -extern __inline__ void net_profile_add(struct timeval *add, +static inline void net_profile_add(struct timeval *add, struct timeval *acc) { __asm__ __volatile__ ("addl %2,%0\n\t" @@ -80,7 +80,7 @@ /* On alpha cycle counter has only 32 bits :-( :-( */ -extern __inline__ void net_profile_stamp(struct timeval *pstamp) +static inline void net_profile_stamp(struct timeval *pstamp) { __u32 result; __asm__ __volatile__ ("rpcc %0" : "r="(result)); @@ -91,7 +91,7 @@ pstamp->tv_usec = alpha_lo; } -extern __inline__ void net_profile_accumulate(struct timeval *entered, +static inline void net_profile_accumulate(struct timeval *entered, struct timeval *leaved, struct timeval *acc) { @@ -113,7 +113,7 @@ acc->tv_usec = usecs; } -extern __inline__ void net_profile_sub(struct timeval *entered, +static inline void net_profile_sub(struct timeval *entered, struct timeval *leaved) { time_t usecs = leaved->tv_usec - entered->tv_usec; @@ -127,7 +127,7 @@ leaved->tv_usec = usecs; } -extern __inline__ void net_profile_add(struct timeval *entered, struct timeval *leaved) +static inline void net_profile_add(struct timeval *entered, struct timeval *leaved) { time_t usecs = leaved->tv_usec + entered->tv_usec; time_t secs = leaved->tv_sec + entered->tv_sec; @@ -143,18 +143,18 @@ #else -extern __inline__ void net_profile_stamp(struct timeval *pstamp) +static inline void net_profile_stamp(struct timeval *pstamp) { /* Not "fast" counterpart! On architectures without cpu clock "fast" routine is absolutely useless in this situation. do_gettimeofday still says something on slow-slow-slow - boxes, though it eats more cpu time than the sobject of + boxes, though it eats more cpu time than the subject of investigation :-) :-) */ do_gettimeofday(pstamp); } -extern __inline__ void net_profile_accumulate(struct timeval *entered, +static inline void net_profile_accumulate(struct timeval *entered, struct timeval *leaved, struct timeval *acc) { @@ -176,7 +176,7 @@ acc->tv_usec = usecs; } -extern __inline__ void net_profile_sub(struct timeval *entered, +static inline void net_profile_sub(struct timeval *entered, struct timeval *leaved) { time_t usecs = leaved->tv_usec - entered->tv_usec; @@ -190,7 +190,7 @@ leaved->tv_usec = usecs; } -extern __inline__ void net_profile_add(struct timeval *entered, struct timeval *leaved) +static inline void net_profile_add(struct timeval *entered, struct timeval *leaved) { time_t usecs = leaved->tv_usec + entered->tv_usec; time_t secs = leaved->tv_sec + entered->tv_sec; @@ -207,7 +207,7 @@ #endif -extern __inline__ void net_profile_enter(struct net_profile_slot *s) +static inline void net_profile_enter(struct net_profile_slot *s) { unsigned long flags; @@ -220,7 +220,7 @@ restore_flags(flags); } -extern __inline__ void net_profile_leave_irq(struct net_profile_slot *s) +static inline void net_profile_leave_irq(struct net_profile_slot *s) { unsigned long flags; @@ -241,7 +241,7 @@ restore_flags(flags); } -extern __inline__ void net_profile_leave(struct net_profile_slot *s) +static inline void net_profile_leave(struct net_profile_slot *s) { unsigned long flags; save_flags(flags); diff -u --recursive --new-file v2.4.0-test8/linux/include/net/route.h linux/include/net/route.h --- v2.4.0-test8/linux/include/net/route.h Fri Sep 8 12:53:54 2000 +++ linux/include/net/route.h Mon Oct 2 12:06:32 2000 @@ -113,7 +113,7 @@ extern int ip_rt_dump(struct sk_buff *skb, struct netlink_callback *cb); /* Deprecated: use ip_route_output_key directly */ -extern __inline__ int ip_route_output(struct rtable **rp, +static inline int ip_route_output(struct rtable **rp, u32 daddr, u32 saddr, u32 tos, int oif) { struct rt_key key = { dst:daddr, src:saddr, oif:oif, tos:tos }; @@ -122,7 +122,7 @@ } -extern __inline__ void ip_rt_put(struct rtable * rt) +static inline void ip_rt_put(struct rtable * rt) { if (rt) dst_release(&rt->u.dst); @@ -137,12 +137,12 @@ extern __u8 ip_tos2prio[16]; -extern __inline__ char rt_tos2priority(u8 tos) +static inline char rt_tos2priority(u8 tos) { return ip_tos2prio[IPTOS_TOS(tos)>>1]; } -extern __inline__ int ip_route_connect(struct rtable **rp, u32 dst, u32 src, u32 tos, int oif) +static inline int ip_route_connect(struct rtable **rp, u32 dst, u32 src, u32 tos, int oif) { int err; err = ip_route_output(rp, dst, src, tos, oif); @@ -157,7 +157,7 @@ extern void rt_bind_peer(struct rtable *rt, int create); -extern __inline__ struct inet_peer *rt_get_peer(struct rtable *rt) +static inline struct inet_peer *rt_get_peer(struct rtable *rt) { if (rt->peer) return rt->peer; diff -u --recursive --new-file v2.4.0-test8/linux/include/net/snmp.h linux/include/net/snmp.h --- v2.4.0-test8/linux/include/net/snmp.h Thu Aug 10 13:01:26 2000 +++ linux/include/net/snmp.h Mon Oct 2 11:01:18 2000 @@ -14,17 +14,34 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * + * $Id: snmp.h,v 1.17 2000/09/21 01:31:50 davem Exp $ + * */ #ifndef _SNMP_H #define _SNMP_H + +#include /* * We use all unsigned longs. Linux will soon be so reliable that even these * will rapidly get too small 8-). Seriously consider the IpInReceives count * on the 20Gb/s + networks people expect in a few years time! */ - + +/* + * The rule for padding: + * Best is power of two because then the right structure can be found by a simple + * shift. The structure should be always cache line aligned. + * gcc needs n=alignto(cachelinesize, popcnt(sizeof(bla_mib))) shift/add instructions + * to emulate multiply in case it is not power-of-two. Currently n is always <=3 for + * all sizes so simple cache line alignment is enough. + * + * The best solution would be a global CPU local area , especially on 64 and 128byte + * cacheline machine it makes a *lot* of sense -AK + */ + + struct ip_mib { unsigned long IpInReceives; @@ -44,8 +61,8 @@ unsigned long IpFragOKs; unsigned long IpFragFails; unsigned long IpFragCreates; - unsigned long __pad[32-19]; -}; + unsigned long __pad[0]; +} ____cacheline_aligned; struct ipv6_mib { @@ -71,8 +88,8 @@ unsigned long Ip6FragCreates; unsigned long Ip6InMcastPkts; unsigned long Ip6OutMcastPkts; - unsigned long __pad[32-22]; -}; + unsigned long __pad[0]; +} ____cacheline_aligned; struct icmp_mib { @@ -102,8 +119,8 @@ unsigned long IcmpOutTimestampReps; unsigned long IcmpOutAddrMasks; unsigned long IcmpOutAddrMaskReps; - unsigned long __pad[32-26]; -}; + unsigned long __pad[0]; +} ____cacheline_aligned; struct icmpv6_mib { @@ -140,8 +157,8 @@ unsigned long Icmp6OutRedirects; unsigned long Icmp6OutGroupMembResponses; unsigned long Icmp6OutGroupMembReductions; - unsigned long __pad[32-28]; -}; + unsigned long __pad[0]; +} ____cacheline_aligned; struct tcp_mib { @@ -159,8 +176,8 @@ unsigned long TcpRetransSegs; unsigned long TcpInErrs; unsigned long TcpOutRsts; - unsigned long __pad[16-14]; -}; + unsigned long __pad[0]; +} ____cacheline_aligned; struct udp_mib { @@ -168,8 +185,8 @@ unsigned long UdpNoPorts; unsigned long UdpInErrors; unsigned long UdpOutDatagrams; - unsigned long __pad[0]; -}; + unsigned long __pad[0]; +} ____cacheline_aligned; struct linux_mib { @@ -237,9 +254,15 @@ unsigned long TCPAbortOnLinger; unsigned long TCPAbortFailed; unsigned long TCPMemoryPressures; - unsigned long __pad[64-64]; -}; + unsigned long __pad[0]; +} ____cacheline_aligned; + +/* + * FIXME: On x86 and some other CPUs the split into user and softirq parts is not needed because + * addl $1,memory is atomic against interrupts (but atomic_inc would be overkill because of the lock + * cycles). Wants new nonlocked_atomic_inc() primitives -AK + */ #define SNMP_INC_STATS(mib, field) ((mib)[2*smp_processor_id()+!in_softirq()].field++) #define SNMP_INC_STATS_BH(mib, field) ((mib)[2*smp_processor_id()].field++) #define SNMP_INC_STATS_USER(mib, field) ((mib)[2*smp_processor_id()+1].field++) diff -u --recursive --new-file v2.4.0-test8/linux/include/net/sock.h linux/include/net/sock.h --- v2.4.0-test8/linux/include/net/sock.h Fri Sep 8 12:53:54 2000 +++ linux/include/net/sock.h Mon Oct 2 12:06:33 2000 @@ -470,7 +470,6 @@ #define sock_lock_init(__sk) \ do { spin_lock_init(&((__sk)->lock.slock)); \ - (__sk)->dst_lock = RW_LOCK_UNLOCKED; \ (__sk)->lock.users = 0; \ init_waitqueue_head(&((__sk)->lock.wq)); \ } while(0); @@ -749,6 +748,7 @@ #define SOCK_SNDBUF_LOCK 1 #define SOCK_RCVBUF_LOCK 2 #define SOCK_BINDADDR_LOCK 4 +#define SOCK_BINDPORT_LOCK 8 /* Used by processes to "lock" a socket state, so that @@ -818,7 +818,6 @@ int priority); extern void sock_wfree(struct sk_buff *skb); extern void sock_rfree(struct sk_buff *skb); -extern unsigned long sock_wspace(struct sock *sk); extern int sock_setsockopt(struct socket *sock, int level, int op, char *optval, @@ -901,7 +900,7 @@ * be accepted or 1 if the packet should be tossed. */ -extern __inline__ int sk_filter(struct sk_buff *skb, struct sk_filter *filter) +static inline int sk_filter(struct sk_buff *skb, struct sk_filter *filter) { int pkt_len; @@ -922,7 +921,7 @@ * Remove a filter from a socket and release its resources. */ -extern __inline__ void sk_filter_release(struct sock *sk, struct sk_filter *fp) +static inline void sk_filter_release(struct sock *sk, struct sk_filter *fp) { unsigned int size = sk_filter_len(fp); @@ -932,7 +931,7 @@ kfree(fp); } -extern __inline__ void sk_filter_charge(struct sock *sk, struct sk_filter *fp) +static inline void sk_filter_charge(struct sock *sk, struct sk_filter *fp) { atomic_inc(&fp->refcnt); atomic_add(sk_filter_len(fp), &sk->omem_alloc); @@ -971,7 +970,7 @@ modifications. */ -extern __inline__ void sock_hold(struct sock *sk) +static inline void sock_hold(struct sock *sk) { atomic_inc(&sk->refcnt); } @@ -979,13 +978,13 @@ /* Ungrab socket in the context, which assumes that socket refcnt cannot hit zero, f.e. it is true in context of any socketcall. */ -extern __inline__ void __sock_put(struct sock *sk) +static inline void __sock_put(struct sock *sk) { atomic_dec(&sk->refcnt); } /* Ungrab socket and destroy it, if it was the last reference. */ -extern __inline__ void sock_put(struct sock *sk) +static inline void sock_put(struct sock *sk) { if (atomic_dec_and_test(&sk->refcnt)) sk_free(sk); @@ -998,7 +997,7 @@ * probably wants some additional cleanups or even continuing * to work with this socket (TCP). */ -extern __inline__ void sock_orphan(struct sock *sk) +static inline void sock_orphan(struct sock *sk) { write_lock_bh(&sk->callback_lock); sk->dead = 1; @@ -1007,7 +1006,7 @@ write_unlock_bh(&sk->callback_lock); } -extern __inline__ void sock_graft(struct sock *sk, struct socket *parent) +static inline void sock_graft(struct sock *sk, struct socket *parent) { write_lock_bh(&sk->callback_lock); sk->sleep = &parent->wait; @@ -1036,13 +1035,13 @@ return ino; } -extern __inline__ struct dst_entry * +static inline struct dst_entry * __sk_dst_get(struct sock *sk) { return sk->dst_cache; } -extern __inline__ struct dst_entry * +static inline struct dst_entry * sk_dst_get(struct sock *sk) { struct dst_entry *dst; @@ -1055,7 +1054,7 @@ return dst; } -extern __inline__ void +static inline void __sk_dst_set(struct sock *sk, struct dst_entry *dst) { struct dst_entry *old_dst; @@ -1065,7 +1064,7 @@ dst_release(old_dst); } -extern __inline__ void +static inline void sk_dst_set(struct sock *sk, struct dst_entry *dst) { write_lock(&sk->dst_lock); @@ -1073,7 +1072,7 @@ write_unlock(&sk->dst_lock); } -extern __inline__ void +static inline void __sk_dst_reset(struct sock *sk) { struct dst_entry *old_dst; @@ -1083,7 +1082,7 @@ dst_release(old_dst); } -extern __inline__ void +static inline void sk_dst_reset(struct sock *sk) { write_lock(&sk->dst_lock); @@ -1091,7 +1090,7 @@ write_unlock(&sk->dst_lock); } -extern __inline__ struct dst_entry * +static inline struct dst_entry * __sk_dst_check(struct sock *sk, u32 cookie) { struct dst_entry *dst = sk->dst_cache; @@ -1104,7 +1103,7 @@ return dst; } -extern __inline__ struct dst_entry * +static inline struct dst_entry * sk_dst_check(struct sock *sk, u32 cookie) { struct dst_entry *dst = sk_dst_get(sk); @@ -1127,7 +1126,7 @@ * packet ever received. */ -extern __inline__ void skb_set_owner_w(struct sk_buff *skb, struct sock *sk) +static inline void skb_set_owner_w(struct sk_buff *skb, struct sock *sk) { sock_hold(sk); skb->sk = sk; @@ -1135,14 +1134,14 @@ atomic_add(skb->truesize, &sk->wmem_alloc); } -extern __inline__ void skb_set_owner_r(struct sk_buff *skb, struct sock *sk) +static inline void skb_set_owner_r(struct sk_buff *skb, struct sock *sk) { skb->sk = sk; skb->destructor = sock_rfree; atomic_add(skb->truesize, &sk->rmem_alloc); } -extern __inline__ int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) +static inline int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) { /* Cast skb->rcvbuf to unsigned... It's pointless, but reduces number of warnings when compiling with -W --ANK @@ -1175,7 +1174,7 @@ return 0; } -extern __inline__ int sock_queue_err_skb(struct sock *sk, struct sk_buff *skb) +static inline int sock_queue_err_skb(struct sock *sk, struct sk_buff *skb) { /* Cast skb->rcvbuf to unsigned... It's pointless, but reduces number of warnings when compiling with -W --ANK @@ -1193,13 +1192,13 @@ * Recover an error report and clear atomically */ -extern __inline__ int sock_error(struct sock *sk) +static inline int sock_error(struct sock *sk) { int err=xchg(&sk->err,0); return -err; } -extern __inline__ unsigned long sock_wspace(struct sock *sk) +static inline unsigned long sock_wspace(struct sock *sk) { int amt = 0; @@ -1211,7 +1210,7 @@ return amt; } -extern __inline__ void sk_wake_async(struct sock *sk, int how, int band) +static inline void sk_wake_async(struct sock *sk, int how, int band) { if (sk->socket && sk->socket->fasync_list) sock_wake_async(sk->socket, how, band); @@ -1226,27 +1225,27 @@ * Default write policy as shown to user space via poll/select/SIGIO * Kernel internally doesn't use the MIN_WRITE_SPACE threshold. */ -extern __inline__ int sock_writeable(struct sock *sk) +static inline int sock_writeable(struct sock *sk) { return sock_wspace(sk) >= SOCK_MIN_WRITE_SPACE; } -extern __inline__ int gfp_any(void) +static inline int gfp_any(void) { return in_softirq() ? GFP_ATOMIC : GFP_KERNEL; } -extern __inline__ long sock_rcvtimeo(struct sock *sk, int noblock) +static inline long sock_rcvtimeo(struct sock *sk, int noblock) { return noblock ? 0 : sk->rcvtimeo; } -extern __inline__ long sock_sndtimeo(struct sock *sk, int noblock) +static inline long sock_sndtimeo(struct sock *sk, int noblock) { return noblock ? 0 : sk->sndtimeo; } -extern __inline__ int sock_rcvlowat(struct sock *sk, int waitall, int len) +static inline int sock_rcvlowat(struct sock *sk, int waitall, int len) { return (waitall ? len : min(sk->rcvlowat, len)) ? : 1; } @@ -1254,7 +1253,7 @@ /* Alas, with timeout socket operations are not restartable. * Compare this to poll(). */ -extern __inline__ int sock_intr_errno(long timeo) +static inline int sock_intr_errno(long timeo) { return timeo == MAX_SCHEDULE_TIMEOUT ? -ERESTARTSYS : -EINTR; } diff -u --recursive --new-file v2.4.0-test8/linux/include/net/tcp.h linux/include/net/tcp.h --- v2.4.0-test8/linux/include/net/tcp.h Fri Sep 8 12:54:06 2000 +++ linux/include/net/tcp.h Mon Oct 2 12:06:41 2000 @@ -166,7 +166,7 @@ extern kmem_cache_t *tcp_timewait_cachep; -extern __inline__ void tcp_tw_put(struct tcp_tw_bucket *tw) +static inline void tcp_tw_put(struct tcp_tw_bucket *tw) { if (atomic_dec_and_test(&tw->refcnt)) { #ifdef INET_REFCNT_DEBUG @@ -495,7 +495,7 @@ #define tcp_openreq_alloc() kmem_cache_alloc(tcp_openreq_cachep, SLAB_ATOMIC) #define tcp_openreq_fastfree(req) kmem_cache_free(tcp_openreq_cachep, req) -extern __inline__ void tcp_openreq_free(struct open_request *req) +static inline void tcp_openreq_free(struct open_request *req) { req->class->destructor(req); tcp_openreq_fastfree(req); @@ -656,20 +656,6 @@ memset(&tp->ack, 0, sizeof(tp->ack)); } -enum tcp_ca_state -{ - TCP_CA_Open = 0, -#define TCPF_CA_Open (1<tp_pinfo.af_tcp; @@ -1034,7 +1020,7 @@ * one half the current congestion window, but no * less than two segments */ -extern __inline__ __u32 tcp_recalc_ssthresh(struct tcp_opt *tp) +static inline __u32 tcp_recalc_ssthresh(struct tcp_opt *tp) { return max(tp->snd_cwnd>>1, 2); } @@ -1043,7 +1029,7 @@ * The exception is rate halving phase, when cwnd is decreasing towards * ssthresh. */ -extern __inline__ __u32 tcp_current_ssthresh(struct tcp_opt *tp) +static inline __u32 tcp_current_ssthresh(struct tcp_opt *tp) { if ((1<ca_state)&(TCPF_CA_CWR|TCPF_CA_Recovery)) return tp->snd_ssthresh; @@ -1072,7 +1058,7 @@ } /* Set slow start threshould and cwnd not falling to slow start */ -extern __inline__ void __tcp_enter_cwr(struct tcp_opt *tp) +static inline void __tcp_enter_cwr(struct tcp_opt *tp) { tp->undo_marker = 0; tp->snd_ssthresh = tcp_recalc_ssthresh(tp); @@ -1083,7 +1069,7 @@ TCP_ECN_queue_cwr(tp); } -extern __inline__ void tcp_enter_cwr(struct tcp_opt *tp) +static inline void tcp_enter_cwr(struct tcp_opt *tp) { tp->prior_ssthresh = 0; if (tp->ca_state < TCP_CA_CWR) { @@ -1307,6 +1293,8 @@ case TCP_CLOSE: sk->prot->unhash(sk); + if (sk->prev && !(sk->userlocks&SOCK_BINDPORT_LOCK)) + tcp_put_port(sk); /* fall through */ default: if (oldstate==TCP_ESTABLISHED) @@ -1378,7 +1366,7 @@ * MAX_SYN_SIZE to match the new maximum number of options that you * can generate. */ -extern __inline__ void tcp_syn_build_options(__u32 *ptr, int mss, int ts, int sack, +static inline void tcp_syn_build_options(__u32 *ptr, int mss, int ts, int sack, int offer_wscale, int wscale, __u32 tstamp, __u32 ts_recent) { /* We always get an MSS option. @@ -1418,7 +1406,7 @@ * be a multiple of mss if possible. We assume here that mss >= 1. * This MUST be enforced by all callers. */ -extern __inline__ void tcp_select_initial_window(int space, __u32 mss, +static inline void tcp_select_initial_window(int space, __u32 mss, __u32 *rcv_wnd, __u32 *window_clamp, int wscale_ok, @@ -1477,32 +1465,32 @@ } /* Note: caller must be prepared to deal with negative returns */ -extern __inline__ int tcp_space(struct sock *sk) +static inline int tcp_space(struct sock *sk) { return tcp_win_from_space(sk->rcvbuf - atomic_read(&sk->rmem_alloc)); } -extern __inline__ int tcp_full_space( struct sock *sk) +static inline int tcp_full_space( struct sock *sk) { return tcp_win_from_space(sk->rcvbuf); } -extern __inline__ void tcp_acceptq_removed(struct sock *sk) +static inline void tcp_acceptq_removed(struct sock *sk) { sk->ack_backlog--; } -extern __inline__ void tcp_acceptq_added(struct sock *sk) +static inline void tcp_acceptq_added(struct sock *sk) { sk->ack_backlog++; } -extern __inline__ int tcp_acceptq_is_full(struct sock *sk) +static inline int tcp_acceptq_is_full(struct sock *sk) { return sk->ack_backlog > sk->max_ack_backlog; } -extern __inline__ void tcp_acceptq_queue(struct sock *sk, struct open_request *req, +static inline void tcp_acceptq_queue(struct sock *sk, struct open_request *req, struct sock *child) { struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; @@ -1528,7 +1516,7 @@ struct open_request *syn_table[TCP_SYNQ_HSIZE]; }; -extern __inline__ void +static inline void tcp_synq_removed(struct sock *sk, struct open_request *req) { struct tcp_listen_opt *lopt = sk->tp_pinfo.af_tcp.listen_opt; @@ -1539,7 +1527,7 @@ lopt->qlen_young--; } -extern __inline__ void tcp_synq_added(struct sock *sk) +static inline void tcp_synq_added(struct sock *sk) { struct tcp_listen_opt *lopt = sk->tp_pinfo.af_tcp.listen_opt; @@ -1548,22 +1536,22 @@ lopt->qlen_young++; } -extern __inline__ int tcp_synq_len(struct sock *sk) +static inline int tcp_synq_len(struct sock *sk) { return sk->tp_pinfo.af_tcp.listen_opt->qlen; } -extern __inline__ int tcp_synq_young(struct sock *sk) +static inline int tcp_synq_young(struct sock *sk) { return sk->tp_pinfo.af_tcp.listen_opt->qlen_young; } -extern __inline__ int tcp_synq_is_full(struct sock *sk) +static inline int tcp_synq_is_full(struct sock *sk) { return tcp_synq_len(sk)>>sk->tp_pinfo.af_tcp.listen_opt->max_qlen_log; } -extern __inline__ void tcp_synq_unlink(struct tcp_opt *tp, struct open_request *req, +static inline void tcp_synq_unlink(struct tcp_opt *tp, struct open_request *req, struct open_request **prev) { write_lock(&tp->syn_wait_lock); @@ -1571,7 +1559,7 @@ write_unlock(&tp->syn_wait_lock); } -extern __inline__ void tcp_synq_drop(struct sock *sk, struct open_request *req, +static inline void tcp_synq_drop(struct sock *sk, struct open_request *req, struct open_request **prev) { tcp_synq_unlink(&sk->tp_pinfo.af_tcp, req, prev); @@ -1679,7 +1667,7 @@ * use plain read_(un)lock(&tcp_lhash_lock). */ -extern __inline__ void tcp_listen_lock(void) +static inline void tcp_listen_lock(void) { /* read_lock synchronizes to candidates to writers */ read_lock(&tcp_lhash_lock); @@ -1687,7 +1675,7 @@ read_unlock(&tcp_lhash_lock); } -extern __inline__ void tcp_listen_unlock(void) +static inline void tcp_listen_unlock(void) { if (atomic_dec_and_test(&tcp_lhash_users)) wake_up(&tcp_lhash_wait); diff -u --recursive --new-file v2.4.0-test8/linux/include/net/x25.h linux/include/net/x25.h --- v2.4.0-test8/linux/include/net/x25.h Fri Apr 14 09:37:20 2000 +++ linux/include/net/x25.h Sun Sep 17 10:03:43 2000 @@ -188,7 +188,7 @@ extern void x25_link_free(void); /* x25_out.c */ -extern void x25_output(struct sock *, struct sk_buff *); +extern int x25_output(struct sock *, struct sk_buff *); extern void x25_kick(struct sock *); extern void x25_enquiry_response(struct sock *); diff -u --recursive --new-file v2.4.0-test8/linux/include/pcmcia/ss.h linux/include/pcmcia/ss.h --- v2.4.0-test8/linux/include/pcmcia/ss.h Sat Sep 2 00:13:49 2000 +++ linux/include/pcmcia/ss.h Fri Sep 15 16:31:09 2000 @@ -82,6 +82,7 @@ #define SS_DMA_MODE 0x0080 #define SS_SPKR_ENA 0x0100 #define SS_OUTPUT_ENA 0x0200 +#define SS_DEBOUNCED 0x0400 /* Tell driver that the debounce delay has ended */ /* Flags for I/O port and memory windows */ #define MAP_ACTIVE 0x01 diff -u --recursive --new-file v2.4.0-test8/linux/include/scsi/scsi_ioctl.h linux/include/scsi/scsi_ioctl.h --- v2.4.0-test8/linux/include/scsi/scsi_ioctl.h Fri May 1 11:19:58 1998 +++ linux/include/scsi/scsi_ioctl.h Tue Sep 19 08:01:34 2000 @@ -32,6 +32,13 @@ __u32 host_unique_id; } Scsi_Idlun; +/* Fibre Channel WWN, port_id struct */ +typedef struct scsi_fctargaddress +{ + __u32 host_port_id; + unsigned char host_wwn[8]; // include NULL term. +} Scsi_FCTargAddress; + extern int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg); extern int kernel_scsi_ioctl (Scsi_Device *dev, int cmd, void *arg); extern int scsi_ioctl_send_command(Scsi_Device *dev, diff -u --recursive --new-file v2.4.0-test8/linux/include/scsi/sg.h linux/include/scsi/sg.h --- v2.4.0-test8/linux/include/scsi/sg.h Mon Jul 31 11:26:27 2000 +++ linux/include/scsi/sg.h Thu Sep 21 20:48:05 2000 @@ -11,9 +11,13 @@ Version 2 and 3 extensions to driver: * Copyright (C) 1998 - 2000 Douglas Gilbert - Version: 3.1.16 (20000716) - This version is for 2.3/2.4 series kernels. + Version: 3.1.17 (20000921) + This version is for 2.4 series kernels. + Changes since 3.1.16 (20000716) + - changes for new scsi subsystem initialization + - change Scsi_Cmnd usage to Scsi_Request + - cleanup for no procfs Changes since 3.1.15 (20000528) - further (scatter gather) buffer length changes Changes since 3.1.14 (20000503) diff -u --recursive --new-file v2.4.0-test8/linux/init/main.c linux/init/main.c --- v2.4.0-test8/linux/init/main.c Fri Sep 1 14:25:26 2000 +++ linux/init/main.c Fri Sep 22 14:11:21 2000 @@ -727,9 +727,6 @@ while (pid != wait(&i)); if (MAJOR(real_root_dev) != RAMDISK_MAJOR || MINOR(real_root_dev) != 0) { -#ifdef CONFIG_BLK_DEV_MD - md_run_setup(); -#endif error = change_root(real_root_dev,"/initrd"); if (error) printk(KERN_ERR "Change root to /initrd: " diff -u --recursive --new-file v2.4.0-test8/linux/init/version.c linux/init/version.c --- v2.4.0-test8/linux/init/version.c Mon Jan 5 01:41:01 1998 +++ linux/init/version.c Mon Oct 2 11:57:01 2000 @@ -14,7 +14,7 @@ #define version(a) Version_ ## a #define version_string(a) version(a) -int version_string(LINUX_VERSION_CODE) = 0; +int version_string(LINUX_VERSION_CODE); struct new_utsname system_utsname = { UTS_SYSNAME, UTS_NODENAME, UTS_RELEASE, UTS_VERSION, diff -u --recursive --new-file v2.4.0-test8/linux/ipc/shm.c linux/ipc/shm.c --- v2.4.0-test8/linux/ipc/shm.c Thu Sep 7 08:34:28 2000 +++ linux/ipc/shm.c Mon Sep 25 08:59:38 2000 @@ -206,7 +206,6 @@ /* some statistics */ static ulong swap_attempts; static ulong swap_successes; -static ulong used_segs; void __init shm_init (void) { @@ -364,7 +363,9 @@ buf->f_blocks = shm_ctlall; buf->f_bavail = buf->f_bfree = shm_ctlall - shm_tot; buf->f_files = shm_ctlmni; - buf->f_ffree = shm_ctlmni - used_segs; + shm_lockall(); + buf->f_ffree = shm_ctlmni - shm_ids.in_use + 1; + shm_unlockall(); buf->f_namelen = SHM_NAME_LEN; return 0; } @@ -593,7 +594,6 @@ if (doacc) { shm_lockall(); shm_tot += pages; - used_segs++; shm_unlockall(); } return ret; @@ -646,7 +646,6 @@ shm_rss -= rss; shm_swp -= swp; shm_tot -= pages; - used_segs--; shm_unlockall(); } } @@ -970,7 +969,7 @@ memset(&shm_info,0,sizeof(shm_info)); shm_lockall(); - shm_info.used_ids = shm_ids.in_use; + shm_info.used_ids = shm_ids.in_use - 1; /* correct the /dev/zero hack */ shm_info.shm_rss = shm_rss; shm_info.shm_tot = shm_tot; shm_info.shm_swp = shm_swp; @@ -1522,7 +1521,7 @@ } /* - * Goes through counter = (shm_rss / (prio + 1)) present shm pages. + * Goes through counter = (shm_rss >> prio) present shm pages. */ static unsigned long swap_id; /* currently being swapped */ static unsigned long swap_idx; /* next to swap */ @@ -1536,8 +1535,14 @@ int counter; struct page * page_map; + /* + * Push this inside: + */ + if (!(gfp_mask & __GFP_IO)) + return 0; + zshm_swap(prio, gfp_mask); - counter = shm_rss / (prio + 1); + counter = shm_rss >> prio; if (!counter) return 0; if (shm_swap_preop(&swap_entry)) @@ -1863,7 +1868,7 @@ int counter; struct page * page_map; - counter = zshm_rss / (prio + 1); + counter = zshm_rss >> prio; if (!counter) return; next: diff -u --recursive --new-file v2.4.0-test8/linux/kernel/exit.c linux/kernel/exit.c --- v2.4.0-test8/linux/kernel/exit.c Fri Sep 1 18:08:46 2000 +++ linux/kernel/exit.c Sun Sep 17 09:51:57 2000 @@ -229,6 +229,7 @@ { __exit_files(tsk); } + static inline void __put_fs_struct(struct fs_struct *fs) { /* No need to hold fs->lock if we are killing it */ diff -u --recursive --new-file v2.4.0-test8/linux/kernel/kmod.c linux/kernel/kmod.c --- v2.4.0-test8/linux/kernel/kmod.c Sat Aug 5 22:58:59 2000 +++ linux/kernel/kmod.c Mon Sep 25 16:18:55 2000 @@ -247,5 +247,44 @@ */ char hotplug_path[256] = "/sbin/hotplug"; + +static int exec_helper (void *arg) +{ + void **params = (void **) arg; + char *path = (char *) params [0]; + char **argv = (char **) params [1]; + char **envp = (char **) params [2]; + return exec_usermodehelper (path, argv, envp); +} + + +int call_usermodehelper (char *path, char **argv, char **envp) +{ + void *params [3] = { path, argv, envp }; + int pid, pid2, retval; + mm_segment_t fs; + + if ( ! current->fs->root ) { + printk(KERN_ERR "call_usermodehelper[%s]: no root fs\n", + path); + return -EPERM; + } + if ((pid = kernel_thread (exec_helper, (void *) params, 0)) < 0) { + printk(KERN_ERR "failed fork %s, errno = %d", argv [0], -pid); + return -1; + } + + fs = get_fs (); + set_fs (KERNEL_DS); + pid2 = waitpid (pid, &retval, __WCLONE); + set_fs (fs); + + if (pid2 != pid) { + printk(KERN_ERR "waitpid(%d) failed, %d\n", pid, pid2); + return -1; + } + return retval; +} + #endif diff -u --recursive --new-file v2.4.0-test8/linux/kernel/ksyms.c linux/kernel/ksyms.c --- v2.4.0-test8/linux/kernel/ksyms.c Tue Sep 5 18:56:47 2000 +++ linux/kernel/ksyms.c Mon Sep 25 16:18:55 2000 @@ -76,6 +76,7 @@ EXPORT_SYMBOL(exec_usermodehelper); #ifdef CONFIG_HOTPLUG EXPORT_SYMBOL(hotplug_path); +EXPORT_SYMBOL(call_usermodehelper); #endif #endif @@ -214,6 +215,9 @@ EXPORT_SYMBOL(page_hash_bits); EXPORT_SYMBOL(page_hash_table); EXPORT_SYMBOL(file_lock_list); +EXPORT_SYMBOL(file_lock_sem); +EXPORT_SYMBOL(locks_init_lock); +EXPORT_SYMBOL(locks_copy_lock); EXPORT_SYMBOL(posix_lock_file); EXPORT_SYMBOL(posix_test_lock); EXPORT_SYMBOL(posix_block_lock); @@ -253,6 +257,10 @@ EXPORT_SYMBOL(page_symlink_inode_operations); EXPORT_SYMBOL(block_symlink); EXPORT_SYMBOL(vfs_readdir); +EXPORT_SYMBOL(__get_lease); +EXPORT_SYMBOL(lease_get_mtime); +EXPORT_SYMBOL(lock_may_read); +EXPORT_SYMBOL(lock_may_write); EXPORT_SYMBOL(dcache_readdir); /* for stackable file systems (lofs, wrapfs, cryptfs, etc.) */ @@ -361,8 +369,6 @@ #if !defined(CONFIG_ARCH_S390) EXPORT_SYMBOL(probe_irq_on); EXPORT_SYMBOL(probe_irq_off); -EXPORT_SYMBOL(autoirq_setup); -EXPORT_SYMBOL(autoirq_report); #endif #ifdef CONFIG_SMP diff -u --recursive --new-file v2.4.0-test8/linux/kernel/sched.c linux/kernel/sched.c --- v2.4.0-test8/linux/kernel/sched.c Fri Sep 1 14:05:25 2000 +++ linux/kernel/sched.c Mon Oct 2 11:45:01 2000 @@ -141,61 +141,54 @@ int weight; /* - * Realtime process, select the first one on the - * runqueue (taking priorities within processes - * into account). + * select the current process after every other + * runnable process, but before the idle thread. + * Also, dont trigger a counter recalculation. */ - if (p->policy != SCHED_OTHER) { - weight = 1000 + p->rt_priority; + weight = -1; + if (p->policy & SCHED_YIELD) goto out; - } /* - * Give the process a first-approximation goodness value - * according to the number of clock-ticks it has left. - * - * Don't do any other calculations if the time slice is - * over.. + * Non-RT process - normal case first. */ - weight = p->counter; - if (!weight) - goto out; + if (p->policy == SCHED_OTHER) { + /* + * Give the process a first-approximation goodness value + * according to the number of clock-ticks it has left. + * + * Don't do any other calculations if the time slice is + * over.. + */ + weight = p->counter; + if (!weight) + goto out; #ifdef CONFIG_SMP - /* Give a largish advantage to the same processor... */ - /* (this is equivalent to penalizing other processors) */ - if (p->processor == this_cpu) - weight += PROC_CHANGE_PENALTY; + /* Give a largish advantage to the same processor... */ + /* (this is equivalent to penalizing other processors) */ + if (p->processor == this_cpu) + weight += PROC_CHANGE_PENALTY; #endif - /* .. and a slight advantage to the current MM */ - if (p->mm == this_mm || !p->mm) - weight += 1; - weight += 20 - p->nice; + /* .. and a slight advantage to the current MM */ + if (p->mm == this_mm || !p->mm) + weight += 1; + weight += 20 - p->nice; + goto out; + } + /* + * Realtime process, select the first one on the + * runqueue (taking priorities within processes + * into account). + */ + weight = 1000 + p->rt_priority; out: return weight; } /* - * subtle. We want to discard a yielded process only if it's being - * considered for a reschedule. Wakeup-time 'queries' of the scheduling - * state do not count. Another optimization we do: sched_yield()-ed - * processes are runnable (and thus will be considered for scheduling) - * right when they are calling schedule(). So the only place we need - * to care about SCHED_YIELD is when we calculate the previous process' - * goodness ... - */ -static inline int prev_goodness(struct task_struct * p, int this_cpu, struct mm_struct *this_mm) -{ - if (p->policy & SCHED_YIELD) { - p->policy &= ~SCHED_YIELD; - return 0; - } - return goodness(p, this_cpu, this_mm); -} - -/* * the 'goodness value' of replacing a process on a given CPU. * positive value means 'replace', zero or negative means 'dont'. */ @@ -451,6 +444,7 @@ static inline void __schedule_tail(struct task_struct *prev) { #ifdef CONFIG_SMP + int yield; unsigned long flags; /* @@ -462,6 +456,8 @@ * cache. */ spin_lock_irqsave(&runqueue_lock, flags); + yield = prev->policy & SCHED_YIELD; + prev->policy &= ~SCHED_YIELD; prev->has_cpu = 0; if (prev->state == TASK_RUNNING) goto running_again; @@ -476,9 +472,11 @@ * current process as well.) */ running_again: - if (prev != idle_task(smp_processor_id())) + if ((prev != idle_task(smp_processor_id())) && !yield) reschedule_idle(prev); goto out_unlock; +#else + prev->policy &= ~SCHED_YIELD; #endif /* CONFIG_SMP */ } @@ -669,7 +667,7 @@ goto repeat_schedule; still_running: - c = prev_goodness(prev, this_cpu, prev->active_mm); + c = goodness(prev, this_cpu, prev->active_mm); next = prev; goto still_running_back; @@ -1030,12 +1028,13 @@ asmlinkage long sys_sched_yield(void) { - spin_lock_irq(&runqueue_lock); + /* + * This process can only be rescheduled by us, + * so this is safe without any locking. + */ if (current->policy == SCHED_OTHER) current->policy |= SCHED_YIELD; current->need_resched = 1; - move_last_runqueue(current); - spin_unlock_irq(&runqueue_lock); return 0; } diff -u --recursive --new-file v2.4.0-test8/linux/kernel/signal.c linux/kernel/signal.c --- v2.4.0-test8/linux/kernel/signal.c Tue Sep 5 09:53:59 2000 +++ linux/kernel/signal.c Mon Sep 25 14:44:14 2000 @@ -41,7 +41,7 @@ __alignof__(struct sigqueue), SIG_SLAB_DEBUG, NULL, NULL); if (!sigqueue_cachep) - panic("signals_init(): cannot create sigueue SLAB cache"); + panic("signals_init(): cannot create sigqueue SLAB cache"); } @@ -191,6 +191,7 @@ /* Ok, it wasn't in the queue. We must have been out of queue space. So zero out the info. */ + sigdelset(&list->signal, sig); info->si_signo = sig; info->si_errno = 0; info->si_code = 0; @@ -939,25 +940,28 @@ spin_lock_irq(¤t->sigmask_lock); sig = dequeue_signal(&these, &info); if (!sig) { - /* None ready -- temporarily unblock those we're interested - in so that we'll be awakened when they arrive. */ - sigset_t oldblocked = current->blocked; - sigandsets(¤t->blocked, ¤t->blocked, &these); - recalc_sigpending(current); - spin_unlock_irq(¤t->sigmask_lock); - timeout = MAX_SCHEDULE_TIMEOUT; if (uts) timeout = (timespec_to_jiffies(&ts) + (ts.tv_sec || ts.tv_nsec)); - current->state = TASK_INTERRUPTIBLE; - timeout = schedule_timeout(timeout); - - spin_lock_irq(¤t->sigmask_lock); - sig = dequeue_signal(&these, &info); - current->blocked = oldblocked; - recalc_sigpending(current); + if (timeout) { + /* None ready -- temporarily unblock those we're + * interested while we are sleeping in so that we'll + * be awakened when they arrive. */ + sigset_t oldblocked = current->blocked; + sigandsets(¤t->blocked, ¤t->blocked, &these); + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + current->state = TASK_INTERRUPTIBLE; + timeout = schedule_timeout(timeout); + + spin_lock_irq(¤t->sigmask_lock); + sig = dequeue_signal(&these, &info); + current->blocked = oldblocked; + recalc_sigpending(current); + } } spin_unlock_irq(¤t->sigmask_lock); diff -u --recursive --new-file v2.4.0-test8/linux/kernel/softirq.c linux/kernel/softirq.c --- v2.4.0-test8/linux/kernel/softirq.c Sun Aug 6 12:42:21 2000 +++ linux/kernel/softirq.c Fri Sep 22 14:07:43 2000 @@ -44,7 +44,7 @@ irq_cpustat_t irq_stat[NR_CPUS]; #endif /* CONFIG_ARCH_S390 */ -static struct softirq_action softirq_vec[32]; +static struct softirq_action softirq_vec[32] __cacheline_aligned; asmlinkage void do_softirq() { @@ -140,6 +140,14 @@ clear_bit(TASKLET_STATE_SCHED, &t->state); t->func(t->data); + /* + * talklet_trylock() uses test_and_set_bit that imply + * an mb when it returns zero, thus we need the explicit + * mb only here: while closing the critical section. + */ +#ifdef CONFIG_SMP + smp_mb__before_clear_bit(); +#endif tasklet_unlock(t); continue; } diff -u --recursive --new-file v2.4.0-test8/linux/kernel/sys.c linux/kernel/sys.c --- v2.4.0-test8/linux/kernel/sys.c Wed Aug 9 18:59:17 2000 +++ linux/kernel/sys.c Mon Sep 11 08:48:53 2000 @@ -123,18 +123,15 @@ int ret=NOTIFY_DONE; struct notifier_block *nb = *n; - read_lock(¬ifier_lock); while(nb) { ret=nb->notifier_call(nb,val,v); if(ret&NOTIFY_STOP_MASK) { - read_unlock(¬ifier_lock); return ret; } nb=nb->next; } - read_unlock(¬ifier_lock); return ret; } diff -u --recursive --new-file v2.4.0-test8/linux/kernel/sysctl.c linux/kernel/sysctl.c --- v2.4.0-test8/linux/kernel/sysctl.c Mon Jul 31 19:36:11 2000 +++ linux/kernel/sysctl.c Fri Sep 22 14:21:22 2000 @@ -235,7 +235,7 @@ static ctl_table vm_table[] = { {VM_FREEPG, "freepages", - &freepages, sizeof(freepages_t), 0644, NULL, &proc_dointvec}, + &freepages, sizeof(freepages_t), 0444, NULL, &proc_dointvec}, {VM_BDFLUSH, "bdflush", &bdf_prm, 9*sizeof(int), 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec, NULL, &bdflush_min, &bdflush_max}, @@ -283,6 +283,12 @@ {FS_OVERFLOWGID, "overflowgid", &fs_overflowgid, sizeof(int), 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec, NULL, &minolduid, &maxolduid}, + {FS_LEASES, "leases-enable", &leases_enable, sizeof(int), + 0644, NULL, &proc_dointvec}, + {FS_DIR_NOTIFY, "dir-notify-enable", &dir_notify_enable, + sizeof(int), 0644, NULL, &proc_dointvec}, + {FS_LEASE_TIME, "lease-break-time", &lease_break_time, sizeof(int), + 0644, NULL, &proc_dointvec}, {0} }; diff -u --recursive --new-file v2.4.0-test8/linux/kernel/timer.c linux/kernel/timer.c --- v2.4.0-test8/linux/kernel/timer.c Mon Aug 28 14:28:27 2000 +++ linux/kernel/timer.c Sun Oct 1 19:55:17 2000 @@ -22,7 +22,6 @@ #include #include #include -#include #include @@ -596,9 +595,6 @@ kstat.per_cpu_system[cpu] += system; } else if (local_bh_count(cpu) || local_irq_count(cpu) > 1) kstat.per_cpu_system[cpu] += system; - - if (slab_cache_drain_mask & (1UL << cpu)) - slab_drain_local_cache(); } /* diff -u --recursive --new-file v2.4.0-test8/linux/mm/filemap.c linux/mm/filemap.c --- v2.4.0-test8/linux/mm/filemap.c Fri Sep 8 12:37:34 2000 +++ linux/mm/filemap.c Mon Oct 2 11:28:38 2000 @@ -44,9 +44,8 @@ atomic_t page_cache_size = ATOMIC_INIT(0); unsigned int page_hash_bits; struct page **page_hash_table; -struct list_head lru_cache; -static spinlock_t pagecache_lock = SPIN_LOCK_UNLOCKED; +spinlock_t pagecache_lock = SPIN_LOCK_UNLOCKED; /* * NOTE: to avoid deadlocking you must never acquire the pagecache_lock with * the pagemap_lru_lock held. @@ -92,7 +91,7 @@ * sure the page is locked and that nobody else uses it - or that usage * is safe. */ -static inline void __remove_inode_page(struct page *page) +void __remove_inode_page(struct page *page) { remove_page_from_inode_queue(page); remove_page_from_hash_queue(page); @@ -235,141 +234,6 @@ spin_unlock(&pagecache_lock); } -/* - * nr_dirty represents the number of dirty pages that we will write async - * before doing sync writes. We can only do sync writes if we can - * wait for IO (__GFP_IO set). - */ -int shrink_mmap(int priority, int gfp_mask) -{ - int ret = 0, count, nr_dirty; - struct list_head * page_lru; - struct page * page = NULL; - - count = nr_lru_pages / (priority + 1); - nr_dirty = priority; - - /* we need pagemap_lru_lock for list_del() ... subtle code below */ - spin_lock(&pagemap_lru_lock); - while (count > 0 && (page_lru = lru_cache.prev) != &lru_cache) { - page = list_entry(page_lru, struct page, lru); - list_del(page_lru); - - if (PageTestandClearReferenced(page)) - goto dispose_continue; - - count--; - /* - * Avoid unscalable SMP locking for pages we can - * immediate tell are untouchable.. - */ - if (!page->buffers && page_count(page) > 1) - goto dispose_continue; - - if (TryLockPage(page)) - goto dispose_continue; - - /* Release the pagemap_lru lock even if the page is not yet - queued in any lru queue since we have just locked down - the page so nobody else may SMP race with us running - a lru_cache_del() (lru_cache_del() always run with the - page locked down ;). */ - spin_unlock(&pagemap_lru_lock); - - /* avoid freeing the page while it's locked */ - page_cache_get(page); - - /* - * Is it a buffer page? Try to clean it up regardless - * of zone - it's old. - */ - if (page->buffers) { - int wait; - /* - * 0 - free it if can do so without IO - * 1 - start write-out of dirty buffers - * 2 - wait for locked buffers - */ - wait = (gfp_mask & __GFP_IO) ? (nr_dirty-- < 0) ? 2 : 1 : 0; - if (!try_to_free_buffers(page, wait)) - goto unlock_continue; - /* page was locked, inode can't go away under us */ - if (!page->mapping) { - atomic_dec(&buffermem_pages); - goto made_buffer_progress; - } - } - - /* Take the pagecache_lock spinlock held to avoid - other tasks to notice the page while we are looking at its - page count. If it's a pagecache-page we'll free it - in one atomic transaction after checking its page count. */ - spin_lock(&pagecache_lock); - - /* - * We can't free pages unless there's just one user - * (count == 2 because we added one ourselves above). - */ - if (page_count(page) != 2) - goto cache_unlock_continue; - - /* - * Is it a page swap page? If so, we want to - * drop it if it is no longer used, even if it - * were to be marked referenced.. - */ - if (PageSwapCache(page)) { - spin_unlock(&pagecache_lock); - __delete_from_swap_cache(page); - goto made_inode_progress; - } - - /* - * Page is from a zone we don't care about. - * Don't drop page cache entries in vain. - */ - if (page->zone->free_pages > page->zone->pages_high) - goto cache_unlock_continue; - - /* is it a page-cache page? */ - if (page->mapping) { - if (!PageDirty(page) && !pgcache_under_min()) { - __remove_inode_page(page); - spin_unlock(&pagecache_lock); - goto made_inode_progress; - } - goto cache_unlock_continue; - } - - printk(KERN_ERR "shrink_mmap: unknown LRU page!\n"); - -cache_unlock_continue: - spin_unlock(&pagecache_lock); -unlock_continue: - spin_lock(&pagemap_lru_lock); - UnlockPage(page); - page_cache_release(page); -dispose_continue: - list_add(page_lru, &lru_cache); - } - goto out; - -made_inode_progress: - page_cache_release(page); -made_buffer_progress: - UnlockPage(page); - page_cache_release(page); - ret = 1; - spin_lock(&pagemap_lru_lock); - /* nr_lru_pages needs the spinlock */ - nr_lru_pages--; - -out: - spin_unlock(&pagemap_lru_lock); - - return ret; -} - static inline struct page * __find_page_nolock(struct address_space *mapping, unsigned long offset, struct page *page) { goto inside; @@ -384,7 +248,14 @@ if (page->index == offset) break; } - SetPageReferenced(page); + /* + * Touching the page may move it to the active list. + * If we end up with too few inactive pages, we wake + * up kswapd. + */ + age_page_up(page); + if (inactive_shortage() > inactive_target / 2 && free_shortage()) + wakeup_kswapd(0); not_found: return page; } @@ -616,6 +487,7 @@ set_task_state(tsk, TASK_UNINTERRUPTIBLE); if (!PageLocked(page)) break; + run_task_queue(&tq_disk); schedule(); } while (PageLocked(page)); tsk->state = TASK_RUNNING; @@ -739,6 +611,53 @@ #endif /* + * We combine this with read-ahead to deactivate pages when we + * think there's sequential IO going on. Note that this is + * harmless since we don't actually evict the pages from memory + * but just move them to the inactive list. + * + * TODO: + * - make the readahead code smarter + * - move readahead to the VMA level so we can do the same + * trick with mmap() + * + * Rik van Riel, 2000 + */ +static void drop_behind(struct file * file, unsigned long index) +{ + struct inode *inode = file->f_dentry->d_inode; + struct address_space *mapping = inode->i_mapping; + struct page **hash; + struct page *page; + unsigned long start; + + /* Nothing to drop-behind if we're on the first page. */ + if (!index) + return; + + if (index > file->f_rawin) + start = index - file->f_rawin; + else + start = 0; + + /* + * Go backwards from index-1 and drop all pages in the + * readahead window. Since the readahead window may have + * been increased since the last time we were called, we + * stop when the page isn't there. + */ + spin_lock(&pagecache_lock); + while (--index >= start) { + hash = page_hash(mapping, index); + page = __find_page_nolock(mapping, index, *hash); + if (!page) + break; + deactivate_page(page); + } + spin_unlock(&pagecache_lock); +} + +/* * Read-ahead profiling information * -------------------------------- * Every PROFILE_MAXREADCOUNT, the following information is written @@ -961,6 +880,12 @@ if (filp->f_ramax > max_readahead) filp->f_ramax = max_readahead; + /* + * Move the pages that have already been passed + * to the inactive list. + */ + drop_behind(filp, index); + #ifdef PROFILE_READAHEAD profile_readahead((reada_ok == 2), filp); #endif @@ -1999,10 +1924,10 @@ * Application no longer needs these pages. If the pages are dirty, * it's OK to just throw them away. The app will be more careful about * data it wants to keep. Be sure to free swap resources too. The - * zap_page_range call sets things up for shrink_mmap to actually free + * zap_page_range call sets things up for refill_inactive to actually free * these pages later if no one else has touched them in the meantime, * although we could add these pages to a global reuse list for - * shrink_mmap to pick up before reclaiming other pages. + * refill_inactive to pick up before reclaiming other pages. * * NB: This interface discards data rather than pushes it out to swap, * as some implementations do. This has performance implications for @@ -2527,6 +2452,7 @@ unlock: /* Mark it unlocked again and drop the page.. */ UnlockPage(page); + deactivate_page(page); page_cache_release(page); if (status < 0) diff -u --recursive --new-file v2.4.0-test8/linux/mm/memory.c linux/mm/memory.c --- v2.4.0-test8/linux/mm/memory.c Fri Sep 1 13:51:10 2000 +++ linux/mm/memory.c Fri Sep 15 16:51:21 2000 @@ -67,7 +67,7 @@ copy_user_highpage(to, from, address); } -mem_map_t * mem_map = NULL; +mem_map_t * mem_map; /* * Note: this doesn't free the actual pages themselves. That @@ -1040,7 +1040,8 @@ num = valid_swaphandles(entry, &offset); for (i = 0; i < num; offset++, i++) { /* Don't block on I/O for read-ahead */ - if (atomic_read(&nr_async_pages) >= pager_daemon.swap_cluster) { + if (atomic_read(&nr_async_pages) >= pager_daemon.swap_cluster + * (1 << page_cluster)) { while (i++ < num) swap_free(SWP_ENTRY(SWP_TYPE(entry), offset++)); break; @@ -1239,7 +1240,7 @@ pgd = pgd_offset(mm, address); pmd = pmd_alloc(pgd, address); - + if (pmd) { pte_t * pte = pte_alloc(pmd, address); if (pte) diff -u --recursive --new-file v2.4.0-test8/linux/mm/mremap.c linux/mm/mremap.c --- v2.4.0-test8/linux/mm/mremap.c Mon Jun 19 13:45:51 2000 +++ linux/mm/mremap.c Thu Sep 28 13:54:32 2000 @@ -225,6 +225,10 @@ /* We can't remap across vm area boundaries */ if (old_len > vma->vm_end - addr) goto out; + if (vma->vm_flags & VM_DONTEXPAND) { + if (new_len > old_len) + goto out; + } if (vma->vm_flags & VM_LOCKED) { unsigned long locked = current->mm->locked_vm << PAGE_SHIFT; locked += new_len - old_len; diff -u --recursive --new-file v2.4.0-test8/linux/mm/page_alloc.c linux/mm/page_alloc.c --- v2.4.0-test8/linux/mm/page_alloc.c Thu Sep 7 08:44:50 2000 +++ linux/mm/page_alloc.c Mon Oct 2 12:02:20 2000 @@ -25,7 +25,8 @@ #endif int nr_swap_pages; -int nr_lru_pages; +int nr_active_pages; +int nr_inactive_dirty_pages; pg_data_t *pgdat_list; static char *zone_names[MAX_NR_ZONES] = { "DMA", "Normal", "HighMem" }; @@ -33,6 +34,8 @@ static int zone_balance_min[MAX_NR_ZONES] = { 10 , 10, 10, }; static int zone_balance_max[MAX_NR_ZONES] = { 255 , 255, 255, }; +struct list_head active_list; +struct list_head inactive_dirty_list; /* * Free_page() adds the page to the free lists. This is optimized for * fast normal cases (no error jumps taken normally). @@ -96,7 +99,16 @@ BUG(); if (PageDirty(page)) BUG(); + if (PageActive(page)) + BUG(); + if (PageInactiveDirty(page)) + BUG(); + if (PageInactiveClean(page)) + BUG(); + page->flags &= ~(1<age = PAGE_AGE_START; + zone = page->zone; mask = (~0UL) << order; @@ -142,10 +154,13 @@ spin_unlock_irqrestore(&zone->lock, flags); - if (zone->free_pages > zone->pages_high) { - zone->zone_wake_kswapd = 0; - zone->low_on_memory = 0; - } + /* + * We don't want to protect this variable from race conditions + * since it's nothing important, but we do want to make sure + * it never gets negative. + */ + if (memory_pressure > NR_CPUS) + memory_pressure--; } #define MARK_USED(index, order, area) \ @@ -203,6 +218,7 @@ set_page_count(page, 1); if (BAD_RANGE(zone,page)) BUG(); + DEBUG_ADD_PAGE return page; } curr_order++; @@ -213,13 +229,77 @@ return NULL; } +#define PAGES_MIN 0 +#define PAGES_LOW 1 +#define PAGES_HIGH 2 + +/* + * This function does the dirty work for __alloc_pages + * and is separated out to keep the code size smaller. + * (suggested by Davem at 1:30 AM, typed by Rik at 6 AM) + */ +static struct page * __alloc_pages_limit(zonelist_t *zonelist, + unsigned long order, int limit, int direct_reclaim) +{ + zone_t **zone = zonelist->zones; + + for (;;) { + zone_t *z = *(zone++); + unsigned long water_mark; + + if (!z) + break; + if (!z->size) + BUG(); + + /* + * We allocate if the number of free + inactive_clean + * pages is above the watermark. + */ + switch (limit) { + default: + case PAGES_MIN: + water_mark = z->pages_min; + break; + case PAGES_LOW: + water_mark = z->pages_low; + break; + case PAGES_HIGH: + water_mark = z->pages_high; + } + + if (z->free_pages + z->inactive_clean_pages > water_mark) { + struct page *page = NULL; + /* If possible, reclaim a page directly. */ + if (direct_reclaim && z->free_pages < z->pages_min + 8) + page = reclaim_page(z); + /* If that fails, fall back to rmqueue. */ + if (!page) + page = rmqueue(z, order); + if (page) + return page; + } + } + + /* Found nothing. */ + return NULL; +} + + /* * This is the 'heart' of the zoned buddy allocator: */ struct page * __alloc_pages(zonelist_t *zonelist, unsigned long order) { zone_t **zone; - extern wait_queue_head_t kswapd_wait; + int direct_reclaim = 0; + unsigned int gfp_mask = zonelist->gfp_mask; + struct page * page = NULL; + + /* + * Allocations put pressure on the VM subsystem. + */ + memory_pressure++; /* * (If anyone calls gfp from interrupts nonatomically then it @@ -229,6 +309,36 @@ * in a higher zone fails. */ + /* + * Can we take pages directly from the inactive_clean + * list? + */ + if (order == 0 && (gfp_mask & __GFP_WAIT) && + !(current->flags & PF_MEMALLOC)) + direct_reclaim = 1; + + /* + * If we are about to get low on free pages and we also have + * an inactive page shortage, wake up kswapd. + */ + if (inactive_shortage() > inactive_target / 2 && free_shortage()) + wakeup_kswapd(0); + /* + * If we are about to get low on free pages and cleaning + * the inactive_dirty pages would fix the situation, + * wake up bdflush. + */ + else if (free_shortage() && nr_inactive_dirty_pages > free_shortage() + && nr_inactive_dirty_pages > freepages.high) + wakeup_bdflush(0); + +try_again: + /* + * First, see if we have any zones with lots of free memory. + * + * We allocate free memory first because it doesn't contain + * any data ... DUH! + */ zone = zonelist->zones; for (;;) { zone_t *z = *(zone++); @@ -237,82 +347,193 @@ if (!z->size) BUG(); - /* Are we supposed to free memory? Don't make it worse.. */ - if (!z->zone_wake_kswapd) { - struct page *page = rmqueue(z, order); - if (z->free_pages < z->pages_low) { - z->zone_wake_kswapd = 1; - if (waitqueue_active(&kswapd_wait)) - wake_up_interruptible(&kswapd_wait); - } + if (z->free_pages > z->pages_low) { + page = rmqueue(z, order); if (page) return page; + } else if (z->free_pages < z->pages_min && + waitqueue_active(&kreclaimd_wait)) { + wake_up_interruptible(&kreclaimd_wait); } } - /* Three possibilities to get here - * - Previous alloc_pages resulted in last zone set to have - * zone_wake_kswapd and start it. kswapd has not been able - * to release enough pages so that one zone does not have - * zone_wake_kswapd set. - * - Different sets of zones (zonelist) - * previous did not have all zones with zone_wake_kswapd but - * this one has... should kswapd be woken up? it will run once. - * - SMP race, kswapd went to sleep slightly after it as running - * in 'if (waitqueue_active(...))' above. - * + anyway the test is very cheap to do... + /* + * Try to allocate a page from a zone with a HIGH + * amount of free + inactive_clean pages. + * + * If there is a lot of activity, inactive_target + * will be high and we'll have a good chance of + * finding a page using the HIGH limit. */ - if (waitqueue_active(&kswapd_wait)) - wake_up_interruptible(&kswapd_wait); + page = __alloc_pages_limit(zonelist, order, PAGES_HIGH, direct_reclaim); + if (page) + return page; /* - * Ok, we don't have any zones that don't need some - * balancing.. See if we have any that aren't critical.. + * Then try to allocate a page from a zone with more + * than zone->pages_low free + inactive_clean pages. + * + * When the working set is very large and VM activity + * is low, we're most likely to have our allocation + * succeed here. */ - zone = zonelist->zones; - for (;;) { - zone_t *z = *(zone++); - if (!z) - break; - if (!z->low_on_memory) { - struct page *page = rmqueue(z, order); - if (z->free_pages < z->pages_min) - z->low_on_memory = 1; - if (page) - return page; - } + page = __alloc_pages_limit(zonelist, order, PAGES_LOW, direct_reclaim); + if (page) + return page; + + /* + * OK, none of the zones on our zonelist has lots + * of pages free. + * + * We wake up kswapd, in the hope that kswapd will + * resolve this situation before memory gets tight. + * + * We also yield the CPU, because that: + * - gives kswapd a chance to do something + * - slows down allocations, in particular the + * allocations from the fast allocator that's + * causing the problems ... + * - ... which minimises the impact the "bad guys" + * have on the rest of the system + * - if we don't have __GFP_IO set, kswapd may be + * able to free some memory we can't free ourselves + */ + wakeup_kswapd(0); + if (gfp_mask & __GFP_WAIT) { + __set_current_state(TASK_RUNNING); + current->policy |= SCHED_YIELD; + schedule(); } /* - * Uhhuh. All the zones have been critical, which means that - * we'd better do some synchronous swap-out. kswapd has not - * been able to cope.. + * After waking up kswapd, we try to allocate a page + * from any zone which isn't critical yet. + * + * Kswapd should, in most situations, bring the situation + * back to normal in no time. + */ + page = __alloc_pages_limit(zonelist, order, PAGES_MIN, direct_reclaim); + if (page) + return page; + + /* + * Damn, we didn't succeed. + * + * This can be due to 2 reasons: + * - we're doing a higher-order allocation + * --> move pages to the free list until we succeed + * - we're /really/ tight on memory + * --> wait on the kswapd waitqueue until memory is freed */ if (!(current->flags & PF_MEMALLOC)) { - int gfp_mask = zonelist->gfp_mask; - if (!try_to_free_pages(gfp_mask)) { - if (!(gfp_mask & __GFP_HIGH)) - goto fail; + /* + * Are we dealing with a higher order allocation? + * + * Move pages from the inactive_clean to the free list + * in the hope of creating a large, physically contiguous + * piece of free memory. + */ + if (order > 0 && (gfp_mask & __GFP_WAIT)) { + zone = zonelist->zones; + /* First, clean some dirty pages. */ + page_launder(gfp_mask, 1); + for (;;) { + zone_t *z = *(zone++); + if (!z) + break; + if (!z->size) + continue; + while (z->inactive_clean_pages) { + struct page * page; + /* Move one page to the free list. */ + page = reclaim_page(z); + if (!page) + break; + __free_page(page); + /* Try if the allocation succeeds. */ + page = rmqueue(z, order); + if (page) + return page; + } + } + } + /* + * When we arrive here, we are really tight on memory. + * + * We wake up kswapd and sleep until kswapd wakes us + * up again. After that we loop back to the start. + * + * We have to do this because something else might eat + * the memory kswapd frees for us and we need to be + * reliable. Note that we don't loop back for higher + * order allocations since it is possible that kswapd + * simply cannot free a large enough contiguous area + * of memory *ever*. + */ + if ((gfp_mask & (__GFP_WAIT|__GFP_IO)) == (__GFP_WAIT|__GFP_IO)) { + wakeup_kswapd(1); + memory_pressure++; + if (!order) + goto try_again; + /* + * If __GFP_IO isn't set, we can't wait on kswapd because + * kswapd just might need some IO locks /we/ are holding ... + * + * SUBTLE: The scheduling point above makes sure that + * kswapd does get the chance to free memory we can't + * free ourselves... + */ + } else if (gfp_mask & __GFP_WAIT) { + try_to_free_pages(gfp_mask); + memory_pressure++; + if (!order) + goto try_again; } + } /* * Final phase: allocate anything we can! + * + * Higher order allocations, GFP_ATOMIC allocations and + * recursive allocations (PF_MEMALLOC) end up here. + * + * Only recursive allocations can use the very last pages + * in the system, otherwise it would be just too easy to + * deadlock the system... */ zone = zonelist->zones; for (;;) { - struct page *page; - zone_t *z = *(zone++); + struct page * page = NULL; if (!z) break; - page = rmqueue(z, order); + if (!z->size) + BUG(); + + /* + * SUBTLE: direct_reclaim is only possible if the task + * becomes PF_MEMALLOC while looping above. This will + * happen when the OOM killer selects this task for + * instant execution... + */ + if (direct_reclaim) + page = reclaim_page(z); + if (page) + return page; + + /* XXX: is pages_min/4 a good amount to reserve for this? */ + if (z->free_pages < z->pages_min / 4 && + !(current->flags & PF_MEMALLOC)) + continue; + if (!page) + page = rmqueue(z, order); if (page) return page; } -fail: /* No luck.. */ + printk(KERN_ERR "__alloc_pages: %lu-order allocation failed.\n", order); return NULL; } @@ -377,18 +598,46 @@ } /* - * Amount of free RAM allocatable as buffer memory: + * Total amount of inactive_clean (allocatable) RAM: */ -unsigned int nr_free_buffer_pages (void) +unsigned int nr_inactive_clean_pages (void) { unsigned int sum; zone_t *zone; int i; - sum = nr_lru_pages / 3; + sum = 0; for (i = 0; i < NUMNODES; i++) - for (zone = NODE_DATA(i)->node_zones; zone <= NODE_DATA(i)->node_zones+ZONE_NORMAL; zone++) - sum += zone->free_pages; + for (zone = NODE_DATA(i)->node_zones; zone < NODE_DATA(i)->node_zones + MAX_NR_ZONES; zone++) + sum += zone->inactive_clean_pages; + return sum; +} + +/* + * Amount of free RAM allocatable as buffer memory: + */ +unsigned int nr_free_buffer_pages (void) +{ + unsigned int sum; + + sum = nr_free_pages(); + sum += nr_inactive_clean_pages(); + sum += nr_inactive_dirty_pages; + + /* + * Keep our write behind queue filled, even if + * kswapd lags a bit right now. + */ + if (sum < freepages.high + inactive_target) + sum = freepages.high + inactive_target; + /* + * We don't want dirty page writebehind to put too + * much pressure on the working set, but we want it + * to be possible to have some dirty pages in the + * working set without upsetting the writebehind logic. + */ + sum += nr_active_pages >> 4; + return sum; } @@ -418,9 +667,11 @@ nr_free_pages() << (PAGE_SHIFT-10), nr_free_highpages() << (PAGE_SHIFT-10)); - printk("( Free: %d, lru_cache: %d (%d %d %d) )\n", + printk("( Active: %d, inactive_dirty: %d, inactive_clean: %d, free: %d (%d %d %d) )\n", + nr_active_pages, + nr_inactive_dirty_pages, + nr_inactive_clean_pages(), nr_free_pages(), - nr_lru_pages, freepages.min, freepages.low, freepages.high); @@ -430,17 +681,6 @@ zone_t *zone = NODE_DATA(nid)->node_zones + type; unsigned long nr, total, flags; - printk(" %c%d%d %s: ", - (zone->free_pages > zone->pages_low - ? (zone->free_pages > zone->pages_high - ? ' ' - : 'H') - : (zone->free_pages > zone->pages_min - ? 'M' - : 'L')), - zone->zone_wake_kswapd, zone->low_on_memory, - zone->name); - total = 0; if (zone->size) { spin_lock_irqsave(&zone->lock, flags); @@ -570,7 +810,8 @@ freepages.min += i; freepages.low += i * 2; freepages.high += i * 3; - memlist_init(&lru_cache); + memlist_init(&active_list); + memlist_init(&inactive_dirty_list); /* * Some architectures (with lots of mem and discontinous memory @@ -618,6 +859,9 @@ zone->lock = SPIN_LOCK_UNLOCKED; zone->zone_pgdat = pgdat; zone->free_pages = 0; + zone->inactive_clean_pages = 0; + zone->inactive_dirty_pages = 0; + memlist_init(&zone->inactive_clean_list); if (!size) continue; @@ -631,8 +875,6 @@ zone->pages_min = mask; zone->pages_low = mask*2; zone->pages_high = mask*3; - zone->low_on_memory = 0; - zone->zone_wake_kswapd = 0; zone->zone_mem_map = mem_map + offset; zone->zone_start_mapnr = offset; zone->zone_start_paddr = zone_start_paddr; diff -u --recursive --new-file v2.4.0-test8/linux/mm/page_io.c linux/mm/page_io.c --- v2.4.0-test8/linux/mm/page_io.c Mon Aug 7 21:01:36 2000 +++ linux/mm/page_io.c Fri Sep 15 16:51:21 2000 @@ -43,7 +43,8 @@ struct inode *swapf = 0; /* Don't allow too many pending pages in flight.. */ - if (atomic_read(&nr_async_pages) > pager_daemon.swap_cluster) + if ((rw == WRITE) && atomic_read(&nr_async_pages) > + pager_daemon.swap_cluster * (1 << page_cluster)) wait = 1; if (rw == READ) { diff -u --recursive --new-file v2.4.0-test8/linux/mm/slab.c linux/mm/slab.c --- v2.4.0-test8/linux/mm/slab.c Fri Aug 11 15:04:54 2000 +++ linux/mm/slab.c Sun Oct 1 19:55:17 2000 @@ -579,7 +579,6 @@ kmem_cache_free(cachep->slabp_cache, slabp); } - /** * kmem_cache_create - Create a cache. * @name: A string which is used in /proc/slabinfo to identify this cache. @@ -838,48 +837,60 @@ } #ifdef CONFIG_SMP -static DECLARE_MUTEX(cache_drain_sem); -static kmem_cache_t *cache_to_drain = NULL; -static DECLARE_WAIT_QUEUE_HEAD(cache_drain_wait); -unsigned long slab_cache_drain_mask; - /* - * Waits for all CPUs to execute slab_drain_local_cache(). - * Caller must be holding cache_drain_sem. + * Waits for all CPUs to execute func(). */ -static void slab_drain_all_sync(void) +static void smp_call_function_all_cpus(void (*func) (void *arg), void *arg) { - DECLARE_WAITQUEUE(wait, current); - local_irq_disable(); - slab_drain_local_cache(); + func(arg); local_irq_enable(); - add_wait_queue(&cache_drain_wait, &wait); - current->state = TASK_UNINTERRUPTIBLE; - while (slab_cache_drain_mask != 0UL) - schedule(); - current->state = TASK_RUNNING; - remove_wait_queue(&cache_drain_wait, &wait); + if (smp_call_function(func, arg, 1, 1)) + BUG(); +} +typedef struct ccupdate_struct_s +{ + kmem_cache_t *cachep; + cpucache_t *new[NR_CPUS]; +} ccupdate_struct_t; + +static void do_ccupdate_local(void *info) +{ + ccupdate_struct_t *new = (ccupdate_struct_t *)info; + cpucache_t *old = cc_data(new->cachep); + + cc_data(new->cachep) = new->new[smp_processor_id()]; + new->new[smp_processor_id()] = old; } +static void free_block (kmem_cache_t* cachep, void** objpp, int len); + static void drain_cpu_caches(kmem_cache_t *cachep) { - unsigned long cpu_mask = 0; + ccupdate_struct_t new; int i; - for (i = 0; i < smp_num_cpus; i++) - cpu_mask |= (1UL << cpu_logical_map(i)); + memset(&new.new,0,sizeof(new.new)); - down(&cache_drain_sem); + new.cachep = cachep; - cache_to_drain = cachep; - slab_cache_drain_mask = cpu_mask; - slab_drain_all_sync(); - cache_to_drain = NULL; + down(&cache_chain_sem); + smp_call_function_all_cpus(do_ccupdate_local, (void *)&new); - up(&cache_drain_sem); + for (i = 0; i < smp_num_cpus; i++) { + cpucache_t* ccold = new.new[cpu_logical_map(i)]; + if (!ccold || (ccold->avail == 0)) + continue; + local_irq_disable(); + free_block(cachep, cc_entry(ccold), ccold->avail); + local_irq_enable(); + ccold->avail = 0; + } + smp_call_function_all_cpus(do_ccupdate_local, (void *)&new); + up(&cache_chain_sem); } + #else #define drain_cpu_caches(cachep) do { } while (0) #endif @@ -1593,56 +1604,6 @@ #ifdef CONFIG_SMP -typedef struct ccupdate_struct_s -{ - kmem_cache_t *cachep; - cpucache_t *new[NR_CPUS]; -} ccupdate_struct_t; - -static ccupdate_struct_t *ccupdate_state = NULL; - -/* Called from per-cpu timer interrupt. */ -void slab_drain_local_cache(void) -{ - if (ccupdate_state != NULL) { - ccupdate_struct_t *new = ccupdate_state; - cpucache_t *old = cc_data(new->cachep); - - cc_data(new->cachep) = new->new[smp_processor_id()]; - new->new[smp_processor_id()] = old; - } else { - kmem_cache_t *cachep = cache_to_drain; - cpucache_t *cc = cc_data(cachep); - - if (cc && cc->avail) { - free_block(cachep, cc_entry(cc), cc->avail); - cc->avail = 0; - } - } - - clear_bit(smp_processor_id(), &slab_cache_drain_mask); - if (slab_cache_drain_mask == 0) - wake_up(&cache_drain_wait); -} - -static void do_ccupdate(ccupdate_struct_t *data) -{ - unsigned long cpu_mask = 0; - int i; - - for (i = 0; i < smp_num_cpus; i++) - cpu_mask |= (1UL << cpu_logical_map(i)); - - down(&cache_drain_sem); - - ccupdate_state = data; - slab_cache_drain_mask = cpu_mask; - slab_drain_all_sync(); - ccupdate_state = NULL; - - up(&cache_drain_sem); -} - /* called with cache_chain_sem acquired. */ static int kmem_tune_cpucache (kmem_cache_t* cachep, int limit, int batchcount) { @@ -1666,7 +1627,6 @@ for (i = 0; i< smp_num_cpus; i++) { cpucache_t* ccnew; - ccnew = kmalloc(sizeof(void*)*limit+ sizeof(cpucache_t), GFP_KERNEL); if (!ccnew) @@ -1681,7 +1641,7 @@ cachep->batchcount = batchcount; spin_unlock_irq(&cachep->spinlock); - do_ccupdate(&new); + smp_call_function_all_cpus(do_ccupdate_local, (void *)&new); for (i = 0; i < smp_num_cpus; i++) { cpucache_t* ccold = new.new[cpu_logical_map(i)]; @@ -1772,14 +1732,6 @@ /* It's safe to test this without holding the cache-lock. */ if (searchp->flags & SLAB_NO_REAP) goto next; - /* FIXME: is this really a good idea? */ - if (gfp_mask & GFP_DMA) { - if (!(searchp->gfpflags & GFP_DMA)) - goto next; - } else { - if (searchp->gfpflags & GFP_DMA) - goto next; - } spin_lock_irq(&searchp->spinlock); if (searchp->growing) goto next_unlock; diff -u --recursive --new-file v2.4.0-test8/linux/mm/swap.c linux/mm/swap.c --- v2.4.0-test8/linux/mm/swap.c Mon Dec 6 10:14:13 1999 +++ linux/mm/swap.c Mon Oct 2 11:28:38 2000 @@ -40,7 +40,18 @@ }; /* How many pages do we try to swap or page in/out together? */ -int page_cluster = 4; /* Default value modified in swap_setup() */ +int page_cluster; + +/* + * This variable contains the amount of page steals the system + * is doing, averaged over a minute. We use this to determine how + * many inactive pages we should have. + * + * In reclaim_page and __alloc_pages: memory_pressure++ + * In __free_pages_ok: memory_pressure-- + * In recalculate_vm_stats the value is decayed (once a second) + */ +int memory_pressure; /* We track the number of pages currently being asynchronously swapped out, so that we don't try to swap TOO many pages out at once */ @@ -61,13 +72,250 @@ pager_daemon_t pager_daemon = { 512, /* base number for calculating the number of tries */ SWAP_CLUSTER_MAX, /* minimum number of tries */ - SWAP_CLUSTER_MAX, /* do swap I/O in clusters of this size */ + 8, /* do swap I/O in clusters of this size */ }; +/** + * age_page_{up,down} - page aging helper functions + * @page - the page we want to age + * @nolock - are we already holding the pagelist_lru_lock? + * + * If the page is on one of the lists (active, inactive_dirty or + * inactive_clean), we will grab the pagelist_lru_lock as needed. + * If you're already holding the lock, call this function with the + * nolock argument non-zero. + */ +void age_page_up_nolock(struct page * page) +{ + /* + * We're dealing with an inactive page, move the page + * to the active list. + */ + if (!page->age) + activate_page_nolock(page); + + /* The actual page aging bit */ + page->age += PAGE_AGE_ADV; + if (page->age > PAGE_AGE_MAX) + page->age = PAGE_AGE_MAX; +} + /* - * Perform any setup for the swap system + * We use this (minimal) function in the case where we + * know we can't deactivate the page (yet). + */ +void age_page_down_ageonly(struct page * page) +{ + page->age /= 2; +} + +void age_page_down_nolock(struct page * page) +{ + /* The actual page aging bit */ + page->age /= 2; + + /* + * The page is now an old page. Move to the inactive + * list (if possible ... see below). + */ + if (!page->age) + deactivate_page_nolock(page); +} + +void age_page_up(struct page * page) +{ + /* + * We're dealing with an inactive page, move the page + * to the active list. + */ + if (!page->age) + activate_page(page); + + /* The actual page aging bit */ + page->age += PAGE_AGE_ADV; + if (page->age > PAGE_AGE_MAX) + page->age = PAGE_AGE_MAX; +} + +void age_page_down(struct page * page) +{ + /* The actual page aging bit */ + page->age /= 2; + + /* + * The page is now an old page. Move to the inactive + * list (if possible ... see below). + */ + if (!page->age) + deactivate_page(page); +} + + +/** + * (de)activate_page - move pages from/to active and inactive lists + * @page: the page we want to move + * @nolock - are we already holding the pagemap_lru_lock? + * + * Deactivate_page will move an active page to the right + * inactive list, while activate_page will move a page back + * from one of the inactive lists to the active list. If + * called on a page which is not on any of the lists, the + * page is left alone. */ +void deactivate_page_nolock(struct page * page) +{ + /* + * One for the cache, one for the extra reference the + * caller has and (maybe) one for the buffers. + * + * This isn't perfect, but works for just about everything. + * Besides, as long as we don't move unfreeable pages to the + * inactive_clean list it doesn't need to be perfect... + */ + int maxcount = (page->buffers ? 3 : 2); + page->age = 0; + + /* + * Don't touch it if it's not on the active list. + * (some pages aren't on any list at all) + */ + if (PageActive(page) && page_count(page) <= maxcount && + !page_ramdisk(page)) { + + /* + * We can move the page to the inactive_dirty list + * if we have the strong suspicion that they might + * become freeable in the near future. + * + * That is, the page has buffer heads attached (that + * need to be cleared away) and/or the function calling + * us has an extra reference count on the page. + */ + if (page->buffers || page_count(page) == 2) { + del_page_from_active_list(page); + add_page_to_inactive_dirty_list(page); + /* + * Only if we are SURE the page is clean and immediately + * reusable, we move it to the inactive_clean list. + */ + } else if (page->mapping && !PageDirty(page) && + !PageLocked(page)) { + del_page_from_active_list(page); + add_page_to_inactive_clean_list(page); + } + /* + * OK, we cannot free the page. Leave it alone. + */ + } +} +void deactivate_page(struct page * page) +{ + spin_lock(&pagemap_lru_lock); + deactivate_page_nolock(page); + spin_unlock(&pagemap_lru_lock); +} + +/* + * Move an inactive page to the active list. + */ +void activate_page_nolock(struct page * page) +{ + if (PageInactiveDirty(page)) { + del_page_from_inactive_dirty_list(page); + add_page_to_active_list(page); + } else if (PageInactiveClean(page)) { + del_page_from_inactive_clean_list(page); + add_page_to_active_list(page); + } else { + /* + * The page was not on any list, so we take care + * not to do anything. + */ + } + + /* Make sure the page gets a fair chance at staying active. */ + if (page->age < PAGE_AGE_START) + page->age = PAGE_AGE_START; +} + +void activate_page(struct page * page) +{ + spin_lock(&pagemap_lru_lock); + activate_page_nolock(page); + spin_unlock(&pagemap_lru_lock); +} + +/** + * lru_cache_add: add a page to the page lists + * @page: the page to add + */ +void lru_cache_add(struct page * page) +{ + spin_lock(&pagemap_lru_lock); + if (!PageLocked(page)) + BUG(); + DEBUG_ADD_PAGE + add_page_to_active_list(page); + /* This should be relatively rare */ + if (!page->age) + deactivate_page_nolock(page); + spin_unlock(&pagemap_lru_lock); +} + +/** + * __lru_cache_del: remove a page from the page lists + * @page: the page to add + * + * This function is for when the caller already holds + * the pagemap_lru_lock. + */ +void __lru_cache_del(struct page * page) +{ + if (PageActive(page)) { + del_page_from_active_list(page); + } else if (PageInactiveDirty(page)) { + del_page_from_inactive_dirty_list(page); + } else if (PageInactiveClean(page)) { + del_page_from_inactive_clean_list(page); + } else { + printk("VM: __lru_cache_del, found unknown page ?!\n"); + } + DEBUG_ADD_PAGE +} + +/** + * lru_cache_del: remove a page from the page lists + * @page: the page to remove + */ +void lru_cache_del(struct page * page) +{ + if (!PageLocked(page)) + BUG(); + spin_lock(&pagemap_lru_lock); + __lru_cache_del(page); + spin_unlock(&pagemap_lru_lock); +} + +/** + * recalculate_vm_stats - recalculate VM statistics + * + * This function should be called once a second to recalculate + * some useful statistics the VM subsystem uses to determine + * its behaviour. + */ +void recalculate_vm_stats(void) +{ + /* + * Substract one second worth of memory_pressure from + * memory_pressure. + */ + memory_pressure -= (memory_pressure >> INACTIVE_SHIFT); +} + +/* + * Perform any setup for the swap system + */ void __init swap_setup(void) { /* Use a smaller cluster for memory <16MB or <32MB */ diff -u --recursive --new-file v2.4.0-test8/linux/mm/swap_state.c linux/mm/swap_state.c --- v2.4.0-test8/linux/mm/swap_state.c Mon Aug 7 21:01:36 2000 +++ linux/mm/swap_state.c Sun Sep 24 12:36:46 2000 @@ -73,7 +73,7 @@ PAGE_BUG(page); PageClearSwapCache(page); - remove_inode_page(page); + __remove_inode_page(page); } /* @@ -105,7 +105,9 @@ if (block_flushpage(page, 0)) lru_cache_del(page); + spin_lock(&pagecache_lock); __delete_from_swap_cache(page); + spin_unlock(&pagecache_lock); page_cache_release(page); } @@ -164,7 +166,7 @@ return 0; /* * Though the "found" page was in the swap cache an instant - * earlier, it might have been removed by shrink_mmap etc. + * earlier, it might have been removed by refill_inactive etc. * Re search ... Since find_lock_page grabs a reference on * the page, it can not be reused for anything else, namely * it can not be associated with another swaphandle, so it diff -u --recursive --new-file v2.4.0-test8/linux/mm/vmalloc.c linux/mm/vmalloc.c --- v2.4.0-test8/linux/mm/vmalloc.c Mon Aug 7 21:01:36 2000 +++ linux/mm/vmalloc.c Sun Oct 1 20:35:16 2000 @@ -14,7 +14,7 @@ #include rwlock_t vmlist_lock = RW_LOCK_UNLOCKED; -struct vm_struct * vmlist = NULL; +struct vm_struct * vmlist; static inline void free_area_pte(pmd_t * pmd, unsigned long address, unsigned long size) { diff -u --recursive --new-file v2.4.0-test8/linux/mm/vmscan.c linux/mm/vmscan.c --- v2.4.0-test8/linux/mm/vmscan.c Fri Sep 1 14:25:26 2000 +++ linux/mm/vmscan.c Mon Oct 2 12:02:20 2000 @@ -9,6 +9,7 @@ * to bring the system back to freepages.high: 2.4.97, Rik van Riel. * Version: $Id: vmscan.c,v 1.5 1998/02/23 22:14:28 sct Exp $ * Zone aware kswapd started 02/00, Kanoj Sarcar (kanoj@sgi.com). + * Multiqueue VM started 5.8.00, Rik van Riel. */ #include @@ -40,6 +41,7 @@ swp_entry_t entry; struct page * page; int (*swapout)(struct page *, struct file *); + int onlist; pte = *page_table; if (!pte_present(pte)) @@ -51,16 +53,37 @@ if (mm->swap_cnt) mm->swap_cnt--; + onlist = PageActive(page); /* Don't look at this pte if it's been accessed recently. */ if (pte_young(pte)) { - /* - * Transfer the "accessed" bit from the page - * tables to the global page map. - */ set_pte(page_table, pte_mkold(pte)); - SetPageReferenced(page); + if (onlist) { + /* + * Transfer the "accessed" bit from the page + * tables to the global page map. Page aging + * will be done by refill_inactive_scan(). + */ + SetPageReferenced(page); + } else { + /* + * The page is not on the active list, so + * we have to do the page aging ourselves. + */ + age_page_up(page); + } goto out_failed; } + if (!onlist) + /* The page is still mapped, so it can't be freeable... */ + age_page_down_ageonly(page); + + /* + * If the page is in active use by us, or if the page + * is in active use by others, don't unmap it or + * (worse) start unneeded IO. + */ + if (page->age > 0) + goto out_failed; if (TryLockPage(page)) goto out_failed; @@ -79,8 +102,9 @@ set_pte(page_table, swp_entry_to_pte(entry)); drop_pte: UnlockPage(page); - vma->vm_mm->rss--; + mm->rss--; flush_tlb_page(vma, address); + deactivate_page(page); page_cache_release(page); goto out_failed; } @@ -96,7 +120,7 @@ * our scan. * * Basically, this just makes it possible for us to do - * some real work in the future in "shrink_mmap()". + * some real work in the future in "refill_inactive()". */ if (!pte_dirty(pte)) { flush_cache_page(vma, address); @@ -116,7 +140,9 @@ * Don't do any of the expensive stuff if * we're not really interested in this zone. */ - if (page->zone->free_pages > page->zone->pages_high) + if (page->zone->free_pages + page->zone->inactive_clean_pages + + page->zone->inactive_dirty_pages + > page->zone->pages_high + inactive_target) goto out_unlock; /* @@ -134,7 +160,7 @@ * NOTE NOTE NOTE! This should just set a * dirty bit in 'page', and just drop the * pte. All the hard work would be done by - * shrink_mmap(). + * refill_inactive(). * * That would get rid of a lot of problems. */ @@ -144,14 +170,15 @@ struct file *file = vma->vm_file; if (file) get_file(file); pte_clear(page_table); - vma->vm_mm->rss--; + mm->rss--; flush_tlb_page(vma, address); - vmlist_access_unlock(vma->vm_mm); + vmlist_access_unlock(mm); error = swapout(page, file); UnlockPage(page); if (file) fput(file); if (!error) goto out_free_success; + deactivate_page(page); page_cache_release(page); return error; } @@ -175,13 +202,14 @@ add_to_swap_cache(page, entry); /* Put the swap entry into the pte after the page is in swapcache */ - vma->vm_mm->rss--; + mm->rss--; set_pte(page_table, swp_entry_to_pte(entry)); flush_tlb_page(vma, address); - vmlist_access_unlock(vma->vm_mm); + vmlist_access_unlock(mm); /* OK, do a physical asynchronous write to swap. */ rw_swap_page(WRITE, page, 0); + deactivate_page(page); out_free_success: page_cache_release(page); @@ -230,7 +258,7 @@ do { int result; - vma->vm_mm->swap_address = address + PAGE_SIZE; + mm->swap_address = address + PAGE_SIZE; result = try_to_swap_out(mm, vma, address, pte, gfp_mask); if (result) return result; @@ -282,7 +310,7 @@ if (vma->vm_flags & VM_LOCKED) return 0; - pgdir = pgd_offset(vma->vm_mm, address); + pgdir = pgd_offset(mm, address); end = vma->vm_end; if (address >= end) @@ -323,17 +351,22 @@ int result = swap_out_vma(mm, vma, address, gfp_mask); if (result) return result; + if (!mm->swap_cnt) + goto out_unlock; vma = vma->vm_next; if (!vma) break; address = vma->vm_start; } } + /* Reset to 0 when we reach the end of address space */ + mm->swap_address = 0; + mm->swap_cnt = 0; + +out_unlock: vmlist_access_unlock(mm); /* We didn't find anything for the process */ - mm->swap_cnt = 0; - mm->swap_address = 0; return 0; } @@ -342,7 +375,10 @@ * N.B. This function returns only 0 or 1. Return values != 1 from * the lower level routines result in continued processing. */ -static int swap_out(unsigned int priority, int gfp_mask) +#define SWAP_SHIFT 5 +#define SWAP_MIN 8 + +static int swap_out(unsigned int priority, int gfp_mask, unsigned long idle_time) { struct task_struct * p; int counter; @@ -363,7 +399,7 @@ * Think of swap_cnt as a "shadow rss" - it tells us which process * we want to page out (always try largest first). */ - counter = (nr_threads << 2) >> (priority >> 2); + counter = (nr_threads << SWAP_SHIFT) >> priority; if (counter < 1) counter = 1; @@ -372,6 +408,7 @@ struct mm_struct *best = NULL; int pid = 0; int assign = 0; + int found_task = 0; select: read_lock(&tasklist_lock); p = init_task.next_task; @@ -381,9 +418,17 @@ continue; if (mm->rss <= 0) continue; + /* Skip tasks which haven't slept long enough yet when idle-swapping. */ + if (idle_time && !assign && (!(p->state & TASK_INTERRUPTIBLE) || + time_after(p->sleep_time + idle_time * HZ, jiffies))) + continue; + found_task++; /* Refresh swap_cnt? */ - if (assign == 1) - mm->swap_cnt = mm->rss; + if (assign == 1) { + mm->swap_cnt = (mm->rss >> SWAP_SHIFT); + if (mm->swap_cnt < SWAP_MIN) + mm->swap_cnt = SWAP_MIN; + } if (mm->swap_cnt > max_cnt) { max_cnt = mm->swap_cnt; best = mm; @@ -392,7 +437,7 @@ } read_unlock(&tasklist_lock); if (!best) { - if (!assign) { + if (!assign && found_task > 0) { assign = 1; goto select; } @@ -418,50 +463,409 @@ return __ret; } -/* - * Check if there is any memory pressure (free_pages < pages_low) + +/** + * reclaim_page - reclaims one page from the inactive_clean list + * @zone: reclaim a page from this zone + * + * The pages on the inactive_clean can be instantly reclaimed. + * The tests look impressive, but most of the time we'll grab + * the first page of the list and exit successfully. */ -static inline int memory_pressure(void) +struct page * reclaim_page(zone_t * zone) { - pg_data_t *pgdat = pgdat_list; + struct page * page = NULL; + struct list_head * page_lru; + int maxscan; - do { - int i; - for(i = 0; i < MAX_NR_ZONES; i++) { - zone_t *zone = pgdat->node_zones+ i; - if (zone->size && - zone->free_pages < zone->pages_low) - return 1; + /* + * We only need the pagemap_lru_lock if we don't reclaim the page, + * but we have to grab the pagecache_lock before the pagemap_lru_lock + * to avoid deadlocks and most of the time we'll succeed anyway. + */ + spin_lock(&pagecache_lock); + spin_lock(&pagemap_lru_lock); + maxscan = zone->inactive_clean_pages; + while ((page_lru = zone->inactive_clean_list.prev) != + &zone->inactive_clean_list && maxscan--) { + page = list_entry(page_lru, struct page, lru); + + /* Wrong page on list?! (list corruption, should not happen) */ + if (!PageInactiveClean(page)) { + printk("VM: reclaim_page, wrong page on list.\n"); + list_del(page_lru); + page->zone->inactive_clean_pages--; + continue; } - pgdat = pgdat->node_next; - } while (pgdat); - return 0; + /* Page is or was in use? Move it to the active list. */ + if (PageTestandClearReferenced(page) || page->age > 0 || + (!page->buffers && page_count(page) > 1)) { + del_page_from_inactive_clean_list(page); + add_page_to_active_list(page); + continue; + } + + /* The page is dirty, or locked, move to inactive_diry list. */ + if (page->buffers || TryLockPage(page)) { + del_page_from_inactive_clean_list(page); + add_page_to_inactive_dirty_list(page); + continue; + } + + /* OK, remove the page from the caches. */ + if (PageSwapCache(page)) { + __delete_from_swap_cache(page); + goto found_page; + } + + if (page->mapping) { + __remove_inode_page(page); + goto found_page; + } + + /* We should never ever get here. */ + printk(KERN_ERR "VM: reclaim_page, found unknown page\n"); + list_del(page_lru); + zone->inactive_clean_pages--; + UnlockPage(page); + } + /* Reset page pointer, maybe we encountered an unfreeable page. */ + page = NULL; + goto out; + +found_page: + del_page_from_inactive_clean_list(page); + UnlockPage(page); + page->age = PAGE_AGE_START; + if (page_count(page) != 1) + printk("VM: reclaim_page, found page with count %d!\n", + page_count(page)); +out: + spin_unlock(&pagemap_lru_lock); + spin_unlock(&pagecache_lock); + memory_pressure++; + return page; +} + +/** + * page_launder - clean dirty inactive pages, move to inactive_clean list + * @gfp_mask: what operations we are allowed to do + * @sync: should we wait synchronously for the cleaning of pages + * + * When this function is called, we are most likely low on free + + * inactive_clean pages. Since we want to refill those pages as + * soon as possible, we'll make two loops over the inactive list, + * one to move the already cleaned pages to the inactive_clean lists + * and one to (often asynchronously) clean the dirty inactive pages. + * + * In situations where kswapd cannot keep up, user processes will + * end up calling this function. Since the user process needs to + * have a page before it can continue with its allocation, we'll + * do synchronous page flushing in that case. + * + * This code is heavily inspired by the FreeBSD source code. Thanks + * go out to Matthew Dillon. + */ +#define MAX_LAUNDER (4 * (1 << page_cluster)) +int page_launder(int gfp_mask, int sync) +{ + int launder_loop, maxscan, cleaned_pages, maxlaunder; + int can_get_io_locks; + struct list_head * page_lru; + struct page * page; + + /* + * We can only grab the IO locks (eg. for flushing dirty + * buffers to disk) if __GFP_IO is set. + */ + can_get_io_locks = gfp_mask & __GFP_IO; + + launder_loop = 0; + maxlaunder = 0; + cleaned_pages = 0; + +dirty_page_rescan: + spin_lock(&pagemap_lru_lock); + maxscan = nr_inactive_dirty_pages; + while ((page_lru = inactive_dirty_list.prev) != &inactive_dirty_list && + maxscan-- > 0) { + page = list_entry(page_lru, struct page, lru); + + /* Wrong page on list?! (list corruption, should not happen) */ + if (!PageInactiveDirty(page)) { + printk("VM: page_launder, wrong page on list.\n"); + list_del(page_lru); + nr_inactive_dirty_pages--; + page->zone->inactive_dirty_pages--; + continue; + } + + /* Page is or was in use? Move it to the active list. */ + if (PageTestandClearReferenced(page) || page->age > 0 || + (!page->buffers && page_count(page) > 1) || + page_ramdisk(page)) { + del_page_from_inactive_dirty_list(page); + add_page_to_active_list(page); + continue; + } + + /* + * The page is locked. IO in progress? + * Move it to the back of the list. + */ + if (TryLockPage(page)) { + list_del(page_lru); + list_add(page_lru, &inactive_dirty_list); + continue; + } + + /* + * If the page has buffers, try to free the buffer mappings + * associated with this page. If we succeed we either free + * the page (in case it was a buffercache only page) or we + * move the page to the inactive_clean list. + * + * On the first round, we should free all previously cleaned + * buffer pages + */ + if (page->buffers) { + int wait, clearedbuf; + int freed_page = 0; + /* + * Since we might be doing disk IO, we have to + * drop the spinlock and take an extra reference + * on the page so it doesn't go away from under us. + */ + del_page_from_inactive_dirty_list(page); + page_cache_get(page); + spin_unlock(&pagemap_lru_lock); + + /* Will we do (asynchronous) IO? */ + if (launder_loop && maxlaunder == 0 && sync) + wait = 2; /* Synchrounous IO */ + else if (launder_loop && maxlaunder-- > 0) + wait = 1; /* Async IO */ + else + wait = 0; /* No IO */ + + /* Try to free the page buffers. */ + clearedbuf = try_to_free_buffers(page, wait); + + /* + * Re-take the spinlock. Note that we cannot + * unlock the page yet since we're still + * accessing the page_struct here... + */ + spin_lock(&pagemap_lru_lock); + + /* The buffers were not freed. */ + if (!clearedbuf) { + add_page_to_inactive_dirty_list(page); + + /* The page was only in the buffer cache. */ + } else if (!page->mapping) { + atomic_dec(&buffermem_pages); + freed_page = 1; + cleaned_pages++; + + /* The page has more users besides the cache and us. */ + } else if (page_count(page) > 2) { + add_page_to_active_list(page); + + /* OK, we "created" a freeable page. */ + } else /* page->mapping && page_count(page) == 2 */ { + add_page_to_inactive_clean_list(page); + cleaned_pages++; + } + + /* + * Unlock the page and drop the extra reference. + * We can only do it here because we ar accessing + * the page struct above. + */ + UnlockPage(page); + page_cache_release(page); + + /* + * If we're freeing buffer cache pages, stop when + * we've got enough free memory. + */ + if (freed_page && !free_shortage()) + break; + continue; + } else if (page->mapping && !PageDirty(page)) { + /* + * If a page had an extra reference in + * deactivate_page(), we will find it here. + * Now the page is really freeable, so we + * move it to the inactive_clean list. + */ + del_page_from_inactive_dirty_list(page); + add_page_to_inactive_clean_list(page); + UnlockPage(page); + cleaned_pages++; + } else { + /* + * OK, we don't know what to do with the page. + * It's no use keeping it here, so we move it to + * the active list. + */ + del_page_from_inactive_dirty_list(page); + add_page_to_active_list(page); + UnlockPage(page); + } + } + spin_unlock(&pagemap_lru_lock); + + /* + * If we don't have enough free pages, we loop back once + * to queue the dirty pages for writeout. When we were called + * by a user process (that /needs/ a free page) and we didn't + * free anything yet, we wait synchronously on the writeout of + * MAX_SYNC_LAUNDER pages. + * + * We also wake up bdflush, since bdflush should, under most + * loads, flush out the dirty pages before we have to wait on + * IO. + */ + if (can_get_io_locks && !launder_loop && free_shortage()) { + launder_loop = 1; + /* If we cleaned pages, never do synchronous IO. */ + if (cleaned_pages) + sync = 0; + /* We only do a few "out of order" flushes. */ + maxlaunder = MAX_LAUNDER; + /* Kflushd takes care of the rest. */ + wakeup_bdflush(0); + goto dirty_page_rescan; + } + + /* Return the number of pages moved to the inactive_clean list. */ + return cleaned_pages; +} + +/** + * refill_inactive_scan - scan the active list and find pages to deactivate + * @priority: the priority at which to scan + * @oneshot: exit after deactivating one page + * + * This function will scan a portion of the active list to find + * unused pages, those pages will then be moved to the inactive list. + */ +int refill_inactive_scan(unsigned int priority, int oneshot) +{ + struct list_head * page_lru; + struct page * page; + int maxscan, page_active = 0; + int ret = 0; + + /* Take the lock while messing with the list... */ + spin_lock(&pagemap_lru_lock); + maxscan = nr_active_pages >> priority; + while (maxscan-- > 0 && (page_lru = active_list.prev) != &active_list) { + page = list_entry(page_lru, struct page, lru); + + /* Wrong page on list?! (list corruption, should not happen) */ + if (!PageActive(page)) { + printk("VM: refill_inactive, wrong page on list.\n"); + list_del(page_lru); + nr_active_pages--; + continue; + } + + /* Do aging on the pages. */ + if (PageTestandClearReferenced(page)) { + age_page_up_nolock(page); + page_active = 1; + } else { + age_page_down_ageonly(page); + /* + * Since we don't hold a reference on the page + * ourselves, we have to do our test a bit more + * strict then deactivate_page(). This is needed + * since otherwise the system could hang shuffling + * unfreeable pages from the active list to the + * inactive_dirty list and back again... + * + * SUBTLE: we can have buffer pages with count 1. + */ + if (page_count(page) <= (page->buffers ? 2 : 1)) { + deactivate_page_nolock(page); + page_active = 0; + } else { + page_active = 1; + } + } + /* + * If the page is still on the active list, move it + * to the other end of the list. Otherwise it was + * deactivated by age_page_down and we exit successfully. + */ + if (page_active || PageActive(page)) { + list_del(page_lru); + list_add(page_lru, &active_list); + } else { + ret = 1; + if (oneshot) + break; + } + } + spin_unlock(&pagemap_lru_lock); + + return ret; } /* - * Check if all zones have recently had memory_pressure (zone_wake_kswapd) + * Check if there are zones with a severe shortage of free pages, + * or if all zones have a minor shortage. */ -static inline int keep_kswapd_awake(void) +int free_shortage(void) { - int all_recent = 1; pg_data_t *pgdat = pgdat_list; + int sum = 0; + int freeable = nr_free_pages() + nr_inactive_clean_pages(); + int freetarget = freepages.high + inactive_target / 3; + + /* Are we low on free pages globally? */ + if (freeable < freetarget) + return freetarget - freeable; + /* If not, are we very low on any particular zone? */ do { int i; for(i = 0; i < MAX_NR_ZONES; i++) { zone_t *zone = pgdat->node_zones+ i; - if (zone->size) { - if (zone->free_pages < zone->pages_min) - return 1; - if (!zone->zone_wake_kswapd) - all_recent = 0; + if (zone->size && (zone->inactive_clean_pages + + zone->free_pages < zone->pages_min)) { + sum += zone->pages_min; + sum -= zone->free_pages; + sum -= zone->inactive_clean_pages; } } pgdat = pgdat->node_next; } while (pgdat); - return all_recent; + return sum; +} + +/* + * How many inactive pages are we short? + */ +int inactive_shortage(void) +{ + int shortage = 0; + + shortage += freepages.high; + shortage += inactive_target; + shortage -= nr_free_pages(); + shortage -= nr_inactive_clean_pages(); + shortage -= nr_inactive_dirty_pages; + + if (shortage > 0) + return shortage; + + return 0; } /* @@ -472,96 +876,140 @@ * We want to try to free "count" pages, and we want to * cluster them so that we get good swap-out behaviour. * - * Don't try _too_ hard, though. We don't want to have bad - * latency. - * - * Note: only called by kswapd and try_to_free_pages - * both can WAIT at top level. + * OTOH, if we're a user process (and not kswapd), we + * really care about latency. In that case we don't try + * to free too many pages. */ -#define FREE_COUNT 8 -#define SWAP_COUNT 16 -static int do_try_to_free_pages(unsigned int gfp_mask) -{ - int priority; - int count = FREE_COUNT; - int swap_count; +static int refill_inactive(unsigned int gfp_mask, int user) +{ + int priority, count, start_count, made_progress; + unsigned long idle_time; + + count = inactive_shortage() + free_shortage(); + if (user) + count = (1 << page_cluster); + start_count = count; /* Always trim SLAB caches when memory gets low. */ kmem_cache_reap(gfp_mask); - priority = 64; + /* + * Calculate the minimum time (in seconds) a process must + * have slept before we consider it for idle swapping. + * This must be the number of seconds it takes to go through + * all of the cache. Doing this idle swapping makes the VM + * smoother once we start hitting swap. + */ + idle_time = atomic_read(&page_cache_size); + idle_time += atomic_read(&buffermem_pages); + idle_time /= (inactive_target + 1); + + priority = 6; do { + made_progress = 0; + if (current->need_resched) { + __set_current_state(TASK_RUNNING); schedule(); - /* time has passed - pressure too? */ - if (!memory_pressure()) - goto done; } - while (shrink_mmap(priority, gfp_mask)) { - if (!--count) + while (refill_inactive_scan(priority, 1) || + swap_out(priority, gfp_mask, idle_time)) { + made_progress = 1; + if (--count <= 0) goto done; } - /* check if mission completed */ - if (!keep_kswapd_awake()) - goto done; + /* + * don't be too light against the d/i cache since + * refill_inactive() almost never fail when there's + * really plenty of memory free. + */ + shrink_dcache_memory(priority, gfp_mask); + shrink_icache_memory(priority, gfp_mask); /* Try to get rid of some shared memory pages.. */ - if (gfp_mask & __GFP_IO) { - /* - * don't be too light against the d/i cache since - * shrink_mmap() almost never fail when there's - * really plenty of memory free. - */ - count -= shrink_dcache_memory(priority, gfp_mask); - count -= shrink_icache_memory(priority, gfp_mask); - /* - * Not currently working, see fixme in shrink_?cache_memory - * In the inner funtions there is a comment: - * "To help debugging, a zero exit status indicates - * all slabs were released." (-arca?) - * lets handle it in a primitive but working way... - * if (count <= 0) - * goto done; - */ - if (!keep_kswapd_awake()) + while (shm_swap(priority, gfp_mask)) { + made_progress = 1; + if (--count <= 0) goto done; - - while (shm_swap(priority, gfp_mask)) { - if (!--count) - goto done; - } } /* * Then, try to page stuff out.. - * - * This will not actually free any pages (they get - * put in the swap cache), so we must not count this - * as a "count" success. - */ - swap_count = SWAP_COUNT; - while (swap_out(priority, gfp_mask)) - if (--swap_count < 0) - break; + */ + while (swap_out(priority, gfp_mask, 0)) { + made_progress = 1; + if (--count <= 0) + goto done; + } - } while (--priority >= 0); + /* + * If we either have enough free memory, or if + * page_launder() will be able to make enough + * free memory, then stop. + */ + if (!inactive_shortage() || !free_shortage()) + goto done; - /* Always end on a shrink_mmap.., may sleep... */ - while (shrink_mmap(0, gfp_mask)) { - if (!--count) + /* + * Only switch to a lower "priority" if we + * didn't make any useful progress in the + * last loop. + */ + if (!made_progress) + priority--; + } while (priority >= 0); + + /* Always end on a refill_inactive.., may sleep... */ + while (refill_inactive_scan(0, 1)) { + if (--count <= 0) goto done; } - /* Return 1 if any page is freed, or - * there are no more memory pressure */ - return (count < FREE_COUNT || !keep_kswapd_awake()); - + done: - return 1; + return (count < start_count); +} + +static int do_try_to_free_pages(unsigned int gfp_mask, int user) +{ + int ret = 0; + + /* + * If we're low on free pages, move pages from the + * inactive_dirty list to the inactive_clean list. + * + * Usually bdflush will have pre-cleaned the pages + * before we get around to moving them to the other + * list, so this is a relatively cheap operation. + */ + if (free_shortage() || nr_inactive_dirty_pages > nr_free_pages() + + nr_inactive_clean_pages()) + ret += page_launder(gfp_mask, user); + + /* + * If needed, we move pages from the active list + * to the inactive list. We also "eat" pages from + * the inode and dentry cache whenever we do this. + */ + if (free_shortage() || inactive_shortage()) { + shrink_dcache_memory(6, gfp_mask); + shrink_icache_memory(6, gfp_mask); + ret += refill_inactive(gfp_mask, user); + } else { + /* + * Reclaim unused slab cache memory. + */ + kmem_cache_reap(gfp_mask); + ret = 1; + } + + return ret; } DECLARE_WAIT_QUEUE_HEAD(kswapd_wait); +DECLARE_WAIT_QUEUE_HEAD(kswapd_done); +struct task_struct *kswapd_task; /* * The background pageout daemon, started as a kernel thread @@ -584,6 +1032,7 @@ tsk->pgrp = 1; strcpy(tsk->comm, "kswapd"); sigfillset(&tsk->blocked); + kswapd_task = tsk; /* * Tell the memory management that we're a "memory allocator", @@ -599,54 +1048,166 @@ */ tsk->flags |= PF_MEMALLOC; + /* + * Kswapd main loop. + */ for (;;) { - if (!keep_kswapd_awake()) { - interruptible_sleep_on(&kswapd_wait); + static int recalc = 0; + + /* If needed, try to free some memory. */ + if (inactive_shortage() || free_shortage()) { + int wait = 0; + /* Do we need to do some synchronous flushing? */ + if (waitqueue_active(&kswapd_done)) + wait = 1; + do_try_to_free_pages(GFP_KSWAPD, wait); + } + + /* + * Do some (very minimal) background scanning. This + * will scan all pages on the active list once + * every minute. This clears old referenced bits + * and moves unused pages to the inactive list. + */ + refill_inactive_scan(6, 0); + + /* Once a second, recalculate some VM stats. */ + if (time_after(jiffies, recalc + HZ)) { + recalc = jiffies; + recalculate_vm_stats(); } - do_try_to_free_pages(GFP_KSWAPD); + /* + * Wake up everybody waiting for free memory + * and unplug the disk queue. + */ + wake_up_all(&kswapd_done); + run_task_queue(&tq_disk); + + /* + * We go to sleep if either the free page shortage + * or the inactive page shortage is gone. We do this + * because: + * 1) we need no more free pages or + * 2) the inactive pages need to be flushed to disk, + * it wouldn't help to eat CPU time now ... + * + * We go to sleep for one second, but if it's needed + * we'll be woken up earlier... + */ + if (!free_shortage() || !inactive_shortage()) + interruptible_sleep_on_timeout(&kswapd_wait, HZ); + /* + * TODO: insert out of memory check & oom killer + * invocation in an else branch here. + */ + } +} + +void wakeup_kswapd(int block) +{ + DECLARE_WAITQUEUE(wait, current); + + if (current == kswapd_task) + return; + + if (!block) { + if (waitqueue_active(&kswapd_wait)) + wake_up(&kswapd_wait); + return; } + + /* + * Kswapd could wake us up before we get a chance + * to sleep, so we have to be very careful here to + * prevent SMP races... + */ + __set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&kswapd_done, &wait); + + if (waitqueue_active(&kswapd_wait)) + wake_up(&kswapd_wait); + schedule(); + + remove_wait_queue(&kswapd_done, &wait); + __set_current_state(TASK_RUNNING); } /* * Called by non-kswapd processes when they want more - * memory. - * - * In a perfect world, this should just wake up kswapd - * and return. We don't actually want to swap stuff out - * from user processes, because the locking issues are - * nasty to the extreme (file write locks, and MM locking) - * - * One option might be to let kswapd do all the page-out - * and VM page table scanning that needs locking, and this - * process thread could do just the mmap shrink stage that - * can be done by just dropping cached pages without having - * any deadlock issues. + * memory but are unable to sleep on kswapd because + * they might be holding some IO locks ... */ int try_to_free_pages(unsigned int gfp_mask) { - int retval = 1; + int ret = 1; if (gfp_mask & __GFP_WAIT) { - current->state = TASK_RUNNING; current->flags |= PF_MEMALLOC; - retval = do_try_to_free_pages(gfp_mask); + ret = do_try_to_free_pages(gfp_mask, 1); current->flags &= ~PF_MEMALLOC; } - /* someone needed memory that kswapd had not provided - * make sure kswapd runs, should not happen often */ - if (waitqueue_active(&kswapd_wait)) - wake_up_interruptible(&kswapd_wait); + return ret; +} + +DECLARE_WAIT_QUEUE_HEAD(kreclaimd_wait); +/* + * Kreclaimd will move pages from the inactive_clean list to the + * free list, in order to keep atomic allocations possible under + * all circumstances. Even when kswapd is blocked on IO. + */ +int kreclaimd(void *unused) +{ + struct task_struct *tsk = current; + pg_data_t *pgdat; - return retval; + tsk->session = 1; + tsk->pgrp = 1; + strcpy(tsk->comm, "kreclaimd"); + sigfillset(&tsk->blocked); + current->flags |= PF_MEMALLOC; + + while (1) { + + /* + * We sleep until someone wakes us up from + * page_alloc.c::__alloc_pages(). + */ + interruptible_sleep_on(&kreclaimd_wait); + + /* + * Move some pages from the inactive_clean lists to + * the free lists, if it is needed. + */ + pgdat = pgdat_list; + do { + int i; + for(i = 0; i < MAX_NR_ZONES; i++) { + zone_t *zone = pgdat->node_zones + i; + if (!zone->size) + continue; + + while (zone->free_pages < zone->pages_low) { + struct page * page; + page = reclaim_page(zone); + if (!page) + break; + __free_page(page); + } + } + pgdat = pgdat->node_next; + } while (pgdat); + } } + static int __init kswapd_init(void) { - printk("Starting kswapd v1.7\n"); + printk("Starting kswapd v1.8\n"); swap_setup(); kernel_thread(kswapd, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL); + kernel_thread(kreclaimd, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL); return 0; } diff -u --recursive --new-file v2.4.0-test8/linux/net/Makefile linux/net/Makefile --- v2.4.0-test8/linux/net/Makefile Sun Aug 6 11:23:41 2000 +++ linux/net/Makefile Wed Sep 27 14:14:34 2000 @@ -1,217 +1,70 @@ # # Makefile for the linux networking. # -# 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). +# 2 Sep 2000, Christoph Hellwig +# Rewritten to use lists instead of if-statements. # -# Note 2! The CFLAGS definition is now in the main makefile... -MOD_SUB_DIRS := ipv4 -ALL_SUB_DIRS := 802 ax25 bridge core ethernet ipv4 ipv6 ipx unix appletalk \ - netrom rose lapb x25 wanrouter netlink sched packet sunrpc \ - econet irda decnet atm khttpd ipv4/netfilter ipv6/netfilter -SUB_DIRS := core ethernet +O_TARGET := network.o -ifeq ($(CONFIG_NET),y) -SUB_DIRS += 802 sched -endif - -ifeq ($(CONFIG_INET),y) -SUB_DIRS += ipv4 -ifeq ($(CONFIG_NETFILTER),y) -SUB_DIRS += ipv4/netfilter -MOD_SUB_DIRS += ipv4/netfilter -endif -endif - -ifeq ($(CONFIG_UNIX),y) -SUB_DIRS += unix -else - ifeq ($(CONFIG_UNIX),m) - MOD_SUB_DIRS += unix - endif -endif - -ifeq ($(CONFIG_IPV6),y) -SUB_DIRS += ipv6 -ifeq ($(CONFIG_NETFILTER),y) -SUB_DIRS += ipv6/netfilter -MOD_SUB_DIRS += ipv6/netfilter -endif -else - ifeq ($(CONFIG_IPV6),m) - MOD_SUB_DIRS += ipv6 - ifeq ($(CONFIG_NETFILTER),y) - MOD_SUB_DIRS += ipv6/netfilter - endif - endif -endif - -ifeq ($(CONFIG_KHTTPD),y) -SUB_DIRS += khttpd -else - ifeq ($(CONFIG_KHTTPD),m) - MOD_SUB_DIRS += khttpd - endif -endif - -ifeq ($(CONFIG_NETLINK),y) -SUB_DIRS += netlink - ifeq ($(CONFIG_NETLINK_DEV),m) - MOD_SUB_DIRS += netlink - endif -endif - -ifeq ($(CONFIG_PACKET),y) -SUB_DIRS += packet -else - ifeq ($(CONFIG_PACKET),m) - MOD_SUB_DIRS += packet - endif -endif - -ifeq ($(CONFIG_NET_SCHED),y) - MOD_SUB_DIRS += sched -endif - -ifeq ($(CONFIG_BRIDGE),y) -SUB_DIRS += bridge -else - ifeq ($(CONFIG_BRIDGE),m) - MOD_SUB_DIRS += bridge - endif -endif - -ifeq ($(CONFIG_IPX),y) -SUB_DIRS += ipx -# SPX can be still a module -MOD_SUB_DIRS += ipx -else - ifeq ($(CONFIG_IPX),m) - MOD_SUB_DIRS += ipx - endif -endif - -ifeq ($(CONFIG_ATALK),y) -SUB_DIRS += appletalk -else - ifeq ($(CONFIG_ATALK),m) - MOD_SUB_DIRS += appletalk - endif -endif - -ifeq ($(CONFIG_WAN_ROUTER),y) -SUB_DIRS += wanrouter -else - ifeq ($(CONFIG_WAN_ROUTER),m) - MOD_SUB_DIRS += wanrouter - endif -endif +mod-subdirs := ipv4/netfilter ipv6/netfilter ipx irda atm +export-objs := netsyms.o -ifeq ($(CONFIG_X25),y) -SUB_DIRS += x25 -else - ifeq ($(CONFIG_X25),m) - MOD_SUB_DIRS += x25 - endif -endif - -ifeq ($(CONFIG_LAPB),y) -SUB_DIRS += lapb -else - ifeq ($(CONFIG_LAPB),m) - MOD_SUB_DIRS += lapb - endif -endif +subdir-y := core ethernet +subdir-m := ipv4 # hum? -ifeq ($(CONFIG_NETROM),y) -SUB_DIRS += netrom -else - ifeq ($(CONFIG_NETROM),m) - MOD_SUB_DIRS += netrom - endif -endif -ifeq ($(CONFIG_ROSE),y) -SUB_DIRS += rose -else - ifeq ($(CONFIG_ROSE),m) - MOD_SUB_DIRS += rose - endif +subdir-$(CONFIG_NET) += 802 sched +subdir-$(CONFIG_INET) += ipv4 +subdir-$(CONFIG_NETFILTER) += ipv4/netfilter +subdir-$(CONFIG_UNIX) += unix +subdir-$(CONFIG_IPV6) += ipv6 + +ifneq ($(CONFIG_IPV6),n) +ifneq ($(CONFIG_IPV6),) +subdir-$(CONFIG_NETFILTER) += ipv6/netfilter endif - -ifeq ($(CONFIG_AX25),y) -SUB_DIRS += ax25 -else - ifeq ($(CONFIG_AX25),m) - MOD_SUB_DIRS += ax25 - endif endif -ifeq ($(CONFIG_IRDA),y) -SUB_DIRS += irda -# There might be some irda features that are compiled as modules -MOD_IN_SUB_DIRS += irda -else - ifeq ($(CONFIG_IRDA),m) - MOD_SUB_DIRS += irda - endif -endif +subdir-$(CONFIG_KHTTPD) += khttpd +subdir-$(CONFIG_NETLINK) += netlink +subdir-$(CONFIG_PACKET) += packet +subdir-$(CONFIG_NET_SCHED) += sched +subdir-$(CONFIG_BRIDGE) += bridge +subdir-$(CONFIG_IPX) += ipx +subdir-$(CONFIG_ATALK) += appletalk +subdir-$(CONFIG_WAN_ROUTER) += wanrouter +subdir-$(CONFIG_X25) += x25 +subdir-$(CONFIG_LAPB) += lapb +subdir-$(CONFIG_NETROM) += netrom +subdir-$(CONFIG_ROSE) += rose +subdir-$(CONFIG_AX25) += ax25 +subdir-$(CONFIG_IRDA) += irda +subdir-$(CONFIG_SUNRPC) += sunrpc +subdir-$(CONFIG_ATM) += atm +subdir-$(CONFIG_DECNET) += decnet +subdir-$(CONFIG_ECONET) += econet -ifeq ($(CONFIG_SUNRPC),y) -SUB_DIRS += sunrpc -else - ifeq ($(CONFIG_SUNRPC),m) - MOD_SUB_DIRS += sunrpc - endif -endif -ifeq ($(CONFIG_ATM),y) -SUB_DIRS += atm -ifeq ($(CONFIG_ATM_LANE),m) - MOD_ATM = atm -endif -ifeq ($(CONFIG_ATM_MPOA),m) - MOD_ATM = atm -endif -MOD_SUB_DIRS += $(MOD_ATM) +obj-y := socket.o protocols.o $(join $(subdir-y), $(patsubst %,/%.o,$(notdir $(subdir-y)))) +ifeq ($(CONFIG_NET),y) +obj-$(CONFIG_MODULES) += netsyms.o +obj-$(CONFIG_SYSCTL) += sysctl_net.o endif -ifeq ($(CONFIG_DECNET),y) -SUB_DIRS += decnet -else - ifeq ($(CONFIG_DECNET),m) - MOD_SUB_DIRS += decnet - endif -endif -ifeq ($(CONFIG_ECONET),y) -SUB_DIRS += econet -else - ifeq ($(CONFIG_ECONET),m) - MOD_SUB_DIRS += econet - endif -endif +# Subdirectories that should be entered when MAKING_MODULES=1, even if set to 'y'. +both-m := $(filter $(mod-subdirs), $(subdir-y)) -# We must attach netsyms.o to socket.o, as otherwise there is nothing -# to pull the object file from the archive. +# 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))) -ifeq ($(CONFIG_NET),y) -ifeq ($(CONFIG_MODULES),y) -OX_OBJS := netsyms.o -endif -endif +SUB_DIRS := $(subdir-y) +MOD_SUB_DIRS := $(sort $(subdir-m) $(both-m)) +ALL_SUB_DIRS := $(sort $(subdir-y) $(subdir-m) $(subdir-n) $(subdir-)) -O_TARGET := network.o -O_OBJS := socket.o protocols.o $(join $(SUB_DIRS), $(patsubst %,/%.o,$(notdir $(SUB_DIRS)))) - -M_OBJS := - -ifeq ($(CONFIG_SYSCTL),y) -ifeq ($(CONFIG_NET),y) -O_OBJS += sysctl_net.o -endif -endif include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.0-test8/linux/net/appletalk/aarp.c linux/net/appletalk/aarp.c --- v2.4.0-test8/linux/net/appletalk/aarp.c Tue Jul 18 16:09:27 2000 +++ linux/net/appletalk/aarp.c Mon Sep 18 14:57:01 2000 @@ -1017,7 +1017,10 @@ * cycle during probing of a slow to respond host addr. */ if (a != NULL) + { a->expires_at = jiffies - 1; + mod_timer(&aarp_timer, jiffies + sysctl_aarp_tick_time); + } } if (sa.s_node != ma->s_node) diff -u --recursive --new-file v2.4.0-test8/linux/net/core/dev.c linux/net/core/dev.c --- v2.4.0-test8/linux/net/core/dev.c Thu Sep 7 08:32:01 2000 +++ linux/net/core/dev.c Fri Sep 22 14:07:43 2000 @@ -295,37 +295,20 @@ * netdev_boot_setup_check - check boot time settings * @dev: the netdevice * - * Check boot time settings for the device. If device's name is a - * mask (eg. eth%d) and settings are found then this will allocate - * name for the device. The found settings are set for the device - * to be used later in the device probing. Returns 0 if no settings - * found, 1 if they are. + * Check boot time settings for the device. + * The found settings are set for the device to be used + * later in the device probing. + * Returns 0 if no settings found, 1 if they are. */ int netdev_boot_setup_check(struct net_device *dev) { struct netdev_boot_setup *s; - char buf[IFNAMSIZ + 1]; - int i, mask = 0; - - memset(buf, 0, sizeof(buf)); - strcpy(buf, dev->name); - if (strchr(dev->name, '%')) { - *strchr(buf, '%') = '\0'; - mask = 1; - } + int i; s = dev_boot_setup; for (i = 0; i < NETDEV_BOOT_SETUP_MAX; i++) { if (s[i].name[0] != '\0' && s[i].name[0] != ' ' && - !strncmp(buf, s[i].name, mask ? strlen(buf) : - strlen(s[i].name))) { - if (__dev_get_by_name(s[i].name)) { - if (!mask) - return 0; - continue; - } - memset(dev->name, 0, IFNAMSIZ); - strcpy(dev->name, s[i].name); + !strncmp(dev->name, s[i].name, strlen(s[i].name))) { dev->irq = s[i].map.irq; dev->base_addr = s[i].map.base_addr; dev->mem_start = s[i].map.mem_start; @@ -333,7 +316,6 @@ return 1; } } - return 0; } @@ -1159,6 +1141,7 @@ struct net_device *dev = head; head = head->next_sched; + smp_mb__before_clear_bit(); clear_bit(__LINK_STATE_SCHED, &dev->state); if (spin_trylock(&dev->queue_lock)) { @@ -2463,27 +2446,26 @@ dev->iflink = -1; dev_hold(dev); + /* + * Allocate name. If the init() fails + * the name will be reissued correctly. + */ + if (strchr(dev->name, '%')) + dev_alloc_name(dev, dev->name); + /* * Check boot time settings for the device. */ - if (!netdev_boot_setup_check(dev)) { - /* - * No settings found - allocate name. If the init() - * fails the name will be reissued correctly. - */ - if (strchr(dev->name, '%')) - dev_alloc_name(dev, dev->name); - } + netdev_boot_setup_check(dev); if (dev->init && dev->init(dev)) { /* - * It failed to come up. Unhook it. + * It failed to come up. It will be unhooked later. + * dev_alloc_name can now advance to next suitable + * name that is checked next. */ - write_lock_bh(&dev_base_lock); - *dp = dev->next; dev->deadbeaf = 1; - write_unlock_bh(&dev_base_lock); - dev_put(dev); + dp = &dev->next; } else { dp = &dev->next; dev->ifindex = dev_new_index(); @@ -2493,6 +2475,21 @@ dev->rebuild_header = default_rebuild_header; dev_init_scheduler(dev); set_bit(__LINK_STATE_PRESENT, &dev->state); + } + } + + /* + * Unhook devices that failed to come up + */ + dp = &dev_base; + while ((dev = *dp) != NULL) { + if (dev->deadbeaf) { + write_lock_bh(&dev_base_lock); + *dp = dev->next; + write_unlock_bh(&dev_base_lock); + dev_put(dev); + } else { + dp = &dev->next; } } diff -u --recursive --new-file v2.4.0-test8/linux/net/core/sock.c linux/net/core/sock.c --- v2.4.0-test8/linux/net/core/sock.c Fri Aug 18 10:26:25 2000 +++ linux/net/core/sock.c Mon Sep 18 15:04:13 2000 @@ -7,7 +7,7 @@ * handler for protocols to use and generic option handler. * * - * Version: $Id: sock.c,v 1.98 2000/08/16 16:09:15 davem Exp $ + * Version: $Id: sock.c,v 1.100 2000/09/18 05:59:48 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -609,7 +609,9 @@ { sk_cachep = kmem_cache_create("sock", sizeof(struct sock), 0, SLAB_HWCACHE_ALIGN, 0, 0); - + if (!sk_cachep) + printk(KERN_CRIT "sk_init: Cannot create sock SLAB cache!"); + if (num_physpages <= 4096) { sysctl_wmem_max = 32767; sysctl_rmem_max = 32767; @@ -1142,6 +1144,7 @@ } else sk->sleep = NULL; + sk->dst_lock = RW_LOCK_UNLOCKED; sk->callback_lock = RW_LOCK_UNLOCKED; sk->state_change = sock_def_wakeup; diff -u --recursive --new-file v2.4.0-test8/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c --- v2.4.0-test8/linux/net/ipv4/af_inet.c Fri Aug 18 10:26:25 2000 +++ linux/net/ipv4/af_inet.c Mon Sep 18 15:04:13 2000 @@ -5,7 +5,7 @@ * * PF_INET protocol family socket handler. * - * Version: $Id: af_inet.c,v 1.112 2000/08/16 16:20:56 davem Exp $ + * Version: $Id: af_inet.c,v 1.114 2000/09/18 05:59:48 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -258,7 +258,6 @@ return -EAGAIN; } sk->sport = htons(sk->num); - sk->prot->hash(sk); } release_sock(sk); return 0; @@ -390,7 +389,6 @@ if (sk->prot->init) { int err = sk->prot->init(sk); if (err != 0) { - sk->dead = 1; inet_sock_release(sk); return(err); } @@ -460,7 +458,7 @@ if (addr_len < sizeof(struct sockaddr_in)) return -EINVAL; - + chk_addr_ret = inet_addr_type(addr->sin_addr.s_addr); snum = ntohs(addr->sin_port); @@ -495,10 +493,11 @@ if (sk->rcv_saddr) sk->userlocks |= SOCK_BINDADDR_LOCK; + if (snum) + sk->userlocks |= SOCK_BINDPORT_LOCK; sk->sport = htons(sk->num); sk->daddr = 0; sk->dport = 0; - sk->prot->hash(sk); sk_dst_reset(sk); err = 0; out: diff -u --recursive --new-file v2.4.0-test8/linux/net/ipv4/arp.c linux/net/ipv4/arp.c --- v2.4.0-test8/linux/net/ipv4/arp.c Fri Aug 4 18:18:49 2000 +++ linux/net/ipv4/arp.c Tue Oct 3 09:24:41 2000 @@ -1066,16 +1066,13 @@ { char tbuf[16]; sprintf(tbuf, "%u.%u.%u.%u", NIPQUAD(*(u32*)n->primary_key)); - - size = sprintf(buffer+len, "%-16s 0x%-10x0x%-10x%s", + size = sprintf(buffer+len, "%-16s 0x%-10x0x%-10x%s" + " * %s\n", tbuf, hatype, arp_state_to_flags(n), - hbuffer); - - size += sprintf(buffer+len+size, - " %-8s %s\n", - "*", dev->name); + hbuffer, + dev->name); } read_unlock(&n->lock); @@ -1099,15 +1096,17 @@ struct net_device *dev = n->dev; int hatype = dev ? dev->type : 0; - size = sprintf(buffer+len, - "%u.%u.%u.%u0x%-10x0x%-10x%s", - NIPQUAD(*(u32*)n->key), - hatype, - ATF_PUBL|ATF_PERM, - "00:00:00:00:00:00"); - size += sprintf(buffer+len+size, - " %-17s %s\n", - "*", dev ? dev->name : "*"); + { + char tbuf[16]; + sprintf(tbuf, "%u.%u.%u.%u", NIPQUAD(*(u32*)n->key)); + size = sprintf(buffer+len, "%-16s 0x%-10x0x%-10x%s" + " * %s\n", + tbuf, + hatype, + ATF_PUBL|ATF_PERM, + "00:00:00:00:00:00", + dev ? dev->name : "*"); + } len += size; pos += size; diff -u --recursive --new-file v2.4.0-test8/linux/net/ipv4/inetpeer.c linux/net/ipv4/inetpeer.c --- v2.4.0-test8/linux/net/ipv4/inetpeer.c Wed May 3 01:48:03 2000 +++ linux/net/ipv4/inetpeer.c Sun Oct 1 20:35:16 2000 @@ -82,12 +82,12 @@ static rwlock_t peer_pool_lock = RW_LOCK_UNLOCKED; #define PEER_MAXDEPTH 40 /* sufficient for about 2^27 nodes */ -static volatile int peer_total = 0; +static volatile int peer_total; int inet_peer_threshold = 65536 + 128; /* start to throw entries more * aggressively at this stage */ int inet_peer_minttl = 120 * HZ; /* TTL under high load: 120 sec */ int inet_peer_maxttl = 10 * 60 * HZ; /* usual time to live: 10 min */ -struct inet_peer *inet_peer_unused_head = NULL, +struct inet_peer *inet_peer_unused_head, **inet_peer_unused_tailp = &inet_peer_unused_head; spinlock_t inet_peer_unused_lock = SPIN_LOCK_UNLOCKED; #define PEER_MAX_CLEANUP_WORK 30 diff -u --recursive --new-file v2.4.0-test8/linux/net/ipv4/ip_sockglue.c linux/net/ipv4/ip_sockglue.c --- v2.4.0-test8/linux/net/ipv4/ip_sockglue.c Thu Aug 10 13:01:26 2000 +++ linux/net/ipv4/ip_sockglue.c Sun Sep 17 10:03:43 2000 @@ -5,7 +5,7 @@ * * The IP to API glue. * - * Version: $Id: ip_sockglue.c,v 1.51 2000/08/09 11:59:04 davem Exp $ + * Version: $Id: ip_sockglue.c,v 1.52 2000/09/09 08:26:04 davem Exp $ * * Authors: see ip.c * @@ -380,31 +380,39 @@ { int val=0,err; - if(optlen>=sizeof(int)) { - if(get_user(val, (int *) optval)) - return -EFAULT; - } else if(optlen>=sizeof(char)) { - unsigned char ucval; - if(get_user(ucval, (unsigned char *) optval)) - return -EFAULT; - val = (int)ucval; + if (optname == IP_PKTINFO || optname == IP_RECVTTL || + optname == IP_RECVTOS || optname == IP_RECVOPTS || + optname == IP_RETOPTS || optname == IP_TOS || + optname == IP_TTL || optname == IP_HDRINCL || + optname == IP_MTU_DISCOVER || optname == IP_RECVERR || + optname == IP_MULTICAST_TTL || optname == IP_MULTICAST_LOOP || + optname == IP_ROUTER_ALERT) { + if (optlen >= sizeof(int)) { + if (get_user(val, (int *) optval)) + return -EFAULT; + } else if (optlen >= sizeof(char)) { + unsigned char ucval; + + if (get_user(ucval, (unsigned char *) optval)) + return -EFAULT; + val = (int) ucval; + } } + /* If optlen==0, it is equivalent to val == 0 */ - if(level!=SOL_IP) + if (level != SOL_IP) return -ENOPROTOOPT; + #ifdef CONFIG_IP_MROUTE - if(optname>=MRT_BASE && optname <=MRT_BASE+10) - { + if (optname >= MRT_BASE && optname <= (MRT_BASE + 10)) return ip_mroute_setsockopt(sk,optname,optval,optlen); - } #endif err = 0; lock_sock(sk); - switch(optname) - { + switch (optname) { case IP_OPTIONS: { struct ip_options * opt = NULL; diff -u --recursive --new-file v2.4.0-test8/linux/net/ipv4/netfilter/ip_fw_compat.c linux/net/ipv4/netfilter/ip_fw_compat.c --- v2.4.0-test8/linux/net/ipv4/netfilter/ip_fw_compat.c Fri Aug 4 13:07:24 2000 +++ linux/net/ipv4/netfilter/ip_fw_compat.c Mon Sep 18 15:09:55 2000 @@ -15,6 +15,10 @@ #include #include +/* Theoretically, we could one day use 2.4 helpers, but for now it + just confuses depmod --RR */ +EXPORT_NO_SYMBOLS; + static struct firewall_ops *fwops; /* From ip_fw_compat_redir.c */ diff -u --recursive --new-file v2.4.0-test8/linux/net/ipv4/netfilter/ip_fw_compat_masq.c linux/net/ipv4/netfilter/ip_fw_compat_masq.c --- v2.4.0-test8/linux/net/ipv4/netfilter/ip_fw_compat_masq.c Fri Jul 14 12:20:22 2000 +++ linux/net/ipv4/netfilter/ip_fw_compat_masq.c Mon Sep 18 15:09:55 2000 @@ -85,7 +85,12 @@ newsrc, newsrc, { htons(61000) }, { htons(65095) } } } }); - ip_nat_setup_info(ct, &range, NF_IP_POST_ROUTING); + ret = ip_nat_setup_info(ct, &range, NF_IP_POST_ROUTING); + if (ret != NF_ACCEPT) { + WRITE_UNLOCK(&ip_nat_lock); + return ret; + } + place_in_hashes(ct, info); info->initialized = 1; } else diff -u --recursive --new-file v2.4.0-test8/linux/net/ipv4/netfilter/ip_nat_ftp.c linux/net/ipv4/netfilter/ip_nat_ftp.c --- v2.4.0-test8/linux/net/ipv4/netfilter/ip_nat_ftp.c Thu Aug 10 12:35:15 2000 +++ linux/net/ipv4/netfilter/ip_nat_ftp.c Sun Sep 17 10:15:00 2000 @@ -372,8 +372,9 @@ newseq = ntohl(tcph->seq) + ftp[dir].syn_offset_before; newseq = htonl(newseq); - /* Ack adjust */ - if (after(ntohl(tcph->ack_seq), ftp[!dir].syn_correction_pos)) + /* Ack adjust: other dir sees offset seq numbers */ + if (after(ntohl(tcph->ack_seq) - ftp[!dir].syn_offset_before, + ftp[!dir].syn_correction_pos)) newack = ntohl(tcph->ack_seq) - ftp[!dir].syn_offset_after; else newack = ntohl(tcph->ack_seq) - ftp[!dir].syn_offset_before; diff -u --recursive --new-file v2.4.0-test8/linux/net/ipv4/netfilter/ip_nat_standalone.c linux/net/ipv4/netfilter/ip_nat_standalone.c --- v2.4.0-test8/linux/net/ipv4/netfilter/ip_nat_standalone.c Thu Sep 7 08:32:01 2000 +++ linux/net/ipv4/netfilter/ip_nat_standalone.c Fri Sep 15 21:37:23 2000 @@ -7,6 +7,7 @@ /* (c) 1999 Paul `Rusty' Russell. Licenced under the GNU General Public Licence. */ +#include #include #include #include diff -u --recursive --new-file v2.4.0-test8/linux/net/ipv4/netfilter/ip_queue.c linux/net/ipv4/netfilter/ip_queue.c --- v2.4.0-test8/linux/net/ipv4/netfilter/ip_queue.c Thu Aug 10 12:35:15 2000 +++ linux/net/ipv4/netfilter/ip_queue.c Mon Sep 18 15:09:55 2000 @@ -414,7 +414,7 @@ return skb; nlmsg_failure: if (skb) - kfree(skb); + kfree_skb(skb); *errp = 0; printk(KERN_ERR "ip_queue: error creating netlink message\n"); return NULL; diff -u --recursive --new-file v2.4.0-test8/linux/net/ipv4/netfilter/ipt_MIRROR.c linux/net/ipv4/netfilter/ipt_MIRROR.c --- v2.4.0-test8/linux/net/ipv4/netfilter/ipt_MIRROR.c Thu Jul 6 21:20:00 2000 +++ linux/net/ipv4/netfilter/ipt_MIRROR.c Mon Sep 18 15:09:55 2000 @@ -89,7 +89,7 @@ dst->neighbour->output(skb); else { printk(KERN_DEBUG "khm in MIRROR\n"); - kfree(skb); + kfree_skb(skb); } } diff -u --recursive --new-file v2.4.0-test8/linux/net/ipv4/netfilter/ipt_REJECT.c linux/net/ipv4/netfilter/ipt_REJECT.c --- v2.4.0-test8/linux/net/ipv4/netfilter/ipt_REJECT.c Thu Aug 10 12:35:15 2000 +++ linux/net/ipv4/netfilter/ipt_REJECT.c Tue Sep 19 08:31:53 2000 @@ -21,12 +21,13 @@ #endif /* Send RST reply */ -static void send_reset(struct sk_buff *oldskb) +static void send_reset(struct sk_buff *oldskb, int local) { struct sk_buff *nskb; struct tcphdr *otcph, *tcph; struct rtable *rt; unsigned int otcplen; + u_int16_t tmp; int needs_ack; /* IP header checks: fragment, too short. */ @@ -64,8 +65,11 @@ tcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl); + /* Swap source and dest */ nskb->nh.iph->daddr = xchg(&nskb->nh.iph->saddr, nskb->nh.iph->daddr); - tcph->source = xchg(&tcph->dest, tcph->source); + tmp = tcph->source; + tcph->source = tcph->dest; + tcph->dest = tmp; /* Truncate to length (no data) */ tcph->doff = sizeof(struct tcphdr)/4; @@ -110,8 +114,9 @@ nskb->nh.iph->check = ip_fast_csum((unsigned char *)nskb->nh.iph, nskb->nh.iph->ihl); - /* Routing */ - if (ip_route_output(&rt, nskb->nh.iph->daddr, nskb->nh.iph->saddr, + /* Routing: if not headed for us, route won't like source */ + if (ip_route_output(&rt, nskb->nh.iph->daddr, + local ? nskb->nh.iph->saddr : 0, RT_TOS(nskb->nh.iph->tos) | RTO_CONN, 0) != 0) goto free_nskb; @@ -184,7 +189,7 @@ } break; case IPT_TCP_RESET: - send_reset(*pskb); + send_reset(*pskb, hooknum == NF_IP_LOCAL_IN); break; } diff -u --recursive --new-file v2.4.0-test8/linux/net/ipv4/netfilter/iptable_mangle.c linux/net/ipv4/netfilter/iptable_mangle.c --- v2.4.0-test8/linux/net/ipv4/netfilter/iptable_mangle.c Thu Sep 7 08:32:01 2000 +++ linux/net/ipv4/netfilter/iptable_mangle.c Fri Sep 15 21:37:23 2000 @@ -3,6 +3,7 @@ * * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling */ +#include #include #include #include diff -u --recursive --new-file v2.4.0-test8/linux/net/ipv4/protocol.c linux/net/ipv4/protocol.c --- v2.4.0-test8/linux/net/ipv4/protocol.c Sat Feb 26 22:34:27 2000 +++ linux/net/ipv4/protocol.c Sun Oct 1 20:35:16 2000 @@ -112,10 +112,7 @@ struct inet_protocol *inet_protocol_base = IPPROTO_PREVIOUS; -struct inet_protocol *inet_protos[MAX_INET_PROTOS] = -{ - NULL -}; +struct inet_protocol *inet_protos[MAX_INET_PROTOS]; /* * Add a protocol handler to the hash tables diff -u --recursive --new-file v2.4.0-test8/linux/net/ipv4/route.c linux/net/ipv4/route.c --- v2.4.0-test8/linux/net/ipv4/route.c Thu Sep 7 08:32:01 2000 +++ linux/net/ipv4/route.c Sun Oct 1 20:35:16 2000 @@ -117,7 +117,7 @@ int ip_rt_min_pmtu = 512+20+20; int ip_rt_min_advmss = 536; -static unsigned long rt_deadline = 0; +static unsigned long rt_deadline; #define RTprint(a...) printk(KERN_DEBUG a) diff -u --recursive --new-file v2.4.0-test8/linux/net/ipv4/sysctl_net_ipv4.c linux/net/ipv4/sysctl_net_ipv4.c --- v2.4.0-test8/linux/net/ipv4/sysctl_net_ipv4.c Thu Sep 7 08:32:01 2000 +++ linux/net/ipv4/sysctl_net_ipv4.c Sun Sep 17 10:03:43 2000 @@ -1,7 +1,7 @@ /* * sysctl_net_ipv4.c: sysctl interface to net IPV4 subsystem. * - * $Id: sysctl_net_ipv4.c,v 1.45 2000/09/06 23:30:29 davem Exp $ + * $Id: sysctl_net_ipv4.c,v 1.46 2000/09/16 09:38:30 davem Exp $ * * Begun April 1, 1996, Mike Shaver. * Added /proc/sys/net/ipv4 directory entry (empty =) ). [MS] @@ -15,19 +15,6 @@ #include #include -/* - * TCP configuration parameters - */ - -#define TCP_PMTU_DISC 0x00000001 /* perform PMTU discovery */ -#define TCP_CONG_AVOID 0x00000002 /* congestion avoidance algorithm */ -#define TCP_DELAY_ACKS 0x00000003 /* delayed ack stategy */ - -#if 0 -static int boolean_min = 0; -static int boolean_max = 1; -#endif - /* From icmp.c */ extern int sysctl_icmp_echo_ignore_all; extern int sysctl_icmp_echo_ignore_broadcasts; @@ -57,7 +44,10 @@ extern int inet_peer_gc_mintime; extern int inet_peer_gc_maxtime; -int tcp_retr1_max = 255; +static int tcp_retr1_max = 255; + +static int ip_local_port_range_min[] = { 1, 1 }; +static int ip_local_port_range_max[] = { 65535, 65535 }; struct ipv4_config ipv4_config; @@ -170,7 +160,8 @@ sizeof(int), 0644, NULL, &proc_dointvec}, {NET_IPV4_LOCAL_PORT_RANGE, "ip_local_port_range", &sysctl_local_port_range, sizeof(sysctl_local_port_range), 0644, - NULL, &proc_dointvec}, + NULL, &proc_dointvec_minmax, &sysctl_intvec, NULL, + ip_local_port_range_min, ip_local_port_range_max }, {NET_IPV4_ICMP_ECHO_IGNORE_ALL, "icmp_echo_ignore_all", &sysctl_icmp_echo_ignore_all, sizeof(int), 0644, NULL, &proc_dointvec}, diff -u --recursive --new-file v2.4.0-test8/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c --- v2.4.0-test8/linux/net/ipv4/tcp.c Fri Aug 18 10:26:25 2000 +++ linux/net/ipv4/tcp.c Sun Oct 1 20:35:16 2000 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp.c,v 1.173 2000/08/15 20:15:23 davem Exp $ + * Version: $Id: tcp.c,v 1.174 2000/09/18 05:59:48 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -436,7 +436,7 @@ atomic_t tcp_orphan_count = ATOMIC_INIT(0); -int sysctl_tcp_mem[3] = { 0, }; +int sysctl_tcp_mem[3]; int sysctl_tcp_wmem[3] = { 4*1024, 16*1024, 128*1024 }; int sysctl_tcp_rmem[3] = { 4*1024, 87380, 87380*2 }; @@ -1952,12 +1952,14 @@ sk->dport = 0; - sk->rcv_saddr = 0; - sk->saddr = 0; + if (!(sk->userlocks&SOCK_BINDADDR_LOCK)) { + sk->rcv_saddr = 0; + sk->saddr = 0; #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - memset(&sk->net_pinfo.af_inet6.saddr, 0, 16); - memset(&sk->net_pinfo.af_inet6.rcv_saddr, 0, 16); + memset(&sk->net_pinfo.af_inet6.saddr, 0, 16); + memset(&sk->net_pinfo.af_inet6.rcv_saddr, 0, 16); #endif + } sk->shutdown = 0; sk->done = 0; @@ -2281,6 +2283,68 @@ case TCP_WINDOW_CLAMP: val = tp->window_clamp; break; + case TCP_INFO: + { + struct tcp_info info; + u32 now = tcp_time_stamp; + + if(get_user(len,optlen)) + return -EFAULT; + info.tcpi_state = sk->state; + info.tcpi_ca_state = tp->ca_state; + info.tcpi_retransmits = tp->retransmits; + info.tcpi_probes = tp->probes_out; + info.tcpi_backoff = tp->backoff; + info.tcpi_options = 0; + if (tp->tstamp_ok) + info.tcpi_options |= TCPI_OPT_TIMESTAMPS; + if (tp->sack_ok) + info.tcpi_options |= TCPI_OPT_SACK; + if (tp->wscale_ok) { + info.tcpi_options |= TCPI_OPT_WSCALE; + info.tcpi_snd_wscale = tp->snd_wscale; + info.tcpi_rcv_wscale = tp->rcv_wscale; + } else { + info.tcpi_snd_wscale = 0; + info.tcpi_rcv_wscale = 0; + } +#ifdef CONFIG_INET_ECN + if (tp->ecn_flags&TCP_ECN_OK) + info.tcpi_options |= TCPI_OPT_ECN; +#endif + + info.tcpi_rto = (1000000*tp->rto)/HZ; + info.tcpi_ato = (1000000*tp->ack.ato)/HZ; + info.tcpi_snd_mss = tp->mss_cache; + info.tcpi_rcv_mss = tp->ack.rcv_mss; + + info.tcpi_unacked = tp->packets_out; + info.tcpi_sacked = tp->sacked_out; + info.tcpi_lost = tp->lost_out; + info.tcpi_retrans = tp->retrans_out; + info.tcpi_fackets = tp->fackets_out; + + info.tcpi_last_data_sent = ((now - tp->lsndtime)*1000)/HZ; + info.tcpi_last_ack_sent = 0; + info.tcpi_last_data_recv = ((now - tp->ack.lrcvtime)*1000)/HZ; + info.tcpi_last_ack_recv = ((now - tp->rcv_tstamp)*1000)/HZ; + + info.tcpi_pmtu = tp->pmtu_cookie; + info.tcpi_rcv_ssthresh = tp->rcv_ssthresh; + info.tcpi_rtt = ((1000000*tp->srtt)/HZ)>>3; + info.tcpi_rttvar = ((1000000*tp->mdev)/HZ)>>2; + info.tcpi_snd_ssthresh = tp->snd_ssthresh; + info.tcpi_snd_cwnd = tp->snd_cwnd; + info.tcpi_advmss = tp->advmss; + info.tcpi_reordering = tp->reordering; + + len = min(len, sizeof(info)); + if(put_user(len, optlen)) + return -EFAULT; + if(copy_to_user(optval, &info,len)) + return -EFAULT; + return 0; + } default: return -ENOPROTOOPT; }; diff -u --recursive --new-file v2.4.0-test8/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c --- v2.4.0-test8/linux/net/ipv4/tcp_input.c Thu Sep 7 08:32:01 2000 +++ linux/net/ipv4/tcp_input.c Thu Sep 21 13:20:12 2000 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_input.c,v 1.199 2000/09/06 23:30:29 davem Exp $ + * Version: $Id: tcp_input.c,v 1.202 2000/09/21 01:05:38 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -58,6 +58,7 @@ * J Hadi Salim: ECN support */ +#include #include #include #include @@ -1492,10 +1493,8 @@ case TCP_CA_Disorder: tcp_try_undo_dsack(sk, tp); - if (IsReno(tp) || !tp->undo_marker) { - tp->undo_marker = 0; - tp->ca_state = TCP_CA_Open; - } + tp->undo_marker = 0; + tp->ca_state = TCP_CA_Open; break; case TCP_CA_Recovery: @@ -1823,7 +1822,9 @@ #ifdef TCP_DEBUG if (before(tp->snd_una + tp->snd_wnd, tp->snd_nxt)) { if (net_ratelimit()) - printk(KERN_DEBUG "TCP: peer shrinks window. Bad, what else can I say?\n"); + printk(KERN_DEBUG "TCP: peer %u.%u.%u.%u:%u/%u shrinks window %u:%u:%u. Bad, what else can I say?\n", + NIPQUAD(sk->daddr), htons(sk->dport), sk->num, + tp->snd_una, tp->snd_wnd, tp->snd_nxt); } #endif @@ -1952,7 +1953,7 @@ if (opsize < 2) /* "silly options" */ return; if (opsize > length) - break; /* don't parse partial options */ + return; /* don't parse partial options */ switch(opcode) { case TCPOPT_MSS: if(opsize==TCPOLEN_MSS && th->syn) { diff -u --recursive --new-file v2.4.0-test8/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c --- v2.4.0-test8/linux/net/ipv4/tcp_ipv4.c Fri Aug 18 10:26:25 2000 +++ linux/net/ipv4/tcp_ipv4.c Sun Oct 1 20:35:16 2000 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_ipv4.c,v 1.212 2000/08/18 17:10:04 davem Exp $ + * Version: $Id: tcp_ipv4.c,v 1.213 2000/09/18 05:59:48 davem Exp $ * * IPv4 specific functions * @@ -82,21 +82,21 @@ * First half of the table is for sockets not in TIME_WAIT, second half * is for TIME_WAIT sockets only. */ -struct tcp_ehash_bucket *tcp_ehash = NULL; +struct tcp_ehash_bucket *tcp_ehash; /* Ok, let's try this, I give up, we do need a local binding * TCP hash as well as the others for fast bind/connect. */ -struct tcp_bind_hashbucket *tcp_bhash = NULL; +struct tcp_bind_hashbucket *tcp_bhash; -int tcp_bhash_size = 0; -int tcp_ehash_size = 0; +int tcp_bhash_size; +int tcp_ehash_size; /* All sockets in TCP_LISTEN state will be in here. This is the only table * where wildcard'd TCP sockets can exist. Hash function here is just local * port number. */ -struct sock *tcp_listening_hash[TCP_LHTABLE_SIZE] = { NULL, }; +struct sock *tcp_listening_hash[TCP_LHTABLE_SIZE]; char __tcp_clean_cacheline_pad[(SMP_CACHE_BYTES - (((sizeof(void *) * (TCP_LHTABLE_SIZE + 2)) + (sizeof(int) * 2)) % SMP_CACHE_BYTES))] = { 0, }; @@ -300,6 +300,7 @@ sk->bind_next->bind_pprev = sk->bind_pprev; *(sk->bind_pprev) = sk->bind_next; sk->prev = NULL; + sk->num = 0; if (tb->owners == NULL) { if (tb->next) tb->next->pprev = tb->pprev; diff -u --recursive --new-file v2.4.0-test8/linux/net/ipv4/tcp_minisocks.c linux/net/ipv4/tcp_minisocks.c --- v2.4.0-test8/linux/net/ipv4/tcp_minisocks.c Thu Sep 7 08:32:01 2000 +++ linux/net/ipv4/tcp_minisocks.c Mon Sep 18 15:04:13 2000 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_minisocks.c,v 1.3 2000/09/05 23:13:48 davem Exp $ + * Version: $Id: tcp_minisocks.c,v 1.4 2000/09/18 05:59:48 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -662,6 +662,7 @@ sock_lock_init(newsk); bh_lock_sock(newsk); + newsk->dst_lock = RW_LOCK_UNLOCKED; atomic_set(&newsk->rmem_alloc, 0); skb_queue_head_init(&newsk->receive_queue); atomic_set(&newsk->wmem_alloc, 0); @@ -671,6 +672,7 @@ newsk->forward_alloc = 0; newsk->done = 0; + newsk->userlocks = sk->userlocks & ~SOCK_BINDPORT_LOCK; newsk->proc = 0; newsk->backlog.head = newsk->backlog.tail = NULL; newsk->callback_lock = RW_LOCK_UNLOCKED; diff -u --recursive --new-file v2.4.0-test8/linux/net/ipv4/tcp_timer.c linux/net/ipv4/tcp_timer.c --- v2.4.0-test8/linux/net/ipv4/tcp_timer.c Sat Aug 12 12:09:55 2000 +++ linux/net/ipv4/tcp_timer.c Sun Oct 1 20:35:16 2000 @@ -29,7 +29,7 @@ int sysctl_tcp_keepalive_intvl = TCP_KEEPALIVE_INTVL; int sysctl_tcp_retries1 = TCP_RETR1; int sysctl_tcp_retries2 = TCP_RETR2; -int sysctl_tcp_orphan_retries = 0; +int sysctl_tcp_orphan_retries; static void tcp_write_timer(unsigned long); static void tcp_delack_timer(unsigned long); diff -u --recursive --new-file v2.4.0-test8/linux/net/ipv4/udp.c linux/net/ipv4/udp.c --- v2.4.0-test8/linux/net/ipv4/udp.c Thu Aug 10 13:01:26 2000 +++ linux/net/ipv4/udp.c Sun Oct 1 20:35:16 2000 @@ -5,7 +5,7 @@ * * The User Datagram Protocol (UDP). * - * Version: $Id: udp.c,v 1.85 2000/08/09 11:59:04 davem Exp $ + * Version: $Id: udp.c,v 1.87 2000/09/20 02:11:34 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -126,7 +126,7 @@ rwlock_t udp_hash_lock = RW_LOCK_UNLOCKED; /* Shared by v4/v6 udp. */ -int udp_port_rover = 0; +int udp_port_rover; static int udp_v4_get_port(struct sock *sk, unsigned short snum) { @@ -188,6 +188,15 @@ } } sk->num = snum; + if (sk->pprev == NULL) { + struct sock **skp = &udp_hash[snum & (UDP_HTABLE_SIZE - 1)]; + if ((sk->next = *skp) != NULL) + (*skp)->pprev = &sk->next; + *skp = sk; + sk->pprev = skp; + sock_prot_inc_use(sk->prot); + sock_hold(sk); + } write_unlock_bh(&udp_hash_lock); return 0; @@ -198,16 +207,7 @@ static void udp_v4_hash(struct sock *sk) { - struct sock **skp = &udp_hash[sk->num & (UDP_HTABLE_SIZE - 1)]; - - write_lock_bh(&udp_hash_lock); - if ((sk->next = *skp) != NULL) - (*skp)->pprev = &sk->next; - *skp = sk; - sk->pprev = skp; - sock_prot_inc_use(sk->prot); - sock_hold(sk); - write_unlock_bh(&udp_hash_lock); + BUG(); } static void udp_v4_unhash(struct sock *sk) @@ -218,6 +218,7 @@ sk->next->pprev = sk->pprev; *sk->pprev = sk->next; sk->pprev = NULL; + sk->num = 0; sock_prot_dec_use(sk->prot); __sock_put(sk); } @@ -493,8 +494,6 @@ if (usin->sin_family != AF_INET) { if (usin->sin_family != AF_UNSPEC) return -EINVAL; - if (net_ratelimit()) - printk("Remind Kuznetsov, he has to repair %s eventually\n", current->comm); } ufh.daddr = usin->sin_addr.s_addr; @@ -678,6 +677,8 @@ if (flags & MSG_ERRQUEUE) return ip_recv_error(sk, msg, len); + + retry: /* * From here the generic datagram does a lot of the work. Come * the finished NET3, it will do _ALL_ the work! @@ -733,26 +734,21 @@ csum_copy_err: UDP_INC_STATS_BH(UdpInErrors); - /* Clear queue. */ - if (flags&MSG_PEEK) { - int clear = 0; + if (flags&(MSG_PEEK|MSG_DONTWAIT)) { + struct sk_buff *skb2; + spin_lock_irq(&sk->receive_queue.lock); - if (skb == skb_peek(&sk->receive_queue)) { + skb2 = skb_peek(&sk->receive_queue); + if ((flags & MSG_PEEK) && skb == skb2) { __skb_unlink(skb, &sk->receive_queue); - clear = 1; } spin_unlock_irq(&sk->receive_queue.lock); - if (clear) - kfree_skb(skb); - } - - skb_free_datagram(sk, skb); - - /* - * Error for blocking case is chosen to masquerade - * as some normal condition. - */ - return (flags&MSG_DONTWAIT) ? -EAGAIN : -EHOSTUNREACH; + skb_free_datagram(sk, skb); + if ((flags & MSG_DONTWAIT) && !skb2) + return -EAGAIN; + } else + skb_free_datagram(sk, skb); + goto retry; } int udp_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) @@ -797,10 +793,21 @@ */ sk->state = TCP_CLOSE; - sk->rcv_saddr = 0; sk->daddr = 0; sk->dport = 0; sk->bound_dev_if = 0; + if (!(sk->userlocks&SOCK_BINDADDR_LOCK)) { + sk->rcv_saddr = 0; + sk->saddr = 0; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + memset(&sk->net_pinfo.af_inet6.saddr, 0, 16); + memset(&sk->net_pinfo.af_inet6.rcv_saddr, 0, 16); +#endif + } + if (!(sk->userlocks&SOCK_BINDPORT_LOCK)) { + sk->prot->unhash(sk); + sk->sport = 0; + } sk_dst_reset(sk); return 0; } diff -u --recursive --new-file v2.4.0-test8/linux/net/ipv4/utils.c linux/net/ipv4/utils.c --- v2.4.0-test8/linux/net/ipv4/utils.c Wed Jun 9 14:45:37 1999 +++ linux/net/ipv4/utils.c Mon Oct 2 14:13:29 2000 @@ -57,12 +57,6 @@ return(buff); } -char *in_ntoa2(__u32 in, char *buff) -{ - sprintf(buff, "%d.%d.%d.%d", NIPQUAD(in)); - return buff; -} - /* * Convert an ASCII string to binary IP. */ diff -u --recursive --new-file v2.4.0-test8/linux/net/ipv6/af_inet6.c linux/net/ipv6/af_inet6.c --- v2.4.0-test8/linux/net/ipv6/af_inet6.c Wed Apr 26 12:13:17 2000 +++ linux/net/ipv6/af_inet6.c Mon Sep 18 15:04:13 2000 @@ -7,10 +7,11 @@ * * Adapted from linux/net/ipv4/af_inet.c * - * $Id: af_inet6.c,v 1.56 2000/04/25 04:13:34 davem Exp $ + * $Id: af_inet6.c,v 1.58 2000/09/18 05:59:48 davem Exp $ * * Fixes: * Hideaki YOSHIFUJI : sin6_scope_id support + * Arnaldo Melo : check proc_net_create return, cleanups * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -189,7 +190,7 @@ if (sk->prot->init) { int err = sk->prot->init(sk); if (err != 0) { - sk->dead = 1; + MOD_DEC_USE_COUNT; inet_sock_release(sk); return(err); } @@ -295,10 +296,13 @@ return -EADDRINUSE; } + if (addr_type != IPV6_ADDR_ANY) + sk->userlocks |= SOCK_BINDADDR_LOCK; + if (snum) + sk->userlocks |= SOCK_BINDPORT_LOCK; sk->sport = ntohs(sk->num); sk->dport = 0; sk->daddr = 0; - sk->prot->hash(sk); release_sock(sk); return 0; @@ -395,10 +399,8 @@ { case FIOSETOWN: case SIOCSPGRP: - err = get_user(pid, (int *) arg); - if(err) - return err; - + if (get_user(pid, (int *) arg)) + return -EFAULT; /* see sock_no_fcntl */ if (current->pid != pid && current->pgrp != -pid && !capable(CAP_NET_ADMIN)) @@ -407,10 +409,7 @@ return(0); case FIOGETOWN: case SIOCGPGRP: - err = put_user(sk->proc,(int *)arg); - if(err) - return err; - return(0); + return put_user(sk->proc,(int *)arg); case SIOCGSTAMP: if(sk->stamp.tv_sec==0) return -ENOENT; @@ -550,6 +549,20 @@ err = igmp6_init(&inet6_family_ops); if (err) goto igmp_fail; + /* Create /proc/foo6 entries. */ +#ifdef CONFIG_PROC_FS + err = -ENOMEM; + if (!proc_net_create("raw6", 0, raw6_get_info)) + goto proc_raw6_fail; + if (!proc_net_create("tcp6", 0, tcp6_get_info)) + goto proc_tcp6_fail; + if (!proc_net_create("udp6", 0, udp6_get_info)) + goto proc_udp6_fail; + if (!proc_net_create("sockstat6", 0, afinet6_get_info)) + goto proc_sockstat6_fail; + if (!proc_net_create("snmp6", 0, afinet6_get_snmp)) + goto proc_snmp6_fail; +#endif ipv6_netdev_notif_init(); ipv6_packet_init(); ip6_route_init(); @@ -561,15 +574,6 @@ udpv6_init(); tcpv6_init(); - /* Create /proc/foo6 entries. */ -#ifdef CONFIG_PROC_FS - proc_net_create("raw6", 0, raw6_get_info); - proc_net_create("tcp6", 0, tcp6_get_info); - proc_net_create("udp6", 0, udp6_get_info); - proc_net_create("sockstat6", 0, afinet6_get_info); - proc_net_create("snmp6", 0, afinet6_get_snmp); -#endif - /* Now the userspace is allowed to create INET6 sockets. */ (void) sock_register(&inet6_family_ops); @@ -579,6 +583,18 @@ return; #endif +#ifdef CONFIG_PROC_FS +proc_snmp6_fail: + proc_net_remove("sockstat6"); +proc_sockstat6_fail: + proc_net_remove("udp6"); +proc_udp6_fail: + proc_net_remove("tcp6"); +proc_tcp6_fail: + proc_net_remove("raw6"); +proc_raw6_fail: + igmp6_cleanup(); +#endif igmp_fail: ndisc_cleanup(); ndisc_fail: diff -u --recursive --new-file v2.4.0-test8/linux/net/ipv6/ip6_fib.c linux/net/ipv6/ip6_fib.c --- v2.4.0-test8/linux/net/ipv6/ip6_fib.c Wed May 3 01:48:04 2000 +++ linux/net/ipv6/ip6_fib.c Sun Sep 17 10:03:43 2000 @@ -5,7 +5,7 @@ * Authors: * Pedro Roque * - * $Id: ip6_fib.c,v 1.21 2000/05/03 06:37:07 davem Exp $ + * $Id: ip6_fib.c,v 1.22 2000/09/12 00:38:34 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -638,10 +638,8 @@ if (narg->addr) { st = fib6_lookup_1(fn->subtree, narg); - if (!(st->fn_flags & RTN_ROOT)) - { + if (st && !(st->fn_flags & RTN_ROOT)) return st; - } } } #endif diff -u --recursive --new-file v2.4.0-test8/linux/net/ipv6/mcast.c linux/net/ipv6/mcast.c --- v2.4.0-test8/linux/net/ipv6/mcast.c Fri Aug 4 18:18:49 2000 +++ linux/net/ipv6/mcast.c Mon Sep 18 15:04:13 2000 @@ -5,7 +5,7 @@ * Authors: * Pedro Roque * - * $Id: mcast.c,v 1.32 2000/07/26 01:04:21 davem Exp $ + * $Id: mcast.c,v 1.33 2000/09/18 05:59:48 davem Exp $ * * Based on linux/ipv4/igmp.c and linux/ipv4/ip_sockglue.c * @@ -766,7 +766,6 @@ return 0; } -#ifdef MODULE void igmp6_cleanup(void) { sock_release(igmp6_socket); @@ -775,4 +774,3 @@ remove_proc_entry("net/igmp6", 0); #endif } -#endif diff -u --recursive --new-file v2.4.0-test8/linux/net/ipv6/protocol.c linux/net/ipv6/protocol.c --- v2.4.0-test8/linux/net/ipv6/protocol.c Sat Feb 26 22:34:27 2000 +++ linux/net/ipv6/protocol.c Mon Oct 2 11:57:01 2000 @@ -32,11 +32,8 @@ #include #include -struct inet6_protocol *inet6_protocol_base = NULL; -struct inet6_protocol *inet6_protos[MAX_INET_PROTOS] = -{ - NULL -}; +struct inet6_protocol *inet6_protocol_base; +struct inet6_protocol *inet6_protos[MAX_INET_PROTOS]; void inet6_add_protocol(struct inet6_protocol *prot) { diff -u --recursive --new-file v2.4.0-test8/linux/net/ipv6/udp.c linux/net/ipv6/udp.c --- v2.4.0-test8/linux/net/ipv6/udp.c Thu Aug 10 13:01:26 2000 +++ linux/net/ipv6/udp.c Mon Sep 18 15:04:13 2000 @@ -7,7 +7,7 @@ * * Based on linux/ipv4/udp.c * - * $Id: udp.c,v 1.56 2000/08/09 11:59:04 davem Exp $ + * $Id: udp.c,v 1.57 2000/09/18 05:59:48 davem Exp $ * * Fixes: * Hideaki YOSHIFUJI : sin6_scope_id support @@ -119,6 +119,15 @@ } sk->num = snum; + if (sk->pprev == NULL) { + struct sock **skp = &udp_hash[snum & (UDP_HTABLE_SIZE - 1)]; + if ((sk->next = *skp) != NULL) + (*skp)->pprev = &sk->next; + *skp = sk; + sk->pprev = skp; + sock_prot_inc_use(sk->prot); + sock_hold(sk); + } write_unlock_bh(&udp_hash_lock); return 0; @@ -129,16 +138,7 @@ static void udp_v6_hash(struct sock *sk) { - struct sock **skp = &udp_hash[sk->num & (UDP_HTABLE_SIZE - 1)]; - - write_lock_bh(&udp_hash_lock); - if ((sk->next = *skp) != NULL) - (*skp)->pprev = &sk->next; - *skp = sk; - sk->pprev = skp; - sock_prot_inc_use(sk->prot); - sock_hold(sk); - write_unlock_bh(&udp_hash_lock); + BUG(); } static void udp_v6_unhash(struct sock *sk) @@ -149,6 +149,7 @@ sk->next->pprev = sk->pprev; *sk->pprev = sk->next; sk->pprev = NULL; + sk->num = 0; sock_prot_dec_use(sk->prot); __sock_put(sk); } diff -u --recursive --new-file v2.4.0-test8/linux/net/socket.c linux/net/socket.c --- v2.4.0-test8/linux/net/socket.c Mon Aug 28 12:04:42 2000 +++ linux/net/socket.c Thu Sep 21 13:20:12 2000 @@ -822,7 +822,7 @@ * Check protocol is in range */ if(family<0 || family>=NPROTO) - return -EINVAL; + return -EAFNOSUPPORT; /* Compatibility. diff -u --recursive --new-file v2.4.0-test8/linux/net/sunrpc/auth_unix.c linux/net/sunrpc/auth_unix.c --- v2.4.0-test8/linux/net/sunrpc/auth_unix.c Mon Mar 20 08:14:04 2000 +++ linux/net/sunrpc/auth_unix.c Mon Sep 25 13:13:53 2000 @@ -180,7 +180,8 @@ memcpy(p, clnt->cl_nodename, n); p += (n + 3) >> 2; - if (ruid) { + /* Note: we don't use real uid if it involves raising priviledge */ + if (ruid && cred->uc_uid != 0 && cred->uc_gid != 0) { *p++ = htonl((u32) cred->uc_uid); *p++ = htonl((u32) cred->uc_gid); } else { diff -u --recursive --new-file v2.4.0-test8/linux/net/sunrpc/clnt.c linux/net/sunrpc/clnt.c --- v2.4.0-test8/linux/net/sunrpc/clnt.c Fri Jul 7 15:57:49 2000 +++ linux/net/sunrpc/clnt.c Mon Sep 25 13:13:53 2000 @@ -708,7 +708,7 @@ * The following is an NFS-specific hack to cater for setuid * processes whose uid is mapped to nobody on the server. */ - if (task->tk_client->cl_prog == NFS_PROGRAM && + if (task->tk_client->cl_droppriv && (ntohl(*p) == NFSERR_ACCES || ntohl(*p) == NFSERR_PERM)) { if (RPC_IS_SETUID(task) && task->tk_suid_retry) { dprintk("RPC: %4d retry squashed uid\n", task->tk_pid); @@ -824,6 +824,7 @@ case RPC_AUTH_TOOWEAK: printk(KERN_NOTICE "call_verify: server requires stronger " "authentication.\n"); + break; default: printk(KERN_WARNING "call_verify: unknown auth error: %x\n", n); error = -EIO; diff -u --recursive --new-file v2.4.0-test8/linux/net/sunrpc/sched.c linux/net/sunrpc/sched.c --- v2.4.0-test8/linux/net/sunrpc/sched.c Wed Aug 23 09:50:19 2000 +++ linux/net/sunrpc/sched.c Sun Oct 1 20:35:16 2000 @@ -24,7 +24,7 @@ #ifdef RPC_DEBUG #define RPCDBG_FACILITY RPCDBG_SCHED -static int rpc_task_id = 0; +static int rpc_task_id; #endif /* @@ -56,7 +56,7 @@ /* * All RPC tasks are linked into this list */ -static struct rpc_task * all_tasks = NULL; +static struct rpc_task * all_tasks; /* * rpciod-related stuff @@ -64,9 +64,9 @@ static DECLARE_WAIT_QUEUE_HEAD(rpciod_idle); static DECLARE_WAIT_QUEUE_HEAD(rpciod_killer); static DECLARE_MUTEX(rpciod_sema); -static unsigned int rpciod_users = 0; -static pid_t rpciod_pid = 0; -static int rpc_inhibit = 0; +static unsigned int rpciod_users; +static pid_t rpciod_pid; +static int rpc_inhibit; /* * Spinlock for wait queues. Access to the latter also has to be @@ -82,7 +82,7 @@ * This is the last-ditch buffer for NFS swap requests */ static u32 swap_buffer[PAGE_SIZE >> 2]; -static int swap_buffer_used = 0; +static int swap_buffer_used; /* * Make allocation of the swap_buffer SMP-safe diff -u --recursive --new-file v2.4.0-test8/linux/net/sunrpc/sysctl.c linux/net/sunrpc/sysctl.c --- v2.4.0-test8/linux/net/sunrpc/sysctl.c Fri Apr 21 16:08:52 2000 +++ linux/net/sunrpc/sysctl.c Sun Oct 1 20:35:16 2000 @@ -25,14 +25,14 @@ /* * Declare the debug flags here */ -unsigned int rpc_debug = 0; -unsigned int nfs_debug = 0; -unsigned int nfsd_debug = 0; -unsigned int nlm_debug = 0; +unsigned int rpc_debug; +unsigned int nfs_debug; +unsigned int nfsd_debug; +unsigned int nlm_debug; #ifdef RPC_DEBUG -static struct ctl_table_header *sunrpc_table_header = NULL; +static struct ctl_table_header *sunrpc_table_header; static ctl_table sunrpc_table[]; void diff -u --recursive --new-file v2.4.0-test8/linux/net/sunrpc/xprt.c linux/net/sunrpc/xprt.c --- v2.4.0-test8/linux/net/sunrpc/xprt.c Tue Jul 18 12:39:29 2000 +++ linux/net/sunrpc/xprt.c Mon Sep 18 15:19:49 2000 @@ -1037,7 +1037,7 @@ return; /* Wait until we have enough socket memory */ - if (sock_wspace(sk) < min(sk->sndbuf,XPRT_MIN_WRITE_SPACE)) + if (!sock_writeable(sk)) return; spin_lock_bh(&xprt_sock_lock); @@ -1212,9 +1212,6 @@ */ while (1) { xprt->write_space = 0; - status = -ENOMEM; - if (sock_wspace(xprt->inet) < req->rq_slen + SOCK_MIN_WRITE_SPACE) - break; status = xprt_sendmsg(xprt, req); if (status < 0) diff -u --recursive --new-file v2.4.0-test8/linux/net/x25/af_x25.c linux/net/x25/af_x25.c --- v2.4.0-test8/linux/net/x25/af_x25.c Mon Aug 28 21:16:05 2000 +++ linux/net/x25/af_x25.c Sun Sep 17 10:03:43 2000 @@ -21,6 +21,8 @@ * facilities negotiation and increased * the throughput upper limit. * 2000-27-08 Arnaldo C. Melo s/suser/capable/ + micro cleanups + * 2000-04-09 Henner Eisen Set sock->state in x25_accept(). + * Fixed x25_output() related skb leakage. */ #include @@ -721,6 +723,7 @@ kfree_skb(skb); sk->ack_backlog--; newsock->sk = newsk; + newsock->state = SS_CONNECTED; return 0; } @@ -971,7 +974,11 @@ if (msg->msg_flags & MSG_OOB) { skb_queue_tail(&sk->protinfo.x25->interrupt_out_queue, skb); } else { - x25_output(sk, skb); + err = x25_output(sk, skb); + if(err){ + len = err; + kfree_skb(skb); + } } x25_kick(sk); diff -u --recursive --new-file v2.4.0-test8/linux/net/x25/x25_dev.c linux/net/x25/x25_dev.c --- v2.4.0-test8/linux/net/x25/x25_dev.c Mon Aug 23 10:01:02 1999 +++ linux/net/x25/x25_dev.c Sun Sep 17 10:03:43 2000 @@ -14,6 +14,7 @@ * * History * X.25 001 Jonathan Naylor Started coding. + * 2000-09-04 Henner Eisen Prevent freeing a dangling skb. */ #include @@ -78,12 +79,13 @@ return x25_rx_call_request(skb, neigh, lci); /* - * Its not a Call Request, nor is it a control frame, throw it awa + * Its not a Call Request, nor is it a control frame. + * Let caller throw it away. */ /* x25_transmit_clear_request(neigh, lci, 0x0D); */ - kfree_skb(skb); + printk(KERN_DEBUG "x25_receive_data(): unknown frame type %2x\n",frametype); return 0; } diff -u --recursive --new-file v2.4.0-test8/linux/net/x25/x25_link.c linux/net/x25/x25_link.c --- v2.4.0-test8/linux/net/x25/x25_link.c Fri Apr 14 09:38:10 2000 +++ linux/net/x25/x25_link.c Sun Sep 17 10:03:43 2000 @@ -17,6 +17,7 @@ * X.25 002 Jonathan Naylor New timer architecture. * mar/20/00 Daniela Squassoni Disabling/enabling of facilities * negotiation. + * 2000-09-04 Henner Eisen dev_hold() / dev_put() for x25_neigh. */ #include @@ -292,6 +293,7 @@ init_timer(&x25_neigh->t20timer); + dev_hold(dev); x25_neigh->dev = dev; x25_neigh->state = X25_LINK_STATE_0; x25_neigh->extended = 0; @@ -349,8 +351,10 @@ neigh = x25_neigh; x25_neigh = x25_neigh->next; - if (neigh->dev == dev) + if (neigh->dev == dev){ x25_remove_neigh(neigh); + dev_put(dev); + } } } diff -u --recursive --new-file v2.4.0-test8/linux/net/x25/x25_out.c linux/net/x25/x25_out.c --- v2.4.0-test8/linux/net/x25/x25_out.c Tue Feb 10 13:07:49 1998 +++ linux/net/x25/x25_out.c Sun Sep 17 10:03:43 2000 @@ -15,6 +15,7 @@ * History * X.25 001 Jonathan Naylor Started coding. * X.25 002 Jonathan Naylor New timer architecture. + * 2000-09-04 Henner Eisen Prevented x25_output() skb leakage. */ #include @@ -56,7 +57,7 @@ /* * This is where all X.25 information frames pass; */ -void x25_output(struct sock *sk, struct sk_buff *skb) +int x25_output(struct sock *sk, struct sk_buff *skb) { struct sk_buff *skbn; unsigned char header[X25_EXT_MIN_LEN]; @@ -73,9 +74,12 @@ frontlen = skb_headroom(skb); while (skb->len > 0) { - if ((skbn = sock_alloc_send_skb(sk, frontlen + max_len, 0, 0, &err)) == NULL) - return; - + if ((skbn = sock_alloc_send_skb(sk, frontlen + max_len, 0, 0, &err)) == NULL){ + int unsent = skb->len - header_len; + SOCK_DEBUG(sk, "x25_output: framgent allocation failed, err=%d, %d bytes unsent\n", err, unsent); + return err; + } + skb_reserve(skbn, frontlen); len = (max_len > skb->len) ? skb->len : max_len; @@ -102,6 +106,7 @@ } else { skb_queue_tail(&sk->write_queue, skb); } + return 0; } /* diff -u --recursive --new-file v2.4.0-test8/linux/scripts/Configure linux/scripts/Configure --- v2.4.0-test8/linux/scripts/Configure Fri Aug 4 18:38:44 2000 +++ linux/scripts/Configure Thu Sep 21 13:20:16 2000 @@ -570,7 +570,7 @@ if [ ! -f .hdepend -o "$CONFIG_MODVERSIONS" = "y" ] ; then echo "*** Next, you must run 'make dep'." else - echo "*** Next, you may run 'make zImage', 'make zdisk', or 'make zlilo'." + echo "*** Next, you may run 'make bzImage', 'make bzdisk', or 'make install'." fi echo diff -u --recursive --new-file v2.4.0-test8/linux/scripts/ksymoops/README linux/scripts/ksymoops/README --- v2.4.0-test8/linux/scripts/ksymoops/README Thu Jul 1 10:54:31 1999 +++ linux/scripts/ksymoops/README Tue Oct 3 09:24:41 2000 @@ -1,7 +1,8 @@ ksymoops has been removed from the kernel. It was always meant to be a free standing utility, not linked to any particular kernel version. -The latest version can be found in ftp://ftp.ocs.com.au/pub/ksymoops, -together with patches to other utilities in order to give more accurate -Oops debugging. +The latest version can be found in +ftp://ftp..kernel.org/pub/linux/utils/kernel/ksymoops together +with patches to other utilities in order to give more accurate Oops +debugging. Keith Owens Sat Jun 19 10:30:34 EST 1999 diff -u --recursive --new-file v2.4.0-test8/linux/scripts/makelst linux/scripts/makelst --- v2.4.0-test8/linux/scripts/makelst Wed Dec 31 16:00:00 1969 +++ linux/scripts/makelst Mon Sep 18 14:59:23 2000 @@ -0,0 +1,21 @@ +#!/bin/bash +# A script to dump mixed source code & assembly +# with correct relocations from System.map +# Requires the following lines in Rules.make. +# +#%.lst: %.c +# $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -g -c -o $*.o $< +# $(TOPDIR)/scripts/makelst $* $(TOPDIR) $(OBJDUMP) +# +# Copyright (C) 2000 IBM Corporation +# Author(s): DJ Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) +# + +t1=`$3 --syms $2/$1.o | grep .text | grep " F " | head -n 1` +t2=`echo $t1 | gawk '{ print $6 }'` +t3=`grep $t2 $2/System.map` +t4=`echo $t3 | gawk '{ print $1 }'` +t5=`echo $t1 | gawk '{ print $1 }'` +t6=`echo $t4 - $t5 | sed s/a/A/g | sed s/b/B/g | sed s/c/C/g | sed s/d/D/g | sed s/e/E/g | sed s/f/F/g` +t7=`( echo ibase=16 ; echo $t6 ) | bc` +$3 --source --adjust-vma=$t7 $2/$1.o > $2/$1.lst diff -u --recursive --new-file v2.4.0-test8/linux/scripts/mkdep.c linux/scripts/mkdep.c --- v2.4.0-test8/linux/scripts/mkdep.c Wed May 24 08:29:47 2000 +++ linux/scripts/mkdep.c Wed Sep 27 14:09:30 2000 @@ -81,15 +81,9 @@ */ void grow_config(int len) { - if (str_config == NULL) { - len_config = 0; - size_config = 4096; - str_config = malloc(4096); - if (str_config == NULL) - { perror("malloc"); exit(1); } - } - while (len_config + len > size_config) { + if (size_config == 0) + size_config = 2048; str_config = realloc(str_config, size_config *= 2); if (str_config == NULL) { perror("malloc config"); exit(1); } @@ -157,15 +151,9 @@ */ void grow_precious(int len) { - if (str_precious == NULL) { - len_precious = 0; - size_precious = 4096; - str_precious = malloc(4096); - if (str_precious == NULL) - { perror("malloc precious"); exit(1); } - } - while (len_precious + len > size_precious) { + if (size_precious == 0) + size_precious = 2048; str_precious = realloc(str_precious, size_precious *= 2); if (str_precious == NULL) { perror("malloc"); exit(1); } @@ -294,6 +282,7 @@ * The state machine looks for (approximately) these Perl regular expressions: * * m|\/\*.*?\*\/| + * m|\/\/.*| * m|'.*?'| * m|".*?"| * m|#\s*include\s*"(.*?)"| @@ -326,9 +315,18 @@ CASE('C', cee); goto start; +/* // */ +slash_slash: + GETNEXT + CASE('\n', start); + NOTCASE('\\', slash_slash); + GETNEXT + goto slash_slash; + /* / */ slash: GETNEXT + CASE('/', slash_slash); NOTCASE('*', __start); slash_star_dot_star: GETNEXT diff -u --recursive --new-file v2.4.0-test8/linux/scripts/ver_linux linux/scripts/ver_linux --- v2.4.0-test8/linux/scripts/ver_linux Tue Dec 14 23:05:03 1999 +++ linux/scripts/ver_linux Sun Sep 17 09:45:06 2000 @@ -10,6 +10,8 @@ uname -a insmod -V 2>&1 | awk 'NR==1 {print "Kernel modules ",$NF}' echo "Gnu C " `gcc --version` +make --version 2>&1 | awk -F, '{print $1}' | awk \ + '/GNU Make/{print "Gnu Make ",$NF}' ld -v 2>&1 | awk -F\) '{print $1}' | awk \ '/BFD/{print "Binutils ",$NF}' ls -l `ldd /bin/sh | awk '/libc/{print $3}'` | sed -e 's/\.so$//' \