diff -urN linux-2.4.23-pre8/CREDITS linux-2.4.23-pre8-pac1/CREDITS --- linux-2.4.23-pre8/CREDITS 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/CREDITS 2003-10-24 14:31:25.000000000 +0200 @@ -63,10 +63,9 @@ S: Belgium N: Anton Altaparmakov -E: aia21@cus.cam.ac.uk +E: aia21@cantab.net W: http://www-stu.christs.cam.ac.uk/~aia21/ -D: NTFS driver maintainer. NTFS fixes and cleanup. -D: Tiny fixes in linear md device and emu10k1 driver. +D: Author of new NTFS driver, various other kernel hacks. S: Christ's College S: Cambridge CB2 3BU S: United Kingdom @@ -2611,6 +2610,12 @@ S: 7000 Stuttgart 50 S: Germany +N: Andrew Rodland +E: arodland@linuxguru.net +D: That crazy morse code thing. +P: D2B1 5215 B1B9 18E0 B6AD 6ADD 4373 165F 1770 BD5C +S: Pennsylvania, USA + N: Christoph Rohland E: hans-christoph.rohland@sap.com E: ch.rohland@gmx.net diff -urN linux-2.4.23-pre8/Documentation/00-INDEX linux-2.4.23-pre8-pac1/Documentation/00-INDEX --- linux-2.4.23-pre8/Documentation/00-INDEX 2001-08-27 16:44:15.000000000 +0200 +++ linux-2.4.23-pre8-pac1/Documentation/00-INDEX 2003-10-24 14:31:25.000000000 +0200 @@ -52,6 +52,8 @@ - directory with information on the CD-ROM drivers that Linux has. computone.txt - info on Computone Intelliport II/Plus Multiport Serial Driver +cpufreq + - describes the CPU frequency and voltage scaling support cpqarray.txt - info on using Compaq's SMART2 Intelligent Disk Array Controllers. devices.txt diff -urN linux-2.4.23-pre8/Documentation/Changes linux-2.4.23-pre8-pac1/Documentation/Changes --- linux-2.4.23-pre8/Documentation/Changes 2002-11-29 00:53:08.000000000 +0100 +++ linux-2.4.23-pre8-pac1/Documentation/Changes 2003-10-24 14:31:25.000000000 +0200 @@ -56,7 +56,9 @@ o e2fsprogs 1.25 # tune2fs o jfsutils 1.0.12 # fsck.jfs -V o reiserfsprogs 3.6.3 # reiserfsck -V 2>&1|grep reiserfsprogs +o xfsprogs 2.1.0 # xfs_db -V o pcmcia-cs 3.1.21 # cardmgr -V +o quota-tools 3.09 # quota -V o PPP 2.4.0 # pppd --version o isdn4k-utils 3.1pre1 # isdnctrl 2>&1|grep version @@ -190,6 +192,17 @@ versions of mkreiserfs, resize_reiserfs, debugreiserfs and reiserfsck. These utils work on both i386 and alpha platforms. +Xfsprogs +-------- + +The latest version of xfsprogs contains mkfs.xfs, xfs_db, and the +xfs_repair utilities, among others, for the XFS filesystem. It is +architecture independent and any version from 2.0.0 onward should +work correctly with this version of the XFS kernel code. For the new +(v2) log format that has better support for stripe-size aligning on +LVM and MD devices at least xfsprogs 2.1.0 is needed. + + Pcmcia-cs --------- @@ -197,6 +210,14 @@ kernel source. Pay attention when you recompile your kernel ;-). Also, be sure to upgrade to the latest pcmcia-cs release. +Quota-tools +----------- + +Support for 32 bit uid's and gid's is required if you want to use +the newer version 2 quota format. Quota-tools version 3.07 and +newer has this support. Use the recommended version or newer +from the table above. + Intel IA32 microcode -------------------- @@ -327,6 +348,10 @@ ------------- o +Xfsprogs +-------- +o + LVM toolset ----------- o @@ -335,6 +360,10 @@ --------- o +Quota-tools +---------- +o + Jade ---- o diff -urN linux-2.4.23-pre8/Documentation/Configure.help linux-2.4.23-pre8-pac1/Documentation/Configure.help --- linux-2.4.23-pre8/Documentation/Configure.help 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/Documentation/Configure.help 2003-10-24 14:31:25.000000000 +0200 @@ -271,6 +271,12 @@ If you don't have this computer, you may safely say N. +Clustered APIC support +CONFIG_X86_CLUSTERED_APIC + This option is required to support systems with more than 8 logical CPUs. + + If you don't have such a computer, you may safely say N. + IO-APIC support on uniprocessors CONFIG_X86_UP_IOAPIC An IO-APIC (I/O Advanced Programmable Interrupt Controller) is an @@ -473,8 +479,14 @@ The initial RAM disk is a RAM disk that is loaded by the boot loader (loadlin or lilo) and that is mounted as root before the normal boot procedure. It is typically used to load modules needed to mount the - "real" root file system, etc. See - for details. + "real" root file system, etc. + + Due to a problem elsewhere in the kernel, initial RAM disks _must_ + have the file system on them created with a 1024 byte block size. + If any other value is used, the kernel will be unable to mount the + RAM disk at boot time, causing a kernel panic. + + See for details. Embed root filesystem ramdisk into the kernel CONFIG_EMBEDDED_RAMDISK @@ -1274,20 +1286,23 @@ If unsure, say N. -PROMISE PDC20246/PDC20262/PDC20265/PDC20267/PDC20268 support +PROMISE PDC20246/PDC20262/PDC20265/PDC20267 support CONFIG_BLK_DEV_PDC202XX_OLD - Promise Ultra33 or PDC20246 - Promise Ultra66 or PDC20262 - Promise Ultra100 or PDC20265/PDC20267/PDC20268 + Promise Ultra 33 [PDC20246] + Promise Ultra 66 [PDC20262] + Promise FastTrak 66 [PDC20263] + Promise MB Ultra 100 [PDC20265] + Promise Ultra 100 [PDC20267] This driver adds up to 4 more EIDE devices sharing a single - interrupt. This add-on card is a bootable PCI UDMA controller. Since + interrupt. This device is a bootable PCI UDMA controller. Since multiple cards can be installed and there are BIOS ROM problems that - happen if the BIOS revisions of all installed cards (three-max) do + happen if the BIOS revisions of all installed cards (max of three) do not match, the driver attempts to do dynamic tuning of the chipset - at boot-time for max-speed. Ultra33 BIOS 1.25 or newer is required + at boot-time for max speed. Ultra33 BIOS 1.25 or newer is required for more than one card. This card may require that you say Y to - "Special UDMA Feature". + "Special UDMA Feature" to force UDMA mode for connected UDMA capable + disk drives. If you say Y here, you need to say Y to "Use DMA by default when available" as well. @@ -1320,7 +1335,30 @@ If unsure, say N. -Special UDMA Feature +PROMISE PDC202{68|69|70|71|75|76|77} support +CONFIG_BLK_DEV_PDC202XX_NEW + Promise Ultra 100 TX2 [PDC20268] + Promise Ultra 133 PTX2 [PDC20269] + Promise FastTrak LP/TX2/TX4 [PDC20270] + Promise FastTrak TX2000 [PDC20271] + Promise MB Ultra 133 [PDC20275] + Promise MB FastTrak 133 [PDC20276] + Promise FastTrak 133 [PDC20277] + + This driver adds up to 4 more EIDE devices sharing a single + interrupt. This device is a bootable PCI UDMA controller. Since + multiple cards can be installed and there are BIOS ROM problems that + happen if the BIOS revisions of all installed cards (max of five) do + not match, the driver attempts to do dynamic tuning of the chipset + at boot-time for max speed. Ultra33 BIOS 1.25 or newer is required + for more than one card. + + If you say Y here, you need to say Y to "Use DMA by default when + available" as well. + + If unsure, say N. + +Override-Enable UDMA for Promise Controllers CONFIG_PDC202XX_BURST This option causes the pdc202xx driver to enable UDMA modes on the PDC202xx even when the PDC202xx BIOS has not done so. @@ -1330,14 +1368,24 @@ used successfully on a PDC20265/Ultra100, allowing use of UDMA modes when the PDC20265 BIOS has been disabled (for faster boot up). - Please read the comments at the top of - . - If unsure, say N. -Special FastTrak Feature +Use FastTrak RAID capable device as plain IDE controller CONFIG_PDC202XX_FORCE - For FastTrak enable overriding BIOS. + Setting this option causes the kernel to use your Promise IDE disk + controller as an ordinary IDE controller, rather than as a FastTrak + RAID controller. RAID is a system for using multiple physical disks + as one virtual disk. + + You need to say Y here if you have a PDC20276 IDE interface but either + you do not have a RAID disk array, or you wish to use the Linux + internal RAID software (/dev/mdX). + + You need to say N here if you wish to use your Promise controller to + control a FastTrak RAID disk array, and you you must also say Y to + CONFIG_BLK_DEV_ATARAID_PDC. + + If unsure, say Y. SiS5513 chipset support CONFIG_BLK_DEV_SIS5513 @@ -1912,6 +1960,20 @@ want), say M here and read . The module will be called lvm-mod.o. +Device-mapper support +CONFIG_BLK_DEV_DM + Device-mapper is a low level volume manager. It works by allowing + people to specify mappings for ranges of logical sectors. Various + mapping types are available, in addition people may write their own + modules containing custom mappings if they wish. + + Higher level volume managers such as LVM2 use this driver. + + If you want to compile this as a module, say M here and read + . The module will be called dm-mod.o. + + If unsure, say N. + Multiple devices driver support (RAID and LVM) CONFIG_MD Support multiple physical spindles through a single logical device. @@ -5211,10 +5273,10 @@ Matrox unified accelerated driver CONFIG_FB_MATROX - Say Y here if you have a Matrox Millennium, Millennium II, Mystique, - Mystique 220, Productiva G100, Mystique G200, Millennium G200, - Matrox G400, G450 or G550 card in your box. At this time, support for - the G-series digital output is almost non-existant. + Say Y here if you have a Matrox Millennium, Matrox Millennium II, + Matrox Mystique, Matrox Mystique 220, Matrox Productiva G100, Matrox + Mystique G200, Matrox Millennium G200, Matrox Marvel G200 video, + Matrox G400, G450 or G550 card in your box. This driver is also available as a module ( = code which can be inserted and removed from the running kernel whenever you want). @@ -5789,6 +5851,19 @@ replacement for kerneld.) Say Y here and read about configuring it in . +Kernel .config file saved in kernel image +CONFIG_IKCONFIG + This option enables the complete Linux kernel ".config" file contents + to be saved in the kernel (zipped) image file. It provides + documentation of which kernel options are used in a running kernel or + in an on-disk kernel. It can be extracted from the kernel image file + with a script and used as input to rebuild the current kernel or to + build another kernel. Since the kernel image is zipped, using this + option adds approximately 8 KB to a kernel image file. + This option is not available as a module. If you want a separate + file to save the kernel's .config contents, use 'installkernel' or 'cp' + or a similar tool, or just save it in '/lib/modules/'. + ARP daemon support CONFIG_ARPD Normally, the kernel maintains an internal cache which maps IP @@ -8135,9 +8210,7 @@ Adapters. Consult the SCSI-HOWTO, available from , and the files and - for more information. If this - driver does not work correctly without modification, please contact - the author, Leonard N. Zubkoff, by email to lnz@dandelion.com. + for more information. You can also build this driver as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -9834,7 +9907,7 @@ Aironet 4500/4800 I365 broken support CONFIG_AIRONET4500_I365 If you have a PCMCIA Aironet 4500/4800 card which you want to use - without the standard PCMCIA cardservices provided by the pcmcia-cs + without the standard PCMCIA card services provided by the pcmcia-cs package, say Y here. This is not recommended, so say N. Aironet 4500/4800 PCMCIA support @@ -12593,6 +12666,11 @@ . The module will be called apricot.o. +Broadcom BCM4400 support +CONFIG_NET_BCM4400 + This adds support for the Broadcom 4400 series of Ethernet drivers + using the v2.0.0 drivers. See Documentation/networking/bcm4400.txt + Generic DECchip & DIGITAL EtherWORKS PCI/EISA CONFIG_DE4X5 This is support for the DIGITAL series of PCI/EISA Ethernet cards. @@ -13559,6 +13637,24 @@ need this functionality say Y here. Note that you will need latest quota utilities for new quota format with this kernel. +Compatible quota interfaces +CONFIG_QIFACE_COMPAT + This option will enable old quota interface in kernel. + If you have old quota tools (version <= 3.04) and you don't want to + upgrade them say Y here. + +Original quota interface +CONFIG_QIFACE_V1 + This is the oldest quota interface. It was used for old quota format. + If you have old quota tools and you use old quota format choose this + interface (if unsure, this interface is the best one to choose). + +VFS v0 quota interface +CONFIG_QIFACE_V2 + This quota interface was used by VFS v0 quota format. If you need + support for VFS v0 quota format (eg. you're using quota on ReiserFS) + and you don't want to upgrade quota tools, choose this interface. + Memory Technology Device (MTD) support CONFIG_MTD Memory Technology Devices are flash, RAM and similar chips, often @@ -13619,14 +13715,15 @@ . The module will be called redboot.o +Command line partition table parsing CONFIG_MTD_CMDLINE_PARTS Allow generic configuration of the MTD paritition tables via the kernel command line. Multiple flash resources are supported for hardware where - different kinds of flash memory are available. + different kinds of flash memory are available. You will still need the parsing functions to be called by the driver - for your particular device. It won't happen automatically. The - SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for + for your particular device. It won't happen automatically. The + SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for example. The format for the command line is as follows: @@ -13635,12 +13732,12 @@ := :[,] := [@offset][][ro] := unique id used in mapping driver/device - := standard linux memsize OR "-" to denote all + := standard linux memsize OR "-" to denote all remaining space := (NAME) - Due to the way Linux handles the command line, no spaces are - allowed in the partition definition, including mtd id's and partition + Due to the way Linux handles the command line, no spaces are + allowed in the partition definition, including mtd id's and partition names. Examples: @@ -13651,6 +13748,8 @@ Same flash, but 2 named partitions, the first one being read-only: mtdparts=sa1100:256k(ARMboot)ro,-(root) + If compiled as a module, it will be called cmdlinepart.o. + If unsure, say 'N'. MTD concatenating support @@ -13829,6 +13928,7 @@ If you wish to support CFI devices on a physical bus which is 32 bits wide, say 'Y'. +Support 64-bit buswidth CONFIG_MTD_CFI_B8 If you wish to support CFI devices on a physical bus which is 64 bits wide, say 'Y'. @@ -13848,6 +13948,7 @@ If your flash chips are interleaved in fours - i.e. you have four flash chips addressed by each bus cycle, then say 'Y'. +Support 8-chip flash interleave CONFIG_MTD_CFI_I8 If your flash chips are interleaved in eights - i.e. you have eight flash chips addressed by each bus cycle, then say 'Y'. @@ -13884,6 +13985,14 @@ provides support for one of those command sets, used on chips chips including the AMD Am29LV320. +Support for ST (Advanced Architecture) flash chips +CONFIG_MTD_CFI_STAA + The Common Flash Interface defines a number of different command + sets which a CFI-compliant chip may claim to implement. This code + provides support for one of those command sets. + + If compiled as a module, it will be called cfi_cmdset_0020.o. + CFI support for Intel/Sharp Standard Commands CONFIG_MTD_CFI_INTELSTD The Common Flash Interface defines a number of different command @@ -13916,11 +14025,6 @@ . The module will be called amd_flash.o -CONFIG_MTD_CFI_STAA - The Common Flash Interface defines a number of different command - sets which a CFI-compliant chip may claim to implement. This code - provides support for one of those command sets. - Support for RAM chips in bus mapping CONFIG_MTD_RAM This option enables basic support for RAM chips accessed through @@ -14351,6 +14455,12 @@ is only really useful if you are developing on this driver or suspect a possible hardware or driver bug. If unsure say N. +DEC MS02-NV NVRAM module support +CONFIG_MTD_MS02NV + Support for NVRAM module on DECstation. + + If compiled as a module, it will be called ms02-nv.o. + Use extra onboard system memory as MTD device CONFIG_MTD_SLRAM If your CPU cannot cache all of the physical memory in your machine, @@ -14759,12 +14869,11 @@ The module will be called powermate.o. If you want to compile it as a module, say M here and read . -Aiptek HyperPen tablet support +Aiptek 6000U/8000U tablet support CONFIG_USB_AIPTEK - Say Y here if you want to use the USB version of the Aiptek HyperPen - Digital Tablet (models 4000U, 5000U, 6000U, 8000U, and 12000U.) - Make sure to say Y to "Mouse support" (CONFIG_INPUT_MOUSEDEV) and/or - "Event interface support" (CONFIG_INPUT_EVDEV) as well. + Say Y here if you want to use the USB version of the Aiptek 6000U/8000U + tablet. Make sure to say Y to "Event interface support" + (CONFIG_INPUT_EVDEV) as well. This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -15479,7 +15588,7 @@ This code is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). - The module will be called ax8817x.o. If you want to compile it as a + The module will be called catc.o. If you want to compile it as a module, say M here and read . USB Kodak DC-2xx Camera support @@ -16761,34 +16870,45 @@ NTFS file system support (read-only) CONFIG_NTFS_FS - NTFS is the file system of Microsoft Windows NT. Say Y if you want - to get read access to files on NTFS partitions of your hard drive. - The Linux NTFS driver supports most of the mount options of the VFAT - driver, see . Saying Y here - will give you read-only access to NTFS partitions. + NTFS is the file system of Microsoft Windows NT/2000/XP. For more + information see . Saying Y + here would allow you to read from NTFS partitions. - This code is also available as a module ( = code which can be + This file system 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 ntfs.o. If you want to compile it as a module, say M here and read . -NTFS write support (DANGEROUS) + If you are not using Windows NT/2000/XP in addition to Linux on your + computer it is safe to say N. + +CONFIG_NTFS_DEBUG + If you are experiencing any problems with the NTFS file system, say + Y here. This will result in additional consistency checks to be + performed by the driver as well as additional debugging messages to + be written to the system log. Note that debugging messages are + disabled by default. To enable them, supply the option debug_msgs=1 + at the kernel command line when booting the kernel or as an option + to insmod when loading the ntfs module. Once the driver is active, + you can enable debugging messages by doing (as root): + echo 1 > /proc/sys/fs/ntfs-debug + Replacing the "1" with "0" would disable debug messages. + + If you leave debugging messages disabled, this results in little + overhead, but enabling debug messages results in very significant + slowdown of the system. + + When reporting bugs, please try to have available a full dump of + debugging messages while the misbehaviour was occurring. + CONFIG_NTFS_RW - If you say Y here, you will (maybe) be able to write to NTFS file - systems as well as read from them. The read-write support in NTFS - is far from being complete and is not well tested. If you say Y - here, back up your NTFS volume first, since it will probably get - damaged. Also, download the Linux-NTFS project distribution from - Sourceforge at and always run the - included ntfsfix utility after writing to an NTFS partition from - Linux to fix some of the damage done by the driver. You should run - ntfsfix _after_ unmounting the partition in Linux but _before_ - rebooting into Windows. When Windows next boots, chkdsk will be - run automatically to fix the remaining damage. - Please note that write support is limited to Windows NT4 and - earlier versions. + This enables the experimental write support in the NTFS driver. - If unsure, say N. + WARNING: Do not use this option unless you are actively developing + NTFS as it is currently guaranteed to be broken and you + may lose all your data! + + It is strongly recommended and perfectly safe to say N here. System V/Xenix/V7/Coherent file system support CONFIG_SYSV_FS @@ -16850,7 +16970,7 @@ say M here and read . If unsure, say N. -Apple HFS file system support +Apple Macintosh file system support CONFIG_HFS_FS If you say Y here, you will be able to mount Macintosh-formatted floppy disks and hard drive partitions with full read-write access. @@ -16863,7 +16983,7 @@ compile it as a module, say M here and read . -Apple HFS+ (Extended HFS) file system support +Apple Extended file system support (EXPERIMENTAL) CONFIG_HFSPLUS_FS If you say Y here, you will be able to mount extended format Macintosh-formatted hard drive partitions with full read-write access. @@ -17056,6 +17176,78 @@ Say Y here if you want to try writing to UFS partitions. This is experimental, so you should back up your UFS partitions beforehand. +XFS filesystem support +CONFIG_XFS_FS + XFS is a high performance journaling filesystem which originated + on the SGI IRIX platform. It is completely multi-threaded, can + support large files and large filesystems, extended attributes, + variable block sizes, is extent based, and makes extensive use of + Btrees (directories, extents, free space) to aid both performance + and scalability. + + Refer to the documentation at + for complete details. This implementation is on-disk compatible + with the IRIX version of XFS. + + If you want to compile this file system as a module ( = code which + can be inserted in and removed from the running kernel whenever you + want), say M here and read . The + module will be called xfs.o. Be aware, however, that if the file + system of your root partition is compiled as a module, you'll need + to use an initial ramdisk (initrd) to boot. + +Quota support +CONFIG_XFS_QUOTA + If you say Y here, you will be able to set limits for disk usage on + a per user and/or per group basis under XFS. XFS considers quota + information as filesystem metadata and uses journaling to provide a + higher level guarantee of consistency. The on-disk data format for + quota is also compatible with the IRIX version of XFS, allowing a + filesystem to be migrated between Linux and IRIX without any need + for conversion. + + If unsure, say N. More comprehensive documentation can be found in + README.quota in the xfsprogs package. XFS quota can be used either + with or without the generic quota support enabled (CONFIG_QUOTA) - + they are completely independent subsystems. + +Realtime support (EXPERIMENTAL) +CONFIG_XFS_RT + If you say Y here you will be able to mount and use XFS filesystems + which contain a realtime subvolume. The realtime subvolume is a + separate area of disk space where only file data is stored. The + realtime subvolume is designed to provide very deterministic + data rates suitable for media streaming applications. + + See the xfs man page in section 5 for a bit more information. + + This feature is unsupported at this time, is not yet fully + functional, and may cause serious problems. + + If unsure, say N. + +Debugging support (EXPERIMENTAL) +CONFIG_XFS_DEBUG + Say Y here to get an XFS build with many debugging features, + including ASSERT checks, function wrappers around macros, + and extra sanity-checking functions in various code paths. + + Note that the resulting code will be HUGE and SLOW, and probably + not useful unless you are debugging a particular problem. + + Say N unless you are an XFS developer, or play one on TV. + +Pagebuf debugging support (EXPERIMENTAL) +CONFIG_PAGEBUF_DEBUG + Say Y here to get an XFS build which may help you debug pagebuf + problems. Enabling this option will attach tracing information + to pagebufs, which can be read with the kdb kernel debugger. + + Note that you will also have to enable the sysctl in + /proc/sys/vm/pagebuf/debug for this to work. + + Say N unless you're interested in debugging pagebuf. + Advanced partition selection CONFIG_PARTITION_ADVANCED Say Y here if you would like to use hard disks under Linux which @@ -17105,7 +17297,7 @@ Say Y here if you would like to use hard disks under Linux which were partitioned on a Macintosh. -Windows Logical Disk Manager (Dynamic Disk) support (EXPERIMENTAL) +Windows Logical Disk Manager (Dynamic Disk) support CONFIG_LDM_PARTITION Say Y here if you would like to use hard disks under Linux which were partitioned using Windows 2000's or XP's Logical Disk Manager. @@ -17120,8 +17312,7 @@ Normal partitions are now called Basic Disks under Windows 2000 and XP. - Technical documentation to accompany this driver is available from: - . + For a fuller description read . If unsure, say N. @@ -17194,8 +17385,9 @@ Intel EFI GUID partition support CONFIG_EFI_PARTITION Say Y here if you would like to use hard disks under Linux which - were partitioned using EFI GPT. Presently only useful on the - IA-64 platform. + were partitioned using EFI GPT. This is the default partition + scheme on IA64, and can be used on other platforms when + large block device (64-bit block address) support is desired. Ultrix partition table support CONFIG_ULTRIX_PARTITION @@ -18037,17 +18229,36 @@ HIL keyboard support CONFIG_HIL The "Human Interface Loop" is a older, 8-channel USB-like controller - used in Hewlett Packard PA-RISC based machines. There are a few - cases where it is seen on PC/MAC architectures as well, usually also - manufactured by HP. This driver is based off MACH and BSD drivers, - and implements support for a keyboard attached to the HIL port. + used in several Hewlett Packard models. This driver is based off + MACH and BSD drivers, and implements support for a keyboard attached + to the HIL port, but not for any other types of HIL input devices + like mice or tablets. However, it has been thoroughly tested and is + stable. + Full support for the USB-like functions and non-keyboard channels of - the HIL is not provided for in this driver. There are vestiges of - mouse support in the driver, but it is probably not working. The - necessary hardware documentation to fully support the HIL controller - and interface it to the linux-input API is lacking. + the HIL is currently being added to the PA-RISC port and will + be backported to work on the m68k port as well. + + Enable this option if you intend to use a HIL keyboard as your + primary keyboard and/or do not wish to test the new HIL driver. - Enable this option if you intend to use a HIL keyboard. +HP System Device Controller support +CONFIG_HP_SDC + This option enables supports for the the "System Device Controller", + an i8042 carrying microcode to manage a few miscellanous devices + on some Hewlett Packard systems. The SDC itself contains a 10ms + resolution timer/clock capable of delivering interrupts on periodic + and one-shot basis. The SDC may also be connected to a battery-backed + real-time clock, a basic audio waveform generator, and an HP-HIL + Master Link Controller serving up to seven input devices. + + By itself this option is rather useless, but enabling it will + enable selection of drivers for the abovementioned devices. + It is, however, incompatible with the old, reliable HIL keyboard + driver, and the new HIL driver is experimental, so if you plan to + use a HIL keyboard as your primary keyboard, you may wish to + keep using that driver until the new HIL drivers have had more + testing. HP System Device Controller support CONFIG_HP_SDC @@ -18263,6 +18474,27 @@ If you want to compile this driver as a module, say M here and read . The module will be called pcxx.o. +Cyclades-PC300 support +CONFIG_PC300 + This is a driver for the Cyclades-PC300 synchronous communication + boards. These boards provide synchronous serial interfaces to your + Linux box (interfaces currently available are RS-232/V.35, X.21 and + T1/E1). If you wish to support Multilink PPP, please select the + option below this one and read the file README.mlppp provided by PC300 + package. + + 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. The module will be + called pc300.o. + + If you haven't heard about it, it's safe to say N. + +Cyclades-PC300 Sync TTY (to MLPPP) support +CONFIG_PC300_MLPPP + Say 'Y' to this option if you are planning to use Multilink PPP over the + PC300 synchronous communication boards. + SDL RISCom/8 card support CONFIG_RISCOM8 This is a driver for the SDL Communications RISCom/8 multiport card, @@ -18395,6 +18627,42 @@ root on this console.) 4. Change the kernel command console parameter to: console=ttyB0 +PDC software console support +CONFIG_PDC_CONSOLE + Saying Y here will enable the software based PDC console to be + used as the system console. This is useful for machines in + which the hardware based console has not been written yet. The + following steps must be competed to use the PDC console: + + 1. create the device entry (mknod /dev/ttyB0 c 60 0) + 2. Edit the /etc/inittab to start a getty listening on /dev/ttyB0 + 3. Add device ttyB0 to /etc/securetty (if you want to log on as + root on this console.) + 4. Change the kernel command console parameter to: console=ttyB0 + +Serial MUX support +CONFIG_SERIAL_MUX + Saying Y here will enable the hardware MUX serial driver for + the Nova and K Class systems. Due to limitations in the 2.4 + serial console driver, the Serial MUX shares the same device + as the PDC software console (Instructions for creating the + /dev/ttyB0 device is listed in the PDC software console + support help). Hopefully the Serial MUX code will share the + /dev/ttyS0 code in new serial console code for 2.6. + +PDC software console support +CONFIG_PDC_CONSOLE + Saying Y here will enable the software based PDC console to be + used as the system console. This is useful for machines in + which the hardware based console has not been written yet. The + following steps must be competed to use the PDC console: + + 1. create the device entry (mknod /dev/ttyB0 c 11 0) + 2. Edit the /etc/inittab to start a getty listening on /dev/ttyB0 + 3. Add device ttyB0 to /etc/securetty (if you want to log on as + root on this console.) + 4. Change the kernel command console parameter to: console=ttyB0 + Microgate SyncLink adapter support CONFIG_SYNCLINK Provides support for the SyncLink ISA and PCI multiprotocol serial @@ -18544,6 +18812,14 @@ doing that; to actually get it to happen you need to pass the option "console=lp0" to the kernel at boot time. + Note that kernel messages can get lost if the printer is out of + paper (or off, or unplugged, or too busy..), but this behaviour + can be changed. See drivers/char/lp.c (do this at your own risk). + + Note that kernel messages can get lost if the printer is out of + paper (or off, or unplugged, or too busy..), but this behaviour + can be changed. See drivers/char/lp.c (do this at your own risk). + If the printer is out of paper (or off, or unplugged, or too busy..) the kernel will stall until the printer is ready again. By defining CONSOLE_LP_STRICT to 0 (at your own risk) you @@ -18854,6 +19130,15 @@ it as a module, say M here and read Documentation/modules.txt. The module will be called i2c-keywest.o. +Powermac Keywest I2C interface +CONFIG_I2C_KEYWEST + This supports the use of the I2C interface in the combo-I/O + chip on recent Apple machines. Say Y if you have such a machine. + + This driver is also available as a module. If you want to compile + it as a module, say M here and read Documentation/modules.txt. + The module will be called i2c-keywest.o. + Bus Mouse Support CONFIG_BUSMOUSE Say Y here if your machine has a bus mouse as opposed to a serial @@ -19370,6 +19655,13 @@ module will be called i830.o. AGP support is required for this driver to work. +Intel 830M, 845G, 852GM, 855GM, 865G +CONFIG_DRM_I830 + Choose this option if you have a system that has Intel 830M, 845G, + 852GM, 855GM or 865G integrated graphics. If M is selected, the + module will be called i830.o. AGP support is required for this driver + to work. + Matrox G200/G400/G450 CONFIG_DRM_MGA Choose this option if you have a Matrox G200, G400 or G450 graphics @@ -21743,17 +22035,6 @@ feature. See and for more information. -PPP filtering for ISDN -CONFIG_IPPP_FILTER - Say Y here if you want to be able to filter the packets passing over - IPPP interfaces. This allows you to control which packets count as - activity (i.e. which packets will reset the idle timer or bring up - a demand-dialled link) and which packets are to be dropped entirely. - You need to say Y here if you wish to use the pass-filter and - active-filter options to ipppd. - - If unsure, say N. - Support generic MP (RFC 1717) CONFIG_ISDN_MPP With synchronous PPP enabled, it is possible to increase throughput @@ -22130,6 +22411,11 @@ This enables HiSax support for the Formula-n enter:now PCI ISDN card. +Formula-n enter:now PCI card (EXPERIMENTAL) +CONFIG_HISAX_ENTERNOW_PCI + This enables HiSax support for the Formula-n enter:now PCI + ISDN card. + Am7930 CONFIG_HISAX_AMD7930 This enables HiSax support for the AMD7930 chips on some SPARCs. @@ -22607,7 +22893,6 @@ SCO Module (SCO links) RFCOMM Module (RFCOMM protocol) BNEP Module (BNEP protocol) - CMTP Module (CMTP protocol) Say Y here to enable Linux Bluetooth support and to build BlueZ Core layer. @@ -22662,15 +22947,6 @@ Say Y here to compile BNEP support into the kernel or say M to compile it as module (bnep.o). -CMTP protocol support -CONFIG_BLUEZ_CMTP - CMTP (CAPI Message Transport Protocol) is a transport layer - for CAPI messages. CMTP is required for the Bluetooth Common - ISDN Access Profile. - - Say Y here to compile CMTP support into the kernel or say M to - compile it as module (cmtp.o). - BNEP multicast filter support CONFIG_BLUEZ_BNEP_MC_FILTER This option enables the multicast filter support for BNEP. @@ -24861,24 +25137,28 @@ system console. Available only if 3270 support is compiled in statically. -Support for HWC line mode terminal -CONFIG_HWC - Include support for IBM HWC line-mode terminals. - -Console on HWC line mode terminal -CONFIG_HWC_CONSOLE - Include support for using an IBM HWC line-mode terminal as the Linux +Support for SCLP +CONFIG_SCLP + Include support for the IBM SCLP interface to the service element. + +Support for SCLP line mode terminal +CONFIG_SCLP_TTY + Include support for IBM SCLP line-mode terminals. + +Support for console on SCLP line mode terminal +CONFIG_SCLP_CONSOLE + Include support for using an IBM SCLP line-mode terminal as a Linux system console. -Control Program Identification -CONFIG_HWC_CPI - Allows for Control Program Identification via the HWC interface, - i.e. provides a mean to pass an OS instance name (system name) - to the machine. - - This option should only be selected as a module since the - system name has to be passed as module parameter. The module - will be called hwc_cpi.o. +Control-Program Identification +CONFIG_SCLP_CPI + This option enables the hardware console interface for system + identification. This is commonly used for workload management and + gives you a nice name for the system on the service element. + Please select this option as a module since built-in operation is + completely untested. + You should only select this option if you know what you are doing, + need this feature and intend to run your kernel in LPAR. S/390 tape device support CONFIG_S390_TAPE @@ -24974,20 +25254,6 @@ enabled, you'll be able to toggle chpids logically offline and online. Even if you don't understand what this means, you should say "Y". -Process warning machine checks -CONFIG_MACHCHK_WARNING - Select this option if you want the machine check handler on IBM S/390 or - zSeries to process warning machine checks (e.g. on power failures). - If unsure, say "Y". - -Use chscs for Common I/O -CONFIG_CHSC - Select this option if you want the s390 common I/O layer to use information - obtained by channel subsystem calls. This will enable Linux to process link - failures and resource accessibility events. Moreover, if you have procfs - enabled, you'll be able to toggle chpids logically offline and online. Even - if you don't understand what this means, you should say "Y". - Kernel support for 31 bit ELF binaries CONFIG_S390_SUPPORT Select this option if you want to enable your system kernel to @@ -25056,12 +25322,40 @@ a debugging option; you probably do not want to set it unless you are an S390 port maintainer. +Gigabit Ethernet device support +CONFIG_QETH + This driver supports the IBM S/390 and zSeries OSA Express adapters + in QDIO mode (all media types), HiperSockets interfaces and VM GuestLAN + interfaces in QDIO and HIPER mode. + + For details please refer to the documentation provided by IBM at + + + This driver is also available as a module (code which can be + inserted in and removed from the running kernel whenever you + want). If you want to compile it as a module, say 'M' here and + read file Documentation/modules.txt. + +IPv6 support for gigabit ethernet +CONFIG_QETH_IPV6 + If CONFIG_QETH is switched on, this option will include IPv6 + support in the qeth device driver. + +VLAN support for gigabit ethernet +CONFIG_QETH_VLAN + If CONFIG_QETH is switched on, this option will include IEEE + 802.1q VLAN support in the qeth device driver. + +Performance statistics in /proc +CONFIG_QETH_PERF_STATS + When switched on, this option will add a file in the proc-fs + (/proc/qeth_perf_stats) containing performance statistics. It + may slightly impact performance, so this is only recommended for + internal tuning of the device driver. + # # ARM options # -# CML2 transition note: CML1 asks ARCH_ARCA5K, then has ARCH_A5K and ARCH_ARK -# as subquestions. CML2 asks the subquestions in the armtype menu and makes -# ARCH_ARCA5K a derived symbol. ARM System type CONFIG_ARCH_ARCA5K This selects what ARM system you wish to build the kernel for. It @@ -25398,6 +25692,46 @@ while the decompressor is running. Unless you have special requirements, you should not change this value. +Disable I-Cache +CONFIG_CPU_ICACHE_DISABLE + Say Y here to disable the processor instruction cache. Unless + you have a reason not to or are unsure, say N. + +Disable D-Cache +CONFIG_CPU_DCACHE_DISABLE + Say Y here to disable the processor data cache. Unless + you have a reason not to or are unsure, say N. + +Force write through D-cache +CONFIG_CPU_DCACHE_WRITETHROUGH + Say Y here to use the data cache in write-through mode. Unless you + specifically require this or are unsure, say N. + +Round robin I and D cache replacement algorithm +CONFIG_CPU_CACHE_ROUND_ROBIN + Say Y here to use the predictable round-robin cache replacement + policy. Unless you specifically require this or are unsure, say N. + +Disable branch prediction +CONFIG_CPU_BPREDICT_DISABLE + Say Y here to disable branch prediction. If unsure, say N. + +Compressed boot loader in ROM/flash +CONFIG_ZBOOT_ROM + Say Y here if you intend to execute your compressed kernel image (zImage) + directly from ROM or flash. If unsure, say N. + +Compressed ROM boot loader base address +CONFIG_ZBOOT_ROM_TEXT + The base address for zImage. Unless you have special requirements, you + should not change this value. + +Compressed ROM boot loader BSS address +CONFIG_ZBOOT_ROM_BSS + The base address of 64KiB of read/write memory, which must be available + while the decompressor is running. Unless you have special requirements, + you should not change this value. + Support StrongARM SA-110 processor CONFIG_CPU_SA110 The Intel StrongARM(R) SA-110 is a 32-bit microprocessor and @@ -25964,6 +26298,44 @@ CONFIG_USB_SERIAL_KEYSPAN_MPR Say Y here to include firmware for the Keyspan MPR converter. +Tieman Voyager USB Braille display support (EXPERIMENTAL) +CONFIG_USB_BRLVGER + Say Y here if you want to use the Voyager USB Braille display from + Tieman. See for more + information. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called brlvger.o. If you want to compile it as + a module, say M here and read . + +KB Gear JamStudio tablet support +CONFIG_USB_KBTAB + Say Y here if you want to use the USB version of the KB Gear + JamStudio tablet. Make sure to say Y to "Mouse support" + (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support" + (CONFIG_INPUT_EVDEV) as well. + + 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 kbtab.o. If you want to compile it as a + module, say M here and read . + +USB Inside Out Edgeport Serial Driver (TI devices) +CONFIG_USB_SERIAL_EDGEPORT_TI + Say Y here if you want to use any of the devices from Inside Out + Networks (Digi) that are not supported by the io_edgeport driver. + This includes the Edgeport/1 device. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called io_ti.o. If you want to compile it + as a module, say M here and read . + +USB Keyspan MPR Firmware +CONFIG_USB_SERIAL_KEYSPAN_MPR + Say Y here to include firmware for the Keyspan MPR converter. + Winbond W83977AF IrDA Device Driver CONFIG_WINBOND_FIR Say Y here if you want to build IrDA support for the Winbond @@ -26034,7 +26406,7 @@ CONFIG_ALI_FIR Say Y here if you want to build support for the ALi M5123 FIR Controller. The ALi M5123 FIR Controller is embedded in ALi M1543C, - M1535, M1535D, M1535+, M1535D Sourth Bridge. This driver supports + M1535, M1535D, M1535+, M1535D South Bridge. This driver supports SIR, MIR and FIR (4Mbps) speeds. If you want to compile it as a module, say M here and read @@ -27297,6 +27669,11 @@ Enables some internal consistency checks for kernel debugging. You should normally say N. +Additional run-time checks +CONFIG_CHECKING + Enables some internal consistency checks for kernel debugging. + You should normally say N. + Read-write spinlock debugging CONFIG_DEBUG_RWLOCK If you say Y here then read-write lock processing will count how many @@ -27316,6 +27693,14 @@ of the BUG call as well as the EIP and oops trace. This aids debugging but costs about 70-100K of memory. +Morse code panics +CONFIG_PANIC_MORSE + Say Y here to receive panic messages in morse code on your keyboard LEDs, and + optionally the PC speaker, if available. + The kernel param "panicblink" controls this feature, set it to 0 to disable, + 1 for LEDs only, 2 for pc speaker, or 3 for both. If you disable this option, + then you will receive a steady blink on the LEDs instead. + Include kgdb kernel debugger CONFIG_KGDB Include in-kernel hooks for kgdb, the Linux kernel source level @@ -27361,9 +27746,11 @@ U2/Uturn I/O MMU CONFIG_IOMMU_CCIO - Say Y here to enable DMA management routines for the first - generation of PA-RISC cache-coherent machines. Programs the - U2/Uturn chip in "Virtual Mode" and use the I/O MMU. + The U2/UTurn is a bus converter with io mmu present in the Cxxx, D, + J, K, and R class machines. Compiling this driver into the kernel will + not hurt anything, removing it will reduce your kernel by about 14k. + + If unsure, say Y. LBA/Elroy PCI support CONFIG_PCI_LBA @@ -27777,20 +28164,13 @@ Say Y if you want support for the ARM926T processor. Otherwise, say N. -Support CPU clock change (EXPERIMENTAL) -CONFIG_CPU_FREQ - CPU clock scaling allows you to change the clock speed of the - running CPU on the fly. This is a nice method to save battery power, - because the lower the clock speed, the less power the CPU - consumes. Note that this driver doesn't automatically change the CPU - clock speed, you need some userland tools (which still have to be - written) to implement the policy. If you don't understand what this - is all about, it's safe to say 'N'. - SiS CONFIG_DRM_SIS - Choose this option if you have a SIS graphics card. AGP support is - required for this driver to work. + Choose this option if you have a SIS 300 series graphics card or + VGA controller (300, 305, 540, 630, 730). + + AGP support as well as the SiS framebuffer driver are required + for this driver to work. Etrax Ethernet slave support (over lp0/1) CONFIG_ETRAX_ETHERNET_LPSLAVE @@ -27800,7 +28180,7 @@ Slave has its own LEDs CONFIG_ETRAX_ETHERNET_LPSLAVE_HAS_LEDS - Enable if the slave has it's own LEDs. + Enable if the slave has its own LEDs. ATA/IDE support CONFIG_ETRAX_IDE @@ -27976,6 +28356,12 @@ hotplug firmware loading support, but a module built outside the kernel tree does. +Hotplug firmware loading support (EXPERIMENTAL) +CONFIG_FW_LOADER + This option is provided for the case where no in-kernel-tree modules require + hotplug firmware loading support, but a module built outside the kernel tree + does. + NatSemi SCx200 support CONFIG_SCx200 This provides basic support for the National Semiconductor SCx200 @@ -28137,7 +28523,7 @@ If compiled as a module, it will be called uclinux.o. NatSemi SCx200 I2C using GPIO pins -CONFIG_SCx200_GPIO +CONFIG_SCx200_I2C Enable the use of two GPIO pins of a SCx200 processor as an I2C bus. If you don't know what to do here, say N. @@ -28199,7 +28585,229 @@ This option is provided for the case where no in-kernel-tree modules require CRC32 functions, but a module built outside the kernel tree does. Such modules that use library CRC32 functions - require that you say M or Y here. + require M here. + +CONFIG_CPU_FREQ + Clock scaling allows you to change the clock speed of CPUs on the + fly. This is a nice method to save battery power on notebooks, + because the lower the clock speed, the less power the CPU consumes. + + For more information, take a look at linux/Documentation/cpu-freq. + + If in doubt, say N. + +CONFIG_CPU_FREQ_TABLE + Many CPUFreq drivers use these helpers, so only say N here if + the CPUFreq driver of your choice doesn't need these helpers. + + If in doubt, say Y. + + Wolfson AC97 Touchscreen support (EXPERIMENTAL) +CONFIG_SOUND_WM97XX + Say Y here to support the Wolfson WM9705 and WM9712 touchscreen + controllers. These controllers are mainly found in PDA's + i.e. Dell Axim and Toshiba e740 + + This is experimental code. + Please see Documentation/wolfson-touchscreen.txt for + a complete list of parameters. + + In order to use this driver, a char device called wm97xx with a major + number of 10 and minor number 16 will have to be created under + /dev/touchscreen. + + e.g. + mknod /dev/touchscreen/wm97xx c 10 16 + + 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. The module will be called ac97_plugin_wm97xx.o. + + If unsure, say N. + + +CONFIG_CPU_FREQ_24_API + This enables the /proc/sys/cpu/ sysctl interface for controlling + CPUFreq, as known from the 2.4.-kernel patches for CPUFreq. 2.5 + uses /proc/cpufreq instead. Please note that some drivers do not + work well with the 2.4. /proc/sys/cpu sysctl interface, so if in + doubt, say N here. + + For details, take a look at linux/Documentation/cpu-freq. + + If in doubt, say N. + +CONFIG_X86_POWERNOW_K6 + This adds the CPUFreq driver for mobile AMD K6-2+ and mobile + AMD K6-3+ processors. + + For details, take a look at linux/Documentation/cpu-freq. + + If in doubt, say N. + +CONFIG_X86_POWERNOW_K7 + This adds the CPUFreq driver for mobile AMD Athlon/Duron + K7 processors. + + For details, take a look at linux/Documentation/cpu-freq. + + If in doubt, say N. + +CONFIG_X86_P4_CLOCKMOD + This adds the CPUFreq driver for Intel Pentium 4 / XEON + processors. + + For details, take a look at linux/Documentation/cpu-freq. + + If in doubt, say N. + +CONFIG_ELAN_CPUFREQ + This adds the CPUFreq driver for AMD Elan SC400 and SC410 + processors. + + You need to specify the processor maximum speed as boot + parameter: elanfreq=maxspeed (in kHz) or as module + parameter "max_freq". + + For details, take a look at linux/Documentation/cpu-freq. + + If in doubt, say N. + +CONFIG_X86_LONGHAUL + This adds the CPUFreq driver for VIA Samuel/CyrixIII, + VIA Cyrix Samuel/C3, VIA Cyrix Ezra and VIA Cyrix Ezra-T + processors. + + If you do not want to scale the Front Side Bus or voltage, + pass the module parameter "dont_scale_fsb=1" or + "dont_scale_voltage=1". Additionally, it is advised that + you pass the current Front Side Bus speed (in MHz) to + this module as module parameter "current_fsb", e.g. + "current_fsb=133" for a Front Side Bus speed of 133 MHz. + + For details, take a look at linux/Documentation/cpu-freq. + + If in doubt, say N. + +CONFIG_X86_SPEEDSTEP_ICH + This adds the CPUFreq driver for certain mobile Intel Pentium III + (Coppermine), all mobile Intel Pentium III-M (Tulaatin) and all + mobile Intel Pentium 4 P4-Ms on chipsets with an Intel ICH2, ICH3, + or ICH4 southbridge. + + For details, take a look at linux/Documentation/cpu-freq. + + If in doubt, say N. + +CONFIG_X86_SPEEDSTEP_CENTRINO + This adds the CPUFreq driver for Enhanced SpeedStep enabled + mobile CPUs. This means Intel Pentium M (Centrino) CPUs. + + For details, take a look at linux/Documentation/cpu-freq. + + If in doubt, say N. + +CONFIG_X86_LONGRUN + This adds the CPUFreq driver for Transmeta Crusoe processors which + support LongRun. + + For details, take a look at linux/Documentation/cpu-freq. + + If in doubt, say N. + +CONFIG_X86_GX_SUSPMOD + This adds the CPUFreq driver for NatSemi Geode processors which + support suspend modulation. + + For details, take a look at linux/Documentation/cpu-freq. + + If in doubt, say N. + +CONFIG_CPU_FREQ_GOV_USERSPACE + Enable this cpufreq governor when you either want to set the + CPU frequency manually or when an userspace programm shall + be able to set the CPU dynamically, like on LART + ( http://www.lart.tudelft.nl/ ) + + For details, take a look at linux/Documentation/cpu-freq. + + If in doubt, say Y. + +Chassis LCD and LED support +CONFIG_CHASSIS_LCD_LED + Say Y here if you want to enable support for the Heartbeat, + Disk/Network activities LEDs on some PA-RISC machines, + or support for the LCD that can be found on recent material. + + This has nothing to do with LED State support for A, J and E class. + + If unsure, say Y. + +VSC/GSC/HSC bus support +CONFIG_GSC + The VSC, GSC and HSC busses were used from the earliest 700-series + workstations up to and including the C360/J2240 workstations. They + were also used in servers from the E-class to the K-class. They + are not found in B1000, C3000, J5000, A500, L1000, N4000 and upwards. + If in doubt, say "Y". + +Wax I/O support +CONFIG_GSC_WAX + Say Y here to support the Wax multifunction chip found in some + older systems, including B/C/D/R class and 715/64, 715/80 and + 715/100. Wax includes an EISA adapter, a serial port (not always + used), a HIL interface chip and is also known to be used as the + GSC bridge for an X.25 GSC card. + +GSCtoPCI/Dino PCI support +CONFIG_GSC_DINO + Say Y here to support the Dino & Cujo GSC to PCI bridges found in + machines from the B132 to the C360, the J2240 and the A180. Some + GSC/HSC cards (eg gigabit & dual 100 Mbit Ethernet) have a Dino on + the card, and you also need to say Y here if you have such a card. + Note that Dino also supplies one of the serial ports on certain + machines. If in doubt, say Y. + +HPET timers +CONFIG_HPET_TIMER + Use the IA-PC HPET (High Precision Event Timer) to manage + time in preference to the PIT and RTC, if a HPET is + present. The HPET provides a stable time base on SMP + systems, unlike the RTC, but it is more expensive to access, + as it is off-chip. You can find the HPET spec at + . + + If unsure, say Y. + +IOMMU support +CONFIG_GART_IOMMU + Support the K8 IOMMU. Needed to run systems with more than 4GB of memory + properly with 32-bit PCI devices that do not support DAC (Double Address + Cycle). The IOMMU can be turned off at runtime with the iommu=off parameter. + Normally the kernel will take the right choice by itself. + If unsure say Y + +Debug __init statements +CONFIG_INIT_DEBUG + Fill __init and __initdata at the end of boot. This helps debugging + invalid uses of __init and __initdata after initialization. + +Force IOMMU to on +CONFIG_IOMMU_DEBUG + Force the IOMMU to on even when you have less than 4GB of memory and add + debugging code. + Can be disabled at boot time with iommu=noforce. + +IOMMU leak tracing +CONFIG_IOMMU_LEAK + Add a simple leak tracer to the IOMMU code. This is useful when you + are debugging a buggy device driver that leaks IOMMU mappings. + +pSeries Hypervisor Virtual Console support +CONFIG_HVC_CONSOLE + pSeries machines when partitioned support a hypervisor virtual + console. This driver allows each pSeries partition to have a console + which is accessed via the HMC. Chassis LCD and LED support CONFIG_CHASSIS_LCD_LED diff -urN linux-2.4.23-pre8/Documentation/DocBook/Makefile linux-2.4.23-pre8-pac1/Documentation/DocBook/Makefile --- linux-2.4.23-pre8/Documentation/DocBook/Makefile 2002-11-29 00:53:08.000000000 +0100 +++ linux-2.4.23-pre8-pac1/Documentation/DocBook/Makefile 2003-10-24 14:31:25.000000000 +0200 @@ -2,7 +2,7 @@ kernel-api.sgml parportbook.sgml kernel-hacking.sgml \ kernel-locking.sgml via-audio.sgml mousedrivers.sgml sis900.sgml \ deviceiobook.sgml procfs-guide.sgml tulip-user.sgml \ - journal-api.sgml + journal-api.sgml atascsi-dev.sgml PS := $(patsubst %.sgml, %.ps, $(BOOKS)) PDF := $(patsubst %.sgml, %.pdf, $(BOOKS)) @@ -79,6 +79,12 @@ $(TOPDIR)/scripts/docgen $(TOPDIR)/arch/i386/kernel/mca.c \ mcabook.sgml +atascsi-dev.sgml: atascsi-dev.tmpl $(TOPDIR)/drivers/scsi/libata.c \ + $(TOPDIR)/drivers/scsi/ata_piix.c + $(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/scsi/libata.c \ + $(TOPDIR)/drivers/scsi/ata_piix.c \ + < atascsi-dev.tmpl > atascsi-dev.sgml + videobook.sgml: videobook.tmpl $(TOPDIR)/drivers/media/video/videodev.c $(TOPDIR)/scripts/docgen $(TOPDIR)/drivers/media/video/videodev.c \ videobook.sgml diff -urN linux-2.4.23-pre8/Documentation/DocBook/atascsi-dev.tmpl linux-2.4.23-pre8-pac1/Documentation/DocBook/atascsi-dev.tmpl --- linux-2.4.23-pre8/Documentation/DocBook/atascsi-dev.tmpl 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/Documentation/DocBook/atascsi-dev.tmpl 2003-10-24 14:31:25.000000000 +0200 @@ -0,0 +1,60 @@ + + + + + ATA-SCSI Developer's Guide + + + + Jeff + Garzik + + + + + 2003 + Jeff Garzik + + + + + The contents of this file are subject to the Open + Software License version 1.1 that can be found at + http://www.opensource.org/licenses/osl-1.1.txt and is included herein + by reference. + + + + Alternatively, the contents of this file may be used under the terms + of the GNU General Public License version 2 (the "GPL") as distributed + in the kernel source COPYING file, in which case the provisions of + the GPL are applicable instead of the above. If you wish to allow + the use of your version of this file only under the terms of the + GPL and not to allow others to use your version of this file under + the OSL, indicate your decision by deleting the provisions above and + replace them with the notice and other provisions required by the GPL. + If you do not delete the provisions above, a recipient may use your + version of this file under either the OSL or the GPL. + + + + + + + + + libata Library +!Edrivers/scsi/libata.c + + + + libata Internals +!Idrivers/scsi/libata.c + + + + ata_piix Internals +!Idrivers/scsi/ata_piix.c + + + diff -urN linux-2.4.23-pre8/Documentation/DriverFixers linux-2.4.23-pre8-pac1/Documentation/DriverFixers --- linux-2.4.23-pre8/Documentation/DriverFixers 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/Documentation/DriverFixers 2003-10-24 14:31:25.000000000 +0200 @@ -0,0 +1,75 @@ +People who fix drivers as a business - ie for money. (No recommendation, +business association or other relationship implied. This for the benefit of +American lawyers is just a list of people who have asked to be listed - nothing +more). + +Companies Who Will Do Small Contract Work +----------------------------------------- + +Company: BitWizard +Contact: Rogier Wolff +E-Mail: R.E.Wolff@BitWizard.nl + +Company: Caederus +Contact: Justin Mitchell +E-Mail: info@caederus.com +Location: Swansea, Wales, UK +URL: http://www.caederus.com/ + +Company: Calsoft Inc +Contact: Anupam Bhide +E-Mail: anupam@calsoftinc.com +URL: http://www.calsoftinc.com +Location: Pune, India + +Company: Hansen Partnership Inc +Contact: James Bottomley +E-Mail: James.Bottomley@HansenPartnership.com +Location: 1, Partridge Square, Oswego, Illinois 60543, USA + +Company: Linking +Contact: Elmer Joandi +E-Mail: elmer@linkingsoft.com + +Company: Penguru Consulting, LLC +Contact: Komron Takmil +E-Mail: komron@penguru.net +Location: Salt Lake City, UT USA + +Company: 7Chips +Contact: Vadim Lebedev +E-Mail: vadim@7chips.com +Location: Paris, France +Notes: Experienced in Linux and uClinux on x86/ARM/Motorola + +Company: Weinigel Ingenjörsbyrå AB +Contact: Christer Weinigel +E-Mail: christer@weinigel.se +Location: Stockholm, Sweden + +Company: WildOpenSource +Contact: Martin Hicks +E-Mail: info@wildopensource.com + + +Companies Only Interested In Larger ($10000+) Jobs +-------------------------------------------------- + + + +Companies Only Interested In Very Large ($100000+) Jobs +------------------------------------------------------- + + +To be added to the list: email giving the +following information + +Company: CompanyName [Required] +Contact: ContactName [Required] +E-Mail: An email address [Required] +URL: Web site [Optional] +Location: Area/Country [Optional] +Telephone: Contact phone number [Optional] +Speciality: Any specific speciality [Optional] +Notes: Any other notes (eg certifications, specialities) + diff -urN linux-2.4.23-pre8/Documentation/cpu-freq/core.txt linux-2.4.23-pre8-pac1/Documentation/cpu-freq/core.txt --- linux-2.4.23-pre8/Documentation/cpu-freq/core.txt 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/Documentation/cpu-freq/core.txt 2003-10-24 14:31:25.000000000 +0200 @@ -0,0 +1,94 @@ + CPU frequency and voltage scaling code in the Linux(TM) kernel + + + L i n u x C P U F r e q + + C P U F r e q C o r e + + + Dominik Brodowski + David Kimdon + + + + Clock scaling allows you to change the clock speed of the CPUs on the + fly. This is a nice method to save battery power, because the lower + the clock speed, the less power the CPU consumes. + + +Contents: +--------- +1. CPUFreq core and interfaces +2. CPUFreq notifiers + +1. General Information +======================= + +The CPUFreq core code is located in linux/kernel/cpufreq.c. This +cpufreq code offers a standardized interface for the CPUFreq +architecture drivers (those pieces of code that do actual +frequency transitions), as well as to "notifiers". These are device +drivers or other part of the kernel that need to be informed of +policy changes (ex. thermal modules like ACPI) or of all +frequency changes (ex. timing code) or even need to force certain +speed limits (like LCD drivers on ARM architecture). Additionally, the +kernel "constant" loops_per_jiffy is updated on frequency changes +here. + +Reference counting is done by cpufreq_get_cpu and cpufreq_put_cpu, +which make sure that the cpufreq processor driver is correctly +registered with the core, and will not be unloaded until +cpufreq_put_cpu is called. + +2. CPUFreq notifiers +==================== + +CPUFreq notifiers conform to the standard kernel notifier interface. +See linux/include/linux/notifier.h for details on notifiers. + +There are two different CPUFreq notifiers - policy notifiers and +transition notifiers. + + +2.1 CPUFreq policy notifiers +---------------------------- + +These are notified when a new policy is intended to be set. Each +CPUFreq policy notifier is called three times for a policy transition: + +1.) During CPUFREQ_ADJUST all CPUFreq notifiers may change the limit if + they see a need for this - may it be thermal considerations or + hardware limitations. + +2.) During CPUFREQ_INCOMPATIBLE only changes may be done in order to avoid + hardware failure. + +3.) And during CPUFREQ_NOTIFY all notifiers are informed of the new policy + - if two hardware drivers failed to agree on a new policy before this + stage, the incompatible hardware shall be shut down, and the user + informed of this. + +The phase is specified in the second argument to the notifier. + +The third argument, a void *pointer, points to a struct cpufreq_policy +consisting of five values: cpu, min, max, policy and max_cpu_freq. min +and max are the lower and upper frequencies (in kHz) of the new +policy, policy the new policy, cpu the number of the affected CPU; and +max_cpu_freq the maximum supported CPU frequency. This value is given +for informational purposes only. + + +2.2 CPUFreq transition notifiers +-------------------------------- + +These are notified twice when the CPUfreq driver switches the CPU core +frequency and this change has any external implications. + +The second argument specifies the phase - CPUFREQ_PRECHANGE or +CPUFREQ_POSTCHANGE. + +The third argument is a struct cpufreq_freqs with the following +values: +cpu - number of the affected CPU +old - old frequency +new - new frequency diff -urN linux-2.4.23-pre8/Documentation/cpu-freq/cpu-drivers.txt linux-2.4.23-pre8-pac1/Documentation/cpu-freq/cpu-drivers.txt --- linux-2.4.23-pre8/Documentation/cpu-freq/cpu-drivers.txt 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/Documentation/cpu-freq/cpu-drivers.txt 2003-10-24 14:31:25.000000000 +0200 @@ -0,0 +1,210 @@ + CPU frequency and voltage scaling code in the Linux(TM) kernel + + + L i n u x C P U F r e q + + C P U D r i v e r s + + - information for developers - + + + Dominik Brodowski + + + + Clock scaling allows you to change the clock speed of the CPUs on the + fly. This is a nice method to save battery power, because the lower + the clock speed, the less power the CPU consumes. + + +Contents: +--------- +1. What To Do? +1.1 Initialization +1.2 Per-CPU Initialization +1.3 verify +1.4 target or setpolicy? +1.5 target +1.6 setpolicy +2. Frequency Table Helpers + + + +1. What To Do? +============== + +So, you just got a brand-new CPU / chipset with datasheets and want to +add cpufreq support for this CPU / chipset? Great. Here are some hints +on what is necessary: + + +1.1 Initialization +------------------ + +First of all, in an __initcall level 7 (module_init()) or later +function check whether this kernel runs on the right CPU and the right +chipset. If so, register a struct cpufreq_driver with the CPUfreq core +using cpufreq_register_driver() + +What shall this struct cpufreq_driver contain? + +cpufreq_driver.name - The name of this driver. + +cpufreq_driver.owner - THIS_MODULE; + +cpufreq_driver.init - A pointer to the per-CPU initialization + function. + +cpufreq_driver.verify - A pointer to a "verification" function. + +cpufreq_driver.setpolicy _or_ +cpufreq_driver.target - See below on the differences. + +And optionally + +cpufreq_driver.exit - A pointer to a per-CPU cleanup function. + +cpufreq_driver.attr - A pointer to a NULL-terminated list of + "struct freq_attr" which allow to + export values to sysfs. + + +1.2 Per-CPU Initialization +-------------------------- + +Whenever a new CPU is registered with the device model, or after the +cpufreq driver registers itself, the per-CPU initialization function +cpufreq_driver.init is called. It takes a struct cpufreq_policy +*policy as argument. What to do now? + +If necessary, activate the CPUfreq support on your CPU. + +Then, the driver must fill in the following values: + +policy->cpuinfo.min_freq _and_ +policy->cpuinfo.max_freq - the minimum and maximum frequency + (in kHz) which is supported by + this CPU +policy->cpuinfo.transition_latency the time it takes on this CPU to + switch between two frequencies (if + appropriate, else specify + CPUFREQ_ETERNAL) + +policy->cur The current operating frequency of + this CPU (if appropriate) +policy->min, +policy->max, +policy->policy and, if necessary, +policy->governor must contain the "default policy" for + this CPU. A few moments later, + cpufreq_driver.verify and either + cpufreq_driver.setpolicy or + cpufreq_driver.target is called with + these values. + +For setting some of these values, the frequency table helpers might be +helpful. See the section 2 for more information on them. + + +1.3 verify +------------ + +When the user decides a new policy (consisting of +"policy,governor,min,max") shall be set, this policy must be validated +so that incompatible values can be corrected. For verifying these +values, a frequency table helper and/or the +cpufreq_verify_within_limits(struct cpufreq_policy *policy, unsigned +int min_freq, unsigned int max_freq) function might be helpful. See +section 2 for details on frequency table helpers. + +You need to make sure that at least one valid frequency (or operating +range) is within policy->min and policy->max. If necessary, increase +policy->max fist, and only if this is no solution, decreas policy->min. + + +1.4 target or setpolicy? +---------------------------- + +Most cpufreq drivers or even most cpu frequency scaling algorithms +only allow the CPU to be set to one frequency. For these, you use the +->target call. + +Some cpufreq-capable processors switch the frequency between certain +limits on their own. These shall use the ->setpolicy call + + +1.4. target +------------- + +The target call has three arguments: struct cpufreq_policy *policy, +unsigned int target_frequency, unsigned int relation. + +The CPUfreq driver must set the new frequency when called here. The +actual frequency must be determined using the following rules: + +- keep close to "target_freq" +- policy->min <= new_freq <= policy->max (THIS MUST BE VALID!!!) +- if relation==CPUFREQ_REL_L, try to select a new_freq higher than or equal + target_freq. ("L for lowest, but no lower than") +- if relation==CPUFREQ_REL_H, try to select a new_freq lower than or equal + target_freq. ("H for highest, but no higher than") + +Here again the frequency table helper might assist you - see section 3 +for details. + + +1.5 setpolicy +--------------- + +The setpolicy call only takes a struct cpufreq_policy *policy as +argument. You need to set the lower limit of the in-processor or +in-chipset dynamic frequency switching to policy->min, the upper limit +to policy->max, and -if supported- select a performance-oriented +setting when policy->policy is CPUFREQ_POLICY_PERFORMANCE, and a +powersaving-oriented setting when CPUFREQ_POLICY_POWERSAVE. Also check +the reference implementation in arch/i386/kernel/cpu/cpufreq/longrun.c + + + +2. Frequency Table Helpers +========================== + +As most cpufreq processors only allow for being set to a few specific +frequencies, a "frequency table" with some functions might assist in +some work of the processor driver. Such a "frequency table" consists +of an array of struct cpufreq_freq_table entries, with any value in +"index" you want to use, and the corresponding frequency in +"frequency". At the end of the table, you need to add a +cpufreq_freq_table entry with frequency set to CPUFREQ_TABLE_END. And +if you want to skip one entry in the table, set the frequency to +CPUFREQ_ENTRY_INVALID. The entries don't need to be in ascending +order. + +By calling cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy, + struct cpufreq_frequency_table *table); +the cpuinfo.min_freq and cpuinfo.max_freq values are detected, and +policy->min and policy->max are set to the same values. This is +helpful for the per-CPU initialization stage. + +int cpufreq_frequency_table_verify(struct cpufreq_policy *policy, + struct cpufreq_frequency_table *table); +assures that at least one valid frequency is within policy->min and +policy->max, and all other criteria are met. This is helpful for the +->verify call. + +int cpufreq_frequency_table_target(struct cpufreq_policy *policy, + struct cpufreq_frequency_table *table, + unsigned int target_freq, + unsigned int relation, + unsigned int *index); + +is the corresponding frequency table helper for the ->target +stage. Just pass the values to this function, and the unsigned int +index returns the number of the frequency table entry which contains +the frequency the CPU shall be set to. PLEASE NOTE: This is not the +"index" which is in this cpufreq_table_entry.index, but instead +cpufreq_table[index]. So, the new frequency is +cpufreq_table[index].frequency, and the value you stored into the +frequency table "index" field is +cpufreq_table[index].index. + diff -urN linux-2.4.23-pre8/Documentation/cpu-freq/governors.txt linux-2.4.23-pre8-pac1/Documentation/cpu-freq/governors.txt --- linux-2.4.23-pre8/Documentation/cpu-freq/governors.txt 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/Documentation/cpu-freq/governors.txt 2003-10-24 14:31:25.000000000 +0200 @@ -0,0 +1,155 @@ + CPU frequency and voltage scaling code in the Linux(TM) kernel + + + L i n u x C P U F r e q + + C P U F r e q G o v e r n o r s + + - information for users and developers - + + + Dominik Brodowski + + + + Clock scaling allows you to change the clock speed of the CPUs on the + fly. This is a nice method to save battery power, because the lower + the clock speed, the less power the CPU consumes. + + +Contents: +--------- +1. What is a CPUFreq Governor? + +2. Governors In the Linux Kernel +2.1 Performance +2.2 Powersave +2.3 Userspace + +3. The Governor Interface in the CPUfreq Core + + + +1. What Is A CPUFreq Governor? +============================== + +Most cpufreq drivers (in fact, all except one, longrun) or even most +cpu frequency scaling algorithms only offer the CPU to be set to one +frequency. In order to offer dynamic frequency scaling, the cpufreq +core must be able to tell these drivers of a "target frequency". So +these specific drivers will be transformed to offer a "->target" +call instead of the existing "->setpolicy" call. For "longrun", all +stays the same, though. + +How to decide what frequency within the CPUfreq policy should be used? +That's done using "cpufreq governors". Two are already in this patch +-- they're the already existing "powersave" and "performance" which +set the frequency statically to the lowest or highest frequency, +respectively. At least two more such governors will be ready for +addition in the near future, but likely many more as there are various +different theories and models about dynamic frequency scaling +around. Using such a generic interface as cpufreq offers to scaling +governors, these can be tested extensively, and the best one can be +selected for each specific use. + +Basically, it's the following flow graph: + +CPU can be set to switch independetly | CPU can only be set + within specific "limits" | to specific frequencies + + "CPUfreq policy" + consists of frequency limits (policy->{min,max}) + and CPUfreq governor to be used + / \ + / \ + / the cpufreq governor decides + / (dynamically or statically) + / what target_freq to set within + / the limits of policy->{min,max} + / \ + / \ + Using the ->setpolicy call, Using the ->target call, + the limits and the the frequency closest + "policy" is set. to target_freq is set. + It is assured that it + is within policy->{min,max} + + +2. Governors In the Linux Kernel +================================ + +2.1 Performance +--------------- + +The CPUfreq governor "performance" sets the CPU statically to the +highest frequency within the borders of scaling_min_freq and +scaling_max_freq. + + +2.1 Powersave +------------- + +The CPUfreq governor "powersave" sets the CPU statically to the +lowest frequency within the borders of scaling_min_freq and +scaling_max_freq. + + +2.2 Userspace +------------- + +The CPUfreq governor "userspace" allows the user, or any userspace +program running with UID "root", to set the CPU to a specific frequency +by making a sysfs file "scaling_setspeed" available in the CPU-device +directory. + + + +3. The Governor Interface in the CPUfreq Core +============================================= + +A new governor must register itself with the CPUfreq core using +"cpufreq_register_governor". The struct cpufreq_governor, which has to +be passed to that function, must contain the following values: + +governor->name - A unique name for this governor +governor->governor - The governor callback function +governor->owner - .THIS_MODULE for the governor module (if + appropriate) + +The governor->governor callback is called with the current (or to-be-set) +cpufreq_policy struct for that CPU, and an unsigned int event. The +following events are currently defined: + +CPUFREQ_GOV_START: This governor shall start its duty for the CPU + policy->cpu +CPUFREQ_GOV_STOP: This governor shall end its duty for the CPU + policy->cpu +CPUFREQ_GOV_LIMITS: The limits for CPU policy->cpu have changed to + policy->min and policy->max. + +If you need other "events" externally of your driver, _only_ use the +cpufreq_governor_l(unsigned int cpu, unsigned int event) call to the +CPUfreq core to ensure proper locking. + + +The CPUfreq governor may call the CPU processor driver using one of +these two functions: + +int cpufreq_driver_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation); + +int __cpufreq_driver_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation); + +target_freq must be within policy->min and policy->max, of course. +What's the difference between these two functions? When your governor +still is in a direct code path of a call to governor->governor, the +per-CPU cpufreq lock is still held in the cpufreq core, and there's +no need to lock it again (in fact, this would cause a deadlock). So +use __cpufreq_driver_target only in these cases. In all other cases +(for example, when there's a "daemonized" function that wakes up +every second), use cpufreq_driver_target to lock the cpufreq per-CPU +lock before the command is passed to the cpufreq processor driver. + diff -urN linux-2.4.23-pre8/Documentation/cpu-freq/index.txt linux-2.4.23-pre8-pac1/Documentation/cpu-freq/index.txt --- linux-2.4.23-pre8/Documentation/cpu-freq/index.txt 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/Documentation/cpu-freq/index.txt 2003-10-24 14:31:25.000000000 +0200 @@ -0,0 +1,56 @@ + CPU frequency and voltage scaling code in the Linux(TM) kernel + + + L i n u x C P U F r e q + + + + + Dominik Brodowski + + + + Clock scaling allows you to change the clock speed of the CPUs on the + fly. This is a nice method to save battery power, because the lower + the clock speed, the less power the CPU consumes. + + + +Documents in this directory: +---------------------------- +core.txt - General description of the CPUFreq core and + of CPUFreq notifiers + +cpu-drivers.txt - How to implement a new cpufreq processor driver + +governors.txt - What are cpufreq governors and how to + implement them? + +index.txt - File index, Mailing list and Links (this document) + +user-guide.txt - User Guide to CPUFreq + + +Mailing List +------------ +There is a CPU frequency changing CVS commit and general list where +you can report bugs, problems or submit patches. To post a message, +send an email to cpufreq@www.linux.org.uk, to subscribe go to +http://www.linux.org.uk/mailman/listinfo/cpufreq. Previous post to the +mailing list are available to subscribers at +http://www.linux.org.uk/mailman/private/cpufreq/. + + +Links +----- +the FTP archives: +* ftp://ftp.linux.org.uk/pub/linux/cpufreq/ + +how to access the CVS repository: +* http://cvs.arm.linux.org.uk/ + +the CPUFreq Mailing list: +* http://www.linux.org.uk/mailman/listinfo/cpufreq + +Clock and voltage scaling for the SA-1100: +* http://www.lart.tudelft.nl/projects/scaling diff -urN linux-2.4.23-pre8/Documentation/cpu-freq/user-guide.txt linux-2.4.23-pre8-pac1/Documentation/cpu-freq/user-guide.txt --- linux-2.4.23-pre8/Documentation/cpu-freq/user-guide.txt 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/Documentation/cpu-freq/user-guide.txt 2003-10-24 14:31:25.000000000 +0200 @@ -0,0 +1,182 @@ + CPU frequency and voltage scaling code in the Linux(TM) kernel + + + L i n u x C P U F r e q + + U S E R G U I D E + + + Dominik Brodowski + + + + Clock scaling allows you to change the clock speed of the CPUs on the + fly. This is a nice method to save battery power, because the lower + the clock speed, the less power the CPU consumes. + + +Contents: +--------- +1. Supported Architectures and Processors +1.1 ARM +1.2 x86 +1.3 sparc64 +1.4 ppc +1.5 SuperH + +2. "Policy" / "Governor"? +2.1 Policy +2.2 Governor + +3. How to change the CPU cpufreq policy and/or speed +3.1 Preferred interface: sysfs +3.2 Deprecated interfaces + + + +1. Supported Architectures and Processors +========================================= + +1.1 ARM +------- + +The following ARM processors are supported by cpufreq: + +ARM Integrator +ARM-SA1100 +ARM-SA1110 + + +1.2 x86 +------- + +The following processors for the x86 architecture are supported by cpufreq: + +AMD Elan - SC400, SC410 +AMD mobile K6-2+ +AMD mobile K6-3+ +AMD mobile Duron +AMD mobile Athlon +Cyrix Media GXm +Intel mobile PIII and Intel mobile PIII-M on certain chipsets +Intel Pentium 4, Intel Xeon +Intel Pentium M (Centrino) +National Semiconductors Geode GX +Transmeta Crusoe +VIA Cyrix 3 / C3 +various processors on some ACPI 2.0-compatible systems [*] + +[*] Only if "ACPI Processor Performance States" are available +to the ACPI<->BIOS interface. + + +1.3 sparc64 +----------- + +The following processors for the sparc64 architecture are supported by +cpufreq: + +UltraSPARC-III + + +1.4 ppc +------- + +Several "PowerBook" and "iBook2" notebooks are supported. + + +1.5 SuperH +---------- + +The following SuperH processors are supported by cpufreq: + +SH-3 +SH-4 + + +2. "Policy" / "Governor" ? +========================== + +Some CPU frequency scaling-capable processor switch between various +frequencies and operating voltages "on the fly" without any kernel or +user involvement. This guarantees very fast switching to a frequency +which is high enough to serve the user's needs, but low enough to save +power. + + +2.1 Policy +---------- + +On these systems, all you can do is select the lower and upper +frequency limit as well as whether you want more aggressive +power-saving or more instantly available processing power. + + +2.2 Governor +------------ + +On all other cpufreq implementations, these boundaries still need to +be set. Then, a "governor" must be selected. Such a "governor" decides +what speed the processor shall run within the boundaries. One such +"governor" is the "userspace" governor. This one allows the user - or +a yet-to-implement userspace program - to decide what specific speed +the processor shall run at. + + +3. How to change the CPU cpufreq policy and/or speed +==================================================== + +3.1 Preferred Interface: sysfs +------------------------------ + +The preferred interface is located in the sysfs filesystem. If you +mounted it at /sys, the cpufreq interface is located in a subdirectory +"cpufreq" within the cpu-device directory +(e.g. /sys/devices/system/cpu/cpu0/cpufreq/ for the first CPU). + +cpuinfo_min_freq : this file shows the minimum operating + frequency the processor can run at(in kHz) +cpuinfo_max_freq : this file shows the maximum operating + frequency the processor can run at(in kHz) +scaling_driver : this file shows what cpufreq driver is + used to set the frequency on this CPU + +scaling_available_governors : this file shows the CPUfreq governors + available in this kernel. You can see the + currently activated governor in + +scaling_governor, and by "echoing" the name of another + governor you can change it. Please note + that some governors won't load - they only + work on some specific architectures or + processors. +scaling_min_freq and +scaling_max_freq show the current "policy limits" (in + kHz). By echoing new values into these + files, you can change these limits. + + +If you have selected the "userspace" governor which allows you to +set the CPU operating frequency to a specific value, you can read out +the current frequency in + +scaling_setspeed. By "echoing" a new frequency into this + you can change the speed of the CPU, + but only within the limits of + scaling_min_freq and scaling_max_freq. + + +3.2 Deprecated Interfaces +------------------------- + +Depending on your kernel configuration, you might find the following +cpufreq-related files: +/proc/cpufreq +/proc/sys/cpu/*/speed +/proc/sys/cpu/*/speed-min +/proc/sys/cpu/*/speed-max + +These are files for deprecated interfaces to cpufreq, which offer far +less functionality. Because of this, these interfaces aren't described +here. + diff -urN linux-2.4.23-pre8/Documentation/filesystems/00-INDEX linux-2.4.23-pre8-pac1/Documentation/filesystems/00-INDEX --- linux-2.4.23-pre8/Documentation/filesystems/00-INDEX 2002-11-29 00:53:08.000000000 +0100 +++ linux-2.4.23-pre8-pac1/Documentation/filesystems/00-INDEX 2003-10-24 14:31:25.000000000 +0200 @@ -48,3 +48,5 @@ - info on using the VFAT filesystem used in Windows NT and Windows 95 vfs.txt - Overview of the Virtual File System +xfs.txt + - info and mount options for the XFS filesystem. diff -urN linux-2.4.23-pre8/Documentation/filesystems/ntfs.txt linux-2.4.23-pre8-pac1/Documentation/filesystems/ntfs.txt --- linux-2.4.23-pre8/Documentation/filesystems/ntfs.txt 2001-12-21 18:41:53.000000000 +0100 +++ linux-2.4.23-pre8-pac1/Documentation/filesystems/ntfs.txt 2003-10-24 14:31:25.000000000 +0200 @@ -1,68 +1,115 @@ -NTFS Overview -============= +The Linux NTFS filesystem driver +================================ -Legato Systems, Inc. (http://www.legato.com) have sponsored Anton Altaparmakov -to develop NTFS on Linux since June 2001. -To mount an NTFS volume, use the filesystem type 'ntfs'. The driver -currently works only in read-only mode, with no fault-tolerance supported. +Table of contents +================= + +- Overview +- Supported mount options +- Features +- Known bugs and (mis-)features +- Using Software RAID with NTFS +- Limitiations when using the MD driver +- ChangeLog + + +Overview +======== + +To mount an NTFS 1.2/3.x (Windows NT4/2000/XP) volume, use the filesystem +type 'ntfs'. The driver currently works only in read-only mode, with no +fault-tolerance or journalling supported. + +For fault tolerance and raid support (i.e. volume and stripe sets), you can use +the kernel's Software RAID / MD driver. See section "Using Software RAID with +NTFS" for details. -If you enable the dangerous(!) write support, make sure you can recover -from a complete loss of data. Also, download the Linux-NTFS project -distribution from Sourceforge at http://sourceforge.net/projects/linux-ntfs/ -and always run the included ntfsfix utility after performing a write to an -NTFS partition from Linux to fix some of the damage done by the Linux NTFS -driver and to schedule an automatic chkdsk when Windows reboots. You should -run ntfsfix _after_ unmounting the partition in Linux but _before_ rebooting -into Windows. During the next reboot into Windows, chkdsk will be run -automatically fixing the remaining damage. If no errors are found it is a -good indication that the driver + ntfsfix together worked to full -satisfaction. (-; - -Please note that the experimental write support is limited to Windows NT4 and -earlier versions at the moment. - -If you think you have discovered a bug please have look at the "Known bugs" -section below to see whether it isn't known already. - -For ftdisk support, limited success was reported with volume sets on top of -the md driver, although mirror and stripe sets should work as well - if the -md driver can be talked into using the same layout as Windows NT. However, -using the md driver will fail if any of your NTFS partitions have an odd -number of sectors. Supported mount options ======================= -iocharset=name Character set to use when returning file names. +In addition to the generic mount options described by the manual page for the +mount command (man 8 mount, also see man 5 fstab), the NTFS driver supports the +following mount options: + +iocharset=name Deprecated option. Still supported but please use + nls=name in the future. See description for nls=name. + +nls=name Character set to use when returning file names. Unlike VFAT, NTFS suppresses names that contain unconvertible characters. Note that most character sets contain insufficient characters to represent all possible Unicode characters that can exist on NTFS. To be sure you are not missing any files, you are advised - to use the iocharset=utf8 which should be capable of - representing all Unicode characters. + to use nls=utf8 which is capable of representing all + Unicode characters. -utf8= Use UTF-8 for converting file names. - It is preferable - to use iocharset=utf8 instead, but if the utf8 NLS is - not available, you can use this utf8 option, which - enables the driver's builtin utf8 conversion functions. +utf8= Option no longer supported. Currently mapped to + nls=utf8 but please use nls=utf8 in the future and + make sure utf8 is compiled either as module or into + the kernel. See description for nls=name. uid= gid= -umask= These options work as documented in mount(8). - By default, the files are owned by root and - not readable by anyone else. - -posix= If enabled, the file system distinguishes between - upper and lower case. The 8.3 alias names are presented - as hard links instead of being suppressed. - -show_sys_files= If enabled, show all system files as normal files. Note - that $MFT does not appear unless specifically - requested. For example in bash, use: "ls -l \$MFT". - Be careful not to write anything to them or you could - crash the kernel and/or corrupt your file system! +umask= Provide default owner, group, and access mode mask. + These options work as documented in mount(8). By + default, the files/directories are owned by root and + he/she has read and write permissions, as well as + browse permission for directories. No one else has any + access permissions. I.e. the mode on all files is by + default rw------- and for directories rwx------, a + consequence of the default fmask=0177 and dmask=0077. + Using a umask of zero will grant all permissions to + everyone, i.e. all files and directories will have mode + rwxrwxrwx. + +fmask= +dmask= Instead of specifying umask which applies both to + files and directories, fmask applies only to files and + dmask only to directories. + +sloppy= If sloppy is specified, ignore unknown mount options. + Otherwise the default behaviour is to abort mount if + any unknown options are found. + +show_sys_files= If show_sys_files is specified, show the system files + in directory listings. Otherwise the default behaviour + is to hide the system files. + Note that even when show_sys_files is specified, "$MFT" + will not be visible due to bugs/mis-features in glibc. + Further, note that irrespective of show_sys_files, all + files are accessible by name, i.e. you can always do + "ls -l \$UpCase" for example to specifically show the + system file containing the Unicode upcase table. + +case_sensitive= If case_sensitive is specified, treat all file names as + case sensitive and create file names in the POSIX + namespace. Otherwise the default behaviour is to treat + file names as case insensitive and to create file names + in the WIN32/LONG name space. Note, the Linux NTFS + driver will never create short file names and will + remove them on rename/delete of the corresponding long + file name. + Note that files remain accessible via their short file + name, if it exists. If case_sensitive, you will need to + provide the correct case of the short file name. + +errors=opt What to do when critical file system errors are found. + Following values can be used for "opt": + continue: DEFAULT, try to clean-up as much as + possible, e.g. marking a corrupt inode as + bad so it is no longer accessed, and then + continue. + recover: At present only supported is recovery of + the boot sector from the backup copy. If a + read-only mount, the recovery is done in + memory only and not written to disk. + Note that the options are additive, i.e. specifying: + errors=continue,errors=recover + This means the driver will attempt to recover and if + that fails it will clean-up as much as possible and + continue. mft_zone_multiplier= Set the MFT zone multiplier for the volume (this setting is not persistent across mounts and can be @@ -82,173 +129,258 @@ 2 25% 3 37.5% 4 50% + Note this option is irrelevant for read-only mounts. + + +Features +======== + +- This is a complete rewrite of the NTFS driver that used to be in the kernel. + This new driver implements NTFS read support and is functionally equivalent + to the old ntfs driver. +- The new driver has full support for sparse files on NTFS 3.x volumes which + the old driver isn't happy with. +- The new driver supports execution of binaries due to mmap() now being + supported. +- A comparison of the two drivers using: + time find . -type f -exec md5sum "{}" \; + run three times in sequence with each driver (after a reboot) on a 1.4GiB + NTFS partition, showed the new driver to be 20% faster in total time elapsed + (from 9:43 minutes on average down to 7:53). The time spent in user space + was unchanged but the time spent in the kernel was decreased by a factor of + 2.5 (from 85 CPU seconds down to 33). +- The driver does not support short file names in general. For backwards + compatibility, we implement access to files using their short file names if + they exist. The driver will not create short file names however, and a rename + will discard any existing short file name. + Known bugs and (mis-)features ============================= -- Do not use the driver for writing as it corrupts the file system. If you do - use it, get the Linux-NTFS tools and use the ntfsfix utility after - dismounting a partition you wrote to. +- The link count on each directory inode entry is set to 1, due to Linux not + supporting directory hard links. This may well confuse some user space + applications, since the directory names will have the same inode numbers. + This also speeds up ntfs_read_inode() immensely. And we haven't found any + problems with this approach so far. If you find a problem with this, please + let us know. -- Writing of extension records is not supported properly. -Please send bug reports/comments/feed back/abuse to the Linux-NTFS development +Please send bug reports/comments/feedback/abuse to the Linux-NTFS development list at sourceforge: linux-ntfs-dev@lists.sourceforge.net + +Using Software RAID with NTFS +============================= + +For support of volume and stripe sets, use the kernel's Software RAID / MD +driver and set up your /etc/raidtab appropriately (see man 5 raidtab). + +Linear volume sets, i.e. linear raid, as well as stripe sets, i.e. raid level 0, +have been tested and work fine (though see section "Limitiations when using the +MD driver with NTFS volumes" especially if you want to use linear raid). Even +though untested, there is no reason why mirrors, i.e. raid level 1, and stripes +with parity, i.e. raid level 5, should not work, too. + +You have to use the "persistent-superblock 0" option for each raid-disk in the +NTFS volume/stripe you are configuring in /etc/raidtab as the persistent +superblock used by the MD driver would damange the NTFS volume. + +Windows by default uses a stripe chunk size of 64k, so you probably want the +"chunk-size 64k" option for each raid-disk, too. + +For example, if you have a stripe set consisting of two partitions /dev/hda5 +and /dev/hdb1 your /etc/raidtab would look like this: + +raiddev /dev/md0 + raid-level 0 + nr-raid-disks 2 + nr-spare-disks 0 + persistent-superblock 0 + chunk-size 64k + device /dev/hda5 + raid-disk 0 + device /dev/hdb1 + raid-disl 1 + +For linear raid, just change the raid-level above to "raid-level linear", for +mirrors, change it to "raid-level 1", and for stripe sets with parity, change +it to "raid-level 5". + +Note for stripe sets with parity you will also need to tell the MD driver which +parity algorithm to use by specifying the option "parity-algorithm which", +where you need to replace "which" with the name of the algorithm to use (see +man 5 raidtab for available algorithms) and you will have to try the different +available algorithms until you find one that works. Make sure you are working +read-only when playing with this as you may damage your data otherwise. If you +find which algorithm works please let us know (email the linux-ntfs developers +list linux-ntfs-dev@lists.sourceforge.net or drop in on IRC in channel #ntfs +on the irc.openprojects.net network) so we can update this documentation. + +Once the raidtab is setup, run for example raid0run -a to start all devices or +raid0run /dev/md0 to start a particular md device, in this case /dev/md0. + +Then just use the mount command as usual to mount the ntfs volume using for +example: mount -t ntfs -o ro /dev/md0 /mnt/myntfsvolume + +It is advisable to do the mount read-only to see if the md volume has been +setup correctly to avoid the possibility of causing damage to the data on the +ntfs volume. + + +Limitiations when using the MD driver +===================================== + +Using the md driver will not work properly if any of your NTFS partitions have +an odd number of sectors. This is especially important for linear raid as all +data after the first partition with an odd number of sectors will be offset by +one or more sectors so if you mount such a partition with write support you +will cause massive damage to the data on the volume which will only become +apparent when you try to use the volume again under Windows. + +So when using linear raid, make sure that all your partitions have an even +number of sectors BEFORE attempting to use it. You have been warned! + + ChangeLog ========= -NTFS 1.1.21: - - Fixed bug with reading $MFT where we try to read higher mft records - before having read the $DATA attribute of $MFT. (Note this is only a - partial solution which will only work in the case that the attribute - list is resident or non-resident but $DATA is in the first 1024 - bytes. But this should be enough in the majority of cases. I am not - going to bother fixing the general case until someone finds this to - be a problem for them, which I doubt very much will ever happen...) - - Fixed bogus BUG() call in readdir(). - -NTFS 1.1.20: - - Fixed two bugs in ntfs_readwrite_attr(). Thanks to Jan Kara for - spotting the out of bounds one. - - Check return value of set_blocksize() in ntfs_read_super() and make - use of get_hardsect_size() to determine the minimum block size. - - Fix return values of ntfs_vcn_to_lcn(). This should stop - peoples start of partition being overwritten at random. - -NTFS 1.1.19: - - Fixed ntfs_getdir_unsorted(), ntfs_readdir() and ntfs_printcb() to - cope with arbitrary cluster sizes. Very important for Win2k+. Also, - make them detect directories which are too large and truncate the - enumeration pretending end of directory was reached. Detect more - error conditions and overflows. All this fixes the problem where the - driver could end up in an infinite loop under certain circumstances. - - Fixed potential memory leaks in Unicode conversion functions and - setup correct NULL return values. - -NTFS 1.1.18: - - - Enhanced & bug fixed cluster deallocation (race fixes, etc.) - - Complete rewrite of cluster allocation, now race free. - - Fixed several bugs in the attribute modification codepaths. - - Hopefully fixed bug where the first sectors of some people's - partitions would be overwritten by the mft. And in general fixed up - mft extension code a bit (still incomplete though). - - Introduce splice_runlist() to allow generic splicing of two run - lists into one. - - MFT zone is now implemented. [Stage 2 of 3; only lack dynamic - growing of mft zone but that is AFAIK not even done by Windows, and - the overhead would be so large that it is probably not worth doing - at all, so Stage 3 might never happen...] - - Complete rewrite of $MFT extension and ntfs inode allocation code. - - Made the NTFS driver initialization string show the compile options - used (i.e. whether read-only or read-write, whether a module, and - whether with debug support). - - Modify ntfs_fill_mft_header() to set all fields and to accept more - arguments. - - Get rid of superfluous add_mft_header(). - - Get rid of some unused code. - - Fixed several bugs in and generally cleaned up ntfs_readdir, - ntfs_getdir_unsorted(), and ntfs_printcb. Now they spew out huge - amounts of debug output if debugging is enabled. This will be - removed once I know that this works for everyone. - - ntfs_readdir now shows hidden files. The only files that are now - hidden are the first 16 inodes (i.e. the hard coded system files), - which is consistent with Windows NT4. Using the show_sys_files mount - option, these files are then shown, too. - - Fixed the displaying of the "." and ".." directories. We still cannot - cope with more than 65536 files in a directory index block which is - not a problem and we now cannot cope with more than 32766 directory - index blocks which should not be a problem unless you have a - directory with an insanely large number of files in it. The exact - number depends on the length of the file names of the directory - entries and on the size of the dircetory index blocks. - - Fixed all problems with the last file in a directory (e.g. the last - file should no longer disappear and tab completion should work). If - there are still disappearing files or any other problems with the - last file in a directory, please report them! Thanks. - - Rewrote ntfs_extend_attr() to use the new cluster allocator and the - freshly introduced splice_runlists() function. This simplified - ntfs_extend_attr() a lot which in turn seems to have removed one or - more bugs from it. - - Probably other things I have forgotten... (-; - - Removed dollar signs from the names in the system file enumeration. - Apparently gcc doesn't support dollar signs on PPC architecture. - (Andrzej Krzysztofowicz) - -NTFS 1.1.17: - - - Fixed system file handling. No longer need to use show_sys_files - option for driver to work fine. System files are now always treated - the same, but without the option, they are made invisible to - directory listings. As a result system files can once again be opened - even without the show_sys_files option. This is important for the - statfs system call to work properly, for example. - - Implemented MFT zone including mount parameter to tune it (just like - in Windows via the registry, only we make it per mount rather than - global for the whole driver, so we are better but we have no way of - storing the value as we don't have a registry so either specify on - each mount or put it in /etc/fstab). [Stage 1 of 3, mount parameter - handling.] - - Fixed fixup functions to handle corruption cases and to return error - codes to the caller. - - Made fixup functions apply hotfixes where sensible. [Stage 1 of 2+, - in memory only.] - - Fixed ommission of "NTFS: " string in ntfs_error() output. - - Fixed stupid if statement bug in unistr.c. Thanks to Yann E. Morin - for spotting it. - - Get rid of all uses of max and min macros. This actually allowed for - optimizing the code in several places so it was a Good Thing(TM). - - Make ntfs use generic_file_open to enforce the O_LARGEFILE flag. - - Detect encrypted files and refuse to access them (return EACCES - error code to user space). - - Fix handling of encrypted & compressed files so that an encrypted - file no longer is considered to be compressed (this was causing - kernel segmentation faults). - -NTFS 1.1.16: - - - Removed non-functional uni_xlate mount options. - - Clarified the semantics of the utf8 and iocharset mount options. - - Threw out the non-functional mount options for using hard coded - character set conversion. Only kept utf8 one. - - Fixed handling of mount options and proper handling of faulty mount - options on remount. - - Cleaned up character conversion which basically became simplified a - lot due to the removal of the above mentioned mount options. - - Made character conversion to be always consistent. Previously we - could output to the VFS file names which we would then not accept - back from the VFS so in effect we were generating ghost entries in - the directory listings which could not be accessed by any means. - - Simplified time conversion functions drastically without sacrificing - accuracy. (-8 - - Fixed a use of a pointer before the check for the pointer being - NULL, reported by the Stanford checker. - - Fixed several missing error checks, reported by the Stanford - checker and fixed by Rasmus Andersen. - -NTFS 1.1.15 (changes since kernel 2.4.4's NTFS driver): - - - New mount option show_sys_files= to show all system files as - normal files. - - Support for files and in general any attributes up to the full 2TiB - size supported by the NTFS filesystem. Note we only support up to - 32-bits worth of inodes/clusters at this point. - - Support for more than 128kiB sized runlists (using vmalloc_32() - instead of kmalloc()). - - Fixed races in allocation of clusters and mft records. - - Fixed major bugs in attribute handling / searching / collation. - - Fixed major bugs in compressing a run list into a mapping pairs array. - - Fixed major bugs in inode allocation. Especially file create and - mkdir. - - Fixed memory leaks. - - Fixed major bug in inode layout assignment of sequence numbers. - - Lots of other bug fixes I can't think of right now... - - Fixed NULL bug found by the Stanford checker in ntfs_dupuni2map(). - - Convert large stack variable to dynamically allocated one in - ntfs_get_free_cluster_count() (found by Stanford checker). - -Kernel 2.4.4: +Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog. +2.1.4b: + - Sync with 2.4.22 kernel. +2.1.4a: + - Reduce compiler requirements. Remove all uses of unnamed structs + and unions in the driver to make old and newer gcc versions happy. + Makes it a bit uglier IMO but at least people will stop hassling + me about it. +2.1.3a: + - Major bug fixes for reading files and volumes in corner cases which + were being hit by Windows 2k/XP users. +2.1.2a: + - Major bug fixes aleviating the hangs in statfs experienced by some + users. +2.1.1a: + - Major bug fix aleviating the random hangs experienced by some users. + - Update handling of compressed files so people no longer get the + frequently reported warning messages about initialized_size != + data_size. +2.1.0a: + - Sync up with ntfs 2.1.0. +2.1.0: + - Add configuration option for developmental write support. + - Initial implementation of file overwriting. (Writes to resident files + are not written out to disk yet, so avoid writing to files smaller + than about 1kiB.) + - Intercept/abort changes in file size as they are not implemented yet. +2.0.25a: + - Sync up with ntfs 2.0.25. +2.0.25: + - Minor bugfixes in error code paths and small cleanups. +2.0.24: + - Small internal cleanups. + - Support for sendfile system call. (Christoph Hellwig) +2.0.23(a): + - Massive internal locking changes to mft record locking. Fixes + various race conditions and deadlocks. + - Fix ntfs over loopback for compressed files by adding an + optimization barrier. (gcc was screwing up otherwise ?) + Thanks go to Christoph Hellwig for pointing these two out: + - Remove now unused function fs/ntfs/malloc.h::vmalloc_nofs(). + - Fix ntfs_free() for ia64 and parisc. +2.0.22a: + - Sync with NTFS 2.0.22 and kernel 2.4.19. +2.0.22: + - Small internal cleanups. +2.0.21a: + - Resync 2.4.18 kernel backport with latest 2.5.x kernel ntfs release. +2.0.21: + These only affect 32-bit architectures: + - Check for, and refuse to mount too large volumes (maximum is 2TiB). + - Check for, and refuse to open too large files and directories + (maximum is 16TiB). +2.0.20: + - Support non-resident directory index bitmaps. This means we now cope + with huge directories without problems. + - Fix a page leak that manifested itself in some cases when reading + directory contents. + - Internal cleanups. +2.0.19: + - Fix race condition and improvements in block i/o interface. + - Optimization when reading compressed files. +2.0.18: + - Fix race condition in reading of compressed files. +2.0.17: + - Cleanups and optimizations. +2.0.16: + - Fix stupid bug introduced in 2.0.15 in new attribute inode API. + - Big internal cleanup replacing the mftbmp access hacks by using the + new attribute inode API instead. +2.0.15: + - Bug fix in parsing of remount options. + - Internal changes implementing attribute (fake) inodes allowing all + attribute i/o to go via the page cache and to use all the normal + vfs/mm functionality. +2.0.14: + - Internal changes improving run list merging code and minor locking + change to not rely on BKL in ntfs_statfs(). +2.0.13: + - Internal changes towards using iget5_locked() in preparation for + fake inodes and small cleanups to ntfs_volume structure. +2.0.12a: + - Resync 2.4.18 backport with 2.0.12. +2.0.12: + - Internal cleanups in address space operations made possible by the + changes introduced in the previous release. +2.0.11: + - Internal updates and cleanups introducing the first step towards + fake inode based attribute i/o. +2.0.10: + - Microsoft says that the maximum number of inodes is 2^32 - 1. Update + the driver accordingly to only use 32-bits to store inode numbers on + 32-bit architectures. This improves the speed of the driver a little. +2.0.9: + - Change decompression engine to use a single buffer. This should not + affect performance except perhaps on the most heavy i/o on SMP + systems when accessing multiple compressed files from multiple + devices simultaneously. + - Minor updates and cleanups. +2.0.8: + - Remove now obsolete show_inodes and posix mount option(s). + - Restore show_sys_files mount option. + - Add new mount option case_sensitive, to determine if the driver + treats file names as case sensitive or not. + - Mostly drop support for short file names (for backwards compatibility + we only support accessing files via their short file name if one + exists). + - Fix dcache aliasing issues wrt short/long file names. + - Cleanups and minor fixes. +2.0.7: + - Just cleanups. +2.0.6b: + - Remove relevant parts of the patch. +2.0.6a: + - Backport from 2.5.x to 2.4.18. +2.0.6: + - Major bugfix to make compatible with other kernel changes. This fixes + the hangs/oopses on umount. + - Locking cleanup in directory operations (remove BKL usage). +2.0.5: + - Major buffer overflow bug fix. + - Minor cleanups and updates for kernel 2.5.12. +2.0.4: + - Cleanups and updates for kernel 2.5.11. +2.0.3: + - Small bug fixes, cleanups, and performance improvements. +2.0.2: + - Use default fmask of 0177 so that files are no executable by default. + If you want owner executable files, just use fmask=0077. + - Update for kernel 2.5.9 but preserve backwards compatibility with + kernel 2.5.7. + - Minor bug fixes, cleanups, and updates. +2.0.1: + - Minor updates, primarily set the executable bit by default on files + so they can be executed. +2.0.0: - Started ChangeLog. diff -urN linux-2.4.23-pre8/Documentation/filesystems/xfs.txt linux-2.4.23-pre8-pac1/Documentation/filesystems/xfs.txt --- linux-2.4.23-pre8/Documentation/filesystems/xfs.txt 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/Documentation/filesystems/xfs.txt 2003-10-24 14:31:25.000000000 +0200 @@ -0,0 +1,124 @@ + +The SGI XFS Filesystem +====================== + +XFS is a high performance journaling filesystem which originated +on the SGI IRIX platform. It is completely multi-threaded, can +support large files and large filesystems, extended attributes, +variable block sizes, is extent based, and makes extensive use of +Btrees (directories, extents, free space) to aid both performance +and scalability. + +Refer to the documentation at http://oss.sgi.com/projects/xfs/ +for further details. This implementation is on-disk compatible +with the IRIX version of XFS. + + +Options +======= + +When mounting an XFS filesystem, the following options are accepted. + + biosize=size + Sets the preferred buffered I/O size (default size is 64K). + "size" must be expressed as the logarithm (base2) of the + desired I/O size. + Valid values for this option are 14 through 16, inclusive + (i.e. 16K, 32K, and 64K bytes). On machines with a 4K + pagesize, 13 (8K bytes) is also a valid size. + The preferred buffered I/O size can also be altered on an + individual file basis using the ioctl(2) system call. + + dmapi + Enable the DMAPI (Data Management API) event callouts. + Use with the "mtpt" option. + + irixsgid + Do not inherit the ISGID bit on subdirectories of ISGID + directories, if the process creating the subdirectory + is not a member of the parent directory group ID. + This matches IRIX behavior. + + logbufs=value + Set the number of in-memory log buffers. Valid numbers range + from 2-8 inclusive. + The default value is 8 buffers for filesystems with a + blocksize of 64K, 4 buffers for filesystems with a blocksize + of 32K, 3 buffers for filesystems with a blocksize of 16K + and 2 buffers for all other configurations. Increasing the + number of buffers may increase performance on some workloads + at the cost of the memory used for the additional log buffers + and their associated control structures. + + logbsize=value + Set the size of each in-memory log buffer. + Size may be specified in bytes, or in kilobytes with a "k" suffix. + Valid sizes for version 1 and version 2 logs are 16384 (16k) and + 32768 (32k). Valid sizes for version 2 logs also include + 65536 (64k), 131072 (128k) and 262144 (256k). + The default value for machines with more than 32MB of memory + is 32768, machines with less memory use 16384 by default. + + logdev=device and rtdev=device + Use an external log (metadata journal) and/or real-time device. + An XFS filesystem has up to three parts: a data section, a log + section, and a real-time section. The real-time section is + optional, and the log section can be separate from the data + section or contained within it. + + mtpt=mountpoint + Use with the "dmapi" option. The value specified here will be + included in the DMAPI mount event, and should be the path of + the actual mountpoint that is used. + + noalign + Data allocations will not be aligned at stripe unit boundaries. + + noatime + Access timestamps are not updated when a file is read. + + norecovery + The filesystem will be mounted without running log recovery. + If the filesystem was not cleanly unmounted, it is likely to + be inconsistent when mounted in "norecovery" mode. + Some files or directories may not be accessible because of this. + Filesystems mounted "norecovery" must be mounted read-only or + the mount will fail. + + osyncisosync + Make O_SYNC writes implement true O_SYNC. WITHOUT this option, + Linux XFS behaves as if an "osyncisdsync" option is used, + which will make writes to files opened with the O_SYNC flag set + behave as if the O_DSYNC flag had been used instead. + This can result in better performance without compromising + data safety. + However if this option is not in effect, timestamp updates from + O_SYNC writes can be lost if the system crashes. + If timestamp updates are critical, use the osyncisosync option. + + quota/usrquota/uqnoenforce + User disk quota accounting enabled, and limits (optionally) + enforced. + + grpquota/gqnoenforce + Group disk quota accounting enabled and limits (optionally) + enforced. + + sunit=value and swidth=value + Used to specify the stripe unit and width for a RAID device or + a stripe volume. "value" must be specified in 512-byte block + units. + If this option is not specified and the filesystem was made on + a stripe volume or the stripe width or unit were specified for + the RAID device at mkfs time, then the mount system call will + restore the value from the superblock. For filesystems that + are made directly on RAID devices, these options can be used + to override the information in the superblock if the underlying + disk layout changes after the filesystem has been created. + The "swidth" option is required if the "sunit" option has been + specified, and must be a multiple of the "sunit" value. + + nouuid + Don't check for double mounted file systems using the file system uuid. + This is useful to mount LVM snapshot volumes. + diff -urN linux-2.4.23-pre8/Documentation/s390/TAPE linux-2.4.23-pre8-pac1/Documentation/s390/TAPE --- linux-2.4.23-pre8/Documentation/s390/TAPE 2001-07-25 23:12:01.000000000 +0200 +++ linux-2.4.23-pre8-pac1/Documentation/s390/TAPE 1970-01-01 01:00:00.000000000 +0100 @@ -1,122 +0,0 @@ -Channel attached Tape device driver - ------------------------------WARNING----------------------------------------- -This driver is considered to be EXPERIMENTAL. Do NOT use it in -production environments. Feel free to test it and report problems back to us. ------------------------------------------------------------------------------ - -The LINUX for zSeries tape device driver manages channel attached tape drives -which are compatible to IBM 3480 or IBM 3490 magnetic tape subsystems. This -includes various models of these devices (for example the 3490E). - - -Tape driver features - -The device driver supports a maximum of 128 tape devices. -No official LINUX device major number is assigned to the zSeries tape device -driver. It allocates major numbers dynamically and reports them on system -startup. -Typically it will get major number 254 for both the character device front-end -and the block device front-end. - -The tape device driver needs no kernel parameters. All supported devices -present are detected on driver initialization at system startup or module load. -The devices detected are ordered by their subchannel numbers. The device with -the lowest subchannel number becomes device 0, the next one will be device 1 -and so on. - - -Tape character device front-end - -The usual way to read or write to the tape device is through the character -device front-end. The zSeries tape device driver provides two character devices -for each physical device -- the first of these will rewind automatically when -it is closed, the second will not rewind automatically. - -The character device nodes are named /dev/rtibm0 (rewinding) and /dev/ntibm0 -(non-rewinding) for the first device, /dev/rtibm1 and /dev/ntibm1 for the -second, and so on. - -The character device front-end can be used as any other LINUX tape device. You -can write to it and read from it using LINUX facilities such as GNU tar. The -tool mt can be used to perform control operations, such as rewinding the tape -or skipping a file. - -Most LINUX tape software should work with either tape character device. - - -Tape block device front-end - -The tape device may also be accessed as a block device in read-only mode. -This could be used for software installation in the same way as it is used with -other operation systems on the zSeries platform (and most LINUX -distributions are shipped on compact disk using ISO9660 filesystems). - -One block device node is provided for each physical device. These are named -/dev/btibm0 for the first device, /dev/btibm1 for the second and so on. -You should only use the ISO9660 filesystem on LINUX for zSeries tapes because -the physical tape devices cannot perform fast seeks and the ISO9660 system is -optimized for this situation. - - -Tape block device example - -In this example a tape with an ISO9660 filesystem is created using the first -tape device. ISO9660 filesystem support must be built into your system kernel -for this. -The mt command is used to issue tape commands and the mkisofs command to -create an ISO9660 filesystem: - -- create a LINUX directory (somedir) with the contents of the filesystem - mkdir somedir - cp contents somedir - -- insert a tape - -- ensure the tape is at the beginning - mt -f /dev/ntibm0 rewind - -- set the blocksize of the character driver. The blocksize 2048 bytes - is commonly used on ISO9660 CD-Roms - mt -f /dev/ntibm0 setblk 2048 - -- write the filesystem to the character device driver - mkisofs -o /dev/ntibm0 somedir - -- rewind the tape again - mt -f /dev/ntibm0 rewind - -- Now you can mount your new filesystem as a block device: - mount -t iso9660 -o ro,block=2048 /dev/btibm0 /mnt - -TODO List - - - Driver has to be stabelized still - -BUGS - -This driver is considered BETA, which means some weaknesses may still -be in it. -If an error occurs which cannot be handled by the code you will get a -sense-data dump.In that case please do the following: - -1. set the tape driver debug level to maximum: - echo 6 >/proc/s390dbf/tape/level - -2. re-perform the actions which produced the bug. (Hopefully the bug will - reappear.) - -3. get a snapshot from the debug-feature: - cat /proc/s390dbf/tape/hex_ascii >somefile - -4. Now put the snapshot together with a detailed description of the situation - that led to the bug: - - Which tool did you use? - - Which hardware do you have? - - Was your tape unit online? - - Is it a shared tape unit? - -5. Send an email with your bug report to: - mailto:Linux390@de.ibm.com - - diff -urN linux-2.4.23-pre8/Documentation/sched-coding.txt linux-2.4.23-pre8-pac1/Documentation/sched-coding.txt --- linux-2.4.23-pre8/Documentation/sched-coding.txt 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/Documentation/sched-coding.txt 2003-10-24 14:31:25.000000000 +0200 @@ -0,0 +1,129 @@ + Reference for various scheduler-related methods in the O(1) scheduler + Robert Love , MontaVista Software + + +Note most of these methods are local to kernel/sched.c - this is by design. +The scheduler is meant to be self-contained and abstracted away. This document +is primarily for understanding the scheduler, not interfacing to it. Some of +the discussed interfaces, however, are general process/scheduling methods. +They are typically defined in include/linux/sched.h. + + +Main Scheduling Methods +----------------------- + +void load_balance(runqueue_t *this_rq, int idle) + Attempts to pull tasks from one cpu to another to balance cpu usage, + if needed. This method is called explicitly if the runqueues are + inbalanced or periodically by the timer tick. Prior to calling, + the current runqueue must be locked and interrupts disabled. + +void schedule() + The main scheduling function. Upon return, the highest priority + process will be active. + + +Locking +------- + +Each runqueue has its own lock, rq->lock. When multiple runqueues need +to be locked, lock acquires must be ordered by ascending &runqueue value. + +A specific runqueue is locked via + + task_rq_lock(task_t pid, unsigned long *flags) + +which disables preemption, disables interrupts, and locks the runqueue pid is +running on. Likewise, + + task_rq_unlock(task_t pid, unsigned long *flags) + +unlocks the runqueue pid is running on, restores interrupts to their previous +state, and reenables preemption. + +The routines + + double_rq_lock(runqueue_t *rq1, runqueue_t *rq2) + +and + + double_rq_unlock(runqueue_t *rq1, runqueue_t rq2) + +safely lock and unlock, respectively, the two specified runqueues. They do +not, however, disable and restore interrupts. Users are required to do so +manually before and after calls. + + +Values +------ + +MAX_PRIO + The maximum priority of the system, stored in the task as task->prio. + Lower priorities are higher. Normal (non-RT) priorities range from + MAX_RT_PRIO to (MAX_PRIO - 1). +MAX_RT_PRIO + The maximum real-time priority of the system. Valid RT priorities + range from 0 to (MAX_RT_PRIO - 1). +MAX_USER_RT_PRIO + The maximum real-time priority that is exported to user-space. Should + always be equal to or less than MAX_RT_PRIO. Setting it less allows + kernel threads to have higher priorities than any user-space task. +MIN_TIMESLICE +MAX_TIMESLICE + Respectively, the minimum and maximum timeslices (quanta) of a process. + +Data +---- + +struct runqueue + The main per-CPU runqueue data structure. +struct task_struct + The main per-process data structure. + + +General Methods +--------------- + +cpu_rq(cpu) + Returns the runqueue of the specified cpu. +this_rq() + Returns the runqueue of the current cpu. +task_rq(task) + Returns the runqueue which holds the specified task. +cpu_curr(cpu) + Returns the task currently running on the given cpu. +rt_task(task) + Returns true if task is real-time, false if not. +task_cpu(task) + + +Process Control Methods +----------------------- + +void set_user_nice(task_t *p, long nice) + Sets the "nice" value of task p to the given value. +int setscheduler(pid_t pid, int policy, struct sched_param *param) + Sets the scheduling policy and parameters for the given pid. +void set_cpus_allowed(task_t *p, unsigned long new_mask) + Sets a given task's CPU affinity and migrates it to a proper cpu. + Callers must have a valid reference to the task and assure the + task not exit prematurely. No locks can be held during the call. +set_task_state(tsk, state_value) + Sets the given task's state to the given value. +set_current_state(state_value) + Sets the current task's state to the given value. +void set_tsk_need_resched(struct task_struct *tsk) + Sets need_resched in the given task. +void clear_tsk_need_resched(struct task_struct *tsk) + Clears need_resched in the given task. +void set_need_resched() + Sets need_resched in the current task. +void set_task_cpu(task, cpu) + Sets task->cpu to cpu on SMP. Noop on UP. +void clear_need_resched() + Clears need_resched in the current task. +int need_resched() + Returns true if need_resched is set in the current task, false + otherwise. +yield() + Place the current process at the end of the runqueue and call schedule. diff -urN linux-2.4.23-pre8/Documentation/sched-design.txt linux-2.4.23-pre8-pac1/Documentation/sched-design.txt --- linux-2.4.23-pre8/Documentation/sched-design.txt 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/Documentation/sched-design.txt 2003-10-24 14:31:25.000000000 +0200 @@ -0,0 +1,165 @@ + Goals, Design and Implementation of the + new ultra-scalable O(1) scheduler + + + This is an edited version of an email Ingo Molnar sent to + lkml on 4 Jan 2002. It describes the goals, design, and + implementation of Ingo's new ultra-scalable O(1) scheduler. + Last Updated: 18 April 2002. + + +Goal +==== + +The main goal of the new scheduler is to keep all the good things we know +and love about the current Linux scheduler: + + - good interactive performance even during high load: if the user + types or clicks then the system must react instantly and must execute + the user tasks smoothly, even during considerable background load. + + - good scheduling/wakeup performance with 1-2 runnable processes. + + - fairness: no process should stay without any timeslice for any + unreasonable amount of time. No process should get an unjustly high + amount of CPU time. + + - priorities: less important tasks can be started with lower priority, + more important tasks with higher priority. + + - SMP efficiency: no CPU should stay idle if there is work to do. + + - SMP affinity: processes which run on one CPU should stay affine to + that CPU. Processes should not bounce between CPUs too frequently. + + - plus additional scheduler features: RT scheduling, CPU binding. + +and the goal is also to add a few new things: + + - fully O(1) scheduling. Are you tired of the recalculation loop + blowing the L1 cache away every now and then? Do you think the goodness + loop is taking a bit too long to finish if there are lots of runnable + processes? This new scheduler takes no prisoners: wakeup(), schedule(), + the timer interrupt are all O(1) algorithms. There is no recalculation + loop. There is no goodness loop either. + + - 'perfect' SMP scalability. With the new scheduler there is no 'big' + runqueue_lock anymore - it's all per-CPU runqueues and locks - two + tasks on two separate CPUs can wake up, schedule and context-switch + completely in parallel, without any interlocking. All + scheduling-relevant data is structured for maximum scalability. + + - better SMP affinity. The old scheduler has a particular weakness that + causes the random bouncing of tasks between CPUs if/when higher + priority/interactive tasks, this was observed and reported by many + people. The reason is that the timeslice recalculation loop first needs + every currently running task to consume its timeslice. But when this + happens on eg. an 8-way system, then this property starves an + increasing number of CPUs from executing any process. Once the last + task that has a timeslice left has finished using up that timeslice, + the recalculation loop is triggered and other CPUs can start executing + tasks again - after having idled around for a number of timer ticks. + The more CPUs, the worse this effect. + + Furthermore, this same effect causes the bouncing effect as well: + whenever there is such a 'timeslice squeeze' of the global runqueue, + idle processors start executing tasks which are not affine to that CPU. + (because the affine tasks have finished off their timeslices already.) + + The new scheduler solves this problem by distributing timeslices on a + per-CPU basis, without having any global synchronization or + recalculation. + + - batch scheduling. A significant proportion of computing-intensive tasks + benefit from batch-scheduling, where timeslices are long and processes + are roundrobin scheduled. The new scheduler does such batch-scheduling + of the lowest priority tasks - so nice +19 jobs will get + 'batch-scheduled' automatically. With this scheduler, nice +19 jobs are + in essence SCHED_IDLE, from an interactiveness point of view. + + - handle extreme loads more smoothly, without breakdown and scheduling + storms. + + - O(1) RT scheduling. For those RT folks who are paranoid about the + O(nr_running) property of the goodness loop and the recalculation loop. + + - run fork()ed children before the parent. Andrea has pointed out the + advantages of this a few months ago, but patches for this feature + do not work with the old scheduler as well as they should, + because idle processes often steal the new child before the fork()ing + CPU gets to execute it. + + +Design +====== + +the core of the new scheduler are the following mechanizms: + + - *two*, priority-ordered 'priority arrays' per CPU. There is an 'active' + array and an 'expired' array. The active array contains all tasks that + are affine to this CPU and have timeslices left. The expired array + contains all tasks which have used up their timeslices - but this array + is kept sorted as well. The active and expired array is not accessed + directly, it's accessed through two pointers in the per-CPU runqueue + structure. If all active tasks are used up then we 'switch' the two + pointers and from now on the ready-to-go (former-) expired array is the + active array - and the empty active array serves as the new collector + for expired tasks. + + - there is a 64-bit bitmap cache for array indices. Finding the highest + priority task is thus a matter of two x86 BSFL bit-search instructions. + +the split-array solution enables us to have an arbitrary number of active +and expired tasks, and the recalculation of timeslices can be done +immediately when the timeslice expires. Because the arrays are always +access through the pointers in the runqueue, switching the two arrays can +be done very quickly. + +this is a hybride priority-list approach coupled with roundrobin +scheduling and the array-switch method of distributing timeslices. + + - there is a per-task 'load estimator'. + +one of the toughest things to get right is good interactive feel during +heavy system load. While playing with various scheduler variants i found +that the best interactive feel is achieved not by 'boosting' interactive +tasks, but by 'punishing' tasks that want to use more CPU time than there +is available. This method is also much easier to do in an O(1) fashion. + +to establish the actual 'load' the task contributes to the system, a +complex-looking but pretty accurate method is used: there is a 4-entry +'history' ringbuffer of the task's activities during the last 4 seconds. +This ringbuffer is operated without much overhead. The entries tell the +scheduler a pretty accurate load-history of the task: has it used up more +CPU time or less during the past N seconds. [the size '4' and the interval +of 4x 1 seconds was found by lots of experimentation - this part is +flexible and can be changed in both directions.] + +the penalty a task gets for generating more load than the CPU can handle +is a priority decrease - there is a maximum amount to this penalty +relative to their static priority, so even fully CPU-bound tasks will +observe each other's priorities, and will share the CPU accordingly. + +the SMP load-balancer can be extended/switched with additional parallel +computing and cache hierarchy concepts: NUMA scheduling, multi-core CPUs +can be supported easily by changing the load-balancer. Right now it's +tuned for my SMP systems. + +i skipped the prev->mm == next->mm advantage - no workload i know of shows +any sensitivity to this. It can be added back by sacrificing O(1) +schedule() [the current and one-lower priority list can be searched for a +that->mm == current->mm condition], but costs a fair number of cycles +during a number of important workloads, so i wanted to avoid this as much +as possible. + +- the SMP idle-task startup code was still racy and the new scheduler +triggered this. So i streamlined the idle-setup code a bit. We do not call +into schedule() before all processors have started up fully and all idle +threads are in place. + +- the patch also cleans up a number of aspects of sched.c - moves code +into other areas of the kernel where it's appropriate, and simplifies +certain code paths and data constructs. As a result, the new scheduler's +code is smaller than the old one. + + Ingo diff -urN linux-2.4.23-pre8/Documentation/vm/overcommit-accounting linux-2.4.23-pre8-pac1/Documentation/vm/overcommit-accounting --- linux-2.4.23-pre8/Documentation/vm/overcommit-accounting 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/Documentation/vm/overcommit-accounting 2003-10-24 14:31:25.000000000 +0200 @@ -0,0 +1,70 @@ +* This describes the overcommit management facility in the latest kernel + tree (FIXME: actually it also describes the stuff that isnt yet done) + +The Linux kernel supports four overcommit handling modes + +0 - Heuristic overcommit handling. Obvious overcommits of + address space are refused. Used for a typical system. It + ensures a seriously wild allocation fails while allowing + overcommit to reduce swap usage + +1 - No overcommit handling. Appropriate for some scientific + applications + +2 - (NEW) strict overcommit. The total address space commit + for the system is not permitted to exceed swap + half ram. + In almost all situations this means a process will not be + killed while accessing pages but only by malloc failures + that are reported back by the kernel mmap/brk code. + +3 - (NEW) paranoid overcommit The total address space commit + for the system is not permitted to exceed swap. The machine + will never kill a process accessing pages it has mapped + except due to a bug (ie report it!) + +Gotchas +------- + +The C language stack growth does an implicit mremap. If you want absolute +guarantees and run close to the edge you MUST mmap your stack for the +largest size you think you will need. For typical stack usage is does +not matter much but its a corner case if you really really care + +In modes 2 and 3 the MAP_NORESERVE flag is ignored. + + +How It Works +------------ + +The overcommit is based on the following rules + +For a file backed map + SHARED or READ-only - 0 cost (the file is the map not swap) + PRIVATE WRITABLE - size of mapping per instance + +For an anonymous or /dev/zero map + SHARED - size of mapping + PRIVATE READ-only - 0 cost (but of little use) + PRIVATE WRITABLE - size of mapping per instance + +Additional accounting + Pages made writable copies by mmap + shmfs memory drawn from the same pool + +Status +------ + +o We account mmap memory mappings +o We account mprotect changes in commit +o We account mremap changes in size +o We account brk +o We account munmap +o We report the commit status in /proc +o Account and check on fork +o Review stack handling/building on exec +o SHMfs accounting +o Implement actual limit enforcement + +To Do +----- +o Account ptrace pages (this is hard) diff -urN linux-2.4.23-pre8/MAINTAINERS linux-2.4.23-pre8-pac1/MAINTAINERS --- linux-2.4.23-pre8/MAINTAINERS 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/MAINTAINERS 2003-10-24 14:31:25.000000000 +0200 @@ -1,4 +1,4 @@ - + List of maintainers and how to submit kernel changes Please try to follow the guidelines below. This will make things @@ -572,6 +572,20 @@ W: http://www.debian.org/~dz/i8k/ S: Maintained +DEVICE-MAPPER +P: Joe Thornber +M: thornber@sistina.com +L: dm@uk.sistina.com +W: http://www.sistina.com/lvm +S: Maintained + +DEVICE MAPPER +P: Joe Thornber +M: dm@uk.sistina.com +L: linux-LVM@sistina.com +W: http://www.sistina.com/lvm +S: Maintained + DEVICE NUMBER REGISTRY P: H. Peter Anvin M: hpa@zytor.com @@ -638,8 +652,6 @@ S: Maintained DRM DRIVERS -P: Rik Faith -M: faith@valinux.com L: dri-devel@lists.sourceforge.net S: Supported @@ -967,6 +979,11 @@ M: jeremy@sgi.com S: Maintained +IOC4 IDE DRIVER +P: Aniket Malatpure +M: aniket@sgi.com +S: Maintained + IP MASQUERADING: P: Juanjo Ciarlante M: jjciarla@raiz.uncu.edu.ar @@ -1049,8 +1066,6 @@ KERNEL BUILD (Makefile, Rules.make, scripts/*) P: Keith Owens M: kaos@ocs.com.au -P: Michael Elizabeth Chastain -M: mec@shout.net L: kbuild-devel@lists.sourceforge.net W: http://kbuild.sourceforge.net S: Maintained @@ -1324,9 +1339,10 @@ NTFS FILESYSTEM P: Anton Altaparmakov -M: aia21@cus.cam.ac.uk +M: aia21@cantab.net L: linux-ntfs-dev@lists.sourceforge.net L: linux-kernel@vger.kernel.org +W: http://linux-ntfs.sf.net/ S: Maintained NVIDIA (RIVA) FRAMEBUFFER DRIVER @@ -2069,10 +2085,9 @@ S: Maintained VFAT FILESYSTEM: -P: Gordon Chaffee -M: chaffee@cs.berkeley.edu +P: OGAWA Hirofumi +M: hirofumi@mail.parknet.co.jp L: linux-kernel@vger.kernel.org -W: http://bmrc.berkeley.edu/people/chaffee S: Maintained VIA 82Cxxx AUDIO DRIVER @@ -2116,12 +2131,26 @@ L: linux-scsi@vger.kernel.org S: Maintained +WOLFSON WM97xx AC97 CODECS & TOUCHSCREEN DRIVERS +P: Liam Girdwood +M: liam.girdwood@wolfsonmicro.com +M: linux@wolfsonmicro.com +S: Supported + X.25 NETWORK LAYER P: Henner Eisen M: eis@baty.hanse.de L: linux-x25@vger.kernel.org S: Maintained +XFS FILESYSTEM +P: Silicon Graphics Inc +M: owner-xfs@oss.sgi.com +M: lord@sgi.com +L: linux-xfs@oss.sgi.com +W: http://oss.sgi.com/projects/xfs +S: Supported + X86 3-LEVEL PAGING (PAE) SUPPORT P: Ingo Molnar M: mingo@redhat.com diff -urN linux-2.4.23-pre8/Makefile linux-2.4.23-pre8-pac1/Makefile --- linux-2.4.23-pre8/Makefile 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/Makefile 2003-10-24 14:31:25.000000000 +0200 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 23 -EXTRAVERSION = -pre8 +EXTRAVERSION = -pre8-pac1 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) @@ -135,12 +135,14 @@ DRIVERS-m := DRIVERS- := -DRIVERS-$(CONFIG_ACPI_BOOT) += drivers/acpi/acpi.o +DRIVERS-$(CONFIG_ACPI) += drivers/acpi/acpi.o +DRIVERS-$(CONFIG_CPU_FREQ) += drivers/cpufreq/cpufreq.o DRIVERS-$(CONFIG_PARPORT) += drivers/parport/driver.o DRIVERS-y += drivers/char/char.o \ drivers/block/block.o \ drivers/misc/misc.o \ drivers/net/net.o + DRIVERS-$(CONFIG_AGP) += drivers/char/agp/agp.o DRIVERS-$(CONFIG_DRM_NEW) += drivers/char/drm/drm.o DRIVERS-$(CONFIG_DRM_OLD) += drivers/char/drm-4.0/drm.o @@ -174,7 +176,7 @@ DRIVERS-$(CONFIG_FC4) += drivers/fc4/fc4.a DRIVERS-$(CONFIG_PPC32) += drivers/macintosh/macintosh.o DRIVERS-$(CONFIG_MAC) += drivers/macintosh/macintosh.o -DRIVERS-$(CONFIG_ISAPNP) += drivers/pnp/pnp.o +DRIVERS-$(CONFIG_PNP) += drivers/pnp/pnp.o DRIVERS-$(CONFIG_SGI_IP22) += drivers/sgi/sgi.a DRIVERS-$(CONFIG_VT) += drivers/video/video.o DRIVERS-$(CONFIG_PARIDE) += drivers/block/paride/paride.a @@ -204,6 +206,7 @@ kernel/ksyms.lst include/linux/compile.h \ vmlinux System.map \ .tmp* \ + scripts/mkconfigs kernel/configs.c kernel/configs.o \ drivers/char/consolemap_deftbl.c drivers/video/promcon_tbl.c \ drivers/char/conmakehash \ drivers/char/drm/*-mod.c \ @@ -231,6 +234,7 @@ # files removed with 'make mrproper' MRPROPER_FILES = \ include/linux/autoconf.h include/linux/version.h \ + tmp* \ lib/crc32table.h lib/gen_crc32table \ drivers/net/hamradio/soundmodem/sm_tbl_{afsk1200,afsk2666,fsk9600}.h \ drivers/net/hamradio/soundmodem/sm_tbl_{hapn4800,psk4800}.h \ @@ -249,6 +253,7 @@ include/asm \ .hdepend scripts/mkdep scripts/split-include scripts/docproc \ $(TOPDIR)/include/linux/modversions.h \ + scripts/mkconfigs kernel/configs.c kernel/configs.o \ kernel.spec # directories removed with 'make mrproper' @@ -322,7 +327,7 @@ linuxsubdirs: $(patsubst %, _dir_%, $(SUBDIRS)) -$(patsubst %, _dir_%, $(SUBDIRS)) : dummy include/linux/version.h include/config/MARKER +$(patsubst %, _dir_%, $(SUBDIRS)) : dummy include/linux/version.h tmp_include_depends $(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" -C $(patsubst _dir_%, %, $@) $(TOPDIR)/include/linux/version.h: include/linux/version.h @@ -362,13 +367,13 @@ comma := , -init/version.o: init/version.c include/linux/compile.h include/config/MARKER +init/version.o: init/version.c include/linux/compile.h tmp_include_depends $(CC) $(CFLAGS) $(CFLAGS_KERNEL) -DUTS_MACHINE='"$(ARCH)"' -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) -c -o init/version.o init/version.c -init/main.o: init/main.c include/config/MARKER +init/main.o: init/main.c tmp_include_depends $(CC) $(CFLAGS) $(CFLAGS_KERNEL) $(PROFILING) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) -c -o $@ $< -init/do_mounts.o: init/do_mounts.c include/config/MARKER +init/do_mounts.o: init/do_mounts.c tmp_include_depends $(CC) $(CFLAGS) $(CFLAGS_KERNEL) $(PROFILING) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) -c -o $@ $< fs lib mm ipc kernel drivers net: dummy @@ -395,7 +400,7 @@ modules: $(patsubst %, _mod_%, $(SUBDIRS)) .PHONY: $(patsubst %, _mod_%, $(SUBDIRS)) -$(patsubst %, _mod_%, $(SUBDIRS)) : include/linux/version.h include/config/MARKER +$(patsubst %, _mod_%, $(SUBDIRS)) : include/linux/version.h tmp_include_depends $(MAKE) -C $(patsubst _mod_%, %, $@) CFLAGS="$(CFLAGS) $(MODFLAGS)" MAKING_MODULES=1 modules .PHONY: modules_install @@ -501,6 +506,13 @@ endif scripts/mkdep -- `find $(FINDHPATH) \( -name SCCS -o -name .svn \) -prune -o -follow -name \*.h ! -name modversions.h -print` > .hdepend scripts/mkdep -- init/*.c > .depend + (find $(TOPDIR) \( -name .depend -o -name .hdepend \) -print | xargs $(AWK) -f scripts/include_deps) > tmp_include_depends + sed -ne 's/^\([^ ].*\):.*/ \1 \\/p' tmp_include_depends > tmp_include_depends_1 + (echo ""; echo "all: \\"; cat tmp_include_depends_1; echo "") >> tmp_include_depends + rm tmp_include_depends_1 + +tmp_include_depends: include/config/MARKER dummy + $(MAKE) -r -f tmp_include_depends all ifdef CONFIG_MODVERSIONS MODVERFILE := $(TOPDIR)/include/linux/modversions.h diff -urN linux-2.4.23-pre8/Rules.make linux-2.4.23-pre8-pac1/Rules.make --- linux-2.4.23-pre8/Rules.make 2002-08-03 02:39:42.000000000 +0200 +++ linux-2.4.23-pre8-pac1/Rules.make 2003-10-24 14:31:25.000000000 +0200 @@ -291,10 +291,6 @@ include .depend endif -ifneq ($(wildcard $(TOPDIR)/.hdepend),) -include $(TOPDIR)/.hdepend -endif - # # Find files whose flags have changed and force recompilation. # For safety, this works in the converse direction: diff -urN linux-2.4.23-pre8/arch/alpha/defconfig linux-2.4.23-pre8-pac1/arch/alpha/defconfig --- linux-2.4.23-pre8/arch/alpha/defconfig 2003-06-13 16:51:29.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/alpha/defconfig 2003-10-24 14:31:25.000000000 +0200 @@ -565,6 +565,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/alpha/kernel/entry.S linux-2.4.23-pre8-pac1/arch/alpha/kernel/entry.S --- linux-2.4.23-pre8/arch/alpha/kernel/entry.S 2003-06-13 16:51:29.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/alpha/kernel/entry.S 2003-10-24 14:31:25.000000000 +0200 @@ -690,6 +690,7 @@ .end entSys .globl ret_from_fork +#if CONFIG_SMP .align 3 .ent ret_from_fork ret_from_fork: @@ -697,6 +698,9 @@ mov $17,$16 jsr $31,schedule_tail .end ret_from_fork +#else +ret_from_fork = ret_from_sys_call +#endif .align 3 .ent reschedule diff -urN linux-2.4.23-pre8/arch/alpha/kernel/process.c linux-2.4.23-pre8-pac1/arch/alpha/kernel/process.c --- linux-2.4.23-pre8/arch/alpha/kernel/process.c 2003-08-25 13:44:39.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/alpha/kernel/process.c 2003-10-24 14:31:25.000000000 +0200 @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -74,9 +75,6 @@ cpu_idle(void) { /* An endless idle loop with no priority at all. */ - current->nice = 20; - current->counter = -100; - while (1) { /* FIXME -- EV6 and LCA45 know how to power down the CPU. */ diff -urN linux-2.4.23-pre8/arch/alpha/kernel/smp.c linux-2.4.23-pre8-pac1/arch/alpha/kernel/smp.c --- linux-2.4.23-pre8/arch/alpha/kernel/smp.c 2003-06-13 16:51:29.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/alpha/kernel/smp.c 2003-10-24 14:31:25.000000000 +0200 @@ -81,6 +81,7 @@ int smp_num_probed; /* Internal processor count */ int smp_num_cpus = 1; /* Number that came online. */ int smp_threads_ready; /* True once the per process idle is forked. */ +unsigned long cache_decay_ticks; int __cpu_number_map[NR_CPUS]; int __cpu_logical_map[NR_CPUS]; @@ -155,11 +156,6 @@ { int cpuid = hard_smp_processor_id(); - if (current != init_tasks[cpu_number_map(cpuid)]) { - printk("BUG: smp_calling: cpu %d current %p init_tasks[cpu_number_map(cpuid)] %p\n", - cpuid, current, init_tasks[cpu_number_map(cpuid)]); - } - DBGS(("CALLIN %d state 0x%lx\n", cpuid, current->state)); /* Turn on machine checks. */ @@ -217,9 +213,6 @@ DBGS(("smp_callin: commencing CPU %d current %p\n", cpuid, current)); - /* Setup the scheduler for this processor. */ - init_idle(); - /* ??? This should be in init_idle. */ atomic_inc(&init_mm.mm_count); current->active_mm = &init_mm; @@ -449,14 +442,11 @@ if (idle == &init_task) panic("idle process is init_task for CPU %d", cpuid); - idle->processor = cpuid; - idle->cpus_runnable = 1 << cpuid; /* we schedule the first task manually */ + init_idle(idle, cpuid); + unhash_process(idle); + __cpu_logical_map[cpunum] = cpuid; __cpu_number_map[cpuid] = cpunum; - - del_from_runqueue(idle); - unhash_process(idle); - init_tasks[cpunum] = idle; DBGS(("smp_boot_one_cpu: CPU %d state 0x%lx flags 0x%lx\n", cpuid, idle->state, idle->flags)); @@ -563,13 +553,10 @@ __cpu_number_map[boot_cpuid] = 0; __cpu_logical_map[0] = boot_cpuid; - current->processor = boot_cpuid; smp_store_cpu_info(boot_cpuid); smp_setup_percpu_timer(boot_cpuid); - init_idle(); - /* ??? This should be in init_idle. */ atomic_inc(&init_mm.mm_count); current->active_mm = &init_mm; diff -urN linux-2.4.23-pre8/arch/alpha/kernel/srmcons.c linux-2.4.23-pre8-pac1/arch/alpha/kernel/srmcons.c --- linux-2.4.23-pre8/arch/alpha/kernel/srmcons.c 2003-06-13 16:51:29.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/alpha/kernel/srmcons.c 2003-10-24 14:31:25.000000000 +0200 @@ -260,7 +260,7 @@ spin_lock_irqsave(&srmconsp->lock, flags); - if (tty->count == 1) { + if (atomic_read(&tty->count) == 1) { srmconsp->tty = NULL; del_timer(&srmconsp->timer); } diff -urN linux-2.4.23-pre8/arch/alpha/mm/fault.c linux-2.4.23-pre8-pac1/arch/alpha/mm/fault.c --- linux-2.4.23-pre8/arch/alpha/mm/fault.c 2002-11-29 00:53:08.000000000 +0100 +++ linux-2.4.23-pre8-pac1/arch/alpha/mm/fault.c 2003-10-24 14:31:25.000000000 +0200 @@ -122,8 +122,6 @@ goto bad_area; if (vma->vm_start <= address) goto good_area; - if (!(vma->vm_flags & VM_GROWSDOWN)) - goto bad_area; if (expand_stack(vma, address)) goto bad_area; /* diff -urN linux-2.4.23-pre8/arch/arm/config.in linux-2.4.23-pre8-pac1/arch/arm/config.in --- linux-2.4.23-pre8/arch/arm/config.in 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/arm/config.in 2003-10-24 14:31:25.000000000 +0200 @@ -722,6 +722,7 @@ bool 'Kernel debugging' CONFIG_DEBUG_KERNEL dep_bool ' Debug memory allocations' CONFIG_DEBUG_SLAB $CONFIG_DEBUG_KERNEL dep_bool ' Magic SysRq key' CONFIG_MAGIC_SYSRQ $CONFIG_DEBUG_KERNEL +dep_bool ' Morse code panics' CONFIG_PANIC_MORSE $CONFIG_DEBUG_KERNEL $CONFIG_PC_KEYB dep_bool ' Spinlock debugging' CONFIG_DEBUG_SPINLOCK $CONFIG_DEBUG_KERNEL dep_bool ' Wait queue debugging' CONFIG_DEBUG_WAITQ $CONFIG_DEBUG_KERNEL dep_bool ' Verbose BUG() reporting (adds 70K)' CONFIG_DEBUG_BUGVERBOSE $CONFIG_DEBUG_KERNEL diff -urN linux-2.4.23-pre8/arch/arm/def-configs/a5k linux-2.4.23-pre8-pac1/arch/arm/def-configs/a5k --- linux-2.4.23-pre8/arch/arm/def-configs/a5k 2000-11-28 02:07:59.000000000 +0100 +++ linux-2.4.23-pre8-pac1/arch/arm/def-configs/a5k 2003-10-24 14:31:25.000000000 +0200 @@ -394,6 +394,7 @@ # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/arm/def-configs/adsbitsy linux-2.4.23-pre8-pac1/arch/arm/def-configs/adsbitsy --- linux-2.4.23-pre8/arch/arm/def-configs/adsbitsy 2003-08-25 13:44:39.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/arm/def-configs/adsbitsy 2003-10-24 14:31:25.000000000 +0200 @@ -737,6 +737,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/arm/def-configs/anakin linux-2.4.23-pre8-pac1/arch/arm/def-configs/anakin --- linux-2.4.23-pre8/arch/arm/def-configs/anakin 2002-08-03 02:39:42.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/arm/def-configs/anakin 2003-10-24 14:31:25.000000000 +0200 @@ -372,6 +372,7 @@ # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/arm/def-configs/assabet linux-2.4.23-pre8-pac1/arch/arm/def-configs/assabet --- linux-2.4.23-pre8/arch/arm/def-configs/assabet 2002-08-03 02:39:42.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/arm/def-configs/assabet 2003-10-24 14:31:25.000000000 +0200 @@ -667,6 +667,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_FREEVXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/arm/def-configs/badge4 linux-2.4.23-pre8-pac1/arch/arm/def-configs/badge4 --- linux-2.4.23-pre8/arch/arm/def-configs/badge4 2003-06-13 16:51:29.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/arm/def-configs/badge4 2003-10-24 14:31:25.000000000 +0200 @@ -838,6 +838,7 @@ CONFIG_MINIX_FS=m # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/arm/def-configs/brutus linux-2.4.23-pre8-pac1/arch/arm/def-configs/brutus --- linux-2.4.23-pre8/arch/arm/def-configs/brutus 2001-08-12 20:13:59.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/arm/def-configs/brutus 2003-10-24 14:31:25.000000000 +0200 @@ -222,6 +222,7 @@ # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/arm/def-configs/cerfcube linux-2.4.23-pre8-pac1/arch/arm/def-configs/cerfcube --- linux-2.4.23-pre8/arch/arm/def-configs/cerfcube 2002-08-03 02:39:42.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/arm/def-configs/cerfcube 2003-10-24 14:31:25.000000000 +0200 @@ -660,6 +660,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_FREEVXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/arm/def-configs/cerfpda linux-2.4.23-pre8-pac1/arch/arm/def-configs/cerfpda --- linux-2.4.23-pre8/arch/arm/def-configs/cerfpda 2002-08-03 02:39:42.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/arm/def-configs/cerfpda 2003-10-24 14:31:25.000000000 +0200 @@ -698,6 +698,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_FREEVXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/arm/def-configs/cerfpod linux-2.4.23-pre8-pac1/arch/arm/def-configs/cerfpod --- linux-2.4.23-pre8/arch/arm/def-configs/cerfpod 2002-08-03 02:39:42.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/arm/def-configs/cerfpod 2003-10-24 14:31:25.000000000 +0200 @@ -662,6 +662,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_FREEVXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/arm/def-configs/clps7500 linux-2.4.23-pre8-pac1/arch/arm/def-configs/clps7500 --- linux-2.4.23-pre8/arch/arm/def-configs/clps7500 2002-08-03 02:39:42.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/arm/def-configs/clps7500 2003-10-24 14:31:25.000000000 +0200 @@ -420,6 +420,8 @@ # CONFIG_ISO9660_FS is not set CONFIG_MINIX_FS=y # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG 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 diff -urN linux-2.4.23-pre8/arch/arm/def-configs/ebsa110 linux-2.4.23-pre8-pac1/arch/arm/def-configs/ebsa110 --- linux-2.4.23-pre8/arch/arm/def-configs/ebsa110 2002-08-03 02:39:42.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/arm/def-configs/ebsa110 2003-10-24 14:31:25.000000000 +0200 @@ -530,6 +530,7 @@ CONFIG_MINIX_FS=y # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/arm/def-configs/edb7211 linux-2.4.23-pre8-pac1/arch/arm/def-configs/edb7211 --- linux-2.4.23-pre8/arch/arm/def-configs/edb7211 2001-10-25 22:53:44.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/arm/def-configs/edb7211 2003-10-24 14:31:25.000000000 +0200 @@ -329,6 +329,7 @@ # CONFIG_JOLIET is not set CONFIG_MINIX_FS=y # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/arm/def-configs/empeg linux-2.4.23-pre8-pac1/arch/arm/def-configs/empeg --- linux-2.4.23-pre8/arch/arm/def-configs/empeg 2003-06-13 16:51:29.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/arm/def-configs/empeg 2003-10-24 14:31:25.000000000 +0200 @@ -222,6 +222,8 @@ # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_QNX4FS_FS is not set diff -urN linux-2.4.23-pre8/arch/arm/def-configs/epxa10db linux-2.4.23-pre8-pac1/arch/arm/def-configs/epxa10db --- linux-2.4.23-pre8/arch/arm/def-configs/epxa10db 2003-08-25 13:44:39.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/arm/def-configs/epxa10db 2003-10-24 14:31:25.000000000 +0200 @@ -574,6 +574,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/arm/def-configs/flexanet linux-2.4.23-pre8-pac1/arch/arm/def-configs/flexanet --- linux-2.4.23-pre8/arch/arm/def-configs/flexanet 2002-08-03 02:39:42.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/arm/def-configs/flexanet 2003-10-24 14:31:25.000000000 +0200 @@ -651,6 +651,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/arm/def-configs/footbridge linux-2.4.23-pre8-pac1/arch/arm/def-configs/footbridge --- linux-2.4.23-pre8/arch/arm/def-configs/footbridge 2003-06-13 16:51:29.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/arm/def-configs/footbridge 2003-10-24 14:31:25.000000000 +0200 @@ -628,6 +628,7 @@ CONFIG_JOLIET=y # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/arm/def-configs/fortunet linux-2.4.23-pre8-pac1/arch/arm/def-configs/fortunet --- linux-2.4.23-pre8/arch/arm/def-configs/fortunet 2002-08-03 02:39:42.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/arm/def-configs/fortunet 2003-10-24 14:31:25.000000000 +0200 @@ -454,6 +454,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/arm/def-configs/freebird linux-2.4.23-pre8-pac1/arch/arm/def-configs/freebird --- linux-2.4.23-pre8/arch/arm/def-configs/freebird 2002-08-03 02:39:42.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/arm/def-configs/freebird 2003-10-24 14:31:25.000000000 +0200 @@ -501,6 +501,7 @@ # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/arm/def-configs/freebird_new linux-2.4.23-pre8-pac1/arch/arm/def-configs/freebird_new --- linux-2.4.23-pre8/arch/arm/def-configs/freebird_new 2002-08-03 02:39:42.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/arm/def-configs/freebird_new 2003-10-24 14:31:25.000000000 +0200 @@ -521,6 +521,7 @@ # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/arm/def-configs/frodo linux-2.4.23-pre8-pac1/arch/arm/def-configs/frodo --- linux-2.4.23-pre8/arch/arm/def-configs/frodo 2003-08-25 13:44:39.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/arm/def-configs/frodo 2003-10-24 14:31:25.000000000 +0200 @@ -716,6 +716,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/arm/def-configs/graphicsclient linux-2.4.23-pre8-pac1/arch/arm/def-configs/graphicsclient --- linux-2.4.23-pre8/arch/arm/def-configs/graphicsclient 2003-08-25 13:44:39.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/arm/def-configs/graphicsclient 2003-10-24 14:31:25.000000000 +0200 @@ -742,6 +742,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/arm/def-configs/graphicsmaster linux-2.4.23-pre8-pac1/arch/arm/def-configs/graphicsmaster --- linux-2.4.23-pre8/arch/arm/def-configs/graphicsmaster 2003-08-25 13:44:39.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/arm/def-configs/graphicsmaster 2003-10-24 14:31:25.000000000 +0200 @@ -738,6 +738,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/arm/def-configs/h3600 linux-2.4.23-pre8-pac1/arch/arm/def-configs/h3600 --- linux-2.4.23-pre8/arch/arm/def-configs/h3600 2002-08-03 02:39:42.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/arm/def-configs/h3600 2003-10-24 14:31:25.000000000 +0200 @@ -659,6 +659,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_FREEVXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/arm/def-configs/huw_webpanel linux-2.4.23-pre8-pac1/arch/arm/def-configs/huw_webpanel --- linux-2.4.23-pre8/arch/arm/def-configs/huw_webpanel 2001-08-12 20:13:59.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/arm/def-configs/huw_webpanel 2003-10-24 14:31:25.000000000 +0200 @@ -335,6 +335,7 @@ # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/arm/def-configs/integrator linux-2.4.23-pre8-pac1/arch/arm/def-configs/integrator --- linux-2.4.23-pre8/arch/arm/def-configs/integrator 2002-08-03 02:39:42.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/arm/def-configs/integrator 2003-10-24 14:31:25.000000000 +0200 @@ -542,6 +542,7 @@ CONFIG_MINIX_FS=y # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/arm/def-configs/jornada720 linux-2.4.23-pre8-pac1/arch/arm/def-configs/jornada720 --- linux-2.4.23-pre8/arch/arm/def-configs/jornada720 2002-08-03 02:39:42.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/arm/def-configs/jornada720 2003-10-24 14:31:25.000000000 +0200 @@ -676,6 +676,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/arm/def-configs/lart linux-2.4.23-pre8-pac1/arch/arm/def-configs/lart --- linux-2.4.23-pre8/arch/arm/def-configs/lart 2002-08-03 02:39:42.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/arm/def-configs/lart 2003-10-24 14:31:25.000000000 +0200 @@ -664,6 +664,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_FREEVXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/arm/def-configs/lusl7200 linux-2.4.23-pre8-pac1/arch/arm/def-configs/lusl7200 --- linux-2.4.23-pre8/arch/arm/def-configs/lusl7200 2003-08-25 13:44:39.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/arm/def-configs/lusl7200 2003-10-24 14:31:25.000000000 +0200 @@ -191,6 +191,7 @@ # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/arm/def-configs/neponset linux-2.4.23-pre8-pac1/arch/arm/def-configs/neponset --- linux-2.4.23-pre8/arch/arm/def-configs/neponset 2002-08-03 02:39:42.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/arm/def-configs/neponset 2003-10-24 14:31:25.000000000 +0200 @@ -653,6 +653,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_FREEVXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/arm/def-configs/omnimeter linux-2.4.23-pre8-pac1/arch/arm/def-configs/omnimeter --- linux-2.4.23-pre8/arch/arm/def-configs/omnimeter 2001-08-12 20:13:59.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/arm/def-configs/omnimeter 2003-10-24 14:31:25.000000000 +0200 @@ -431,6 +431,7 @@ # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/arm/def-configs/pangolin linux-2.4.23-pre8-pac1/arch/arm/def-configs/pangolin --- linux-2.4.23-pre8/arch/arm/def-configs/pangolin 2002-08-03 02:39:42.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/arm/def-configs/pangolin 2003-10-24 14:31:25.000000000 +0200 @@ -568,6 +568,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/arm/def-configs/pfs168_mqtft linux-2.4.23-pre8-pac1/arch/arm/def-configs/pfs168_mqtft --- linux-2.4.23-pre8/arch/arm/def-configs/pfs168_mqtft 2002-08-03 02:39:42.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/arm/def-configs/pfs168_mqtft 2003-10-24 14:31:25.000000000 +0200 @@ -608,6 +608,7 @@ # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/arm/def-configs/pfs168_mqvga linux-2.4.23-pre8-pac1/arch/arm/def-configs/pfs168_mqvga --- linux-2.4.23-pre8/arch/arm/def-configs/pfs168_mqvga 2002-08-03 02:39:42.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/arm/def-configs/pfs168_mqvga 2003-10-24 14:31:25.000000000 +0200 @@ -608,6 +608,7 @@ # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/arm/def-configs/pfs168_sastn linux-2.4.23-pre8-pac1/arch/arm/def-configs/pfs168_sastn --- linux-2.4.23-pre8/arch/arm/def-configs/pfs168_sastn 2002-08-03 02:39:42.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/arm/def-configs/pfs168_sastn 2003-10-24 14:31:25.000000000 +0200 @@ -601,6 +601,7 @@ # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/arm/def-configs/pfs168_satft linux-2.4.23-pre8-pac1/arch/arm/def-configs/pfs168_satft --- linux-2.4.23-pre8/arch/arm/def-configs/pfs168_satft 2002-08-03 02:39:42.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/arm/def-configs/pfs168_satft 2003-10-24 14:31:25.000000000 +0200 @@ -608,6 +608,7 @@ # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/arm/def-configs/pleb linux-2.4.23-pre8-pac1/arch/arm/def-configs/pleb --- linux-2.4.23-pre8/arch/arm/def-configs/pleb 2002-08-03 02:39:42.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/arm/def-configs/pleb 2003-10-24 14:31:25.000000000 +0200 @@ -459,6 +459,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/arm/def-configs/rpc linux-2.4.23-pre8-pac1/arch/arm/def-configs/rpc --- linux-2.4.23-pre8/arch/arm/def-configs/rpc 2002-08-03 02:39:42.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/arm/def-configs/rpc 2003-10-24 14:31:25.000000000 +0200 @@ -629,6 +629,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/arm/def-configs/shannon linux-2.4.23-pre8-pac1/arch/arm/def-configs/shannon --- linux-2.4.23-pre8/arch/arm/def-configs/shannon 2002-08-03 02:39:42.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/arm/def-configs/shannon 2003-10-24 14:31:25.000000000 +0200 @@ -537,6 +537,8 @@ CONFIG_MINIX_FS=y # CONFIG_FREEVXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG 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 diff -urN linux-2.4.23-pre8/arch/arm/def-configs/shark linux-2.4.23-pre8-pac1/arch/arm/def-configs/shark --- linux-2.4.23-pre8/arch/arm/def-configs/shark 2002-08-03 02:39:42.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/arm/def-configs/shark 2003-10-24 14:31:25.000000000 +0200 @@ -637,6 +637,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_FREEVXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/arm/def-configs/sherman linux-2.4.23-pre8-pac1/arch/arm/def-configs/sherman --- linux-2.4.23-pre8/arch/arm/def-configs/sherman 2003-08-25 13:44:39.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/arm/def-configs/sherman 2003-10-24 14:31:25.000000000 +0200 @@ -151,6 +151,8 @@ # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_QNX4FS_FS is not set diff -urN linux-2.4.23-pre8/arch/arm/def-configs/system3 linux-2.4.23-pre8-pac1/arch/arm/def-configs/system3 --- linux-2.4.23-pre8/arch/arm/def-configs/system3 2002-08-03 02:39:42.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/arm/def-configs/system3 2003-10-24 14:31:25.000000000 +0200 @@ -693,6 +693,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/arm/def-configs/victor linux-2.4.23-pre8-pac1/arch/arm/def-configs/victor --- linux-2.4.23-pre8/arch/arm/def-configs/victor 2003-08-25 13:44:39.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/arm/def-configs/victor 2003-10-24 14:31:25.000000000 +0200 @@ -144,6 +144,8 @@ CONFIG_JOLIET=y # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set # CONFIG_PROC_FS is not set # CONFIG_QNX4FS_FS is not set diff -urN linux-2.4.23-pre8/arch/arm/defconfig linux-2.4.23-pre8-pac1/arch/arm/defconfig --- linux-2.4.23-pre8/arch/arm/defconfig 2001-05-20 02:43:05.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/arm/defconfig 2003-10-24 14:31:25.000000000 +0200 @@ -420,6 +420,7 @@ # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/arm/mm/fault-common.c linux-2.4.23-pre8-pac1/arch/arm/mm/fault-common.c --- linux-2.4.23-pre8/arch/arm/mm/fault-common.c 2003-08-25 13:44:39.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/arm/mm/fault-common.c 2003-10-24 14:31:25.000000000 +0200 @@ -254,7 +254,7 @@ goto survive; check_stack: - if (vma->vm_flags & VM_GROWSDOWN && !expand_stack(vma, addr)) + if (!expand_stack(vma, addr)) goto good_area; out: return fault; diff -urN linux-2.4.23-pre8/arch/cris/defconfig linux-2.4.23-pre8-pac1/arch/cris/defconfig --- linux-2.4.23-pre8/arch/cris/defconfig 2003-08-25 13:44:39.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/cris/defconfig 2003-10-24 14:31:25.000000000 +0200 @@ -455,6 +455,7 @@ # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/cris/drivers/serial.c linux-2.4.23-pre8-pac1/arch/cris/drivers/serial.c --- linux-2.4.23-pre8/arch/cris/drivers/serial.c 2003-08-25 13:44:39.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/cris/drivers/serial.c 2003-10-24 14:31:25.000000000 +0200 @@ -4502,7 +4502,7 @@ printk("[%d] rs_close ttyS%d, count = %d\n", current->pid, info->line, info->count); #endif - if ((tty->count == 1) && (info->count != 1)) { + if ((atomic_read(&tty->count) == 1) && (info->count != 1)) { /* * Uh, oh. tty->count is 1, which means that the tty * structure will be freed. Info->count should always diff -urN linux-2.4.23-pre8/arch/i386/Makefile linux-2.4.23-pre8-pac1/arch/i386/Makefile --- linux-2.4.23-pre8/arch/i386/Makefile 2003-06-13 16:51:29.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/i386/Makefile 2003-10-24 14:31:25.000000000 +0200 @@ -53,11 +53,11 @@ endif ifdef CONFIG_MPENTIUMIII -CFLAGS += -march=i686 +CFLAGS += $(call check_gcc,-march=pentium3,-march=i686) endif ifdef CONFIG_MPENTIUM4 -CFLAGS += -march=i686 +CFLAGS += $(call check_gcc,-march=pentium4,-march=i686) endif ifdef CONFIG_MK6 diff -urN linux-2.4.23-pre8/arch/i386/config.in linux-2.4.23-pre8-pac1/arch/i386/config.in --- linux-2.4.23-pre8/arch/i386/config.in 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/i386/config.in 2003-10-24 14:31:25.000000000 +0200 @@ -56,6 +56,7 @@ define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n define_bool CONFIG_X86_PPRO_FENCE y define_bool CONFIG_X86_F00F_WORKS_OK n + define_bool CONFIG_X86_HAS_TSC n else define_bool CONFIG_X86_WP_WORKS_OK y define_bool CONFIG_X86_INVLPG y @@ -72,6 +73,7 @@ define_bool CONFIG_X86_ALIGNMENT_16 y define_bool CONFIG_X86_PPRO_FENCE y define_bool CONFIG_X86_F00F_WORKS_OK n + define_bool CONFIG_X86_HAS_TSC n fi if [ "$CONFIG_M586" = "y" ]; then define_int CONFIG_X86_L1_CACHE_SHIFT 5 @@ -79,6 +81,7 @@ define_bool CONFIG_X86_ALIGNMENT_16 y define_bool CONFIG_X86_PPRO_FENCE y define_bool CONFIG_X86_F00F_WORKS_OK n + define_bool CONFIG_X86_HAS_TSC n fi if [ "$CONFIG_M586TSC" = "y" ]; then define_int CONFIG_X86_L1_CACHE_SHIFT 5 @@ -194,6 +197,30 @@ bool 'Machine Check Exception' CONFIG_X86_MCE +mainmenu_option next_comment +comment 'CPU Frequency scaling' +bool 'CPU Frequency scaling' CONFIG_CPU_FREQ +if [ "$CONFIG_CPU_FREQ" = "y" ]; then + bool ' CPU frequency table helpers' CONFIG_CPU_FREQ_TABLE + define_bool CONFIG_CPU_FREQ_PROC_INTF y + comment 'CPUFreq governors' + bool ' "userspace" for userspace frequency scaling' CONFIG_CPU_FREQ_GOV_USERSPACE + define_bool CONFIG_CPU_FREQ_24_API y + comment 'CPUFreq processor drivers' + dep_tristate ' AMD Mobile K6-2/K6-3 PowerNow!' CONFIG_X86_POWERNOW_K6 $CONFIG_CPU_FREQ_TABLE + dep_tristate ' AMD Mobile Athlon/Duron K7 PowerNow!' CONFIG_X86_POWERNOW_K7 $CONFIG_CPU_FREQ_TABLE + if [ "$CONFIG_MELAN" = "y" ]; then + dep_tristate ' AMD Elan' CONFIG_ELAN_CPUFREQ $CONFIG_CPU_FREQ_TABLE + fi + dep_tristate ' VIA Cyrix III Longhaul' CONFIG_X86_LONGHAUL $CONFIG_CPU_FREQ_TABLE + dep_tristate ' Intel Speedstep (ICH)' CONFIG_X86_SPEEDSTEP_ICH $CONFIG_CPU_FREQ_TABLE + dep_tristate ' Intel Pentium-M Enhanced SpeedStep' CONFIG_X86_SPEEDSTEP_CENTRINO $CONFIG_CPU_FREQ_TABLE + dep_tristate ' Intel Pentium 4 clock modulation' CONFIG_X86_P4_CLOCKMOD $CONFIG_CPU_FREQ_TABLE + tristate ' Transmeta LongRun' CONFIG_X86_LONGRUN + tristate ' Cyrix MediaGX/NatSemi Geode Suspend Modulation' CONFIG_X86_GX_SUSPMOD +fi +endmenu + tristate 'Toshiba Laptop support' CONFIG_TOSHIBA tristate 'Dell laptop support' CONFIG_I8K @@ -297,6 +324,8 @@ bool 'ISA bus support' CONFIG_ISA fi +tristate 'NatSemi SCx200 support' CONFIG_SCx200 + source drivers/pci/Config.in bool 'EISA support' CONFIG_EISA @@ -329,6 +358,8 @@ tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC +bool 'Kernel .config support' CONFIG_IKCONFIG + bool 'Power Management support' CONFIG_PM dep_tristate ' Advanced Power Management BIOS support' CONFIG_APM $CONFIG_PM @@ -473,12 +504,13 @@ bool 'Kernel debugging' CONFIG_DEBUG_KERNEL if [ "$CONFIG_DEBUG_KERNEL" != "n" ]; then bool ' Check for stack overflows' CONFIG_DEBUG_STACKOVERFLOW + bool ' Compile the kernel with frame pointers' CONFIG_FRAME_POINTER bool ' Debug high memory support' CONFIG_DEBUG_HIGHMEM bool ' Debug memory allocations' CONFIG_DEBUG_SLAB bool ' Memory mapped I/O debugging' CONFIG_DEBUG_IOVIRT bool ' Magic SysRq key' CONFIG_MAGIC_SYSRQ + bool ' Morse code panics' CONFIG_PANIC_MORSE bool ' Spinlock debugging' CONFIG_DEBUG_SPINLOCK - bool ' Compile the kernel with frame pointers' CONFIG_FRAME_POINTER fi int 'Kernel messages buffer length shift (0 = default)' CONFIG_LOG_BUF_SHIFT 0 diff -urN linux-2.4.23-pre8/arch/i386/defconfig linux-2.4.23-pre8-pac1/arch/i386/defconfig --- linux-2.4.23-pre8/arch/i386/defconfig 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/i386/defconfig 2003-10-24 14:31:25.000000000 +0200 @@ -609,6 +609,8 @@ CONFIG_AGP_SIS=y CONFIG_AGP_ALI=y # CONFIG_AGP_SWORKS is not set +CONFIG_AGP_ATI=y +CONFIG_AGP_NVIDIA=y CONFIG_DRM=y # CONFIG_DRM_OLD is not set @@ -668,6 +670,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/i386/kernel/Makefile linux-2.4.23-pre8-pac1/arch/i386/kernel/Makefile --- linux-2.4.23-pre8/arch/i386/kernel/Makefile 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/i386/kernel/Makefile 2003-10-24 14:31:25.000000000 +0200 @@ -14,7 +14,8 @@ O_TARGET := kernel.o -export-objs := mca.o mtrr.o msr.o cpuid.o microcode.o i386_ksyms.o time.o setup.o +export-objs := mca.o mtrr.o msr.o cpuid.o microcode.o i386_ksyms.o time.o \ + setup.o speedstep-lib.o 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 \ @@ -36,12 +37,22 @@ obj-$(CONFIG_X86_CPUID) += cpuid.o obj-$(CONFIG_MICROCODE) += microcode.o obj-$(CONFIG_APM) += apm.o -obj-$(CONFIG_ACPI_BOOT) += acpi.o +obj-$(CONFIG_ACPI_BOOT) += acpi.o pic.o obj-$(CONFIG_ACPI_SLEEP) += acpi_wakeup.o obj-$(CONFIG_SMP) += smp.o smpboot.o trampoline.o obj-$(CONFIG_X86_LOCAL_APIC) += mpparse.o apic.o nmi.o obj-$(CONFIG_X86_IO_APIC) += io_apic.o obj-$(CONFIG_X86_VISWS_APIC) += visws_apic.o obj-$(CONFIG_EDD) += edd.o +obj-$(CONFIG_X86_POWERNOW_K6) += powernow-k6.o +obj-$(CONFIG_X86_POWERNOW_K7) += powernow-k7.o +obj-$(CONFIG_X86_LONGHAUL) += longhaul.o +obj-$(CONFIG_X86_SPEEDSTEP_CENTRINO) += speedstep-centrino.o +obj-$(CONFIG_X86_SPEEDSTEP_ICH) += speedstep-ich.o speedstep-lib.o +obj-$(CONFIG_X86_P4_CLOCKMOD) += p4-clockmod.o +obj-$(CONFIG_X86_LONGRUN) += longrun.o +obj-$(CONFIG_ELAN_CPUFREQ) += elanfreq.o +obj-$(CONFIG_X86_GX_SUSPMOD) += gx-suspmod.o + include $(TOPDIR)/Rules.make diff -urN linux-2.4.23-pre8/arch/i386/kernel/acpi.c linux-2.4.23-pre8-pac1/arch/i386/kernel/acpi.c --- linux-2.4.23-pre8/arch/i386/kernel/acpi.c 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/i386/kernel/acpi.c 2003-10-24 14:31:25.000000000 +0200 @@ -333,8 +333,10 @@ * Initialize the ACPI boot-time table parser. */ result = acpi_table_init(); - if (result) + if (result) { + acpi_disabled = 1; return result; + } result = acpi_blacklisted(); if (result) { diff -urN linux-2.4.23-pre8/arch/i386/kernel/elanfreq.c linux-2.4.23-pre8-pac1/arch/i386/kernel/elanfreq.c --- linux-2.4.23-pre8/arch/i386/kernel/elanfreq.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/arch/i386/kernel/elanfreq.c 2003-10-24 14:31:25.000000000 +0200 @@ -0,0 +1,286 @@ +/* + * elanfreq: cpufreq driver for the AMD ELAN family + * + * (c) Copyright 2002 Robert Schwebel + * + * Parts of this code are (c) Sven Geggus + * + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * 2002-02-13: - initial revision for 2.4.18-pre9 by Robert Schwebel + * + */ + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#define REG_CSCIR 0x22 /* Chip Setup and Control Index Register */ +#define REG_CSCDR 0x23 /* Chip Setup and Control Data Register */ + +/* Module parameter */ +static int max_freq; + +struct s_elan_multiplier { + int clock; /* frequency in kHz */ + int val40h; /* PMU Force Mode register */ + int val80h; /* CPU Clock Speed Register */ +}; + +/* + * It is important that the frequencies + * are listed in ascending order here! + */ +struct s_elan_multiplier elan_multiplier[] = { + {1000, 0x02, 0x18}, + {2000, 0x02, 0x10}, + {4000, 0x02, 0x08}, + {8000, 0x00, 0x00}, + {16000, 0x00, 0x02}, + {33000, 0x00, 0x04}, + {66000, 0x01, 0x04}, + {99000, 0x01, 0x05} +}; + +static struct cpufreq_frequency_table elanfreq_table[] = { + {0, 1000}, + {1, 2000}, + {2, 4000}, + {3, 8000}, + {4, 16000}, + {5, 33000}, + {6, 66000}, + {7, 99000}, + {0, CPUFREQ_TABLE_END}, +}; + + +/** + * elanfreq_get_cpu_frequency: determine current cpu speed + * + * Finds out at which frequency the CPU of the Elan SOC runs + * at the moment. Frequencies from 1 to 33 MHz are generated + * the normal way, 66 and 99 MHz are called "Hyperspeed Mode" + * and have the rest of the chip running with 33 MHz. + */ + +static unsigned int elanfreq_get_cpu_frequency(void) +{ + u8 clockspeed_reg; /* Clock Speed Register */ + + local_irq_disable(); + outb_p(0x80,REG_CSCIR); + clockspeed_reg = inb_p(REG_CSCDR); + local_irq_enable(); + + if ((clockspeed_reg & 0xE0) == 0xE0) { return 0; } + + /* Are we in CPU clock multiplied mode (66/99 MHz)? */ + if ((clockspeed_reg & 0xE0) == 0xC0) { + if ((clockspeed_reg & 0x01) == 0) { + return 66000; + } else { + return 99000; + } + } + + /* 33 MHz is not 32 MHz... */ + if ((clockspeed_reg & 0xE0)==0xA0) + return 33000; + + return ((1<<((clockspeed_reg & 0xE0) >> 5)) * 1000); +} + + +/** + * elanfreq_set_cpu_frequency: Change the CPU core frequency + * @cpu: cpu number + * @freq: frequency in kHz + * + * This function takes a frequency value and changes the CPU frequency + * according to this. Note that the frequency has to be checked by + * elanfreq_validatespeed() for correctness! + * + * There is no return value. + */ + +static void elanfreq_set_cpu_state (unsigned int state) { + + struct cpufreq_freqs freqs; + + freqs.old = elanfreq_get_cpu_frequency(); + freqs.new = elan_multiplier[state].clock; + freqs.cpu = 0; /* elanfreq.c is UP only driver */ + + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + + printk(KERN_INFO "elanfreq: attempting to set frequency to %i kHz\n",elan_multiplier[state].clock); + + + /* + * Access to the Elan's internal registers is indexed via + * 0x22: Chip Setup & Control Register Index Register (CSCI) + * 0x23: Chip Setup & Control Register Data Register (CSCD) + * + */ + + /* + * 0x40 is the Power Management Unit's Force Mode Register. + * Bit 6 enables Hyperspeed Mode (66/100 MHz core frequency) + */ + + local_irq_disable(); + outb_p(0x40,REG_CSCIR); /* Disable hyperspeed mode */ + outb_p(0x00,REG_CSCDR); + local_irq_enable(); /* wait till internal pipelines and */ + udelay(1000); /* buffers have cleaned up */ + + local_irq_disable(); + + /* now, set the CPU clock speed register (0x80) */ + outb_p(0x80,REG_CSCIR); + outb_p(elan_multiplier[state].val80h,REG_CSCDR); + + /* now, the hyperspeed bit in PMU Force Mode Register (0x40) */ + outb_p(0x40,REG_CSCIR); + outb_p(elan_multiplier[state].val40h,REG_CSCDR); + udelay(10000); + local_irq_enable(); + + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); +}; + + +/** + * elanfreq_validatespeed: test if frequency range is valid + * + * This function checks if a given frequency range in kHz is valid + * for the hardware supported by the driver. + */ + +static int elanfreq_verify (struct cpufreq_policy *policy) +{ + return cpufreq_frequency_table_verify(policy, &elanfreq_table[0]); +} + +static int elanfreq_target (struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + unsigned int newstate = 0; + + if (cpufreq_frequency_table_target(policy, &elanfreq_table[0], target_freq, relation, &newstate)) + return -EINVAL; + + elanfreq_set_cpu_state(newstate); + + return 0; +} + + +/* + * Module init and exit code + */ + +static int elanfreq_cpu_init(struct cpufreq_policy *policy) +{ + struct cpuinfo_x86 *c = cpu_data; + unsigned int i; + + /* capability check */ + if ((c->x86_vendor != X86_VENDOR_AMD) || + (c->x86 != 4) || (c->x86_model!=10)) + return -ENODEV; + + /* max freq */ + if (!max_freq) + max_freq = elanfreq_get_cpu_frequency(); + + /* table init */ + for (i=0; (elanfreq_table[i].frequency != CPUFREQ_TABLE_END); i++) { + if (elanfreq_table[i].frequency > max_freq) + elanfreq_table[i].frequency = CPUFREQ_ENTRY_INVALID; + } + + /* cpuinfo and default policy values */ + policy->policy = CPUFREQ_POLICY_PERFORMANCE; + policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; + policy->cur = elanfreq_get_cpu_frequency(); + + return cpufreq_frequency_table_cpuinfo(policy, &elanfreq_table[0]);; +} + + +#ifndef MODULE +/** + * elanfreq_setup - elanfreq command line parameter parsing + * + * elanfreq command line parameter. Use: + * elanfreq=66000 + * to set the maximum CPU frequency to 66 MHz. Note that in + * case you do not give this boot parameter, the maximum + * frequency will fall back to _current_ CPU frequency which + * might be lower. If you build this as a module, use the + * max_freq module parameter instead. + */ +static int __init elanfreq_setup(char *str) +{ + max_freq = simple_strtoul(str, &str, 0); + return 1; +} +__setup("elanfreq=", elanfreq_setup); +#endif + + +static struct cpufreq_driver elanfreq_driver = { + .verify = elanfreq_verify, + .target = elanfreq_target, + .init = elanfreq_cpu_init, + .name = "elanfreq", +}; + + +static int __init elanfreq_init(void) +{ + struct cpuinfo_x86 *c = cpu_data; + + /* Test if we have the right hardware */ + if ((c->x86_vendor != X86_VENDOR_AMD) || + (c->x86 != 4) || (c->x86_model!=10)) + { + printk(KERN_INFO "elanfreq: error: no Elan processor found!\n"); + return -ENODEV; + } + + return cpufreq_register_driver(&elanfreq_driver); +} + + +static void __exit elanfreq_exit(void) +{ + cpufreq_unregister_driver(&elanfreq_driver); +} + + +MODULE_PARM (max_freq, "i"); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Robert Schwebel , Sven Geggus "); +MODULE_DESCRIPTION("cpufreq driver for AMD's Elan CPUs"); + +module_init(elanfreq_init); +module_exit(elanfreq_exit); + diff -urN linux-2.4.23-pre8/arch/i386/kernel/entry.S linux-2.4.23-pre8-pac1/arch/i386/kernel/entry.S --- linux-2.4.23-pre8/arch/i386/kernel/entry.S 2003-06-13 16:51:29.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/i386/kernel/entry.S 2003-10-24 14:31:25.000000000 +0200 @@ -79,7 +79,7 @@ exec_domain = 16 need_resched = 20 tsk_ptrace = 24 -processor = 52 +cpu = 32 ENOSYS = 38 @@ -184,9 +184,11 @@ ENTRY(ret_from_fork) +#if CONFIG_SMP pushl %ebx call SYMBOL_NAME(schedule_tail) addl $4, %esp +#endif GET_CURRENT(%ebx) testb $0x02,tsk_ptrace(%ebx) # PT_TRACESYS jne tracesys_exit @@ -645,8 +647,8 @@ .long SYMBOL_NAME(sys_tkill) .long SYMBOL_NAME(sys_sendfile64) .long SYMBOL_NAME(sys_ni_syscall) /* 240 reserved for futex */ - .long SYMBOL_NAME(sys_ni_syscall) /* reserved for sched_setaffinity */ - .long SYMBOL_NAME(sys_ni_syscall) /* reserved for sched_getaffinity */ + .long SYMBOL_NAME(sys_sched_setaffinity) + .long SYMBOL_NAME(sys_sched_getaffinity) .long SYMBOL_NAME(sys_ni_syscall) /* sys_set_thread_area */ .long SYMBOL_NAME(sys_ni_syscall) /* sys_get_thread_area */ .long SYMBOL_NAME(sys_ni_syscall) /* 245 sys_io_setup */ diff -urN linux-2.4.23-pre8/arch/i386/kernel/gx-suspmod.c linux-2.4.23-pre8-pac1/arch/i386/kernel/gx-suspmod.c --- linux-2.4.23-pre8/arch/i386/kernel/gx-suspmod.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/arch/i386/kernel/gx-suspmod.c 2003-10-24 14:31:25.000000000 +0200 @@ -0,0 +1,510 @@ +/* + * Cyrix MediaGX and NatSemi Geode Suspend Modulation + * (C) 2002 Zwane Mwaikambo + * (C) 2002 Hiroshi Miura + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation + * + * The author(s) of this software shall not be held liable for damages + * of any nature resulting due to the use of this software. This + * software is provided AS-IS with no warranties. + * + * Theoritical note: + * + * (see Geode(tm) CS5530 manual (rev.4.1) page.56) + * + * CPU frequency control on NatSemi Geode GX1/GXLV processor and CS55x0 + * are based on Suspend Moduration. + * + * Suspend Modulation works by asserting and de-asserting the SUSP# pin + * to CPU(GX1/GXLV) for configurable durations. When asserting SUSP# + * the CPU enters an idle state. GX1 stops its core clock when SUSP# is + * asserted then power consumption is reduced. + * + * Suspend Modulation's OFF/ON duration are configurable + * with 'Suspend Modulation OFF Count Register' + * and 'Suspend Modulation ON Count Register'. + * These registers are 8bit counters that represent the number of + * 32us intervals which the SUSP# pin is asserted/de-asserted to the + * processor. + * + * These counters define a ratio which is the effective frequency + * of operation of the system. + * + * On Count + * F_eff = Fgx * ---------------------- + * On Count + Off Count + * + * 0 <= On Count, Off Count <= 255 + * + * From these limits, we can get register values + * + * on_duration + off_duration <= MAX_DURATION + * off_duration = on_duration * (stock_freq - freq) / freq + * + * on_duration = (freq * DURATION) / stock_freq + * off_duration = DURATION - on_duration + * + * + *--------------------------------------------------------------------------- + * + * ChangeLog: + * Dec. 11, 2002 Hiroshi Miura + * - rewrite for Cyrix MediaGX Cx5510/5520 and + * NatSemi Geode Cs5530(A). + * + * Jul. ??, 2002 Zwane Mwaikambo + * - cs5530_mod patch for 2.4.19-rc1. + * + *--------------------------------------------------------------------------- + * + * Todo + * Test on machines with 5510, 5530, 5530A + */ + +/************************************************************************ + * Suspend Modulation - Definitions * + ************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* PCI config registers, all at F0 */ +#define PCI_PMER1 0x80 /* power management enable register 1 */ +#define PCI_PMER2 0x81 /* power management enable register 2 */ +#define PCI_PMER3 0x82 /* power management enable register 3 */ +#define PCI_IRQTC 0x8c /* irq speedup timer counter register:typical 2 to 4ms */ +#define PCI_VIDTC 0x8d /* video speedup timer counter register: typical 50 to 100ms */ +#define PCI_MODOFF 0x94 /* suspend modulation OFF counter register, 1 = 32us */ +#define PCI_MODON 0x95 /* suspend modulation ON counter register */ +#define PCI_SUSCFG 0x96 /* suspend configuration register */ + +/* PMER1 bits */ +#define GPM (1<<0) /* global power management */ +#define GIT (1<<1) /* globally enable PM device idle timers */ +#define GTR (1<<2) /* globally enable IO traps */ +#define IRQ_SPDUP (1<<3) /* disable clock throttle during interrupt handling */ +#define VID_SPDUP (1<<4) /* disable clock throttle during vga video handling */ + +/* SUSCFG bits */ +#define SUSMOD (1<<0) /* enable/disable suspend modulation */ +/* the belows support only with cs5530 (after rev.1.2)/cs5530A */ +#define SMISPDUP (1<<1) /* select how SMI re-enable suspend modulation: */ + /* IRQTC timer or read SMI speedup disable reg.(F1BAR[08-09h]) */ +#define SUSCFG (1<<2) /* enable powering down a GXLV processor. "Special 3Volt Suspend" mode */ +/* the belows support only with cs5530A */ +#define PWRSVE_ISA (1<<3) /* stop ISA clock */ +#define PWRSVE (1<<4) /* active idle */ + +struct gxfreq_params { + u8 on_duration; + u8 off_duration; + u8 pci_suscfg; + u8 pci_pmer1; + u8 pci_pmer2; + u8 pci_rev; + struct pci_dev *cs55x0; +}; + +static struct gxfreq_params *gx_params; +static int stock_freq; + +/* PCI bus clock - defaults to 30.000 if cpu_khz is not available */ +static int pci_busclk = 0; +MODULE_PARM(pci_busclk, "i"); + +/* maximum duration for which the cpu may be suspended + * (32us * MAX_DURATION). If no parameter is given, this defaults + * to 255. + * Note that this leads to a maximum of 8 ms(!) where the CPU clock + * is suspended -- processing power is just 0.39% of what it used to be, + * though. 781.25 kHz(!) for a 200 MHz processor -- wow. */ +static int max_duration = 255; +MODULE_PARM(max_duration, "i"); + +/* For the default policy, we want at least some processing power + * - let's say 5%. (min = maxfreq / POLICY_MIN_DIV) + */ +#define POLICY_MIN_DIV 20 + + +/* DEBUG + * Define it if you want verbose debug output + */ + +#define SUSPMOD_DEBUG 1 + +#ifdef SUSPMOD_DEBUG +#define dprintk(msg...) printk(KERN_DEBUG "cpufreq:" msg) +#else +#define dprintk(msg...) do { } while(0) +#endif + +/** + * we can detect a core multipiler from dir0_lsb + * from GX1 datasheet p.56, + * MULT[3:0]: + * 0000 = SYSCLK multiplied by 4 (test only) + * 0001 = SYSCLK multiplied by 10 + * 0010 = SYSCLK multiplied by 4 + * 0011 = SYSCLK multiplied by 6 + * 0100 = SYSCLK multiplied by 9 + * 0101 = SYSCLK multiplied by 5 + * 0110 = SYSCLK multiplied by 7 + * 0111 = SYSCLK multiplied by 8 + * of 33.3MHz + **/ +static int gx_freq_mult[16] = { + 4, 10, 4, 6, 9, 5, 7, 8, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + + +/**************************************************************** + * Low Level chipset interface * + ****************************************************************/ +static struct pci_device_id gx_chipset_tbl[] __initdata = { + { PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_LEGACY, PCI_ANY_ID, PCI_ANY_ID }, + { PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520, PCI_ANY_ID, PCI_ANY_ID }, + { PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5510, PCI_ANY_ID, PCI_ANY_ID }, + { 0, }, +}; + +/** + * gx_detect_chipset: + * + **/ +static __init struct pci_dev *gx_detect_chipset(void) +{ + struct pci_dev *gx_pci = NULL; + + /* check if CPU is a MediaGX or a Geode. */ + if ((current_cpu_data.x86_vendor != X86_VENDOR_NSC) && + (current_cpu_data.x86_vendor != X86_VENDOR_CYRIX)) { + printk(KERN_INFO "gx-suspmod: error: no MediaGX/Geode processor found!\n"); + return NULL; + } + + /* detect which companion chip is used */ + while ((gx_pci = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, gx_pci)) != NULL) { + if ((pci_match_device (gx_chipset_tbl, gx_pci)) != NULL) { + return gx_pci; + } + } + + dprintk(KERN_INFO "gx-suspmod: error: no supported chipset found!\n"); + return NULL; +} + +/** + * gx_get_cpuspeed: + * + * Finds out at which efficient frequency the Cyrix MediaGX/NatSemi Geode CPU runs. + */ +static int gx_get_cpuspeed(void) +{ + if ((gx_params->pci_suscfg & SUSMOD) == 0) + return stock_freq; + + return (stock_freq * gx_params->on_duration) + / (gx_params->on_duration + gx_params->off_duration); +} + +/** + * gx_validate_speed: + * determine current cpu speed + * +**/ + +static unsigned int gx_validate_speed(unsigned int khz, u8 *on_duration, u8 *off_duration) +{ + unsigned int i; + u8 tmp_on, tmp_off; + int old_tmp_freq = stock_freq; + int tmp_freq; + + *on_duration=1; + *off_duration=0; + + for (i=max_duration; i>0; i--) { + tmp_on = ((khz * i) / stock_freq) & 0xff; + tmp_off = i - tmp_on; + tmp_freq = (stock_freq * tmp_on) / i; + /* if this relation is closer to khz, use this. If it's equal, + * prefer it, too - lower latency */ + if (abs(tmp_freq - khz) <= abs(old_tmp_freq - khz)) { + *on_duration = tmp_on; + *off_duration = tmp_off; + old_tmp_freq = tmp_freq; + } + } + + return old_tmp_freq; +} + + +/** + * gx_set_cpuspeed: + * set cpu speed in khz. + **/ + +static void gx_set_cpuspeed(unsigned int khz) +{ + u8 suscfg, pmer1; + unsigned int new_khz; + unsigned long flags; + struct cpufreq_freqs freqs; + + + freqs.cpu = 0; + freqs.old = gx_get_cpuspeed(); + + new_khz = gx_validate_speed(khz, &gx_params->on_duration, &gx_params->off_duration); + + freqs.new = new_khz; + + if (new_khz == stock_freq) { /* if new khz == 100% of CPU speed, it is special case */ + local_irq_save(flags); + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + pci_write_config_byte(gx_params->cs55x0, PCI_SUSCFG, (gx_params->pci_suscfg & ~(SUSMOD))); + pci_read_config_byte(gx_params->cs55x0, PCI_SUSCFG, &(gx_params->pci_suscfg)); + local_irq_restore(flags); + dprintk("suspend modulation disabled: cpu runs 100 percent speed.\n"); + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + return; + } + + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + + local_irq_save(flags); + switch (gx_params->cs55x0->device) { + case PCI_DEVICE_ID_CYRIX_5530_LEGACY: + pmer1 = gx_params->pci_pmer1 | IRQ_SPDUP | VID_SPDUP; + /* FIXME: need to test other values -- Zwane,Miura */ + pci_write_config_byte(gx_params->cs55x0, PCI_IRQTC, 4); /* typical 2 to 4ms */ + pci_write_config_byte(gx_params->cs55x0, PCI_VIDTC, 100);/* typical 50 to 100ms */ + pci_write_config_byte(gx_params->cs55x0, PCI_PMER1, pmer1); + + if (gx_params->pci_rev < 0x10) { /* CS5530(rev 1.2, 1.3) */ + suscfg = gx_params->pci_suscfg | SUSMOD; + } else { /* CS5530A,B.. */ + suscfg = gx_params->pci_suscfg | SUSMOD | PWRSVE; + } + break; + case PCI_DEVICE_ID_CYRIX_5520: + case PCI_DEVICE_ID_CYRIX_5510: + suscfg = gx_params->pci_suscfg | SUSMOD; + break; + default: + local_irq_restore(flags); + dprintk("fatal: try to set unknown chipset.\n"); + return; + } + + pci_write_config_byte(gx_params->cs55x0, PCI_MODOFF, gx_params->off_duration); + pci_write_config_byte(gx_params->cs55x0, PCI_MODON, gx_params->on_duration); + + pci_write_config_byte(gx_params->cs55x0, PCI_SUSCFG, suscfg); + pci_read_config_byte(gx_params->cs55x0, PCI_SUSCFG, &suscfg); + + local_irq_restore(flags); + + gx_params->pci_suscfg = suscfg; + + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + + dprintk("suspend modulation w/ duration of ON:%d us, OFF:%d us\n", + gx_params->on_duration * 32, gx_params->off_duration * 32); + dprintk("suspend modulation w/ clock speed: %d kHz.\n", freqs.new); +} + +/**************************************************************** + * High level functions * + ****************************************************************/ + +/* + * cpufreq_gx_verify: test if frequency range is valid + * + * This function checks if a given frequency range in kHz is valid + * for the hardware supported by the driver. + */ + +static int cpufreq_gx_verify(struct cpufreq_policy *policy) +{ + unsigned int tmp_freq = 0; + u8 tmp1, tmp2; + + if (!stock_freq || !policy) + return -EINVAL; + + policy->cpu = 0; + cpufreq_verify_within_limits(policy, (stock_freq / max_duration), stock_freq); + + /* it needs to be assured that at least one supported frequency is + * within policy->min and policy->max. If it is not, policy->max + * needs to be increased until one freuqency is supported. + * policy->min may not be decreased, though. This way we guarantee a + * specific processing capacity. + */ + tmp_freq = gx_validate_speed(policy->min, &tmp1, &tmp2); + if (tmp_freq < policy->min) + tmp_freq += stock_freq / max_duration; + policy->min = tmp_freq; + if (policy->min > policy->max) + policy->max = tmp_freq; + tmp_freq = gx_validate_speed(policy->max, &tmp1, &tmp2); + if (tmp_freq > policy->max) + tmp_freq -= stock_freq / max_duration; + policy->max = tmp_freq; + if (policy->max < policy->min) + policy->max = policy->min; + cpufreq_verify_within_limits(policy, (stock_freq / max_duration), stock_freq); + + return 0; +} + +/* + * cpufreq_gx_target: + * + */ +static int cpufreq_gx_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + u8 tmp1, tmp2; + unsigned int tmp_freq; + + if (!stock_freq || !policy) + return -EINVAL; + + policy->cpu = 0; + + tmp_freq = gx_validate_speed(target_freq, &tmp1, &tmp2); + while (tmp_freq < policy->min) { + tmp_freq += stock_freq / max_duration; + tmp_freq = gx_validate_speed(tmp_freq, &tmp1, &tmp2); + } + while (tmp_freq > policy->max) { + tmp_freq -= stock_freq / max_duration; + tmp_freq = gx_validate_speed(tmp_freq, &tmp1, &tmp2); + } + + gx_set_cpuspeed(tmp_freq); + + return 0; +} + +static int cpufreq_gx_cpu_init(struct cpufreq_policy *policy) +{ + int maxfreq, curfreq; + + if (!policy || policy->cpu != 0) + return -ENODEV; + + /* determine maximum frequency */ + if (pci_busclk) { + maxfreq = pci_busclk * gx_freq_mult[getCx86(CX86_DIR1) & 0x0f]; + } else if (cpu_khz) { + maxfreq = cpu_khz; + } else { + maxfreq = 30000 * gx_freq_mult[getCx86(CX86_DIR1) & 0x0f]; + } + stock_freq = maxfreq; + curfreq = gx_get_cpuspeed(); + + dprintk("cpu max frequency is %d.\n", maxfreq); + dprintk("cpu current frequency is %dkHz.\n",curfreq); + + /* setup basic struct for cpufreq API */ + policy->cpu = 0; + + if (max_duration < POLICY_MIN_DIV) + policy->min = maxfreq / max_duration; + else + policy->min = maxfreq / POLICY_MIN_DIV; + policy->max = maxfreq; + policy->cur = curfreq; + policy->policy = CPUFREQ_POLICY_PERFORMANCE; + policy->cpuinfo.min_freq = maxfreq / max_duration; + policy->cpuinfo.max_freq = maxfreq; + policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; + + return 0; +} + +/* + * cpufreq_gx_init: + * MediaGX/Geode GX initialize cpufreq driver + */ +static struct cpufreq_driver gx_suspmod_driver = { + .verify = cpufreq_gx_verify, + .target = cpufreq_gx_target, + .init = cpufreq_gx_cpu_init, + .name = "gx-suspmod", +}; + +static int __init cpufreq_gx_init(void) +{ + int ret; + struct gxfreq_params *params; + struct pci_dev *gx_pci; + u32 class_rev; + + /* Test if we have the right hardware */ + if ((gx_pci = gx_detect_chipset()) == NULL) + return -ENODEV; + + /* check whether module parameters are sane */ + if (max_duration > 0xff) + max_duration = 0xff; + + dprintk("geode suspend modulation available.\n"); + + params = kmalloc(sizeof(struct gxfreq_params), GFP_KERNEL); + if (params == NULL) + return -ENOMEM; + memset(params, 0, sizeof(struct gxfreq_params)); + + params->cs55x0 = gx_pci; + gx_params = params; + + /* keep cs55x0 configurations */ + pci_read_config_byte(params->cs55x0, PCI_SUSCFG, &(params->pci_suscfg)); + pci_read_config_byte(params->cs55x0, PCI_PMER1, &(params->pci_pmer1)); + pci_read_config_byte(params->cs55x0, PCI_PMER2, &(params->pci_pmer2)); + pci_read_config_byte(params->cs55x0, PCI_MODON, &(params->on_duration)); + pci_read_config_byte(params->cs55x0, PCI_MODOFF, &(params->off_duration)); + pci_read_config_dword(params->cs55x0, PCI_CLASS_REVISION, &class_rev); + params->pci_rev = class_rev && 0xff; + + if ((ret = cpufreq_register_driver(&gx_suspmod_driver))) { + kfree(params); + return ret; /* register error! */ + } + + return 0; +} + +static void __exit cpufreq_gx_exit(void) +{ + cpufreq_unregister_driver(&gx_suspmod_driver); + kfree(gx_params); +} + +MODULE_AUTHOR ("Hiroshi Miura "); +MODULE_DESCRIPTION ("Cpufreq driver for Cyrix MediaGX and NatSemi Geode"); +MODULE_LICENSE ("GPL"); + +module_init(cpufreq_gx_init); +module_exit(cpufreq_gx_exit); + diff -urN linux-2.4.23-pre8/arch/i386/kernel/head.S linux-2.4.23-pre8-pac1/arch/i386/kernel/head.S --- linux-2.4.23-pre8/arch/i386/kernel/head.S 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/i386/kernel/head.S 2003-10-24 14:31:25.000000000 +0200 @@ -445,4 +445,15 @@ .quad 0x00409a0000000000 /* 0x48 APM CS code */ .quad 0x00009a0000000000 /* 0x50 APM CS 16 code (16 bit) */ .quad 0x0040920000000000 /* 0x58 APM DS data */ + /* Segments used for calling PnP BIOS */ + .quad 0x00c09a0000000000 /* 0x60 32-bit code */ + .quad 0x00809a0000000000 /* 0x68 16-bit code */ + .quad 0x0080920000000000 /* 0x70 16-bit data */ + .quad 0x0080920000000000 /* 0x78 16-bit data */ + .quad 0x0080920000000000 /* 0x80 16-bit data */ + .quad 0x0000000000000000 /* 0x88 not used */ + .quad 0x0000000000000000 /* 0x90 not used */ + .quad 0x0000000000000000 /* 0x98 not used */ + /* Per CPU segments */ .fill NR_CPUS*4,8,0 /* space for TSS's and LDT's */ + diff -urN linux-2.4.23-pre8/arch/i386/kernel/i386_ksyms.c linux-2.4.23-pre8-pac1/arch/i386/kernel/i386_ksyms.c --- linux-2.4.23-pre8/arch/i386/kernel/i386_ksyms.c 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/i386/kernel/i386_ksyms.c 2003-10-24 14:31:25.000000000 +0200 @@ -50,6 +50,7 @@ EXPORT_SYMBOL(drive_info); #endif +extern unsigned long cpu_khz; extern unsigned long get_cmos_time(void); /* platform dependent support */ @@ -72,6 +73,7 @@ EXPORT_SYMBOL(pm_idle); EXPORT_SYMBOL(pm_power_off); EXPORT_SYMBOL(get_cmos_time); +EXPORT_SYMBOL(cpu_khz); EXPORT_SYMBOL(apm_info); EXPORT_SYMBOL(gdt); EXPORT_SYMBOL(empty_zero_page); @@ -131,7 +133,9 @@ EXPORT_SYMBOL(cpu_data); EXPORT_SYMBOL(kernel_flag_cacheline); EXPORT_SYMBOL(smp_num_cpus); +EXPORT_SYMBOL(smp_num_siblings); EXPORT_SYMBOL(cpu_online_map); +EXPORT_SYMBOL_GPL(cpu_sibling_map); EXPORT_SYMBOL_NOVERS(__write_lock_failed); EXPORT_SYMBOL_NOVERS(__read_lock_failed); diff -urN linux-2.4.23-pre8/arch/i386/kernel/i387.c linux-2.4.23-pre8-pac1/arch/i386/kernel/i387.c --- linux-2.4.23-pre8/arch/i386/kernel/i387.c 2003-08-25 13:44:39.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/i386/kernel/i387.c 2003-10-24 14:31:25.000000000 +0200 @@ -248,7 +248,7 @@ * FXSR floating point environment conversions. */ -static inline int convert_fxsr_to_user( struct _fpstate *buf, +static int convert_fxsr_to_user( struct _fpstate *buf, struct i387_fxsave_struct *fxsave ) { unsigned long env[7]; @@ -270,13 +270,18 @@ to = &buf->_st[0]; from = (struct _fpxreg *) &fxsave->st_space[0]; for ( i = 0 ; i < 8 ; i++, to++, from++ ) { - if ( __copy_to_user( to, from, sizeof(*to) ) ) + unsigned long *t = (unsigned long *)to; + unsigned long *f = (unsigned long *)from; + + if (__put_user(*f, t) || + __put_user(*(f + 1), t + 1) || + __put_user(from->exponent, &to->exponent)) return 1; } return 0; } -static inline int convert_fxsr_from_user( struct i387_fxsave_struct *fxsave, +static int convert_fxsr_from_user( struct i387_fxsave_struct *fxsave, struct _fpstate *buf ) { unsigned long env[7]; @@ -299,7 +304,12 @@ to = (struct _fpxreg *) &fxsave->st_space[0]; from = &buf->_st[0]; for ( i = 0 ; i < 8 ; i++, to++, from++ ) { - if ( __copy_from_user( to, from, sizeof(*from) ) ) + unsigned long *t = (unsigned long *)to; + unsigned long *f = (unsigned long *)from; + + if (__get_user(*t, f) || + __get_user(*(t + 1), f + 1) || + __get_user(to->exponent, &from->exponent)) return 1; } return 0; @@ -321,7 +331,7 @@ return 1; } -static inline int save_i387_fxsave( struct _fpstate *buf ) +static int save_i387_fxsave( struct _fpstate *buf ) { struct task_struct *tsk = current; int err = 0; @@ -371,7 +381,7 @@ sizeof(struct i387_fsave_struct) ); } -static inline int restore_i387_fxsave( struct _fpstate *buf ) +static int restore_i387_fxsave( struct _fpstate *buf ) { int err; struct task_struct *tsk = current; @@ -389,7 +399,7 @@ if ( HAVE_HWFP ) { if ( cpu_has_fxsr ) { - err = restore_i387_fxsave( buf ); + err = restore_i387_fxsave( buf ); } else { err = restore_i387_fsave( buf ); } diff -urN linux-2.4.23-pre8/arch/i386/kernel/irq.c linux-2.4.23-pre8-pac1/arch/i386/kernel/irq.c --- linux-2.4.23-pre8/arch/i386/kernel/irq.c 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/i386/kernel/irq.c 2003-10-24 14:31:25.000000000 +0200 @@ -1091,7 +1091,7 @@ static struct proc_dir_entry * smp_affinity_entry [NR_IRQS]; -static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL }; +unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL }; static int irq_affinity_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data) { diff -urN linux-2.4.23-pre8/arch/i386/kernel/ldt.c linux-2.4.23-pre8-pac1/arch/i386/kernel/ldt.c --- linux-2.4.23-pre8/arch/i386/kernel/ldt.c 2001-10-17 23:46:29.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/i386/kernel/ldt.c 2003-10-24 14:31:25.000000000 +0200 @@ -12,37 +12,139 @@ #include #include #include +#include #include #include #include #include +#ifdef CONFIG_SMP /* avoids "defined but not used" warnig */ +static void flush_ldt(void *mm) +{ + if (current->active_mm) + load_LDT(¤t->active_mm->context); +} +#endif + +static int alloc_ldt(mm_context_t *pc, int mincount, int reload) +{ + void *oldldt; + void *newldt; + int oldsize; + + if (mincount <= pc->size) + return 0; + oldsize = pc->size; + mincount = (mincount+511)&(~511); + if (mincount*LDT_ENTRY_SIZE > PAGE_SIZE) + newldt = vmalloc(mincount*LDT_ENTRY_SIZE); + else + newldt = kmalloc(mincount*LDT_ENTRY_SIZE, GFP_KERNEL); + + if (!newldt) + return -ENOMEM; + + if (oldsize) + memcpy(newldt, pc->ldt, oldsize*LDT_ENTRY_SIZE); + + oldldt = pc->ldt; + memset(newldt+oldsize*LDT_ENTRY_SIZE, 0, (mincount-oldsize)*LDT_ENTRY_SIZE); + wmb(); + pc->ldt = newldt; + pc->size = mincount; + if (reload) { + load_LDT(pc); +#ifdef CONFIG_SMP + if (current->mm->cpu_vm_mask != (1< PAGE_SIZE) + vfree(oldldt); + else + kfree(oldldt); + } + return 0; +} + +static inline int copy_ldt(mm_context_t *new, mm_context_t *old) +{ + int err = alloc_ldt(new, old->size, 0); + if (err < 0) { + printk(KERN_WARNING "ldt allocation failed\n"); + new->size = 0; + return err; + } + memcpy(new->ldt, old->ldt, old->size*LDT_ENTRY_SIZE); + return 0; +} + +/* + * we do not have to muck with descriptors here, that is + * done in switch_mm() as needed. + */ +int init_new_context(struct task_struct *tsk, struct mm_struct *mm) +{ + struct mm_struct * old_mm; + int retval = 0; + + init_MUTEX(&mm->context.sem); + mm->context.size = 0; + old_mm = current->mm; + if (old_mm && old_mm->context.size > 0) { + down(&old_mm->context.sem); + retval = copy_ldt(&mm->context, &old_mm->context); + up(&old_mm->context.sem); + } + return retval; +} + /* - * read_ldt() is not really atomic - this is not a problem since - * synchronization of reads and writes done to the LDT has to be - * assured by user-space anyway. Writes are atomic, to protect - * the security checks done on new descriptors. + * No need to lock the MM as we are the last user + * Do not touch the ldt register, we are already + * in the next thread. */ +void destroy_context(struct mm_struct *mm) +{ + if (mm->context.size) { + if (mm->context.size*LDT_ENTRY_SIZE > PAGE_SIZE) + vfree(mm->context.ldt); + else + kfree(mm->context.ldt); + mm->context.size = 0; + } +} + static int read_ldt(void * ptr, unsigned long bytecount) { int err; unsigned long size; struct mm_struct * mm = current->mm; - err = 0; - if (!mm->context.segments) - goto out; + if (!mm->context.size) + return 0; + if (bytecount > LDT_ENTRY_SIZE*LDT_ENTRIES) + bytecount = LDT_ENTRY_SIZE*LDT_ENTRIES; - size = LDT_ENTRIES*LDT_ENTRY_SIZE; + down(&mm->context.sem); + size = mm->context.size*LDT_ENTRY_SIZE; if (size > bytecount) size = bytecount; - err = size; - if (copy_to_user(ptr, mm->context.segments, size)) + err = 0; + if (copy_to_user(ptr, mm->context.ldt, size)) err = -EFAULT; -out: - return err; + up(&mm->context.sem); + if (err < 0) + return err; + if (size != bytecount) { + /* zero-fill the rest */ + clear_user(ptr+size, bytecount-size); + } + return bytecount; } static int read_default_ldt(void * ptr, unsigned long bytecount) @@ -53,7 +155,7 @@ err = 0; address = &default_ldt[0]; - size = sizeof(struct desc_struct); + size = 5*sizeof(struct desc_struct); if (size > bytecount) size = bytecount; @@ -88,24 +190,14 @@ goto out; } - /* - * the GDT index of the LDT is allocated dynamically, and is - * limited by MAX_LDT_DESCRIPTORS. - */ - down_write(&mm->mmap_sem); - if (!mm->context.segments) { - void * segments = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE); - error = -ENOMEM; - if (!segments) + down(&mm->context.sem); + if (ldt_info.entry_number >= mm->context.size) { + error = alloc_ldt(¤t->mm->context, ldt_info.entry_number+1, 1); + if (error < 0) goto out_unlock; - memset(segments, 0, LDT_ENTRIES*LDT_ENTRY_SIZE); - wmb(); - mm->context.segments = segments; - mm->context.cpuvalid = 1UL << smp_processor_id(); - load_LDT(mm); } - lp = (__u32 *) ((ldt_info.entry_number << 3) + (char *) mm->context.segments); + lp = (__u32 *) ((ldt_info.entry_number << 3) + (char *) mm->context.ldt); /* Allow LDTs to be cleared by the user. */ if (ldt_info.base_addr == 0 && ldt_info.limit == 0) { @@ -143,7 +235,7 @@ error = 0; out_unlock: - up_write(&mm->mmap_sem); + up(&mm->context.sem); out: return error; } diff -urN linux-2.4.23-pre8/arch/i386/kernel/longhaul.c linux-2.4.23-pre8-pac1/arch/i386/kernel/longhaul.c --- linux-2.4.23-pre8/arch/i386/kernel/longhaul.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/arch/i386/kernel/longhaul.c 2003-10-24 14:31:25.000000000 +0200 @@ -0,0 +1,635 @@ +/* + * (C) 2001-2003 Dave Jones. + * (C) 2002 Padraig Brady. + * + * Licensed under the terms of the GNU GPL License version 2. + * Based upon datasheets & sample CPUs kindly provided by VIA. + * + * VIA have currently 3 different versions of Longhaul. + * + * +---------------------+----------+---------------------------------+ + * | Marketing name | Codename | longhaul version / features. | + * +---------------------+----------+---------------------------------+ + * | Samuel/CyrixIII | C5A | v1 : multipliers only | + * | Samuel2/C3 | C3E/C5B | v1 : multiplier only | + * | Ezra | C5C | v2 : multipliers & voltage | + * | Ezra-T | C5M/C5N | v3 : multipliers, voltage & FSB | + * +---------------------+----------+---------------------------------+ + * + * BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous* + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "longhaul.h" + +#define DEBUG + +#ifdef DEBUG +#define dprintk(msg...) printk(msg) +#else +#define dprintk(msg...) do { } while(0) +#endif + +#define PFX "longhaul: " + +static unsigned int numscales=16, numvscales; +static int minvid, maxvid; +static int can_scale_voltage; +static int vrmrev; + + +/* Module parameters */ +static int dont_scale_voltage; +static unsigned int fsb; + +#define __hlt() __asm__ __volatile__("hlt": : :"memory") + +/* + * Clock ratio tables. + * The eblcr ones specify the ratio read from the CPU. + * The clock_ratio ones specify what to write to the CPU. + */ + +/* VIA C3 Samuel 1 & Samuel 2 (stepping 0)*/ +static int __initdata longhaul1_clock_ratio[16] = { + -1, /* 0000 -> RESERVED */ + 30, /* 0001 -> 3.0x */ + 40, /* 0010 -> 4.0x */ + -1, /* 0011 -> RESERVED */ + -1, /* 0100 -> RESERVED */ + 35, /* 0101 -> 3.5x */ + 45, /* 0110 -> 4.5x */ + 55, /* 0111 -> 5.5x */ + 60, /* 1000 -> 6.0x */ + 70, /* 1001 -> 7.0x */ + 80, /* 1010 -> 8.0x */ + 50, /* 1011 -> 5.0x */ + 65, /* 1100 -> 6.5x */ + 75, /* 1101 -> 7.5x */ + -1, /* 1110 -> RESERVED */ + -1, /* 1111 -> RESERVED */ +}; + +static int __initdata samuel1_eblcr[16] = { + 50, /* 0000 -> RESERVED */ + 30, /* 0001 -> 3.0x */ + 40, /* 0010 -> 4.0x */ + -1, /* 0011 -> RESERVED */ + 55, /* 0100 -> 5.5x */ + 35, /* 0101 -> 3.5x */ + 45, /* 0110 -> 4.5x */ + -1, /* 0111 -> RESERVED */ + -1, /* 1000 -> RESERVED */ + 70, /* 1001 -> 7.0x */ + 80, /* 1010 -> 8.0x */ + 60, /* 1011 -> 6.0x */ + -1, /* 1100 -> RESERVED */ + 75, /* 1101 -> 7.5x */ + -1, /* 1110 -> RESERVED */ + 65, /* 1111 -> 6.5x */ +}; + +/* VIA C3 Samuel2 Stepping 1->15 & VIA C3 Ezra */ +static int __initdata longhaul2_clock_ratio[16] = { + 100, /* 0000 -> 10.0x */ + 30, /* 0001 -> 3.0x */ + 40, /* 0010 -> 4.0x */ + 90, /* 0011 -> 9.0x */ + 95, /* 0100 -> 9.5x */ + 35, /* 0101 -> 3.5x */ + 45, /* 0110 -> 4.5x */ + 55, /* 0111 -> 5.5x */ + 60, /* 1000 -> 6.0x */ + 70, /* 1001 -> 7.0x */ + 80, /* 1010 -> 8.0x */ + 50, /* 1011 -> 5.0x */ + 65, /* 1100 -> 6.5x */ + 75, /* 1101 -> 7.5x */ + 85, /* 1110 -> 8.5x */ + 120, /* 1111 -> 12.0x */ +}; + +static int __initdata samuel2_eblcr[16] = { + 50, /* 0000 -> 5.0x */ + 30, /* 0001 -> 3.0x */ + 40, /* 0010 -> 4.0x */ + 100, /* 0011 -> 10.0x */ + 55, /* 0100 -> 5.5x */ + 35, /* 0101 -> 3.5x */ + 45, /* 0110 -> 4.5x */ + 110, /* 0111 -> 11.0x */ + 90, /* 1000 -> 9.0x */ + 70, /* 1001 -> 7.0x */ + 80, /* 1010 -> 8.0x */ + 60, /* 1011 -> 6.0x */ + 120, /* 1100 -> 12.0x */ + 75, /* 1101 -> 7.5x */ + 130, /* 1110 -> 13.0x */ + 65, /* 1111 -> 6.5x */ +}; + +static int __initdata ezra_eblcr[16] = { + 50, /* 0000 -> 5.0x */ + 30, /* 0001 -> 3.0x */ + 40, /* 0010 -> 4.0x */ + 100, /* 0011 -> 10.0x */ + 55, /* 0100 -> 5.5x */ + 35, /* 0101 -> 3.5x */ + 45, /* 0110 -> 4.5x */ + 95, /* 0111 -> 9.5x */ + 90, /* 1000 -> 9.0x */ + 70, /* 1001 -> 7.0x */ + 80, /* 1010 -> 8.0x */ + 60, /* 1011 -> 6.0x */ + 120, /* 1100 -> 12.0x */ + 75, /* 1101 -> 7.5x */ + 85, /* 1110 -> 8.5x */ + 65, /* 1111 -> 6.5x */ +}; + +/* VIA C5M. */ +static int __initdata longhaul3_clock_ratio[32] = { + 100, /* 0000 -> 10.0x */ + 30, /* 0001 -> 3.0x */ + 40, /* 0010 -> 4.0x */ + 90, /* 0011 -> 9.0x */ + 95, /* 0100 -> 9.5x */ + 35, /* 0101 -> 3.5x */ + 45, /* 0110 -> 4.5x */ + 55, /* 0111 -> 5.5x */ + 60, /* 1000 -> 6.0x */ + 70, /* 1001 -> 7.0x */ + 80, /* 1010 -> 8.0x */ + 50, /* 1011 -> 5.0x */ + 65, /* 1100 -> 6.5x */ + 75, /* 1101 -> 7.5x */ + 85, /* 1110 -> 8.5x */ + 120, /* 1111 -> 12.0x */ + + -1, /* 0000 -> RESERVED (10.0x) */ + 110, /* 0001 -> 11.0x */ + 120, /* 0010 -> 12.0x */ + -1, /* 0011 -> RESERVED (9.0x)*/ + 105, /* 0100 -> 10.5x */ + 115, /* 0101 -> 11.5x */ + 125, /* 0110 -> 12.5x */ + 135, /* 0111 -> 13.5x */ + 140, /* 1000 -> 14.0x */ + 150, /* 1001 -> 15.0x */ + 160, /* 1010 -> 16.0x */ + 130, /* 1011 -> 13.0x */ + 145, /* 1100 -> 14.5x */ + 155, /* 1101 -> 15.5x */ + -1, /* 1110 -> RESERVED (13.0x) */ + -1, /* 1111 -> RESERVED (12.0x) */ +}; + +static int __initdata c5m_eblcr[32] = { + 50, /* 0000 -> 5.0x */ + 30, /* 0001 -> 3.0x */ + 40, /* 0010 -> 4.0x */ + 100, /* 0011 -> 10.0x */ + 55, /* 0100 -> 5.5x */ + 35, /* 0101 -> 3.5x */ + 45, /* 0110 -> 4.5x */ + 95, /* 0111 -> 9.5x */ + 90, /* 1000 -> 9.0x */ + 70, /* 1001 -> 7.0x */ + 80, /* 1010 -> 8.0x */ + 60, /* 1011 -> 6.0x */ + 120, /* 1100 -> 12.0x */ + 75, /* 1101 -> 7.5x */ + 85, /* 1110 -> 8.5x */ + 65, /* 1111 -> 6.5x */ + + -1, /* 0000 -> RESERVED (9.0x) */ + 110, /* 0001 -> 11.0x */ + 120, /* 0010 -> 12.0x */ + -1, /* 0011 -> RESERVED (10.0x)*/ + 135, /* 0100 -> 13.5x */ + 115, /* 0101 -> 11.5x */ + 125, /* 0110 -> 12.5x */ + 105, /* 0111 -> 10.5x */ + 130, /* 1000 -> 13.0x */ + 150, /* 1001 -> 15.0x */ + 160, /* 1010 -> 16.0x */ + 140, /* 1011 -> 14.0x */ + -1, /* 1100 -> RESERVED (12.0x) */ + 155, /* 1101 -> 15.5x */ + -1, /* 1110 -> RESERVED (13.0x) */ + 145, /* 1111 -> 14.5x */ +}; + +/* Voltage scales. Div by 1000 to get actual voltage. */ +static int __initdata vrm85scales[32] = { + 1250, 1200, 1150, 1100, 1050, 1800, 1750, 1700, + 1650, 1600, 1550, 1500, 1450, 1400, 1350, 1300, + 1275, 1225, 1175, 1125, 1075, 1825, 1775, 1725, + 1675, 1625, 1575, 1525, 1475, 1425, 1375, 1325, +}; + +static int __initdata mobilevrmscales[32] = { + 2000, 1950, 1900, 1850, 1800, 1750, 1700, 1650, + 1600, 1550, 1500, 1450, 1500, 1350, 1300, -1, + 1275, 1250, 1225, 1200, 1175, 1150, 1125, 1100, + 1075, 1050, 1025, 1000, 975, 950, 925, -1, +}; + +/* Clock ratios multiplied by 10 */ +static int clock_ratio[32]; +static int eblcr_table[32]; +static int voltage_table[32]; +static unsigned int highest_speed, lowest_speed; /* kHz */ +static int longhaul_version; +static struct cpufreq_frequency_table *longhaul_table; + + +static int longhaul_get_cpu_fsb (void) +{ + unsigned int eblcr_fsb_table[] = { 66, 133, 100, -1 }; + unsigned long invalue=0,lo, hi; + + if (fsb == 0) { + rdmsr (MSR_IA32_EBL_CR_POWERON, lo, hi); + invalue = (lo & (1<<18|1<<19)) >>18; + return eblcr_fsb_table[invalue]; + } else { + return fsb; + } +} + + +static int longhaul_get_cpu_mult (void) +{ + unsigned long invalue=0,lo, hi; + + rdmsr (MSR_IA32_EBL_CR_POWERON, lo, hi); + invalue = (lo & (1<<22|1<<23|1<<24|1<<25)) >>22; + if (longhaul_version==3) { + if (lo & (1<<27)) + invalue+=16; + } + return eblcr_table[invalue]; +} + + +/** + * longhaul_set_cpu_frequency() + * @clock_ratio_index : bitpattern of the new multiplier. + * + * Sets a new clock ratio, and -if applicable- a new Front Side Bus + */ + +static void longhaul_setstate (unsigned int clock_ratio_index) +{ + int vidindex, i; + struct cpufreq_freqs freqs; + union msr_longhaul longhaul; + union msr_bcr2 bcr2; + + if (clock_ratio[clock_ratio_index] == -1) + return; + + if (((clock_ratio[clock_ratio_index] * fsb * 100) > highest_speed) || + ((clock_ratio[clock_ratio_index] * fsb * 100) < lowest_speed)) + return; + + freqs.old = longhaul_get_cpu_mult() * longhaul_get_cpu_fsb() * 100; + freqs.new = clock_ratio[clock_ratio_index] * fsb * 100; + freqs.cpu = 0; /* longhaul.c is UP only driver */ + + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + + dprintk (KERN_INFO PFX "FSB:%d Mult(x10):%d\n", + fsb * 100, clock_ratio[clock_ratio_index]); + + switch (longhaul_version) { + case 1: + rdmsrl (MSR_VIA_BCR2, bcr2.val); + /* Enable software clock multiplier */ + bcr2.bits.ESOFTBF = 1; + bcr2.bits.CLOCKMUL = clock_ratio_index; + wrmsrl (MSR_VIA_BCR2, bcr2.val); + + __hlt(); + + /* Disable software clock multiplier */ + rdmsrl (MSR_VIA_BCR2, bcr2.val); + bcr2.bits.ESOFTBF = 0; + wrmsrl (MSR_VIA_BCR2, bcr2.val); + break; + + case 2: + rdmsrl (MSR_VIA_LONGHAUL, longhaul.val); + longhaul.bits.SoftBusRatio = clock_ratio_index & 0xf; + longhaul.bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4; + longhaul.bits.EnableSoftBusRatio = 1; + /* We must program the revision key only with values we + * know about, not blindly copy it from 0:3 */ + longhaul.bits.RevisionKey = 1; + + if (can_scale_voltage) { + /* PB: TODO fix this up */ + vidindex = (((highest_speed-lowest_speed) / (fsb/2)) - + ((highest_speed-((clock_ratio[clock_ratio_index] * fsb * 100)/1000)) / (fsb/2))); + for (i=0;i<32;i++) { + dprintk (KERN_INFO "VID hunting. Looking for %d, found %d\n", + minvid+(vidindex*25), voltage_table[i]); + if (voltage_table[i]==(minvid + (vidindex * 25))) + break; + } + if (i==32) + goto bad_voltage; + + dprintk (KERN_INFO PFX "Desired vid index=%d\n", i); +#if 0 + longhaul.bits.SoftVID = i; + longhaul.bits.EnableSoftVID = 1; +#endif + } +/* FIXME: Do voltage and freq seperatly like we do in powernow-k7 */ +bad_voltage: + wrmsrl (MSR_VIA_LONGHAUL, longhaul.val); + __hlt(); + + rdmsrl (MSR_VIA_LONGHAUL, longhaul.val); + longhaul.bits.EnableSoftBusRatio = 0; + if (can_scale_voltage) + longhaul.bits.EnableSoftVID = 0; + longhaul.bits.RevisionKey = 1; + wrmsrl (MSR_VIA_LONGHAUL, longhaul.val); + break; + + case 3: + rdmsrl (MSR_VIA_LONGHAUL, longhaul.val); + longhaul.bits.SoftBusRatio = clock_ratio_index & 0xf; + longhaul.bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4; + longhaul.bits.EnableSoftBusRatio = 1; + /* We must program the revision key only with values we + * know about, not blindly copy it from 0:3 */ + longhaul.bits.RevisionKey = 3; /* SoftVID & SoftBSEL */ + + wrmsrl(MSR_VIA_LONGHAUL, longhaul.val); + __hlt(); + + rdmsrl (MSR_VIA_LONGHAUL, longhaul.val); + longhaul.bits.EnableSoftBusRatio = 0; + longhaul.bits.RevisionKey = 3; + wrmsrl (MSR_VIA_LONGHAUL, longhaul.val); + break; + } + + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); +} + + +static int __init longhaul_get_ranges (void) +{ + unsigned long invalue; + unsigned int minmult=0, maxmult=0; + unsigned int multipliers[32]= { + 50,30,40,100,55,35,45,95,90,70,80,60,120,75,85,65, + -1,110,120,-1,135,115,125,105,130,150,160,140,-1,155,-1,145 }; + unsigned int j, k = 0; + union msr_longhaul longhaul; + + switch (longhaul_version) { + case 1: + /* Ugh, Longhaul v1 didn't have the min/max MSRs. + Assume min=3.0x & max = whatever we booted at. */ + minmult = 30; + maxmult = longhaul_get_cpu_mult(); + break; + + case 2 ... 3: + rdmsrl (MSR_VIA_LONGHAUL, longhaul.val); + + invalue = longhaul.bits.MaxMHzBR; + if (longhaul.bits.MaxMHzBR4) + invalue += 16; + maxmult=multipliers[invalue]; + +#if 0 + invalue = longhaul.bits.MinMHzBR; + if (longhaul.bits.MinMHzBR4); + invalue += 16; + minmult = multipliers[invalue]; +#else + minmult = 30; /* as per spec */ +#endif + break; + } + + highest_speed = maxmult * fsb * 100; + lowest_speed = minmult * fsb * 100; + dprintk (KERN_INFO PFX "MinMult(x10)=%d MaxMult(x10)=%d\n", + minmult, maxmult); + dprintk (KERN_INFO PFX "Lowestspeed=%d Highestspeed=%d\n", + lowest_speed, highest_speed); + + longhaul_table = kmalloc((numscales + 1) * sizeof(struct cpufreq_frequency_table), GFP_KERNEL); + if(!longhaul_table) + return -ENOMEM; + + for (j=0; (j maxmult) || ((unsigned int)clock_ratio[j] < minmult)) + continue; + longhaul_table[k].frequency= clock_ratio[j] * fsb * 100; + longhaul_table[k].index = (j << 8); + k++; + } + + longhaul_table[k].frequency = CPUFREQ_TABLE_END; + if (!k) { + kfree (longhaul_table); + return -EINVAL; + } + + return 0; +} + + +static void __init longhaul_setup_voltagescaling(void) +{ + union msr_longhaul longhaul; + + rdmsrl (MSR_VIA_LONGHAUL, longhaul.val); + + if (!(longhaul.bits.RevisionID & 1)) + return; + + minvid = longhaul.bits.MinimumVID; + maxvid = longhaul.bits.MaximumVID; + vrmrev = longhaul.bits.VRMRev; + + if (minvid == 0 || maxvid == 0) { + printk (KERN_INFO PFX "Bogus values Min:%d.%03d Max:%d.%03d. " + "Voltage scaling disabled.\n", + minvid/1000, minvid%1000, maxvid/1000, maxvid%1000); + return; + } + + if (minvid == maxvid) { + printk (KERN_INFO PFX "Claims to support voltage scaling but min & max are " + "both %d.%03d. Voltage scaling disabled\n", + maxvid/1000, maxvid%1000); + return; + } + + if (vrmrev==0) { + dprintk (KERN_INFO PFX "VRM 8.5 : "); + memcpy (voltage_table, vrm85scales, sizeof(voltage_table)); + numvscales = (voltage_table[maxvid]-voltage_table[minvid])/25; + } else { + dprintk (KERN_INFO PFX "Mobile VRM : "); + memcpy (voltage_table, mobilevrmscales, sizeof(voltage_table)); + numvscales = (voltage_table[maxvid]-voltage_table[minvid])/5; + } + + /* Current voltage isn't readable at first, so we need to + set it to a known value. The spec says to use maxvid */ + longhaul.bits.RevisionKey = longhaul.bits.RevisionID; /* FIXME: This is bad. */ + longhaul.bits.EnableSoftVID = 1; + longhaul.bits.SoftVID = maxvid; + wrmsrl (MSR_VIA_LONGHAUL, longhaul.val); + + minvid = voltage_table[minvid]; + maxvid = voltage_table[maxvid]; + + dprintk ("Min VID=%d.%03d Max VID=%d.%03d, %d possible voltage scales\n", + maxvid/1000, maxvid%1000, minvid/1000, minvid%1000, numvscales); + + can_scale_voltage = 1; +} + + +static int longhaul_verify(struct cpufreq_policy *policy) +{ + return cpufreq_frequency_table_verify(policy, longhaul_table); +} + + +static int longhaul_target (struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + unsigned int table_index = 0; + unsigned int new_clock_ratio = 0; + + if (cpufreq_frequency_table_target(policy, longhaul_table, target_freq, relation, &table_index)) + return -EINVAL; + + new_clock_ratio = longhaul_table[table_index].index & 0xFF; + + longhaul_setstate(new_clock_ratio); + + return 0; +} + +static int longhaul_cpu_init (struct cpufreq_policy *policy) +{ + struct cpuinfo_x86 *c = cpu_data; + int ret; + + switch (c->x86_model) { + case 6: /* VIA C3 Samuel C5A */ + longhaul_version=1; + memcpy (clock_ratio, longhaul1_clock_ratio, sizeof(longhaul1_clock_ratio)); + memcpy (eblcr_table, samuel1_eblcr, sizeof(samuel1_eblcr)); + break; + + case 7: /* C5B / C5C */ + switch (c->x86_mask) { + case 0: + longhaul_version=1; + memcpy (clock_ratio, longhaul1_clock_ratio, sizeof(longhaul1_clock_ratio)); + memcpy (eblcr_table, samuel2_eblcr, sizeof(samuel2_eblcr)); + break; + case 1 ... 15: + longhaul_version=2; + memcpy (clock_ratio, longhaul2_clock_ratio, sizeof(longhaul2_clock_ratio)); + memcpy (eblcr_table, ezra_eblcr, sizeof(ezra_eblcr)); + break; + } + break; + + case 8: /* C5M/C5N */ + return -ENODEV; // Waiting on updated docs from VIA before this is usable + longhaul_version=3; + numscales=32; + memcpy (clock_ratio, longhaul3_clock_ratio, sizeof(longhaul3_clock_ratio)); + memcpy (eblcr_table, c5m_eblcr, sizeof(c5m_eblcr)); + break; + } + + printk (KERN_INFO PFX "VIA CPU detected. Longhaul version %d supported\n", + longhaul_version); + + if ((longhaul_version==2 || longhaul_version==3) && (dont_scale_voltage==0)) + longhaul_setup_voltagescaling(); + + ret = longhaul_get_ranges(); + if (ret != 0) + return ret; + + policy->policy = CPUFREQ_POLICY_PERFORMANCE; + policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; + + policy->cur = (unsigned int) (longhaul_get_cpu_fsb() * longhaul_get_cpu_mult() * 100); + + return cpufreq_frequency_table_cpuinfo(policy, longhaul_table); +} + +static struct cpufreq_driver longhaul_driver = { + .verify = longhaul_verify, + .target = longhaul_target, + .init = longhaul_cpu_init, + .name = "longhaul", +}; + +static int __init longhaul_init (void) +{ + struct cpuinfo_x86 *c = cpu_data; + + if ((c->x86_vendor != X86_VENDOR_CENTAUR) || (c->x86 !=6) ) + return -ENODEV; + + switch (c->x86_model) { + case 6 ... 7: + return cpufreq_register_driver(&longhaul_driver); + case 8: + return -ENODEV; + default: + printk (KERN_INFO PFX "Unknown VIA CPU. Contact davej@codemonkey.org.uk\n"); + } + + return -ENODEV; +} + +static void __exit longhaul_exit (void) +{ + cpufreq_unregister_driver(&longhaul_driver); + kfree(longhaul_table); +} + +MODULE_PARM (dont_scale_voltage, "i"); + +MODULE_AUTHOR ("Dave Jones "); +MODULE_DESCRIPTION ("Longhaul driver for VIA Cyrix processors."); +MODULE_LICENSE ("GPL"); + +module_init(longhaul_init); +module_exit(longhaul_exit); + diff -urN linux-2.4.23-pre8/arch/i386/kernel/longhaul.h linux-2.4.23-pre8-pac1/arch/i386/kernel/longhaul.h --- linux-2.4.23-pre8/arch/i386/kernel/longhaul.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/arch/i386/kernel/longhaul.h 2003-10-24 14:31:25.000000000 +0200 @@ -0,0 +1,49 @@ +/* + * longhaul.h + * (C) 2003 Dave Jones. + * + * Licensed under the terms of the GNU GPL License version 2. + * + * VIA-specific information + */ + +union msr_bcr2 { + struct { + unsigned Reseved:19, // 18:0 + ESOFTBF:1, // 19 + Reserved2:3, // 22:20 + CLOCKMUL:4, // 26:23 + Reserved3:5; // 31:27 + } bits; + unsigned long val; +}; + +union msr_longhaul { + struct { + unsigned RevisionID:4, // 3:0 + RevisionKey:4, // 7:4 + EnableSoftBusRatio:1, // 8 + EnableSoftVID:1, // 9 + EnableSoftBSEL:1, // 10 + Reserved:3, // 11:13 + SoftBusRatio4:1, // 14 + VRMRev:1, // 15 + SoftBusRatio:4, // 19:16 + SoftVID:5, // 24:20 + Reserved2:3, // 27:25 + SoftBSEL:2, // 29:28 + Reserved3:2, // 31:30 + MaxMHzBR:4, // 35:32 + MaximumVID:5, // 40:36 + MaxMHzFSB:2, // 42:41 + MaxMHzBR4:1, // 43 + Reserved4:4, // 47:44 + MinMHzBR:4, // 51:48 + MinimumVID:5, // 56:52 + MinMHzFSB:2, // 58:57 + MinMHzBR4:1, // 59 + Reserved5:4; // 63:60 + } bits; + unsigned long long val; +}; + diff -urN linux-2.4.23-pre8/arch/i386/kernel/longrun.c linux-2.4.23-pre8-pac1/arch/i386/kernel/longrun.c --- linux-2.4.23-pre8/arch/i386/kernel/longrun.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/arch/i386/kernel/longrun.c 2003-10-24 14:31:25.000000000 +0200 @@ -0,0 +1,284 @@ +/* + * (C) 2002 - 2003 Dominik Brodowski + * + * Licensed under the terms of the GNU GPL License version 2. + * + * BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous* + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +static struct cpufreq_driver longrun_driver; + +/** + * longrun_{low,high}_freq is needed for the conversion of cpufreq kHz + * values into per cent values. In TMTA microcode, the following is valid: + * performance_pctg = (current_freq - low_freq)/(high_freq - low_freq) + */ +static unsigned int longrun_low_freq, longrun_high_freq; + + +/** + * longrun_get_policy - get the current LongRun policy + * @policy: struct cpufreq_policy where current policy is written into + * + * Reads the current LongRun policy by access to MSR_TMTA_LONGRUN_FLAGS + * and MSR_TMTA_LONGRUN_CTRL + */ +static void longrun_get_policy(struct cpufreq_policy *policy) +{ + u32 msr_lo, msr_hi; + + rdmsr(MSR_TMTA_LONGRUN_FLAGS, msr_lo, msr_hi); + if (msr_lo & 0x01) + policy->policy = CPUFREQ_POLICY_PERFORMANCE; + else + policy->policy = CPUFREQ_POLICY_POWERSAVE; + + rdmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi); + msr_lo &= 0x0000007F; + msr_hi &= 0x0000007F; + + policy->min = longrun_low_freq + msr_lo * + ((longrun_high_freq - longrun_low_freq) / 100); + policy->max = longrun_low_freq + msr_hi * + ((longrun_high_freq - longrun_low_freq) / 100); + policy->cpu = 0; +} + + +/** + * longrun_set_policy - sets a new CPUFreq policy + * @policy - new policy + * + * Sets a new CPUFreq policy on LongRun-capable processors. This function + * has to be called with cpufreq_driver locked. + */ +static int longrun_set_policy(struct cpufreq_policy *policy) +{ + u32 msr_lo, msr_hi; + u32 pctg_lo, pctg_hi; + + if (!policy) + return -EINVAL; + + pctg_lo = (policy->min - longrun_low_freq) / + ((longrun_high_freq - longrun_low_freq) / 100); + pctg_hi = (policy->max - longrun_low_freq) / + ((longrun_high_freq - longrun_low_freq) / 100); + + if (pctg_hi > 100) + pctg_hi = 100; + if (pctg_lo > pctg_hi) + pctg_lo = pctg_hi; + + /* performance or economy mode */ + rdmsr(MSR_TMTA_LONGRUN_FLAGS, msr_lo, msr_hi); + msr_lo &= 0xFFFFFFFE; + switch (policy->policy) { + case CPUFREQ_POLICY_PERFORMANCE: + msr_lo |= 0x00000001; + break; + case CPUFREQ_POLICY_POWERSAVE: + break; + } + wrmsr(MSR_TMTA_LONGRUN_FLAGS, msr_lo, msr_hi); + + /* lower and upper boundary */ + rdmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi); + msr_lo &= 0xFFFFFF80; + msr_hi &= 0xFFFFFF80; + msr_lo |= pctg_lo; + msr_hi |= pctg_hi; + wrmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi); + + return 0; +} + + +/** + * longrun_verify_poliy - verifies a new CPUFreq policy + * + * Validates a new CPUFreq policy. This function has to be called with + * cpufreq_driver locked. + */ +static int longrun_verify_policy(struct cpufreq_policy *policy) +{ + if (!policy) + return -EINVAL; + + policy->cpu = 0; + cpufreq_verify_within_limits(policy, + policy->cpuinfo.min_freq, + policy->cpuinfo.max_freq); + + if (policy->policy == CPUFREQ_POLICY_GOVERNOR) + return -EINVAL; + + return 0; +} + + +/** + * longrun_determine_freqs - determines the lowest and highest possible core frequency + * + * Determines the lowest and highest possible core frequencies on this CPU. + * This is necessary to calculate the performance percentage according to + * TMTA rules: + * performance_pctg = (target_freq - low_freq)/(high_freq - low_freq) + */ +static unsigned int __init longrun_determine_freqs(unsigned int *low_freq, + unsigned int *high_freq) +{ + u32 msr_lo, msr_hi; + u32 save_lo, save_hi; + u32 eax, ebx, ecx, edx; + struct cpuinfo_x86 *c = cpu_data; + + if (!low_freq || !high_freq) + return -EINVAL; + + if (cpu_has(c, X86_FEATURE_LRTI)) { + /* if the LongRun Table Interface is present, the + * detection is a bit easier: + * For minimum frequency, read out the maximum + * level (msr_hi), write that into "currently + * selected level", and read out the frequency. + * For maximum frequency, read out level zero. + */ + /* minimum */ + rdmsr(MSR_TMTA_LRTI_READOUT, msr_lo, msr_hi); + wrmsr(MSR_TMTA_LRTI_READOUT, msr_hi, msr_hi); + rdmsr(MSR_TMTA_LRTI_VOLT_MHZ, msr_lo, msr_hi); + *low_freq = msr_lo * 1000; /* to kHz */ + + /* maximum */ + wrmsr(MSR_TMTA_LRTI_READOUT, 0, msr_hi); + rdmsr(MSR_TMTA_LRTI_VOLT_MHZ, msr_lo, msr_hi); + *high_freq = msr_lo * 1000; /* to kHz */ + + if (*low_freq > *high_freq) + *low_freq = *high_freq; + return 0; + } + + /* set the upper border to the value determined during TSC init */ + *high_freq = (cpu_khz / 1000); + *high_freq = *high_freq * 1000; + + /* get current borders */ + rdmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi); + save_lo = msr_lo & 0x0000007F; + save_hi = msr_hi & 0x0000007F; + + /* if current perf_pctg is larger than 90%, we need to decrease the + * upper limit to make the calculation more accurate. + */ + cpuid(0x80860007, &eax, &ebx, &ecx, &edx); + if (ecx > 90) { + /* set to 0 to 80 perf_pctg */ + msr_lo &= 0xFFFFFF80; + msr_hi &= 0xFFFFFF80; + msr_lo |= 0; + msr_hi |= 80; + wrmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi); + + /* read out current core MHz and current perf_pctg */ + cpuid(0x80860007, &eax, &ebx, &ecx, &edx); + + /* restore values */ + wrmsr(MSR_TMTA_LONGRUN_CTRL, save_lo, save_hi); + } + + /* performance_pctg = (current_freq - low_freq)/(high_freq - low_freq) + * eqals + * low_freq * ( 1 - perf_pctg) = (cur_freq - high_freq * perf_pctg) + * + * high_freq * perf_pctg is stored tempoarily into "ebx". + */ + ebx = (((cpu_khz / 1000) * ecx) / 100); /* to MHz */ + + if ((ecx > 95) || (ecx == 0) || (eax < ebx)) + return -EIO; + + edx = (eax - ebx) / (100 - ecx); + *low_freq = edx * 1000; /* back to kHz */ + + if (*low_freq > *high_freq) + *low_freq = *high_freq; + + return 0; +} + + +static int longrun_cpu_init(struct cpufreq_policy *policy) +{ + int result = 0; + + /* capability check */ + if (policy->cpu != 0) + return -ENODEV; + + /* detect low and high frequency */ + result = longrun_determine_freqs(&longrun_low_freq, &longrun_high_freq); + if (result) + return result; + + /* cpuinfo and default policy values */ + policy->cpuinfo.min_freq = longrun_low_freq; + policy->cpuinfo.max_freq = longrun_high_freq; + policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; + longrun_get_policy(policy); + + return 0; +} + + +static struct cpufreq_driver longrun_driver = { + .verify = longrun_verify_policy, + .setpolicy = longrun_set_policy, + .init = longrun_cpu_init, + .name = "longrun", +}; + + +/** + * longrun_init - initializes the Transmeta Crusoe LongRun CPUFreq driver + * + * Initializes the LongRun support. + */ +static int __init longrun_init(void) +{ + struct cpuinfo_x86 *c = cpu_data; + + if (c->x86_vendor != X86_VENDOR_TRANSMETA || + !cpu_has(c, X86_FEATURE_LONGRUN)) + return -ENODEV; + + return cpufreq_register_driver(&longrun_driver); +} + + +/** + * longrun_exit - unregisters LongRun support + */ +static void __exit longrun_exit(void) +{ + cpufreq_unregister_driver(&longrun_driver); +} + + +MODULE_AUTHOR ("Dominik Brodowski "); +MODULE_DESCRIPTION ("LongRun driver for Transmeta Crusoe processors."); +MODULE_LICENSE ("GPL"); + +module_init(longrun_init); +module_exit(longrun_exit); diff -urN linux-2.4.23-pre8/arch/i386/kernel/mpparse.c linux-2.4.23-pre8-pac1/arch/i386/kernel/mpparse.c --- linux-2.4.23-pre8/arch/i386/kernel/mpparse.c 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/i386/kernel/mpparse.c 2003-10-24 14:31:25.000000000 +0200 @@ -78,6 +78,7 @@ unsigned char clustered_apic_mode = CLUSTERED_APIC_NONE; unsigned int apic_broadcast_id = APIC_BROADCAST_ID_APIC; #endif +unsigned int xapic_support = 0; unsigned char raw_phys_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID }; /* @@ -243,6 +244,8 @@ return; } ver = m->mpc_apicver; + if (APIC_XAPIC_SUPPORT(ver)) + xapic_support = 1; logical_cpu_present_map |= 1 << (num_processors-1); phys_cpu_present_map |= apicid_to_phys_cpu_present(m->mpc_apicid); @@ -592,15 +595,6 @@ } - printk("Enabling APIC mode: "); - if(clustered_apic_mode == CLUSTERED_APIC_NUMAQ) - printk("Clustered Logical. "); - else if(clustered_apic_mode == CLUSTERED_APIC_XAPIC) - printk("Physical. "); - else - printk("Flat. "); - printk("Using %d I/O APICs\n",nr_ioapics); - if (!num_processors) printk(KERN_ERR "SMP mptable: no processors registered!\n"); return num_processors; @@ -854,6 +848,34 @@ BUG(); printk("Processors: %d\n", num_processors); + printk("xAPIC support %s present\n", (xapic_support?"is":"is not")); + +#ifdef CONFIG_X86_CLUSTERED_APIC + /* + * Switch to Physical destination mode in case of generic + * more than 8 CPU system, which has xAPIC support + */ +#define FLAT_APIC_CPU_MAX 8 + if ((clustered_apic_mode == CLUSTERED_APIC_NONE) && + (xapic_support) && + (num_processors > FLAT_APIC_CPU_MAX)) { + clustered_apic_mode = CLUSTERED_APIC_XAPIC; + apic_broadcast_id = APIC_BROADCAST_ID_XAPIC; + int_dest_addr_mode = APIC_DEST_PHYSICAL; + int_delivery_mode = dest_Fixed; + esr_disable = 1; + } +#endif + + printk("Enabling APIC mode: "); + if (clustered_apic_mode == CLUSTERED_APIC_NUMAQ) + printk("Clustered Logical. "); + else if (clustered_apic_mode == CLUSTERED_APIC_XAPIC) + printk("Physical. "); + else + printk("Flat. "); + printk("Using %d I/O APICs\n",nr_ioapics); + /* * Only use the first configuration found. */ @@ -1291,10 +1313,11 @@ #ifdef CONFIG_ACPI_PCI -void __init mp_parse_prt (void) +int __init mp_parse_prt (void) { struct list_head *node = NULL; struct acpi_prt_entry *entry = NULL; + struct acpi_prt_list *prt_list = NULL; int ioapic = -1; int ioapic_pin = 0; int irq = 0; @@ -1302,16 +1325,31 @@ int edge_level = 0; int active_high_low = 0; + /* Get the current PRT */ + prt_list = acpi_pci_get_prt_list(); + + if (!prt_list->count) { + acpi_pci_destroy_prt_list(prt_list); + printk(KERN_WARNING "ACPI tables contain no IO-APIC PCI IRQ " + "routing entries\n"); + return_VALUE(-ENODEV); + } + /* * Parsing through the PCI Interrupt Routing Table (PRT) and program * routing for all entries. */ - list_for_each(node, &acpi_prt.entries) { + list_for_each(node, &prt_list->entries) { entry = list_entry(node, struct acpi_prt_entry, node); /* Need to get irq for dynamic entry */ if (entry->link.handle) { irq = acpi_pci_link_get_irq(entry->link.handle, entry->link.index, &edge_level, &active_high_low); + if (irq < 0) { + acpi_pci_destroy_prt_list(prt_list); + return -ENODEV; + } + if (!irq) continue; } @@ -1364,8 +1402,11 @@ mp_ioapic_routing[ioapic].apic_id, ioapic_pin, entry->irq); } - - return; + + /* if we get here, the PRT was fine. commit it */ + acpi_pci_commit_prt_list(prt_list); + + return 0; } #endif /*CONFIG_ACPI_PCI*/ diff -urN linux-2.4.23-pre8/arch/i386/kernel/p4-clockmod.c linux-2.4.23-pre8-pac1/arch/i386/kernel/p4-clockmod.c --- linux-2.4.23-pre8/arch/i386/kernel/p4-clockmod.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/arch/i386/kernel/p4-clockmod.c 2003-10-24 14:31:25.000000000 +0200 @@ -0,0 +1,271 @@ +/* + * Pentium 4/Xeon CPU on demand clock modulation/speed scaling + * (C) 2002 - 2003 Dominik Brodowski + * (C) 2002 Zwane Mwaikambo + * (C) 2002 Arjan van de Ven + * (C) 2002 Tora T. Engstad + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * The author(s) of this software shall not be held liable for damages + * of any nature resulting due to the use of this software. This + * software is provided AS-IS with no warranties. + * + * Date Errata Description + * 20020525 N44, O17 12.5% or 25% DC causes lockup + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define PFX "cpufreq: " + +/* + * Duty Cycle (3bits), note DC_DISABLE is not specified in + * intel docs i just use it to mean disable + */ +enum { + DC_RESV, DC_DFLT, DC_25PT, DC_38PT, DC_50PT, + DC_64PT, DC_75PT, DC_88PT, DC_DISABLE +}; + +#define DC_ENTRIES 8 + + +static int has_N44_O17_errata[NR_CPUS]; +static int stock_freq; + + +static int cpufreq_p4_setdc(unsigned int cpu, unsigned int newstate) +{ + u32 l, h; + unsigned long cpus_allowed; + struct cpufreq_freqs freqs; + int hyperthreading = 0; + int affected_cpu_map = 0; + int sibling = 0; + + if (!cpu_online(cpu) || (newstate > DC_DISABLE) || + (newstate == DC_RESV)) + return -EINVAL; + + /* switch to physical CPU where state is to be changed*/ + cpus_allowed = current->cpus_allowed; + + /* only run on CPU to be set, or on its sibling */ + affected_cpu_map = 1 << cpu; +#ifdef CONFIG_X86_HT + hyperthreading = ((cpu_has_ht) && (smp_num_siblings == 2)); + if (hyperthreading) { + sibling = cpu_sibling_map[cpu]; + affected_cpu_map |= (1 << sibling); + } +#endif + set_cpus_allowed(current, affected_cpu_map); + BUG_ON(!(affected_cpu_map & (1 << smp_processor_id()))); + + /* get current state */ + rdmsr(MSR_IA32_THERM_CONTROL, l, h); + if (l & 0x10) { + l = l >> 1; + l &= 0x7; + } else + l = DC_DISABLE; + + if (l == newstate) { + set_cpus_allowed(current, cpus_allowed); + return 0; + } else if (l == DC_RESV) { + printk(KERN_ERR PFX "BIG FAT WARNING: currently in invalid setting\n"); + } + + /* notifiers */ + freqs.old = stock_freq * l / 8; + freqs.new = stock_freq * newstate / 8; + freqs.cpu = cpu; + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + if (hyperthreading) { + freqs.cpu = sibling; + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + } + + rdmsr(MSR_IA32_THERM_STATUS, l, h); +#if 0 + if (l & 0x01) + printk(KERN_DEBUG PFX "CPU#%d currently thermal throttled\n", cpu); +#endif + if (has_N44_O17_errata[cpu] && (newstate == DC_25PT || newstate == DC_DFLT)) + newstate = DC_38PT; + + rdmsr(MSR_IA32_THERM_CONTROL, l, h); + if (newstate == DC_DISABLE) { + /* printk(KERN_INFO PFX "CPU#%d disabling modulation\n", cpu); */ + wrmsr(MSR_IA32_THERM_CONTROL, l & ~(1<<4), h); + } else { + /* printk(KERN_INFO PFX "CPU#%d setting duty cycle to %d%%\n", + cpu, ((125 * newstate) / 10)); */ + /* bits 63 - 5 : reserved + * bit 4 : enable/disable + * bits 3-1 : duty cycle + * bit 0 : reserved + */ + l = (l & ~14); + l = l | (1<<4) | ((newstate & 0x7)<<1); + wrmsr(MSR_IA32_THERM_CONTROL, l, h); + } + + set_cpus_allowed(current, cpus_allowed); + + /* notifiers */ + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + if (hyperthreading) { + freqs.cpu = cpu; + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + } + + return 0; +} + + +static struct cpufreq_frequency_table p4clockmod_table[] = { + {DC_RESV, CPUFREQ_ENTRY_INVALID}, + {DC_DFLT, 0}, + {DC_25PT, 0}, + {DC_38PT, 0}, + {DC_50PT, 0}, + {DC_64PT, 0}, + {DC_75PT, 0}, + {DC_88PT, 0}, + {DC_DISABLE, 0}, + {DC_RESV, CPUFREQ_TABLE_END}, +}; + + +static int cpufreq_p4_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + unsigned int newstate = DC_RESV; + + if (cpufreq_frequency_table_target(policy, &p4clockmod_table[0], target_freq, relation, &newstate)) + return -EINVAL; + + cpufreq_p4_setdc(policy->cpu, p4clockmod_table[newstate].index); + + return 0; +} + + +static int cpufreq_p4_verify(struct cpufreq_policy *policy) +{ + return cpufreq_frequency_table_verify(policy, &p4clockmod_table[0]); +} + + +static int cpufreq_p4_cpu_init(struct cpufreq_policy *policy) +{ + struct cpuinfo_x86 *c = &cpu_data[policy->cpu]; + int cpuid = 0; + unsigned int i; + + /* Errata workaround */ + cpuid = (c->x86 << 8) | (c->x86_model << 4) | c->x86_mask; + switch (cpuid) { + case 0x0f07: + case 0x0f0a: + case 0x0f11: + case 0x0f12: + has_N44_O17_errata[policy->cpu] = 1; + } + + /* get frequency */ + if (!stock_freq) { + if (cpu_khz) + stock_freq = cpu_khz; + else { + printk(KERN_INFO PFX "unknown core frequency - please use module parameter 'stock_freq'\n"); + return -EINVAL; + } + } + + /* table init */ + for (i=1; (p4clockmod_table[i].frequency != CPUFREQ_TABLE_END); i++) { + if ((i<2) && (has_N44_O17_errata[policy->cpu])) + p4clockmod_table[i].frequency = CPUFREQ_ENTRY_INVALID; + else + p4clockmod_table[i].frequency = (stock_freq * i)/8; + } + + /* cpuinfo and default policy values */ + policy->policy = CPUFREQ_POLICY_PERFORMANCE; + policy->cpuinfo.transition_latency = 1000; + policy->cur = stock_freq; + + return cpufreq_frequency_table_cpuinfo(policy, &p4clockmod_table[0]); +} + + +static int cpufreq_p4_cpu_exit(struct cpufreq_policy *policy) +{ + return cpufreq_p4_setdc(policy->cpu, DC_DISABLE); +} + +static struct cpufreq_driver p4clockmod_driver = { + .verify = cpufreq_p4_verify, + .target = cpufreq_p4_target, + .init = cpufreq_p4_cpu_init, + .exit = cpufreq_p4_cpu_exit, + .name = "p4-clockmod", +}; + + +static int __init cpufreq_p4_init(void) +{ + struct cpuinfo_x86 *c = cpu_data; + + /* + * THERM_CONTROL is architectural for IA32 now, so + * we can rely on the capability checks + */ + if (c->x86_vendor != X86_VENDOR_INTEL) + return -ENODEV; + + if (!test_bit(X86_FEATURE_ACPI, c->x86_capability) || + !test_bit(X86_FEATURE_ACC, c->x86_capability)) + return -ENODEV; + + printk(KERN_INFO PFX "P4/Xeon(TM) CPU On-Demand Clock Modulation available\n"); + + return cpufreq_register_driver(&p4clockmod_driver); +} + + +static void __exit cpufreq_p4_exit(void) +{ + cpufreq_unregister_driver(&p4clockmod_driver); +} + + +MODULE_PARM(stock_freq, "i"); + +MODULE_AUTHOR ("Zwane Mwaikambo "); +MODULE_DESCRIPTION ("cpufreq driver for Pentium(TM) 4/Xeon(TM)"); +MODULE_LICENSE ("GPL"); + +module_init(cpufreq_p4_init); +module_exit(cpufreq_p4_exit); + diff -urN linux-2.4.23-pre8/arch/i386/kernel/pci-dma.c linux-2.4.23-pre8-pac1/arch/i386/kernel/pci-dma.c --- linux-2.4.23-pre8/arch/i386/kernel/pci-dma.c 2002-11-29 00:53:09.000000000 +0100 +++ linux-2.4.23-pre8-pac1/arch/i386/kernel/pci-dma.c 2003-10-24 14:31:25.000000000 +0200 @@ -19,7 +19,7 @@ void *ret; int gfp = GFP_ATOMIC; - if (hwdev == NULL || ((u32)hwdev->dma_mask < 0xffffffff)) + if (hwdev == NULL || hwdev->dma_mask < 0xffffffff) gfp |= GFP_DMA; ret = (void *)__get_free_pages(gfp, get_order(size)); diff -urN linux-2.4.23-pre8/arch/i386/kernel/pci-pc.c linux-2.4.23-pre8-pac1/arch/i386/kernel/pci-pc.c --- linux-2.4.23-pre8/arch/i386/kernel/pci-pc.c 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/i386/kernel/pci-pc.c 2003-10-24 14:31:25.000000000 +0200 @@ -1425,8 +1425,12 @@ void __init pcibios_init(void) { + extern int acpi_disabled; int quad; + if (acpi_disabled) + use_acpi_pci = 0; + if (!pci_root_ops) pcibios_config_init(); if (!pci_root_ops) { diff -urN linux-2.4.23-pre8/arch/i386/kernel/pic.c linux-2.4.23-pre8-pac1/arch/i386/kernel/pic.c --- linux-2.4.23-pre8/arch/i386/kernel/pic.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/arch/i386/kernel/pic.c 2003-10-24 14:31:25.000000000 +0200 @@ -0,0 +1,102 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2003 Andrew de Quincey - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139, + * USA; either version 2 of the License, or (at your option) any later + * version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef CONFIG_ACPI_PCI + +extern void eisa_set_level_irq(unsigned int irq); + +int __init pic_parse_prt (void) +{ + struct list_head *node = NULL; + struct acpi_prt_entry *entry = NULL; + struct acpi_prt_list *prt_list = NULL; + int edge_level = 0; + int active_high_low = 0; + int irq = 0; + int programmed[16]; + + /* Get the current PRT */ + prt_list = acpi_pci_get_prt_list(); + + if (!prt_list->count) { + acpi_pci_destroy_prt_list(prt_list); + printk(KERN_WARNING "ACPI tables contain no PIC PCI IRQ " + "routing entries\n"); + return_VALUE(-ENODEV); + } + + /* mark all IRQs as unprogrammed */ + memset(programmed, 0, sizeof(programmed)); + + /* + * Parsing through the PCI Interrupt Routing Table (PRT) and program + * IRQs if necessary. + */ + list_for_each(node, &prt_list->entries) { + entry = list_entry(node, struct acpi_prt_entry, node); + + /* Need to get irq for dynamic entry */ + if (entry->link.handle) { + irq = acpi_pci_link_get_irq(entry->link.handle, entry->link.index, &edge_level, &active_high_low); + if (irq < 0) { + acpi_pci_destroy_prt_list(prt_list); + return -ENODEV; + } + if (!irq) + continue; + } + + /* sanity check + update entry */ + if ((irq < 0) || (irq > 15)) { + printk(KERN_ERR "Invalid IRQ (%i) passed to PIC programming code\n", irq); + entry->irq = 0; + continue; + } + entry->irq = irq; + + /* check if it has already been dealt with */ + if (programmed[irq]) { + printk(KERN_DEBUG "PIC: IRQ (%i) already programmed\n", irq); + continue; + } + programmed[irq] = 1; + + /* program it */ + if (edge_level) { + eisa_set_level_irq(irq); + } + + printk(KERN_DEBUG "%02x:%02x:%02x[%c] -> IRQ %d Mode %d Trigger %d\n", + entry->id.segment, entry->id.bus, + entry->id.device, ('A' + entry->pin), + entry->irq, edge_level, active_high_low); + } + + /* if we get here, the PRT was fine. commit it */ + acpi_pci_commit_prt_list(prt_list); + + return 0; +} + +#endif /*CONFIG_ACPI_PCI*/ diff -urN linux-2.4.23-pre8/arch/i386/kernel/powernow-k6.c linux-2.4.23-pre8-pac1/arch/i386/kernel/powernow-k6.c --- linux-2.4.23-pre8/arch/i386/kernel/powernow-k6.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/arch/i386/kernel/powernow-k6.c 2003-10-24 14:31:25.000000000 +0200 @@ -0,0 +1,234 @@ +/* + * This file was based upon code in Powertweak Linux (http://powertweak.sf.net) + * (C) 2000-2003 Dave Jones, Arjan van de Ven, Janne Pänkälä, Dominik Brodowski. + * + * Licensed under the terms of the GNU GPL License version 2. + * + * BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous* + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +#define POWERNOW_IOPORT 0xfff0 /* it doesn't matter where, as long + as it is unused */ + +static unsigned int busfreq; /* FSB, in 10 kHz */ +static unsigned int max_multiplier; + + +/* Clock ratio multiplied by 10 - see table 27 in AMD#23446 */ +static struct cpufreq_frequency_table clock_ratio[] = { + {45, /* 000 -> 4.5x */ 0}, + {50, /* 001 -> 5.0x */ 0}, + {40, /* 010 -> 4.0x */ 0}, + {55, /* 011 -> 5.5x */ 0}, + {20, /* 100 -> 2.0x */ 0}, + {30, /* 101 -> 3.0x */ 0}, + {60, /* 110 -> 6.0x */ 0}, + {35, /* 111 -> 3.5x */ 0}, + {0, CPUFREQ_TABLE_END} +}; + + +/** + * powernow_k6_get_cpu_multiplier - returns the current FSB multiplier + * + * Returns the current setting of the frequency multiplier. Core clock + * speed is frequency of the Front-Side Bus multiplied with this value. + */ +static int powernow_k6_get_cpu_multiplier(void) +{ + u64 invalue = 0; + u32 msrval; + + msrval = POWERNOW_IOPORT + 0x1; + wrmsr(MSR_K6_EPMR, msrval, 0); /* enable the PowerNow port */ + invalue=inl(POWERNOW_IOPORT + 0x8); + msrval = POWERNOW_IOPORT + 0x0; + wrmsr(MSR_K6_EPMR, msrval, 0); /* disable it again */ + + return clock_ratio[(invalue >> 5)&7].index; +} + + +/** + * powernow_k6_set_state - set the PowerNow! multiplier + * @best_i: clock_ratio[best_i] is the target multiplier + * + * Tries to change the PowerNow! multiplier + */ +static void powernow_k6_set_state (unsigned int best_i) +{ + unsigned long outvalue=0, invalue=0; + unsigned long msrval; + struct cpufreq_freqs freqs; + + if (clock_ratio[best_i].index > max_multiplier) { + printk(KERN_ERR "cpufreq: invalid target frequency\n"); + return; + } + + freqs.old = busfreq * powernow_k6_get_cpu_multiplier(); + freqs.new = busfreq * clock_ratio[best_i].index; + freqs.cpu = 0; /* powernow-k6.c is UP only driver */ + + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + + /* we now need to transform best_i to the BVC format, see AMD#23446 */ + + outvalue = (1<<12) | (1<<10) | (1<<9) | (best_i<<5); + + msrval = POWERNOW_IOPORT + 0x1; + wrmsr(MSR_K6_EPMR, msrval, 0); /* enable the PowerNow port */ + invalue=inl(POWERNOW_IOPORT + 0x8); + invalue = invalue & 0xf; + outvalue = outvalue | invalue; + outl(outvalue ,(POWERNOW_IOPORT + 0x8)); + msrval = POWERNOW_IOPORT + 0x0; + wrmsr(MSR_K6_EPMR, msrval, 0); /* disable it again */ + + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + + return; +} + + +/** + * powernow_k6_verify - verifies a new CPUfreq policy + * @policy: new policy + * + * Policy must be within lowest and highest possible CPU Frequency, + * and at least one possible state must be within min and max. + */ +static int powernow_k6_verify(struct cpufreq_policy *policy) +{ + return cpufreq_frequency_table_verify(policy, &clock_ratio[0]); +} + + +/** + * powernow_k6_setpolicy - sets a new CPUFreq policy + * @policy - new policy + * + * sets a new CPUFreq policy + */ +static int powernow_k6_target (struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + unsigned int newstate = 0; + + if (cpufreq_frequency_table_target(policy, &clock_ratio[0], target_freq, relation, &newstate)) + return -EINVAL; + + powernow_k6_set_state(newstate); + + return 0; +} + + +static int powernow_k6_cpu_init(struct cpufreq_policy *policy) +{ + unsigned int i; + + if (policy->cpu != 0) + return -ENODEV; + + /* get frequencies */ + max_multiplier = powernow_k6_get_cpu_multiplier(); + busfreq = cpu_khz / max_multiplier; + + /* table init */ + for (i=0; (clock_ratio[i].frequency != CPUFREQ_TABLE_END); i++) { + if (clock_ratio[i].index > max_multiplier) + clock_ratio[i].frequency = CPUFREQ_ENTRY_INVALID; + else + clock_ratio[i].frequency = busfreq * clock_ratio[i].index; + } + + /* cpuinfo and default policy values */ + policy->policy = CPUFREQ_POLICY_PERFORMANCE; + policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; + policy->cur = busfreq * max_multiplier; + + return cpufreq_frequency_table_cpuinfo(policy, &clock_ratio[0]); +} + + +static int powernow_k6_cpu_exit(struct cpufreq_policy *policy) +{ + unsigned int i; + for (i=0; i<8; i++) { + if (i==max_multiplier) + powernow_k6_set_state(i); + } + return 0; +} + + +static struct cpufreq_driver powernow_k6_driver = { + .verify = powernow_k6_verify, + .target = powernow_k6_target, + .init = powernow_k6_cpu_init, + .exit = powernow_k6_cpu_exit, + .name = "powernow-k6", +}; + + +/** + * powernow_k6_init - initializes the k6 PowerNow! CPUFreq driver + * + * Initializes the K6 PowerNow! support. Returns -ENODEV on unsupported + * devices, -EINVAL or -ENOMEM on problems during initiatization, and zero + * on success. + */ +static int __init powernow_k6_init(void) +{ + struct cpuinfo_x86 *c = cpu_data; + + if ((c->x86_vendor != X86_VENDOR_AMD) || (c->x86 != 5) || + ((c->x86_model != 12) && (c->x86_model != 13))) + return -ENODEV; + + if (!request_region(POWERNOW_IOPORT, 16, "PowerNow!")) { + printk("cpufreq: PowerNow IOPORT region already used.\n"); + return -EIO; + } + + if (cpufreq_register_driver(&powernow_k6_driver)) { + release_region (POWERNOW_IOPORT, 16); + return -EINVAL; + } + + return 0; +} + + +/** + * powernow_k6_exit - unregisters AMD K6-2+/3+ PowerNow! support + * + * Unregisters AMD K6-2+ / K6-3+ PowerNow! support. + */ +static void __exit powernow_k6_exit(void) +{ + cpufreq_unregister_driver(&powernow_k6_driver); + release_region (POWERNOW_IOPORT, 16); +} + + +MODULE_AUTHOR ("Arjan van de Ven , Dave Jones , Dominik Brodowski "); +MODULE_DESCRIPTION ("PowerNow! driver for AMD K6-2+ / K6-3+ processors."); +MODULE_LICENSE ("GPL"); + +module_init(powernow_k6_init); +module_exit(powernow_k6_exit); diff -urN linux-2.4.23-pre8/arch/i386/kernel/powernow-k7.c linux-2.4.23-pre8-pac1/arch/i386/kernel/powernow-k7.c --- linux-2.4.23-pre8/arch/i386/kernel/powernow-k7.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/arch/i386/kernel/powernow-k7.c 2003-10-24 14:31:25.000000000 +0200 @@ -0,0 +1,410 @@ +/* + * AMD K7 Powernow driver. + * (C) 2003 Dave Jones on behalf of SuSE Labs. + * + * Licensed under the terms of the GNU GPL License version 2. + * Based upon datasheets & sample CPUs kindly provided by AMD. + * + * BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous* + * + * Errata 5: Processor may fail to execute a FID/VID change in presence of interrupt. + * - We cli/sti on stepping A0 CPUs around the FID/VID transition. + * Errata 15: Processors with half frequency multipliers may hang upon wakeup from disconnect. + * - We disable half multipliers if ACPI is used on A0 stepping CPUs. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "powernow-k7.h" + +#define DEBUG + +#ifdef DEBUG +#define dprintk(msg...) printk(msg) +#else +#define dprintk(msg...) do { } while(0) +#endif + +#define PFX "powernow: " + + +struct psb_s { + u8 signature[10]; + u8 tableversion; + u8 flags; + u16 settlingtime; + u8 reserved1; + u8 numpst; +}; + +struct pst_s { + u32 cpuid; + u8 fsbspeed; + u8 maxfid; + u8 startvid; + u8 numpstates; +}; + + +/* divide by 1000 to get VID. */ +static int mobile_vid_table[32] = { + 2000, 1950, 1900, 1850, 1800, 1750, 1700, 1650, + 1600, 1550, 1500, 1450, 1400, 1350, 1300, 0, + 1275, 1250, 1225, 1200, 1175, 1150, 1125, 1100, + 1075, 1050, 1024, 1000, 975, 950, 925, 0, +}; + +/* divide by 10 to get FID. */ +static int fid_codes[32] = { + 110, 115, 120, 125, 50, 55, 60, 65, + 70, 75, 80, 85, 90, 95, 100, 105, + 30, 190, 40, 200, 130, 135, 140, 210, + 150, 225, 160, 165, 170, 180, -1, -1, +}; + +static struct cpufreq_frequency_table *powernow_table; + +static unsigned int can_scale_bus; +static unsigned int can_scale_vid; +static unsigned int minimum_speed=-1; +static unsigned int maximum_speed; +static unsigned int number_scales; +static unsigned int fsb; +static unsigned int latency; +static char have_a0; + + +static int check_powernow(void) +{ + struct cpuinfo_x86 *c = cpu_data; + unsigned int maxei, eax, ebx, ecx, edx; + + if (c->x86_vendor != X86_VENDOR_AMD) { + printk (KERN_INFO PFX "AMD processor not detected.\n"); + return 0; + } + + if (c->x86 !=6) { + printk (KERN_INFO PFX "This module only works with AMD K7 CPUs\n"); + return 0; + } + + printk (KERN_INFO PFX "AMD K7 CPU detected.\n"); + + if ((c->x86_model == 6) && (c->x86_mask == 0)) { + printk (KERN_INFO PFX "K7 660[A0] core detected, enabling errata workarounds\n"); + have_a0 = 1; + } + + /* Get maximum capabilities */ + maxei = cpuid_eax (0x80000000); + if (maxei < 0x80000007) { /* Any powernow info ? */ + printk (KERN_INFO PFX "No powernow capabilities detected\n"); + return 0; + } + + cpuid(0x80000007, &eax, &ebx, &ecx, &edx); + printk (KERN_INFO PFX "PowerNOW! Technology present. Can scale: "); + + if (edx & 1 << 1) { + printk ("frequency"); + can_scale_bus=1; + } + + if ((edx & (1 << 1 | 1 << 2)) == 0x6) + printk (" and "); + + if (edx & 1 << 2) { + printk ("voltage"); + can_scale_vid=1; + } + + if (!(edx & (1 << 1 | 1 << 2))) { + printk ("nothing.\n"); + return 0; + } + + printk (".\n"); + return 1; +} + + +static int get_ranges (unsigned char *pst) +{ + unsigned int j, speed; + u8 fid, vid; + + powernow_table = kmalloc((sizeof(struct cpufreq_frequency_table) * (number_scales + 1)), GFP_KERNEL); + if (!powernow_table) + return -ENOMEM; + memset(powernow_table, 0, (sizeof(struct cpufreq_frequency_table) * (number_scales + 1))); + + for (j=0 ; j < number_scales; j++) { + fid = *pst++; + + powernow_table[j].frequency = fsb * fid_codes[fid] * 100; + powernow_table[j].index = fid; /* lower 8 bits */ + + speed = fsb * (fid_codes[fid]/10); + if ((fid_codes[fid] % 10)==5) { + speed += fsb/2; +#if defined(CONFIG_ACPI_PROCESSOR) || defined(CONFIG_ACPI_PROCESSOR_MODULE) + if (have_a0 == 1) + powernow_table[j].frequency = CPUFREQ_ENTRY_INVALID; +#endif + } + + dprintk (KERN_INFO PFX " FID: 0x%x (%d.%dx [%dMHz])\t", fid, + fid_codes[fid] / 10, fid_codes[fid] % 10, speed); + + if (speed < minimum_speed) + minimum_speed = speed; + if (speed > maximum_speed) + maximum_speed = speed; + + vid = *pst++; + powernow_table[j].index |= (vid << 8); /* upper 8 bits */ + dprintk ("VID: 0x%x (%d.%03dV)\n", vid, mobile_vid_table[vid]/1000, + mobile_vid_table[vid]%1000); + } + dprintk ("\n"); + + powernow_table[number_scales].frequency = CPUFREQ_TABLE_END; + powernow_table[number_scales].index = 0; + + return 0; +} + + +static void change_FID(int fid) +{ + union msr_fidvidctl fidvidctl; + + if (fidvidctl.bits.FID != fid) { + rdmsrl (MSR_K7_FID_VID_CTL, fidvidctl.val); + fidvidctl.bits.SGTC = latency; + fidvidctl.bits.FID = fid; + fidvidctl.bits.FIDC = 1; + wrmsrl (MSR_K7_FID_VID_CTL, fidvidctl.val); + } +} + + +static void change_VID(int vid) +{ + union msr_fidvidctl fidvidctl; + + if (fidvidctl.bits.VID != vid) { + rdmsrl (MSR_K7_FID_VID_CTL, fidvidctl.val); + fidvidctl.bits.VID = vid; + fidvidctl.bits.VIDC = 1; + wrmsrl (MSR_K7_FID_VID_CTL, fidvidctl.val); + } +} + + +static void change_speed (unsigned int index) +{ + u8 fid, vid; + struct cpufreq_freqs freqs; + union msr_fidvidstatus fidvidstatus; + int cfid; + + /* fid are the lower 8 bits of the index we stored into + * the cpufreq frequency table in powernow_decode_bios, + * vid are the upper 8 bits. + */ + + fid = powernow_table[index].index & 0xFF; + vid = (powernow_table[index].index & 0xFF00) >> 8; + + freqs.cpu = 0; + + rdmsrl (MSR_K7_FID_VID_STATUS, fidvidstatus.val); + cfid = fidvidstatus.bits.CFID; + freqs.old = fsb * fid_codes[cfid] * 100; + freqs.new = powernow_table[index].frequency; + + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + + /* Now do the magic poking into the MSRs. */ + + if (have_a0 == 1) /* A0 errata 5 */ + local_irq_disable(); + + if (freqs.old > freqs.new) { + /* Going down, so change FID first */ + change_FID(fid); + change_VID(vid); + } else { + /* Going up, so change VID first */ + change_VID(vid); + change_FID(fid); + } + + + if (have_a0 == 1) + local_irq_enable(); + + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); +} + + +static int powernow_decode_bios (int maxfid, int startvid) +{ + struct psb_s *psb; + struct pst_s *pst; + struct cpuinfo_x86 *c = cpu_data; + unsigned int i, j; + unsigned char *p; + unsigned int etuple; + unsigned int ret; + + etuple = cpuid_eax(0x80000001); + etuple &= 0xf00; + etuple |= (c->x86_model<<4)|(c->x86_mask); + + for (i=0xC0000; i < 0xffff0 ; i+=16) { + + p = phys_to_virt(i); + + if (memcmp(p, "AMDK7PNOW!", 10) == 0){ + dprintk (KERN_INFO PFX "Found PSB header at %p\n", p); + psb = (struct psb_s *) p; + dprintk (KERN_INFO PFX "Table version: 0x%x\n", psb->tableversion); + if (psb->tableversion != 0x12) { + printk (KERN_INFO PFX "Sorry, only v1.2 tables supported right now\n"); + return -ENODEV; + } + + dprintk (KERN_INFO PFX "Flags: 0x%x (", psb->flags); + if ((psb->flags & 1)==0) { + dprintk ("Mobile"); + } else { + dprintk ("Desktop"); + } + dprintk (" voltage regulator)\n"); + + latency = psb->settlingtime; + dprintk (KERN_INFO PFX "Settling Time: %d microseconds.\n", psb->settlingtime); + dprintk (KERN_INFO PFX "Has %d PST tables. (Only dumping ones relevant to this CPU).\n", psb->numpst); + + p += sizeof (struct psb_s); + + pst = (struct pst_s *) p; + + for (i = 0 ; i numpst; i++) { + pst = (struct pst_s *) p; + number_scales = pst->numpstates; + + if ((etuple == pst->cpuid) && (maxfid==pst->maxfid) && (startvid==pst->startvid)) + { + dprintk (KERN_INFO PFX "PST:%d (@%p)\n", i, pst); + dprintk (KERN_INFO PFX " cpuid: 0x%x\t", pst->cpuid); + dprintk ("fsb: %d\t", pst->fsbspeed); + dprintk ("maxFID: 0x%x\t", pst->maxfid); + dprintk ("startvid: 0x%x\n", pst->startvid); + + fsb = pst->fsbspeed; + ret = get_ranges ((char *) pst + sizeof (struct pst_s)); + return ret; + + } else { + p = (char *) pst + sizeof (struct pst_s); + for (j=0 ; j < number_scales; j++) + p+=2; + } + } + return -EINVAL; + } + p++; + } + + return -ENODEV; +} + + +static int powernow_target (struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + unsigned int newstate; + + if (cpufreq_frequency_table_target(policy, powernow_table, target_freq, relation, &newstate)) + return -EINVAL; + + change_speed(newstate); + + return 0; +} + + +static int powernow_verify (struct cpufreq_policy *policy) +{ + return cpufreq_frequency_table_verify(policy, powernow_table); +} + + +static int __init powernow_cpu_init (struct cpufreq_policy *policy) +{ + union msr_fidvidstatus fidvidstatus; + int result; + + if (policy->cpu != 0) + return -ENODEV; + + rdmsrl (MSR_K7_FID_VID_STATUS, fidvidstatus.val); + + result = powernow_decode_bios(fidvidstatus.bits.MFID, fidvidstatus.bits.SVID); + if (result) + return result; + + printk (KERN_INFO PFX "Minimum speed %d MHz. Maximum speed %d MHz.\n", + minimum_speed, maximum_speed); + + policy->policy = CPUFREQ_POLICY_PERFORMANCE; + policy->cpuinfo.transition_latency = latency; + policy->cur = maximum_speed; + + return cpufreq_frequency_table_cpuinfo(policy, powernow_table); +} + +static struct cpufreq_driver powernow_driver = { + .verify = powernow_verify, + .target = powernow_target, + .init = powernow_cpu_init, + .name = "powernow-k7", +}; + +static int __init powernow_init (void) +{ + if (check_powernow()==0) + return -ENODEV; + return cpufreq_register_driver(&powernow_driver); +} + + +static void __exit powernow_exit (void) +{ + cpufreq_unregister_driver(&powernow_driver); + if (powernow_table) + kfree(powernow_table); +} + +MODULE_AUTHOR ("Dave Jones "); +MODULE_DESCRIPTION ("Powernow driver for AMD K7 processors."); +MODULE_LICENSE ("GPL"); + +module_init(powernow_init); +module_exit(powernow_exit); + diff -urN linux-2.4.23-pre8/arch/i386/kernel/powernow-k7.h linux-2.4.23-pre8-pac1/arch/i386/kernel/powernow-k7.h --- linux-2.4.23-pre8/arch/i386/kernel/powernow-k7.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/arch/i386/kernel/powernow-k7.h 2003-10-24 14:31:25.000000000 +0200 @@ -0,0 +1,44 @@ +/* + * $Id: powernow-k7.h,v 1.2 2003/02/10 18:26:01 davej Exp $ + * (C) 2003 Dave Jones. + * + * Licensed under the terms of the GNU GPL License version 2. + * + * AMD-specific information + * + */ + +union msr_fidvidctl { + struct { + unsigned FID:5, // 4:0 + reserved1:3, // 7:5 + VID:5, // 12:8 + reserved2:3, // 15:13 + FIDC:1, // 16 + VIDC:1, // 17 + reserved3:2, // 19:18 + FIDCHGRATIO:1, // 20 + reserved4:11, // 31-21 + SGTC:20, // 32:51 + reserved5:12; // 63:52 + } bits; + unsigned long long val; +}; + +union msr_fidvidstatus { + struct { + unsigned CFID:5, // 4:0 + reserved1:3, // 7:5 + SFID:5, // 12:8 + reserved2:3, // 15:13 + MFID:5, // 20:16 + reserved3:11, // 31:21 + CVID:5, // 36:32 + reserved4:3, // 39:37 + SVID:5, // 44:40 + reserved5:3, // 47:45 + MVID:5, // 52:48 + reserved6:11; // 63:53 + } bits; + unsigned long long val; +}; diff -urN linux-2.4.23-pre8/arch/i386/kernel/process.c linux-2.4.23-pre8-pac1/arch/i386/kernel/process.c --- linux-2.4.23-pre8/arch/i386/kernel/process.c 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/i386/kernel/process.c 2003-10-24 14:31:25.000000000 +0200 @@ -125,15 +125,12 @@ void cpu_idle (void) { /* endless idle loop with no priority at all */ - init_idle(); - current->nice = 20; - current->counter = -100; while (1) { void (*idle)(void) = pm_idle; if (!idle) idle = default_idle; - while (!current->need_resched) + if (!current->need_resched) idle(); schedule(); check_pgt_cache(); @@ -188,7 +185,7 @@ } /* we will leave sorting out the final value when we are ready to reboot, since we might not - have set up boot_cpu_id or smp_num_cpu */ + have set up boot_cpu_physical_apicid or smp_num_cpu */ break; #endif } @@ -475,23 +472,6 @@ } /* - * No need to lock the MM as we are the last user - */ -void release_segments(struct mm_struct *mm) -{ - void * ldt = mm->context.segments; - - /* - * free the LDT - */ - if (ldt) { - mm->context.segments = NULL; - clear_LDT(); - vfree(ldt); - } -} - -/* * Create a kernel thread */ int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) @@ -544,45 +524,19 @@ void release_thread(struct task_struct *dead_task) { if (dead_task->mm) { - void * ldt = dead_task->mm->context.segments; - // temporary debugging check - if (ldt) { - printk("WARNING: dead process %8s still has LDT? <%p>\n", - dead_task->comm, ldt); + if (dead_task->mm->context.size) { + printk("WARNING: dead process %8s still has LDT? <%p/%d>\n", + dead_task->comm, + dead_task->mm->context.ldt, + dead_task->mm->context.size); BUG(); } } - release_x86_irqs(dead_task); } /* - * we do not have to muck with descriptors here, that is - * done in switch_mm() as needed. - */ -void copy_segments(struct task_struct *p, struct mm_struct *new_mm) -{ - struct mm_struct * old_mm; - void *old_ldt, *ldt; - - ldt = NULL; - old_mm = current->mm; - if (old_mm && (old_ldt = old_mm->context.segments) != NULL) { - /* - * Completely new LDT, we initialize it from the parent: - */ - ldt = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE); - if (!ldt) - printk(KERN_WARNING "ldt allocation failed\n"); - else - memcpy(ldt, old_ldt, LDT_ENTRIES*LDT_ENTRY_SIZE); - } - new_mm->context.segments = ldt; - new_mm->context.cpuvalid = ~0UL; /* valid on all CPU's - they can't have stale data */ -} - -/* * Save a segment. */ #define savesegment(seg,value) \ @@ -707,15 +661,17 @@ asm volatile("movl %%gs,%0":"=m" (*(int *)&prev->gs)); /* - * Restore %fs and %gs. + * Restore %fs and %gs if needed. */ - loadsegment(fs, next->fs); - loadsegment(gs, next->gs); + if (unlikely(prev->fs | prev->gs | next->fs | next->gs)) { + loadsegment(fs, next->fs); + loadsegment(gs, next->gs); + } /* * Now maybe reload the debug registers */ - if (next->debugreg[7]){ + if (unlikely(next->debugreg[7])) { loaddebug(next, 0); loaddebug(next, 1); loaddebug(next, 2); @@ -725,7 +681,7 @@ loaddebug(next, 7); } - if (prev->ioperm || next->ioperm) { + if (unlikely(prev->ioperm || next->ioperm)) { if (next->ioperm) { /* * 4 cachelines copy ... not good, but not that diff -urN linux-2.4.23-pre8/arch/i386/kernel/setup.c linux-2.4.23-pre8-pac1/arch/i386/kernel/setup.c --- linux-2.4.23-pre8/arch/i386/kernel/setup.c 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/i386/kernel/setup.c 2003-10-24 14:31:25.000000000 +0200 @@ -3013,6 +3013,7 @@ * applications want to get the raw CPUID data, they should access * /dev/cpu//cpuid instead. */ + extern int phys_proc_id[NR_CPUS]; static char *x86_cap_flags[] = { /* Intel-defined */ "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce", @@ -3083,6 +3084,11 @@ /* Cache size */ if (c->x86_cache_size >= 0) seq_printf(m, "cache size\t: %d KB\n", c->x86_cache_size); + +#ifdef CONFIG_SMP + seq_printf(m, "physical id\t: %d\n",phys_proc_id[n]); + seq_printf(m, "siblings\t: %d\n",smp_num_siblings); +#endif /* We use exception 16 if we have hardware math and we've either seen it or the CPU claims it is internal */ fpu_exception = c->hard_math && (ignore_irq13 || cpu_has_fpu); @@ -3185,11 +3191,12 @@ set_tss_desc(nr,t); gdt_table[__TSS(nr)].b &= 0xfffffdff; load_TR(nr); - load_LDT(&init_mm); + load_LDT(&init_mm.context); - /* - * Clear all 6 debug registers: - */ + /* Clear %fs and %gs. */ + asm volatile ("xorl %eax, %eax; movl %eax, %fs; movl %eax, %gs"); + + /* Clear all 6 debug registers: */ #define CD(register) __asm__("movl %0,%%db" #register ::"r"(0) ); diff -urN linux-2.4.23-pre8/arch/i386/kernel/smp.c linux-2.4.23-pre8-pac1/arch/i386/kernel/smp.c --- linux-2.4.23-pre8/arch/i386/kernel/smp.c 2003-06-13 16:51:29.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/i386/kernel/smp.c 2003-10-24 14:31:25.000000000 +0200 @@ -496,13 +496,23 @@ * it goes straight through and wastes no time serializing * anything. Worst case is that we lose a reschedule ... */ - void smp_send_reschedule(int cpu) { send_IPI_mask(1 << cpu, RESCHEDULE_VECTOR); } /* + * this function sends a reschedule IPI to all (other) CPUs. + * This should only be used if some 'global' task became runnable, + * such as a RT task, that must be handled now. The first CPU + * that manages to grab the task will run it. + */ +void smp_send_reschedule_all(void) +{ + send_IPI_allbutself(RESCHEDULE_VECTOR); +} + +/* * Structure and data for smp_call_function(). This is designed to minimise * static memory requirements. It also looks cleaner. */ @@ -553,7 +563,7 @@ spin_lock(&call_lock); call_data = &data; - wmb(); + mb(); /* Send a message to all other CPUs and wait for them to respond */ send_IPI_allbutself(CALL_FUNCTION_VECTOR); diff -urN linux-2.4.23-pre8/arch/i386/kernel/smpboot.c linux-2.4.23-pre8-pac1/arch/i386/kernel/smpboot.c --- linux-2.4.23-pre8/arch/i386/kernel/smpboot.c 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/i386/kernel/smpboot.c 2003-10-24 14:31:25.000000000 +0200 @@ -58,7 +58,7 @@ /* Number of siblings per CPU package */ int smp_num_siblings = 1; -int __initdata phys_proc_id[NR_CPUS]; /* Package ID of each logical CPU */ +int phys_proc_id[NR_CPUS]; /* Package ID of each logical CPU */ /* Bitmask of currently online CPUs */ unsigned long cpu_online_map; @@ -365,7 +365,7 @@ * (This works even if the APIC is not enabled.) */ phys_id = GET_APIC_ID(apic_read(APIC_ID)); - cpuid = current->processor; + cpuid = cpu(); if (test_and_set_bit(cpuid, &cpu_online_map)) { printk("huh, phys CPU#%d, CPU#%d already present??\n", phys_id, cpuid); @@ -435,6 +435,7 @@ */ smp_store_cpu_info(cpuid); + disable_APIC_timer(); /* * Allow the master to continue. */ @@ -443,7 +444,7 @@ /* * Synchronize the TSC with the BP */ - if (cpu_has_tsc) + if (cpu_has_tsc > 1) synchronize_tsc_ap(); } @@ -465,6 +466,7 @@ smp_callin(); while (!atomic_read(&smp_commenced)) rep_nop(); + enable_APIC_timer(); /* * low-memory mappings have been cleared, flush them from * the local TLBs too. @@ -803,16 +805,13 @@ if (!idle) panic("No idle process for CPU %d", cpu); - idle->processor = cpu; - idle->cpus_runnable = 1 << cpu; /* we schedule the first task manually */ + init_idle(idle, cpu); map_cpu_to_boot_apicid(cpu, apicid); idle->thread.eip = (unsigned long) start_secondary; - del_from_runqueue(idle); unhash_process(idle); - init_tasks[cpu] = idle; /* start_eip had better be page-aligned! */ start_eip = setup_trampoline(); @@ -925,6 +924,7 @@ } cycles_t cacheflush_time; +unsigned long cache_decay_ticks; static void smp_tune_scheduling (void) { @@ -958,9 +958,13 @@ cacheflush_time = (cpu_khz>>10) * (cachesize<<10) / bandwidth; } + cache_decay_ticks = (long)cacheflush_time/cpu_khz * HZ / 1000; + printk("per-CPU timeslice cutoff: %ld.%02ld usecs.\n", (long)cacheflush_time/(cpu_khz/1000), ((long)cacheflush_time*100/(cpu_khz/1000)) % 100); + printk("task migration cache decay timeout: %ld msecs.\n", + (cache_decay_ticks + 1) * 1000 / HZ); } /* @@ -1026,8 +1030,7 @@ map_cpu_to_boot_apicid(0, boot_cpu_apicid); global_irq_holder = 0; - current->processor = 0; - init_idle(); + current->cpu = 0; smp_tune_scheduling(); /* @@ -1219,7 +1222,7 @@ /* * Synchronize the TSC with the AP */ - if (cpu_has_tsc && cpucount) + if (cpu_has_tsc > 1 && cpucount) synchronize_tsc_bp(); smp_done: diff -urN linux-2.4.23-pre8/arch/i386/kernel/speedstep-centrino.c linux-2.4.23-pre8-pac1/arch/i386/kernel/speedstep-centrino.c --- linux-2.4.23-pre8/arch/i386/kernel/speedstep-centrino.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/arch/i386/kernel/speedstep-centrino.c 2003-10-24 14:31:25.000000000 +0200 @@ -0,0 +1,382 @@ +/* + * cpufreq driver for Enhanced SpeedStep, as found in Intel's Pentium + * M (part of the Centrino chipset). + * + * Despite the "SpeedStep" in the name, this is almost entirely unlike + * traditional SpeedStep. + * + * Modelled on speedstep.c + * + * Copyright (C) 2003 Jeremy Fitzhardinge + * + * WARNING WARNING WARNING + * + * This driver manipulates the PERF_CTL MSR, which is only somewhat + * documented. While it seems to work on my laptop, it has not been + * tested anywhere else, and it may not work for you, do strange + * things or simply crash. + */ + +#include +#include +#include +#include +#include /* BACKPORT: for strcmp */ +#include +#include +#include + +#define PFX "speedstep-centrino: " +#define MAINTAINER "Jeremy Fitzhardinge " + +/*#define CENTRINO_DEBUG*/ + +#ifdef CENTRINO_DEBUG +#define dprintk(msg...) printk(msg) +#else +#define dprintk(msg...) do { } while(0) +#endif + +struct cpu_model +{ + const char *model_name; + unsigned max_freq; /* max clock in kHz */ + + struct cpufreq_frequency_table *op_points; /* clock/voltage pairs */ +}; + +/* Operating points for current CPU */ +static const struct cpu_model *centrino_model; + +/* Computes the correct form for IA32_PERF_CTL MSR for a particular + frequency/voltage operating point; frequency in MHz, volts in mV. + This is stored as "index" in the structure. */ +#define OP(mhz, mv) \ + { \ + .frequency = (mhz) * 1000, \ + .index = (((mhz)/100) << 8) | ((mv - 700) / 16) \ + } + +/* + * These voltage tables were derived from the Intel Pentium M + * datasheet, document 25261202.pdf, Table 5. I have verified they + * are consistent with my IBM ThinkPad X31, which has a 1.3GHz Pentium + * M. + */ + +/* Ultra Low Voltage Intel Pentium M processor 900MHz */ +static struct cpufreq_frequency_table op_900[] = +{ + OP(600, 844), + OP(800, 988), + OP(900, 1004), + { .frequency = CPUFREQ_TABLE_END } +}; + +/* Low Voltage Intel Pentium M processor 1.10GHz */ +static struct cpufreq_frequency_table op_1100[] = +{ + OP( 600, 956), + OP( 800, 1020), + OP( 900, 1100), + OP(1000, 1164), + OP(1100, 1180), + { .frequency = CPUFREQ_TABLE_END } +}; + + +/* Low Voltage Intel Pentium M processor 1.20GHz */ +static struct cpufreq_frequency_table op_1200[] = +{ + OP( 600, 956), + OP( 800, 1004), + OP( 900, 1020), + OP(1000, 1100), + OP(1100, 1164), + OP(1200, 1180), + { .frequency = CPUFREQ_TABLE_END } +}; + +/* Intel Pentium M processor 1.30GHz */ +static struct cpufreq_frequency_table op_1300[] = +{ + OP( 600, 956), + OP( 800, 1260), + OP(1000, 1292), + OP(1200, 1356), + OP(1300, 1388), + { .frequency = CPUFREQ_TABLE_END } +}; + +/* Intel Pentium M processor 1.40GHz */ +static struct cpufreq_frequency_table op_1400[] = +{ + OP( 600, 956), + OP( 800, 1180), + OP(1000, 1308), + OP(1200, 1436), + OP(1400, 1484), + { .frequency = CPUFREQ_TABLE_END } +}; + +/* Intel Pentium M processor 1.50GHz */ +static struct cpufreq_frequency_table op_1500[] = +{ + OP( 600, 956), + OP( 800, 1116), + OP(1000, 1228), + OP(1200, 1356), + OP(1400, 1452), + OP(1500, 1484), + { .frequency = CPUFREQ_TABLE_END } +}; + +/* Intel Pentium M processor 1.60GHz */ +static struct cpufreq_frequency_table op_1600[] = +{ + OP( 600, 956), + OP( 800, 1036), + OP(1000, 1164), + OP(1200, 1276), + OP(1400, 1420), + OP(1600, 1484), + { .frequency = CPUFREQ_TABLE_END } +}; + +/* Intel Pentium M processor 1.70GHz */ +static struct cpufreq_frequency_table op_1700[] = +{ + OP( 600, 956), + OP( 800, 1004), + OP(1000, 1116), + OP(1200, 1228), + OP(1400, 1308), + OP(1700, 1484), + { .frequency = CPUFREQ_TABLE_END } +}; +#undef OP + +#define _CPU(max, name) \ + { "Intel(R) Pentium(R) M processor " name "MHz", (max)*1000, op_##max } +#define CPU(max) _CPU(max, #max) + +/* CPU models, their operating frequency range, and freq/voltage + operating points */ +static const struct cpu_model models[] = +{ + _CPU( 900, " 900"), + CPU(1100), + CPU(1200), + CPU(1300), + CPU(1400), + CPU(1500), + CPU(1600), + CPU(1700), + { 0, } +}; +#undef CPU + +/* Extract clock in kHz from PERF_CTL value */ +static unsigned extract_clock(unsigned msr) +{ + msr = (msr >> 8) & 0xff; + return msr * 100000; +} + +/* Return the current CPU frequency in kHz */ +static unsigned get_cur_freq(void) +{ + unsigned l, h; + + rdmsr(MSR_IA32_PERF_STATUS, l, h); + return extract_clock(l); +} + +static int centrino_cpu_init(struct cpufreq_policy *policy) +{ + unsigned freq; + + if (policy->cpu != 0 || centrino_model == NULL) + return -ENODEV; + + freq = get_cur_freq(); + + policy->policy = (freq == centrino_model->max_freq) ? + CPUFREQ_POLICY_PERFORMANCE : + CPUFREQ_POLICY_POWERSAVE; + policy->cpuinfo.transition_latency = 10; /* 10uS transition latency */ + policy->cur = freq; + + dprintk(KERN_INFO PFX "centrino_cpu_init: policy=%d cur=%dkHz\n", + policy->policy, policy->cur); + + return cpufreq_frequency_table_cpuinfo(policy, centrino_model->op_points); +} + +/** + * centrino_verify - verifies a new CPUFreq policy + * @freq: new policy + * + * Limit must be within this model's frequency range at least one + * border included. + */ +static int centrino_verify (struct cpufreq_policy *policy) +{ + return cpufreq_frequency_table_verify(policy, centrino_model->op_points); +} + +/** + * centrino_setpolicy - set a new CPUFreq policy + * @policy: new policy + * + * Sets a new CPUFreq policy. + */ +static int centrino_target (struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + unsigned int newstate = 0; + unsigned int msr, oldmsr, h; + struct cpufreq_freqs freqs; + + if (centrino_model == NULL) + return -ENODEV; + + if (cpufreq_frequency_table_target(policy, centrino_model->op_points, target_freq, + relation, &newstate)) + return -EINVAL; + + msr = centrino_model->op_points[newstate].index; + rdmsr(MSR_IA32_PERF_CTL, oldmsr, h); + + if (msr == (oldmsr & 0xffff)) + return 0; + + /* Hm, old frequency can either be the last value we put in + PERF_CTL, or whatever it is now. The trouble is that TM2 + can change it behind our back, which means we never get to + see the speed change. Reading back the current speed would + tell us something happened, but it may leave the things on + the notifier chain confused; we therefore stick to using + the last programmed speed rather than the current speed for + "old". + + TODO: work out how the TCC interrupts work, and try to + catch the CPU changing things under us. + */ + freqs.cpu = 0; + freqs.old = extract_clock(oldmsr); + freqs.new = extract_clock(msr); + + dprintk(KERN_INFO PFX "target=%dkHz old=%d new=%d msr=%04x\n", + target_freq, freqs.old, freqs.new, msr); + + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + + /* all but 16 LSB are "reserved", so treat them with + care */ + oldmsr &= ~0xffff; + msr &= 0xffff; + oldmsr |= msr; + + wrmsr(MSR_IA32_PERF_CTL, oldmsr, h); + + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + + return 0; +} + +static struct cpufreq_driver centrino_driver = { + .name = "centrino", /* should be speedstep-centrino, + but there's a 16 char limit */ + .init = centrino_cpu_init, + .verify = centrino_verify, + .target = centrino_target, +}; + + +/** + * centrino_init - initializes the Enhanced SpeedStep CPUFreq driver + * + * Initializes the Enhanced SpeedStep support. Returns -ENODEV on + * unsupported devices, -ENOENT if there's no voltage table for this + * particular CPU model, -EINVAL on problems during initiatization, + * and zero on success. + * + * This is quite picky. Not only does the CPU have to advertise the + * "est" flag in the cpuid capability flags, we look for a specific + * CPU model and stepping, and we need to have the exact model name in + * our voltage tables. That is, be paranoid about not releasing + * someone's valuable magic smoke. + */ +static int __init centrino_init(void) +{ + struct cpuinfo_x86 *cpu = cpu_data; + const struct cpu_model *model; + unsigned l, h; + int dummy, ecx; + + /* backport info: we can't use cpu_has here, as cpuid(1) isn't + * stored in 2.4 + */ + cpuid(1,&dummy,&dummy,&ecx,&dummy); + if (!(ecx & (1<<7))) + return -ENODEV; + + /* Only Intel Pentium M stepping 5 for now - add new CPUs as + they appear after making sure they use PERF_CTL in the same + way. */ + if (cpu->x86_vendor != X86_VENDOR_INTEL || + cpu->x86 != 6 || + cpu->x86_model != 9 || + cpu->x86_mask != 5) { + printk(KERN_INFO PFX "found unsupported CPU with Enhanced SpeedStep: " + "send /proc/cpuinfo to " MAINTAINER "\n"); + return -ENODEV; + } + + /* Check to see if Enhanced SpeedStep is enabled, and try to + enable it if not. */ + rdmsr(MSR_IA32_MISC_ENABLE, l, h); + + if (!(l & (1<<16))) { + l |= (1<<16); + wrmsr(MSR_IA32_MISC_ENABLE, l, h); + + /* check to see if it stuck */ + rdmsr(MSR_IA32_MISC_ENABLE, l, h); + if (!(l & (1<<16))) { + printk(KERN_INFO PFX "couldn't enable Enhanced SpeedStep\n"); + return -ENODEV; + } + } + + for(model = models; model->model_name != NULL; model++) + if (strcmp(cpu->x86_model_id, model->model_name) == 0) + break; + if (model->model_name == NULL) { + printk(KERN_INFO PFX "no support for CPU model \"%s\": " + "send /proc/cpuinfo to " MAINTAINER "\n", + cpu->x86_model_id); + return -ENOENT; + } + + centrino_model = model; + + printk(KERN_INFO PFX "found \"%s\": max frequency: %dkHz\n", + model->model_name, model->max_freq); + + return cpufreq_register_driver(¢rino_driver); +} + +static void __exit centrino_exit(void) +{ + cpufreq_unregister_driver(¢rino_driver); +} + +MODULE_AUTHOR ("Jeremy Fitzhardinge "); +MODULE_DESCRIPTION ("Enhanced SpeedStep driver for Intel Pentium M processors."); +MODULE_LICENSE ("GPL"); + +module_init(centrino_init); +module_exit(centrino_exit); diff -urN linux-2.4.23-pre8/arch/i386/kernel/speedstep-ich.c linux-2.4.23-pre8-pac1/arch/i386/kernel/speedstep-ich.c --- linux-2.4.23-pre8/arch/i386/kernel/speedstep-ich.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/arch/i386/kernel/speedstep-ich.c 2003-10-24 14:31:25.000000000 +0200 @@ -0,0 +1,363 @@ +/* + * (C) 2001 Dave Jones, Arjan van de ven. + * (C) 2002 - 2003 Dominik Brodowski + * + * Licensed under the terms of the GNU GPL License version 2. + * Based upon reverse engineered information, and on Intel documentation + * for chipsets ICH2-M and ICH3-M. + * + * Many thanks to Ducrot Bruno for finding and fixing the last + * "missing link" for ICH2-M/ICH3-M support, and to Thomas Winkler + * for extensive testing. + * + * BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous* + */ + + +/********************************************************************* + * SPEEDSTEP - DEFINITIONS * + *********************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include "speedstep-lib.h" + + +/* speedstep_chipset: + * It is necessary to know which chipset is used. As accesses to + * this device occur at various places in this module, we need a + * static struct pci_dev * pointing to that device. + */ +static struct pci_dev *speedstep_chipset_dev; + + +/* speedstep_processor + */ +static unsigned int speedstep_processor = 0; + + +/* + * There are only two frequency states for each processor. Values + * are in kHz for the time being. + */ +static struct cpufreq_frequency_table speedstep_freqs[] = { + {SPEEDSTEP_HIGH, 0}, + {SPEEDSTEP_LOW, 0}, + {0, CPUFREQ_TABLE_END}, +}; + + +/* DEBUG + * Define it if you want verbose debug output, e.g. for bug reporting + */ +//#define SPEEDSTEP_DEBUG + +#ifdef SPEEDSTEP_DEBUG +#define dprintk(msg...) printk(msg) +#else +#define dprintk(msg...) do { } while(0) +#endif + + +/** + * speedstep_set_state - set the SpeedStep state + * @state: new processor frequency state (SPEEDSTEP_LOW or SPEEDSTEP_HIGH) + * + * Tries to change the SpeedStep state. + */ +static void speedstep_set_state (unsigned int state, unsigned int notify) +{ + u32 pmbase; + u8 pm2_blk; + u8 value; + unsigned long flags; + struct cpufreq_freqs freqs; + + if (!speedstep_chipset_dev || (state > 0x1)) + return; + + freqs.old = speedstep_get_processor_frequency(speedstep_processor); + freqs.new = speedstep_freqs[state].frequency; + freqs.cpu = 0; /* speedstep.c is UP only driver */ + + if (notify) + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + + /* get PMBASE */ + pci_read_config_dword(speedstep_chipset_dev, 0x40, &pmbase); + if (!(pmbase & 0x01)) + { + printk(KERN_ERR "cpufreq: could not find speedstep register\n"); + return; + } + + pmbase &= 0xFFFFFFFE; + if (!pmbase) { + printk(KERN_ERR "cpufreq: could not find speedstep register\n"); + return; + } + + /* Disable IRQs */ + local_irq_save(flags); + + /* read state */ + value = inb(pmbase + 0x50); + + dprintk(KERN_DEBUG "cpufreq: read at pmbase 0x%x + 0x50 returned 0x%x\n", pmbase, value); + + /* write new state */ + value &= 0xFE; + value |= state; + + dprintk(KERN_DEBUG "cpufreq: writing 0x%x to pmbase 0x%x + 0x50\n", value, pmbase); + + /* Disable bus master arbitration */ + pm2_blk = inb(pmbase + 0x20); + pm2_blk |= 0x01; + outb(pm2_blk, (pmbase + 0x20)); + + /* Actual transition */ + outb(value, (pmbase + 0x50)); + + /* Restore bus master arbitration */ + pm2_blk &= 0xfe; + outb(pm2_blk, (pmbase + 0x20)); + + /* check if transition was successful */ + value = inb(pmbase + 0x50); + + /* Enable IRQs */ + local_irq_restore(flags); + + dprintk(KERN_DEBUG "cpufreq: read at pmbase 0x%x + 0x50 returned 0x%x\n", pmbase, value); + + if (state == (value & 0x1)) { + dprintk (KERN_INFO "cpufreq: change to %u MHz succeeded\n", (speedstep_get_processor_frequency(speedstep_processor) / 1000)); + } else { + printk (KERN_ERR "cpufreq: change failed - I/O error\n"); + } + + if (notify) + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + + return; +} + + +/** + * speedstep_activate - activate SpeedStep control in the chipset + * + * Tries to activate the SpeedStep status and control registers. + * Returns -EINVAL on an unsupported chipset, and zero on success. + */ +static int speedstep_activate (void) +{ + u16 value = 0; + + if (!speedstep_chipset_dev) + return -EINVAL; + + pci_read_config_word(speedstep_chipset_dev, + 0x00A0, &value); + if (!(value & 0x08)) { + value |= 0x08; + dprintk(KERN_DEBUG "cpufreq: activating SpeedStep (TM) registers\n"); + pci_write_config_word(speedstep_chipset_dev, + 0x00A0, value); + } + + return 0; +} + + +/** + * speedstep_detect_chipset - detect the Southbridge which contains SpeedStep logic + * + * Detects PIIX4, ICH2-M and ICH3-M so far. The pci_dev points to + * the LPC bridge / PM module which contains all power-management + * functions. Returns the SPEEDSTEP_CHIPSET_-number for the detected + * chipset, or zero on failure. + */ +static unsigned int speedstep_detect_chipset (void) +{ + speedstep_chipset_dev = pci_find_subsys(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82801DB_12, + PCI_ANY_ID, + PCI_ANY_ID, + NULL); + if (speedstep_chipset_dev) + return 4; /* 4-M */ + + speedstep_chipset_dev = pci_find_subsys(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82801CA_12, + PCI_ANY_ID, + PCI_ANY_ID, + NULL); + if (speedstep_chipset_dev) + return 3; /* 3-M */ + + + speedstep_chipset_dev = pci_find_subsys(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82801BA_10, + PCI_ANY_ID, + PCI_ANY_ID, + NULL); + if (speedstep_chipset_dev) { + /* speedstep.c causes lockups on Dell Inspirons 8000 and + * 8100 which use a pretty old revision of the 82815 + * host brige. Abort on these systems. + */ + static struct pci_dev *hostbridge; + u8 rev = 0; + + hostbridge = pci_find_subsys(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82815_MC, + PCI_ANY_ID, + PCI_ANY_ID, + NULL); + + if (!hostbridge) + return 2; /* 2-M */ + + pci_read_config_byte(hostbridge, PCI_REVISION_ID, &rev); + if (rev < 5) { + dprintk(KERN_INFO "cpufreq: hostbridge does not support speedstep\n"); + speedstep_chipset_dev = NULL; + return 0; + } + + return 2; /* 2-M */ + } + + return 0; +} + + +/** + * speedstep_setpolicy - set a new CPUFreq policy + * @policy: new policy + * + * Sets a new CPUFreq policy. + */ +static int speedstep_target (struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + unsigned int newstate = 0; + + if (cpufreq_frequency_table_target(policy, &speedstep_freqs[0], target_freq, relation, &newstate)) + return -EINVAL; + + speedstep_set_state(newstate, 1); + + return 0; +} + + +/** + * speedstep_verify - verifies a new CPUFreq policy + * @freq: new policy + * + * Limit must be within speedstep_low_freq and speedstep_high_freq, with + * at least one border included. + */ +static int speedstep_verify (struct cpufreq_policy *policy) +{ + return cpufreq_frequency_table_verify(policy, &speedstep_freqs[0]); +} + + +static int speedstep_cpu_init(struct cpufreq_policy *policy) +{ + int result = 0; + unsigned int speed; + + /* capability check */ + if (policy->cpu != 0) + return -ENODEV; + + /* detect low and high frequency */ + result = speedstep_get_freqs(speedstep_processor, + &speedstep_freqs[SPEEDSTEP_LOW].frequency, + &speedstep_freqs[SPEEDSTEP_HIGH].frequency, + &speedstep_set_state); + if (result) + return result; + + /* get current speed setting */ + speed = speedstep_get_processor_frequency(speedstep_processor); + if (!speed) + return -EIO; + + dprintk(KERN_INFO "cpufreq: currently at %s speed setting - %i MHz\n", + (speed == speedstep_freqs[SPEEDSTEP_LOW].frequency) ? "low" : "high", + (speed / 1000)); + + /* cpuinfo and default policy values */ + policy->policy = (speed == speedstep_freqs[SPEEDSTEP_LOW].frequency) ? + CPUFREQ_POLICY_POWERSAVE : CPUFREQ_POLICY_PERFORMANCE; + policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; + policy->cur = speed; + + return cpufreq_frequency_table_cpuinfo(policy, &speedstep_freqs[0]); +} + + +static struct cpufreq_driver speedstep_driver = { + .name = "speedstep", + .verify = speedstep_verify, + .target = speedstep_target, + .init = speedstep_cpu_init, +}; + + +/** + * speedstep_init - initializes the SpeedStep CPUFreq driver + * + * Initializes the SpeedStep support. Returns -ENODEV on unsupported + * devices, -EINVAL on problems during initiatization, and zero on + * success. + */ +static int __init speedstep_init(void) +{ + /* detect processor */ + speedstep_processor = speedstep_detect_processor(); + if (!speedstep_processor) + return -ENODEV; + + /* detect chipset */ + if (!speedstep_detect_chipset()) { + printk(KERN_INFO "cpufreq: Intel(R) SpeedStep(TM) for this chipset not (yet) available.\n"); + return -ENODEV; + } + + /* activate speedstep support */ + if (speedstep_activate()) + return -EINVAL; + + return cpufreq_register_driver(&speedstep_driver); +} + + +/** + * speedstep_exit - unregisters SpeedStep support + * + * Unregisters SpeedStep support. + */ +static void __exit speedstep_exit(void) +{ + cpufreq_unregister_driver(&speedstep_driver); +} + + +MODULE_AUTHOR ("Dave Jones , Dominik Brodowski "); +MODULE_DESCRIPTION ("Speedstep driver for Intel mobile processors on chipsets with ICH-M southbridges."); +MODULE_LICENSE ("GPL"); + +module_init(speedstep_init); +module_exit(speedstep_exit); diff -urN linux-2.4.23-pre8/arch/i386/kernel/speedstep-lib.c linux-2.4.23-pre8-pac1/arch/i386/kernel/speedstep-lib.c --- linux-2.4.23-pre8/arch/i386/kernel/speedstep-lib.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/arch/i386/kernel/speedstep-lib.c 2003-10-24 14:31:25.000000000 +0200 @@ -0,0 +1,275 @@ +/* + * (C) 2002 - 2003 Dominik Brodowski + * + * Licensed under the terms of the GNU GPL License version 2. + * + * Library for common functions for Intel SpeedStep v.1 and v.2 support + * + * BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous* + */ + +#include +#include +#include +#include +#include +#include + +#include +#include "speedstep-lib.h" + + +/* DEBUG + * Define it if you want verbose debug output, e.g. for bug reporting + */ +//#define SPEEDSTEP_DEBUG + +#ifdef SPEEDSTEP_DEBUG +#define dprintk(msg...) printk(msg) +#else +#define dprintk(msg...) do { } while(0) +#endif + +/********************************************************************* + * GET PROCESSOR CORE SPEED IN KHZ * + *********************************************************************/ + +static unsigned int pentium3_get_frequency (unsigned int processor) +{ + /* See table 14 of p3_ds.pdf and table 22 of 29834003.pdf */ + struct { + unsigned int ratio; /* Frequency Multiplier (x10) */ + u8 bitmap; /* power on configuration bits + [27, 25:22] (in MSR 0x2a) */ + } msr_decode_mult [] = { + { 30, 0x01 }, + { 35, 0x05 }, + { 40, 0x02 }, + { 45, 0x06 }, + { 50, 0x00 }, + { 55, 0x04 }, + { 60, 0x0b }, + { 65, 0x0f }, + { 70, 0x09 }, + { 75, 0x0d }, + { 80, 0x0a }, + { 85, 0x26 }, + { 90, 0x20 }, + { 100, 0x2b }, + { 0, 0xff } /* error or unknown value */ + }; + + /* PIII(-M) FSB settings: see table b1-b of 24547206.pdf */ + struct { + unsigned int value; /* Front Side Bus speed in MHz */ + u8 bitmap; /* power on configuration bits [18: 19] + (in MSR 0x2a) */ + } msr_decode_fsb [] = { + { 66, 0x0 }, + { 100, 0x2 }, + { 133, 0x1 }, + { 0, 0xff} + }; + + u32 msr_lo, msr_tmp; + int i = 0, j = 0; + + /* read MSR 0x2a - we only need the low 32 bits */ + rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_tmp); + dprintk(KERN_DEBUG "speedstep-lib: P3 - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n", msr_lo, msr_tmp); + msr_tmp = msr_lo; + + /* decode the FSB */ + msr_tmp &= 0x00c0000; + msr_tmp >>= 18; + while (msr_tmp != msr_decode_fsb[i].bitmap) { + if (msr_decode_fsb[i].bitmap == 0xff) + return 0; + i++; + } + + /* decode the multiplier */ + if (processor == SPEEDSTEP_PROCESSOR_PIII_C_EARLY) + msr_lo &= 0x03c00000; + else + msr_lo &= 0x0bc00000; + msr_lo >>= 22; + while (msr_lo != msr_decode_mult[j].bitmap) { + if (msr_decode_mult[j].bitmap == 0xff) + return 0; + j++; + } + + return (msr_decode_mult[j].ratio * msr_decode_fsb[i].value * 100); +} + + +static unsigned int pentium4_get_frequency(void) +{ + u32 msr_lo, msr_hi; + + rdmsr(0x2c, msr_lo, msr_hi); + + dprintk(KERN_DEBUG "speedstep-lib: P4 - MSR_EBC_FREQUENCY_ID: 0x%x 0x%x\n", msr_lo, msr_hi); + + msr_lo >>= 24; + return (msr_lo * 100000); +} + + +unsigned int speedstep_get_processor_frequency(unsigned int processor) +{ + switch (processor) { + case SPEEDSTEP_PROCESSOR_P4M: + return pentium4_get_frequency(); + case SPEEDSTEP_PROCESSOR_PIII_T: + case SPEEDSTEP_PROCESSOR_PIII_C: + case SPEEDSTEP_PROCESSOR_PIII_C_EARLY: + return pentium3_get_frequency(processor); + default: + return 0; + }; + return 0; +} +EXPORT_SYMBOL_GPL(speedstep_get_processor_frequency); + + +/********************************************************************* + * DETECT SPEEDSTEP-CAPABLE PROCESSOR * + *********************************************************************/ + +unsigned int speedstep_detect_processor (void) +{ + struct cpuinfo_x86 *c = cpu_data; + u32 ebx, msr_lo, msr_hi; + + if ((c->x86_vendor != X86_VENDOR_INTEL) || + ((c->x86 != 6) && (c->x86 != 0xF))) + return 0; + + if (c->x86 == 0xF) { + /* Intel Mobile Pentium 4-M + * or Intel Mobile Pentium 4 with 533 MHz FSB */ + if (c->x86_model != 2) + return 0; + + if ((c->x86_mask != 4) && /* B-stepping [M-P4-M] */ + (c->x86_mask != 7) && /* C-stepping [M-P4-M] */ + (c->x86_mask != 9)) /* D-stepping [M-P4-M or M-P4/533] */ + return 0; + + ebx = cpuid_ebx(0x00000001); + ebx &= 0x000000FF; + if ((ebx != 0x0e) && (ebx != 0x0f)) + return 0; + + return SPEEDSTEP_PROCESSOR_P4M; + } + + switch (c->x86_model) { + case 0x0B: /* Intel PIII [Tualatin] */ + /* cpuid_ebx(1) is 0x04 for desktop PIII, + 0x06 for mobile PIII-M */ + ebx = cpuid_ebx(0x00000001); + + ebx &= 0x000000FF; + if (ebx != 0x06) + return 0; + + /* So far all PIII-M processors support SpeedStep. See + * Intel's 24540640.pdf of June 2003 + */ + + return SPEEDSTEP_PROCESSOR_PIII_T; + + case 0x08: /* Intel PIII [Coppermine] */ + + /* all mobile PIII Coppermines have FSB 100 MHz + * ==> sort out a few desktop PIIIs. */ + rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_hi); + dprintk(KERN_DEBUG "cpufreq: Coppermine: MSR_IA32_EBL_CR_POWERON is 0x%x, 0x%x\n", msr_lo, msr_hi); + msr_lo &= 0x00c0000; + if (msr_lo != 0x0080000) + return 0; + + /* + * If the processor is a mobile version, + * platform ID has bit 50 set + * it has SpeedStep technology if either + * bit 56 or 57 is set + */ + rdmsr(MSR_IA32_PLATFORM_ID, msr_lo, msr_hi); + dprintk(KERN_DEBUG "cpufreq: Coppermine: MSR_IA32_PLATFORM ID is 0x%x, 0x%x\n", msr_lo, msr_hi); + if ((msr_hi & (1<<18)) && (msr_hi & (3<<24))) { + if (c->x86_mask == 0x01) + return SPEEDSTEP_PROCESSOR_PIII_C_EARLY; + else + return SPEEDSTEP_PROCESSOR_PIII_C; + } + + default: + return 0; + } +} +EXPORT_SYMBOL_GPL(speedstep_detect_processor); + + +/********************************************************************* + * DETECT SPEEDSTEP SPEEDS * + *********************************************************************/ + +unsigned int speedstep_get_freqs(unsigned int processor, + unsigned int *low_speed, + unsigned int *high_speed, + void (*set_state) (unsigned int state, + unsigned int notify) + ) +{ + unsigned int prev_speed; + unsigned int ret = 0; + unsigned long flags; + + if ((!processor) || (!low_speed) || (!high_speed) || (!set_state)) + return EINVAL; + + /* get current speed */ + prev_speed = speedstep_get_processor_frequency(processor); + if (!prev_speed) + return EIO; + + local_irq_save(flags); + + /* switch to low state */ + set_state(SPEEDSTEP_LOW, 0); + *low_speed = speedstep_get_processor_frequency(processor); + if (!*low_speed) { + ret = EIO; + goto out; + } + + /* switch to high state */ + set_state(SPEEDSTEP_HIGH, 0); + *high_speed = speedstep_get_processor_frequency(processor); + if (!*high_speed) { + ret = EIO; + goto out; + } + + if (*low_speed == *high_speed) { + ret = ENODEV; + goto out; + } + + /* switch to previous state, if necessary */ + if (*high_speed != prev_speed) + set_state(SPEEDSTEP_LOW, 0); + + out: + local_irq_restore(flags); + return (ret); +} +EXPORT_SYMBOL_GPL(speedstep_get_freqs); + +MODULE_AUTHOR ("Dominik Brodowski "); +MODULE_DESCRIPTION ("Library for Intel SpeedStep 1 or 2 cpufreq drivers."); +MODULE_LICENSE ("GPL"); diff -urN linux-2.4.23-pre8/arch/i386/kernel/speedstep-lib.h linux-2.4.23-pre8-pac1/arch/i386/kernel/speedstep-lib.h --- linux-2.4.23-pre8/arch/i386/kernel/speedstep-lib.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/arch/i386/kernel/speedstep-lib.h 2003-10-24 14:31:25.000000000 +0200 @@ -0,0 +1,41 @@ +/* + * (C) 2002 - 2003 Dominik Brodowski + * + * Licensed under the terms of the GNU GPL License version 2. + * + * Library for common functions for Intel SpeedStep v.1 and v.2 support + * + * BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous* + */ + + + +/* processors */ + +#define SPEEDSTEP_PROCESSOR_PIII_C_EARLY 0x00000001 /* Coppermine core */ +#define SPEEDSTEP_PROCESSOR_PIII_C 0x00000002 /* Coppermine core */ +#define SPEEDSTEP_PROCESSOR_PIII_T 0x00000003 /* Tualatin core */ +#define SPEEDSTEP_PROCESSOR_P4M 0x00000004 /* P4-M with 100 MHz FSB */ + +/* speedstep states -- only two of them */ + +#define SPEEDSTEP_HIGH 0x00000000 +#define SPEEDSTEP_LOW 0x00000001 + + +/* detect a speedstep-capable processor */ +extern unsigned int speedstep_detect_processor (void); + +/* detect the current speed (in khz) of the processor */ +extern unsigned int speedstep_get_processor_frequency(unsigned int processor); + + +/* detect the low and high speeds of the processor. The callback + * set_state"'s first argument is either SPEEDSTEP_HIGH or + * SPEEDSTEP_LOW; the second argument is zero so that no + * cpufreq_notify_transition calls are initiated. + */ +extern unsigned int speedstep_get_freqs(unsigned int processor, + unsigned int *low_speed, + unsigned int *high_speed, + void (*set_state) (unsigned int state, unsigned int notify)); diff -urN linux-2.4.23-pre8/arch/i386/kernel/time.c linux-2.4.23-pre8-pac1/arch/i386/kernel/time.c --- linux-2.4.23-pre8/arch/i386/kernel/time.c 2003-06-13 16:51:29.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/i386/kernel/time.c 2003-10-24 14:31:25.000000000 +0200 @@ -55,6 +55,7 @@ #include #include #include +#include #include #include @@ -833,6 +834,49 @@ return 0; } +#ifdef CONFIG_CPU_FREQ +static unsigned int ref_freq = 0; +static unsigned long loops_per_jiffy_ref = 0; + +#ifndef CONFIG_SMP +static unsigned long fast_gettimeoffset_ref = 0; +static unsigned long cpu_khz_ref = 0; +#endif + +static int +time_cpufreq_notifier(struct notifier_block *nb, unsigned long val, + void *data) +{ + struct cpufreq_freqs *freq = data; + + if (!ref_freq) { + ref_freq = freq->old; + loops_per_jiffy_ref = cpu_data[freq->cpu].loops_per_jiffy; +#ifndef CONFIG_SMP + fast_gettimeoffset_ref = fast_gettimeoffset_quotient; + cpu_khz_ref = cpu_khz; +#endif + } + + if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) || + (val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) { + cpu_data[freq->cpu].loops_per_jiffy = cpufreq_scale(loops_per_jiffy_ref, ref_freq, freq->new); +#ifndef CONFIG_SMP + if (use_tsc) { + fast_gettimeoffset_quotient = cpufreq_scale(fast_gettimeoffset_ref, freq->new, ref_freq); + cpu_khz = cpufreq_scale(cpu_khz_ref, ref_freq, freq->new); + } +#endif + } + + return 0; +} + +static struct notifier_block time_cpufreq_notifier_block = { + .notifier_call = time_cpufreq_notifier +}; +#endif + void __init time_init(void) { extern int x86_udelay_tsc; @@ -901,6 +945,9 @@ "0" (eax), "1" (edx)); printk("Detected %lu.%03lu MHz processor.\n", cpu_khz / 1000, cpu_khz % 1000); } +#if defined(CONFIG_CPU_FREQ) + cpufreq_register_notifier(&time_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); +#endif } } diff -urN linux-2.4.23-pre8/arch/i386/kernel/traps.c linux-2.4.23-pre8-pac1/arch/i386/kernel/traps.c --- linux-2.4.23-pre8/arch/i386/kernel/traps.c 2002-11-29 00:53:09.000000000 +0100 +++ linux-2.4.23-pre8-pac1/arch/i386/kernel/traps.c 2003-10-24 14:31:25.000000000 +0200 @@ -284,6 +284,20 @@ void die(const char * str, struct pt_regs * regs, long err) { +#ifdef CONFIG_PNPBIOS + if (regs->xcs == 0x60 || regs->xcs == 0x68) + { + extern u32 pnp_bios_fault_eip, pnp_bios_fault_esp; + extern u32 pnp_bios_is_utter_crap; + pnp_bios_is_utter_crap = 1; + printk(KERN_CRIT "PNPBIOS fault.. attempting recovery.\n"); + __asm__ volatile( + "movl %0, %%esp\n\t" + "jmp %1\n\t" + : "=a" (pnp_bios_fault_esp), "=b" (pnp_bios_fault_eip)); + panic("do_trap: can't hit this"); + } +#endif console_verbose(); spin_lock_irq(&die_lock); bust_spinlocks(1); diff -urN linux-2.4.23-pre8/arch/i386/math-emu/fpu_system.h linux-2.4.23-pre8-pac1/arch/i386/math-emu/fpu_system.h --- linux-2.4.23-pre8/arch/i386/math-emu/fpu_system.h 2000-12-29 23:07:20.000000000 +0100 +++ linux-2.4.23-pre8-pac1/arch/i386/math-emu/fpu_system.h 2003-10-24 14:31:25.000000000 +0200 @@ -20,7 +20,7 @@ of the stack frame of math_emulate() */ #define SETUP_DATA_AREA(arg) FPU_info = (struct info *) &arg -#define LDT_DESCRIPTOR(s) (((struct desc_struct *)current->mm->context.segments)[(s) >> 3]) +#define LDT_DESCRIPTOR(s) (((struct desc_struct *)current->mm->context.ldt)[(s) >> 3]) #define SEG_D_SIZE(x) ((x).b & (3 << 21)) #define SEG_G_BIT(x) ((x).b & (1 << 23)) #define SEG_GRANULARITY(x) (((x).b & (1 << 23)) ? 4096 : 1) diff -urN linux-2.4.23-pre8/arch/i386/mm/fault.c linux-2.4.23-pre8-pac1/arch/i386/mm/fault.c --- linux-2.4.23-pre8/arch/i386/mm/fault.c 2002-11-29 00:53:09.000000000 +0100 +++ linux-2.4.23-pre8-pac1/arch/i386/mm/fault.c 2003-10-24 14:31:25.000000000 +0200 @@ -76,9 +76,7 @@ return 1; check_stack: - if (!(vma->vm_flags & VM_GROWSDOWN)) - goto bad_area; - if (expand_stack(vma, start) == 0) + if (!expand_stack(vma, start)) goto good_area; bad_area: diff -urN linux-2.4.23-pre8/arch/i386/mm/init.c linux-2.4.23-pre8-pac1/arch/i386/mm/init.c --- linux-2.4.23-pre8/arch/i386/mm/init.c 2003-06-13 16:51:29.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/i386/mm/init.c 2003-10-24 14:31:25.000000000 +0200 @@ -510,7 +510,15 @@ if (!mem_map) BUG(); - +#ifdef CONFIG_HIGHMEM + /* check that fixmap and pkmap do not overlap */ + if (PKMAP_BASE+LAST_PKMAP*PAGE_SIZE >= FIXADDR_START) { + printk(KERN_ERR "fixmap and kmap areas overlap - this will crash\n"); + printk(KERN_ERR "pkstart: %lxh pkend: %lxh fixstart %lxh\n", + PKMAP_BASE, PKMAP_BASE+LAST_PKMAP*PAGE_SIZE, FIXADDR_START); + BUG(); + } +#endif set_max_mapnr_init(); high_memory = (void *) __va(max_low_pfn * PAGE_SIZE); diff -urN linux-2.4.23-pre8/arch/ia64/defconfig linux-2.4.23-pre8-pac1/arch/ia64/defconfig --- linux-2.4.23-pre8/arch/ia64/defconfig 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/ia64/defconfig 2003-10-24 14:31:25.000000000 +0200 @@ -705,6 +705,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/ia64/kernel/entry.S linux-2.4.23-pre8-pac1/arch/ia64/kernel/entry.S --- linux-2.4.23-pre8/arch/ia64/kernel/entry.S 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/ia64/kernel/entry.S 2003-10-24 14:31:25.000000000 +0200 @@ -1411,7 +1411,7 @@ data8 ia64_ni_syscall data8 ia64_ni_syscall // 1245 data8 ia64_ni_syscall - data8 ia64_ni_syscall + data8 sys_semtimedop data8 ia64_ni_syscall data8 ia64_ni_syscall data8 ia64_ni_syscall // 1250 diff -urN linux-2.4.23-pre8/arch/ia64/mm/fault.c linux-2.4.23-pre8-pac1/arch/ia64/mm/fault.c --- linux-2.4.23-pre8/arch/ia64/mm/fault.c 2003-08-25 13:44:39.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/ia64/mm/fault.c 2003-10-24 14:31:25.000000000 +0200 @@ -154,8 +154,6 @@ check_expansion: if (!(prev_vma && (prev_vma->vm_flags & VM_GROWSUP) && (address == prev_vma->vm_end))) { - if (!(vma->vm_flags & VM_GROWSDOWN)) - goto bad_area; if (rgn_index(address) != rgn_index(vma->vm_start) || rgn_offset(address) >= RGN_MAP_LIMIT) goto bad_area; diff -urN linux-2.4.23-pre8/arch/m68k/defconfig linux-2.4.23-pre8-pac1/arch/m68k/defconfig --- linux-2.4.23-pre8/arch/m68k/defconfig 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/m68k/defconfig 2003-10-24 14:31:25.000000000 +0200 @@ -228,6 +228,8 @@ # CONFIG_JOLIET is not set CONFIG_MINIX_FS=y # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG 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 diff -urN linux-2.4.23-pre8/arch/mips/defconfig linux-2.4.23-pre8-pac1/arch/mips/defconfig --- linux-2.4.23-pre8/arch/mips/defconfig 2003-08-25 13:44:39.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/mips/defconfig 2003-10-24 14:31:25.000000000 +0200 @@ -544,6 +544,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/mips/defconfig-atlas linux-2.4.23-pre8-pac1/arch/mips/defconfig-atlas --- linux-2.4.23-pre8/arch/mips/defconfig-atlas 2003-08-25 13:44:39.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/mips/defconfig-atlas 2003-10-24 14:31:25.000000000 +0200 @@ -572,6 +572,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/mips/defconfig-cobalt linux-2.4.23-pre8-pac1/arch/mips/defconfig-cobalt --- linux-2.4.23-pre8/arch/mips/defconfig-cobalt 2003-08-25 13:44:39.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/mips/defconfig-cobalt 2003-10-24 14:31:25.000000000 +0200 @@ -556,6 +556,8 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set +# CONFIG_NTFS_RW is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/mips/defconfig-ddb5476 linux-2.4.23-pre8-pac1/arch/mips/defconfig-ddb5476 --- linux-2.4.23-pre8/arch/mips/defconfig-ddb5476 2003-08-25 13:44:39.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/mips/defconfig-ddb5476 2003-10-24 14:31:25.000000000 +0200 @@ -575,6 +575,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/mips/defconfig-ddb5477 linux-2.4.23-pre8-pac1/arch/mips/defconfig-ddb5477 --- linux-2.4.23-pre8/arch/mips/defconfig-ddb5477 2003-08-25 13:44:39.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/mips/defconfig-ddb5477 2003-10-24 14:31:25.000000000 +0200 @@ -492,6 +492,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/mips/defconfig-decstation linux-2.4.23-pre8-pac1/arch/mips/defconfig-decstation --- linux-2.4.23-pre8/arch/mips/defconfig-decstation 2003-08-25 13:44:39.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/mips/defconfig-decstation 2003-10-24 14:31:25.000000000 +0200 @@ -530,6 +530,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/mips/defconfig-ev64120 linux-2.4.23-pre8-pac1/arch/mips/defconfig-ev64120 --- linux-2.4.23-pre8/arch/mips/defconfig-ev64120 2003-08-25 13:44:39.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/mips/defconfig-ev64120 2003-10-24 14:31:25.000000000 +0200 @@ -499,6 +499,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/mips/defconfig-ev96100 linux-2.4.23-pre8-pac1/arch/mips/defconfig-ev96100 --- linux-2.4.23-pre8/arch/mips/defconfig-ev96100 2003-08-25 13:44:39.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/mips/defconfig-ev96100 2003-10-24 14:31:25.000000000 +0200 @@ -496,6 +496,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/mips/defconfig-hp-lj linux-2.4.23-pre8-pac1/arch/mips/defconfig-hp-lj --- linux-2.4.23-pre8/arch/mips/defconfig-hp-lj 2003-08-25 13:44:39.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/mips/defconfig-hp-lj 2003-10-24 14:31:25.000000000 +0200 @@ -648,6 +648,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/mips/defconfig-ip22 linux-2.4.23-pre8-pac1/arch/mips/defconfig-ip22 --- linux-2.4.23-pre8/arch/mips/defconfig-ip22 2003-08-25 13:44:39.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/mips/defconfig-ip22 2003-10-24 14:31:25.000000000 +0200 @@ -567,6 +567,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/mips/defconfig-it8172 linux-2.4.23-pre8-pac1/arch/mips/defconfig-it8172 --- linux-2.4.23-pre8/arch/mips/defconfig-it8172 2003-08-25 13:44:39.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/mips/defconfig-it8172 2003-10-24 14:31:25.000000000 +0200 @@ -644,6 +644,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/mips/defconfig-ivr linux-2.4.23-pre8-pac1/arch/mips/defconfig-ivr --- linux-2.4.23-pre8/arch/mips/defconfig-ivr 2003-08-25 13:44:39.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/mips/defconfig-ivr 2003-10-24 14:31:25.000000000 +0200 @@ -592,6 +592,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/mips/defconfig-jmr3927 linux-2.4.23-pre8-pac1/arch/mips/defconfig-jmr3927 --- linux-2.4.23-pre8/arch/mips/defconfig-jmr3927 2003-08-25 13:44:39.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/mips/defconfig-jmr3927 2003-10-24 14:31:25.000000000 +0200 @@ -514,6 +514,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/mips/defconfig-malta linux-2.4.23-pre8-pac1/arch/mips/defconfig-malta --- linux-2.4.23-pre8/arch/mips/defconfig-malta 2003-08-25 13:44:39.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/mips/defconfig-malta 2003-10-24 14:31:25.000000000 +0200 @@ -568,6 +568,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/mips/defconfig-nino linux-2.4.23-pre8-pac1/arch/mips/defconfig-nino --- linux-2.4.23-pre8/arch/mips/defconfig-nino 2003-08-25 13:44:39.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/mips/defconfig-nino 2003-10-24 14:31:25.000000000 +0200 @@ -404,6 +404,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/mips/defconfig-ocelot linux-2.4.23-pre8-pac1/arch/mips/defconfig-ocelot --- linux-2.4.23-pre8/arch/mips/defconfig-ocelot 2003-08-25 13:44:39.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/mips/defconfig-ocelot 2003-10-24 14:31:25.000000000 +0200 @@ -564,6 +564,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/mips/defconfig-osprey linux-2.4.23-pre8-pac1/arch/mips/defconfig-osprey --- linux-2.4.23-pre8/arch/mips/defconfig-osprey 2003-08-25 13:44:39.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/mips/defconfig-osprey 2003-10-24 14:31:25.000000000 +0200 @@ -450,6 +450,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/mips/defconfig-pb1000 linux-2.4.23-pre8-pac1/arch/mips/defconfig-pb1000 --- linux-2.4.23-pre8/arch/mips/defconfig-pb1000 2003-08-25 13:44:39.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/mips/defconfig-pb1000 2003-10-24 14:31:25.000000000 +0200 @@ -703,6 +703,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/mips/defconfig-pb1500 linux-2.4.23-pre8-pac1/arch/mips/defconfig-pb1500 --- linux-2.4.23-pre8/arch/mips/defconfig-pb1500 2003-08-25 13:44:39.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/mips/defconfig-pb1500 2003-10-24 14:31:25.000000000 +0200 @@ -752,6 +752,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/mips/defconfig-rm200 linux-2.4.23-pre8-pac1/arch/mips/defconfig-rm200 --- linux-2.4.23-pre8/arch/mips/defconfig-rm200 2003-08-25 13:44:39.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/mips/defconfig-rm200 2003-10-24 14:31:25.000000000 +0200 @@ -395,6 +395,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/mips/defconfig-sb1250-swarm linux-2.4.23-pre8-pac1/arch/mips/defconfig-sb1250-swarm --- linux-2.4.23-pre8/arch/mips/defconfig-sb1250-swarm 2003-08-25 13:44:39.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/mips/defconfig-sb1250-swarm 2003-10-24 14:31:25.000000000 +0200 @@ -528,6 +528,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/mips/mm/fault.c linux-2.4.23-pre8-pac1/arch/mips/mm/fault.c --- linux-2.4.23-pre8/arch/mips/mm/fault.c 2003-08-25 13:44:40.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/mips/mm/fault.c 2003-10-24 14:31:25.000000000 +0200 @@ -112,8 +112,6 @@ goto bad_area; if (vma->vm_start <= address) goto good_area; - if (!(vma->vm_flags & VM_GROWSDOWN)) - goto bad_area; if (expand_stack(vma, address)) goto bad_area; /* diff -urN linux-2.4.23-pre8/arch/mips64/defconfig linux-2.4.23-pre8-pac1/arch/mips64/defconfig --- linux-2.4.23-pre8/arch/mips64/defconfig 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/mips64/defconfig 2003-10-24 14:31:25.000000000 +0200 @@ -508,6 +508,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/mips64/defconfig-atlas linux-2.4.23-pre8-pac1/arch/mips64/defconfig-atlas --- linux-2.4.23-pre8/arch/mips64/defconfig-atlas 2003-08-25 13:44:40.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/mips64/defconfig-atlas 2003-10-24 14:31:25.000000000 +0200 @@ -518,6 +518,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/mips64/defconfig-ip22 linux-2.4.23-pre8-pac1/arch/mips64/defconfig-ip22 --- linux-2.4.23-pre8/arch/mips64/defconfig-ip22 2003-08-25 13:44:40.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/mips64/defconfig-ip22 2003-10-24 14:31:25.000000000 +0200 @@ -561,6 +561,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/mips64/defconfig-ip27 linux-2.4.23-pre8-pac1/arch/mips64/defconfig-ip27 --- linux-2.4.23-pre8/arch/mips64/defconfig-ip27 2003-08-25 13:44:40.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/mips64/defconfig-ip27 2003-10-24 14:31:25.000000000 +0200 @@ -507,6 +507,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/mips64/defconfig-malta linux-2.4.23-pre8-pac1/arch/mips64/defconfig-malta --- linux-2.4.23-pre8/arch/mips64/defconfig-malta 2003-08-25 13:44:40.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/mips64/defconfig-malta 2003-10-24 14:31:25.000000000 +0200 @@ -521,6 +521,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/mips64/defconfig-sb1250-swarm linux-2.4.23-pre8-pac1/arch/mips64/defconfig-sb1250-swarm --- linux-2.4.23-pre8/arch/mips64/defconfig-sb1250-swarm 2003-08-25 13:44:40.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/mips64/defconfig-sb1250-swarm 2003-10-24 14:31:25.000000000 +0200 @@ -493,6 +493,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/mips64/kernel/ioctl32.c linux-2.4.23-pre8-pac1/arch/mips64/kernel/ioctl32.c --- linux-2.4.23-pre8/arch/mips64/kernel/ioctl32.c 2003-08-25 13:44:40.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/mips64/kernel/ioctl32.c 2003-10-24 14:31:25.000000000 +0200 @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -1228,6 +1229,22 @@ IOCTL32_DEFAULT(SBPROF_ZBWAITFULL), #endif /* CONFIG_SIBYTE_TBPROF */ +#if defined(CONFIG_BLK_DEV_DM) || defined(CONFIG_BLK_DEV_DM_MODULE) + IOCTL32_DEFAULT(DM_VERSION), + IOCTL32_DEFAULT(DM_REMOVE_ALL), + IOCTL32_DEFAULT(DM_DEV_CREATE), + IOCTL32_DEFAULT(DM_DEV_REMOVE), + IOCTL32_DEFAULT(DM_TABLE_LOAD), + IOCTL32_DEFAULT(DM_DEV_SUSPEND), + IOCTL32_DEFAULT(DM_DEV_RENAME), + IOCTL32_DEFAULT(DM_TABLE_DEPS), + IOCTL32_DEFAULT(DM_DEV_STATUS), + IOCTL32_DEFAULT(DM_TABLE_STATUS), + IOCTL32_DEFAULT(DM_DEV_WAIT), + IOCTL32_DEFAULT(DM_LIST_DEVICES), + IOCTL32_DEFAULT(DM_TABLE_CLEAR), +#endif /* CONFIG_BLK_DEV_DM */ + IOCTL32_DEFAULT(MTIOCTOP), /* mtio.h ioctls */ IOCTL32_HANDLER(MTIOCGET32, mt_ioctl_trans), IOCTL32_HANDLER(MTIOCPOS32, mt_ioctl_trans), diff -urN linux-2.4.23-pre8/arch/mips64/mm/fault.c linux-2.4.23-pre8-pac1/arch/mips64/mm/fault.c --- linux-2.4.23-pre8/arch/mips64/mm/fault.c 2003-08-25 13:44:40.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/mips64/mm/fault.c 2003-10-24 14:31:25.000000000 +0200 @@ -135,8 +135,6 @@ goto bad_area; if (vma->vm_start <= address) goto good_area; - if (!(vma->vm_flags & VM_GROWSDOWN)) - goto bad_area; if (expand_stack(vma, address)) goto bad_area; /* diff -urN linux-2.4.23-pre8/arch/parisc/config.in linux-2.4.23-pre8-pac1/arch/parisc/config.in --- linux-2.4.23-pre8/arch/parisc/config.in 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/parisc/config.in 2003-10-24 14:31:25.000000000 +0200 @@ -51,12 +51,9 @@ bool 'Chassis LCD and LED support' CONFIG_CHASSIS_LCD_LED -bool 'Kernel Debugger support' CONFIG_KWDB -# define_bool CONFIG_KWDB n - bool 'U2/Uturn I/O MMU' CONFIG_IOMMU_CCIO bool 'VSC/GSC/HSC bus support' CONFIG_GSC -dep_bool ' Lasi I/O support' CONFIG_GSC_LASI $CONFIG_GSC +dep_bool ' Asp/Lasi I/O support' CONFIG_GSC_LASI $CONFIG_GSC dep_bool ' Wax I/O support' CONFIG_GSC_WAX $CONFIG_GSC dep_bool 'EISA support' CONFIG_EISA $CONFIG_GSC @@ -198,6 +195,7 @@ #bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ +bool 'Debug spinlocks' CONFIG_DEBUG_SPINLOCK int 'Kernel messages buffer length shift (0 = default)' CONFIG_LOG_BUF_SHIFT 0 diff -urN linux-2.4.23-pre8/arch/parisc/defconfig linux-2.4.23-pre8-pac1/arch/parisc/defconfig --- linux-2.4.23-pre8/arch/parisc/defconfig 2003-06-13 16:51:31.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/parisc/defconfig 2003-10-24 14:31:25.000000000 +0200 @@ -615,6 +615,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/parisc/kernel/ioctl32.c linux-2.4.23-pre8-pac1/arch/parisc/kernel/ioctl32.c --- linux-2.4.23-pre8/arch/parisc/kernel/ioctl32.c 2003-08-25 13:44:40.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/parisc/kernel/ioctl32.c 2003-10-24 14:31:25.000000000 +0200 @@ -55,6 +55,7 @@ #define max max */ #include #endif /* LVM */ +#include #include /* Ugly hack. */ @@ -3423,6 +3424,22 @@ COMPATIBLE_IOCTL(LV_BMAP) COMPATIBLE_IOCTL(LV_SNAPSHOT_USE_RATE) #endif /* LVM */ +/* Device-Mapper */ +#if defined(CONFIG_BLK_DEV_DM) || defined(CONFIG_BLK_DEV_DM_MODULE) +COMPATIBLE_IOCTL(DM_VERSION) +COMPATIBLE_IOCTL(DM_REMOVE_ALL) +COMPATIBLE_IOCTL(DM_DEV_CREATE) +COMPATIBLE_IOCTL(DM_DEV_REMOVE) +COMPATIBLE_IOCTL(DM_TABLE_LOAD) +COMPATIBLE_IOCTL(DM_DEV_SUSPEND) +COMPATIBLE_IOCTL(DM_DEV_RENAME) +COMPATIBLE_IOCTL(DM_TABLE_DEPS) +COMPATIBLE_IOCTL(DM_DEV_STATUS) +COMPATIBLE_IOCTL(DM_TABLE_STATUS) +COMPATIBLE_IOCTL(DM_DEV_WAIT) +COMPATIBLE_IOCTL(DM_LIST_DEVICES) +COMPATIBLE_IOCTL(DM_TABLE_CLEAR) +#endif /* CONFIG_BLK_DEV_DM */ #if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE) COMPATIBLE_IOCTL(DRM_IOCTL_GET_MAGIC) COMPATIBLE_IOCTL(DRM_IOCTL_IRQ_BUSID) diff -urN linux-2.4.23-pre8/arch/parisc/kernel/lasimap.map linux-2.4.23-pre8-pac1/arch/parisc/kernel/lasimap.map --- linux-2.4.23-pre8/arch/parisc/kernel/lasimap.map 2000-12-05 21:29:39.000000000 +0100 +++ linux-2.4.23-pre8-pac1/arch/parisc/kernel/lasimap.map 1970-01-01 01:00:00.000000000 +0100 @@ -1,322 +0,0 @@ -# HP 712 kernel keymap. This uses 7 modifier combinations. - -keymaps 0-2,4-5,8,12 -# ie, plain, Shift, AltGr, Control, Control+Shift, Alt and Control+Alt - - -# Change the above line into -# keymaps 0-2,4-6,8,12 -# in case you want the entries -# altgr control keycode 83 = Boot -# altgr control keycode 111 = Boot -# below. -# -# In fact AltGr is used very little, and one more keymap can -# be saved by mapping AltGr to Alt (and adapting a few entries): -# keycode 100 = Alt -# -keycode 1 = F9 F19 Console_21 - control keycode 1 = F9 - alt keycode 1 = Console_9 - control alt keycode 1 = Console_9 -keycode 2 = -keycode 3 = F5 F15 Console_17 - control keycode 3 = F5 - alt keycode 3 = Console_5 - control alt keycode 3 = Console_5 -keycode 4 = F3 F13 Console_15 - control keycode 4 = F3 - alt keycode 4 = Console_3 - control alt keycode 4 = Console_3 -keycode 5 = F1 F11 Console_13 - control keycode 5 = F1 - alt keycode 5 = Console_1 - control alt keycode 5 = Console_1 -keycode 6 = F2 F12 Console_14 - control keycode 6 = F2 - alt keycode 6 = Console_2 - control alt keycode 6 = Console_2 -keycode 7 = F12 F12 Console_24 - control keycode 7 = F12 - alt keycode 7 = Console_12 - control alt keycode 7 = Console_12 -keycode 8 = -keycode 9 = F10 F20 Console_22 - control keycode 9 = F10 - alt keycode 9 = Console_10 - control alt keycode 9 = Console_10 -keycode 10 = F8 F18 Console_20 - control keycode 10 = F8 - alt keycode 10 = Console_8 - control alt keycode 10 = Console_8 -keycode 11 = F6 F16 Console_18 - control keycode 11 = F6 - alt keycode 11 = Console_6 - control alt keycode 11 = Console_6 -keycode 12 = F4 F14 Console_16 - control keycode 12 = F4 - alt keycode 12 = Console_4 - control alt keycode 12 = Console_4 -keycode 13 = Tab Tab - alt keycode 13 = Meta_Tab -keycode 14 = grave asciitilde - control keycode 14 = nul - alt keycode 14 = Meta_grave -keycode 15 = -keycode 16 = -keycode 17 = Alt -keycode 18 = Shift -keycode 19 = -keycode 20 = Control -keycode 21 = q -keycode 22 = one exclam exclam -keycode 23 = -keycode 24 = -keycode 25 = -keycode 26 = z -keycode 27 = s -keycode 28 = a - altgr keycode 28 = Hex_A -keycode 29 = w -keycode 30 = two at at -keycode 31 = -keycode 32 = -keycode 33 = c - altgr keycode 46 = Hex_C -keycode 34 = x -keycode 35 = d - altgr keycode 35 = Hex_D -keycode 36 = e - altgr keycode 36 = Hex_E -keycode 37 = four dollar -keycode 38 = three numbersign -keycode 39 = -keycode 40 = -keycode 41 = -keycode 42 = v -keycode 43 = f - altgr keycode 43 = Hex_F -keycode 44 = t -keycode 45 = r -keycode 46 = five percent -keycode 47 = -keycode 48 = -keycode 49 = n -keycode 50 = b - altgr keycode 50 = Hex_B -keycode 51 = h -keycode 52 = g -keycode 53 = y -keycode 54 = six asciicircum -keycode 55 = -keycode 56 = -keycode 57 = -keycode 58 = m -keycode 59 = j -keycode 60 = u -keycode 61 = seven ampersand -keycode 62 = eight asterisk asterisk -keycode 63 = -keycode 64 = -keycode 65 = comma less - alt keycode 65 = Meta_comma -keycode 66 = k -keycode 67 = i -keycode 68 = o -keycode 69 = zero parenright bracketright -keycode 70 = nine parenleft bracketleft -keycode 71 = -keycode 72 = -keycode 73 = period greater - control keycode 73 = Compose - alt keycode 73 = Meta_period -keycode 74 = slash question - control keycode 74 = Delete - alt keycode 53 = Meta_slash -keycode 75 = l -keycode 76 = semicolon colon - alt keycode 39 = Meta_semicolon -keycode 77 = p -keycode 78 = minus underscore -keycode 79 = -keycode 80 = -keycode 81 = -keycode 82 = apostrophe quotedbl - control keycode 82 = Control_g - alt keycode 40 = Meta_apostrophe -keycode 83 = -keycode 84 = bracketleft braceleft - control keycode 84 = Escape - alt keycode 26 = Meta_bracketleft -keycode 85 = equal plus -keycode 86 = -keycode 87 = -keycode 88 = Caps_Lock -keycode 88 = -keycode 89 = -keycode 89 = -keycode 89 = -keycode 90 = Return - alt keycode 90 = Meta_Control_m -keycode 91 = bracketright braceright asciitilde - control keycode 91 = Control_bracketright - alt keycode 91 = Meta_bracketright -keycode 92 = -keycode 93 = backslash bar - control keycode 43 = Control_backslash - alt keycode 43 = Meta_backslash -keycode 94 = -keycode 95 = -keycode 96 = -keycode 97 = -keycode 98 = -keycode 99 = -keycode 100 = -keycode 101 = -keycode 102 = BackSpace -keycode 103 = -keycode 104 = -keycode 105 = KP_1 - alt keycode 105 = Ascii_1 - altgr keycode 105 = Hex_1 -keycode 106 = -keycode 107 = KP_4 - alt keycode 107 = Ascii_4 - altgr keycode 107 = Hex_4 -keycode 108 = KP_7 - alt keycode 108 = Ascii_7 - altgr keycode 108 = Hex_7 -keycode 109 = -keycode 110 = -keycode 111 = -keycode 112 = KP_0 - alt keycode 82 = Ascii_0 - altgr keycode 82 = Hex_0 -keycode 113 = KP_Period -keycode 114 = KP_2 - alt keycode 114 = Ascii_2 - altgr keycode 114 = Hex_2 -keycode 115 = KP_5 - alt keycode 115 = Ascii_5 - altgr keycode 115 = Hex_5 -keycode 116 = KP_6 - alt keycode 116 = Ascii_6 - altgr keycode 116 = Hex_6 -keycode 117 = KP_8 - alt keycode 117 = Ascii_8 - altgr keycode 117 = Hex_8 -keycode 118 = Escape -keycode 119 = -keycode 120 = F11 -keycode 121 = KP_Add -keycode 122 = KP_3 - alt keycode 122 = Ascii_3 - altgr keycode 122 = Hex_3 -keycode 123 = KP_Subtract -keycode 124 = KP_Multiply -keycode 125 = KP_9 - alt keycode 125 = Ascii_9 - altgr keycode 125 = Hex_9 -keycode 126 = -# 131!! -keycode 127 = F7 F17 Console_19 - control keycode 127 = F7 - alt keycode 127 = Console_7 - control alt keycode 127 = Console_7 - -string F1 = "\033[[A" -string F2 = "\033[[B" -string F3 = "\033[[C" -string F4 = "\033[[D" -string F5 = "\033[[E" -string F6 = "\033[17~" -string F7 = "\033[18~" -string F8 = "\033[19~" -string F9 = "\033[20~" -string F10 = "\033[21~" -string F11 = "\033[23~" -string F12 = "\033[24~" -string F13 = "\033[25~" -string F14 = "\033[26~" -string F15 = "\033[28~" -string F16 = "\033[29~" -string F17 = "\033[31~" -string F18 = "\033[32~" -string F19 = "\033[33~" -string F20 = "\033[34~" -string Find = "\033[1~" -string Insert = "\033[2~" -string Remove = "\033[3~" -string Select = "\033[4~" -string Prior = "\033[5~" -string Next = "\033[6~" -string Macro = "\033[M" -string Pause = "\033[P" -compose '`' 'A' to 'À' -compose '`' 'a' to 'à' -compose '\'' 'A' to 'Á' -compose '\'' 'a' to 'á' -compose '^' 'A' to 'Â' -compose '^' 'a' to 'â' -compose '~' 'A' to 'Ã' -compose '~' 'a' to 'ã' -compose '"' 'A' to 'Ä' -compose '"' 'a' to 'ä' -compose 'O' 'A' to 'Å' -compose 'o' 'a' to 'å' -compose '0' 'A' to 'Å' -compose '0' 'a' to 'å' -compose 'A' 'A' to 'Å' -compose 'a' 'a' to 'å' -compose 'A' 'E' to 'Æ' -compose 'a' 'e' to 'æ' -compose ',' 'C' to 'Ç' -compose ',' 'c' to 'ç' -compose '`' 'E' to 'È' -compose '`' 'e' to 'è' -compose '\'' 'E' to 'É' -compose '\'' 'e' to 'é' -compose '^' 'E' to 'Ê' -compose '^' 'e' to 'ê' -compose '"' 'E' to 'Ë' -compose '"' 'e' to 'ë' -compose '`' 'I' to 'Ì' -compose '`' 'i' to 'ì' -compose '\'' 'I' to 'Í' -compose '\'' 'i' to 'í' -compose '^' 'I' to 'Î' -compose '^' 'i' to 'î' -compose '"' 'I' to 'Ï' -compose '"' 'i' to 'ï' -compose '-' 'D' to 'Ð' -compose '-' 'd' to 'ð' -compose '~' 'N' to 'Ñ' -compose '~' 'n' to 'ñ' -compose '`' 'O' to 'Ò' -compose '`' 'o' to 'ò' -compose '\'' 'O' to 'Ó' -compose '\'' 'o' to 'ó' -compose '^' 'O' to 'Ô' -compose '^' 'o' to 'ô' -compose '~' 'O' to 'Õ' -compose '~' 'o' to 'õ' -compose '"' 'O' to 'Ö' -compose '"' 'o' to 'ö' -compose '/' 'O' to 'Ø' -compose '/' 'o' to 'ø' -compose '`' 'U' to 'Ù' -compose '`' 'u' to 'ù' -compose '\'' 'U' to 'Ú' -compose '\'' 'u' to 'ú' -compose '^' 'U' to 'Û' -compose '^' 'u' to 'û' -compose '"' 'U' to 'Ü' -compose '"' 'u' to 'ü' -compose '\'' 'Y' to 'Ý' -compose '\'' 'y' to 'ý' -compose 'T' 'H' to 'Þ' -compose 't' 'h' to 'þ' -compose 's' 's' to 'ß' -compose '"' 'y' to 'ÿ' -compose 's' 'z' to 'ß' -compose 'i' 'j' to 'ÿ' diff -urN linux-2.4.23-pre8/arch/ppc/8xx_io/uart.c linux-2.4.23-pre8-pac1/arch/ppc/8xx_io/uart.c --- linux-2.4.23-pre8/arch/ppc/8xx_io/uart.c 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/ppc/8xx_io/uart.c 2003-10-24 14:31:25.000000000 +0200 @@ -1723,7 +1723,7 @@ #ifdef SERIAL_DEBUG_OPEN printk("rs_close ttys%d, count = %d\n", info->line, state->count); #endif - if ((tty->count == 1) && (state->count != 1)) { + if ((atomic_read(&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 diff -urN linux-2.4.23-pre8/arch/ppc/configs/IVMS8_defconfig linux-2.4.23-pre8-pac1/arch/ppc/configs/IVMS8_defconfig --- linux-2.4.23-pre8/arch/ppc/configs/IVMS8_defconfig 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/ppc/configs/IVMS8_defconfig 2003-10-24 14:31:25.000000000 +0200 @@ -440,6 +440,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/ppc/configs/SM850_defconfig linux-2.4.23-pre8-pac1/arch/ppc/configs/SM850_defconfig --- linux-2.4.23-pre8/arch/ppc/configs/SM850_defconfig 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/ppc/configs/SM850_defconfig 2003-10-24 14:31:25.000000000 +0200 @@ -404,6 +404,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/ppc/configs/SPD823TS_defconfig linux-2.4.23-pre8-pac1/arch/ppc/configs/SPD823TS_defconfig --- linux-2.4.23-pre8/arch/ppc/configs/SPD823TS_defconfig 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/ppc/configs/SPD823TS_defconfig 2003-10-24 14:31:25.000000000 +0200 @@ -403,6 +403,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/ppc/configs/TQM823L_defconfig linux-2.4.23-pre8-pac1/arch/ppc/configs/TQM823L_defconfig --- linux-2.4.23-pre8/arch/ppc/configs/TQM823L_defconfig 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/ppc/configs/TQM823L_defconfig 2003-10-24 14:31:25.000000000 +0200 @@ -404,6 +404,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/ppc/configs/TQM850L_defconfig linux-2.4.23-pre8-pac1/arch/ppc/configs/TQM850L_defconfig --- linux-2.4.23-pre8/arch/ppc/configs/TQM850L_defconfig 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/ppc/configs/TQM850L_defconfig 2003-10-24 14:31:25.000000000 +0200 @@ -404,6 +404,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/ppc/configs/TQM860L_defconfig linux-2.4.23-pre8-pac1/arch/ppc/configs/TQM860L_defconfig --- linux-2.4.23-pre8/arch/ppc/configs/TQM860L_defconfig 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/ppc/configs/TQM860L_defconfig 2003-10-24 14:31:25.000000000 +0200 @@ -441,6 +441,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/ppc/configs/apus_defconfig linux-2.4.23-pre8-pac1/arch/ppc/configs/apus_defconfig --- linux-2.4.23-pre8/arch/ppc/configs/apus_defconfig 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/ppc/configs/apus_defconfig 2003-10-24 14:31:25.000000000 +0200 @@ -724,6 +724,7 @@ CONFIG_MINIX_FS=y # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/ppc/configs/bseip_defconfig linux-2.4.23-pre8-pac1/arch/ppc/configs/bseip_defconfig --- linux-2.4.23-pre8/arch/ppc/configs/bseip_defconfig 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/ppc/configs/bseip_defconfig 2003-10-24 14:31:25.000000000 +0200 @@ -403,6 +403,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/ppc/configs/common_defconfig linux-2.4.23-pre8-pac1/arch/ppc/configs/common_defconfig --- linux-2.4.23-pre8/arch/ppc/configs/common_defconfig 2003-06-13 16:51:31.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/ppc/configs/common_defconfig 2003-10-24 14:31:25.000000000 +0200 @@ -785,6 +785,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/ppc/configs/est8260_defconfig linux-2.4.23-pre8-pac1/arch/ppc/configs/est8260_defconfig --- linux-2.4.23-pre8/arch/ppc/configs/est8260_defconfig 2003-06-13 16:51:31.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/ppc/configs/est8260_defconfig 2003-10-24 14:31:25.000000000 +0200 @@ -387,6 +387,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/ppc/configs/gemini_defconfig linux-2.4.23-pre8-pac1/arch/ppc/configs/gemini_defconfig --- linux-2.4.23-pre8/arch/ppc/configs/gemini_defconfig 2003-06-13 16:51:31.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/ppc/configs/gemini_defconfig 2003-10-24 14:31:25.000000000 +0200 @@ -488,6 +488,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/ppc/configs/ibmchrp_defconfig linux-2.4.23-pre8-pac1/arch/ppc/configs/ibmchrp_defconfig --- linux-2.4.23-pre8/arch/ppc/configs/ibmchrp_defconfig 2003-06-13 16:51:31.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/ppc/configs/ibmchrp_defconfig 2003-10-24 14:31:25.000000000 +0200 @@ -655,6 +655,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/ppc/configs/mbx_defconfig linux-2.4.23-pre8-pac1/arch/ppc/configs/mbx_defconfig --- linux-2.4.23-pre8/arch/ppc/configs/mbx_defconfig 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/ppc/configs/mbx_defconfig 2003-10-24 14:31:25.000000000 +0200 @@ -399,6 +399,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/ppc/configs/oak_defconfig linux-2.4.23-pre8-pac1/arch/ppc/configs/oak_defconfig --- linux-2.4.23-pre8/arch/ppc/configs/oak_defconfig 2003-06-13 16:51:31.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/ppc/configs/oak_defconfig 2003-10-24 14:31:25.000000000 +0200 @@ -387,6 +387,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/ppc/configs/pmac_defconfig linux-2.4.23-pre8-pac1/arch/ppc/configs/pmac_defconfig --- linux-2.4.23-pre8/arch/ppc/configs/pmac_defconfig 2003-06-13 16:51:31.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/ppc/configs/pmac_defconfig 2003-10-24 14:31:25.000000000 +0200 @@ -894,6 +894,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/ppc/configs/power3_defconfig linux-2.4.23-pre8-pac1/arch/ppc/configs/power3_defconfig --- linux-2.4.23-pre8/arch/ppc/configs/power3_defconfig 2003-06-13 16:51:31.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/ppc/configs/power3_defconfig 2003-10-24 14:31:25.000000000 +0200 @@ -625,6 +625,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/ppc/configs/rpxcllf_defconfig linux-2.4.23-pre8-pac1/arch/ppc/configs/rpxcllf_defconfig --- linux-2.4.23-pre8/arch/ppc/configs/rpxcllf_defconfig 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/ppc/configs/rpxcllf_defconfig 2003-10-24 14:31:25.000000000 +0200 @@ -438,6 +438,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/ppc/configs/rpxlite_defconfig linux-2.4.23-pre8-pac1/arch/ppc/configs/rpxlite_defconfig --- linux-2.4.23-pre8/arch/ppc/configs/rpxlite_defconfig 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/ppc/configs/rpxlite_defconfig 2003-10-24 14:31:25.000000000 +0200 @@ -438,6 +438,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/ppc/configs/walnut_defconfig linux-2.4.23-pre8-pac1/arch/ppc/configs/walnut_defconfig --- linux-2.4.23-pre8/arch/ppc/configs/walnut_defconfig 2003-08-25 13:44:40.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/ppc/configs/walnut_defconfig 2003-10-24 14:31:25.000000000 +0200 @@ -400,6 +400,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/ppc/defconfig linux-2.4.23-pre8-pac1/arch/ppc/defconfig --- linux-2.4.23-pre8/arch/ppc/defconfig 2003-06-13 16:51:31.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/ppc/defconfig 2003-10-24 14:31:25.000000000 +0200 @@ -785,6 +785,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/ppc/kernel/entry.S linux-2.4.23-pre8-pac1/arch/ppc/kernel/entry.S --- linux-2.4.23-pre8/arch/ppc/kernel/entry.S 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/ppc/kernel/entry.S 2003-10-24 14:31:25.000000000 +0200 @@ -269,7 +269,9 @@ .globl ret_from_fork ret_from_fork: +#ifdef CONFIG_SMP bl schedule_tail +#endif lwz r0,TASK_PTRACE(r2) andi. r0,r0,PT_TRACESYS bnel- syscall_trace diff -urN linux-2.4.23-pre8/arch/ppc/kernel/idle.c linux-2.4.23-pre8-pac1/arch/ppc/kernel/idle.c --- linux-2.4.23-pre8/arch/ppc/kernel/idle.c 2003-08-25 13:44:40.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/ppc/kernel/idle.c 2003-10-24 14:31:25.000000000 +0200 @@ -46,9 +46,6 @@ do_power_save = 1; /* endless loop with no priority at all */ - current->nice = 20; - current->counter = -100; - init_idle(); for (;;) { #ifdef CONFIG_SMP if (!do_power_save) { @@ -64,13 +61,12 @@ } } #endif +#ifdef CONFIG_6xx if (do_power_save && !current->need_resched) +#endif /* CONFIG_6xx */ power_save(); - - if (current->need_resched) { - schedule(); - check_pgt_cache(); - } + schedule(); + check_pgt_cache(); } return 0; } diff -urN linux-2.4.23-pre8/arch/ppc/kernel/mk_defs.c linux-2.4.23-pre8-pac1/arch/ppc/kernel/mk_defs.c --- linux-2.4.23-pre8/arch/ppc/kernel/mk_defs.c 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/ppc/kernel/mk_defs.c 2003-10-24 14:31:25.000000000 +0200 @@ -34,8 +34,7 @@ /*DEFINE(KERNELBASE, KERNELBASE);*/ DEFINE(STATE, offsetof(struct task_struct, state)); DEFINE(NEXT_TASK, offsetof(struct task_struct, next_task)); - DEFINE(COUNTER, offsetof(struct task_struct, counter)); - DEFINE(PROCESSOR, offsetof(struct task_struct, processor)); + DEFINE(PROCESSOR, offsetof(struct task_struct, cpu)); DEFINE(SIGPENDING, offsetof(struct task_struct, sigpending)); DEFINE(THREAD, offsetof(struct task_struct, thread)); DEFINE(MM, offsetof(struct task_struct, mm)); diff -urN linux-2.4.23-pre8/arch/ppc/kernel/ppc_defs.h linux-2.4.23-pre8-pac1/arch/ppc/kernel/ppc_defs.h --- linux-2.4.23-pre8/arch/ppc/kernel/ppc_defs.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/arch/ppc/kernel/ppc_defs.h 2003-10-24 14:31:25.000000000 +0200 @@ -0,0 +1,81 @@ +/* + * WARNING! This file is automatically generated - DO NOT EDIT! + */ +#define STATE 0 +#define NEXT_TASK 76 +#define PROCESSOR 32 +#define SIGPENDING 8 +#define THREAD 608 +#define MM 84 +#define ACTIVE_MM 88 +#define TASK_STRUCT_SIZE 1520 +#define KSP 0 +#define PGDIR 16 +#define LAST_SYSCALL 20 +#define PT_REGS 8 +#define PT_TRACESYS 2 +#define TASK_FLAGS 4 +#define TASK_PTRACE 24 +#define NEED_RESCHED 20 +#define THREAD_FPR0 24 +#define THREAD_FPSCR 284 +#define THREAD_VR0 288 +#define THREAD_VRSAVE 816 +#define THREAD_VSCR 800 +#define TASK_UNION_SIZE 8192 +#define STACK_FRAME_OVERHEAD 16 +#define INT_FRAME_SIZE 192 +#define GPR0 16 +#define GPR1 20 +#define GPR2 24 +#define GPR3 28 +#define GPR4 32 +#define GPR5 36 +#define GPR6 40 +#define GPR7 44 +#define GPR8 48 +#define GPR9 52 +#define GPR10 56 +#define GPR11 60 +#define GPR12 64 +#define GPR13 68 +#define GPR14 72 +#define GPR15 76 +#define GPR16 80 +#define GPR17 84 +#define GPR18 88 +#define GPR19 92 +#define GPR20 96 +#define GPR21 100 +#define GPR22 104 +#define GPR23 108 +#define GPR24 112 +#define GPR25 116 +#define GPR26 120 +#define GPR27 124 +#define GPR28 128 +#define GPR29 132 +#define GPR30 136 +#define GPR31 140 +#define _NIP 144 +#define _MSR 148 +#define _CTR 156 +#define _LINK 160 +#define _CCR 168 +#define _MQ 172 +#define _XER 164 +#define _DAR 180 +#define _DSISR 184 +#define _DEAR 180 +#define _ESR 184 +#define ORIG_GPR3 152 +#define RESULT 188 +#define TRAP 176 +#define CLONE_VM 256 +#define MM_PGD 12 +#define CPU_SPEC_ENTRY_SIZE 32 +#define CPU_SPEC_PVR_MASK 0 +#define CPU_SPEC_PVR_VALUE 4 +#define CPU_SPEC_FEATURES 12 +#define CPU_SPEC_SETUP 28 +#define NUM_USER_SEGMENTS 8 diff -urN linux-2.4.23-pre8/arch/ppc/kernel/ppc_ksyms.c linux-2.4.23-pre8-pac1/arch/ppc/kernel/ppc_ksyms.c --- linux-2.4.23-pre8/arch/ppc/kernel/ppc_ksyms.c 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/ppc/kernel/ppc_ksyms.c 2003-10-24 14:31:25.000000000 +0200 @@ -357,6 +357,8 @@ EXPORT_SYMBOL(cpm_free_handler); EXPORT_SYMBOL(m8xx_cpm_hostalloc); EXPORT_SYMBOL(m8xx_cpm_dpalloc); +#else +EXPORT_SYMBOL(local_flush_tlb_page); #endif /* CONFIG_8xx */ /* Those should really be inline */ diff -urN linux-2.4.23-pre8/arch/ppc/kernel/smp.c linux-2.4.23-pre8-pac1/arch/ppc/kernel/smp.c --- linux-2.4.23-pre8/arch/ppc/kernel/smp.c 2003-08-25 13:44:40.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/ppc/kernel/smp.c 2003-10-24 14:31:25.000000000 +0200 @@ -294,8 +294,6 @@ cpu_callin_map[0] = 1; current->processor = 0; - init_idle(); - for (i = 0; i < NR_CPUS; i++) { prof_counter[i] = 1; prof_multiplier[i] = 1; @@ -351,7 +349,8 @@ p = init_task.prev_task; if (!p) panic("No idle task for CPU %d", i); - del_from_runqueue(p); + init_idle(p, i); + unhash_process(p); init_tasks[i] = p; diff -urN linux-2.4.23-pre8/arch/ppc/mm/fault.c linux-2.4.23-pre8-pac1/arch/ppc/mm/fault.c --- linux-2.4.23-pre8/arch/ppc/mm/fault.c 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/ppc/mm/fault.c 2003-10-24 14:31:25.000000000 +0200 @@ -141,42 +141,40 @@ goto bad_area; if (vma->vm_start <= address) goto good_area; - if (!(vma->vm_flags & VM_GROWSDOWN)) - goto bad_area; - if (!is_write) - goto bad_area; - - /* - * N.B. The rs6000/xcoff ABI allows programs to access up to - * a few hundred bytes below the stack pointer. - * The kernel signal delivery code writes up to about 1.5kB - * below the stack pointer (r1) before decrementing it. - * The exec code can write slightly over 640kB to the stack - * before setting the user r1. Thus we allow the stack to - * expand to 1MB without further checks. - */ - if (address + 0x100000 < vma->vm_end) { - /* get user regs even if this fault is in kernel mode */ - struct pt_regs *uregs = current->thread.regs; - if (uregs == NULL) - goto bad_area; - - /* - * A user-mode access to an address a long way below - * the stack pointer is only valid if the instruction - * is one which would update the stack pointer to the - * address accessed if the instruction completed, - * i.e. either stwu rs,n(r1) or stwux rs,r1,rb - * (or the byte, halfword, float or double forms). - * - * If we don't check this then any write to the area - * between the last mapped region and the stack will - * expand the stack rather than segfaulting. - */ - if (address + 2048 < uregs->gpr[1] - && (!user_mode(regs) || !store_updates_sp(regs))) - goto bad_area; - } + if (!is_write) + goto bad_area; + + /* + * N.B. The rs6000/xcoff ABI allows programs to access up to + * a few hundred bytes below the stack pointer. + * The kernel signal delivery code writes up to about 1.5kB + * below the stack pointer (r1) before decrementing it. + * The exec code can write slightly over 640kB to the stack + * before setting the user r1. Thus we allow the stack to + * expand to 1MB without further checks. + */ + if (address + 0x100000 < vma->vm_end) { + /* get user regs even if this fault is in kernel mode */ + struct pt_regs *uregs = current->thread.regs; + if (uregs == NULL) + goto bad_area; + + /* + * A user-mode access to an address a long way below + * the stack pointer is only valid if the instruction + * is one which would update the stack pointer to the + * address accessed if the instruction completed, + * i.e. either stwu rs,n(r1) or stwux rs,r1,rb + * (or the byte, halfword, float or double forms). + * + * If we don't check this then any write to the area + * between the last mapped region and the stack will + * expand the stack rather than segfaulting. + */ + if (address + 2048 < uregs->gpr[1] + && (!user_mode(regs) || !store_updates_sp(regs))) + goto bad_area; + } if (expand_stack(vma, address)) goto bad_area; diff -urN linux-2.4.23-pre8/arch/ppc64/configs/iSeries_devfs_defconfig linux-2.4.23-pre8-pac1/arch/ppc64/configs/iSeries_devfs_defconfig --- linux-2.4.23-pre8/arch/ppc64/configs/iSeries_devfs_defconfig 2003-08-25 13:44:40.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/ppc64/configs/iSeries_devfs_defconfig 2003-10-24 14:31:25.000000000 +0200 @@ -491,6 +491,7 @@ # CONFIG_JFS_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/ppc64/configs/iSeries_nodevfs_ideemul_defconfig linux-2.4.23-pre8-pac1/arch/ppc64/configs/iSeries_nodevfs_ideemul_defconfig --- linux-2.4.23-pre8/arch/ppc64/configs/iSeries_nodevfs_ideemul_defconfig 2003-08-25 13:44:40.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/ppc64/configs/iSeries_nodevfs_ideemul_defconfig 2003-10-24 14:31:25.000000000 +0200 @@ -521,6 +521,7 @@ # CONFIG_JFS_DEBUG is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/ppc64/configs/pSeries_defconfig linux-2.4.23-pre8-pac1/arch/ppc64/configs/pSeries_defconfig --- linux-2.4.23-pre8/arch/ppc64/configs/pSeries_defconfig 2003-08-25 13:44:40.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/ppc64/configs/pSeries_defconfig 2003-10-24 14:31:25.000000000 +0200 @@ -610,6 +610,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/ppc64/defconfig linux-2.4.23-pre8-pac1/arch/ppc64/defconfig --- linux-2.4.23-pre8/arch/ppc64/defconfig 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/ppc64/defconfig 2003-10-24 14:31:25.000000000 +0200 @@ -612,6 +612,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/ppc64/kernel/ioctl32.c linux-2.4.23-pre8-pac1/arch/ppc64/kernel/ioctl32.c --- linux-2.4.23-pre8/arch/ppc64/kernel/ioctl32.c 2003-08-25 13:44:40.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/ppc64/kernel/ioctl32.c 2003-10-24 14:31:25.000000000 +0200 @@ -66,6 +66,7 @@ #if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE) #include #endif /* LVM */ +#include #include /* Ugly hack. */ @@ -4435,6 +4436,22 @@ COMPATIBLE_IOCTL(NBD_PRINT_DEBUG), COMPATIBLE_IOCTL(NBD_SET_SIZE_BLOCKS), COMPATIBLE_IOCTL(NBD_DISCONNECT), +/* device-mapper */ +#if defined(CONFIG_BLK_DEV_DM) || defined(CONFIG_BLK_DEV_DM_MODULE) +COMPATIBLE_IOCTL(DM_VERSION), +COMPATIBLE_IOCTL(DM_REMOVE_ALL), +COMPATIBLE_IOCTL(DM_DEV_CREATE), +COMPATIBLE_IOCTL(DM_DEV_REMOVE), +COMPATIBLE_IOCTL(DM_TABLE_LOAD), +COMPATIBLE_IOCTL(DM_DEV_SUSPEND), +COMPATIBLE_IOCTL(DM_DEV_RENAME), +COMPATIBLE_IOCTL(DM_TABLE_DEPS), +COMPATIBLE_IOCTL(DM_DEV_STATUS), +COMPATIBLE_IOCTL(DM_TABLE_STATUS), +COMPATIBLE_IOCTL(DM_DEV_WAIT), +COMPATIBLE_IOCTL(DM_LIST_DEVICES), +COMPATIBLE_IOCTL(DM_TABLE_CLEAR), +#endif /* CONFIG_BLK_DEV_DM */ /* Remove *PRIVATE in 2.5 */ COMPATIBLE_IOCTL(SIOCDEVPRIVATE), COMPATIBLE_IOCTL(SIOCDEVPRIVATE+1), diff -urN linux-2.4.23-pre8/arch/ppc64/kernel/sys_ppc32.c linux-2.4.23-pre8-pac1/arch/ppc64/kernel/sys_ppc32.c --- linux-2.4.23-pre8/arch/ppc64/kernel/sys_ppc32.c 2003-08-25 13:44:40.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/ppc64/kernel/sys_ppc32.c 2003-10-24 14:31:25.000000000 +0200 @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include diff -urN linux-2.4.23-pre8/arch/s390/defconfig linux-2.4.23-pre8-pac1/arch/s390/defconfig --- linux-2.4.23-pre8/arch/s390/defconfig 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/s390/defconfig 2003-10-24 14:31:25.000000000 +0200 @@ -35,6 +35,8 @@ CONFIG_FAST_IRQ=y CONFIG_MACHCHK_WARNING=y CONFIG_CHSC=y +CONFIG_QDIO=m +# CONFIG_QDIO_PERF_STATS is not set CONFIG_IPL=y CONFIG_IPL_TAPE=y # CONFIG_IPL_VM is not set @@ -126,6 +128,14 @@ # CONFIG_CHANDEV=y CONFIG_HOTPLUG=y +CONFIG_QETH=m + +# +# Gigabit Ethernet default settings +# +# CONFIG_QETH_IPV6 is not set +CONFIG_QETH_VLAN=y +# CONFIG_QETH_PERF_STATS is not set CONFIG_CTC=m CONFIG_IUCV=m @@ -301,6 +311,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/s390/kernel/asm-offsets.c linux-2.4.23-pre8-pac1/arch/s390/kernel/asm-offsets.c --- linux-2.4.23-pre8/arch/s390/kernel/asm-offsets.c 2002-08-03 02:39:43.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/s390/kernel/asm-offsets.c 2003-10-24 14:31:25.000000000 +0200 @@ -26,7 +26,7 @@ DEFINE(__TASK_need_resched, offsetof(struct task_struct, need_resched),); DEFINE(__TASK_ptrace, offsetof(struct task_struct, ptrace),); - DEFINE(__TASK_processor, offsetof(struct task_struct, processor),); + DEFINE(__TASK_processor, offsetof(struct task_struct, cpu),); return 0; } diff -urN linux-2.4.23-pre8/arch/s390/kernel/bitmap.S linux-2.4.23-pre8-pac1/arch/s390/kernel/bitmap.S --- linux-2.4.23-pre8/arch/s390/kernel/bitmap.S 2000-05-12 20:41:44.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/s390/kernel/bitmap.S 2003-10-24 14:31:25.000000000 +0200 @@ -35,3 +35,21 @@ .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4 .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,8 + .globl _sb_findmap +_sb_findmap: + .byte 8,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 + .byte 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 + .byte 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 + .byte 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 + .byte 6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 + .byte 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 + .byte 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 + .byte 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 + .byte 7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 + .byte 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 + .byte 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 + .byte 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 + .byte 6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 + .byte 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 + .byte 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 + .byte 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 diff -urN linux-2.4.23-pre8/arch/s390/kernel/entry.S linux-2.4.23-pre8-pac1/arch/s390/kernel/entry.S --- linux-2.4.23-pre8/arch/s390/kernel/entry.S 2003-06-13 16:51:32.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/s390/kernel/entry.S 2003-10-24 14:31:25.000000000 +0200 @@ -254,13 +254,14 @@ ret_from_fork: basr %r13,0 l %r13,.Lentry_base-.(%r13) # setup base pointer to &entry_base + # not saving R14 here because we go to sysc_return ultimately + l %r1,BASED(.Lschedtail) + basr %r14,%r1 # call schedule_tail (unlock stuff) GET_CURRENT # load pointer to task_struct to R9 stosm 24(%r15),0x03 # reenable interrupts sr %r0,%r0 # child returns 0 st %r0,SP_R2(%r15) # store return value (change R2 on stack) - l %r1,BASED(.Lschedtail) - la %r14,BASED(sysc_return) - br %r1 # call schedule_tail, return to sysc_return + b BASED(sysc_return) # # clone, fork, vfork, exec and sigreturn need glue, diff -urN linux-2.4.23-pre8/arch/s390/kernel/process.c linux-2.4.23-pre8-pac1/arch/s390/kernel/process.c --- linux-2.4.23-pre8/arch/s390/kernel/process.c 2003-06-13 16:51:32.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/s390/kernel/process.c 2003-10-24 14:31:25.000000000 +0200 @@ -50,15 +50,11 @@ * The idle loop on a S390... */ -int cpu_idle(void *unused) +int cpu_idle(void) { psw_t wait_psw; unsigned long reg; - /* endless idle loop with no priority at all */ - init_idle(); - current->nice = 20; - current->counter = -100; while (1) { if (current->need_resched) { schedule(); @@ -94,7 +90,7 @@ { struct task_struct *tsk = current; - printk("CPU: %d %s\n", tsk->processor, print_tainted()); + printk("CPU: %d %s\n", tsk->cpu, print_tainted()); printk("Process %s (pid: %d, task: %08lx, ksp: %08x)\n", current->comm, current->pid, (unsigned long) tsk, tsk->thread.ksp); diff -urN linux-2.4.23-pre8/arch/s390/kernel/setup.c linux-2.4.23-pre8-pac1/arch/s390/kernel/setup.c --- linux-2.4.23-pre8/arch/s390/kernel/setup.c 2003-08-25 13:44:40.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/s390/kernel/setup.c 2003-10-24 14:31:25.000000000 +0200 @@ -276,9 +276,9 @@ static int __init conmode_setup(char *str) { -#if defined(CONFIG_HWC_CONSOLE) - if (strncmp(str, "hwc", 4) == 0) - SET_CONSOLE_HWC; +#if defined(CONFIG_SCLP_CONSOLE) + if (strncmp(str, "hwc", 4) == 0 || strncmp(str, "sclp", 5) == 0) + SET_CONSOLE_SCLP; #endif #if defined(CONFIG_TN3215_CONSOLE) if (strncmp(str, "3215", 5) == 0) @@ -310,8 +310,8 @@ */ cpcmd("TERM CONMODE 3215", NULL, 0); if (ptr == NULL) { -#if defined(CONFIG_HWC_CONSOLE) - SET_CONSOLE_HWC; +#if defined(CONFIG_SCLP_CONSOLE) + SET_CONSOLE_SCLP; #endif return; } @@ -320,16 +320,16 @@ SET_CONSOLE_3270; #elif defined(CONFIG_TN3215_CONSOLE) SET_CONSOLE_3215; -#elif defined(CONFIG_HWC_CONSOLE) - SET_CONSOLE_HWC; +#elif defined(CONFIG_SCLP_CONSOLE) + SET_CONSOLE_SCLP; #endif } else if (strncmp(ptr + 8, "3215", 4) == 0) { #if defined(CONFIG_TN3215_CONSOLE) SET_CONSOLE_3215; #elif defined(CONFIG_TN3270_CONSOLE) SET_CONSOLE_3270; -#elif defined(CONFIG_HWC_CONSOLE) - SET_CONSOLE_HWC; +#elif defined(CONFIG_SCLP_CONSOLE) + SET_CONSOLE_SCLP; #endif } } else if (MACHINE_IS_P390) { @@ -339,8 +339,8 @@ SET_CONSOLE_3270; #endif } else { -#if defined(CONFIG_HWC_CONSOLE) - SET_CONSOLE_HWC; +#if defined(CONFIG_SCLP_CONSOLE) + SET_CONSOLE_SCLP; #endif } } @@ -383,21 +383,25 @@ /* * Reboot, halt and power_off stubs. They just call _machine_restart, - * _machine_halt or _machine_power_off. + * _machine_halt or _machine_power_off after making sure that all pending + * printks reached their destination. */ void machine_restart(char *command) { + console_unblank(); _machine_restart(command); } void machine_halt(void) { + console_unblank(); _machine_halt(); } void machine_power_off(void) { + console_unblank(); _machine_power_off(); } diff -urN linux-2.4.23-pre8/arch/s390/kernel/smp.c linux-2.4.23-pre8-pac1/arch/s390/kernel/smp.c --- linux-2.4.23-pre8/arch/s390/kernel/smp.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.23-pre8-pac1/arch/s390/kernel/smp.c 2003-10-24 14:31:25.000000000 +0200 @@ -38,7 +38,7 @@ #include /* prototypes */ -extern int cpu_idle(void * unused); +extern int cpu_idle(void); extern __u16 boot_cpu_addr; extern volatile int __cpu_logical_map[]; @@ -56,6 +56,7 @@ spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; unsigned long cpu_online_map; +unsigned long cache_decay_ticks; /* * Setup routine for controlling SMP activation @@ -468,7 +469,7 @@ { int curr_cpu; - current->processor = 0; + current->cpu = 0; smp_num_cpus = 1; cpu_online_map = 1; for (curr_cpu = 0; @@ -509,7 +510,7 @@ pfault_init(); #endif /* cpu_idle will call schedule for us */ - return cpu_idle(NULL); + return cpu_idle(); } /* @@ -547,12 +548,9 @@ idle = init_task.prev_task; if (!idle) panic("No idle process for CPU %d",cpu); - idle->processor = cpu; - idle->cpus_runnable = 1 << cpu; /* we schedule the first task manually */ + init_idle(idle, cpu); - del_from_runqueue(idle); unhash_process(idle); - init_tasks[cpu] = idle; cpu_lowcore = get_cpu_lowcore(cpu); cpu_lowcore->save_area[15] = idle->thread.ksp; @@ -604,6 +602,8 @@ panic("Couldn't request external interrupt 0x1202"); smp_count_cpus(); memset(lowcore_ptr,0,sizeof(lowcore_ptr)); + + cache_decay_ticks = (200 * HZ) / 1000; /* Is 200ms ok? Robus? XXX */ /* * Initialize the logical to physical CPU number mapping diff -urN linux-2.4.23-pre8/arch/s390/kernel/traps.c linux-2.4.23-pre8-pac1/arch/s390/kernel/traps.c --- linux-2.4.23-pre8/arch/s390/kernel/traps.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.23-pre8-pac1/arch/s390/kernel/traps.c 2003-10-24 14:31:25.000000000 +0200 @@ -142,7 +142,7 @@ * We can't print the backtrace of a running process. It is * unreliable at best and can cause kernel oopses. */ - if (task_has_cpu(tsk)) + if (tsk->state == TASK_RUNNING) return; show_trace((unsigned long *) tsk->thread.ksp); } diff -urN linux-2.4.23-pre8/arch/s390x/defconfig linux-2.4.23-pre8-pac1/arch/s390x/defconfig --- linux-2.4.23-pre8/arch/s390x/defconfig 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/s390x/defconfig 2003-10-24 14:31:25.000000000 +0200 @@ -36,6 +36,8 @@ CONFIG_FAST_IRQ=y CONFIG_MACHCHK_WARNING=y CONFIG_CHSC=y +CONFIG_QDIO=m +# CONFIG_QDIO_PERF_STATS is not set CONFIG_IPL=y CONFIG_IPL_TAPE=y # CONFIG_IPL_VM is not set @@ -243,6 +245,7 @@ # CONFIG_MINIX_FS is not set # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/s390x/kernel/asm-offsets.c linux-2.4.23-pre8-pac1/arch/s390x/kernel/asm-offsets.c --- linux-2.4.23-pre8/arch/s390x/kernel/asm-offsets.c 2002-08-03 02:39:43.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/s390x/kernel/asm-offsets.c 2003-10-24 14:31:25.000000000 +0200 @@ -26,7 +26,7 @@ DEFINE(__TASK_need_resched, offsetof(struct task_struct, need_resched),); DEFINE(__TASK_ptrace, offsetof(struct task_struct, ptrace),); - DEFINE(__TASK_processor, offsetof(struct task_struct, processor),); + DEFINE(__TASK_processor, offsetof(struct task_struct, cpu),); return 0; } diff -urN linux-2.4.23-pre8/arch/s390x/kernel/bitmap.S linux-2.4.23-pre8-pac1/arch/s390x/kernel/bitmap.S --- linux-2.4.23-pre8/arch/s390x/kernel/bitmap.S 2001-02-13 23:13:44.000000000 +0100 +++ linux-2.4.23-pre8-pac1/arch/s390x/kernel/bitmap.S 2003-10-24 14:31:25.000000000 +0200 @@ -35,3 +35,22 @@ .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4 .byte 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,8 + .globl _sb_findmap +_sb_findmap: + .byte 8,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 + .byte 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 + .byte 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 + .byte 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 + .byte 6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 + .byte 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 + .byte 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 + .byte 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 + .byte 7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 + .byte 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 + .byte 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 + .byte 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 + .byte 6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 + .byte 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 + .byte 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 + .byte 4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 + diff -urN linux-2.4.23-pre8/arch/s390x/kernel/entry.S linux-2.4.23-pre8-pac1/arch/s390x/kernel/entry.S --- linux-2.4.23-pre8/arch/s390x/kernel/entry.S 2003-08-25 13:44:40.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/s390x/kernel/entry.S 2003-10-24 14:31:25.000000000 +0200 @@ -240,11 +240,11 @@ # .globl ret_from_fork ret_from_fork: + brasl %r14,schedule_tail GET_CURRENT # load pointer to task_struct to R9 stosm 48(%r15),0x03 # reenable interrupts xc SP_R2(8,%r15),SP_R2(%r15) # child returns 0 - larl %r14,sysc_return - jg schedule_tail # return to sysc_return + j sysc_return # # clone, fork, vfork, exec and sigreturn need glue, diff -urN linux-2.4.23-pre8/arch/s390x/kernel/ioctl32.c linux-2.4.23-pre8-pac1/arch/s390x/kernel/ioctl32.c --- linux-2.4.23-pre8/arch/s390x/kernel/ioctl32.c 2003-08-25 13:44:40.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/s390x/kernel/ioctl32.c 2003-10-24 14:31:25.000000000 +0200 @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -627,6 +628,20 @@ IOCTL32_DEFAULT(SIOCGSTAMP), + IOCTL32_DEFAULT(DM_VERSION), + IOCTL32_DEFAULT(DM_REMOVE_ALL), + IOCTL32_DEFAULT(DM_DEV_CREATE), + IOCTL32_DEFAULT(DM_DEV_REMOVE), + IOCTL32_DEFAULT(DM_TABLE_LOAD), + IOCTL32_DEFAULT(DM_DEV_SUSPEND), + IOCTL32_DEFAULT(DM_DEV_RENAME), + IOCTL32_DEFAULT(DM_TABLE_DEPS), + IOCTL32_DEFAULT(DM_DEV_STATUS), + IOCTL32_DEFAULT(DM_TABLE_STATUS), + IOCTL32_DEFAULT(DM_DEV_WAIT), + IOCTL32_DEFAULT(DM_LIST_DEVICES), + IOCTL32_DEFAULT(DM_TABLE_CLEAR), + IOCTL32_DEFAULT(LOOP_SET_FD), IOCTL32_DEFAULT(LOOP_CLR_FD), diff -urN linux-2.4.23-pre8/arch/s390x/kernel/linux32.c linux-2.4.23-pre8-pac1/arch/s390x/kernel/linux32.c --- linux-2.4.23-pre8/arch/s390x/kernel/linux32.c 2003-08-25 13:44:40.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/s390x/kernel/linux32.c 2003-10-24 14:31:25.000000000 +0200 @@ -4499,7 +4499,7 @@ error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); if (!IS_ERR((void *) error) && error + len >= 0x80000000ULL) { /* Result is out of bounds. */ - do_munmap(current->mm, addr, len); + do_munmap(current->mm, addr, len, 1); error = -ENOMEM; } up_write(¤t->mm->mmap_sem); diff -urN linux-2.4.23-pre8/arch/s390x/kernel/process.c linux-2.4.23-pre8-pac1/arch/s390x/kernel/process.c --- linux-2.4.23-pre8/arch/s390x/kernel/process.c 2003-06-13 16:51:32.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/s390x/kernel/process.c 2003-10-24 14:31:25.000000000 +0200 @@ -55,10 +55,6 @@ psw_t wait_psw; unsigned long reg; - /* endless idle loop with no priority at all */ - init_idle(); - current->nice = 20; - current->counter = -100; while (1) { if (current->need_resched) { schedule(); @@ -91,7 +87,7 @@ { struct task_struct *tsk = current; - printk("CPU: %d %s\n", tsk->processor, print_tainted()); + printk("CPU: %d %s\n", tsk->cpu, print_tainted()); printk("Process %s (pid: %d, task: %016lx, ksp: %016lx)\n", current->comm, current->pid, (unsigned long) tsk, tsk->thread.ksp); diff -urN linux-2.4.23-pre8/arch/s390x/kernel/setup.c linux-2.4.23-pre8-pac1/arch/s390x/kernel/setup.c --- linux-2.4.23-pre8/arch/s390x/kernel/setup.c 2003-08-25 13:44:40.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/s390x/kernel/setup.c 2003-10-24 14:31:25.000000000 +0200 @@ -164,9 +164,9 @@ static int __init conmode_setup(char *str) { -#if defined(CONFIG_HWC_CONSOLE) - if (strncmp(str, "hwc", 4) == 0) - SET_CONSOLE_HWC; +#if defined(CONFIG_SCLP_CONSOLE) + if (strncmp(str, "hwc", 4) == 0 || strncmp(str, "sclp", 5) == 0) + SET_CONSOLE_SCLP; #endif #if defined(CONFIG_TN3215_CONSOLE) if (strncmp(str, "3215", 5) == 0) @@ -198,8 +198,8 @@ */ cpcmd("TERM CONMODE 3215", NULL, 0); if (ptr == NULL) { -#if defined(CONFIG_HWC_CONSOLE) - SET_CONSOLE_HWC; +#if defined(CONFIG_SCLP_CONSOLE) + SET_CONSOLE_SCLP; #endif return; } @@ -208,16 +208,16 @@ SET_CONSOLE_3270; #elif defined(CONFIG_TN3215_CONSOLE) SET_CONSOLE_3215; -#elif defined(CONFIG_HWC_CONSOLE) - SET_CONSOLE_HWC; +#elif defined(CONFIG_SCLP_CONSOLE) + SET_CONSOLE_SCLP; #endif } else if (strncmp(ptr + 8, "3215", 4) == 0) { #if defined(CONFIG_TN3215_CONSOLE) SET_CONSOLE_3215; #elif defined(CONFIG_TN3270_CONSOLE) SET_CONSOLE_3270; -#elif defined(CONFIG_HWC_CONSOLE) - SET_CONSOLE_HWC; +#elif defined(CONFIG_SCLP_CONSOLE) + SET_CONSOLE_SCLP; #endif } } else if (MACHINE_IS_P390) { @@ -227,8 +227,8 @@ SET_CONSOLE_3270; #endif } else { -#if defined(CONFIG_HWC_CONSOLE) - SET_CONSOLE_HWC; +#if defined(CONFIG_SCLP_CONSOLE) + SET_CONSOLE_SCLP; #endif } } @@ -271,21 +271,25 @@ /* * Reboot, halt and power_off stubs. They just call _machine_restart, - * _machine_halt or _machine_power_off. + * _machine_halt or _machine_power_off after making sure that all pending + * printks reached their destination. */ void machine_restart(char *command) { + console_unblank(); _machine_restart(command); } void machine_halt(void) { + console_unblank(); _machine_halt(); } void machine_power_off(void) { + console_unblank(); _machine_power_off(); } diff -urN linux-2.4.23-pre8/arch/s390x/kernel/smp.c linux-2.4.23-pre8-pac1/arch/s390x/kernel/smp.c --- linux-2.4.23-pre8/arch/s390x/kernel/smp.c 2003-06-13 16:51:32.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/s390x/kernel/smp.c 2003-10-24 14:31:25.000000000 +0200 @@ -38,7 +38,7 @@ #include /* prototypes */ -extern int cpu_idle(void * unused); +extern int cpu_idle(void); extern __u16 boot_cpu_addr; extern volatile int __cpu_logical_map[]; @@ -56,6 +56,7 @@ spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; unsigned long cpu_online_map; +unsigned long cache_decay_ticks; /* * Setup routine for controlling SMP activation @@ -451,7 +452,7 @@ { int curr_cpu; - current->processor = 0; + current->cpu = 0; smp_num_cpus = 1; cpu_online_map = 1; for (curr_cpu = 0; @@ -491,7 +492,7 @@ pfault_init(); #endif /* cpu_idle will call schedule for us */ - return cpu_idle(NULL); + return cpu_idle(); } /* @@ -529,12 +530,9 @@ idle = init_task.prev_task; if (!idle) panic("No idle process for CPU %d",cpu); - idle->processor = cpu; - idle->cpus_runnable = 1 << cpu; /* we schedule the first task manually */ + init_idle(idle, cpu); - del_from_runqueue(idle); unhash_process(idle); - init_tasks[cpu] = idle; cpu_lowcore = get_cpu_lowcore(cpu); cpu_lowcore->save_area[15] = idle->thread.ksp; @@ -588,6 +586,8 @@ smp_count_cpus(); memset(lowcore_ptr,0,sizeof(lowcore_ptr)); + cache_decay_ticks = (200 * HZ) / 1000; /* Is 200ms ok? Robus? XXX */ + /* * Initialize the logical to physical CPU number mapping */ diff -urN linux-2.4.23-pre8/arch/s390x/kernel/traps.c linux-2.4.23-pre8-pac1/arch/s390x/kernel/traps.c --- linux-2.4.23-pre8/arch/s390x/kernel/traps.c 2002-11-29 00:53:11.000000000 +0100 +++ linux-2.4.23-pre8-pac1/arch/s390x/kernel/traps.c 2003-10-24 14:31:25.000000000 +0200 @@ -144,7 +144,7 @@ * We can't print the backtrace of a running process. It is * unreliable at best and can cause kernel oopses. */ - if (task_has_cpu(tsk)) + if (tsk->state == TASK_RUNNING) return; show_trace((unsigned long *) tsk->thread.ksp); } diff -urN linux-2.4.23-pre8/arch/sh/defconfig linux-2.4.23-pre8-pac1/arch/sh/defconfig --- linux-2.4.23-pre8/arch/sh/defconfig 2001-10-15 22:36:48.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/sh/defconfig 2003-10-24 14:31:25.000000000 +0200 @@ -165,6 +165,7 @@ # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/sh/mm/fault.c linux-2.4.23-pre8-pac1/arch/sh/mm/fault.c --- linux-2.4.23-pre8/arch/sh/mm/fault.c 2003-08-25 13:44:40.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/sh/mm/fault.c 2003-10-24 14:31:25.000000000 +0200 @@ -76,8 +76,6 @@ return 1; check_stack: - if (!(vma->vm_flags & VM_GROWSDOWN)) - goto bad_area; if (expand_stack(vma, start) == 0) goto good_area; diff -urN linux-2.4.23-pre8/arch/sparc/defconfig linux-2.4.23-pre8-pac1/arch/sparc/defconfig --- linux-2.4.23-pre8/arch/sparc/defconfig 2002-08-03 02:39:43.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/sparc/defconfig 2003-10-24 14:31:25.000000000 +0200 @@ -308,6 +308,7 @@ CONFIG_MINIX_FS=m # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set CONFIG_HPFS_FS=m CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/sparc/kernel/sunos_ioctl.c linux-2.4.23-pre8-pac1/arch/sparc/kernel/sunos_ioctl.c --- linux-2.4.23-pre8/arch/sparc/kernel/sunos_ioctl.c 2000-09-07 17:32:00.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/sparc/kernel/sunos_ioctl.c 2003-10-24 14:31:25.000000000 +0200 @@ -39,8 +39,12 @@ { int ret = -EBADF; - if (fd >= SUNOS_NR_OPEN || !fcheck(fd)) + read_lock(¤t->files->file_lock); + if (fd >= SUNOS_NR_OPEN || !fcheck(fd)) { + read_unlock(¤t->files->file_lock); goto out; + } + read_unlock(¤t->files->file_lock); /* First handle an easy compat. case for tty ldisc. */ if(cmd == TIOCSETD) { diff -urN linux-2.4.23-pre8/arch/sparc/mm/fault.c linux-2.4.23-pre8-pac1/arch/sparc/mm/fault.c --- linux-2.4.23-pre8/arch/sparc/mm/fault.c 2003-06-13 16:51:32.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/sparc/mm/fault.c 2003-10-24 14:31:25.000000000 +0200 @@ -249,8 +249,6 @@ goto bad_area; if(vma->vm_start <= address) goto good_area; - if(!(vma->vm_flags & VM_GROWSDOWN)) - goto bad_area; if(expand_stack(vma, address)) goto bad_area; /* @@ -496,8 +494,6 @@ goto bad_area; if(vma->vm_start <= address) goto good_area; - if(!(vma->vm_flags & VM_GROWSDOWN)) - goto bad_area; if(expand_stack(vma, address)) goto bad_area; good_area: diff -urN linux-2.4.23-pre8/arch/sparc64/defconfig linux-2.4.23-pre8-pac1/arch/sparc64/defconfig --- linux-2.4.23-pre8/arch/sparc64/defconfig 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/sparc64/defconfig 2003-10-24 14:31:25.000000000 +0200 @@ -758,6 +758,7 @@ CONFIG_MINIX_FS=m # CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set # CONFIG_NTFS_RW is not set CONFIG_HPFS_FS=m CONFIG_PROC_FS=y diff -urN linux-2.4.23-pre8/arch/sparc64/kernel/ioctl32.c linux-2.4.23-pre8-pac1/arch/sparc64/kernel/ioctl32.c --- linux-2.4.23-pre8/arch/sparc64/kernel/ioctl32.c 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/sparc64/kernel/ioctl32.c 2003-10-24 14:31:25.000000000 +0200 @@ -56,6 +56,7 @@ #if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE) #include #endif /* LVM */ +#include #include /* Ugly hack. */ @@ -5086,6 +5087,22 @@ COMPATIBLE_IOCTL(NBD_PRINT_DEBUG) COMPATIBLE_IOCTL(NBD_SET_SIZE_BLOCKS) COMPATIBLE_IOCTL(NBD_DISCONNECT) +/* device-mapper */ +#if defined(CONFIG_BLK_DEV_DM) || defined(CONFIG_BLK_DEV_DM_MODULE) +COMPATIBLE_IOCTL(DM_VERSION) +COMPATIBLE_IOCTL(DM_REMOVE_ALL) +COMPATIBLE_IOCTL(DM_DEV_CREATE) +COMPATIBLE_IOCTL(DM_DEV_REMOVE) +COMPATIBLE_IOCTL(DM_TABLE_LOAD) +COMPATIBLE_IOCTL(DM_DEV_SUSPEND) +COMPATIBLE_IOCTL(DM_DEV_RENAME) +COMPATIBLE_IOCTL(DM_TABLE_DEPS) +COMPATIBLE_IOCTL(DM_DEV_STATUS) +COMPATIBLE_IOCTL(DM_TABLE_STATUS) +COMPATIBLE_IOCTL(DM_DEV_WAIT) +COMPATIBLE_IOCTL(DM_LIST_DEVICES) +COMPATIBLE_IOCTL(DM_TABLE_CLEAR) +#endif /* CONFIG_BLK_DEV_DM */ /* Linux-1394 */ #if defined(CONFIG_IEEE1394) || defined(CONFIG_IEEE1394_MODULE) COMPATIBLE_IOCTL(AMDTP_IOC_CHANNEL) diff -urN linux-2.4.23-pre8/arch/sparc64/kernel/sunos_ioctl32.c linux-2.4.23-pre8-pac1/arch/sparc64/kernel/sunos_ioctl32.c --- linux-2.4.23-pre8/arch/sparc64/kernel/sunos_ioctl32.c 2000-08-05 03:16:11.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/sparc64/kernel/sunos_ioctl32.c 2003-10-24 14:31:25.000000000 +0200 @@ -100,8 +100,12 @@ if(fd >= SUNOS_NR_OPEN) goto out; - if(!fcheck(fd)) + read_lock(¤t->files->file_lock); + if(!fcheck(fd)) { + read_unlock(¤t->files->file_lock); goto out; + } + read_unlock(¤t->files->file_lock); if(cmd == TIOCSETD) { mm_segment_t old_fs = get_fs(); diff -urN linux-2.4.23-pre8/arch/sparc64/mm/fault.c linux-2.4.23-pre8-pac1/arch/sparc64/mm/fault.c --- linux-2.4.23-pre8/arch/sparc64/mm/fault.c 2002-11-29 00:53:12.000000000 +0100 +++ linux-2.4.23-pre8-pac1/arch/sparc64/mm/fault.c 2003-10-24 14:31:25.000000000 +0200 @@ -373,8 +373,6 @@ if (vma->vm_start <= address) goto good_area; - if (!(vma->vm_flags & VM_GROWSDOWN)) - goto bad_area; if (!(fault_code & FAULT_CODE_WRITE)) { /* Non-faulting loads shouldn't expand stack. */ insn = get_fault_insn(regs, insn); diff -urN linux-2.4.23-pre8/arch/sparc64/solaris/timod.c linux-2.4.23-pre8-pac1/arch/sparc64/solaris/timod.c --- linux-2.4.23-pre8/arch/sparc64/solaris/timod.c 2002-08-03 02:39:43.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/sparc64/solaris/timod.c 2003-10-24 14:31:25.000000000 +0200 @@ -149,7 +149,9 @@ struct socket *sock; SOLD("wakeing socket"); + read_lock(¤t->files->file_lock); sock = ¤t->files->fd[fd]->f_dentry->d_inode->u.socket_i; + read_unlock(¤t->files->file_lock); wake_up_interruptible(&sock->wait); read_lock(&sock->sk->callback_lock); if (sock->fasync_list && !test_bit(SOCK_ASYNC_WAITDATA, &sock->flags)) @@ -163,7 +165,9 @@ struct sol_socket_struct *sock; SOLD("queuing primsg"); + read_lock(¤t->files->file_lock); sock = (struct sol_socket_struct *)current->files->fd[fd]->private_data; + read_unlock(¤t->files->file_lock); it->next = sock->pfirst; sock->pfirst = it; if (!sock->plast) @@ -177,7 +181,9 @@ struct sol_socket_struct *sock; SOLD("queuing primsg at end"); + read_lock(¤t->files->file_lock); sock = (struct sol_socket_struct *)current->files->fd[fd]->private_data; + read_unlock(¤t->files->file_lock); it->next = NULL; if (sock->plast) sock->plast->next = it; @@ -355,7 +361,11 @@ (int (*)(int, unsigned long *))SYS(socketcall); int (*sys_sendto)(int, void *, size_t, unsigned, struct sockaddr *, int) = (int (*)(int, void *, size_t, unsigned, struct sockaddr *, int))SYS(sendto); - filp = current->files->fd[fd]; + read_lock(¤t->files->file_lock); + filp = fcheck(fd); + read_unlock(¤t->files->file_lock); + if (!filp) + return -EBADF; ino = filp->f_dentry->d_inode; sock = (struct sol_socket_struct *)filp->private_data; SOLD("entry"); @@ -636,7 +646,11 @@ SOLD("entry"); SOLDD(("%u %p %d %p %p %d %p %d\n", fd, ctl_buf, ctl_maxlen, ctl_len, data_buf, data_maxlen, data_len, *flags_p)); - filp = current->files->fd[fd]; + read_lock(¤t->files->file_lock); + filp = fcheck(fd); + read_unlock(¤t->files->file_lock); + if (!filp) + return -EBADF; ino = filp->f_dentry->d_inode; sock = (struct sol_socket_struct *)filp->private_data; SOLDD(("%p %p\n", sock->pfirst, sock->pfirst ? sock->pfirst->next : NULL)); @@ -847,7 +861,9 @@ lock_kernel(); if(fd >= NR_OPEN) goto out; - filp = current->files->fd[fd]; + read_lock(¤t->files->file_lock); + filp = fcheck(fd); + read_unlock(¤t->files->file_lock); if(!filp) goto out; ino = filp->f_dentry->d_inode; @@ -914,7 +930,9 @@ lock_kernel(); if(fd >= NR_OPEN) goto out; - filp = current->files->fd[fd]; + read_lock(¤t->files->file_lock); + filp = fcheck(fd); + read_unlock(¤t->files->file_lock); if(!filp) goto out; ino = filp->f_dentry->d_inode; diff -urN linux-2.4.23-pre8/arch/x86_64/ia32/ia32_ioctl.c linux-2.4.23-pre8-pac1/arch/x86_64/ia32/ia32_ioctl.c --- linux-2.4.23-pre8/arch/x86_64/ia32/ia32_ioctl.c 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/x86_64/ia32/ia32_ioctl.c 2003-10-24 14:31:25.000000000 +0200 @@ -67,6 +67,7 @@ #define max max #include #endif /* LVM */ +#include #include /* Ugly hack. */ @@ -4051,6 +4052,22 @@ COMPATIBLE_IOCTL(LV_BMAP) COMPATIBLE_IOCTL(LV_SNAPSHOT_USE_RATE) #endif /* LVM */ +/* Device-Mapper */ +#if defined(CONFIG_BLK_DEV_DM) || defined(CONFIG_BLK_DEV_DM_MODULE) +COMPATIBLE_IOCTL(DM_VERSION) +COMPATIBLE_IOCTL(DM_REMOVE_ALL) +COMPATIBLE_IOCTL(DM_DEV_CREATE) +COMPATIBLE_IOCTL(DM_DEV_REMOVE) +COMPATIBLE_IOCTL(DM_TABLE_LOAD) +COMPATIBLE_IOCTL(DM_DEV_SUSPEND) +COMPATIBLE_IOCTL(DM_DEV_RENAME) +COMPATIBLE_IOCTL(DM_TABLE_DEPS) +COMPATIBLE_IOCTL(DM_DEV_STATUS) +COMPATIBLE_IOCTL(DM_TABLE_STATUS) +COMPATIBLE_IOCTL(DM_DEV_WAIT) +COMPATIBLE_IOCTL(DM_LIST_DEVICES) +COMPATIBLE_IOCTL(DM_TABLE_CLEAR) +#endif /* CONFIG_BLK_DEV_DM */ #ifdef CONFIG_AUTOFS_FS COMPATIBLE_IOCTL(AUTOFS_IOC_READY) COMPATIBLE_IOCTL(AUTOFS_IOC_FAIL) diff -urN linux-2.4.23-pre8/arch/x86_64/kernel/Makefile linux-2.4.23-pre8-pac1/arch/x86_64/kernel/Makefile --- linux-2.4.23-pre8/arch/x86_64/kernel/Makefile 2003-08-25 13:44:40.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/x86_64/kernel/Makefile 2003-10-24 14:31:25.000000000 +0200 @@ -37,7 +37,7 @@ obj-$(CONFIG_GART_IOMMU) += pci-gart.o aperture.o obj-$(CONFIG_DUMMY_IOMMU) += pci-nommu.o obj-$(CONFIG_MCE) += bluesmoke.o -obj-$(CONFIG_ACPI) += acpi.o +obj-$(CONFIG_ACPI) += acpi.o pic.o obj-$(CONFIG_ACPI_SLEEP) += acpi_wakeup.o suspend.o diff -urN linux-2.4.23-pre8/arch/x86_64/kernel/mpparse.c linux-2.4.23-pre8-pac1/arch/x86_64/kernel/mpparse.c --- linux-2.4.23-pre8/arch/x86_64/kernel/mpparse.c 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/arch/x86_64/kernel/mpparse.c 2003-10-24 14:31:25.000000000 +0200 @@ -955,6 +955,7 @@ { struct list_head *node = NULL; struct acpi_prt_entry *entry = NULL; + struct acpi_prt_list *prt_list = NULL; int vector = 0; int ioapic = -1; int ioapic_pin = 0; @@ -963,16 +964,29 @@ int edge_level = 0; int active_high_low = 0; + /* Get the current PRT */ + prt_list = acpi_pci_get_prt_list(); + if (!prt_list->count) { + acpi_pci_destroy_prt_list(prt_list); + printk(KERN_WARNING "ACPI tables contain no IO-APIC PCI IRQ " + "routing entries\n"); + return_VALUE(-ENODEV); + } + /* * Parsing through the PCI Interrupt Routing Table (PRT) and program * routing for all static (IOAPIC-direct) entries. */ - list_for_each(node, &acpi_prt.entries) { + list_for_each(node, &prt_list->entries) entry = list_entry(node, struct acpi_prt_entry, node); /* Need to get irq for dynamic entry */ if (entry->link.handle) { irq = acpi_pci_link_get_irq(entry->link.handle, entry->link.index, &edge_level, &active_high_low); + if (irq < 0) { + acpi_pci_destroy_prt_list(prt_list); + return -ENODEV; + } if (!irq) continue; } else { @@ -1026,8 +1040,11 @@ mp_ioapic_routing[ioapic].apic_id, ioapic_pin, vector, entry->irq); } - - return; + + /* if we get here, the PRT was fine. commit it */ + acpi_pci_commit_prt_list(prt_list); + + return 0; } #endif /*CONFIG_ACPI_PCI*/ diff -urN linux-2.4.23-pre8/arch/x86_64/kernel/pic.c linux-2.4.23-pre8-pac1/arch/x86_64/kernel/pic.c --- linux-2.4.23-pre8/arch/x86_64/kernel/pic.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/arch/x86_64/kernel/pic.c 2003-10-24 14:31:25.000000000 +0200 @@ -0,0 +1,102 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2003 Andrew de Quincey - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139, + * USA; either version 2 of the License, or (at your option) any later + * version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef CONFIG_ACPI_PCI + +extern void eisa_set_level_irq(unsigned int irq); + +int __init pic_parse_prt (void) +{ + struct list_head *node = NULL; + struct acpi_prt_entry *entry = NULL; + struct acpi_prt_list *prt_list = NULL; + int edge_level = 0; + int active_high_low = 0; + int irq = 0; + int programmed[16]; + + /* Get the current PRT */ + prt_list = acpi_pci_get_prt_list(); + + if (!prt_list->count) { + acpi_pci_destroy_prt_list(prt_list); + printk(KERN_WARNING "ACPI tables contain no PIC PCI IRQ " + "routing entries\n"); + return_VALUE(-ENODEV); + } + + /* mark all IRQs as unprogrammed */ + memset(programmed, 0, sizeof(programmed)); + + /* + * Parsing through the PCI Interrupt Routing Table (PRT) and program + * IRQs if necessary. + */ + list_for_each(node, &prt_list->entries) { + entry = list_entry(node, struct acpi_prt_entry, node); + + /* Need to get irq for dynamic entry */ + if (entry->link.handle) { + irq = acpi_pci_link_get_irq(entry->link.handle, entry->link.index, &edge_level, &active_high_low); + if (irq < 0) { + acpi_pci_destroy_prt_list(prt_list); + return -ENODEV; + } + if (!irq) + continue; + } + + /* sanity check + update entry */ + if ((irq < 0) || (irq > 15)) { + printk(KERN_ERR "Invalid IRQ (%i) passed to PIC programming code\n", irq); + entry->irq = 0; + continue; + } + entry->irq = irq; + + /* check if it has already been dealt with */ + if (programmed[irq]) { + printk(KERN_DEBUG "PIC: IRQ (%i) already programmed\n", irq); + continue; + } + programmed[irq] = 1; + + /* program it */ + if (edge_level) { + eisa_set_level_irq(irq); + } + + printk(KERN_DEBUG "%02x:%02x:%02x[%c] -> IRQ %d Mode %d Trigger %d\n", + entry->id.segment, entry->id.bus, + entry->id.device, ('A' + entry->pin), + entry->irq, edge_level, active_high_low); + } + + /* if we get here, the PRT was fine. commit it */ + acpi_pci_commit_prt_list(prt_list); + + return 0; +} + +#endif /*CONFIG_ACPI_PCI*/ diff -urN linux-2.4.23-pre8/drivers/Makefile linux-2.4.23-pre8-pac1/drivers/Makefile --- linux-2.4.23-pre8/drivers/Makefile 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/Makefile 2003-10-24 14:31:25.000000000 +0200 @@ -8,12 +8,13 @@ mod-subdirs := dio hil mtd sbus video macintosh usb input telephony ide \ message/i2o message/fusion scsi md ieee1394 pnp isdn atm \ - fc4 net/hamradio i2c acpi bluetooth usb/gadget + fc4 net/hamradio i2c acpi bluetooth usb/gadget cpufreq subdir-y := parport char block net sound misc media cdrom hotplug subdir-m := $(subdir-y) +subdir-$(CONFIG_CPU_FREQ) += cpufreq subdir-$(CONFIG_DIO) += dio subdir-$(CONFIG_PCI) += pci subdir-$(CONFIG_GSC) += gsc diff -urN linux-2.4.23-pre8/drivers/acpi/bus.c linux-2.4.23-pre8-pac1/drivers/acpi/bus.c --- linux-2.4.23-pre8/drivers/acpi/bus.c 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/acpi/bus.c 2003-10-24 14:31:25.000000000 +0200 @@ -1802,7 +1802,7 @@ Initialization/Cleanup -------------------------------------------------------------------------- */ -static int __init +int acpi_bus_init_irq (void) { acpi_status status = AE_OK; diff -urN linux-2.4.23-pre8/drivers/acpi/pci_irq.c linux-2.4.23-pre8-pac1/drivers/acpi/pci_irq.c --- linux-2.4.23-pre8/drivers/acpi/pci_irq.c 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/acpi/pci_irq.c 2003-10-24 14:31:25.000000000 +0200 @@ -50,7 +50,22 @@ #define PREFIX "PCI: " -struct acpi_prt_list acpi_prt; +struct acpi_prt_list* acpi_prt = NULL; + +struct acpi_prt_ref { + struct list_head node; + struct acpi_device *device; + acpi_handle handle; + int segment; + int bus; +}; + +struct acpi_prt_ref_list { + int count; + struct list_head entries; +}; + +struct acpi_prt_ref_list acpi_prt_ref_list; #ifdef CONFIG_X86 extern void eisa_set_level_irq(unsigned int irq); @@ -73,16 +88,22 @@ ACPI_FUNCTION_TRACE("acpi_pci_irq_find_prt_entry"); - if (!acpi_prt.count) + if (!acpi_prt->count) return_PTR(NULL); + /* ensure we're not called before the routing table has been determined */ + if (acpi_prt == NULL) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Called before acpi_prt determined")); + return_PTR(NULL); + } + /* * Parse through all PRT entries looking for a match on the specified * PCI device's segment, bus, device, and pin (don't care about func). * * TBD: Acquire/release lock */ - list_for_each(node, &acpi_prt.entries) { + list_for_each(node, &acpi_prt->entries) { entry = list_entry(node, struct acpi_prt_entry, node); if ((segment == entry->id.segment) && (bus == entry->id.bus) @@ -98,6 +119,7 @@ static int acpi_pci_irq_add_entry ( + struct acpi_prt_list* prt_list, acpi_handle handle, int segment, int bus, @@ -154,12 +176,115 @@ ('A' + entry->pin), prt->source, entry->link.index)); /* TBD: Acquire/release lock */ - list_add_tail(&entry->node, &acpi_prt.entries); - acpi_prt.count++; + list_add_tail(&entry->node, &prt_list->entries); + prt_list->count++; return_VALUE(0); } +struct acpi_prt_list* +acpi_pci_get_prt_list (void) +{ + acpi_status status = AE_OK; + struct acpi_buffer buffer = {0, NULL}; + struct acpi_pci_routing_table *prt = NULL; + struct acpi_pci_routing_table *entry = NULL; + struct acpi_prt_list *prt_list = NULL; + struct acpi_prt_ref *prt_ref_entry = NULL; + struct list_head *node = NULL; + + ACPI_FUNCTION_TRACE("acpi_pci_irq_get_prt_list"); + + /* Create a brand new acpi_prt_list */ + prt_list = kmalloc(sizeof(struct acpi_prt_list), GFP_KERNEL); + if (!prt_list) + return_PTR(NULL); + memset(prt_list, 0, sizeof(struct acpi_prt_list)); + + prt_list->count = 0; + INIT_LIST_HEAD(&prt_list->entries); + + /* iterate over all entries in acpi_prt_ref_list, extracting the current _PRT entries */ + list_for_each(node, &acpi_prt_ref_list.entries) { + prt_ref_entry = list_entry(node, struct acpi_prt_ref, node); + + /* + * Evaluate this _PRT and add its entries to our local list (prt_list). + */ + + buffer.length = 0; + buffer.pointer = NULL; + status = acpi_get_irq_routing_table(prt_ref_entry->handle, &buffer); + if (status != AE_BUFFER_OVERFLOW) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PRT [%s]\n", + acpi_format_exception(status))); + kfree(prt_list); + return_PTR(NULL); + } + + prt = kmalloc(buffer.length, GFP_KERNEL); + if (!prt) { + kfree(prt_list); + return_VALUE(NULL); + } + memset(prt, 0, buffer.length); + buffer.pointer = prt; + + status = acpi_get_irq_routing_table(prt_ref_entry->handle, &buffer); + if (ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PRT [%s]\n", + acpi_format_exception(status))); + kfree(buffer.pointer); + kfree(prt_list); + return_PTR(NULL); + } + + entry = prt; + + while (entry && (entry->length > 0)) { + acpi_pci_irq_add_entry(prt_list, prt_ref_entry->handle, prt_ref_entry->segment, + prt_ref_entry->bus, entry); + entry = (struct acpi_pci_routing_table *) + ((unsigned long) entry + entry->length); + } + + kfree(prt); + } + + return_PTR(prt_list); +} + +int +acpi_pci_destroy_prt_list (struct acpi_prt_list* prt_list) { + struct list_head *node = NULL; + struct list_head *tmp = NULL; + struct acpi_prt_entry *entry = NULL; + + ACPI_FUNCTION_TRACE("acpi_pci_irq_destroy_prt_list"); + + list_for_each_safe(node, tmp, &prt_list->entries) { + entry = list_entry(node, struct acpi_prt_entry, node); + list_del(node); + kfree(entry); + } + kfree(prt_list); + + return_VALUE(0); +} + +int +acpi_pci_commit_prt_list (struct acpi_prt_list* prt_list) { + + ACPI_FUNCTION_TRACE("acpi_pci_irq_commit_prt_list"); + + if (acpi_prt != NULL) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Attempt to commit acpi_prt twice\n")); + return_VALUE(-ENODEV); + } + + acpi_prt = prt_list; + return_VALUE(0); +} int acpi_pci_irq_add_prt ( @@ -167,21 +292,20 @@ int segment, int bus) { - acpi_status status = AE_OK; - char pathname[ACPI_PATHNAME_MAX] = {0}; - struct acpi_buffer buffer = {0, NULL}; - struct acpi_pci_routing_table *prt = NULL; - struct acpi_pci_routing_table *entry = NULL; - static int first_time = 1; + static int first_time = 1; + struct acpi_prt_ref *entry = NULL; + struct acpi_buffer buffer = {0, NULL}; + char pathname[ACPI_PATHNAME_MAX] = {0}; ACPI_FUNCTION_TRACE("acpi_pci_irq_add_prt"); if (first_time) { - acpi_prt.count = 0; - INIT_LIST_HEAD(&acpi_prt.entries); + acpi_prt_ref_list.count = 0; + INIT_LIST_HEAD(&acpi_prt_ref_list.entries); first_time = 0; } + /* * NOTE: We're given a 'handle' to the _PRT object's parent device * (either a PCI root bridge or PCI-PCI bridge). @@ -194,42 +318,19 @@ printk(KERN_DEBUG "ACPI: PCI Interrupt Routing Table [%s._PRT]\n", pathname); - /* - * Evaluate this _PRT and add its entries to our global list (acpi_prt). - */ - - buffer.length = 0; - buffer.pointer = NULL; - status = acpi_get_irq_routing_table(handle, &buffer); - if (status != AE_BUFFER_OVERFLOW) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PRT [%s]\n", - acpi_format_exception(status))); - return_VALUE(-ENODEV); - } - - prt = kmalloc(buffer.length, GFP_KERNEL); - if (!prt) + + + entry = kmalloc(sizeof(struct acpi_prt_ref), GFP_KERNEL); + if (!entry) return_VALUE(-ENOMEM); - memset(prt, 0, buffer.length); - buffer.pointer = prt; - - status = acpi_get_irq_routing_table(handle, &buffer); - if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PRT [%s]\n", - acpi_format_exception(status))); - kfree(buffer.pointer); - return_VALUE(-ENODEV); - } + memset(entry, 0, sizeof(struct acpi_prt_ref)); + + entry->handle = handle; + entry->segment = segment; + entry->bus = bus; - entry = prt; - - while (entry && (entry->length > 0)) { - acpi_pci_irq_add_entry(handle, segment, bus, entry); - entry = (struct acpi_pci_routing_table *) - ((unsigned long) entry + entry->length); - } - - kfree(prt); + list_add_tail(&entry->node, &acpi_prt_ref_list.entries); + acpi_prt_ref_list.count++; return_VALUE(0); } @@ -390,6 +491,15 @@ } +static void __init acpi_irq_pic_mode(void) +{ + acpi_irq_model = ACPI_IRQ_MODEL_PIC; + acpi_bus_init_irq(); + + /* recalculate penalties */ + acpi_pci_link_calc_penalties(); +} + int __init acpi_pci_irq_init (void) { @@ -397,26 +507,25 @@ ACPI_FUNCTION_TRACE("acpi_pci_irq_init"); - if (!acpi_prt.count) { - printk(KERN_WARNING PREFIX "ACPI tables contain no PCI IRQ " - "routing entries\n"); - return_VALUE(-ENODEV); - } - - /* Make sure all link devices have a valid IRQ. */ - if (acpi_pci_link_check()) { - return_VALUE(-ENODEV); - } + /* Calculate IRQ penalties for each link device */ + acpi_pci_link_calc_penalties(); #ifdef CONFIG_X86_IO_APIC /* Program IOAPICs using data from PRT entries. */ if (acpi_irq_model == ACPI_IRQ_MODEL_IOAPIC) - mp_parse_prt(); + if (mp_parse_prt()) + acpi_irq_pic_mode(); #endif #ifdef CONFIG_IOSAPIC if (acpi_irq_model == ACPI_IRQ_MODEL_IOSAPIC) - iosapic_parse_prt(); + if (iosapic_parse_prt()) + return_VALUE(-ENODEV); #endif + + /* This one is last, as a catchall */ + if (acpi_irq_model == ACPI_IRQ_MODEL_PIC) + if (pic_parse_prt()) + return_VALUE(-ENODEV); pci_for_each_dev(dev) acpi_pci_irq_enable(dev); diff -urN linux-2.4.23-pre8/drivers/acpi/pci_link.c linux-2.4.23-pre8-pac1/drivers/acpi/pci_link.c --- linux-2.4.23-pre8/drivers/acpi/pci_link.c 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/acpi/pci_link.c 2003-10-24 14:31:25.000000000 +0200 @@ -444,23 +444,26 @@ * as 'best bets' for PCI use. */ -static int acpi_irq_penalty[ACPI_MAX_IRQS] = { +static int acpi_irq_default_penalty[ACPI_MAX_IRQS] = { 1000000, 1000000, 1000000, 10000, 10000, 0, 10000, 10000, 10000, 0, 0, 0, 10000, 100000, 100000, 100000, }; +static int acpi_irq_penalty[ACPI_MAX_IRQS] = { 0 }; int -acpi_pci_link_check (void) +acpi_pci_link_calc_penalties (void) { struct list_head *node = NULL; struct acpi_pci_link *link = NULL; int i = 0; - ACPI_FUNCTION_TRACE("acpi_pci_link_check"); + ACPI_FUNCTION_TRACE("acpi_pci_calc_penalties"); + memcpy(&acpi_irq_penalty, &acpi_irq_default_penalty, sizeof(acpi_irq_default_penalty)); + /* * Update penalties to facilitate IRQ balancing. */ @@ -471,7 +474,8 @@ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid link context\n")); continue; } - + link->irq.setonboot = 0; + if (link->irq.active) acpi_irq_penalty[link->irq.active] += 100; else if (link->irq.possible_count) { diff -urN linux-2.4.23-pre8/drivers/acpi/tables.c linux-2.4.23-pre8-pac1/drivers/acpi/tables.c --- linux-2.4.23-pre8/drivers/acpi/tables.c 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/acpi/tables.c 2003-10-24 14:31:25.000000000 +0200 @@ -262,10 +262,17 @@ /* Map the DSDT header via the pointer in the FADT */ if (id == ACPI_DSDT) { - struct acpi_table_fadt *fadt = (struct acpi_table_fadt *) *header; + struct fadt_descriptor_rev2 *fadt = (struct fadt_descriptor_rev2 *) *header; + + if (fadt->revision == 3 && fadt->Xdsdt) { + *header = (void *) __acpi_map_table(fadt->Xdsdt, + sizeof(struct acpi_table_header)); + } else if (fadt->V1_dsdt) { + *header = (void *) __acpi_map_table(fadt->V1_dsdt, + sizeof(struct acpi_table_header)); + } else + *header = 0; - *header = (void *) __acpi_map_table(fadt->dsdt_addr, - sizeof(struct acpi_table_header)); if (!*header) { printk(KERN_WARNING PREFIX "Unable to map DSDT\n"); return -ENODEV; diff -urN linux-2.4.23-pre8/drivers/block/DAC960.c linux-2.4.23-pre8-pac1/drivers/block/DAC960.c --- linux-2.4.23-pre8/drivers/block/DAC960.c 2002-11-29 00:53:12.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/block/DAC960.c 2003-10-24 14:31:25.000000000 +0200 @@ -1133,6 +1133,26 @@ DAC960PU/PD/PL 3.51 and above DAC960PU/PD/PL/P 2.73 and above */ +#if defined(__alpha__) + /* + DEC Alpha machines were often equipped with DAC960 cards that were + OEMed from Mylex, and had their own custom firmware. Version 2.70, + the last custom FW revision to be released by DEC for these older + controllers, appears to work quite well with this driver. + + Cards tested successfully were several versions each of the PD and + PU, called by DEC the KZPSC and KZPAC, respectively, and having + the Manufacturer Numbers (from Mylex), usually on a sticker on the + back of the board, of: + + KZPSC D040347 (1ch) or D040348 (2ch) or D040349 (3ch) + KZPAC D040395 (1ch) or D040396 (2ch) or D040397 (3ch) + */ +# define FIRMWARE_27x "2.70" +#else +# define FIRMWARE_27x "2.73" +#endif + if (Enquiry2.FirmwareID.MajorVersion == 0) { Enquiry2.FirmwareID.MajorVersion = @@ -1152,7 +1172,7 @@ (Controller->FirmwareVersion[0] == '3' && strcmp(Controller->FirmwareVersion, "3.51") >= 0) || (Controller->FirmwareVersion[0] == '2' && - strcmp(Controller->FirmwareVersion, "2.73") >= 0))) + strcmp(Controller->FirmwareVersion, FIRMWARE_27x) >= 0))) { DAC960_Failure(Controller, "FIRMWARE VERSION VERIFICATION"); DAC960_Error("Firmware Version = '%s'\n", Controller, diff -urN linux-2.4.23-pre8/drivers/block/elevator.c linux-2.4.23-pre8-pac1/drivers/block/elevator.c --- linux-2.4.23-pre8/drivers/block/elevator.c 2003-06-13 16:51:32.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/block/elevator.c 2003-10-24 14:31:25.000000000 +0200 @@ -27,6 +27,25 @@ #include #include + +static int compatible(struct request *req, struct buffer_head *bh, + request_queue_t *q, int rw, + int count, int max_sectors) +{ + if (q->head_active) + return 0; + if (req->waiting) + return 0; + if (req->rq_dev != bh->b_rdev) + return 0; + if (req->cmd != rw) + return 0; + if (req->nr_sectors + count > max_sectors) + return 0; + return 1; +} + + /* * This is a bit tricky. It's given that bh and rq are for the same * device, but the next request might of course not be. Run through @@ -83,22 +102,38 @@ struct list_head *entry = &q->queue_head; unsigned int count = bh->b_size >> 9, ret = ELEVATOR_NO_MERGE; struct request *__rq; - int backmerge_only = 0; + + /* + * Quick one-entry cache of last merge + * nb. we do no latency accounting this way. + */ + + if (q->last_request) { + struct request *__rq = q->last_request; - while (!backmerge_only && (entry = entry->prev) != head) { + if (compatible(__rq, bh, q, rw, count, max_sectors)) { + if (__rq->sector + __rq->nr_sectors == bh->b_rsector) { + *req = __rq; + return ELEVATOR_BACK_MERGE; + } + } + } + + + while ((entry = entry->prev) != head) { __rq = blkdev_entry_to_request(entry); /* * we can't insert beyond a zero sequence point */ if (__rq->elevator_sequence <= 0) - backmerge_only = 1; + break; if (__rq->waiting) continue; if (__rq->rq_dev != bh->b_rdev) continue; - if (!*req && bh_rq_in_between(bh, __rq, &q->queue_head) && !backmerge_only) + if (!*req && bh_rq_in_between(bh, __rq, &q->queue_head)) *req = __rq; if (__rq->cmd != rw) continue; @@ -108,7 +143,7 @@ ret = ELEVATOR_BACK_MERGE; *req = __rq; break; - } else if (__rq->sector - count == bh->b_rsector && !backmerge_only) { + } else if (__rq->sector - count == bh->b_rsector) { ret = ELEVATOR_FRONT_MERGE; __rq->elevator_sequence--; *req = __rq; diff -urN linux-2.4.23-pre8/drivers/block/ll_rw_blk.c linux-2.4.23-pre8-pac1/drivers/block/ll_rw_blk.c --- linux-2.4.23-pre8/drivers/block/ll_rw_blk.c 2003-10-24 14:27:20.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/block/ll_rw_blk.c 2003-10-24 14:31:25.000000000 +0200 @@ -383,8 +383,12 @@ { if (q->plugged) { q->plugged = 0; - if (!list_empty(&q->queue_head)) + if (!list_empty(&q->queue_head)) { + if (q->last_request == + blkdev_entry_next_request(&q->queue_head)) + q->last_request = NULL; q->request_fn(q); + } } } @@ -532,6 +536,7 @@ q->plug_tq.routine = &generic_unplug_device; q->plug_tq.data = q; q->plugged = 0; + q->last_request = NULL; q->can_throttle = 0; /* @@ -871,6 +876,7 @@ * inserted at elevator_merge time */ list_add(&req->queue, insert_here); + q->last_request = req; } /* @@ -893,24 +899,26 @@ if (q->can_throttle) oversized_batch = blk_oversized_queue_batch(q); - rl->count++; - /* - * paranoia check - */ - if (req->cmd == READ || req->cmd == WRITE) - rl->pending[req->cmd]--; - if (rl->pending[READ] > q->nr_requests) - printk("blk: reads: %u\n", rl->pending[READ]); - if (rl->pending[WRITE] > q->nr_requests) - printk("blk: writes: %u\n", rl->pending[WRITE]); - if (rl->pending[READ] + rl->pending[WRITE] > q->nr_requests) - printk("blk: r/w: %u + %u > %u\n", rl->pending[READ], rl->pending[WRITE], q->nr_requests); - list_add(&req->queue, &rl->free); - if (rl->count >= q->batch_requests && !oversized_batch) { + if (q->last_request == req) + q->last_request = NULL; + rl->count++; + /* + * paranoia check + */ + if (req->cmd == READ || req->cmd == WRITE) + rl->pending[req->cmd]--; + if (rl->pending[READ] > q->nr_requests) + printk("blk: reads: %u\n", rl->pending[READ]); + if (rl->pending[WRITE] > q->nr_requests) + printk("blk: writes: %u\n", rl->pending[WRITE]); + if (rl->pending[READ] + rl->pending[WRITE] > q->nr_requests) + printk("blk: r/w: %u + %u > %u\n", rl->pending[READ], rl->pending[WRITE], q->nr_requests); + list_add(&req->queue, &rl->free); + if (rl->count >= q->batch_requests && !oversized_batch) { smp_mb(); if (waitqueue_active(&q->wait_for_requests)) wake_up(&q->wait_for_requests); - } + } } } @@ -946,6 +954,7 @@ req->bhtail = next->bhtail; req->nr_sectors = req->hard_nr_sectors += next->hard_nr_sectors; list_del(&next->queue); + q->last_request = req; /* One last thing: we have removed a request, so we now have one less expected IO to complete for accounting purposes. */ diff -urN linux-2.4.23-pre8/drivers/cdrom/cdrom.c linux-2.4.23-pre8-pac1/drivers/cdrom/cdrom.c --- linux-2.4.23-pre8/drivers/cdrom/cdrom.c 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/cdrom/cdrom.c 2003-10-24 14:31:25.000000000 +0200 @@ -467,6 +467,10 @@ if ((fp->f_mode & FMODE_WRITE) && !CDROM_CAN(CDC_DVD_RAM)) return -EROFS; + + /* If the device is opened O_EXCL but there are other openers, return busy */ + if ( (fp->f_flags & O_EXCL) && (cdi->use_count>0) ) + return -EBUSY; /* if this was a O_NONBLOCK open and we should honor the flags, * do a quick open without drive/disc integrity checks. */ diff -urN linux-2.4.23-pre8/drivers/char/Config.in linux-2.4.23-pre8-pac1/drivers/char/Config.in --- linux-2.4.23-pre8/drivers/char/Config.in 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/Config.in 2003-10-24 14:31:25.000000000 +0200 @@ -35,6 +35,7 @@ fi bool 'Non-standard serial port support' CONFIG_SERIAL_NONSTANDARD if [ "$CONFIG_SERIAL_NONSTANDARD" = "y" ]; then + tristate ' Aurora Technology, Inc. asynchronous PCI cards V2' CONFIG_ATI_CD1865 tristate ' Computone IntelliPort Plus serial support' CONFIG_COMPUTONE tristate ' Comtrol Rocketport support' CONFIG_ROCKETPORT tristate ' Cyclades async mux support' CONFIG_CYCLADES @@ -225,6 +226,7 @@ tristate ' Acquire SBC Watchdog Timer' CONFIG_ACQUIRE_WDT tristate ' Advantech SBC Watchdog Timer' CONFIG_ADVANTECH_WDT tristate ' ALi M7101 PMU on ALi 1535D+ Watchdog Timer' CONFIG_ALIM1535_WDT + tristate ' ALi M6117 Watchdog Timer' CONFIG_ALIM6117_WDT tristate ' ALi M7101 PMU Watchdog Timer' CONFIG_ALIM7101_WDT tristate ' AMD "Elan" SC520 Watchdog Timer' CONFIG_SC520_WDT tristate ' Berkshire Products PC Watchdog' CONFIG_PCWATCHDOG @@ -300,6 +302,7 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_X86" = "y" -a "$CONFIG_X86_64" != "y" ]; then dep_tristate 'Sony Vaio Programmable I/O Control Device support (EXPERIMENTAL)' CONFIG_SONYPI $CONFIG_PCI fi +tristate 'Vertical blank driver' CONFIG_VBLANK $CONFIG_PCI mainmenu_option next_comment comment 'Ftape, the floppy tape device driver' diff -urN linux-2.4.23-pre8/drivers/char/Makefile linux-2.4.23-pre8-pac1/drivers/char/Makefile --- linux-2.4.23-pre8/drivers/char/Makefile 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/Makefile 2003-10-24 14:31:25.000000000 +0200 @@ -199,6 +199,12 @@ obj-$(CONFIG_SYNCLINKMP) += synclinkmp.o obj-$(CONFIG_N_HDLC) += n_hdlc.o obj-$(CONFIG_SPECIALIX) += specialix.o + +subdir-$(CONFIG_ATI_CD1865) += cd1865 +ifeq ($(CONFIG_ATI_CD1865),y) + obj-y += cd1865/SILX.o +endif + obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o obj-$(CONFIG_A2232) += ser_a2232.o generic_serial.o obj-$(CONFIG_SX) += sx.o generic_serial.o @@ -276,6 +282,8 @@ obj-$(CONFIG_NWFLASH) += nwflash.o obj-$(CONFIG_SCx200_GPIO) += scx200_gpio.o scx200.o +obj-$(CONFIG_VBLANK) += vblank.o + # 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 @@ -298,6 +306,7 @@ obj-$(CONFIG_SH_WDT) += shwdt.o obj-$(CONFIG_EUROTECH_WDT) += eurotechwdt.o obj-$(CONFIG_ALIM7101_WDT) += alim7101_wdt.o +obj-$(CONFIG_ALIM6117_WDT) += alim6117_wdt.o obj-$(CONFIG_ALIM1535_WDT) += alim1535d_wdt.o obj-$(CONFIG_INDYDOG) += indydog.o obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o diff -urN linux-2.4.23-pre8/drivers/char/alim6117_wdt.c linux-2.4.23-pre8-pac1/drivers/char/alim6117_wdt.c --- linux-2.4.23-pre8/drivers/char/alim6117_wdt.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/char/alim6117_wdt.c 2003-10-24 14:31:25.000000000 +0200 @@ -0,0 +1,446 @@ +/** + * ALi M6117 Watchdog timer driver. + * + * (c) Copyright 2003 Federico Bareilles , + * Instituto Argentino de Radio Astronomia (IAR). + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * The author does NOT admit liability nor provide warranty for any + * of this software. This material is provided "AS-IS" in the hope + * that it may be useful for others. + * + * Based on alim1535_wdt.c by Alan Cox and other WDT by several + * authors... + * + * ALi (Acer Labs) M6117 is an i386 that has the watchdog timer + * built in. Watchdog uses a 32.768KHz clock with a 24 bits + * counter. The timer ranges is from 30.5u sec to 512 sec with + * resolution 30.5u sec. When the timer times out; a system reset, + * NMI or IRQ may happen. This can be decided by the user's + * programming. + **/ + +#define ALI_WDT_VERSION "0.01c" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define OUR_NAME "alim6117_wdt" + +/* Port definitions: */ +#define M6117_PORT_INDEX 0x22 +#define M6117_PORT_DATA 0x23 +/* YES, the two unused ports of 8259: + * 0020-003f : pic1 + * + * The 8259 Interrup Controller uses four port addresses (0x20 through + * 0x23). Although IBM documentation indicates that these four port + * addresses are reserved for the 8259, only the two lower ports (0x20 + * and 0x21) ar documented as usable by programers. The two ports + * (0x22 and 0x23) are used only when reprogramming the 8259 for + * special dedicated systems that operate in modes which are not + * compatible with normal IBM PC operation (this case). + **/ + +/* Index for ALI M6117: */ +#define ALI_LOCK_REGISTER 0x13 +#define ALI_WDT 0x37 +#define ALI_WDT_SELECT 0x38 +#define ALI_WDT_DATA0 0x39 +#define ALI_WDT_DATA1 0x3a +#define ALI_WDT_DATA2 0x3b +#define ALI_WDT_CTRL 0x3c + +/* Time out generates signal select: */ +#define WDT_SIGNAL_IRQ3 0x10 +#define WDT_SIGNAL_IRQ4 0x20 +#define WDT_SIGNAL_IRQ5 0x30 +#define WDT_SIGNAL_IRQ6 0x40 +#define WDT_SIGNAL_IRQ7 0x50 +#define WDT_SIGNAL_IRQ9 0x60 +#define WDT_SIGNAL_IRQ10 0x70 +#define WDT_SIGNAL_IRQ11 0x80 +#define WDT_SIGNAL_IRQ12 0x90 +#define WDT_SIGNAL_IRQ14 0xa0 +#define WDT_SIGNAL_IRQ15 0xb0 +#define WDT_SIGNAL_NMI 0xc0 +#define WDT_SIGNAL_SRSET 0xd0 +/* set signal to use: */ +#define WDT_SIGNAL WDT_SIGNAL_SRSET + +/* ALI_WD_TIME_FACTOR is 1000000/30.5 */ +#define ALI_WD_TIME_FACTOR 32787 /* (from seconds to ALi counter) */ + +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int nowayout = 1; +#else +static int nowayout = 0; +#endif + +static unsigned long wdt_is_open; +static char ali_expect_close; +static int wdt_timeout = 60; +static int wdt_run = 0; +static spinlock_t ali_lock; /* Needed for 2.6/pre-empt to avoid clashing + index writes */ + +MODULE_PARM(nowayout, "i"); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); + +MODULE_PARM(wdt_timeout, "i"); +MODULE_PARM_DESC(wdt_timeout,"Watchdog timeout in seconds"); + + +static int alim6117_read(int index) +{ + outb(index, M6117_PORT_INDEX); + return inb(M6117_PORT_DATA); +} + +static void alim6117_write(int index, int data) +{ + outb(index, M6117_PORT_INDEX); + outb(data, M6117_PORT_DATA); +} + +static void alim6117_ulock_conf_register(void) +{ + alim6117_write(ALI_LOCK_REGISTER, 0xc5); +} + +static void alim6117_lock_conf_register(void) +{ + alim6117_write(ALI_LOCK_REGISTER, 0x00); +} + +static void alim6117_set_timeout(int time) +{ + u32 timeout_bits; + + timeout_bits = time * ALI_WD_TIME_FACTOR; + alim6117_write(ALI_WDT_DATA0, timeout_bits & 0xff); + alim6117_write(ALI_WDT_DATA1, (timeout_bits & 0xff00) >> 8); + alim6117_write(ALI_WDT_DATA2, (timeout_bits & 0xff0000) >> 16); + + return; +} + +static void alim6117_wdt_disable(void) +{ + int val = alim6117_read(ALI_WDT); + + val &= 0xbf; /* 1011|1111 */ + alim6117_write(ALI_WDT, val); +} + +static void alim6117_wdt_enable(void) +{ + int val = alim6117_read(ALI_WDT); + + val |= 0x40; /* 0100|0000 */ + alim6117_write(ALI_WDT, val); +} + +static void alim6117_wdt_signal_select(int signal) +{ + int val = alim6117_read(ALI_WDT_SELECT); + + val &= 0xf0; + val |= signal; + alim6117_write(ALI_WDT_SELECT, val); +} + +static void ali_wdt_ping(void) +{ + int val; + + /* if no run, no ping; wdt start when ping it. */ + if (wdt_run) { + spin_lock(&ali_lock); + alim6117_ulock_conf_register(); + val = alim6117_read(ALI_WDT); + val &= ~0x40; /* 0100|0000 */ + alim6117_write(ALI_WDT, val); + val |= 0x40; /* 0100|0000 */ + alim6117_write(ALI_WDT, val); + alim6117_lock_conf_register(); + spin_unlock(&ali_lock); + /* + printk(KERN_INFO OUR_NAME ": WDT ping...\n"); + */ + } else { + printk(KERN_WARNING OUR_NAME ": WDT is stopped\n"); + } +} + +static void ali_wdt_start(void) +{ + spin_lock(&ali_lock); + alim6117_ulock_conf_register(); + alim6117_wdt_disable(); + alim6117_set_timeout(wdt_timeout); + alim6117_wdt_signal_select(WDT_SIGNAL); + alim6117_wdt_enable(); + alim6117_lock_conf_register(); + spin_unlock(&ali_lock); + wdt_run = 1; +} + +static void ali_wdt_stop(void) +{ + int val; + if ( wdt_run ) { + spin_lock(&ali_lock); + alim6117_ulock_conf_register(); + val = alim6117_read(ALI_WDT); + val &= ~0x40; /* 0100|0000 */ + alim6117_write(ALI_WDT, val); + alim6117_lock_conf_register(); + spin_unlock(&ali_lock); + wdt_run = 0; + /* + printk(KERN_INFO OUR_NAME ": WDT stop...\n"); + */ + } +} + +/** + * ali_wdt_notify_sys: + * @this: our notifier block + * @code: the event being reported + * @unused: unused + * + * Our notifier is called on system shutdowns. We want to turn the timer + * off at reboot otherwise the machine will reboot again during memory + * test or worse yet during the following fsck. + * + */ + +static int ali_wdt_notify_sys(struct notifier_block *this, + unsigned long code, void *unused) +{ + if (code == SYS_DOWN || code == SYS_HALT) { + /* Turn the timer off */ + ali_wdt_stop(); + } + return NOTIFY_DONE; +} + +/** + * ali_write - writes to ALi watchdog + * @file: file handle to the watchdog + * @data: user address of data + * @len: length of data + * @ppos: pointer to the file offset + * + * Handle a write to the ALi watchdog. Writing to the file pings + * the watchdog and resets it. Writing the magic 'V' sequence allows + * the next close to turn off the watchdog. + */ + +static ssize_t ali_write(struct file *file, const char *data, + size_t len, loff_t * ppos) +{ + /* Can't seek (pwrite) on this device */ + if (ppos != &file->f_pos) + return -ESPIPE; + + /* Check if we've got the magic character 'V' and reload the timer */ + if (len) { + size_t i; + + ali_expect_close = 0; + + /* scan to see wether or not we got the magic character */ + for (i = 0; i != len; i++) { + u8 c; + if (get_user(c, data + i)) + return -EFAULT; + if (c == 'V') + ali_expect_close = 42; + } + ali_wdt_ping(); + return 1; + } + return 0; +} + +/** + * ali_ioctl - handle watchdog ioctls + * @inode: inode of the device + * @file: file handle to the device + * @cmd: watchdog command + * @arg: argument pointer + * + * Handle the watchdog ioctls supported by the ALi driver. + */ + +static int ali_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int options; + + static struct watchdog_info ident = { + .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT, + .firmware_version = 0, + .identity = "ALi M6117 WDT", + }; + + switch (cmd) { + case WDIOC_KEEPALIVE: + ali_wdt_ping(); + return 0; + case WDIOC_SETTIMEOUT: + if (get_user(options, (int *) arg)) + return -EFAULT; + if (options < 1 || options > 512) + return -EFAULT; + wdt_timeout = options; + ali_wdt_start(); + case WDIOC_GETTIMEOUT: + return put_user(wdt_timeout, (int *) arg); + case WDIOC_GETSUPPORT: + if (copy_to_user((struct watchdog_info *) arg, &ident, sizeof(ident))) + return -EFAULT; + return 0; + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + return put_user(0, (int *) arg); + case WDIOC_SETOPTIONS: + if (get_user(options, (int *) arg)) + return -EFAULT; + if (options & WDIOS_DISABLECARD) { + ali_wdt_stop(); + return 0; + } + if (options & WDIOS_ENABLECARD) { + ali_wdt_start(); + return 0; + } + return -EINVAL; + + default: + return -ENOTTY; + + } +} + +/** + * ali_open - handle open of ali watchdog + * @inode: inode of device + * @file: file handle to device + * + * Open the ALi watchdog device. Ensure only one person opens it + * at a time. Also start the watchdog running. + */ + +static int ali_open(struct inode *inode, struct file *file) +{ + if(test_and_set_bit(0, &wdt_is_open)) + return -EBUSY; + ali_wdt_start(); + + return 0; +} + +/** + * ali_release - close an ALi watchdog + * @inode: inode from VFS + * @file: file from VFS + * + * Close the ALi watchdog device. Actual shutdown of the timer + * only occurs if the magic sequence has been set or nowayout is + * disabled. + */ + +static int ali_release(struct inode *inode, struct file *file) +{ + if (ali_expect_close == 42 && !nowayout) { + ali_wdt_stop(); + } else { + printk(KERN_CRIT OUR_NAME + ": Unexpected close, not stopping watchdog!\n"); + } + ali_expect_close = 0; + clear_bit(0, &wdt_is_open); + + return 0; +} + +static struct file_operations ali_fops = { + .owner = THIS_MODULE, + .write = ali_write, + .ioctl = ali_ioctl, + .open = ali_open, + .release = ali_release, +}; + +static struct miscdevice ali_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &ali_fops, +}; + +/* + * The WDT needs to learn about soft shutdowns in order to turn the + * timebomb registers off. + */ + +static struct notifier_block ali_notifier = { + .notifier_call = ali_wdt_notify_sys, + .next = NULL, + .priority = 0 +}; + +static int __init alim6117_init(void) +{ + if (wdt_timeout < 1 || wdt_timeout > 512){ + printk(KERN_ERR OUR_NAME + ": Timeout out of range (0 < wdt_timeout <= 512)\n"); + return -EIO; + } + + spin_lock_init(&ali_lock); + + if (misc_register(&ali_miscdev) != 0) { + printk(KERN_ERR OUR_NAME + ": cannot register watchdog device node.\n"); + return -EIO; + } + + register_reboot_notifier(&ali_notifier); + + printk(KERN_INFO "WDT driver for ALi M6117 v(" + ALI_WDT_VERSION ") initialising.\n"); + + return 0; +} + +static void __exit alim6117_exit(void) +{ + misc_deregister(&ali_miscdev); + unregister_reboot_notifier(&ali_notifier); + + ali_wdt_stop(); /* Stop the timer */ +} + +module_init(alim6117_init); +module_exit(alim6117_exit); + +MODULE_AUTHOR("Federico Bareilles "); +MODULE_DESCRIPTION("Driver for watchdog timer in ALi M6117 chip."); +MODULE_LICENSE("GPL"); +MODULE_SUPPORTED_DEVICE("watchdog"); + +EXPORT_NO_SYMBOLS; diff -urN linux-2.4.23-pre8/drivers/char/amiserial.c linux-2.4.23-pre8-pac1/drivers/char/amiserial.c --- linux-2.4.23-pre8/drivers/char/amiserial.c 2002-11-29 00:53:12.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/char/amiserial.c 2003-10-24 14:31:25.000000000 +0200 @@ -1544,7 +1544,7 @@ #ifdef SERIAL_DEBUG_OPEN printk("rs_close ttys%d, count = %d\n", info->line, state->count); #endif - if ((tty->count == 1) && (state->count != 1)) { + if ((atomic_read(&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 diff -urN linux-2.4.23-pre8/drivers/char/cd1865/Makefile linux-2.4.23-pre8-pac1/drivers/char/cd1865/Makefile --- linux-2.4.23-pre8/drivers/char/cd1865/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/char/cd1865/Makefile 2003-10-24 14:31:25.000000000 +0200 @@ -0,0 +1,27 @@ +# Copyright (C) 2001 By Joachim Martillo, Telford Tools, Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version +# 2 of the License, or (at your option) any later version. + +# File: drivers/net/WAN/atiXX50/Makefile +# +# Makefile for the Aurora ESSC based cards +# Specifically the 2520, 4020, 4520, 8520 +# + +all: SILX.o + +O_TARGET := SILX.o + +obj-y := cd1865.o +obj-m := $(O_TARGET) + +EXTRA_CFLAGS += -I. + +include $(TOPDIR)/Rules.make + +clean: + rm -f core *.o *.a *.s *~ + diff -urN linux-2.4.23-pre8/drivers/char/cd1865/cd1865.c linux-2.4.23-pre8-pac1/drivers/char/cd1865/cd1865.c --- linux-2.4.23-pre8/drivers/char/cd1865/cd1865.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/char/cd1865/cd1865.c 2003-10-24 14:31:25.000000000 +0200 @@ -0,0 +1,2913 @@ +/* -*- linux-c -*- */ +/* + * This code was modified from + * specialix.c -- specialix IO8+ multiport serial driver. + * + * Copyright (C) 1997 Roger Wolff (R.E.Wolff@BitWizard.nl) + * Copyright (C) 1994-1996 Dmitry Gorodchanin (pgmdsg@ibi.com) + * Modifications (C) 2002 Telford Tools, Inc. (martillo@telfordtools.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. + * + */ + +#define VERSION "2.11" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cdsiolx.h" +#include "../cd1865.h" /* will move all files up one level */ +#include "siolx.h" +#include "plx9060.h" + +#define SIOLX_NORMAL_MAJOR 254 /* One is needed */ +#define SIOLX_ID 0x10 +#define CD186x_MSMR 0x61 /* modem/timer iack */ +#define CD186x_TSMR 0x62 /* tx iack */ +#define CD186x_RSMR 0x63 /* rx iack */ + +/* Configurable options: */ + +/* Am I paranoid or not ? ;-) */ +#define SIOLX_PARANOIA_CHECK + +/* Do I trust the IRQ from the card? (enabeling it doesn't seem to help) + When the IRQ routine leaves the chip in a state that is keeps on + requiring attention, the timer doesn't help either. */ +#undef SIOLX_TIMER +/* + * The following defines are mostly for testing purposes. But if you need + * some nice reporting in your syslog, you can define them also. + */ +#undef SIOLX_REPORT_FIFO +#undef SIOLX_REPORT_OVERRUN + +#ifdef CONFIG_SIOLX_RTSCTS /* may need to set this */ +#define SIOLX_CRTSCTS(bla) 1 +#else +#define SIOLX_CRTSCTS(tty) C_CRTSCTS(tty) +#endif + +/* Used to be outb (0xff, 0x80); */ +#define short_pause() udelay (1) + +#define SIOLX_LEGAL_FLAGS \ + (ASYNC_HUP_NOTIFY | ASYNC_SAK | ASYNC_SPLIT_TERMIOS | \ + ASYNC_SPD_HI | ASYNC_SPEED_VHI | ASYNC_SESSION_LOCKOUT | \ + ASYNC_PGRP_LOCKOUT | ASYNC_CALLOUT_NOHUP) + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +DECLARE_TASK_QUEUE(tq_siolx); + +#undef RS_EVENT_WRITE_WAKEUP +#define RS_EVENT_WRITE_WAKEUP 0 + +#define SIOLX_TYPE_NORMAL 1 +#define SIOLX_TYPE_CALLOUT 2 + +#define BD_8000P 1 +#define BD_16000P 2 +#define BD_8000C 3 +#define BD_16000C 4 +#define BD_MAX BD_16000C + +static struct siolx_board *SiolxIrqRoot[SIOLX_NUMINTS]; + +static char *sio16_board_type[] = +{ + "unknown", + " 8000P ", + "16000P ", + " 8000C ", + "16000C " +}; +static struct tty_driver siolx_driver, siolx_callout_driver; +static int siolx_refcount; +static unsigned char * tmp_buf; +static DECLARE_MUTEX(tmp_buf_sem); +static unsigned long baud_table[] = +{ + 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, + 9600, 19200, 38400, 57600, 115200, 0, +}; +static int siolx_debug = 0; /* turns on lots of */ + /* debugging messages*/ +static int siolx_major = SIOLX_NORMAL_MAJOR; +#ifdef MODULE +static int siolx_minorstart = 256; +#endif +static int siolx_vendor_id = PCI_VENDOR_ID_PLX; +static int siolx_device_id = PCI_DEVICE_ID_PLX_9060SD; +static int siolx_subsystem_vendor = AURASUBSYSTEM_VENDOR_ID; +static int siolx_subsystem_pci_device = AURASUBSYSTEM_MPASYNCPCI; +static int siolx_subsystem_cpci_device = AURASUBSYSTEM_MPASYNCcPCI; +static int siolx_bhindex = SIOLX_BH; /* if this softinterrupt slot is filled */ + +MODULE_PARM(siolx_vendor_id, "i"); +MODULE_PARM(siolx_device_id, "i"); +#ifdef MODULE +MODULE_PARM(siolx_minorstart, "i"); +#endif +MODULE_PARM(siolx_major, "i"); +MODULE_PARM(siolx_subsystem_vendor, "i"); +MODULE_PARM(siolx_subsystem_pci_device, "i"); +MODULE_PARM(siolx_subsystem_cpci_device, "i"); +MODULE_PARM(siolx_bhindex, "i"); + +static struct siolx_board *siolx_board_root; +static struct siolx_board *siolx_board_last; +static struct siolx_port *siolx_port_root; +static struct siolx_port *siolx_port_last; +static unsigned int NumSiolxPorts; +static struct tty_struct **siolx_table; /* make dynamic */ +static struct termios **siolx_termios; +static struct termios **siolx_termios_locked; +static int siolx_driver_registered; +static int siolx_callout_driver_registered; + +#ifdef SIOLX_TIMER +static struct timer_list missed_irq_timer; +static void siolx_interrupt(int irq, void * dev_id, struct pt_regs * regs); +#endif + +extern struct tty_driver *get_tty_driver(kdev_t device); + +static inline int port_No_by_chip (struct siolx_port const * port) +{ + return SIOLX_PORT(port->boardport); +} + +/* Describe the current board and port configuration */ + +static int siolx_read_proc(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + struct siolx_port *port = siolx_port_root; + off_t begin = 0; + int len = 0; + unsigned int typeno; + char *revision = "$Revision: 1.11 $"; + + len += sprintf(page, "SIOLX Version %s. %s\n", VERSION, revision); + len += sprintf(page+len, "TTY MAJOR = %d, CUA MAJOR = %d.\n", + siolx_driver.major, siolx_callout_driver.major); + + for (port = siolx_port_root; port != NULL; port = port->next_by_global_list) + { + typeno = port->board->boardtype; + if(typeno > BD_MAX) + { + typeno = 0; + } + len += sprintf(page+len, + "%3.3d: bd %2.2d: %s: ch %d: pt %2.2d/%d: tp %4.4d%c: bs %2.2d: sl %2.2d: ir %2.2d: fl %c%c%c%c%c\n", + siolx_driver.minor_start + port->driverport, + port->board->boardnumber, + sio16_board_type[typeno], + port->board->chipnumber, + port->boardport, + port_No_by_chip(port), /* port relative to chip */ + port->board->chiptype, + port->board->chiprev, + port->board->pdev.bus->number, + PCI_SLOT(port->board->pdev.devfn), + port->board->irq, + (port->flags & ASYNC_INITIALIZED) ? 'I' : ' ', + (port->flags & ASYNC_CALLOUT_ACTIVE) ? 'D' : ' ', + (port->flags & ASYNC_NORMAL_ACTIVE) ? 'T' : ' ', + (port->flags & ASYNC_CLOSING) ? 'C' : ' ', + port->board->reario ? 'R' : ' '); + if (len+begin > off+count) + { + goto done; + } + if (len+begin < off) + { + begin += len; + len = 0; + } + } + *eof = 1; + done: + if (off >= len+begin) + { + return 0; + } + *start = page + (off-begin); + return ((count < begin+len-off) ? count : begin+len-off); +} + +#ifndef MODULE +static int GetMinorStart(void) /* minor start can be determined on fly when driver linked to kernel */ +{ + struct tty_driver *ttydriver; + int minor_start = 0; + kdev_t device; + + device = MKDEV(siolx_major, minor_start); + while(ttydriver = get_tty_driver(device), ttydriver != NULL) + { + minor_start += ttydriver->num; + device = MKDEV(TTY_MAJOR, minor_start); + } + return minor_start; + +} +#endif + +/* only once per board chain */ +void SiolxResetBoard(struct siolx_board * bp, struct pci_dev *pdev) +{ + register unsigned int regvalue; + unsigned char savedvalue; + /* + * Yuch. Here's the deal with the reset bits in the + * ECNTL register of the 9060SD. + * + * It appears that LCLRST resets the PLX local configuration + * registers (not the PCI configuration registers) to their + * default values. We need to use LCLRST because it + * is the command (I think) that pulls the local reset + * line on the local bus side of the 9060SD. + * + * Unfortunately, by resetting the PLX local configuration + * registers, we can't use the damn board. So we must + * reinitialize them. The easiest way to do that is to run + * the LDREG command. Unfortunately, it has the side effect + * of reinitializing the PCI configuration registers. It seems, + * however that only the value stowed in ILINE gets choked; all + * of the others seem to be properly preserved. + * + * So, what the code does now is to get a copy of ILINE by + * hand, and then restore it after reloading the registers. + */ + + bp->pdev = *pdev; + bp->plx_vaddr = (unsigned long) ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); + if(bp->plx_vaddr) + { + regvalue = readl(bp->plx_vaddr + PLX_ECNTL); + regvalue &= ~PLX_ECNTLLDREG; + regvalue |= PLX_ECNTLLCLRST; + writel(regvalue, bp->plx_vaddr + PLX_ECNTL); + udelay(200); + regvalue &= ~PLX_ECNTLLCLRST; + writel(regvalue, bp->plx_vaddr + PLX_ECNTL); + pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &savedvalue); + regvalue |= PLX_ECNTLLDREG; + writel(regvalue, bp->plx_vaddr + PLX_ECNTL); + udelay(200); + regvalue &= ~PLX_ECNTLLDREG; + writel(regvalue, bp->plx_vaddr + PLX_ECNTL); + pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, savedvalue); + regvalue |= PLX_ECNTLINITSTAT; + writel(regvalue, bp->plx_vaddr + PLX_ECNTL); + writel(0, bp->plx_vaddr + PLX_ICSR); + } +} + +void SiolxShutdownBoard(struct siolx_board * bp) +{ + register unsigned int regvalue; + unsigned char savedvalue; + struct pci_dev *pdev; + + if(bp->chipnumber == 0) /* only shutdown first in a chain */ + { + pdev = &bp->pdev; + + writel(0, bp->plx_vaddr + PLX_ICSR); + regvalue = readl(bp->plx_vaddr + PLX_ECNTL); + regvalue &= ~PLX_ECNTLLDREG; + regvalue |= PLX_ECNTLLCLRST; + writel(regvalue, bp->plx_vaddr + PLX_ECNTL); + udelay(200); + regvalue &= ~PLX_ECNTLLCLRST; + writel(regvalue, bp->plx_vaddr + PLX_ECNTL); + pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &savedvalue); + regvalue |= PLX_ECNTLLDREG; + writel(regvalue, bp->plx_vaddr + PLX_ECNTL); + udelay(200); + regvalue &= ~PLX_ECNTLLDREG; + writel(regvalue, bp->plx_vaddr + PLX_ECNTL); + pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, savedvalue); + regvalue |= PLX_ECNTLINITSTAT; + writel(regvalue, bp->plx_vaddr + PLX_ECNTL); + writel(0, bp->plx_vaddr + PLX_ICSR); + iounmap((void*)bp->plx_vaddr); + bp->plx_vaddr = 0; + } +} + +static inline int siolx_paranoia_check(struct siolx_port const * port, + kdev_t device, const char *routine) +{ +#ifdef SIOLX_PARANOIA_CHECK + static const char *badmagic = + KERN_ERR "siolx: Warning: bad siolx port magic number for device %s in %s\n"; + static const char *badinfo = + KERN_ERR "siolx: Warning: null siolx port for device %s in %s\n"; + + if (!port) + { + printk(badinfo, kdevname(device), routine); + return 1; + } + if (port->magic != SIOLX_MAGIC) + { + printk(badmagic, kdevname(device), routine); + return 1; + } +#endif + return 0; +} + + +/* + * + * Service functions for siolx Aurora Asynchronous Adapter driver. + * + */ + +/* Get board number from pointer */ +static inline int board_No (struct siolx_board * bp) +{ + return bp->boardnumber; /* note same for all chips/boards in a chain */ +} + + +/* Get port number from pointer */ +static inline int port_No (struct siolx_port const * port) +{ + return port->driverport; /* offset from minor start */ +} + +/* Get pointer to board from pointer to port */ +static inline struct siolx_board * port_Board(struct siolx_port const * port) +{ + return port->board; /* same for ports on both chips on a board */ +} + + +/* Input Byte from CL CD186x register */ +static inline unsigned char siolx_in(struct siolx_board * bp, unsigned short reg) +{ + return readb (bp->base + reg); +} + + +/* Output Byte to CL CD186x register */ +static inline void siolx_out(struct siolx_board * bp, unsigned short reg, + unsigned char val) +{ + writeb(val, bp->base + reg); +} + + +/* Wait for Channel Command Register ready */ +static int siolx_wait_CCR(struct siolx_board * bp) +{ + unsigned long delay; + + for (delay = SIOLX_CCR_TIMEOUT; delay; delay--) + { + udelay(1); + if (!siolx_in(bp, CD186x_CCR)) + { + return 0; + } + } + printk(KERN_ERR "siolx:board %d: timeout waiting for CCR.\n", board_No(bp)); + return -1; +} + +/* Wait for ready */ +static int siolx_wait_GIVR(struct siolx_board * bp) +{ + unsigned long delay; + + for (delay = SIOLX_CCR_TIMEOUT; delay; delay--) + { + udelay(1); + if (siolx_in(bp, CD186x_GIVR) == (unsigned char) 0xff) + { + return 0; + } + } + printk(KERN_ERR "siolx: board %d: timeout waiting for GIVR.\n", board_No(bp)); + return -1; +} + +static inline void siolx_release_io_range(struct siolx_board * bp) +{ + if((bp->chipnumber == 0) && bp->vaddr) /* only release from first board in a chain */ + { + iounmap((void*)bp->vaddr); + bp->vaddr = 0; + } +} + +/* Must be called with enabled interrupts */ + +static inline void siolx_long_delay(unsigned long delay) +{ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(delay); +} + +/* Reset and setup CD186x chip */ +static int siolx_init_CD186x(struct siolx_board * bp) +{ + unsigned long flags; + int scaler; + int rv = 1; + int rev; + int chip; + + save_flags(flags); /* not sure of need to turn off ints */ + cli(); + if(siolx_wait_CCR(bp)) + { + restore_flags(flags); + return 0; /* Wait for CCR ready */ + } + siolx_out(bp, CD186x_CAR, 0); + siolx_out(bp, CD186x_GIVR, 0); + siolx_out(bp, CD186x_CCR, CCR_HARDRESET); /* Reset CD186x chip */ + if(siolx_wait_GIVR(bp)) + { + restore_flags(flags); + return 0; + } + sti(); + siolx_long_delay(HZ/20); /* Delay 0.05 sec */ + cli(); + siolx_out(bp, CD186x_GIVR, SIOLX_ID | (bp->chipnumber ? 0x80 : 0)); /* Set ID for this chip */ +#if 0 + siolx_out(bp, CD186x_GICR, 0); /* Clear all bits */ +#endif + scaler = SIOLX_OSCFREQ/1000; + siolx_out(bp, CD186x_PPRH, scaler >> 8); + siolx_out(bp, CD186x_PPRL, scaler & 0xff); + + /* Chip revcode pkgtype + GFRCR SRCR bit 7 + CD180 rev B 0x81 0 + CD180 rev C 0x82 0 + CD1864 rev A 0x82 1 + CD1865 rev A 0x83 1 -- Do not use!!! Does not work. + CD1865 rev B 0x84 1 + -- Thanks to Gwen Wang, Cirrus Logic. + */ + + switch (siolx_in(bp, CD186x_GFRCR)) + { + case 0x82: + chip = 1864; + rev='A'; + break; + case 0x83: + chip = 1865; + rev='A'; + break; + case 0x84: + chip = 1865; + rev='B'; + break; + case 0x85: + chip = 1865; + rev='C'; + break; /* Does not exist at this time */ + default: + chip=-1; + rev='x'; + break; + } + +#if SIOLX_DEBUG > 2 + printk (KERN_DEBUG " GFCR = 0x%02x\n", siolx_in(bp, CD186x_GFRCR) ); +#endif + + siolx_out(bp, CD186x_MSMR, CD186x_MRAR); /* load up match regs with address regs */ + siolx_out(bp, CD186x_TSMR, CD186x_TRAR); + siolx_out(bp, CD186x_RSMR, CD186x_RRAR); + +#if 0 + DEBUGPRINT((KERN_ALERT "match reg values are msmr %x, tsmr %x, rsmr %x.\n", + siolx_in(bp, CD186x_MSMR), + siolx_in(bp, CD186x_TSMR), + siolx_in(bp, CD186x_RSMR))); +#endif + + siolx_out(bp, CD186x_SRCR, SRCR_AUTOPRI | SRCR_GLOBPRI | SRCR_REGACKEN); + /* Setting up prescaler. We need 4 ticks per 1 ms */ + + printk(KERN_INFO"siolx: CD%4.4d%c detected at 0x%lx, IRQ %d, on Aurora asynchronous adapter board %d, chip number %d.\n", + chip, rev, bp->base, bp->irq, board_No(bp), bp->chipnumber); + + bp->chiptype = chip; + bp->chiprev = rev; + + restore_flags(flags); + return rv; +} + + +#ifdef SIOLX_TIMER +void missed_irq (unsigned long data) +{ + if (siolx_in ((struct siolx_board *)data, CD186x_SRSR) & + (SRSR_RREQint | + SRSR_TREQint | + SRSR_MREQint)) + { + printk (KERN_INFO "Missed interrupt... Calling int from timer. \n"); + siolx_interrupt (((struct siolx_board *)data)->irq, + NULL, NULL); + } + missed_irq_timer.expires = jiffies + HZ; + add_timer (&missed_irq_timer); +} +#endif + +/* Main probing routine, also sets irq. */ +static int siolx_probe(struct siolx_board *bp) +{ + unsigned char val1, val2; + + /* Are the I/O ports here ? */ + siolx_out(bp, CD186x_PPRL, 0x5a); + short_pause (); + val1 = siolx_in(bp, CD186x_PPRL); + + siolx_out(bp, CD186x_PPRL, 0xa5); + short_pause (); + val2 = siolx_in(bp, CD186x_PPRL); + + if ((val1 != 0x5a) || (val2 != 0xa5)) + { + printk(KERN_INFO + "siolx: cd serial chip not found at base %ld.\n", + bp->base); + return 1; + } + + /* Reset CD186x */ + if (!siolx_init_CD186x(bp)) + { + return -EIO; + } + +#ifdef SIOLX_TIMER + init_timer (&missed_irq_timer); + missed_irq_timer.function = missed_irq; + missed_irq_timer.data = (unsigned long) bp; + missed_irq_timer.expires = jiffies + HZ; + add_timer (&missed_irq_timer); +#endif + return 0; +} + +/* + * + * Interrupt processing routines. + * */ + +static inline void siolx_mark_event(struct siolx_port * port, int event) +{ + /* + * I'm not quite happy with current scheme all serial + * drivers use their own BH routine. + * It seems this easily can be done with one BH routine + * serving for all serial drivers. + * For now I must introduce another one - SIOLX_BH. + * Still hope this will be changed in near future. + * -- Dmitry. + */ + /* I use a module parameter that can be set at module + * load time so that this driver can be downloaded into + * a kernel where the value of SIOLX_BX has been allocated + * to something else. This kludge was not necessary + * in the ASLX driver because AURORA_BH had already + * been allocated for the sparc and there was no + * similar driver for x86 while the ASLX driver probably + * will not work for the SPARC and is not guaranteed to + * do so (at some point I should clean this situation up) -- Joachim*/ + set_bit(event, &port->event); + queue_task(&port->tqueue, &tq_siolx); + mark_bh(siolx_bhindex); +} + +static inline struct siolx_port * siolx_get_port(struct siolx_board * bp, + unsigned char const * what) +{ + unsigned char channel; + struct siolx_port * port; + + channel = siolx_in(bp, CD186x_GICR) >> GICR_CHAN_OFF; + if (channel < CD186x_NCH) + { + port = bp->portlist; + while(port) + { + if(channel == 0) + { + break; + } + port = port->next_by_board; + --channel; + } + + if(port && (port->flags & ASYNC_INITIALIZED)) /* port should be opened */ + { + return port; + } + } + printk(KERN_INFO "sx%d: %s interrupt from invalid port %d\n", + board_No(bp), what, channel); + return NULL; +} + + +static inline void siolx_receive_exc(struct siolx_board * bp) +{ + struct siolx_port *port; + struct tty_struct *tty; + unsigned char status; + unsigned char ch; + + if (!(port = siolx_get_port(bp, "Receive"))) + return; + + tty = port->tty; + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + { + printk(KERN_INFO "sx%d: port %d: Working around flip buffer overflow.\n", + board_No(bp), port_No(port)); + return; + } + +#ifdef SIOLX_REPORT_OVERRUN + status = siolx_in(bp, CD186x_RCSR); + if (status & RCSR_OE) + { + port->overrun++; +#if SIOLX_DEBUG + printk(KERN_DEBUG "sx%d: port %d: Overrun. Total %ld overruns.\n", + board_No(bp), port_No(port), port->overrun); +#endif + } + status &= port->mark_mask; +#else + status = siolx_in(bp, CD186x_RCSR) & port->mark_mask; +#endif + ch = siolx_in(bp, CD186x_RDR); + if (!status) + { + return; + } + if (status & RCSR_TOUT) + { + printk(KERN_INFO "siolx: board %d: chip %d: port %d: Receiver timeout. Hardware problems ?\n", + board_No(bp), bp->chipnumber, port_No(port)); + return; + + } + else if (status & RCSR_BREAK) + { +#ifdef SIOLX_DEBUG + printk(KERN_DEBUG "siolx: board %d: chip %d: port %d: Handling break...\n", + board_No(bp), bp->chipnumber, port_No(port)); +#endif + *tty->flip.flag_buf_ptr++ = TTY_BREAK; + if (port->flags & ASYNC_SAK) + { + do_SAK(tty); + } + + } + else if (status & RCSR_PE) + { + *tty->flip.flag_buf_ptr++ = TTY_PARITY; + } + else if (status & RCSR_FE) + { + *tty->flip.flag_buf_ptr++ = TTY_FRAME; + } + + else if (status & RCSR_OE) + { + *tty->flip.flag_buf_ptr++ = TTY_OVERRUN; + } + + else + { + *tty->flip.flag_buf_ptr++ = 0; + } + + *tty->flip.char_buf_ptr++ = ch; + tty->flip.count++; + queue_task(&tty->flip.tqueue, &tq_timer); +} + + +static inline void siolx_receive(struct siolx_board * bp) +{ + struct siolx_port *port; + struct tty_struct *tty; + unsigned char count; + + if (!(port = siolx_get_port(bp, "Receive"))) + return; + + tty = port->tty; + + count = siolx_in(bp, CD186x_RDCR); + +#ifdef SIOLX_REPORT_FIFO + port->hits[count > 8 ? 9 : count]++; +#endif + + while (count--) + { + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + { + printk(KERN_INFO "siolx: board %d: chip %d: port %d: Working around flip buffer overflow.\n", + board_No(bp), bp->chipnumber, port_No(port)); + break; + } + *tty->flip.char_buf_ptr++ = siolx_in(bp, CD186x_RDR); + *tty->flip.flag_buf_ptr++ = 0; + tty->flip.count++; + } + queue_task(&tty->flip.tqueue, &tq_timer); +} + +static inline void siolx_transmit(struct siolx_board * bp) +{ + struct siolx_port *port; + struct tty_struct *tty; + unsigned char count; + + if (!(port = siolx_get_port(bp, "Transmit"))) + return; + + tty = port->tty; + + if(port->IER & IER_TXEMPTY) + { + /* FIFO drained */ +#if 0 + siolx_out(bp, CD186x_CAR, port_No_by_chip(port)); +#endif + port->IER &= ~IER_TXEMPTY; + siolx_out(bp, CD186x_IER, port->IER); + return; + } + + if(((port->xmit_cnt <= 0) && !port->break_length) || + tty->stopped || tty->hw_stopped) + { +#if 0 + siolx_out(bp, CD186x_CAR, port_No_by_chip(port)); +#endif + port->IER &= ~IER_TXRDY; + siolx_out(bp, CD186x_IER, port->IER); + return; + } + + if (port->break_length) + { + if (port->break_length > 0) + { + if (port->COR2 & COR2_ETC) + { + siolx_out(bp, CD186x_TDR, CD186x_C_ESC); + siolx_out(bp, CD186x_TDR, CD186x_C_SBRK); + port->COR2 &= ~COR2_ETC; + } + count = MIN(port->break_length, 0xff); + siolx_out(bp, CD186x_TDR, CD186x_C_ESC); + siolx_out(bp, CD186x_TDR, CD186x_C_DELAY); + siolx_out(bp, CD186x_TDR, count); + if (!(port->break_length -= count)) + { + port->break_length--; + } + } + else + { + siolx_out(bp, CD186x_TDR, CD186x_C_ESC); + siolx_out(bp, CD186x_TDR, CD186x_C_EBRK); + siolx_out(bp, CD186x_COR2, port->COR2); + siolx_wait_CCR(bp); + siolx_out(bp, CD186x_CCR, CCR_CORCHG2); + port->break_length = 0; + } + return; + } + + count = CD186x_NFIFO; + do + { + siolx_out(bp, CD186x_TDR, port->xmit_buf[port->xmit_tail++]); + port->xmit_tail = port->xmit_tail & (SERIAL_XMIT_SIZE-1); + if (--port->xmit_cnt <= 0) + { + break; + } + } while (--count > 0); + + if (port->xmit_cnt <= 0) + { +#if 0 + siolx_out(bp, CD186x_CAR, port_No_by_chip(port)); +#endif + port->IER &= ~IER_TXRDY; + siolx_out(bp, CD186x_IER, port->IER); + } + if (port->xmit_cnt <= port->wakeup_chars) + { + siolx_mark_event(port, RS_EVENT_WRITE_WAKEUP); + } +} + + +static inline void siolx_check_modem(struct siolx_board * bp) +{ + struct siolx_port *port; + struct tty_struct *tty; + unsigned char mcr; + +#ifdef SIOLX_DEBUG + printk (KERN_DEBUG "Modem intr. "); +#endif + if (!(port = siolx_get_port(bp, "Modem"))) + { + return; + } + + tty = port->tty; + + mcr = siolx_in(bp, CD186x_MCR); + DEBUGPRINT((KERN_ALERT "mcr = %02x.\n", mcr)); + + if ((mcr & MCR_CDCHG)) + { +#ifdef SIOLX_DEBUG + DEBUGPRINT((KERN_DEBUG "CD just changed... ")); +#endif + if (siolx_in(bp, CD186x_MSVR) & MSVR_CD) + { +#ifdef SIOLX_DEBUG + DEBUGPRINT(( "Waking up guys in open.\n")); +#endif + wake_up_interruptible(&port->open_wait); /* note no linefeed in previous print */ + } + else if (!((port->flags & ASYNC_CALLOUT_ACTIVE) && + (port->flags & ASYNC_CALLOUT_NOHUP))) + { +#ifdef SIOLX_DEBUG + DEBUGPRINT(( "Sending HUP.\n")); /* note no linefeed in previous print */ +#endif + MOD_INC_USE_COUNT; + if (schedule_task(&port->tqueue_hangup) == 0) + { + MOD_DEC_USE_COUNT; + } + } + else + { +#ifdef SIOLX_DEBUG + DEBUGPRINT(("Don't need to send HUP.\n")); /* note no linefeed in previous print */ +#endif + } + } + +#ifdef SIOLX_BRAIN_DAMAGED_CTS + if (mcr & MCR_CTSCHG) + { + if (siolx_in(bp, CD186x_MSVR) & MSVR_CTS) + { + tty->hw_stopped = 0; + port->IER |= IER_TXRDY; + if (port->xmit_cnt <= port->wakeup_chars) + siolx_mark_event(port, RS_EVENT_WRITE_WAKEUP); + } + else + { + tty->hw_stopped = 1; + port->IER &= ~IER_TXRDY; + } + siolx_out(bp, CD186x_IER, port->IER); + } + if (mcr & MCR_DSSXHG) + { + if (siolx_in(bp, CD186x_MSVR) & MSVR_DSR) + { + tty->hw_stopped = 0; + port->IER |= IER_TXRDY; + if (port->xmit_cnt <= port->wakeup_chars) + { + siolx_mark_event(port, RS_EVENT_WRITE_WAKEUP); + } + } + else + { + tty->hw_stopped = 1; + port->IER &= ~IER_TXRDY; + } + siolx_out(bp, CD186x_IER, port->IER); + } +#endif /* SIOLX_BRAIN_DAMAGED_CTS */ + + /* Clear change bits */ + siolx_out(bp, CD186x_MCR, 0); +} + +/* The main interrupt processing routine */ +static void siolx_interrupt(int irq, void * dev_id, struct pt_regs * regs) +{ + unsigned char status; + unsigned char rcsr; + struct siolx_board *bp; + + if((irq < 0) || (irq >= SIOLX_NUMINTS)) + { + printk(KERN_ALERT "siolx: bad interrupt value %i.\n", irq); + return; + } + /* walk through all the cards on the interrupt that occurred. */ + for(bp = SiolxIrqRoot[irq]; bp != NULL; bp = bp->next_by_interrupt) + + { + while((readl(bp->intstatus) & PLX_ICSRINTACTIVE) != 0) /* work on on board */ + { + status = siolx_in(bp, CD186x_SRSR); + + if(status & SRSR_RREQint) + { + siolx_in(bp, CD186x_RRAR); + rcsr = siolx_in(bp, CD186x_RCSR); + if(rcsr == 0) + { + siolx_receive(bp); + } + else + { + siolx_receive_exc(bp); + } + } + else if (status & SRSR_TREQint) + { + siolx_in(bp, CD186x_TRAR); + siolx_transmit(bp); + } + else if (status & SRSR_MREQint) + { + siolx_in(bp, CD186x_MRAR); + siolx_check_modem(bp); + } + siolx_out(bp, CD186x_EOIR, 1); /* acknowledge the interrupt */ + bp = bp->next_by_chain; /* go to next chip on card -- maybe this one */ + } /* it does not matter if bp changes all in a chain have same next by interrupt */ + } +} + + +/* + * Setting up port characteristics. + * Must be called with disabled interrupts + */ +static void siolx_change_speed(struct siolx_board *bp, struct siolx_port *port) +{ + struct tty_struct *tty; + unsigned long baud; + long tmp; + unsigned char cor1 = 0, cor3 = 0; + unsigned char mcor1 = 0, mcor2 = 0; + static int again; + + tty = port->tty; + + if(!tty || !tty->termios) + { + return; + } + + port->IER = 0; + port->COR2 = 0; + /* Select port on the board */ + siolx_out(bp, CD186x_CAR, port_No_by_chip(port)); + + /* The Siolx board doens't implement the RTS lines. + They are used to set the IRQ level. Don't touch them. */ + /* Must check how to apply these to sio16 boards */ + if (SIOLX_CRTSCTS(tty)) + { + port->MSVR = (MSVR_DTR | (siolx_in(bp, CD186x_MSVR) & MSVR_RTS)); + } + else + { + port->MSVR = (siolx_in(bp, CD186x_MSVR) & MSVR_RTS); + } +#ifdef DEBUG_SIOLX + DEBUGPRINT((KERN_DEBUG "siolx: got MSVR=%02x.\n", port->MSVR)); +#endif + baud = C_BAUD(tty); + + if (baud & CBAUDEX) + { + baud &= ~CBAUDEX; + if((baud < 1) || (baud > 2)) + { + port->tty->termios->c_cflag &= ~CBAUDEX; + } + else + { + baud += 15; + } + } + if (baud == 15) + { + if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + { + baud ++; + } + if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + { + baud += 2; + } + } + + + if (!baud_table[baud]) + { + /* Drop DTR & exit */ +#ifdef SIOLX_DEBUG + DEBUGPRINT((KERN_DEBUG "siolx: Dropping DTR... Hmm....\n")); +#endif + if (!SIOLX_CRTSCTS (tty)) + { + port->MSVR &= ~ MSVR_DTR; + siolx_out(bp, CD186x_MSVR, port->MSVR ); + } +#ifdef DEBUG_SIOLX + else + { + DEBUGPRINT((KERN_DEBUG "siolx: Can't drop DTR: no DTR.\n")); + } +#endif + return; + } + else + { + /* Set DTR on */ + if (!SIOLX_CRTSCTS (tty)) + { + port ->MSVR |= MSVR_DTR; + } + } + + /* + * Now we must calculate some speed depended things + */ + + /* Set baud rate for port */ + tmp = port->custom_divisor ; + if(tmp) + { + DEBUGPRINT((KERN_INFO "siolx: board %d: chip %d: port %d: Using custom baud rate divisor %ld. \n" + "This is an untested option, please be carefull.\n", + board_No(bp), + bp->chipnumber, + port_No(port), tmp)); + } + else + { + tmp = (((SIOLX_OSCFREQ + baud_table[baud]/2) / baud_table[baud] + + CD186x_TPC/2) / CD186x_TPC); + } + + if ((tmp < 0x10) && time_before(again, jiffies)) + { + again = jiffies + HZ * 60; + /* Page 48 of version 2.0 of the CL-CD1865 databook */ + if (tmp >= 12) + { + DEBUGPRINT((KERN_INFO "siolx: board %d: chip %d: port %d:Baud rate divisor is %ld. \n" + "Performance degradation is possible.\n" + "Read siolx.txt for more info.\n", + board_No(bp), bp->chipnumber, + port_No (port), tmp)); + } else + { + DEBUGPRINT((KERN_INFO "siolx: board %d: chip %d: port %d: Baud rate divisor is %ld. \n" + " Warning: overstressing Cirrus chip. " + " This might not work.\n" + " Read siolx.txt for more info.\n", + board_No(bp), bp->chipnumber, port_No (port), tmp)); + } + } + + siolx_out(bp, CD186x_RBPRH, (tmp >> 8) & 0xff); + siolx_out(bp, CD186x_TBPRH, (tmp >> 8) & 0xff); + siolx_out(bp, CD186x_RBPRL, tmp & 0xff); + siolx_out(bp, CD186x_TBPRL, tmp & 0xff); + + if (port->custom_divisor) + { + baud = (SIOLX_OSCFREQ + port->custom_divisor/2) / port->custom_divisor; + baud = ( baud + 5 ) / 10; + } else + { + baud = (baud_table[baud] + 5) / 10; /* Estimated CPS */ + } + + /* Two timer ticks seems enough to wakeup something like SLIP driver */ + tmp = ((baud + HZ/2) / HZ) * 2 - CD186x_NFIFO; + port->wakeup_chars = (tmp < 0) ? 0 : ((tmp >= SERIAL_XMIT_SIZE) ? + SERIAL_XMIT_SIZE - 1 : tmp); + + /* Receiver timeout will be transmission time for 1.5 chars */ + tmp = (SIOLX_TPS + SIOLX_TPS/2 + baud/2) / baud; + tmp = (tmp > 0xff) ? 0xff : tmp; + siolx_out(bp, CD186x_RTPR, tmp); + + switch (C_CSIZE(tty)) + { + case CS5: + cor1 |= COR1_5BITS; + break; + case CS6: + cor1 |= COR1_6BITS; + break; + case CS7: + cor1 |= COR1_7BITS; + break; + case CS8: + cor1 |= COR1_8BITS; + break; + } + + if (C_CSTOPB(tty)) + { + cor1 |= COR1_2SB; + } + + cor1 |= COR1_IGNORE; + if (C_PARENB(tty)) + { + cor1 |= COR1_NORMPAR; + if (C_PARODD(tty)) + { + cor1 |= COR1_ODDP; + } + if (I_INPCK(tty)) + { + cor1 &= ~COR1_IGNORE; + } + } + /* Set marking of some errors */ + port->mark_mask = RCSR_OE | RCSR_TOUT; + if (I_INPCK(tty)) + { + port->mark_mask |= RCSR_FE | RCSR_PE; + } + if (I_BRKINT(tty) || I_PARMRK(tty)) + { + port->mark_mask |= RCSR_BREAK; + } + if (I_IGNPAR(tty)) + { + port->mark_mask &= ~(RCSR_FE | RCSR_PE); + } + if (I_IGNBRK(tty)) + { + port->mark_mask &= ~RCSR_BREAK; + if (I_IGNPAR(tty)) + { + /* Real raw mode. Ignore all */ + port->mark_mask &= ~RCSR_OE; + } + } + /* Enable Hardware Flow Control */ + if (C_CRTSCTS(tty)) + { +#ifdef SIOLX_BRAIN_DAMAGED_CTS + port->IER |= IER_DSR | IER_CTS; + mcor1 |= MCOR1_DSRZD | MCOR1_CTSZD; + mcor2 |= MCOR2_DSROD | MCOR2_CTSOD; + tty->hw_stopped = !(siolx_in(bp, CD186x_MSVR) & (MSVR_CTS|MSVR_DSR)); +#else + port->COR2 |= COR2_CTSAE; +#endif + } + /* Enable Software Flow Control. FIXME: I'm not sure about this */ + /* Some people reported that it works, but I still doubt it */ + if (I_IXON(tty)) + { + port->COR2 |= COR2_TXIBE; + cor3 |= (COR3_FCT | COR3_SCDE); + if (I_IXANY(tty)) + { + port->COR2 |= COR2_IXM; + } + siolx_out(bp, CD186x_SCHR1, START_CHAR(tty)); + siolx_out(bp, CD186x_SCHR2, STOP_CHAR(tty)); + siolx_out(bp, CD186x_SCHR3, START_CHAR(tty)); + siolx_out(bp, CD186x_SCHR4, STOP_CHAR(tty)); + } + if (!C_CLOCAL(tty)) + { + /* Enable CD check */ + port->IER |= IER_CD; + mcor1 |= MCOR1_CDZD; + mcor2 |= MCOR2_CDOD; + } + + if (C_CREAD(tty)) + { + /* Enable receiver */ + port->IER |= IER_RXD; + } + + /* Set input FIFO size (1-8 bytes) */ + cor3 |= SIOLX_RXFIFO; + /* Setting up CD186x channel registers */ + siolx_out(bp, CD186x_COR1, cor1); + siolx_out(bp, CD186x_COR2, port->COR2); + siolx_out(bp, CD186x_COR3, cor3); + /* Make CD186x know about registers change */ + siolx_wait_CCR(bp); + siolx_out(bp, CD186x_CCR, CCR_CORCHG1 | CCR_CORCHG2 | CCR_CORCHG3); + /* Setting up modem option registers */ +#ifdef DEBUG_SIOLX + DEBUGPRINT((KERN_ALERT "siolx: Mcor1 = %02x, mcor2 = %02x.\n", mcor1, mcor2)); +#endif + siolx_out(bp, CD186x_MCOR1, mcor1); + siolx_out(bp, CD186x_MCOR2, mcor2); + /* Enable CD186x transmitter & receiver */ + siolx_wait_CCR(bp); + siolx_out(bp, CD186x_CCR, CCR_TXEN | CCR_RXEN); + /* Enable interrupts */ + siolx_out(bp, CD186x_IER, port->IER); + /* And finally set the modem lines... */ + siolx_out(bp, CD186x_MSVR, port->MSVR); +} + + +/* Must be called with interrupts enabled */ +static int siolx_setup_port(struct siolx_board *bp, struct siolx_port *port) +{ + unsigned long flags; + + if (port->flags & ASYNC_INITIALIZED) + { + return 0; + } + + if (!port->xmit_buf) + { + /* We may sleep in get_free_page() */ + unsigned long tmp; + + if (!(tmp = get_free_page(GFP_KERNEL))) + { + return -ENOMEM; + } + + if (port->xmit_buf) + { + free_page(tmp); + return -ERESTARTSYS; + } + port->xmit_buf = (unsigned char *) tmp; + } + + save_flags(flags); cli(); + + if (port->tty) + { + clear_bit(TTY_IO_ERROR, &port->tty->flags); + } + + port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; + siolx_change_speed(bp, port); + port->flags |= ASYNC_INITIALIZED; + + restore_flags(flags); + return 0; +} + + +/* Must be called with interrupts disabled */ +static void siolx_shutdown_port(struct siolx_board *bp, struct siolx_port *port) +{ + struct tty_struct *tty; + + if (!(port->flags & ASYNC_INITIALIZED)) + { + return; + } + +#ifdef SIOLX_REPORT_OVERRUN + DEBUGPRINT((KERN_INFO "siolx: board %d: chip %d: port %d: Total %ld overruns were detected.\n", + board_No(bp), bp->chipnumber, port_No(port), port->overrun)); +#endif +#ifdef SIOLX_REPORT_FIFO + { + int i; + + DEBUGPRINT((KERN_INFO "siolx: board %d: chip %d: port %d: FIFO hits [ ", + board_No(bp), bp->chipnumber, port_No(port))); + for (i = 0; i < 10; i++) + { + DEBUGPRINT(("%ld ", port->hits[i])); + } + DEBUGPRINT(("].\n")); + } +#endif + if (port->xmit_buf) + { + free_page((unsigned long) port->xmit_buf); + port->xmit_buf = NULL; + } + + /* Select port */ + siolx_out(bp, CD186x_CAR, port_No_by_chip(port)); + + if (!(tty = port->tty) || C_HUPCL(tty)) + { + /* Drop DTR */ + siolx_out(bp, CD186x_MSVDTR, 0); + } + + /* Reset port */ + siolx_wait_CCR(bp); + siolx_out(bp, CD186x_CCR, CCR_SOFTRESET); + /* Disable all interrupts from this port */ + port->IER = 0; + siolx_out(bp, CD186x_IER, port->IER); + + if (tty) + { + set_bit(TTY_IO_ERROR, &tty->flags); + } + port->flags &= ~ASYNC_INITIALIZED; + + /* + * If this is the last opened port on the board + * shutdown whole board + */ + MOD_DEC_USE_COUNT; +} + + +static int block_til_ready(struct tty_struct *tty, struct file * filp, + struct siolx_port *port) +{ + DECLARE_WAITQUEUE(wait, current); + struct siolx_board *bp = port_Board(port); + int retval; + int do_clocal = 0; + int CD; + + /* + * 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) || port->flags & ASYNC_CLOSING) + { + interruptible_sleep_on(&port->close_wait); + if (port->flags & ASYNC_HUP_NOTIFY) + { + return -EAGAIN; + } + else + { + return -ERESTARTSYS; + } + } + + /* + * If this is a callout device, then just make sure the normal + * device isn't being used. + */ + if (tty->driver.subtype == SIOLX_TYPE_CALLOUT) + { + if (port->flags & ASYNC_NORMAL_ACTIVE) + { + return -EBUSY; + } + if ((port->flags & ASYNC_CALLOUT_ACTIVE) && + (port->flags & ASYNC_SESSION_LOCKOUT) && + (port->session != current->session)) + { + return -EBUSY; + } + if ((port->flags & ASYNC_CALLOUT_ACTIVE) && + (port->flags & ASYNC_PGRP_LOCKOUT) && + (port->pgrp != current->pgrp)) + { + return -EBUSY; + } + port->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 (port->flags & ASYNC_CALLOUT_ACTIVE) + { + return -EBUSY; + } + port->flags |= ASYNC_NORMAL_ACTIVE; + return 0; + } + + if (port->flags & ASYNC_CALLOUT_ACTIVE) + { + if (port->normal_termios.c_cflag & CLOCAL) + { + do_clocal = 1; + } + } + else + { + if (C_CLOCAL(tty)) + { + do_clocal = 1; + } + } + + /* + * Block waiting for the carrier detect and the line to become + * free (i.e., not in use by the callout). While we are in + * this loop, info->count is dropped by one, so that + * rs_close() knows when to free things. We restore it upon + * exit, either normal or abnormal. + */ + retval = 0; + add_wait_queue(&port->open_wait, &wait); + cli(); + if (!tty_hung_up_p(filp)) + { + port->count--; + } + sti(); + port->blocked_open++; + while (1) + { + cli(); + siolx_out(bp, CD186x_CAR, port_No_by_chip(port)); + CD = siolx_in(bp, CD186x_MSVR) & MSVR_CD; + if (!(port->flags & ASYNC_CALLOUT_ACTIVE)) + { + if (SIOLX_CRTSCTS (tty)) + { + /* Activate RTS */ + port->MSVR |= MSVR_DTR; + siolx_out (bp, CD186x_MSVR, port->MSVR); + } + else + { + /* Activate DTR */ + port->MSVR |= MSVR_DTR; + siolx_out (bp, CD186x_MSVR, port->MSVR); + } + } + sti(); + set_current_state(TASK_INTERRUPTIBLE); + if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) + { + if (port->flags & ASYNC_HUP_NOTIFY) + { + retval = -EAGAIN; + } + else + { + retval = -ERESTARTSYS; + } + break; + } + if (!(port->flags & ASYNC_CALLOUT_ACTIVE) && + !(port->flags & ASYNC_CLOSING) && + (do_clocal || CD)) + { + break; + } + if (signal_pending(current)) + { + retval = -ERESTARTSYS; + break; + } + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(&port->open_wait, &wait); + if (!tty_hung_up_p(filp)) + { + port->count++; + } + port->blocked_open--; + if (retval) + { + return retval; + } + + port->flags |= ASYNC_NORMAL_ACTIVE; + return 0; +} + +static inline struct siolx_port *siolx_portstruc(register int line) +{ + register struct siolx_port *pp; + + line -= siolx_driver.minor_start; + for(pp = siolx_port_root; (pp != NULL) && (line >= 0); --line, pp = pp->next_by_global_list) + { + if(line == 0) + { + return pp; + } + } + return NULL; +} + + +static int siolx_open(struct tty_struct * tty, struct file * filp) +{ + int error; + struct siolx_port * port; + struct siolx_board * bp; + unsigned long flags; + + port = siolx_portstruc(MINOR(tty->device)); + + if(port == NULL) + { + return -ENODEV; + } + bp = port->board; + if(bp == NULL) + { + return -ENODEV; + } + +#ifdef DEBUG_SIOLX + printk (KERN_DEBUG "Board = %d, bp = %p, port = %p, portno = %d.\n", + bp->boardnumber, bp, port, siolx_portstruc(MINOR(tty->device))); +#endif + + if (siolx_paranoia_check(port, tty->device, "siolx_open")) + return -ENODEV; + + MOD_INC_USE_COUNT; + + port->count++; + tty->driver_data = port; + port->tty = tty; + + if ((error = siolx_setup_port(bp, port))) + return error; + + if ((error = block_til_ready(tty, filp, port))) + return error; + + if ((port->count == 1) && (port->flags & ASYNC_SPLIT_TERMIOS)) { + if (tty->driver.subtype == SIOLX_TYPE_NORMAL) + *tty->termios = port->normal_termios; + else + *tty->termios = port->callout_termios; + save_flags(flags); cli(); + siolx_change_speed(bp, port); + restore_flags(flags); + } + + port->session = current->session; + port->pgrp = current->pgrp; + return 0; +} + + +static void siolx_close(struct tty_struct * tty, struct file * filp) +{ + struct siolx_port *port = (struct siolx_port *) tty->driver_data; + struct siolx_board *bp; + unsigned long flags; + unsigned long timeout; + + if (!port || siolx_paranoia_check(port, tty->device, "close")) + return; + + save_flags(flags); cli(); + if (tty_hung_up_p(filp)) { + restore_flags(flags); + return; + } + + bp = port_Board(port); + if ((atomic_read(&tty->count) == 1) && (port->count != 1)) { + printk(KERN_ERR "sx%d: siolx_close: bad port count;" + " tty->count is 1, port count is %d\n", + board_No(bp), port->count); + port->count = 1; + } + if (--port->count < 0) { + printk(KERN_ERR "sx%d: siolx_close: bad port count for tty%d: %d\n", + board_No(bp), port_No(port), port->count); + port->count = 0; + } + if (port->count) { + restore_flags(flags); + return; + } + port->flags |= ASYNC_CLOSING; + /* + * Save the termios structure, since this port may have + * separate termios for callout and dialin. + */ + if (port->flags & ASYNC_NORMAL_ACTIVE) + port->normal_termios = *tty->termios; + if (port->flags & ASYNC_CALLOUT_ACTIVE) + port->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 (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, port->closing_wait); + /* + * At this point we stop accepting input. To do this, we + * disable the receive line status interrupts, and tell the + * interrupt driver to stop checking the data ready bit in the + * line status register. + */ + port->IER &= ~IER_RXD; + if (port->flags & ASYNC_INITIALIZED) { + port->IER &= ~IER_TXRDY; + port->IER |= IER_TXEMPTY; + siolx_out(bp, CD186x_CAR, port_No_by_chip(port)); + siolx_out(bp, CD186x_IER, port->IER); + /* + * Before we drop DTR, make sure the UART transmitter + * has completely drained; this is especially + * important if there is a transmit FIFO! + */ + timeout = jiffies+HZ; + while(port->IER & IER_TXEMPTY) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(port->timeout); + if (time_after(jiffies, timeout)) { + printk (KERN_INFO "siolx: Timeout waiting for close\n"); + break; + } + } + + } + siolx_shutdown_port(bp, port); + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + tty->closing = 0; + port->event = 0; + port->tty = 0; + if (port->blocked_open) { + if (port->close_delay) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(port->close_delay); + } + wake_up_interruptible(&port->open_wait); + } + port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| + ASYNC_CLOSING); + wake_up_interruptible(&port->close_wait); + restore_flags(flags); +} + + +static int siolx_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ + struct siolx_port *port = (struct siolx_port *)tty->driver_data; + struct siolx_board *bp; + int c, total = 0; + unsigned long flags; + + if (siolx_paranoia_check(port, tty->device, "siolx_write")) + return 0; + + bp = port_Board(port); + + if (!tty || !port->xmit_buf || !tmp_buf) + return 0; + + save_flags(flags); + if (from_user) { + down(&tmp_buf_sem); + while (1) { + c = MIN(count, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, + SERIAL_XMIT_SIZE - port->xmit_head)); + if (c <= 0) + break; + + c -= copy_from_user(tmp_buf, buf, c); + if (!c) { + if (!total) + total = -EFAULT; + break; + } + + cli(); + c = MIN(c, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, + SERIAL_XMIT_SIZE - port->xmit_head)); + memcpy(port->xmit_buf + port->xmit_head, tmp_buf, c); + port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1); + port->xmit_cnt += c; + restore_flags(flags); + + buf += c; + count -= c; + total += c; + } + up(&tmp_buf_sem); + } else { + while (1) { + cli(); + c = MIN(count, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, + SERIAL_XMIT_SIZE - port->xmit_head)); + if (c <= 0) { + restore_flags(flags); + break; + } + memcpy(port->xmit_buf + port->xmit_head, buf, c); + port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1); + port->xmit_cnt += c; + restore_flags(flags); + + buf += c; + count -= c; + total += c; + } + } + + cli(); + if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped && + !(port->IER & IER_TXRDY)) { + port->IER |= IER_TXRDY; + siolx_out(bp, CD186x_CAR, port_No_by_chip(port)); + siolx_out(bp, CD186x_IER, port->IER); + } + restore_flags(flags); + return total; +} + + +static void siolx_put_char(struct tty_struct * tty, unsigned char ch) +{ + struct siolx_port *port = (struct siolx_port *)tty->driver_data; + unsigned long flags; + + if (siolx_paranoia_check(port, tty->device, "siolx_put_char")) + return; + + if (!tty || !port->xmit_buf) + return; + + save_flags(flags); cli(); + + if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) { + restore_flags(flags); + return; + } + + port->xmit_buf[port->xmit_head++] = ch; + port->xmit_head &= SERIAL_XMIT_SIZE - 1; + port->xmit_cnt++; + restore_flags(flags); +} + + +static void siolx_flush_chars(struct tty_struct * tty) +{ + struct siolx_port *port = (struct siolx_port *)tty->driver_data; + unsigned long flags; + + if (siolx_paranoia_check(port, tty->device, "siolx_flush_chars")) + return; + + if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || + !port->xmit_buf) + return; + + save_flags(flags); cli(); + port->IER |= IER_TXRDY; + siolx_out(port_Board(port), CD186x_CAR, port_No_by_chip(port)); + siolx_out(port_Board(port), CD186x_IER, port->IER); + restore_flags(flags); +} + + +static int siolx_write_room(struct tty_struct * tty) +{ + struct siolx_port *port = (struct siolx_port *)tty->driver_data; + int ret; + + if (siolx_paranoia_check(port, tty->device, "siolx_write_room")) + return 0; + + ret = SERIAL_XMIT_SIZE - port->xmit_cnt - 1; + if (ret < 0) + ret = 0; + return ret; +} + + +static int siolx_chars_in_buffer(struct tty_struct *tty) +{ + struct siolx_port *port = (struct siolx_port *)tty->driver_data; + + if (siolx_paranoia_check(port, tty->device, "siolx_chars_in_buffer")) + return 0; + + return port->xmit_cnt; +} + + +static void siolx_flush_buffer(struct tty_struct *tty) +{ + struct siolx_port *port = (struct siolx_port *)tty->driver_data; + unsigned long flags; + + if (siolx_paranoia_check(port, tty->device, "siolx_flush_buffer")) + return; + + save_flags(flags); cli(); + port->xmit_cnt = port->xmit_head = port->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); +} + + +static int siolx_get_modem_info(struct siolx_port * port, unsigned int *value) +{ + struct siolx_board * bp; + unsigned char status; + unsigned int result; + unsigned long flags; + + bp = port_Board(port); + save_flags(flags); cli(); + siolx_out(bp, CD186x_CAR, port_No_by_chip(port)); + status = siolx_in(bp, CD186x_MSVR); + restore_flags(flags); +#ifdef DEBUG_SIOLX + printk (KERN_DEBUG "Got msvr[%d] = %02x, car = %d.\n", + port_No(port), status, siolx_in (bp, CD186x_CAR)); + printk (KERN_DEBUG "siolx_port = %p, port = %p\n", siolx_port, port); +#endif + if (SIOLX_CRTSCTS(port->tty)) { + result = /* (status & MSVR_RTS) ? */ TIOCM_DTR /* : 0) */ + | ((status & MSVR_DTR) ? TIOCM_RTS : 0) + | ((status & MSVR_CD) ? TIOCM_CAR : 0) + |/* ((status & MSVR_DSR) ? */ TIOCM_DSR /* : 0) */ + | ((status & MSVR_CTS) ? TIOCM_CTS : 0); + } else { + result = /* (status & MSVR_RTS) ? */ TIOCM_RTS /* : 0) */ + | ((status & MSVR_DTR) ? TIOCM_DTR : 0) + | ((status & MSVR_CD) ? TIOCM_CAR : 0) + |/* ((status & MSVR_DSR) ? */ TIOCM_DSR /* : 0) */ + | ((status & MSVR_CTS) ? TIOCM_CTS : 0); + } + put_user(result,(unsigned int *) value); + return 0; +} + + +static int siolx_set_modem_info(struct siolx_port * port, unsigned int cmd, + unsigned int *value) +{ + int error; + unsigned int arg; + unsigned long flags; + struct siolx_board *bp = port_Board(port); + + error = verify_area(VERIFY_READ, value, sizeof(int)); + if (error) + return error; + + get_user(arg, (unsigned long *) value); + switch (cmd) { + case TIOCMBIS: + /* if (arg & TIOCM_RTS) + port->MSVR |= MSVR_RTS; */ + /* if (arg & TIOCM_DTR) + port->MSVR |= MSVR_DTR; */ + + if (SIOLX_CRTSCTS(port->tty)) { + if (arg & TIOCM_RTS) + port->MSVR |= MSVR_DTR; + } else { + if (arg & TIOCM_DTR) + port->MSVR |= MSVR_DTR; + } + break; + case TIOCMBIC: + /* if (arg & TIOCM_RTS) + port->MSVR &= ~MSVR_RTS; */ + /* if (arg & TIOCM_DTR) + port->MSVR &= ~MSVR_DTR; */ + if (SIOLX_CRTSCTS(port->tty)) { + if (arg & TIOCM_RTS) + port->MSVR &= ~MSVR_DTR; + } else { + if (arg & TIOCM_DTR) + port->MSVR &= ~MSVR_DTR; + } + break; + case TIOCMSET: + /* port->MSVR = (arg & TIOCM_RTS) ? (port->MSVR | MSVR_RTS) : + (port->MSVR & ~MSVR_RTS); */ + /* port->MSVR = (arg & TIOCM_DTR) ? (port->MSVR | MSVR_DTR) : + (port->MSVR & ~MSVR_DTR); */ + if (SIOLX_CRTSCTS(port->tty)) { + port->MSVR = (arg & TIOCM_RTS) ? + (port->MSVR | MSVR_DTR) : + (port->MSVR & ~MSVR_DTR); + } else { + port->MSVR = (arg & TIOCM_DTR) ? + (port->MSVR | MSVR_DTR): + (port->MSVR & ~MSVR_DTR); + } + break; + default: + return -EINVAL; + } + save_flags(flags); cli(); + siolx_out(bp, CD186x_CAR, port_No_by_chip(port)); + siolx_out(bp, CD186x_MSVR, port->MSVR); + restore_flags(flags); + return 0; +} + + +static inline void siolx_send_break(struct siolx_port * port, unsigned long length) +{ + struct siolx_board *bp = port_Board(port); + unsigned long flags; + + save_flags(flags); cli(); + port->break_length = SIOLX_TPS / HZ * length; + port->COR2 |= COR2_ETC; + port->IER |= IER_TXRDY; + siolx_out(bp, CD186x_CAR, port_No_by_chip(port)); + siolx_out(bp, CD186x_COR2, port->COR2); + siolx_out(bp, CD186x_IER, port->IER); + siolx_wait_CCR(bp); + siolx_out(bp, CD186x_CCR, CCR_CORCHG2); + siolx_wait_CCR(bp); + restore_flags(flags); +} + + +static inline int siolx_set_serial_info(struct siolx_port * port, + struct serial_struct * newinfo) +{ + struct serial_struct tmp; + struct siolx_board *bp = port_Board(port); + int change_speed; + unsigned long flags; + int error; + + error = verify_area(VERIFY_READ, (void *) newinfo, sizeof(tmp)); + if (error) + return error; + + if (copy_from_user(&tmp, newinfo, sizeof(tmp))) + return -EFAULT; + +#if 0 + if ((tmp.irq != bp->irq) || + (tmp.port != bp->base) || + (tmp.type != PORT_CIRRUS) || + (tmp.baud_base != (SIOLX_OSCFREQ + CD186x_TPC/2) / CD186x_TPC) || + (tmp.custom_divisor != 0) || + (tmp.xmit_fifo_size != CD186x_NFIFO) || + (tmp.flags & ~SIOLX_LEGAL_FLAGS)) + return -EINVAL; +#endif + + change_speed = ((port->flags & ASYNC_SPD_MASK) != + (tmp.flags & ASYNC_SPD_MASK)); + change_speed |= (tmp.custom_divisor != port->custom_divisor); + + if (!capable(CAP_SYS_ADMIN)) { + if ((tmp.close_delay != port->close_delay) || + (tmp.closing_wait != port->closing_wait) || + ((tmp.flags & ~ASYNC_USR_MASK) != + (port->flags & ~ASYNC_USR_MASK))) + return -EPERM; + port->flags = ((port->flags & ~ASYNC_USR_MASK) | + (tmp.flags & ASYNC_USR_MASK)); + port->custom_divisor = tmp.custom_divisor; + } else { + port->flags = ((port->flags & ~ASYNC_FLAGS) | + (tmp.flags & ASYNC_FLAGS)); + port->close_delay = tmp.close_delay; + port->closing_wait = tmp.closing_wait; + port->custom_divisor = tmp.custom_divisor; + } + if (change_speed) { + save_flags(flags); cli(); + siolx_change_speed(bp, port); + restore_flags(flags); + } + return 0; +} + + +static inline int siolx_get_serial_info(struct siolx_port * port, + struct serial_struct * retinfo) +{ + struct serial_struct tmp; + struct siolx_board *bp = port_Board(port); + int error; + + error = verify_area(VERIFY_WRITE, (void *) retinfo, sizeof(tmp)); + if (error) + return error; + + memset(&tmp, 0, sizeof(tmp)); + tmp.type = PORT_CIRRUS; + tmp.line = port->driverport; + tmp.port = bp->base; + tmp.irq = bp->irq; + tmp.flags = port->flags; + tmp.baud_base = (SIOLX_OSCFREQ + CD186x_TPC/2) / CD186x_TPC; + tmp.close_delay = port->close_delay * HZ/100; + tmp.closing_wait = port->closing_wait * HZ/100; + tmp.custom_divisor = port->custom_divisor; + tmp.xmit_fifo_size = CD186x_NFIFO; + if (copy_to_user(retinfo, &tmp, sizeof(tmp))) + return -EFAULT; + return 0; +} + + +static int siolx_ioctl(struct tty_struct * tty, struct file * filp, + unsigned int cmd, unsigned long arg) +{ + struct siolx_port *port = (struct siolx_port *)tty->driver_data; + int error; + int retval; + + if (siolx_paranoia_check(port, tty->device, "siolx_ioctl")) + return -ENODEV; + + switch (cmd) { + case TCSBRK: /* SVID version: non-zero arg --> no break */ + retval = tty_check_change(tty); + if (retval) + return retval; + tty_wait_until_sent(tty, 0); + if (!arg) + siolx_send_break(port, HZ/4); /* 1/4 second */ + return 0; + case TCSBRKP: /* support for POSIX tcsendbreak() */ + retval = tty_check_change(tty); + if (retval) + return retval; + tty_wait_until_sent(tty, 0); + siolx_send_break(port, arg ? arg*(HZ/10) : HZ/4); + return 0; + case TIOCGSOFTCAR: + error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long)); + if (error) + return error; + put_user(C_CLOCAL(tty) ? 1 : 0, + (unsigned long *) arg); + return 0; + case TIOCSSOFTCAR: + get_user(arg, (unsigned long *) arg); + tty->termios->c_cflag = + ((tty->termios->c_cflag & ~CLOCAL) | + (arg ? CLOCAL : 0)); + return 0; + case TIOCMGET: + error = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(unsigned int)); + if (error) + return error; + return siolx_get_modem_info(port, (unsigned int *) arg); + case TIOCMBIS: + case TIOCMBIC: + case TIOCMSET: + return siolx_set_modem_info(port, cmd, (unsigned int *) arg); + case TIOCGSERIAL: + return siolx_get_serial_info(port, (struct serial_struct *) arg); + case TIOCSSERIAL: + return siolx_set_serial_info(port, (struct serial_struct *) arg); + default: + return -ENOIOCTLCMD; + } + return 0; +} + + +static void siolx_throttle(struct tty_struct * tty) +{ + struct siolx_port *port = (struct siolx_port *)tty->driver_data; + struct siolx_board *bp; + unsigned long flags; + + if (siolx_paranoia_check(port, tty->device, "siolx_throttle")) + return; + + bp = port_Board(port); + + save_flags(flags); cli(); + + /* Use DTR instead of RTS ! */ + if (SIOLX_CRTSCTS (tty)) + { + port->MSVR &= ~MSVR_DTR; + } + else + { + /* Auch!!! I think the system shouldn't call this then. */ + /* Or maybe we're supposed (allowed?) to do our side of hw + handshake anyway, even when hardware handshake is off. + When you see this in your logs, please report.... */ + printk (KERN_ERR "sx%d: Need to throttle, but can't (hardware hs is off)\n", + port_No (port)); + } + siolx_out(bp, CD186x_CAR, port_No_by_chip(port)); + if (I_IXOFF(tty)) + { + siolx_wait_CCR(bp); + siolx_out(bp, CD186x_CCR, CCR_SSCH2); + siolx_wait_CCR(bp); + } + siolx_out(bp, CD186x_MSVR, port->MSVR); + restore_flags(flags); +} + + +static void siolx_unthrottle(struct tty_struct * tty) +{ + struct siolx_port *port = (struct siolx_port *)tty->driver_data; + struct siolx_board *bp; + unsigned long flags; + + if (siolx_paranoia_check(port, tty->device, "siolx_unthrottle")) + return; + + bp = port_Board(port); + + save_flags(flags); cli(); + /* XXXX Use DTR INSTEAD???? */ + if (SIOLX_CRTSCTS(tty)) { + port->MSVR |= MSVR_DTR; + } /* Else clause: see remark in "siolx_throttle"... */ + + siolx_out(bp, CD186x_CAR, port_No_by_chip(port)); + if (I_IXOFF(tty)) { + siolx_wait_CCR(bp); + siolx_out(bp, CD186x_CCR, CCR_SSCH1); + siolx_wait_CCR(bp); + } + siolx_out(bp, CD186x_MSVR, port->MSVR); + restore_flags(flags); +} + + +static void siolx_stop(struct tty_struct * tty) +{ + struct siolx_port *port = (struct siolx_port *)tty->driver_data; + struct siolx_board *bp; + unsigned long flags; + + if (siolx_paranoia_check(port, tty->device, "siolx_stop")) + return; + + bp = port_Board(port); + + save_flags(flags); cli(); + port->IER &= ~IER_TXRDY; + siolx_out(bp, CD186x_CAR, port_No_by_chip(port)); + siolx_out(bp, CD186x_IER, port->IER); + restore_flags(flags); +} + + +static void siolx_start(struct tty_struct * tty) +{ + struct siolx_port *port = (struct siolx_port *)tty->driver_data; + struct siolx_board *bp; + unsigned long flags; + + if (siolx_paranoia_check(port, tty->device, "siolx_start")) + return; + + bp = port_Board(port); + + save_flags(flags); cli(); + if (port->xmit_cnt && port->xmit_buf && !(port->IER & IER_TXRDY)) { + port->IER |= IER_TXRDY; + siolx_out(bp, CD186x_CAR, port_No_by_chip(port)); + siolx_out(bp, CD186x_IER, port->IER); + } + restore_flags(flags); +} + + +/* + * This routine is called from the scheduler tqueue when the interrupt + * routine has signalled that a hangup has occurred. The path of + * hangup processing is: + * + * serial interrupt routine -> (scheduler tqueue) -> + * do_siolx_hangup() -> tty->hangup() -> siolx_hangup() + * + */ +static void do_siolx_hangup(void *private_) +{ + struct siolx_port *port = (struct siolx_port *) private_; + struct tty_struct *tty; + + tty = port->tty; + if (tty) + { + tty_hangup(tty); /* FIXME: module removal race here */ + } + MOD_DEC_USE_COUNT; +} + + +static void siolx_hangup(struct tty_struct * tty) +{ + struct siolx_port *port = (struct siolx_port *)tty->driver_data; + struct siolx_board *bp; + + if (siolx_paranoia_check(port, tty->device, "siolx_hangup")) + return; + + bp = port_Board(port); + + siolx_shutdown_port(bp, port); + port->event = 0; + port->count = 0; + port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); + port->tty = 0; + wake_up_interruptible(&port->open_wait); +} + + +static void siolx_set_termios(struct tty_struct * tty, struct termios * old_termios) +{ + struct siolx_port *port = (struct siolx_port *)tty->driver_data; + unsigned long flags; + + if (siolx_paranoia_check(port, tty->device, "siolx_set_termios")) + return; + + if (tty->termios->c_cflag == old_termios->c_cflag && + tty->termios->c_iflag == old_termios->c_iflag) + return; + + save_flags(flags); cli(); + siolx_change_speed(port_Board(port), port); + restore_flags(flags); + + if ((old_termios->c_cflag & CRTSCTS) && + !(tty->termios->c_cflag & CRTSCTS)) { + tty->hw_stopped = 0; + siolx_start(tty); + } +} + + +static void do_siolx_bh(void) +{ + run_task_queue(&tq_siolx); +} + + +static void do_softint(void *private_) +{ + struct siolx_port *port = (struct siolx_port *) private_; + struct tty_struct *tty; + + if(!(tty = port->tty)) + return; + + if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) { + 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 siolx_finish_init_drivers(void) +{ + register struct siolx_board *bp; + register unsigned int count; + unsigned int maxport; + struct siolx_port *port; + struct siolx_port *lastport; + int error; + + bp = siolx_board_root; + + while(bp) + { + if(bp->chipnumber == 0) + { + maxport = SIOLX_NPORT; + } + else if((bp->boardtype == BD_16000C) && bp->reario) /* must be second chip of 16000C */ + { + maxport = SIOLX_NPORT/2; + } + else + { + maxport = SIOLX_NPORT; /* must be second chip of 16000P */ + } + + port = NULL; /* probably unnecessary */ + lastport = NULL; + for(count = 0; count < maxport; ++count) + { + port = (struct siolx_port*)kmalloc(sizeof(struct siolx_port), GFP_KERNEL); + if(port == NULL) + { + printk(KERN_ALERT + "siolx: Failed to create port structure on board %p.\n", bp); + break; /* no memory available */ + } + memset(port, 0, sizeof(struct siolx_port)); + + port->callout_termios = siolx_callout_driver.init_termios; + port->normal_termios = siolx_driver.init_termios; + port->magic = SIOLX_MAGIC; + port->tqueue.routine = do_softint; + port->tqueue.data = port; + port->tqueue_hangup.routine = do_siolx_hangup; + port->tqueue_hangup.data = port; + port->close_delay = 50 * HZ/100; + port->closing_wait = 3000 * HZ/100; + init_waitqueue_head(&port->open_wait); + init_waitqueue_head(&port->close_wait); + + port->board = bp; + port->driverport = NumSiolxPorts; + port->boardport = (count + (port->board->chipnumber*SIOLX_NPORT)); /* 0-16 */ + + if(count == 0) + { + bp->portlist = port; + } + else if(lastport) /* if count != 0 lastport should be non-null */ + { + lastport->next_by_board = port; + } + if(siolx_port_root == NULL) + { + siolx_port_root = port; + siolx_port_last = port; + } + else + { + siolx_port_last->next_by_global_list = port; + siolx_port_last = port; + } + lastport = port; + ++NumSiolxPorts; + } + bp = bp->next_by_global_list; + } + + siolx_driver.num = NumSiolxPorts; + + siolx_table = (struct tty_struct **) kmalloc(NumSiolxPorts*sizeof(struct tty_struct *), GFP_KERNEL); + if(siolx_table == NULL) + { + printk(KERN_ALERT "siolx: Could not allocate memory for siolx_table.\n"); + return 1; + } + memset(siolx_table, 0, NumSiolxPorts*sizeof(struct tty_struct *)); + + siolx_termios = (struct termios **) kmalloc(NumSiolxPorts*sizeof(struct termios *), GFP_KERNEL); + if(siolx_termios == NULL) + { + printk(KERN_ALERT "siolx: Could not allocate memory for siolx_termios.\n"); + return 1; + } + memset(siolx_termios, 0, NumSiolxPorts*sizeof(struct termios *)); + + siolx_termios_locked = (struct termios **) kmalloc(NumSiolxPorts*sizeof(struct termios *), GFP_KERNEL); + if(siolx_termios_locked == NULL) + { + printk(KERN_ALERT "siolx: Could not allocate memory for siolx_termios_locked.\n"); + return 1; + } + memset(siolx_termios_locked, 0, NumSiolxPorts*sizeof(struct termios *)); + + siolx_driver.table = siolx_table; /* will be changed */ + siolx_driver.termios = siolx_termios; /* will be changed */ + siolx_driver.termios_locked = siolx_termios_locked; /* will be changed */ + + if ((error = tty_register_driver(&siolx_driver))) + { + if(tmp_buf) + { + free_page((unsigned long)tmp_buf); + tmp_buf = 0; + } + printk(KERN_ERR "siolx: Couldn't register Aurora Asynchronous Adapter driver, error = %d\n", + error); + return 1; + } + if ((error = tty_register_driver(&siolx_callout_driver))) + { + if(tmp_buf) + { + free_page((unsigned long)tmp_buf); + tmp_buf = NULL; + } + tty_unregister_driver(&siolx_driver); + printk(KERN_ERR "siolx: Couldn't register Aurora Asynchronous Adapter callout driver, error = %d\n", + error); + return 1; + } + siolx_driver_registered = 1; + siolx_callout_driver_registered = 1; + return 0; /* success */ +} + +static int siolx_init_drivers(void) +{ + if (!(tmp_buf = (unsigned char *) get_free_page(GFP_KERNEL))) + { + printk(KERN_ERR "siolx: Couldn't get free page.\n"); + return 1; + } + init_bh(siolx_bhindex, do_siolx_bh); + memset(&siolx_driver, 0, sizeof(siolx_driver)); + siolx_driver.magic = TTY_DRIVER_MAGIC; + + siolx_driver.driver_name = "aurasiolx"; + siolx_driver.name = "ttyS"; + siolx_driver.major = siolx_major; +#ifdef MODULE + siolx_driver.minor_start = siolx_minorstart; /* changed from command line */ +#else + siolx_driver.minor_start = GetMinorStart(); +#endif + siolx_driver.num = 0; /* will be changed */ + + siolx_driver.type = TTY_DRIVER_TYPE_SERIAL; + siolx_driver.subtype = SIOLX_TYPE_NORMAL; + siolx_driver.init_termios = tty_std_termios; + siolx_driver.init_termios.c_cflag = + B9600 | CS8 | CREAD | HUPCL | CLOCAL; + siolx_driver.flags = TTY_DRIVER_REAL_RAW; + siolx_driver.refcount = &siolx_refcount; + + siolx_driver.table = siolx_table; /* will be changed */ + siolx_driver.termios = siolx_termios; /* will be changed */ + siolx_driver.termios_locked = siolx_termios_locked; /* will be changed */ + + siolx_driver.open = siolx_open; + siolx_driver.close = siolx_close; + siolx_driver.write = siolx_write; + siolx_driver.put_char = siolx_put_char; + siolx_driver.flush_chars = siolx_flush_chars; + siolx_driver.write_room = siolx_write_room; + siolx_driver.chars_in_buffer = siolx_chars_in_buffer; + siolx_driver.flush_buffer = siolx_flush_buffer; + siolx_driver.ioctl = siolx_ioctl; + siolx_driver.throttle = siolx_throttle; + siolx_driver.unthrottle = siolx_unthrottle; + siolx_driver.set_termios = siolx_set_termios; + siolx_driver.stop = siolx_stop; + siolx_driver.start = siolx_start; + siolx_driver.hangup = siolx_hangup; + + siolx_callout_driver = siolx_driver; + siolx_callout_driver.name = "cuw"; + siolx_callout_driver.major = (siolx_major+1); + siolx_callout_driver.subtype = SIOLX_TYPE_CALLOUT; + + siolx_driver.read_proc = siolx_read_proc; + return 0; +} + + +static void siolx_release_drivers(void) +{ + unsigned int intr_val; + struct siolx_board *bp; + + if(tmp_buf) + { + free_page((unsigned long)tmp_buf); + tmp_buf = NULL; + } + if(siolx_driver_registered) + { + tty_unregister_driver(&siolx_driver); + siolx_driver_registered = 0; + } + if(siolx_callout_driver_registered) + { + tty_unregister_driver(&siolx_callout_driver); + siolx_callout_driver_registered = 0; + } + /* unallocate and turn off ints */ + for(intr_val = 0; intr_val < SIOLX_NUMINTS; ++intr_val) + { + if(SiolxIrqRoot[intr_val] != NULL) + { + for(bp = SiolxIrqRoot[intr_val]; bp != NULL; + bp = bp->next_by_interrupt) + { + SiolxShutdownBoard(bp); /* turn off int; release the plx vaddr space */ + } + free_irq(intr_val, &SiolxIrqRoot[intr_val]); + } + } + +} + +static void siolx_release_memory(void) +{ + register struct siolx_board *bp; + register struct siolx_port *port; + + while(siolx_board_root) + { + bp = siolx_board_root; + siolx_board_root = bp->next_by_global_list; + siolx_release_io_range(bp); /* releases the chip vaddr */ + kfree(bp); + } + while(siolx_port_root) + { + port = siolx_port_root; + if(port->xmit_buf) + { /* should have been done when port shutdown */ + free_page((unsigned long) port->xmit_buf); + port->xmit_buf = NULL; + } + siolx_port_root = port->next_by_global_list; + kfree(port); + } + if(siolx_table) + { + kfree(siolx_table); + siolx_table = NULL; + } + if(siolx_termios) + { + kfree(siolx_termios); + siolx_termios = NULL; + } + if(siolx_termios_locked) + { + kfree(siolx_termios_locked); + siolx_termios_locked = NULL; + } + +#ifdef SIOLX_TIMER + del_timer (&missed_irq_timer); +#endif +} + + +static void siolx_cleanup(void) +{ + siolx_release_drivers(); + siolx_release_memory(); +} + +/* + * This routine must be called by kernel at boot time + */ + +static int __init siolx_init(void) +{ + unsigned char bus; + unsigned char devfn; + struct siolx_board *bp; + struct siolx_board *bp2; + unsigned int boardcount; + struct pci_dev *pdev = NULL; + unsigned int ecntl; + unsigned int intr_val; + + printk(KERN_ALERT "aurora interea miseris mortalibus almam extulerat lucem\n"); + printk(KERN_ALERT " referens opera atque labores\n"); + printk(KERN_INFO "siolx: Siolx Aurora Asynchronous Adapter driver v" VERSION ", (c) Telford Tools, Inc.\n"); +#ifdef CONFIG_SIOLX_RTSCTS + printk (KERN_INFO "siolx: DTR/RTS pin is always RTS.\n"); +#else + printk (KERN_INFO "siolx: DTR/RTS pin is RTS when CRTSCTS is on.\n"); +#endif + memset(SiolxIrqRoot, 0, sizeof(SiolxIrqRoot)); + tmp_buf = NULL; + siolx_board_root = NULL; /* clear out the global pointers */ + siolx_board_last = NULL; + siolx_port_root = NULL; + siolx_port_last = NULL; + NumSiolxPorts = 0; + siolx_table = NULL; /* make dynamic */ + siolx_termios = NULL; + siolx_termios_locked = NULL; + siolx_driver_registered = 0; + siolx_callout_driver_registered = 0; + + boardcount = 0; + + if (siolx_init_drivers()) + { + printk(KERN_INFO "siolx: Could not initialize drivers.\n"); + return -EIO; + } + + if (!pci_present()) + { + printk(KERN_INFO "siolx: Could not find PCI bus.\n"); + return -EIO; /* no PCI bus no Aurora cards */ + } + + while(1) + { + pdev = pci_find_device (siolx_vendor_id, siolx_device_id, pdev); + if (!pdev) + { + break; /* found no devices */ + } + + DEBUGPRINT((KERN_ALERT "%s\n", pdev->name)); + DEBUGPRINT((KERN_ALERT "subsystem vendor is %x.\n", + pdev->subsystem_vendor)); + DEBUGPRINT((KERN_ALERT "subsystem device is %x.\n", + pdev->subsystem_device)); + DEBUGPRINT((KERN_ALERT + "BAR0 = %lx\nBAR1 = %lx\nBAR2 = %lx\nBAR3 = %lx\nBAR4 = %lx\nBAR5 = %lx\n", + pci_resource_start(pdev, 0), + pci_resource_start(pdev, 1), + pci_resource_start(pdev, 2), + pci_resource_start(pdev, 3), + pci_resource_start(pdev, 4), + pci_resource_start(pdev, 5))); + DEBUGPRINT((KERN_ALERT + "LAS0 = %lx\nLAS1 = %lx\nLAS2 = %lx\nLAS3 = %lx\nLAS4 = %lx\nLAS5 = %lx\n", + pci_resource_len(pdev, 0), + pci_resource_len(pdev, 1), + pci_resource_len(pdev, 2), + pci_resource_len(pdev, 3), + pci_resource_len(pdev, 4), + pci_resource_len(pdev, 5))); + + if(pdev->subsystem_vendor == siolx_subsystem_vendor) + { + if(pdev->subsystem_device == siolx_subsystem_pci_device) + { + bp = (struct siolx_board*)kmalloc(sizeof(struct siolx_board), GFP_KERNEL); + if(bp == NULL) + { + printk(KERN_ALERT "siolx: Failed to create board structure on board %d.\n", boardcount); + break; /* no memory available */ + } + memset(bp, 0, sizeof(struct siolx_board)); + bp->boardtype = BD_8000P; + } + else if(pdev->subsystem_device == siolx_subsystem_cpci_device) + { + bp = (struct siolx_board*)kmalloc(sizeof(struct siolx_board), GFP_KERNEL); + if(bp == NULL) + { + printk(KERN_ALERT + "siolx: Failed to create board structure on board%p.\n", bp); + break; /* no memory available */ + } + memset(bp, 0, sizeof(struct siolx_board)); + bp->boardtype = BD_8000C; + } + else + { + continue; + } + } + else + { + continue; + } + + DEBUGPRINT((KERN_ALERT "siolx: interrupt is %i.\n", pdev->irq)); + bus = pdev->bus->number; + devfn = pdev->devfn; + DEBUGPRINT((KERN_ALERT "siolx: bus is %x, slot is %x.\n", bus, PCI_SLOT(devfn))); + + if (pci_enable_device(pdev)) + { + kfree(bp); + continue; /* enable failed */ + } + pci_set_master(pdev); + + bp->irq = pdev->irq; + SiolxResetBoard(bp, pdev); /* make sure the board is in a known state */ + if(bp->plx_vaddr == 0) + { + printk(KERN_ALERT "siolx: failed to remap plx address space.\n"); + kfree(bp); + continue; + } + bp->vaddr = (unsigned long) ioremap_nocache(pci_resource_start(pdev, 2), + pci_resource_len(pdev, 2)); + if(bp->vaddr) + { + bp->base = (bp->vaddr + MPASYNC_CHIP1_OFFSET); + bp->boardnumber = boardcount; + if (siolx_probe(bp)) /* failure is nonzero */ + { + iounmap((void*)bp->plx_vaddr); + bp->plx_vaddr = 0; + iounmap((void*)bp->vaddr); + bp->vaddr = 0; + kfree(bp); /* something wrong with board */ + continue; + } + intr_val = bp->irq; + if((intr_val < 0) || (intr_val >= SIOLX_NUMINTS)) + { + printk(KERN_ALERT "siolx: bad interrupt %i board %p.\n", intr_val, bp); + iounmap((void*)bp->plx_vaddr); /* but plx space was remapped */ + bp->plx_vaddr = 0; + iounmap((void*)bp->vaddr); /* release chip space */ + bp->vaddr = 0; + kfree(bp); /* release the board structure */ + continue; + } + bp->next_by_interrupt = SiolxIrqRoot[intr_val]; + SiolxIrqRoot[intr_val] = bp; + if(siolx_board_last == NULL) + { + siolx_board_root = bp; + siolx_board_last = bp; + } + else + { + siolx_board_last->next_by_global_list = bp; + siolx_board_last = bp; + } + bp->chipnumber = 0; + bp->intstatus = bp->plx_vaddr + PLX_ICSR; + bp->next_by_chain = bp; /* one item chain */ + ecntl = readl(bp->plx_vaddr + PLX_ECNTL); + boardcount++; /* added a board */ + if(pci_resource_len(pdev, 2) > MPASYNC_CHIP2_OFFSET) + { + ++(bp->boardtype); /* works because how types are defined 8000X --> 16000X*/ + if(bp->boardtype == BD_16000C) + { + if((ecntl & PLX_ECNTLUSERI) == 0) + { + bp->reario = 1; + } + } + bp2 = (struct siolx_board*)kmalloc(sizeof(struct siolx_board), GFP_KERNEL); + if(bp2 == NULL) + { + printk(KERN_ALERT + "siolx: Failed to create second board structure on board %p.\n", bp); + /* fall through because must turn on ints for other chip */ + } + else + { + memset(bp2, 0, sizeof(struct siolx_board)); /* unnecessary */ + *bp2 = *bp; /* note that all guys in chain point to same next_by interrupt */ + bp->next_by_chain = bp2; /* circular list */ + bp2->next_by_chain = bp;/* now chain two elements*/ + ++(bp2->chipnumber); /* chipnumber 1 */ + bp2->base = (bp2->vaddr + MPASYNC_CHIP2_OFFSET); + if(siolx_probe(bp2)) + { + printk(KERN_ALERT "siolx: Failed to probe second board structure on board %p.\n", bp); + kfree(bp2); + /* fall through because must turn on ints for other chip */ + /* don't release pci memory remap -- still works for other chip */ + } + else if(siolx_board_last == NULL) + { + siolx_board_root = bp2; /* this case should not occur */ + siolx_board_last = bp2; + } + else + { + siolx_board_last->next_by_global_list = bp2; + siolx_board_last = bp2; + } + /* don't increment boardnumber */ + } + } + } + else /* could not remap the cd18xx space */ + { + iounmap((void*)bp->plx_vaddr); /* but plx space was remapped */ + bp->plx_vaddr = 0; + kfree(bp); + } + } + if (boardcount == 0) + { + printk(KERN_INFO "siolx: No Aurora Asynchronous Adapter boards detected.\n"); + siolx_cleanup(); /* don't need any allocated memory */ + return -EIO; + } + if (siolx_finish_init_drivers()) + { + printk(KERN_INFO "siolx: Could not finish driver initialization.\n"); + siolx_cleanup(); + return -EIO; + } + + for(intr_val = 0; intr_val < SIOLX_NUMINTS; ++intr_val) /* trying to install as few int handlers as possible */ + { /* one for each group of boards (actually chips) on a given irq */ + if(SiolxIrqRoot[intr_val] != NULL) + { + if (request_irq(intr_val, siolx_interrupt, SA_SHIRQ, "siolx Aurora Asynchronous Adapter", + &SiolxIrqRoot[intr_val]) == 0) + /* interrupts on perboard basis + * cycle through chips and then + * ports */ + /* NOTE PLX INTS ARE OFF -- so turn them on */ + { + for(bp = SiolxIrqRoot[intr_val]; bp != NULL; bp = bp->next_by_interrupt) + { + writel(PLX_ICSRLCLINTPCI | PLX_ICSRPCIINTS, bp->plx_vaddr + PLX_ICSR); /* enable interrupts */ + } + } + else + { + printk(KERN_ALERT "siolx: Unable to get interrupt, board set up not complete %i.\n", intr_val); + /* no interrupts but on all lists */ + } + } + } + return 0; +} + +module_init(siolx_init); +module_exit(siolx_cleanup); +MODULE_DESCRIPTION("multiport Aurora asynchronous driver"); +MODULE_AUTHOR("Joachim Martillo "); +MODULE_LICENSE("GPL"); diff -urN linux-2.4.23-pre8/drivers/char/cd1865/cdsiolx.h linux-2.4.23-pre8-pac1/drivers/char/cd1865/cdsiolx.h --- linux-2.4.23-pre8/drivers/char/cd1865/cdsiolx.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/char/cd1865/cdsiolx.h 2003-10-24 14:31:25.000000000 +0200 @@ -0,0 +1,136 @@ +/* -*- linux-c -*- */ +/* + * This file was modified from + * linux/drivers/char/siolx_io8.h -- + * Siolx IO8+ multiport serial driver. + * + * Copyright (C) 1997 Roger Wolff (R.E.Wolff@BitWizard.nl) + * Copyright (C) 1994-1996 Dmitry Gorodchanin (pgmdsg@ibi.com) + * Modifications (C) 2002 Telford Tools, Inc. (martillo@telfordtools.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. + * */ + +#ifndef __LINUX_SIOLX_H +#define __LINUX_SIOLX_H + +#include + +#ifdef __KERNEL__ + +#define SIOLX_NBOARD 8 + +/* eight ports per chip. */ +#define SIOLX_NPORT 8 +#define SIOLX_PORT(line) ((line) & (SIOLX_NPORT - 1)) + +#define MHz *1000000 /* I'm ashamed of myself. */ + +/* On-board oscillator frequency */ +#define SIOLX_OSCFREQ (33 MHz) +/* oregano is in /1 which mace 66Mhz is in /2 mode */ + +/* Ticks per sec. Used for setting receiver timeout and break length */ +#define SIOLX_TPS 4000 + +/* Yeah, after heavy testing I decided it must be 6. + * Sure, You can change it if needed. + */ +#define SIOLX_RXFIFO 6 /* Max. receiver FIFO size (1-8) */ + +#define SIOLX_MAGIC 0x0907 + +#define SIOLX_CCR_TIMEOUT 10000 /* CCR timeout. You may need to wait upto + 10 milliseconds before the internal + processor is available again after + you give it a command */ +#define SIOLX_NUMINTS 32 + +struct siolx_board +{ + unsigned long flags; + unsigned long base; + unsigned char irq; + unsigned char DTR; + unsigned long vaddr; + unsigned long plx_vaddr; + unsigned long intstatus; + struct siolx_board *next_by_chain; /* chains are circular */ + struct siolx_board *next_by_interrupt; /* only chip 0 */ + struct siolx_board *next_by_global_list; /* all boards not circular */ + struct siolx_port *portlist; + struct pci_dev pdev; + unsigned int chipnumber; /* for 8000X this structure really defines the board + * for 16000X the chain corresponds to a board and each + * structure corresponds to a dhip on a single board */ + unsigned int boardnumber; /* same for all boards/chips in a board chain */ + unsigned int boardtype; + unsigned int chiptype; + unsigned int chiprev; + unsigned int reario; + unsigned int rj45; +}; + +#define DRIVER_DEBUG() (siolx_debug) +#define DEBUGPRINT(arg) if(DRIVER_DEBUG()) printk arg + +struct siolx_port +{ + int magic; + int baud_base; + int flags; + struct tty_struct * tty; + int count; + int blocked_open; + int event; + int timeout; + int close_delay; + long session; + long pgrp; + unsigned char * xmit_buf; + int custom_divisor; + int xmit_head; + int xmit_tail; + int xmit_cnt; + struct termios normal_termios; + struct termios callout_termios; + wait_queue_head_t open_wait; + wait_queue_head_t close_wait; + struct tq_struct tqueue; + struct tq_struct tqueue_hangup; + short wakeup_chars; + short break_length; + unsigned short closing_wait; + unsigned char mark_mask; + unsigned char IER; + unsigned char MSVR; + unsigned char COR2; +#ifdef SIOLX_REPORT_OVERRUN + unsigned long overrun; +#endif +#ifdef SIOLX_REPORT_FIFO + unsigned long hits[10]; +#endif + struct siolx_port *next_by_global_list; + struct siolx_port *next_by_board; + struct siolx_board *board; + unsigned int boardport; /* relative to chain 0-15 for 16000X */ + unsigned int driverport; /* maps to minor device number */ +}; + +#endif /* __KERNEL__ */ +#endif /* __LINUX_SIOLX_H */ diff -urN linux-2.4.23-pre8/drivers/char/cd1865/plx9060.h linux-2.4.23-pre8-pac1/drivers/char/cd1865/plx9060.h --- linux-2.4.23-pre8/drivers/char/cd1865/plx9060.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/char/cd1865/plx9060.h 2003-10-24 14:31:25.000000000 +0200 @@ -0,0 +1,97 @@ +#ifndef _PLX9060_H_ +#define _PLX9060_H_ +/* + * Aurora Cirrus CL-CD180/1865 Async Driver (sio16) + * + * This module contains the definitions for the PLX + * 9060SD PCI controller chip. + * + * COPYRIGHT (c) 1996-1998 BY AURORA TECHNOLOGIES, INC., WALTHAM, MA. + * Modifications Copyright (C) 2002 By Telford Tools, Inc., Boston, MA. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the 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. + * + * file: plx9060.h + * author: cmw + * created: 11/21/1996 + * info: $Id: plx9060.h,v 1.2 2002/06/11 02:50:02 martillo Exp $ + */ + +/* + * $Log: plx9060.h,v $ + * Revision 1.2 2002/06/11 02:50:02 martillo + * using silx_ and SILX_ instead of sx_ and SX_ + * + * Revision 1.1 2002/05/21 17:30:16 martillo + * first pass for the sio16 driver. + * + * Revision 1.4 1999/02/12 15:38:13 bkd + * Changed PLX_ECNTUSER0 to PLX_ECNTLUSERO and added PLX_ECNTLUSERI. + * + * Revision 1.3 1998/03/23 19:35:42 bkd + * Added definitions for all of the missing PLX9060SD registers. + * + * Revision 1.2 1998/03/13 21:02:16 bkd + * Updated copyright date to include 1998. + * + * Revision 1.1 1996/11/23 01:07:46 bkd + * cmw/bkd (PCI port): + * Initial check-in. + * + */ + +/* + * Register definitions + */ + +#define PLX_LAS0RR 0x00 +#define PLX_LAS0BAR 0x04 +#define PLX_LAR 0x08 +#define PLX_ENDR 0x0c +#define PLX_EROMRR 0x10 +#define PLX_EROMBAR 0x14 +#define PLX_LAS0BRD 0x18 +#define PLX_LAS1RR 0x30 +#define PLX_LAS1BAR 0x34 +#define PLX_LAS1BRD 0x38 + +#define PLX_MBR0 0x40 +#define PLX_MBR1 0x44 +#define PLX_MBR2 0x48 +#define PLX_MBR3 0x4c +#define PLX_PCI2LCLDBR 0x60 +#define PLX_LCL2PCIDBR 0x64 +#define PLX_ICSR 0x68 +#define PLX_ECNTL 0x6c + +/* + * Bit definitions + */ + +#define PLX_ECNTLUSERO 0x00010000 /* turn on user output */ +#define PLX_ECNTLUSERI 0x00020000 /* user input */ +#define PLX_ECNTLLDREG 0x20000000 /* reload configuration registers */ +#define PLX_ECNTLLCLRST 0x40000000 /* local bus reset */ +#define PLX_ECNTLINITSTAT 0x80000000 /* mark board init'ed */ + + +#define PLX_ICSRLSERR_ENA 0x00000001 /* enable local bus LSERR# */ +#define PLX_ICSRLSERRP_ENA 0x00000002 /* enable local bus LSERR# PCI */ +#define PLX_ICSRPCIINTS 0x00000100 /* enable PCI interrupts */ +#define PLX_ICSRLCLINTPCI 0x00000800 +#define PLX_ICSRINTACTIVE 0x00008000 /* RO: local interrupt active */ + +#endif diff -urN linux-2.4.23-pre8/drivers/char/cd1865/siolx.h linux-2.4.23-pre8-pac1/drivers/char/cd1865/siolx.h --- linux-2.4.23-pre8/drivers/char/cd1865/siolx.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/char/cd1865/siolx.h 2003-10-24 14:31:25.000000000 +0200 @@ -0,0 +1,94 @@ +/* -*- linux-c -*- */ +#ifndef _SIOLX_H_ +#define _SIOLX_H_ + +/* + * Modifications Copyright (C) 2002 By Telford Tools, Inc., Boston, MA. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the 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. + */ + +#define AURASUBSYSTEM_VENDOR_ID 0x125c +#define AURASUBSYSTEM_MPASYNCPCI 0x0640 +#define AURASUBSYSTEM_MPASYNCcPCI 0x0641 + +/* + * Aurora Cirrus CL-CD180/1865 Async Driver (sio16) + * + */ + +/* + * Register sets. These must match the order of the registers specified + * in the prom on the board! + */ + +#define MPASYNC_REG_CSR 1 +#define MPASYNC_REG_CD 2 + +#define MPASYNC_CHIP1_OFFSET 0x080 +#define MPASYNC_CHIP2_OFFSET 0x100 + +#define MPASYNC_REG_NO_OBP_CSR 1 +#define MPASYNC_REG_NO_OBP_CD 3 + +#define TX_FIFO 0x8 /* how deep is the chip fifo */ + +/* + * state flags + */ + +/* + * the following defines the model types + */ + +#define OREGANO_MODEL(mod) ((mod) == BD_16000P || (mod) == BD_8000P) +#define MACE_MODEL(mod) ((mod) == BD_16000C || (mod) == BD_8000C) + +/* + * I/O options: + */ + +#define MACE8_STD 0x0 /* 8000CP -- standard I/O */ +#define MACE8_RJ45 0x1 /* 8000CP -- rear RJ45 I/O */ + +#define MACE16_STD 0x0 /* 16000CP -- standard I/O */ +#define MACE16_RJ45 0x1 /* 16000CP -- rear RJ45 I/O */ + +#define SE2_CLK ((unsigned int) 11059200) /* 11.0592 MHz */ +#define SE_CLK ((unsigned int) 14745600) /* 14.7456 MHz */ +#define SE3_CLK ((unsigned int) 33000000) /* 33.3333 MHz */ + +/* divide x by y, rounded */ +#define ROUND_DIV(x, y) (((x) + ((y) >> 1)) / (y)) + +/* Calculate a 16 bit baud rate divisor for the given "encoded" + * (multiplied by two) baud rate. + */ + +/* chip types: */ +#define CT_UNKNOWN 0x0 /* unknown */ +#define CT_CL_CD180 0x1 /* Cirrus Logic CD-180 */ +#define CT_CL_CD1864 0x2 /* Cirrus Logic CD-1864 */ +#define CT_CL_CD1865 0x3 /* Cirrus Logic CD-1864 */ + +/* chip revisions: */ +#define CR_UNKNOWN 0x0 /* unknown */ +#define CR_REVA 0x1 /* revision A */ +#define CR_REVB 0x2 /* revision B */ +#define CR_REVC 0x3 /* revision C */ +/* ...and so on ... */ + +#endif diff -urN linux-2.4.23-pre8/drivers/char/console.c linux-2.4.23-pre8-pac1/drivers/char/console.c --- linux-2.4.23-pre8/drivers/char/console.c 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/console.c 2003-10-24 14:31:25.000000000 +0200 @@ -2405,7 +2405,7 @@ tty->winsize.ws_row = video_num_lines; tty->winsize.ws_col = video_num_columns; } - if (tty->count == 1) + if (atomic_read(&tty->count) == 1) vcs_make_devfs (currcons, 0); return 0; } @@ -2414,7 +2414,7 @@ { if (!tty) return; - if (tty->count != 1) return; + if (atomic_read(&tty->count) != 1) return; vcs_make_devfs (MINOR (tty->device) - tty->driver.minor_start, 1); tty->driver_data = 0; } diff -urN linux-2.4.23-pre8/drivers/char/cyclades.c linux-2.4.23-pre8-pac1/drivers/char/cyclades.c --- linux-2.4.23-pre8/drivers/char/cyclades.c 2003-06-13 16:51:32.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/cyclades.c 2003-10-24 14:31:25.000000000 +0200 @@ -2822,7 +2822,7 @@ #ifdef CY_DEBUG_OPEN printk("cyc:cy_close ttyC%d, count = %d\n", info->line, info->count); #endif - if ((tty->count == 1) && (info->count != 1)) { + if ((atomic_read(&tty->count) == 1) && (info->count != 1)) { /* * Uh, oh. tty->count is 1, which means that the tty * structure will be freed. Info->count should always diff -urN linux-2.4.23-pre8/drivers/char/drm/Config.in linux-2.4.23-pre8-pac1/drivers/char/drm/Config.in --- linux-2.4.23-pre8/drivers/char/drm/Config.in 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/Config.in 2003-10-24 14:40:43.000000000 +0200 @@ -1,5 +1,5 @@ # -# drm device configuration +# Drm device configuration # # This driver provides support for the # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. @@ -10,11 +10,10 @@ tristate ' ATI Rage 128' CONFIG_DRM_R128 tristate ' ATI Radeon' CONFIG_DRM_RADEON dep_tristate ' Intel I810' CONFIG_DRM_I810 $CONFIG_AGP -dep_mbool ' Enabled XFree 4.1 ioctl interface by default' CONFIG_DRM_I810_XFREE_41 $CONFIG_DRM_I810 -dep_tristate ' Intel 830M' CONFIG_DRM_I830 $CONFIG_AGP +dep_tristate ' Intel 830M/845G/852GM/855GM/865G' CONFIG_DRM_I830 $CONFIG_AGP dep_tristate ' Matrox g200/g400' CONFIG_DRM_MGA $CONFIG_AGP dep_tristate ' SiS' CONFIG_DRM_SIS $CONFIG_AGP -# -# Not ready yet. XFree DRI folks have to fix this up. -# dep_tristate ' S3 Savage' CONFIG_DRM_SAVAGE $CONFIG_AGP -# dep_tristate ' VIA CLE266' CONFIG_DRM_VIA $CONFIG_AGP +# The following are known broken and need to be fixed by the DRI folks. +# Enabled anyway just in case someone wants to fix them ;) +dep_tristate ' VIA' CONFIG_DRM_VIA $CONFIG_AGP +dep_tristate ' S3 Savage' CONFIG_DRM_S3 $CONFIG_AGP diff -urN linux-2.4.23-pre8/drivers/char/drm/Imakefile linux-2.4.23-pre8-pac1/drivers/char/drm/Imakefile --- linux-2.4.23-pre8/drivers/char/drm/Imakefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/Imakefile 2003-10-11 23:18:11.000000000 +0200 @@ -0,0 +1,48 @@ +XCOMM $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/Imakefile,v 1.10 2003/09/28 20:16:06 alanh Exp $ + +#include + +XCOMM This is a kludge until we determine how best to build the +XCOMM kernel-specific device driver. This allows us to continue +XCOMM to maintain the single Makefile.linux with kernel-specific +XCOMM support. Later, we can move to a different Imakefile. + +#if BuildXF86DRI && BuildXF86DRM +all:: + $(MAKE) -f Makefile.linux + +clean:: + $(MAKE) -f Makefile.linux clean +#else +all:: + @echo 'Use "make -f Makefile.linux" to manually build drm.o' +#endif + +LinkSourceFile(drm_sarea.h,$(XF86OSSRC)/shared/drm/kernel) +LinkSourceFile(mga.h,$(XF86OSSRC)/shared/drm/kernel) +LinkSourceFile(mga_dma.c,$(XF86OSSRC)/shared/drm/kernel) +LinkSourceFile(mga_drm.h,$(XF86OSSRC)/shared/drm/kernel) +LinkSourceFile(mga_drv.h,$(XF86OSSRC)/shared/drm/kernel) +LinkSourceFile(mga_irq.c,$(XF86OSSRC)/shared/drm/kernel) +LinkSourceFile(mga_state.c,$(XF86OSSRC)/shared/drm/kernel) +LinkSourceFile(mga_ucode.h,$(XF86OSSRC)/shared/drm/kernel) +LinkSourceFile(mga_warp.c,$(XF86OSSRC)/shared/drm/kernel) +LinkSourceFile(r128.h,$(XF86OSSRC)/shared/drm/kernel) +LinkSourceFile(r128_cce.c,$(XF86OSSRC)/shared/drm/kernel) +LinkSourceFile(r128_drm.h,$(XF86OSSRC)/shared/drm/kernel) +LinkSourceFile(r128_drv.h,$(XF86OSSRC)/shared/drm/kernel) +LinkSourceFile(r128_irq.c,$(XF86OSSRC)/shared/drm/kernel) +LinkSourceFile(r128_state.c,$(XF86OSSRC)/shared/drm/kernel) +LinkSourceFile(radeon.h,$(XF86OSSRC)/shared/drm/kernel) +LinkSourceFile(radeon_cp.c,$(XF86OSSRC)/shared/drm/kernel) +LinkSourceFile(radeon_drm.h,$(XF86OSSRC)/shared/drm/kernel) +LinkSourceFile(radeon_drv.h,$(XF86OSSRC)/shared/drm/kernel) +LinkSourceFile(radeon_state.c,$(XF86OSSRC)/shared/drm/kernel) +LinkSourceFile(radeon_mem.c,$(XF86OSSRC)/shared/drm/kernel) +LinkSourceFile(radeon_irq.c,$(XF86OSSRC)/shared/drm/kernel) +LinkSourceFile(sis.h,$(XF86OSSRC)/shared/drm/kernel) +LinkSourceFile(sis_drm.h,$(XF86OSSRC)/shared/drm/kernel) +LinkSourceFile(sis_drv.h,$(XF86OSSRC)/shared/drm/kernel) +LinkSourceFile(sis_ds.c,$(XF86OSSRC)/shared/drm/kernel) +LinkSourceFile(sis_ds.h,$(XF86OSSRC)/shared/drm/kernel) +LinkSourceFile(sis_mm.c,$(XF86OSSRC)/shared/drm/kernel) diff -urN linux-2.4.23-pre8/drivers/char/drm/Kconfig linux-2.4.23-pre8-pac1/drivers/char/drm/Kconfig --- linux-2.4.23-pre8/drivers/char/drm/Kconfig 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/Kconfig 2003-08-18 12:56:12.000000000 +0200 @@ -0,0 +1,83 @@ +# +# Drm device configuration +# +# This driver provides support for the +# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. +# +config DRM + bool "Direct Rendering Manager (XFree86 4.1.0 and higher DRI support)" + help + Kernel-level support for the Direct Rendering Infrastructure (DRI) + introduced in XFree86 4.0. If you say Y here, you need to select + the module that's right for your graphics card from the list below. + These modules provide support for synchronization, security, and + DMA transfers. Please see for more + details. You should also select and configure AGP + (/dev/agpgart) support. + +config DRM_TDFX + tristate "3dfx Banshee/Voodoo3+" + depends on DRM + help + Choose this option if you have a 3dfx Banshee or Voodoo3 (or later), + graphics card. If M is selected, the module will be called tdfx. + +config DRM_GAMMA + tristate "3dlabs GMX 2000" + depends on DRM + help + This is the old gamma driver, please tell me if it might actually + work. + +config DRM_R128 + tristate "ATI Rage 128" + depends on DRM + help + Choose this option if you have an ATI Rage 128 graphics card. If M + is selected, the module will be called r128. AGP support for + this card is strongly suggested (unless you have a PCI version). + +config DRM_RADEON + tristate "ATI Radeon" + depends on DRM + help + Choose this option if you have an ATI Radeon graphics card. There + are both PCI and AGP versions. You don't need to choose this to + run the Radeon in plain VGA mode. There is a product page at + . + If M is selected, the module will be called radeon. + +config DRM_I810 + tristate "Intel I810" + depends on DRM && AGP && AGP_INTEL + help + Choose this option if you have an Intel I810 graphics card. If M is + selected, the module will be called i810. AGP support is required + for this driver to work. + +config DRM_I830 + tristate "Intel 830M, 845G, 852GM, 855GM, 865G" + depends on DRM && AGP && AGP_INTEL + help + Choose this option if you have a system that has Intel 830M, 845G, + 852GM, 855GM or 865G integrated graphics. If M is selected, the + module will be called i830. AGP support is required for this driver + to work. + + +config DRM_MGA + tristate "Matrox g200/g400" + depends on DRM && AGP + help + Choose this option if you have a Matrox G200, G400 or G450 graphics + card. If M is selected, the module will be called mga. AGP + support is required for this driver to work. + +config DRM_SIS + tristate "SiS video cards" + depends on DRM && AGP && FB_SIS + help + Choose this option if you have a SiS 630 or compatibel video + chipset. If M is selected the module will be called sis. AGP + and SiS FB support is required for this driver to work. + diff -urN linux-2.4.23-pre8/drivers/char/drm/Makefile linux-2.4.23-pre8-pac1/drivers/char/drm/Makefile --- linux-2.4.23-pre8/drivers/char/drm/Makefile 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/Makefile 2003-10-24 14:29:02.000000000 +0200 @@ -1,22 +1,43 @@ # # Makefile for the drm device driver. This driver provides support for the # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. - -O_TARGET := drm.o -list-multi := gamma.o tdfx.o r128.o mga.o i810.o i830.o radeon.o ffb.o sis.o savage.o +# +# Based on David Woodhouse's mtd build. +# +# $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/Makefile.kernel,v 1.18 2003/08/16 17:59:17 dawes Exp $ +# gamma-objs := gamma_drv.o gamma_dma.o tdfx-objs := tdfx_drv.o -r128-objs := r128_drv.o r128_cce.o r128_state.o -mga-objs := mga_drv.o mga_dma.o mga_state.o mga_warp.o +r128-objs := r128_drv.o r128_cce.o r128_state.o r128_irq.o +mga-objs := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o i810-objs := i810_drv.o i810_dma.o i830-objs := i830_drv.o i830_dma.o i830_irq.o -savage-objs := savage_dma.o savage_drv.o savage_state.o radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o -ffb-objs := ffb_drv.o ffb_context.o sis-objs := sis_drv.o sis_ds.o sis_mm.o +ffb-objs := ffb_drv.o ffb_context.o +savage-objs := savage_dma.o savage_drv.o savage_state.o via-objs := via_drv.o via_ds.o via_map.o via_mm.o +EXTRA_CFLAGS += -DDO_MUNMAP_4_ARGS + +# Kernel version checks + +BELOW25 := $(shell if [ $(PATCHLEVEL) -lt 5 ]; then echo y; fi) +# There were major build changes starting with 2.5.52 +ifneq ($(BELOW25),y) +BELOW2552 := $(shell if [ $(PATCHLEVEL) -eq 5 -a $(SUBLEVEL) -lt 52 ]; then echo y; fi) +else +BELOW2552 := y +endif + +ifeq ($(BELOW25),y) +O_TARGET := drm.o +list-multi := gamma.o tdfx.o r128.o mga.o i810.o i830.o ffb.o radeon.o savage.o via.o +obj-m := +obj-n := +obj- := +endif obj-$(CONFIG_DRM_GAMMA) += gamma.o obj-$(CONFIG_DRM_TDFX) += tdfx.o @@ -25,13 +46,16 @@ obj-$(CONFIG_DRM_MGA) += mga.o obj-$(CONFIG_DRM_I810) += i810.o obj-$(CONFIG_DRM_I830) += i830.o -obj-$(CONFIG_DRM_FFB) += ffb.o obj-$(CONFIG_DRM_SIS) += sis.o -obj-$(CONFIG_DRM_SAVAGE) += savage.o +obj-$(CONFIG_DRM_FFB) += ffb.o +obj-$(CONFIG_DRM_S3) += savage.o obj-$(CONFIG_DRM_VIA) += via.o +ifeq ($(BELOW2552),y) include $(TOPDIR)/Rules.make +endif +ifeq ($(BELOW25),y) gamma.o: $(gamma-objs) $(lib) $(LD) -r -o $@ $(gamma-objs) $(lib) @@ -53,14 +77,15 @@ radeon.o: $(radeon-objs) $(lib) $(LD) -r -o $@ $(radeon-objs) $(lib) -ffb.o: $(ffb-objs) $(lib) - $(LD) -r -o $@ $(ffb-objs) $(lib) - sis.o: $(sis-objs) $(lib) $(LD) -r -o $@ $(sis-objs) $(lib) +ffb.o: $(ffb-objs) $(lib) + $(LD) -r -o $@ $(ffb-objs) $(lib) + savage.o: $(savage-objs) $(lib) $(LD) -r -o $@ $(savage-objs) $(lib) via.o: $(via-objs) $(lib) $(LD) -r -o $@ $(via-objs) $(lib) +endif diff -urN linux-2.4.23-pre8/drivers/char/drm/Makefile.kernel linux-2.4.23-pre8-pac1/drivers/char/drm/Makefile.kernel --- linux-2.4.23-pre8/drivers/char/drm/Makefile.kernel 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/Makefile.kernel 2003-08-18 12:56:12.000000000 +0200 @@ -0,0 +1,81 @@ +# +# Makefile for the drm device driver. This driver provides support for the +# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. +# +# Based on David Woodhouse's mtd build. +# +# $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/Makefile.kernel,v 1.18 2003/08/16 17:59:17 dawes Exp $ +# + +gamma-objs := gamma_drv.o gamma_dma.o +tdfx-objs := tdfx_drv.o +r128-objs := r128_drv.o r128_cce.o r128_state.o r128_irq.o +mga-objs := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o +i810-objs := i810_drv.o i810_dma.o +i830-objs := i830_drv.o i830_dma.o i830_irq.o +radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o +sis-objs := sis_drv.o sis_ds.o sis_mm.o +ffb-objs := ffb_drv.o ffb_context.o + +# Kernel version checks + +BELOW25 := $(shell if [ $(PATCHLEVEL) -lt 5 ]; then echo y; fi) + +# There were major build changes starting with 2.5.52 +ifneq ($(BELOW25),y) +BELOW2552 := $(shell if [ $(PATCHLEVEL) -eq 5 -a $(SUBLEVEL) -lt 52 ]; then echo y; fi) +else +BELOW2552 := y +endif + +ifeq ($(BELOW25),y) +O_TARGET := drm.o +list-multi := gamma.o tdfx.o r128.o mga.o i810.o i830.o ffb.o radeon.o +obj-m := +obj-n := +obj- := +endif + +obj-$(CONFIG_DRM_GAMMA) += gamma.o +obj-$(CONFIG_DRM_TDFX) += tdfx.o +obj-$(CONFIG_DRM_R128) += r128.o +obj-$(CONFIG_DRM_RADEON)+= radeon.o +obj-$(CONFIG_DRM_MGA) += mga.o +obj-$(CONFIG_DRM_I810) += i810.o +obj-$(CONFIG_DRM_I830) += i830.o +obj-$(CONFIG_DRM_SIS) += sis.o +obj-$(CONFIG_DRM_FFB) += ffb.o + +ifeq ($(BELOW2552),y) +include $(TOPDIR)/Rules.make +endif + +ifeq ($(BELOW25),y) +gamma.o: $(gamma-objs) $(lib) + $(LD) -r -o $@ $(gamma-objs) $(lib) + +tdfx.o: $(tdfx-objs) $(lib) + $(LD) -r -o $@ $(tdfx-objs) $(lib) + +mga.o: $(mga-objs) $(lib) + $(LD) -r -o $@ $(mga-objs) $(lib) + +i810.o: $(i810-objs) $(lib) + $(LD) -r -o $@ $(i810-objs) $(lib) + +i830.o: $(i830-objs) $(lib) + $(LD) -r -o $@ $(i830-objs) $(lib) + +r128.o: $(r128-objs) $(lib) + $(LD) -r -o $@ $(r128-objs) $(lib) + +radeon.o: $(radeon-objs) $(lib) + $(LD) -r -o $@ $(radeon-objs) $(lib) + +sis.o: $(sis-objs) $(lib) + $(LD) -r -o $@ $(sis-objs) $(lib) + +ffb.o: $(ffb-objs) $(lib) + $(LD) -r -o $@ $(ffb-objs) $(lib) +endif + diff -urN linux-2.4.23-pre8/drivers/char/drm/Makefile.linux linux-2.4.23-pre8-pac1/drivers/char/drm/Makefile.linux --- linux-2.4.23-pre8/drivers/char/drm/Makefile.linux 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/Makefile.linux 2003-10-11 23:18:11.000000000 +0200 @@ -0,0 +1,361 @@ +# Makefile -- For the Direct Rendering Manager module (drm) +# +# Based on David Woodhouse's mtd build. +# +# Modified to handle the DRM requirements and builds on a wider range of +# platforms in a flexible way by David Dawes. It's not clear, however, +# that this approach is simpler than the old one. +# +# The purpose of this Makefile.linux file is to handle setting up everything +# needed for an out-of-kernel source build. Makefile.kernel contains +# everything required for in-kernel source builds. It is included into +# this file, so none of that should be duplicated here. +# +# $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/Makefile.linux,v 1.41 2003/09/28 20:16:06 alanh Exp $ +# + +# +# By default, the build is done against the running linux kernel source. +# To build against a different kernel source tree, set LINUXDIR: +# +# make -f Makefile.linux LINUXDIR=/path/to/kernel/source + +# +# To build only some modules, either set DRM_MODULES to the list of modules, +# or specify the modules as targets: +# +# make -f Makefile.linux r128.o radeon.o +# +# or: +# +# make -f Makefile.linux DRM_MODULES="r128 radeon" +# + +SHELL=/bin/sh + +.SUFFIXES: + +ifndef LINUXDIR +RUNNING_REL := $(shell uname -r) + +LINUXDIR := /lib/modules/$(RUNNING_REL)/build +endif + +MACHINE := $(shell uname -m) + +# Modules for all architectures +MODULE_LIST := gamma.o tdfx.o r128.o radeon.o mga.o sis.o + +# Modules only for ix86 architectures +ifneq (,$(findstring 86,$(MACHINE))) +ARCHX86 := 1 +MODULE_LIST += i830.o i810.o +endif + +# Add ffb.o for sparc?? + +DRM_MODULES ?= $(MODULE_LIST) + +# These definitions are for handling dependencies in the out of kernel build. + +DRMTEMPLATES = drm_auth.h drm_bufs.h drm_context.h drm_dma.h drm_drawable.h \ + drm_drv.h drm_fops.h drm_init.h drm_ioctl.h \ + drm_lock.h drm_memory.h drm_proc.h drm_stub.h drm_vm.h + +DRMSHARED = drm_sarea.h +DRMHEADERS = drm.h drmP.h $(DRMSHARED) + +GAMMAHEADERS = gamma.h gamma_context.h gamma_drm.h gamma_drv.h gamma_lists.h \ + gamma_old_dma.h gamma_lock.h $(DRMHEADERS) $(DRMTEMPLATES) +TDFXHEADERS = tdfx.h $(DRMHEADERS) $(DRMTEMPLATES) +R128HEADERS = r128.h r128_drv.h r128_drm.h $(DRMHEADERS) $(DRMTEMPLATES) +R128SHARED = r128.h r128_drv.h r128_drm.h r128_cce.c r128_state.c r128_irq.c +RADEONHEADERS = radeon.h radeon_drv.h radeon_drm.h $(DRMHEADERS) \ + $(DRMTEMPLATES) +RADEONSHARED = radeon.h radeon_drv.h radeon_drm.h radeon_cp.c radeon_irq.c \ + radeon_mem.c radeon_state.c +MGAHEADERS = mga.h mga_drv.h mga_drm.h mga_ucode.h $(DRMHEADERS) \ + $(DRMTEMPLATES) +MGASHARED = mga.h mga_dma.c mga_drm.h mga_drv.h mga_irq.c mga_state.c \ + mga_ucode.h mga_warp.c +I810HEADERS = i810.h i810_drv.h i810_drm.h $(DRMHEADERS) $(DRMTEMPLATES) +I830HEADERS = i830.h i830_drv.h i830_drm.h $(DRMHEADERS) $(DRMTEMPLATES) +SISHEADERS= sis_drv.h sis_drm.h $(DRMHEADERS) + +SHAREDSRC = $(DRMSHARED) $(MGASHARED) $(R128SHARED) $(RADEONSHARED) + +PROGS = dristat drmstat + +CLEANFILES = *.o *.ko $(PROGS) .depend .*.flags .*.d .*.cmd + +# VERSION is not defined from the initial invocation. It is defined when +# this Makefile is invoked from the kernel's root Makefile. + +ifndef VERSION + +ifdef RUNNING_REL + +# SuSE has the version.h and autoconf.h headers for the current kernel +# in /boot as /boot/vmlinuz.version.h and /boot/vmlinuz.autoconf.h. +# Check these first to see if they match the running kernel. + +BOOTVERSION_PREFIX = /boot/vmlinuz. + +V := $(shell if [ -f $(BOOTVERSION_PREFIX)version.h ]; then \ + grep UTS_RELEASE $(BOOTVERSION_PREFIX)version.h | \ + cut -d' ' -f3; fi) + +ifeq ($(V),"$(RUNNING_REL)") +HEADERFROMBOOT := 1 +GETCONFIG := MAKEFILES=$(shell pwd)/.config +HAVECONFIG := y +endif + +# On Red Hat we need to check if there is a .config file in the kernel +# source directory. If there isn't, we need to check if there's a +# matching file in the configs subdirectory. + +ifneq ($(HAVECONFIG),y) +HAVECONFIG := $(shell if [ -e $(LINUXDIR)/.config ]; then echo y; fi) +endif + +ifneq ($(HAVECONFIG),y) +REL_BASE := $(shell echo $(RUNNING_REL) | sed 's/-.*//') +REL_TYPE := $(shell echo $(RUNNING_REL) | sed 's/[0-9.-]//g') +ifeq ($(REL_TYPE),) +RHCONFIG := configs/kernel-$(REL_BASE)-$(MACHINE).config +else +RHCONFIG := configs/kernel-$(REL_BASE)-$(MACHINE)-$(REL_TYPE).config +endif +HAVECONFIG := $(shell if [ -e $(LINUXDIR)/$(RHCONFIG) ]; then echo y; fi) +ifneq ($(HAVECONFIG),y) +RHCONFIG := +endif +endif + +ifneq ($(HAVECONFIG),y) +$(error Cannot find a kernel config file) +endif + +endif + +CLEANCONFIG := $(shell if cmp -s $(LINUXDIR)/.config .config; then echo y; fi) +ifeq ($(CLEANCONFIG),y) +CLEANFILES += $(LINUXDIR)/.config .config $(LINUXDIR)/tmp_include_depends +endif + +# The Makefile renaming hack is required because the standard kernel build, +# especially 2.5.52 and later, explicitly references the Makefile by the +# name "Makefile". For builds prior to 2.5.52, the name GNUmakefile could +# have been used. + +all: modules + +modules: includes + @if test -f Makefile && cmp -s Makefile Makefile.linux; then : ; \ + else \ + if [ -e Makefile ]; then \ + (set -x; mv -f Makefile Makefile._xx_); fi; \ + (set -x; ln -s Makefile.linux Makefile); fi + make -C $(LINUXDIR) $(GETCONFIG) SUBDIRS=`pwd` DRMSRCDIR=`pwd` modules + @if cmp -s Makefile Makefile.linux; then \ + (set -x; rm -f Makefile); \ + if [ -e Makefile._xx_ ]; then \ + (set -x; mv -f Makefile._xx_ Makefile); fi; fi + +ifeq ($(HEADERFROMBOOT),1) + +BOOTHEADERS = version.h autoconf.h +BOOTCONFIG = .config + +CLEANFILES += $(BOOTHEADERS) $(BOOTCONFIG) + +includes:: $(BOOTHEADERS) $(BOOTCONFIG) + +version.h: $(BOOTVERSION_PREFIX)version.h + rm -f $@ + ln -s $< $@ + +autoconf.h: $(BOOTVERSION_PREFIX)autoconf.h + rm -f $@ + ln -s $< $@ + +.config: $(BOOTVERSION_PREFIX)config + rm -f $@ + ln -s $< $@ +endif + +# This prepares an unused Red Hat kernel tree for the build. +ifneq ($(RHCONFIG),) +includes:: $(LINUXDIR)/.config $(LINUXDIR)/tmp_include_depends .config + +$(LINUXDIR)/.config: $(LINUXDIR)/$(RHCONFIG) + rm -f $@ + ln -s $< $@ + +.config: $(LINUXDIR)/$(RHCONFIG) + rm -f $@ + ln -s $< $@ + +$(LINUXDIR)/tmp_include_depends: + echo all: > $@ +endif + +# Make sure that the shared source files are linked into this directory. + + +SHAREDDIR := ../../../shared/drm/kernel + +HASSHARED := $(shell if [ -d $(SHAREDDIR) ]; then echo y; fi) + +ifeq ($(HASSHARED),y) +includes:: $(SHAREDSRC) + +$(SHAREDSRC): + @if [ -r $(SHAREDDIR)/$@ ]; then \ + (rm -f $@; set -x; ln -s $(SHAREDDIR)/$@ $@); fi + +CLEANFILES += $(SHAREDSRC) +endif + +includes:: linux + +linux: + rm -f linux + ln -s . linux + +clean cleandir: + rm -f $(CLEANFILES) + +$(MODULE_LIST):: + make -f Makefile.linux DRM_MODULES=$@ modules + +# Build test utilities + +PRGCFLAGS = $(CFLAGS) -g -ansi -pedantic -DPOSIX_C_SOURCE=199309L \ + -D_POSIX_SOURCE -D_XOPEN_SOURCE -D_BSD_SOURCE -D_SVID_SOURCE \ + -I. -I../../.. + +DRMSTATLIBS = -L../../.. -L.. -ldrm -lxf86_os \ + -L../../../../dummylib -ldummy -lm + +programs: $(PROGS) + +dristat: dristat.c + $(CC) $(PRGCFLAGS) $< -o $@ + +drmstat: drmstat.c + $(CC) $(PRGCFLAGS) $< -o $@ $(DRMSTATLIBS) + +else + +# Check for kernel versions that we don't support. + +BELOW24 := $(shell if [ $(VERSION) -lt 2 -o $(PATCHLEVEL) -lt 4 ]; then \ + echo y; fi) + +ifeq ($(BELOW24),y) +$(error Only 2.4.x and later kernels are supported \ + ($(VERSION).$(PATCHLEVEL).$(SUBLEVEL))) +endif + +ifdef ARCHX86 +ifndef CONFIG_X86_CMPXCHG +$(error CONFIG_X86_CMPXCHG needs to be enabled in the kernel) +endif +endif + +# This needs to go before all other include paths. +CC += -I$(DRMSRCDIR) + +# Check for Red Hat's 4-argument do_munmap(). +DOMUNMAP := $(shell grep do_munmap $(LINUXDIR)/include/linux/mm.h | \ + grep -c acct) + +ifneq ($(DOMUNMAP),0) +EXTRA_CFLAGS += -DDO_MUNMAP_4_ARGS +endif + +# Check for 5-argument remap_page_range() in RH9 kernel, and 2.5.x kernels +RPR := $(shell grep remap_page_range $(LINUXDIR)/include/linux/mm.h | \ + grep -c vma) + +ifneq ($(RPR),0) +EXTRA_CFLAGS += -DREMAP_PAGE_RANGE_5_ARGS +endif + +# Check for 4-argument vmap() in some 2.5.x and 2.4.x kernels +VMAP := $(shell grep -A1 'vmap.*count,$$' $(LINUXDIR)/include/linux/vmalloc.h | \ + grep -c prot) + +ifneq ($(VMAP),0) +EXTRA_CFLAGS += -DVMAP_4_ARGS +endif + +# Check for PAGE_AGP definition +PAGE_AGP := $(shell cat $(LINUXDIR)/include/asm/agp.h 2>/dev/null | \ + grep -c PAGE_AGP) + +ifneq ($(PAGE_AGP),0) +EXTRA_CFLAGS += -DHAVE_PAGE_AGP +endif + + +# Start with all modules turned off. +CONFIG_DRM_GAMMA := n +CONFIG_DRM_TDFX := n +CONFIG_DRM_MGA := n +CONFIG_DRM_I810 := n +CONFIG_DRM_R128 := n +CONFIG_DRM_RADEON := n +CONFIG_DRM_I830 := n +CONFIG_DRM_SIS := n +CONFIG_DRM_FFB := n + +# Enable module builds for the modules requested/supported. + +ifneq (,$(findstring gamma,$(DRM_MODULES))) +CONFIG_DRM_GAMMA := m +endif +ifneq (,$(findstring tdfx,$(DRM_MODULES))) +CONFIG_DRM_TDFX := m +endif +ifneq (,$(findstring r128,$(DRM_MODULES))) +CONFIG_DRM_R128 := m +endif +ifneq (,$(findstring radeon,$(DRM_MODULES))) +CONFIG_DRM_RADEON := m +endif +ifneq (,$(findstring sis,$(DRM_MODULES))) +CONFIG_DRM_SIS := m +endif + +# These require AGP support + +ifdef CONFIG_AGP +ifneq (,$(findstring mga,$(DRM_MODULES))) +CONFIG_DRM_MGA := m +endif +ifneq (,$(findstring i810,$(DRM_MODULES))) +CONFIG_DRM_I810 := m +endif +ifneq (,$(findstring i830,$(DRM_MODULES))) +CONFIG_DRM_I830 := m +endif +endif + +include $(DRMSRCDIR)/Makefile.kernel + +# Depencencies +$(gamma-objs): $(GAMMAHEADERS) +$(tdfx-objs): $(TDFXHEADERS) +$(r128-objs): $(R128HEADERS) +$(mga-objs): $(MGAHEADERS) +$(i810-objs): $(I810HEADERS) +$(i830-objs): $(I830HEADERS) +$(radeon-objs): $(RADEONHEADERS) +$(sis-objs): $(SISHEADERS) +$(ffb-objs): $(FFBHEADERS) + +endif + diff -urN linux-2.4.23-pre8/drivers/char/drm/Makefile.tmp linux-2.4.23-pre8-pac1/drivers/char/drm/Makefile.tmp --- linux-2.4.23-pre8/drivers/char/drm/Makefile.tmp 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/Makefile.tmp 2003-10-24 14:29:02.000000000 +0200 @@ -0,0 +1,86 @@ +# +# Makefile for the drm device driver. This driver provides support for the +# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. +# +# Based on David Woodhouse's mtd build. +# +# $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/Makefile.kernel,v 1.18 2003/08/16 17:59:17 dawes Exp $ +# + +gamma-objs := gamma_drv.o gamma_dma.o +tdfx-objs := tdfx_drv.o +r128-objs := r128_drv.o r128_cce.o r128_state.o r128_irq.o +mga-objs := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o +i810-objs := i810_drv.o i810_dma.o +i830-objs := i830_drv.o i830_dma.o i830_irq.o +radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o +sis-objs := sis_drv.o sis_ds.o sis_mm.o +ffb-objs := ffb_drv.o ffb_context.o +savage-objs := savage_dma.o savage_drv.o savage_state.o +via-objs := via_drv.o via_ds.o via_map.o via_mm.o +EXTRA_CFLAGS += -DDO_MUNMAP_4_ARGS + +# Kernel version checks + +BELOW25 := $(shell if [ $(PATCHLEVEL) -lt 5 ]; then echo y; fi) + +# There were major build changes starting with 2.5.52 +ifneq ($(BELOW25),y) +BELOW2552 := $(shell if [ $(PATCHLEVEL) -eq 5 -a $(SUBLEVEL) -lt 52 ]; then echo y; fi) +else +BELOW2552 := y +endif + +ifeq ($(BELOW25),y) +O_TARGET := drm.o +list-multi := gamma.o tdfx.o r128.o mga.o i810.o i830.o ffb.o radeon.o savage.o via.o +obj-m := +obj-n := +obj- := +endif + +obj-$(CONFIG_DRM_GAMMA) += gamma.o +obj-$(CONFIG_DRM_TDFX) += tdfx.o +obj-$(CONFIG_DRM_R128) += r128.o +obj-$(CONFIG_DRM_RADEON)+= radeon.o +obj-$(CONFIG_DRM_MGA) += mga.o +obj-$(CONFIG_DRM_I810) += i810.o +obj-$(CONFIG_DRM_I830) += i830.o +obj-$(CONFIG_DRM_SIS) += sis.o +obj-$(CONFIG_DRM_FFB) += ffb.o +obj-$(CONFIG_DRM_S3) += savage.o +obj-$(CONFIG_DRM_VIA) += via.o + +ifeq ($(BELOW2552),y) +include $(TOPDIR)/Rules.make +endif + +ifeq ($(BELOW25),y) +gamma.o: $(gamma-objs) $(lib) + $(LD) -r -o $@ $(gamma-objs) $(lib) + +tdfx.o: $(tdfx-objs) $(lib) + $(LD) -r -o $@ $(tdfx-objs) $(lib) + +mga.o: $(mga-objs) $(lib) + $(LD) -r -o $@ $(mga-objs) $(lib) + +i810.o: $(i810-objs) $(lib) + $(LD) -r -o $@ $(i810-objs) $(lib) + +i830.o: $(i830-objs) $(lib) + $(LD) -r -o $@ $(i830-objs) $(lib) + +r128.o: $(r128-objs) $(lib) + $(LD) -r -o $@ $(r128-objs) $(lib) + +radeon.o: $(radeon-objs) $(lib) + $(LD) -r -o $@ $(radeon-objs) $(lib) + +sis.o: $(sis-objs) $(lib) + $(LD) -r -o $@ $(sis-objs) $(lib) + +ffb.o: $(ffb-objs) $(lib) + $(LD) -r -o $@ $(ffb-objs) $(lib) +endif + diff -urN linux-2.4.23-pre8/drivers/char/drm/ati_pcigart.h linux-2.4.23-pre8-pac1/drivers/char/drm/ati_pcigart.h --- linux-2.4.23-pre8/drivers/char/drm/ati_pcigart.h 2002-11-29 00:53:12.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/ati_pcigart.h 2003-08-18 12:56:12.000000000 +0200 @@ -1,4 +1,11 @@ -/* ati_pcigart.h -- ATI PCI GART support -*- linux-c -*- +/** + * \file ati_pcigart.h + * ATI PCI GART support + * + * \author Gareth Hughes + */ + +/* * Created: Wed Dec 13 21:52:19 2000 by gareth@valinux.com * * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. @@ -22,19 +29,17 @@ * 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: - * Gareth Hughes */ +#define __NO_VERSION__ #include "drmP.h" #if PAGE_SIZE == 65536 -# define ATI_PCIGART_TABLE_ORDER 0 -# define ATI_PCIGART_TABLE_PAGES (1 << 0) +# define ATI_PCIGART_TABLE_ORDER 0 +# define ATI_PCIGART_TABLE_PAGES (1 << 0) #elif PAGE_SIZE == 16384 -# define ATI_PCIGART_TABLE_ORDER 1 -# define ATI_PCIGART_TABLE_PAGES (1 << 1) +# define ATI_PCIGART_TABLE_ORDER 1 +# define ATI_PCIGART_TABLE_PAGES (1 << 1) #elif PAGE_SIZE == 8192 # define ATI_PCIGART_TABLE_ORDER 2 # define ATI_PCIGART_TABLE_PAGES (1 << 2) @@ -45,8 +50,8 @@ # error - PAGE_SIZE not 64K, 16K, 8K or 4K #endif -# define ATI_MAX_PCIGART_PAGES 8192 /* 32 MB aperture, 4K pages */ -# define ATI_PCIGART_PAGE_SIZE 4096 /* PCI GART page size */ +# define ATI_MAX_PCIGART_PAGES 8192 /**< 32 MB aperture, 4K pages */ +# define ATI_PCIGART_PAGE_SIZE 4096 /**< PCI GART page size */ static unsigned long DRM(ati_alloc_pcigart_table)( void ) { @@ -153,7 +158,7 @@ ret = 1; -#if defined(__i386__) || defined(__x86_64__) +#if defined(__i386__) || defined(__AMD64__) asm volatile ( "wbinvd" ::: "memory" ); #else mb(); diff -urN linux-2.4.23-pre8/drivers/char/drm/dristat.c linux-2.4.23-pre8-pac1/drivers/char/drm/dristat.c --- linux-2.4.23-pre8/drivers/char/drm/dristat.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/dristat.c 2003-06-30 00:32:45.000000000 +0200 @@ -0,0 +1,270 @@ +/* dristat.c -- + * Created: Mon Jan 15 05:05:07 2001 by faith@acm.org + * + * Copyright 2000 VA Linux Systems, Inc., Fremont, California. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * 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 + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * 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 + * + */ + +#include +#include +#include +#include "../../../xf86drm.h" +#include "../xf86drmRandom.c" +#include "../xf86drmHash.c" +#include "../xf86drm.c" + +#define DRM_VERSION 0x00000001 +#define DRM_MEMORY 0x00000002 +#define DRM_CLIENTS 0x00000004 +#define DRM_STATS 0x00000008 +#define DRM_BUSID 0x00000010 + +static void getversion(int fd) +{ + drmVersionPtr version; + + version = drmGetVersion(fd); + if (version) { + printf(" Version information:\n"); + printf(" Name: %s\n", version->name ? version->name : "?"); + printf(" Version: %d.%d.%d\n", + version->version_major, + version->version_minor, + version->version_patchlevel); + printf(" Date: %s\n", version->date ? version->date : "?"); + printf(" Desc: %s\n", version->desc ? version->desc : "?"); + drmFreeVersion(version); + } else { + printf(" No version information available\n"); + } +} + +static void getbusid(int fd) +{ + const char *busid = drmGetBusid(fd); + + printf(" Busid: %s\n", *busid ? busid : "(not set)"); + drmFreeBusid(busid); +} + + +static void getvm(int fd) +{ + int i; + const char *typename; + char flagname[33]; + drmHandle offset; + drmSize size; + drmMapType type; + drmMapFlags flags; + drmHandle handle; + int mtrr; + + printf(" VM map information:\n"); + printf(" flags: (R)estricted (r)ead/(w)rite (l)ocked (k)ernel (W)rite-combine (L)ock:\n"); + printf(" slot offset size type flags address mtrr\n"); + + for (i = 0; + !drmGetMap(fd, i, &offset, &size, &type, &flags, &handle, &mtrr); + i++) { + + switch (type) { + case DRM_FRAME_BUFFER: typename = "FB"; break; + case DRM_REGISTERS: typename = "REG"; break; + case DRM_SHM: typename = "SHM"; break; + case DRM_AGP: typename = "AGP"; break; + case DRM_SCATTER_GATHER: typename = "SG"; break; + default: typename = "???"; break; + } + + flagname[0] = (flags & DRM_RESTRICTED) ? 'R' : ' '; + flagname[1] = (flags & DRM_READ_ONLY) ? 'r' : 'w'; + flagname[2] = (flags & DRM_LOCKED) ? 'l' : ' '; + flagname[3] = (flags & DRM_KERNEL) ? 'k' : ' '; + flagname[4] = (flags & DRM_WRITE_COMBINING) ? 'W' : ' '; + flagname[5] = (flags & DRM_CONTAINS_LOCK) ? 'L' : ' '; + flagname[6] = '\0'; + + printf(" %4d 0x%08lx 0x%08lx %3.3s %6.6s 0x%08lx ", + i, offset, (unsigned long)size, typename, flagname, handle); + if (mtrr < 0) printf("none\n"); + else printf("%4d\n", mtrr); + } +} + +static void getclients(int fd) +{ + int i; + int auth; + int pid; + int uid; + unsigned long magic; + unsigned long iocs; + char buf[64]; + char cmd[40]; + int procfd; + + printf(" DRI client information:\n"); + printf(" a pid uid magic ioctls prog\n"); + + for (i = 0; !drmGetClient(fd, i, &auth, &pid, &uid, &magic, &iocs); i++) { + sprintf(buf, "/proc/%d/cmdline", pid); + memset(cmd, sizeof(cmd), 0); + if ((procfd = open(buf, O_RDONLY, 0)) >= 0) { + read(procfd, cmd, sizeof(cmd)-1); + close(procfd); + } + if (*cmd) { + char *pt; + + for (pt = cmd; *pt; pt++) if (!isprint(*pt)) *pt = ' '; + printf(" %c %5d %5d %10lu %10lu %s\n", + auth ? 'y' : 'n', pid, uid, magic, iocs, cmd); + } else { + printf(" %c %5d %5d %10lu %10lu\n", + auth ? 'y' : 'n', pid, uid, magic, iocs); + } + } +} + +static void printhuman(unsigned long value, const char *name, int mult) +{ + const char *p; + double f; + /* Print width 5 number in width 6 space */ + if (value < 100000) { + printf(" %5lu", value); + return; + } + + p = name; + f = (double)value / (double)mult; + if (f < 10.0) { + printf(" %4.2f%c", f, *p); + return; + } + + p++; + f = (double)value / (double)mult; + if (f < 10.0) { + printf(" %4.2f%c", f, *p); + return; + } + + p++; + f = (double)value / (double)mult; + if (f < 10.0) { + printf(" %4.2f%c", f, *p); + return; + } +} + +static void getstats(int fd, int i) +{ + drmStatsT prev, curr; + int j; + double rate; + + printf(" System statistics:\n"); + + if (drmGetStats(fd, &prev)) return; + if (!i) { + for (j = 0; j < prev.count; j++) { + printf(" "); + printf(prev.data[j].long_format, prev.data[j].long_name); + if (prev.data[j].isvalue) printf(" 0x%08lx\n", prev.data[j].value); + else printf(" %10lu\n", prev.data[j].value); + } + return; + } + + printf(" "); + for (j = 0; j < prev.count; j++) + if (!prev.data[j].verbose) { + printf(" "); + printf(prev.data[j].rate_format, prev.data[j].rate_name); + } + printf("\n"); + + for (;;) { + sleep(i); + if (drmGetStats(fd, &curr)) return; + printf(" "); + for (j = 0; j < curr.count; j++) { + if (curr.data[j].verbose) continue; + if (curr.data[j].isvalue) { + printf(" %08lx", curr.data[j].value); + } else { + rate = (curr.data[j].value - prev.data[j].value) / (double)i; + printhuman(rate, curr.data[j].mult_names, curr.data[j].mult); + } + } + printf("\n"); + memcpy(&prev, &curr, sizeof(prev)); + } + +} + +int main(int argc, char **argv) +{ + int c; + int mask = 0; + int minor = 0; + int interval = 0; + int fd; + char buf[64]; + int i; + + while ((c = getopt(argc, argv, "avmcsbM:i:")) != EOF) + switch (c) { + case 'a': mask = ~0; break; + case 'v': mask |= DRM_VERSION; break; + case 'm': mask |= DRM_MEMORY; break; + case 'c': mask |= DRM_CLIENTS; break; + case 's': mask |= DRM_STATS; break; + case 'b': mask |= DRM_BUSID; break; + case 'i': interval = strtol(optarg, NULL, 0); break; + case 'M': minor = strtol(optarg, NULL, 0); break; + default: + fprintf( stderr, "Usage: dristat [options]\n" ); + return 1; + } + + for (i = 0; i < 16; i++) if (!minor || i == minor) { + sprintf(buf, DRM_DEV_NAME, DRM_DIR_NAME, i); + fd = drmOpenMinor(i, 1); + if (fd >= 0) { + printf("%s\n", buf); + if (mask & DRM_BUSID) getbusid(fd); + if (mask & DRM_VERSION) getversion(fd); + if (mask & DRM_MEMORY) getvm(fd); + if (mask & DRM_CLIENTS) getclients(fd); + if (mask & DRM_STATS) getstats(fd, interval); + close(fd); + } + } + + return 0; +} diff -urN linux-2.4.23-pre8/drivers/char/drm/drm.h linux-2.4.23-pre8-pac1/drivers/char/drm/drm.h --- linux-2.4.23-pre8/drivers/char/drm/drm.h 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/drm.h 2003-09-11 15:07:14.000000000 +0200 @@ -1,6 +1,14 @@ -/* drm.h -- Header for Direct Rendering Manager -*- linux-c -*- - * Created: Mon Jan 4 10:05:05 1999 by faith@precisioninsight.com +/** + * \file drm.h + * Header for the Direct Rendering Manager + * + * \author Rickard E. (Rik) Faith * + * \par Acknowledgments: + * Dec 1999, Richard Henderson , move to generic \c cmpxchg. + */ + +/* * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. * All rights reserved. @@ -23,15 +31,9 @@ * 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 - * - * Acknowledgements: - * Dec 1999, Richard Henderson , move to generic cmpxchg. - * */ + #ifndef _DRM_H_ #define _DRM_H_ @@ -44,8 +46,8 @@ #define DRM_IOC_WRITE _IOC_WRITE #define DRM_IOC_READWRITE _IOC_READ|_IOC_WRITE #define DRM_IOC(dir, group, nr, size) _IOC(dir, group, nr, size) -#elif defined(__FreeBSD__) || defined(__NetBSD__) -#if defined(__FreeBSD__) && defined(XFree86Server) +#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) +#if defined(__FreeBSD__) && defined(IN_MODULE) /* Prevent name collision when including sys/ioccom.h */ #undef ioctl #include @@ -79,32 +81,40 @@ #endif #if CONFIG_XFREE86_VERSION >= XFREE86_VERSION(4,1,0,0) +#ifdef __OpenBSD__ +#define DRM_MAJOR 81 +#else #define DRM_MAJOR 226 +#endif #define DRM_MAX_MINOR 15 #endif -#define DRM_NAME "drm" /* Name in kernel, /dev, and /proc */ -#define DRM_MIN_ORDER 5 /* At least 2^5 bytes = 32 bytes */ -#define DRM_MAX_ORDER 22 /* Up to 2^22 bytes = 4MB */ -#define DRM_RAM_PERCENT 10 /* How much system ram can we lock? */ +#define DRM_NAME "drm" /**< Name in kernel, /dev, and /proc */ +#define DRM_MIN_ORDER 5 /**< At least 2^5 bytes = 32 bytes */ +#define DRM_MAX_ORDER 22 /**< Up to 2^22 bytes = 4MB */ +#define DRM_RAM_PERCENT 10 /**< How much system ram can we lock? */ -#define _DRM_LOCK_HELD 0x80000000 /* Hardware lock is held */ -#define _DRM_LOCK_CONT 0x40000000 /* Hardware lock is contended */ +#define _DRM_LOCK_HELD 0x80000000 /**< Hardware lock is held */ +#define _DRM_LOCK_CONT 0x40000000 /**< Hardware lock is contended */ #define _DRM_LOCK_IS_HELD(lock) ((lock) & _DRM_LOCK_HELD) #define _DRM_LOCK_IS_CONT(lock) ((lock) & _DRM_LOCK_CONT) #define _DRM_LOCKING_CONTEXT(lock) ((lock) & ~(_DRM_LOCK_HELD|_DRM_LOCK_CONT)) + typedef unsigned long drm_handle_t; typedef unsigned int drm_context_t; typedef unsigned int drm_drawable_t; typedef unsigned int drm_magic_t; -/* Warning: If you change this structure, make sure you change - * XF86DRIClipRectRec in the server as well */ -/* KW: Actually it's illegal to change either for +/** + * Cliprect. + * + * \warning: If you change this structure, make sure you change + * XF86DRIClipRectRec in the server as well + * + * \note KW: Actually it's illegal to change either for * backwards-compatibility reasons. */ - typedef struct drm_clip_rect { unsigned short x1; unsigned short y1; @@ -112,6 +122,10 @@ unsigned short y2; } drm_clip_rect_t; + +/** + * Texture region, + */ typedef struct drm_tex_region { unsigned char next; unsigned char prev; @@ -120,42 +134,52 @@ unsigned int age; } drm_tex_region_t; -/* Seperate include files for the i810/mga/r128 specific structures */ -#include "mga_drm.h" -#include "i810_drm.h" -#include "r128_drm.h" -#include "radeon_drm.h" -#include "sis_drm.h" -#include "i830_drm.h" -#include "savage_drm.h" -#include "via_drm.h" +/** + * DRM_IOCTL_VERSION ioctl argument type. + * + * \sa drmGetVersion(). + */ typedef struct drm_version { - int version_major; /* Major version */ - int version_minor; /* Minor version */ - int version_patchlevel;/* Patch level */ - size_t name_len; /* Length of name buffer */ - char *name; /* Name of driver */ - size_t date_len; /* Length of date buffer */ - char *date; /* User-space buffer to hold date */ - size_t desc_len; /* Length of desc buffer */ - char *desc; /* User-space buffer to hold desc */ + int version_major; /**< Major version */ + int version_minor; /**< Minor version */ + int version_patchlevel;/**< Patch level */ + size_t name_len; /**< Length of name buffer */ + char *name; /**< Name of driver */ + size_t date_len; /**< Length of date buffer */ + char *date; /**< User-space buffer to hold date */ + size_t desc_len; /**< Length of desc buffer */ + char *desc; /**< User-space buffer to hold desc */ } drm_version_t; + +/** + * DRM_IOCTL_GET_UNIQUE ioctl argument type. + * + * \sa drmGetBusid() and drmSetBusId(). + */ typedef struct drm_unique { - size_t unique_len; /* Length of unique */ - char *unique; /* Unique name for driver instantiation */ + size_t unique_len; /**< Length of unique */ + char *unique; /**< Unique name for driver instantiation */ } drm_unique_t; + typedef struct drm_list { - int count; /* Length of user-space structures */ + int count; /**< Length of user-space structures */ drm_version_t *version; } drm_list_t; + typedef struct drm_block { int unused; } drm_block_t; + +/** + * DRM_IOCTL_CONTROL ioctl argument type. + * + * \sa drmCtlInstHandler() and drmCtlUninstHandler(). + */ typedef struct drm_control { enum { DRM_ADD_COMMAND, @@ -166,49 +190,70 @@ int irq; } drm_control_t; + +/** + * Type of memory to map. + */ typedef enum drm_map_type { - _DRM_FRAME_BUFFER = 0, /* WC (no caching), no core dump */ - _DRM_REGISTERS = 1, /* no caching, no core dump */ - _DRM_SHM = 2, /* shared, cached */ - _DRM_AGP = 3, /* AGP/GART */ - _DRM_SCATTER_GATHER = 4 /* Scatter/gather memory for PCI DMA */ + _DRM_FRAME_BUFFER = 0, /**< WC (no caching), no core dump */ + _DRM_REGISTERS = 1, /**< no caching, no core dump */ + _DRM_SHM = 2, /**< shared, cached */ + _DRM_AGP = 3, /**< AGP/GART */ + _DRM_SCATTER_GATHER = 4 /**< Scatter/gather memory for PCI DMA */ } drm_map_type_t; + +/** + * Memory mapping flags. + */ typedef enum drm_map_flags { - _DRM_RESTRICTED = 0x01, /* Cannot be mapped to user-virtual */ + _DRM_RESTRICTED = 0x01, /**< Cannot be mapped to user-virtual */ _DRM_READ_ONLY = 0x02, - _DRM_LOCKED = 0x04, /* shared, cached, locked */ - _DRM_KERNEL = 0x08, /* kernel requires access */ - _DRM_WRITE_COMBINING = 0x10, /* use write-combining if available */ - _DRM_CONTAINS_LOCK = 0x20, /* SHM page that contains lock */ - _DRM_REMOVABLE = 0x40 /* Removable mapping */ + _DRM_LOCKED = 0x04, /**< shared, cached, locked */ + _DRM_KERNEL = 0x08, /**< kernel requires access */ + _DRM_WRITE_COMBINING = 0x10, /**< use write-combining if available */ + _DRM_CONTAINS_LOCK = 0x20, /**< SHM page that contains lock */ + _DRM_REMOVABLE = 0x40 /**< Removable mapping */ } drm_map_flags_t; + typedef struct drm_ctx_priv_map { - unsigned int ctx_id; /* Context requesting private mapping */ - void *handle; /* Handle of map */ + unsigned int ctx_id; /**< Context requesting private mapping */ + void *handle; /**< Handle of map */ } drm_ctx_priv_map_t; + +/** + * DRM_IOCTL_GET_MAP, DRM_IOCTL_ADD_MAP and DRM_IOCTL_RM_MAP ioctls + * argument type. + * + * \sa drmAddMap(). + */ typedef struct drm_map { - unsigned long offset; /* Requested physical address (0 for SAREA)*/ - unsigned long size; /* Requested physical size (bytes) */ - drm_map_type_t type; /* Type of memory to map */ - drm_map_flags_t flags; /* Flags */ - void *handle; /* User-space: "Handle" to pass to mmap */ - /* Kernel-space: kernel-virtual address */ - int mtrr; /* MTRR slot used */ - /* Private data */ + unsigned long offset; /**< Requested physical address (0 for SAREA)*/ + unsigned long size; /**< Requested physical size (bytes) */ + drm_map_type_t type; /**< Type of memory to map */ + drm_map_flags_t flags; /**< Flags */ + void *handle; /**< User-space: "Handle" to pass to mmap() */ + /**< Kernel-space: kernel-virtual address */ + int mtrr; /**< MTRR slot used */ + /* Private data */ } drm_map_t; + +/** + * DRM_IOCTL_GET_CLIENT ioctl argument type. + */ typedef struct drm_client { - int idx; /* Which client desired? */ - int auth; /* Is client authenticated? */ - unsigned long pid; /* Process id */ - unsigned long uid; /* User id */ - unsigned long magic; /* Magic */ - unsigned long iocs; /* Ioctl count */ + int idx; /**< Which client desired? */ + int auth; /**< Is client authenticated? */ + unsigned long pid; /**< Process ID */ + unsigned long uid; /**< User ID */ + unsigned long magic; /**< Magic */ + unsigned long iocs; /**< Ioctl count */ } drm_client_t; + typedef enum { _DRM_STAT_LOCK, _DRM_STAT_OPENS, @@ -216,20 +261,24 @@ _DRM_STAT_IOCTLS, _DRM_STAT_LOCKS, _DRM_STAT_UNLOCKS, - _DRM_STAT_VALUE, /* Generic value */ - _DRM_STAT_BYTE, /* Generic byte counter (1024bytes/K) */ - _DRM_STAT_COUNT, /* Generic non-byte counter (1000/k) */ - - _DRM_STAT_IRQ, /* IRQ */ - _DRM_STAT_PRIMARY, /* Primary DMA bytes */ - _DRM_STAT_SECONDARY, /* Secondary DMA bytes */ - _DRM_STAT_DMA, /* DMA */ - _DRM_STAT_SPECIAL, /* Special DMA (e.g., priority or polled) */ - _DRM_STAT_MISSED /* Missed DMA opportunity */ + _DRM_STAT_VALUE, /**< Generic value */ + _DRM_STAT_BYTE, /**< Generic byte counter (1024bytes/K) */ + _DRM_STAT_COUNT, /**< Generic non-byte counter (1000/k) */ + + _DRM_STAT_IRQ, /**< IRQ */ + _DRM_STAT_PRIMARY, /**< Primary DMA bytes */ + _DRM_STAT_SECONDARY, /**< Secondary DMA bytes */ + _DRM_STAT_DMA, /**< DMA */ + _DRM_STAT_SPECIAL, /**< Special DMA (e.g., priority or polled) */ + _DRM_STAT_MISSED /**< Missed DMA opportunity */ /* Add to the *END* of the list */ } drm_stat_type_t; + +/** + * DRM_IOCTL_GET_STATS ioctl argument type. + */ typedef struct drm_stats { unsigned long count; struct { @@ -238,137 +287,220 @@ } data[15]; } drm_stats_t; + +/** + * Hardware locking flags. + */ typedef enum drm_lock_flags { - _DRM_LOCK_READY = 0x01, /* Wait until hardware is ready for DMA */ - _DRM_LOCK_QUIESCENT = 0x02, /* Wait until hardware quiescent */ - _DRM_LOCK_FLUSH = 0x04, /* Flush this context's DMA queue first */ - _DRM_LOCK_FLUSH_ALL = 0x08, /* Flush all DMA queues first */ + _DRM_LOCK_READY = 0x01, /**< Wait until hardware is ready for DMA */ + _DRM_LOCK_QUIESCENT = 0x02, /**< Wait until hardware quiescent */ + _DRM_LOCK_FLUSH = 0x04, /**< Flush this context's DMA queue first */ + _DRM_LOCK_FLUSH_ALL = 0x08, /**< Flush all DMA queues first */ /* These *HALT* flags aren't supported yet -- they will be used to support the full-screen DGA-like mode. */ - _DRM_HALT_ALL_QUEUES = 0x10, /* Halt all current and future queues */ - _DRM_HALT_CUR_QUEUES = 0x20 /* Halt all current queues */ + _DRM_HALT_ALL_QUEUES = 0x10, /**< Halt all current and future queues */ + _DRM_HALT_CUR_QUEUES = 0x20 /**< Halt all current queues */ } drm_lock_flags_t; + +/** + * DRM_IOCTL_LOCK, DRM_IOCTL_UNLOCK and DRM_IOCTL_FINISH ioctl argument type. + * + * \sa drmGetLock() and drmUnlock(). + */ typedef struct drm_lock { int context; drm_lock_flags_t flags; } drm_lock_t; -typedef enum drm_dma_flags { /* These values *MUST* match xf86drm.h */ - /* Flags for DMA buffer dispatch */ - _DRM_DMA_BLOCK = 0x01, /* Block until buffer dispatched. - Note, the buffer may not yet have - been processed by the hardware -- - getting a hardware lock with the - hardware quiescent will ensure - that the buffer has been - processed. */ - _DRM_DMA_WHILE_LOCKED = 0x02, /* Dispatch while lock held */ - _DRM_DMA_PRIORITY = 0x04, /* High priority dispatch */ - - /* Flags for DMA buffer request */ - _DRM_DMA_WAIT = 0x10, /* Wait for free buffers */ - _DRM_DMA_SMALLER_OK = 0x20, /* Smaller-than-requested buffers ok */ - _DRM_DMA_LARGER_OK = 0x40 /* Larger-than-requested buffers ok */ + +/** + * DMA flags + * + * \warning + * These values \e must match xf86drm.h. + * + * \sa drm_dma. + */ +typedef enum drm_dma_flags { + /* Flags for DMA buffer dispatch */ + _DRM_DMA_BLOCK = 0x01, /**< + * Block until buffer dispatched. + * + * \note The buffer may not yet have + * been processed by the hardware -- + * getting a hardware lock with the + * hardware quiescent will ensure + * that the buffer has been + * processed. + */ + _DRM_DMA_WHILE_LOCKED = 0x02, /**< Dispatch while lock held */ + _DRM_DMA_PRIORITY = 0x04, /**< High priority dispatch */ + + /* Flags for DMA buffer request */ + _DRM_DMA_WAIT = 0x10, /**< Wait for free buffers */ + _DRM_DMA_SMALLER_OK = 0x20, /**< Smaller-than-requested buffers OK */ + _DRM_DMA_LARGER_OK = 0x40 /**< Larger-than-requested buffers OK */ } drm_dma_flags_t; + +/** + * DRM_IOCTL_ADD_BUFS and DRM_IOCTL_MARK_BUFS ioctl argument type. + * + * \sa drmAddBufs(). + */ typedef struct drm_buf_desc { - int count; /* Number of buffers of this size */ - int size; /* Size in bytes */ - int low_mark; /* Low water mark */ - int high_mark; /* High water mark */ + int count; /**< Number of buffers of this size */ + int size; /**< Size in bytes */ + int low_mark; /**< Low water mark */ + int high_mark; /**< High water mark */ enum { - _DRM_PAGE_ALIGN = 0x01, /* Align on page boundaries for DMA */ - _DRM_AGP_BUFFER = 0x02, /* Buffer is in agp space */ - _DRM_SG_BUFFER = 0x04 /* Scatter/gather memory buffer */ + _DRM_PAGE_ALIGN = 0x01, /**< Align on page boundaries for DMA */ + _DRM_AGP_BUFFER = 0x02, /**< Buffer is in AGP space */ + _DRM_SG_BUFFER = 0x04 /**< Scatter/gather memory buffer */ } flags; - unsigned long agp_start; /* Start address of where the agp buffers - * are in the agp aperture */ + unsigned long agp_start; /**< + * Start address of where the AGP buffers are + * in the AGP aperture + */ } drm_buf_desc_t; + +/** + * DRM_IOCTL_INFO_BUFS ioctl argument type. + */ typedef struct drm_buf_info { - int count; /* Entries in list */ + int count; /**< Entries in list */ drm_buf_desc_t *list; } drm_buf_info_t; + +/** + * DRM_IOCTL_FREE_BUFS ioctl argument type. + */ typedef struct drm_buf_free { int count; int *list; } drm_buf_free_t; + +/** + * Buffer information + * + * \sa drm_buf_map. + */ typedef struct drm_buf_pub { - int idx; /* Index into master buflist */ - int total; /* Buffer size */ - int used; /* Amount of buffer in use (for DMA) */ - void *address; /* Address of buffer */ + int idx; /**< Index into the master buffer list */ + int total; /**< Buffer size */ + int used; /**< Amount of buffer in use (for DMA) */ + void *address; /**< Address of buffer */ } drm_buf_pub_t; + +/** + * DRM_IOCTL_MAP_BUFS ioctl argument type. + */ typedef struct drm_buf_map { - int count; /* Length of buflist */ - void *virtual; /* Mmaped area in user-virtual */ - drm_buf_pub_t *list; /* Buffer information */ + int count; /**< Length of the buffer list */ + void *virtual; /**< Mmap'd area in user-virtual */ + drm_buf_pub_t *list; /**< Buffer information */ } drm_buf_map_t; + +/** + * DRM_IOCTL_DMA ioctl argument type. + * + * Indices here refer to the offset into the buffer list in drm_buf_get. + * + * \sa drmDMA(). + */ typedef struct drm_dma { - /* Indices here refer to the offset into - buflist in drm_buf_get_t. */ - int context; /* Context handle */ - int send_count; /* Number of buffers to send */ - int *send_indices; /* List of handles to buffers */ - int *send_sizes; /* Lengths of data to send */ - drm_dma_flags_t flags; /* Flags */ - int request_count; /* Number of buffers requested */ - int request_size; /* Desired size for buffers */ - int *request_indices; /* Buffer information */ + int context; /**< Context handle */ + int send_count; /**< Number of buffers to send */ + int *send_indices; /**< List of handles to buffers */ + int *send_sizes; /**< Lengths of data to send */ + drm_dma_flags_t flags; /**< Flags */ + int request_count; /**< Number of buffers requested */ + int request_size; /**< Desired size for buffers */ + int *request_indices; /**< Buffer information */ int *request_sizes; - int granted_count; /* Number of buffers granted */ + int granted_count; /**< Number of buffers granted */ } drm_dma_t; + typedef enum { _DRM_CONTEXT_PRESERVED = 0x01, _DRM_CONTEXT_2DONLY = 0x02 } drm_ctx_flags_t; + +/** + * DRM_IOCTL_ADD_CTX ioctl argument type. + * + * \sa drmCreateContext() and drmDestroyContext(). + */ typedef struct drm_ctx { drm_context_t handle; drm_ctx_flags_t flags; } drm_ctx_t; + +/** + * DRM_IOCTL_RES_CTX ioctl argument type. + */ typedef struct drm_ctx_res { int count; drm_ctx_t *contexts; } drm_ctx_res_t; + +/** + * DRM_IOCTL_ADD_DRAW and DRM_IOCTL_RM_DRAW ioctl argument type. + */ typedef struct drm_draw { drm_drawable_t handle; } drm_draw_t; + +/** + * DRM_IOCTL_GET_MAGIC and DRM_IOCTL_AUTH_MAGIC ioctl argument type. + */ typedef struct drm_auth { drm_magic_t magic; } drm_auth_t; + +/** + * DRM_IOCTL_IRQ_BUSID ioctl argument type. + * + * \sa drmGetInterruptFromBusID(). + */ typedef struct drm_irq_busid { - int irq; - int busnum; - int devnum; - int funcnum; + int irq; /**< IRQ number */ + int busnum; /**< bus number */ + int devnum; /**< device number */ + int funcnum; /**< function number */ } drm_irq_busid_t; + typedef enum { - _DRM_VBLANK_ABSOLUTE = 0x0, /* Wait for specific vblank sequence number */ - _DRM_VBLANK_RELATIVE = 0x1, /* Wait for given number of vblanks */ - _DRM_VBLANK_SIGNAL = 0x40000000 /* Send signal instead of blocking */ + _DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */ + _DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */ + _DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking */ } drm_vblank_seq_type_t; + #define _DRM_VBLANK_FLAGS_MASK _DRM_VBLANK_SIGNAL + struct drm_wait_vblank_request { drm_vblank_seq_type_t type; unsigned int sequence; unsigned long signal; }; + struct drm_wait_vblank_reply { drm_vblank_seq_type_t type; unsigned int sequence; @@ -376,29 +508,59 @@ long tval_usec; }; + +/** + * DRM_IOCTL_WAIT_VBLANK ioctl argument type. + * + * \sa drmWaitVBlank(). + */ typedef union drm_wait_vblank { struct drm_wait_vblank_request request; struct drm_wait_vblank_reply reply; } drm_wait_vblank_t; + +/** + * DRM_IOCTL_AGP_ENABLE ioctl argument type. + * + * \sa drmAgpEnable(). + */ typedef struct drm_agp_mode { - unsigned long mode; + unsigned long mode; /**< AGP mode */ } drm_agp_mode_t; - /* For drm_agp_alloc -- allocated a buffer */ + +/** + * DRM_IOCTL_AGP_ALLOC and DRM_IOCTL_AGP_FREE ioctls argument type. + * + * \sa drmAgpAlloc() and drmAgpFree(). + */ typedef struct drm_agp_buffer { - unsigned long size; /* In bytes -- will round to page boundary */ - unsigned long handle; /* Used for BIND/UNBIND ioctls */ - unsigned long type; /* Type of memory to allocate */ - unsigned long physical; /* Physical used by i810 */ + unsigned long size; /**< In bytes -- will round to page boundary */ + unsigned long handle; /**< Used for binding / unbinding */ + unsigned long type; /**< Type of memory to allocate */ + unsigned long physical; /**< Physical used by i810 */ } drm_agp_buffer_t; - /* For drm_agp_bind */ + +/** + * DRM_IOCTL_AGP_BIND and DRM_IOCTL_AGP_UNBIND ioctls argument type. + * + * \sa drmAgpBind() and drmAgpUnbind(). + */ typedef struct drm_agp_binding { - unsigned long handle; /* From drm_agp_buffer */ - unsigned long offset; /* In bytes -- will round to page boundary */ + unsigned long handle; /**< From drm_agp_buffer */ + unsigned long offset; /**< In bytes -- will round to page boundary */ } drm_agp_binding_t; + +/** + * DRM_IOCTL_AGP_INFO ioctl argument type. + * + * \sa drmAgpVersionMajor(), drmAgpVersionMinor(), drmAgpGetMode(), + * drmAgpBase(), drmAgpSize(), drmAgpMemoryUsed(), drmAgpMemoryAvail(), + * drmAgpVendorId() and drmAgpDeviceId(). + */ typedef struct drm_agp_info { int agp_version_major; int agp_version_minor; @@ -413,11 +575,16 @@ unsigned short id_device; } drm_agp_info_t; + +/** + * DRM_IOCTL_SG_ALLOC ioctl argument type. + */ typedef struct drm_scatter_gather { - unsigned long size; /* In bytes -- will round to page boundary */ - unsigned long handle; /* Used for mapping / unmapping */ + unsigned long size; /**< In bytes -- will round to page boundary */ + unsigned long handle; /**< Used for mapping / unmapping */ } drm_scatter_gather_t; + #define DRM_IOCTL_BASE 'd' #define DRM_IO(nr) _IO(DRM_IOCTL_BASE,nr) #define DRM_IOR(nr,type) _IOR(DRM_IOCTL_BASE,nr,type) @@ -477,8 +644,13 @@ #define DRM_IOCTL_WAIT_VBLANK DRM_IOWR(0x3a, drm_wait_vblank_t) -/* Device specfic ioctls should only be in their respective headers - * The device specific ioctl range is 0x40 to 0x79. */ +/** + * Device specific ioctls should only be in their respective headers + * The device specific ioctl range is from 0x40 to 0x79. + * + * \sa drmCommandNone(), drmCommandRead(), drmCommandWrite(), and + * drmCommandReadWrite(). + */ #define DRM_COMMAND_BASE 0x40 #endif diff -urN linux-2.4.23-pre8/drivers/char/drm/drmP.h linux-2.4.23-pre8-pac1/drivers/char/drm/drmP.h --- linux-2.4.23-pre8/drivers/char/drm/drmP.h 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/drmP.h 2003-10-11 23:18:11.000000000 +0200 @@ -1,6 +1,12 @@ -/* drmP.h -- Private header for Direct Rendering Manager -*- linux-c -*- - * Created: Mon Jan 4 10:05:05 1999 by faith@precisioninsight.com - * +/** + * \file drmP.h + * Private header for Direct Rendering Manager + * + * \author Rickard E. (Rik) Faith + * \author Gareth Hughes + */ + +/* * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. * All rights reserved. @@ -23,15 +29,12 @@ * 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 - * Gareth Hughes */ #ifndef _DRM_P_H_ #define _DRM_P_H_ + #ifdef __KERNEL__ #ifdef __alpha__ /* add include of current.h so that "current" is defined @@ -48,7 +51,6 @@ #include #include #include -#include #include #include #include /* For (un)lock_kernel */ @@ -67,15 +69,27 @@ #include #include #endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,41) +#define HAS_WORKQUEUE 0 +#else +#define HAS_WORKQUEUE 1 +#endif +#if !HAS_WORKQUEUE #include +#else +#include +#endif #include #include #include "drm.h" #include "drm_os_linux.h" -/* DRM template customization defaults - */ + +/***********************************************************************/ +/** \name DRM template customization defaults */ +/*@{*/ + #ifndef __HAVE_AGP #define __HAVE_AGP 0 #endif @@ -97,134 +111,31 @@ #ifndef __HAVE_DMA_FREELIST #define __HAVE_DMA_FREELIST 0 #endif -#ifndef __HAVE_DMA_HISTOGRAM -#define __HAVE_DMA_HISTOGRAM 0 -#endif #define __REALLY_HAVE_AGP (__HAVE_AGP && (defined(CONFIG_AGP) || \ defined(CONFIG_AGP_MODULE))) #define __REALLY_HAVE_MTRR (__HAVE_MTRR && defined(CONFIG_MTRR)) +#define __REALLY_HAVE_SG (__HAVE_SG) +/*@}*/ - /* Generic cmpxchg added in 2.3.x */ -#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; -} +/***********************************************************************/ +/** \name Begin the DRM... */ +/*@{*/ -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) -{ - unsigned long prev; - switch (size) { - case 1: - __asm__ __volatile__(LOCK_PREFIX "cmpxchgb %b1,%2" - : "=a"(prev) - : "q"(new), "m"(*__xg(ptr)), "0"(old) - : "memory"); - return prev; - case 2: - __asm__ __volatile__(LOCK_PREFIX "cmpxchgw %w1,%2" - : "=a"(prev) - : "q"(new), "m"(*__xg(ptr)), "0"(old) - : "memory"); - return prev; - case 4: - __asm__ __volatile__(LOCK_PREFIX "cmpxchgl %1,%2" - : "=a"(prev) - : "q"(new), "m"(*__xg(ptr)), "0"(old) - : "memory"); - return prev; - } - return old; -} - -#define cmpxchg(ptr,o,n) \ - ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o), \ - (unsigned long)(n),sizeof(*(ptr)))) -#endif /* i386 & alpha */ -#endif -#define __REALLY_HAVE_SG (__HAVE_SG) - -/* Begin the DRM... - */ - -#define DRM_DEBUG_CODE 2 /* Include debugging code (if > 1, then +#define DRM_DEBUG_CODE 2 /**< Include debugging code if > 1, then also include looping detection. */ -#define DRM_HASH_SIZE 16 /* Size of key hash table */ -#define DRM_KERNEL_CONTEXT 0 /* Change drm_resctx if changed */ -#define DRM_RESERVED_CONTEXTS 1 /* Change drm_resctx if changed */ +#define DRM_HASH_SIZE 16 /**< Size of key hash table. Must be power of 2. */ +#define DRM_KERNEL_CONTEXT 0 /**< Change drm_resctx if changed */ +#define DRM_RESERVED_CONTEXTS 1 /**< Change drm_resctx if changed */ #define DRM_LOOPING_LIMIT 5000000 -#define DRM_BSZ 1024 /* Buffer size for /dev/drm? output */ -#define DRM_TIME_SLICE (HZ/20) /* Time slice for GLXContexts */ -#define DRM_LOCK_SLICE 1 /* Time slice for lock, in jiffies */ +#define DRM_BSZ 1024 /**< Buffer size for /dev/drm? output */ +#define DRM_TIME_SLICE (HZ/20) /**< Time slice for GLXContexts */ +#define DRM_LOCK_SLICE 1 /**< Time slice for lock, in jiffies */ #define DRM_FLAG_DEBUG 0x01 -#define DRM_FLAG_NOCTX 0x02 #define DRM_MEM_DMA 0 #define DRM_MEM_SAREA 1 @@ -249,8 +160,14 @@ #define DRM_MEM_SGLISTS 20 #define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8) + +/*@}*/ + + +/***********************************************************************/ +/** \name Backward compatibility section */ +/*@{*/ - /* Backward compatibility section */ #ifndef minor #define minor(x) MINOR((x)) #endif @@ -259,12 +176,31 @@ #define MODULE_LICENSE(x) #endif +#ifndef preempt_disable +#define preempt_disable() +#define preempt_enable() +#endif #ifndef pte_offset_map #define pte_offset_map pte_offset #define pte_unmap(pte) #endif +#ifndef list_for_each_safe +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) +#endif + +#ifndef list_for_each_entry +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + prefetch(pos->member.next); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member), \ + prefetch(pos->member.next)) +#endif + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,19) static inline struct page * vmalloc_to_page(void * vmalloc_addr) { @@ -277,34 +213,61 @@ if (!pgd_none(*pgd)) { pmd = pmd_offset(pgd, addr); if (!pmd_none(*pmd)) { + preempt_disable(); ptep = pte_offset_map(pmd, addr); pte = *ptep; if (pte_present(pte)) page = pte_page(pte); pte_unmap(ptep); + preempt_enable(); } } return page; } #endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +#ifndef REMAP_PAGE_RANGE_5_ARGS #define DRM_RPR_ARG(vma) #else #define DRM_RPR_ARG(vma) vma, #endif - #define VM_OFFSET(vma) ((vma)->vm_pgoff << PAGE_SHIFT) - /* Macros to make printk easier */ +/*@}*/ + + +/***********************************************************************/ +/** \name Macros to make printk easier */ +/*@{*/ + +/** + * Error output. + * + * \param fmt printf() like format string. + * \param arg arguments + */ #define DRM_ERROR(fmt, arg...) \ printk(KERN_ERR "[" DRM_NAME ":%s] *ERROR* " fmt , __FUNCTION__ , ##arg) + +/** + * Memory error output. + * + * \param area memory area where the error occurred. + * \param fmt printf() like format string. + * \param arg arguments + */ #define DRM_MEM_ERROR(area, fmt, arg...) \ printk(KERN_ERR "[" DRM_NAME ":%s:%s] *ERROR* " fmt , __FUNCTION__, \ DRM(mem_stats)[area].name , ##arg) #define DRM_INFO(fmt, arg...) printk(KERN_INFO "[" DRM_NAME "] " fmt , ##arg) +/** + * Debug output. + * + * \param fmt printf() like format string. + * \param arg arguments + */ #if DRM_DEBUG_CODE #define DRM_DEBUG(fmt, arg...) \ do { \ @@ -327,33 +290,61 @@ len += sprintf(&buf[len], fmt , ##arg); \ if (len > DRM_PROC_LIMIT) { ret; *eof = 1; return len - offset; } - /* Mapping helper macros */ -#define DRM_IOREMAP(map) \ - (map)->handle = DRM(ioremap)( (map)->offset, (map)->size ) +/*@}*/ -#define DRM_IOREMAP_NOCACHE(map) \ - (map)->handle = DRM(ioremap_nocache)((map)->offset, (map)->size) -#define DRM_IOREMAPFREE(map) \ - do { \ - if ( (map)->handle && (map)->size ) \ - DRM(ioremapfree)( (map)->handle, (map)->size ); \ +/***********************************************************************/ +/** \name Mapping helper macros */ +/*@{*/ + +#define DRM_IOREMAP(map, dev) \ + (map)->handle = DRM(ioremap)( (map)->offset, (map)->size, (dev) ) + +#define DRM_IOREMAP_NOCACHE(map, dev) \ + (map)->handle = DRM(ioremap_nocache)((map)->offset, (map)->size, (dev)) + +#define DRM_IOREMAPFREE(map, dev) \ + do { \ + if ( (map)->handle && (map)->size ) \ + DRM(ioremapfree)( (map)->handle, (map)->size, (dev) ); \ } while (0) -#define DRM_FIND_MAP(_map, _o) \ -do { \ - struct list_head *_list; \ - list_for_each( _list, &dev->maplist->head ) { \ - drm_map_list_t *_entry = (drm_map_list_t *)_list; \ - if ( _entry->map && \ - _entry->map->offset == (_o) ) { \ - (_map) = _entry->map; \ - break; \ - } \ - } \ +/** + * Find mapping. + * + * \param _map matching mapping if found, untouched otherwise. + * \param _o offset. + * + * Expects the existence of a local variable named \p dev pointing to the + * drm_device structure. + */ +#define DRM_FIND_MAP(_map, _o) \ +do { \ + struct list_head *_list; \ + list_for_each( _list, &dev->maplist->head ) { \ + drm_map_list_t *_entry = list_entry( _list, drm_map_list_t, head ); \ + if ( _entry->map && \ + _entry->map->offset == (_o) ) { \ + (_map) = _entry->map; \ + break; \ + } \ + } \ } while(0) - /* Internal types and structures */ +/** + * Drop mapping. + * + * \sa #DRM_FIND_MAP. + */ +#define DRM_DROP_MAP(_map) + +/*@}*/ + + +/***********************************************************************/ +/** \name Internal types and structures */ +/*@{*/ + #define DRM_ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) #define DRM_MIN(a,b) ((a)<(b)?(a):(b)) #define DRM_MAX(a,b) ((a)>(b)?(a):(b)) @@ -362,10 +353,41 @@ #define DRM_BUFCOUNT(x) ((x)->count - DRM_LEFTCOUNT(x)) #define DRM_WAITCOUNT(dev,idx) DRM_BUFCOUNT(&dev->queuelist[idx]->waitlist) +/** + * Get the private SAREA mapping. + * + * \param _dev DRM device. + * \param _ctx context number. + * \param _map output mapping. + */ #define DRM_GET_PRIV_SAREA(_dev, _ctx, _map) do { \ (_map) = (_dev)->context_sareas[_ctx]; \ } while(0) +/** + * Test that the hardware lock is held by the caller, returning otherwise. + * + * \param dev DRM device. + * \param filp file pointer of the caller. + */ +#define LOCK_TEST_WITH_RETURN( dev, filp ) \ +do { \ + if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || \ + dev->lock.filp != filp ) { \ + DRM_ERROR( "%s called without lock held\n", \ + __FUNCTION__ ); \ + return -EINVAL; \ + } \ +} while (0) + +/** + * Ioctl function type. + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg argument. + */ typedef int drm_ioctl_t( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ); @@ -381,8 +403,7 @@ } drm_ioctl_desc_t; typedef struct drm_devstate { - pid_t owner; /* X server pid holding x_lock */ - + pid_t owner; /**< X server pid holding x_lock */ } drm_devstate_t; typedef struct drm_magic_entry { @@ -402,21 +423,24 @@ pid_t pid; } drm_vma_entry_t; +/** + * DMA buffer. + */ typedef struct drm_buf { - int idx; /* Index into master buflist */ - int total; /* Buffer size */ - int order; /* log-base-2(total) */ - int used; /* Amount of buffer in use (for DMA) */ - unsigned long offset; /* Byte offset (used internally) */ - void *address; /* Address of buffer */ - unsigned long bus_address; /* Bus address of buffer */ - struct drm_buf *next; /* Kernel-only: used for free list */ - __volatile__ int waiting; /* On kernel DMA queue */ - __volatile__ int pending; /* On hardware DMA queue */ - wait_queue_head_t dma_wait; /* Processes waiting */ - pid_t pid; /* PID of holding process */ - int context; /* Kernel queue for this buffer */ - int while_locked;/* Dispatch this buffer while locked */ + int idx; /**< Index into master buflist */ + int total; /**< Buffer size */ + int order; /**< log-base-2(total) */ + int used; /**< Amount of buffer in use (for DMA) */ + unsigned long offset; /**< Byte offset (used internally) */ + void *address; /**< Address of buffer */ + unsigned long bus_address; /**< Bus address of buffer */ + struct drm_buf *next; /**< Kernel-only: used for free list */ + __volatile__ int waiting; /**< On kernel DMA queue */ + __volatile__ int pending; /**< On hardware DMA queue */ + wait_queue_head_t dma_wait; /**< Processes waiting */ + struct file *filp; /**< Pointer to holding file descr */ + int context; /**< Kernel queue for this buffer */ + int while_locked;/**< Dispatch this buffer while locked */ enum { DRM_LIST_NONE = 0, DRM_LIST_FREE = 1, @@ -424,68 +448,43 @@ DRM_LIST_PEND = 3, DRM_LIST_PRIO = 4, DRM_LIST_RECLAIM = 5 - } list; /* Which list we're on */ - -#if DRM_DMA_HISTOGRAM - cycles_t time_queued; /* Queued to kernel DMA queue */ - cycles_t time_dispatched; /* Dispatched to hardware */ - cycles_t time_completed; /* Completed by hardware */ - cycles_t time_freed; /* Back on freelist */ -#endif + } list; /**< Which list we're on */ - int dev_priv_size; /* Size of buffer private stoarge */ - void *dev_private; /* Per-buffer private storage */ + int dev_priv_size; /**< Size of buffer private storage */ + void *dev_private; /**< Per-buffer private storage */ } drm_buf_t; -#if DRM_DMA_HISTOGRAM -#define DRM_DMA_HISTOGRAM_SLOTS 9 -#define DRM_DMA_HISTOGRAM_INITIAL 10 -#define DRM_DMA_HISTOGRAM_NEXT(current) ((current)*10) -typedef struct drm_histogram { - atomic_t total; - - atomic_t queued_to_dispatched[DRM_DMA_HISTOGRAM_SLOTS]; - atomic_t dispatched_to_completed[DRM_DMA_HISTOGRAM_SLOTS]; - atomic_t completed_to_freed[DRM_DMA_HISTOGRAM_SLOTS]; - - atomic_t queued_to_completed[DRM_DMA_HISTOGRAM_SLOTS]; - atomic_t queued_to_freed[DRM_DMA_HISTOGRAM_SLOTS]; - - atomic_t dma[DRM_DMA_HISTOGRAM_SLOTS]; - atomic_t schedule[DRM_DMA_HISTOGRAM_SLOTS]; - atomic_t ctx[DRM_DMA_HISTOGRAM_SLOTS]; - atomic_t lacq[DRM_DMA_HISTOGRAM_SLOTS]; - atomic_t lhld[DRM_DMA_HISTOGRAM_SLOTS]; -} drm_histogram_t; -#endif - /* bufs is one longer than it has to be */ +/** bufs is one longer than it has to be */ typedef struct drm_waitlist { - int count; /* Number of possible buffers */ - drm_buf_t **bufs; /* List of pointers to buffers */ - drm_buf_t **rp; /* Read pointer */ - drm_buf_t **wp; /* Write pointer */ - drm_buf_t **end; /* End pointer */ + int count; /**< Number of possible buffers */ + drm_buf_t **bufs; /**< List of pointers to buffers */ + drm_buf_t **rp; /**< Read pointer */ + drm_buf_t **wp; /**< Write pointer */ + drm_buf_t **end; /**< End pointer */ spinlock_t read_lock; spinlock_t write_lock; } drm_waitlist_t; typedef struct drm_freelist { - int initialized; /* Freelist in use */ - atomic_t count; /* Number of free buffers */ - drm_buf_t *next; /* End pointer */ - - wait_queue_head_t waiting; /* Processes waiting on free bufs */ - int low_mark; /* Low water mark */ - int high_mark; /* High water mark */ - atomic_t wfh; /* If waiting for high mark */ + int initialized; /**< Freelist in use */ + atomic_t count; /**< Number of free buffers */ + drm_buf_t *next; /**< End pointer */ + + wait_queue_head_t waiting; /**< Processes waiting on free bufs */ + int low_mark; /**< Low water mark */ + int high_mark; /**< High water mark */ + atomic_t wfh; /**< If waiting for high mark */ spinlock_t lock; } drm_freelist_t; +/** + * Buffer entry. There is one of this for each buffer size order. + */ typedef struct drm_buf_entry { - int buf_size; - int buf_count; - drm_buf_t *buflist; + int buf_size; /**< size */ + int buf_count; /**< number of buffers */ + drm_buf_t *buflist; /**< buffer list */ int seg_count; int page_order; unsigned long *seglist; @@ -493,11 +492,19 @@ drm_freelist_t freelist; } drm_buf_entry_t; +/** + * Hardware lock. + * + * The lock structure is a simple cache-line aligned integer. To avoid + * processor bus contention on a multiprocessor system, there should not be any + * other data stored in the same cache line. + */ typedef struct drm_hw_lock { - __volatile__ unsigned int lock; - char padding[60]; /* Pad to cache line */ + __volatile__ unsigned int lock; /**< lock variable */ + char padding[60]; /**< Pad to cache line */ } drm_hw_lock_t; +/** File private data */ typedef struct drm_file { int authenticated; int minor; @@ -509,87 +516,88 @@ struct drm_file *prev; struct drm_device *dev; int remove_auth_on_close; + unsigned long lock_count; } drm_file_t; - +/** Wait queue */ typedef struct drm_queue { - atomic_t use_count; /* Outstanding uses (+1) */ - atomic_t finalization; /* Finalization in progress */ - atomic_t block_count; /* Count of processes waiting */ - atomic_t block_read; /* Queue blocked for reads */ - wait_queue_head_t read_queue; /* Processes waiting on block_read */ - atomic_t block_write; /* Queue blocked for writes */ - wait_queue_head_t write_queue; /* Processes waiting on block_write */ + atomic_t use_count; /**< Outstanding uses (+1) */ + atomic_t finalization; /**< Finalization in progress */ + atomic_t block_count; /**< Count of processes waiting */ + atomic_t block_read; /**< Queue blocked for reads */ + wait_queue_head_t read_queue; /**< Processes waiting on block_read */ + atomic_t block_write; /**< Queue blocked for writes */ + wait_queue_head_t write_queue; /**< Processes waiting on block_write */ #if 1 - atomic_t total_queued; /* Total queued statistic */ - atomic_t total_flushed;/* Total flushes statistic */ - atomic_t total_locks; /* Total locks statistics */ -#endif - drm_ctx_flags_t flags; /* Context preserving and 2D-only */ - drm_waitlist_t waitlist; /* Pending buffers */ - wait_queue_head_t flush_queue; /* Processes waiting until flush */ + atomic_t total_queued; /**< Total queued statistic */ + atomic_t total_flushed;/**< Total flushes statistic */ + atomic_t total_locks; /**< Total locks statistics */ +#endif + drm_ctx_flags_t flags; /**< Context preserving and 2D-only */ + drm_waitlist_t waitlist; /**< Pending buffers */ + wait_queue_head_t flush_queue; /**< Processes waiting until flush */ } drm_queue_t; +/** + * Lock data. + */ typedef struct drm_lock_data { - drm_hw_lock_t *hw_lock; /* Hardware lock */ - pid_t pid; /* PID of lock holder (0=kernel) */ - wait_queue_head_t lock_queue; /* Queue of blocked processes */ - unsigned long lock_time; /* Time of last lock in jiffies */ + drm_hw_lock_t *hw_lock; /**< Hardware lock */ + struct file *filp; /**< File descr of lock holder (0=kernel) */ + wait_queue_head_t lock_queue; /**< Queue of blocked processes */ + unsigned long lock_time; /**< Time of last lock in jiffies */ } drm_lock_data_t; +/** + * DMA data. + */ typedef struct drm_device_dma { -#if 0 - /* Performance Counters */ - atomic_t total_prio; /* Total DRM_DMA_PRIORITY */ - atomic_t total_bytes; /* Total bytes DMA'd */ - atomic_t total_dmas; /* Total DMA buffers dispatched */ - - atomic_t total_missed_dma; /* Missed drm_do_dma */ - atomic_t total_missed_lock; /* Missed lock in drm_do_dma */ - atomic_t total_missed_free; /* Missed drm_free_this_buffer */ - atomic_t total_missed_sched;/* Missed drm_dma_schedule */ - - atomic_t total_tried; /* Tried next_buffer */ - atomic_t total_hit; /* Sent next_buffer */ - atomic_t total_lost; /* Lost interrupt */ -#endif - - drm_buf_entry_t bufs[DRM_MAX_ORDER+1]; - int buf_count; - drm_buf_t **buflist; /* Vector of pointers info bufs */ + + drm_buf_entry_t bufs[DRM_MAX_ORDER+1]; /**< buffers, grouped by their size order */ + int buf_count; /**< total number of buffers */ + drm_buf_t **buflist; /**< Vector of pointers into drm_device_dma::bufs */ int seg_count; - int page_count; - unsigned long *pagelist; + int page_count; /**< number of pages */ + unsigned long *pagelist; /**< page list */ unsigned long byte_count; enum { _DRM_DMA_USE_AGP = 0x01, _DRM_DMA_USE_SG = 0x02 } flags; - /* DMA support */ - drm_buf_t *this_buffer; /* Buffer being sent */ - drm_buf_t *next_buffer; /* Selected buffer to send */ - drm_queue_t *next_queue; /* Queue from which buffer selected*/ - wait_queue_head_t waiting; /* Processes waiting on free bufs */ + /** \name DMA support */ + /*@{*/ + drm_buf_t *this_buffer; /**< Buffer being sent */ + drm_buf_t *next_buffer; /**< Selected buffer to send */ + drm_queue_t *next_queue; /**< Queue from which buffer selected*/ + wait_queue_head_t waiting; /**< Processes waiting on free bufs */ + /*@}*/ } drm_device_dma_t; #if __REALLY_HAVE_AGP +/** + * AGP memory entry. Stored as a doubly linked list. + */ typedef struct drm_agp_mem { - unsigned long handle; - agp_memory *memory; - unsigned long bound; /* address */ + unsigned long handle; /**< handle */ + DRM_AGP_MEM *memory; + unsigned long bound; /**< address */ int pages; - struct drm_agp_mem *prev; - struct drm_agp_mem *next; + struct drm_agp_mem *prev; /**< previous entry */ + struct drm_agp_mem *next; /**< next entry */ } drm_agp_mem_t; +/** + * AGP data. + * + * \sa DRM(agp_init)() and drm_device::agp. + */ typedef struct drm_agp_head { - agp_kern_info agp_info; - const char *chipset; - drm_agp_mem_t *memory; - unsigned long mode; - int enabled; - int acquired; + DRM_AGP_KERN agp_info; /**< AGP device information */ + drm_agp_mem_t *memory; /**< memory entries */ + unsigned long mode; /**< AGP mode */ + int enabled; /**< whether the AGP bus as been enabled */ + int acquired; /**< whether the AGP device has been acquired */ unsigned long base; int agp_mtrr; int cant_use_aperture; @@ -597,6 +605,9 @@ } drm_agp_head_t; #endif +/** + * Scatter-gather memory. + */ typedef struct drm_sg_mem { unsigned long handle; void *virtual; @@ -610,11 +621,16 @@ drm_hw_lock_t *lock; } drm_sigdata_t; +/** + * Mappings list + */ typedef struct drm_map_list { - struct list_head head; - drm_map_t *map; + struct list_head head; /**< list head */ + drm_map_t *map; /**< mapping */ } drm_map_list_t; +typedef drm_map_t drm_local_map_t; + #if __HAVE_VBL_IRQ typedef struct drm_vbl_sig { @@ -626,106 +642,130 @@ #endif +/** + * DRM device structure. + */ typedef struct drm_device { - const char *name; /* Simple driver name */ - char *unique; /* Unique identifier: e.g., busid */ - int unique_len; /* Length of unique field */ - dev_t device; /* Device number for mknod */ - char *devname; /* For /proc/interrupts */ - - int blocked; /* Blocked due to VC switch? */ - struct proc_dir_entry *root; /* Root for this device's entries */ - - /* Locks */ - spinlock_t count_lock; /* For inuse, open_count, buf_use */ - struct semaphore struct_sem; /* For others */ - - /* Usage Counters */ - int open_count; /* Outstanding files open */ - atomic_t ioctl_count; /* Outstanding IOCTLs pending */ - atomic_t vma_count; /* Outstanding vma areas open */ - int buf_use; /* Buffers in use -- cannot alloc */ - atomic_t buf_alloc; /* Buffer allocation in progress */ + const char *name; /**< Simple driver name */ + char *unique; /**< Unique identifier: e.g., busid */ + int unique_len; /**< Length of unique field */ + dev_t device; /**< Device number for mknod */ + char *devname; /**< For /proc/interrupts */ + + int blocked; /**< Blocked due to VC switch? */ + struct proc_dir_entry *root; /**< Root for this device's entries */ + + /** \name Locks */ + /*@{*/ + spinlock_t count_lock; /**< For inuse, drm_device::open_count, drm_device::buf_use */ + struct semaphore struct_sem; /**< For others */ + /*@}*/ + + /** \name Usage Counters */ + /*@{*/ + int open_count; /**< Outstanding files open */ + atomic_t ioctl_count; /**< Outstanding IOCTLs pending */ + atomic_t vma_count; /**< Outstanding vma areas open */ + int buf_use; /**< Buffers in use -- cannot alloc */ + atomic_t buf_alloc; /**< Buffer allocation in progress */ + /*@}*/ - /* Performance counters */ + /** \name Performance counters */ + /*@{*/ unsigned long counters; drm_stat_type_t types[15]; atomic_t counts[15]; + /*@}*/ - /* Authentication */ - drm_file_t *file_first; - drm_file_t *file_last; - drm_magic_head_t magiclist[DRM_HASH_SIZE]; - - /* Memory management */ - drm_map_list_t *maplist; /* Linked list of regions */ - int map_count; /* Number of mappable regions */ + /** \name Authentication */ + /*@{*/ + drm_file_t *file_first; /**< file list head */ + drm_file_t *file_last; /**< file list tail */ + drm_magic_head_t magiclist[DRM_HASH_SIZE]; /**< magic hash table */ + /*@}*/ + + /** \name Memory management */ + /*@{*/ + drm_map_list_t *maplist; /**< Linked list of regions */ + int map_count; /**< Number of mappable regions */ - drm_map_t **context_sareas; + drm_map_t **context_sareas; /**< per-context SAREA's */ int max_context; - drm_vma_entry_t *vmalist; /* List of vmas (for debugging) */ - drm_lock_data_t lock; /* Information on hardware lock */ - - /* DMA queues (contexts) */ - int queue_count; /* Number of active DMA queues */ - int queue_reserved; /* Number of reserved DMA queues */ - int queue_slots; /* Actual length of queuelist */ - drm_queue_t **queuelist; /* Vector of pointers to DMA queues */ - drm_device_dma_t *dma; /* Optional pointer for DMA support */ - - /* Context support */ - int irq; /* Interrupt used by board */ - __volatile__ long context_flag; /* Context swapping flag */ - __volatile__ long interrupt_flag; /* Interruption handler flag */ - __volatile__ long dma_flag; /* DMA dispatch flag */ - struct timer_list timer; /* Timer for delaying ctx switch */ - wait_queue_head_t context_wait; /* Processes waiting on ctx switch */ - int last_checked; /* Last context checked for DMA */ - int last_context; /* Last current context */ - unsigned long last_switch; /* jiffies at last context switch */ + drm_vma_entry_t *vmalist; /**< List of vmas (for debugging) */ + drm_lock_data_t lock; /**< Information on hardware lock */ + /*@}*/ + + /** \name DMA queues (contexts) */ + /*@{*/ + int queue_count; /**< Number of active DMA queues */ + int queue_reserved; /**< Number of reserved DMA queues */ + int queue_slots; /**< Actual length of queuelist */ + drm_queue_t **queuelist; /**< Vector of pointers to DMA queues */ + drm_device_dma_t *dma; /**< Optional pointer for DMA support */ + /*@}*/ + + /** \name Context support */ + /*@{*/ + int irq; /**< Interrupt used by board */ + __volatile__ long context_flag; /**< Context swapping flag */ + __volatile__ long interrupt_flag; /**< Interruption handler flag */ + __volatile__ long dma_flag; /**< DMA dispatch flag */ + struct timer_list timer; /**< Timer for delaying ctx switch */ + wait_queue_head_t context_wait; /**< Processes waiting on ctx switch */ + int last_checked; /**< Last context checked for DMA */ + int last_context; /**< Last current context */ + unsigned long last_switch; /**< jiffies at last context switch */ + /*@}*/ + +#if !HAS_WORKQUEUE struct tq_struct tq; +#else + struct work_struct work; +#endif + /** \name VBLANK IRQ support */ + /*@{*/ #if __HAVE_VBL_IRQ - wait_queue_head_t vbl_queue; + wait_queue_head_t vbl_queue; /**< VBLANK wait queue */ atomic_t vbl_received; spinlock_t vbl_lock; - drm_vbl_sig_t vbl_sigs; + drm_vbl_sig_t vbl_sigs; /**< signal list to send on VBLANK */ unsigned int vbl_pending; #endif + /*@}*/ cycles_t ctx_start; cycles_t lck_start; -#if __HAVE_DMA_HISTOGRAM - drm_histogram_t histo; -#endif - /* Callback to X server for context switch - and for heavy-handed reset. */ - char buf[DRM_BSZ]; /* Output buffer */ - char *buf_rp; /* Read pointer */ - char *buf_wp; /* Write pointer */ - char *buf_end; /* End pointer */ - struct fasync_struct *buf_async;/* Processes waiting for SIGIO */ - wait_queue_head_t buf_readers; /* Processes waiting to read */ - wait_queue_head_t buf_writers; /* Processes waiting to ctx switch */ + char buf[DRM_BSZ]; /**< Output buffer */ + char *buf_rp; /**< Read pointer */ + char *buf_wp; /**< Write pointer */ + char *buf_end; /**< End pointer */ + struct fasync_struct *buf_async;/**< Processes waiting for SIGIO */ + wait_queue_head_t buf_readers; /**< Processes waiting to read */ + wait_queue_head_t buf_writers; /**< Processes waiting to ctx switch */ #if __REALLY_HAVE_AGP - drm_agp_head_t *agp; + drm_agp_head_t *agp; /**< AGP data */ #endif - struct pci_dev *pdev; + struct pci_dev *pdev; /**< PCI device structure */ #ifdef __alpha__ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,3) + struct pci_controler *hose; +#else struct pci_controller *hose; #endif - drm_sg_mem_t *sg; /* Scatter gather memory */ - unsigned long *ctx_bitmap; - void *dev_private; - drm_sigdata_t sigdata; /* For block_all_signals */ +#endif + drm_sg_mem_t *sg; /**< Scatter gather memory */ + unsigned long *ctx_bitmap; /**< context bitmap */ + void *dev_private; /**< device private data */ + drm_sigdata_t sigdata; /**< For block_all_signals */ sigset_t sigmask; } drm_device_t; -/* ================================================================ - * Internal function definitions - */ +/******************************************************************/ +/** \name Internal function definitions */ +/*@{*/ /* Misc. support (drm_init.h) */ extern int DRM(flags); @@ -748,13 +788,7 @@ extern int DRM(open_helper)(struct inode *inode, struct file *filp, drm_device_t *dev); extern int DRM(flush)(struct file *filp); -extern int DRM(release_fuck)(struct inode *inode, struct file *filp); extern int DRM(fasync)(int fd, struct file *filp, int on); -extern ssize_t DRM(read)(struct file *filp, char *buf, size_t count, - loff_t *off); -extern int DRM(write_string)(drm_device_t *dev, const char *s); -extern unsigned int DRM(poll)(struct file *filp, - struct poll_table_struct *wait); /* Mapping support (drm_vm.h) */ extern struct page *DRM(vm_nopage)(struct vm_area_struct *vma, @@ -775,29 +809,31 @@ extern int DRM(mmap_dma)(struct file *filp, struct vm_area_struct *vma); extern int DRM(mmap)(struct file *filp, struct vm_area_struct *vma); +extern unsigned int DRM(poll)(struct file *filp, struct poll_table_struct *wait); +extern ssize_t DRM(read)(struct file *filp, char *buf, size_t count, loff_t *off); /* Memory management support (drm_memory.h) */ extern void DRM(mem_init)(void); extern int DRM(mem_info)(char *buf, char **start, off_t offset, int request, int *eof, void *data); extern void *DRM(alloc)(size_t size, int area); +extern void *DRM(calloc)(size_t nmemb, size_t size, int area); extern void *DRM(realloc)(void *oldpt, size_t oldsize, size_t size, int area); -extern char *DRM(strdup)(const char *s, int area); -extern void DRM(strfree)(const char *s, int area); extern void DRM(free)(void *pt, size_t size, int area); extern unsigned long DRM(alloc_pages)(int order, int area); extern void DRM(free_pages)(unsigned long address, int order, int area); -extern void *DRM(ioremap)(unsigned long offset, unsigned long size); -extern void *DRM(ioremap_nocache)(unsigned long offset, unsigned long size); -extern void DRM(ioremapfree)(void *pt, unsigned long size); +extern void *DRM(ioremap)(unsigned long offset, unsigned long size, drm_device_t *dev); +extern void *DRM(ioremap_nocache)(unsigned long offset, unsigned long size, + drm_device_t *dev); +extern void DRM(ioremapfree)(void *pt, unsigned long size, drm_device_t *dev); #if __REALLY_HAVE_AGP -extern agp_memory *DRM(alloc_agp)(int pages, u32 type); -extern int DRM(free_agp)(agp_memory *handle, int pages); -extern int DRM(bind_agp)(agp_memory *handle, unsigned int start); -extern int DRM(unbind_agp)(agp_memory *handle); +extern DRM_AGP_MEM *DRM(alloc_agp)(int pages, u32 type); +extern int DRM(free_agp)(DRM_AGP_MEM *handle, int pages); +extern int DRM(bind_agp)(DRM_AGP_MEM *handle, unsigned int start); +extern int DRM(unbind_agp)(DRM_AGP_MEM *handle); #endif /* Misc. IOCTL support (drm_ioctl.h) */ @@ -859,12 +895,11 @@ extern int DRM(authmagic)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); + /* Placeholder for ioctls past */ +extern int DRM(noop)(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); /* Locking IOCTL support (drm_lock.h) */ -extern int DRM(block)(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int DRM(unblock)(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); extern int DRM(lock_take)(__volatile__ unsigned int *lock, unsigned int context); extern int DRM(lock_transfer)(drm_device_t *dev, @@ -873,12 +908,6 @@ extern int DRM(lock_free)(drm_device_t *dev, __volatile__ unsigned int *lock, unsigned int context); -extern int DRM(finish)(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg); -extern int DRM(flush_unblock)(drm_device_t *dev, int context, - drm_lock_flags_t flags); -extern int DRM(flush_block_and_flush)(drm_device_t *dev, int context, - drm_lock_flags_t flags); extern int DRM(notifier)(void *priv); /* Buffer management support (drm_bufs.h) */ @@ -903,23 +932,13 @@ extern int DRM(dma_setup)(drm_device_t *dev); extern void DRM(dma_takedown)(drm_device_t *dev); extern void DRM(free_buffer)(drm_device_t *dev, drm_buf_t *buf); -extern void DRM(reclaim_buffers)(drm_device_t *dev, pid_t pid); -#if __HAVE_OLD_DMA -/* GH: This is a dirty hack for now... - */ -extern void DRM(clear_next_buffer)(drm_device_t *dev); -extern int DRM(select_queue)(drm_device_t *dev, - void (*wrapper)(unsigned long)); -extern int DRM(dma_enqueue)(drm_device_t *dev, drm_dma_t *dma); -extern int DRM(dma_get_buffers)(drm_device_t *dev, drm_dma_t *dma); -#endif +extern void DRM(reclaim_buffers)( struct file *filp ); #if __HAVE_DMA_IRQ extern int DRM(control)( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ); extern int DRM(irq_install)( drm_device_t *dev, int irq ); extern int DRM(irq_uninstall)( drm_device_t *dev ); -extern void DRM(dma_service)( int irq, void *device, - struct pt_regs *regs ); +extern irqreturn_t DRM(dma_service)( DRM_IRQ_ARGS ); extern void DRM(driver_irq_preinstall)( drm_device_t *dev ); extern void DRM(driver_irq_postinstall)( drm_device_t *dev ); extern void DRM(driver_irq_uninstall)( drm_device_t *dev ); @@ -933,25 +952,7 @@ extern void DRM(dma_immediate_bh)( void *dev ); #endif #endif -#if DRM_DMA_HISTOGRAM -extern int DRM(histogram_slot)(unsigned long count); -extern void DRM(histogram_compute)(drm_device_t *dev, drm_buf_t *buf); -#endif - - /* Buffer list support (drm_lists.h) */ -#if __HAVE_DMA_WAITLIST -extern int DRM(waitlist_create)(drm_waitlist_t *bl, int count); -extern int DRM(waitlist_destroy)(drm_waitlist_t *bl); -extern int DRM(waitlist_put)(drm_waitlist_t *bl, drm_buf_t *buf); -extern drm_buf_t *DRM(waitlist_get)(drm_waitlist_t *bl); -#endif -#if __HAVE_DMA_FREELIST -extern int DRM(freelist_create)(drm_freelist_t *bl, int count); -extern int DRM(freelist_destroy)(drm_freelist_t *bl); -extern int DRM(freelist_put)(drm_device_t *dev, drm_freelist_t *bl, - drm_buf_t *buf); -extern drm_buf_t *DRM(freelist_get)(drm_freelist_t *bl, int block); -#endif + #endif /* __HAVE_DMA */ #if __REALLY_HAVE_AGP @@ -975,10 +976,10 @@ unsigned int cmd, unsigned long arg); extern int DRM(agp_bind)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); -extern agp_memory *DRM(agp_allocate_memory)(size_t pages, u32 type); -extern int DRM(agp_free_memory)(agp_memory *handle); -extern int DRM(agp_bind_memory)(agp_memory *handle, off_t start); -extern int DRM(agp_unbind_memory)(agp_memory *handle); +extern DRM_AGP_MEM *DRM(agp_allocate_memory)(size_t pages, u32 type); +extern int DRM(agp_free_memory)(DRM_AGP_MEM *handle); +extern int DRM(agp_bind_memory)(DRM_AGP_MEM *handle, off_t start); +extern int DRM(agp_unbind_memory)(DRM_AGP_MEM *handle); #endif /* Stub support (drm_stub.h) */ @@ -1013,5 +1014,7 @@ unsigned long addr, dma_addr_t bus_addr); +/*@}*/ + #endif /* __KERNEL__ */ #endif diff -urN linux-2.4.23-pre8/drivers/char/drm/drm_agpsupport.h linux-2.4.23-pre8-pac1/drivers/char/drm/drm_agpsupport.h --- linux-2.4.23-pre8/drivers/char/drm/drm_agpsupport.h 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/drm_agpsupport.h 2003-08-18 12:56:12.000000000 +0200 @@ -1,6 +1,12 @@ -/* drm_agpsupport.h -- DRM support for AGP/GART backend -*- linux-c -*- - * Created: Mon Dec 13 09:56:45 1999 by faith@precisioninsight.com - * +/** + * \file drm_agpsupport.h + * DRM support for AGP/GART backend + * + * \author Rickard E. (Rik) Faith + * \author Gareth Hughes + */ + +/* * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. * All Rights Reserved. @@ -23,28 +29,41 @@ * 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. - * - * Author: - * Rickard E. (Rik) Faith - * Gareth Hughes */ +#define __NO_VERSION__ #include "drmP.h" #include #if __REALLY_HAVE_AGP + #define DRM_AGP_GET (drm_agp_t *)inter_module_get("drm_agp") #define DRM_AGP_PUT inter_module_put("drm_agp") +/** + * Pointer to the drm_agp_t structure made available by the agpgart module. + */ static const drm_agp_t *drm_agp = NULL; +/** + * AGP information ioctl. + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg pointer to a (output) drm_agp_info structure. + * \return zero on success or a negative number on failure. + * + * Verifies the AGP device has been initialized and acquired and fills in the + * drm_agp_info structure with the information in drm_agp_head::agp_info. + */ int DRM(agp_info)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; - agp_kern_info *kern; + DRM_AGP_KERN *kern; drm_agp_info_t info; if (!dev->agp || !dev->agp->acquired || !drm_agp->copy_info) @@ -66,6 +85,18 @@ return 0; } +/** + * Acquire the AGP device (ioctl). + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg user argument. + * \return zero on success or a negative number on failure. + * + * Verifies the AGP device hasn't been acquired before and calls + * drm_agp->acquire(). + */ int DRM(agp_acquire)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { @@ -73,18 +104,29 @@ drm_device_t *dev = priv->dev; int retcode; - if (!dev->agp) - return -ENODEV; - if (dev->agp->acquired) - return -EBUSY; - if(!drm_agp->acquire) + if (!dev->agp || dev->agp->acquired || !drm_agp->acquire) + return -EINVAL; +#ifndef VMAP_4_ARGS + if ( dev->agp->cant_use_aperture ) return -EINVAL; - if (retcode = drm_agp->acquire()) +#endif + if ((retcode = drm_agp->acquire())) return retcode; dev->agp->acquired = 1; return 0; } +/** + * Release the AGP device (ioctl). + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg user argument. + * \return zero on success or a negative number on failure. + * + * Verifies the AGP device has been acquired and calls drm_agp->release(). + */ int DRM(agp_release)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { @@ -99,11 +141,29 @@ } +/** + * Release the AGP device. + * + * Calls drm_agp->release(). + */ void DRM(agp_do_release)(void) { - if (drm_agp->release) drm_agp->release(); + if (drm_agp->release) + drm_agp->release(); } +/** + * Enable the AGP bus. + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg pointer to a drm_agp_mode structure. + * \return zero on success or a negative number on failure. + * + * Verifies the AGP device has been acquired but not enabled, and calls + * drm_agp->enable(). + */ int DRM(agp_enable)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { @@ -124,6 +184,18 @@ return 0; } +/** + * Allocate AGP memory. + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg pointer to a drm_agp_buffer structure. + * \return zero on success or a negative number on failure. + * + * Verifies the AGP device is present and has been acquired, allocates the + * memory via alloc_agp() and creates a drm_agp_mem entry for it. + */ int DRM(agp_alloc)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { @@ -131,11 +203,12 @@ drm_device_t *dev = priv->dev; drm_agp_buffer_t request; drm_agp_mem_t *entry; - agp_memory *memory; + DRM_AGP_MEM *memory; unsigned long pages; u32 type; - if (!dev->agp || !dev->agp->acquired) return -EINVAL; + if (!dev->agp || !dev->agp->acquired) + return -EINVAL; if (copy_from_user(&request, (drm_agp_buffer_t *)arg, sizeof(request))) return -EFAULT; if (!(entry = DRM(alloc)(sizeof(*entry), DRM_MEM_AGPLISTS))) @@ -151,17 +224,18 @@ return -ENOMEM; } - entry->handle = (unsigned long)memory->memory; + entry->handle = (unsigned long)memory->key + 1; entry->memory = memory; entry->bound = 0; entry->pages = pages; entry->prev = NULL; entry->next = dev->agp->memory; - if (dev->agp->memory) dev->agp->memory->prev = entry; + if (dev->agp->memory) + dev->agp->memory->prev = entry; dev->agp->memory = entry; request.handle = entry->handle; - request.physical = memory->physical; + request.physical = memory->physical; if (copy_to_user((drm_agp_buffer_t *)arg, &request, sizeof(request))) { dev->agp->memory = entry->next; @@ -173,17 +247,39 @@ return 0; } +/** + * Search for the AGP memory entry associated with a handle. + * + * \param dev DRM device structure. + * \param handle AGP memory handle. + * \return pointer to the drm_agp_mem structure associated with \p handle. + * + * Walks through drm_agp_head::memory until finding a matching handle. + */ static drm_agp_mem_t *DRM(agp_lookup_entry)(drm_device_t *dev, unsigned long handle) { drm_agp_mem_t *entry; for (entry = dev->agp->memory; entry; entry = entry->next) { - if (entry->handle == handle) return entry; + if (entry->handle == handle) + return entry; } return NULL; } +/** + * Unbind AGP memory from the GATT (ioctl). + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg pointer to a drm_agp_binding structure. + * \return zero on success or a negative number on failure. + * + * Verifies the AGP device is present and acquired, looks-up the AGP memory + * entry and passes it to the unbind_agp() function. + */ int DRM(agp_unbind)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { @@ -191,16 +287,35 @@ drm_device_t *dev = priv->dev; drm_agp_binding_t request; drm_agp_mem_t *entry; + int ret; - if (!dev->agp || !dev->agp->acquired) return -EINVAL; + if (!dev->agp || !dev->agp->acquired) + return -EINVAL; if (copy_from_user(&request, (drm_agp_binding_t *)arg, sizeof(request))) return -EFAULT; if (!(entry = DRM(agp_lookup_entry)(dev, request.handle))) return -EINVAL; - if (!entry->bound) return -EINVAL; - return DRM(unbind_agp)(entry->memory); + if (!entry->bound) + return -EINVAL; + ret = DRM(unbind_agp)(entry->memory); + if (ret == 0) + entry->bound = 0; + return ret; } +/** + * Bind AGP memory into the GATT (ioctl) + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg pointer to a drm_agp_binding structure. + * \return zero on success or a negative number on failure. + * + * Verifies the AGP device is present and has been acquired and that no memory + * is currently bound into the GATT. Looks-up the AGP memory entry and passes + * it to bind_agp() function. + */ int DRM(agp_bind)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { @@ -217,15 +332,31 @@ return -EFAULT; if (!(entry = DRM(agp_lookup_entry)(dev, request.handle))) return -EINVAL; - if (entry->bound) return -EINVAL; + if (entry->bound) + return -EINVAL; page = (request.offset + PAGE_SIZE - 1) / PAGE_SIZE; - if ((retcode = DRM(bind_agp)(entry->memory, page))) return retcode; + if ((retcode = DRM(bind_agp)(entry->memory, page))) + return retcode; entry->bound = dev->agp->base + (page << PAGE_SHIFT); DRM_DEBUG("base = 0x%lx entry->bound = 0x%lx\n", dev->agp->base, entry->bound); return 0; } +/** + * Free AGP memory (ioctl). + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg pointer to a drm_agp_buffer structure. + * \return zero on success or a negative number on failure. + * + * Verifies the AGP device is present and has been acquired and looks up the + * AGP memory entry. If the memory it's currently bound, unbind it via + * unbind_agp(). Frees it via free_agp() as well as the entry itself + * and unlinks from the doubly linked list it's inserted in. + */ int DRM(agp_free)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { @@ -234,21 +365,37 @@ drm_agp_buffer_t request; drm_agp_mem_t *entry; - if (!dev->agp || !dev->agp->acquired) return -EINVAL; + if (!dev->agp || !dev->agp->acquired) + return -EINVAL; if (copy_from_user(&request, (drm_agp_buffer_t *)arg, sizeof(request))) return -EFAULT; if (!(entry = DRM(agp_lookup_entry)(dev, request.handle))) return -EINVAL; - if (entry->bound) DRM(unbind_agp)(entry->memory); + if (entry->bound) + DRM(unbind_agp)(entry->memory); + + if (entry->prev) + entry->prev->next = entry->next; + else + dev->agp->memory = entry->next; + + if (entry->next) + entry->next->prev = entry->prev; - if (entry->prev) entry->prev->next = entry->next; - else dev->agp->memory = entry->next; - if (entry->next) entry->next->prev = entry->prev; DRM(free_agp)(entry->memory, entry->pages); DRM(free)(entry, sizeof(*entry), DRM_MEM_AGPLISTS); return 0; } +/** + * Initialize the AGP resources. + * + * \return pointer to a drm_agp_head structure. + * + * Gets the drm_agp_t structure which is made available by the agpgart module + * via the inter_module_* functions. Creates and initializes a drm_agp_head + * structure. + */ drm_agp_head_t *DRM(agp_init)(void) { drm_agp_head_t *head = NULL; @@ -264,47 +411,58 @@ return NULL; } head->memory = NULL; - +#if LINUX_VERSION_CODE <= 0x020408 + head->cant_use_aperture = 0; + head->page_mask = ~(0xfff); +#else head->cant_use_aperture = head->agp_info.cant_use_aperture; head->page_mask = head->agp_info.page_mask; - - DRM_INFO("AGP %d.%d Aperture @ 0x%08lx %ZuMB\n", - head->agp_info.version.major, - head->agp_info.version.minor, - head->agp_info.aper_base, - head->agp_info.aper_size); +#endif } return head; } +/** + * Free the AGP resources. + * + * Releases the pointer in ::drm_agp. + */ void DRM(agp_uninit)(void) { DRM_AGP_PUT; drm_agp = NULL; } -agp_memory *DRM(agp_allocate_memory)(size_t pages, u32 type) +/** Calls drm_agp->allocate_memory() */ +DRM_AGP_MEM *DRM(agp_allocate_memory)(size_t pages, u32 type) { - if (!drm_agp->allocate_memory) return NULL; + if (!drm_agp->allocate_memory) + return NULL; return drm_agp->allocate_memory(pages, type); } -int DRM(agp_free_memory)(agp_memory *handle) +/** Calls drm_agp->free_memory() */ +int DRM(agp_free_memory)(DRM_AGP_MEM *handle) { - if (!handle || !drm_agp->free_memory) return 0; + if (!handle || !drm_agp->free_memory) + return 0; drm_agp->free_memory(handle); return 1; } -int DRM(agp_bind_memory)(agp_memory *handle, off_t start) +/** Calls drm_agp->bind_memory() */ +int DRM(agp_bind_memory)(DRM_AGP_MEM *handle, off_t start) { - if (!handle || !drm_agp->bind_memory) return -EINVAL; + if (!handle || !drm_agp->bind_memory) + return -EINVAL; return drm_agp->bind_memory(handle, start); } -int DRM(agp_unbind_memory)(agp_memory *handle) +/** Calls drm_agp->unbind_memory() */ +int DRM(agp_unbind_memory)(DRM_AGP_MEM *handle) { - if (!handle || !drm_agp->unbind_memory) return -EINVAL; + if (!handle || !drm_agp->unbind_memory) + return -EINVAL; return drm_agp->unbind_memory(handle); } diff -urN linux-2.4.23-pre8/drivers/char/drm/drm_auth.h linux-2.4.23-pre8-pac1/drivers/char/drm/drm_auth.h --- linux-2.4.23-pre8/drivers/char/drm/drm_auth.h 2003-06-13 16:51:32.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/drm_auth.h 2003-08-18 12:56:12.000000000 +0200 @@ -1,4 +1,12 @@ -/* drm_auth.h -- IOCTLs for authentication -*- linux-c -*- +/** + * \file drm_auth.h + * IOCTLs for authentication + * + * \author Rickard E. (Rik) Faith + * \author Gareth Hughes + */ + +/* * Created: Tue Feb 2 08:37:54 1999 by faith@valinux.com * * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. @@ -23,19 +31,35 @@ * 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 - * Gareth Hughes */ +#define __NO_VERSION__ #include "drmP.h" +/** + * Generate a hash key from a magic. + * + * \param magic magic. + * \return hash key. + * + * The key is the modulus of the hash table size, #DRM_HASH_SIZE, which must be + * a power of 2. + */ static int DRM(hash_magic)(drm_magic_t magic) { return magic & (DRM_HASH_SIZE-1); } +/** + * Find the file with the given magic number. + * + * \param dev DRM device. + * \param magic magic number. + * + * Searches in drm_device::magiclist within all files with the same hash key + * the one with matching magic number, while holding the drm_device::struct_sem + * lock. + */ static drm_file_t *DRM(find_file)(drm_device_t *dev, drm_magic_t magic) { drm_file_t *retval = NULL; @@ -53,6 +77,17 @@ return retval; } +/** + * Adds a magic number. + * + * \param dev DRM device. + * \param priv file private data. + * \param magic magic number. + * + * Creates a drm_magic_entry structure and appends to the linked list + * associated the magic number hash key in drm_device::magiclist, while holding + * the drm_device::struct_sem lock. + */ int DRM(add_magic)(drm_device_t *dev, drm_file_t *priv, drm_magic_t magic) { int hash; @@ -81,12 +116,22 @@ return 0; } +/** + * Remove a magic number. + * + * \param dev DRM device. + * \param magic magic number. + * + * Searches and unlinks the entry in drm_device::magiclist with the magic + * number hash key, while holding the drm_device::struct_sem lock. + */ int DRM(remove_magic)(drm_device_t *dev, drm_magic_t magic) { drm_magic_entry_t *prev = NULL; drm_magic_entry_t *pt; int hash; + DRM_DEBUG("%d\n", magic); hash = DRM(hash_magic)(magic); @@ -113,6 +158,19 @@ return -EINVAL; } +/** + * Get a unique magic number (ioctl). + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg pointer to a resulting drm_auth structure. + * \return zero on success, or a negative number on failure. + * + * If there is a magic number in drm_file::magic then use it, otherwise + * searches an unique non-zero magic number and add it associating it with \p + * filp. + */ int DRM(getmagic)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { @@ -142,6 +200,17 @@ return 0; } +/** + * Authenticate with a magic. + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg pointer to a drm_auth structure. + * \return zero if authentication successed, or a negative number otherwise. + * + * Checks if \p filp is associated with the magic number passed in \arg. + */ int DRM(authmagic)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { diff -urN linux-2.4.23-pre8/drivers/char/drm/drm_bufs.h linux-2.4.23-pre8-pac1/drivers/char/drm/drm_bufs.h --- linux-2.4.23-pre8/drivers/char/drm/drm_bufs.h 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/drm_bufs.h 2003-08-18 12:56:12.000000000 +0200 @@ -1,4 +1,12 @@ -/* drm_bufs.h -- Generic buffer template -*- linux-c -*- +/** + * \file drm_bufs.h + * Generic buffer template + * + * \author Rickard E. (Rik) Faith + * \author Gareth Hughes + */ + +/* * Created: Thu Nov 23 03:10:50 2000 by gareth@valinux.com * * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. @@ -23,12 +31,9 @@ * 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 - * Gareth Hughes */ +#define __NO_VERSION__ #include #include "drmP.h" @@ -51,8 +56,15 @@ #endif #endif -/* - * Compute order. Can be made faster. + +/** + * Compute size order. Returns the exponent of the smaller power of two which + * is greater or equal to given number. + * + * \param size size. + * \return order. + * + * \todo Can be made faster. */ int DRM(order)( unsigned long size ) { @@ -67,6 +79,19 @@ return order; } +/** + * Ioctl to specify a range of memory that is available for mapping by a non-root process. + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg pointer to a drm_map structure. + * \return zero on success or a negative value on error. + * + * Adjusts the memory offset to its absolute value according to the mapping + * type. Adds the map to the map list drm_device::maplist. Adds MTRR's where + * applicable and if supported by the kernel. + */ int DRM(addmap)( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ) { @@ -123,12 +148,12 @@ MTRR_TYPE_WRCOMB, 1 ); } #endif - map->handle = DRM(ioremap)( map->offset, map->size ); + map->handle = DRM(ioremap)( map->offset, map->size, dev ); break; case _DRM_SHM: map->handle = vmalloc_32(map->size); - DRM_DEBUG( "%ld %d %p\n", + DRM_DEBUG( "%lu %d %p\n", map->size, DRM(order)( map->size ), map->handle ); if ( !map->handle ) { DRM(free)( map, sizeof(*map), DRM_MEM_MAPS ); @@ -145,7 +170,7 @@ #ifdef __alpha__ map->offset += dev->hose->mem_space->start; #endif - map->offset = map->offset + dev->agp->base; + map->offset += dev->agp->base; map->mtrr = dev->agp->agp_mtrr; /* for getmap */ break; #endif @@ -154,7 +179,7 @@ DRM(free)(map, sizeof(*map), DRM_MEM_MAPS); return -EINVAL; } - map->offset = map->offset + dev->sg->handle; + map->offset += dev->sg->handle; break; default: @@ -186,10 +211,22 @@ } -/* Remove a map private from list and deallocate resources if the mapping +/** + * Remove a map private from list and deallocate resources if the mapping * isn't in use. + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg pointer to a drm_map_t structure. + * \return zero on success or a negative value on error. + * + * Searches the map on drm_device::maplist, removes it from the list, see if + * its being used, and free any associate resource (such as MTRR's) if it's not + * being on use. + * + * \sa addmap(). */ - int DRM(rmmap)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { @@ -210,7 +247,7 @@ down(&dev->struct_sem); list = &dev->maplist->head; list_for_each(list, &dev->maplist->head) { - r_list = (drm_map_list_t *) list; + r_list = list_entry(list, drm_map_list_t, head); if(r_list->map && r_list->map->handle == request.handle && @@ -245,7 +282,7 @@ DRM_DEBUG("mtrr_del = %d\n", retcode); } #endif - DRM(ioremapfree)(map->handle, map->size); + DRM(ioremapfree)(map->handle, map->size, dev); break; case _DRM_SHM: vfree(map->handle); @@ -262,16 +299,24 @@ #if __HAVE_DMA - +/** + * Cleanup after an error on one of the addbufs() functions. + * + * \param entry buffer entry where the error occurred. + * + * Frees any pages and buffers associated with the given entry. + */ static void DRM(cleanup_buf_error)(drm_buf_entry_t *entry) { int i; if (entry->seg_count) { for (i = 0; i < entry->seg_count; i++) { - DRM(free_pages)(entry->seglist[i], - entry->page_order, - DRM_MEM_DMA); + if (entry->seglist[i]) { + DRM(free_pages)(entry->seglist[i], + entry->page_order, + DRM_MEM_DMA); + } } DRM(free)(entry->seglist, entry->seg_count * @@ -281,9 +326,9 @@ entry->seg_count = 0; } - if(entry->buf_count) { - for(i = 0; i < entry->buf_count; i++) { - if(entry->buflist[i].dev_private) { + if (entry->buf_count) { + for (i = 0; i < entry->buf_count; i++) { + if (entry->buflist[i].dev_private) { DRM(free)(entry->buflist[i].dev_private, entry->buflist[i].dev_priv_size, DRM_MEM_BUFS); @@ -303,6 +348,19 @@ } #if __REALLY_HAVE_AGP +/** + * Add AGP buffers for DMA transfers (ioctl). + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg pointer to a drm_buf_desc_t request. + * \return zero on success or a negative number on failure. + * + * After some sanity checks creates a drm_buf structure for each buffer and + * reallocates the buffer list of the same size order to accommodate the new + * buffers. + */ int DRM(addbufs_agp)( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ) { @@ -345,7 +403,7 @@ DRM_DEBUG( "count: %d\n", count ); DRM_DEBUG( "order: %d\n", order ); DRM_DEBUG( "size: %d\n", size ); - DRM_DEBUG( "agp_offset: %ld\n", agp_offset ); + DRM_DEBUG( "agp_offset: %lu\n", agp_offset ); DRM_DEBUG( "alignment: %d\n", alignment ); DRM_DEBUG( "page_order: %d\n", page_order ); DRM_DEBUG( "total: %d\n", total ); @@ -403,7 +461,7 @@ buf->waiting = 0; buf->pending = 0; init_waitqueue_head( &buf->dma_wait ); - buf->pid = 0; + buf->filp = 0; buf->dev_priv_size = sizeof(DRIVER_BUF_PRIV_T); buf->dev_private = DRM(alloc)( sizeof(DRIVER_BUF_PRIV_T), @@ -412,15 +470,12 @@ /* Set count correctly so we free the proper amount. */ entry->buf_count = count; DRM(cleanup_buf_error)(entry); + up( &dev->struct_sem ); + atomic_dec( &dev->buf_alloc ); + return -ENOMEM; } memset( buf->dev_private, 0, buf->dev_priv_size ); -#if __HAVE_DMA_HISTOGRAM - buf->time_queued = 0; - buf->time_dispatched = 0; - buf->time_completed = 0; - buf->time_freed = 0; -#endif DRM_DEBUG( "buffer %d @ %p\n", entry->buf_count, buf->address ); @@ -565,12 +620,13 @@ } memset( entry->seglist, 0, count * sizeof(*entry->seglist) ); - temp_pagelist = DRM(realloc)( dma->pagelist, - dma->page_count * sizeof(*dma->pagelist), - (dma->page_count + (count << page_order)) - * sizeof(*dma->pagelist), - DRM_MEM_PAGES ); - if(!temp_pagelist) { + /* Keep the original pagelist until we know all the allocations + * have succeeded + */ + temp_pagelist = DRM(alloc)( (dma->page_count + (count << page_order)) + * sizeof(*dma->pagelist), + DRM_MEM_PAGES ); + if (!temp_pagelist) { DRM(free)( entry->buflist, count * sizeof(*entry->buflist), DRM_MEM_BUFS ); @@ -581,8 +637,9 @@ atomic_dec( &dev->buf_alloc ); return -ENOMEM; } - - dma->pagelist = temp_pagelist; + memcpy(temp_pagelist, + dma->pagelist, + dma->page_count * sizeof(*dma->pagelist)); DRM_DEBUG( "pagelist: %d entries\n", dma->page_count + (count << page_order) ); @@ -593,13 +650,25 @@ while ( entry->buf_count < count ) { page = DRM(alloc_pages)( page_order, DRM_MEM_DMA ); - if ( !page ) break; + if ( !page ) { + /* Set count correctly so we free the proper amount. */ + entry->buf_count = count; + entry->seg_count = count; + DRM(cleanup_buf_error)(entry); + DRM(free)( temp_pagelist, + (dma->page_count + (count << page_order)) + * sizeof(*dma->pagelist), + DRM_MEM_PAGES ); + up( &dev->struct_sem ); + atomic_dec( &dev->buf_alloc ); + return -ENOMEM; + } entry->seglist[entry->seg_count++] = page; for ( i = 0 ; i < (1 << page_order) ; i++ ) { DRM_DEBUG( "page %d @ 0x%08lx\n", dma->page_count + page_count, page + PAGE_SIZE * i ); - dma->pagelist[dma->page_count + page_count++] + temp_pagelist[dma->page_count + page_count++] = page + PAGE_SIZE * i; } for ( offset = 0 ; @@ -616,13 +685,26 @@ buf->waiting = 0; buf->pending = 0; init_waitqueue_head( &buf->dma_wait ); - buf->pid = 0; -#if __HAVE_DMA_HISTOGRAM - buf->time_queued = 0; - buf->time_dispatched = 0; - buf->time_completed = 0; - buf->time_freed = 0; -#endif + buf->filp = 0; + + buf->dev_priv_size = sizeof(DRIVER_BUF_PRIV_T); + buf->dev_private = DRM(alloc)( sizeof(DRIVER_BUF_PRIV_T), + DRM_MEM_BUFS ); + if(!buf->dev_private) { + /* Set count correctly so we free the proper amount. */ + entry->buf_count = count; + entry->seg_count = count; + DRM(cleanup_buf_error)(entry); + DRM(free)( temp_pagelist, + (dma->page_count + (count << page_order)) + * sizeof(*dma->pagelist), + DRM_MEM_PAGES ); + up( &dev->struct_sem ); + atomic_dec( &dev->buf_alloc ); + return -ENOMEM; + } + memset( buf->dev_private, 0, buf->dev_priv_size ); + DRM_DEBUG( "buffer %d @ %p\n", entry->buf_count, buf->address ); } @@ -634,9 +716,13 @@ (dma->buf_count + entry->buf_count) * sizeof(*dma->buflist), DRM_MEM_BUFS ); - if(!temp_buflist) { + if (!temp_buflist) { /* Free the entry because it isn't valid */ DRM(cleanup_buf_error)(entry); + DRM(free)( temp_pagelist, + (dma->page_count + (count << page_order)) + * sizeof(*dma->pagelist), + DRM_MEM_PAGES ); up( &dev->struct_sem ); atomic_dec( &dev->buf_alloc ); return -ENOMEM; @@ -647,6 +733,16 @@ dma->buflist[i + dma->buf_count] = &entry->buflist[i]; } + /* No allocations failed, so now we can replace the orginal pagelist + * with the new one. + */ + if (dma->page_count) { + DRM(free)(dma->pagelist, + dma->page_count * sizeof(*dma->pagelist), + DRM_MEM_PAGES); + } + dma->pagelist = temp_pagelist; + dma->buf_count += entry->buf_count; dma->seg_count += entry->seg_count; dma->page_count += entry->seg_count << page_order; @@ -672,7 +768,7 @@ } #endif /* __HAVE_PCI_DMA */ -#ifdef __HAVE_SG +#if __HAVE_SG int DRM(addbufs_sg)( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ) { @@ -715,7 +811,7 @@ DRM_DEBUG( "count: %d\n", count ); DRM_DEBUG( "order: %d\n", order ); DRM_DEBUG( "size: %d\n", size ); - DRM_DEBUG( "agp_offset: %ld\n", agp_offset ); + DRM_DEBUG( "agp_offset: %lu\n", agp_offset ); DRM_DEBUG( "alignment: %d\n", alignment ); DRM_DEBUG( "page_order: %d\n", page_order ); DRM_DEBUG( "total: %d\n", total ); @@ -773,7 +869,7 @@ buf->waiting = 0; buf->pending = 0; init_waitqueue_head( &buf->dma_wait ); - buf->pid = 0; + buf->filp = 0; buf->dev_priv_size = sizeof(DRIVER_BUF_PRIV_T); buf->dev_private = DRM(alloc)( sizeof(DRIVER_BUF_PRIV_T), @@ -789,12 +885,6 @@ memset( buf->dev_private, 0, buf->dev_priv_size ); -# if __HAVE_DMA_HISTOGRAM - buf->time_queued = 0; - buf->time_dispatched = 0; - buf->time_completed = 0; - buf->time_freed = 0; -# endif DRM_DEBUG( "buffer %d @ %p\n", entry->buf_count, buf->address ); @@ -850,6 +940,20 @@ } #endif /* __HAVE_SG */ +/** + * Add buffers for DMA transfers (ioctl). + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg pointer to a drm_buf_desc_t request. + * \return zero on success or a negative number on failure. + * + * According with the memory type specified in drm_buf_desc::flags and the + * build options, it dispatches the call either to addbufs_agp(), + * addbufs_sg() or addbufs_pci() for AGP, scatter-gather or consistent + * PCI memory respectively. + */ int DRM(addbufs)( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ) { @@ -876,6 +980,24 @@ #endif } + +/** + * Get information about the buffer mappings. + * + * This was originally mean for debugging purposes, or by a sophisticated + * client library to determine how best to use the available buffers (e.g., + * large buffers can be used for image transfer). + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg pointer to a drm_buf_info structure. + * \return zero on success or a negative number on failure. + * + * Increments drm_device::buf_use while holding the drm_device::count_lock + * lock, preventing of allocating more buffers after this call. Information + * about each requested buffer is then copied into user space. + */ int DRM(infobufs)( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ) { @@ -947,6 +1069,20 @@ return 0; } +/** + * Specifies a low and high water mark for buffer allocation + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg a pointer to a drm_buf_desc structure. + * \return zero on success or a negative number on failure. + * + * Verifies that the size order is bounded between the admissible orders and + * updates the respective drm_device_dma::bufs entry low and high water mark. + * + * \note This ioctl is deprecated and mostly never used. + */ int DRM(markbufs)( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ) { @@ -981,6 +1117,18 @@ return 0; } +/** + * Unreserve the buffers in list, previously reserved using drmDMA. + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg pointer to a drm_buf_free structure. + * \return zero on success or a negative number on failure. + * + * Calls free_buffer() for each used buffer. + * This function is primarily used for debugging. + */ int DRM(freebufs)( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ) { @@ -1011,9 +1159,9 @@ return -EINVAL; } buf = dma->buflist[idx]; - if ( buf->pid != current->pid ) { - DRM_ERROR( "Process %d freeing buffer owned by %d\n", - current->pid, buf->pid ); + if ( buf->filp != filp ) { + DRM_ERROR( "Process %d freeing buffer not owned\n", + current->pid ); return -EINVAL; } DRM(free_buffer)( dev, buf ); @@ -1022,6 +1170,19 @@ return 0; } +/** + * Maps all of the DMA buffers into client-virtual space (ioctl). + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg pointer to a drm_buf_map structure. + * \return zero on success or a negative number on failure. + * + * Maps the AGP or SG buffer region with do_mmap(), and copies information + * about each buffer into user space. The PCI buffers are already mapped on the + * addbufs_pci() call. + */ int DRM(mapbufs)( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ) { @@ -1059,18 +1220,34 @@ goto done; } +#if LINUX_VERSION_CODE <= 0x020402 + down( ¤t->mm->mmap_sem ); +#else down_write( ¤t->mm->mmap_sem ); +#endif virtual = do_mmap( filp, 0, map->size, PROT_READ | PROT_WRITE, MAP_SHARED, (unsigned long)map->offset ); +#if LINUX_VERSION_CODE <= 0x020402 + up( ¤t->mm->mmap_sem ); +#else up_write( ¤t->mm->mmap_sem ); +#endif } else { +#if LINUX_VERSION_CODE <= 0x020402 + down( ¤t->mm->mmap_sem ); +#else down_write( ¤t->mm->mmap_sem ); +#endif virtual = do_mmap( filp, 0, dma->byte_count, PROT_READ | PROT_WRITE, MAP_SHARED, 0 ); +#if LINUX_VERSION_CODE <= 0x020402 + up( ¤t->mm->mmap_sem ); +#else up_write( ¤t->mm->mmap_sem ); +#endif } if ( virtual > -1024UL ) { /* Real error */ diff -urN linux-2.4.23-pre8/drivers/char/drm/drm_context.h linux-2.4.23-pre8-pac1/drivers/char/drm/drm_context.h --- linux-2.4.23-pre8/drivers/char/drm/drm_context.h 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/drm_context.h 2003-08-18 12:56:12.000000000 +0200 @@ -1,4 +1,12 @@ -/* drm_context.h -- IOCTLs for generic contexts -*- linux-c -*- +/** + * \file drm_context.h + * IOCTLs for generic contexts + * + * \author Rickard E. (Rik) Faith + * \author Gareth Hughes + */ + +/* * Created: Fri Nov 24 18:31:37 2000 by gareth@valinux.com * * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. @@ -23,24 +31,37 @@ * 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 - * Gareth Hughes + */ + +/* * ChangeLog: * 2001-11-16 Torsten Duwe * added context constructor/destructor hooks, * needed by SiS driver's memory management. */ +#define __NO_VERSION__ #include "drmP.h" -#if __HAVE_CTX_BITMAP +#if !__HAVE_CTX_BITMAP +#error "__HAVE_CTX_BITMAP must be defined" +#endif -/* ================================================================ - * Context bitmap support - */ +/******************************************************************/ +/** \name Context bitmap support */ +/*@{*/ + +/** + * Free a handle from the context bitmap. + * + * \param dev DRM device. + * \param ctx_handle context handle. + * + * Clears the bit specified by \p ctx_handle in drm_device::ctx_bitmap and the entry + * in drm_device::context_sareas, while holding the drm_device::struct_sem + * lock. + */ void DRM(ctxbitmap_free)( drm_device_t *dev, int ctx_handle ) { if ( ctx_handle < 0 ) goto failed; @@ -59,6 +80,16 @@ return; } +/** + * Context bitmap allocation. + * + * \param dev DRM device. + * \return (non-negative) context handle on success or a negative number on failure. + * + * Find the first zero bit in drm_device::ctx_bitmap and (re)allocates + * drm_device::context_sareas to accommodate the new entry while holding the + * drm_device::struct_sem lock. + */ int DRM(ctxbitmap_next)( drm_device_t *dev ) { int bit; @@ -109,6 +140,14 @@ return -1; } +/** + * Context bitmap initialization. + * + * \param dev DRM device. + * + * Allocates and initialize drm_device::ctx_bitmap and drm_device::context_sareas, while holding + * the drm_device::struct_sem lock. + */ int DRM(ctxbitmap_init)( drm_device_t *dev ) { int i; @@ -134,6 +173,14 @@ return 0; } +/** + * Context bitmap cleanup. + * + * \param dev DRM device. + * + * Frees drm_device::ctx_bitmap and drm_device::context_sareas, while holding + * the drm_device::struct_sem lock. + */ void DRM(ctxbitmap_cleanup)( drm_device_t *dev ) { down(&dev->struct_sem); @@ -145,10 +192,24 @@ up(&dev->struct_sem); } -/* ================================================================ - * Per Context SAREA Support - */ +/*@}*/ +/******************************************************************/ +/** \name Per Context SAREA Support */ +/*@{*/ + +/** + * Get per-context SAREA. + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg user argument pointing to a drm_ctx_priv_map structure. + * \return zero on success or a negative number on failure. + * + * Gets the map from drm_device::context_sareas with the handle specified and + * returns its handle. + */ int DRM(getsareactx)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { @@ -177,6 +238,18 @@ return 0; } +/** + * Set per-context SAREA. + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg user argument pointing to a drm_ctx_priv_map structure. + * \return zero on success or a negative number on failure. + * + * Searches the mapping specified in \p arg and update the entry in + * drm_device::context_sareas with it. + */ int DRM(setsareactx)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { @@ -194,7 +267,7 @@ down(&dev->struct_sem); list_for_each(list, &dev->maplist->head) { - r_list = (drm_map_list_t *)list; + r_list = list_entry(list, drm_map_list_t, head); if(r_list->map && r_list->map->handle == request.handle) goto found; @@ -215,22 +288,29 @@ return 0; } -/* ================================================================ - * The actual DRM context handling routines - */ +/*@}*/ +/******************************************************************/ +/** \name The actual DRM context handling routines */ +/*@{*/ + +/** + * Switch context. + * + * \param dev DRM device. + * \param old old context handle. + * \param new new context handle. + * \return zero on success or a negative number on failure. + * + * Attempt to set drm_device::context_flag. + */ int DRM(context_switch)( drm_device_t *dev, int old, int new ) { - char buf[64]; - if ( test_and_set_bit( 0, &dev->context_flag ) ) { DRM_ERROR( "Reentering -- FIXME\n" ); return -EBUSY; } -#if __HAVE_DMA_HISTOGRAM - dev->ctx_start = get_cycles(); -#endif DRM_DEBUG( "Context switch from %d to %d\n", old, new ); @@ -239,16 +319,20 @@ return 0; } - if ( DRM(flags) & DRM_FLAG_NOCTX ) { - DRM(context_switch_complete)( dev, new ); - } else { - sprintf( buf, "C %d %d\n", old, new ); - DRM(write_string)( dev, buf ); - } - return 0; } +/** + * Complete context switch. + * + * \param dev DRM device. + * \param new new context handle. + * \return zero on success or a negative number on failure. + * + * Updates drm_device::last_context and drm_device::last_switch. Verifies the + * hardware lock is held, clears the drm_device::context_flag and wakes up + * drm_device::context_wait. + */ int DRM(context_switch_complete)( drm_device_t *dev, int new ) { dev->last_context = new; /* PRE/POST: This is the _only_ writer. */ @@ -261,17 +345,21 @@ /* If a context switch is ever initiated when the kernel holds the lock, release that lock here. */ -#if __HAVE_DMA_HISTOGRAM - atomic_inc( &dev->histo.ctx[DRM(histogram_slot)(get_cycles() - - dev->ctx_start)] ); - -#endif clear_bit( 0, &dev->context_flag ); wake_up( &dev->context_wait ); return 0; } +/** + * Reserve contexts. + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg user argument pointing to a drm_ctx_res structure. + * \return zero on success or a negative number on failure. + */ int DRM(resctx)( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ) { @@ -298,6 +386,17 @@ return 0; } +/** + * Add context. + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg user argument pointing to a drm_ctx structure. + * \return zero on success or a negative number on failure. + * + * Get a new handle for the context and copy to userspace. + */ int DRM(addctx)( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ) { @@ -336,6 +435,15 @@ return 0; } +/** + * Get context. + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg user argument pointing to a drm_ctx structure. + * \return zero on success or a negative number on failure. + */ int DRM(getctx)( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ) { @@ -352,6 +460,17 @@ return 0; } +/** + * Switch context. + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg user argument pointing to a drm_ctx structure. + * \return zero on success or a negative number on failure. + * + * Calls context_switch(). + */ int DRM(switchctx)( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ) { @@ -366,6 +485,17 @@ return DRM(context_switch)( dev, dev->last_context, ctx.handle ); } +/** + * New context. + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg user argument pointing to a drm_ctx structure. + * \return zero on success or a negative number on failure. + * + * Calls context_switch_complete(). + */ int DRM(newctx)( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ) { @@ -382,6 +512,17 @@ return 0; } +/** + * Remove context. + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg user argument pointing to a drm_ctx structure. + * \return zero on success or a negative number on failure. + * + * If not the special kernel context, calls ctxbitmap_free() to free the specified context. + */ int DRM(rmctx)( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ) { @@ -406,375 +547,4 @@ return 0; } - -#else /* __HAVE_CTX_BITMAP */ - -/* ================================================================ - * Old-style context support - */ - - -int DRM(context_switch)(drm_device_t *dev, int old, int new) -{ - char buf[64]; - drm_queue_t *q; - -#if 0 - atomic_inc(&dev->total_ctx); -#endif - - if (test_and_set_bit(0, &dev->context_flag)) { - DRM_ERROR("Reentering -- FIXME\n"); - return -EBUSY; - } - -#if __HAVE_DMA_HISTOGRAM - dev->ctx_start = get_cycles(); -#endif - - DRM_DEBUG("Context switch from %d to %d\n", old, new); - - if (new >= dev->queue_count) { - clear_bit(0, &dev->context_flag); - return -EINVAL; - } - - if (new == dev->last_context) { - clear_bit(0, &dev->context_flag); - return 0; - } - - q = dev->queuelist[new]; - atomic_inc(&q->use_count); - if (atomic_read(&q->use_count) == 1) { - atomic_dec(&q->use_count); - clear_bit(0, &dev->context_flag); - return -EINVAL; - } - - if (DRM(flags) & DRM_FLAG_NOCTX) { - DRM(context_switch_complete)(dev, new); - } else { - sprintf(buf, "C %d %d\n", old, new); - DRM(write_string)(dev, buf); - } - - atomic_dec(&q->use_count); - - return 0; -} - -int DRM(context_switch_complete)(drm_device_t *dev, int new) -{ - drm_device_dma_t *dma = dev->dma; - - dev->last_context = new; /* PRE/POST: This is the _only_ writer. */ - dev->last_switch = jiffies; - - if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { - DRM_ERROR("Lock isn't held after context switch\n"); - } - - if (!dma || !(dma->next_buffer && dma->next_buffer->while_locked)) { - if (DRM(lock_free)(dev, &dev->lock.hw_lock->lock, - DRM_KERNEL_CONTEXT)) { - DRM_ERROR("Cannot free lock\n"); - } - } - -#if __HAVE_DMA_HISTOGRAM - atomic_inc(&dev->histo.ctx[DRM(histogram_slot)(get_cycles() - - dev->ctx_start)]); - -#endif - clear_bit(0, &dev->context_flag); - wake_up_interruptible(&dev->context_wait); - - return 0; -} - -static int DRM(init_queue)(drm_device_t *dev, drm_queue_t *q, drm_ctx_t *ctx) -{ - DRM_DEBUG("\n"); - - if (atomic_read(&q->use_count) != 1 - || atomic_read(&q->finalization) - || atomic_read(&q->block_count)) { - DRM_ERROR("New queue is already in use: u%d f%d b%d\n", - atomic_read(&q->use_count), - atomic_read(&q->finalization), - atomic_read(&q->block_count)); - } - - atomic_set(&q->finalization, 0); - atomic_set(&q->block_count, 0); - atomic_set(&q->block_read, 0); - atomic_set(&q->block_write, 0); - atomic_set(&q->total_queued, 0); - atomic_set(&q->total_flushed, 0); - atomic_set(&q->total_locks, 0); - - init_waitqueue_head(&q->write_queue); - init_waitqueue_head(&q->read_queue); - init_waitqueue_head(&q->flush_queue); - - q->flags = ctx->flags; - - DRM(waitlist_create)(&q->waitlist, dev->dma->buf_count); - - return 0; -} - - -/* drm_alloc_queue: -PRE: 1) dev->queuelist[0..dev->queue_count] is allocated and will not - disappear (so all deallocation must be done after IOCTLs are off) - 2) dev->queue_count < dev->queue_slots - 3) dev->queuelist[i].use_count == 0 and - dev->queuelist[i].finalization == 0 if i not in use -POST: 1) dev->queuelist[i].use_count == 1 - 2) dev->queue_count < dev->queue_slots */ - -static int DRM(alloc_queue)(drm_device_t *dev) -{ - int i; - drm_queue_t *queue; - int oldslots; - int newslots; - /* Check for a free queue */ - for (i = 0; i < dev->queue_count; i++) { - atomic_inc(&dev->queuelist[i]->use_count); - if (atomic_read(&dev->queuelist[i]->use_count) == 1 - && !atomic_read(&dev->queuelist[i]->finalization)) { - DRM_DEBUG("%d (free)\n", i); - return i; - } - atomic_dec(&dev->queuelist[i]->use_count); - } - /* Allocate a new queue */ - down(&dev->struct_sem); - - queue = DRM(alloc)(sizeof(*queue), DRM_MEM_QUEUES); - memset(queue, 0, sizeof(*queue)); - atomic_set(&queue->use_count, 1); - - ++dev->queue_count; - if (dev->queue_count >= dev->queue_slots) { - oldslots = dev->queue_slots * sizeof(*dev->queuelist); - if (!dev->queue_slots) dev->queue_slots = 1; - dev->queue_slots *= 2; - newslots = dev->queue_slots * sizeof(*dev->queuelist); - - dev->queuelist = DRM(realloc)(dev->queuelist, - oldslots, - newslots, - DRM_MEM_QUEUES); - if (!dev->queuelist) { - up(&dev->struct_sem); - DRM_DEBUG("out of memory\n"); - return -ENOMEM; - } - } - dev->queuelist[dev->queue_count-1] = queue; - - up(&dev->struct_sem); - DRM_DEBUG("%d (new)\n", dev->queue_count - 1); - return dev->queue_count - 1; -} - -int DRM(resctx)(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) -{ - drm_ctx_res_t res; - 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) { - memset(&ctx, 0, sizeof(ctx)); - for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) { - ctx.handle = i; - if (copy_to_user(&res.contexts[i], - &i, - sizeof(i))) - return -EFAULT; - } - } - res.count = DRM_RESERVED_CONTEXTS; - if (copy_to_user((drm_ctx_res_t *)arg, &res, sizeof(res))) - return -EFAULT; - return 0; -} - -int DRM(addctx)(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) -{ - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; - drm_ctx_t ctx; - - if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) - return -EFAULT; - if ((ctx.handle = DRM(alloc_queue)(dev)) == DRM_KERNEL_CONTEXT) { - /* Init kernel's context and get a new one. */ - DRM(init_queue)(dev, dev->queuelist[ctx.handle], &ctx); - ctx.handle = DRM(alloc_queue)(dev); - } - DRM(init_queue)(dev, dev->queuelist[ctx.handle], &ctx); - DRM_DEBUG("%d\n", ctx.handle); - if (copy_to_user((drm_ctx_t *)arg, &ctx, sizeof(ctx))) - return -EFAULT; - return 0; -} - -int DRM(modctx)(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) -{ - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; - drm_ctx_t ctx; - drm_queue_t *q; - - if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) - return -EFAULT; - - DRM_DEBUG("%d\n", ctx.handle); - - if (ctx.handle < 0 || ctx.handle >= dev->queue_count) return -EINVAL; - q = dev->queuelist[ctx.handle]; - - atomic_inc(&q->use_count); - if (atomic_read(&q->use_count) == 1) { - /* No longer in use */ - atomic_dec(&q->use_count); - return -EINVAL; - } - - if (DRM_BUFCOUNT(&q->waitlist)) { - atomic_dec(&q->use_count); - return -EBUSY; - } - - q->flags = ctx.flags; - - atomic_dec(&q->use_count); - return 0; -} - -int DRM(getctx)(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) -{ - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; - drm_ctx_t ctx; - drm_queue_t *q; - - if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) - return -EFAULT; - - DRM_DEBUG("%d\n", ctx.handle); - - if (ctx.handle >= dev->queue_count) return -EINVAL; - q = dev->queuelist[ctx.handle]; - - atomic_inc(&q->use_count); - if (atomic_read(&q->use_count) == 1) { - /* No longer in use */ - atomic_dec(&q->use_count); - return -EINVAL; - } - - ctx.flags = q->flags; - atomic_dec(&q->use_count); - - if (copy_to_user((drm_ctx_t *)arg, &ctx, sizeof(ctx))) - return -EFAULT; - - return 0; -} - -int DRM(switchctx)(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) -{ - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; - drm_ctx_t ctx; - - if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) - return -EFAULT; - DRM_DEBUG("%d\n", ctx.handle); - return DRM(context_switch)(dev, dev->last_context, ctx.handle); -} - -int DRM(newctx)(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) -{ - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; - drm_ctx_t ctx; - - if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) - return -EFAULT; - DRM_DEBUG("%d\n", ctx.handle); - DRM(context_switch_complete)(dev, ctx.handle); - - return 0; -} - -int DRM(rmctx)(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) -{ - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; - drm_ctx_t ctx; - drm_queue_t *q; - drm_buf_t *buf; - - if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) - return -EFAULT; - DRM_DEBUG("%d\n", ctx.handle); - - if (ctx.handle >= dev->queue_count) return -EINVAL; - q = dev->queuelist[ctx.handle]; - - atomic_inc(&q->use_count); - if (atomic_read(&q->use_count) == 1) { - /* No longer in use */ - atomic_dec(&q->use_count); - return -EINVAL; - } - - atomic_inc(&q->finalization); /* Mark queue in finalization state */ - atomic_sub(2, &q->use_count); /* Mark queue as unused (pending - finalization) */ - - while (test_and_set_bit(0, &dev->interrupt_flag)) { - schedule(); - if (signal_pending(current)) { - clear_bit(0, &dev->interrupt_flag); - return -EINTR; - } - } - /* Remove queued buffers */ - while ((buf = DRM(waitlist_get)(&q->waitlist))) { - DRM(free_buffer)(dev, buf); - } - clear_bit(0, &dev->interrupt_flag); - - /* Wakeup blocked processes */ - wake_up_interruptible(&q->read_queue); - wake_up_interruptible(&q->write_queue); - wake_up_interruptible(&q->flush_queue); - - /* Finalization over. Queue is made - available when both use_count and - finalization become 0, which won't - happen until all the waiting processes - stop waiting. */ - atomic_dec(&q->finalization); - return 0; -} - -#endif /* __HAVE_CTX_BITMAP */ +/*@}*/ diff -urN linux-2.4.23-pre8/drivers/char/drm/drm_dma.h linux-2.4.23-pre8-pac1/drivers/char/drm/drm_dma.h --- linux-2.4.23-pre8/drivers/char/drm/drm_dma.h 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/drm_dma.h 2003-08-18 12:56:12.000000000 +0200 @@ -1,4 +1,12 @@ -/* drm_dma.c -- DMA IOCTL and function support -*- linux-c -*- +/** + * \file drm_dma.h + * DMA IOCTL and function support + * + * \author Rickard E. (Rik) Faith + * \author Gareth Hughes + */ + +/* * Created: Fri Mar 19 14:30:16 1999 by faith@valinux.com * * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. @@ -23,14 +31,11 @@ * 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 - * Gareth Hughes */ +#define __NO_VERSION__ #include "drmP.h" -#include "drm_os_linux.h" + #include /* For task queue support */ #ifndef __HAVE_DMA_WAITQUEUE @@ -51,6 +56,14 @@ #if __HAVE_DMA +/** + * Initialize the DMA data. + * + * \param dev DRM device. + * \return zero on success or a negative value on failure. + * + * Allocate and initialize a drm_device_dma structure. + */ int DRM(dma_setup)( drm_device_t *dev ) { int i; @@ -67,6 +80,14 @@ return 0; } +/** + * Cleanup the DMA resources. + * + * \param dev DRM device. + * + * Free all pages associated with DMA buffers, the buffers and pages lists, and + * finally the the drm_device::dma structure itself. + */ void DRM(dma_takedown)(drm_device_t *dev) { drm_device_dma_t *dma = dev->dma; @@ -83,22 +104,24 @@ dma->bufs[i].buf_count, dma->bufs[i].seg_count); for (j = 0; j < dma->bufs[i].seg_count; j++) { - DRM(free_pages)(dma->bufs[i].seglist[j], - dma->bufs[i].page_order, - DRM_MEM_DMA); + if (dma->bufs[i].seglist[j]) { + DRM(free_pages)(dma->bufs[i].seglist[j], + dma->bufs[i].page_order, + DRM_MEM_DMA); + } } DRM(free)(dma->bufs[i].seglist, dma->bufs[i].seg_count * sizeof(*dma->bufs[0].seglist), DRM_MEM_SEGS); } - if(dma->bufs[i].buf_count) { - for(j = 0; j < dma->bufs[i].buf_count; j++) { - if(dma->bufs[i].buflist[j].dev_private) { - DRM(free)(dma->bufs[i].buflist[j].dev_private, - dma->bufs[i].buflist[j].dev_priv_size, - DRM_MEM_BUFS); - } + if (dma->bufs[i].buf_count) { + for (j = 0; j < dma->bufs[i].buf_count; j++) { + if (dma->bufs[i].buflist[j].dev_private) { + DRM(free)(dma->bufs[i].buflist[j].dev_private, + dma->bufs[i].buflist[j].dev_priv_size, + DRM_MEM_BUFS); + } } DRM(free)(dma->bufs[i].buflist, dma->bufs[i].buf_count * @@ -126,73 +149,22 @@ } -#if __HAVE_DMA_HISTOGRAM -/* This is slow, but is useful for debugging. */ -int DRM(histogram_slot)(unsigned long count) -{ - int value = DRM_DMA_HISTOGRAM_INITIAL; - int slot; - - for (slot = 0; - slot < DRM_DMA_HISTOGRAM_SLOTS; - ++slot, value = DRM_DMA_HISTOGRAM_NEXT(value)) { - if (count < value) return slot; - } - return DRM_DMA_HISTOGRAM_SLOTS - 1; -} - -void DRM(histogram_compute)(drm_device_t *dev, drm_buf_t *buf) -{ - cycles_t queued_to_dispatched; - cycles_t dispatched_to_completed; - cycles_t completed_to_freed; - int q2d, d2c, c2f, q2c, q2f; - - if (buf->time_queued) { - queued_to_dispatched = (buf->time_dispatched - - buf->time_queued); - dispatched_to_completed = (buf->time_completed - - buf->time_dispatched); - completed_to_freed = (buf->time_freed - - buf->time_completed); - - q2d = DRM(histogram_slot)(queued_to_dispatched); - d2c = DRM(histogram_slot)(dispatched_to_completed); - c2f = DRM(histogram_slot)(completed_to_freed); - - q2c = DRM(histogram_slot)(queued_to_dispatched - + dispatched_to_completed); - q2f = DRM(histogram_slot)(queued_to_dispatched - + dispatched_to_completed - + completed_to_freed); - - atomic_inc(&dev->histo.total); - atomic_inc(&dev->histo.queued_to_dispatched[q2d]); - atomic_inc(&dev->histo.dispatched_to_completed[d2c]); - atomic_inc(&dev->histo.completed_to_freed[c2f]); - - atomic_inc(&dev->histo.queued_to_completed[q2c]); - atomic_inc(&dev->histo.queued_to_freed[q2f]); - - } - buf->time_queued = 0; - buf->time_dispatched = 0; - buf->time_completed = 0; - buf->time_freed = 0; -} -#endif - +/** + * Free a buffer. + * + * \param dev DRM device. + * \param buf buffer to free. + * + * Resets the fields of \p buf. + */ void DRM(free_buffer)(drm_device_t *dev, drm_buf_t *buf) { if (!buf) return; buf->waiting = 0; buf->pending = 0; - buf->pid = 0; + buf->filp = 0; buf->used = 0; -#if __HAVE_DMA_HISTOGRAM - buf->time_completed = get_cycles(); -#endif if ( __HAVE_DMA_WAITQUEUE && waitqueue_active(&buf->dma_wait)) { wake_up_interruptible(&buf->dma_wait); @@ -210,14 +182,23 @@ } #if !__HAVE_DMA_RECLAIM -void DRM(reclaim_buffers)(drm_device_t *dev, pid_t pid) +/** + * Reclaim the buffers. + * + * \param filp file pointer. + * + * Frees each buffer associated with \p filp not already on the hardware. + */ +void DRM(reclaim_buffers)( struct file *filp ) { + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; drm_device_dma_t *dma = dev->dma; int i; if (!dma) return; for (i = 0; i < dma->buf_count; i++) { - if (dma->buflist[i]->pid == pid) { + if (dma->buflist[i]->filp == filp) { switch (dma->buflist[i]->list) { case DRM_LIST_NONE: DRM(free_buffer)(dev, dma->buflist[i]); @@ -235,276 +216,20 @@ #endif -/* GH: This is a big hack for now... - */ -#if __HAVE_OLD_DMA - -void DRM(clear_next_buffer)(drm_device_t *dev) -{ - drm_device_dma_t *dma = dev->dma; - - dma->next_buffer = NULL; - if (dma->next_queue && !DRM_BUFCOUNT(&dma->next_queue->waitlist)) { - wake_up_interruptible(&dma->next_queue->flush_queue); - } - dma->next_queue = NULL; -} - -int DRM(select_queue)(drm_device_t *dev, void (*wrapper)(unsigned long)) -{ - int i; - int candidate = -1; - int j = jiffies; - - if (!dev) { - DRM_ERROR("No device\n"); - return -1; - } - if (!dev->queuelist || !dev->queuelist[DRM_KERNEL_CONTEXT]) { - /* This only happens between the time the - interrupt is initialized and the time - the queues are initialized. */ - return -1; - } - - /* Doing "while locked" DMA? */ - if (DRM_WAITCOUNT(dev, DRM_KERNEL_CONTEXT)) { - return DRM_KERNEL_CONTEXT; - } - - /* If there are buffers on the last_context - queue, and we have not been executing - this context very long, continue to - execute this context. */ - if (dev->last_switch <= j - && dev->last_switch + DRM_TIME_SLICE > j - && DRM_WAITCOUNT(dev, dev->last_context)) { - return dev->last_context; - } - - /* Otherwise, find a candidate */ - for (i = dev->last_checked + 1; i < dev->queue_count; i++) { - if (DRM_WAITCOUNT(dev, i)) { - candidate = dev->last_checked = i; - break; - } - } - - if (candidate < 0) { - for (i = 0; i < dev->queue_count; i++) { - if (DRM_WAITCOUNT(dev, i)) { - candidate = dev->last_checked = i; - break; - } - } - } - - if (wrapper - && candidate >= 0 - && candidate != dev->last_context - && dev->last_switch <= j - && dev->last_switch + DRM_TIME_SLICE > j) { - if (dev->timer.expires != dev->last_switch + DRM_TIME_SLICE) { - del_timer(&dev->timer); - dev->timer.function = wrapper; - dev->timer.data = (unsigned long)dev; - dev->timer.expires = dev->last_switch+DRM_TIME_SLICE; - add_timer(&dev->timer); - } - return -1; - } - - return candidate; -} - - -int DRM(dma_enqueue)(drm_device_t *dev, drm_dma_t *d) -{ - int i; - drm_queue_t *q; - drm_buf_t *buf; - int idx; - int while_locked = 0; - drm_device_dma_t *dma = dev->dma; - DECLARE_WAITQUEUE(entry, current); - - DRM_DEBUG("%d\n", d->send_count); - - if (d->flags & _DRM_DMA_WHILE_LOCKED) { - int context = dev->lock.hw_lock->lock; - - if (!_DRM_LOCK_IS_HELD(context)) { - DRM_ERROR("No lock held during \"while locked\"" - " request\n"); - return -EINVAL; - } - if (d->context != _DRM_LOCKING_CONTEXT(context) - && _DRM_LOCKING_CONTEXT(context) != DRM_KERNEL_CONTEXT) { - DRM_ERROR("Lock held by %d while %d makes" - " \"while locked\" request\n", - _DRM_LOCKING_CONTEXT(context), - d->context); - return -EINVAL; - } - q = dev->queuelist[DRM_KERNEL_CONTEXT]; - while_locked = 1; - } else { - q = dev->queuelist[d->context]; - } - - - atomic_inc(&q->use_count); - if (atomic_read(&q->block_write)) { - 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)) { - atomic_dec(&q->use_count); - remove_wait_queue(&q->write_queue, &entry); - return -EINTR; - } - } - atomic_dec(&q->block_count); - current->state = TASK_RUNNING; - remove_wait_queue(&q->write_queue, &entry); - } - - for (i = 0; i < d->send_count; i++) { - idx = d->send_indices[i]; - if (idx < 0 || idx >= dma->buf_count) { - atomic_dec(&q->use_count); - DRM_ERROR("Index %d (of %d max)\n", - d->send_indices[i], dma->buf_count - 1); - return -EINVAL; - } - buf = dma->buflist[ idx ]; - if (buf->pid != current->pid) { - atomic_dec(&q->use_count); - DRM_ERROR("Process %d using buffer owned by %d\n", - current->pid, buf->pid); - return -EINVAL; - } - if (buf->list != DRM_LIST_NONE) { - atomic_dec(&q->use_count); - DRM_ERROR("Process %d using buffer %d on list %d\n", - current->pid, buf->idx, buf->list); - } - buf->used = d->send_sizes[i]; - buf->while_locked = while_locked; - buf->context = d->context; - if (!buf->used) { - DRM_ERROR("Queueing 0 length buffer\n"); - } - if (buf->pending) { - atomic_dec(&q->use_count); - DRM_ERROR("Queueing pending buffer:" - " buffer %d, offset %d\n", - d->send_indices[i], i); - return -EINVAL; - } - if (buf->waiting) { - atomic_dec(&q->use_count); - DRM_ERROR("Queueing waiting buffer:" - " buffer %d, offset %d\n", - d->send_indices[i], i); - return -EINVAL; - } - buf->waiting = 1; - if (atomic_read(&q->use_count) == 1 - || atomic_read(&q->finalization)) { - DRM(free_buffer)(dev, buf); - } else { - DRM(waitlist_put)(&q->waitlist, buf); - atomic_inc(&q->total_queued); - } - } - atomic_dec(&q->use_count); - - return 0; -} - -static int DRM(dma_get_buffers_of_order)(drm_device_t *dev, drm_dma_t *d, - int order) -{ - int i; - drm_buf_t *buf; - drm_device_dma_t *dma = dev->dma; - - for (i = d->granted_count; i < d->request_count; i++) { - buf = DRM(freelist_get)(&dma->bufs[order].freelist, - d->flags & _DRM_DMA_WAIT); - if (!buf) break; - if (buf->pending || buf->waiting) { - DRM_ERROR("Free buffer %d in use by %d (w%d, p%d)\n", - buf->idx, - buf->pid, - buf->waiting, - buf->pending); - } - buf->pid = current->pid; - if (copy_to_user(&d->request_indices[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; - } - return 0; -} - - -int DRM(dma_get_buffers)(drm_device_t *dev, drm_dma_t *dma) -{ - int order; - int retcode = 0; - int tmp_order; - - order = DRM(order)(dma->request_size); - - dma->granted_count = 0; - retcode = DRM(dma_get_buffers_of_order)(dev, dma, order); - - if (dma->granted_count < dma->request_count - && (dma->flags & _DRM_DMA_SMALLER_OK)) { - for (tmp_order = order - 1; - !retcode - && dma->granted_count < dma->request_count - && tmp_order >= DRM_MIN_ORDER; - --tmp_order) { - - retcode = DRM(dma_get_buffers_of_order)(dev, dma, - tmp_order); - } - } - - if (dma->granted_count < dma->request_count - && (dma->flags & _DRM_DMA_LARGER_OK)) { - for (tmp_order = order + 1; - !retcode - && dma->granted_count < dma->request_count - && tmp_order <= DRM_MAX_ORDER; - ++tmp_order) { - - retcode = DRM(dma_get_buffers_of_order)(dev, dma, - tmp_order); - } - } - return 0; -} - -#endif /* __HAVE_OLD_DMA */ #if __HAVE_DMA_IRQ +/** + * Install IRQ handler. + * + * \param dev DRM device. + * \param irq IRQ number. + * + * Initializes the IRQ related data, and setups drm_device::vbl_queue. Installs the handler, calling the driver + * \c DRM(driver_irq_preinstall)() and \c DRM(driver_irq_postinstall)() functions + * before and after the installation. + */ int DRM(irq_install)( drm_device_t *dev, int irq ) { int ret; @@ -513,6 +238,13 @@ return -EINVAL; down( &dev->struct_sem ); + + /* Driver must have been initialized */ + if ( !dev->dev_private ) { + up( &dev->struct_sem ); + return -EINVAL; + } + if ( dev->irq ) { up( &dev->struct_sem ); return -EBUSY; @@ -531,10 +263,14 @@ dev->dma->this_buffer = NULL; #if __HAVE_DMA_IRQ_BH +#if !HAS_WORKQUEUE INIT_LIST_HEAD( &dev->tq.list ); dev->tq.sync = 0; dev->tq.routine = DRM(dma_immediate_bh); dev->tq.data = dev; +#else + INIT_WORK(&dev->work, DRM(dma_immediate_bh), dev); +#endif #endif #if __HAVE_VBL_IRQ @@ -566,6 +302,13 @@ return 0; } +/** + * Uninstall the IRQ handler. + * + * \param dev DRM device. + * + * Calls the driver's \c DRM(driver_irq_uninstall)() function, and stops the irq. + */ int DRM(irq_uninstall)( drm_device_t *dev ) { int irq; @@ -587,6 +330,17 @@ return 0; } +/** + * IRQ control ioctl. + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg user argument, pointing to a drm_control structure. + * \return zero on success or a negative number on failure. + * + * Calls irq_install() or irq_uninstall() according to \p arg. + */ int DRM(control)( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ) { @@ -609,7 +363,26 @@ #if __HAVE_VBL_IRQ -int DRM(wait_vblank)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long data ) +/** + * Wait for VBLANK. + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param data user argument, pointing to a drm_wait_vblank structure. + * \return zero on success or a negative number on failure. + * + * Verifies the IRQ is installed. + * + * If a signal is requested checks if this task has already scheduled the same signal + * for the same vblank sequence number - nothing to be done in + * that case. If the number of tasks waiting for the interrupt exceeds 100 the + * function fails. Otherwise adds a new entry to drm_device::vbl_sigs for this + * task. + * + * If a signal is not requested, then calls vblank_wait(). + */ +int DRM(wait_vblank)( DRM_IOCTL_ARGS ) { drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; @@ -648,7 +421,7 @@ * for the same vblank sequence number; nothing to be done in * that case */ - list_for_each( ( (struct list_head *) vbl_sig ), &dev->vbl_sigs.head ) { + list_for_each_entry( vbl_sig, &dev->vbl_sigs.head, head ) { if (vbl_sig->sequence == vblwait.request.sequence && vbl_sig->info.si_signo == vblwait.request.signal && vbl_sig->task == current) @@ -667,9 +440,9 @@ spin_unlock_irqrestore( &dev->vbl_lock, irqflags ); - if ( !( vbl_sig = kmalloc(sizeof(drm_vbl_sig_t), GFP_KERNEL) ) ) + if ( !( vbl_sig = DRM_MALLOC( sizeof( drm_vbl_sig_t ) ) ) ) { return -ENOMEM; - + } memset( (void *)vbl_sig, 0, sizeof(*vbl_sig) ); @@ -697,24 +470,34 @@ return ret; } +/** + * Send the VBLANK signals. + * + * \param dev DRM device. + * + * Sends a signal for each task in drm_device::vbl_sigs and empties the list. + * + * If a signal is not requested, then calls vblank_wait(). + */ void DRM(vbl_send_signals)( drm_device_t *dev ) { - struct list_head *tmp; + struct list_head *list, *tmp; drm_vbl_sig_t *vbl_sig; unsigned int vbl_seq = atomic_read( &dev->vbl_received ); unsigned long flags; spin_lock_irqsave( &dev->vbl_lock, flags ); - list_for_each_safe( ( (struct list_head *) vbl_sig ), tmp, &dev->vbl_sigs.head ) { + list_for_each_safe( list, tmp, &dev->vbl_sigs.head ) { + vbl_sig = list_entry( list, drm_vbl_sig_t, head ); if ( ( vbl_seq - vbl_sig->sequence ) <= (1<<23) ) { vbl_sig->info.si_code = vbl_seq; send_sig_info( vbl_sig->info.si_signo, &vbl_sig->info, vbl_sig->task ); - list_del( (struct list_head *) vbl_sig ); + list_del( list ); + DRM_FREE( vbl_sig, sizeof(*vbl_sig) ); - kfree( vbl_sig ); dev->vbl_pending--; } } diff -urN linux-2.4.23-pre8/drivers/char/drm/drm_drawable.h linux-2.4.23-pre8-pac1/drivers/char/drm/drm_drawable.h --- linux-2.4.23-pre8/drivers/char/drm/drm_drawable.h 2002-11-29 00:53:12.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/drm_drawable.h 2003-08-18 12:56:12.000000000 +0200 @@ -1,4 +1,12 @@ -/* drm_drawable.h -- IOCTLs for drawables -*- linux-c -*- +/** + * \file drm_drawable.h + * IOCTLs for drawables + * + * \author Rickard E. (Rik) Faith + * \author Gareth Hughes + */ + +/* * Created: Tue Feb 2 08:37:54 1999 by faith@valinux.com * * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. @@ -23,14 +31,12 @@ * 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 - * Gareth Hughes */ +#define __NO_VERSION__ #include "drmP.h" +/** No-op. */ int DRM(adddraw)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { @@ -43,6 +49,7 @@ return 0; } +/** No-op. */ int DRM(rmdraw)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { diff -urN linux-2.4.23-pre8/drivers/char/drm/drm_drv.h linux-2.4.23-pre8-pac1/drivers/char/drm/drm_drv.h --- linux-2.4.23-pre8/drivers/char/drm/drm_drv.h 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/drm_drv.h 2003-08-18 12:56:12.000000000 +0200 @@ -1,4 +1,31 @@ -/* drm_drv.h -- Generic driver template -*- linux-c -*- +/** + * \file drm_drv.h + * Generic driver template + * + * \author Rickard E. (Rik) Faith + * \author Gareth Hughes + * + * To use this template, you must at least define the following (samples + * given for the MGA driver): + * + * \code + * #define DRIVER_AUTHOR "VA Linux Systems, Inc." + * + * #define DRIVER_NAME "mga" + * #define DRIVER_DESC "Matrox G200/G400" + * #define DRIVER_DATE "20001127" + * + * #define DRIVER_MAJOR 2 + * #define DRIVER_MINOR 0 + * #define DRIVER_PATCHLEVEL 2 + * + * #define DRIVER_IOCTL_COUNT DRM_ARRAY_SIZE( mga_ioctls ) + * + * #define DRM(x) mga_##x + * \endcode + */ + +/* * Created: Thu Nov 23 03:10:50 2000 by gareth@valinux.com * * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. @@ -23,29 +50,6 @@ * 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 - * Gareth Hughes - */ - -/* - * To use this template, you must at least define the following (samples - * given for the MGA driver): - * - * #define DRIVER_AUTHOR "VA Linux Systems, Inc." - * - * #define DRIVER_NAME "mga" - * #define DRIVER_DESC "Matrox G200/G400" - * #define DRIVER_DATE "20001127" - * - * #define DRIVER_MAJOR 2 - * #define DRIVER_MINOR 0 - * #define DRIVER_PATCHLEVEL 2 - * - * #define DRIVER_IOCTL_COUNT DRM_ARRAY_SIZE( mga_ioctls ) - * - * #define DRM(x) mga_##x */ #ifndef __MUST_HAVE_AGP @@ -84,9 +88,19 @@ #ifndef __HAVE_SG #define __HAVE_SG 0 #endif +/* __HAVE_KERNEL_CTX_SWITCH isn't used by any of the drm modules in + * the DRI cvs tree, but it is required by the kernel tree's sparc + * driver. + */ #ifndef __HAVE_KERNEL_CTX_SWITCH #define __HAVE_KERNEL_CTX_SWITCH 0 #endif +#ifndef __HAVE_DRIVER_FOPS_READ +#define __HAVE_DRIVER_FOPS_READ 0 +#endif +#ifndef __HAVE_DRIVER_FOPS_POLL +#define __HAVE_DRIVER_FOPS_POLL 0 +#endif #ifndef DRIVER_PREINIT #define DRIVER_PREINIT() @@ -121,19 +135,20 @@ .release = DRM(release), \ .ioctl = DRM(ioctl), \ .mmap = DRM(mmap), \ - .read = DRM(read), \ .fasync = DRM(fasync), \ .poll = DRM(poll), \ + .read = DRM(read), \ } #endif #ifndef MODULE -/* DRM(options) is called by the kernel to parse command-line options - * passed via the boot-loader (e.g., LILO). It calls the insmod option - * routine, drm_parse_drm. - */ -/* Use an additional macro to avoid preprocessor troubles */ +/** Use an additional macro to avoid preprocessor troubles */ #define DRM_OPTIONS_FUNC DRM(options) +/** + * Called by the kernel to parse command-line options passed via the + * boot-loader (e.g., LILO). It calls the insmod option routine, + * parse_options(). + */ static int __init DRM(options)( char *str ) { DRM(parse_options)( str ); @@ -144,7 +159,7 @@ #undef DRM_OPTIONS_FUNC #endif -/* +/** * The default number of instances (minor numbers) to initialize. */ #ifndef DRIVER_NUM_CARDS @@ -157,6 +172,7 @@ DRIVER_FOPS; +/** Ioctl table */ static drm_ioctl_desc_t DRM(ioctls)[] = { [DRM_IOCTL_NR(DRM_IOCTL_VERSION)] = { DRM(version), 0, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)] = { DRM(getunique), 0, 0 }, @@ -167,8 +183,8 @@ [DRM_IOCTL_NR(DRM_IOCTL_GET_STATS)] = { DRM(getstats), 0, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_SET_UNIQUE)] = { DRM(setunique), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_BLOCK)] = { DRM(block), 1, 1 }, - [DRM_IOCTL_NR(DRM_IOCTL_UNBLOCK)] = { DRM(unblock), 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_BLOCK)] = { DRM(noop), 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_UNBLOCK)] = { DRM(noop), 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_AUTH_MAGIC)] = { DRM(authmagic), 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)] = { DRM(addmap), 1, 1 }, @@ -192,7 +208,13 @@ [DRM_IOCTL_NR(DRM_IOCTL_LOCK)] = { DRM(lock), 1, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)] = { DRM(unlock), 1, 0 }, + +#if __HAVE_DMA_FLUSH + /* Gamma only, really */ [DRM_IOCTL_NR(DRM_IOCTL_FINISH)] = { DRM(finish), 1, 0 }, +#else + [DRM_IOCTL_NR(DRM_IOCTL_FINISH)] = { DRM(noop), 1, 0 }, +#endif #if __HAVE_DMA [DRM_IOCTL_NR(DRM_IOCTL_ADD_BUFS)] = { DRM(addbufs), 1, 1 }, @@ -307,7 +329,6 @@ if(dev->maplist == NULL) return -ENOMEM; memset(dev->maplist, 0, sizeof(*dev->maplist)); INIT_LIST_HEAD(&dev->maplist->head); - dev->map_count = 0; dev->vmalist = NULL; dev->sigdata.lock = dev->lock.hw_lock = NULL; @@ -323,7 +344,6 @@ dev->last_context = 0; dev->last_switch = 0; dev->last_checked = 0; - init_timer( &dev->timer ); init_waitqueue_head( &dev->context_wait ); dev->ctx_start = 0; @@ -338,7 +358,8 @@ DRM_DEBUG( "\n" ); - /* The kernel's context could be created here, but is now created + /* + * 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 @@ -349,6 +370,15 @@ } +/** + * Take down the DRM device. + * + * \param dev DRM device structure. + * + * Frees every resource in \p dev. + * + * \sa drm_device and setup(). + */ static int DRM(takedown)( drm_device_t *dev ) { drm_magic_entry_t *pt, *next; @@ -422,51 +452,49 @@ } if( dev->maplist ) { - for(list = dev->maplist->head.next; - list != &dev->maplist->head; - list = list_next) { - list_next = list->next; + list_for_each_safe( list, list_next, &dev->maplist->head ) { r_list = (drm_map_list_t *)list; - map = r_list->map; - DRM(free)(r_list, sizeof(*r_list), DRM_MEM_MAPS); - if(!map) continue; - switch ( map->type ) { - case _DRM_REGISTERS: - case _DRM_FRAME_BUFFER: + if ( ( map = r_list->map ) ) { + switch ( map->type ) { + case _DRM_REGISTERS: + case _DRM_FRAME_BUFFER: #if __REALLY_HAVE_MTRR - if ( map->mtrr >= 0 ) { - int retcode; - retcode = mtrr_del( map->mtrr, - map->offset, - map->size ); - DRM_DEBUG( "mtrr_del=%d\n", retcode ); - } -#endif - DRM(ioremapfree)( map->handle, map->size ); - break; - case _DRM_SHM: - vfree(map->handle); - break; - - case _DRM_AGP: - /* Do nothing here, because this is all - * handled in the AGP/GART driver. - */ - break; - case _DRM_SCATTER_GATHER: - /* Handle it, but do nothing, if HAVE_SG - * isn't defined. - */ + if ( map->mtrr >= 0 ) { + int retcode; + retcode = mtrr_del( map->mtrr, + map->offset, + map->size ); + DRM_DEBUG( "mtrr_del=%d\n", retcode ); + } +#endif + DRM(ioremapfree)( map->handle, map->size, dev ); + break; + case _DRM_SHM: + vfree(map->handle); + break; + + case _DRM_AGP: + /* Do nothing here, because this is all + * handled in the AGP/GART driver. + */ + break; + case _DRM_SCATTER_GATHER: + /* Handle it, but do nothing, if HAVE_SG + * isn't defined. + */ #if __HAVE_SG - if(dev->sg) { - DRM(sg_cleanup)(dev->sg); - dev->sg = NULL; - } + if(dev->sg) { + DRM(sg_cleanup)(dev->sg); + dev->sg = NULL; + } #endif - break; + break; + } + DRM(free)(map, sizeof(*map), DRM_MEM_MAPS); } - DRM(free)(map, sizeof(*map), DRM_MEM_MAPS); + list_del( list ); + DRM(free)(r_list, sizeof(*r_list), DRM_MEM_MAPS); } DRM(free)(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS); dev->maplist = NULL; @@ -475,7 +503,9 @@ #if __HAVE_DMA_QUEUE || __HAVE_MULTIPLE_DMA_QUEUES if ( dev->queuelist ) { for ( i = 0 ; i < dev->queue_count ; i++ ) { +#if __HAVE_DMA_WAITLIST DRM(waitlist_destroy)( &dev->queuelist[i]->waitlist ); +#endif if ( dev->queuelist[i] ) { DRM(free)( dev->queuelist[i], sizeof(*dev->queuelist[0]), @@ -496,7 +526,7 @@ #endif if ( dev->lock.hw_lock ) { dev->sigdata.lock = dev->lock.hw_lock = NULL; /* SHM removed */ - dev->lock.pid = 0; + dev->lock.filp = 0; wake_up_interruptible( &dev->lock.lock_queue ); } up( &dev->struct_sem ); @@ -504,8 +534,12 @@ return 0; } -/* +/** * Figure out how many instances to initialize. + * + * \return number of cards found. + * + * Searches for every PCI card in \c DRIVER_CARD_LIST with matching vendor and device ids. */ static int drm_count_cards(void) { @@ -539,8 +573,18 @@ return num; } -/* drm_init is called via init_module at module load time, or via +/** + * Module initialization. Called via init_module at module load time, or via * linux/init/main.c (this is not currently supported). + * + * \return zero on success or a negative number on failure. + * + * Allocates and initialize an array of drm_device structures, and attempts to + * initialize all available devices, using consecutive minors, registering the + * stubs and initializing the AGP device. + * + * Expands the \c DRIVER_PREINIT and \c DRIVER_POST_INIT macros before and + * after the initialization for driver customization. */ static int __init drm_init( void ) { @@ -579,6 +623,7 @@ dev = &(DRM(device)[i]); memset( (void *)dev, 0, sizeof(*dev) ); dev->count_lock = SPIN_LOCK_UNLOCKED; + init_timer( &dev->timer ); sema_init( &dev->struct_sem, 1 ); if ((DRM(minor)[i] = DRM(stub_register)(DRIVER_NAME, &DRM(fops),dev)) < 0) @@ -628,7 +673,12 @@ return 0; } -/* drm_cleanup is called via cleanup_module at module unload time. +/** + * Called via cleanup_module() at module unload time. + * + * Cleans up all DRM device, calling takedown(). + * + * \sa drm_init(). */ static void __exit drm_cleanup( void ) { @@ -681,6 +731,17 @@ module_exit( drm_cleanup ); +/** + * Get version information + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg user argument, pointing to a drm_version structure. + * \return zero on success or negative number on failure. + * + * Fills in the version information in \p arg. + */ int DRM(version)( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ) { @@ -716,6 +777,17 @@ return 0; } +/** + * Open file. + * + * \param inode device inode + * \param filp file pointer. + * \return zero on success or a negative number on failure. + * + * Searches the DRM device with the same minor number, calls open_helper(), and + * increments the device open count. If the open count was previous at zero, + * i.e., it's the first that the device is open, then calls setup(). + */ int DRM(open)( struct inode *inode, struct file *filp ) { drm_device_t *dev = NULL; @@ -732,8 +804,6 @@ return -ENODEV; } - DRM_DEBUG( "open_count = %d\n", dev->open_count ); - retcode = DRM(open_helper)( inode, filp, dev ); if ( !retcode ) { atomic_inc( &dev->counts[_DRM_STAT_OPENS] ); @@ -748,6 +818,18 @@ return retcode; } +/** + * Release file. + * + * \param inode device inode + * \param filp file pointer. + * \return zero on success or a negative number on failure. + * + * If the hardware lock is held then free it, and take it again for the kernel + * context since it's necessary to reclaim buffers. Unlink the file private + * data from its list and free it. Decreases the open count and if it reaches + * zero calls takedown(). + */ int DRM(release)( struct inode *inode, struct file *filp ) { drm_file_t *priv = filp->private_data; @@ -768,12 +850,12 @@ DRM_DEBUG( "pid = %d, device = 0x%lx, open_count = %d\n", current->pid, (long)dev->device, dev->open_count ); - if ( dev->lock.hw_lock && + if ( priv->lock_count && dev->lock.hw_lock && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) && - dev->lock.pid == current->pid ) { - DRM_DEBUG( "Process %d dead, freeing lock for context %d\n", - current->pid, - _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock) ); + dev->lock.filp == filp ) { + DRM_DEBUG( "File %p released, freeing lock for context %d\n", + filp, + _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock) ); #if __HAVE_RELEASE DRIVER_RELEASE(); #endif @@ -786,9 +868,10 @@ server. */ } #if __HAVE_RELEASE - else if ( dev->lock.hw_lock ) { + else if ( priv->lock_count && 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; @@ -799,15 +882,12 @@ } if ( DRM(lock_take)( &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT ) ) { - dev->lock.pid = priv->pid; + dev->lock.filp = filp; dev->lock.lock_time = jiffies; atomic_inc( &dev->counts[_DRM_STAT_LOCKS] ); break; /* Got lock */ } /* Contention */ -#if 0 - atomic_inc( &dev->total_sleeps ); -#endif schedule(); if ( signal_pending( current ) ) { retcode = -ERESTARTSYS; @@ -823,7 +903,7 @@ } } #elif __HAVE_DMA - DRM(reclaim_buffers)( dev, priv->pid ); + DRM(reclaim_buffers)( filp ); #endif DRM(fasync)( -1, filp, 0 ); @@ -847,7 +927,7 @@ dev->file_last = priv->prev; } up( &dev->struct_sem ); - + DRM(free)( priv, sizeof(*priv), DRM_MEM_FILES ); /* ======================================================== @@ -872,10 +952,21 @@ spin_unlock( &dev->count_lock ); unlock_kernel(); + return retcode; } -/* DRM(ioctl) is called whenever a process performs an ioctl on /dev/drm. +/** + * Called whenever a process performs an ioctl on /dev/drm. + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg user argument. + * \return zero on success or negative number on failure. + * + * Looks up the ioctl function in the ::ioctls table, checking for root + * previleges if so required, and dispatches to the respective function. */ int DRM(ioctl)( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ) @@ -916,6 +1007,17 @@ return retcode; } +/** + * Lock ioctl. + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg user argument, pointing to a drm_lock structure. + * \return zero on success or negative number on failure. + * + * Add the current task to the lock wait queue, and attempt to take to lock. + */ int DRM(lock)( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ) { @@ -927,11 +1029,8 @@ #if __HAVE_MULTIPLE_DMA_QUEUES drm_queue_t *q; #endif -#if __HAVE_DMA_HISTOGRAM - cycles_t start; - dev->lck_start = start = get_cycles(); -#endif + ++priv->lock_count; if ( copy_from_user( &lock, (drm_lock_t *)arg, sizeof(lock) ) ) return -EFAULT; @@ -969,7 +1068,7 @@ } if ( DRM(lock_take)( &dev->lock.hw_lock->lock, lock.context ) ) { - dev->lock.pid = current->pid; + dev->lock.filp = filp; dev->lock.lock_time = jiffies; atomic_inc( &dev->counts[_DRM_STAT_LOCKS] ); break; /* Got lock */ @@ -1011,6 +1110,10 @@ DRIVER_DMA_QUIESCENT(); } #endif + /* __HAVE_KERNEL_CTX_SWITCH isn't used by any of the + * drm modules in the DRI cvs tree, but it is required + * by the Sparc driver. + */ #if __HAVE_KERNEL_CTX_SWITCH if ( dev->last_context != lock.context ) { DRM(context_switch)(dev, dev->last_context, @@ -1021,13 +1124,20 @@ DRM_DEBUG( "%d %s\n", lock.context, ret ? "interrupted" : "has lock" ); -#if __HAVE_DMA_HISTOGRAM - atomic_inc(&dev->histo.lacq[DRM(histogram_slot)(get_cycles()-start)]); -#endif return ret; } - +/** + * Unlock ioctl. + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg user argument, pointing to a drm_lock structure. + * \return zero on success or negative number on failure. + * + * Transfer and free the lock. + */ int DRM(unlock)( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ) { @@ -1046,12 +1156,16 @@ atomic_inc( &dev->counts[_DRM_STAT_UNLOCKS] ); + /* __HAVE_KERNEL_CTX_SWITCH isn't used by any of the drm + * modules in the DRI cvs tree, but it is required by the + * Sparc driver. + */ #if __HAVE_KERNEL_CTX_SWITCH /* We no longer really hold it, but if we are the next * agent to request it then we should just be able to * take it immediately and not eat the ioctl. */ - dev->lock.pid = 0; + dev->lock.filp = 0; { __volatile__ unsigned int *plock = &dev->lock.hw_lock->lock; unsigned int old, new, prev, ctx; @@ -1071,13 +1185,9 @@ DRM(dma_schedule)( dev, 1 ); #endif - /* FIXME: Do we ever really need to check this??? - */ - if ( 1 /* !dev->context_flag */ ) { - if ( DRM(lock_free)( dev, &dev->lock.hw_lock->lock, - DRM_KERNEL_CONTEXT ) ) { - DRM_ERROR( "\n" ); - } + if ( DRM(lock_free)( dev, &dev->lock.hw_lock->lock, + DRM_KERNEL_CONTEXT ) ) { + DRM_ERROR( "\n" ); } #endif /* !__HAVE_KERNEL_CTX_SWITCH */ diff -urN linux-2.4.23-pre8/drivers/char/drm/drm_fops.h linux-2.4.23-pre8-pac1/drivers/char/drm/drm_fops.h --- linux-2.4.23-pre8/drivers/char/drm/drm_fops.h 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/drm_fops.h 2003-08-18 12:56:12.000000000 +0200 @@ -1,4 +1,13 @@ -/* drm_fops.h -- File operations for DRM -*- linux-c -*- +/** + * \file drm_fops.h + * File operations for DRM + * + * \author Rickard E. (Rik) Faith + * \author Daryll Strauss + * \author Gareth Hughes + */ + +/* * Created: Mon Jan 4 08:58:31 1999 by faith@valinux.com * * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. @@ -23,18 +32,24 @@ * 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 - * Gareth Hughes */ +#define __NO_VERSION__ #include "drmP.h" #include -/* drm_open is called whenever a process opens /dev/drm. */ +/** + * Called whenever a process opens /dev/drm. + * + * \param inode device inode. + * \param filp file pointer. + * \param dev device. + * \return zero on success or a negative number on failure. + * + * Creates and initializes a drm_file structure for the file private data in \p + * filp and add it into the double linked list in \p dev. + */ int DRM(open_helper)(struct inode *inode, struct file *filp, drm_device_t *dev) { int minor = minor(inode->i_rdev); @@ -56,6 +71,7 @@ priv->dev = dev; priv->ioctl_count = 0; priv->authenticated = capable(CAP_SYS_ADMIN); + priv->lock_count = 0; down(&dev->struct_sem); if (!dev->file_last) { @@ -89,6 +105,7 @@ return 0; } +/** No-op. */ int DRM(flush)(struct file *filp) { drm_file_t *priv = filp->private_data; @@ -99,6 +116,7 @@ return 0; } +/** No-op. */ int DRM(fasync)(int fd, struct file *filp, int on) { drm_file_t *priv = filp->private_data; @@ -111,108 +129,19 @@ return 0; } - -/* The drm_read and drm_write_string code (especially that which manages - the circular buffer), is based on Alessandro Rubini's LINUX DEVICE - DRIVERS (Cambridge: O'Reilly, 1998), pages 111-113. */ - -ssize_t DRM(read)(struct file *filp, char *buf, size_t count, loff_t *off) -{ - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; - int left; - int avail; - int send; - int cur; - DECLARE_WAITQUEUE(wait, current); - - DRM_DEBUG("%p, %p\n", dev->buf_rp, dev->buf_wp); - - add_wait_queue(&dev->buf_readers, &wait); - set_current_state(TASK_INTERRUPTIBLE); - while (dev->buf_rp == dev->buf_wp) { - DRM_DEBUG(" sleeping\n"); - if (filp->f_flags & O_NONBLOCK) { - remove_wait_queue(&dev->buf_readers, &wait); - set_current_state(TASK_RUNNING); - return -EAGAIN; - } - schedule(); /* wait for dev->buf_readers */ - if (signal_pending(current)) { - DRM_DEBUG(" interrupted\n"); - remove_wait_queue(&dev->buf_readers, &wait); - set_current_state(TASK_RUNNING); - return -ERESTARTSYS; - } - DRM_DEBUG(" awake\n"); - set_current_state(TASK_INTERRUPTIBLE); - } - remove_wait_queue(&dev->buf_readers, &wait); - set_current_state(TASK_RUNNING); - - left = (dev->buf_rp + DRM_BSZ - dev->buf_wp) % DRM_BSZ; - avail = DRM_BSZ - left; - send = DRM_MIN(avail, count); - - while (send) { - if (dev->buf_wp > dev->buf_rp) { - cur = DRM_MIN(send, dev->buf_wp - dev->buf_rp); - } else { - cur = DRM_MIN(send, dev->buf_end - dev->buf_rp); - } - if (copy_to_user(buf, dev->buf_rp, cur)) - return -EFAULT; - dev->buf_rp += cur; - if (dev->buf_rp == dev->buf_end) dev->buf_rp = dev->buf; - send -= cur; - } - - wake_up_interruptible(&dev->buf_writers); - return DRM_MIN(avail, count);; -} - -int DRM(write_string)(drm_device_t *dev, const char *s) +#if !__HAVE_DRIVER_FOPS_POLL +/** No-op. */ +unsigned int DRM(poll)(struct file *filp, struct poll_table_struct *wait) { - int left = (dev->buf_rp + DRM_BSZ - dev->buf_wp) % DRM_BSZ; - int send = strlen(s); - int count; - - DRM_DEBUG("%d left, %d to send (%p, %p)\n", - left, send, dev->buf_rp, dev->buf_wp); - - if (left == 1 || dev->buf_wp != dev->buf_rp) { - DRM_ERROR("Buffer not empty (%d left, wp = %p, rp = %p)\n", - left, - dev->buf_wp, - dev->buf_rp); - } - - while (send) { - if (dev->buf_wp >= dev->buf_rp) { - count = DRM_MIN(send, dev->buf_end - dev->buf_wp); - if (count == left) --count; /* Leave a hole */ - } else { - count = DRM_MIN(send, dev->buf_rp - dev->buf_wp - 1); - } - strncpy(dev->buf_wp, s, count); - dev->buf_wp += count; - if (dev->buf_wp == dev->buf_end) dev->buf_wp = dev->buf; - send -= count; - } - - if (dev->buf_async) kill_fasync(&dev->buf_async, SIGIO, POLL_IN); - - DRM_DEBUG("waking\n"); - wake_up_interruptible(&dev->buf_readers); return 0; } +#endif -unsigned int DRM(poll)(struct file *filp, struct poll_table_struct *wait) -{ - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; - poll_wait(filp, &dev->buf_readers, wait); - if (dev->buf_wp != dev->buf_rp) return POLLIN | POLLRDNORM; +#if !__HAVE_DRIVER_FOPS_READ +/** No-op. */ +ssize_t DRM(read)(struct file *filp, char *buf, size_t count, loff_t *off) +{ return 0; } +#endif diff -urN linux-2.4.23-pre8/drivers/char/drm/drm_init.h linux-2.4.23-pre8-pac1/drivers/char/drm/drm_init.h --- linux-2.4.23-pre8/drivers/char/drm/drm_init.h 2002-11-29 00:53:12.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/drm_init.h 2003-08-18 12:56:12.000000000 +0200 @@ -1,4 +1,12 @@ -/* drm_init.h -- Setup/Cleanup for DRM -*- linux-c -*- +/** + * \file drm_init.h + * Setup/Cleanup for DRM + * + * \author Rickard E. (Rik) Faith + * \author Gareth Hughes + */ + +/* * Created: Mon Jan 4 08:58:31 1999 by faith@valinux.com * * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. @@ -23,22 +31,24 @@ * 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 - * Gareth Hughes */ +#define __NO_VERSION__ #include "drmP.h" +/** Debug flags. Set by parse_option(). */ #if 0 int DRM(flags) = DRM_FLAG_DEBUG; #else int DRM(flags) = 0; #endif -/* drm_parse_option parses a single option. See description for - * drm_parse_options for details. +/** + * Parse a single option. + * + * \param s option string. + * + * \sa See parse_options() for details. */ static void DRM(parse_option)(char *s) { @@ -49,11 +59,6 @@ for (c = s; *c && *c != ':'; c++); /* find : or \0 */ if (*c) r = c + 1; else r = NULL; /* remember remainder */ *c = '\0'; /* terminate */ - if (!strcmp(s, "noctx")) { - DRM(flags) |= DRM_FLAG_NOCTX; - DRM_INFO("Server-mediated context switching OFF\n"); - return; - } if (!strcmp(s, "debug")) { DRM(flags) |= DRM_FLAG_DEBUG; DRM_INFO("Debug messages ON\n"); @@ -63,26 +68,33 @@ return; } -/* drm_parse_options parse the insmod "drm_opts=" options, or the command-line - * options passed to the kernel via LILO. The grammar of the format is as +/** + * Parse the insmod "drm_opts=" options, or the command-line + * options passed to the kernel via LILO. + * + * \param s contains option_list without the 'drm_opts=' part. + * + * The grammar of the format is as * follows: * + * \code * drm ::= 'drm_opts=' option_list * option_list ::= option [ ';' option_list ] * option ::= 'device:' major * | 'debug' * | 'noctx' * major ::= INTEGER + * \endcode * - * Note that 's' contains option_list without the 'drm_opts=' part. - * - * device=major,minor specifies the device number used for /dev/drm - * if major == 0 then the misc device is used - * if major == 0 and minor == 0 then dynamic misc allocation is used - * debug=on specifies that debugging messages will be printk'd - * debug=trace specifies that each function call will be logged via printk - * debug=off turns off all debugging options + * - device=major,minor specifies the device number used for /dev/drm + * - if major == 0 then the misc device is used + * - if major == 0 and minor == 0 then dynamic misc allocation is used + * - debug=on specifies that debugging messages will be printk'd + * - debug=trace specifies that each function call will be logged via printk + * - debug=off turns off all debugging options * + * \todo Actually only the \e presence of the 'debug' option is currently + * checked. */ void DRM(parse_options)(char *s) @@ -100,8 +112,10 @@ } } -/* drm_cpu_valid returns non-zero if the DRI will run on this CPU, and 0 - * otherwise. +/** + * Check whether DRI will run on this CPU. + * + * \return non-zero if the DRI will run on this CPU, or zero otherwise. */ int DRM(cpu_valid)(void) { diff -urN linux-2.4.23-pre8/drivers/char/drm/drm_ioctl.h linux-2.4.23-pre8-pac1/drivers/char/drm/drm_ioctl.h --- linux-2.4.23-pre8/drivers/char/drm/drm_ioctl.h 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/drm_ioctl.h 2003-08-18 12:56:12.000000000 +0200 @@ -1,4 +1,12 @@ -/* drm_ioctl.h -- IOCTL processing for DRM -*- linux-c -*- +/** + * \file drm_ioctl.h + * IOCTL processing for DRM + * + * \author Rickard E. (Rik) Faith + * \author Gareth Hughes + */ + +/* * Created: Fri Jan 8 09:01:26 1999 by faith@valinux.com * * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. @@ -23,14 +31,23 @@ * 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 - * Gareth Hughes */ +#define __NO_VERSION__ #include "drmP.h" + +/** + * Get interrupt from bus id. + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg user argument, pointing to a drm_irq_busid structure. + * \return zero on success or a negative number on failure. + * + * Finds the PCI device with the specified bus id and gets its IRQ number. + */ int DRM(irq_busid)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { @@ -39,6 +56,28 @@ if (copy_from_user(&p, (drm_irq_busid_t *)arg, sizeof(p))) return -EFAULT; +#ifdef __alpha__ + { + int domain = p.busnum >> 8; + p.busnum &= 0xff; + + /* + * Find the hose the device is on (the domain number is the + * hose index) and offset the bus by the root bus of that + * hose. + */ + for(dev = pci_find_device(PCI_ANY_ID,PCI_ANY_ID,NULL); + dev; + dev = pci_find_device(PCI_ANY_ID,PCI_ANY_ID,dev)) { + struct pci_controller *hose = dev->sysdata; + + if (hose->index == domain) { + p.busnum += hose->bus->number; + break; + } + } + } +#endif dev = pci_find_slot(p.busnum, PCI_DEVFN(p.devnum, p.funcnum)); if (!dev) { DRM_ERROR("pci_find_slot failed for %d:%d:%d\n", @@ -61,6 +100,17 @@ return 0; } +/** + * Get the bus id. + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg user argument, pointing to a drm_unique structure. + * \return zero on success or a negative number on failure. + * + * Copies the bus id from drm_device::unique into user space. + */ int DRM(getunique)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { @@ -80,6 +130,18 @@ return 0; } +/** + * Set the bus id. + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg user argument, pointing to a drm_unique structure. + * \return zero on success or a negative number on failure. + * + * Copies the bus id from userspace into drm_device::unique, and searches for + * the respective PCI device, updating drm_device::pdev. + */ int DRM(setunique)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { @@ -157,6 +219,19 @@ } +/** + * Get a mapping information. + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg user argument, pointing to a drm_map structure. + * + * \return zero on success or a negative number on failure. + * + * Searches for the mapping with the specified offset and copies its information + * into userspace + */ int DRM(getmap)( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ) { @@ -173,7 +248,7 @@ idx = map.offset; down(&dev->struct_sem); - if (idx < 0 || idx >= dev->map_count) { + if (idx < 0) { up(&dev->struct_sem); return -EINVAL; } @@ -181,7 +256,7 @@ i = 0; list_for_each(list, &dev->maplist->head) { if(i == idx) { - r_list = (drm_map_list_t *)list; + r_list = list_entry(list, drm_map_list_t, head); break; } i++; @@ -203,6 +278,19 @@ return 0; } +/** + * Get client information. + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg user argument, pointing to a drm_client structure. + * + * \return zero on success or a negative number on failure. + * + * Searches for the client with the specified index and copies its information + * into userspace + */ int DRM(getclient)( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ) { @@ -236,6 +324,16 @@ return 0; } +/** + * Get statistics information. + * + * \param inode device inode. + * \param filp file pointer. + * \param cmd command. + * \param arg user argument, pointing to a drm_stats structure. + * + * \return zero on success or a negative number on failure. + */ int DRM(getstats)( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ) { diff -urN linux-2.4.23-pre8/drivers/char/drm/drm_lists.h linux-2.4.23-pre8-pac1/drivers/char/drm/drm_lists.h --- linux-2.4.23-pre8/drivers/char/drm/drm_lists.h 2003-06-13 16:51:32.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/drm_lists.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,229 +0,0 @@ -/* drm_lists.h -- Buffer list handling routines -*- linux-c -*- - * Created: Mon Apr 19 20:54:22 1999 by faith@valinux.com - * - * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. - * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * 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 - * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR - * 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 - * Gareth Hughes - */ - -#include "drmP.h" - -#if __HAVE_DMA_WAITLIST - -int DRM(waitlist_create)(drm_waitlist_t *bl, int count) -{ - if (bl->count) return -EINVAL; - - bl->bufs = DRM(alloc)((bl->count + 2) * sizeof(*bl->bufs), - DRM_MEM_BUFLISTS); - - if(!bl->bufs) return -ENOMEM; - memset(bl->bufs, 0, sizeof(*bl->bufs)); - bl->count = count; - bl->rp = bl->bufs; - bl->wp = bl->bufs; - bl->end = &bl->bufs[bl->count+1]; - bl->write_lock = SPIN_LOCK_UNLOCKED; - bl->read_lock = SPIN_LOCK_UNLOCKED; - return 0; -} - -int DRM(waitlist_destroy)(drm_waitlist_t *bl) -{ - if (bl->rp != bl->wp) return -EINVAL; - if (bl->bufs) DRM(free)(bl->bufs, - (bl->count + 2) * sizeof(*bl->bufs), - DRM_MEM_BUFLISTS); - bl->count = 0; - bl->bufs = NULL; - bl->rp = NULL; - bl->wp = NULL; - bl->end = NULL; - return 0; -} - -int DRM(waitlist_put)(drm_waitlist_t *bl, drm_buf_t *buf) -{ - int left; - unsigned long flags; - - left = DRM_LEFTCOUNT(bl); - if (!left) { - DRM_ERROR("Overflow while adding buffer %d from pid %d\n", - buf->idx, buf->pid); - return -EINVAL; - } -#if __HAVE_DMA_HISTOGRAM - buf->time_queued = get_cycles(); -#endif - buf->list = DRM_LIST_WAIT; - - spin_lock_irqsave(&bl->write_lock, flags); - *bl->wp = buf; - if (++bl->wp >= bl->end) bl->wp = bl->bufs; - spin_unlock_irqrestore(&bl->write_lock, flags); - - return 0; -} - -drm_buf_t *DRM(waitlist_get)(drm_waitlist_t *bl) -{ - drm_buf_t *buf; - unsigned long flags; - - spin_lock_irqsave(&bl->read_lock, flags); - buf = *bl->rp; - if (bl->rp == bl->wp) { - spin_unlock_irqrestore(&bl->read_lock, flags); - return NULL; - } - if (++bl->rp >= bl->end) bl->rp = bl->bufs; - spin_unlock_irqrestore(&bl->read_lock, flags); - - return buf; -} - -#endif /* __HAVE_DMA_WAITLIST */ - - -#if __HAVE_DMA_FREELIST - -int DRM(freelist_create)(drm_freelist_t *bl, int count) -{ - atomic_set(&bl->count, 0); - bl->next = NULL; - init_waitqueue_head(&bl->waiting); - bl->low_mark = 0; - bl->high_mark = 0; - atomic_set(&bl->wfh, 0); - bl->lock = SPIN_LOCK_UNLOCKED; - ++bl->initialized; - return 0; -} - -int DRM(freelist_destroy)(drm_freelist_t *bl) -{ - atomic_set(&bl->count, 0); - bl->next = NULL; - return 0; -} - -int DRM(freelist_put)(drm_device_t *dev, drm_freelist_t *bl, drm_buf_t *buf) -{ - drm_device_dma_t *dma = dev->dma; - - if (!dma) { - DRM_ERROR("No DMA support\n"); - return 1; - } - - if (buf->waiting || buf->pending || buf->list == DRM_LIST_FREE) { - DRM_ERROR("Freed buffer %d: w%d, p%d, l%d\n", - buf->idx, buf->waiting, buf->pending, buf->list); - } - if (!bl) return 1; -#if __HAVE_DMA_HISTOGRAM - buf->time_freed = get_cycles(); - DRM(histogram_compute)(dev, buf); -#endif - buf->list = DRM_LIST_FREE; - - spin_lock(&bl->lock); - buf->next = bl->next; - bl->next = buf; - spin_unlock(&bl->lock); - - atomic_inc(&bl->count); - if (atomic_read(&bl->count) > dma->buf_count) { - DRM_ERROR("%d of %d buffers free after addition of %d\n", - atomic_read(&bl->count), dma->buf_count, buf->idx); - return 1; - } - /* Check for high water mark */ - if (atomic_read(&bl->wfh) && atomic_read(&bl->count)>=bl->high_mark) { - atomic_set(&bl->wfh, 0); - wake_up_interruptible(&bl->waiting); - } - return 0; -} - -static drm_buf_t *DRM(freelist_try)(drm_freelist_t *bl) -{ - drm_buf_t *buf; - - if (!bl) return NULL; - - /* Get buffer */ - spin_lock(&bl->lock); - if (!bl->next) { - spin_unlock(&bl->lock); - return NULL; - } - buf = bl->next; - bl->next = bl->next->next; - spin_unlock(&bl->lock); - - atomic_dec(&bl->count); - buf->next = NULL; - buf->list = DRM_LIST_NONE; - 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); - } - - return buf; -} - -drm_buf_t *DRM(freelist_get)(drm_freelist_t *bl, int block) -{ - drm_buf_t *buf = NULL; - DECLARE_WAITQUEUE(entry, current); - - if (!bl || !bl->initialized) return NULL; - - /* Check for low water mark */ - if (atomic_read(&bl->count) <= bl->low_mark) /* Became low */ - atomic_set(&bl->wfh, 1); - if (atomic_read(&bl->wfh)) { - if (block) { - add_wait_queue(&bl->waiting, &entry); - for (;;) { - current->state = TASK_INTERRUPTIBLE; - if (!atomic_read(&bl->wfh) - && (buf = DRM(freelist_try)(bl))) break; - schedule(); - if (signal_pending(current)) break; - } - current->state = TASK_RUNNING; - remove_wait_queue(&bl->waiting, &entry); - } - return buf; - } - - return DRM(freelist_try)(bl); -} - -#endif /* __HAVE_DMA_FREELIST */ diff -urN linux-2.4.23-pre8/drivers/char/drm/drm_lock.h linux-2.4.23-pre8-pac1/drivers/char/drm/drm_lock.h --- linux-2.4.23-pre8/drivers/char/drm/drm_lock.h 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/drm_lock.h 2003-08-18 12:56:12.000000000 +0200 @@ -1,4 +1,12 @@ -/* lock.c -- IOCTLs for locking -*- linux-c -*- +/** + * \file drm_lock.h + * IOCTLs for locking + * + * \author Rickard E. (Rik) Faith + * \author Gareth Hughes + */ + +/* * Created: Tue Feb 2 08:37:54 1999 by faith@valinux.com * * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. @@ -23,28 +31,28 @@ * 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 - * Gareth Hughes */ +#define __NO_VERSION__ #include "drmP.h" -int DRM(block)(struct inode *inode, struct file *filp, unsigned int cmd, +/** No-op ioctl. */ +int DRM(noop)(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { DRM_DEBUG("\n"); return 0; } -int DRM(unblock)(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) -{ - DRM_DEBUG("\n"); - return 0; -} - +/** + * Take the heavyweight lock. + * + * \param lock lock pointer. + * \param context locking context. + * \return one if the lock is held, or zero otherwise. + * + * Attempt to mark the lock as held by the given context, via the \p cmpxchg instruction. + */ int DRM(lock_take)(__volatile__ unsigned int *lock, unsigned int context) { unsigned int old, new, prev; @@ -71,14 +79,24 @@ return 0; } -/* This takes a lock forcibly and hands it to context. Should ONLY be used - inside *_unlock to give lock to kernel before calling *_dma_schedule. */ +/** + * This takes a lock forcibly and hands it to context. Should ONLY be used + * inside *_unlock to give lock to kernel before calling *_dma_schedule. + * + * \param dev DRM device. + * \param lock lock pointer. + * \param context locking context. + * \return always one. + * + * Resets the lock file pointer. + * Marks the lock as held by the given context, via the \p cmpxchg instruction. + */ int DRM(lock_transfer)(drm_device_t *dev, __volatile__ unsigned int *lock, unsigned int context) { unsigned int old, new, prev; - dev->lock.pid = 0; + dev->lock.filp = 0; do { old = *lock; new = context | _DRM_LOCK_HELD; @@ -87,148 +105,49 @@ return 1; } +/** + * Free lock. + * + * \param dev DRM device. + * \param lock lock. + * \param context context. + * + * Resets the lock file pointer. + * Marks the lock as not held, via the \p cmpxchg instruction. Wakes any task + * waiting on the lock queue. + */ int DRM(lock_free)(drm_device_t *dev, __volatile__ unsigned int *lock, unsigned int context) { unsigned int old, new, prev; - pid_t pid = dev->lock.pid; - dev->lock.pid = 0; + dev->lock.filp = 0; do { old = *lock; new = 0; prev = cmpxchg(lock, old, new); } while (prev != old); if (_DRM_LOCK_IS_HELD(old) && _DRM_LOCKING_CONTEXT(old) != context) { - DRM_ERROR("%d freed heavyweight lock held by %d (pid %d)\n", + DRM_ERROR("%d freed heavyweight lock held by %d\n", context, - _DRM_LOCKING_CONTEXT(old), - pid); + _DRM_LOCKING_CONTEXT(old)); return 1; } wake_up_interruptible(&dev->lock.lock_queue); return 0; } -static int DRM(flush_queue)(drm_device_t *dev, int context) -{ - DECLARE_WAITQUEUE(entry, current); - int ret = 0; - drm_queue_t *q = dev->queuelist[context]; - - DRM_DEBUG("\n"); - - atomic_inc(&q->use_count); - if (atomic_read(&q->use_count) > 1) { - atomic_inc(&q->block_write); - 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)) { - ret = -EINTR; /* Can't restart */ - break; - } - } - atomic_dec(&q->block_count); - current->state = TASK_RUNNING; - remove_wait_queue(&q->flush_queue, &entry); - } - atomic_dec(&q->use_count); - - /* NOTE: block_write is still incremented! - Use drm_flush_unlock_queue to decrement. */ - return ret; -} - -static int DRM(flush_unblock_queue)(drm_device_t *dev, int context) -{ - drm_queue_t *q = dev->queuelist[context]; - - DRM_DEBUG("\n"); - - atomic_inc(&q->use_count); - if (atomic_read(&q->use_count) > 1) { - if (atomic_read(&q->block_write)) { - atomic_dec(&q->block_write); - wake_up_interruptible(&q->write_queue); - } - } - atomic_dec(&q->use_count); - return 0; -} - -int DRM(flush_block_and_flush)(drm_device_t *dev, int context, - drm_lock_flags_t flags) -{ - int ret = 0; - int i; - - DRM_DEBUG("\n"); - - if (flags & _DRM_LOCK_FLUSH) { - ret = DRM(flush_queue)(dev, DRM_KERNEL_CONTEXT); - if (!ret) ret = DRM(flush_queue)(dev, context); - } - if (flags & _DRM_LOCK_FLUSH_ALL) { - for (i = 0; !ret && i < dev->queue_count; i++) { - ret = DRM(flush_queue)(dev, i); - } - } - return ret; -} - -int DRM(flush_unblock)(drm_device_t *dev, int context, drm_lock_flags_t flags) -{ - int ret = 0; - int i; - - DRM_DEBUG("\n"); - - if (flags & _DRM_LOCK_FLUSH) { - ret = DRM(flush_unblock_queue)(dev, DRM_KERNEL_CONTEXT); - if (!ret) ret = DRM(flush_unblock_queue)(dev, context); - } - if (flags & _DRM_LOCK_FLUSH_ALL) { - for (i = 0; !ret && i < dev->queue_count; i++) { - ret = DRM(flush_unblock_queue)(dev, i); - } - } - - return ret; -} - -int DRM(finish)(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) -{ - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; - int ret = 0; - drm_lock_t lock; - - DRM_DEBUG("\n"); - - if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock))) - return -EFAULT; - ret = DRM(flush_block_and_flush)(dev, lock.context, lock.flags); - DRM(flush_unblock)(dev, lock.context, lock.flags); - return ret; -} - -/* If we get here, it means that the process has called DRM_IOCTL_LOCK - without calling DRM_IOCTL_UNLOCK. - - If the lock is not held, then let the signal proceed as usual. - - If the lock is held, then set the contended flag and keep the signal - blocked. - - - Return 1 if the signal should be delivered normally. - Return 0 if the signal should be blocked. */ - +/** + * If we get here, it means that the process has called DRM_IOCTL_LOCK + * without calling DRM_IOCTL_UNLOCK. + * + * If the lock is not held, then let the signal proceed as usual. If the lock + * is held, then set the contended flag and keep the signal blocked. + * + * \param priv pointer to a drm_sigdata structure. + * \return one if the signal should be delivered normally, or zero if the + * signal should be blocked. + */ int DRM(notifier)(void *priv) { drm_sigdata_t *s = (drm_sigdata_t *)priv; diff -urN linux-2.4.23-pre8/drivers/char/drm/drm_memory.h linux-2.4.23-pre8-pac1/drivers/char/drm/drm_memory.h --- linux-2.4.23-pre8/drivers/char/drm/drm_memory.h 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/drm_memory.h 2003-10-11 23:18:11.000000000 +0200 @@ -1,4 +1,12 @@ -/* drm_memory.h -- Memory management wrappers for DRM -*- linux-c -*- +/** + * \file drm_memory.h + * Memory management wrappers for DRM + * + * \author Rickard E. (Rik) Faith + * \author Gareth Hughes + */ + +/* * Created: Thu Feb 4 14:00:34 1999 by faith@valinux.com * * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. @@ -23,198 +31,241 @@ * 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 - * Gareth Hughes */ +#define __NO_VERSION__ #include #include "drmP.h" -#include -typedef struct drm_mem_stats { - const char *name; - int succeed_count; - int free_count; - int fail_count; - unsigned long bytes_allocated; - unsigned long bytes_freed; -} drm_mem_stats_t; - -static spinlock_t DRM(mem_lock) = SPIN_LOCK_UNLOCKED; -static unsigned long DRM(ram_available) = 0; /* In pages */ -static unsigned long DRM(ram_used) = 0; -static drm_mem_stats_t DRM(mem_stats)[] = { - [DRM_MEM_DMA] = { "dmabufs" }, - [DRM_MEM_SAREA] = { "sareas" }, - [DRM_MEM_DRIVER] = { "driver" }, - [DRM_MEM_MAGIC] = { "magic" }, - [DRM_MEM_IOCTLS] = { "ioctltab" }, - [DRM_MEM_MAPS] = { "maplist" }, - [DRM_MEM_VMAS] = { "vmalist" }, - [DRM_MEM_BUFS] = { "buflist" }, - [DRM_MEM_SEGS] = { "seglist" }, - [DRM_MEM_PAGES] = { "pagelist" }, - [DRM_MEM_FILES] = { "files" }, - [DRM_MEM_QUEUES] = { "queues" }, - [DRM_MEM_CMDS] = { "commands" }, - [DRM_MEM_MAPPINGS] = { "mappings" }, - [DRM_MEM_BUFLISTS] = { "buflists" }, - [DRM_MEM_AGPLISTS] = { "agplist" }, - [DRM_MEM_SGLISTS] = { "sglist" }, - [DRM_MEM_TOTALAGP] = { "totalagp" }, - [DRM_MEM_BOUNDAGP] = { "boundagp" }, - [DRM_MEM_CTXBITMAP] = { "ctxbitmap"}, - [DRM_MEM_STUB] = { "stub" }, - { NULL, 0, } /* Last entry must be null */ -}; +/** + * Cut down version of drm_memory_debug.h, which used to be called + * drm_memory.h. If you want the debug functionality, change 0 to 1 + * below. + */ +#define DEBUG_MEMORY 0 -void DRM(mem_init)(void) -{ - drm_mem_stats_t *mem; - struct sysinfo si; +/* Need the 4-argument version of vmap(). */ +#if __REALLY_HAVE_AGP && defined(VMAP_4_ARGS) + +#include - for (mem = DRM(mem_stats); mem->name; ++mem) { - mem->succeed_count = 0; - mem->free_count = 0; - mem->fail_count = 0; - mem->bytes_allocated = 0; - mem->bytes_freed = 0; +#ifdef HAVE_PAGE_AGP +#include +#else +# ifdef __powerpc__ +# define PAGE_AGP __pgprot(_PAGE_KERNEL | _PAGE_NO_CACHE) +# else +# define PAGE_AGP PAGE_KERNEL +# endif +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) +# define pte_offset_kernel(dir, address) pte_offset(dir, address) +# define pte_pfn(pte) (pte_page(pte) - mem_map) +# define pfn_to_page(pfn) (mem_map + (pfn)) +#endif + +/* + * Find the drm_map that covers the range [offset, offset+size). + */ +static inline drm_map_t * +drm_lookup_map (unsigned long offset, unsigned long size, drm_device_t *dev) +{ + struct list_head *list; + drm_map_list_t *r_list; + drm_map_t *map; + + list_for_each(list, &dev->maplist->head) { + r_list = (drm_map_list_t *) list; + map = r_list->map; + if (!map) + continue; + if (map->offset <= offset && (offset + size) <= (map->offset + map->size)) + return map; } + return NULL; +} - si_meminfo(&si); - DRM(ram_available) = si.totalram; - DRM(ram_used) = 0; +static inline void * +agp_remap (unsigned long offset, unsigned long size, drm_device_t *dev) +{ + unsigned long *phys_addr_map, i, num_pages = PAGE_ALIGN(size) / PAGE_SIZE; + struct drm_agp_mem *agpmem; + struct page **page_map; + void *addr; + + size = PAGE_ALIGN(size); + +#ifdef __alpha__ + offset -= dev->hose->mem_space->start; +#endif + + for (agpmem = dev->agp->memory; agpmem; agpmem = agpmem->next) + if (agpmem->bound <= offset + && (agpmem->bound + (agpmem->pages << PAGE_SHIFT)) >= (offset + size)) + break; + if (!agpmem) + return NULL; + + /* + * OK, we're mapping AGP space on a chipset/platform on which memory accesses by + * the CPU do not get remapped by the GART. We fix this by using the kernel's + * page-table instead (that's probably faster anyhow...). + */ + /* note: use vmalloc() because num_pages could be large... */ + page_map = vmalloc(num_pages * sizeof(struct page *)); + if (!page_map) + return NULL; + + phys_addr_map = agpmem->memory->memory + (offset - agpmem->bound) / PAGE_SIZE; + for (i = 0; i < num_pages; ++i) + page_map[i] = pfn_to_page(phys_addr_map[i] >> PAGE_SHIFT); + addr = vmap(page_map, num_pages, VM_IOREMAP, PAGE_AGP); + vfree(page_map); + + return addr; +} + +static inline unsigned long +drm_follow_page (void *vaddr) +{ + pgd_t *pgd = pgd_offset_k((unsigned long) vaddr); + pmd_t *pmd = pmd_offset(pgd, (unsigned long) vaddr); + pte_t *ptep = pte_offset_kernel(pmd, (unsigned long) vaddr); + return pte_pfn(*ptep) << PAGE_SHIFT; } -/* drm_mem_info is called whenever a process reads /dev/drm/mem. */ +#endif /* __REALLY_HAVE_AGP && defined(VMAP_4_ARGS) */ -static int DRM(_mem_info)(char *buf, char **start, off_t offset, - int request, int *eof, void *data) +static inline void *drm_ioremap(unsigned long offset, unsigned long size, drm_device_t *dev) { - drm_mem_stats_t *pt; - int len = 0; +#if __REALLY_HAVE_AGP && defined(VMAP_4_ARGS) + if (dev->agp && dev->agp->cant_use_aperture) { + drm_map_t *map = drm_lookup_map(offset, size, dev); - if (offset > DRM_PROC_LIMIT) { - *eof = 1; - return 0; + if (map && map->type == _DRM_AGP) + return agp_remap(offset, size, dev); } +#endif - *eof = 0; - *start = &buf[offset]; + return ioremap(offset, size); +} - DRM_PROC_PRINT(" total counts " - " | outstanding \n"); - DRM_PROC_PRINT("type alloc freed fail bytes freed" - " | allocs bytes\n\n"); - DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu kB |\n", - "system", 0, 0, 0, - DRM(ram_available) << (PAGE_SHIFT - 10)); - DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu kB |\n", - "locked", 0, 0, 0, DRM(ram_used) >> 10); - DRM_PROC_PRINT("\n"); - for (pt = DRM(mem_stats); pt->name; pt++) { - DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu %10lu | %6d %10ld\n", - pt->name, - pt->succeed_count, - pt->free_count, - pt->fail_count, - pt->bytes_allocated, - pt->bytes_freed, - pt->succeed_count - pt->free_count, - (long)pt->bytes_allocated - - (long)pt->bytes_freed); +static inline void *drm_ioremap_nocache(unsigned long offset, unsigned long size, + drm_device_t *dev) +{ +#if __REALLY_HAVE_AGP && defined(VMAP_4_ARGS) + if (dev->agp && dev->agp->cant_use_aperture) { + drm_map_t *map = drm_lookup_map(offset, size, dev); + + if (map && map->type == _DRM_AGP) + return agp_remap(offset, size, dev); + } +#endif + + return ioremap_nocache(offset, size); +} + +static inline void drm_ioremapfree(void *pt, unsigned long size, drm_device_t *dev) +{ +#if __REALLY_HAVE_AGP && defined(VMAP_4_ARGS) + /* + * This is a bit ugly. It would be much cleaner if the DRM API would use separate + * routines for handling mappings in the AGP space. Hopefully this can be done in + * a future revision of the interface... + */ + if (dev->agp && dev->agp->cant_use_aperture + && ((unsigned long) pt >= VMALLOC_START && (unsigned long) pt < VMALLOC_END)) + { + unsigned long offset; + drm_map_t *map; + + offset = drm_follow_page(pt) | ((unsigned long) pt & ~PAGE_MASK); + map = drm_lookup_map(offset, size, dev); + if (map && map->type == _DRM_AGP) { + vunmap(pt); + return; + } } +#endif + + iounmap(pt); +} - if (len > request + offset) return request; - *eof = 1; - return len - offset; +#if DEBUG_MEMORY +#include "drm_memory_debug.h" +#else + +/** No-op. */ +void DRM(mem_init)(void) +{ } +/** + * Called when "/proc/dri/%dev%/mem" is read. + * + * \param buf output buffer. + * \param start start of output data. + * \param offset requested start offset. + * \param len requested number of bytes. + * \param eof whether there is no more data to return. + * \param data private data. + * \return number of written bytes. + * + * No-op. + */ int DRM(mem_info)(char *buf, char **start, off_t offset, int len, int *eof, void *data) { - int ret; - - spin_lock(&DRM(mem_lock)); - ret = DRM(_mem_info)(buf, start, offset, len, eof, data); - spin_unlock(&DRM(mem_lock)); - return ret; + return 0; } +/** Wrapper around kmalloc() */ void *DRM(alloc)(size_t size, int area) { - void *pt; + return kmalloc(size, GFP_KERNEL); +} - if (!size) { - DRM_MEM_ERROR(area, "Allocating 0 bytes\n"); - return NULL; - } +/** Wrapper around kmalloc() */ +void *DRM(calloc)(size_t size, size_t nmemb, int area) +{ + void *addr; - if (!(pt = kmalloc(size, GFP_KERNEL))) { - spin_lock(&DRM(mem_lock)); - ++DRM(mem_stats)[area].fail_count; - spin_unlock(&DRM(mem_lock)); - return NULL; - } - spin_lock(&DRM(mem_lock)); - ++DRM(mem_stats)[area].succeed_count; - DRM(mem_stats)[area].bytes_allocated += size; - spin_unlock(&DRM(mem_lock)); - return pt; + addr = kmalloc(size * nmemb, GFP_KERNEL); + if (addr != NULL) + memset((void *)addr, 0, size * nmemb); + + return addr; } +/** Wrapper around kmalloc() and kfree() */ void *DRM(realloc)(void *oldpt, size_t oldsize, size_t size, int area) { void *pt; - if (!(pt = DRM(alloc)(size, area))) return NULL; + if (!(pt = kmalloc(size, GFP_KERNEL))) return NULL; if (oldpt && oldsize) { memcpy(pt, oldpt, oldsize); - DRM(free)(oldpt, oldsize, area); + kfree(oldpt); } return pt; } -char *DRM(strdup)(const char *s, int area) -{ - char *pt; - int length = s ? strlen(s) : 0; - - if (!(pt = DRM(alloc)(length+1, area))) return NULL; - strcpy(pt, s); - return pt; -} - -void DRM(strfree)(const char *s, int area) -{ - unsigned int size; - - if (!s) return; - - size = 1 + (s ? strlen(s) : 0); - DRM(free)((void *)s, size, area); -} - +/** Wrapper around kfree() */ void DRM(free)(void *pt, size_t size, int area) { - int alloc_count; - int free_count; - - if (!pt) DRM_MEM_ERROR(area, "Attempt to free NULL pointer\n"); - else kfree(pt); - spin_lock(&DRM(mem_lock)); - DRM(mem_stats)[area].bytes_freed += size; - free_count = ++DRM(mem_stats)[area].free_count; - alloc_count = DRM(mem_stats)[area].succeed_count; - spin_unlock(&DRM(mem_lock)); - if (free_count > alloc_count) { - DRM_MEM_ERROR(area, "Excess frees: %d frees, %d allocs\n", - free_count, alloc_count); - } + kfree(pt); } +/** + * Allocate pages. + * + * \param order size order. + * \param area memory area. (Not used.) + * \return page address on success, or zero on failure. + * + * Allocate and reserve free pages. + */ unsigned long DRM(alloc_pages)(int order, int area) { unsigned long address; @@ -222,245 +273,92 @@ unsigned long addr; unsigned int sz; - spin_lock(&DRM(mem_lock)); - if ((DRM(ram_used) >> PAGE_SHIFT) - > (DRM_RAM_PERCENT * DRM(ram_available)) / 100) { - spin_unlock(&DRM(mem_lock)); - return 0; - } - spin_unlock(&DRM(mem_lock)); - address = __get_free_pages(GFP_KERNEL, order); - if (!address) { - spin_lock(&DRM(mem_lock)); - ++DRM(mem_stats)[area].fail_count; - spin_unlock(&DRM(mem_lock)); + if (!address) return 0; - } - spin_lock(&DRM(mem_lock)); - ++DRM(mem_stats)[area].succeed_count; - DRM(mem_stats)[area].bytes_allocated += bytes; - DRM(ram_used) += bytes; - spin_unlock(&DRM(mem_lock)); - - /* Zero outside the lock */ + /* Zero */ memset((void *)address, 0, bytes); /* Reserve */ for (addr = address, sz = bytes; sz > 0; addr += PAGE_SIZE, sz -= PAGE_SIZE) { - mem_map_reserve(virt_to_page(addr)); + SetPageReserved(virt_to_page(addr)); } return address; } +/** + * Free pages. + * + * \param address address of the pages to free. + * \param order size order. + * \param area memory area. (Not used.) + * + * Unreserve and free pages allocated by alloc_pages(). + */ void DRM(free_pages)(unsigned long address, int order, int area) { unsigned long bytes = PAGE_SIZE << order; - int alloc_count; - int free_count; unsigned long addr; unsigned int sz; - if (!address) { - DRM_MEM_ERROR(area, "Attempt to free address 0\n"); - } else { - /* Unreserve */ - for (addr = address, sz = bytes; - sz > 0; - addr += PAGE_SIZE, sz -= PAGE_SIZE) { - mem_map_unreserve(virt_to_page(addr)); - } - free_pages(address, order); - } + if (!address) + return; - spin_lock(&DRM(mem_lock)); - free_count = ++DRM(mem_stats)[area].free_count; - alloc_count = DRM(mem_stats)[area].succeed_count; - DRM(mem_stats)[area].bytes_freed += bytes; - DRM(ram_used) -= bytes; - spin_unlock(&DRM(mem_lock)); - if (free_count > alloc_count) { - DRM_MEM_ERROR(area, - "Excess frees: %d frees, %d allocs\n", - free_count, alloc_count); + /* Unreserve */ + for (addr = address, sz = bytes; + sz > 0; + addr += PAGE_SIZE, sz -= PAGE_SIZE) { + ClearPageReserved(virt_to_page(addr)); } + + free_pages(address, order); } -void *DRM(ioremap)(unsigned long offset, unsigned long size) +/** Wrapper around drm_ioremap() */ +void *DRM(ioremap)(unsigned long offset, unsigned long size, drm_device_t *dev) { - void *pt; - - if (!size) { - DRM_MEM_ERROR(DRM_MEM_MAPPINGS, - "Mapping 0 bytes at 0x%08lx\n", offset); - return NULL; - } - - if (!(pt = ioremap(offset, size))) { - spin_lock(&DRM(mem_lock)); - ++DRM(mem_stats)[DRM_MEM_MAPPINGS].fail_count; - spin_unlock(&DRM(mem_lock)); - return NULL; - } - spin_lock(&DRM(mem_lock)); - ++DRM(mem_stats)[DRM_MEM_MAPPINGS].succeed_count; - DRM(mem_stats)[DRM_MEM_MAPPINGS].bytes_allocated += size; - spin_unlock(&DRM(mem_lock)); - return pt; + return drm_ioremap(offset, size, dev); } -void *DRM(ioremap_nocache)(unsigned long offset, unsigned long size) +/** Wrapper around drm_ioremap_nocache() */ +void *DRM(ioremap_nocache)(unsigned long offset, unsigned long size, drm_device_t *dev) { - void *pt; - - if (!size) { - DRM_MEM_ERROR(DRM_MEM_MAPPINGS, - "Mapping 0 bytes at 0x%08lx\n", offset); - return NULL; - } - - if (!(pt = ioremap_nocache(offset, size))) { - spin_lock(&DRM(mem_lock)); - ++DRM(mem_stats)[DRM_MEM_MAPPINGS].fail_count; - spin_unlock(&DRM(mem_lock)); - return NULL; - } - spin_lock(&DRM(mem_lock)); - ++DRM(mem_stats)[DRM_MEM_MAPPINGS].succeed_count; - DRM(mem_stats)[DRM_MEM_MAPPINGS].bytes_allocated += size; - spin_unlock(&DRM(mem_lock)); - return pt; + return drm_ioremap_nocache(offset, size, dev); } -void DRM(ioremapfree)(void *pt, unsigned long size) +/** Wrapper around drm_iounmap() */ +void DRM(ioremapfree)(void *pt, unsigned long size, drm_device_t *dev) { - int alloc_count; - int free_count; - - if (!pt) - DRM_MEM_ERROR(DRM_MEM_MAPPINGS, - "Attempt to free NULL pointer\n"); - else - iounmap(pt); - - spin_lock(&DRM(mem_lock)); - DRM(mem_stats)[DRM_MEM_MAPPINGS].bytes_freed += size; - free_count = ++DRM(mem_stats)[DRM_MEM_MAPPINGS].free_count; - alloc_count = DRM(mem_stats)[DRM_MEM_MAPPINGS].succeed_count; - spin_unlock(&DRM(mem_lock)); - if (free_count > alloc_count) { - DRM_MEM_ERROR(DRM_MEM_MAPPINGS, - "Excess frees: %d frees, %d allocs\n", - free_count, alloc_count); - } + drm_ioremapfree(pt, size, dev); } #if __REALLY_HAVE_AGP - -agp_memory *DRM(alloc_agp)(int pages, u32 type) +/** Wrapper around agp_allocate_memory() */ +DRM_AGP_MEM *DRM(alloc_agp)(int pages, u32 type) { - agp_memory *handle; - - if (!pages) { - DRM_MEM_ERROR(DRM_MEM_TOTALAGP, "Allocating 0 pages\n"); - return NULL; - } - - if ((handle = DRM(agp_allocate_memory)(pages, type))) { - spin_lock(&DRM(mem_lock)); - ++DRM(mem_stats)[DRM_MEM_TOTALAGP].succeed_count; - DRM(mem_stats)[DRM_MEM_TOTALAGP].bytes_allocated - += pages << PAGE_SHIFT; - spin_unlock(&DRM(mem_lock)); - return handle; - } - spin_lock(&DRM(mem_lock)); - ++DRM(mem_stats)[DRM_MEM_TOTALAGP].fail_count; - spin_unlock(&DRM(mem_lock)); - return NULL; + return DRM(agp_allocate_memory)(pages, type); } -int DRM(free_agp)(agp_memory *handle, int pages) +/** Wrapper around agp_free_memory() */ +int DRM(free_agp)(DRM_AGP_MEM *handle, int pages) { - int alloc_count; - int free_count; - int retval = -EINVAL; - - if (!handle) { - DRM_MEM_ERROR(DRM_MEM_TOTALAGP, - "Attempt to free NULL AGP handle\n"); - return retval;; - } - - if (DRM(agp_free_memory)(handle)) { - spin_lock(&DRM(mem_lock)); - free_count = ++DRM(mem_stats)[DRM_MEM_TOTALAGP].free_count; - alloc_count = DRM(mem_stats)[DRM_MEM_TOTALAGP].succeed_count; - DRM(mem_stats)[DRM_MEM_TOTALAGP].bytes_freed - += pages << PAGE_SHIFT; - spin_unlock(&DRM(mem_lock)); - if (free_count > alloc_count) { - DRM_MEM_ERROR(DRM_MEM_TOTALAGP, - "Excess frees: %d frees, %d allocs\n", - free_count, alloc_count); - } - return 0; - } - return retval; + return DRM(agp_free_memory)(handle) ? 0 : -EINVAL; } -int DRM(bind_agp)(agp_memory *handle, unsigned int start) +/** Wrapper around agp_bind_memory() */ +int DRM(bind_agp)(DRM_AGP_MEM *handle, unsigned int start) { - int retcode = -EINVAL; - - if (!handle) { - DRM_MEM_ERROR(DRM_MEM_BOUNDAGP, - "Attempt to bind NULL AGP handle\n"); - return retcode; - } - - if (!(retcode = DRM(agp_bind_memory)(handle, start))) { - spin_lock(&DRM(mem_lock)); - ++DRM(mem_stats)[DRM_MEM_BOUNDAGP].succeed_count; - DRM(mem_stats)[DRM_MEM_BOUNDAGP].bytes_allocated - += handle->page_count << PAGE_SHIFT; - spin_unlock(&DRM(mem_lock)); - return retcode; - } - spin_lock(&DRM(mem_lock)); - ++DRM(mem_stats)[DRM_MEM_BOUNDAGP].fail_count; - spin_unlock(&DRM(mem_lock)); - return retcode; -} - -int DRM(unbind_agp)(agp_memory *handle) -{ - int alloc_count; - int free_count; - int retcode = -EINVAL; - - if (!handle) { - DRM_MEM_ERROR(DRM_MEM_BOUNDAGP, - "Attempt to unbind NULL AGP handle\n"); - return retcode; - } + return DRM(agp_bind_memory)(handle, start); +} - if ((retcode = DRM(agp_unbind_memory)(handle))) return retcode; - spin_lock(&DRM(mem_lock)); - free_count = ++DRM(mem_stats)[DRM_MEM_BOUNDAGP].free_count; - alloc_count = DRM(mem_stats)[DRM_MEM_BOUNDAGP].succeed_count; - DRM(mem_stats)[DRM_MEM_BOUNDAGP].bytes_freed - += handle->page_count << PAGE_SHIFT; - spin_unlock(&DRM(mem_lock)); - if (free_count > alloc_count) { - DRM_MEM_ERROR(DRM_MEM_BOUNDAGP, - "Excess frees: %d frees, %d allocs\n", - free_count, alloc_count); - } - return retcode; +/** Wrapper around agp_unbind_memory() */ +int DRM(unbind_agp)(DRM_AGP_MEM *handle) +{ + return DRM(agp_unbind_memory)(handle); } -#endif +#endif /* agp */ +#endif /* debug_memory */ diff -urN linux-2.4.23-pre8/drivers/char/drm/drm_memory_debug.h linux-2.4.23-pre8-pac1/drivers/char/drm/drm_memory_debug.h --- linux-2.4.23-pre8/drivers/char/drm/drm_memory_debug.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/drm_memory_debug.h 2003-10-11 23:18:11.000000000 +0200 @@ -0,0 +1,459 @@ +/** + * \file drm_memory.h + * Memory management wrappers for DRM. + * + * \author Rickard E. (Rik) Faith + * \author Gareth Hughes + */ + +/* + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * 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 + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * 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. + */ + +#define __NO_VERSION__ +#include +#include "drmP.h" + +typedef struct drm_mem_stats { + const char *name; + int succeed_count; + int free_count; + int fail_count; + unsigned long bytes_allocated; + unsigned long bytes_freed; +} drm_mem_stats_t; + +static spinlock_t DRM(mem_lock) = SPIN_LOCK_UNLOCKED; +static unsigned long DRM(ram_available) = 0; /* In pages */ +static unsigned long DRM(ram_used) = 0; +static drm_mem_stats_t DRM(mem_stats)[] = { + [DRM_MEM_DMA] = { "dmabufs" }, + [DRM_MEM_SAREA] = { "sareas" }, + [DRM_MEM_DRIVER] = { "driver" }, + [DRM_MEM_MAGIC] = { "magic" }, + [DRM_MEM_IOCTLS] = { "ioctltab" }, + [DRM_MEM_MAPS] = { "maplist" }, + [DRM_MEM_VMAS] = { "vmalist" }, + [DRM_MEM_BUFS] = { "buflist" }, + [DRM_MEM_SEGS] = { "seglist" }, + [DRM_MEM_PAGES] = { "pagelist" }, + [DRM_MEM_FILES] = { "files" }, + [DRM_MEM_QUEUES] = { "queues" }, + [DRM_MEM_CMDS] = { "commands" }, + [DRM_MEM_MAPPINGS] = { "mappings" }, + [DRM_MEM_BUFLISTS] = { "buflists" }, + [DRM_MEM_AGPLISTS] = { "agplist" }, + [DRM_MEM_SGLISTS] = { "sglist" }, + [DRM_MEM_TOTALAGP] = { "totalagp" }, + [DRM_MEM_BOUNDAGP] = { "boundagp" }, + [DRM_MEM_CTXBITMAP] = { "ctxbitmap"}, + [DRM_MEM_STUB] = { "stub" }, + { NULL, 0, } /* Last entry must be null */ +}; + +void DRM(mem_init)(void) +{ + drm_mem_stats_t *mem; + struct sysinfo si; + + for (mem = DRM(mem_stats); mem->name; ++mem) { + mem->succeed_count = 0; + mem->free_count = 0; + mem->fail_count = 0; + mem->bytes_allocated = 0; + mem->bytes_freed = 0; + } + + si_meminfo(&si); + DRM(ram_available) = si.totalram; + DRM(ram_used) = 0; +} + +/* drm_mem_info is called whenever a process reads /dev/drm/mem. */ + +static int DRM(_mem_info)(char *buf, char **start, off_t offset, + int request, int *eof, void *data) +{ + drm_mem_stats_t *pt; + int len = 0; + + if (offset > DRM_PROC_LIMIT) { + *eof = 1; + return 0; + } + + *eof = 0; + *start = &buf[offset]; + + DRM_PROC_PRINT(" total counts " + " | outstanding \n"); + DRM_PROC_PRINT("type alloc freed fail bytes freed" + " | allocs bytes\n\n"); + DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu kB |\n", + "system", 0, 0, 0, + DRM(ram_available) << (PAGE_SHIFT - 10)); + DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu kB |\n", + "locked", 0, 0, 0, DRM(ram_used) >> 10); + DRM_PROC_PRINT("\n"); + for (pt = DRM(mem_stats); pt->name; pt++) { + DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu %10lu | %6d %10ld\n", + pt->name, + pt->succeed_count, + pt->free_count, + pt->fail_count, + pt->bytes_allocated, + pt->bytes_freed, + pt->succeed_count - pt->free_count, + (long)pt->bytes_allocated + - (long)pt->bytes_freed); + } + + if (len > request + offset) return request; + *eof = 1; + return len - offset; +} + +int DRM(mem_info)(char *buf, char **start, off_t offset, + int len, int *eof, void *data) +{ + int ret; + + spin_lock(&DRM(mem_lock)); + ret = DRM(_mem_info)(buf, start, offset, len, eof, data); + spin_unlock(&DRM(mem_lock)); + return ret; +} + +void *DRM(alloc)(size_t size, int area) +{ + void *pt; + + if (!size) { + DRM_MEM_ERROR(area, "Allocating 0 bytes\n"); + return NULL; + } + + if (!(pt = kmalloc(size, GFP_KERNEL))) { + spin_lock(&DRM(mem_lock)); + ++DRM(mem_stats)[area].fail_count; + spin_unlock(&DRM(mem_lock)); + return NULL; + } + spin_lock(&DRM(mem_lock)); + ++DRM(mem_stats)[area].succeed_count; + DRM(mem_stats)[area].bytes_allocated += size; + spin_unlock(&DRM(mem_lock)); + return pt; +} + +void *DRM(calloc)(size_t size, size_t nmemb, int area) +{ + void *addr; + + addr = DRM(alloc)(nmemb * size, area); + if (addr != NULL) + memset((void *)addr, 0, size * nmemb); + + return addr; +} + +void *DRM(realloc)(void *oldpt, size_t oldsize, size_t size, int area) +{ + void *pt; + + if (!(pt = DRM(alloc)(size, area))) return NULL; + if (oldpt && oldsize) { + memcpy(pt, oldpt, oldsize); + DRM(free)(oldpt, oldsize, area); + } + return pt; +} + +void DRM(free)(void *pt, size_t size, int area) +{ + int alloc_count; + int free_count; + + if (!pt) DRM_MEM_ERROR(area, "Attempt to free NULL pointer\n"); + else kfree(pt); + spin_lock(&DRM(mem_lock)); + DRM(mem_stats)[area].bytes_freed += size; + free_count = ++DRM(mem_stats)[area].free_count; + alloc_count = DRM(mem_stats)[area].succeed_count; + spin_unlock(&DRM(mem_lock)); + if (free_count > alloc_count) { + DRM_MEM_ERROR(area, "Excess frees: %d frees, %d allocs\n", + free_count, alloc_count); + } +} + +unsigned long DRM(alloc_pages)(int order, int area) +{ + unsigned long address; + unsigned long bytes = PAGE_SIZE << order; + unsigned long addr; + unsigned int sz; + + spin_lock(&DRM(mem_lock)); + if ((DRM(ram_used) >> PAGE_SHIFT) + > (DRM_RAM_PERCENT * DRM(ram_available)) / 100) { + spin_unlock(&DRM(mem_lock)); + return 0; + } + spin_unlock(&DRM(mem_lock)); + + address = __get_free_pages(GFP_KERNEL, order); + if (!address) { + spin_lock(&DRM(mem_lock)); + ++DRM(mem_stats)[area].fail_count; + spin_unlock(&DRM(mem_lock)); + return 0; + } + spin_lock(&DRM(mem_lock)); + ++DRM(mem_stats)[area].succeed_count; + DRM(mem_stats)[area].bytes_allocated += bytes; + DRM(ram_used) += bytes; + spin_unlock(&DRM(mem_lock)); + + + /* Zero outside the lock */ + memset((void *)address, 0, bytes); + + /* Reserve */ + for (addr = address, sz = bytes; + sz > 0; + addr += PAGE_SIZE, sz -= PAGE_SIZE) { + SetPageReserved(virt_to_page(addr)); + } + + return address; +} + +void DRM(free_pages)(unsigned long address, int order, int area) +{ + unsigned long bytes = PAGE_SIZE << order; + int alloc_count; + int free_count; + unsigned long addr; + unsigned int sz; + + if (!address) { + DRM_MEM_ERROR(area, "Attempt to free address 0\n"); + } else { + /* Unreserve */ + for (addr = address, sz = bytes; + sz > 0; + addr += PAGE_SIZE, sz -= PAGE_SIZE) { + ClearPageReserved(virt_to_page(addr)); + } + free_pages(address, order); + } + + spin_lock(&DRM(mem_lock)); + free_count = ++DRM(mem_stats)[area].free_count; + alloc_count = DRM(mem_stats)[area].succeed_count; + DRM(mem_stats)[area].bytes_freed += bytes; + DRM(ram_used) -= bytes; + spin_unlock(&DRM(mem_lock)); + if (free_count > alloc_count) { + DRM_MEM_ERROR(area, + "Excess frees: %d frees, %d allocs\n", + free_count, alloc_count); + } +} + +void *DRM(ioremap)(unsigned long offset, unsigned long size, drm_device_t *dev) +{ + void *pt; + + if (!size) { + DRM_MEM_ERROR(DRM_MEM_MAPPINGS, + "Mapping 0 bytes at 0x%08lx\n", offset); + return NULL; + } + + if (!(pt = drm_ioremap(offset, size, dev))) { + spin_lock(&DRM(mem_lock)); + ++DRM(mem_stats)[DRM_MEM_MAPPINGS].fail_count; + spin_unlock(&DRM(mem_lock)); + return NULL; + } + spin_lock(&DRM(mem_lock)); + ++DRM(mem_stats)[DRM_MEM_MAPPINGS].succeed_count; + DRM(mem_stats)[DRM_MEM_MAPPINGS].bytes_allocated += size; + spin_unlock(&DRM(mem_lock)); + return pt; +} + +void *DRM(ioremap_nocache)(unsigned long offset, unsigned long size, drm_device_t *dev) +{ + void *pt; + + if (!size) { + DRM_MEM_ERROR(DRM_MEM_MAPPINGS, + "Mapping 0 bytes at 0x%08lx\n", offset); + return NULL; + } + + if (!(pt = drm_ioremap_nocache(offset, size, dev))) { + spin_lock(&DRM(mem_lock)); + ++DRM(mem_stats)[DRM_MEM_MAPPINGS].fail_count; + spin_unlock(&DRM(mem_lock)); + return NULL; + } + spin_lock(&DRM(mem_lock)); + ++DRM(mem_stats)[DRM_MEM_MAPPINGS].succeed_count; + DRM(mem_stats)[DRM_MEM_MAPPINGS].bytes_allocated += size; + spin_unlock(&DRM(mem_lock)); + return pt; +} + +void DRM(ioremapfree)(void *pt, unsigned long size, drm_device_t *dev) +{ + int alloc_count; + int free_count; + + if (!pt) + DRM_MEM_ERROR(DRM_MEM_MAPPINGS, + "Attempt to free NULL pointer\n"); + else + drm_ioremapfree(pt, size, dev); + + spin_lock(&DRM(mem_lock)); + DRM(mem_stats)[DRM_MEM_MAPPINGS].bytes_freed += size; + free_count = ++DRM(mem_stats)[DRM_MEM_MAPPINGS].free_count; + alloc_count = DRM(mem_stats)[DRM_MEM_MAPPINGS].succeed_count; + spin_unlock(&DRM(mem_lock)); + if (free_count > alloc_count) { + DRM_MEM_ERROR(DRM_MEM_MAPPINGS, + "Excess frees: %d frees, %d allocs\n", + free_count, alloc_count); + } +} + +#if __REALLY_HAVE_AGP + +DRM_AGP_MEM *DRM(alloc_agp)(int pages, u32 type) +{ + DRM_AGP_MEM *handle; + + if (!pages) { + DRM_MEM_ERROR(DRM_MEM_TOTALAGP, "Allocating 0 pages\n"); + return NULL; + } + + if ((handle = DRM(agp_allocate_memory)(pages, type))) { + spin_lock(&DRM(mem_lock)); + ++DRM(mem_stats)[DRM_MEM_TOTALAGP].succeed_count; + DRM(mem_stats)[DRM_MEM_TOTALAGP].bytes_allocated + += pages << PAGE_SHIFT; + spin_unlock(&DRM(mem_lock)); + return handle; + } + spin_lock(&DRM(mem_lock)); + ++DRM(mem_stats)[DRM_MEM_TOTALAGP].fail_count; + spin_unlock(&DRM(mem_lock)); + return NULL; +} + +int DRM(free_agp)(DRM_AGP_MEM *handle, int pages) +{ + int alloc_count; + int free_count; + int retval = -EINVAL; + + if (!handle) { + DRM_MEM_ERROR(DRM_MEM_TOTALAGP, + "Attempt to free NULL AGP handle\n"); + return retval;; + } + + if (DRM(agp_free_memory)(handle)) { + spin_lock(&DRM(mem_lock)); + free_count = ++DRM(mem_stats)[DRM_MEM_TOTALAGP].free_count; + alloc_count = DRM(mem_stats)[DRM_MEM_TOTALAGP].succeed_count; + DRM(mem_stats)[DRM_MEM_TOTALAGP].bytes_freed + += pages << PAGE_SHIFT; + spin_unlock(&DRM(mem_lock)); + if (free_count > alloc_count) { + DRM_MEM_ERROR(DRM_MEM_TOTALAGP, + "Excess frees: %d frees, %d allocs\n", + free_count, alloc_count); + } + return 0; + } + return retval; +} + +int DRM(bind_agp)(DRM_AGP_MEM *handle, unsigned int start) +{ + int retcode = -EINVAL; + + if (!handle) { + DRM_MEM_ERROR(DRM_MEM_BOUNDAGP, + "Attempt to bind NULL AGP handle\n"); + return retcode; + } + + if (!(retcode = DRM(agp_bind_memory)(handle, start))) { + spin_lock(&DRM(mem_lock)); + ++DRM(mem_stats)[DRM_MEM_BOUNDAGP].succeed_count; + DRM(mem_stats)[DRM_MEM_BOUNDAGP].bytes_allocated + += handle->page_count << PAGE_SHIFT; + spin_unlock(&DRM(mem_lock)); + return retcode; + } + spin_lock(&DRM(mem_lock)); + ++DRM(mem_stats)[DRM_MEM_BOUNDAGP].fail_count; + spin_unlock(&DRM(mem_lock)); + return retcode; +} + +int DRM(unbind_agp)(DRM_AGP_MEM *handle) +{ + int alloc_count; + int free_count; + int retcode = -EINVAL; + + if (!handle) { + DRM_MEM_ERROR(DRM_MEM_BOUNDAGP, + "Attempt to unbind NULL AGP handle\n"); + return retcode; + } + + if ((retcode = DRM(agp_unbind_memory)(handle))) return retcode; + spin_lock(&DRM(mem_lock)); + free_count = ++DRM(mem_stats)[DRM_MEM_BOUNDAGP].free_count; + alloc_count = DRM(mem_stats)[DRM_MEM_BOUNDAGP].succeed_count; + DRM(mem_stats)[DRM_MEM_BOUNDAGP].bytes_freed + += handle->page_count << PAGE_SHIFT; + spin_unlock(&DRM(mem_lock)); + if (free_count > alloc_count) { + DRM_MEM_ERROR(DRM_MEM_BOUNDAGP, + "Excess frees: %d frees, %d allocs\n", + free_count, alloc_count); + } + return retcode; +} +#endif diff -urN linux-2.4.23-pre8/drivers/char/drm/drm_os_linux.h linux-2.4.23-pre8-pac1/drivers/char/drm/drm_os_linux.h --- linux-2.4.23-pre8/drivers/char/drm/drm_os_linux.h 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/drm_os_linux.h 2003-08-18 12:56:12.000000000 +0200 @@ -1,24 +1,97 @@ +/** + * \file drm_os_linux.h + * OS abstraction macros. + */ + #define __NO_VERSION__ #include /* For task queue support */ #include +/** File pointer type */ +#define DRMFILE struct file * +/** Ioctl arguments */ +#define DRM_IOCTL_ARGS struct inode *inode, struct file *filp, unsigned int cmd, unsigned long data +#define DRM_ERR(d) -(d) +/** Current process ID */ +#define DRM_CURRENTPID current->pid +#define DRM_UDELAY(d) udelay(d) +/** Read a byte from a MMIO region */ +#define DRM_READ8(map, offset) readb(((unsigned long)(map)->handle) + (offset)) +/** Read a dword from a MMIO region */ +#define DRM_READ32(map, offset) readl(((unsigned long)(map)->handle) + (offset)) +/** Write a byte into a MMIO region */ +#define DRM_WRITE8(map, offset, val) writeb(val, ((unsigned long)(map)->handle) + (offset)) +/** Write a dword into a MMIO region */ +#define DRM_WRITE32(map, offset, val) writel(val, ((unsigned long)(map)->handle) + (offset)) +/** Read memory barrier */ +#define DRM_READMEMORYBARRIER() rmb() +/** Write memory barrier */ +#define DRM_WRITEMEMORYBARRIER() wmb() +/** Read/write memory barrier */ +#define DRM_MEMORYBARRIER() mb() +/** DRM device local declaration */ +#define DRM_DEVICE drm_file_t *priv = filp->private_data; \ + drm_device_t *dev = priv->dev + +/** IRQ handler arguments and return type and values */ +#define DRM_IRQ_ARGS int irq, void *arg, struct pt_regs *regs +/** backwards compatibility with old irq return values */ +#ifndef IRQ_HANDLED +typedef void irqreturn_t; +#define IRQ_HANDLED /* nothing */ +#define IRQ_NONE /* nothing */ +#endif + +/** AGP types */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,70) +#define DRM_AGP_MEM agp_memory +#define DRM_AGP_KERN agp_kern_info +#else +#define DRM_AGP_MEM struct agp_memory +#define DRM_AGP_KERN struct agp_kern_info +#endif + +/** Task queue handler arguments */ +#define DRM_TASKQUEUE_ARGS void *arg -/* For data going from/to the kernel through the ioctl argument */ +/** For data going into the kernel through the ioctl argument */ #define DRM_COPY_FROM_USER_IOCTL(arg1, arg2, arg3) \ if ( copy_from_user(&arg1, arg2, arg3) ) \ return -EFAULT +/** For data going from the kernel through the ioctl argument */ #define DRM_COPY_TO_USER_IOCTL(arg1, arg2, arg3) \ if ( copy_to_user(arg1, &arg2, arg3) ) \ return -EFAULT - - -#warning the author of this code needs to read up on list_entry +/** Other copying of data to kernel space */ +#define DRM_COPY_FROM_USER(arg1, arg2, arg3) \ + copy_from_user(arg1, arg2, arg3) +/** Other copying of data from kernel space */ +#define DRM_COPY_TO_USER(arg1, arg2, arg3) \ + copy_to_user(arg1, arg2, arg3) +/* Macros for copyfrom user, but checking readability only once */ +#define DRM_VERIFYAREA_READ( uaddr, size ) \ + verify_area( VERIFY_READ, uaddr, size ) +#define DRM_COPY_FROM_USER_UNCHECKED(arg1, arg2, arg3) \ + __copy_from_user(arg1, arg2, arg3) +#define DRM_GET_USER_UNCHECKED(val, uaddr) \ + __get_user(val, uaddr) + + +/** 'malloc' without the overhead of DRM(alloc)() */ +#define DRM_MALLOC(x) kmalloc(x, GFP_KERNEL) +/** 'free' without the overhead of DRM(free)() */ +#define DRM_FREE(x,size) kfree(x) + +/** + * Get the pointer to the SAREA. + * + * Searches the SAREA on the mapping lists and points drm_device::sarea to it. + */ #define DRM_GETSAREA() \ do { \ - struct list_head *list; \ - list_for_each( list, &dev->maplist->head ) { \ - drm_map_list_t *entry = (drm_map_list_t *)list; \ + drm_map_list_t *entry; \ + list_for_each_entry( entry, &dev->maplist->head, head ) { \ if ( entry->map && \ entry->map->type == _DRM_SHM && \ (entry->map->flags & _DRM_CONTAINS_LOCK) ) { \ @@ -28,29 +101,33 @@ } \ } while (0) -#define DRM_WAIT_ON( ret, queue, timeout, condition ) \ -do { \ - DECLARE_WAITQUEUE(entry, current); \ - unsigned long end = jiffies + (timeout); \ - add_wait_queue(&(queue), &entry); \ - \ - for (;;) { \ - set_current_state(TASK_INTERRUPTIBLE); \ - if (condition) \ - break; \ - if((signed)(end - jiffies) <= 0) { \ - ret = -EBUSY; \ - break; \ - } \ +#define DRM_HZ HZ + +#define DRM_WAIT_ON( ret, queue, timeout, condition ) \ +do { \ + DECLARE_WAITQUEUE(entry, current); \ + unsigned long end = jiffies + (timeout); \ + add_wait_queue(&(queue), &entry); \ + \ + for (;;) { \ + current->state = TASK_INTERRUPTIBLE; \ + if (condition) \ + break; \ + if (time_after_eq(jiffies, end)) { \ + ret = -EBUSY; \ + break; \ + } \ schedule_timeout((HZ/100 > 1) ? HZ/100 : 1); \ - if (signal_pending(current)) { \ - ret = -EINTR; \ - break; \ - } \ - } \ - set_current_state(TASK_RUNNING); \ - remove_wait_queue(&(queue), &entry); \ + if (signal_pending(current)) { \ + ret = -EINTR; \ + break; \ + } \ + } \ + current->state = TASK_RUNNING; \ + remove_wait_queue(&(queue), &entry); \ } while (0) +#define DRM_WAKEUP( queue ) wake_up_interruptible( queue ) +#define DRM_INIT_WAITQUEUE( queue ) init_waitqueue_head( queue ) diff -urN linux-2.4.23-pre8/drivers/char/drm/drm_proc.h linux-2.4.23-pre8-pac1/drivers/char/drm/drm_proc.h --- linux-2.4.23-pre8/drivers/char/drm/drm_proc.h 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/drm_proc.h 2003-08-18 12:56:12.000000000 +0200 @@ -1,4 +1,16 @@ -/* drm_proc.h -- /proc support for DRM -*- linux-c -*- +/** + * \file drm_proc.h + * /proc support for DRM + * + * \author Rickard E. (Rik) Faith + * \author Gareth Hughes + * + * \par Acknowledgements: + * Matthew J Sottek sent in a patch to fix + * the problem with the proc files not outputting all their information. + */ + +/* * Created: Mon Jan 11 09:48:47 1999 by faith@valinux.com * * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. @@ -23,16 +35,9 @@ * 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 - * Gareth Hughes - * - * Acknowledgements: - * Matthew J Sottek sent in a patch to fix - * the problem with the proc files not outputting all their information. */ +#define __NO_VERSION__ #include "drmP.h" static int DRM(name_info)(char *buf, char **start, off_t offset, @@ -49,14 +54,13 @@ static int DRM(vma_info)(char *buf, char **start, off_t offset, int request, int *eof, void *data); #endif -#if __HAVE_DMA_HISTOGRAM -static int DRM(histo_info)(char *buf, char **start, off_t offset, - int request, int *eof, void *data); -#endif +/** + * Proc file list. + */ struct drm_proc_list { - const char *name; - int (*f)(char *, char **, off_t, int, int *, void *); + const char *name; /**< file name */ + int (*f)(char *, char **, off_t, int, int *, void *); /**< proc callback*/ } DRM(proc_list)[] = { { "name", DRM(name_info) }, { "mem", DRM(mem_info) }, @@ -67,12 +71,22 @@ #if DRM_DEBUG_CODE { "vma", DRM(vma_info) }, #endif -#if __HAVE_DMA_HISTOGRAM - { "histo", DRM(histo_info) }, -#endif }; #define DRM_PROC_ENTRIES (sizeof(DRM(proc_list))/sizeof(DRM(proc_list)[0])) +/** + * Initialize the DRI proc filesystem for a device. + * + * \param dev DRM device. + * \param minor device minor number. + * \param root DRI proc dir entry. + * \param dev_root resulting DRI device proc dir entry. + * \return root entry pointer on success, or NULL on failure. + * + * Create the DRI proc root entry "/proc/dri", the device proc root entry + * "/proc/dri/%minor%/", and each entry in proc_list as + * "/proc/dri/%minor%/%name%". + */ struct proc_dir_entry *DRM(proc_init)(drm_device_t *dev, int minor, struct proc_dir_entry *root, struct proc_dir_entry **dev_root) @@ -90,7 +104,7 @@ sprintf(name, "%d", minor); *dev_root = create_proc_entry(name, S_IFDIR, root); if (!*dev_root) { - DRM_ERROR("Cannot create /proc/%s\n", name); + DRM_ERROR("Cannot create /proc/dri/%s\n", name); return NULL; } @@ -115,6 +129,16 @@ } +/** + * Cleanup the proc filesystem resources. + * + * \param minor device minor number. + * \param root DRI proc dir entry. + * \param dev_root DRI device proc dir entry. + * \return always zero. + * + * Remove all proc entries created by proc_init(). + */ int DRM(proc_cleanup)(int minor, struct proc_dir_entry *root, struct proc_dir_entry *dev_root) { @@ -132,6 +156,19 @@ return 0; } +/** + * Called when "/proc/dri/.../name" is read. + * + * \param buf output buffer. + * \param start start of output data. + * \param offset requested start offset. + * \param request requested number of bytes. + * \param eof whether there is no more data to return. + * \param data private data. + * \return number of written bytes. + * + * Prints the device name together with the bus id if available. + */ static int DRM(name_info)(char *buf, char **start, off_t offset, int request, int *eof, void *data) { @@ -158,6 +195,19 @@ return len - offset; } +/** + * Called when "/proc/dri/.../vm" is read. + * + * \param buf output buffer. + * \param start start of output data. + * \param offset requested start offset. + * \param request requested number of bytes. + * \param eof whether there is no more data to return. + * \param data private data. + * \return number of written bytes. + * + * Prints information about all mappings in drm_device::maplist. + */ static int DRM(_vm_info)(char *buf, char **start, off_t offset, int request, int *eof, void *data) { @@ -168,9 +218,9 @@ struct list_head *list; /* Hardcoded from _DRM_FRAME_BUFFER, - _DRM_REGISTERS, _DRM_SHM, and - _DRM_AGP. */ - const char *types[] = { "FB", "REG", "SHM", "AGP" }; + _DRM_REGISTERS, _DRM_SHM, _DRM_AGP, and + _DRM_SCATTER_GATHER. */ + const char *types[] = { "FB", "REG", "SHM", "AGP", "SG" }; const char *type; int i; @@ -186,10 +236,10 @@ "address mtrr\n\n"); i = 0; if (dev->maplist != NULL) list_for_each(list, &dev->maplist->head) { - r_list = (drm_map_list_t *)list; + r_list = list_entry(list, drm_map_list_t, head); map = r_list->map; if(!map) continue; - if (map->type < 0 || map->type > 3) type = "??"; + if (map->type < 0 || map->type > 4) type = "??"; else type = types[map->type]; DRM_PROC_PRINT("%4d 0x%08lx 0x%08lx %4.4s 0x%02x 0x%08lx ", i, @@ -211,6 +261,9 @@ return len - offset; } +/** + * Simply calls _vm_info() while holding the drm_device::struct_sem lock. + */ static int DRM(vm_info)(char *buf, char **start, off_t offset, int request, int *eof, void *data) { @@ -223,7 +276,17 @@ return ret; } - +/** + * Called when "/proc/dri/.../queues" is read. + * + * \param buf output buffer. + * \param start start of output data. + * \param offset requested start offset. + * \param request requested number of bytes. + * \param eof whether there is no more data to return. + * \param data private data. + * \return number of written bytes. + */ static int DRM(_queues_info)(char *buf, char **start, off_t offset, int request, int *eof, void *data) { @@ -268,6 +331,9 @@ return len - offset; } +/** + * Simply calls _queues_info() while holding the drm_device::struct_sem lock. + */ static int DRM(queues_info)(char *buf, char **start, off_t offset, int request, int *eof, void *data) { @@ -280,9 +346,17 @@ return ret; } -/* drm_bufs_info is called whenever a process reads - /dev/dri//bufs. */ - +/** + * Called when "/proc/dri/.../bufs" is read. + * + * \param buf output buffer. + * \param start start of output data. + * \param offset requested start offset. + * \param request requested number of bytes. + * \param eof whether there is no more data to return. + * \param data private data. + * \return number of written bytes. + */ static int DRM(_bufs_info)(char *buf, char **start, off_t offset, int request, int *eof, void *data) { @@ -327,6 +401,9 @@ return len - offset; } +/** + * Simply calls _bufs_info() while holding the drm_device::struct_sem lock. + */ static int DRM(bufs_info)(char *buf, char **start, off_t offset, int request, int *eof, void *data) { @@ -339,7 +416,17 @@ return ret; } - +/** + * Called when "/proc/dri/.../clients" is read. + * + * \param buf output buffer. + * \param start start of output data. + * \param offset requested start offset. + * \param request requested number of bytes. + * \param eof whether there is no more data to return. + * \param data private data. + * \return number of written bytes. + */ static int DRM(_clients_info)(char *buf, char **start, off_t offset, int request, int *eof, void *data) { @@ -371,6 +458,9 @@ return len - offset; } +/** + * Simply calls _clients_info() while holding the drm_device::struct_sem lock. + */ static int DRM(clients_info)(char *buf, char **start, off_t offset, int request, int *eof, void *data) { @@ -385,8 +475,6 @@ #if DRM_DEBUG_CODE -#define DRM_VMA_VERBOSE 0 - static int DRM(_vma_info)(char *buf, char **start, off_t offset, int request, int *eof, void *data) { @@ -394,13 +482,6 @@ int len = 0; drm_vma_entry_t *pt; struct vm_area_struct *vma; -#if DRM_VMA_VERBOSE - unsigned long i; - unsigned long address; - pgd_t *pgd; - pmd_t *pmd; - pte_t *pte; -#endif #if defined(__i386__) unsigned int pgprot; #endif @@ -444,28 +525,6 @@ pgprot & _PAGE_GLOBAL ? 'g' : 'l' ); #endif DRM_PROC_PRINT("\n"); -#if 0 - for (i = vma->vm_start; i < vma->vm_end; i += PAGE_SIZE) { - pgd = pgd_offset(vma->vm_mm, i); - pmd = pmd_offset(pgd, i); - pte = pte_offset(pmd, i); - if (pte_present(*pte)) { - address = __pa(pte_page(*pte)) - + (i & (PAGE_SIZE-1)); - DRM_PROC_PRINT(" 0x%08lx -> 0x%08lx" - " %c%c%c%c%c\n", - i, - address, - pte_read(*pte) ? 'r' : '-', - pte_write(*pte) ? 'w' : '-', - pte_exec(*pte) ? 'x' : '-', - pte_dirty(*pte) ? 'd' : '-', - pte_young(*pte) ? 'a' : '-' ); - } else { - DRM_PROC_PRINT(" 0x%08lx\n", i); - } - } -#endif } if (len > request + offset) return request; @@ -487,143 +546,3 @@ #endif -#if __HAVE_DMA_HISTOGRAM -static int DRM(_histo_info)(char *buf, char **start, off_t offset, int request, - int *eof, void *data) -{ - drm_device_t *dev = (drm_device_t *)data; - int len = 0; - drm_device_dma_t *dma = dev->dma; - int i; - unsigned long slot_value = DRM_DMA_HISTOGRAM_INITIAL; - unsigned long prev_value = 0; - drm_buf_t *buffer; - - if (offset > DRM_PROC_LIMIT) { - *eof = 1; - return 0; - } - - *start = &buf[offset]; - *eof = 0; - - DRM_PROC_PRINT("general statistics:\n"); - DRM_PROC_PRINT("total %10u\n", atomic_read(&dev->histo.total)); - DRM_PROC_PRINT("open %10u\n", - atomic_read(&dev->counts[_DRM_STAT_OPENS])); - DRM_PROC_PRINT("close %10u\n", - atomic_read(&dev->counts[_DRM_STAT_CLOSES])); - DRM_PROC_PRINT("ioctl %10u\n", - atomic_read(&dev->counts[_DRM_STAT_IOCTLS])); - - DRM_PROC_PRINT("\nlock statistics:\n"); - DRM_PROC_PRINT("locks %10u\n", - atomic_read(&dev->counts[_DRM_STAT_LOCKS])); - DRM_PROC_PRINT("unlocks %10u\n", - atomic_read(&dev->counts[_DRM_STAT_UNLOCKS])); - - if (dma) { -#if 0 - DRM_PROC_PRINT("\ndma statistics:\n"); - DRM_PROC_PRINT("prio %10u\n", - atomic_read(&dma->total_prio)); - DRM_PROC_PRINT("bytes %10u\n", - atomic_read(&dma->total_bytes)); - DRM_PROC_PRINT("dmas %10u\n", - atomic_read(&dma->total_dmas)); - DRM_PROC_PRINT("missed:\n"); - DRM_PROC_PRINT(" dma %10u\n", - atomic_read(&dma->total_missed_dma)); - DRM_PROC_PRINT(" lock %10u\n", - atomic_read(&dma->total_missed_lock)); - DRM_PROC_PRINT(" free %10u\n", - atomic_read(&dma->total_missed_free)); - DRM_PROC_PRINT(" sched %10u\n", - atomic_read(&dma->total_missed_sched)); - DRM_PROC_PRINT("tried %10u\n", - atomic_read(&dma->total_tried)); - DRM_PROC_PRINT("hit %10u\n", - atomic_read(&dma->total_hit)); - DRM_PROC_PRINT("lost %10u\n", - atomic_read(&dma->total_lost)); -#endif - - buffer = dma->next_buffer; - if (buffer) { - DRM_PROC_PRINT("next_buffer %7d\n", buffer->idx); - } else { - DRM_PROC_PRINT("next_buffer none\n"); - } - buffer = dma->this_buffer; - if (buffer) { - DRM_PROC_PRINT("this_buffer %7d\n", buffer->idx); - } else { - DRM_PROC_PRINT("this_buffer none\n"); - } - } - - - DRM_PROC_PRINT("\nvalues:\n"); - if (dev->lock.hw_lock) { - DRM_PROC_PRINT("lock 0x%08x\n", - dev->lock.hw_lock->lock); - } else { - DRM_PROC_PRINT("lock none\n"); - } - DRM_PROC_PRINT("context_flag 0x%08lx\n", dev->context_flag); - DRM_PROC_PRINT("interrupt_flag 0x%08lx\n", dev->interrupt_flag); - DRM_PROC_PRINT("dma_flag 0x%08lx\n", dev->dma_flag); - - DRM_PROC_PRINT("queue_count %10d\n", dev->queue_count); - DRM_PROC_PRINT("last_context %10d\n", dev->last_context); - DRM_PROC_PRINT("last_switch %10lu\n", dev->last_switch); - DRM_PROC_PRINT("last_checked %10d\n", dev->last_checked); - - - DRM_PROC_PRINT("\n q2d d2c c2f" - " q2c q2f dma sch" - " ctx lacq lhld\n\n"); - for (i = 0; i < DRM_DMA_HISTOGRAM_SLOTS; i++) { - DRM_PROC_PRINT("%s %10lu %10u %10u %10u %10u %10u" - " %10u %10u %10u %10u %10u\n", - i == DRM_DMA_HISTOGRAM_SLOTS - 1 ? ">=" : "< ", - i == DRM_DMA_HISTOGRAM_SLOTS - 1 - ? prev_value : slot_value , - - atomic_read(&dev->histo - .queued_to_dispatched[i]), - atomic_read(&dev->histo - .dispatched_to_completed[i]), - atomic_read(&dev->histo - .completed_to_freed[i]), - - atomic_read(&dev->histo - .queued_to_completed[i]), - atomic_read(&dev->histo - .queued_to_freed[i]), - atomic_read(&dev->histo.dma[i]), - atomic_read(&dev->histo.schedule[i]), - atomic_read(&dev->histo.ctx[i]), - atomic_read(&dev->histo.lacq[i]), - atomic_read(&dev->histo.lhld[i])); - prev_value = slot_value; - slot_value = DRM_DMA_HISTOGRAM_NEXT(slot_value); - } - - if (len > request + offset) return request; - *eof = 1; - return len - offset; -} - -static int DRM(histo_info)(char *buf, char **start, off_t offset, int request, - int *eof, void *data) -{ - drm_device_t *dev = (drm_device_t *)data; - int ret; - - down(&dev->struct_sem); - ret = DRM(_histo_info)(buf, start, offset, request, eof, data); - up(&dev->struct_sem); - return ret; -} -#endif diff -urN linux-2.4.23-pre8/drivers/char/drm/drm_sarea.h linux-2.4.23-pre8-pac1/drivers/char/drm/drm_sarea.h --- linux-2.4.23-pre8/drivers/char/drm/drm_sarea.h 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/drm_sarea.h 2003-08-18 12:56:12.000000000 +0200 @@ -1,5 +1,11 @@ -/* sarea.h -- SAREA definitions -*- linux-c -*- +/** + * \file drm_sarea.h + * \brief SAREA definitions * + * \author Michel Dänzer + */ + +/* * Copyright 2002 Tungsten Graphics, Inc., Cedar Park, Texas. * All Rights Reserved. * @@ -21,22 +27,22 @@ * 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: - * Michel Dänzer */ #ifndef _DRM_SAREA_H_ #define _DRM_SAREA_H_ +/** Maximum number of drawables in the SAREA */ #define SAREA_MAX_DRAWABLES 256 -typedef struct _drm_sarea_drawable_t { +/** SAREA drawable */ +typedef struct drm_sarea_drawable { unsigned int stamp; unsigned int flags; } drm_sarea_drawable_t; -typedef struct _dri_sarea_frame_t { +/** SAREA frame */ +typedef struct drm_sarea_frame { unsigned int x; unsigned int y; unsigned int width; @@ -44,13 +50,14 @@ unsigned int fullscreen; } drm_sarea_frame_t; -typedef struct _drm_sarea_t { - /* first thing is always the drm locking structure */ +/** SAREA */ +typedef struct drm_sarea { + /** first thing is always the DRM locking structure */ drm_hw_lock_t lock; - /* NOT_DONE: Use readers/writer lock for drawable_lock */ + /** \todo Use readers/writer lock for drm_sarea::drawable_lock */ drm_hw_lock_t drawable_lock; - drm_sarea_drawable_t drawableTable[SAREA_MAX_DRAWABLES]; - drm_sarea_frame_t frame; + drm_sarea_drawable_t drawableTable[SAREA_MAX_DRAWABLES]; /**< drawables */ + drm_sarea_frame_t frame; /**< frame */ drm_context_t dummy_context; } drm_sarea_t; diff -urN linux-2.4.23-pre8/drivers/char/drm/drm_scatter.h linux-2.4.23-pre8-pac1/drivers/char/drm/drm_scatter.h --- linux-2.4.23-pre8/drivers/char/drm/drm_scatter.h 2003-06-13 16:51:32.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/drm_scatter.h 2003-08-18 12:56:12.000000000 +0200 @@ -1,4 +1,11 @@ -/* drm_scatter.h -- IOCTLs to manage scatter/gather memory -*- linux-c -*- +/** + * \file drm_scatter.h + * IOCTLs to manage scatter/gather memory + * + * \author Gareth Hughes + */ + +/* * Created: Mon Dec 18 23:20:54 2000 by gareth@valinux.com * * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. @@ -22,11 +29,9 @@ * 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: - * Gareth Hughes */ +#define __NO_VERSION__ #include #include #include "drmP.h" diff -urN linux-2.4.23-pre8/drivers/char/drm/drm_stub.h linux-2.4.23-pre8-pac1/drivers/char/drm/drm_stub.h --- linux-2.4.23-pre8/drivers/char/drm/drm_stub.h 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/drm_stub.h 2003-08-18 12:56:12.000000000 +0200 @@ -1,4 +1,11 @@ -/* drm_stub.h -- -*- linux-c -*- +/** + * \file drm_stub.h + * Stub support + * + * \author Rickard E. (Rik) Faith + */ + +/* * Created: Fri Jan 19 10:48:35 2001 by faith@acm.org * * Copyright 2001 VA Linux Systems, Inc., Sunnyvale, California. @@ -22,30 +29,38 @@ * 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 - * */ +#define __NO_VERSION__ #include "drmP.h" #define DRM_STUB_MAXCARDS 16 /* Enough for one machine */ +/** Stub list. One for each minor. */ static struct drm_stub_list { const char *name; - struct file_operations *fops; - struct proc_dir_entry *dev_root; + struct file_operations *fops; /**< file operations */ + struct proc_dir_entry *dev_root; /**< proc directory entry */ } *DRM(stub_list); static struct proc_dir_entry *DRM(stub_root); +/** Stub information */ static struct drm_stub_info { int (*info_register)(const char *name, struct file_operations *fops, drm_device_t *dev); int (*info_unregister)(int minor); } DRM(stub_info); +/** + * File \c open operation. + * + * \param inode device inode. + * \param filp file pointer. + * + * Puts the drm_stub_list::fops corresponding to the device minor number into + * \p filp, call the \c open method, and restore the file operations. + */ static int DRM(stub_open)(struct inode *inode, struct file *filp) { int minor = minor(inode->i_rdev); @@ -64,11 +79,24 @@ return err; } +/** File operations structure */ static struct file_operations DRM(stub_fops) = { .owner = THIS_MODULE, .open = DRM(stub_open) }; +/** + * Get a device minor number. + * + * \param name driver name. + * \param fops file operations. + * \param dev DRM device. + * \return minor number on success, or a negative number on failure. + * + * Allocate and initialize ::stub_list if one doesn't exist already. Search an + * empty entry and initialize it to the given parameters, and create the proc + * init entry via proc_init(). + */ static int DRM(stub_getminor)(const char *name, struct file_operations *fops, drm_device_t *dev) { @@ -96,6 +124,16 @@ return -1; } +/** + * Put a device minor number. + * + * \param minor minor number. + * \return always zero. + * + * Cleans up the proc resources. If a minor is zero then release the foreign + * "drm" data, otherwise unregisters the "drm" data, frees the stub list and + * unregisters the character device. + */ static int DRM(stub_putminor)(int minor) { if (minor < 0 || minor >= DRM_STUB_MAXCARDS) return -1; @@ -115,7 +153,20 @@ return 0; } - +/** + * Register. + * + * \param name driver name. + * \param fops file operations + * \param dev DRM device. + * \return zero on success or a negative number on failure. + * + * Attempt to register the char device and get the foreign "drm" data. If + * successful then another module already registered so gets the stub info, + * otherwise use this module stub info and make it available for other modules. + * + * Finally calls stub_info::info_register. + */ int DRM(stub_register)(const char *name, struct file_operations *fops, drm_device_t *dev) { @@ -141,6 +192,13 @@ return -1; } +/** + * Unregister. + * + * \param minor + * + * Calls drm_stub_info::unregister. + */ int DRM(stub_unregister)(int minor) { DRM_DEBUG("%d\n", minor); diff -urN linux-2.4.23-pre8/drivers/char/drm/drm_vm.h linux-2.4.23-pre8-pac1/drivers/char/drm/drm_vm.h --- linux-2.4.23-pre8/drivers/char/drm/drm_vm.h 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/drm_vm.h 2003-08-18 12:56:12.000000000 +0200 @@ -1,4 +1,12 @@ -/* drm_vm.h -- Memory mapping for DRM -*- linux-c -*- +/** + * \file drm_vm.h + * Memory mapping for DRM + * + * \author Rickard E. (Rik) Faith + * \author Gareth Hughes + */ + +/* * Created: Mon Jan 4 08:58:31 1999 by faith@valinux.com * * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. @@ -23,38 +31,50 @@ * 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 - * Gareth Hughes */ +#define __NO_VERSION__ #include "drmP.h" +/** AGP virtual memory operations */ struct vm_operations_struct DRM(vm_ops) = { - nopage: DRM(vm_nopage), - open: DRM(vm_open), - close: DRM(vm_close), + .nopage = DRM(vm_nopage), + .open = DRM(vm_open), + .close = DRM(vm_close), }; +/** Shared virtual memory operations */ struct vm_operations_struct DRM(vm_shm_ops) = { - nopage: DRM(vm_shm_nopage), - open: DRM(vm_open), - close: DRM(vm_shm_close), + .nopage = DRM(vm_shm_nopage), + .open = DRM(vm_open), + .close = DRM(vm_shm_close), }; +/** DMA virtual memory operations */ struct vm_operations_struct DRM(vm_dma_ops) = { - nopage: DRM(vm_dma_nopage), - open: DRM(vm_open), - close: DRM(vm_close), + .nopage = DRM(vm_dma_nopage), + .open = DRM(vm_open), + .close = DRM(vm_close), }; +/** Scatter-gather virtual memory operations */ struct vm_operations_struct DRM(vm_sg_ops) = { - nopage: DRM(vm_sg_nopage), - open: DRM(vm_open), - close: DRM(vm_close), + .nopage = DRM(vm_sg_nopage), + .open = DRM(vm_open), + .close = DRM(vm_close), }; +/** + * \c nopage method for AGP virtual memory. + * + * \param vma virtual memory area. + * \param address access address. + * \param write_access sharing. + * \return pointer to the page structure. + * + * Find the right map and if it's AGP memory find the real physical page to + * map, get the page, increment the use count and return it. + */ struct page *DRM(vm_nopage)(struct vm_area_struct *vma, unsigned long address, int write_access) @@ -73,7 +93,7 @@ if(!dev->agp || !dev->agp->cant_use_aperture) goto vm_nopage_error; list_for_each(list, &dev->maplist->head) { - r_list = (drm_map_list_t *)list; + r_list = list_entry(list, drm_map_list_t, head); map = r_list->map; if (!map) continue; if (map->offset == VM_OFFSET(vma)) break; @@ -107,12 +127,12 @@ * Get the page, inc the use count, and return it */ offset = (baddr - agpmem->bound) >> PAGE_SHIFT; - agpmem->memory->memory[offset] &= dev->agp->page_mask; page = virt_to_page(__va(agpmem->memory->memory[offset])); get_page(page); - DRM_DEBUG("baddr = 0x%lx page = 0x%p, offset = 0x%lx\n", - baddr, __va(agpmem->memory->memory[offset]), offset); + DRM_DEBUG("baddr = 0x%lx page = 0x%p, offset = 0x%lx, count=%d\n", + baddr, __va(agpmem->memory->memory[offset]), offset, + atomic_read(&page->count)); return page; } @@ -122,6 +142,17 @@ return NOPAGE_SIGBUS; /* Disallow mremap */ } +/** + * \c nopage method for shared virtual memory. + * + * \param vma virtual memory area. + * \param address access address. + * \param write_access sharing. + * \return pointer to the page structure. + * + * Get the the mapping, find the real physical page to map, get the page, and + * return it. + */ struct page *DRM(vm_shm_nopage)(struct vm_area_struct *vma, unsigned long address, int write_access) @@ -145,10 +176,15 @@ return page; } -/* Special close routine which deletes map information if we are the last - * person to close a mapping and its not in the global maplist. - */ +/** + * \c close method for shared virtual memory. + * + * \param vma virtual memory area. + * + * Deletes map information if we are the last + * person to close a mapping and it's not in the global maplist. + */ void DRM(vm_shm_close)(struct vm_area_struct *vma) { drm_file_t *priv = vma->vm_file->private_data; @@ -189,7 +225,7 @@ found_maps = 0; list = &dev->maplist->head; list_for_each(list, &dev->maplist->head) { - r_list = (drm_map_list_t *) list; + r_list = list_entry(list, drm_map_list_t, head); if (r_list->map == map) found_maps++; } @@ -206,7 +242,7 @@ DRM_DEBUG("mtrr_del = %d\n", retcode); } #endif - DRM(ioremapfree)(map->handle, map->size); + DRM(ioremapfree)(map->handle, map->size, dev); break; case _DRM_SHM: vfree(map->handle); @@ -221,6 +257,16 @@ up(&dev->struct_sem); } +/** + * \c nopage method for DMA virtual memory. + * + * \param vma virtual memory area. + * \param address access address. + * \param write_access sharing. + * \return pointer to the page structure. + * + * Determine the page number from the page offset and get it from drm_device_dma::pagelist. + */ struct page *DRM(vm_dma_nopage)(struct vm_area_struct *vma, unsigned long address, int write_access) @@ -247,6 +293,16 @@ return page; } +/** + * \c nopage method for scatter-gather virtual memory. + * + * \param vma virtual memory area. + * \param address access address. + * \param write_access sharing. + * \return pointer to the page structure. + * + * Determine the map offset from the page offset and get it from drm_sg_mem::pagelist. + */ struct page *DRM(vm_sg_nopage)(struct vm_area_struct *vma, unsigned long address, int write_access) @@ -274,6 +330,14 @@ return page; } +/** + * \c open method for shared virtual memory. + * + * \param vma virtual memory area. + * + * Create a new drm_vma_entry structure as the \p vma private data entry and + * add it to drm_device::vmalist. + */ void DRM(vm_open)(struct vm_area_struct *vma) { drm_file_t *priv = vma->vm_file->private_data; @@ -295,6 +359,14 @@ } } +/** + * \c close method for all virtual memory types. + * + * \param vma virtual memory area. + * + * Search the \p vma private data entry in drm_device::vmalist, unlink it, and + * free it. + */ void DRM(vm_close)(struct vm_area_struct *vma) { drm_file_t *priv = vma->vm_file->private_data; @@ -320,6 +392,16 @@ up(&dev->struct_sem); } +/** + * mmap DMA memory. + * + * \param filp file pointer. + * \param vma virtual memory area. + * \return zero on success or a negative number on failure. + * + * Sets the virtual memory area operations structure to vm_dma_ops, the file + * pointer, and calls vm_open(). + */ int DRM(mmap_dma)(struct file *filp, struct vm_area_struct *vma) { drm_file_t *priv = filp->private_data; @@ -341,7 +423,13 @@ unlock_kernel(); vma->vm_ops = &DRM(vm_dma_ops); + +#if LINUX_VERSION_CODE <= 0x02040e /* KERNEL_VERSION(2,4,14) */ + vma->vm_flags |= VM_LOCKED | VM_SHM; /* Don't swap */ +#else vma->vm_flags |= VM_RESERVED; /* Don't swap */ +#endif + vma->vm_file = filp; /* Needed for drm_vm_open() */ DRM(vm_open)(vma); return 0; @@ -360,6 +448,19 @@ #endif #endif +/** + * mmap DMA memory. + * + * \param filp file pointer. + * \param vma virtual memory area. + * \return zero on success or a negative number on failure. + * + * If the virtual memory area has no offset associated with it then it's a DMA + * area, so calls mmap_dma(). Otherwise searches the map in drm_device::maplist, + * checks that the restricted flag is not set, sets the virtual memory operations + * according to the mapping type and remaps the pages. Finally sets the file + * pointer and calls vm_open(). + */ int DRM(mmap)(struct file *filp, struct vm_area_struct *vma) { drm_file_t *priv = filp->private_data; @@ -374,7 +475,16 @@ if ( !priv->authenticated ) return -EACCES; - if (!VM_OFFSET(vma)) return DRM(mmap_dma)(filp, vma); + /* We check for "dma". On Apple's UniNorth, it's valid to have + * the AGP mapped at physical address 0 + * --BenH. + */ + if (!VM_OFFSET(vma) +#if __REALLY_HAVE_AGP + && (!dev->agp || dev->agp->agp_info.device->vendor != PCI_VENDOR_ID_APPLE) +#endif + ) + return DRM(mmap_dma)(filp, vma); /* A sequential search of a linked list is fine here because: 1) there will only be @@ -386,7 +496,7 @@ list_for_each(list, &dev->maplist->head) { unsigned long off; - r_list = (drm_map_list_t *)list; + r_list = list_entry(list, drm_map_list_t, head); map = r_list->map; if (!map) continue; off = DRIVER_GET_MAP_OFS(); @@ -400,8 +510,8 @@ if (map->size != vma->vm_end - vma->vm_start) return -EINVAL; if (!capable(CAP_SYS_ADMIN) && (map->flags & _DRM_READ_ONLY)) { - vma->vm_flags &= VM_MAYWRITE; -#if defined(__i386__) || defined(__x86_64__) + vma->vm_flags &= ~(VM_WRITE | VM_MAYWRITE); +#if defined(__i386__) || defined(__AMD64__) pgprot_val(vma->vm_page_prot) &= ~_PAGE_RW; #else /* Ye gads this is ugly. With more thought @@ -414,34 +524,38 @@ switch (map->type) { case _DRM_AGP: -#if defined(__alpha__) +#if __REALLY_HAVE_AGP + if (dev->agp->cant_use_aperture) { /* - * On Alpha we can't talk to bus dma address from the - * CPU, so for memory of type DRM_AGP, we'll deal with - * sorting out the real physical pages and mappings - * in nopage() + * On some platforms we can't talk to bus dma address from the CPU, so for + * memory of type DRM_AGP, we'll deal with sorting out the real physical + * pages and mappings in nopage() */ +#if defined(__powerpc__) + pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE; +#endif vma->vm_ops = &DRM(vm_ops); break; + } #endif /* fall through to _DRM_FRAME_BUFFER... */ case _DRM_FRAME_BUFFER: case _DRM_REGISTERS: if (VM_OFFSET(vma) >= __pa(high_memory)) { -#if defined(__i386__) || defined(__x86_64__) +#if defined(__i386__) || defined(__AMD64__) if (boot_cpu_data.x86 > 3 && map->type != _DRM_AGP) { pgprot_val(vma->vm_page_prot) |= _PAGE_PCD; pgprot_val(vma->vm_page_prot) &= ~_PAGE_PWT; } -#elif defined(__ia64__) - if (map->type != _DRM_AGP) - vma->vm_page_prot = - pgprot_writecombine(vma->vm_page_prot); #elif defined(__powerpc__) pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE | _PAGE_GUARDED; #endif vma->vm_flags |= VM_IO; /* not in core dump */ } +#if defined(__ia64__) + if (map->type != _DRM_AGP) + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); +#endif offset = DRIVER_GET_REG_OFS(); #ifdef __sparc__ if (io_remap_page_range(DRM_RPR_ARG(vma) vma->vm_start, @@ -466,15 +580,29 @@ vma->vm_private_data = (void *)map; /* Don't let this area swap. Change when DRM_KERNEL advisory is supported. */ +#if LINUX_VERSION_CODE <= 0x02040e /* KERNEL_VERSION(2,4,14) */ + vma->vm_flags |= VM_LOCKED; +#else + vma->vm_flags |= VM_RESERVED; +#endif break; case _DRM_SCATTER_GATHER: vma->vm_ops = &DRM(vm_sg_ops); vma->vm_private_data = (void *)map; +#if LINUX_VERSION_CODE <= 0x02040e /* KERNEL_VERSION(2,4,14) */ + vma->vm_flags |= VM_LOCKED; +#else + vma->vm_flags |= VM_RESERVED; +#endif break; default: return -EINVAL; /* This should never happen. */ } +#if LINUX_VERSION_CODE <= 0x02040e /* KERNEL_VERSION(2,4,14) */ + vma->vm_flags |= VM_LOCKED | VM_SHM; /* Don't swap */ +#else vma->vm_flags |= VM_RESERVED; /* Don't swap */ +#endif vma->vm_file = filp; /* Needed for drm_vm_open() */ DRM(vm_open)(vma); diff -urN linux-2.4.23-pre8/drivers/char/drm/drmstat.c linux-2.4.23-pre8-pac1/drivers/char/drm/drmstat.c --- linux-2.4.23-pre8/drivers/char/drm/drmstat.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/drmstat.c 2003-06-30 00:32:46.000000000 +0200 @@ -0,0 +1,425 @@ +/* drmstat.c -- DRM device status and testing program + * Created: Tue Jan 5 08:19:24 1999 by faith@precisioninsight.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * 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 + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * 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 + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "xf86drm.h" + +int sigio_fd; + +static double usec(struct timeval *end, struct timeval *start) +{ + double e = end->tv_sec * 1000000 + end->tv_usec; + double s = start->tv_sec * 1000000 + start->tv_usec; + + return e - s; +} + +static void getversion(int fd) +{ + drmVersionPtr version; + + version = drmGetVersion(fd); + if (version) { + printf( "Name: %s\n", version->name ? version->name : "?" ); + printf( " Version: %d.%d.%d\n", + version->version_major, + version->version_minor, + version->version_patchlevel ); + printf( " Date: %s\n", version->date ? version->date : "?" ); + printf( " Desc: %s\n", version->desc ? version->desc : "?" ); + drmFreeVersion(version); + } else { + printf( "No driver available\n" ); + } +} + +void handler(int fd, void *oldctx, void *newctx) +{ + printf("Got fd %d\n", fd); +} + +void process_sigio(char *device) +{ + int fd; + + if ((fd = open(device, 0)) < 0) { + drmError(-errno, __FUNCTION__); + exit(1); + } + + sigio_fd = fd; + drmInstallSIGIOHandler(fd, handler); + for (;;) sleep(60); +} + +int main(int argc, char **argv) +{ + int c; + int r = 0; + int fd = -1; + drmHandle handle; + void *address; + char *pt; + unsigned long count; + unsigned long offset; + unsigned long size; + drmContext context; + int loops; + char buf[1024]; + int i; + drmBufInfoPtr info; + drmBufMapPtr bufs; + drmLockPtr lock; + int secs; + + while ((c = getopt(argc, argv, + "lc:vo:O:f:s:w:W:b:r:R:P:L:C:XS:B:F:")) != EOF) + switch (c) { + case 'F': + count = strtoul(optarg, NULL, 0); + if (!fork()) { + dup(fd); + sleep(count); + } + close(fd); + break; + case 'v': getversion(fd); break; + case 'X': + if ((r = drmCreateContext(fd, &context))) { + drmError(r, argv[0]); + return 1; + } + printf( "Got %d\n", context); + break; + case 'S': + process_sigio(optarg); + break; + case 'C': + if ((r = drmSwitchToContext(fd, strtoul(optarg, NULL, 0)))) { + drmError(r, argv[0]); + return 1; + } + break; + case 'c': + if ((r = drmSetBusid(fd,optarg))) { + drmError(r, argv[0]); + return 1; + } + break; + case 'o': + if ((fd = drmOpen(optarg, NULL)) < 0) { + drmError(fd, argv[0]); + return 1; + } + break; + case 'O': + if ((fd = drmOpen(NULL, optarg)) < 0) { + drmError(fd, argv[0]); + return 1; + } + break; + case 'B': /* Test buffer allocation */ + count = strtoul(optarg, &pt, 0); + size = strtoul(pt+1, &pt, 0); + secs = strtoul(pt+1, NULL, 0); + { + drmDMAReq dma; + int *indices, *sizes; + + indices = alloca(sizeof(*indices) * count); + sizes = alloca(sizeof(*sizes) * count); + dma.context = context; + dma.send_count = 0; + dma.request_count = count; + dma.request_size = size; + dma.request_list = indices; + dma.request_sizes = sizes; + dma.flags = DRM_DMA_WAIT; + if ((r = drmDMA(fd, &dma))) { + drmError(r, argv[0]); + return 1; + } + for (i = 0; i < dma.granted_count; i++) { + printf("%5d: index = %d, size = %d\n", + i, dma.request_list[i], dma.request_sizes[i]); + } + sleep(secs); + drmFreeBufs(fd, dma.granted_count, indices); + } + break; + case 'b': + count = strtoul(optarg, &pt, 0); + size = strtoul(pt+1, NULL, 0); + if ((r = drmAddBufs(fd, count, size, 0, 65536)) < 0) { + drmError(r, argv[0]); + return 1; + } + if (!(info = drmGetBufInfo(fd))) { + drmError(0, argv[0]); + return 1; + } + for (i = 0; i < info->count; i++) { + printf("%5d buffers of size %6d (low = %d, high = %d)\n", + info->list[i].count, + info->list[i].size, + info->list[i].low_mark, + info->list[i].high_mark); + } + if ((r = drmMarkBufs(fd, 0.50, 0.80))) { + drmError(r, argv[0]); + return 1; + } + if (!(info = drmGetBufInfo(fd))) { + drmError(0, argv[0]); + return 1; + } + for (i = 0; i < info->count; i++) { + printf("%5d buffers of size %6d (low = %d, high = %d)\n", + info->list[i].count, + info->list[i].size, + info->list[i].low_mark, + info->list[i].high_mark); + } + printf("===== /proc/dri/0/mem =====\n"); + sprintf(buf, "cat /proc/dri/0/mem"); + system(buf); +#if 1 + if (!(bufs = drmMapBufs(fd))) { + drmError(0, argv[0]); + return 1; + } + printf("===============================\n"); + printf( "%d bufs\n", bufs->count); + for (i = 0; i < bufs->count; i++) { + printf( " %4d: %8d bytes at %p\n", + i, + bufs->list[i].total, + bufs->list[i].address); + } + printf("===== /proc/dri/0/vma =====\n"); + sprintf(buf, "cat /proc/dri/0/vma"); + system(buf); +#endif + break; + case 'f': + offset = strtoul(optarg, &pt, 0); + size = strtoul(pt+1, NULL, 0); + handle = 0; + if ((r = drmAddMap(fd, offset, size, + DRM_FRAME_BUFFER, 0, &handle))) { + drmError(r, argv[0]); + return 1; + } + printf("0x%08lx:0x%04lx added\n", offset, size); + printf("===== /proc/dri/0/mem =====\n"); + sprintf(buf, "cat /proc/dri/0/mem"); + system(buf); + break; + case 'r': + case 'R': + offset = strtoul(optarg, &pt, 0); + size = strtoul(pt+1, NULL, 0); + handle = 0; + if ((r = drmAddMap(fd, offset, size, + DRM_REGISTERS, + c == 'R' ? DRM_READ_ONLY : 0, + &handle))) { + drmError(r, argv[0]); + return 1; + } + printf("0x%08lx:0x%04lx added\n", offset, size); + printf("===== /proc/dri/0/mem =====\n"); + sprintf(buf, "cat /proc/dri/0/mem"); + system(buf); + break; + case 's': + size = strtoul(optarg, &pt, 0); + handle = 0; + if ((r = drmAddMap(fd, 0, size, + DRM_SHM, DRM_CONTAINS_LOCK, + &handle))) { + drmError(r, argv[0]); + return 1; + } + printf("0x%04lx byte shm added at 0x%08lx\n", size, handle); + sprintf(buf, "cat /proc/dri/0/vm"); + system(buf); + break; + case 'P': + offset = strtoul(optarg, &pt, 0); + size = strtoul(pt+1, NULL, 0); + address = NULL; + if ((r = drmMap(fd, offset, size, &address))) { + drmError(r, argv[0]); + return 1; + } + printf("0x%08lx:0x%04lx mapped at %p for pid %d\n", + offset, size, address, getpid()); + printf("===== /proc/dri/0/vma =====\n"); + sprintf(buf, "cat /proc/dri/0/vma"); + system(buf); + mprotect((void *)offset, size, PROT_READ); + printf("===== /proc/dri/0/vma =====\n"); + sprintf(buf, "cat /proc/dri/0/vma"); + system(buf); + break; + case 'w': + case 'W': + offset = strtoul(optarg, &pt, 0); + size = strtoul(pt+1, NULL, 0); + address = NULL; + if ((r = drmMap(fd, offset, size, &address))) { + drmError(r, argv[0]); + return 1; + } + printf("0x%08lx:0x%04lx mapped at %p for pid %d\n", + offset, size, address, getpid()); + printf("===== /proc/%d/maps =====\n", getpid()); + sprintf(buf, "cat /proc/%d/maps", getpid()); + system(buf); + printf("===== /proc/dri/0/mem =====\n"); + sprintf(buf, "cat /proc/dri/0/mem"); + system(buf); + printf("===== /proc/dri/0/vma =====\n"); + sprintf(buf, "cat /proc/dri/0/vma"); + system(buf); + printf("===== READING =====\n"); + for (i = 0; i < 0x10; i++) + printf("%02x ", (unsigned int)((unsigned char *)address)[i]); + printf("\n"); + if (c == 'w') { + printf("===== WRITING =====\n"); + for (i = 0; i < size; i+=2) { + ((char *)address)[i] = i & 0xff; + ((char *)address)[i+1] = i & 0xff; + } + } + printf("===== READING =====\n"); + for (i = 0; i < 0x10; i++) + printf("%02x ", (unsigned int)((unsigned char *)address)[i]); + printf("\n"); + printf("===== /proc/dri/0/vma =====\n"); + sprintf(buf, "cat /proc/dri/0/vma"); + system(buf); + break; + case 'L': + context = strtoul(optarg, &pt, 0); + offset = strtoul(pt+1, &pt, 0); + size = strtoul(pt+1, &pt, 0); + loops = strtoul(pt+1, NULL, 0); + address = NULL; + if ((r = drmMap(fd, offset, size, &address))) { + drmError(r, argv[0]); + return 1; + } + lock = address; +#if 1 + { + int counter = 0; + struct timeval loop_start, loop_end; + struct timeval lock_start, lock_end; + double wt; +#define HISTOSIZE 9 + int histo[HISTOSIZE]; + int output = 0; + int fast = 0; + + if (loops < 0) { + loops = -loops; + ++output; + } + + for (i = 0; i < HISTOSIZE; i++) histo[i] = 0; + + gettimeofday(&loop_start, NULL); + for (i = 0; i < loops; i++) { + gettimeofday(&lock_start, NULL); + DRM_LIGHT_LOCK_COUNT(fd,lock,context,fast); + gettimeofday(&lock_end, NULL); + DRM_UNLOCK(fd,lock,context); + ++counter; + wt = usec(&lock_end, &lock_start); + if (wt <= 2.5) ++histo[8]; + if (wt < 5.0) ++histo[0]; + else if (wt < 50.0) ++histo[1]; + else if (wt < 500.0) ++histo[2]; + else if (wt < 5000.0) ++histo[3]; + else if (wt < 50000.0) ++histo[4]; + else if (wt < 500000.0) ++histo[5]; + else if (wt < 5000000.0) ++histo[6]; + else ++histo[7]; + if (output) printf( "%.2f uSec, %d fast\n", wt, fast); + } + gettimeofday(&loop_end, NULL); + printf( "Average wait time = %.2f usec, %d fast\n", + usec(&loop_end, &loop_start) / counter, fast); + printf( "%9d <= 2.5 uS\n", histo[8]); + printf( "%9d < 5 uS\n", histo[0]); + printf( "%9d < 50 uS\n", histo[1]); + printf( "%9d < 500 uS\n", histo[2]); + printf( "%9d < 5000 uS\n", histo[3]); + printf( "%9d < 50000 uS\n", histo[4]); + printf( "%9d < 500000 uS\n", histo[5]); + printf( "%9d < 5000000 uS\n", histo[6]); + printf( "%9d >= 5000000 uS\n", histo[7]); + } +#else + printf( "before lock: 0x%08x\n", lock->lock); + printf( "lock: 0x%08x\n", lock->lock); + sleep(5); + printf( "unlock: 0x%08x\n", lock->lock); +#endif + break; + default: + fprintf( stderr, "Usage: drmstat [options]\n" ); + return 1; + } + + return r; +} + +void +xf86VDrvMsgVerb(int scrnIndex, int type, int verb, const char *format, + va_list args) +{ + vfprintf(stderr, format, args); +} + +int xf86ConfigDRI[10]; diff -urN linux-2.4.23-pre8/drivers/char/drm/ffb.h linux-2.4.23-pre8-pac1/drivers/char/drm/ffb.h --- linux-2.4.23-pre8/drivers/char/drm/ffb.h 2001-08-08 18:42:14.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/ffb.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,15 +0,0 @@ -/* ffb.h -- ffb DRM template customization -*- linux-c -*- - */ - -#ifndef __FFB_H__ -#define __FFB_H__ - -/* This remains constant for all DRM template files. - */ -#define DRM(x) ffb_##x - -/* General customization: - */ -#define __HAVE_KERNEL_CTX_SWITCH 1 -#define __HAVE_RELEASE 1 -#endif diff -urN linux-2.4.23-pre8/drivers/char/drm/ffb_context.c linux-2.4.23-pre8-pac1/drivers/char/drm/ffb_context.c --- linux-2.4.23-pre8/drivers/char/drm/ffb_context.c 2001-08-12 20:23:32.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/ffb_context.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,539 +0,0 @@ -/* $Id: ffb_context.c,v 1.5 2001/08/09 17:47:51 davem Exp $ - * ffb_context.c: Creator/Creator3D DRI/DRM context switching. - * - * Copyright (C) 2000 David S. Miller (davem@redhat.com) - * - * Almost entirely stolen from tdfx_context.c, see there - * for authors. - */ - -#include -#include - -#include "ffb.h" -#include "drmP.h" - -#include "ffb_drv.h" - -static int DRM(alloc_queue)(drm_device_t *dev, int is_2d_only) -{ - ffb_dev_priv_t *fpriv = (ffb_dev_priv_t *) dev->dev_private; - int i; - - for (i = 0; i < FFB_MAX_CTXS; i++) { - if (fpriv->hw_state[i] == NULL) - break; - } - if (i == FFB_MAX_CTXS) - return -1; - - fpriv->hw_state[i] = kmalloc(sizeof(struct ffb_hw_context), GFP_KERNEL); - if (fpriv->hw_state[i] == NULL) - return -1; - - fpriv->hw_state[i]->is_2d_only = is_2d_only; - - /* Plus one because 0 is the special DRM_KERNEL_CONTEXT. */ - return i + 1; -} - -static void ffb_save_context(ffb_dev_priv_t *fpriv, int idx) -{ - ffb_fbcPtr ffb = fpriv->regs; - struct ffb_hw_context *ctx; - int i; - - ctx = fpriv->hw_state[idx - 1]; - if (idx == 0 || ctx == NULL) - return; - - if (ctx->is_2d_only) { - /* 2D applications only care about certain pieces - * of state. - */ - ctx->drawop = upa_readl(&ffb->drawop); - ctx->ppc = upa_readl(&ffb->ppc); - ctx->wid = upa_readl(&ffb->wid); - ctx->fg = upa_readl(&ffb->fg); - ctx->bg = upa_readl(&ffb->bg); - ctx->xclip = upa_readl(&ffb->xclip); - ctx->fbc = upa_readl(&ffb->fbc); - ctx->rop = upa_readl(&ffb->rop); - ctx->cmp = upa_readl(&ffb->cmp); - ctx->matchab = upa_readl(&ffb->matchab); - ctx->magnab = upa_readl(&ffb->magnab); - ctx->pmask = upa_readl(&ffb->pmask); - ctx->xpmask = upa_readl(&ffb->xpmask); - ctx->lpat = upa_readl(&ffb->lpat); - ctx->fontxy = upa_readl(&ffb->fontxy); - ctx->fontw = upa_readl(&ffb->fontw); - ctx->fontinc = upa_readl(&ffb->fontinc); - - /* stencil/stencilctl only exists on FFB2+ and later - * due to the introduction of 3DRAM-III. - */ - if (fpriv->ffb_type == ffb2_vertical_plus || - fpriv->ffb_type == ffb2_horizontal_plus) { - ctx->stencil = upa_readl(&ffb->stencil); - ctx->stencilctl = upa_readl(&ffb->stencilctl); - } - - for (i = 0; i < 32; i++) - ctx->area_pattern[i] = upa_readl(&ffb->pattern[i]); - ctx->ucsr = upa_readl(&ffb->ucsr); - return; - } - - /* Fetch drawop. */ - ctx->drawop = upa_readl(&ffb->drawop); - - /* If we were saving the vertex registers, this is where - * we would do it. We would save 32 32-bit words starting - * at ffb->suvtx. - */ - - /* Capture rendering attributes. */ - - ctx->ppc = upa_readl(&ffb->ppc); /* Pixel Processor Control */ - ctx->wid = upa_readl(&ffb->wid); /* Current WID */ - ctx->fg = upa_readl(&ffb->fg); /* Constant FG color */ - ctx->bg = upa_readl(&ffb->bg); /* Constant BG color */ - ctx->consty = upa_readl(&ffb->consty); /* Constant Y */ - ctx->constz = upa_readl(&ffb->constz); /* Constant Z */ - ctx->xclip = upa_readl(&ffb->xclip); /* X plane clip */ - ctx->dcss = upa_readl(&ffb->dcss); /* Depth Cue Scale Slope */ - ctx->vclipmin = upa_readl(&ffb->vclipmin); /* Primary XY clip, minimum */ - ctx->vclipmax = upa_readl(&ffb->vclipmax); /* Primary XY clip, maximum */ - ctx->vclipzmin = upa_readl(&ffb->vclipzmin); /* Primary Z clip, minimum */ - ctx->vclipzmax = upa_readl(&ffb->vclipzmax); /* Primary Z clip, maximum */ - ctx->dcsf = upa_readl(&ffb->dcsf); /* Depth Cue Scale Front Bound */ - ctx->dcsb = upa_readl(&ffb->dcsb); /* Depth Cue Scale Back Bound */ - ctx->dczf = upa_readl(&ffb->dczf); /* Depth Cue Scale Z Front */ - ctx->dczb = upa_readl(&ffb->dczb); /* Depth Cue Scale Z Back */ - ctx->blendc = upa_readl(&ffb->blendc); /* Alpha Blend Control */ - ctx->blendc1 = upa_readl(&ffb->blendc1); /* Alpha Blend Color 1 */ - ctx->blendc2 = upa_readl(&ffb->blendc2); /* Alpha Blend Color 2 */ - ctx->fbc = upa_readl(&ffb->fbc); /* Frame Buffer Control */ - ctx->rop = upa_readl(&ffb->rop); /* Raster Operation */ - ctx->cmp = upa_readl(&ffb->cmp); /* Compare Controls */ - ctx->matchab = upa_readl(&ffb->matchab); /* Buffer A/B Match Ops */ - ctx->matchc = upa_readl(&ffb->matchc); /* Buffer C Match Ops */ - ctx->magnab = upa_readl(&ffb->magnab); /* Buffer A/B Magnitude Ops */ - ctx->magnc = upa_readl(&ffb->magnc); /* Buffer C Magnitude Ops */ - ctx->pmask = upa_readl(&ffb->pmask); /* RGB Plane Mask */ - ctx->xpmask = upa_readl(&ffb->xpmask); /* X Plane Mask */ - ctx->ypmask = upa_readl(&ffb->ypmask); /* Y Plane Mask */ - ctx->zpmask = upa_readl(&ffb->zpmask); /* Z Plane Mask */ - - /* Auxiliary Clips. */ - ctx->auxclip0min = upa_readl(&ffb->auxclip[0].min); - ctx->auxclip0max = upa_readl(&ffb->auxclip[0].max); - ctx->auxclip1min = upa_readl(&ffb->auxclip[1].min); - ctx->auxclip1max = upa_readl(&ffb->auxclip[1].max); - ctx->auxclip2min = upa_readl(&ffb->auxclip[2].min); - ctx->auxclip2max = upa_readl(&ffb->auxclip[2].max); - ctx->auxclip3min = upa_readl(&ffb->auxclip[3].min); - ctx->auxclip3max = upa_readl(&ffb->auxclip[3].max); - - ctx->lpat = upa_readl(&ffb->lpat); /* Line Pattern */ - ctx->fontxy = upa_readl(&ffb->fontxy); /* XY Font Coordinate */ - ctx->fontw = upa_readl(&ffb->fontw); /* Font Width */ - ctx->fontinc = upa_readl(&ffb->fontinc); /* Font X/Y Increment */ - - /* These registers/features only exist on FFB2 and later chips. */ - if (fpriv->ffb_type >= ffb2_prototype) { - ctx->dcss1 = upa_readl(&ffb->dcss1); /* Depth Cue Scale Slope 1 */ - ctx->dcss2 = upa_readl(&ffb->dcss2); /* Depth Cue Scale Slope 2 */ - ctx->dcss2 = upa_readl(&ffb->dcss3); /* Depth Cue Scale Slope 3 */ - ctx->dcs2 = upa_readl(&ffb->dcs2); /* Depth Cue Scale 2 */ - ctx->dcs3 = upa_readl(&ffb->dcs3); /* Depth Cue Scale 3 */ - ctx->dcs4 = upa_readl(&ffb->dcs4); /* Depth Cue Scale 4 */ - ctx->dcd2 = upa_readl(&ffb->dcd2); /* Depth Cue Depth 2 */ - ctx->dcd3 = upa_readl(&ffb->dcd3); /* Depth Cue Depth 3 */ - ctx->dcd4 = upa_readl(&ffb->dcd4); /* Depth Cue Depth 4 */ - - /* And stencil/stencilctl only exists on FFB2+ and later - * due to the introduction of 3DRAM-III. - */ - if (fpriv->ffb_type == ffb2_vertical_plus || - fpriv->ffb_type == ffb2_horizontal_plus) { - ctx->stencil = upa_readl(&ffb->stencil); - ctx->stencilctl = upa_readl(&ffb->stencilctl); - } - } - - /* Save the 32x32 area pattern. */ - for (i = 0; i < 32; i++) - ctx->area_pattern[i] = upa_readl(&ffb->pattern[i]); - - /* Finally, stash away the User Constol/Status Register. */ - ctx->ucsr = upa_readl(&ffb->ucsr); -} - -static void ffb_restore_context(ffb_dev_priv_t *fpriv, int old, int idx) -{ - ffb_fbcPtr ffb = fpriv->regs; - struct ffb_hw_context *ctx; - int i; - - ctx = fpriv->hw_state[idx - 1]; - if (idx == 0 || ctx == NULL) - return; - - if (ctx->is_2d_only) { - /* 2D applications only care about certain pieces - * of state. - */ - upa_writel(ctx->drawop, &ffb->drawop); - - /* If we were restoring the vertex registers, this is where - * we would do it. We would restore 32 32-bit words starting - * at ffb->suvtx. - */ - - upa_writel(ctx->ppc, &ffb->ppc); - upa_writel(ctx->wid, &ffb->wid); - upa_writel(ctx->fg, &ffb->fg); - upa_writel(ctx->bg, &ffb->bg); - upa_writel(ctx->xclip, &ffb->xclip); - upa_writel(ctx->fbc, &ffb->fbc); - upa_writel(ctx->rop, &ffb->rop); - upa_writel(ctx->cmp, &ffb->cmp); - upa_writel(ctx->matchab, &ffb->matchab); - upa_writel(ctx->magnab, &ffb->magnab); - upa_writel(ctx->pmask, &ffb->pmask); - upa_writel(ctx->xpmask, &ffb->xpmask); - upa_writel(ctx->lpat, &ffb->lpat); - upa_writel(ctx->fontxy, &ffb->fontxy); - upa_writel(ctx->fontw, &ffb->fontw); - upa_writel(ctx->fontinc, &ffb->fontinc); - - /* stencil/stencilctl only exists on FFB2+ and later - * due to the introduction of 3DRAM-III. - */ - if (fpriv->ffb_type == ffb2_vertical_plus || - fpriv->ffb_type == ffb2_horizontal_plus) { - upa_writel(ctx->stencil, &ffb->stencil); - upa_writel(ctx->stencilctl, &ffb->stencilctl); - upa_writel(0x80000000, &ffb->fbc); - upa_writel((ctx->stencilctl | 0x80000), - &ffb->rawstencilctl); - upa_writel(ctx->fbc, &ffb->fbc); - } - - for (i = 0; i < 32; i++) - upa_writel(ctx->area_pattern[i], &ffb->pattern[i]); - upa_writel((ctx->ucsr & 0xf0000), &ffb->ucsr); - return; - } - - /* Restore drawop. */ - upa_writel(ctx->drawop, &ffb->drawop); - - /* If we were restoring the vertex registers, this is where - * we would do it. We would restore 32 32-bit words starting - * at ffb->suvtx. - */ - - /* Restore rendering attributes. */ - - upa_writel(ctx->ppc, &ffb->ppc); /* Pixel Processor Control */ - upa_writel(ctx->wid, &ffb->wid); /* Current WID */ - upa_writel(ctx->fg, &ffb->fg); /* Constant FG color */ - upa_writel(ctx->bg, &ffb->bg); /* Constant BG color */ - upa_writel(ctx->consty, &ffb->consty); /* Constant Y */ - upa_writel(ctx->constz, &ffb->constz); /* Constant Z */ - upa_writel(ctx->xclip, &ffb->xclip); /* X plane clip */ - upa_writel(ctx->dcss, &ffb->dcss); /* Depth Cue Scale Slope */ - upa_writel(ctx->vclipmin, &ffb->vclipmin); /* Primary XY clip, minimum */ - upa_writel(ctx->vclipmax, &ffb->vclipmax); /* Primary XY clip, maximum */ - upa_writel(ctx->vclipzmin, &ffb->vclipzmin); /* Primary Z clip, minimum */ - upa_writel(ctx->vclipzmax, &ffb->vclipzmax); /* Primary Z clip, maximum */ - upa_writel(ctx->dcsf, &ffb->dcsf); /* Depth Cue Scale Front Bound */ - upa_writel(ctx->dcsb, &ffb->dcsb); /* Depth Cue Scale Back Bound */ - upa_writel(ctx->dczf, &ffb->dczf); /* Depth Cue Scale Z Front */ - upa_writel(ctx->dczb, &ffb->dczb); /* Depth Cue Scale Z Back */ - upa_writel(ctx->blendc, &ffb->blendc); /* Alpha Blend Control */ - upa_writel(ctx->blendc1, &ffb->blendc1); /* Alpha Blend Color 1 */ - upa_writel(ctx->blendc2, &ffb->blendc2); /* Alpha Blend Color 2 */ - upa_writel(ctx->fbc, &ffb->fbc); /* Frame Buffer Control */ - upa_writel(ctx->rop, &ffb->rop); /* Raster Operation */ - upa_writel(ctx->cmp, &ffb->cmp); /* Compare Controls */ - upa_writel(ctx->matchab, &ffb->matchab); /* Buffer A/B Match Ops */ - upa_writel(ctx->matchc, &ffb->matchc); /* Buffer C Match Ops */ - upa_writel(ctx->magnab, &ffb->magnab); /* Buffer A/B Magnitude Ops */ - upa_writel(ctx->magnc, &ffb->magnc); /* Buffer C Magnitude Ops */ - upa_writel(ctx->pmask, &ffb->pmask); /* RGB Plane Mask */ - upa_writel(ctx->xpmask, &ffb->xpmask); /* X Plane Mask */ - upa_writel(ctx->ypmask, &ffb->ypmask); /* Y Plane Mask */ - upa_writel(ctx->zpmask, &ffb->zpmask); /* Z Plane Mask */ - - /* Auxiliary Clips. */ - upa_writel(ctx->auxclip0min, &ffb->auxclip[0].min); - upa_writel(ctx->auxclip0max, &ffb->auxclip[0].max); - upa_writel(ctx->auxclip1min, &ffb->auxclip[1].min); - upa_writel(ctx->auxclip1max, &ffb->auxclip[1].max); - upa_writel(ctx->auxclip2min, &ffb->auxclip[2].min); - upa_writel(ctx->auxclip2max, &ffb->auxclip[2].max); - upa_writel(ctx->auxclip3min, &ffb->auxclip[3].min); - upa_writel(ctx->auxclip3max, &ffb->auxclip[3].max); - - upa_writel(ctx->lpat, &ffb->lpat); /* Line Pattern */ - upa_writel(ctx->fontxy, &ffb->fontxy); /* XY Font Coordinate */ - upa_writel(ctx->fontw, &ffb->fontw); /* Font Width */ - upa_writel(ctx->fontinc, &ffb->fontinc); /* Font X/Y Increment */ - - /* These registers/features only exist on FFB2 and later chips. */ - if (fpriv->ffb_type >= ffb2_prototype) { - upa_writel(ctx->dcss1, &ffb->dcss1); /* Depth Cue Scale Slope 1 */ - upa_writel(ctx->dcss2, &ffb->dcss2); /* Depth Cue Scale Slope 2 */ - upa_writel(ctx->dcss3, &ffb->dcss2); /* Depth Cue Scale Slope 3 */ - upa_writel(ctx->dcs2, &ffb->dcs2); /* Depth Cue Scale 2 */ - upa_writel(ctx->dcs3, &ffb->dcs3); /* Depth Cue Scale 3 */ - upa_writel(ctx->dcs4, &ffb->dcs4); /* Depth Cue Scale 4 */ - upa_writel(ctx->dcd2, &ffb->dcd2); /* Depth Cue Depth 2 */ - upa_writel(ctx->dcd3, &ffb->dcd3); /* Depth Cue Depth 3 */ - upa_writel(ctx->dcd4, &ffb->dcd4); /* Depth Cue Depth 4 */ - - /* And stencil/stencilctl only exists on FFB2+ and later - * due to the introduction of 3DRAM-III. - */ - if (fpriv->ffb_type == ffb2_vertical_plus || - fpriv->ffb_type == ffb2_horizontal_plus) { - /* Unfortunately, there is a hardware bug on - * the FFB2+ chips which prevents a normal write - * to the stencil control register from working - * as it should. - * - * The state controlled by the FFB stencilctl register - * really gets transferred to the per-buffer instances - * of the stencilctl register in the 3DRAM chips. - * - * The bug is that FFB does not update buffer C correctly, - * so we have to do it by hand for them. - */ - - /* This will update buffers A and B. */ - upa_writel(ctx->stencil, &ffb->stencil); - upa_writel(ctx->stencilctl, &ffb->stencilctl); - - /* Force FFB to use buffer C 3dram regs. */ - upa_writel(0x80000000, &ffb->fbc); - upa_writel((ctx->stencilctl | 0x80000), - &ffb->rawstencilctl); - - /* Now restore the correct FBC controls. */ - upa_writel(ctx->fbc, &ffb->fbc); - } - } - - /* Restore the 32x32 area pattern. */ - for (i = 0; i < 32; i++) - upa_writel(ctx->area_pattern[i], &ffb->pattern[i]); - - /* Finally, stash away the User Constol/Status Register. - * The only state we really preserve here is the picking - * control. - */ - upa_writel((ctx->ucsr & 0xf0000), &ffb->ucsr); -} - -#define FFB_UCSR_FB_BUSY 0x01000000 -#define FFB_UCSR_RP_BUSY 0x02000000 -#define FFB_UCSR_ALL_BUSY (FFB_UCSR_RP_BUSY|FFB_UCSR_FB_BUSY) - -static void FFBWait(ffb_fbcPtr ffb) -{ - int limit = 100000; - - do { - u32 regval = upa_readl(&ffb->ucsr); - - if ((regval & FFB_UCSR_ALL_BUSY) == 0) - break; - } while (--limit); -} - -int DRM(context_switch)(drm_device_t *dev, int old, int new) -{ - ffb_dev_priv_t *fpriv = (ffb_dev_priv_t *) dev->dev_private; - -#if DRM_DMA_HISTOGRAM - dev->ctx_start = get_cycles(); -#endif - - DRM_DEBUG("Context switch from %d to %d\n", old, new); - - if (new == dev->last_context || - dev->last_context == 0) { - dev->last_context = new; - return 0; - } - - FFBWait(fpriv->regs); - ffb_save_context(fpriv, old); - ffb_restore_context(fpriv, old, new); - FFBWait(fpriv->regs); - - dev->last_context = new; - - return 0; -} - -int DRM(resctx)(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) -{ - drm_ctx_res_t res; - 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) { - memset(&ctx, 0, sizeof(ctx)); - for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) { - ctx.handle = i; - if (copy_to_user(&res.contexts[i], - &i, - sizeof(i))) - return -EFAULT; - } - } - res.count = DRM_RESERVED_CONTEXTS; - if (copy_to_user((drm_ctx_res_t *)arg, &res, sizeof(res))) - return -EFAULT; - return 0; -} - - -int DRM(addctx)(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) -{ - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; - drm_ctx_t ctx; - int idx; - - if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) - return -EFAULT; - idx = DRM(alloc_queue)(dev, (ctx.flags & _DRM_CONTEXT_2DONLY)); - if (idx < 0) - return -ENFILE; - - DRM_DEBUG("%d\n", ctx.handle); - ctx.handle = idx; - if (copy_to_user((drm_ctx_t *)arg, &ctx, sizeof(ctx))) - return -EFAULT; - return 0; -} - -int DRM(modctx)(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) -{ - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; - ffb_dev_priv_t *fpriv = (ffb_dev_priv_t *) dev->dev_private; - struct ffb_hw_context *hwctx; - drm_ctx_t ctx; - int idx; - - if (copy_from_user(&ctx, (drm_ctx_t*)arg, sizeof(ctx))) - return -EFAULT; - - idx = ctx.handle; - if (idx <= 0 || idx >= FFB_MAX_CTXS) - return -EINVAL; - - hwctx = fpriv->hw_state[idx - 1]; - if (hwctx == NULL) - return -EINVAL; - - if ((ctx.flags & _DRM_CONTEXT_2DONLY) == 0) - hwctx->is_2d_only = 0; - else - hwctx->is_2d_only = 1; - - return 0; -} - -int DRM(getctx)(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) -{ - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; - ffb_dev_priv_t *fpriv = (ffb_dev_priv_t *) dev->dev_private; - struct ffb_hw_context *hwctx; - drm_ctx_t ctx; - int idx; - - if (copy_from_user(&ctx, (drm_ctx_t*)arg, sizeof(ctx))) - return -EFAULT; - - idx = ctx.handle; - if (idx <= 0 || idx >= FFB_MAX_CTXS) - return -EINVAL; - - hwctx = fpriv->hw_state[idx - 1]; - if (hwctx == NULL) - return -EINVAL; - - if (hwctx->is_2d_only != 0) - ctx.flags = _DRM_CONTEXT_2DONLY; - else - ctx.flags = 0; - - if (copy_to_user((drm_ctx_t*)arg, &ctx, sizeof(ctx))) - return -EFAULT; - - return 0; -} - -int DRM(switchctx)(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) -{ - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; - drm_ctx_t ctx; - - if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) - return -EFAULT; - DRM_DEBUG("%d\n", ctx.handle); - return DRM(context_switch)(dev, dev->last_context, ctx.handle); -} - -int DRM(newctx)(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) -{ - drm_ctx_t ctx; - - if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) - return -EFAULT; - DRM_DEBUG("%d\n", ctx.handle); - - return 0; -} - -int DRM(rmctx)(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) -{ - drm_ctx_t ctx; - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; - ffb_dev_priv_t *fpriv = (ffb_dev_priv_t *) dev->dev_private; - int idx; - - if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) - return -EFAULT; - DRM_DEBUG("%d\n", ctx.handle); - - idx = ctx.handle - 1; - if (idx < 0 || idx >= FFB_MAX_CTXS) - return -EINVAL; - - if (fpriv->hw_state[idx] != NULL) { - kfree(fpriv->hw_state[idx]); - fpriv->hw_state[idx] = NULL; - } - return 0; -} diff -urN linux-2.4.23-pre8/drivers/char/drm/ffb_drv.c linux-2.4.23-pre8-pac1/drivers/char/drm/ffb_drv.c --- linux-2.4.23-pre8/drivers/char/drm/ffb_drv.c 2001-10-21 19:40:36.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/ffb_drv.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,401 +0,0 @@ -/* $Id: ffb_drv.c,v 1.16 2001/10/18 16:00:24 davem Exp $ - * ffb_drv.c: Creator/Creator3D direct rendering driver. - * - * Copyright (C) 2000 David S. Miller (davem@redhat.com) - */ - -#include -#include "ffb.h" -#include "drmP.h" - -#include "ffb_drv.h" - -#include -#include -#include -#include -#include - -#define DRIVER_AUTHOR "David S. Miller" - -#define DRIVER_NAME "ffb" -#define DRIVER_DESC "Creator/Creator3D" -#define DRIVER_DATE "20000517" - -#define DRIVER_MAJOR 0 -#define DRIVER_MINOR 0 -#define DRIVER_PATCHLEVEL 1 - -#define DRIVER_FOPS \ -static struct file_operations DRM(fops) = { \ - owner: THIS_MODULE, \ - open: DRM(open), \ - flush: DRM(flush), \ - release: DRM(release), \ - ioctl: DRM(ioctl), \ - mmap: DRM(mmap), \ - read: DRM(read), \ - fasync: DRM(fasync), \ - poll: DRM(poll), \ - get_unmapped_area: ffb_get_unmapped_area, \ -} - -#define DRIVER_COUNT_CARDS() ffb_count_card_instances() -/* Allocate private structure and fill it */ -#define DRIVER_PRESETUP() do { \ - int _ret; \ - _ret = ffb_presetup(dev); \ - if (_ret != 0) return _ret; \ -} while(0) - -/* Free private structure */ -#define DRIVER_PRETAKEDOWN() do { \ - if (dev->dev_private) kfree(dev->dev_private); \ -} while(0) - -#define DRIVER_POSTCLEANUP() do { \ - if (ffb_position != NULL) kfree(ffb_position); \ -} while(0) - -/* We have to free up the rogue hw context state holding error or - * else we will leak it. - */ -#define DRIVER_RELEASE() do { \ - ffb_dev_priv_t *fpriv = (ffb_dev_priv_t *) dev->dev_private; \ - int context = _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock); \ - int idx; \ - \ - idx = context - 1; \ - if (fpriv && \ - context != DRM_KERNEL_CONTEXT && \ - fpriv->hw_state[idx] != NULL) { \ - kfree(fpriv->hw_state[idx]); \ - fpriv->hw_state[idx] = NULL; \ - } \ -} while(0) - -/* For mmap customization */ -#define DRIVER_GET_MAP_OFS() (map->offset & 0xffffffff) -#define DRIVER_GET_REG_OFS() ffb_get_reg_offset(dev) - -typedef struct _ffb_position_t { - int node; - int root; -} ffb_position_t; - -static ffb_position_t *ffb_position; - -static void get_ffb_type(ffb_dev_priv_t *ffb_priv, int instance) -{ - volatile unsigned char *strap_bits; - unsigned char val; - - strap_bits = (volatile unsigned char *) - (ffb_priv->card_phys_base + 0x00200000UL); - - /* Don't ask, you have to read the value twice for whatever - * reason to get correct contents. - */ - val = upa_readb(strap_bits); - val = upa_readb(strap_bits); - switch (val & 0x78) { - case (0x0 << 5) | (0x0 << 3): - ffb_priv->ffb_type = ffb1_prototype; - printk("ffb%d: Detected FFB1 pre-FCS prototype\n", instance); - break; - case (0x0 << 5) | (0x1 << 3): - ffb_priv->ffb_type = ffb1_standard; - printk("ffb%d: Detected FFB1\n", instance); - break; - case (0x0 << 5) | (0x3 << 3): - ffb_priv->ffb_type = ffb1_speedsort; - printk("ffb%d: Detected FFB1-SpeedSort\n", instance); - break; - case (0x1 << 5) | (0x0 << 3): - ffb_priv->ffb_type = ffb2_prototype; - printk("ffb%d: Detected FFB2/vertical pre-FCS prototype\n", instance); - break; - case (0x1 << 5) | (0x1 << 3): - ffb_priv->ffb_type = ffb2_vertical; - printk("ffb%d: Detected FFB2/vertical\n", instance); - break; - case (0x1 << 5) | (0x2 << 3): - ffb_priv->ffb_type = ffb2_vertical_plus; - printk("ffb%d: Detected FFB2+/vertical\n", instance); - break; - case (0x2 << 5) | (0x0 << 3): - ffb_priv->ffb_type = ffb2_horizontal; - printk("ffb%d: Detected FFB2/horizontal\n", instance); - break; - case (0x2 << 5) | (0x2 << 3): - ffb_priv->ffb_type = ffb2_horizontal; - printk("ffb%d: Detected FFB2+/horizontal\n", instance); - break; - default: - ffb_priv->ffb_type = ffb2_vertical; - printk("ffb%d: Unknown boardID[%08x], assuming FFB2\n", instance, val); - break; - }; -} - -static void ffb_apply_upa_parent_ranges(int parent, - struct linux_prom64_registers *regs) -{ - struct linux_prom64_ranges ranges[PROMREG_MAX]; - char name[128]; - int len, i; - - prom_getproperty(parent, "name", name, sizeof(name)); - if (strcmp(name, "upa") != 0) - return; - - len = prom_getproperty(parent, "ranges", (void *) ranges, sizeof(ranges)); - if (len <= 0) - return; - - len /= sizeof(struct linux_prom64_ranges); - for (i = 0; i < len; i++) { - struct linux_prom64_ranges *rng = &ranges[i]; - u64 phys_addr = regs->phys_addr; - - if (phys_addr >= rng->ot_child_base && - phys_addr < (rng->ot_child_base + rng->or_size)) { - regs->phys_addr -= rng->ot_child_base; - regs->phys_addr += rng->ot_parent_base; - return; - } - } - - return; -} - -static int ffb_init_one(drm_device_t *dev, int prom_node, int parent_node, - int instance) -{ - struct linux_prom64_registers regs[2*PROMREG_MAX]; - ffb_dev_priv_t *ffb_priv = (ffb_dev_priv_t *)dev->dev_private; - int i; - - ffb_priv->prom_node = prom_node; - if (prom_getproperty(ffb_priv->prom_node, "reg", - (void *)regs, sizeof(regs)) <= 0) { - return -EINVAL; - } - ffb_apply_upa_parent_ranges(parent_node, ®s[0]); - ffb_priv->card_phys_base = regs[0].phys_addr; - ffb_priv->regs = (ffb_fbcPtr) - (regs[0].phys_addr + 0x00600000UL); - get_ffb_type(ffb_priv, instance); - for (i = 0; i < FFB_MAX_CTXS; i++) - ffb_priv->hw_state[i] = NULL; - - return 0; -} - -static int __init ffb_count_siblings(int root) -{ - int node, child, count = 0; - - child = prom_getchild(root); - for (node = prom_searchsiblings(child, "SUNW,ffb"); node; - node = prom_searchsiblings(prom_getsibling(node), "SUNW,ffb")) - count++; - - return count; -} - -static int __init ffb_scan_siblings(int root, int instance) -{ - int node, child; - - child = prom_getchild(root); - for (node = prom_searchsiblings(child, "SUNW,ffb"); node; - node = prom_searchsiblings(prom_getsibling(node), "SUNW,ffb")) { - ffb_position[instance].node = node; - ffb_position[instance].root = root; - instance++; - } - - return instance; -} - -static int ffb_presetup(drm_device_t *); - -static int __init ffb_count_card_instances(void) -{ - int root, total, instance; - - total = ffb_count_siblings(prom_root_node); - root = prom_getchild(prom_root_node); - for (root = prom_searchsiblings(root, "upa"); root; - root = prom_searchsiblings(prom_getsibling(root), "upa")) - total += ffb_count_siblings(root); - - ffb_position = kmalloc(sizeof(ffb_position_t) * total, GFP_KERNEL); - - /* Actual failure will be caught during ffb_presetup b/c we can't catch - * it easily here. - */ - if (!ffb_position) - return -ENOMEM; - - instance = ffb_scan_siblings(prom_root_node, 0); - - root = prom_getchild(prom_root_node); - for (root = prom_searchsiblings(root, "upa"); root; - root = prom_searchsiblings(prom_getsibling(root), "upa")) - instance = ffb_scan_siblings(root, instance); - - return total; -} - -static drm_map_t *ffb_find_map(struct file *filp, unsigned long off) -{ - drm_file_t *priv = filp->private_data; - drm_device_t *dev; - drm_map_list_t *r_list; - struct list_head *list; - drm_map_t *map; - - if (!priv || (dev = priv->dev) == NULL) - return NULL; - - list_for_each(list, &dev->maplist->head) { - unsigned long uoff; - - r_list = (drm_map_list_t *)list; - map = r_list->map; - if (!map) - continue; - uoff = (map->offset & 0xffffffff); - if (uoff == off) - return map; - } - - return NULL; -} - -static unsigned long ffb_get_unmapped_area(struct file *filp, - unsigned long hint, - unsigned long len, - unsigned long pgoff, - unsigned long flags) -{ - drm_map_t *map = ffb_find_map(filp, pgoff << PAGE_SHIFT); - unsigned long addr = -ENOMEM; - - if (!map) - return get_unmapped_area(NULL, hint, len, pgoff, flags); - - if (map->type == _DRM_FRAME_BUFFER || - map->type == _DRM_REGISTERS) { -#ifdef HAVE_ARCH_FB_UNMAPPED_AREA - addr = get_fb_unmapped_area(filp, hint, len, pgoff, flags); -#else - addr = get_unmapped_area(NULL, hint, len, pgoff, flags); -#endif - } else if (map->type == _DRM_SHM && SHMLBA > PAGE_SIZE) { - unsigned long slack = SHMLBA - PAGE_SIZE; - - addr = get_unmapped_area(NULL, hint, len + slack, pgoff, flags); - if (!(addr & ~PAGE_MASK)) { - unsigned long kvirt = (unsigned long) map->handle; - - if ((kvirt & (SHMLBA - 1)) != (addr & (SHMLBA - 1))) { - unsigned long koff, aoff; - - koff = kvirt & (SHMLBA - 1); - aoff = addr & (SHMLBA - 1); - if (koff < aoff) - koff += SHMLBA; - - addr += (koff - aoff); - } - } - } else { - addr = get_unmapped_area(NULL, hint, len, pgoff, flags); - } - - return addr; -} - -static unsigned long ffb_get_reg_offset(drm_device_t *dev) -{ - ffb_dev_priv_t *ffb_priv = (ffb_dev_priv_t *)dev->dev_private; - - if (ffb_priv) - return ffb_priv->card_phys_base; - - return 0; -} - -#include "drm_auth.h" -#include "drm_bufs.h" -#include "drm_dma.h" -#include "drm_drawable.h" -#include "drm_drv.h" - -/* This functions must be here since it references DRM(numdevs) - * which drm_drv.h declares. - */ -static int ffb_presetup(drm_device_t *dev) -{ - ffb_dev_priv_t *ffb_priv; - drm_device_t *temp_dev; - int ret = 0; - int i; - - /* Check for the case where no device was found. */ - if (ffb_position == NULL) - return -ENODEV; - - /* Find our instance number by finding our device in dev structure */ - for (i = 0; i < DRM(numdevs); i++) { - temp_dev = &(DRM(device)[i]); - if(temp_dev == dev) - break; - } - - if (i == DRM(numdevs)) - return -ENODEV; - - ffb_priv = kmalloc(sizeof(ffb_dev_priv_t), GFP_KERNEL); - if (!ffb_priv) - return -ENOMEM; - memset(ffb_priv, 0, sizeof(*ffb_priv)); - dev->dev_private = ffb_priv; - - ret = ffb_init_one(dev, - ffb_position[i].node, - ffb_position[i].root, - i); - return ret; -} - -#ifndef MODULE -/* DRM(options) is called by the kernel to parse command-line options - * passed via the boot-loader (e.g., LILO). It calls the insmod option - * routine, drm_parse_drm. - */ - -/* JH- We have to hand expand the string ourselves because of the cpp. If - * anyone can think of a way that we can fit into the __setup macro without - * changing it, then please send the solution my way. - */ -static int __init ffb_options(char *str) -{ - DRM(parse_options)(str); - return 1; -} - -__setup(DRIVER_NAME "=", ffb_options); -#endif - -#include "drm_fops.h" -#include "drm_init.h" -#include "drm_ioctl.h" -#include "drm_lock.h" -#include "drm_memory.h" -#include "drm_proc.h" -#include "drm_vm.h" -#include "drm_stub.h" diff -urN linux-2.4.23-pre8/drivers/char/drm/ffb_drv.h linux-2.4.23-pre8-pac1/drivers/char/drm/ffb_drv.h --- linux-2.4.23-pre8/drivers/char/drm/ffb_drv.h 2000-06-21 19:10:02.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/ffb_drv.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,276 +0,0 @@ -/* $Id: ffb_drv.h,v 1.1 2000/06/01 04:24:39 davem Exp $ - * ffb_drv.h: Creator/Creator3D direct rendering driver. - * - * Copyright (C) 2000 David S. Miller (davem@redhat.com) - */ - -/* Auxilliary clips. */ -typedef struct { - volatile unsigned int min; - volatile unsigned int max; -} ffb_auxclip, *ffb_auxclipPtr; - -/* FFB register set. */ -typedef struct _ffb_fbc { - /* Next vertex registers, on the right we list which drawops - * use said register and the logical name the register has in - * that context. - */ /* DESCRIPTION DRAWOP(NAME) */ -/*0x00*/unsigned int pad1[3]; /* Reserved */ -/*0x0c*/volatile unsigned int alpha; /* ALPHA Transparency */ -/*0x10*/volatile unsigned int red; /* RED */ -/*0x14*/volatile unsigned int green; /* GREEN */ -/*0x18*/volatile unsigned int blue; /* BLUE */ -/*0x1c*/volatile unsigned int z; /* DEPTH */ -/*0x20*/volatile unsigned int y; /* Y triangle(DOYF) */ - /* aadot(DYF) */ - /* ddline(DYF) */ - /* aaline(DYF) */ -/*0x24*/volatile unsigned int x; /* X triangle(DOXF) */ - /* aadot(DXF) */ - /* ddline(DXF) */ - /* aaline(DXF) */ -/*0x28*/unsigned int pad2[2]; /* Reserved */ -/*0x30*/volatile unsigned int ryf; /* Y (alias to DOYF) ddline(RYF) */ - /* aaline(RYF) */ - /* triangle(RYF) */ -/*0x34*/volatile unsigned int rxf; /* X ddline(RXF) */ - /* aaline(RXF) */ - /* triangle(RXF) */ -/*0x38*/unsigned int pad3[2]; /* Reserved */ -/*0x40*/volatile unsigned int dmyf; /* Y (alias to DOYF) triangle(DMYF) */ -/*0x44*/volatile unsigned int dmxf; /* X triangle(DMXF) */ -/*0x48*/unsigned int pad4[2]; /* Reserved */ -/*0x50*/volatile unsigned int ebyi; /* Y (alias to RYI) polygon(EBYI) */ -/*0x54*/volatile unsigned int ebxi; /* X polygon(EBXI) */ -/*0x58*/unsigned int pad5[2]; /* Reserved */ -/*0x60*/volatile unsigned int by; /* Y brline(RYI) */ - /* fastfill(OP) */ - /* polygon(YI) */ - /* rectangle(YI) */ - /* bcopy(SRCY) */ - /* vscroll(SRCY) */ -/*0x64*/volatile unsigned int bx; /* X brline(RXI) */ - /* polygon(XI) */ - /* rectangle(XI) */ - /* bcopy(SRCX) */ - /* vscroll(SRCX) */ - /* fastfill(GO) */ -/*0x68*/volatile unsigned int dy; /* destination Y fastfill(DSTY) */ - /* bcopy(DSRY) */ - /* vscroll(DSRY) */ -/*0x6c*/volatile unsigned int dx; /* destination X fastfill(DSTX) */ - /* bcopy(DSTX) */ - /* vscroll(DSTX) */ -/*0x70*/volatile unsigned int bh; /* Y (alias to RYI) brline(DYI) */ - /* dot(DYI) */ - /* polygon(ETYI) */ - /* Height fastfill(H) */ - /* bcopy(H) */ - /* vscroll(H) */ - /* Y count fastfill(NY) */ -/*0x74*/volatile unsigned int bw; /* X dot(DXI) */ - /* brline(DXI) */ - /* polygon(ETXI) */ - /* fastfill(W) */ - /* bcopy(W) */ - /* vscroll(W) */ - /* fastfill(NX) */ -/*0x78*/unsigned int pad6[2]; /* Reserved */ -/*0x80*/unsigned int pad7[32]; /* Reserved */ - - /* Setup Unit's vertex state register */ -/*100*/ volatile unsigned int suvtx; -/*104*/ unsigned int pad8[63]; /* Reserved */ - - /* Frame Buffer Control Registers */ -/*200*/ volatile unsigned int ppc; /* Pixel Processor Control */ -/*204*/ volatile unsigned int wid; /* Current WID */ -/*208*/ volatile unsigned int fg; /* FG data */ -/*20c*/ volatile unsigned int bg; /* BG data */ -/*210*/ volatile unsigned int consty; /* Constant Y */ -/*214*/ volatile unsigned int constz; /* Constant Z */ -/*218*/ volatile unsigned int xclip; /* X Clip */ -/*21c*/ volatile unsigned int dcss; /* Depth Cue Scale Slope */ -/*220*/ volatile unsigned int vclipmin; /* Viewclip XY Min Bounds */ -/*224*/ volatile unsigned int vclipmax; /* Viewclip XY Max Bounds */ -/*228*/ volatile unsigned int vclipzmin; /* Viewclip Z Min Bounds */ -/*22c*/ volatile unsigned int vclipzmax; /* Viewclip Z Max Bounds */ -/*230*/ volatile unsigned int dcsf; /* Depth Cue Scale Front Bound */ -/*234*/ volatile unsigned int dcsb; /* Depth Cue Scale Back Bound */ -/*238*/ volatile unsigned int dczf; /* Depth Cue Z Front */ -/*23c*/ volatile unsigned int dczb; /* Depth Cue Z Back */ -/*240*/ unsigned int pad9; /* Reserved */ -/*244*/ volatile unsigned int blendc; /* Alpha Blend Control */ -/*248*/ volatile unsigned int blendc1; /* Alpha Blend Color 1 */ -/*24c*/ volatile unsigned int blendc2; /* Alpha Blend Color 2 */ -/*250*/ volatile unsigned int fbramitc; /* FB RAM Interleave Test Control */ -/*254*/ volatile unsigned int fbc; /* Frame Buffer Control */ -/*258*/ volatile unsigned int rop; /* Raster OPeration */ -/*25c*/ volatile unsigned int cmp; /* Frame Buffer Compare */ -/*260*/ volatile unsigned int matchab; /* Buffer AB Match Mask */ -/*264*/ volatile unsigned int matchc; /* Buffer C(YZ) Match Mask */ -/*268*/ volatile unsigned int magnab; /* Buffer AB Magnitude Mask */ -/*26c*/ volatile unsigned int magnc; /* Buffer C(YZ) Magnitude Mask */ -/*270*/ volatile unsigned int fbcfg0; /* Frame Buffer Config 0 */ -/*274*/ volatile unsigned int fbcfg1; /* Frame Buffer Config 1 */ -/*278*/ volatile unsigned int fbcfg2; /* Frame Buffer Config 2 */ -/*27c*/ volatile unsigned int fbcfg3; /* Frame Buffer Config 3 */ -/*280*/ volatile unsigned int ppcfg; /* Pixel Processor Config */ -/*284*/ volatile unsigned int pick; /* Picking Control */ -/*288*/ volatile unsigned int fillmode; /* FillMode */ -/*28c*/ volatile unsigned int fbramwac; /* FB RAM Write Address Control */ -/*290*/ volatile unsigned int pmask; /* RGB PlaneMask */ -/*294*/ volatile unsigned int xpmask; /* X PlaneMask */ -/*298*/ volatile unsigned int ypmask; /* Y PlaneMask */ -/*29c*/ volatile unsigned int zpmask; /* Z PlaneMask */ -/*2a0*/ ffb_auxclip auxclip[4]; /* Auxilliary Viewport Clip */ - - /* New 3dRAM III support regs */ -/*2c0*/ volatile unsigned int rawblend2; -/*2c4*/ volatile unsigned int rawpreblend; -/*2c8*/ volatile unsigned int rawstencil; -/*2cc*/ volatile unsigned int rawstencilctl; -/*2d0*/ volatile unsigned int threedram1; -/*2d4*/ volatile unsigned int threedram2; -/*2d8*/ volatile unsigned int passin; -/*2dc*/ volatile unsigned int rawclrdepth; -/*2e0*/ volatile unsigned int rawpmask; -/*2e4*/ volatile unsigned int rawcsrc; -/*2e8*/ volatile unsigned int rawmatch; -/*2ec*/ volatile unsigned int rawmagn; -/*2f0*/ volatile unsigned int rawropblend; -/*2f4*/ volatile unsigned int rawcmp; -/*2f8*/ volatile unsigned int rawwac; -/*2fc*/ volatile unsigned int fbramid; - -/*300*/ volatile unsigned int drawop; /* Draw OPeration */ -/*304*/ unsigned int pad10[2]; /* Reserved */ -/*30c*/ volatile unsigned int lpat; /* Line Pattern control */ -/*310*/ unsigned int pad11; /* Reserved */ -/*314*/ volatile unsigned int fontxy; /* XY Font coordinate */ -/*318*/ volatile unsigned int fontw; /* Font Width */ -/*31c*/ volatile unsigned int fontinc; /* Font Increment */ -/*320*/ volatile unsigned int font; /* Font bits */ -/*324*/ unsigned int pad12[3]; /* Reserved */ -/*330*/ volatile unsigned int blend2; -/*334*/ volatile unsigned int preblend; -/*338*/ volatile unsigned int stencil; -/*33c*/ volatile unsigned int stencilctl; - -/*340*/ unsigned int pad13[4]; /* Reserved */ -/*350*/ volatile unsigned int dcss1; /* Depth Cue Scale Slope 1 */ -/*354*/ volatile unsigned int dcss2; /* Depth Cue Scale Slope 2 */ -/*358*/ volatile unsigned int dcss3; /* Depth Cue Scale Slope 3 */ -/*35c*/ volatile unsigned int widpmask; -/*360*/ volatile unsigned int dcs2; -/*364*/ volatile unsigned int dcs3; -/*368*/ volatile unsigned int dcs4; -/*36c*/ unsigned int pad14; /* Reserved */ -/*370*/ volatile unsigned int dcd2; -/*374*/ volatile unsigned int dcd3; -/*378*/ volatile unsigned int dcd4; -/*37c*/ unsigned int pad15; /* Reserved */ -/*380*/ volatile unsigned int pattern[32]; /* area Pattern */ -/*400*/ unsigned int pad16[8]; /* Reserved */ -/*420*/ volatile unsigned int reset; /* chip RESET */ -/*424*/ unsigned int pad17[247]; /* Reserved */ -/*800*/ volatile unsigned int devid; /* Device ID */ -/*804*/ unsigned int pad18[63]; /* Reserved */ -/*900*/ volatile unsigned int ucsr; /* User Control & Status Register */ -/*904*/ unsigned int pad19[31]; /* Reserved */ -/*980*/ volatile unsigned int mer; /* Mode Enable Register */ -/*984*/ unsigned int pad20[1439]; /* Reserved */ -} ffb_fbc, *ffb_fbcPtr; - -struct ffb_hw_context { - int is_2d_only; - - unsigned int ppc; - unsigned int wid; - unsigned int fg; - unsigned int bg; - unsigned int consty; - unsigned int constz; - unsigned int xclip; - unsigned int dcss; - unsigned int vclipmin; - unsigned int vclipmax; - unsigned int vclipzmin; - unsigned int vclipzmax; - unsigned int dcsf; - unsigned int dcsb; - unsigned int dczf; - unsigned int dczb; - unsigned int blendc; - unsigned int blendc1; - unsigned int blendc2; - unsigned int fbc; - unsigned int rop; - unsigned int cmp; - unsigned int matchab; - unsigned int matchc; - unsigned int magnab; - unsigned int magnc; - unsigned int pmask; - unsigned int xpmask; - unsigned int ypmask; - unsigned int zpmask; - unsigned int auxclip0min; - unsigned int auxclip0max; - unsigned int auxclip1min; - unsigned int auxclip1max; - unsigned int auxclip2min; - unsigned int auxclip2max; - unsigned int auxclip3min; - unsigned int auxclip3max; - unsigned int drawop; - unsigned int lpat; - unsigned int fontxy; - unsigned int fontw; - unsigned int fontinc; - unsigned int area_pattern[32]; - unsigned int ucsr; - unsigned int stencil; - unsigned int stencilctl; - unsigned int dcss1; - unsigned int dcss2; - unsigned int dcss3; - unsigned int dcs2; - unsigned int dcs3; - unsigned int dcs4; - unsigned int dcd2; - unsigned int dcd3; - unsigned int dcd4; - unsigned int mer; -}; - -#define FFB_MAX_CTXS 32 - -enum ffb_chip_type { - ffb1_prototype = 0, /* Early pre-FCS FFB */ - ffb1_standard, /* First FCS FFB, 100Mhz UPA, 66MHz gclk */ - ffb1_speedsort, /* Second FCS FFB, 100Mhz UPA, 75MHz gclk */ - ffb2_prototype, /* Early pre-FCS vertical FFB2 */ - ffb2_vertical, /* First FCS FFB2/vertical, 100Mhz UPA, 100MHZ gclk, - 75(SingleBuffer)/83(DoubleBuffer) MHz fclk */ - ffb2_vertical_plus, /* Second FCS FFB2/vertical, same timings */ - ffb2_horizontal, /* First FCS FFB2/horizontal, same timings as FFB2/vert */ - ffb2_horizontal_plus, /* Second FCS FFB2/horizontal, same timings */ - afb_m3, /* FCS Elite3D, 3 float chips */ - afb_m6 /* FCS Elite3D, 6 float chips */ -}; - -typedef struct ffb_dev_priv { - /* Misc software state. */ - int prom_node; - enum ffb_chip_type ffb_type; - u64 card_phys_base; - struct miscdevice miscdev; - - /* Controller registers. */ - ffb_fbcPtr regs; - - /* Context table. */ - struct ffb_hw_context *hw_state[FFB_MAX_CTXS]; -} ffb_dev_priv_t; diff -urN linux-2.4.23-pre8/drivers/char/drm/gamma.h linux-2.4.23-pre8-pac1/drivers/char/drm/gamma.h --- linux-2.4.23-pre8/drivers/char/drm/gamma.h 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/gamma.h 2003-06-30 00:32:46.000000000 +0200 @@ -63,6 +63,12 @@ #define __HAVE_COUNTER9 _DRM_STAT_SPECIAL #define __HAVE_COUNTER10 _DRM_STAT_MISSED +/* Driver customization: + */ +#define DRIVER_PRETAKEDOWN() do { \ + gamma_do_cleanup_dma( dev ); \ +} while (0) + /* DMA customization: */ #define __HAVE_DMA 1 @@ -71,6 +77,9 @@ #define __HAVE_OLD_DMA 1 #define __HAVE_PCI_DMA 1 +#define __HAVE_DRIVER_FOPS_READ 1 +#define __HAVE_DRIVER_FOPS_POLL 1 + #define __HAVE_MULTIPLE_DMA_QUEUES 1 #define __HAVE_DMA_WAITQUEUE 1 @@ -87,62 +96,19 @@ #define __HAVE_DMA_QUIESCENT 1 #define DRIVER_DMA_QUIESCENT() do { \ - /* FIXME ! */ \ - gamma_dma_quiescent_single(dev); \ + drm_gamma_private_t *dev_priv = \ + (drm_gamma_private_t *)dev->dev_private; \ + if (dev_priv->num_rast == 2) \ + gamma_dma_quiescent_dual(dev); \ + else gamma_dma_quiescent_single(dev); \ return 0; \ } while (0) #define __HAVE_DMA_IRQ 1 #define __HAVE_DMA_IRQ_BH 1 -#if 1 -#define DRIVER_PREINSTALL() do { \ - drm_gamma_private_t *dev_priv = \ - (drm_gamma_private_t *)dev->dev_private;\ - while(GAMMA_READ(GAMMA_INFIFOSPACE) < 2) cpu_relax(); \ - GAMMA_WRITE( GAMMA_GCOMMANDMODE, 0x00000004 ); \ - GAMMA_WRITE( GAMMA_GDMACONTROL, 0x00000000 ); \ -} while (0) -#define DRIVER_POSTINSTALL() do { \ - drm_gamma_private_t *dev_priv = \ - (drm_gamma_private_t *)dev->dev_private;\ - while(GAMMA_READ(GAMMA_INFIFOSPACE) < 2) cpu_relax(); \ - while(GAMMA_READ(GAMMA_INFIFOSPACE) < 3) cpu_relax(); \ - GAMMA_WRITE( GAMMA_GINTENABLE, 0x00002001 ); \ - GAMMA_WRITE( GAMMA_COMMANDINTENABLE, 0x00000008 ); \ - GAMMA_WRITE( GAMMA_GDELAYTIMER, 0x00039090 ); \ -} while (0) -#else -#define DRIVER_POSTINSTALL() do { \ - drm_gamma_private_t *dev_priv = \ - (drm_gamma_private_t *)dev->dev_private;\ - while(GAMMA_READ(GAMMA_INFIFOSPACE) < 2) cpu_relax(); \ - while(GAMMA_READ(GAMMA_INFIFOSPACE) < 2) cpu_relax(); \ - GAMMA_WRITE( GAMMA_GINTENABLE, 0x00002000 ); \ - GAMMA_WRITE( GAMMA_COMMANDINTENABLE, 0x00000004 ); \ -} while (0) - -#define DRIVER_PREINSTALL() do { \ - drm_gamma_private_t *dev_priv = \ - (drm_gamma_private_t *)dev->dev_private;\ - while(GAMMA_READ(GAMMA_INFIFOSPACE) < 2) cpu_relax(); \ - while(GAMMA_READ(GAMMA_INFIFOSPACE) < 2) cpu_relax(); \ - GAMMA_WRITE( GAMMA_GCOMMANDMODE, GAMMA_QUEUED_DMA_MODE );\ - GAMMA_WRITE( GAMMA_GDMACONTROL, 0x00000000 );\ -} while (0) -#endif - -#define DRIVER_UNINSTALL() do { \ - drm_gamma_private_t *dev_priv = \ - (drm_gamma_private_t *)dev->dev_private;\ - while(GAMMA_READ(GAMMA_INFIFOSPACE) < 2) cpu_relax(); \ - while(GAMMA_READ(GAMMA_INFIFOSPACE) < 3) cpu_relax(); \ - GAMMA_WRITE( GAMMA_GDELAYTIMER, 0x00000000 ); \ - GAMMA_WRITE( GAMMA_COMMANDINTENABLE, 0x00000000 ); \ - GAMMA_WRITE( GAMMA_GINTENABLE, 0x00000000 ); \ -} while (0) - #define DRIVER_AGP_BUFFERS_MAP( dev ) \ ((drm_gamma_private_t *)((dev)->dev_private))->buffers + #endif /* __GAMMA_H__ */ diff -urN linux-2.4.23-pre8/drivers/char/drm/gamma_context.h linux-2.4.23-pre8-pac1/drivers/char/drm/gamma_context.h --- linux-2.4.23-pre8/drivers/char/drm/gamma_context.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/gamma_context.h 2003-06-30 00:32:46.000000000 +0200 @@ -0,0 +1,489 @@ +/* drm_context.h -- IOCTLs for generic contexts -*- linux-c -*- + * Created: Fri Nov 24 18:31:37 2000 by gareth@valinux.com + * + * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * 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 + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * 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 + * Gareth Hughes + * ChangeLog: + * 2001-11-16 Torsten Duwe + * added context constructor/destructor hooks, + * needed by SiS driver's memory management. + */ + +/* ================================================================ + * Old-style context support -- only used by gamma. + */ + + +/* The drm_read and drm_write_string code (especially that which manages + the circular buffer), is based on Alessandro Rubini's LINUX DEVICE + DRIVERS (Cambridge: O'Reilly, 1998), pages 111-113. */ + +ssize_t DRM(read)(struct file *filp, char *buf, size_t count, loff_t *off) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + int left; + int avail; + int send; + int cur; + + DRM_DEBUG("%p, %p\n", dev->buf_rp, dev->buf_wp); + + while (dev->buf_rp == dev->buf_wp) { + DRM_DEBUG(" sleeping\n"); + if (filp->f_flags & O_NONBLOCK) { + return -EAGAIN; + } + interruptible_sleep_on(&dev->buf_readers); + if (signal_pending(current)) { + DRM_DEBUG(" interrupted\n"); + return -ERESTARTSYS; + } + DRM_DEBUG(" awake\n"); + } + + left = (dev->buf_rp + DRM_BSZ - dev->buf_wp) % DRM_BSZ; + avail = DRM_BSZ - left; + send = DRM_MIN(avail, count); + + while (send) { + if (dev->buf_wp > dev->buf_rp) { + cur = DRM_MIN(send, dev->buf_wp - dev->buf_rp); + } else { + cur = DRM_MIN(send, dev->buf_end - dev->buf_rp); + } + if (copy_to_user(buf, dev->buf_rp, cur)) + return -EFAULT; + dev->buf_rp += cur; + if (dev->buf_rp == dev->buf_end) dev->buf_rp = dev->buf; + send -= cur; + } + + wake_up_interruptible(&dev->buf_writers); + return DRM_MIN(avail, count);; +} + + +/* In an incredibly convoluted setup, the kernel module actually calls + * back into the X server to perform context switches on behalf of the + * 3d clients. + */ +int DRM(write_string)(drm_device_t *dev, const char *s) +{ + int left = (dev->buf_rp + DRM_BSZ - dev->buf_wp) % DRM_BSZ; + int send = strlen(s); + int count; + + DRM_DEBUG("%d left, %d to send (%p, %p)\n", + left, send, dev->buf_rp, dev->buf_wp); + + if (left == 1 || dev->buf_wp != dev->buf_rp) { + DRM_ERROR("Buffer not empty (%d left, wp = %p, rp = %p)\n", + left, + dev->buf_wp, + dev->buf_rp); + } + + while (send) { + if (dev->buf_wp >= dev->buf_rp) { + count = DRM_MIN(send, dev->buf_end - dev->buf_wp); + if (count == left) --count; /* Leave a hole */ + } else { + count = DRM_MIN(send, dev->buf_rp - dev->buf_wp - 1); + } + strncpy(dev->buf_wp, s, count); + dev->buf_wp += count; + if (dev->buf_wp == dev->buf_end) dev->buf_wp = dev->buf; + send -= count; + } + + if (dev->buf_async) kill_fasync(&dev->buf_async, SIGIO, POLL_IN); + + DRM_DEBUG("waking\n"); + wake_up_interruptible(&dev->buf_readers); + return 0; +} + +unsigned int DRM(poll)(struct file *filp, struct poll_table_struct *wait) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + + poll_wait(filp, &dev->buf_readers, wait); + if (dev->buf_wp != dev->buf_rp) return POLLIN | POLLRDNORM; + return 0; +} + +int DRM(context_switch)(drm_device_t *dev, int old, int new) +{ + char buf[64]; + drm_queue_t *q; + + if (test_and_set_bit(0, &dev->context_flag)) { + DRM_ERROR("Reentering -- FIXME\n"); + return -EBUSY; + } + + DRM_DEBUG("Context switch from %d to %d\n", old, new); + + if (new >= dev->queue_count) { + clear_bit(0, &dev->context_flag); + return -EINVAL; + } + + if (new == dev->last_context) { + clear_bit(0, &dev->context_flag); + return 0; + } + + q = dev->queuelist[new]; + atomic_inc(&q->use_count); + if (atomic_read(&q->use_count) == 1) { + atomic_dec(&q->use_count); + clear_bit(0, &dev->context_flag); + return -EINVAL; + } + + /* This causes the X server to wake up & do a bunch of hardware + * interaction to actually effect the context switch. + */ + sprintf(buf, "C %d %d\n", old, new); + DRM(write_string)(dev, buf); + + atomic_dec(&q->use_count); + + return 0; +} + +int DRM(context_switch_complete)(drm_device_t *dev, int new) +{ + drm_device_dma_t *dma = dev->dma; + + dev->last_context = new; /* PRE/POST: This is the _only_ writer. */ + dev->last_switch = jiffies; + + if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("Lock isn't held after context switch\n"); + } + + if (!dma || !(dma->next_buffer && dma->next_buffer->while_locked)) { + if (DRM(lock_free)(dev, &dev->lock.hw_lock->lock, + DRM_KERNEL_CONTEXT)) { + DRM_ERROR("Cannot free lock\n"); + } + } + + clear_bit(0, &dev->context_flag); + wake_up_interruptible(&dev->context_wait); + + return 0; +} + +static int DRM(init_queue)(drm_device_t *dev, drm_queue_t *q, drm_ctx_t *ctx) +{ + DRM_DEBUG("\n"); + + if (atomic_read(&q->use_count) != 1 + || atomic_read(&q->finalization) + || atomic_read(&q->block_count)) { + DRM_ERROR("New queue is already in use: u%d f%d b%d\n", + atomic_read(&q->use_count), + atomic_read(&q->finalization), + atomic_read(&q->block_count)); + } + + atomic_set(&q->finalization, 0); + atomic_set(&q->block_count, 0); + atomic_set(&q->block_read, 0); + atomic_set(&q->block_write, 0); + atomic_set(&q->total_queued, 0); + atomic_set(&q->total_flushed, 0); + atomic_set(&q->total_locks, 0); + + init_waitqueue_head(&q->write_queue); + init_waitqueue_head(&q->read_queue); + init_waitqueue_head(&q->flush_queue); + + q->flags = ctx->flags; + + DRM(waitlist_create)(&q->waitlist, dev->dma->buf_count); + + return 0; +} + + +/* drm_alloc_queue: +PRE: 1) dev->queuelist[0..dev->queue_count] is allocated and will not + disappear (so all deallocation must be done after IOCTLs are off) + 2) dev->queue_count < dev->queue_slots + 3) dev->queuelist[i].use_count == 0 and + dev->queuelist[i].finalization == 0 if i not in use +POST: 1) dev->queuelist[i].use_count == 1 + 2) dev->queue_count < dev->queue_slots */ + +static int DRM(alloc_queue)(drm_device_t *dev) +{ + int i; + drm_queue_t *queue; + int oldslots; + int newslots; + /* Check for a free queue */ + for (i = 0; i < dev->queue_count; i++) { + atomic_inc(&dev->queuelist[i]->use_count); + if (atomic_read(&dev->queuelist[i]->use_count) == 1 + && !atomic_read(&dev->queuelist[i]->finalization)) { + DRM_DEBUG("%d (free)\n", i); + return i; + } + atomic_dec(&dev->queuelist[i]->use_count); + } + /* Allocate a new queue */ + down(&dev->struct_sem); + + queue = DRM(alloc)(sizeof(*queue), DRM_MEM_QUEUES); + memset(queue, 0, sizeof(*queue)); + atomic_set(&queue->use_count, 1); + + ++dev->queue_count; + if (dev->queue_count >= dev->queue_slots) { + oldslots = dev->queue_slots * sizeof(*dev->queuelist); + if (!dev->queue_slots) dev->queue_slots = 1; + dev->queue_slots *= 2; + newslots = dev->queue_slots * sizeof(*dev->queuelist); + + dev->queuelist = DRM(realloc)(dev->queuelist, + oldslots, + newslots, + DRM_MEM_QUEUES); + if (!dev->queuelist) { + up(&dev->struct_sem); + DRM_DEBUG("out of memory\n"); + return -ENOMEM; + } + } + dev->queuelist[dev->queue_count-1] = queue; + + up(&dev->struct_sem); + DRM_DEBUG("%d (new)\n", dev->queue_count - 1); + return dev->queue_count - 1; +} + +int DRM(resctx)(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_ctx_res_t res; + 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) { + memset(&ctx, 0, sizeof(ctx)); + for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) { + ctx.handle = i; + if (copy_to_user(&res.contexts[i], + &i, + sizeof(i))) + return -EFAULT; + } + } + res.count = DRM_RESERVED_CONTEXTS; + if (copy_to_user((drm_ctx_res_t *)arg, &res, sizeof(res))) + return -EFAULT; + return 0; +} + +int DRM(addctx)(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_ctx_t ctx; + + if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) + return -EFAULT; + if ((ctx.handle = DRM(alloc_queue)(dev)) == DRM_KERNEL_CONTEXT) { + /* Init kernel's context and get a new one. */ + DRM(init_queue)(dev, dev->queuelist[ctx.handle], &ctx); + ctx.handle = DRM(alloc_queue)(dev); + } + DRM(init_queue)(dev, dev->queuelist[ctx.handle], &ctx); + DRM_DEBUG("%d\n", ctx.handle); + if (copy_to_user((drm_ctx_t *)arg, &ctx, sizeof(ctx))) + return -EFAULT; + return 0; +} + +int DRM(modctx)(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_ctx_t ctx; + drm_queue_t *q; + + if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) + return -EFAULT; + + DRM_DEBUG("%d\n", ctx.handle); + + if (ctx.handle < 0 || ctx.handle >= dev->queue_count) return -EINVAL; + q = dev->queuelist[ctx.handle]; + + atomic_inc(&q->use_count); + if (atomic_read(&q->use_count) == 1) { + /* No longer in use */ + atomic_dec(&q->use_count); + return -EINVAL; + } + + if (DRM_BUFCOUNT(&q->waitlist)) { + atomic_dec(&q->use_count); + return -EBUSY; + } + + q->flags = ctx.flags; + + atomic_dec(&q->use_count); + return 0; +} + +int DRM(getctx)(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_ctx_t ctx; + drm_queue_t *q; + + if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) + return -EFAULT; + + DRM_DEBUG("%d\n", ctx.handle); + + if (ctx.handle >= dev->queue_count) return -EINVAL; + q = dev->queuelist[ctx.handle]; + + atomic_inc(&q->use_count); + if (atomic_read(&q->use_count) == 1) { + /* No longer in use */ + atomic_dec(&q->use_count); + return -EINVAL; + } + + ctx.flags = q->flags; + atomic_dec(&q->use_count); + + if (copy_to_user((drm_ctx_t *)arg, &ctx, sizeof(ctx))) + return -EFAULT; + + return 0; +} + +int DRM(switchctx)(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_ctx_t ctx; + + if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) + return -EFAULT; + DRM_DEBUG("%d\n", ctx.handle); + return DRM(context_switch)(dev, dev->last_context, ctx.handle); +} + +int DRM(newctx)(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_ctx_t ctx; + + if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) + return -EFAULT; + DRM_DEBUG("%d\n", ctx.handle); + DRM(context_switch_complete)(dev, ctx.handle); + + return 0; +} + +int DRM(rmctx)(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_ctx_t ctx; + drm_queue_t *q; + drm_buf_t *buf; + + if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx))) + return -EFAULT; + DRM_DEBUG("%d\n", ctx.handle); + + if (ctx.handle >= dev->queue_count) return -EINVAL; + q = dev->queuelist[ctx.handle]; + + atomic_inc(&q->use_count); + if (atomic_read(&q->use_count) == 1) { + /* No longer in use */ + atomic_dec(&q->use_count); + return -EINVAL; + } + + atomic_inc(&q->finalization); /* Mark queue in finalization state */ + atomic_sub(2, &q->use_count); /* Mark queue as unused (pending + finalization) */ + + while (test_and_set_bit(0, &dev->interrupt_flag)) { + schedule(); + if (signal_pending(current)) { + clear_bit(0, &dev->interrupt_flag); + return -EINTR; + } + } + /* Remove queued buffers */ + while ((buf = DRM(waitlist_get)(&q->waitlist))) { + DRM(free_buffer)(dev, buf); + } + clear_bit(0, &dev->interrupt_flag); + + /* Wakeup blocked processes */ + wake_up_interruptible(&q->read_queue); + wake_up_interruptible(&q->write_queue); + wake_up_interruptible(&q->flush_queue); + + /* Finalization over. Queue is made + available when both use_count and + finalization become 0, which won't + happen until all the waiting processes + stop waiting. */ + atomic_dec(&q->finalization); + return 0; +} + diff -urN linux-2.4.23-pre8/drivers/char/drm/gamma_dma.c linux-2.4.23-pre8-pac1/drivers/char/drm/gamma_dma.c --- linux-2.4.23-pre8/drivers/char/drm/gamma_dma.c 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/gamma_dma.c 2003-08-18 12:56:12.000000000 +0200 @@ -29,6 +29,7 @@ * */ +#define __NO_VERSION__ #include "gamma.h" #include "drmP.h" #include "drm.h" @@ -44,9 +45,9 @@ drm_gamma_private_t *dev_priv = (drm_gamma_private_t *)dev->dev_private; mb(); - while ( GAMMA_READ(GAMMA_INFIFOSPACE) < 2) cpu_relax(); + while ( GAMMA_READ(GAMMA_INFIFOSPACE) < 2); GAMMA_WRITE(GAMMA_DMAADDRESS, address); - while (GAMMA_READ(GAMMA_GCOMMANDSTATUS) != 4) cpu_relax(); + while (GAMMA_READ(GAMMA_GCOMMANDSTATUS) != 4); GAMMA_WRITE(GAMMA_DMACOUNT, length / 4); } @@ -54,9 +55,9 @@ { drm_gamma_private_t *dev_priv = (drm_gamma_private_t *)dev->dev_private; - while (GAMMA_READ(GAMMA_DMACOUNT)) cpu_relax(); + while (GAMMA_READ(GAMMA_DMACOUNT)); - while (GAMMA_READ(GAMMA_INFIFOSPACE) < 2) cpu_relax(); + while (GAMMA_READ(GAMMA_INFIFOSPACE) < 2); GAMMA_WRITE(GAMMA_FILTERMODE, 1 << 10); GAMMA_WRITE(GAMMA_SYNC, 0); @@ -71,9 +72,9 @@ { drm_gamma_private_t *dev_priv = (drm_gamma_private_t *)dev->dev_private; - while (GAMMA_READ(GAMMA_DMACOUNT)) cpu_relax(); + while (GAMMA_READ(GAMMA_DMACOUNT)); - while (GAMMA_READ(GAMMA_INFIFOSPACE) < 3) cpu_relax(); + while (GAMMA_READ(GAMMA_INFIFOSPACE) < 3); GAMMA_WRITE(GAMMA_BROADCASTMASK, 3); GAMMA_WRITE(GAMMA_FILTERMODE, 1 << 10); @@ -81,12 +82,12 @@ /* Read from first MX */ do { - while (!GAMMA_READ(GAMMA_OUTFIFOWORDS)) cpu_relax(); + while (!GAMMA_READ(GAMMA_OUTFIFOWORDS)); } while (GAMMA_READ(GAMMA_OUTPUTFIFO) != GAMMA_SYNC_TAG); /* Read from second MX */ do { - while (!GAMMA_READ(GAMMA_OUTFIFOWORDS + 0x10000)) cpu_relax(); + while (!GAMMA_READ(GAMMA_OUTFIFOWORDS + 0x10000)); } while (GAMMA_READ(GAMMA_OUTPUTFIFO + 0x10000) != GAMMA_SYNC_TAG); } @@ -94,7 +95,7 @@ { drm_gamma_private_t *dev_priv = (drm_gamma_private_t *)dev->dev_private; - while (GAMMA_READ(GAMMA_DMACOUNT)) cpu_relax(); + while (GAMMA_READ(GAMMA_DMACOUNT)); } static inline int gamma_dma_is_ready(drm_device_t *dev) @@ -104,32 +105,38 @@ return(!GAMMA_READ(GAMMA_DMACOUNT)); } -void gamma_dma_service(int irq, void *device, struct pt_regs *regs) +irqreturn_t gamma_dma_service( DRM_IRQ_ARGS ) { - drm_device_t *dev = (drm_device_t *)device; + drm_device_t *dev = (drm_device_t *)arg; drm_device_dma_t *dma = dev->dma; drm_gamma_private_t *dev_priv = (drm_gamma_private_t *)dev->dev_private; + /* FIXME: should check whether we're actually interested in the interrupt? */ atomic_inc(&dev->counts[6]); /* _DRM_STAT_IRQ */ - while (GAMMA_READ(GAMMA_INFIFOSPACE) < 3) cpu_relax(); + while (GAMMA_READ(GAMMA_INFIFOSPACE) < 3); GAMMA_WRITE(GAMMA_GDELAYTIMER, 0xc350/2); /* 0x05S */ GAMMA_WRITE(GAMMA_GCOMMANDINTFLAGS, 8); GAMMA_WRITE(GAMMA_GINTFLAGS, 0x2001); if (gamma_dma_is_ready(dev)) { /* Free previous buffer */ - if (test_and_set_bit(0, &dev->dma_flag)) return; + if (test_and_set_bit(0, &dev->dma_flag)) return IRQ_HANDLED; if (dma->this_buffer) { gamma_free_buffer(dev, dma->this_buffer); dma->this_buffer = NULL; } clear_bit(0, &dev->dma_flag); +#if !HAS_WORKQUEUE /* Dispatch new buffer */ queue_task(&dev->tq, &tq_immediate); mark_bh(IMMEDIATE_BH); +#else + schedule_work(&dev->work); +#endif } + return IRQ_HANDLED; } /* Only called by gamma_dma_schedule. */ @@ -140,15 +147,9 @@ drm_buf_t *buf; int retcode = 0; drm_device_dma_t *dma = dev->dma; -#if DRM_DMA_HISTOGRAM - cycles_t dma_start, dma_stop; -#endif if (test_and_set_bit(0, &dev->dma_flag)) return -EBUSY; -#if DRM_DMA_HISTOGRAM - dma_start = get_cycles(); -#endif if (!dma->next_buffer) { DRM_ERROR("No next_buffer\n"); @@ -189,7 +190,7 @@ if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { DRM_ERROR("Dispatching buffer %d from pid %d" " \"while locked\", but no lock held\n", - buf->idx, buf->pid); + buf->idx, current->pid); } } else { if (!locked && !gamma_lock_take(&dev->lock.hw_lock->lock, @@ -222,9 +223,6 @@ buf->pending = 1; buf->waiting = 0; buf->list = DRM_LIST_PEND; -#if DRM_DMA_HISTOGRAM - buf->time_dispatched = get_cycles(); -#endif /* WE NOW ARE ON LOGICAL PAGES!!! - overriding address */ address = buf->idx << 12; @@ -246,10 +244,6 @@ clear_bit(0, &dev->dma_flag); -#if DRM_DMA_HISTOGRAM - dma_stop = get_cycles(); - atomic_inc(&dev->histo.dma[gamma_histogram_slot(dma_stop - dma_start)]); -#endif return retcode; } @@ -274,9 +268,6 @@ int missed; int expire = 20; drm_device_dma_t *dma = dev->dma; -#if DRM_DMA_HISTOGRAM - cycles_t schedule_start; -#endif if (test_and_set_bit(0, &dev->interrupt_flag)) { /* Not reentrant */ @@ -285,9 +276,6 @@ } missed = atomic_read(&dev->counts[10]); -#if DRM_DMA_HISTOGRAM - schedule_start = get_cycles(); -#endif again: if (dev->context_flag) { @@ -334,14 +322,11 @@ clear_bit(0, &dev->interrupt_flag); -#if DRM_DMA_HISTOGRAM - atomic_inc(&dev->histo.schedule[gamma_histogram_slot(get_cycles() - - schedule_start)]); -#endif return retcode; } -static int gamma_dma_priority(drm_device_t *dev, drm_dma_t *d) +static int gamma_dma_priority(struct file *filp, + drm_device_t *dev, drm_dma_t *d) { unsigned long address; unsigned long length; @@ -379,15 +364,15 @@ continue; } buf = dma->buflist[ idx ]; - if (buf->pid != current->pid) { - DRM_ERROR("Process %d using buffer owned by %d\n", - current->pid, buf->pid); + if (buf->filp != filp) { + DRM_ERROR("Process %d using buffer not owned\n", + current->pid); retcode = -EINVAL; goto cleanup; } if (buf->list != DRM_LIST_NONE) { - DRM_ERROR("Process %d using %d's buffer on list %d\n", - current->pid, buf->pid, buf->list); + DRM_ERROR("Process %d using buffer on list %d\n", + current->pid, buf->list); retcode = -EINVAL; goto cleanup; } @@ -448,10 +433,6 @@ } } -#if DRM_DMA_HISTOGRAM - buf->time_queued = get_cycles(); - buf->time_dispatched = buf->time_queued; -#endif gamma_dma_dispatch(dev, address, length); atomic_inc(&dev->counts[9]); /* _DRM_STAT_SPECIAL */ atomic_add(length, &dev->counts[8]); /* _DRM_STAT_PRIMARY */ @@ -479,7 +460,8 @@ return retcode; } -static int gamma_dma_send_buffers(drm_device_t *dev, drm_dma_t *d) +static int gamma_dma_send_buffers(struct file *filp, + drm_device_t *dev, drm_dma_t *d) { DECLARE_WAITQUEUE(entry, current); drm_buf_t *last_buf = NULL; @@ -491,7 +473,7 @@ add_wait_queue(&last_buf->dma_wait, &entry); } - if ((retcode = gamma_dma_enqueue(dev, d))) { + if ((retcode = gamma_dma_enqueue(filp, d))) { if (d->flags & _DRM_DMA_BLOCK) remove_wait_queue(&last_buf->dma_wait, &entry); return retcode; @@ -521,14 +503,13 @@ } } if (retcode) { - DRM_ERROR("ctx%d w%d p%d c%ld i%d l%d %d/%d\n", + DRM_ERROR("ctx%d w%d p%d c%ld i%d l%d pid:%d\n", d->context, last_buf->waiting, last_buf->pending, (long)DRM_WAITCOUNT(dev, d->context), last_buf->idx, last_buf->list, - last_buf->pid, current->pid); } } @@ -561,15 +542,15 @@ if (d.send_count) { if (d.flags & _DRM_DMA_PRIORITY) - retcode = gamma_dma_priority(dev, &d); + retcode = gamma_dma_priority(filp, dev, &d); else - retcode = gamma_dma_send_buffers(dev, &d); + retcode = gamma_dma_send_buffers(filp, dev, &d); } d.granted_count = 0; if (!retcode && d.request_count) { - retcode = gamma_dma_get_buffers(dev, &d); + retcode = gamma_dma_get_buffers(filp, &d); } DRM_DEBUG("%d returning, granted = %d\n", @@ -604,9 +585,10 @@ memset( dev_priv, 0, sizeof(drm_gamma_private_t) ); + dev_priv->num_rast = init->num_rast; + list_for_each(list, &dev->maplist->head) { - #warning list_entry() is needed here - drm_map_list_t *r_list = (drm_map_list_t *)list; + drm_map_list_t *r_list = list_entry(list, drm_map_list_t, head); if( r_list->map && r_list->map->type == _DRM_SHM && r_list->map->flags & _DRM_CONTAINS_LOCK ) { @@ -638,7 +620,7 @@ } else { DRM_FIND_MAP( dev_priv->buffers, init->buffers_offset ); - DRM_IOREMAP( dev_priv->buffers ); + DRM_IOREMAP( dev_priv->buffers, dev ); buf = dma->buflist[GLINT_DRI_BUF_COUNT]; pgt = buf->address; @@ -651,10 +633,10 @@ buf = dma->buflist[GLINT_DRI_BUF_COUNT]; - while (GAMMA_READ(GAMMA_INFIFOSPACE) < 1) cpu_relax(); - GAMMA_WRITE( GAMMA_GDMACONTROL, 0xe) ; + while (GAMMA_READ(GAMMA_INFIFOSPACE) < 1); + GAMMA_WRITE( GAMMA_GDMACONTROL, 0xe); } - while (GAMMA_READ(GAMMA_INFIFOSPACE) < 2); cpu_relax(); + while (GAMMA_READ(GAMMA_INFIFOSPACE) < 2); GAMMA_WRITE( GAMMA_PAGETABLEADDR, virt_to_phys((void*)buf->address) ); GAMMA_WRITE( GAMMA_PAGETABLELENGTH, 2 ); @@ -665,10 +647,19 @@ { DRM_DEBUG( "%s\n", __FUNCTION__ ); +#if _HAVE_DMA_IRQ + /* Make sure interrupts are disabled here because the uninstall ioctl + * may not have been called from userspace and after dev_private + * is freed, it's too late. + */ + if ( dev->irq ) DRM(irq_uninstall)(dev); +#endif + if ( dev->dev_private ) { drm_gamma_private_t *dev_priv = dev->dev_private; - DRM_IOREMAPFREE( dev_priv->buffers ); + if ( dev_priv->buffers != NULL ) + DRM_IOREMAPFREE( dev_priv->buffers, dev ); DRM(free)( dev->dev_private, sizeof(drm_gamma_private_t), DRM_MEM_DRIVER ); @@ -685,6 +676,8 @@ drm_device_t *dev = priv->dev; drm_gamma_init_t init; + LOCK_TEST_WITH_RETURN( dev, filp ); + if ( copy_from_user( &init, (drm_gamma_init_t *)arg, sizeof(init) ) ) return -EFAULT; @@ -810,7 +803,7 @@ down(&dev->struct_sem); r_list = NULL; list_for_each(list, &dev->maplist->head) { - r_list = (drm_map_list_t *)list; + r_list = list_entry(list, drm_map_list_t, head); if(r_list->map && r_list->map->handle == request.handle) break; } @@ -833,13 +826,36 @@ return 0; } -/* drm_dma.h hooks -*/ void DRM(driver_irq_preinstall)( drm_device_t *dev ) { + drm_gamma_private_t *dev_priv = + (drm_gamma_private_t *)dev->dev_private; + + while(GAMMA_READ(GAMMA_INFIFOSPACE) < 2); + + GAMMA_WRITE( GAMMA_GCOMMANDMODE, 0x00000004 ); + GAMMA_WRITE( GAMMA_GDMACONTROL, 0x00000000 ); } void DRM(driver_irq_postinstall)( drm_device_t *dev ) { + drm_gamma_private_t *dev_priv = + (drm_gamma_private_t *)dev->dev_private; + + while(GAMMA_READ(GAMMA_INFIFOSPACE) < 3); + + GAMMA_WRITE( GAMMA_GINTENABLE, 0x00002001 ); + GAMMA_WRITE( GAMMA_COMMANDINTENABLE, 0x00000008 ); + GAMMA_WRITE( GAMMA_GDELAYTIMER, 0x00039090 ); } void DRM(driver_irq_uninstall)( drm_device_t *dev ) { + drm_gamma_private_t *dev_priv = + (drm_gamma_private_t *)dev->dev_private; + if (!dev_priv) + return; + + while(GAMMA_READ(GAMMA_INFIFOSPACE) < 3); + + GAMMA_WRITE( GAMMA_GDELAYTIMER, 0x00000000 ); + GAMMA_WRITE( GAMMA_COMMANDINTENABLE, 0x00000000 ); + GAMMA_WRITE( GAMMA_GINTENABLE, 0x00000000 ); } diff -urN linux-2.4.23-pre8/drivers/char/drm/gamma_drm.h linux-2.4.23-pre8-pac1/drivers/char/drm/gamma_drm.h --- linux-2.4.23-pre8/drivers/char/drm/gamma_drm.h 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/gamma_drm.h 2003-05-01 14:18:11.000000000 +0200 @@ -48,8 +48,8 @@ int vertex_prim; } drm_gamma_sarea_t; -/* WARNING: If you change any of these defines, make sure to wear a bullet - * proof vest because these are part of the stable kernel<->userspace ABI +/* WARNING: If you change any of these defines, make sure to change the + * defines in the Xserver file (xf86drmGamma.h) */ /* Gamma specific ioctls @@ -84,6 +84,7 @@ unsigned int mmio2; unsigned int mmio3; unsigned int buffers_offset; + int num_rast; } drm_gamma_init_t; #endif /* _GAMMA_DRM_H_ */ diff -urN linux-2.4.23-pre8/drivers/char/drm/gamma_drv.c linux-2.4.23-pre8-pac1/drivers/char/drm/gamma_drv.c --- linux-2.4.23-pre8/drivers/char/drm/gamma_drv.c 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/gamma_drv.c 2003-05-01 14:18:11.000000000 +0200 @@ -39,16 +39,18 @@ #include "drm_auth.h" #include "drm_agpsupport.h" #include "drm_bufs.h" -#include "drm_context.h" +#include "gamma_context.h" /* NOTE! */ #include "drm_dma.h" +#include "gamma_old_dma.h" /* NOTE */ #include "drm_drawable.h" #include "drm_drv.h" #include "drm_fops.h" #include "drm_init.h" #include "drm_ioctl.h" -#include "drm_lists.h" +#include "gamma_lists.h" /* NOTE */ #include "drm_lock.h" +#include "gamma_lock.h" /* NOTE */ #include "drm_memory.h" #include "drm_proc.h" #include "drm_vm.h" diff -urN linux-2.4.23-pre8/drivers/char/drm/gamma_drv.h linux-2.4.23-pre8-pac1/drivers/char/drm/gamma_drv.h --- linux-2.4.23-pre8/drivers/char/drm/gamma_drv.h 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/gamma_drv.h 2003-06-30 00:32:46.000000000 +0200 @@ -40,24 +40,16 @@ drm_map_t *mmio1; drm_map_t *mmio2; drm_map_t *mmio3; + int num_rast; } drm_gamma_private_t; -#define LOCK_TEST_WITH_RETURN( dev ) \ -do { \ - if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || \ - dev->lock.pid != current->pid ) { \ - DRM_ERROR( "%s called without lock held\n", \ - __FUNCTION__ ); \ - return -EINVAL; \ - } \ -} while (0) - /* gamma_dma.c */ extern int gamma_dma_init( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ); extern int gamma_dma_copy( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ); +extern int gamma_do_cleanup_dma( drm_device_t *dev ); extern void gamma_dma_ready(drm_device_t *dev); extern void gamma_dma_quiescent_single(drm_device_t *dev); extern void gamma_dma_quiescent_dual(drm_device_t *dev); @@ -69,6 +61,38 @@ extern int gamma_find_devices(void); extern int gamma_found(void); +/* Gamma-specific code pulled from drm_fops.h: + */ +extern int DRM(finish)(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); +extern int DRM(flush_unblock)(drm_device_t *dev, int context, + drm_lock_flags_t flags); +extern int DRM(flush_block_and_flush)(drm_device_t *dev, int context, + drm_lock_flags_t flags); + +/* Gamma-specific code pulled from drm_dma.h: + */ +extern void DRM(clear_next_buffer)(drm_device_t *dev); +extern int DRM(select_queue)(drm_device_t *dev, + void (*wrapper)(unsigned long)); +extern int DRM(dma_enqueue)(struct file *filp, drm_dma_t *dma); +extern int DRM(dma_get_buffers)(struct file *filp, drm_dma_t *dma); + + +/* Gamma-specific code pulled from drm_lists.h (now renamed gamma_lists.h): + */ +extern int DRM(waitlist_create)(drm_waitlist_t *bl, int count); +extern int DRM(waitlist_destroy)(drm_waitlist_t *bl); +extern int DRM(waitlist_put)(drm_waitlist_t *bl, drm_buf_t *buf); +extern drm_buf_t *DRM(waitlist_get)(drm_waitlist_t *bl); +extern int DRM(freelist_create)(drm_freelist_t *bl, int count); +extern int DRM(freelist_destroy)(drm_freelist_t *bl); +extern int DRM(freelist_put)(drm_device_t *dev, drm_freelist_t *bl, + drm_buf_t *buf); +extern drm_buf_t *DRM(freelist_get)(drm_freelist_t *bl, int block); + + + #define GLINT_DRI_BUF_COUNT 256 #define GAMMA_OFF(reg) \ diff -urN linux-2.4.23-pre8/drivers/char/drm/gamma_lists.h linux-2.4.23-pre8-pac1/drivers/char/drm/gamma_lists.h --- linux-2.4.23-pre8/drivers/char/drm/gamma_lists.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/gamma_lists.h 2003-04-23 03:37:13.000000000 +0200 @@ -0,0 +1,216 @@ +/* drm_lists.h -- Buffer list handling routines -*- linux-c -*- + * Created: Mon Apr 19 20:54:22 1999 by faith@valinux.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * 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 + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * 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 + * Gareth Hughes + */ + +#define __NO_VERSION__ +#include "drmP.h" + + +int DRM(waitlist_create)(drm_waitlist_t *bl, int count) +{ + if (bl->count) return -EINVAL; + + bl->bufs = DRM(alloc)((bl->count + 2) * sizeof(*bl->bufs), + DRM_MEM_BUFLISTS); + + if(!bl->bufs) return -ENOMEM; + memset(bl->bufs, 0, sizeof(*bl->bufs)); + bl->count = count; + bl->rp = bl->bufs; + bl->wp = bl->bufs; + bl->end = &bl->bufs[bl->count+1]; + bl->write_lock = SPIN_LOCK_UNLOCKED; + bl->read_lock = SPIN_LOCK_UNLOCKED; + return 0; +} + +int DRM(waitlist_destroy)(drm_waitlist_t *bl) +{ + if (bl->rp != bl->wp) return -EINVAL; + if (bl->bufs) DRM(free)(bl->bufs, + (bl->count + 2) * sizeof(*bl->bufs), + DRM_MEM_BUFLISTS); + bl->count = 0; + bl->bufs = NULL; + bl->rp = NULL; + bl->wp = NULL; + bl->end = NULL; + return 0; +} + +int DRM(waitlist_put)(drm_waitlist_t *bl, drm_buf_t *buf) +{ + int left; + unsigned long flags; + + left = DRM_LEFTCOUNT(bl); + if (!left) { + DRM_ERROR("Overflow while adding buffer %d from filp %p\n", + buf->idx, buf->filp); + return -EINVAL; + } + buf->list = DRM_LIST_WAIT; + + spin_lock_irqsave(&bl->write_lock, flags); + *bl->wp = buf; + if (++bl->wp >= bl->end) bl->wp = bl->bufs; + spin_unlock_irqrestore(&bl->write_lock, flags); + + return 0; +} + +drm_buf_t *DRM(waitlist_get)(drm_waitlist_t *bl) +{ + drm_buf_t *buf; + unsigned long flags; + + spin_lock_irqsave(&bl->read_lock, flags); + buf = *bl->rp; + if (bl->rp == bl->wp) { + spin_unlock_irqrestore(&bl->read_lock, flags); + return NULL; + } + if (++bl->rp >= bl->end) bl->rp = bl->bufs; + spin_unlock_irqrestore(&bl->read_lock, flags); + + return buf; +} + +int DRM(freelist_create)(drm_freelist_t *bl, int count) +{ + atomic_set(&bl->count, 0); + bl->next = NULL; + init_waitqueue_head(&bl->waiting); + bl->low_mark = 0; + bl->high_mark = 0; + atomic_set(&bl->wfh, 0); + bl->lock = SPIN_LOCK_UNLOCKED; + ++bl->initialized; + return 0; +} + +int DRM(freelist_destroy)(drm_freelist_t *bl) +{ + atomic_set(&bl->count, 0); + bl->next = NULL; + return 0; +} + +int DRM(freelist_put)(drm_device_t *dev, drm_freelist_t *bl, drm_buf_t *buf) +{ + drm_device_dma_t *dma = dev->dma; + + if (!dma) { + DRM_ERROR("No DMA support\n"); + return 1; + } + + if (buf->waiting || buf->pending || buf->list == DRM_LIST_FREE) { + DRM_ERROR("Freed buffer %d: w%d, p%d, l%d\n", + buf->idx, buf->waiting, buf->pending, buf->list); + } + if (!bl) return 1; + buf->list = DRM_LIST_FREE; + + spin_lock(&bl->lock); + buf->next = bl->next; + bl->next = buf; + spin_unlock(&bl->lock); + + atomic_inc(&bl->count); + if (atomic_read(&bl->count) > dma->buf_count) { + DRM_ERROR("%d of %d buffers free after addition of %d\n", + atomic_read(&bl->count), dma->buf_count, buf->idx); + return 1; + } + /* Check for high water mark */ + if (atomic_read(&bl->wfh) && atomic_read(&bl->count)>=bl->high_mark) { + atomic_set(&bl->wfh, 0); + wake_up_interruptible(&bl->waiting); + } + return 0; +} + +static drm_buf_t *DRM(freelist_try)(drm_freelist_t *bl) +{ + drm_buf_t *buf; + + if (!bl) return NULL; + + /* Get buffer */ + spin_lock(&bl->lock); + if (!bl->next) { + spin_unlock(&bl->lock); + return NULL; + } + buf = bl->next; + bl->next = bl->next->next; + spin_unlock(&bl->lock); + + atomic_dec(&bl->count); + buf->next = NULL; + buf->list = DRM_LIST_NONE; + 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); + } + + return buf; +} + +drm_buf_t *DRM(freelist_get)(drm_freelist_t *bl, int block) +{ + drm_buf_t *buf = NULL; + DECLARE_WAITQUEUE(entry, current); + + if (!bl || !bl->initialized) return NULL; + + /* Check for low water mark */ + if (atomic_read(&bl->count) <= bl->low_mark) /* Became low */ + atomic_set(&bl->wfh, 1); + if (atomic_read(&bl->wfh)) { + if (block) { + add_wait_queue(&bl->waiting, &entry); + for (;;) { + current->state = TASK_INTERRUPTIBLE; + if (!atomic_read(&bl->wfh) + && (buf = DRM(freelist_try)(bl))) break; + schedule(); + if (signal_pending(current)) break; + } + current->state = TASK_RUNNING; + remove_wait_queue(&bl->waiting, &entry); + } + return buf; + } + + return DRM(freelist_try)(bl); +} + diff -urN linux-2.4.23-pre8/drivers/char/drm/gamma_lock.h linux-2.4.23-pre8-pac1/drivers/char/drm/gamma_lock.h --- linux-2.4.23-pre8/drivers/char/drm/gamma_lock.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/gamma_lock.h 2003-04-23 03:37:13.000000000 +0200 @@ -0,0 +1,140 @@ +/* lock.c -- IOCTLs for locking -*- linux-c -*- + * Created: Tue Feb 2 08:37:54 1999 by faith@valinux.com + * + * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * 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 + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * 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 + * Gareth Hughes + */ + + +/* Gamma-specific code extracted from drm_lock.h: + */ +static int DRM(flush_queue)(drm_device_t *dev, int context) +{ + DECLARE_WAITQUEUE(entry, current); + int ret = 0; + drm_queue_t *q = dev->queuelist[context]; + + DRM_DEBUG("\n"); + + atomic_inc(&q->use_count); + if (atomic_read(&q->use_count) > 1) { + atomic_inc(&q->block_write); + 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)) { + ret = -EINTR; /* Can't restart */ + break; + } + } + atomic_dec(&q->block_count); + current->state = TASK_RUNNING; + remove_wait_queue(&q->flush_queue, &entry); + } + atomic_dec(&q->use_count); + + /* NOTE: block_write is still incremented! + Use drm_flush_unlock_queue to decrement. */ + return ret; +} + +static int DRM(flush_unblock_queue)(drm_device_t *dev, int context) +{ + drm_queue_t *q = dev->queuelist[context]; + + DRM_DEBUG("\n"); + + atomic_inc(&q->use_count); + if (atomic_read(&q->use_count) > 1) { + if (atomic_read(&q->block_write)) { + atomic_dec(&q->block_write); + wake_up_interruptible(&q->write_queue); + } + } + atomic_dec(&q->use_count); + return 0; +} + +int DRM(flush_block_and_flush)(drm_device_t *dev, int context, + drm_lock_flags_t flags) +{ + int ret = 0; + int i; + + DRM_DEBUG("\n"); + + if (flags & _DRM_LOCK_FLUSH) { + ret = DRM(flush_queue)(dev, DRM_KERNEL_CONTEXT); + if (!ret) ret = DRM(flush_queue)(dev, context); + } + if (flags & _DRM_LOCK_FLUSH_ALL) { + for (i = 0; !ret && i < dev->queue_count; i++) { + ret = DRM(flush_queue)(dev, i); + } + } + return ret; +} + +int DRM(flush_unblock)(drm_device_t *dev, int context, drm_lock_flags_t flags) +{ + int ret = 0; + int i; + + DRM_DEBUG("\n"); + + if (flags & _DRM_LOCK_FLUSH) { + ret = DRM(flush_unblock_queue)(dev, DRM_KERNEL_CONTEXT); + if (!ret) ret = DRM(flush_unblock_queue)(dev, context); + } + if (flags & _DRM_LOCK_FLUSH_ALL) { + for (i = 0; !ret && i < dev->queue_count; i++) { + ret = DRM(flush_unblock_queue)(dev, i); + } + } + + return ret; +} + +int DRM(finish)(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + int ret = 0; + drm_lock_t lock; + + DRM_DEBUG("\n"); + + if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock))) + return -EFAULT; + ret = DRM(flush_block_and_flush)(dev, lock.context, lock.flags); + DRM(flush_unblock)(dev, lock.context, lock.flags); + return ret; +} diff -urN linux-2.4.23-pre8/drivers/char/drm/gamma_old_dma.h linux-2.4.23-pre8-pac1/drivers/char/drm/gamma_old_dma.h --- linux-2.4.23-pre8/drivers/char/drm/gamma_old_dma.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/gamma_old_dma.h 2003-04-23 03:37:13.000000000 +0200 @@ -0,0 +1,300 @@ +/* drm_dma.c -- DMA IOCTL and function support -*- linux-c -*- + * Created: Fri Mar 19 14:30:16 1999 by faith@valinux.com + * + * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * 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 + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * 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 + * Gareth Hughes + */ + + +/* Gamma-specific code pulled from drm_dma.h: + */ + +void DRM(clear_next_buffer)(drm_device_t *dev) +{ + drm_device_dma_t *dma = dev->dma; + + dma->next_buffer = NULL; + if (dma->next_queue && !DRM_BUFCOUNT(&dma->next_queue->waitlist)) { + wake_up_interruptible(&dma->next_queue->flush_queue); + } + dma->next_queue = NULL; +} + +int DRM(select_queue)(drm_device_t *dev, void (*wrapper)(unsigned long)) +{ + int i; + int candidate = -1; + int j = jiffies; + + if (!dev) { + DRM_ERROR("No device\n"); + return -1; + } + if (!dev->queuelist || !dev->queuelist[DRM_KERNEL_CONTEXT]) { + /* This only happens between the time the + interrupt is initialized and the time + the queues are initialized. */ + return -1; + } + + /* Doing "while locked" DMA? */ + if (DRM_WAITCOUNT(dev, DRM_KERNEL_CONTEXT)) { + return DRM_KERNEL_CONTEXT; + } + + /* If there are buffers on the last_context + queue, and we have not been executing + this context very long, continue to + execute this context. */ + if (dev->last_switch <= j + && dev->last_switch + DRM_TIME_SLICE > j + && DRM_WAITCOUNT(dev, dev->last_context)) { + return dev->last_context; + } + + /* Otherwise, find a candidate */ + for (i = dev->last_checked + 1; i < dev->queue_count; i++) { + if (DRM_WAITCOUNT(dev, i)) { + candidate = dev->last_checked = i; + break; + } + } + + if (candidate < 0) { + for (i = 0; i < dev->queue_count; i++) { + if (DRM_WAITCOUNT(dev, i)) { + candidate = dev->last_checked = i; + break; + } + } + } + + if (wrapper + && candidate >= 0 + && candidate != dev->last_context + && dev->last_switch <= j + && dev->last_switch + DRM_TIME_SLICE > j) { + if (dev->timer.expires != dev->last_switch + DRM_TIME_SLICE) { + del_timer(&dev->timer); + dev->timer.function = wrapper; + dev->timer.data = (unsigned long)dev; + dev->timer.expires = dev->last_switch+DRM_TIME_SLICE; + add_timer(&dev->timer); + } + return -1; + } + + return candidate; +} + + +int DRM(dma_enqueue)(struct file *filp, drm_dma_t *d) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + int i; + drm_queue_t *q; + drm_buf_t *buf; + int idx; + int while_locked = 0; + drm_device_dma_t *dma = dev->dma; + DECLARE_WAITQUEUE(entry, current); + + DRM_DEBUG("%d\n", d->send_count); + + if (d->flags & _DRM_DMA_WHILE_LOCKED) { + int context = dev->lock.hw_lock->lock; + + if (!_DRM_LOCK_IS_HELD(context)) { + DRM_ERROR("No lock held during \"while locked\"" + " request\n"); + return -EINVAL; + } + if (d->context != _DRM_LOCKING_CONTEXT(context) + && _DRM_LOCKING_CONTEXT(context) != DRM_KERNEL_CONTEXT) { + DRM_ERROR("Lock held by %d while %d makes" + " \"while locked\" request\n", + _DRM_LOCKING_CONTEXT(context), + d->context); + return -EINVAL; + } + q = dev->queuelist[DRM_KERNEL_CONTEXT]; + while_locked = 1; + } else { + q = dev->queuelist[d->context]; + } + + + atomic_inc(&q->use_count); + if (atomic_read(&q->block_write)) { + 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)) { + atomic_dec(&q->use_count); + remove_wait_queue(&q->write_queue, &entry); + return -EINTR; + } + } + atomic_dec(&q->block_count); + current->state = TASK_RUNNING; + remove_wait_queue(&q->write_queue, &entry); + } + + for (i = 0; i < d->send_count; i++) { + idx = d->send_indices[i]; + if (idx < 0 || idx >= dma->buf_count) { + atomic_dec(&q->use_count); + DRM_ERROR("Index %d (of %d max)\n", + d->send_indices[i], dma->buf_count - 1); + return -EINVAL; + } + buf = dma->buflist[ idx ]; + if (buf->filp != filp) { + atomic_dec(&q->use_count); + DRM_ERROR("Process %d using buffer not owned\n", + current->pid); + return -EINVAL; + } + if (buf->list != DRM_LIST_NONE) { + atomic_dec(&q->use_count); + DRM_ERROR("Process %d using buffer %d on list %d\n", + current->pid, buf->idx, buf->list); + } + buf->used = d->send_sizes[i]; + buf->while_locked = while_locked; + buf->context = d->context; + if (!buf->used) { + DRM_ERROR("Queueing 0 length buffer\n"); + } + if (buf->pending) { + atomic_dec(&q->use_count); + DRM_ERROR("Queueing pending buffer:" + " buffer %d, offset %d\n", + d->send_indices[i], i); + return -EINVAL; + } + if (buf->waiting) { + atomic_dec(&q->use_count); + DRM_ERROR("Queueing waiting buffer:" + " buffer %d, offset %d\n", + d->send_indices[i], i); + return -EINVAL; + } + buf->waiting = 1; + if (atomic_read(&q->use_count) == 1 + || atomic_read(&q->finalization)) { + DRM(free_buffer)(dev, buf); + } else { + DRM(waitlist_put)(&q->waitlist, buf); + atomic_inc(&q->total_queued); + } + } + atomic_dec(&q->use_count); + + return 0; +} + +static int DRM(dma_get_buffers_of_order)(struct file *filp, drm_dma_t *d, + int order) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + int i; + drm_buf_t *buf; + drm_device_dma_t *dma = dev->dma; + + for (i = d->granted_count; i < d->request_count; i++) { + buf = DRM(freelist_get)(&dma->bufs[order].freelist, + d->flags & _DRM_DMA_WAIT); + if (!buf) break; + if (buf->pending || buf->waiting) { + DRM_ERROR("Free buffer %d in use: filp %p (w%d, p%d)\n", + buf->idx, + buf->filp, + buf->waiting, + buf->pending); + } + buf->filp = filp; + if (copy_to_user(&d->request_indices[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; + } + return 0; +} + + +int DRM(dma_get_buffers)(struct file *filp, drm_dma_t *dma) +{ + int order; + int retcode = 0; + int tmp_order; + + order = DRM(order)(dma->request_size); + + dma->granted_count = 0; + retcode = DRM(dma_get_buffers_of_order)(filp, dma, order); + + if (dma->granted_count < dma->request_count + && (dma->flags & _DRM_DMA_SMALLER_OK)) { + for (tmp_order = order - 1; + !retcode + && dma->granted_count < dma->request_count + && tmp_order >= DRM_MIN_ORDER; + --tmp_order) { + + retcode = DRM(dma_get_buffers_of_order)(filp, dma, + tmp_order); + } + } + + if (dma->granted_count < dma->request_count + && (dma->flags & _DRM_DMA_LARGER_OK)) { + for (tmp_order = order + 1; + !retcode + && dma->granted_count < dma->request_count + && tmp_order <= DRM_MAX_ORDER; + ++tmp_order) { + + retcode = DRM(dma_get_buffers_of_order)(filp, dma, + tmp_order); + } + } + return 0; +} + diff -urN linux-2.4.23-pre8/drivers/char/drm/i810.h linux-2.4.23-pre8-pac1/drivers/char/drm/i810.h --- linux-2.4.23-pre8/drivers/char/drm/i810.h 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/i810.h 2003-08-18 12:56:12.000000000 +0200 @@ -45,7 +45,7 @@ #define DRIVER_NAME "i810" #define DRIVER_DESC "Intel i810" -#define DRIVER_DATE "20020211" +#define DRIVER_DATE "20030605" /* Interface history * @@ -54,10 +54,12 @@ * - XFree86 4.2 * 1.2.1 - Disable copying code (leave stub ioctls for backwards compatibility) * - Remove requirement for interrupt (leave stubs again) + * 1.3 - Add page flipping. + * 1.4 - fix DRM interface */ #define DRIVER_MAJOR 1 -#define DRIVER_MINOR 2 -#define DRIVER_PATCHLEVEL 1 +#define DRIVER_MINOR 4 +#define DRIVER_PATCHLEVEL 0 #define DRIVER_IOCTLS \ [DRM_IOCTL_NR(DRM_IOCTL_I810_INIT)] = { i810_dma_init, 1, 1 }, \ @@ -73,8 +75,9 @@ [DRM_IOCTL_NR(DRM_IOCTL_I810_FSTATUS)] = { i810_fstatus, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_I810_OV0FLIP)] = { i810_ov0_flip, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_I810_MC)] = { i810_dma_mc, 1, 1 }, \ - [DRM_IOCTL_NR(DRM_IOCTL_I810_RSTATUS)] = { i810_rstatus, 1, 0 } - + [DRM_IOCTL_NR(DRM_IOCTL_I810_RSTATUS)] = { i810_rstatus, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_I810_FLIP)] = { i810_flip_bufs, 1, 0 } + #define __HAVE_COUNTERS 4 #define __HAVE_COUNTER6 _DRM_STAT_IRQ @@ -86,14 +89,18 @@ */ #define __HAVE_RELEASE 1 #define DRIVER_RELEASE() do { \ - i810_reclaim_buffers( dev, priv->pid ); \ + i810_reclaim_buffers( filp ); \ +} while (0) + +#define DRIVER_PRETAKEDOWN() do { \ + i810_dma_cleanup( dev ); \ } while (0) /* DMA customization: */ #define __HAVE_DMA 1 #define __HAVE_DMA_QUEUE 1 -#define __HAVE_DMA_WAITLIST 1 +#define __HAVE_DMA_WAITLIST 0 #define __HAVE_DMA_RECLAIM 1 #define __HAVE_DMA_QUIESCENT 1 @@ -104,6 +111,7 @@ /* Don't need an irq any more. The template code will make sure that * a noop stub is generated for compatibility. */ +/* XXX: Add vblank support? */ #define __HAVE_DMA_IRQ 0 /* Buffer customization: diff -urN linux-2.4.23-pre8/drivers/char/drm/i810_dma.c linux-2.4.23-pre8-pac1/drivers/char/drm/i810_dma.c --- linux-2.4.23-pre8/drivers/char/drm/i810_dma.c 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/i810_dma.c 2003-08-18 12:56:12.000000000 +0200 @@ -30,7 +30,7 @@ * */ -#include +#define __NO_VERSION__ #include "i810.h" #include "drmP.h" #include "drm.h" @@ -38,8 +38,13 @@ #include "i810_drv.h" #include /* For task queue support */ #include +#include +#ifdef DO_MUNMAP_4_ARGS +#define DO_MUNMAP(m, a, l) do_munmap(m, a, l, 1) +#else #define DO_MUNMAP(m, a, l) do_munmap(m, a, l) +#endif #define I810_BUF_FREE 2 #define I810_BUF_CLIENT 1 @@ -48,36 +53,16 @@ #define I810_BUF_UNMAPPED 0 #define I810_BUF_MAPPED 1 -#define RING_LOCALS unsigned int outring, ringmask; volatile char *virt; - -#define BEGIN_LP_RING(n) do { \ - if (0) DRM_DEBUG("BEGIN_LP_RING(%d) in %s\n", n, __FUNCTION__); \ - if (dev_priv->ring.space < n*4) \ - i810_wait_ring(dev, n*4); \ - dev_priv->ring.space -= n*4; \ - outring = dev_priv->ring.tail; \ - ringmask = dev_priv->ring.tail_mask; \ - virt = dev_priv->ring.virtual_start; \ -} while (0) - -#define ADVANCE_LP_RING() do { \ - if (0) DRM_DEBUG("ADVANCE_LP_RING\n"); \ - dev_priv->ring.tail = outring; \ - I810_WRITE(LP_RING + RING_TAIL, outring); \ -} while(0) - -#define OUT_RING(n) do { \ - if (0) DRM_DEBUG(" OUT_RING %x\n", (int)(n)); \ - *(volatile unsigned int *)(virt + outring) = n; \ - outring += 4; \ - outring &= ringmask; \ -} while (0) +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,2) +#define down_write down +#define up_write up +#endif static inline void i810_print_status_page(drm_device_t *dev) { drm_device_dma_t *dma = dev->dma; drm_i810_private_t *dev_priv = dev->dev_private; - u32 *temp = (u32 *)dev_priv->hw_status_page; + u32 *temp = dev_priv->hw_status_page; int i; DRM_DEBUG( "hw_status: Interrupt Status : %x\n", temp[0]); @@ -105,7 +90,7 @@ /* In use is already a pointer */ used = cmpxchg(buf_priv->in_use, I810_BUF_FREE, I810_BUF_CLIENT); - if(used == I810_BUF_FREE) { + if (used == I810_BUF_FREE) { return buf; } } @@ -123,7 +108,7 @@ /* In use is already a pointer */ used = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT, I810_BUF_FREE); - if(used != I810_BUF_CLIENT) { + if (used != I810_BUF_CLIENT) { DRM_ERROR("Freeing buffer thats not in use : %d\n", buf->idx); return -EINVAL; } @@ -137,9 +122,7 @@ .release = DRM(release), .ioctl = DRM(ioctl), .mmap = i810_mmap_buffers, - .read = DRM(read), .fasync = DRM(fasync), - .poll = DRM(poll), }; int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma) @@ -178,13 +161,10 @@ struct file_operations *old_fops; int retcode = 0; - if(buf_priv->currently_mapped == I810_BUF_MAPPED) return -EINVAL; - - - + if (buf_priv->currently_mapped == I810_BUF_MAPPED) + return -EINVAL; down_write( ¤t->mm->mmap_sem ); - old_fops = filp->f_op; filp->f_op = &i810_buffer_fops; dev_priv->mmap_buffer = buf; @@ -196,13 +176,10 @@ filp->f_op = old_fops; if ((unsigned long)buf_priv->virtual > -1024UL) { /* Real error */ - DRM_DEBUG("mmap error\n"); + DRM_ERROR("mmap error\n"); retcode = (signed int)buf_priv->virtual; buf_priv->virtual = 0; } - - - up_write( ¤t->mm->mmap_sem ); return retcode; @@ -213,20 +190,14 @@ drm_i810_buf_priv_t *buf_priv = buf->dev_private; int retcode = 0; - if(buf_priv->currently_mapped != I810_BUF_MAPPED) + if (buf_priv->currently_mapped != I810_BUF_MAPPED) return -EINVAL; - - - down_write( ¤t->mm->mmap_sem ); - + down_write(¤t->mm->mmap_sem); retcode = DO_MUNMAP(current->mm, (unsigned long)buf_priv->virtual, (size_t) buf->total); - - - - up_write( ¤t->mm->mmap_sem ); + up_write(¤t->mm->mmap_sem); buf_priv->currently_mapped = I810_BUF_UNMAPPED; buf_priv->virtual = 0; @@ -237,7 +208,6 @@ static int i810_dma_get_buffer(drm_device_t *dev, drm_i810_dma_t *d, struct file *filp) { - drm_file_t *priv = filp->private_data; drm_buf_t *buf; drm_i810_buf_priv_t *buf_priv; int retcode = 0; @@ -250,12 +220,12 @@ } retcode = i810_map_buffer(buf, filp); - if(retcode) { + if (retcode) { i810_freelist_put(dev, buf); - DRM_DEBUG("mapbuf failed, retcode %d\n", retcode); + DRM_ERROR("mapbuf failed, retcode %d\n", retcode); return retcode; } - buf->pid = priv->pid; + buf->filp = filp; buf_priv = buf->dev_private; d->granted = 1; d->request_idx = buf->idx; @@ -265,22 +235,30 @@ return retcode; } -static int i810_dma_cleanup(drm_device_t *dev) +int i810_dma_cleanup(drm_device_t *dev) { drm_device_dma_t *dma = dev->dma; - if(dev->dev_private) { +#if _HAVE_DMA_IRQ + /* Make sure interrupts are disabled here because the uninstall ioctl + * may not have been called from userspace and after dev_private + * is freed, it's too late. + */ + if (dev->irq) DRM(irq_uninstall)(dev); +#endif + + if (dev->dev_private) { int i; drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private; - if(dev_priv->ring.virtual_start) { + if (dev_priv->ring.virtual_start) { DRM(ioremapfree)((void *) dev_priv->ring.virtual_start, - dev_priv->ring.Size); + dev_priv->ring.Size, dev); } - if(dev_priv->hw_status_page != 0UL) { + if (dev_priv->hw_status_page) { pci_free_consistent(dev->pdev, PAGE_SIZE, - (void *)dev_priv->hw_status_page, + dev_priv->hw_status_page, dev_priv->dma_status_page); /* Need to rewrite hardware status page */ I810_WRITE(0x02080, 0x1ffff000); @@ -292,7 +270,8 @@ for (i = 0; i < dma->buf_count; i++) { drm_buf_t *buf = dma->buflist[ i ]; drm_i810_buf_priv_t *buf_priv = buf->dev_private; - DRM(ioremapfree)(buf_priv->kernel_virtual, buf->total); + if ( buf_priv->kernel_virtual && buf->total ) + DRM(ioremapfree)(buf_priv->kernel_virtual, buf->total, dev); } } return 0; @@ -311,17 +290,19 @@ ring->head = I810_READ(LP_RING + RING_HEAD) & HEAD_ADDR; ring->space = ring->head - (ring->tail+8); if (ring->space < 0) ring->space += ring->Size; - - if (ring->head != last_head) - end = jiffies + (HZ*3); - + + if (ring->head != last_head) { + end = jiffies + (HZ*3); + last_head = ring->head; + } + iters++; - if(time_before(end, jiffies)) { + if (time_before(end, jiffies)) { DRM_ERROR("space: %d wanted %d\n", ring->space, n); DRM_ERROR("lockup\n"); goto out_wait_ring; } - udelay(1); + udelay(1); } out_wait_ring: @@ -346,7 +327,7 @@ u32 *hw_status = (u32 *)(dev_priv->hw_status_page + my_idx); int i; - if(dma->buf_count > 1019) { + if (dma->buf_count > 1019) { /* Not enough space in the status page for the freelist */ return -EINVAL; } @@ -362,7 +343,7 @@ *buf_priv->in_use = I810_BUF_FREE; buf_priv->kernel_virtual = DRM(ioremap)(buf->bus_address, - buf->total); + buf->total, dev); } return 0; } @@ -376,29 +357,29 @@ memset(dev_priv, 0, sizeof(drm_i810_private_t)); list_for_each(list, &dev->maplist->head) { - drm_map_list_t *r_list = (drm_map_list_t *)list; - if( r_list->map && + drm_map_list_t *r_list = list_entry(list, drm_map_list_t, head); + if (r_list->map && r_list->map->type == _DRM_SHM && r_list->map->flags & _DRM_CONTAINS_LOCK ) { dev_priv->sarea_map = r_list->map; break; } } - if(!dev_priv->sarea_map) { + if (!dev_priv->sarea_map) { dev->dev_private = (void *)dev_priv; i810_dma_cleanup(dev); DRM_ERROR("can not find sarea!\n"); return -EINVAL; } DRM_FIND_MAP( dev_priv->mmio_map, init->mmio_offset ); - if(!dev_priv->mmio_map) { + if (!dev_priv->mmio_map) { dev->dev_private = (void *)dev_priv; i810_dma_cleanup(dev); DRM_ERROR("can not find mmio map!\n"); return -EINVAL; } DRM_FIND_MAP( dev_priv->buffer_map, init->buffers_offset ); - if(!dev_priv->buffer_map) { + if (!dev_priv->buffer_map) { dev->dev_private = (void *)dev_priv; i810_dma_cleanup(dev); DRM_ERROR("can not find dma buffer map!\n"); @@ -415,7 +396,7 @@ dev_priv->ring.virtual_start = DRM(ioremap)(dev->agp->base + init->ring_start, - init->ring_size); + init->ring_size, dev); if (dev_priv->ring.virtual_start == NULL) { dev->dev_private = (void *) dev_priv; @@ -432,6 +413,7 @@ dev_priv->pitch = init->pitch; dev_priv->back_offset = init->back_offset; dev_priv->depth_offset = init->depth_offset; + dev_priv->front_offset = init->front_offset; dev_priv->overlay_offset = init->overlay_offset; dev_priv->overlay_physical = init->overlay_physical; @@ -442,22 +424,22 @@ /* Program Hardware Status Page */ dev_priv->hw_status_page = - (unsigned long) pci_alloc_consistent(dev->pdev, PAGE_SIZE, + pci_alloc_consistent(dev->pdev, PAGE_SIZE, &dev_priv->dma_status_page); - if(dev_priv->hw_status_page == 0UL) { + if (!dev_priv->hw_status_page) { dev->dev_private = (void *)dev_priv; i810_dma_cleanup(dev); DRM_ERROR("Can not allocate hardware status page\n"); return -ENOMEM; } - memset((void *) dev_priv->hw_status_page, 0, PAGE_SIZE); - DRM_DEBUG("hw status page @ %lx\n", dev_priv->hw_status_page); + memset(dev_priv->hw_status_page, 0, PAGE_SIZE); + DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page); I810_WRITE(0x02080, dev_priv->dma_status_page); DRM_DEBUG("Enabled hardware status page\n"); /* Now we need to init our freelist */ - if(i810_freelist_init(dev, dev_priv) != 0) { + if (i810_freelist_init(dev, dev_priv) != 0) { dev->dev_private = (void *)dev_priv; i810_dma_cleanup(dev); DRM_ERROR("Not enough space in the status page for" @@ -469,14 +451,48 @@ return 0; } -#ifdef CONFIG_DRM_I810_XFREE_41 -int xfreeversion = 41; -#else -int xfreeversion = -1; -#endif +/* i810 DRM version 1.1 used a smaller init structure with different + * ordering of values than is currently used (drm >= 1.2). There is + * no defined way to detect the XFree version to correct this problem, + * however by checking using this procedure we can detect the correct + * thing to do. + * + * #1 Read the Smaller init structure from user-space + * #2 Verify the overlay_physical is a valid physical address, or NULL + * If it isn't then we have a v1.1 client. Fix up params. + * If it is, then we have a 1.2 client... get the rest of the data. + */ +int i810_dma_init_compat(drm_i810_init_t *init, unsigned long arg) +{ + + /* Get v1.1 init data */ + if (copy_from_user(init, (drm_i810_pre12_init_t *)arg, + sizeof(drm_i810_pre12_init_t))) { + return -EFAULT; + } + + if ((!init->overlay_physical) || (init->overlay_physical > 4096)) { + + /* This is a v1.2 client, just get the v1.2 init data */ + DRM_INFO("Using POST v1.2 init.\n"); + if (copy_from_user(init, (drm_i810_init_t *)arg, + sizeof(drm_i810_init_t))) { + return -EFAULT; + } + } else { + + /* This is a v1.1 client, fix the params */ + DRM_INFO("Using PRE v1.2 init.\n"); + init->pitch_bits = init->h; + init->pitch = init->w; + init->h = init->overlay_physical; + init->w = init->overlay_offset; + init->overlay_physical = 0; + init->overlay_offset = 0; + } -MODULE_PARM(xfreeversion, "i"); -MODULE_PARM_DESC(xfreeversion, "The version of XFree86 that needs to be supported"); + return 0; +} int i810_dma_init(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) @@ -487,44 +503,46 @@ drm_i810_init_t init; int retcode = 0; - if (copy_from_user(&init, (drm_i810_init_t *)arg, sizeof(init))) + /* Get only the init func */ + if (copy_from_user(&init, (void *)arg, sizeof(drm_i810_init_func_t))) return -EFAULT; - - if ((xfreeversion == 41) || - ((xfreeversion == -1) && (init.pitch == 0))) { - /* - * Ok we have a problem here. Someone decided it was - * funny to add two fields in the middle of the - * drm_i810_init_it structure in the transition between - * XFree86 4.1.0 and 4.2.0. - * - * The code below tries to fix this ABI breakage up as - * good as possible, unfortionatly it's impossible to - * autodetect which interface the user wants, hence the - * module parameter -- Arjan - */ - - init.pitch_bits = init.h; - init.pitch = init.w; - init.h = init.overlay_physical; - init.w = init.overlay_offset; - init.overlay_physical = 0; - init.overlay_offset = 0; - } switch(init.func) { case I810_INIT_DMA: + /* This case is for backward compatibility. It + * handles XFree 4.1.0 and 4.2.0, and has to + * do some parameter checking as described below. + * It will someday go away. + */ + retcode = i810_dma_init_compat(&init, arg); + if (retcode) + return retcode; + dev_priv = DRM(alloc)(sizeof(drm_i810_private_t), DRM_MEM_DRIVER); - if(dev_priv == NULL) return -ENOMEM; + if (dev_priv == NULL) + return -ENOMEM; retcode = i810_dma_initialize(dev, dev_priv, &init); - break; + break; + + default: + case I810_INIT_DMA_1_4: + DRM_INFO("Using v1.4 init.\n"); + if (copy_from_user(&init, (drm_i810_init_t *)arg, + sizeof(drm_i810_init_t))) { + return -EFAULT; + } + dev_priv = DRM(alloc)(sizeof(drm_i810_private_t), + DRM_MEM_DRIVER); + if (dev_priv == NULL) + return -ENOMEM; + retcode = i810_dma_initialize(dev, dev_priv, &init); + break; + case I810_CLEANUP_DMA: + DRM_INFO("DMA Cleanup\n"); retcode = i810_dma_cleanup(dev); - break; - default: - retcode = -EINVAL; - break; + break; } return retcode; @@ -534,12 +552,16 @@ /* Most efficient way to verify state for the i810 is as it is * emitted. Non-conformant state is silently dropped. + * + * Use 'volatile' & local var tmp to force the emitted values to be + * identical to the verified ones. */ static void i810EmitContextVerified( drm_device_t *dev, - unsigned int *code ) + volatile unsigned int *code ) { drm_i810_private_t *dev_priv = dev->dev_private; int i, j = 0; + unsigned int tmp; RING_LOCALS; BEGIN_LP_RING( I810_CTX_SETUP_SIZE ); @@ -551,10 +573,12 @@ OUT_RING( code[I810_CTXREG_ST1] ); for ( i = 4 ; i < I810_CTX_SETUP_SIZE ; i++ ) { - if ((code[i] & (7<<29)) == (3<<29) && - (code[i] & (0x1f<<24)) < (0x1d<<24)) + tmp = code[i]; + + if ((tmp & (7<<29)) == (3<<29) && + (tmp & (0x1f<<24)) < (0x1d<<24)) { - OUT_RING( code[i] ); + OUT_RING( tmp ); j++; } else printk("constext state dropped!!!\n"); @@ -571,6 +595,7 @@ { drm_i810_private_t *dev_priv = dev->dev_private; int i, j = 0; + unsigned int tmp; RING_LOCALS; BEGIN_LP_RING( I810_TEX_SETUP_SIZE ); @@ -581,11 +606,12 @@ OUT_RING( code[I810_TEXREG_MI3] ); for ( i = 4 ; i < I810_TEX_SETUP_SIZE ; i++ ) { + tmp = code[i]; - if ((code[i] & (7<<29)) == (3<<29) && - (code[i] & (0x1f<<24)) < (0x1d<<24)) + if ((tmp & (7<<29)) == (3<<29) && + (tmp & (0x1f<<24)) < (0x1d<<24)) { - OUT_RING( code[i] ); + OUT_RING( tmp ); j++; } else printk("texture state dropped!!!\n"); @@ -613,9 +639,9 @@ if (tmp == dev_priv->front_di1 || tmp == dev_priv->back_di1) { OUT_RING( CMD_OP_DESTBUFFER_INFO ); OUT_RING( tmp ); - } - else - printk("buffer state dropped\n"); + } else + DRM_DEBUG("bad di1 %x (allow %x or %x)\n", + tmp, dev_priv->front_di1, dev_priv->back_di1); /* invarient: */ @@ -642,6 +668,8 @@ drm_i810_private_t *dev_priv = dev->dev_private; drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv; unsigned int dirty = sarea_priv->dirty; + + DRM_DEBUG("%s %x\n", __FUNCTION__, dirty); if (dirty & I810_UPLOAD_BUFFERS) { i810EmitDestVerified( dev, sarea_priv->BufferState ); @@ -680,6 +708,14 @@ int cpp = 2; int i; RING_LOCALS; + + if ( dev_priv->current_page == 1 ) { + unsigned int tmp = flags; + + flags &= ~(I810_FRONT | I810_BACK); + if (tmp & I810_FRONT) flags |= I810_BACK; + if (tmp & I810_BACK) flags |= I810_FRONT; + } i810_kernel_lost_context(dev); @@ -745,10 +781,11 @@ drm_clip_rect_t *pbox = sarea_priv->boxes; int pitch = dev_priv->pitch; int cpp = 2; - int ofs = dev_priv->back_offset; int i; RING_LOCALS; + DRM_DEBUG("swapbuffers\n"); + i810_kernel_lost_context(dev); if (nbox > I810_NR_SAREA_CLIPRECTS) @@ -759,7 +796,7 @@ unsigned int w = pbox->x2 - pbox->x1; unsigned int h = pbox->y2 - pbox->y1; unsigned int dst = pbox->x1*cpp + pbox->y1*pitch; - unsigned int start = ofs + dst; + unsigned int start = dst; if (pbox->x1 > pbox->x2 || pbox->y1 > pbox->y2 || @@ -771,9 +808,15 @@ OUT_RING( BR00_BITBLT_CLIENT | BR00_OP_SRC_COPY_BLT | 0x4 ); OUT_RING( pitch | (0xCC << 16)); OUT_RING( (h << 16) | (w * cpp)); - OUT_RING( dst ); + if (dev_priv->current_page == 0) + OUT_RING(dev_priv->front_offset + start); + else + OUT_RING(dev_priv->back_offset + start); OUT_RING( pitch ); - OUT_RING( start ); + if (dev_priv->current_page == 0) + OUT_RING(dev_priv->back_offset + start); + else + OUT_RING(dev_priv->front_offset + start); ADVANCE_LP_RING(); } } @@ -860,6 +903,52 @@ } } +static void i810_dma_dispatch_flip( drm_device_t *dev ) +{ + drm_i810_private_t *dev_priv = dev->dev_private; + int pitch = dev_priv->pitch; + RING_LOCALS; + + DRM_DEBUG( "%s: page=%d pfCurrentPage=%d\n", + __FUNCTION__, + dev_priv->current_page, + dev_priv->sarea_priv->pf_current_page); + + i810_kernel_lost_context(dev); + + BEGIN_LP_RING( 2 ); + OUT_RING( INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE ); + OUT_RING( 0 ); + ADVANCE_LP_RING(); + + BEGIN_LP_RING( I810_DEST_SETUP_SIZE + 2 ); + /* On i815 at least ASYNC is buggy */ + /* pitch<<5 is from 11.2.8 p158, + its the pitch / 8 then left shifted 8, + so (pitch >> 3) << 8 */ + OUT_RING( CMD_OP_FRONTBUFFER_INFO | (pitch<<5) /*| ASYNC_FLIP */ ); + if ( dev_priv->current_page == 0 ) { + OUT_RING( dev_priv->back_offset ); + dev_priv->current_page = 1; + } else { + OUT_RING( dev_priv->front_offset ); + dev_priv->current_page = 0; + } + OUT_RING(0); + ADVANCE_LP_RING(); + + BEGIN_LP_RING(2); + OUT_RING( CMD_OP_WAIT_FOR_EVENT | WAIT_FOR_PLANE_A_FLIP ); + OUT_RING( 0 ); + ADVANCE_LP_RING(); + + /* Increment the frame counter. The client-side 3D driver must + * throttle the framerate by waiting for this value before + * performing the swapbuffer ioctl. + */ + dev_priv->sarea_priv->pf_current_page = dev_priv->current_page; + +} void i810_dma_quiescent(drm_device_t *dev) { @@ -915,8 +1004,10 @@ } /* Must be called with the lock held */ -void i810_reclaim_buffers(drm_device_t *dev, pid_t pid) +void i810_reclaim_buffers(struct file *filp) { + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; drm_device_dma_t *dma = dev->dma; int i; @@ -930,13 +1021,13 @@ drm_buf_t *buf = dma->buflist[ i ]; drm_i810_buf_priv_t *buf_priv = buf->dev_private; - if (buf->pid == pid && buf_priv) { + if (buf->filp == filp && buf_priv) { int used = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT, I810_BUF_FREE); if (used == I810_BUF_CLIENT) DRM_DEBUG("reclaimed from client\n"); - if(buf_priv->currently_mapped == I810_BUF_MAPPED) + if (buf_priv->currently_mapped == I810_BUF_MAPPED) buf_priv->currently_mapped = I810_BUF_UNMAPPED; } } @@ -948,7 +1039,7 @@ drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; - if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { DRM_ERROR("i810_flush_ioctl called without lock held\n"); return -EINVAL; } @@ -965,7 +1056,7 @@ drm_device_t *dev = priv->dev; drm_device_dma_t *dma = dev->dma; drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; - u32 *hw_status = (u32 *)dev_priv->hw_status_page; + u32 *hw_status = dev_priv->hw_status_page; drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *) dev_priv->sarea_priv; drm_i810_vertex_t vertex; @@ -973,12 +1064,16 @@ if (copy_from_user(&vertex, (drm_i810_vertex_t *)arg, sizeof(vertex))) return -EFAULT; - if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { DRM_ERROR("i810_dma_vertex called without lock held\n"); return -EINVAL; } - if(vertex.idx < 0 || vertex.idx > dma->buf_count) return -EINVAL; + DRM_DEBUG("i810 dma vertex, idx %d used %d discard %d\n", + vertex.idx, vertex.used, vertex.discard); + + if (vertex.idx < 0 || vertex.idx > dma->buf_count) + return -EINVAL; i810_dma_dispatch_vertex( dev, dma->buflist[ vertex.idx ], @@ -1004,7 +1099,7 @@ if (copy_from_user(&clear, (drm_i810_clear_t *)arg, sizeof(clear))) return -EFAULT; - if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { DRM_ERROR("i810_clear_bufs called without lock held\n"); return -EINVAL; } @@ -1026,7 +1121,9 @@ drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; - if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_DEBUG("i810_swap_bufs\n"); + + if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { DRM_ERROR("i810_swap_buf called without lock held\n"); return -EINVAL; } @@ -1041,7 +1138,7 @@ drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; - u32 *hw_status = (u32 *)dev_priv->hw_status_page; + u32 *hw_status = dev_priv->hw_status_page; drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *) dev_priv->sarea_priv; @@ -1057,14 +1154,14 @@ int retcode = 0; drm_i810_dma_t d; drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; - u32 *hw_status = (u32 *)dev_priv->hw_status_page; + u32 *hw_status = dev_priv->hw_status_page; drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *) dev_priv->sarea_priv; if (copy_from_user(&d, (drm_i810_dma_t *)arg, sizeof(d))) return -EFAULT; - if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { DRM_ERROR("i810_dma called without lock held\n"); return -EINVAL; } @@ -1073,6 +1170,9 @@ retcode = i810_dma_get_buffer(dev, &d, filp); + DRM_DEBUG("i810_dma: %d returning %d, granted = %d\n", + current->pid, retcode, d.granted); + if (copy_to_user((drm_dma_t *)arg, &d, sizeof(d))) return -EFAULT; sarea_priv->last_dispatch = (int) hw_status[5]; @@ -1111,7 +1211,7 @@ u = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT, I810_BUF_HARDWARE); - if(u != I810_BUF_CLIENT) { + if (u != I810_BUF_CLIENT) { DRM_DEBUG("MC found buffer that isn't mine!\n"); } @@ -1166,7 +1266,7 @@ drm_device_t *dev = priv->dev; drm_device_dma_t *dma = dev->dma; drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; - u32 *hw_status = (u32 *)dev_priv->hw_status_page; + u32 *hw_status = dev_priv->hw_status_page; drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *) dev_priv->sarea_priv; drm_i810_mc_t mc; @@ -1175,7 +1275,7 @@ return -EFAULT; - if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { DRM_ERROR("i810_dma_mc called without lock held\n"); return -EINVAL; } @@ -1223,7 +1323,7 @@ drm_device_t *dev = priv->dev; drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; - if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { DRM_ERROR("i810_fstatus called without lock held\n"); return -EINVAL; } @@ -1237,7 +1337,7 @@ drm_device_t *dev = priv->dev; drm_i810_private_t *dev_priv = (drm_i810_private_t *)dev->dev_private; - if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { DRM_ERROR("i810_ov0_flip called without lock held\n"); return -EINVAL; } @@ -1249,3 +1349,47 @@ } +/* Not sure why this isn't set all the time: + */ +static void i810_do_init_pageflip( drm_device_t *dev ) +{ + drm_i810_private_t *dev_priv = dev->dev_private; + + DRM_DEBUG("%s\n", __FUNCTION__); + dev_priv->page_flipping = 1; + dev_priv->current_page = 0; + dev_priv->sarea_priv->pf_current_page = dev_priv->current_page; +} + +int i810_do_cleanup_pageflip( drm_device_t *dev ) +{ + drm_i810_private_t *dev_priv = dev->dev_private; + + DRM_DEBUG("%s\n", __FUNCTION__); + if (dev_priv->current_page != 0) + i810_dma_dispatch_flip( dev ); + + dev_priv->page_flipping = 0; + return 0; +} + +int i810_flip_bufs(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_i810_private_t *dev_priv = dev->dev_private; + + DRM_DEBUG("%s\n", __FUNCTION__); + + if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("i810_flip_buf called without lock held\n"); + return -EINVAL; + } + + if (!dev_priv->page_flipping) + i810_do_init_pageflip( dev ); + + i810_dma_dispatch_flip( dev ); + return 0; +} diff -urN linux-2.4.23-pre8/drivers/char/drm/i810_drm.h linux-2.4.23-pre8-pac1/drivers/char/drm/i810_drm.h --- linux-2.4.23-pre8/drivers/char/drm/i810_drm.h 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/i810_drm.h 2003-08-18 12:56:12.000000000 +0200 @@ -38,7 +38,7 @@ * - zbuffer linear offset and pitch -- also invarient * - drawing origin in back and depth buffers. * - * Keep the depth/back buffer state here to acommodate private buffers + * Keep the depth/back buffer state here to accommodate private buffers * in the future. */ #define I810_DESTREG_DI0 0 /* CMD_OP_DESTBUFFER_INFO (2 dwords) */ @@ -94,12 +94,15 @@ #define I810_BACK 0x2 #define I810_DEPTH 0x4 +typedef enum _drm_i810_init_func { + I810_INIT_DMA = 0x01, + I810_CLEANUP_DMA = 0x02, + I810_INIT_DMA_1_4 = 0x03 + } drm_i810_init_func_t; +/* This is the init structure after v1.2 */ typedef struct _drm_i810_init { - enum { - I810_INIT_DMA = 0x01, - I810_CLEANUP_DMA = 0x02 - } func; + drm_i810_init_func_t func; #if CONFIG_XFREE86_VERSION < XFREE86_VERSION(4,1,0,0) int ring_map_idx; int buffer_map_idx; @@ -122,6 +125,29 @@ unsigned int pitch_bits; } drm_i810_init_t; +/* This is the init structure prior to v1.2 */ +typedef struct _drm_i810_pre12_init { + drm_i810_init_func_t func; +#if CONFIG_XFREE86_VERSION < XFREE86_VERSION(4,1,0,0) + int ring_map_idx; + int buffer_map_idx; +#else + unsigned int mmio_offset; + unsigned int buffers_offset; +#endif + int sarea_priv_offset; + unsigned int ring_start; + unsigned int ring_end; + unsigned int ring_size; + unsigned int front_offset; + unsigned int back_offset; + unsigned int depth_offset; + unsigned int w; + unsigned int h; + unsigned int pitch; + unsigned int pitch_bits; +} drm_i810_pre12_init_t; + /* Warning: If you change the SAREA structure you must change the Xserver * structure as well */ @@ -166,10 +192,13 @@ int vertex_prim; + int pf_enabled; /* is pageflipping allowed? */ + int pf_active; + int pf_current_page; /* which buffer is being displayed? */ } drm_i810_sarea_t; -/* WARNING: If you change any of these defines, make sure to wear a bullet - * proof vest since these are part of the stable kernel<->userspace ABI +/* WARNING: If you change any of these defines, make sure to change the + * defines in the Xserver file (xf86drmMga.h) */ /* i810 specific ioctls @@ -189,6 +218,7 @@ #define DRM_IOCTL_I810_OV0FLIP DRM_IO ( 0x4b) #define DRM_IOCTL_I810_MC DRM_IOW( 0x4c, drm_i810_mc_t) #define DRM_IOCTL_I810_RSTATUS DRM_IO ( 0x4d ) +#define DRM_IOCTL_I810_FLIP DRM_IO ( 0x4e ) typedef struct _drm_i810_clear { int clear_color; diff -urN linux-2.4.23-pre8/drivers/char/drm/i810_drv.c linux-2.4.23-pre8-pac1/drivers/char/drm/i810_drv.c --- linux-2.4.23-pre8/drivers/char/drm/i810_drv.c 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/i810_drv.c 2003-05-01 14:18:11.000000000 +0200 @@ -49,7 +49,6 @@ #include "drm_init.h" #include "drm_ioctl.h" #include "drm_lock.h" -#include "drm_lists.h" #include "drm_memory.h" #include "drm_proc.h" #include "drm_vm.h" diff -urN linux-2.4.23-pre8/drivers/char/drm/i810_drv.h linux-2.4.23-pre8-pac1/drivers/char/drm/i810_drv.h --- linux-2.4.23-pre8/drivers/char/drm/i810_drv.h 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/i810_drv.h 2003-08-18 12:56:12.000000000 +0200 @@ -38,8 +38,6 @@ int currently_mapped; void *virtual; void *kernel_virtual; - int map_count; - struct vm_area_struct *vma; } drm_i810_buf_priv_t; typedef struct _drm_i810_ring_buffer{ @@ -61,7 +59,7 @@ drm_i810_sarea_t *sarea_priv; drm_i810_ring_buffer_t ring; - unsigned long hw_status_page; + void *hw_status_page; unsigned long counter; dma_addr_t dma_status_page; @@ -77,7 +75,20 @@ int overlay_physical; int w, h; int pitch; + int back_pitch; + int depth_pitch; + int do_boxes; + int dma_used; + + int current_page; + int page_flipping; + + wait_queue_head_t irq_queue; + atomic_t irq_received; + atomic_t irq_emitted; + + int front_offset; } drm_i810_private_t; /* i810_dma.c */ @@ -86,9 +97,10 @@ unsigned int cmd, unsigned long arg); extern int i810_dma_init(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); +extern int i810_dma_cleanup(drm_device_t *dev); extern int i810_flush_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); -extern void i810_reclaim_buffers(drm_device_t *dev, pid_t pid); +extern void i810_reclaim_buffers(struct file *filp); extern int i810_getage(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); extern int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma); @@ -125,6 +137,8 @@ int i810_clear_bufs(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); +int i810_flip_bufs(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); #define I810_BASE(reg) ((unsigned long) \ dev_priv->mmio_map->handle) @@ -136,6 +150,33 @@ #define I810_READ16(reg) I810_DEREF16(reg) #define I810_WRITE16(reg,val) do { I810_DEREF16(reg) = val; } while (0) +#define I810_VERBOSE 0 +#define RING_LOCALS unsigned int outring, ringmask; \ + volatile char *virt; + +#define BEGIN_LP_RING(n) do { \ + if (I810_VERBOSE) \ + DRM_DEBUG("BEGIN_LP_RING(%d) in %s\n", n, __FUNCTION__); \ + if (dev_priv->ring.space < n*4) \ + i810_wait_ring(dev, n*4); \ + dev_priv->ring.space -= n*4; \ + outring = dev_priv->ring.tail; \ + ringmask = dev_priv->ring.tail_mask; \ + virt = dev_priv->ring.virtual_start; \ +} while (0) + +#define ADVANCE_LP_RING() do { \ + if (I810_VERBOSE) DRM_DEBUG("ADVANCE_LP_RING\n"); \ + dev_priv->ring.tail = outring; \ + I810_WRITE(LP_RING + RING_TAIL, outring); \ +} while(0) + +#define OUT_RING(n) do { \ + if (I810_VERBOSE) DRM_DEBUG(" OUT_RING %x\n", (int)(n)); \ + *(volatile unsigned int *)(virt + outring) = n; \ + outring += 4; \ + outring &= ringmask; \ +} while (0) #define GFX_OP_USER_INTERRUPT ((0<<29)|(2<<23)) #define GFX_OP_BREAKPOINT_INTERRUPT ((0<<29)|(1<<23)) @@ -199,12 +240,15 @@ #define CMD_OP_Z_BUFFER_INFO ((0x0<<29)|(0x16<<23)) #define CMD_OP_DESTBUFFER_INFO ((0x0<<29)|(0x15<<23)) #define CMD_OP_FRONTBUFFER_INFO ((0x0<<29)|(0x14<<23)) +#define CMD_OP_WAIT_FOR_EVENT ((0x0<<29)|(0x03<<23)) #define BR00_BITBLT_CLIENT 0x40000000 #define BR00_OP_COLOR_BLT 0x10000000 #define BR00_OP_SRC_COPY_BLT 0x10C00000 #define BR13_SOLID_PATTERN 0x80000000 - +#define WAIT_FOR_PLANE_A_SCANLINES (1<<1) +#define WAIT_FOR_PLANE_A_FLIP (1<<2) +#define WAIT_FOR_VBLANK (1<<3) #endif diff -urN linux-2.4.23-pre8/drivers/char/drm/i830.h linux-2.4.23-pre8-pac1/drivers/char/drm/i830.h --- linux-2.4.23-pre8/drivers/char/drm/i830.h 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/i830.h 2003-06-30 00:32:46.000000000 +0200 @@ -87,14 +87,18 @@ */ #define __HAVE_RELEASE 1 #define DRIVER_RELEASE() do { \ - i830_reclaim_buffers( dev, priv->pid ); \ + i830_reclaim_buffers( filp ); \ +} while (0) + +#define DRIVER_PRETAKEDOWN() do { \ + i830_dma_cleanup( dev ); \ } while (0) /* DMA customization: */ #define __HAVE_DMA 1 #define __HAVE_DMA_QUEUE 1 -#define __HAVE_DMA_WAITLIST 1 +#define __HAVE_DMA_WAITLIST 0 #define __HAVE_DMA_RECLAIM 1 #define __HAVE_DMA_QUIESCENT 1 @@ -107,45 +111,17 @@ * the card, but are subject to subtle interactions between bios, * hardware and the driver. */ +/* XXX: Add vblank support? */ #define USE_IRQS 0 - #if USE_IRQS #define __HAVE_DMA_IRQ 1 #define __HAVE_SHARED_IRQ 1 - -#define DRIVER_PREINSTALL() do { \ - drm_i830_private_t *dev_priv = \ - (drm_i830_private_t *)dev->dev_private; \ - \ - I830_WRITE16( I830REG_HWSTAM, 0xffff ); \ - I830_WRITE16( I830REG_INT_MASK_R, 0x0 ); \ - I830_WRITE16( I830REG_INT_ENABLE_R, 0x0 ); \ -} while (0) - - -#define DRIVER_POSTINSTALL() do { \ - drm_i830_private_t *dev_priv = \ - (drm_i830_private_t *)dev->dev_private; \ - I830_WRITE16( I830REG_INT_ENABLE_R, 0x2 ); \ - atomic_set(&dev_priv->irq_received, 0); \ - atomic_set(&dev_priv->irq_emitted, 0); \ - init_waitqueue_head(&dev_priv->irq_queue); \ -} while (0) - - -/* This gets called too late to be useful: dev_priv has already been - * freed. - */ -#define DRIVER_UNINSTALL() do { \ -} while (0) - #else #define __HAVE_DMA_IRQ 0 #endif - /* Buffer customization: */ diff -urN linux-2.4.23-pre8/drivers/char/drm/i830_dma.c linux-2.4.23-pre8-pac1/drivers/char/drm/i830_dma.c --- linux-2.4.23-pre8/drivers/char/drm/i830_dma.c 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/i830_dma.c 2003-06-30 00:32:46.000000000 +0200 @@ -31,7 +31,7 @@ * */ - +#define __NO_VERSION__ #include "i830.h" #include "drmP.h" #include "drm.h" @@ -41,7 +41,11 @@ #include /* For FASTCALL on unlock_page() */ #include +#ifdef DO_MUNMAP_4_ARGS +#define DO_MUNMAP(m, a, l) do_munmap(m, a, l, 1) +#else #define DO_MUNMAP(m, a, l) do_munmap(m, a, l) +#endif #define I830_BUF_FREE 2 #define I830_BUF_CLIENT 1 @@ -50,24 +54,16 @@ #define I830_BUF_UNMAPPED 0 #define I830_BUF_MAPPED 1 - - - - - - - - - - - - +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,2) +#define down_write down +#define up_write up +#endif static inline void i830_print_status_page(drm_device_t *dev) { drm_device_dma_t *dma = dev->dma; drm_i830_private_t *dev_priv = dev->dev_private; - u32 *temp = (u32 *)dev_priv->hw_status_page; + u32 *temp = dev_priv->hw_status_page; int i; DRM_DEBUG( "hw_status: Interrupt Status : %x\n", temp[0]); @@ -126,9 +122,7 @@ .release = DRM(release), .ioctl = DRM(ioctl), .mmap = i830_mmap_buffers, - .read = DRM(read), .fasync = DRM(fasync), - .poll = DRM(poll), }; int i830_mmap_buffers(struct file *filp, struct vm_area_struct *vma) @@ -179,10 +173,10 @@ buf->bus_address); dev_priv->mmap_buffer = NULL; filp->f_op = old_fops; - if ((unsigned long)buf_priv->virtual > -1024UL) { + if (IS_ERR(buf_priv->virtual)) { /* Real error */ DRM_ERROR("mmap error\n"); - retcode = (signed int)buf_priv->virtual; + retcode = PTR_ERR(buf_priv->virtual); buf_priv->virtual = 0; } up_write( ¤t->mm->mmap_sem ); @@ -213,7 +207,6 @@ static int i830_dma_get_buffer(drm_device_t *dev, drm_i830_dma_t *d, struct file *filp) { - drm_file_t *priv = filp->private_data; drm_buf_t *buf; drm_i830_buf_priv_t *buf_priv; int retcode = 0; @@ -231,7 +224,7 @@ DRM_ERROR("mapbuf failed, retcode %d\n", retcode); return retcode; } - buf->pid = priv->pid; + buf->filp = filp; buf_priv = buf->dev_private; d->granted = 1; d->request_idx = buf->idx; @@ -241,35 +234,35 @@ return retcode; } -static int i830_dma_cleanup(drm_device_t *dev) +int i830_dma_cleanup(drm_device_t *dev) { drm_device_dma_t *dma = dev->dma; - if(dev->dev_private) { +#if _HAVE_DMA_IRQ + /* Make sure interrupts are disabled here because the uninstall ioctl + * may not have been called from userspace and after dev_private + * is freed, it's too late. + */ + if (dev->irq) DRM(irq_uninstall)(dev); +#endif + + if (dev->dev_private) { int i; drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private; - if(dev_priv->ring.virtual_start) { + if (dev_priv->ring.virtual_start) { DRM(ioremapfree)((void *) dev_priv->ring.virtual_start, - dev_priv->ring.Size); + dev_priv->ring.Size, dev); } - if(dev_priv->hw_status_page != 0UL) { + if (dev_priv->hw_status_page) { pci_free_consistent(dev->pdev, PAGE_SIZE, - (void *)dev_priv->hw_status_page, + dev_priv->hw_status_page, dev_priv->dma_status_page); /* Need to rewrite hardware status page */ I830_WRITE(0x02080, 0x1ffff000); } - /* Disable interrupts here because after dev_private - * is freed, it's too late. - */ - if (dev->irq) { - I830_WRITE16( I830REG_INT_MASK_R, 0xffff ); - I830_WRITE16( I830REG_INT_ENABLE_R, 0x0 ); - } - DRM(free)(dev->dev_private, sizeof(drm_i830_private_t), DRM_MEM_DRIVER); dev->dev_private = NULL; @@ -277,7 +270,8 @@ for (i = 0; i < dma->buf_count; i++) { drm_buf_t *buf = dma->buflist[ i ]; drm_i830_buf_priv_t *buf_priv = buf->dev_private; - DRM(ioremapfree)(buf_priv->kernel_virtual, buf->total); + if ( buf_priv->kernel_virtual && buf->total ) + DRM(ioremapfree)(buf_priv->kernel_virtual, buf->total, dev); } } return 0; @@ -353,7 +347,7 @@ *buf_priv->in_use = I830_BUF_FREE; buf_priv->kernel_virtual = DRM(ioremap)(buf->bus_address, - buf->total); + buf->total, dev); } return 0; } @@ -367,7 +361,7 @@ memset(dev_priv, 0, sizeof(drm_i830_private_t)); list_for_each(list, &dev->maplist->head) { - drm_map_list_t *r_list = (drm_map_list_t *)list; + drm_map_list_t *r_list = list_entry(list, drm_map_list_t, head); if( r_list->map && r_list->map->type == _DRM_SHM && r_list->map->flags & _DRM_CONTAINS_LOCK ) { @@ -407,7 +401,7 @@ dev_priv->ring.virtual_start = DRM(ioremap)(dev->agp->base + init->ring_start, - init->ring_size); + init->ring_size, dev); if (dev_priv->ring.virtual_start == NULL) { dev->dev_private = (void *) dev_priv; @@ -436,7 +430,7 @@ DRM_DEBUG("pitch_bits %x\n", init->pitch_bits); dev_priv->cpp = init->cpp; - /* We are using seperate values as placeholders for mechanisms for + /* We are using separate values as placeholders for mechanisms for * private backbuffer/depthbuffer usage. */ @@ -447,18 +441,18 @@ /* Program Hardware Status Page */ dev_priv->hw_status_page = - (unsigned long) pci_alloc_consistent(dev->pdev, PAGE_SIZE, + pci_alloc_consistent(dev->pdev, PAGE_SIZE, &dev_priv->dma_status_page); - if(dev_priv->hw_status_page == 0UL) { + if (!dev_priv->hw_status_page) { dev->dev_private = (void *)dev_priv; i830_dma_cleanup(dev); DRM_ERROR("Can not allocate hardware status page\n"); return -ENOMEM; } - memset((void *) dev_priv->hw_status_page, 0, PAGE_SIZE); - DRM_DEBUG("hw status page @ %lx\n", dev_priv->hw_status_page); + memset(dev_priv->hw_status_page, 0, PAGE_SIZE); + DRM_DEBUG("hw status page @ %p\n", dev_priv->hw_status_page); - I830_WRITE(0x02080, dev_priv->dma_status_page); + I830_WRITE(0x02080, dev_priv->dma_status_page); DRM_DEBUG("Enabled hardware status page\n"); /* Now we need to init our freelist */ @@ -627,7 +621,7 @@ int i; RING_LOCALS; - return; /* Is this right ? -- Arjan */ + return; BEGIN_LP_RING( 258 ); @@ -1297,8 +1291,10 @@ } /* Must be called with the lock held */ -void i830_reclaim_buffers(drm_device_t *dev, pid_t pid) +void i830_reclaim_buffers( struct file *filp ) { + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; drm_device_dma_t *dma = dev->dma; int i; @@ -1312,7 +1308,7 @@ drm_buf_t *buf = dma->buflist[ i ]; drm_i830_buf_priv_t *buf_priv = buf->dev_private; - if (buf->pid == pid && buf_priv) { + if (buf->filp == filp && buf_priv) { int used = cmpxchg(buf_priv->in_use, I830_BUF_CLIENT, I830_BUF_FREE); @@ -1346,7 +1342,7 @@ drm_device_t *dev = priv->dev; drm_device_dma_t *dma = dev->dma; drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private; - u32 *hw_status = (u32 *)dev_priv->hw_status_page; + u32 *hw_status = dev_priv->hw_status_page; drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *) dev_priv->sarea_priv; drm_i830_vertex_t vertex; @@ -1471,7 +1467,7 @@ drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private; - u32 *hw_status = (u32 *)dev_priv->hw_status_page; + u32 *hw_status = dev_priv->hw_status_page; drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *) dev_priv->sarea_priv; @@ -1487,7 +1483,7 @@ int retcode = 0; drm_i830_dma_t d; drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private; - u32 *hw_status = (u32 *)dev_priv->hw_status_page; + u32 *hw_status = dev_priv->hw_status_page; drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *) dev_priv->sarea_priv; diff -urN linux-2.4.23-pre8/drivers/char/drm/i830_drm.h linux-2.4.23-pre8-pac1/drivers/char/drm/i830_drm.h --- linux-2.4.23-pre8/drivers/char/drm/i830_drm.h 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/i830_drm.h 2003-05-01 14:18:11.000000000 +0200 @@ -70,7 +70,7 @@ * - zbuffer linear offset and pitch -- also invarient * - drawing origin in back and depth buffers. * - * Keep the depth/back buffer state here to acommodate private buffers + * Keep the depth/back buffer state here to accommodate private buffers * in the future. */ diff -urN linux-2.4.23-pre8/drivers/char/drm/i830_drv.c linux-2.4.23-pre8-pac1/drivers/char/drm/i830_drv.c --- linux-2.4.23-pre8/drivers/char/drm/i830_drv.c 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/i830_drv.c 2003-05-01 14:18:11.000000000 +0200 @@ -51,7 +51,6 @@ #include "drm_init.h" #include "drm_ioctl.h" #include "drm_lock.h" -#include "drm_lists.h" #include "drm_memory.h" #include "drm_proc.h" #include "drm_vm.h" diff -urN linux-2.4.23-pre8/drivers/char/drm/i830_drv.h linux-2.4.23-pre8-pac1/drivers/char/drm/i830_drv.h --- linux-2.4.23-pre8/drivers/char/drm/i830_drv.h 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/i830_drv.h 2003-06-30 00:32:46.000000000 +0200 @@ -38,8 +38,6 @@ int currently_mapped; void *virtual; void *kernel_virtual; - int map_count; - struct vm_area_struct *vma; } drm_i830_buf_priv_t; typedef struct _drm_i830_ring_buffer{ @@ -61,7 +59,7 @@ drm_i830_sarea_t *sarea_priv; drm_i830_ring_buffer_t ring; - unsigned long hw_status_page; + void * hw_status_page; unsigned long counter; dma_addr_t dma_status_page; @@ -99,9 +97,10 @@ unsigned int cmd, unsigned long arg); extern int i830_dma_init(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); +extern int i830_dma_cleanup(drm_device_t *dev); extern int i830_flush_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); -extern void i830_reclaim_buffers(drm_device_t *dev, pid_t pid); +extern void i830_reclaim_buffers(struct file *filp); extern int i830_getage(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); extern int i830_mmap_buffers(struct file *filp, struct vm_area_struct *vma); diff -urN linux-2.4.23-pre8/drivers/char/drm/i830_irq.c linux-2.4.23-pre8-pac1/drivers/char/drm/i830_irq.c --- linux-2.4.23-pre8/drivers/char/drm/i830_irq.c 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/i830_irq.c 2003-08-18 12:56:12.000000000 +0200 @@ -26,7 +26,7 @@ * */ - +#define __NO_VERSION__ #include "i830.h" #include "drmP.h" #include "drm.h" @@ -36,24 +36,24 @@ #include -void DRM(dma_service)(int irq, void *device, struct pt_regs *regs) +irqreturn_t DRM(dma_service)( DRM_IRQ_ARGS ) { - drm_device_t *dev = (drm_device_t *)device; + drm_device_t *dev = (drm_device_t *)arg; drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private; u16 temp; - + temp = I830_READ16(I830REG_INT_IDENTITY_R); - printk("%s: %x\n", __FUNCTION__, temp); - - if(temp == 0) - return; + DRM_DEBUG("%x\n", temp); + + if ( !( temp & 2 ) ) + return IRQ_NONE; I830_WRITE16(I830REG_INT_IDENTITY_R, temp); - if (temp & 2) { - atomic_inc(&dev_priv->irq_received); - wake_up_interruptible(&dev_priv->irq_queue); - } + atomic_inc(&dev_priv->irq_received); + wake_up_interruptible(&dev_priv->irq_queue); + + return IRQ_HANDLED; } @@ -96,7 +96,7 @@ current->state = TASK_INTERRUPTIBLE; if (atomic_read(&dev_priv->irq_received) >= irq_nr) break; - if (time_after(jiffies, end)) { + if((signed)(end - jiffies) <= 0) { DRM_ERROR("timeout iir %x imr %x ier %x hwstam %x\n", I830_READ16( I830REG_INT_IDENTITY_R ), I830_READ16( I830REG_INT_MASK_R ), @@ -176,3 +176,34 @@ return i830_wait_irq( dev, irqwait.irq_seq ); } + +/* drm_dma.h hooks +*/ +void DRM(driver_irq_preinstall)( drm_device_t *dev ) { + drm_i830_private_t *dev_priv = + (drm_i830_private_t *)dev->dev_private; + + I830_WRITE16( I830REG_HWSTAM, 0xffff ); + I830_WRITE16( I830REG_INT_MASK_R, 0x0 ); + I830_WRITE16( I830REG_INT_ENABLE_R, 0x0 ); +} + +void DRM(driver_irq_postinstall)( drm_device_t *dev ) { + drm_i830_private_t *dev_priv = + (drm_i830_private_t *)dev->dev_private; + + I830_WRITE16( I830REG_INT_ENABLE_R, 0x2 ); + atomic_set(&dev_priv->irq_received, 0); + atomic_set(&dev_priv->irq_emitted, 0); + init_waitqueue_head(&dev_priv->irq_queue); +} + +void DRM(driver_irq_uninstall)( drm_device_t *dev ) { + drm_i830_private_t *dev_priv = + (drm_i830_private_t *)dev->dev_private; + if (!dev_priv) + return; + + I830_WRITE16( I830REG_INT_MASK_R, 0xffff ); + I830_WRITE16( I830REG_INT_ENABLE_R, 0x0 ); +} diff -urN linux-2.4.23-pre8/drivers/char/drm/mga.h linux-2.4.23-pre8-pac1/drivers/char/drm/mga.h --- linux-2.4.23-pre8/drivers/char/drm/mga.h 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/mga.h 2003-06-30 00:32:46.000000000 +0200 @@ -45,11 +45,11 @@ #define DRIVER_NAME "mga" #define DRIVER_DESC "Matrox G200/G400" -#define DRIVER_DATE "20010321" +#define DRIVER_DATE "20021029" #define DRIVER_MAJOR 3 -#define DRIVER_MINOR 0 -#define DRIVER_PATCHLEVEL 2 +#define DRIVER_MINOR 1 +#define DRIVER_PATCHLEVEL 0 #define DRIVER_IOCTLS \ [DRM_IOCTL_NR(DRM_IOCTL_DMA)] = { mga_dma_buffers, 1, 0 }, \ @@ -61,7 +61,8 @@ [DRM_IOCTL_NR(DRM_IOCTL_MGA_VERTEX)] = { mga_dma_vertex, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_MGA_INDICES)] = { mga_dma_indices, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_MGA_ILOAD)] = { mga_dma_iload, 1, 0 }, \ - [DRM_IOCTL_NR(DRM_IOCTL_MGA_BLIT)] = { mga_dma_blit, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_MGA_BLIT)] = { mga_dma_blit, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_MGA_GETPARAM)]= { mga_getparam, 1, 0 }, #define __HAVE_COUNTERS 3 #define __HAVE_COUNTER6 _DRM_STAT_IRQ @@ -71,12 +72,15 @@ /* Driver customization: */ #define DRIVER_PRETAKEDOWN() do { \ - if ( dev->dev_private ) mga_do_cleanup_dma( dev ); \ + mga_do_cleanup_dma( dev ); \ } while (0) /* DMA customization: */ #define __HAVE_DMA 1 +#define __HAVE_DMA_IRQ 1 +#define __HAVE_VBL_IRQ 1 +#define __HAVE_SHARED_IRQ 1 #define __HAVE_DMA_QUIESCENT 1 #define DRIVER_DMA_QUIESCENT() do { \ diff -urN linux-2.4.23-pre8/drivers/char/drm/mga_dma.c linux-2.4.23-pre8-pac1/drivers/char/drm/mga_dma.c --- linux-2.4.23-pre8/drivers/char/drm/mga_dma.c 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/mga_dma.c 2003-06-30 00:32:46.000000000 +0200 @@ -38,8 +38,6 @@ #include "drm.h" #include "mga_drm.h" #include "mga_drv.h" -#include -#include "drm_os_linux.h" #define MGA_DEFAULT_USEC_TIMEOUT 10000 #define MGA_FREELIST_DEBUG 0 @@ -61,14 +59,14 @@ MGA_WRITE8( MGA_CRTC_INDEX, 0 ); return 0; } - udelay( 1 ); + DRM_UDELAY( 1 ); } #if MGA_DMA_DEBUG DRM_ERROR( "failed!\n" ); DRM_INFO( " status=0x%08x\n", status ); #endif - return -EBUSY; + return DRM_ERR(EBUSY); } int mga_do_dma_idle( drm_mga_private_t *dev_priv ) @@ -80,13 +78,13 @@ for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { status = MGA_READ( MGA_STATUS ) & MGA_DMA_IDLE_MASK; if ( status == MGA_ENDPRDMASTS ) return 0; - udelay( 1 ); + DRM_UDELAY( 1 ); } #if MGA_DMA_DEBUG DRM_ERROR( "failed! status=0x%08x\n", status ); #endif - return -EBUSY; + return DRM_ERR(EBUSY); } int mga_do_dma_reset( drm_mga_private_t *dev_priv ) @@ -121,7 +119,7 @@ * How about we clean up after ourselves? */ MGA_WRITE( MGA_RST, MGA_SOFTRESET ); - udelay( 15 ); /* Wait at least 10 usecs */ + DRM_UDELAY( 15 ); /* Wait at least 10 usecs */ MGA_WRITE( MGA_RST, 0 ); /* Initialize the registers that get clobbered by the soft @@ -168,7 +166,7 @@ for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { status = MGA_READ( MGA_STATUS ) & MGA_ENGINE_IDLE_MASK; if ( status == MGA_ENDPRDMASTS ) break; - udelay( 1 ); + DRM_UDELAY( 1 ); } if ( primary->tail == primary->last_flush ) { @@ -313,7 +311,7 @@ dev_priv->head = DRM(alloc)( sizeof(drm_mga_freelist_t), DRM_MEM_DRIVER ); if ( dev_priv->head == NULL ) - return -ENOMEM; + return DRM_ERR(ENOMEM); memset( dev_priv->head, 0, sizeof(drm_mga_freelist_t) ); SET_AGE( &dev_priv->head->age, MGA_BUFFER_USED, 0 ); @@ -325,7 +323,7 @@ entry = DRM(alloc)( sizeof(drm_mga_freelist_t), DRM_MEM_DRIVER ); if ( entry == NULL ) - return -ENOMEM; + return DRM_ERR(ENOMEM); memset( entry, 0, sizeof(drm_mga_freelist_t) ); @@ -462,7 +460,7 @@ dev_priv = DRM(alloc)( sizeof(drm_mga_private_t), DRM_MEM_DRIVER ); if ( !dev_priv ) - return -ENOMEM; + return DRM_ERR(ENOMEM); memset( dev_priv, 0, sizeof(drm_mga_private_t) ); @@ -499,7 +497,7 @@ /* Assign dev_private so we can do cleanup. */ dev->dev_private = (void *)dev_priv; mga_do_cleanup_dma( dev ); - return -EINVAL; + return DRM_ERR(EINVAL); } DRM_FIND_MAP( dev_priv->fb, init->fb_offset ); @@ -508,7 +506,7 @@ /* Assign dev_private so we can do cleanup. */ dev->dev_private = (void *)dev_priv; mga_do_cleanup_dma( dev ); - return -EINVAL; + return DRM_ERR(EINVAL); } DRM_FIND_MAP( dev_priv->mmio, init->mmio_offset ); if(!dev_priv->mmio) { @@ -516,7 +514,7 @@ /* Assign dev_private so we can do cleanup. */ dev->dev_private = (void *)dev_priv; mga_do_cleanup_dma( dev ); - return -EINVAL; + return DRM_ERR(EINVAL); } DRM_FIND_MAP( dev_priv->status, init->status_offset ); if(!dev_priv->status) { @@ -524,7 +522,7 @@ /* Assign dev_private so we can do cleanup. */ dev->dev_private = (void *)dev_priv; mga_do_cleanup_dma( dev ); - return -EINVAL; + return DRM_ERR(EINVAL); } DRM_FIND_MAP( dev_priv->warp, init->warp_offset ); @@ -533,7 +531,7 @@ /* Assign dev_private so we can do cleanup. */ dev->dev_private = (void *)dev_priv; mga_do_cleanup_dma( dev ); - return -EINVAL; + return DRM_ERR(EINVAL); } DRM_FIND_MAP( dev_priv->primary, init->primary_offset ); if(!dev_priv->primary) { @@ -541,7 +539,7 @@ /* Assign dev_private so we can do cleanup. */ dev->dev_private = (void *)dev_priv; mga_do_cleanup_dma( dev ); - return -EINVAL; + return DRM_ERR(EINVAL); } DRM_FIND_MAP( dev_priv->buffers, init->buffers_offset ); if(!dev_priv->buffers) { @@ -549,16 +547,16 @@ /* Assign dev_private so we can do cleanup. */ dev->dev_private = (void *)dev_priv; mga_do_cleanup_dma( dev ); - return -EINVAL; + return DRM_ERR(EINVAL); } dev_priv->sarea_priv = (drm_mga_sarea_t *)((u8 *)dev_priv->sarea->handle + init->sarea_priv_offset); - DRM_IOREMAP( dev_priv->warp ); - DRM_IOREMAP( dev_priv->primary ); - DRM_IOREMAP( dev_priv->buffers ); + DRM_IOREMAP( dev_priv->warp, dev ); + DRM_IOREMAP( dev_priv->primary, dev ); + DRM_IOREMAP( dev_priv->buffers, dev ); if(!dev_priv->warp->handle || !dev_priv->primary->handle || @@ -567,7 +565,7 @@ /* Assign dev_private so we can do cleanup. */ dev->dev_private = (void *)dev_priv; mga_do_cleanup_dma( dev ); - return -ENOMEM; + return DRM_ERR(ENOMEM); } ret = mga_warp_install_microcode( dev_priv ); @@ -629,7 +627,7 @@ /* Assign dev_private so we can do cleanup. */ dev->dev_private = (void *)dev_priv; mga_do_cleanup_dma( dev ); - return -ENOMEM; + return DRM_ERR(ENOMEM); } /* Make dev_private visable to others. */ @@ -641,12 +639,23 @@ { DRM_DEBUG( "\n" ); +#if _HAVE_DMA_IRQ + /* Make sure interrupts are disabled here because the uninstall ioctl + * may not have been called from userspace and after dev_private + * is freed, it's too late. + */ + if ( dev->irq ) DRM(irq_uninstall)(dev); +#endif + if ( dev->dev_private ) { drm_mga_private_t *dev_priv = dev->dev_private; - DRM_IOREMAPFREE( dev_priv->warp ); - DRM_IOREMAPFREE( dev_priv->primary ); - DRM_IOREMAPFREE( dev_priv->buffers ); + if ( dev_priv->warp != NULL ) + DRM_IOREMAPFREE( dev_priv->warp, dev ); + if ( dev_priv->primary != NULL ) + DRM_IOREMAPFREE( dev_priv->primary, dev ); + if ( dev_priv->buffers != NULL ) + DRM_IOREMAPFREE( dev_priv->buffers, dev ); if ( dev_priv->head != NULL ) { mga_freelist_cleanup( dev ); @@ -660,15 +669,14 @@ return 0; } -int mga_dma_init( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) +int mga_dma_init( DRM_IOCTL_ARGS ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; + DRM_DEVICE; drm_mga_init_t init; - if ( copy_from_user( &init, (drm_mga_init_t *)arg, sizeof(init) ) ) - return -EFAULT; + LOCK_TEST_WITH_RETURN( dev, filp ); + + DRM_COPY_FROM_USER_IOCTL( init, (drm_mga_init_t *)data, sizeof(init) ); switch ( init.func ) { case MGA_INIT_DMA: @@ -677,7 +685,7 @@ return mga_do_cleanup_dma( dev ); } - return -EINVAL; + return DRM_ERR(EINVAL); } @@ -685,21 +693,17 @@ * Primary DMA stream management */ -int mga_dma_flush( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) +int mga_dma_flush( DRM_IOCTL_ARGS ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; + DRM_DEVICE; drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; drm_lock_t lock; - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); - if ( copy_from_user( &lock, (drm_lock_t *)arg, sizeof(lock) ) ) - return -EFAULT; + DRM_COPY_FROM_USER_IOCTL( lock, (drm_lock_t *)data, sizeof(lock) ); - DRM_DEBUG( "%s: %s%s%s\n", - __FUNCTION__, + DRM_DEBUG( "%s%s%s\n", (lock.flags & _DRM_LOCK_FLUSH) ? "flush, " : "", (lock.flags & _DRM_LOCK_FLUSH_ALL) ? "flush all, " : "", (lock.flags & _DRM_LOCK_QUIESCENT) ? "idle, " : "" ); @@ -724,14 +728,12 @@ } } -int mga_dma_reset( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) +int mga_dma_reset( DRM_IOCTL_ARGS ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; + DRM_DEVICE; drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); return mga_do_dma_reset( dev_priv ); } @@ -741,58 +743,56 @@ * DMA buffer management */ -static int mga_dma_get_buffers( drm_device_t *dev, drm_dma_t *d ) +static int mga_dma_get_buffers( DRMFILE filp, + drm_device_t *dev, drm_dma_t *d ) { drm_buf_t *buf; int i; for ( i = d->granted_count ; i < d->request_count ; i++ ) { buf = mga_freelist_get( dev ); - if ( !buf ) return -EAGAIN; + if ( !buf ) return DRM_ERR(EAGAIN); - buf->pid = current->pid; + buf->filp = filp; - if ( copy_to_user( &d->request_indices[i], + if ( DRM_COPY_TO_USER( &d->request_indices[i], &buf->idx, sizeof(buf->idx) ) ) - return -EFAULT; - if ( copy_to_user( &d->request_sizes[i], + return DRM_ERR(EFAULT); + if ( DRM_COPY_TO_USER( &d->request_sizes[i], &buf->total, sizeof(buf->total) ) ) - return -EFAULT; + return DRM_ERR(EFAULT); d->granted_count++; } return 0; } -int mga_dma_buffers( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) +int mga_dma_buffers( DRM_IOCTL_ARGS ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; + DRM_DEVICE; drm_device_dma_t *dma = dev->dma; drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; drm_dma_t d; int ret = 0; - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); - if ( copy_from_user( &d, (drm_dma_t *)arg, sizeof(d) ) ) - return -EFAULT; + DRM_COPY_FROM_USER_IOCTL( d, (drm_dma_t *)data, sizeof(d) ); /* Please don't send us buffers. */ if ( d.send_count != 0 ) { DRM_ERROR( "Process %d trying to send %d buffers via drmDMA\n", - current->pid, d.send_count ); - return -EINVAL; + DRM_CURRENTPID, d.send_count ); + return DRM_ERR(EINVAL); } /* We'll send you buffers. */ if ( d.request_count < 0 || d.request_count > dma->buf_count ) { DRM_ERROR( "Process %d trying to get %d buffers (of %d max)\n", - current->pid, d.request_count, dma->buf_count ); - return -EINVAL; + DRM_CURRENTPID, d.request_count, dma->buf_count ); + return DRM_ERR(EINVAL); } WRAP_TEST_WITH_RETURN( dev_priv ); @@ -800,11 +800,10 @@ d.granted_count = 0; if ( d.request_count ) { - ret = mga_dma_get_buffers( dev, &d ); + ret = mga_dma_get_buffers( filp, dev, &d ); } - if ( copy_to_user( (drm_dma_t *)arg, &d, sizeof(d) ) ) - return -EFAULT; + DRM_COPY_TO_USER_IOCTL( (drm_dma_t *)data, d, sizeof(d) ); return ret; } diff -urN linux-2.4.23-pre8/drivers/char/drm/mga_drm.h linux-2.4.23-pre8-pac1/drivers/char/drm/mga_drm.h --- linux-2.4.23-pre8/drivers/char/drm/mga_drm.h 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/mga_drm.h 2002-12-18 03:40:36.000000000 +0100 @@ -38,6 +38,7 @@ /* WARNING: If you change any of these defines, make sure to change the * defines in the Xserver file (mga_sarea.h) */ + #ifndef __MGA_SAREA_DEFINES__ #define __MGA_SAREA_DEFINES__ @@ -238,6 +239,7 @@ #define DRM_IOCTL_MGA_INDICES DRM_IOW( 0x46, drm_mga_indices_t) #define DRM_IOCTL_MGA_ILOAD DRM_IOW( 0x47, drm_mga_iload_t) #define DRM_IOCTL_MGA_BLIT DRM_IOW( 0x48, drm_mga_blit_t) +#define DRM_IOCTL_MGA_GETPARAM DRM_IOWR(0x49, drm_mga_getparam_t) typedef struct _drm_mga_warp_index { int installed; @@ -321,4 +323,14 @@ int source_pitch, dest_pitch; } drm_mga_blit_t; +/* 3.1: An ioctl to get parameters that aren't available to the 3d + * client any other way. + */ +#define MGA_PARAM_IRQ_NR 1 + +typedef struct drm_mga_getparam { + int param; + int *value; +} drm_mga_getparam_t; + #endif diff -urN linux-2.4.23-pre8/drivers/char/drm/mga_drv.h linux-2.4.23-pre8-pac1/drivers/char/drm/mga_drv.h --- linux-2.4.23-pre8/drivers/char/drm/mga_drv.h 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/mga_drv.h 2003-06-30 00:32:46.000000000 +0200 @@ -90,25 +90,21 @@ unsigned int texture_offset; unsigned int texture_size; - drm_map_t *sarea; - drm_map_t *fb; - drm_map_t *mmio; - drm_map_t *status; - drm_map_t *warp; - drm_map_t *primary; - drm_map_t *buffers; - drm_map_t *agp_textures; + drm_local_map_t *sarea; + drm_local_map_t *fb; + drm_local_map_t *mmio; + drm_local_map_t *status; + drm_local_map_t *warp; + drm_local_map_t *primary; + drm_local_map_t *buffers; + drm_local_map_t *agp_textures; } drm_mga_private_t; /* mga_dma.c */ -extern int mga_dma_init( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int mga_dma_flush( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int mga_dma_reset( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int mga_dma_buffers( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); +extern int mga_dma_init( DRM_IOCTL_ARGS ); +extern int mga_dma_flush( DRM_IOCTL_ARGS ); +extern int mga_dma_reset( DRM_IOCTL_ARGS ); +extern int mga_dma_buffers( DRM_IOCTL_ARGS ); extern int mga_do_wait_for_idle( drm_mga_private_t *dev_priv ); extern int mga_do_dma_idle( drm_mga_private_t *dev_priv ); @@ -123,47 +119,42 @@ extern int mga_freelist_put( drm_device_t *dev, drm_buf_t *buf ); /* mga_state.c */ -extern int mga_dma_clear( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int mga_dma_swap( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int mga_dma_vertex( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int mga_dma_indices( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int mga_dma_iload( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int mga_dma_blit( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); +extern int mga_dma_clear( DRM_IOCTL_ARGS ); +extern int mga_dma_swap( DRM_IOCTL_ARGS ); +extern int mga_dma_vertex( DRM_IOCTL_ARGS ); +extern int mga_dma_indices( DRM_IOCTL_ARGS ); +extern int mga_dma_iload( DRM_IOCTL_ARGS ); +extern int mga_dma_blit( DRM_IOCTL_ARGS ); +extern int mga_getparam( DRM_IOCTL_ARGS ); /* mga_warp.c */ extern int mga_warp_install_microcode( drm_mga_private_t *dev_priv ); extern int mga_warp_init( drm_mga_private_t *dev_priv ); -#define mga_flush_write_combine() mb() - +#define mga_flush_write_combine() DRM_WRITEMEMORYBARRIER() +#if defined(__linux__) && defined(__alpha__) #define MGA_BASE( reg ) ((unsigned long)(dev_priv->mmio->handle)) #define MGA_ADDR( reg ) (MGA_BASE(reg) + reg) #define MGA_DEREF( reg ) *(volatile u32 *)MGA_ADDR( reg ) #define MGA_DEREF8( reg ) *(volatile u8 *)MGA_ADDR( reg ) -#ifdef __alpha__ #define MGA_READ( reg ) (_MGA_READ((u32 *)MGA_ADDR(reg))) -#define MGA_WRITE( reg, val ) do { wmb(); MGA_DEREF( reg ) = val; } while (0) -#define MGA_WRITE8( reg, val ) do { wmb(); MGA_DEREF8( reg ) = val; } while (0) +#define MGA_READ8( reg ) (_MGA_READ((u8 *)MGA_ADDR(reg))) +#define MGA_WRITE( reg, val ) do { DRM_WRITEMEMORYBARRIER(); MGA_DEREF( reg ) = val; } while (0) +#define MGA_WRITE8( reg, val ) do { DRM_WRITEMEMORYBARRIER(); MGA_DEREF8( reg ) = val; } while (0) static inline u32 _MGA_READ(u32 *addr) { - mb(); + DRM_MEMORYBARRIER(); return *(volatile u32 *)addr; } - #else -#define MGA_READ( reg ) MGA_DEREF( reg ) -#define MGA_WRITE( reg, val ) do { MGA_DEREF( reg ) = val; } while (0) -#define MGA_WRITE8( reg, val ) do { MGA_DEREF8( reg ) = val; } while (0) +#define MGA_READ8( reg ) DRM_READ8(dev_priv->mmio, (reg)) +#define MGA_READ( reg ) DRM_READ32(dev_priv->mmio, (reg)) +#define MGA_WRITE8( reg, val ) DRM_WRITE8(dev_priv->mmio, (reg), (val)) +#define MGA_WRITE( reg, val ) DRM_WRITE32(dev_priv->mmio, (reg), (val)) #endif #define DWGREG0 0x1c00 @@ -193,16 +184,6 @@ } \ } while (0) -#define LOCK_TEST_WITH_RETURN( dev ) \ -do { \ - if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || \ - dev->lock.pid != current->pid ) { \ - DRM_ERROR( "%s called without lock held\n", \ - __FUNCTION__ ); \ - return -EINVAL; \ - } \ -} while (0) - #define WRAP_TEST_WITH_RETURN( dev_priv ) \ do { \ if ( test_bit( 0, &dev_priv->prim.wrapped ) ) { \ @@ -212,7 +193,7 @@ dev_priv->prim.high_mark ) { \ if ( MGA_DMA_DEBUG ) \ DRM_INFO( "%s: wrap...\n", __FUNCTION__ ); \ - return -EBUSY; \ + return DRM_ERR(EBUSY); \ } \ } \ } while (0) @@ -223,7 +204,7 @@ if ( mga_do_wait_for_idle( dev_priv ) < 0 ) { \ if ( MGA_DMA_DEBUG ) \ DRM_INFO( "%s: wrap...\n", __FUNCTION__ ); \ - return -EBUSY; \ + return DRM_ERR(EBUSY); \ } \ mga_do_dma_wrap_end( dev_priv ); \ } \ @@ -245,7 +226,7 @@ if ( MGA_VERBOSE ) { \ DRM_INFO( "BEGIN_DMA( %d ) in %s\n", \ (n), __FUNCTION__ ); \ - DRM_INFO( " space=0x%x req=0x%x\n", \ + DRM_INFO( " space=0x%x req=0x%Zx\n", \ dev_priv->prim.space, (n) * DMA_BLOCK_SIZE ); \ } \ prim = dev_priv->prim.start; \ @@ -295,7 +276,7 @@ #define DMA_WRITE( offset, val ) \ do { \ if ( MGA_VERBOSE ) { \ - DRM_INFO( " DMA_WRITE( 0x%08x ) at 0x%04x\n", \ + DRM_INFO( " DMA_WRITE( 0x%08x ) at 0x%04Zx\n", \ (u32)(val), write + (offset) * sizeof(u32) ); \ } \ *(volatile u32 *)(prim + write + (offset) * sizeof(u32)) = val; \ @@ -355,6 +336,11 @@ /* A reduced set of the mga registers. */ #define MGA_CRTC_INDEX 0x1fd4 +#define MGA_CRTC_DATA 0x1fd5 + +/* CRTC11 */ +#define MGA_VINTCLR (1 << 4) +#define MGA_VINTEN (1 << 5) #define MGA_ALPHACTRL 0x2c7c #define MGA_AR0 0x1c60 @@ -426,8 +412,10 @@ #define MGA_ICLEAR 0x1e18 # define MGA_SOFTRAPICLR (1 << 0) +# define MGA_VLINEICLR (1 << 5) #define MGA_IEN 0x1e1c # define MGA_SOFTRAPIEN (1 << 0) +# define MGA_VLINEIEN (1 << 5) #define MGA_LEN 0x1c5c @@ -466,6 +454,8 @@ # define MGA_SRCACC_AGP (1 << 1) #define MGA_STATUS 0x1e14 # define MGA_SOFTRAPEN (1 << 0) +# define MGA_VSYNCPEN (1 << 4) +# define MGA_VLINEPEN (1 << 5) # define MGA_DWGENGSTS (1 << 16) # define MGA_ENDPRDMASTS (1 << 17) #define MGA_STENCIL 0x2cc8 @@ -632,7 +622,7 @@ /* Simple idle test. */ -static inline int mga_is_idle( drm_mga_private_t *dev_priv ) +static __inline__ int mga_is_idle( drm_mga_private_t *dev_priv ) { u32 status = MGA_READ( MGA_STATUS ) & MGA_ENGINE_IDLE_MASK; return ( status == MGA_ENDPRDMASTS ); diff -urN linux-2.4.23-pre8/drivers/char/drm/mga_irq.c linux-2.4.23-pre8-pac1/drivers/char/drm/mga_irq.c --- linux-2.4.23-pre8/drivers/char/drm/mga_irq.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/mga_irq.c 2003-08-18 12:56:12.000000000 +0200 @@ -0,0 +1,103 @@ +/* mga_irq.c -- IRQ handling for radeon -*- linux-c -*- + * + * Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved. + * + * The Weather Channel (TM) funded Tungsten Graphics to develop the + * initial release of the Radeon 8500 driver under the XFree86 license. + * This notice must be preserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * 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 + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * 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: + * Keith Whitwell + * Eric Anholt + */ + +#include "mga.h" +#include "drmP.h" +#include "drm.h" +#include "mga_drm.h" +#include "mga_drv.h" + +irqreturn_t mga_dma_service( DRM_IRQ_ARGS ) +{ + drm_device_t *dev = (drm_device_t *) arg; + drm_mga_private_t *dev_priv = + (drm_mga_private_t *)dev->dev_private; + int status; + + status = MGA_READ( MGA_STATUS ); + + /* VBLANK interrupt */ + if ( status & MGA_VLINEPEN ) { + MGA_WRITE( MGA_ICLEAR, MGA_VLINEICLR ); + atomic_inc(&dev->vbl_received); + DRM_WAKEUP(&dev->vbl_queue); + DRM(vbl_send_signals)( dev ); + return IRQ_HANDLED; + } + return IRQ_NONE; +} + +int mga_vblank_wait(drm_device_t *dev, unsigned int *sequence) +{ + unsigned int cur_vblank; + int ret = 0; + + /* Assume that the user has missed the current sequence number + * by about a day rather than she wants to wait for years + * using vertical blanks... + */ + DRM_WAIT_ON( ret, dev->vbl_queue, 3*DRM_HZ, + ( ( ( cur_vblank = atomic_read(&dev->vbl_received ) ) + - *sequence ) <= (1<<23) ) ); + + *sequence = cur_vblank; + + return ret; +} + +void mga_driver_irq_preinstall( drm_device_t *dev ) { + drm_mga_private_t *dev_priv = + (drm_mga_private_t *)dev->dev_private; + + /* Disable *all* interrupts */ + MGA_WRITE( MGA_IEN, 0 ); + /* Clear bits if they're already high */ + MGA_WRITE( MGA_ICLEAR, ~0 ); +} + +void mga_driver_irq_postinstall( drm_device_t *dev ) { + drm_mga_private_t *dev_priv = + (drm_mga_private_t *)dev->dev_private; + + /* Turn on VBL interrupt */ + MGA_WRITE( MGA_IEN, MGA_VLINEIEN ); +} + +void mga_driver_irq_uninstall( drm_device_t *dev ) { + drm_mga_private_t *dev_priv = + (drm_mga_private_t *)dev->dev_private; + if (!dev_priv) + return; + + /* Disable *all* interrupts */ + MGA_WRITE( MGA_IEN, 0 ); +} diff -urN linux-2.4.23-pre8/drivers/char/drm/mga_state.c linux-2.4.23-pre8-pac1/drivers/char/drm/mga_state.c --- linux-2.4.23-pre8/drivers/char/drm/mga_state.c 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/mga_state.c 2003-05-01 14:18:11.000000000 +0200 @@ -69,7 +69,7 @@ ADVANCE_DMA(); } -static inline void mga_g200_emit_context( drm_mga_private_t *dev_priv ) +static __inline__ void mga_g200_emit_context( drm_mga_private_t *dev_priv ) { drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_mga_context_regs_t *ctx = &sarea_priv->context_state; @@ -95,7 +95,7 @@ ADVANCE_DMA(); } -static inline void mga_g400_emit_context( drm_mga_private_t *dev_priv ) +static __inline__ void mga_g400_emit_context( drm_mga_private_t *dev_priv ) { drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_mga_context_regs_t *ctx = &sarea_priv->context_state; @@ -126,7 +126,7 @@ ADVANCE_DMA(); } -static inline void mga_g200_emit_tex0( drm_mga_private_t *dev_priv ) +static __inline__ void mga_g200_emit_tex0( drm_mga_private_t *dev_priv ) { drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_mga_texture_regs_t *tex = &sarea_priv->tex_state[0]; @@ -157,12 +157,15 @@ ADVANCE_DMA(); } -static inline void mga_g400_emit_tex0( drm_mga_private_t *dev_priv ) +static __inline__ void mga_g400_emit_tex0( drm_mga_private_t *dev_priv ) { drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_mga_texture_regs_t *tex = &sarea_priv->tex_state[0]; DMA_LOCALS; +/* printk("mga_g400_emit_tex0 %x %x %x\n", tex->texorg, */ +/* tex->texctl, tex->texctl2); */ + BEGIN_DMA( 6 ); DMA_BLOCK( MGA_TEXCTL2, tex->texctl2 | MGA_G400_TC2_MAGIC, @@ -198,12 +201,15 @@ ADVANCE_DMA(); } -static inline void mga_g400_emit_tex1( drm_mga_private_t *dev_priv ) +static __inline__ void mga_g400_emit_tex1( drm_mga_private_t *dev_priv ) { drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_mga_texture_regs_t *tex = &sarea_priv->tex_state[1]; DMA_LOCALS; +/* printk("mga_g400_emit_tex1 %x %x %x\n", tex->texorg, */ +/* tex->texctl, tex->texctl2); */ + BEGIN_DMA( 5 ); DMA_BLOCK( MGA_TEXCTL2, (tex->texctl2 | @@ -236,7 +242,7 @@ ADVANCE_DMA(); } -static inline void mga_g200_emit_pipe( drm_mga_private_t *dev_priv ) +static __inline__ void mga_g200_emit_pipe( drm_mga_private_t *dev_priv ) { drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; unsigned int pipe = sarea_priv->warp_pipe; @@ -266,12 +272,14 @@ ADVANCE_DMA(); } -static inline void mga_g400_emit_pipe( drm_mga_private_t *dev_priv ) +static __inline__ void mga_g400_emit_pipe( drm_mga_private_t *dev_priv ) { drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; unsigned int pipe = sarea_priv->warp_pipe; DMA_LOCALS; +/* printk("mga_g400_emit_pipe %x\n", pipe); */ + BEGIN_DMA( 10 ); DMA_BLOCK( MGA_WIADDR2, MGA_WMODE_SUSPEND, @@ -412,7 +420,7 @@ ctx->dstorg, dev_priv->front_offset, dev_priv->back_offset ); ctx->dstorg = 0; - return -EINVAL; + return DRM_ERR(EINVAL); } return 0; @@ -432,7 +440,7 @@ DRM_ERROR( "*** bad TEXORG: 0x%x, unit %d\n", tex->texorg, unit ); tex->texorg = 0; - return -EINVAL; + return DRM_ERR(EINVAL); } return 0; @@ -474,13 +482,13 @@ dstorg + length > (dev_priv->texture_offset + dev_priv->texture_size) ) { DRM_ERROR( "*** bad iload DSTORG: 0x%x\n", dstorg ); - return -EINVAL; + return DRM_ERR(EINVAL); } if ( length & MGA_ILOAD_MASK ) { DRM_ERROR( "*** bad iload length: 0x%x\n", length & MGA_ILOAD_MASK ); - return -EINVAL; + return DRM_ERR(EINVAL); } return 0; @@ -493,7 +501,7 @@ (dstorg & 0x3) == (MGA_SRCACC_PCI | MGA_SRCMAP_SYSMEM) ) { DRM_ERROR( "*** bad blit: src=0x%x dst=0x%x\n", srcorg, dstorg ); - return -EINVAL; + return DRM_ERR(EINVAL); } return 0; } @@ -872,19 +880,16 @@ * */ -int mga_dma_clear( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) +int mga_dma_clear( DRM_IOCTL_ARGS ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; + DRM_DEVICE; drm_mga_private_t *dev_priv = dev->dev_private; drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_mga_clear_t clear; - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); - if ( copy_from_user( &clear, (drm_mga_clear_t *) arg, sizeof(clear) ) ) - return -EFAULT; + DRM_COPY_FROM_USER_IOCTL( clear, (drm_mga_clear_t *)data, sizeof(clear) ); if ( sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS ) sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS; @@ -900,15 +905,13 @@ return 0; } -int mga_dma_swap( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) +int mga_dma_swap( DRM_IOCTL_ARGS ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; + DRM_DEVICE; drm_mga_private_t *dev_priv = dev->dev_private; drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); if ( sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS ) sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS; @@ -924,25 +927,22 @@ return 0; } -int mga_dma_vertex( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) +int mga_dma_vertex( DRM_IOCTL_ARGS ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; + DRM_DEVICE; drm_mga_private_t *dev_priv = dev->dev_private; drm_device_dma_t *dma = dev->dma; drm_buf_t *buf; drm_mga_buf_priv_t *buf_priv; drm_mga_vertex_t vertex; - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); - if ( copy_from_user( &vertex, - (drm_mga_vertex_t *)arg, - sizeof(vertex) ) ) - return -EFAULT; + DRM_COPY_FROM_USER_IOCTL( vertex, + (drm_mga_vertex_t *)data, + sizeof(vertex) ); - if(vertex.idx < 0 || vertex.idx > dma->buf_count) return -EINVAL; + if(vertex.idx < 0 || vertex.idx > dma->buf_count) return DRM_ERR(EINVAL); buf = dma->buflist[vertex.idx]; buf_priv = buf->dev_private; @@ -956,7 +956,7 @@ buf_priv->dispatched = 0; mga_freelist_put( dev, buf ); } - return -EINVAL; + return DRM_ERR(EINVAL); } WRAP_TEST_WITH_RETURN( dev_priv ); @@ -966,25 +966,22 @@ return 0; } -int mga_dma_indices( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) +int mga_dma_indices( DRM_IOCTL_ARGS ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; + DRM_DEVICE; drm_mga_private_t *dev_priv = dev->dev_private; drm_device_dma_t *dma = dev->dma; drm_buf_t *buf; drm_mga_buf_priv_t *buf_priv; drm_mga_indices_t indices; - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); - if ( copy_from_user( &indices, - (drm_mga_indices_t *)arg, - sizeof(indices) ) ) - return -EFAULT; + DRM_COPY_FROM_USER_IOCTL( indices, + (drm_mga_indices_t *)data, + sizeof(indices) ); - if(indices.idx < 0 || indices.idx > dma->buf_count) return -EINVAL; + if(indices.idx < 0 || indices.idx > dma->buf_count) return DRM_ERR(EINVAL); buf = dma->buflist[indices.idx]; buf_priv = buf->dev_private; @@ -998,7 +995,7 @@ buf_priv->dispatched = 0; mga_freelist_put( dev, buf ); } - return -EINVAL; + return DRM_ERR(EINVAL); } WRAP_TEST_WITH_RETURN( dev_priv ); @@ -1008,38 +1005,35 @@ return 0; } -int mga_dma_iload( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) +int mga_dma_iload( DRM_IOCTL_ARGS ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; + DRM_DEVICE; drm_device_dma_t *dma = dev->dma; drm_mga_private_t *dev_priv = dev->dev_private; drm_buf_t *buf; drm_mga_buf_priv_t *buf_priv; drm_mga_iload_t iload; - DRM_DEBUG( "%s:\n", __FUNCTION__ ); + DRM_DEBUG( "\n" ); - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); - if ( copy_from_user( &iload, (drm_mga_iload_t *)arg, sizeof(iload) ) ) - return -EFAULT; + DRM_COPY_FROM_USER_IOCTL( iload, (drm_mga_iload_t *)data, sizeof(iload) ); #if 0 if ( mga_do_wait_for_idle( dev_priv ) < 0 ) { if ( MGA_DMA_DEBUG ) - DRM_INFO( "%s: -EBUSY\n" , __FUNCTION__); - return -EBUSY; + DRM_INFO( "%s: -EBUSY\n", __FUNCTION__ ); + return DRM_ERR(EBUSY); } #endif - if(iload.idx < 0 || iload.idx > dma->buf_count) return -EINVAL; + if(iload.idx < 0 || iload.idx > dma->buf_count) return DRM_ERR(EINVAL); buf = dma->buflist[iload.idx]; buf_priv = buf->dev_private; if ( mga_verify_iload( dev_priv, iload.dstorg, iload.length ) ) { mga_freelist_put( dev, buf ); - return -EINVAL; + return DRM_ERR(EINVAL); } WRAP_TEST_WITH_RETURN( dev_priv ); @@ -1053,26 +1047,23 @@ return 0; } -int mga_dma_blit( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) +int mga_dma_blit( DRM_IOCTL_ARGS ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; + DRM_DEVICE; drm_mga_private_t *dev_priv = dev->dev_private; drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_mga_blit_t blit; - DRM_DEBUG( "%s\n", __FUNCTION__ ); + DRM_DEBUG( "\n" ); - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); - if ( copy_from_user( &blit, (drm_mga_blit_t *)arg, sizeof(blit) ) ) - return -EFAULT; + DRM_COPY_FROM_USER_IOCTL( blit, (drm_mga_blit_t *)data, sizeof(blit) ); if ( sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS ) sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS; if ( mga_verify_blit( dev_priv, blit.srcorg, blit.dstorg ) ) - return -EINVAL; + return DRM_ERR(EINVAL); WRAP_TEST_WITH_RETURN( dev_priv ); @@ -1084,3 +1075,36 @@ return 0; } + +int mga_getparam( DRM_IOCTL_ARGS ) +{ + DRM_DEVICE; + drm_mga_private_t *dev_priv = dev->dev_private; + drm_mga_getparam_t param; + int value; + + if ( !dev_priv ) { + DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); + return DRM_ERR(EINVAL); + } + + DRM_COPY_FROM_USER_IOCTL( param, (drm_mga_getparam_t *)data, + sizeof(param) ); + + DRM_DEBUG( "pid=%d\n", DRM_CURRENTPID ); + + switch( param.param ) { + case MGA_PARAM_IRQ_NR: + value = dev->irq; + break; + default: + return DRM_ERR(EINVAL); + } + + if ( DRM_COPY_TO_USER( param.value, &value, sizeof(int) ) ) { + DRM_ERROR( "copy_to_user\n" ); + return DRM_ERR(EFAULT); + } + + return 0; +} diff -urN linux-2.4.23-pre8/drivers/char/drm/mga_warp.c linux-2.4.23-pre8-pac1/drivers/char/drm/mga_warp.c --- linux-2.4.23-pre8/drivers/char/drm/mga_warp.c 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/mga_warp.c 2003-10-11 23:18:12.000000000 +0200 @@ -27,7 +27,6 @@ * Gareth Hughes */ - #include "mga.h" #include "drmP.h" #include "drm.h" @@ -107,7 +106,7 @@ if ( size > dev_priv->warp->size ) { DRM_ERROR( "microcode too large! (%u > %lu)\n", size, dev_priv->warp->size ); - return -ENOMEM; + return DRM_ERR(ENOMEM); } memset( dev_priv->warp_pipe_phys, 0, @@ -144,7 +143,7 @@ if ( size > dev_priv->warp->size ) { DRM_ERROR( "microcode too large! (%u > %lu)\n", size, dev_priv->warp->size ); - return -ENOMEM; + return DRM_ERR(ENOMEM); } memset( dev_priv->warp_pipe_phys, 0, @@ -170,7 +169,7 @@ case MGA_CARD_TYPE_G200: return mga_warp_install_g200_microcode( dev_priv ); default: - return -EINVAL; + return DRM_ERR(EINVAL); } } @@ -195,7 +194,7 @@ MGA_WRITE( MGA_WVRTXSZ, 7 ); break; default: - return -EINVAL; + return DRM_ERR(EINVAL); } MGA_WRITE( MGA_WMISC, (MGA_WUCODECACHE_ENABLE | @@ -205,7 +204,7 @@ if ( wmisc != WMISC_EXPECTED ) { DRM_ERROR( "WARP engine config failed! 0x%x != 0x%x\n", wmisc, WMISC_EXPECTED ); - return -EINVAL; + return DRM_ERR(EINVAL); } return 0; diff -urN linux-2.4.23-pre8/drivers/char/drm/r128.h linux-2.4.23-pre8-pac1/drivers/char/drm/r128.h --- linux-2.4.23-pre8/drivers/char/drm/r128.h 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/r128.h 2003-08-18 12:56:12.000000000 +0200 @@ -47,13 +47,18 @@ #define DRIVER_NAME "r128" #define DRIVER_DESC "ATI Rage 128" -#define DRIVER_DATE "20010917" +#define DRIVER_DATE "20030725" #define DRIVER_MAJOR 2 -#define DRIVER_MINOR 2 +#define DRIVER_MINOR 5 #define DRIVER_PATCHLEVEL 0 - +/* Interface history: + * + * ?? - ?? + * 2.4 - Add support for ycbcr textures (no new ioctls) + * 2.5 - Add FLIP ioctl, disable FULLSCREEN. + */ #define DRIVER_IOCTLS \ [DRM_IOCTL_NR(DRM_IOCTL_DMA)] = { r128_cce_buffers, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_R128_INIT)] = { r128_cce_init, 1, 1 }, \ @@ -64,13 +69,15 @@ [DRM_IOCTL_NR(DRM_IOCTL_R128_RESET)] = { r128_engine_reset, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_R128_FULLSCREEN)] = { r128_fullscreen, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_R128_SWAP)] = { r128_cce_swap, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_R128_FLIP)] = { r128_cce_flip, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_R128_CLEAR)] = { r128_cce_clear, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_R128_VERTEX)] = { r128_cce_vertex, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_R128_INDICES)] = { r128_cce_indices, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_R128_BLIT)] = { r128_cce_blit, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_R128_DEPTH)] = { r128_cce_depth, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_R128_STIPPLE)] = { r128_cce_stipple, 1, 0 }, \ - [DRM_IOCTL_NR(DRM_IOCTL_R128_INDIRECT)] = { r128_cce_indirect, 1, 1 }, + [DRM_IOCTL_NR(DRM_IOCTL_R128_INDIRECT)] = { r128_cce_indirect, 1, 1 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_R128_GETPARAM)] = { r128_getparam, 1, 0 }, /* Driver customization: */ @@ -84,12 +91,15 @@ } while (0) #define DRIVER_PRETAKEDOWN() do { \ - if ( dev->dev_private ) r128_do_cleanup_cce( dev ); \ + r128_do_cleanup_cce( dev ); \ } while (0) /* DMA customization: */ #define __HAVE_DMA 1 +#define __HAVE_DMA_IRQ 1 +#define __HAVE_VBL_IRQ 1 +#define __HAVE_SHARED_IRQ 1 #if 0 /* GH: Remove this for now... */ diff -urN linux-2.4.23-pre8/drivers/char/drm/r128_cce.c linux-2.4.23-pre8-pac1/drivers/char/drm/r128_cce.c --- linux-2.4.23-pre8/drivers/char/drm/r128_cce.c 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/r128_cce.c 2003-10-11 23:18:12.000000000 +0200 @@ -33,8 +33,6 @@ #include "drm.h" #include "r128_drm.h" #include "r128_drv.h" -#include "drm_os_linux.h" -#include #define R128_FIFO_DEBUG 0 @@ -83,8 +81,6 @@ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -int r128_do_wait_for_idle( drm_r128_private_t *dev_priv ); - int R128_READ_PLL(drm_device_t *dev, int addr) { drm_r128_private_t *dev_priv = dev->dev_private; @@ -128,13 +124,13 @@ if ( !(R128_READ( R128_PC_NGUI_CTLSTAT ) & R128_PC_BUSY) ) { return 0; } - udelay( 1 ); + DRM_UDELAY( 1 ); } #if R128_FIFO_DEBUG DRM_ERROR( "failed!\n" ); #endif - return -EBUSY; + return DRM_ERR(EBUSY); } static int r128_do_wait_for_fifo( drm_r128_private_t *dev_priv, int entries ) @@ -144,16 +140,16 @@ for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { int slots = R128_READ( R128_GUI_STAT ) & R128_GUI_FIFOCNT_MASK; if ( slots >= entries ) return 0; - udelay( 1 ); + DRM_UDELAY( 1 ); } #if R128_FIFO_DEBUG DRM_ERROR( "failed!\n" ); #endif - return -EBUSY; + return DRM_ERR(EBUSY); } -int r128_do_wait_for_idle( drm_r128_private_t *dev_priv ) +static int r128_do_wait_for_idle( drm_r128_private_t *dev_priv ) { int i, ret; @@ -165,13 +161,13 @@ r128_do_pixcache_flush( dev_priv ); return 0; } - udelay( 1 ); + DRM_UDELAY( 1 ); } #if R128_FIFO_DEBUG DRM_ERROR( "failed!\n" ); #endif - return -EBUSY; + return DRM_ERR(EBUSY); } @@ -225,14 +221,14 @@ return r128_do_pixcache_flush( dev_priv ); } } - udelay( 1 ); + DRM_UDELAY( 1 ); } #if R128_FIFO_DEBUG DRM_ERROR( "failed!\n" ); r128_status( dev_priv ); #endif - return -EBUSY; + return DRM_ERR(EBUSY); } /* Start the Concurrent Command Engine. @@ -352,8 +348,8 @@ R128_WRITE( R128_PM4_BUFFER_DL_RPTR_ADDR, entry->busaddr[page_ofs]); - DRM_DEBUG( "ring rptr: offset=0x%08x handle=0x%08lx\n", - entry->busaddr[page_ofs], + DRM_DEBUG( "ring rptr: offset=0x%08lx handle=0x%08lx\n", + (unsigned long) entry->busaddr[page_ofs], entry->handle + tmp_ofs ); } @@ -380,7 +376,7 @@ dev_priv = DRM(alloc)( sizeof(drm_r128_private_t), DRM_MEM_DRIVER ); if ( dev_priv == NULL ) - return -ENOMEM; + return DRM_ERR(ENOMEM); memset( dev_priv, 0, sizeof(drm_r128_private_t) ); @@ -390,7 +386,7 @@ DRM_ERROR( "PCI GART memory not allocated!\n" ); dev->dev_private = (void *)dev_priv; r128_do_cleanup_cce( dev ); - return -EINVAL; + return DRM_ERR(EINVAL); } dev_priv->usec_timeout = init->usec_timeout; @@ -399,7 +395,7 @@ DRM_DEBUG( "TIMEOUT problem!\n" ); dev->dev_private = (void *)dev_priv; r128_do_cleanup_cce( dev ); - return -EINVAL; + return DRM_ERR(EINVAL); } dev_priv->cce_mode = init->cce_mode; @@ -419,7 +415,7 @@ DRM_DEBUG( "Bad cce_mode!\n" ); dev->dev_private = (void *)dev_priv; r128_do_cleanup_cce( dev ); - return -EINVAL; + return DRM_ERR(EINVAL); } switch ( init->cce_mode ) { @@ -487,7 +483,7 @@ DRM_ERROR("could not find sarea!\n"); dev->dev_private = (void *)dev_priv; r128_do_cleanup_cce( dev ); - return -EINVAL; + return DRM_ERR(EINVAL); } DRM_FIND_MAP( dev_priv->fb, init->fb_offset ); @@ -495,35 +491,35 @@ DRM_ERROR("could not find framebuffer!\n"); dev->dev_private = (void *)dev_priv; r128_do_cleanup_cce( dev ); - return -EINVAL; + return DRM_ERR(EINVAL); } DRM_FIND_MAP( dev_priv->mmio, init->mmio_offset ); if(!dev_priv->mmio) { DRM_ERROR("could not find mmio region!\n"); dev->dev_private = (void *)dev_priv; r128_do_cleanup_cce( dev ); - return -EINVAL; + return DRM_ERR(EINVAL); } DRM_FIND_MAP( dev_priv->cce_ring, init->ring_offset ); if(!dev_priv->cce_ring) { DRM_ERROR("could not find cce ring region!\n"); dev->dev_private = (void *)dev_priv; r128_do_cleanup_cce( dev ); - return -EINVAL; + return DRM_ERR(EINVAL); } DRM_FIND_MAP( dev_priv->ring_rptr, init->ring_rptr_offset ); if(!dev_priv->ring_rptr) { DRM_ERROR("could not find ring read pointer!\n"); dev->dev_private = (void *)dev_priv; r128_do_cleanup_cce( dev ); - return -EINVAL; + return DRM_ERR(EINVAL); } DRM_FIND_MAP( dev_priv->buffers, init->buffers_offset ); if(!dev_priv->buffers) { DRM_ERROR("could not find dma buffer region!\n"); dev->dev_private = (void *)dev_priv; r128_do_cleanup_cce( dev ); - return -EINVAL; + return DRM_ERR(EINVAL); } if ( !dev_priv->is_pci ) { @@ -533,7 +529,7 @@ DRM_ERROR("could not find agp texture region!\n"); dev->dev_private = (void *)dev_priv; r128_do_cleanup_cce( dev ); - return -EINVAL; + return DRM_ERR(EINVAL); } } @@ -541,19 +537,22 @@ (drm_r128_sarea_t *)((u8 *)dev_priv->sarea->handle + init->sarea_priv_offset); +#if __REALLY_HAVE_AGP if ( !dev_priv->is_pci ) { - DRM_IOREMAP( dev_priv->cce_ring ); - DRM_IOREMAP( dev_priv->ring_rptr ); - DRM_IOREMAP( dev_priv->buffers ); + DRM_IOREMAP( dev_priv->cce_ring, dev ); + DRM_IOREMAP( dev_priv->ring_rptr, dev ); + DRM_IOREMAP( dev_priv->buffers, dev ); if(!dev_priv->cce_ring->handle || !dev_priv->ring_rptr->handle || !dev_priv->buffers->handle) { DRM_ERROR("Could not ioremap agp regions!\n"); dev->dev_private = (void *)dev_priv; r128_do_cleanup_cce( dev ); - return -ENOMEM; + return DRM_ERR(ENOMEM); } - } else { + } else +#endif + { dev_priv->cce_ring->handle = (void *)dev_priv->cce_ring->offset; dev_priv->ring_rptr->handle = @@ -581,6 +580,7 @@ (dev_priv->ring.size / sizeof(u32)) - 1; dev_priv->ring.high_mark = 128; + dev_priv->ring.ring_rptr = dev_priv->ring_rptr; dev_priv->sarea_priv->last_frame = 0; R128_WRITE( R128_LAST_FRAME_REG, dev_priv->sarea_priv->last_frame ); @@ -589,16 +589,18 @@ R128_WRITE( R128_LAST_DISPATCH_REG, dev_priv->sarea_priv->last_dispatch ); +#if __REALLY_HAVE_SG if ( dev_priv->is_pci ) { if (!DRM(ati_pcigart_init)( dev, &dev_priv->phys_pci_gart, &dev_priv->bus_pci_gart) ) { DRM_ERROR( "failed to init PCI GART!\n" ); dev->dev_private = (void *)dev_priv; r128_do_cleanup_cce( dev ); - return -ENOMEM; + return DRM_ERR(ENOMEM); } R128_WRITE( R128_PCI_GART_PAGE, dev_priv->bus_pci_gart ); } +#endif r128_cce_init_ring_buffer( dev, dev_priv ); r128_cce_load_microcode( dev_priv ); @@ -612,23 +614,34 @@ int r128_do_cleanup_cce( drm_device_t *dev ) { + +#if _HAVE_DMA_IRQ + /* Make sure interrupts are disabled here because the uninstall ioctl + * may not have been called from userspace and after dev_private + * is freed, it's too late. + */ + if ( dev->irq ) DRM(irq_uninstall)(dev); +#endif + if ( dev->dev_private ) { drm_r128_private_t *dev_priv = dev->dev_private; -#if __REALLY_HAVE_SG +#if __REALLY_HAVE_AGP if ( !dev_priv->is_pci ) { + if ( dev_priv->cce_ring != NULL ) + DRM_IOREMAPFREE( dev_priv->cce_ring, dev ); + if ( dev_priv->ring_rptr != NULL ) + DRM_IOREMAPFREE( dev_priv->ring_rptr, dev ); + if ( dev_priv->buffers != NULL ) + DRM_IOREMAPFREE( dev_priv->buffers, dev ); + } else #endif - DRM_IOREMAPFREE( dev_priv->cce_ring ); - DRM_IOREMAPFREE( dev_priv->ring_rptr ); - DRM_IOREMAPFREE( dev_priv->buffers ); -#if __REALLY_HAVE_SG - } else { + { if (!DRM(ati_pcigart_cleanup)( dev, dev_priv->phys_pci_gart, dev_priv->bus_pci_gart )) DRM_ERROR( "failed to cleanup PCI GART!\n" ); } -#endif DRM(free)( dev->dev_private, sizeof(drm_r128_private_t), DRM_MEM_DRIVER ); @@ -638,17 +651,16 @@ return 0; } -int r128_cce_init( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) +int r128_cce_init( DRM_IOCTL_ARGS ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; + DRM_DEVICE; drm_r128_init_t init; - DRM_DEBUG( "%s\n", __FUNCTION__ ); + DRM_DEBUG( "\n" ); + + LOCK_TEST_WITH_RETURN( dev, filp ); - if ( copy_from_user( &init, (drm_r128_init_t *)arg, sizeof(init) ) ) - return -EFAULT; + DRM_COPY_FROM_USER_IOCTL( init, (drm_r128_init_t *)data, sizeof(init) ); switch ( init.func ) { case R128_INIT_CCE: @@ -657,18 +669,16 @@ return r128_do_cleanup_cce( dev ); } - return -EINVAL; + return DRM_ERR(EINVAL); } -int r128_cce_start( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) +int r128_cce_start( DRM_IOCTL_ARGS ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; + DRM_DEVICE; drm_r128_private_t *dev_priv = dev->dev_private; - DRM_DEBUG( "%s\n", __FUNCTION__ ); + DRM_DEBUG( "\n" ); - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); if ( dev_priv->cce_running || dev_priv->cce_mode == R128_PM4_NONPM4 ) { DRM_DEBUG( "%s while CCE running\n", __FUNCTION__ ); @@ -683,20 +693,17 @@ /* Stop the CCE. The engine must have been idled before calling this * routine. */ -int r128_cce_stop( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) +int r128_cce_stop( DRM_IOCTL_ARGS ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; + DRM_DEVICE; drm_r128_private_t *dev_priv = dev->dev_private; drm_r128_cce_stop_t stop; int ret; - DRM_DEBUG( "%s\n", __FUNCTION__ ); + DRM_DEBUG( "\n" ); - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); - if ( copy_from_user( &stop, (drm_r128_init_t *)arg, sizeof(stop) ) ) - return -EFAULT; + DRM_COPY_FROM_USER_IOCTL(stop, (drm_r128_cce_stop_t *)data, sizeof(stop) ); /* Flush any pending CCE commands. This ensures any outstanding * commands are exectuted by the engine before we turn it off. @@ -727,19 +734,17 @@ /* Just reset the CCE ring. Called as part of an X Server engine reset. */ -int r128_cce_reset( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) +int r128_cce_reset( DRM_IOCTL_ARGS ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; + DRM_DEVICE; drm_r128_private_t *dev_priv = dev->dev_private; - DRM_DEBUG( "%s\n", __FUNCTION__ ); + DRM_DEBUG( "\n" ); - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); if ( !dev_priv ) { DRM_DEBUG( "%s called before init done\n", __FUNCTION__ ); - return -EINVAL; + return DRM_ERR(EINVAL); } r128_do_cce_reset( dev_priv ); @@ -750,15 +755,13 @@ return 0; } -int r128_cce_idle( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) +int r128_cce_idle( DRM_IOCTL_ARGS ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; + DRM_DEVICE; drm_r128_private_t *dev_priv = dev->dev_private; - DRM_DEBUG( "%s\n", __FUNCTION__ ); + DRM_DEBUG( "\n" ); - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); if ( dev_priv->cce_running ) { r128_do_cce_flush( dev_priv ); @@ -767,75 +770,19 @@ return r128_do_cce_idle( dev_priv ); } -int r128_engine_reset( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) +int r128_engine_reset( DRM_IOCTL_ARGS ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; - DRM_DEBUG( "%s\n", __FUNCTION__ ); - - LOCK_TEST_WITH_RETURN( dev ); - - return r128_do_engine_reset( dev ); -} - - -/* ================================================================ - * Fullscreen mode - */ - -static int r128_do_init_pageflip( drm_device_t *dev ) -{ - drm_r128_private_t *dev_priv = dev->dev_private; - DRM_DEBUG( "\n" ); - - dev_priv->crtc_offset = R128_READ( R128_CRTC_OFFSET ); - dev_priv->crtc_offset_cntl = R128_READ( R128_CRTC_OFFSET_CNTL ); - - R128_WRITE( R128_CRTC_OFFSET, dev_priv->front_offset ); - R128_WRITE( R128_CRTC_OFFSET_CNTL, - dev_priv->crtc_offset_cntl | R128_CRTC_OFFSET_FLIP_CNTL ); - - dev_priv->page_flipping = 1; - dev_priv->current_page = 0; - - return 0; -} - -int r128_do_cleanup_pageflip( drm_device_t *dev ) -{ - drm_r128_private_t *dev_priv = dev->dev_private; + DRM_DEVICE; DRM_DEBUG( "\n" ); - R128_WRITE( R128_CRTC_OFFSET, dev_priv->crtc_offset ); - R128_WRITE( R128_CRTC_OFFSET_CNTL, dev_priv->crtc_offset_cntl ); - - dev_priv->page_flipping = 0; - dev_priv->current_page = 0; + LOCK_TEST_WITH_RETURN( dev, filp ); - return 0; + return r128_do_engine_reset( dev ); } -int r128_fullscreen( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) +int r128_fullscreen( DRM_IOCTL_ARGS ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; - drm_r128_fullscreen_t fs; - - LOCK_TEST_WITH_RETURN( dev ); - - if ( copy_from_user( &fs, (drm_r128_fullscreen_t *)arg, sizeof(fs) ) ) - return -EFAULT; - - switch ( fs.func ) { - case R128_INIT_FULLSCREEN: - return r128_do_init_pageflip( dev ); - case R128_CLEANUP_FULLSCREEN: - return r128_do_cleanup_pageflip( dev ); - } - - return -EINVAL; + return DRM_ERR(EINVAL); } @@ -858,7 +805,7 @@ dev_priv->head = DRM(alloc)( sizeof(drm_r128_freelist_t), DRM_MEM_DRIVER ); if ( dev_priv->head == NULL ) - return -ENOMEM; + return DRM_ERR(ENOMEM); memset( dev_priv->head, 0, sizeof(drm_r128_freelist_t) ); dev_priv->head->age = R128_BUFFER_USED; @@ -869,7 +816,7 @@ entry = DRM(alloc)( sizeof(drm_r128_freelist_t), DRM_MEM_DRIVER ); - if ( !entry ) return -ENOMEM; + if ( !entry ) return DRM_ERR(ENOMEM); entry->age = R128_BUFFER_FREE; entry->buf = buf; @@ -906,7 +853,7 @@ for ( i = 0 ; i < dma->buf_count ; i++ ) { buf = dma->buflist[i]; buf_priv = buf->dev_private; - if ( buf->pid == 0 ) + if ( buf->filp == 0 ) return buf; } @@ -924,10 +871,10 @@ return buf; } } - udelay( 1 ); + DRM_UDELAY( 1 ); } - DRM_ERROR( "returning NULL!\n" ); + DRM_DEBUG( "returning NULL!\n" ); return NULL; } @@ -957,75 +904,71 @@ r128_update_ring_snapshot( ring ); if ( ring->space >= n ) return 0; - udelay( 1 ); + DRM_UDELAY( 1 ); } /* FIXME: This is being ignored... */ DRM_ERROR( "failed!\n" ); - return -EBUSY; + return DRM_ERR(EBUSY); } -static int r128_cce_get_buffers( drm_device_t *dev, drm_dma_t *d ) +static int r128_cce_get_buffers( DRMFILE filp, drm_device_t *dev, drm_dma_t *d ) { int i; drm_buf_t *buf; for ( i = d->granted_count ; i < d->request_count ; i++ ) { buf = r128_freelist_get( dev ); - if ( !buf ) return -EAGAIN; + if ( !buf ) return DRM_ERR(EAGAIN); - buf->pid = current->pid; + buf->filp = filp; - if ( copy_to_user( &d->request_indices[i], &buf->idx, + if ( DRM_COPY_TO_USER( &d->request_indices[i], &buf->idx, sizeof(buf->idx) ) ) - return -EFAULT; - if ( copy_to_user( &d->request_sizes[i], &buf->total, + return DRM_ERR(EFAULT); + if ( DRM_COPY_TO_USER( &d->request_sizes[i], &buf->total, sizeof(buf->total) ) ) - return -EFAULT; + return DRM_ERR(EFAULT); d->granted_count++; } return 0; } -int r128_cce_buffers( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) +int r128_cce_buffers( DRM_IOCTL_ARGS ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; + DRM_DEVICE; drm_device_dma_t *dma = dev->dma; int ret = 0; drm_dma_t d; - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); - if ( copy_from_user( &d, (drm_dma_t *) arg, sizeof(d) ) ) - return -EFAULT; + DRM_COPY_FROM_USER_IOCTL( d, (drm_dma_t *) data, sizeof(d) ); /* Please don't send us buffers. */ if ( d.send_count != 0 ) { DRM_ERROR( "Process %d trying to send %d buffers via drmDMA\n", - current->pid, d.send_count ); - return -EINVAL; + DRM_CURRENTPID, d.send_count ); + return DRM_ERR(EINVAL); } /* We'll send you buffers. */ if ( d.request_count < 0 || d.request_count > dma->buf_count ) { DRM_ERROR( "Process %d trying to get %d buffers (of %d max)\n", - current->pid, d.request_count, dma->buf_count ); - return -EINVAL; + DRM_CURRENTPID, d.request_count, dma->buf_count ); + return DRM_ERR(EINVAL); } d.granted_count = 0; if ( d.request_count ) { - ret = r128_cce_get_buffers( dev, &d ); + ret = r128_cce_get_buffers( filp, dev, &d ); } - if ( copy_to_user( (drm_dma_t *) arg, &d, sizeof(d) ) ) - return -EFAULT; + DRM_COPY_TO_USER_IOCTL((drm_dma_t *) data, d, sizeof(d) ); return ret; } diff -urN linux-2.4.23-pre8/drivers/char/drm/r128_drm.h linux-2.4.23-pre8-pac1/drivers/char/drm/r128_drm.h --- linux-2.4.23-pre8/drivers/char/drm/r128_drm.h 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/r128_drm.h 2003-08-18 12:56:12.000000000 +0200 @@ -162,8 +162,10 @@ unsigned int last_dispatch; drm_tex_region_t tex_list[R128_NR_TEX_HEAPS][R128_NR_TEX_REGIONS+1]; - int tex_age[R128_NR_TEX_HEAPS]; + unsigned int tex_age[R128_NR_TEX_HEAPS]; int ctx_owner; + int pfAllowPageFlip; /* number of 3d windows (0,1,2 or more) */ + int pfCurrentPage; /* which buffer is being displayed? */ } drm_r128_sarea_t; @@ -190,6 +192,8 @@ #define DRM_IOCTL_R128_INDIRECT DRM_IOWR(0x4f, drm_r128_indirect_t) #define DRM_IOCTL_R128_FULLSCREEN DRM_IOW( 0x50, drm_r128_fullscreen_t) #define DRM_IOCTL_R128_CLEAR2 DRM_IOW( 0x51, drm_r128_clear2_t) +#define DRM_IOCTL_R128_GETPARAM DRM_IOW( 0x52, drm_r128_getparam_t) +#define DRM_IOCTL_R128_FLIP DRM_IO( 0x53) typedef struct drm_r128_init { enum { @@ -305,4 +309,14 @@ } func; } drm_r128_fullscreen_t; +/* 2.3: An ioctl to get parameters that aren't available to the 3d + * client any other way. + */ +#define R128_PARAM_IRQ_NR 1 + +typedef struct drm_r128_getparam { + int param; + int *value; +} drm_r128_getparam_t; + #endif diff -urN linux-2.4.23-pre8/drivers/char/drm/r128_drv.h linux-2.4.23-pre8-pac1/drivers/char/drm/r128_drv.h --- linux-2.4.23-pre8/drivers/char/drm/r128_drv.h 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/r128_drv.h 2003-08-18 12:56:12.000000000 +0200 @@ -33,10 +33,9 @@ #ifndef __R128_DRV_H__ #define __R128_DRV_H__ -#include -#define GET_RING_HEAD(ring) readl( (volatile u32 *) (ring)->head ) -#define SET_RING_HEAD(ring,val) writel( (val), (volatile u32 *) (ring)->head ) +#define GET_RING_HEAD(ring) DRM_READ32( (ring)->ring_rptr, 0 ) /* (ring)->head */ +#define SET_RING_HEAD(ring,val) DRM_WRITE32( (ring)->ring_rptr, 0, (val) ) /* (ring)->head */ typedef struct drm_r128_freelist { unsigned int age; @@ -57,6 +56,7 @@ int space; int high_mark; + drm_local_map_t *ring_rptr; } drm_r128_ring_buffer_t; typedef struct drm_r128_private { @@ -99,13 +99,13 @@ u32 depth_pitch_offset_c; u32 span_pitch_offset_c; - drm_map_t *sarea; - drm_map_t *fb; - drm_map_t *mmio; - drm_map_t *cce_ring; - drm_map_t *ring_rptr; - drm_map_t *buffers; - drm_map_t *agp_textures; + drm_local_map_t *sarea; + drm_local_map_t *fb; + drm_local_map_t *mmio; + drm_local_map_t *cce_ring; + drm_local_map_t *ring_rptr; + drm_local_map_t *buffers; + drm_local_map_t *agp_textures; } drm_r128_private_t; typedef struct drm_r128_buf_priv { @@ -117,29 +117,22 @@ } drm_r128_buf_priv_t; /* r128_cce.c */ -extern int r128_cce_init( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int r128_cce_start( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int r128_cce_stop( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int r128_cce_reset( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int r128_cce_idle( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int r128_engine_reset( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int r128_fullscreen( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int r128_cce_buffers( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); +extern int r128_cce_init( DRM_IOCTL_ARGS ); +extern int r128_cce_start( DRM_IOCTL_ARGS ); +extern int r128_cce_stop( DRM_IOCTL_ARGS ); +extern int r128_cce_reset( DRM_IOCTL_ARGS ); +extern int r128_cce_idle( DRM_IOCTL_ARGS ); +extern int r128_engine_reset( DRM_IOCTL_ARGS ); +extern int r128_fullscreen( DRM_IOCTL_ARGS ); +extern int r128_cce_buffers( DRM_IOCTL_ARGS ); +extern int r128_getparam( DRM_IOCTL_ARGS ); extern void r128_freelist_reset( drm_device_t *dev ); extern drm_buf_t *r128_freelist_get( drm_device_t *dev ); extern int r128_wait_ring( drm_r128_private_t *dev_priv, int n ); -static inline void +static __inline__ void r128_update_ring_snapshot( drm_r128_ring_buffer_t *ring ) { ring->space = (GET_RING_HEAD( ring ) - ring->tail) * sizeof(u32); @@ -152,22 +145,15 @@ extern int r128_do_cleanup_pageflip( drm_device_t *dev ); /* r128_state.c */ -extern int r128_cce_clear( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int r128_cce_swap( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int r128_cce_vertex( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int r128_cce_indices( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int r128_cce_blit( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int r128_cce_depth( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int r128_cce_stipple( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int r128_cce_indirect( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); +extern int r128_cce_clear( DRM_IOCTL_ARGS ); +extern int r128_cce_swap( DRM_IOCTL_ARGS ); +extern int r128_cce_flip( DRM_IOCTL_ARGS ); +extern int r128_cce_vertex( DRM_IOCTL_ARGS ); +extern int r128_cce_indices( DRM_IOCTL_ARGS ); +extern int r128_cce_blit( DRM_IOCTL_ARGS ); +extern int r128_cce_depth( DRM_IOCTL_ARGS ); +extern int r128_cce_stipple( DRM_IOCTL_ARGS ); +extern int r128_cce_indirect( DRM_IOCTL_ARGS ); /* Register definitions, register access macros and drmAddMap constants @@ -230,6 +216,11 @@ #define R128_DST_PITCH_OFFSET_C 0x1c80 # define R128_DST_TILE (1 << 31) +#define R128_GEN_INT_CNTL 0x0040 +# define R128_CRTC_VBLANK_INT_EN (1 << 0) +#define R128_GEN_INT_STATUS 0x0044 +# define R128_CRTC_VBLANK_INT (1 << 0) +# define R128_CRTC_VBLANK_INT_AK (1 << 0) #define R128_GEN_RESET_CNTL 0x00f0 # define R128_SOFT_RESET_GUI (1 << 0) @@ -353,13 +344,20 @@ #define R128_CCE_VC_CNTL_PRIM_WALK_RING 0x00000030 #define R128_CCE_VC_CNTL_NUM_SHIFT 16 +#define R128_DATATYPE_VQ 0 +#define R128_DATATYPE_CI4 1 #define R128_DATATYPE_CI8 2 #define R128_DATATYPE_ARGB1555 3 #define R128_DATATYPE_RGB565 4 #define R128_DATATYPE_RGB888 5 #define R128_DATATYPE_ARGB8888 6 #define R128_DATATYPE_RGB332 7 +#define R128_DATATYPE_Y8 8 #define R128_DATATYPE_RGB8 9 +#define R128_DATATYPE_CI16 10 +#define R128_DATATYPE_YVYU422 11 +#define R128_DATATYPE_VYUY422 12 +#define R128_DATATYPE_AYUV444 14 #define R128_DATATYPE_ARGB4444 15 /* Constants */ @@ -381,15 +379,10 @@ #define R128_PERFORMANCE_BOXES 0 - -#define R128_BASE(reg) ((unsigned long)(dev_priv->mmio->handle)) -#define R128_ADDR(reg) (R128_BASE( reg ) + reg) - -#define R128_READ(reg) readl( (volatile u32 *) R128_ADDR(reg) ) -#define R128_WRITE(reg,val) writel( (val) , (volatile u32 *) R128_ADDR(reg)) - -#define R128_READ8(reg) readb( (volatile u8 *) R128_ADDR(reg) ) -#define R128_WRITE8(reg,val) writeb( (val), (volatile u8 *) R128_ADDR(reg) ) +#define R128_READ(reg) DRM_READ32( dev_priv->mmio, (reg) ) +#define R128_WRITE(reg,val) DRM_WRITE32( dev_priv->mmio, (reg), (val) ) +#define R128_READ8(reg) DRM_READ8( dev_priv->mmio, (reg) ) +#define R128_WRITE8(reg,val) DRM_WRITE8( dev_priv->mmio, (reg), (val) ) #define R128_WRITE_PLL(addr,val) \ do { \ @@ -414,16 +407,6 @@ * Misc helper macros */ -#define LOCK_TEST_WITH_RETURN( dev ) \ -do { \ - if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || \ - dev->lock.pid != current->pid ) { \ - DRM_ERROR( "%s called without lock held\n", \ - __FUNCTION__ ); \ - return -EINVAL; \ - } \ -} while (0) - #define RING_SPACE_TEST_WITH_RETURN( dev_priv ) \ do { \ drm_r128_ring_buffer_t *ring = &dev_priv->ring; int i; \ @@ -432,13 +415,13 @@ r128_update_ring_snapshot( ring ); \ if ( ring->space >= ring->high_mark ) \ goto __ring_space_done; \ - udelay( 1 ); \ + DRM_UDELAY(1); \ } \ DRM_ERROR( "ring space check failed!\n" ); \ - return -EBUSY; \ + return DRM_ERR(EBUSY); \ } \ - __ring_space_done: ; \ - break; \ + __ring_space_done: \ + ; \ } while (0) #define VB_AGE_TEST_WITH_RETURN( dev_priv ) \ @@ -446,7 +429,7 @@ drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; \ if ( sarea_priv->last_dispatch >= R128_MAX_VB_AGE ) { \ int __ret = r128_do_cce_idle( dev_priv ); \ - if ( __ret < 0 ) return __ret; \ + if ( __ret ) return __ret; \ sarea_priv->last_dispatch = 0; \ r128_freelist_reset( dev ); \ } \ @@ -465,7 +448,7 @@ #if defined(__powerpc__) #define r128_flush_write_combine() (void) GET_RING_HEAD( &dev_priv->ring ) #else -#define r128_flush_write_combine() mb() +#define r128_flush_write_combine() DRM_WRITEMEMORYBARRIER() #endif diff -urN linux-2.4.23-pre8/drivers/char/drm/r128_irq.c linux-2.4.23-pre8-pac1/drivers/char/drm/r128_irq.c --- linux-2.4.23-pre8/drivers/char/drm/r128_irq.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/r128_irq.c 2003-08-18 12:56:12.000000000 +0200 @@ -0,0 +1,103 @@ +/* r128_irq.c -- IRQ handling for radeon -*- linux-c -*- + * + * Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved. + * + * The Weather Channel (TM) funded Tungsten Graphics to develop the + * initial release of the Radeon 8500 driver under the XFree86 license. + * This notice must be preserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * 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 + * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * 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: + * Keith Whitwell + * Eric Anholt + */ + +#include "r128.h" +#include "drmP.h" +#include "drm.h" +#include "r128_drm.h" +#include "r128_drv.h" + +irqreturn_t r128_dma_service( DRM_IRQ_ARGS ) +{ + drm_device_t *dev = (drm_device_t *) arg; + drm_r128_private_t *dev_priv = + (drm_r128_private_t *)dev->dev_private; + int status; + + status = R128_READ( R128_GEN_INT_STATUS ); + + /* VBLANK interrupt */ + if ( status & R128_CRTC_VBLANK_INT ) { + R128_WRITE( R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK ); + atomic_inc(&dev->vbl_received); + DRM_WAKEUP(&dev->vbl_queue); + DRM(vbl_send_signals)( dev ); + return IRQ_HANDLED; + } + return IRQ_NONE; +} + +int DRM(vblank_wait)(drm_device_t *dev, unsigned int *sequence) +{ + unsigned int cur_vblank; + int ret = 0; + + /* Assume that the user has missed the current sequence number + * by about a day rather than she wants to wait for years + * using vertical blanks... + */ + DRM_WAIT_ON( ret, dev->vbl_queue, 3*DRM_HZ, + ( ( ( cur_vblank = atomic_read(&dev->vbl_received ) ) + - *sequence ) <= (1<<23) ) ); + + *sequence = cur_vblank; + + return ret; +} + +void r128_driver_irq_preinstall( drm_device_t *dev ) { + drm_r128_private_t *dev_priv = + (drm_r128_private_t *)dev->dev_private; + + /* Disable *all* interrupts */ + R128_WRITE( R128_GEN_INT_CNTL, 0 ); + /* Clear vblank bit if it's already high */ + R128_WRITE( R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK ); +} + +void r128_driver_irq_postinstall( drm_device_t *dev ) { + drm_r128_private_t *dev_priv = + (drm_r128_private_t *)dev->dev_private; + + /* Turn on VBL interrupt */ + R128_WRITE( R128_GEN_INT_CNTL, R128_CRTC_VBLANK_INT_EN ); +} + +void r128_driver_irq_uninstall( drm_device_t *dev ) { + drm_r128_private_t *dev_priv = + (drm_r128_private_t *)dev->dev_private; + if (!dev_priv) + return; + + /* Disable *all* interrupts */ + R128_WRITE( R128_GEN_INT_CNTL, 0 ); +} diff -urN linux-2.4.23-pre8/drivers/char/drm/r128_state.c linux-2.4.23-pre8-pac1/drivers/char/drm/r128_state.c --- linux-2.4.23-pre8/drivers/char/drm/r128_state.c 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/r128_state.c 2003-08-18 12:56:12.000000000 +0200 @@ -81,7 +81,7 @@ ADVANCE_RING(); } -static inline void r128_emit_core( drm_r128_private_t *dev_priv ) +static __inline__ void r128_emit_core( drm_r128_private_t *dev_priv ) { drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_r128_context_regs_t *ctx = &sarea_priv->context_state; @@ -96,7 +96,7 @@ ADVANCE_RING(); } -static inline void r128_emit_context( drm_r128_private_t *dev_priv ) +static __inline__ void r128_emit_context( drm_r128_private_t *dev_priv ) { drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_r128_context_regs_t *ctx = &sarea_priv->context_state; @@ -122,7 +122,7 @@ ADVANCE_RING(); } -static inline void r128_emit_setup( drm_r128_private_t *dev_priv ) +static __inline__ void r128_emit_setup( drm_r128_private_t *dev_priv ) { drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_r128_context_regs_t *ctx = &sarea_priv->context_state; @@ -138,7 +138,7 @@ ADVANCE_RING(); } -static inline void r128_emit_masks( drm_r128_private_t *dev_priv ) +static __inline__ void r128_emit_masks( drm_r128_private_t *dev_priv ) { drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_r128_context_regs_t *ctx = &sarea_priv->context_state; @@ -157,7 +157,7 @@ ADVANCE_RING(); } -static inline void r128_emit_window( drm_r128_private_t *dev_priv ) +static __inline__ void r128_emit_window( drm_r128_private_t *dev_priv ) { drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_r128_context_regs_t *ctx = &sarea_priv->context_state; @@ -172,7 +172,7 @@ ADVANCE_RING(); } -static inline void r128_emit_tex0( drm_r128_private_t *dev_priv ) +static __inline__ void r128_emit_tex0( drm_r128_private_t *dev_priv ) { drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_r128_context_regs_t *ctx = &sarea_priv->context_state; @@ -199,7 +199,7 @@ ADVANCE_RING(); } -static inline void r128_emit_tex1( drm_r128_private_t *dev_priv ) +static __inline__ void r128_emit_tex1( drm_r128_private_t *dev_priv ) { drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_r128_texture_regs_t *tex = &sarea_priv->tex_state[1]; @@ -223,7 +223,7 @@ ADVANCE_RING(); } -static inline void r128_emit_state( drm_r128_private_t *dev_priv ) +static __inline__ void r128_emit_state( drm_r128_private_t *dev_priv ) { drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; unsigned int dirty = sarea_priv->dirty; @@ -500,8 +500,16 @@ R128_GMC_AUX_CLIP_DIS | R128_GMC_WR_MSK_DIS ); - OUT_RING( dev_priv->back_pitch_offset_c ); - OUT_RING( dev_priv->front_pitch_offset_c ); + /* Make this work even if front & back are flipped: + */ + if (dev_priv->current_page == 0) { + OUT_RING( dev_priv->back_pitch_offset_c ); + OUT_RING( dev_priv->front_pitch_offset_c ); + } + else { + OUT_RING( dev_priv->front_pitch_offset_c ); + OUT_RING( dev_priv->back_pitch_offset_c ); + } OUT_RING( (x << 16) | y ); OUT_RING( (x << 16) | y ); @@ -528,7 +536,10 @@ { drm_r128_private_t *dev_priv = dev->dev_private; RING_LOCALS; - DRM_DEBUG( "page=%d\n", dev_priv->current_page ); + DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n", + __FUNCTION__, + dev_priv->current_page, + dev_priv->sarea_priv->pfCurrentPage); #if R128_PERFORMANCE_BOXES /* Do some trivial performance monitoring... @@ -543,10 +554,8 @@ if ( dev_priv->current_page == 0 ) { OUT_RING( dev_priv->back_offset ); - dev_priv->current_page = 1; } else { OUT_RING( dev_priv->front_offset ); - dev_priv->current_page = 0; } ADVANCE_RING(); @@ -556,6 +565,8 @@ * performing the swapbuffer ioctl. */ dev_priv->sarea_priv->last_frame++; + dev_priv->sarea_priv->pfCurrentPage = dev_priv->current_page = + 1 - dev_priv->current_page; BEGIN_RING( 2 ); @@ -778,7 +789,8 @@ sarea_priv->nbox = 0; } -static int r128_cce_dispatch_blit( drm_device_t *dev, +static int r128_cce_dispatch_blit( DRMFILE filp, + drm_device_t *dev, drm_r128_blit_t *blit ) { drm_r128_private_t *dev_priv = dev->dev_private; @@ -801,6 +813,8 @@ case R128_DATATYPE_ARGB1555: case R128_DATATYPE_RGB565: case R128_DATATYPE_ARGB4444: + case R128_DATATYPE_YVYU422: + case R128_DATATYPE_VYUY422: dword_shift = 1; break; case R128_DATATYPE_CI8: @@ -809,7 +823,7 @@ break; default: DRM_ERROR( "invalid blit format %d\n", blit->format ); - return -EINVAL; + return DRM_ERR(EINVAL); } /* Flush the pixel cache, and mark the contents as Read Invalid. @@ -829,14 +843,14 @@ buf = dma->buflist[blit->idx]; buf_priv = buf->dev_private; - if ( buf->pid != current->pid ) { - DRM_ERROR( "process %d using buffer owned by %d\n", - current->pid, buf->pid ); - return -EINVAL; + if ( buf->filp != filp ) { + DRM_ERROR( "process %d using buffer owned by %p\n", + DRM_CURRENTPID, buf->filp ); + return DRM_ERR(EINVAL); } if ( buf->pending ) { DRM_ERROR( "sending pending buffer %d\n", blit->idx ); - return -EINVAL; + return DRM_ERR(EINVAL); } buf_priv->discard = 1; @@ -896,38 +910,38 @@ int count, x, y; u32 *buffer; u8 *mask; - int i; + int i, buffer_size, mask_size; RING_LOCALS; - DRM_DEBUG( "%s\n", __FUNCTION__ ); + DRM_DEBUG( "\n" ); count = depth->n; - if ( copy_from_user( &x, depth->x, sizeof(x) ) ) { - return -EFAULT; + if ( DRM_COPY_FROM_USER( &x, depth->x, sizeof(x) ) ) { + return DRM_ERR(EFAULT); } - if ( copy_from_user( &y, depth->y, sizeof(y) ) ) { - return -EFAULT; + if ( DRM_COPY_FROM_USER( &y, depth->y, sizeof(y) ) ) { + return DRM_ERR(EFAULT); } - buffer = kmalloc( depth->n * sizeof(u32), GFP_KERNEL ); + buffer_size = depth->n * sizeof(u32); + buffer = DRM_MALLOC( buffer_size ); if ( buffer == NULL ) - return -ENOMEM; - if ( copy_from_user( buffer, depth->buffer, - depth->n * sizeof(u32) ) ) { - kfree( buffer ); - return -EFAULT; + return DRM_ERR(ENOMEM); + if ( DRM_COPY_FROM_USER( buffer, depth->buffer, buffer_size ) ) { + DRM_FREE( buffer, buffer_size); + return DRM_ERR(EFAULT); } + mask_size = depth->n * sizeof(u8); if ( depth->mask ) { - mask = kmalloc( depth->n * sizeof(u8), GFP_KERNEL ); + mask = DRM_MALLOC( mask_size ); if ( mask == NULL ) { - kfree( buffer ); - return -ENOMEM; + DRM_FREE( buffer, buffer_size ); + return DRM_ERR(ENOMEM); } - if ( copy_from_user( mask, depth->mask, - depth->n * sizeof(u8) ) ) { - kfree( buffer ); - kfree( mask ); - return -EFAULT; + if ( DRM_COPY_FROM_USER( mask, depth->mask, mask_size ) ) { + DRM_FREE( buffer, buffer_size ); + DRM_FREE( mask, mask_size ); + return DRM_ERR(EFAULT); } for ( i = 0 ; i < count ; i++, x++ ) { @@ -953,7 +967,7 @@ } } - kfree( mask ); + DRM_FREE( mask, mask_size ); } else { for ( i = 0 ; i < count ; i++, x++ ) { BEGIN_RING( 6 ); @@ -977,7 +991,7 @@ } } - kfree( buffer ); + DRM_FREE( buffer, buffer_size ); return 0; } @@ -989,61 +1003,63 @@ int count, *x, *y; u32 *buffer; u8 *mask; - int i; + int i, xbuf_size, ybuf_size, buffer_size, mask_size; RING_LOCALS; - DRM_DEBUG( "%s\n", __FUNCTION__ ); + DRM_DEBUG( "\n" ); count = depth->n; - x = kmalloc( count * sizeof(*x), GFP_KERNEL ); + xbuf_size = count * sizeof(*x); + ybuf_size = count * sizeof(*y); + x = DRM_MALLOC( xbuf_size ); if ( x == NULL ) { - return -ENOMEM; + return DRM_ERR(ENOMEM); } - y = kmalloc( count * sizeof(*y), GFP_KERNEL ); + y = DRM_MALLOC( ybuf_size ); if ( y == NULL ) { - kfree( x ); - return -ENOMEM; + DRM_FREE( x, xbuf_size ); + return DRM_ERR(ENOMEM); } - if ( copy_from_user( x, depth->x, count * sizeof(int) ) ) { - kfree( x ); - kfree( y ); - return -EFAULT; - } - if ( copy_from_user( y, depth->y, count * sizeof(int) ) ) { - kfree( x ); - kfree( y ); - return -EFAULT; + if ( DRM_COPY_FROM_USER( x, depth->x, xbuf_size ) ) { + DRM_FREE( x, xbuf_size ); + DRM_FREE( y, ybuf_size ); + return DRM_ERR(EFAULT); + } + if ( DRM_COPY_FROM_USER( y, depth->y, xbuf_size ) ) { + DRM_FREE( x, xbuf_size ); + DRM_FREE( y, ybuf_size ); + return DRM_ERR(EFAULT); } - buffer = kmalloc( depth->n * sizeof(u32), GFP_KERNEL ); + buffer_size = depth->n * sizeof(u32); + buffer = DRM_MALLOC( buffer_size ); if ( buffer == NULL ) { - kfree( x ); - kfree( y ); - return -ENOMEM; - } - if ( copy_from_user( buffer, depth->buffer, - depth->n * sizeof(u32) ) ) { - kfree( x ); - kfree( y ); - kfree( buffer ); - return -EFAULT; + DRM_FREE( x, xbuf_size ); + DRM_FREE( y, ybuf_size ); + return DRM_ERR(ENOMEM); + } + if ( DRM_COPY_FROM_USER( buffer, depth->buffer, buffer_size ) ) { + DRM_FREE( x, xbuf_size ); + DRM_FREE( y, ybuf_size ); + DRM_FREE( buffer, buffer_size ); + return DRM_ERR(EFAULT); } if ( depth->mask ) { - mask = kmalloc( depth->n * sizeof(u8), GFP_KERNEL ); + mask_size = depth->n * sizeof(u8); + mask = DRM_MALLOC( mask_size ); if ( mask == NULL ) { - kfree( x ); - kfree( y ); - kfree( buffer ); - return -ENOMEM; + DRM_FREE( x, xbuf_size ); + DRM_FREE( y, ybuf_size ); + DRM_FREE( buffer, buffer_size ); + return DRM_ERR(ENOMEM); } - if ( copy_from_user( mask, depth->mask, - depth->n * sizeof(u8) ) ) { - kfree( x ); - kfree( y ); - kfree( buffer ); - kfree( mask ); - return -EFAULT; + if ( DRM_COPY_FROM_USER( mask, depth->mask, mask_size ) ) { + DRM_FREE( x, xbuf_size ); + DRM_FREE( y, ybuf_size ); + DRM_FREE( buffer, buffer_size ); + DRM_FREE( mask, mask_size ); + return DRM_ERR(EFAULT); } for ( i = 0 ; i < count ; i++ ) { @@ -1069,7 +1085,7 @@ } } - kfree( mask ); + DRM_FREE( mask, mask_size ); } else { for ( i = 0 ; i < count ; i++ ) { BEGIN_RING( 6 ); @@ -1093,9 +1109,9 @@ } } - kfree( x ); - kfree( y ); - kfree( buffer ); + DRM_FREE( x, xbuf_size ); + DRM_FREE( y, ybuf_size ); + DRM_FREE( buffer, buffer_size ); return 0; } @@ -1106,14 +1122,14 @@ drm_r128_private_t *dev_priv = dev->dev_private; int count, x, y; RING_LOCALS; - DRM_DEBUG( "%s\n", __FUNCTION__ ); + DRM_DEBUG( "\n" ); count = depth->n; - if ( copy_from_user( &x, depth->x, sizeof(x) ) ) { - return -EFAULT; + if ( DRM_COPY_FROM_USER( &x, depth->x, sizeof(x) ) ) { + return DRM_ERR(EFAULT); } - if ( copy_from_user( &y, depth->y, sizeof(y) ) ) { - return -EFAULT; + if ( DRM_COPY_FROM_USER( &y, depth->y, sizeof(y) ) ) { + return DRM_ERR(EFAULT); } BEGIN_RING( 7 ); @@ -1146,7 +1162,7 @@ { drm_r128_private_t *dev_priv = dev->dev_private; int count, *x, *y; - int i; + int i, xbuf_size, ybuf_size; RING_LOCALS; DRM_DEBUG( "%s\n", __FUNCTION__ ); @@ -1155,24 +1171,26 @@ count = dev_priv->depth_pitch; } - x = kmalloc( count * sizeof(*x), GFP_KERNEL ); + xbuf_size = count * sizeof(*x); + ybuf_size = count * sizeof(*y); + x = DRM_MALLOC( xbuf_size ); if ( x == NULL ) { - return -ENOMEM; + return DRM_ERR(ENOMEM); } - y = kmalloc( count * sizeof(*y), GFP_KERNEL ); + y = DRM_MALLOC( ybuf_size ); if ( y == NULL ) { - kfree( x ); - return -ENOMEM; + DRM_FREE( x, xbuf_size ); + return DRM_ERR(ENOMEM); } - if ( copy_from_user( x, depth->x, count * sizeof(int) ) ) { - kfree( x ); - kfree( y ); - return -EFAULT; - } - if ( copy_from_user( y, depth->y, count * sizeof(int) ) ) { - kfree( x ); - kfree( y ); - return -EFAULT; + if ( DRM_COPY_FROM_USER( x, depth->x, xbuf_size ) ) { + DRM_FREE( x, xbuf_size ); + DRM_FREE( y, ybuf_size ); + return DRM_ERR(EFAULT); + } + if ( DRM_COPY_FROM_USER( y, depth->y, ybuf_size ) ) { + DRM_FREE( x, xbuf_size ); + DRM_FREE( y, ybuf_size ); + return DRM_ERR(EFAULT); } for ( i = 0 ; i < count ; i++ ) { @@ -1199,8 +1217,8 @@ ADVANCE_RING(); } - kfree( x ); - kfree( y ); + DRM_FREE( x, xbuf_size ); + DRM_FREE( y, ybuf_size ); return 0; } @@ -1232,21 +1250,18 @@ * IOCTL functions */ -int r128_cce_clear( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) +int r128_cce_clear( DRM_IOCTL_ARGS ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; + DRM_DEVICE; drm_r128_private_t *dev_priv = dev->dev_private; drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_r128_clear_t clear; - DRM_DEBUG( "%s\n", __FUNCTION__ ); + DRM_DEBUG( "\n" ); - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); - if ( copy_from_user( &clear, (drm_r128_clear_t *) arg, - sizeof(clear) ) ) - return -EFAULT; + DRM_COPY_FROM_USER_IOCTL( clear, (drm_r128_clear_t *) data, + sizeof(clear) ); RING_SPACE_TEST_WITH_RETURN( dev_priv ); @@ -1262,68 +1277,115 @@ return 0; } -int r128_cce_swap( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) +static int r128_do_init_pageflip( drm_device_t *dev ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; + drm_r128_private_t *dev_priv = dev->dev_private; + DRM_DEBUG( "\n" ); + + dev_priv->crtc_offset = R128_READ( R128_CRTC_OFFSET ); + dev_priv->crtc_offset_cntl = R128_READ( R128_CRTC_OFFSET_CNTL ); + + R128_WRITE( R128_CRTC_OFFSET, dev_priv->front_offset ); + R128_WRITE( R128_CRTC_OFFSET_CNTL, + dev_priv->crtc_offset_cntl | R128_CRTC_OFFSET_FLIP_CNTL ); + + dev_priv->page_flipping = 1; + dev_priv->current_page = 0; + dev_priv->sarea_priv->pfCurrentPage = dev_priv->current_page; + + return 0; +} + +int r128_do_cleanup_pageflip( drm_device_t *dev ) +{ + drm_r128_private_t *dev_priv = dev->dev_private; + DRM_DEBUG( "\n" ); + + R128_WRITE( R128_CRTC_OFFSET, dev_priv->crtc_offset ); + R128_WRITE( R128_CRTC_OFFSET_CNTL, dev_priv->crtc_offset_cntl ); + + if (dev_priv->current_page != 0) + r128_cce_dispatch_flip( dev ); + + dev_priv->page_flipping = 0; + return 0; +} + +/* Swapping and flipping are different operations, need different ioctls. + * They can & should be intermixed to support multiple 3d windows. + */ + +int r128_cce_flip( DRM_IOCTL_ARGS ) +{ + DRM_DEVICE; + drm_r128_private_t *dev_priv = dev->dev_private; + DRM_DEBUG( "%s\n", __FUNCTION__ ); + + LOCK_TEST_WITH_RETURN( dev, filp ); + + RING_SPACE_TEST_WITH_RETURN( dev_priv ); + + if (!dev_priv->page_flipping) + r128_do_init_pageflip( dev ); + + r128_cce_dispatch_flip( dev ); + + return 0; +} + +int r128_cce_swap( DRM_IOCTL_ARGS ) +{ + DRM_DEVICE; drm_r128_private_t *dev_priv = dev->dev_private; drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; DRM_DEBUG( "%s\n", __FUNCTION__ ); - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); RING_SPACE_TEST_WITH_RETURN( dev_priv ); if ( sarea_priv->nbox > R128_NR_SAREA_CLIPRECTS ) sarea_priv->nbox = R128_NR_SAREA_CLIPRECTS; - if ( !dev_priv->page_flipping ) { - r128_cce_dispatch_swap( dev ); - dev_priv->sarea_priv->dirty |= (R128_UPLOAD_CONTEXT | - R128_UPLOAD_MASKS); - } else { - r128_cce_dispatch_flip( dev ); - } + r128_cce_dispatch_swap( dev ); + dev_priv->sarea_priv->dirty |= (R128_UPLOAD_CONTEXT | + R128_UPLOAD_MASKS); return 0; } -int r128_cce_vertex( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) +int r128_cce_vertex( DRM_IOCTL_ARGS ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; + DRM_DEVICE; drm_r128_private_t *dev_priv = dev->dev_private; drm_device_dma_t *dma = dev->dma; drm_buf_t *buf; drm_r128_buf_priv_t *buf_priv; drm_r128_vertex_t vertex; - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); if ( !dev_priv ) { DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); - return -EINVAL; + return DRM_ERR(EINVAL); } - if ( copy_from_user( &vertex, (drm_r128_vertex_t *)arg, - sizeof(vertex) ) ) - return -EFAULT; + DRM_COPY_FROM_USER_IOCTL( vertex, (drm_r128_vertex_t *) data, + sizeof(vertex) ); - DRM_DEBUG( "%s: pid=%d index=%d count=%d discard=%d\n", - __FUNCTION__, current->pid, + DRM_DEBUG( "pid=%d index=%d count=%d discard=%d\n", + DRM_CURRENTPID, vertex.idx, vertex.count, vertex.discard ); if ( vertex.idx < 0 || vertex.idx >= dma->buf_count ) { DRM_ERROR( "buffer index %d (of %d max)\n", vertex.idx, dma->buf_count - 1 ); - return -EINVAL; + return DRM_ERR(EINVAL); } if ( vertex.prim < 0 || vertex.prim > R128_CCE_VC_CNTL_PRIM_TYPE_TRI_TYPE2 ) { DRM_ERROR( "buffer prim %d\n", vertex.prim ); - return -EINVAL; + return DRM_ERR(EINVAL); } RING_SPACE_TEST_WITH_RETURN( dev_priv ); @@ -1332,14 +1394,14 @@ buf = dma->buflist[vertex.idx]; buf_priv = buf->dev_private; - if ( buf->pid != current->pid ) { - DRM_ERROR( "process %d using buffer owned by %d\n", - current->pid, buf->pid ); - return -EINVAL; + if ( buf->filp != filp ) { + DRM_ERROR( "process %d using buffer owned by %p\n", + DRM_CURRENTPID, buf->filp ); + return DRM_ERR(EINVAL); } if ( buf->pending ) { DRM_ERROR( "sending pending buffer %d\n", vertex.idx ); - return -EINVAL; + return DRM_ERR(EINVAL); } buf->used = vertex.count; @@ -1351,11 +1413,9 @@ return 0; } -int r128_cce_indices( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) +int r128_cce_indices( DRM_IOCTL_ARGS ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; + DRM_DEVICE; drm_r128_private_t *dev_priv = dev->dev_private; drm_device_dma_t *dma = dev->dma; drm_buf_t *buf; @@ -1363,30 +1423,28 @@ drm_r128_indices_t elts; int count; - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); if ( !dev_priv ) { DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); - return -EINVAL; + return DRM_ERR(EINVAL); } - if ( copy_from_user( &elts, (drm_r128_indices_t *)arg, - sizeof(elts) ) ) - return -EFAULT; + DRM_COPY_FROM_USER_IOCTL( elts, (drm_r128_indices_t *) data, + sizeof(elts) ); - DRM_DEBUG( "%s: pid=%d buf=%d s=%d e=%d d=%d\n", - __FUNCTION__, current->pid, + DRM_DEBUG( "pid=%d buf=%d s=%d e=%d d=%d\n", DRM_CURRENTPID, elts.idx, elts.start, elts.end, elts.discard ); if ( elts.idx < 0 || elts.idx >= dma->buf_count ) { DRM_ERROR( "buffer index %d (of %d max)\n", elts.idx, dma->buf_count - 1 ); - return -EINVAL; + return DRM_ERR(EINVAL); } if ( elts.prim < 0 || elts.prim > R128_CCE_VC_CNTL_PRIM_TYPE_TRI_TYPE2 ) { DRM_ERROR( "buffer prim %d\n", elts.prim ); - return -EINVAL; + return DRM_ERR(EINVAL); } RING_SPACE_TEST_WITH_RETURN( dev_priv ); @@ -1395,14 +1453,14 @@ buf = dma->buflist[elts.idx]; buf_priv = buf->dev_private; - if ( buf->pid != current->pid ) { - DRM_ERROR( "process %d using buffer owned by %d\n", - current->pid, buf->pid ); - return -EINVAL; + if ( buf->filp != filp ) { + DRM_ERROR( "process %d using buffer owned by %p\n", + DRM_CURRENTPID, buf->filp ); + return DRM_ERR(EINVAL); } if ( buf->pending ) { DRM_ERROR( "sending pending buffer %d\n", elts.idx ); - return -EINVAL; + return DRM_ERR(EINVAL); } count = (elts.end - elts.start) / sizeof(u16); @@ -1410,11 +1468,11 @@ if ( elts.start & 0x7 ) { DRM_ERROR( "misaligned buffer 0x%x\n", elts.start ); - return -EINVAL; + return DRM_ERR(EINVAL); } if ( elts.start < buf->used ) { DRM_ERROR( "no header 0x%x - 0x%x\n", elts.start, buf->used ); - return -EINVAL; + return DRM_ERR(EINVAL); } buf->used = elts.end; @@ -1426,49 +1484,42 @@ return 0; } -int r128_cce_blit( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) +int r128_cce_blit( DRM_IOCTL_ARGS ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; + DRM_DEVICE; drm_device_dma_t *dma = dev->dma; drm_r128_private_t *dev_priv = dev->dev_private; drm_r128_blit_t blit; - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); - if ( copy_from_user( &blit, (drm_r128_blit_t *)arg, - sizeof(blit) ) ) - return -EFAULT; + DRM_COPY_FROM_USER_IOCTL( blit, (drm_r128_blit_t *) data, + sizeof(blit) ); - DRM_DEBUG( "%s: pid=%d index=%d\n", - __FUNCTION__, current->pid, blit.idx ); + DRM_DEBUG( "pid=%d index=%d\n", DRM_CURRENTPID, blit.idx ); if ( blit.idx < 0 || blit.idx >= dma->buf_count ) { DRM_ERROR( "buffer index %d (of %d max)\n", blit.idx, dma->buf_count - 1 ); - return -EINVAL; + return DRM_ERR(EINVAL); } RING_SPACE_TEST_WITH_RETURN( dev_priv ); VB_AGE_TEST_WITH_RETURN( dev_priv ); - return r128_cce_dispatch_blit( dev, &blit ); + return r128_cce_dispatch_blit( filp, dev, &blit ); } -int r128_cce_depth( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) +int r128_cce_depth( DRM_IOCTL_ARGS ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; + DRM_DEVICE; drm_r128_private_t *dev_priv = dev->dev_private; drm_r128_depth_t depth; - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); - if ( copy_from_user( &depth, (drm_r128_depth_t *)arg, - sizeof(depth) ) ) - return -EFAULT; + DRM_COPY_FROM_USER_IOCTL( depth, (drm_r128_depth_t *) data, + sizeof(depth) ); RING_SPACE_TEST_WITH_RETURN( dev_priv ); @@ -1483,27 +1534,24 @@ return r128_cce_dispatch_read_pixels( dev, &depth ); } - return -EINVAL; + return DRM_ERR(EINVAL); } -int r128_cce_stipple( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) +int r128_cce_stipple( DRM_IOCTL_ARGS ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; + DRM_DEVICE; drm_r128_private_t *dev_priv = dev->dev_private; drm_r128_stipple_t stipple; u32 mask[32]; - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); - if ( copy_from_user( &stipple, (drm_r128_stipple_t *)arg, - sizeof(stipple) ) ) - return -EFAULT; + DRM_COPY_FROM_USER_IOCTL( stipple, (drm_r128_stipple_t *) data, + sizeof(stipple) ); - if ( copy_from_user( &mask, stipple.mask, + if ( DRM_COPY_FROM_USER( &mask, stipple.mask, 32 * sizeof(u32) ) ) - return -EFAULT; + return DRM_ERR( EFAULT ); RING_SPACE_TEST_WITH_RETURN( dev_priv ); @@ -1512,11 +1560,9 @@ return 0; } -int r128_cce_indirect( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) +int r128_cce_indirect( DRM_IOCTL_ARGS ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; + DRM_DEVICE; drm_r128_private_t *dev_priv = dev->dev_private; drm_device_dma_t *dma = dev->dma; drm_buf_t *buf; @@ -1526,16 +1572,15 @@ RING_LOCALS; #endif - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); if ( !dev_priv ) { DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); - return -EINVAL; + return DRM_ERR(EINVAL); } - if ( copy_from_user( &indirect, (drm_r128_indirect_t *)arg, - sizeof(indirect) ) ) - return -EFAULT; + DRM_COPY_FROM_USER_IOCTL( indirect, (drm_r128_indirect_t *) data, + sizeof(indirect) ); DRM_DEBUG( "indirect: idx=%d s=%d e=%d d=%d\n", indirect.idx, indirect.start, @@ -1544,26 +1589,26 @@ if ( indirect.idx < 0 || indirect.idx >= dma->buf_count ) { DRM_ERROR( "buffer index %d (of %d max)\n", indirect.idx, dma->buf_count - 1 ); - return -EINVAL; + return DRM_ERR(EINVAL); } buf = dma->buflist[indirect.idx]; buf_priv = buf->dev_private; - if ( buf->pid != current->pid ) { - DRM_ERROR( "process %d using buffer owned by %d\n", - current->pid, buf->pid ); - return -EINVAL; + if ( buf->filp != filp ) { + DRM_ERROR( "process %d using buffer owned by %p\n", + DRM_CURRENTPID, buf->filp ); + return DRM_ERR(EINVAL); } if ( buf->pending ) { DRM_ERROR( "sending pending buffer %d\n", indirect.idx ); - return -EINVAL; + return DRM_ERR(EINVAL); } if ( indirect.start < buf->used ) { DRM_ERROR( "reusing indirect: start=0x%x actual=0x%x\n", indirect.start, buf->used ); - return -EINVAL; + return DRM_ERR(EINVAL); } RING_SPACE_TEST_WITH_RETURN( dev_priv ); @@ -1589,3 +1634,36 @@ return 0; } + +int r128_getparam( DRM_IOCTL_ARGS ) +{ + DRM_DEVICE; + drm_r128_private_t *dev_priv = dev->dev_private; + drm_r128_getparam_t param; + int value; + + if ( !dev_priv ) { + DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); + return DRM_ERR(EINVAL); + } + + DRM_COPY_FROM_USER_IOCTL( param, (drm_r128_getparam_t *)data, + sizeof(param) ); + + DRM_DEBUG( "pid=%d\n", DRM_CURRENTPID ); + + switch( param.param ) { + case R128_PARAM_IRQ_NR: + value = dev->irq; + break; + default: + return DRM_ERR(EINVAL); + } + + if ( DRM_COPY_TO_USER( param.value, &value, sizeof(int) ) ) { + DRM_ERROR( "copy_to_user\n" ); + return DRM_ERR(EFAULT); + } + + return 0; +} diff -urN linux-2.4.23-pre8/drivers/char/drm/radeon.h linux-2.4.23-pre8-pac1/drivers/char/drm/radeon.h --- linux-2.4.23-pre8/drivers/char/drm/radeon.h 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/radeon.h 2003-10-11 23:18:12.000000000 +0200 @@ -51,7 +51,7 @@ #define DRIVER_DATE "20020828" #define DRIVER_MAJOR 1 -#define DRIVER_MINOR 7 +#define DRIVER_MINOR 9 #define DRIVER_PATCHLEVEL 0 /* Interface history: @@ -68,15 +68,19 @@ * 1.5 - Add r200 packets to cmdbuf ioctl * - Add r200 function to init ioctl * - Add 'scalar2' instruction to cmdbuf - * 1.6 - Add static agp memory manager + * 1.6 - Add static GART memory manager * Add irq handler (won't be turned on unless X server knows to) * Add irq ioctls and irq_active getparam. * Add wait command for cmdbuf ioctl - * Add agp offset query for getparam + * Add GART offset query for getparam * 1.7 - Add support for cube map registers: R200_PP_CUBIC_FACES_[0..5] * and R200_PP_CUBIC_OFFSET_F1_[0..5]. * Added packets R200_EMIT_PP_CUBIC_FACES_[0..5] and * R200_EMIT_PP_CUBIC_OFFSETS_[0..5]. (brian) + * 1.8 - Remove need to call cleanup ioctls on last client exit (keith) + * Add 'GET' queries for starting additional clients on different VT's. + * 1.9 - Add DRM_IOCTL_RADEON_CP_RESUME ioctl. + * Add texture rectangle support for r100. */ #define DRIVER_IOCTLS \ [DRM_IOCTL_NR(DRM_IOCTL_DMA)] = { radeon_cp_buffers, 1, 0 }, \ @@ -85,6 +89,7 @@ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_CP_STOP)] = { radeon_cp_stop, 1, 1 }, \ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_CP_RESET)] = { radeon_cp_reset, 1, 1 }, \ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_CP_IDLE)] = { radeon_cp_idle, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_RADEON_CP_RESUME)] = { radeon_cp_resume, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_RESET)] = { radeon_engine_reset, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_FULLSCREEN)] = { radeon_fullscreen, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_SWAP)] = { radeon_cp_swap, 1, 0 }, \ @@ -105,47 +110,41 @@ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_IRQ_WAIT)] = { radeon_irq_wait, 1, 0 }, -#define USE_IRQS 1 -#if USE_IRQS -#define __HAVE_DMA_IRQ 1 -#define __HAVE_VBL_IRQ 1 -#define __HAVE_SHARED_IRQ 1 /* When a client dies: * - Check for and clean up flipped page state - * - Free any alloced agp memory. + * - Free any alloced GART memory. * * DRM infrastructure takes care of reclaiming dma buffers. */ -#define DRIVER_PRERELEASE() do { \ +#define DRIVER_PRERELEASE() \ +do { \ if ( dev->dev_private ) { \ drm_radeon_private_t *dev_priv = dev->dev_private; \ if ( dev_priv->page_flipping ) { \ radeon_do_cleanup_pageflip( dev ); \ } \ - radeon_mem_release( dev_priv->agp_heap ); \ + radeon_mem_release( filp, dev_priv->gart_heap ); \ + radeon_mem_release( filp, dev_priv->fb_heap ); \ } \ } while (0) -/* On unloading the module: - * - Free memory heap structure - * - Remove mappings made at startup and free dev_private. +/* When the last client dies, shut down the CP and free dev->dev_priv. */ -#define DRIVER_PRETAKEDOWN() do { \ - if ( dev->dev_private ) { \ - drm_radeon_private_t *dev_priv = dev->dev_private; \ - radeon_mem_takedown( &(dev_priv->agp_heap) ); \ - radeon_do_cleanup_cp( dev ); \ - } \ +/* #define __HAVE_RELEASE 1 */ +#define DRIVER_PRETAKEDOWN() \ +do { \ + radeon_do_release( dev ); \ } while (0) -#else -#define __HAVE_DMA_IRQ 0 -#endif + /* DMA customization: */ #define __HAVE_DMA 1 +#define __HAVE_DMA_IRQ 1 +#define __HAVE_VBL_IRQ 1 +#define __HAVE_SHARED_IRQ 1 /* Buffer customization: diff -urN linux-2.4.23-pre8/drivers/char/drm/radeon_cp.c linux-2.4.23-pre8-pac1/drivers/char/drm/radeon_cp.c --- linux-2.4.23-pre8/drivers/char/drm/radeon_cp.c 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/radeon_cp.c 2003-10-24 02:50:32.000000000 +0200 @@ -33,14 +33,10 @@ #include "drm.h" #include "radeon_drm.h" #include "radeon_drv.h" -#include "drm_os_linux.h" -#include /* For task queue support */ -#include #define RADEON_FIFO_DEBUG 0 - /* CP microcode (from ATI) */ static u32 R200_cp_microcode[][2] = { { 0x21007000, 0000000000 }, @@ -614,14 +610,14 @@ & RADEON_RB2D_DC_BUSY) ) { return 0; } - udelay( 1 ); + DRM_UDELAY( 1 ); } #if RADEON_FIFO_DEBUG DRM_ERROR( "failed!\n" ); radeon_status( dev_priv ); #endif - return -EBUSY; + return DRM_ERR(EBUSY); } static int radeon_do_wait_for_fifo( drm_radeon_private_t *dev_priv, @@ -635,14 +631,14 @@ int slots = ( RADEON_READ( RADEON_RBBM_STATUS ) & RADEON_RBBM_FIFOCNT_MASK ); if ( slots >= entries ) return 0; - udelay( 1 ); + DRM_UDELAY( 1 ); } #if RADEON_FIFO_DEBUG DRM_ERROR( "failed!\n" ); radeon_status( dev_priv ); #endif - return -EBUSY; + return DRM_ERR(EBUSY); } static int radeon_do_wait_for_idle( drm_radeon_private_t *dev_priv ) @@ -660,14 +656,14 @@ radeon_do_pixcache_flush( dev_priv ); return 0; } - udelay( 1 ); + DRM_UDELAY( 1 ); } #if RADEON_FIFO_DEBUG DRM_ERROR( "failed!\n" ); radeon_status( dev_priv ); #endif - return -EBUSY; + return DRM_ERR(EBUSY); } @@ -775,7 +771,7 @@ cur_read_ptr = RADEON_READ( RADEON_CP_RB_RPTR ); RADEON_WRITE( RADEON_CP_RB_WPTR, cur_read_ptr ); - *dev_priv->ring.head = cur_read_ptr; + SET_RING_HEAD( dev_priv, cur_read_ptr ); dev_priv->ring.tail = cur_read_ptr; } @@ -859,42 +855,46 @@ /* Initialize the memory controller */ RADEON_WRITE( RADEON_MC_FB_LOCATION, - (dev_priv->agp_vm_start - 1) & 0xffff0000 ); + (dev_priv->gart_vm_start - 1) & 0xffff0000 | + (dev_priv->fb_base >> 16)); +#if __REALLY_HAVE_AGP if ( !dev_priv->is_pci ) { RADEON_WRITE( RADEON_MC_AGP_LOCATION, - (((dev_priv->agp_vm_start - 1 + - dev_priv->agp_size) & 0xffff0000) | - (dev_priv->agp_vm_start >> 16)) ); - } + (((dev_priv->gart_vm_start - 1 + + dev_priv->gart_size) & 0xffff0000) | + (dev_priv->gart_vm_start >> 16)) ); -#if __REALLY_HAVE_AGP - if ( !dev_priv->is_pci ) ring_start = (dev_priv->cp_ring->offset - dev->agp->base - + dev_priv->agp_vm_start); - else + + dev_priv->gart_vm_start); + } else #endif ring_start = (dev_priv->cp_ring->offset - dev->sg->handle - + dev_priv->agp_vm_start); + + dev_priv->gart_vm_start); RADEON_WRITE( RADEON_CP_RB_BASE, ring_start ); /* Set the write pointer delay */ RADEON_WRITE( RADEON_CP_RB_WPTR_DELAY, 0 ); - RADEON_READ( RADEON_CP_RB_WPTR_DELAY ); /* read back to propagate */ /* Initialize the ring buffer's read and write pointers */ cur_read_ptr = RADEON_READ( RADEON_CP_RB_RPTR ); RADEON_WRITE( RADEON_CP_RB_WPTR, cur_read_ptr ); - *dev_priv->ring.head = cur_read_ptr; + SET_RING_HEAD( dev_priv, cur_read_ptr ); + dev_priv->ring.tail = cur_read_ptr; +#if __REALLY_HAVE_AGP if ( !dev_priv->is_pci ) { RADEON_WRITE( RADEON_CP_RB_RPTR_ADDR, - dev_priv->ring_rptr->offset ); - } else { + dev_priv->ring_rptr->offset + - dev->agp->base + + dev_priv->gart_vm_start); + } else +#endif + { drm_sg_mem_t *entry = dev->sg; unsigned long tmp_ofs, page_ofs; @@ -903,8 +903,8 @@ RADEON_WRITE( RADEON_CP_RB_RPTR_ADDR, entry->busaddr[page_ofs]); - DRM_DEBUG( "ring rptr: offset=0x%08x handle=0x%08lx\n", - entry->busaddr[page_ofs], + DRM_DEBUG( "ring rptr: offset=0x%08lx handle=0x%08lx\n", + (unsigned long) entry->busaddr[page_ofs], entry->handle + tmp_ofs ); } @@ -919,19 +919,20 @@ + RADEON_SCRATCH_REG_OFFSET ); dev_priv->scratch = ((__volatile__ u32 *) - dev_priv->ring.head + + dev_priv->ring_rptr->handle + (RADEON_SCRATCH_REG_OFFSET / sizeof(u32))); RADEON_WRITE( RADEON_SCRATCH_UMSK, 0x7 ); + /* Writeback doesn't seem to work everywhere, test it first */ - writel(0, &dev_priv->scratch[1]); + DRM_WRITE32( dev_priv->ring_rptr, RADEON_SCRATCHOFF(1), 0 ); RADEON_WRITE( RADEON_SCRATCH_REG1, 0xdeadbeef ); for ( tmp = 0 ; tmp < dev_priv->usec_timeout ; tmp++ ) { - if ( readl( &dev_priv->scratch[1] ) == 0xdeadbeef ) + if ( DRM_READ32( dev_priv->ring_rptr, RADEON_SCRATCHOFF(1) ) == 0xdeadbeef ) break; - udelay(1); + DRM_UDELAY( 1 ); } if ( tmp < dev_priv->usec_timeout ) { @@ -975,15 +976,41 @@ RADEON_ISYNC_CPSCRATCH_IDLEGUI) ); } +/* Enable or disable PCI GART on the chip */ +static void radeon_set_pcigart( drm_radeon_private_t *dev_priv, int on ) +{ + u32 tmp = RADEON_READ( RADEON_AIC_CNTL ); + + if ( on ) { + RADEON_WRITE( RADEON_AIC_CNTL, tmp | RADEON_PCIGART_TRANSLATE_EN ); + + /* set PCI GART page-table base address + */ + RADEON_WRITE( RADEON_AIC_PT_BASE, dev_priv->bus_pci_gart ); + + /* set address range for PCI address translate + */ + RADEON_WRITE( RADEON_AIC_LO_ADDR, dev_priv->gart_vm_start ); + RADEON_WRITE( RADEON_AIC_HI_ADDR, dev_priv->gart_vm_start + + dev_priv->gart_size - 1); + + /* Turn off AGP aperture -- is this required for PCI GART? + */ + RADEON_WRITE( RADEON_MC_AGP_LOCATION, 0xffffffc0 ); /* ?? */ + RADEON_WRITE( RADEON_AGP_COMMAND, 0 ); /* clear AGP_COMMAND */ + } else { + RADEON_WRITE( RADEON_AIC_CNTL, tmp & ~RADEON_PCIGART_TRANSLATE_EN ); + } +} + static int radeon_do_init_cp( drm_device_t *dev, drm_radeon_init_t *init ) { drm_radeon_private_t *dev_priv; - u32 tmp; DRM_DEBUG( "\n" ); dev_priv = DRM(alloc)( sizeof(drm_radeon_private_t), DRM_MEM_DRIVER ); if ( dev_priv == NULL ) - return -ENOMEM; + return DRM_ERR(ENOMEM); memset( dev_priv, 0, sizeof(drm_radeon_private_t) ); @@ -993,7 +1020,7 @@ DRM_ERROR( "PCI GART memory not allocated!\n" ); dev->dev_private = (void *)dev_priv; radeon_do_cleanup_cp(dev); - return -EINVAL; + return DRM_ERR(EINVAL); } dev_priv->usec_timeout = init->usec_timeout; @@ -1002,7 +1029,7 @@ DRM_DEBUG( "TIMEOUT problem!\n" ); dev->dev_private = (void *)dev_priv; radeon_do_cleanup_cp(dev); - return -EINVAL; + return DRM_ERR(EINVAL); } dev_priv->is_r200 = (init->func == RADEON_INIT_R200_CP); @@ -1018,7 +1045,7 @@ DRM_DEBUG( "BAD cp_mode (%x)!\n", init->cp_mode ); dev->dev_private = (void *)dev_priv; radeon_do_cleanup_cp(dev); - return -EINVAL; + return DRM_ERR(EINVAL); } switch ( init->fb_bpp ) { @@ -1047,13 +1074,6 @@ dev_priv->depth_offset = init->depth_offset; dev_priv->depth_pitch = init->depth_pitch; - dev_priv->front_pitch_offset = (((dev_priv->front_pitch/64) << 22) | - (dev_priv->front_offset >> 10)); - dev_priv->back_pitch_offset = (((dev_priv->back_pitch/64) << 22) | - (dev_priv->back_offset >> 10)); - dev_priv->depth_pitch_offset = (((dev_priv->depth_pitch/64) << 22) | - (dev_priv->depth_offset >> 10)); - /* Hardware state for depth clears. Remove this if/when we no * longer clear the depth buffer with a 3D rectangle. Hard-code * all values to prevent unwanted 3D state from slipping through @@ -1085,12 +1105,19 @@ RADEON_ROUND_PREC_8TH_PIX); DRM_GETSAREA(); + + dev_priv->fb_offset = init->fb_offset; + dev_priv->mmio_offset = init->mmio_offset; + dev_priv->ring_offset = init->ring_offset; + dev_priv->ring_rptr_offset = init->ring_rptr_offset; + dev_priv->buffers_offset = init->buffers_offset; + dev_priv->gart_textures_offset = init->gart_textures_offset; if(!dev_priv->sarea) { DRM_ERROR("could not find sarea!\n"); dev->dev_private = (void *)dev_priv; radeon_do_cleanup_cp(dev); - return -EINVAL; + return DRM_ERR(EINVAL); } DRM_FIND_MAP( dev_priv->fb, init->fb_offset ); @@ -1098,45 +1125,44 @@ DRM_ERROR("could not find framebuffer!\n"); dev->dev_private = (void *)dev_priv; radeon_do_cleanup_cp(dev); - return -EINVAL; + return DRM_ERR(EINVAL); } DRM_FIND_MAP( dev_priv->mmio, init->mmio_offset ); if(!dev_priv->mmio) { DRM_ERROR("could not find mmio region!\n"); dev->dev_private = (void *)dev_priv; radeon_do_cleanup_cp(dev); - return -EINVAL; + return DRM_ERR(EINVAL); } DRM_FIND_MAP( dev_priv->cp_ring, init->ring_offset ); if(!dev_priv->cp_ring) { DRM_ERROR("could not find cp ring region!\n"); dev->dev_private = (void *)dev_priv; radeon_do_cleanup_cp(dev); - return -EINVAL; + return DRM_ERR(EINVAL); } DRM_FIND_MAP( dev_priv->ring_rptr, init->ring_rptr_offset ); if(!dev_priv->ring_rptr) { DRM_ERROR("could not find ring read pointer!\n"); dev->dev_private = (void *)dev_priv; radeon_do_cleanup_cp(dev); - return -EINVAL; + return DRM_ERR(EINVAL); } DRM_FIND_MAP( dev_priv->buffers, init->buffers_offset ); if(!dev_priv->buffers) { DRM_ERROR("could not find dma buffer region!\n"); dev->dev_private = (void *)dev_priv; radeon_do_cleanup_cp(dev); - return -EINVAL; + return DRM_ERR(EINVAL); } - if ( !dev_priv->is_pci ) { - DRM_FIND_MAP( dev_priv->agp_textures, - init->agp_textures_offset ); - if(!dev_priv->agp_textures) { - DRM_ERROR("could not find agp texture region!\n"); + if ( init->gart_textures_offset ) { + DRM_FIND_MAP( dev_priv->gart_textures, init->gart_textures_offset ); + if ( !dev_priv->gart_textures ) { + DRM_ERROR("could not find GART texture region!\n"); dev->dev_private = (void *)dev_priv; radeon_do_cleanup_cp(dev); - return -EINVAL; + return DRM_ERR(EINVAL); } } @@ -1144,19 +1170,22 @@ (drm_radeon_sarea_t *)((u8 *)dev_priv->sarea->handle + init->sarea_priv_offset); +#if __REALLY_HAVE_AGP if ( !dev_priv->is_pci ) { - DRM_IOREMAP( dev_priv->cp_ring ); - DRM_IOREMAP( dev_priv->ring_rptr ); - DRM_IOREMAP( dev_priv->buffers ); + DRM_IOREMAP( dev_priv->cp_ring, dev ); + DRM_IOREMAP( dev_priv->ring_rptr, dev ); + DRM_IOREMAP( dev_priv->buffers, dev ); if(!dev_priv->cp_ring->handle || !dev_priv->ring_rptr->handle || !dev_priv->buffers->handle) { DRM_ERROR("could not find ioremap agp regions!\n"); dev->dev_private = (void *)dev_priv; radeon_do_cleanup_cp(dev); - return -EINVAL; + return DRM_ERR(EINVAL); } - } else { + } else +#endif + { dev_priv->cp_ring->handle = (void *)dev_priv->cp_ring->offset; dev_priv->ring_rptr->handle = @@ -1172,28 +1201,32 @@ } - dev_priv->agp_size = init->agp_size; - dev_priv->agp_vm_start = RADEON_READ( RADEON_CONFIG_APER_SIZE ); + dev_priv->fb_base = (RADEON_READ( RADEON_MC_FB_LOCATION ) & 0xffff) << 16; + dev_priv->front_pitch_offset = (((dev_priv->front_pitch/64) << 22) | + ((dev_priv->front_offset+dev_priv->fb_base) >> 10)); + dev_priv->back_pitch_offset = (((dev_priv->back_pitch/64) << 22) | + ((dev_priv->back_offset+dev_priv->fb_base) >> 10)); + dev_priv->depth_pitch_offset = (((dev_priv->depth_pitch/64) << 22) | + ((dev_priv->depth_offset+dev_priv->fb_base) >> 10)); + dev_priv->gart_size = init->gart_size; + dev_priv->gart_vm_start = RADEON_READ( RADEON_CONFIG_APER_SIZE ) + dev_priv->fb_base; #if __REALLY_HAVE_AGP if ( !dev_priv->is_pci ) - dev_priv->agp_buffers_offset = (dev_priv->buffers->offset + dev_priv->gart_buffers_offset = (dev_priv->buffers->offset - dev->agp->base - + dev_priv->agp_vm_start); + + dev_priv->gart_vm_start); else #endif - dev_priv->agp_buffers_offset = (dev_priv->buffers->offset + dev_priv->gart_buffers_offset = (dev_priv->buffers->offset - dev->sg->handle - + dev_priv->agp_vm_start); + + dev_priv->gart_vm_start); - DRM_DEBUG( "dev_priv->agp_size %d\n", - dev_priv->agp_size ); - DRM_DEBUG( "dev_priv->agp_vm_start 0x%x\n", - dev_priv->agp_vm_start ); - DRM_DEBUG( "dev_priv->agp_buffers_offset 0x%lx\n", - dev_priv->agp_buffers_offset ); - - dev_priv->ring.head = ((__volatile__ u32 *) - dev_priv->ring_rptr->handle); + DRM_DEBUG( "dev_priv->gart_size %d\n", + dev_priv->gart_size ); + DRM_DEBUG( "dev_priv->gart_vm_start 0x%x\n", + dev_priv->gart_vm_start ); + DRM_DEBUG( "dev_priv->gart_buffers_offset 0x%lx\n", + dev_priv->gart_buffers_offset ); dev_priv->ring.start = (u32 *)dev_priv->cp_ring->handle; dev_priv->ring.end = ((u32 *)dev_priv->cp_ring->handle @@ -1206,45 +1239,24 @@ dev_priv->ring.high_mark = RADEON_RING_HIGH_MARK; -#if __REALLY_HAVE_SG - if ( dev_priv->is_pci ) { +#if __REALLY_HAVE_AGP + if ( !dev_priv->is_pci ) { + /* Turn off PCI GART */ + radeon_set_pcigart( dev_priv, 0 ); + } else +#endif + { if (!DRM(ati_pcigart_init)( dev, &dev_priv->phys_pci_gart, &dev_priv->bus_pci_gart)) { DRM_ERROR( "failed to init PCI GART!\n" ); dev->dev_private = (void *)dev_priv; radeon_do_cleanup_cp(dev); - return -ENOMEM; + return DRM_ERR(ENOMEM); } - /* Turn on PCI GART - */ - tmp = RADEON_READ( RADEON_AIC_CNTL ) - | RADEON_PCIGART_TRANSLATE_EN; - RADEON_WRITE( RADEON_AIC_CNTL, tmp ); - - /* set PCI GART page-table base address - */ - RADEON_WRITE( RADEON_AIC_PT_BASE, dev_priv->bus_pci_gart ); - /* set address range for PCI address translate - */ - RADEON_WRITE( RADEON_AIC_LO_ADDR, dev_priv->agp_vm_start ); - RADEON_WRITE( RADEON_AIC_HI_ADDR, dev_priv->agp_vm_start - + dev_priv->agp_size - 1); - - /* Turn off AGP aperture -- is this required for PCIGART? - */ - RADEON_WRITE( RADEON_MC_AGP_LOCATION, 0xffffffc0 ); /* ?? */ - RADEON_WRITE( RADEON_AGP_COMMAND, 0 ); /* clear AGP_COMMAND */ - } else { -#endif /* __REALLY_HAVE_SG */ - /* Turn off PCI GART - */ - tmp = RADEON_READ( RADEON_AIC_CNTL ) - & ~RADEON_PCIGART_TRANSLATE_EN; - RADEON_WRITE( RADEON_AIC_CNTL, tmp ); -#if __REALLY_HAVE_SG + /* Turn on PCI GART */ + radeon_set_pcigart( dev_priv, 1 ); } -#endif /* __REALLY_HAVE_SG */ radeon_cp_load_microcode( dev_priv ); radeon_cp_init_ring_buffer( dev, dev_priv ); @@ -1262,20 +1274,32 @@ { DRM_DEBUG( "\n" ); +#if _HAVE_DMA_IRQ + /* Make sure interrupts are disabled here because the uninstall ioctl + * may not have been called from userspace and after dev_private + * is freed, it's too late. + */ + if ( dev->irq ) DRM(irq_uninstall)(dev); +#endif + if ( dev->dev_private ) { drm_radeon_private_t *dev_priv = dev->dev_private; +#if __REALLY_HAVE_AGP if ( !dev_priv->is_pci ) { - DRM_IOREMAPFREE( dev_priv->cp_ring ); - DRM_IOREMAPFREE( dev_priv->ring_rptr ); - DRM_IOREMAPFREE( dev_priv->buffers ); - } else { -#if __REALLY_HAVE_SG + if ( dev_priv->cp_ring != NULL ) + DRM_IOREMAPFREE( dev_priv->cp_ring, dev ); + if ( dev_priv->ring_rptr != NULL ) + DRM_IOREMAPFREE( dev_priv->ring_rptr, dev ); + if ( dev_priv->buffers != NULL ) + DRM_IOREMAPFREE( dev_priv->buffers, dev ); + } else +#endif + { if (!DRM(ati_pcigart_cleanup)( dev, dev_priv->phys_pci_gart, dev_priv->bus_pci_gart )) DRM_ERROR( "failed to cleanup PCI GART!\n" ); -#endif /* __REALLY_HAVE_SG */ } DRM(free)( dev->dev_private, sizeof(drm_radeon_private_t), @@ -1286,15 +1310,54 @@ return 0; } -int radeon_cp_init( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) +/* This code will reinit the Radeon CP hardware after a resume from disc. + * AFAIK, it would be very difficult to pickle the state at suspend time, so + * here we make sure that all Radeon hardware initialisation is re-done without + * affecting running applications. + * + * Charl P. Botha + */ +static int radeon_do_resume_cp( drm_device_t *dev ) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + + if ( !dev_priv ) { + DRM_ERROR( "Called with no initialization\n" ); + return DRM_ERR( EINVAL ); + } + + DRM_DEBUG("Starting radeon_do_resume_cp()\n"); + +#if __REALLY_HAVE_AGP + if ( !dev_priv->is_pci ) { + /* Turn off PCI GART */ + radeon_set_pcigart( dev_priv, 0 ); + } else +#endif + { + /* Turn on PCI GART */ + radeon_set_pcigart( dev_priv, 1 ); + } + + radeon_cp_load_microcode( dev_priv ); + radeon_cp_init_ring_buffer( dev, dev_priv ); + + radeon_do_engine_reset( dev ); + + DRM_DEBUG("radeon_do_resume_cp() complete\n"); + + return 0; +} + + +int radeon_cp_init( DRM_IOCTL_ARGS ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; + DRM_DEVICE; drm_radeon_init_t init; - if ( copy_from_user( &init, (drm_radeon_init_t *)arg, sizeof(init) ) ) - return -EFAULT; + LOCK_TEST_WITH_RETURN( dev, filp ); + + DRM_COPY_FROM_USER_IOCTL( init, (drm_radeon_init_t *)data, sizeof(init) ); switch ( init.func ) { case RADEON_INIT_CP: @@ -1304,18 +1367,16 @@ return radeon_do_cleanup_cp( dev ); } - return -EINVAL; + return DRM_ERR(EINVAL); } -int radeon_cp_start( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) +int radeon_cp_start( DRM_IOCTL_ARGS ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; + DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; - DRM_DEBUG( "%s\n", __FUNCTION__ ); + DRM_DEBUG( "\n" ); - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); if ( dev_priv->cp_running ) { DRM_DEBUG( "%s while CP running\n", __FUNCTION__ ); @@ -1335,20 +1396,20 @@ /* Stop the CP. The engine must have been idled before calling this * routine. */ -int radeon_cp_stop( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) +int radeon_cp_stop( DRM_IOCTL_ARGS ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; + DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; drm_radeon_cp_stop_t stop; int ret; - DRM_DEBUG( "%s\n", __FUNCTION__ ); + DRM_DEBUG( "\n" ); - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); - if ( copy_from_user( &stop, (drm_radeon_init_t *)arg, sizeof(stop) ) ) - return -EFAULT; + DRM_COPY_FROM_USER_IOCTL( stop, (drm_radeon_cp_stop_t *)data, sizeof(stop) ); + + if (!dev_priv->cp_running) + return 0; /* Flush any pending CP commands. This ensures any outstanding * commands are exectuted by the engine before we turn it off. @@ -1377,21 +1438,52 @@ return 0; } + +void radeon_do_release( drm_device_t *dev ) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + int ret; + + if (dev_priv) { + if (dev_priv->cp_running) { + /* Stop the cp */ + while ((ret = radeon_do_cp_idle( dev_priv )) != 0) { + DRM_DEBUG("radeon_do_cp_idle %d\n", ret); +#ifdef __linux__ + schedule(); +#else + tsleep(&ret, PZERO, "rdnrel", 1); +#endif + } + radeon_do_cp_stop( dev_priv ); + radeon_do_engine_reset( dev ); + } + + /* Disable *all* interrupts */ + RADEON_WRITE( RADEON_GEN_INT_CNTL, 0 ); + + /* Free memory heap structures */ + radeon_mem_takedown( &(dev_priv->gart_heap) ); + radeon_mem_takedown( &(dev_priv->fb_heap) ); + + /* deallocate kernel resources */ + radeon_do_cleanup_cp( dev ); + } +} + /* Just reset the CP ring. Called as part of an X Server engine reset. */ -int radeon_cp_reset( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) +int radeon_cp_reset( DRM_IOCTL_ARGS ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; + DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; - DRM_DEBUG( "%s\n", __FUNCTION__ ); + DRM_DEBUG( "\n" ); - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); if ( !dev_priv ) { DRM_DEBUG( "%s called before init done\n", __FUNCTION__ ); - return -EINVAL; + return DRM_ERR(EINVAL); } radeon_do_cp_reset( dev_priv ); @@ -1402,27 +1494,33 @@ return 0; } -int radeon_cp_idle( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) +int radeon_cp_idle( DRM_IOCTL_ARGS ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; + DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; - DRM_DEBUG( "%s\n", __FUNCTION__ ); + DRM_DEBUG( "\n" ); - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); return radeon_do_cp_idle( dev_priv ); } -int radeon_engine_reset( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) +/* Added by Charl P. Botha to call radeon_do_resume_cp(). + */ +int radeon_cp_resume( DRM_IOCTL_ARGS ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; - DRM_DEBUG( "%s\n", __FUNCTION__ ); + DRM_DEVICE; + + return radeon_do_resume_cp(dev); +} + + +int radeon_engine_reset( DRM_IOCTL_ARGS ) +{ + DRM_DEVICE; + DRM_DEBUG( "\n" ); - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); return radeon_do_engine_reset( dev ); } @@ -1434,7 +1532,7 @@ /* KW: Deprecated to say the least: */ -int radeon_fullscreen(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long data) +int radeon_fullscreen( DRM_IOCTL_ARGS ) { return 0; } @@ -1481,7 +1579,7 @@ for ( i = start ; i < dma->buf_count ; i++ ) { buf = dma->buflist[i]; buf_priv = buf->dev_private; - if ( buf->pid == 0 || (buf->pending && + if ( buf->filp == 0 || (buf->pending && buf_priv->age <= done_age) ) { dev_priv->stats.requested_bufs++; buf->pending = 0; @@ -1491,7 +1589,7 @@ } if (t) { - udelay(1); + DRM_UDELAY( 1 ); dev_priv->stats.freelist_loops++; } } @@ -1508,7 +1606,7 @@ drm_buf_t *buf; int i, t; int start; - u32 done_age = readl(&dev_priv->scratch[1]); + u32 done_age = DRM_READ32(dev_priv->ring_rptr, RADEON_SCRATCHOFF(1)); if ( ++dev_priv->last_buf >= dma->buf_count ) dev_priv->last_buf = 0; @@ -1520,7 +1618,7 @@ for ( i = start ; i < dma->buf_count ; i++ ) { buf = dma->buflist[i]; buf_priv = buf->dev_private; - if ( buf->pid == 0 || (buf->pending && + if ( buf->filp == 0 || (buf->pending && buf_priv->age <= done_age) ) { dev_priv->stats.requested_bufs++; buf->pending = 0; @@ -1557,10 +1655,10 @@ { drm_radeon_ring_buffer_t *ring = &dev_priv->ring; int i; - u32 last_head = GET_RING_HEAD(ring); + u32 last_head = GET_RING_HEAD( dev_priv ); for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { - u32 head = GET_RING_HEAD(ring); + u32 head = GET_RING_HEAD( dev_priv ); ring->space = (head - ring->tail) * sizeof(u32); if ( ring->space <= 0 ) @@ -1574,7 +1672,7 @@ i = 0; last_head = head; - udelay( 1 ); + DRM_UDELAY( 1 ); } /* FIXME: This return value is ignored in the BEGIN_RING macro! */ @@ -1582,70 +1680,66 @@ radeon_status( dev_priv ); DRM_ERROR( "failed!\n" ); #endif - return -EBUSY; + return DRM_ERR(EBUSY); } -static int radeon_cp_get_buffers( drm_device_t *dev, drm_dma_t *d ) +static int radeon_cp_get_buffers( DRMFILE filp, drm_device_t *dev, drm_dma_t *d ) { int i; drm_buf_t *buf; for ( i = d->granted_count ; i < d->request_count ; i++ ) { buf = radeon_freelist_get( dev ); - if ( !buf ) return -EAGAIN; + if ( !buf ) return DRM_ERR(EBUSY); /* NOTE: broken client */ - buf->pid = current->pid; + buf->filp = filp; - if ( copy_to_user( &d->request_indices[i], &buf->idx, + if ( DRM_COPY_TO_USER( &d->request_indices[i], &buf->idx, sizeof(buf->idx) ) ) - return -EFAULT; - if ( copy_to_user( &d->request_sizes[i], &buf->total, + return DRM_ERR(EFAULT); + if ( DRM_COPY_TO_USER( &d->request_sizes[i], &buf->total, sizeof(buf->total) ) ) - return -EFAULT; + return DRM_ERR(EFAULT); d->granted_count++; } return 0; } -int radeon_cp_buffers( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) +int radeon_cp_buffers( DRM_IOCTL_ARGS ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; + DRM_DEVICE; drm_device_dma_t *dma = dev->dma; int ret = 0; drm_dma_t d; - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); - if ( copy_from_user( &d, (drm_dma_t *)arg, sizeof(d) ) ) - return -EFAULT; + DRM_COPY_FROM_USER_IOCTL( d, (drm_dma_t *)data, sizeof(d) ); /* Please don't send us buffers. */ if ( d.send_count != 0 ) { DRM_ERROR( "Process %d trying to send %d buffers via drmDMA\n", - current->pid, d.send_count ); - return -EINVAL; + DRM_CURRENTPID, d.send_count ); + return DRM_ERR(EINVAL); } /* We'll send you buffers. */ if ( d.request_count < 0 || d.request_count > dma->buf_count ) { DRM_ERROR( "Process %d trying to get %d buffers (of %d max)\n", - current->pid, d.request_count, dma->buf_count ); - return -EINVAL; + DRM_CURRENTPID, d.request_count, dma->buf_count ); + return DRM_ERR(EINVAL); } d.granted_count = 0; if ( d.request_count ) { - ret = radeon_cp_get_buffers( dev, &d ); + ret = radeon_cp_get_buffers( filp, dev, &d ); } - if ( copy_to_user( (drm_dma_t *)arg, &d, sizeof(d) ) ) - return -EFAULT; + DRM_COPY_TO_USER_IOCTL( (drm_dma_t *)data, d, sizeof(d) ); return ret; } diff -urN linux-2.4.23-pre8/drivers/char/drm/radeon_drm.h linux-2.4.23-pre8-pac1/drivers/char/drm/radeon_drm.h --- linux-2.4.23-pre8/drivers/char/drm/radeon_drm.h 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/radeon_drm.h 2003-10-11 23:18:12.000000000 +0200 @@ -141,7 +141,10 @@ #define R200_EMIT_PP_CUBIC_OFFSETS_4 70 #define R200_EMIT_PP_CUBIC_FACES_5 71 #define R200_EMIT_PP_CUBIC_OFFSETS_5 72 -#define RADEON_MAX_STATE_PACKETS 73 +#define RADEON_EMIT_PP_TEX_SIZE_0 73 +#define RADEON_EMIT_PP_TEX_SIZE_1 74 +#define RADEON_EMIT_PP_TEX_SIZE_2 75 +#define RADEON_MAX_STATE_PACKETS 76 /* Commands understood by cmd_buffer ioctl. More can be added but @@ -211,11 +214,11 @@ #define RADEON_NR_SAREA_CLIPRECTS 12 -/* There are 2 heaps (local/AGP). Each region within a heap is a +/* There are 2 heaps (local/GART). Each region within a heap is a * minimum of 64k, and there are at most 64 of them per heap. */ #define RADEON_LOCAL_TEX_HEAP 0 -#define RADEON_AGP_TEX_HEAP 1 +#define RADEON_GART_TEX_HEAP 1 #define RADEON_NR_TEX_HEAPS 2 #define RADEON_NR_TEX_REGIONS 64 #define RADEON_LOG_TEX_GRANULARITY 16 @@ -323,12 +326,6 @@ typedef struct { - unsigned char next, prev; - unsigned char in_use; - int age; -} drm_radeon_tex_region_t; - -typedef struct { /* The channel for communication of state information to the * kernel on firing a vertex buffer with either of the * obsoleted vertex/index ioctls. @@ -350,8 +347,8 @@ unsigned int last_dispatch; unsigned int last_clear; - drm_radeon_tex_region_t tex_list[RADEON_NR_TEX_HEAPS][RADEON_NR_TEX_REGIONS+1]; - int tex_age[RADEON_NR_TEX_HEAPS]; + drm_tex_region_t tex_list[RADEON_NR_TEX_HEAPS][RADEON_NR_TEX_REGIONS+1]; + unsigned int tex_age[RADEON_NR_TEX_HEAPS]; int ctx_owner; int pfState; /* number of 3d windows (0,1,2ormore) */ int pfCurrentPage; /* which buffer is being displayed? */ @@ -391,17 +388,19 @@ #define DRM_IOCTL_RADEON_INIT_HEAP DRM_IOW( 0x55, drm_radeon_mem_init_heap_t) #define DRM_IOCTL_RADEON_IRQ_EMIT DRM_IOWR( 0x56, drm_radeon_irq_emit_t) #define DRM_IOCTL_RADEON_IRQ_WAIT DRM_IOW( 0x57, drm_radeon_irq_wait_t) +/* added by Charl P. Botha - see radeon_cp.c for details */ +#define DRM_IOCTL_RADEON_CP_RESUME DRM_IO(0x58) typedef struct drm_radeon_init { enum { RADEON_INIT_CP = 0x01, RADEON_CLEANUP_CP = 0x02, - RADEON_INIT_R200_CP = 0x03, + RADEON_INIT_R200_CP = 0x03 } func; unsigned long sarea_priv_offset; int is_pci; int cp_mode; - int agp_size; + int gart_size; int ring_size; int usec_timeout; @@ -416,7 +415,7 @@ unsigned long ring_offset; unsigned long ring_rptr_offset; unsigned long buffers_offset; - unsigned long agp_textures_offset; + unsigned long gart_textures_offset; } drm_radeon_init_t; typedef struct drm_radeon_cp_stop { @@ -526,12 +525,18 @@ /* 1.3: An ioctl to get parameters that aren't available to the 3d * client any other way. */ -#define RADEON_PARAM_AGP_BUFFER_OFFSET 1 /* card offset of 1st agp buffer */ +#define RADEON_PARAM_GART_BUFFER_OFFSET 1 /* card offset of 1st GART buffer */ #define RADEON_PARAM_LAST_FRAME 2 #define RADEON_PARAM_LAST_DISPATCH 3 #define RADEON_PARAM_LAST_CLEAR 4 +/* Added with DRM version 1.6. */ #define RADEON_PARAM_IRQ_NR 5 -#define RADEON_PARAM_AGP_BASE 6 /* card offset of agp base */ +#define RADEON_PARAM_GART_BASE 6 /* card offset of GART base */ +/* Added with DRM version 1.8. */ +#define RADEON_PARAM_REGISTER_HANDLE 7 /* for drmMap() */ +#define RADEON_PARAM_STATUS_HANDLE 8 +#define RADEON_PARAM_SAREA_HANDLE 9 +#define RADEON_PARAM_GART_TEX_HANDLE 10 typedef struct drm_radeon_getparam { int param; @@ -540,14 +545,14 @@ /* 1.6: Set up a memory manager for regions of shared memory: */ -#define RADEON_MEM_REGION_AGP 1 -#define RADEON_MEM_REGION_FB 2 +#define RADEON_MEM_REGION_GART 1 +#define RADEON_MEM_REGION_FB 2 typedef struct drm_radeon_mem_alloc { int region; int alignment; int size; - int *region_offset; /* offset from start of fb or agp */ + int *region_offset; /* offset from start of fb or GART */ } drm_radeon_mem_alloc_t; typedef struct drm_radeon_mem_free { diff -urN linux-2.4.23-pre8/drivers/char/drm/radeon_drv.c linux-2.4.23-pre8-pac1/drivers/char/drm/radeon_drv.c --- linux-2.4.23-pre8/drivers/char/drm/radeon_drv.c 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/radeon_drv.c 2003-08-18 12:56:12.000000000 +0200 @@ -1,6 +1,11 @@ -/* radeon_drv.c -- ATI Radeon driver -*- linux-c -*- - * Created: Wed Feb 14 17:10:04 2001 by gareth@valinux.com +/** + * \file radeon_drv.c + * ATI Radeon driver * + * \author Gareth Hughes + */ + +/* * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. * All Rights Reserved. * @@ -22,11 +27,9 @@ * 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: - * Gareth Hughes */ + #include #include "radeon.h" #include "drmP.h" diff -urN linux-2.4.23-pre8/drivers/char/drm/radeon_drv.h linux-2.4.23-pre8-pac1/drivers/char/drm/radeon_drv.h --- linux-2.4.23-pre8/drivers/char/drm/radeon_drv.h 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/radeon_drv.h 2003-10-24 02:50:32.000000000 +0200 @@ -31,8 +31,8 @@ #ifndef __RADEON_DRV_H__ #define __RADEON_DRV_H__ -#define GET_RING_HEAD(ring) readl( (volatile u32 *) (ring)->head ) -#define SET_RING_HEAD(ring,val) writel( (val), (volatile u32 *) (ring)->head ) +#define GET_RING_HEAD(dev_priv) DRM_READ32( (dev_priv)->ring_rptr, 0 ) +#define SET_RING_HEAD(dev_priv,val) DRM_WRITE32( (dev_priv)->ring_rptr, 0, (val) ) typedef struct drm_radeon_freelist { unsigned int age; @@ -47,7 +47,6 @@ int size; int size_l2qw; - volatile u32 *head; u32 tail; u32 tail_mask; int space; @@ -67,16 +66,16 @@ struct mem_block *prev; int start; int size; - int pid; /* 0: free, -1: heap, other: real pids */ + DRMFILE filp; /* 0: free, -1: heap, other: real files */ }; typedef struct drm_radeon_private { drm_radeon_ring_buffer_t ring; drm_radeon_sarea_t *sarea_priv; - int agp_size; - u32 agp_vm_start; - unsigned long agp_buffers_offset; + int gart_size; + u32 gart_vm_start; + unsigned long gart_buffers_offset; int cp_mode; int cp_running; @@ -125,16 +124,24 @@ u32 depth_pitch_offset; drm_radeon_depth_clear_t depth_clear; + + unsigned long fb_base; + unsigned long fb_offset; + unsigned long mmio_offset; + unsigned long ring_offset; + unsigned long ring_rptr_offset; + unsigned long buffers_offset; + unsigned long gart_textures_offset; + + drm_local_map_t *sarea; + drm_local_map_t *fb; + drm_local_map_t *mmio; + drm_local_map_t *cp_ring; + drm_local_map_t *ring_rptr; + drm_local_map_t *buffers; + drm_local_map_t *gart_textures; - drm_map_t *sarea; - drm_map_t *fb; - drm_map_t *mmio; - drm_map_t *cp_ring; - drm_map_t *ring_rptr; - drm_map_t *buffers; - drm_map_t *agp_textures; - - struct mem_block *agp_heap; + struct mem_block *gart_heap; struct mem_block *fb_heap; /* SW interrupt */ @@ -148,22 +155,15 @@ } drm_radeon_buf_priv_t; /* radeon_cp.c */ -extern int radeon_cp_init( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int radeon_cp_start( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int radeon_cp_stop( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int radeon_cp_reset( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int radeon_cp_idle( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int radeon_engine_reset( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int radeon_fullscreen( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int radeon_cp_buffers( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); +extern int radeon_cp_init( DRM_IOCTL_ARGS ); +extern int radeon_cp_start( DRM_IOCTL_ARGS ); +extern int radeon_cp_stop( DRM_IOCTL_ARGS ); +extern int radeon_cp_reset( DRM_IOCTL_ARGS ); +extern int radeon_cp_idle( DRM_IOCTL_ARGS ); +extern int radeon_cp_resume( DRM_IOCTL_ARGS ); +extern int radeon_engine_reset( DRM_IOCTL_ARGS ); +extern int radeon_fullscreen( DRM_IOCTL_ARGS ); +extern int radeon_cp_buffers( DRM_IOCTL_ARGS ); extern void radeon_freelist_reset( drm_device_t *dev ); extern drm_buf_t *radeon_freelist_get( drm_device_t *dev ); @@ -175,39 +175,33 @@ extern int radeon_do_cleanup_pageflip( drm_device_t *dev ); /* radeon_state.c */ -extern int radeon_cp_clear( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int radeon_cp_swap( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int radeon_cp_vertex( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int radeon_cp_indices( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int radeon_cp_texture( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int radeon_cp_stipple( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int radeon_cp_indirect( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ); -extern int radeon_cp_vertex2(struct inode *inode, struct file *filp,unsigned int cmd, unsigned long arg ); -extern int radeon_cp_cmdbuf(struct inode *inode, struct file *filp,unsigned int cmd, unsigned long arg ); -extern int radeon_cp_getparam(struct inode *inode, struct file *filp,unsigned int cmd, unsigned long arg ); -extern int radeon_cp_flip(struct inode *inode, struct file *filp,unsigned int cmd, unsigned long arg ); - -extern int radeon_mem_alloc(struct inode *inode, struct file *filp,unsigned int cmd, unsigned long arg ); -extern int radeon_mem_free(struct inode *inode, struct file *filp,unsigned int cmd, unsigned long arg ); -extern int radeon_mem_init_heap(struct inode *inode, struct file *filp,unsigned int cmd, unsigned long arg ); +extern int radeon_cp_clear( DRM_IOCTL_ARGS ); +extern int radeon_cp_swap( DRM_IOCTL_ARGS ); +extern int radeon_cp_vertex( DRM_IOCTL_ARGS ); +extern int radeon_cp_indices( DRM_IOCTL_ARGS ); +extern int radeon_cp_texture( DRM_IOCTL_ARGS ); +extern int radeon_cp_stipple( DRM_IOCTL_ARGS ); +extern int radeon_cp_indirect( DRM_IOCTL_ARGS ); +extern int radeon_cp_vertex2( DRM_IOCTL_ARGS ); +extern int radeon_cp_cmdbuf( DRM_IOCTL_ARGS ); +extern int radeon_cp_getparam( DRM_IOCTL_ARGS ); +extern int radeon_cp_flip( DRM_IOCTL_ARGS ); + +extern int radeon_mem_alloc( DRM_IOCTL_ARGS ); +extern int radeon_mem_free( DRM_IOCTL_ARGS ); +extern int radeon_mem_init_heap( DRM_IOCTL_ARGS ); extern void radeon_mem_takedown( struct mem_block **heap ); -extern void radeon_mem_release( struct mem_block *heap ); +extern void radeon_mem_release( DRMFILE filp, struct mem_block *heap ); /* radeon_irq.c */ -extern int radeon_irq_emit(struct inode *inode, struct file *filp,unsigned int cmd, unsigned long arg ); -extern int radeon_irq_wait(struct inode *inode, struct file *filp,unsigned int cmd, unsigned long arg ); +extern int radeon_irq_emit( DRM_IOCTL_ARGS ); +extern int radeon_irq_wait( DRM_IOCTL_ARGS ); extern int radeon_emit_and_wait_irq(drm_device_t *dev); extern int radeon_wait_irq(drm_device_t *dev, int swi_nr); extern int radeon_emit_irq(drm_device_t *dev); +extern void radeon_do_release(drm_device_t *dev); /* Flags for stats.boxes */ @@ -281,8 +275,10 @@ #define RADEON_SCRATCH_UMSK 0x0770 #define RADEON_SCRATCH_ADDR 0x0774 +#define RADEON_SCRATCHOFF( x ) (RADEON_SCRATCH_REG_OFFSET + 4*(x)) + #define GET_SCRATCH( x ) (dev_priv->writeback_works \ - ? readl( &dev_priv->scratch[(x)] ) \ + ? DRM_READ32( dev_priv->ring_rptr, RADEON_SCRATCHOFF(x) ) \ : RADEON_READ( RADEON_SCRATCH_REG0 + 4*(x) ) ) @@ -587,6 +583,7 @@ #define RADEON_TXFORMAT_ARGB4444 5 #define RADEON_TXFORMAT_ARGB8888 6 #define RADEON_TXFORMAT_RGBA8888 7 +#define RADEON_TXFORMAT_Y8 8 #define RADEON_TXFORMAT_VYUY422 10 #define RADEON_TXFORMAT_YVYU422 11 #define RADEON_TXFORMAT_DXT1 12 @@ -673,6 +670,10 @@ #define R200_RE_POINTSIZE 0x2648 #define R200_SE_TCL_INPUT_VTX_VECTOR_ADDR_0 0x2254 +#define RADEON_PP_TEX_SIZE_0 0x1d04 /* NPOT */ +#define RADEON_PP_TEX_SIZE_1 0x1d0c +#define RADEON_PP_TEX_SIZE_2 0x1d14 + #define SE_VAP_CNTL__TCL_ENA_MASK 0x00000001 #define SE_VAP_CNTL__FORCE_W_TO_ONE_MASK 0x00010000 @@ -701,15 +702,10 @@ #define RADEON_RING_HIGH_MARK 128 - -#define RADEON_BASE(reg) ((unsigned long)(dev_priv->mmio->handle)) -#define RADEON_ADDR(reg) (RADEON_BASE( reg ) + reg) - -#define RADEON_READ(reg) readl( (volatile u32 *) RADEON_ADDR(reg) ) -#define RADEON_WRITE(reg,val) writel( (val), (volatile u32 *) RADEON_ADDR(reg)) - -#define RADEON_READ8(reg) readb( (volatile u8 *) RADEON_ADDR(reg) ) -#define RADEON_WRITE8(reg,val) writeb( (val), (volatile u8 *) RADEON_ADDR(reg)) +#define RADEON_READ(reg) DRM_READ32( dev_priv->mmio, (reg) ) +#define RADEON_WRITE(reg,val) DRM_WRITE32( dev_priv->mmio, (reg), (val) ) +#define RADEON_READ8(reg) DRM_READ8( dev_priv->mmio, (reg) ) +#define RADEON_WRITE8(reg,val) DRM_WRITE8( dev_priv->mmio, (reg), (val) ) #define RADEON_WRITE_PLL( addr, val ) \ do { \ @@ -786,23 +782,12 @@ * Misc helper macros */ -#define LOCK_TEST_WITH_RETURN( dev ) \ -do { \ - if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || \ - dev->lock.pid != current->pid ) { \ - DRM_ERROR( "%s called without lock held\n", \ - __FUNCTION__ ); \ - return -EINVAL; \ - } \ -} while (0) - - /* Perfbox functionality only. */ #define RING_SPACE_TEST_WITH_RETURN( dev_priv ) \ do { \ if (!(dev_priv->stats.boxes & RADEON_BOX_DMA_IDLE)) { \ - u32 head = GET_RING_HEAD(&dev_priv->ring); \ + u32 head = GET_RING_HEAD( dev_priv ); \ if (head == dev_priv->ring.tail) \ dev_priv->stats.boxes |= RADEON_BOX_DMA_IDLE; \ } \ @@ -839,14 +824,6 @@ * Ring control */ -#if defined(__powerpc__) -#define radeon_flush_write_combine() (void) GET_RING_HEAD( &dev_priv->ring ) -#else -#define radeon_flush_write_combine() wmb() -#warning PCI posting bug -#endif - - #define RADEON_VERBOSE 0 #define RING_LOCALS int write, _nr; unsigned int mask; u32 *ring; @@ -880,11 +857,11 @@ dev_priv->ring.tail = write; \ } while (0) -#define COMMIT_RING() do { \ +#define COMMIT_RING() do { \ /* Flush writes to ring */ \ - rmb(); \ - GET_RING_HEAD( &dev_priv->ring ); \ - RADEON_WRITE( RADEON_CP_RB_WPTR, dev_priv->ring.tail ); \ + DRM_MEMORYBARRIER(); \ + GET_RING_HEAD( dev_priv ); \ + RADEON_WRITE( RADEON_CP_RB_WPTR, dev_priv->ring.tail ); \ /* read from PCI bus to ensure correct posting */ \ RADEON_READ( RADEON_CP_RB_RPTR ); \ } while (0) @@ -910,17 +887,17 @@ \ if (write + _size > mask) { \ int i = (mask+1) - write; \ - if (__copy_from_user( (int *)(ring+write), \ + if (DRM_COPY_FROM_USER_UNCHECKED( (int *)(ring+write), \ _tab, i*4 )) \ - return -EFAULT; \ + return DRM_ERR(EFAULT); \ write = 0; \ _size -= i; \ _tab += i; \ } \ \ - if (_size && __copy_from_user( (int *)(ring+write), \ + if (_size && DRM_COPY_FROM_USER_UNCHECKED( (int *)(ring+write), \ _tab, _size*4 )) \ - return -EFAULT; \ + return DRM_ERR(EFAULT); \ \ write += _size; \ write &= mask; \ diff -urN linux-2.4.23-pre8/drivers/char/drm/radeon_irq.c linux-2.4.23-pre8-pac1/drivers/char/drm/radeon_irq.c --- linux-2.4.23-pre8/drivers/char/drm/radeon_irq.c 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/radeon_irq.c 2003-08-18 12:56:13.000000000 +0200 @@ -35,7 +35,6 @@ #include "drm.h" #include "radeon_drm.h" #include "radeon_drv.h" -#include "drm_os_linux.h" /* Interrupts - Used for device synchronization and flushing in the * following circumstances: @@ -55,34 +54,36 @@ * tied to dma at all, this is just a hangover from dri prehistory. */ -void DRM(dma_service)(int irq, void *arg, struct pt_regs *reg) +irqreturn_t DRM(dma_service)( DRM_IRQ_ARGS ) { drm_device_t *dev = (drm_device_t *) arg; drm_radeon_private_t *dev_priv = (drm_radeon_private_t *)dev->dev_private; u32 stat; - stat = RADEON_READ(RADEON_GEN_INT_STATUS) - & (RADEON_SW_INT_TEST | RADEON_CRTC_VBLANK_STAT); + /* Only consider the bits we're interested in - others could be used + * outside the DRM + */ + stat = RADEON_READ(RADEON_GEN_INT_STATUS) + & (RADEON_SW_INT_TEST | RADEON_CRTC_VBLANK_STAT); if (!stat) - return; + return IRQ_NONE; /* SW interrupt */ if (stat & RADEON_SW_INT_TEST) { - wake_up_interruptible( &dev_priv->swi_queue ); + DRM_WAKEUP( &dev_priv->swi_queue ); } /* VBLANK interrupt */ if (stat & RADEON_CRTC_VBLANK_STAT) { atomic_inc(&dev->vbl_received); - wake_up_interruptible(&dev->vbl_queue); - DRM(vbl_send_signals)(dev); + DRM_WAKEUP(&dev->vbl_queue); + DRM(vbl_send_signals)( dev ); } - /* Acknowledge all the bits in GEN_INT_STATUS -- seem to get - * more than we asked for... - */ + /* Acknowledge interrupts we handle */ RADEON_WRITE(RADEON_GEN_INT_STATUS, stat); + return IRQ_HANDLED; } static __inline__ void radeon_acknowledge_irqs(drm_radeon_private_t *dev_priv) @@ -128,7 +129,7 @@ */ radeon_acknowledge_irqs( dev_priv ); - DRM_WAIT_ON( ret, dev_priv->swi_queue, 3 * HZ, + DRM_WAIT_ON( ret, dev_priv->swi_queue, 3 * DRM_HZ, RADEON_READ( RADEON_LAST_SWI_REG ) >= swi_nr ); return ret; @@ -149,7 +150,7 @@ if ( !dev_priv ) { DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); - return -EINVAL; + return DRM_ERR(EINVAL); } radeon_acknowledge_irqs( dev_priv ); @@ -160,7 +161,7 @@ * by about a day rather than she wants to wait for years * using vertical blanks... */ - DRM_WAIT_ON( ret, dev->vbl_queue, 3*HZ, + DRM_WAIT_ON( ret, dev->vbl_queue, 3*DRM_HZ, ( ( ( cur_vblank = atomic_read(&dev->vbl_received ) ) - *sequence ) <= (1<<23) ) ); @@ -172,19 +173,18 @@ /* Needs the lock as it touches the ring. */ -int radeon_irq_emit(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long data) +int radeon_irq_emit( DRM_IOCTL_ARGS ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; + DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; drm_radeon_irq_emit_t emit; int result; - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); if ( !dev_priv ) { DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); - return -EINVAL; + return DRM_ERR(EINVAL); } DRM_COPY_FROM_USER_IOCTL( emit, (drm_radeon_irq_emit_t *)data, @@ -192,9 +192,9 @@ result = radeon_emit_irq( dev ); - if ( copy_to_user( emit.irq_seq, &result, sizeof(int) ) ) { + if ( DRM_COPY_TO_USER( emit.irq_seq, &result, sizeof(int) ) ) { DRM_ERROR( "copy_to_user\n" ); - return -EFAULT; + return DRM_ERR(EFAULT); } return 0; @@ -203,16 +203,15 @@ /* Doesn't need the hardware lock. */ -int radeon_irq_wait(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long data) +int radeon_irq_wait( DRM_IOCTL_ARGS ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; + DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; drm_radeon_irq_wait_t irqwait; if ( !dev_priv ) { DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); - return -EINVAL; + return DRM_ERR(EINVAL); } DRM_COPY_FROM_USER_IOCTL( irqwait, (drm_radeon_irq_wait_t *)data, @@ -240,7 +239,7 @@ (drm_radeon_private_t *)dev->dev_private; atomic_set(&dev_priv->swi_emitted, 0); - init_waitqueue_head( &dev_priv->swi_queue ); + DRM_INIT_WAITQUEUE( &dev_priv->swi_queue ); /* Turn on SW and VBL ints */ RADEON_WRITE( RADEON_GEN_INT_CNTL, @@ -251,8 +250,9 @@ void DRM(driver_irq_uninstall)( drm_device_t *dev ) { drm_radeon_private_t *dev_priv = (drm_radeon_private_t *)dev->dev_private; - if ( dev_priv ) { - /* Disable *all* interrupts */ - RADEON_WRITE( RADEON_GEN_INT_CNTL, 0 ); - } + if (!dev_priv) + return; + + /* Disable *all* interrupts */ + RADEON_WRITE( RADEON_GEN_INT_CNTL, 0 ); } diff -urN linux-2.4.23-pre8/drivers/char/drm/radeon_mem.c linux-2.4.23-pre8-pac1/drivers/char/drm/radeon_mem.c --- linux-2.4.23-pre8/drivers/char/drm/radeon_mem.c 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/radeon_mem.c 2003-10-11 23:18:12.000000000 +0200 @@ -1,4 +1,4 @@ -/* radeon_mem.c -- Simple agp/fb memory manager for radeon -*- linux-c -*- +/* radeon_mem.c -- Simple GART/fb memory manager for radeon -*- linux-c -*- * * Copyright (C) The Weather Channel, Inc. 2002. All Rights Reserved. * @@ -34,23 +34,22 @@ #include "drm.h" #include "radeon_drm.h" #include "radeon_drv.h" -#include "drm_os_linux.h" -/* Very simple allocator for agp memory, working on a static range +/* Very simple allocator for GART memory, working on a static range * already mapped into each client's address space. */ static struct mem_block *split_block(struct mem_block *p, int start, int size, - int pid ) + DRMFILE filp ) { /* Maybe cut off the start of an existing block */ if (start > p->start) { - struct mem_block *newblock = kmalloc(sizeof(*newblock), GFP_KERNEL); + struct mem_block *newblock = DRM_MALLOC(sizeof(*newblock)); if (!newblock) goto out; newblock->start = start; newblock->size = p->size - (start - p->start); - newblock->pid = 0; + newblock->filp = 0; newblock->next = p->next; newblock->prev = p; p->next->prev = newblock; @@ -61,12 +60,12 @@ /* Maybe cut off the end of an existing block */ if (size < p->size) { - struct mem_block *newblock = kmalloc(sizeof(*newblock), GFP_KERNEL); + struct mem_block *newblock = DRM_MALLOC(sizeof(*newblock)); if (!newblock) goto out; newblock->start = start + size; newblock->size = p->size - size; - newblock->pid = 0; + newblock->filp = 0; newblock->next = p->next; newblock->prev = p; p->next->prev = newblock; @@ -76,20 +75,20 @@ out: /* Our block is in the middle */ - p->pid = pid; + p->filp = filp; return p; } static struct mem_block *alloc_block( struct mem_block *heap, int size, - int align2, int pid ) + int align2, DRMFILE filp ) { struct mem_block *p; int mask = (1 << align2)-1; for (p = heap->next ; p != heap ; p = p->next) { int start = (p->start + mask) & ~mask; - if (p->pid == 0 && start + size <= p->start + p->size) - return split_block( p, start, size, pid ); + if (p->filp == 0 && start + size <= p->start + p->size) + return split_block( p, start, size, filp ); } return NULL; @@ -109,90 +108,79 @@ static void free_block( struct mem_block *p ) { - p->pid = 0; + p->filp = 0; - /* Assumes a single contiguous range. Needs a special pid in + /* Assumes a single contiguous range. Needs a special filp in * 'heap' to stop it being subsumed. */ - if (p->next->pid == 0) { + if (p->next->filp == 0) { struct mem_block *q = p->next; p->size += q->size; p->next = q->next; p->next->prev = p; - kfree(q); + DRM_FREE(q, sizeof(*q)); } - if (p->prev->pid == 0) { + if (p->prev->filp == 0) { struct mem_block *q = p->prev; q->size += p->size; q->next = p->next; q->next->prev = q; - kfree(p); + DRM_FREE(p, sizeof(*q)); } } -static void print_heap( struct mem_block *heap ) -{ - struct mem_block *p; - - for (p = heap->next ; p != heap ; p = p->next) - DRM_DEBUG("0x%x..0x%x (0x%x) -- owner %d\n", - p->start, p->start + p->size, - p->size, p->pid); -} - /* Initialize. How to check for an uninitialized heap? */ static int init_heap(struct mem_block **heap, int start, int size) { - struct mem_block *blocks = kmalloc(sizeof(*blocks), GFP_KERNEL); + struct mem_block *blocks = DRM_MALLOC(sizeof(*blocks)); if (!blocks) return -ENOMEM; - *heap = kmalloc(sizeof(**heap), GFP_KERNEL); + *heap = DRM_MALLOC(sizeof(**heap)); if (!*heap) { - kfree( blocks ); + DRM_FREE( blocks, sizeof(*blocks) ); return -ENOMEM; } blocks->start = start; blocks->size = size; - blocks->pid = 0; + blocks->filp = 0; blocks->next = blocks->prev = *heap; memset( *heap, 0, sizeof(**heap) ); - (*heap)->pid = -1; + (*heap)->filp = (DRMFILE) -1; (*heap)->next = (*heap)->prev = blocks; return 0; } -/* Free all blocks associated with the releasing pid. +/* Free all blocks associated with the releasing file. */ -void radeon_mem_release( struct mem_block *heap ) +void radeon_mem_release( DRMFILE filp, struct mem_block *heap ) { - int pid = current->pid; struct mem_block *p; if (!heap || !heap->next) return; for (p = heap->next ; p != heap ; p = p->next) { - if (p->pid == pid) - p->pid = 0; + if (p->filp == filp) + p->filp = 0; } - /* Assumes a single contiguous range. Needs a special pid in + /* Assumes a single contiguous range. Needs a special filp in * 'heap' to stop it being subsumed. */ for (p = heap->next ; p != heap ; p = p->next) { - while (p->pid == 0 && p->next->pid == 0) { + while (p->filp == 0 && p->next->filp == 0) { struct mem_block *q = p->next; p->size += q->size; p->next = q->next; p->next->prev = p; - kfree(q); + DRM_FREE(q, sizeof(*q)); } } } @@ -209,10 +197,10 @@ for (p = (*heap)->next ; p != *heap ; ) { struct mem_block *q = p; p = p->next; - kfree(q); + DRM_FREE(q, sizeof(*q)); } - kfree( *heap ); + DRM_FREE( *heap, sizeof(**heap) ); *heap = 0; } @@ -224,8 +212,8 @@ int region ) { switch( region ) { - case RADEON_MEM_REGION_AGP: - return &dev_priv->agp_heap; + case RADEON_MEM_REGION_GART: + return &dev_priv->gart_heap; case RADEON_MEM_REGION_FB: return &dev_priv->fb_heap; default: @@ -233,17 +221,16 @@ } } -int radeon_mem_alloc(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long data ) +int radeon_mem_alloc( DRM_IOCTL_ARGS ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; - drm_radeon_private_t *dev_priv = dev->dev_private; + DRM_DEVICE; + drm_radeon_private_t *dev_priv = dev->dev_private; drm_radeon_mem_alloc_t alloc; struct mem_block *block, **heap; if ( !dev_priv ) { DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); - return -EINVAL; + return DRM_ERR(EINVAL); } DRM_COPY_FROM_USER_IOCTL( alloc, (drm_radeon_mem_alloc_t *)data, @@ -251,7 +238,7 @@ heap = get_heap( dev_priv, alloc.region ); if (!heap || !*heap) - return -EFAULT; + return DRM_ERR(EFAULT); /* Make things easier on ourselves: all allocations at least * 4k aligned. @@ -260,15 +247,15 @@ alloc.alignment = 12; block = alloc_block( *heap, alloc.size, alloc.alignment, - current->pid ); + filp ); if (!block) - return -ENOMEM; + return DRM_ERR(ENOMEM); - if ( copy_to_user( alloc.region_offset, &block->start, + if ( DRM_COPY_TO_USER( alloc.region_offset, &block->start, sizeof(int) ) ) { DRM_ERROR( "copy_to_user\n" ); - return -EFAULT; + return DRM_ERR(EFAULT); } return 0; @@ -276,17 +263,16 @@ -int radeon_mem_free(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long data) +int radeon_mem_free( DRM_IOCTL_ARGS ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; + DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; drm_radeon_mem_free_t memfree; struct mem_block *block, **heap; if ( !dev_priv ) { DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); - return -EINVAL; + return DRM_ERR(EINVAL); } DRM_COPY_FROM_USER_IOCTL( memfree, (drm_radeon_mem_free_t *)data, @@ -294,30 +280,29 @@ heap = get_heap( dev_priv, memfree.region ); if (!heap || !*heap) - return -EFAULT; + return DRM_ERR(EFAULT); block = find_block( *heap, memfree.region_offset ); if (!block) - return -EFAULT; + return DRM_ERR(EFAULT); - if (block->pid != current->pid) - return -EPERM; + if (block->filp != filp) + return DRM_ERR(EPERM); free_block( block ); return 0; } -int radeon_mem_init_heap(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long data) +int radeon_mem_init_heap( DRM_IOCTL_ARGS ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; + DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; drm_radeon_mem_init_heap_t initheap; struct mem_block **heap; if ( !dev_priv ) { DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); - return -EINVAL; + return DRM_ERR(EINVAL); } DRM_COPY_FROM_USER_IOCTL( initheap, (drm_radeon_mem_init_heap_t *)data, @@ -325,11 +310,11 @@ heap = get_heap( dev_priv, initheap.region ); if (!heap) - return -EFAULT; + return DRM_ERR(EFAULT); if (*heap) { DRM_ERROR("heap already initialized?"); - return -EFAULT; + return DRM_ERR(EFAULT); } return init_heap( heap, initheap.start, initheap.size ); diff -urN linux-2.4.23-pre8/drivers/char/drm/radeon_state.c linux-2.4.23-pre8-pac1/drivers/char/drm/radeon_state.c --- linux-2.4.23-pre8/drivers/char/drm/radeon_state.c 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/radeon_state.c 2003-10-24 02:50:32.000000000 +0200 @@ -33,13 +33,13 @@ #include "drm_sarea.h" #include "radeon_drm.h" #include "radeon_drv.h" -#include "drm_os_linux.h" + /* ================================================================ * CP hardware state programming functions */ -static inline void radeon_emit_clip_rect( drm_radeon_private_t *dev_priv, +static __inline__ void radeon_emit_clip_rect( drm_radeon_private_t *dev_priv, drm_clip_rect_t *box ) { RING_LOCALS; @@ -153,7 +153,7 @@ OUT_RING( CP_PACKET0( RADEON_PP_TXFILTER_0, 5 ) ); OUT_RING( tex[0].pp_txfilter ); OUT_RING( tex[0].pp_txformat ); - OUT_RING( tex[0].pp_txoffset ); + OUT_RING( tex[0].pp_txoffset + dev_priv->fb_base); OUT_RING( tex[0].pp_txcblend ); OUT_RING( tex[0].pp_txablend ); OUT_RING( tex[0].pp_tfactor ); @@ -167,7 +167,7 @@ OUT_RING( CP_PACKET0( RADEON_PP_TXFILTER_1, 5 ) ); OUT_RING( tex[1].pp_txfilter ); OUT_RING( tex[1].pp_txformat ); - OUT_RING( tex[1].pp_txoffset ); + OUT_RING( tex[1].pp_txoffset + dev_priv->fb_base); OUT_RING( tex[1].pp_txcblend ); OUT_RING( tex[1].pp_txablend ); OUT_RING( tex[1].pp_tfactor ); @@ -181,7 +181,7 @@ OUT_RING( CP_PACKET0( RADEON_PP_TXFILTER_2, 5 ) ); OUT_RING( tex[2].pp_txfilter ); OUT_RING( tex[2].pp_txformat ); - OUT_RING( tex[2].pp_txoffset ); + OUT_RING( tex[2].pp_txoffset + dev_priv->fb_base); OUT_RING( tex[2].pp_txcblend ); OUT_RING( tex[2].pp_txablend ); OUT_RING( tex[2].pp_tfactor ); @@ -292,6 +292,9 @@ { R200_PP_CUBIC_OFFSET_F1_4, 5, "R200_PP_CUBIC_OFFSET_F1_4" }, { R200_PP_CUBIC_FACES_5, 1, "R200_PP_CUBIC_FACES_5" }, { R200_PP_CUBIC_OFFSET_F1_5, 5, "R200_PP_CUBIC_OFFSET_F1_5" }, + { RADEON_PP_TEX_SIZE_0, 2, "RADEON_PP_TEX_SIZE_0" }, + { RADEON_PP_TEX_SIZE_1, 2, "RADEON_PP_TEX_SIZE_1" }, + { RADEON_PP_TEX_SIZE_2, 2, "RADEON_PP_TEX_SIZE_1" }, }; @@ -885,15 +888,14 @@ static void radeon_cp_dispatch_vertex( drm_device_t *dev, drm_buf_t *buf, - drm_radeon_tcl_prim_t *prim, - drm_clip_rect_t *boxes, - int nbox ) + drm_radeon_tcl_prim_t *prim ) { drm_radeon_private_t *dev_priv = dev->dev_private; - drm_clip_rect_t box; - int offset = dev_priv->agp_buffers_offset + buf->offset + prim->start; + drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; + int offset = dev_priv->gart_buffers_offset + buf->offset + prim->start; int numverts = (int)prim->numverts; + int nbox = sarea_priv->nbox; int i = 0; RING_LOCALS; @@ -913,10 +915,8 @@ do { /* Emit the next cliprect */ if ( i < nbox ) { - if (__copy_from_user( &box, &boxes[i], sizeof(box) )) - return; - - radeon_emit_clip_rect( dev_priv, &box ); + radeon_emit_clip_rect( dev_priv, + &sarea_priv->boxes[i] ); } /* Emit the vertex buffer rendering commands */ @@ -932,7 +932,6 @@ (numverts << RADEON_NUM_VERTICES_SHIFT) ); ADVANCE_RING(); - i++; } while ( i < nbox ); } @@ -966,7 +965,7 @@ buf->idx, start, end ); if ( start != end ) { - int offset = (dev_priv->agp_buffers_offset + int offset = (dev_priv->gart_buffers_offset + buf->offset + start); int dwords = (end - start + 3) / sizeof(u32); @@ -995,26 +994,17 @@ static void radeon_cp_dispatch_indices( drm_device_t *dev, drm_buf_t *elt_buf, - drm_radeon_tcl_prim_t *prim, - drm_clip_rect_t *boxes, - int nbox ) + drm_radeon_tcl_prim_t *prim ) { drm_radeon_private_t *dev_priv = dev->dev_private; - drm_clip_rect_t box; - int offset = dev_priv->agp_buffers_offset + prim->offset; + drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; + int offset = dev_priv->gart_buffers_offset + prim->offset; u32 *data; int dwords; int i = 0; int start = prim->start + RADEON_INDEX_PRIM_OFFSET; int count = (prim->finish - start) / sizeof(u16); - - DRM_DEBUG("hwprim 0x%x vfmt 0x%x %d..%d offset: %x nr %d\n", - prim->prim, - prim->vc_format, - prim->start, - prim->finish, - prim->offset, - prim->numverts); + int nbox = sarea_priv->nbox; if (bad_prim_vertex_nr( prim->prim, count )) { DRM_ERROR( "bad prim %x count %d\n", @@ -1045,12 +1035,9 @@ (count << RADEON_NUM_VERTICES_SHIFT) ); do { - if ( i < nbox ) { - if (__copy_from_user( &box, &boxes[i], sizeof(box) )) - return; - - radeon_emit_clip_rect( dev_priv, &box ); - } + if ( i < nbox ) + radeon_emit_clip_rect( dev_priv, + &sarea_priv->boxes[i] ); radeon_cp_dispatch_indirect( dev, elt_buf, prim->start, @@ -1063,7 +1050,8 @@ #define RADEON_MAX_TEXTURE_SIZE (RADEON_BUFFER_SIZE - 8 * sizeof(u32)) -static int radeon_cp_dispatch_texture( drm_device_t *dev, +static int radeon_cp_dispatch_texture( DRMFILE filp, + drm_device_t *dev, drm_radeon_texture_t *tex, drm_radeon_tex_image_t *image ) { @@ -1128,7 +1116,7 @@ break; default: DRM_ERROR( "invalid texture format %d\n", tex->format ); - return -EINVAL; + return DRM_ERR(EINVAL); } DRM_DEBUG("tex=%dx%d blit=%d\n", tex_width, tex->height, blit_width ); @@ -1140,17 +1128,17 @@ /* Make a copy of some parameters in case we have to * update them for a multi-pass texture blit. - */ - height = image->height; - data = (const u8 *)image->data; - - size = height * blit_width; - - if ( size > RADEON_MAX_TEXTURE_SIZE ) { - height = RADEON_MAX_TEXTURE_SIZE / blit_width; + */ + height = image->height; + data = (const u8 *)image->data; + size = height * blit_width; - } else if ( size < 4 && size > 0 ) { - size = 4; + + if ( size > RADEON_MAX_TEXTURE_SIZE ) { + height = RADEON_MAX_TEXTURE_SIZE / blit_width; + size = height * blit_width; + } else if ( size < 4 && size > 0 ) { + size = 4; } else if ( size == 0 ) { return 0; } @@ -1162,63 +1150,65 @@ } if ( !buf ) { DRM_DEBUG("radeon_cp_dispatch_texture: EAGAIN\n"); - copy_to_user( tex->image, image, sizeof(*image) ); - return -EAGAIN; - } + DRM_COPY_TO_USER( tex->image, image, sizeof(*image) ); + return DRM_ERR(EAGAIN); + } - /* Dispatch the indirect buffer. - */ + /* Dispatch the indirect buffer. + */ buffer = (u32*)((char*)dev_priv->buffers->handle + buf->offset); dwords = size / 4; - buffer[0] = CP_PACKET3( RADEON_CNTL_HOSTDATA_BLT, dwords + 6 ); - buffer[1] = (RADEON_GMC_DST_PITCH_OFFSET_CNTL | - RADEON_GMC_BRUSH_NONE | - (format << 8) | - RADEON_GMC_SRC_DATATYPE_COLOR | - RADEON_ROP3_S | - RADEON_DP_SRC_SOURCE_HOST_DATA | - RADEON_GMC_CLR_CMP_CNTL_DIS | - RADEON_GMC_WR_MSK_DIS); - - buffer[2] = (tex->pitch << 22) | (tex->offset >> 10); - buffer[3] = 0xffffffff; - buffer[4] = 0xffffffff; - buffer[5] = (image->y << 16) | image->x; - buffer[6] = (height << 16) | image->width; - buffer[7] = dwords; - - buffer += 8; - - if ( tex_width >= 32 ) { - /* Texture image width is larger than the minimum, so we - * can upload it directly. - */ - if ( copy_from_user( buffer, data, dwords * sizeof(u32) ) ) { - DRM_ERROR( "EFAULT on data, %d dwords\n", dwords ); - return -EFAULT; - } - } else { - /* Texture image width is less than the minimum, so we - * need to pad out each image scanline to the minimum - * width. - */ - for ( i = 0 ; i < tex->height ; i++ ) { - if ( copy_from_user( buffer, data, tex_width ) ) { - DRM_ERROR( "EFAULT on pad, %d bytes\n", - tex_width ); - return -EFAULT; + buffer[0] = CP_PACKET3( RADEON_CNTL_HOSTDATA_BLT, dwords + 6 ); + buffer[1] = (RADEON_GMC_DST_PITCH_OFFSET_CNTL | + RADEON_GMC_BRUSH_NONE | + (format << 8) | + RADEON_GMC_SRC_DATATYPE_COLOR | + RADEON_ROP3_S | + RADEON_DP_SRC_SOURCE_HOST_DATA | + RADEON_GMC_CLR_CMP_CNTL_DIS | + RADEON_GMC_WR_MSK_DIS); + + buffer[2] = ((tex->pitch << 22) | + ((tex->offset + dev_priv->fb_base) >> 10)); + buffer[3] = 0xffffffff; + buffer[4] = 0xffffffff; + buffer[5] = (image->y << 16) | image->x; + buffer[6] = (height << 16) | image->width; + buffer[7] = dwords; + buffer += 8; + + if ( tex_width >= 32 ) { + /* Texture image width is larger than the minimum, so we + * can upload it directly. + */ + if ( DRM_COPY_FROM_USER( buffer, data, + dwords * sizeof(u32) ) ) { + DRM_ERROR( "EFAULT on data, %d dwords\n", + dwords ); + return DRM_ERR(EFAULT); + } + } else { + /* Texture image width is less than the minimum, so we + * need to pad out each image scanline to the minimum + * width. + */ + for ( i = 0 ; i < tex->height ; i++ ) { + if ( DRM_COPY_FROM_USER( buffer, data, + tex_width ) ) { + DRM_ERROR( "EFAULT on pad, %d bytes\n", + tex_width ); + return DRM_ERR(EFAULT); + } + buffer += 8; + data += tex_width; } - buffer += 8; - data += tex_width; } - } - buf->pid = current->pid; - buf->used = (dwords + 8) * sizeof(u32); - - radeon_cp_dispatch_indirect( dev, buf, 0, buf->used ); - radeon_cp_discard_buffer( dev, buf ); + buf->filp = filp; + buf->used = (dwords + 8) * sizeof(u32); + radeon_cp_dispatch_indirect( dev, buf, 0, buf->used ); + radeon_cp_discard_buffer( dev, buf ); /* Update the input parameters for next time */ image->y += height; @@ -1263,31 +1253,28 @@ * IOCTL functions */ -int radeon_cp_clear( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) +int radeon_cp_clear( DRM_IOCTL_ARGS ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; + DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_radeon_clear_t clear; drm_radeon_clear_rect_t depth_boxes[RADEON_NR_SAREA_CLIPRECTS]; DRM_DEBUG( "\n" ); - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); - if ( copy_from_user( &clear, (drm_radeon_clear_t *)arg, - sizeof(clear) ) ) - return -EFAULT; + DRM_COPY_FROM_USER_IOCTL( clear, (drm_radeon_clear_t *)data, + sizeof(clear) ); RING_SPACE_TEST_WITH_RETURN( dev_priv ); if ( sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS ) sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS; - if ( copy_from_user( &depth_boxes, clear.depth_boxes, + if ( DRM_COPY_FROM_USER( &depth_boxes, clear.depth_boxes, sarea_priv->nbox * sizeof(depth_boxes[0]) ) ) - return -EFAULT; + return DRM_ERR(EFAULT); radeon_cp_dispatch_clear( dev, &clear, depth_boxes ); @@ -1338,14 +1325,13 @@ /* Swapping and flipping are different operations, need different ioctls. * They can & should be intermixed to support multiple 3d windows. */ -int radeon_cp_flip(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long data ) +int radeon_cp_flip( DRM_IOCTL_ARGS ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; + DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; DRM_DEBUG( "\n" ); - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); RING_SPACE_TEST_WITH_RETURN( dev_priv ); @@ -1358,16 +1344,14 @@ return 0; } -int radeon_cp_swap( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) +int radeon_cp_swap( DRM_IOCTL_ARGS ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; + DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; DRM_DEBUG( "\n" ); - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); RING_SPACE_TEST_WITH_RETURN( dev_priv ); @@ -1381,11 +1365,9 @@ return 0; } -int radeon_cp_vertex( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) +int radeon_cp_vertex( DRM_IOCTL_ARGS ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; + DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_device_dma_t *dma = dev->dma; @@ -1393,30 +1375,29 @@ drm_radeon_vertex_t vertex; drm_radeon_tcl_prim_t prim; - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); if ( !dev_priv ) { DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); - return -EINVAL; + return DRM_ERR(EINVAL); } - if ( copy_from_user( &vertex, (drm_radeon_vertex_t *)arg, - sizeof(vertex) ) ) - return -EFAULT; + DRM_COPY_FROM_USER_IOCTL( vertex, (drm_radeon_vertex_t *)data, + sizeof(vertex) ); DRM_DEBUG( "pid=%d index=%d count=%d discard=%d\n", - current->pid, + DRM_CURRENTPID, vertex.idx, vertex.count, vertex.discard ); if ( vertex.idx < 0 || vertex.idx >= dma->buf_count ) { DRM_ERROR( "buffer index %d (of %d max)\n", vertex.idx, dma->buf_count - 1 ); - return -EINVAL; + return DRM_ERR(EINVAL); } if ( vertex.prim < 0 || vertex.prim > RADEON_PRIM_TYPE_3VRT_LINE_LIST ) { DRM_ERROR( "buffer prim %d\n", vertex.prim ); - return -EINVAL; + return DRM_ERR(EINVAL); } RING_SPACE_TEST_WITH_RETURN( dev_priv ); @@ -1424,14 +1405,14 @@ buf = dma->buflist[vertex.idx]; - if ( buf->pid != current->pid ) { - DRM_ERROR( "process %d using buffer owned by %d\n", - current->pid, buf->pid ); - return -EINVAL; + if ( buf->filp != filp ) { + DRM_ERROR( "process %d using buffer owned by %p\n", + DRM_CURRENTPID, buf->filp ); + return DRM_ERR(EINVAL); } if ( buf->pending ) { DRM_ERROR( "sending pending buffer %d\n", vertex.idx ); - return -EINVAL; + return DRM_ERR(EINVAL); } /* Build up a prim_t record: @@ -1457,9 +1438,7 @@ prim.numverts = vertex.count; prim.vc_format = dev_priv->sarea_priv->vc_format; - radeon_cp_dispatch_vertex( dev, buf, &prim, - dev_priv->sarea_priv->boxes, - dev_priv->sarea_priv->nbox ); + radeon_cp_dispatch_vertex( dev, buf, &prim ); } if (vertex.discard) { @@ -1470,11 +1449,9 @@ return 0; } -int radeon_cp_indices( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) +int radeon_cp_indices( DRM_IOCTL_ARGS ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; + DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_device_dma_t *dma = dev->dma; @@ -1483,30 +1460,29 @@ drm_radeon_tcl_prim_t prim; int count; - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); if ( !dev_priv ) { DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); - return -EINVAL; + return DRM_ERR(EINVAL); } - if ( copy_from_user( &elts, (drm_radeon_indices_t *)arg, - sizeof(elts) ) ) - return -EFAULT; + DRM_COPY_FROM_USER_IOCTL( elts, (drm_radeon_indices_t *)data, + sizeof(elts) ); - DRM_DEBUG( "%s: pid=%d index=%d start=%d end=%d discard=%d\n", - __FUNCTION__, current->pid, + DRM_DEBUG( "pid=%d index=%d start=%d end=%d discard=%d\n", + DRM_CURRENTPID, elts.idx, elts.start, elts.end, elts.discard ); if ( elts.idx < 0 || elts.idx >= dma->buf_count ) { DRM_ERROR( "buffer index %d (of %d max)\n", elts.idx, dma->buf_count - 1 ); - return -EINVAL; + return DRM_ERR(EINVAL); } if ( elts.prim < 0 || elts.prim > RADEON_PRIM_TYPE_3VRT_LINE_LIST ) { DRM_ERROR( "buffer prim %d\n", elts.prim ); - return -EINVAL; + return DRM_ERR(EINVAL); } RING_SPACE_TEST_WITH_RETURN( dev_priv ); @@ -1514,14 +1490,14 @@ buf = dma->buflist[elts.idx]; - if ( buf->pid != current->pid ) { - DRM_ERROR( "process %d using buffer owned by %d\n", - current->pid, buf->pid ); - return -EINVAL; + if ( buf->filp != filp ) { + DRM_ERROR( "process %d using buffer owned by %p\n", + DRM_CURRENTPID, buf->filp ); + return DRM_ERR(EINVAL); } if ( buf->pending ) { DRM_ERROR( "sending pending buffer %d\n", elts.idx ); - return -EINVAL; + return DRM_ERR(EINVAL); } count = (elts.end - elts.start) / sizeof(u16); @@ -1529,11 +1505,11 @@ if ( elts.start & 0x7 ) { DRM_ERROR( "misaligned buffer 0x%x\n", elts.start ); - return -EINVAL; + return DRM_ERR(EINVAL); } if ( elts.start < buf->used ) { DRM_ERROR( "no header 0x%x - 0x%x\n", elts.start, buf->used ); - return -EINVAL; + return DRM_ERR(EINVAL); } buf->used = elts.end; @@ -1560,9 +1536,7 @@ prim.numverts = RADEON_MAX_VB_VERTS; /* duh */ prim.vc_format = dev_priv->sarea_priv->vc_format; - radeon_cp_dispatch_indices( dev, buf, &prim, - dev_priv->sarea_priv->boxes, - dev_priv->sarea_priv->nbox ); + radeon_cp_dispatch_indices( dev, buf, &prim ); if (elts.discard) { radeon_cp_discard_buffer( dev, buf ); } @@ -1571,57 +1545,51 @@ return 0; } -int radeon_cp_texture( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) +int radeon_cp_texture( DRM_IOCTL_ARGS ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; + DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; drm_radeon_texture_t tex; drm_radeon_tex_image_t image; int ret; - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); - if ( copy_from_user( &tex, (drm_radeon_texture_t *)arg, sizeof(tex) ) ) - return -EFAULT; + DRM_COPY_FROM_USER_IOCTL( tex, (drm_radeon_texture_t *)data, sizeof(tex) ); if ( tex.image == NULL ) { DRM_ERROR( "null texture image!\n" ); - return -EINVAL; + return DRM_ERR(EINVAL); } - if ( copy_from_user( &image, + if ( DRM_COPY_FROM_USER( &image, (drm_radeon_tex_image_t *)tex.image, sizeof(image) ) ) - return -EFAULT; + return DRM_ERR(EFAULT); RING_SPACE_TEST_WITH_RETURN( dev_priv ); VB_AGE_TEST_WITH_RETURN( dev_priv ); - ret = radeon_cp_dispatch_texture( dev, &tex, &image ); + ret = radeon_cp_dispatch_texture( filp, dev, &tex, &image ); COMMIT_RING(); return ret; } -int radeon_cp_stipple( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) +int radeon_cp_stipple( DRM_IOCTL_ARGS ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; + DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; drm_radeon_stipple_t stipple; u32 mask[32]; - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); - if ( copy_from_user( &stipple, (drm_radeon_stipple_t *)arg, - sizeof(stipple) ) ) - return -EFAULT; + DRM_COPY_FROM_USER_IOCTL( stipple, (drm_radeon_stipple_t *)data, + sizeof(stipple) ); - if ( copy_from_user( &mask, stipple.mask, 32 * sizeof(u32) ) ) - return -EFAULT; + if ( DRM_COPY_FROM_USER( &mask, stipple.mask, 32 * sizeof(u32) ) ) + return DRM_ERR(EFAULT); RING_SPACE_TEST_WITH_RETURN( dev_priv ); @@ -1631,27 +1599,24 @@ return 0; } -int radeon_cp_indirect( struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg ) +int radeon_cp_indirect( DRM_IOCTL_ARGS ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; + DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; drm_device_dma_t *dma = dev->dma; drm_buf_t *buf; drm_radeon_indirect_t indirect; RING_LOCALS; - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); if ( !dev_priv ) { DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); - return -EINVAL; + return DRM_ERR(EINVAL); } - if ( copy_from_user( &indirect, (drm_radeon_indirect_t *)arg, - sizeof(indirect) ) ) - return -EFAULT; + DRM_COPY_FROM_USER_IOCTL( indirect, (drm_radeon_indirect_t *)data, + sizeof(indirect) ); DRM_DEBUG( "indirect: idx=%d s=%d e=%d d=%d\n", indirect.idx, indirect.start, @@ -1660,25 +1625,25 @@ if ( indirect.idx < 0 || indirect.idx >= dma->buf_count ) { DRM_ERROR( "buffer index %d (of %d max)\n", indirect.idx, dma->buf_count - 1 ); - return -EINVAL; + return DRM_ERR(EINVAL); } buf = dma->buflist[indirect.idx]; - if ( buf->pid != current->pid ) { - DRM_ERROR( "process %d using buffer owned by %d\n", - current->pid, buf->pid ); - return -EINVAL; + if ( buf->filp != filp ) { + DRM_ERROR( "process %d using buffer owned by %p\n", + DRM_CURRENTPID, buf->filp ); + return DRM_ERR(EINVAL); } if ( buf->pending ) { DRM_ERROR( "sending pending buffer %d\n", indirect.idx ); - return -EINVAL; + return DRM_ERR(EINVAL); } if ( indirect.start < buf->used ) { DRM_ERROR( "reusing indirect: start=0x%x actual=0x%x\n", indirect.start, buf->used ); - return -EINVAL; + return DRM_ERR(EINVAL); } RING_SPACE_TEST_WITH_RETURN( dev_priv ); @@ -1709,10 +1674,9 @@ return 0; } -int radeon_cp_vertex2(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long data ) +int radeon_cp_vertex2( DRM_IOCTL_ARGS ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; + DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_device_dma_t *dma = dev->dma; @@ -1721,24 +1685,24 @@ int i; unsigned char laststate; - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); if ( !dev_priv ) { DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); - return -EINVAL; + return DRM_ERR(EINVAL); } DRM_COPY_FROM_USER_IOCTL( vertex, (drm_radeon_vertex2_t *)data, sizeof(vertex) ); DRM_DEBUG( "pid=%d index=%d discard=%d\n", - current->pid, + DRM_CURRENTPID, vertex.idx, vertex.discard ); if ( vertex.idx < 0 || vertex.idx >= dma->buf_count ) { DRM_ERROR( "buffer index %d (of %d max)\n", vertex.idx, dma->buf_count - 1 ); - return -EINVAL; + return DRM_ERR(EINVAL); } RING_SPACE_TEST_WITH_RETURN( dev_priv ); @@ -1746,34 +1710,34 @@ buf = dma->buflist[vertex.idx]; - if ( buf->pid != current->pid ) { - DRM_ERROR( "process %d using buffer owned by %d\n", - current->pid, buf->pid ); - return -EINVAL; + if ( buf->filp != filp ) { + DRM_ERROR( "process %d using buffer owned by %p\n", + DRM_CURRENTPID, buf->filp ); + return DRM_ERR(EINVAL); } if ( buf->pending ) { DRM_ERROR( "sending pending buffer %d\n", vertex.idx ); - return -EINVAL; + return DRM_ERR(EINVAL); } if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS) - return -EINVAL; + return DRM_ERR(EINVAL); for (laststate = 0xff, i = 0 ; i < vertex.nr_prims ; i++) { drm_radeon_prim_t prim; drm_radeon_tcl_prim_t tclprim; - if ( copy_from_user( &prim, &vertex.prim[i], sizeof(prim) ) ) - return -EFAULT; + if ( DRM_COPY_FROM_USER( &prim, &vertex.prim[i], sizeof(prim) ) ) + return DRM_ERR(EFAULT); if ( prim.stateidx != laststate ) { drm_radeon_state_t state; - if ( copy_from_user( &state, + if ( DRM_COPY_FROM_USER( &state, &vertex.state[prim.stateidx], sizeof(state) ) ) - return -EFAULT; + return DRM_ERR(EFAULT); radeon_emit_state2( dev_priv, &state ); @@ -1789,16 +1753,12 @@ tclprim.offset = prim.numverts * 64; tclprim.numverts = RADEON_MAX_VB_VERTS; /* duh */ - radeon_cp_dispatch_indices( dev, buf, &tclprim, - sarea_priv->boxes, - sarea_priv->nbox); + radeon_cp_dispatch_indices( dev, buf, &tclprim ); } else { tclprim.numverts = prim.numverts; tclprim.offset = 0; /* not used */ - radeon_cp_dispatch_vertex( dev, buf, &tclprim, - sarea_priv->boxes, - sarea_priv->nbox); + radeon_cp_dispatch_vertex( dev, buf, &tclprim ); } if (sarea_priv->nbox == 1) @@ -1825,19 +1785,19 @@ RING_LOCALS; if (id >= RADEON_MAX_STATE_PACKETS) - return -EINVAL; + return DRM_ERR(EINVAL); sz = packet[id].len; reg = packet[id].start; if (sz * sizeof(int) > cmdbuf->bufsz) - return -EINVAL; + return DRM_ERR(EINVAL); BEGIN_RING(sz+1); OUT_RING( CP_PACKET0( reg, (sz-1) ) ); OUT_RING_USER_TABLE( data, sz ); ADVANCE_RING(); - + cmdbuf->buf += sz * sizeof(int); cmdbuf->bufsz -= sz * sizeof(int); return 0; @@ -1860,6 +1820,7 @@ OUT_RING( CP_PACKET0_TABLE( RADEON_SE_TCL_SCALAR_DATA_REG, sz-1 ) ); OUT_RING_USER_TABLE( data, sz ); ADVANCE_RING(); + cmdbuf->buf += sz * sizeof(int); cmdbuf->bufsz -= sz * sizeof(int); return 0; @@ -1884,6 +1845,7 @@ OUT_RING( CP_PACKET0_TABLE( RADEON_SE_TCL_SCALAR_DATA_REG, sz-1 ) ); OUT_RING_USER_TABLE( data, sz ); ADVANCE_RING(); + cmdbuf->buf += sz * sizeof(int); cmdbuf->bufsz -= sz * sizeof(int); return 0; @@ -1924,14 +1886,14 @@ DRM_DEBUG("\n"); - if (__get_user( tmp, &cmd[0])) - return -EFAULT; + if (DRM_GET_USER_UNCHECKED( tmp, &cmd[0])) + return DRM_ERR(EFAULT); cmdsz = 2 + ((tmp & RADEON_CP_PACKET_COUNT_MASK) >> 16); if ((tmp & 0xc0000000) != RADEON_CP_PACKET3 || cmdsz * 4 > cmdbuf->bufsz) - return -EINVAL; + return DRM_ERR(EINVAL); BEGIN_RING( cmdsz ); OUT_RING_USER_TABLE( cmd, cmdsz ); @@ -1957,22 +1919,22 @@ DRM_DEBUG("\n"); - if (__get_user( tmp, &cmd[0])) - return -EFAULT; + if (DRM_GET_USER_UNCHECKED( tmp, &cmd[0])) + return DRM_ERR(EFAULT); cmdsz = 2 + ((tmp & RADEON_CP_PACKET_COUNT_MASK) >> 16); if ((tmp & 0xc0000000) != RADEON_CP_PACKET3 || cmdsz * 4 > cmdbuf->bufsz) - return -EINVAL; + return DRM_ERR(EINVAL); if (!orig_nbox) goto out; do { if ( i < cmdbuf->nbox ) { - if (__copy_from_user( &box, &boxes[i], sizeof(box) )) - return -EFAULT; + if (DRM_COPY_FROM_USER_UNCHECKED( &box, &boxes[i], sizeof(box) )) + return DRM_ERR(EFAULT); /* FIXME The second and subsequent times round * this loop, send a WAIT_UNTIL_3D_IDLE before * calling emit_clip_rect(). This fixes a @@ -1992,11 +1954,11 @@ } radeon_emit_clip_rect( dev_priv, &box ); } - + BEGIN_RING( cmdsz ); OUT_RING_USER_TABLE( cmd, cmdsz ); ADVANCE_RING(); - + } while ( ++i < cmdbuf->nbox ); if (cmdbuf->nbox == 1) cmdbuf->nbox = 0; @@ -2031,16 +1993,15 @@ ADVANCE_RING(); break; default: - return -EINVAL; + return DRM_ERR(EINVAL); } return 0; } -int radeon_cp_cmdbuf(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long data ) +int radeon_cp_cmdbuf( DRM_IOCTL_ARGS ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; + DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; drm_device_dma_t *dma = dev->dma; drm_buf_t *buf = 0; @@ -2049,11 +2010,11 @@ drm_radeon_cmd_header_t header; int orig_nbox; - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); if ( !dev_priv ) { DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); - return -EINVAL; + return DRM_ERR(EINVAL); } DRM_COPY_FROM_USER_IOCTL( cmdbuf, (drm_radeon_cmd_buffer_t *)data, @@ -2063,21 +2024,21 @@ VB_AGE_TEST_WITH_RETURN( dev_priv ); - if (verify_area( VERIFY_READ, cmdbuf.buf, cmdbuf.bufsz )) - return -EFAULT; + if (DRM_VERIFYAREA_READ( cmdbuf.buf, cmdbuf.bufsz )) + return DRM_ERR(EFAULT); if (cmdbuf.nbox && - verify_area( VERIFY_READ, cmdbuf.boxes, + DRM_VERIFYAREA_READ(cmdbuf.boxes, cmdbuf.nbox * sizeof(drm_clip_rect_t))) - return -EFAULT; + return DRM_ERR(EFAULT); orig_nbox = cmdbuf.nbox; while ( cmdbuf.bufsz >= sizeof(header) ) { - if (__get_user( header.i, (int *)cmdbuf.buf )) { + if (DRM_GET_USER_UNCHECKED( header.i, (int *)cmdbuf.buf )) { DRM_ERROR("__get_user %p\n", cmdbuf.buf); - return -EFAULT; + return DRM_ERR(EFAULT); } cmdbuf.buf += sizeof(header); @@ -2088,7 +2049,7 @@ DRM_DEBUG("RADEON_CMD_PACKET\n"); if (radeon_emit_packets( dev_priv, header, &cmdbuf )) { DRM_ERROR("radeon_emit_packets failed\n"); - return -EINVAL; + return DRM_ERR(EINVAL); } break; @@ -2096,7 +2057,7 @@ DRM_DEBUG("RADEON_CMD_SCALARS\n"); if (radeon_emit_scalars( dev_priv, header, &cmdbuf )) { DRM_ERROR("radeon_emit_scalars failed\n"); - return -EINVAL; + return DRM_ERR(EINVAL); } break; @@ -2104,7 +2065,7 @@ DRM_DEBUG("RADEON_CMD_VECTORS\n"); if (radeon_emit_vectors( dev_priv, header, &cmdbuf )) { DRM_ERROR("radeon_emit_vectors failed\n"); - return -EINVAL; + return DRM_ERR(EINVAL); } break; @@ -2114,13 +2075,14 @@ if ( idx < 0 || idx >= dma->buf_count ) { DRM_ERROR( "buffer index %d (of %d max)\n", idx, dma->buf_count - 1 ); - return -EINVAL; + return DRM_ERR(EINVAL); } buf = dma->buflist[idx]; - if ( buf->pid != current->pid || buf->pending ) { - DRM_ERROR( "bad buffer\n" ); - return -EINVAL; + if ( buf->filp != filp || buf->pending ) { + DRM_ERROR( "bad buffer %p %p %d\n", + buf->filp, filp, buf->pending); + return DRM_ERR(EINVAL); } radeon_cp_discard_buffer( dev, buf ); @@ -2130,7 +2092,7 @@ DRM_DEBUG("RADEON_CMD_PACKET3\n"); if (radeon_emit_packet3( dev, &cmdbuf )) { DRM_ERROR("radeon_emit_packet3 failed\n"); - return -EINVAL; + return DRM_ERR(EINVAL); } break; @@ -2138,7 +2100,7 @@ DRM_DEBUG("RADEON_CMD_PACKET3_CLIP\n"); if (radeon_emit_packet3_cliprect( dev, &cmdbuf, orig_nbox )) { DRM_ERROR("radeon_emit_packet3_clip failed\n"); - return -EINVAL; + return DRM_ERR(EINVAL); } break; @@ -2146,7 +2108,7 @@ DRM_DEBUG("RADEON_CMD_SCALARS2\n"); if (radeon_emit_scalars2( dev_priv, header, &cmdbuf )) { DRM_ERROR("radeon_emit_scalars2 failed\n"); - return -EINVAL; + return DRM_ERR(EINVAL); } break; @@ -2154,14 +2116,14 @@ DRM_DEBUG("RADEON_CMD_WAIT\n"); if (radeon_emit_wait( dev, header.wait.flags )) { DRM_ERROR("radeon_emit_wait failed\n"); - return -EINVAL; + return DRM_ERR(EINVAL); } break; default: DRM_ERROR("bad cmd_type %d at %p\n", header.header.cmd_type, cmdbuf.buf - sizeof(header)); - return -EINVAL; + return DRM_ERR(EINVAL); } } @@ -2173,27 +2135,26 @@ -int radeon_cp_getparam(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long data) +int radeon_cp_getparam( DRM_IOCTL_ARGS ) { - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; + DRM_DEVICE; drm_radeon_private_t *dev_priv = dev->dev_private; drm_radeon_getparam_t param; int value; if ( !dev_priv ) { DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); - return -EINVAL; + return DRM_ERR(EINVAL); } DRM_COPY_FROM_USER_IOCTL( param, (drm_radeon_getparam_t *)data, sizeof(param) ); - DRM_DEBUG( "pid=%d\n", current->pid ); + DRM_DEBUG( "pid=%d\n", DRM_CURRENTPID ); switch( param.param ) { - case RADEON_PARAM_AGP_BUFFER_OFFSET: - value = dev_priv->agp_buffers_offset; + case RADEON_PARAM_GART_BUFFER_OFFSET: + value = dev_priv->gart_buffers_offset; break; case RADEON_PARAM_LAST_FRAME: dev_priv->stats.last_frame_reads++; @@ -2209,16 +2170,29 @@ case RADEON_PARAM_IRQ_NR: value = dev->irq; break; - case RADEON_PARAM_AGP_BASE: - value = dev_priv->agp_vm_start; + case RADEON_PARAM_GART_BASE: + value = dev_priv->gart_vm_start; + break; + case RADEON_PARAM_REGISTER_HANDLE: + value = dev_priv->mmio_offset; + break; + case RADEON_PARAM_STATUS_HANDLE: + value = dev_priv->ring_rptr_offset; + break; + case RADEON_PARAM_SAREA_HANDLE: + /* The lock is the first dword in the sarea. */ + value = (int)dev->lock.hw_lock; + break; + case RADEON_PARAM_GART_TEX_HANDLE: + value = dev_priv->gart_textures_offset; break; default: - return -EINVAL; + return DRM_ERR(EINVAL); } - if ( copy_to_user( param.value, &value, sizeof(int) ) ) { + if ( DRM_COPY_TO_USER( param.value, &value, sizeof(int) ) ) { DRM_ERROR( "copy_to_user\n" ); - return -EFAULT; + return DRM_ERR(EFAULT); } return 0; diff -urN linux-2.4.23-pre8/drivers/char/drm/sis.h linux-2.4.23-pre8-pac1/drivers/char/drm/sis.h --- linux-2.4.23-pre8/drivers/char/drm/sis.h 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/sis.h 2003-09-28 22:16:09.000000000 +0200 @@ -24,7 +24,7 @@ * DEALINGS IN THE SOFTWARE. * */ -/* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/sis.h,v 1.2 2001/12/19 21:25:59 dawes Exp $ */ +/* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/shared/drm/kernel/sis.h,v 1.1 2003/09/28 20:16:09 alanh Exp $ */ #ifndef __SIS_H__ #define __SIS_H__ @@ -33,7 +33,11 @@ * Name it sisdrv_##x as there's a conflict with sis_free/malloc in the kernel * that's used for fb devices */ +#ifdef __linux__ #define DRM(x) sisdrv_##x +#else +#define DRM(x) sis_##x +#endif /* General customization: */ @@ -42,28 +46,21 @@ #define __HAVE_MTRR 1 #define __HAVE_CTX_BITMAP 1 -#define DRIVER_AUTHOR "SIS" -#define DRIVER_NAME "sis" -#define DRIVER_DESC "SIS 300/630/540" -#define DRIVER_DATE "20010503" -#define DRIVER_MAJOR 1 -#define DRIVER_MINOR 0 -#define DRIVER_PATCHLEVEL 0 +#define DRIVER_AUTHOR "SIS" +#define DRIVER_NAME "sis" +#define DRIVER_DESC "SIS 300/630/540" +#define DRIVER_DATE "20030826" +#define DRIVER_MAJOR 1 +#define DRIVER_MINOR 1 +#define DRIVER_PATCHLEVEL 0 #define DRIVER_IOCTLS \ - [DRM_IOCTL_NR(SIS_IOCTL_FB_ALLOC)] = { sis_fb_alloc, 1, 0 }, \ - [DRM_IOCTL_NR(SIS_IOCTL_FB_FREE)] = { sis_fb_free, 1, 0 }, \ - /* AGP Memory Management */ \ - [DRM_IOCTL_NR(SIS_IOCTL_AGP_INIT)] = { sisp_agp_init, 1, 0 }, \ - [DRM_IOCTL_NR(SIS_IOCTL_AGP_ALLOC)] = { sisp_agp_alloc, 1, 0 }, \ - [DRM_IOCTL_NR(SIS_IOCTL_AGP_FREE)] = { sisp_agp_free, 1, 0 } -#if 0 /* these don't appear to be defined */ - /* SIS Stereo */ - [DRM_IOCTL_NR(DRM_IOCTL_CONTROL)] = { sis_control, 1, 1 }, - [DRM_IOCTL_NR(SIS_IOCTL_FLIP)] = { sis_flip, 1, 1 }, - [DRM_IOCTL_NR(SIS_IOCTL_FLIP_INIT)] = { sis_flip_init, 1, 1 }, - [DRM_IOCTL_NR(SIS_IOCTL_FLIP_FINAL)] = { sis_flip_final, 1, 1 } -#endif + [DRM_IOCTL_NR(DRM_IOCTL_SIS_FB_ALLOC)] = { sis_fb_alloc, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_SIS_FB_FREE)] = { sis_fb_free, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_SIS_AGP_INIT)] = { sis_ioctl_agp_init, 1, 1 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_SIS_AGP_ALLOC)] = { sis_ioctl_agp_alloc, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_SIS_AGP_FREE)] = { sis_ioctl_agp_free, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_SIS_FB_INIT)] = { sis_fb_init, 1, 1 } #define __HAVE_COUNTERS 5 diff -urN linux-2.4.23-pre8/drivers/char/drm/sis_drm.h linux-2.4.23-pre8-pac1/drivers/char/drm/sis_drm.h --- linux-2.4.23-pre8/drivers/char/drm/sis_drm.h 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/sis_drm.h 2003-09-28 22:16:09.000000000 +0200 @@ -1,46 +1,33 @@ -#ifndef _sis_drm_public_h_ -#define _sis_drm_public_h_ +#ifndef __SIS_DRM_H__ +#define __SIS_DRM_H__ /* SiS specific ioctls */ -#define SIS_IOCTL_FB_ALLOC DRM_IOWR(0x44, drm_sis_mem_t) -#define SIS_IOCTL_FB_FREE DRM_IOW( 0x45, drm_sis_mem_t) -#define SIS_IOCTL_AGP_INIT DRM_IOWR(0x53, drm_sis_agp_t) -#define SIS_IOCTL_AGP_ALLOC DRM_IOWR(0x54, drm_sis_mem_t) -#define SIS_IOCTL_AGP_FREE DRM_IOW( 0x55, drm_sis_mem_t) -#define SIS_IOCTL_FLIP DRM_IOW( 0x48, drm_sis_flip_t) -#define SIS_IOCTL_FLIP_INIT DRM_IO( 0x49) -#define SIS_IOCTL_FLIP_FINAL DRM_IO( 0x50) +#define DRM_IOCTL_SIS_FB_ALLOC DRM_IOWR(0x44, drm_sis_mem_t) +#define DRM_IOCTL_SIS_FB_FREE DRM_IOW( 0x45, drm_sis_mem_t) +#define DRM_IOCTL_SIS_AGP_INIT DRM_IOWR(0x53, drm_sis_agp_t) +#define DRM_IOCTL_SIS_AGP_ALLOC DRM_IOWR(0x54, drm_sis_mem_t) +#define DRM_IOCTL_SIS_AGP_FREE DRM_IOW( 0x55, drm_sis_mem_t) +#define DRM_IOCTL_SIS_FB_INIT DRM_IOW( 0x56, drm_sis_fb_t) +/* +#define DRM_IOCTL_SIS_FLIP DRM_IOW( 0x48, drm_sis_flip_t) +#define DRM_IOCTL_SIS_FLIP_INIT DRM_IO( 0x49) +#define DRM_IOCTL_SIS_FLIP_FINAL DRM_IO( 0x50) +*/ typedef struct { - int context; - unsigned int offset; - unsigned int size; - unsigned long free; + int context; + unsigned int offset; + unsigned int size; + unsigned long free; } drm_sis_mem_t; typedef struct { - unsigned int offset, size; + unsigned int offset, size; } drm_sis_agp_t; typedef struct { - unsigned int left, right; -} drm_sis_flip_t; + unsigned int offset, size; +} drm_sis_fb_t; -#ifdef __KERNEL__ - -int sis_fb_alloc(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg); -int sis_fb_free(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg); - -int sisp_agp_init(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg); -int sisp_agp_alloc(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg); -int sisp_agp_free(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg); - -#endif - -#endif +#endif /* __SIS_DRM_H__ */ diff -urN linux-2.4.23-pre8/drivers/char/drm/sis_drv.c linux-2.4.23-pre8-pac1/drivers/char/drm/sis_drv.c --- linux-2.4.23-pre8/drivers/char/drm/sis_drv.c 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/sis_drv.c 2003-05-01 14:18:11.000000000 +0200 @@ -41,7 +41,6 @@ #include "drm_fops.h" #include "drm_init.h" #include "drm_ioctl.h" -#include "drm_lists.h" #include "drm_lock.h" #include "drm_memory.h" #include "drm_proc.h" diff -urN linux-2.4.23-pre8/drivers/char/drm/sis_drv.h linux-2.4.23-pre8-pac1/drivers/char/drm/sis_drv.h --- linux-2.4.23-pre8/drivers/char/drm/sis_drv.h 2001-12-21 18:41:53.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/sis_drv.h 2003-09-28 22:16:09.000000000 +0200 @@ -28,18 +28,20 @@ #ifndef _SIS_DRV_H_ #define _SIS_DRV_H_ +#include "sis_ds.h" + typedef struct drm_sis_private { drm_map_t *buffers; -} drm_sis_private_t; -/* Stereo ? - this was never committed */ + memHeap_t *AGPHeap; + memHeap_t *FBHeap; +} drm_sis_private_t; -int sis_flip(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg); -int sis_flip_init(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg); -int sis_flip_final(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg); -void flip_final(void); +extern int sis_fb_alloc( DRM_IOCTL_ARGS ); +extern int sis_fb_free( DRM_IOCTL_ARGS ); +extern int sis_ioctl_agp_init( DRM_IOCTL_ARGS ); +extern int sis_ioctl_agp_alloc( DRM_IOCTL_ARGS ); +extern int sis_ioctl_agp_free( DRM_IOCTL_ARGS ); +extern int sis_fb_init( DRM_IOCTL_ARGS ); #endif diff -urN linux-2.4.23-pre8/drivers/char/drm/sis_ds.c linux-2.4.23-pre8-pac1/drivers/char/drm/sis_ds.c --- linux-2.4.23-pre8/drivers/char/drm/sis_ds.c 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/sis_ds.c 2003-09-28 22:16:09.000000000 +0200 @@ -28,15 +28,9 @@ * */ -#include -#include -#include -#include -#include -#include -#include -#include - +#include "sis.h" +#include "drmP.h" +#include "drm.h" #include "sis_ds.h" /* Set Data Structure, not check repeated value @@ -45,101 +39,98 @@ set_t *setInit(void) { - int i; - set_t *set; + int i; + set_t *set; - set = (set_t *)MALLOC(sizeof(set_t)); - if(set) - { - for(i = 0; i < SET_SIZE; i++){ - set->list[i].free_next = i+1; - set->list[i].alloc_next = -1; - } - - set->list[SET_SIZE-1].free_next = -1; - set->free = 0; - set->alloc = -1; - set->trace = -1; - } - - return set; + set = (set_t *)DRM(alloc)(sizeof(set_t), DRM_MEM_DRIVER); + if (set != NULL) { + for (i = 0; i < SET_SIZE; i++) { + set->list[i].free_next = i + 1; + set->list[i].alloc_next = -1; + } + set->list[SET_SIZE-1].free_next = -1; + set->free = 0; + set->alloc = -1; + set->trace = -1; + } + return set; } int setAdd(set_t *set, ITEM_TYPE item) { - int free = set->free; + int free = set->free; - if(free != -1){ - set->list[free].val = item; - set->free = set->list[free].free_next; - } - else{ - return 0; - } - - set->list[free].alloc_next = set->alloc; - set->alloc = free; - set->list[free].free_next = -1; + if (free != -1) { + set->list[free].val = item; + set->free = set->list[free].free_next; + } else { + return 0; + } + + set->list[free].alloc_next = set->alloc; + set->alloc = free; + set->list[free].free_next = -1; - return 1; + return 1; } int setDel(set_t *set, ITEM_TYPE item) { - int alloc = set->alloc; - int prev = -1; - - while(alloc != -1){ - if(set->list[alloc].val == item){ - if(prev != -1) - set->list[prev].alloc_next = set->list[alloc].alloc_next; - else - set->alloc = set->list[alloc].alloc_next; - break; - } - prev = alloc; - alloc = set->list[alloc].alloc_next; - } + int alloc = set->alloc; + int prev = -1; - if(alloc == -1) - return 0; - - set->list[alloc].free_next = set->free; - set->free = alloc; - set->list[alloc].alloc_next = -1; + while (alloc != -1) { + if (set->list[alloc].val == item) { + if (prev != -1) + set->list[prev].alloc_next = + set->list[alloc].alloc_next; + else + set->alloc = set->list[alloc].alloc_next; + break; + } + prev = alloc; + alloc = set->list[alloc].alloc_next; + } + + if (alloc == -1) + return 0; + + set->list[alloc].free_next = set->free; + set->free = alloc; + set->list[alloc].alloc_next = -1; - return 1; + return 1; } /* setFirst -> setAdd -> setNext is wrong */ int setFirst(set_t *set, ITEM_TYPE *item) { - if(set->alloc == -1) - return 0; + if (set->alloc == -1) + return 0; - *item = set->list[set->alloc].val; - set->trace = set->list[set->alloc].alloc_next; + *item = set->list[set->alloc].val; + set->trace = set->list[set->alloc].alloc_next; - return 1; + return 1; } int setNext(set_t *set, ITEM_TYPE *item) { - if(set->trace == -1) - return 0; - - *item = set->list[set->trace].val; - set->trace = set->list[set->trace].alloc_next; + if (set->trace == -1) + return 0; - return 1; + *item = set->list[set->trace].val; + set->trace = set->list[set->trace].alloc_next; + + return 1; } int setDestroy(set_t *set) { - FREE(set); + DRM(free)(set, sizeof(set_t), DRM_MEM_DRIVER); - return 1; + return 1; } /* @@ -168,54 +159,40 @@ #define ISFREE(bptr) ((bptr)->free) -#define PRINTF(fmt, arg...) do{}while(0) -#define fprintf(fmt, arg...) do{}while(0) - -static void *calloc(size_t nmemb, size_t size) -{ - void *addr; - addr = kmalloc(nmemb*size, GFP_KERNEL); - if (addr) - memset(addr, 0, nmemb*size); - return addr; -} -#define free(n) kfree(n) - -void mmDumpMemInfo( memHeap_t *heap ) -{ - TMemBlock *p; - - PRINTF ("Memory heap %p:\n", heap); - if (heap == 0) { - PRINTF (" heap == 0\n"); - } else { - p = (TMemBlock *)heap; - while (p) { - PRINTF (" Offset:%08x, Size:%08x, %c%c\n",p->ofs,p->size, - p->free ? '.':'U', - p->reserved ? 'R':'.'); - p = p->next; - } - } - PRINTF ("End of memory blocks\n"); -} - memHeap_t *mmInit(int ofs, int size) { - PMemBlock blocks; - - if (size <= 0) { - return 0; - } - blocks = (TMemBlock *) calloc(1,sizeof(TMemBlock)); - if (blocks) { - blocks->ofs = ofs; - blocks->size = size; - blocks->free = 1; - return (memHeap_t *)blocks; - } else - return 0; + PMemBlock blocks; + + if (size <= 0) + return 0; + + blocks = (TMemBlock *)DRM(calloc)(1, sizeof(TMemBlock), DRM_MEM_DRIVER); + if (blocks != NULL) { + blocks->ofs = ofs; + blocks->size = size; + blocks->free = 1; + return (memHeap_t *)blocks; + } else + return 0; +} + +/* Checks if a pointer 'b' is part of the heap 'heap' */ +int mmBlockInHeap(memHeap_t *heap, PMemBlock b) +{ + TMemBlock *p; + + if (heap == NULL || b == NULL) + return 0; + + p = heap; + while (p != NULL && p != b) { + p = p->next; + } + if (p == b) + return 1; + else + return 0; } /* Kludgey workaround for existing i810 server. Remove soon. @@ -224,187 +201,186 @@ int ofs, int size ) { - PMemBlock blocks; - blocks = (TMemBlock *) calloc(2,sizeof(TMemBlock)); - if (blocks) { - blocks[0].size = size; - blocks[0].free = 1; - blocks[0].ofs = ofs; - blocks[0].next = &blocks[1]; - - /* Discontinuity - stops JoinBlock from trying to join non-adjacent - * ranges. - */ - blocks[1].size = 0; - blocks[1].free = 0; - blocks[1].ofs = ofs+size; - blocks[1].next = (PMemBlock) heap; - return (memHeap_t *)blocks; - } - else - return heap; + PMemBlock blocks; + blocks = (TMemBlock *)DRM(calloc)(2, sizeof(TMemBlock), DRM_MEM_DRIVER); + if (blocks != NULL) { + blocks[0].size = size; + blocks[0].free = 1; + blocks[0].ofs = ofs; + blocks[0].next = &blocks[1]; + + /* Discontinuity - stops JoinBlock from trying to join + * non-adjacent ranges. + */ + blocks[1].size = 0; + blocks[1].free = 0; + blocks[1].ofs = ofs+size; + blocks[1].next = (PMemBlock)heap; + return (memHeap_t *)blocks; + } else + return heap; } static TMemBlock* SliceBlock(TMemBlock *p, int startofs, int size, int reserved, int alignment) { - TMemBlock *newblock; + TMemBlock *newblock; - /* break left */ - if (startofs > p->ofs) { - newblock = (TMemBlock*) calloc(1,sizeof(TMemBlock)); - newblock->ofs = startofs; - newblock->size = p->size - (startofs - p->ofs); - newblock->free = 1; - newblock->next = p->next; - p->size -= newblock->size; - p->next = newblock; - p = newblock; - } - - /* break right */ - if (size < p->size) { - newblock = (TMemBlock*) calloc(1,sizeof(TMemBlock)); - newblock->ofs = startofs + size; - newblock->size = p->size - size; - newblock->free = 1; - newblock->next = p->next; - p->size = size; - p->next = newblock; - } - - /* p = middle block */ - p->align = alignment; - p->free = 0; - p->reserved = reserved; - return p; + /* break left */ + if (startofs > p->ofs) { + newblock = (TMemBlock*) DRM(calloc)(1, sizeof(TMemBlock), + DRM_MEM_DRIVER); + newblock->ofs = startofs; + newblock->size = p->size - (startofs - p->ofs); + newblock->free = 1; + newblock->next = p->next; + p->size -= newblock->size; + p->next = newblock; + p = newblock; + } + + /* break right */ + if (size < p->size) { + newblock = (TMemBlock*) DRM(calloc)(1, sizeof(TMemBlock), + DRM_MEM_DRIVER); + newblock->ofs = startofs + size; + newblock->size = p->size - size; + newblock->free = 1; + newblock->next = p->next; + p->size = size; + p->next = newblock; + } + + /* p = middle block */ + p->align = alignment; + p->free = 0; + p->reserved = reserved; + return p; } PMemBlock mmAllocMem( memHeap_t *heap, int size, int align2, int startSearch) { - int mask,startofs,endofs; - TMemBlock *p; - - if (!heap || align2 < 0 || size <= 0) - return NULL; - mask = (1 << align2)-1; - startofs = 0; - p = (TMemBlock *)heap; - while (p) { - if (ISFREE(p)) { - startofs = (p->ofs + mask) & ~mask; - if ( startofs < startSearch ) { - startofs = startSearch; - } - endofs = startofs+size; - if (endofs <= (p->ofs+p->size)) - break; - } - p = p->next; - } - if (!p) - return NULL; - p = SliceBlock(p,startofs,size,0,mask+1); - p->heap = heap; - return p; + int mask,startofs, endofs; + TMemBlock *p; + + if (heap == NULL || align2 < 0 || size <= 0) + return NULL; + + mask = (1 << align2)-1; + startofs = 0; + p = (TMemBlock *)heap; + while (p != NULL) { + if (ISFREE(p)) { + startofs = (p->ofs + mask) & ~mask; + if ( startofs < startSearch ) { + startofs = startSearch; + } + endofs = startofs+size; + if (endofs <= (p->ofs+p->size)) + break; + } + p = p->next; + } + if (p == NULL) + return NULL; + p = SliceBlock(p,startofs,size,0,mask+1); + p->heap = heap; + return p; } static __inline__ int Join2Blocks(TMemBlock *p) { - if (p->free && p->next && p->next->free) { - TMemBlock *q = p->next; - p->size += q->size; - p->next = q->next; - free(q); - return 1; - } - return 0; + if (p->free && p->next && p->next->free) { + TMemBlock *q = p->next; + p->size += q->size; + p->next = q->next; + DRM(free)(q, sizeof(TMemBlock), DRM_MEM_DRIVER); + return 1; + } + return 0; } int mmFreeMem(PMemBlock b) { - TMemBlock *p,*prev; + TMemBlock *p, *prev; - if (!b) - return 0; - if (!b->heap) { - fprintf(stderr, "no heap\n"); - return -1; - } - p = b->heap; - prev = NULL; - while (p && p != b) { - prev = p; - p = p->next; - } - if (!p || p->free || p->reserved) { - if (!p) - fprintf(stderr, "block not found in heap\n"); - else if (p->free) - fprintf(stderr, "block already free\n"); - else - fprintf(stderr, "block is reserved\n"); - return -1; - } - p->free = 1; - Join2Blocks(p); - if (prev) - Join2Blocks(prev); - return 0; + if (b == NULL) + return 0; + if (b->heap == NULL) + return -1; + + p = b->heap; + prev = NULL; + while (p != NULL && p != b) { + prev = p; + p = p->next; + } + if (p == NULL || p->free || p->reserved) + return -1; + + p->free = 1; + Join2Blocks(p); + if (prev) + Join2Blocks(prev); + return 0; } int mmReserveMem(memHeap_t *heap, int offset,int size) { - int endofs; - TMemBlock *p; + int endofs; + TMemBlock *p; + + if (heap == NULL || size <= 0) + return -1; - if (!heap || size <= 0) - return -1; - endofs = offset+size; - p = (TMemBlock *)heap; - while (p && p->ofs <= offset) { - if (ISFREE(p) && endofs <= (p->ofs+p->size)) { - SliceBlock(p,offset,size,1,1); - return 0; - } - p = p->next; - } - return -1; + endofs = offset + size; + p = (TMemBlock *)heap; + while (p && p->ofs <= offset) { + if (ISFREE(p) && endofs <= (p->ofs+p->size)) { + SliceBlock(p,offset,size,1,1); + return 0; + } + p = p->next; + } + return -1; } int mmFreeReserved(memHeap_t *heap, int offset) { - TMemBlock *p,*prev; + TMemBlock *p,*prev; - if (!heap) - return -1; - p = (TMemBlock *)heap; - prev = NULL; - while (p && p->ofs != offset) { - prev = p; - p = p->next; - } - if (!p || !p->reserved) - return -1; - p->free = 1; - p->reserved = 0; - Join2Blocks(p); - if (prev) - Join2Blocks(prev); - return 0; + if (heap == NULL) + return -1; + + p = (TMemBlock *)heap; + prev = NULL; + while (p != NULL && p->ofs != offset) { + prev = p; + p = p->next; + } + if (p == NULL || !p->reserved) + return -1; + + p->free = 1; + p->reserved = 0; + Join2Blocks(p); + if (prev != NULL) + Join2Blocks(prev); + return 0; } void mmDestroy(memHeap_t *heap) { - TMemBlock *p,*q; + TMemBlock *p,*q; + + if (heap == NULL) + return; - if (!heap) - return; - p = (TMemBlock *)heap; - while (p) { - q = p->next; - free(p); - p = q; - } + p = (TMemBlock *)heap; + while (p != NULL) { + q = p->next; + DRM(free)(p, sizeof(TMemBlock), DRM_MEM_DRIVER); + p = q; + } } diff -urN linux-2.4.23-pre8/drivers/char/drm/sis_ds.h linux-2.4.23-pre8-pac1/drivers/char/drm/sis_ds.h --- linux-2.4.23-pre8/drivers/char/drm/sis_ds.h 2001-12-21 18:41:53.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/sis_ds.h 2003-09-28 22:16:09.000000000 +0200 @@ -28,27 +28,25 @@ * */ -#ifndef _sis_ds_h_ -#define _sis_ds_h_ +#ifndef __SIS_DS_H__ +#define __SIS_DS_H__ /* Set Data Structure */ #define SET_SIZE 5000 -#define MALLOC(s) kmalloc(s, GFP_KERNEL) -#define FREE(s) kfree(s) typedef unsigned int ITEM_TYPE; typedef struct { - ITEM_TYPE val; - int alloc_next, free_next; + ITEM_TYPE val; + int alloc_next, free_next; } list_item_t; typedef struct { - int alloc; - int free; - int trace; - list_item_t list[SET_SIZE]; + int alloc; + int free; + int trace; + list_item_t list[SET_SIZE]; } set_t; set_t *setInit(void); @@ -58,8 +56,6 @@ int setNext(set_t *set, ITEM_TYPE *item); int setDestroy(set_t *set); -#endif - /* * GLX Hardware Device Driver common code * Copyright (C) 1999 Keith Whitwell @@ -84,16 +80,13 @@ * */ -#ifndef MM_INC -#define MM_INC - struct mem_block_t { - struct mem_block_t *next; - struct mem_block_t *heap; - int ofs,size; - int align; - int free:1; - int reserved:1; + struct mem_block_t *next; + struct mem_block_t *heap; + int ofs,size; + int align; + int free:1; + int reserved:1; }; typedef struct mem_block_t TMemBlock; typedef struct mem_block_t *PMemBlock; @@ -102,13 +95,19 @@ typedef struct mem_block_t memHeap_t; static __inline__ int mmBlockSize(PMemBlock b) -{ return b->size; } +{ + return b->size; +} static __inline__ int mmOffset(PMemBlock b) -{ return b->ofs; } +{ + return b->ofs; +} static __inline__ void mmMarkReserved(PMemBlock b) -{ b->reserved = 1; } +{ + b->reserved = 1; +} /* * input: total size in bytes @@ -116,13 +115,10 @@ */ memHeap_t *mmInit( int ofs, int size ); - - memHeap_t *mmAddRange( memHeap_t *heap, int ofs, int size ); - /* * Allocate 'size' bytes with 2^align2 bytes alignment, * restrict the search to free memory after 'startSearch' @@ -133,14 +129,19 @@ * startSearch = linear offset from start of heap to begin search * return: pointer to the allocated block, 0 if error */ -PMemBlock mmAllocMem( memHeap_t *heap, int size, int align2, int startSearch ); +PMemBlock mmAllocMem( memHeap_t *heap, int size, int align2, int startSearch ); + +/* + * Returns 1 if the block 'b' is part of the heap 'heap' + */ +int mmBlockInHeap( PMemBlock heap, PMemBlock b ); /* * Free block starts at offset * input: pointer to a block * return: 0 if OK, -1 if error */ -int mmFreeMem( PMemBlock b ); +int mmFreeMem( PMemBlock b ); /* * Reserve 'size' bytes block start at offset @@ -160,4 +161,4 @@ /* For debuging purpose. */ void mmDumpMemInfo( memHeap_t *mmInit ); -#endif +#endif /* __SIS_DS_H__ */ diff -urN linux-2.4.23-pre8/drivers/char/drm/sis_mm.c linux-2.4.23-pre8-pac1/drivers/char/drm/sis_mm.c --- linux-2.4.23-pre8/drivers/char/drm/sis_mm.c 2002-11-29 00:53:12.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/char/drm/sis_mm.c 2003-09-28 22:16:09.000000000 +0200 @@ -29,230 +29,327 @@ */ #include "sis.h" -#include #include "drmP.h" #include "sis_drm.h" #include "sis_drv.h" #include "sis_ds.h" +#if defined(__linux__) && defined(CONFIG_FB_SIS) +#include +#endif #define MAX_CONTEXT 100 #define VIDEO_TYPE 0 #define AGP_TYPE 1 typedef struct { - int used; - int context; - set_t *sets[2]; /* 0 for video, 1 for AGP */ + int used; + int context; + set_t *sets[2]; /* 0 for video, 1 for AGP */ } sis_context_t; static sis_context_t global_ppriv[MAX_CONTEXT]; + static int add_alloc_set(int context, int type, unsigned int val) { - int i, retval = 0; - - for(i = 0; i < MAX_CONTEXT; i++) - if(global_ppriv[i].used && global_ppriv[i].context == context){ - retval = setAdd(global_ppriv[i].sets[type], val); - break; - } - return retval; + int i, retval = 0; + + for (i = 0; i < MAX_CONTEXT; i++) { + if (global_ppriv[i].used && global_ppriv[i].context == context) + { + retval = setAdd(global_ppriv[i].sets[type], val); + break; + } + } + return retval; } static int del_alloc_set(int context, int type, unsigned int val) { - int i, retval = 0; - for(i = 0; i < MAX_CONTEXT; i++) - if(global_ppriv[i].used && global_ppriv[i].context == context){ - retval = setDel(global_ppriv[i].sets[type], val); - break; - } - return retval; + int i, retval = 0; + + for (i = 0; i < MAX_CONTEXT; i++) { + if (global_ppriv[i].used && global_ppriv[i].context == context) + { + retval = setDel(global_ppriv[i].sets[type], val); + break; + } + } + return retval; } /* fb management via fb device */ -#if 1 -int sis_fb_alloc(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) -{ - drm_sis_mem_t fb; - struct sis_memreq req; - int retval = 0; - - if (copy_from_user(&fb, (drm_sis_mem_t *)arg, sizeof(fb))) - return -EFAULT; - - req.size = fb.size; - sis_malloc(&req); - if(req.offset){ - /* TODO */ - fb.offset = req.offset; - fb.free = req.offset; - if(!add_alloc_set(fb.context, VIDEO_TYPE, fb.free)){ - DRM_DEBUG("adding to allocation set fails\n"); - sis_free(req.offset); - retval = -1; - } - } - else{ - fb.offset = 0; - fb.size = 0; - fb.free = 0; - } - - if (copy_to_user((drm_sis_mem_t *)arg, &fb, sizeof(fb))) return -EFAULT; +#if defined(__linux__) && defined(CONFIG_FB_SIS) + +int sis_fb_init( DRM_IOCTL_ARGS ) +{ + return 0; +} + +int sis_fb_alloc( DRM_IOCTL_ARGS ) +{ + drm_sis_mem_t fb; + struct sis_memreq req; + int retval = 0; + + DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_mem_t *)data, sizeof(fb)); + + req.size = fb.size; + sis_malloc(&req); + if (req.offset) { + /* TODO */ + fb.offset = req.offset; + fb.free = req.offset; + if (!add_alloc_set(fb.context, VIDEO_TYPE, fb.free)) { + DRM_DEBUG("adding to allocation set fails\n"); + sis_free(req.offset); + retval = DRM_ERR(EINVAL); + } + } else { + fb.offset = 0; + fb.size = 0; + fb.free = 0; + } - DRM_DEBUG("alloc fb, size = %d, offset = %ld\n", fb.size, req.offset); + DRM_COPY_TO_USER_IOCTL((drm_sis_mem_t *)data, fb, sizeof(fb)); - return retval; + DRM_DEBUG("alloc fb, size = %d, offset = %ld\n", fb.size, req.offset); + + return retval; } -int sis_fb_free(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) +int sis_fb_free( DRM_IOCTL_ARGS ) { - drm_sis_mem_t fb; - int retval = 0; - - if (copy_from_user(&fb, (drm_sis_mem_t *)arg, sizeof(fb))) - return -EFAULT; - - if(!fb.free){ - return -1; - } - - sis_free(fb.free); - if(!del_alloc_set(fb.context, VIDEO_TYPE, fb.free)) - retval = -1; + drm_sis_mem_t fb; + int retval = 0; - DRM_DEBUG("free fb, offset = %ld\n", fb.free); - - return retval; + DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_mem_t *)data, sizeof(fb)); + + if (!fb.free) + return DRM_ERR(EINVAL); + + if (!del_alloc_set(fb.context, VIDEO_TYPE, fb.free)) + retval = DRM_ERR(EINVAL); + sis_free(fb.free); + + DRM_DEBUG("free fb, offset = %d\n", fb.free); + + return retval; } #else -int sis_fb_alloc(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) +/* Called by the X Server to initialize the FB heap. Allocations will fail + * unless this is called. Offset is the beginning of the heap from the + * framebuffer offset (MaxXFBMem in XFree86). + * + * Memory layout according to Thomas Winischofer: + * |------------------|DDDDDDDDDDDDDDDDDDDDDDDDDDDDD|HHHH|CCCCCCCCCCC| + * + * X driver/sisfb HW- Command- + * framebuffer memory DRI heap Cursor queue + */ +int sis_fb_init( DRM_IOCTL_ARGS ) +{ + DRM_DEVICE; + drm_sis_private_t *dev_priv = dev->dev_private; + drm_sis_fb_t fb; + + DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_fb_t *)data, sizeof(fb)); + + if (dev_priv == NULL) { + dev->dev_private = DRM(calloc)(1, sizeof(drm_sis_private_t), + DRM_MEM_DRIVER); + dev_priv = dev->dev_private; + if (dev_priv == NULL) + return ENOMEM; + } + + if (dev_priv->FBHeap != NULL) + return DRM_ERR(EINVAL); + + dev_priv->FBHeap = mmInit(fb.offset, fb.size); + + DRM_DEBUG("offset = %u, size = %u", fb.offset, fb.size); + + return 0; +} + +int sis_fb_alloc( DRM_IOCTL_ARGS ) { - return -1; + DRM_DEVICE; + drm_sis_private_t *dev_priv = dev->dev_private; + drm_sis_mem_t fb; + PMemBlock block; + int retval = 0; + + if (dev_priv == NULL || dev_priv->FBHeap == NULL) + return DRM_ERR(EINVAL); + + DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_mem_t *)data, sizeof(fb)); + + block = mmAllocMem(dev_priv->FBHeap, fb.size, 0, 0); + if (block) { + /* TODO */ + fb.offset = block->ofs; + fb.free = (unsigned long)block; + if (!add_alloc_set(fb.context, VIDEO_TYPE, fb.free)) { + DRM_DEBUG("adding to allocation set fails\n"); + mmFreeMem((PMemBlock)fb.free); + retval = DRM_ERR(EINVAL); + } + } else { + fb.offset = 0; + fb.size = 0; + fb.free = 0; + } + + DRM_COPY_TO_USER_IOCTL((drm_sis_mem_t *)data, fb, sizeof(fb)); + + DRM_DEBUG("alloc fb, size = %d, offset = %d\n", fb.size, fb.offset); + + return retval; } -int sis_fb_free(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) +int sis_fb_free( DRM_IOCTL_ARGS ) { - return 0; + DRM_DEVICE; + drm_sis_private_t *dev_priv = dev->dev_private; + drm_sis_mem_t fb; + + if (dev_priv == NULL || dev_priv->FBHeap == NULL) + return DRM_ERR(EINVAL); + + DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_mem_t *)data, sizeof(fb)); + + if (!mmBlockInHeap(dev_priv->FBHeap, (PMemBlock)fb.free)) + return DRM_ERR(EINVAL); + + if (!del_alloc_set(fb.context, VIDEO_TYPE, fb.free)) + return DRM_ERR(EINVAL); + mmFreeMem((PMemBlock)fb.free); + + DRM_DEBUG("free fb, free = 0x%lx\n", fb.free); + + return 0; } #endif /* agp memory management */ -#if 1 - -static memHeap_t *AgpHeap = NULL; -int sisp_agp_init(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) +int sis_ioctl_agp_init( DRM_IOCTL_ARGS ) { - drm_sis_agp_t agp; - - if (copy_from_user(&agp, (drm_sis_agp_t *)arg, sizeof(agp))) - return -EFAULT; + DRM_DEVICE; + drm_sis_private_t *dev_priv = dev->dev_private; + drm_sis_agp_t agp; + + if (dev_priv == NULL) { + dev->dev_private = DRM(calloc)(1, sizeof(drm_sis_private_t), + DRM_MEM_DRIVER); + dev_priv = dev->dev_private; + if (dev_priv == NULL) + return ENOMEM; + } - AgpHeap = mmInit(agp.offset, agp.size); + if (dev_priv->AGPHeap != NULL) + return DRM_ERR(EINVAL); - DRM_DEBUG("offset = %u, size = %u", agp.offset, agp.size); + DRM_COPY_FROM_USER_IOCTL(agp, (drm_sis_agp_t *)data, sizeof(agp)); + + dev_priv->AGPHeap = mmInit(agp.offset, agp.size); + + DRM_DEBUG("offset = %u, size = %u", agp.offset, agp.size); - return 0; + return 0; } -int sisp_agp_alloc(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) +int sis_ioctl_agp_alloc( DRM_IOCTL_ARGS ) { - drm_sis_mem_t agp; - PMemBlock block; - int retval = 0; + DRM_DEVICE; + drm_sis_private_t *dev_priv = dev->dev_private; + drm_sis_mem_t agp; + PMemBlock block; + int retval = 0; - if(!AgpHeap) - return -1; + if (dev_priv == NULL || dev_priv->AGPHeap == NULL) + return DRM_ERR(EINVAL); - if (copy_from_user(&agp, (drm_sis_mem_t *)arg, sizeof(agp))) - return -EFAULT; + DRM_COPY_FROM_USER_IOCTL(agp, (drm_sis_mem_t *)data, sizeof(agp)); - block = mmAllocMem(AgpHeap, agp.size, 0, 0); - if(block){ - /* TODO */ - agp.offset = block->ofs; - agp.free = (unsigned long)block; - if(!add_alloc_set(agp.context, AGP_TYPE, agp.free)){ - DRM_DEBUG("adding to allocation set fails\n"); - mmFreeMem((PMemBlock)agp.free); - retval = -1; - } - } - else{ - agp.offset = 0; - agp.size = 0; - agp.free = 0; - } - - if (copy_to_user((drm_sis_mem_t *)arg, &agp, sizeof(agp))) return -EFAULT; + block = mmAllocMem(dev_priv->AGPHeap, agp.size, 0, 0); + if (block) { + /* TODO */ + agp.offset = block->ofs; + agp.free = (unsigned long)block; + if (!add_alloc_set(agp.context, AGP_TYPE, agp.free)) { + DRM_DEBUG("adding to allocation set fails\n"); + mmFreeMem((PMemBlock)agp.free); + retval = -1; + } + } else { + agp.offset = 0; + agp.size = 0; + agp.free = 0; + } - DRM_DEBUG("alloc agp, size = %d, offset = %d\n", agp.size, agp.offset); + DRM_COPY_TO_USER_IOCTL((drm_sis_mem_t *)data, agp, sizeof(agp)); - return retval; + DRM_DEBUG("alloc agp, size = %d, offset = %d\n", agp.size, agp.offset); + + return retval; } -int sisp_agp_free(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) +int sis_ioctl_agp_free( DRM_IOCTL_ARGS ) { - drm_sis_mem_t agp; - int retval = 0; + DRM_DEVICE; + drm_sis_private_t *dev_priv = dev->dev_private; + drm_sis_mem_t agp; - if(!AgpHeap) - return -1; - - if (copy_from_user(&agp, (drm_sis_mem_t *)arg, sizeof(agp))) - return -EFAULT; - - if(!agp.free){ - return -1; - } - - mmFreeMem((PMemBlock)agp.free); - if(!del_alloc_set(agp.context, AGP_TYPE, agp.free)) - retval = -1; + if (dev_priv == NULL || dev_priv->AGPHeap == NULL) + return DRM_ERR(EINVAL); - DRM_DEBUG("free agp, free = %ld\n", agp.free); - - return retval; -} + DRM_COPY_FROM_USER_IOCTL(agp, (drm_sis_mem_t *)data, sizeof(agp)); -#endif + if (!mmBlockInHeap(dev_priv->AGPHeap, (PMemBlock)agp.free)) + return DRM_ERR(EINVAL); + + mmFreeMem((PMemBlock)agp.free); + if (!del_alloc_set(agp.context, AGP_TYPE, agp.free)) + return DRM_ERR(EINVAL); + + DRM_DEBUG("free agp, free = 0x%lx\n", agp.free); + + return 0; +} int sis_init_context(int context) { int i; - - for(i = 0; i < MAX_CONTEXT ; i++) - if(global_ppriv[i].used && (global_ppriv[i].context == context)) - break; - - if(i >= MAX_CONTEXT){ - for(i = 0; i < MAX_CONTEXT ; i++){ - if(!global_ppriv[i].used){ - global_ppriv[i].context = context; - global_ppriv[i].used = 1; - global_ppriv[i].sets[0] = setInit(); - global_ppriv[i].sets[1] = setInit(); - DRM_DEBUG("init allocation set, socket=%d, context = %d\n", - i, context); - break; - } - } - if((i >= MAX_CONTEXT) || (global_ppriv[i].sets[0] == NULL) || - (global_ppriv[i].sets[1] == NULL)){ - return 0; - } + + for (i = 0; i < MAX_CONTEXT ; i++) { + if (global_ppriv[i].used && + (global_ppriv[i].context == context)) + break; + } + + if (i >= MAX_CONTEXT) { + for (i = 0; i < MAX_CONTEXT ; i++) { + if (!global_ppriv[i].used) { + global_ppriv[i].context = context; + global_ppriv[i].used = 1; + global_ppriv[i].sets[0] = setInit(); + global_ppriv[i].sets[1] = setInit(); + DRM_DEBUG("init allocation set, socket=%d, " + "context = %d\n", i, context); + break; + } + } + if ((i >= MAX_CONTEXT) || (global_ppriv[i].sets[0] == NULL) || + (global_ppriv[i].sets[1] == NULL)) + { + return 0; + } } return 1; @@ -262,45 +359,45 @@ { int i; - for(i=0; icount == 1) && (info->count != 1)) { + if ((atomic_read(&tty->count) == 1) && (info->count != 1)) { /* * Uh, oh. tty->count is 1, which means that the tty * structure will be freed. Info->count should always diff -urN linux-2.4.23-pre8/drivers/char/esp.c linux-2.4.23-pre8-pac1/drivers/char/esp.c --- linux-2.4.23-pre8/drivers/char/esp.c 2002-08-03 02:39:43.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/esp.c 2003-10-24 14:31:26.000000000 +0200 @@ -136,7 +136,7 @@ #if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT) #define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \ - kdevname(tty->device), (info->flags), serial_refcount,info->count,tty->count,s) + kdevname(tty->device), (info->flags), serial_refcount,info->count,atomic_read(&tty->count),s) #else #define DBG_CNT(s) #endif @@ -2051,7 +2051,7 @@ #ifdef SERIAL_DEBUG_OPEN printk("rs_close ttys%d, count = %d\n", info->line, info->count); #endif - if ((tty->count == 1) && (info->count != 1)) { + if ((atomic_read(&tty->count) == 1) && (info->count != 1)) { /* * Uh, oh. tty->count is 1, which means that the tty * structure will be freed. Info->count should always diff -urN linux-2.4.23-pre8/drivers/char/generic_serial.c linux-2.4.23-pre8-pac1/drivers/char/generic_serial.c --- linux-2.4.23-pre8/drivers/char/generic_serial.c 2002-11-29 00:53:12.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/char/generic_serial.c 2003-10-24 14:31:26.000000000 +0200 @@ -753,7 +753,7 @@ return; } - if ((tty->count == 1) && (port->count != 1)) { + if ((atomic_read(&tty->count) == 1) && (port->count != 1)) { printk(KERN_ERR "gs: gs_close: bad port count;" " tty->count is 1, port count is %d\n", port->count); port->count = 1; diff -urN linux-2.4.23-pre8/drivers/char/ip2main.c linux-2.4.23-pre8-pac1/drivers/char/ip2main.c --- linux-2.4.23-pre8/drivers/char/ip2main.c 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/ip2main.c 2003-10-24 14:31:26.000000000 +0200 @@ -372,7 +372,7 @@ #if defined(MODULE) && defined(IP2DEBUG_OPEN) #define DBG_CNT(s) printk(KERN_DEBUG "(%s): [%x] refc=%d, ttyc=%d, modc=%x -> %s\n", \ kdevname(tty->device),(pCh->flags),ref_count, \ - tty->count,/*GET_USE_COUNT(module)*/0,s) + atomic_read(&tty->count),/*GET_USE_COUNT(module)*/0,s) #else #define DBG_CNT(s) #endif @@ -1740,7 +1740,7 @@ noblock: /* first open - Assign termios structure to port */ - if ( tty->count == 1 ) { + if ( atomic_read(&tty->count) == 1 ) { i2QueueCommands(PTYPE_INLINE, pCh, 0, 2, CMD_CTSFL_DSAB, CMD_RTSFL_DSAB); if ( pCh->flags & ASYNC_SPLIT_TERMIOS ) { if ( tty->driver.subtype == SERIAL_TYPE_NORMAL ) { @@ -1805,7 +1805,7 @@ return; } - if ( tty->count > 1 ) { /* not the last close */ + if ( atomic_read(&tty->count) > 1 ) { /* not the last close */ MOD_DEC_USE_COUNT; ip2trace (CHANN, ITRC_CLOSE, 2, 1, 3 ); @@ -3364,7 +3364,7 @@ pCh = DevTable[i]; if (pCh) { tty = pCh->pTTY; - if (tty && tty->count) { + if (tty && atomic_read(&tty->count)) { len += sprintf(buf+len,FMTLINE,i,(int)tty->flags,pCh->flags, tty->termios->c_cflag,tty->termios->c_iflag); diff -urN linux-2.4.23-pre8/drivers/char/isicom.c linux-2.4.23-pre8-pac1/drivers/char/isicom.c --- linux-2.4.23-pre8/drivers/char/isicom.c 2003-06-13 16:51:33.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/isicom.c 2003-10-24 14:31:26.000000000 +0200 @@ -1160,7 +1160,7 @@ return; } - if ((tty->count == 1) && (port->count != 1)) { + if ((atomic_read(&tty->count) == 1) && (port->count != 1)) { printk(KERN_WARNING "ISICOM:(0x%x) isicom_close: bad port count" "tty->count = 1 port count = %d.\n", card->base, port->count); diff -urN linux-2.4.23-pre8/drivers/char/istallion.c linux-2.4.23-pre8-pac1/drivers/char/istallion.c --- linux-2.4.23-pre8/drivers/char/istallion.c 2002-08-03 02:39:43.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/istallion.c 2003-10-24 14:31:26.000000000 +0200 @@ -1173,7 +1173,7 @@ restore_flags(flags); return; } - if ((tty->count == 1) && (portp->refcount != 1)) + if ((atomic_read(&tty->count) == 1) && (portp->refcount != 1)) portp->refcount = 1; if (portp->refcount-- > 1) { MOD_DEC_USE_COUNT; diff -urN linux-2.4.23-pre8/drivers/char/moxa.c linux-2.4.23-pre8-pac1/drivers/char/moxa.c --- linux-2.4.23-pre8/drivers/char/moxa.c 2001-10-25 22:53:47.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/moxa.c 2003-10-24 14:31:26.000000000 +0200 @@ -642,7 +642,7 @@ } ch = (struct moxa_str *) tty->driver_data; - if ((tty->count == 1) && (ch->count != 1)) { + if ((atomic_read(&tty->count) == 1) && (ch->count != 1)) { printk("moxa_close: bad serial port count; tty->count is 1, " "ch->count is %d\n", ch->count); ch->count = 1; diff -urN linux-2.4.23-pre8/drivers/char/mwave/mwavedd.c linux-2.4.23-pre8-pac1/drivers/char/mwave/mwavedd.c --- linux-2.4.23-pre8/drivers/char/mwave/mwavedd.c 2003-06-13 16:51:33.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/mwave/mwavedd.c 2003-10-24 14:31:26.000000000 +0200 @@ -279,7 +279,6 @@ pDrvData->IPCs[ipcnum].bIsHere = FALSE; pDrvData->IPCs[ipcnum].bIsEnabled = TRUE; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) - current->nice = -20; /* boost to provide priority timing */ #else current->priority = 0x28; /* boost to provide priority timing */ #endif diff -urN linux-2.4.23-pre8/drivers/char/mxser.c linux-2.4.23-pre8-pac1/drivers/char/mxser.c --- linux-2.4.23-pre8/drivers/char/mxser.c 2002-11-29 00:53:12.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/char/mxser.c 2003-10-24 14:31:26.000000000 +0200 @@ -824,7 +824,7 @@ MOD_DEC_USE_COUNT; return; } - if ((tty->count == 1) && (info->count != 1)) { + if ((atomic_read(&tty->count) == 1) && (info->count != 1)) { /* * Uh, oh. tty->count is 1, which means that the tty * structure will be freed. Info->count should always diff -urN linux-2.4.23-pre8/drivers/char/n_tty.c linux-2.4.23-pre8-pac1/drivers/char/n_tty.c --- linux-2.4.23-pre8/drivers/char/n_tty.c 2003-08-25 13:44:41.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/n_tty.c 2003-10-24 14:31:26.000000000 +0200 @@ -119,7 +119,7 @@ */ static void check_unthrottle(struct tty_struct * tty) { - if (tty->count && + if (atomic_read(&tty->count) && test_and_clear_bit(TTY_THROTTLED, &tty->flags) && tty->driver.unthrottle) tty->driver.unthrottle(tty); @@ -1170,7 +1170,8 @@ retval = -ERESTARTSYS; break; } - if (tty_hung_up_p(file) || (tty->link && !tty->link->count)) { + if (tty_hung_up_p(file) || + (tty->link && !atomic_read(&tty->link->count))) { retval = -EIO; break; } diff -urN linux-2.4.23-pre8/drivers/char/nwflash.c linux-2.4.23-pre8-pac1/drivers/char/nwflash.c --- linux-2.4.23-pre8/drivers/char/nwflash.c 2001-10-12 22:48:42.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/nwflash.c 2003-10-24 14:31:26.000000000 +0200 @@ -154,12 +154,11 @@ if (down_interruptible(&nwflash_sem)) return -ERESTARTSYS; - ret = copy_to_user(buf, (void *)(FLASH_BASE + p), count); - if (ret == 0) { - ret = count; - *ppos += count; - } + ret = count - copy_to_user(buf, (void *)(FLASH_BASE + p), count); + *ppos += ret; up(&nwflash_sem); + if (ret == 0) + ret = -EFAULT; } return ret; } diff -urN linux-2.4.23-pre8/drivers/char/pc_keyb.c linux-2.4.23-pre8-pac1/drivers/char/pc_keyb.c --- linux-2.4.23-pre8/drivers/char/pc_keyb.c 2002-11-29 00:53:12.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/char/pc_keyb.c 2003-10-24 14:31:26.000000000 +0200 @@ -1225,41 +1225,13 @@ #endif /* CONFIG_PSMOUSE */ -static int blink_frequency = HZ/2; +void pckbd_blink (char led) { + led = led ? (0x01 | 0x04) : 0x00; -/* Tell the user who may be running in X and not see the console that we have - panic'ed. This is to distingush panics from "real" lockups. - Could in theory send the panic message as morse, but that is left as an - exercise for the reader. */ -void panic_blink(void) -{ - static unsigned long last_jiffie; - static char led; - /* Roughly 1/2s frequency. KDB uses about 1s. Make sure it is - different. */ - if (!blink_frequency) - return; - if (jiffies - last_jiffie > blink_frequency) { - led ^= 0x01 | 0x04; while (kbd_read_status() & KBD_STAT_IBF) mdelay(1); kbd_write_output(KBD_CMD_SET_LEDS); mdelay(1); while (kbd_read_status() & KBD_STAT_IBF) mdelay(1); mdelay(1); kbd_write_output(led); - last_jiffie = jiffies; - } -} - -static int __init panicblink_setup(char *str) -{ - int par; - if (get_option(&str,&par)) - blink_frequency = par*(1000/HZ); - return 1; } - -/* panicblink=0 disables the blinking as it caused problems with some console - switches. otherwise argument is ms of a blink period. */ -__setup("panicblink=", panicblink_setup); - diff -urN linux-2.4.23-pre8/drivers/char/pcmcia/synclink_cs.c linux-2.4.23-pre8-pac1/drivers/char/pcmcia/synclink_cs.c --- linux-2.4.23-pre8/drivers/char/pcmcia/synclink_cs.c 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/pcmcia/synclink_cs.c 2003-10-24 14:31:26.000000000 +0200 @@ -2638,7 +2638,7 @@ if (tty_hung_up_p(filp)) goto cleanup; - if ((tty->count == 1) && (info->count != 1)) { + if ((atomic_read(&tty->count) == 1) && (info->count != 1)) { /* * tty->count is 1 and the tty structure will be freed. * info->count should be one in this case. @@ -3015,7 +3015,7 @@ cleanup: if (retval) { - if (tty->count == 1) + if (atomic_read(&tty->count) == 1) info->tty = 0; /* tty layer will release tty struct */ if(MOD_IN_USE) MOD_DEC_USE_COUNT; diff -urN linux-2.4.23-pre8/drivers/char/pcxx.c linux-2.4.23-pre8-pac1/drivers/char/pcxx.c --- linux-2.4.23-pre8/drivers/char/pcxx.c 2002-11-29 00:53:12.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/char/pcxx.c 2003-10-24 14:31:26.000000000 +0200 @@ -123,7 +123,7 @@ MODULE_PARM(numports, "1-4i"); # endif -#endif MODULE +#endif /* MODULE */ static int numcards = 1; static int nbdevs = 0; @@ -581,7 +581,7 @@ return; } /* this check is in serial.c, it won't hurt to do it here too */ - if ((tty->count == 1) && (info->count != 1)) { + if ((atomic_read(&tty->count) == 1) && (info->count != 1)) { /* * Uh, oh. tty->count is 1, which means that the tty * structure will be freed. Info->count should always diff -urN linux-2.4.23-pre8/drivers/char/pty.c linux-2.4.23-pre8-pac1/drivers/char/pty.c --- linux-2.4.23-pre8/drivers/char/pty.c 2002-08-03 02:39:43.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/pty.c 2003-10-24 14:31:26.000000000 +0200 @@ -70,13 +70,18 @@ static void pty_close(struct tty_struct * tty, struct file * filp) { + int count; + if (!tty) return; + + count = atomic_read(&tty->count); if (tty->driver.subtype == PTY_TYPE_MASTER) { - if (tty->count > 1) - printk("master pty_close: count = %d!!\n", tty->count); + if (count > 1) + printk("master pty_close: count = %d!!\n", + atomic_read(&tty->count)); } else { - if (tty->count > 2) + if (count > 2) return; } wake_up_interruptible(&tty->read_wait); @@ -329,7 +334,7 @@ goto out; if (test_bit(TTY_PTY_LOCK, &tty->link->flags)) goto out; - if (tty->link->count != 1) + if (atomic_read(&tty->link->count) != 1) goto out; clear_bit(TTY_OTHER_CLOSED, &tty->link->flags); diff -urN linux-2.4.23-pre8/drivers/char/raw.c linux-2.4.23-pre8-pac1/drivers/char/raw.c --- linux-2.4.23-pre8/drivers/char/raw.c 2003-06-13 16:51:33.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/raw.c 2003-10-24 14:31:26.000000000 +0200 @@ -86,12 +86,6 @@ filp->f_op = &raw_ctl_fops; return 0; } - - if (!filp->f_iobuf) { - err = alloc_kiovec(1, &filp->f_iobuf); - if (err) - return err; - } down(&raw_devices[minor].mutex); /* @@ -292,7 +286,6 @@ size_t size, loff_t *offp) { struct kiobuf * iobuf; - int new_iobuf; int err = 0; unsigned long blocknr, blocks; size_t transferred; @@ -311,18 +304,10 @@ minor = MINOR(filp->f_dentry->d_inode->i_rdev); - new_iobuf = 0; - iobuf = filp->f_iobuf; - if (test_and_set_bit(0, &filp->f_iobuf_lock)) { - /* - * A parallel read/write is using the preallocated iobuf - * so just run slow and allocate a new one. - */ - err = alloc_kiovec(1, &iobuf); - if (err) - goto out; - new_iobuf = 1; - } + err = alloc_kiovec(1, &iobuf); + if (err) + return err; + dev = to_kdev_t(raw_devices[minor].binding->bd_dev); sector_size = raw_devices[minor].sector_size; @@ -395,10 +380,6 @@ } out_free: - if (!new_iobuf) - clear_bit(0, &filp->f_iobuf_lock); - else - free_kiovec(1, &iobuf); - out: + free_kiovec(1, &iobuf); return err; } diff -urN linux-2.4.23-pre8/drivers/char/riscom8.c linux-2.4.23-pre8-pac1/drivers/char/riscom8.c --- linux-2.4.23-pre8/drivers/char/riscom8.c 2001-09-14 00:21:32.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/riscom8.c 2003-10-24 14:31:26.000000000 +0200 @@ -1142,7 +1142,7 @@ goto out; bp = port_Board(port); - if ((tty->count == 1) && (port->count != 1)) { + if ((atomic_read(&tty->count) == 1) && (port->count != 1)) { printk(KERN_INFO "rc%d: rc_close: bad port count;" " tty->count is 1, port count is %d\n", board_No(bp), port->count); diff -urN linux-2.4.23-pre8/drivers/char/rocket.c linux-2.4.23-pre8-pac1/drivers/char/rocket.c --- linux-2.4.23-pre8/drivers/char/rocket.c 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/rocket.c 2003-10-24 14:31:26.000000000 +0200 @@ -1052,7 +1052,7 @@ restore_flags(flags); return; } - if ((tty->count == 1) && (info->count != 1)) { + if ((atomic_read(&tty->count) == 1) && (info->count != 1)) { /* * Uh, oh. tty->count is 1, which means that the tty * structure will be freed. Info->count should always diff -urN linux-2.4.23-pre8/drivers/char/serial.c linux-2.4.23-pre8-pac1/drivers/char/serial.c --- linux-2.4.23-pre8/drivers/char/serial.c 2003-08-25 13:44:41.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/serial.c 2003-10-24 14:31:26.000000000 +0200 @@ -62,6 +62,10 @@ * Robert Schwebel , * Juergen Beisert , * Theodore Ts'o + * 4/02: added TTY_DO_WRITE_WAKEUP to enable n_tty to send POLL_OUTS + * to waiting processes + * Sapan Bhatia + * */ static char *serial_version = "5.05c"; @@ -203,6 +207,7 @@ #include #include #include +#include #if (LINUX_VERSION_CODE >= 131343) #include #endif @@ -306,8 +311,8 @@ { "TI16750", 64, UART_CLEAR_FIFO | UART_USE_FIFO}, { "Startech", 1, 0}, /* usurped by cyclades.c */ { "16C950/954", 128, UART_CLEAR_FIFO | UART_USE_FIFO}, - { "ST16654", 64, UART_CLEAR_FIFO | UART_USE_FIFO | - UART_STARTECH }, + { "ST16654", 64-8, UART_CLEAR_FIFO | UART_USE_FIFO | + UART_STARTECH }, /* ST16654 xmit trigger lvl = 8 */ { "XR16850", 128, UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH }, { "RSA", 2048, UART_CLEAR_FIFO | UART_USE_FIFO }, @@ -370,7 +375,7 @@ #if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT) #define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \ - kdevname(tty->device), (info->flags), serial_refcount,info->count,tty->count,s) + kdevname(tty->device), (info->flags), serial_refcount,info->count,atomic_read(&tty->count),s) #else #define DBG_CNT(s) #endif @@ -1218,7 +1223,7 @@ if (!page) return -ENOMEM; - save_flags(flags); cli(); + spin_lock_irqsave( &info->irq_spinlock, flags); if (info->flags & ASYNC_INITIALIZED) { free_page(page); @@ -1456,11 +1461,11 @@ change_speed(info, 0); info->flags |= ASYNC_INITIALIZED; - restore_flags(flags); + spin_unlock_irqrestore( &info->irq_spinlock, flags); return 0; errout: - restore_flags(flags); + spin_unlock_irqrestore( &info->irq_spinlock, flags); return retval; } @@ -1484,7 +1489,7 @@ state->irq); #endif - save_flags(flags); cli(); /* Disable interrupts */ + spin_lock_irqsave( &info->irq_spinlock, flags); /* * clear delta_msr_wait queue to avoid mem leaks: we may free the irq @@ -1492,41 +1497,6 @@ */ wake_up_interruptible(&info->delta_msr_wait); - /* - * First unlink the serial port from the IRQ chain... - */ - if (info->next_port) - info->next_port->prev_port = info->prev_port; - if (info->prev_port) - info->prev_port->next_port = info->next_port; - else - IRQ_ports[state->irq] = info->next_port; - figure_IRQ_timeout(state->irq); - - /* - * Free the IRQ, if necessary - */ - if (state->irq && (!IRQ_ports[state->irq] || - !IRQ_ports[state->irq]->next_port)) { - if (IRQ_ports[state->irq]) { - free_irq(state->irq, &IRQ_ports[state->irq]); - retval = request_irq(state->irq, rs_interrupt_single, - SA_SHIRQ, "serial", - &IRQ_ports[state->irq]); - - if (retval) - printk("serial shutdown: request_irq: error %d" - " Couldn't reacquire IRQ.\n", retval); - } else - free_irq(state->irq, &IRQ_ports[state->irq]); - } - - if (info->xmit.buf) { - unsigned long pg = (unsigned long) info->xmit.buf; - info->xmit.buf = 0; - free_page(pg); - } - info->IER = 0; serial_outp(info, UART_IER, 0x00); /* disable all intrs */ #ifdef CONFIG_SERIAL_MANY_PORTS @@ -1583,7 +1553,43 @@ serial_outp(info, UART_IER, UART_IERX_SLEEP); } info->flags &= ~ASYNC_INITIALIZED; - restore_flags(flags); + + /* + * First unlink the serial port from the IRQ chain... + */ + if (info->next_port) + info->next_port->prev_port = info->prev_port; + if (info->prev_port) + info->prev_port->next_port = info->next_port; + else + IRQ_ports[state->irq] = info->next_port; + figure_IRQ_timeout(state->irq); + + /* + * Free the IRQ, if necessary + */ + if (state->irq && (!IRQ_ports[state->irq] || + !IRQ_ports[state->irq]->next_port)) { + if (IRQ_ports[state->irq]) { + free_irq(state->irq, &IRQ_ports[state->irq]); + retval = request_irq(state->irq, rs_interrupt_single, + SA_SHIRQ, "serial", + &IRQ_ports[state->irq]); + + if (retval) + printk("serial shutdown: request_irq: error %d" + " Couldn't reacquire IRQ.\n", retval); + } else + free_irq(state->irq, &IRQ_ports[state->irq]); + } + + if (info->xmit.buf) { + unsigned long pg = (unsigned long) info->xmit.buf; + info->xmit.buf = 0; + free_page(pg); + } + + spin_unlock_irqrestore( &info->irq_spinlock, flags); } #if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */ @@ -2791,7 +2797,7 @@ #ifdef SERIAL_DEBUG_OPEN printk("rs_close ttys%d, count = %d\n", info->line, state->count); #endif - if ((tty->count == 1) && (state->count != 1)) { + if ((atomic_read(&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 @@ -3128,6 +3134,7 @@ info->tqueue.routine = do_softint; info->tqueue.data = info; info->state = sstate; + spin_lock_init(&info->irq_spinlock); if (sstate->info) { kfree(info); *ret_info = sstate->info; @@ -3242,6 +3249,7 @@ #ifdef SERIAL_DEBUG_OPEN printk("rs_open ttys%d successful...", info->line); #endif + set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); return 0; } @@ -3655,6 +3663,7 @@ info->io_type = state->io_type; info->iomem_base = state->iomem_base; info->iomem_reg_shift = state->iomem_reg_shift; + info->irq_spinlock= (spinlock_t) SPIN_LOCK_UNLOCKED; save_flags(flags); cli(); @@ -3907,7 +3916,14 @@ case 6: /* BAR 4*/ case 7: base_idx=idx-2; /* BAR 5*/ } - + + /* AFAVLAB uses a different mixture of BARs and offsets */ + /* Not that ugly ;) -- HW */ + if (dev->vendor == PCI_VENDOR_ID_AFAVLAB && idx >= 4) { + base_idx = 4; + offset = (idx - 4) * 8; + } + /* Some Titan cards are also a little weird */ if (dev->vendor == PCI_VENDOR_ID_TITAN && (dev->device == PCI_DEVICE_ID_TITAN_400L || @@ -4311,9 +4327,11 @@ pbn_b0_bt_1_115200, pbn_b0_bt_2_115200, + pbn_b0_bt_8_115200, pbn_b0_bt_1_460800, pbn_b0_bt_2_460800, pbn_b0_bt_2_921600, + pbn_b0_bt_4_460800, pbn_b1_1_115200, pbn_b1_2_115200, @@ -4370,6 +4388,8 @@ pbn_computone_4, pbn_computone_6, pbn_computone_8, + + netmos_9845 }; static struct pci_board pci_boards[] __devinitdata = { @@ -4393,9 +4413,11 @@ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 }, /* pbn_b0_bt_1_115200 */ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 }, /* pbn_b0_bt_2_115200 */ + { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 8, 115200 }, /* pbn_b0_bt_8_115200 */ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 460800 }, /* pbn_b0_bt_1_460800 */ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 460800 }, /* pbn_b0_bt_2_460800 */ { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600 }, /* pbn_b0_bt_2_921600 */ + { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 4, 460800 }, /* pbn_b0_bt_4_460800 */ { SPCI_FL_BASE1, 1, 115200 }, /* pbn_b1_1_115200 */ { SPCI_FL_BASE1, 2, 115200 }, /* pbn_b1_2_115200 */ @@ -4478,6 +4500,7 @@ 0x40, 2, NULL, 0x200 }, { SPCI_FL_BASE0, 8, 921600, /* IOMEM */ /* pbn_computone_8 */ 0x40, 2, NULL, 0x200 }, + { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 6, 115200 }, /* netmos_9845 */ }; /* @@ -4861,6 +4884,12 @@ { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b0_bt_2_460800 }, + { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_OCTO_A, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_4_460800 }, + { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_OCTO_B, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_4_460800 }, { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_SSERIAL, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b0_bt_1_115200 }, @@ -4873,6 +4902,11 @@ PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b2_bt_2_115200 }, + /* AFAVLAB serial card, from Harald Welte */ + { PCI_VENDOR_ID_AFAVLAB, PCI_DEVICE_ID_AFAVLAB_P028, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_8_115200 }, + /* EKF addition for i960 Boards form EKF with serial port */ { PCI_VENDOR_ID_INTEL, 0x1960, 0xE4BF, PCI_ANY_ID, 0, 0, @@ -4892,6 +4926,7 @@ 0x1048, 0x1500, 0, 0, pbn_b1_1_115200 }, + /* SGI IOC3 board */ { PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3, 0xFF00, 0, 0, 0, pbn_sgi_ioc3 }, @@ -4921,6 +4956,10 @@ PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_dci_pccom8 }, + { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9845, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9845 + }, + { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xffff00, }, { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, @@ -5545,12 +5584,22 @@ tty_register_devfs(&callout_driver, 0, callout_driver.minor_start + state->line); } +#ifdef CONFIG_SERIAL_GSC + probe_serial_gsc(); +#endif +#ifdef CONFIG_SUPERIO + superio_serial_init(); +#endif #ifdef ENABLE_SERIAL_PCI probe_serial_pci(); #endif #ifdef ENABLE_SERIAL_PNP probe_serial_pnp(); #endif + // FIXME: Clean this one up +#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_PARISC) + serial_console_init(); +#endif return 0; } @@ -5660,6 +5709,7 @@ info->io_type = req->io_type; info->iomem_base = req->iomem_base; info->iomem_reg_shift = req->iomem_reg_shift; + info->irq_spinlock= (spinlock_t) SPIN_LOCK_UNLOCKED; } autoconfig(state); if (state->type == PORT_UNKNOWN) { @@ -5967,6 +6017,7 @@ info->io_type = state->io_type; info->iomem_base = state->iomem_base; info->iomem_reg_shift = state->iomem_reg_shift; + info->irq_spinlock= (spinlock_t) SPIN_LOCK_UNLOCKED; quot = state->baud_base / baud; cval = cflag & (CSIZE | CSTOPB); #if defined(__powerpc__) || defined(__alpha__) diff -urN linux-2.4.23-pre8/drivers/char/serial167.c linux-2.4.23-pre8-pac1/drivers/char/serial167.c --- linux-2.4.23-pre8/drivers/char/serial167.c 2002-11-29 00:53:12.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/char/serial167.c 2003-10-24 14:31:26.000000000 +0200 @@ -1877,7 +1877,7 @@ printk("cy_close ttyS%d, count = %d\n", info->line, info->count); #endif - if ((tty->count == 1) && (info->count != 1)) { + if ((atomic_read(&tty->count) == 1) && (info->count != 1)) { /* * Uh, oh. tty->count is 1, which means that the tty * structure will be freed. Info->count should always diff -urN linux-2.4.23-pre8/drivers/char/serial_amba.c linux-2.4.23-pre8-pac1/drivers/char/serial_amba.c --- linux-2.4.23-pre8/drivers/char/serial_amba.c 2002-08-03 02:39:43.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/serial_amba.c 2003-10-24 14:31:26.000000000 +0200 @@ -1404,7 +1404,7 @@ return; } - if ((tty->count == 1) && (state->count != 1)) { + if ((atomic_read(&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 diff -urN linux-2.4.23-pre8/drivers/char/serial_txx927.c linux-2.4.23-pre8-pac1/drivers/char/serial_txx927.c --- linux-2.4.23-pre8/drivers/char/serial_txx927.c 2002-08-03 02:39:43.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/serial_txx927.c 2003-10-24 14:31:26.000000000 +0200 @@ -155,7 +155,7 @@ #if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT) #define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \ - kdevname(tty->device), (info->flags), serial_refcount,info->count,tty->count,s) + kdevname(tty->device), (info->flags), serial_refcount,info->count,atomic_read(&tty->count),s) #else #define DBG_CNT(s) #endif @@ -1407,7 +1407,7 @@ #ifdef SERIAL_DEBUG_OPEN printk("rs_close ttys%d, count = %d\n", info->line, state->count); #endif - if ((tty->count == 1) && (state->count != 1)) { + if ((atomic_read(&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 diff -urN linux-2.4.23-pre8/drivers/char/sgiserial.c linux-2.4.23-pre8-pac1/drivers/char/sgiserial.c --- linux-2.4.23-pre8/drivers/char/sgiserial.c 2003-08-25 13:44:41.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/sgiserial.c 2003-10-24 14:31:26.000000000 +0200 @@ -1443,7 +1443,7 @@ #ifdef SERIAL_DEBUG_OPEN printk("rs_close ttys%d, count = %d\n", info->line, info->count); #endif - if ((tty->count == 1) && (info->count != 1)) { + if ((atomic_read(&tty->count) == 1) && (info->count != 1)) { /* * Uh, oh. tty->count is 1, which means that the tty * structure will be freed. Info->count should always diff -urN linux-2.4.23-pre8/drivers/char/specialix.c linux-2.4.23-pre8-pac1/drivers/char/specialix.c --- linux-2.4.23-pre8/drivers/char/specialix.c 2002-08-03 02:39:43.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/specialix.c 2003-10-24 14:31:26.000000000 +0200 @@ -1517,7 +1517,7 @@ } bp = port_Board(port); - if ((tty->count == 1) && (port->count != 1)) { + if ((atomic_read(&tty->count) == 1) && (port->count != 1)) { printk(KERN_ERR "sx%d: sx_close: bad port count;" " tty->count is 1, port count is %d\n", board_No(bp), port->count); diff -urN linux-2.4.23-pre8/drivers/char/stallion.c linux-2.4.23-pre8-pac1/drivers/char/stallion.c --- linux-2.4.23-pre8/drivers/char/stallion.c 2002-11-29 00:53:12.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/char/stallion.c 2003-10-24 14:31:26.000000000 +0200 @@ -1197,7 +1197,7 @@ restore_flags(flags); return; } - if ((tty->count == 1) && (portp->refcount != 1)) + if ((atomic_read(&tty->count) == 1) && (portp->refcount != 1)) portp->refcount = 1; if (portp->refcount-- > 1) { MOD_DEC_USE_COUNT; diff -urN linux-2.4.23-pre8/drivers/char/synclink.c linux-2.4.23-pre8-pac1/drivers/char/synclink.c --- linux-2.4.23-pre8/drivers/char/synclink.c 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/synclink.c 2003-10-24 14:31:26.000000000 +0200 @@ -3295,7 +3295,7 @@ if (tty_hung_up_p(filp)) goto cleanup; - if ((tty->count == 1) && (info->count != 1)) { + if ((atomic_read(&tty->count) == 1) && (info->count != 1)) { /* * tty->count is 1 and the tty structure will be freed. * info->count should be one in this case. @@ -3724,7 +3724,7 @@ cleanup: if (retval) { - if (tty->count == 1) + if (atomic_read(&tty->count) == 1) info->tty = 0; /* tty layer will release tty struct */ if(MOD_IN_USE) MOD_DEC_USE_COUNT; diff -urN linux-2.4.23-pre8/drivers/char/synclinkmp.c linux-2.4.23-pre8-pac1/drivers/char/synclinkmp.c --- linux-2.4.23-pre8/drivers/char/synclinkmp.c 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/synclinkmp.c 2003-10-24 14:31:26.000000000 +0200 @@ -826,7 +826,7 @@ cleanup: if (retval) { - if (tty->count == 1) + if (atomic_read(&tty->count) == 1) info->tty = 0; /* tty layer will release tty struct */ if(MOD_IN_USE) MOD_DEC_USE_COUNT; @@ -857,7 +857,7 @@ if (tty_hung_up_p(filp)) goto cleanup; - if ((tty->count == 1) && (info->count != 1)) { + if ((atomic_read(&tty->count) == 1) && (info->count != 1)) { /* * tty->count is 1 and the tty structure will be freed. * info->count should be one in this case. diff -urN linux-2.4.23-pre8/drivers/char/tipar.c linux-2.4.23-pre8-pac1/drivers/char/tipar.c --- linux-2.4.23-pre8/drivers/char/tipar.c 2003-06-13 16:51:33.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/tipar.c 2003-10-24 14:31:26.000000000 +0200 @@ -71,9 +71,11 @@ #define DRIVER_DESC "Device driver for TI/PC parallel link cables" #define DRIVER_LICENSE "GPL" -#define VERSION(ver,rel,seq) (((ver)<<16) | ((rel)<<8) | (seq)) -#if LINUX_VERSION_CODE < VERSION(2,5,0) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,18) # define minor(x) MINOR(x) +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) # define need_resched() (current->need_resched) #endif diff -urN linux-2.4.23-pre8/drivers/char/tty_io.c linux-2.4.23-pre8-pac1/drivers/char/tty_io.c --- linux-2.4.23-pre8/drivers/char/tty_io.c 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/tty_io.c 2003-10-24 14:31:26.000000000 +0200 @@ -145,8 +145,8 @@ extern void au1x00_serial_console_init(void); extern int rs_8xx_init(void); extern void mac_scc_console_init(void); -extern void hwc_console_init(void); -extern void hwc_tty_init(void); +extern void sclp_console_init(void); +extern void sclp_tty_init(void); extern void con3215_init(void); extern void tty3215_init(void); extern void tub3270_con_init(void); @@ -247,14 +247,15 @@ file_list_unlock(); if (tty->driver.type == TTY_DRIVER_TYPE_PTY && tty->driver.subtype == PTY_TYPE_SLAVE && - tty->link && tty->link->count) + tty->link && atomic_read(&tty->link->count)) count++; - if (tty->count != count) { + if (atomic_read(&tty->count) != count) { printk(KERN_WARNING "Warning: dev (%s) tty->count(%d) " "!= #fd's(%d) in %s\n", - kdevname(tty->device), tty->count, count, routine); + kdevname(tty->device), atomic_read(&tty->count), + count, routine); return count; - } + } #endif return 0; } @@ -930,7 +931,7 @@ o_tty->termios_locked = *o_ltp_loc; (*driver->other->refcount)++; if (driver->subtype == PTY_TYPE_MASTER) - o_tty->count++; + atomic_inc(&o_tty->count); /* Establish the links in both directions */ tty->link = o_tty; @@ -951,7 +952,7 @@ tty->termios = *tp_loc; tty->termios_locked = *ltp_loc; (*driver->refcount)++; - tty->count++; + atomic_inc(&tty->count); /* * Structures all installed ... call the ldisc open routines. @@ -990,13 +991,13 @@ * special case for PTY masters: only one open permitted, * and the slave side open count is incremented as well. */ - if (tty->count) { + if (atomic_read(&tty->count)) { retval = -EIO; goto end_init; } - tty->link->count++; + atomic_inc(&tty->link->count); } - tty->count++; + atomic_inc(&tty->count); tty->driver = *driver; /* N.B. why do this every time?? */ success: @@ -1120,7 +1121,7 @@ #ifdef TTY_DEBUG_HANGUP printk(KERN_DEBUG "release_dev of %s (tty count=%d)...", - tty_name(tty, buf), tty->count); + tty_name(tty, buf), atomic_read(&tty->count)); #endif #ifdef TTY_PARANOIA_CHECK @@ -1172,9 +1173,9 @@ * each iteration we avoid any problems. */ while (1) { - tty_closing = tty->count <= 1; + tty_closing = atomic_read(&tty->count) <= 1; o_tty_closing = o_tty && - (o_tty->count <= (pty_master ? 1 : 0)); + (atomic_read(&o_tty->count) <= (pty_master ? 1 : 0)); do_sleep = 0; if (tty_closing) { @@ -1211,17 +1212,20 @@ * block, so it's safe to proceed with closing. */ if (pty_master) { - if (--o_tty->count < 0) { + atomic_dec(&o_tty->count); + if (atomic_read(&o_tty->count) < 0) { printk(KERN_WARNING "release_dev: bad pty slave count " "(%d) for %s\n", - o_tty->count, tty_name(o_tty, buf)); - o_tty->count = 0; + atomic_read(&o_tty->count), + tty_name(o_tty, buf)); + atomic_set(&o_tty->count, 0); } } - if (--tty->count < 0) { + atomic_dec(&tty->count); + if (atomic_read(&tty->count) < 0) { printk(KERN_WARNING "release_dev: bad tty->count (%d) for %s\n", - tty->count, tty_name(tty, buf)); - tty->count = 0; + atomic_read(&tty->count), tty_name(tty, buf)); + atomic_set(&tty->count, 0); } /* @@ -1437,7 +1441,7 @@ } if ((tty->driver.type == TTY_DRIVER_TYPE_SERIAL) && (tty->driver.subtype == SERIAL_TYPE_CALLOUT) && - (tty->count == 1)) { + (atomic_read(&tty->count) == 1)) { static int nr_warns; if (nr_warns < 5) { printk(KERN_WARNING "tty_io.c: " @@ -2278,8 +2282,8 @@ #ifdef CONFIG_TN3215 con3215_init(); #endif -#ifdef CONFIG_HWC - hwc_console_init(); +#ifdef CONFIG_SCLP_CONSOLE + sclp_console_init(); #endif #ifdef CONFIG_STDIO_CONSOLE stdio_console_init(); @@ -2450,8 +2454,8 @@ #ifdef CONFIG_TN3215 tty3215_init(); #endif -#ifdef CONFIG_HWC - hwc_tty_init(); +#ifdef CONFIG_SCLP_TTY + sclp_tty_init(); #endif #ifdef CONFIG_A2232 a2232board_init(); diff -urN linux-2.4.23-pre8/drivers/char/vac-serial.c linux-2.4.23-pre8-pac1/drivers/char/vac-serial.c --- linux-2.4.23-pre8/drivers/char/vac-serial.c 2003-08-25 13:44:41.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/char/vac-serial.c 2003-10-24 14:31:26.000000000 +0200 @@ -29,7 +29,7 @@ #if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT) #define DBG_CNT(s) baget_printk("(%s):[%x] refc=%d, serc=%d, ttyc=%d-> %s\n", \ - kdevname(tty->device),(info->flags),serial_refcount,info->count,tty->count,s) + kdevname(tty->device),(info->flags),serial_refcount,info->count,atomic_read(&tty->count),s) #else #define DBG_CNT(s) #endif @@ -1658,7 +1658,7 @@ baget_printk("rs_close ttys%d, count = %d\n", info->line, state->count); #endif - if ((tty->count == 1) && (state->count != 1)) { + if ((atomic_read(&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 diff -urN linux-2.4.23-pre8/drivers/char/vblank.c linux-2.4.23-pre8-pac1/drivers/char/vblank.c --- linux-2.4.23-pre8/drivers/char/vblank.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/char/vblank.c 2003-10-24 14:31:26.000000000 +0200 @@ -0,0 +1,612 @@ +/* + * Vertical blank interrupt driver for PCI devices + * + * (C) Copyright 2003 Soeren Sandmann + * (C) Copyright 2003 Red Hat + * + * Based heavily on svgalib interrupt.c by Matan Ziv-Av + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * 0.00 SS Original Driver + * 0.01 Alan Moved to miscdev, rewrote interfaces + * 0.02 SS Fixed lots of bugs + * Andersca + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static int try_vga = 0; /* Set to try generic VGA on unknowns */ + +struct video_card; + +struct vblank_ops +{ + int (*test)(struct video_card *); + void (*enable)(struct video_card *); + void (*disable)(struct video_card *); +}; + +struct video_card +{ + struct pci_dev *pci_dev; /* PCI device */ + unsigned long iobase; /* Base for I/O */ + unsigned long mmio; /* Our MMIO mapping if any */ + unsigned long mmio_len; + struct vblank_ops *vops; + + int running:1; + + unsigned int count; /* Counter for interrupts */ + spinlock_t lock; /* Protects count */ + + wait_queue_head_t wait; /* Woken each vblank */ + struct fasync_struct *async_queue; /* Async chain */ + + u32 saved_pmc; +}; + + +/* + * Based on interrupt.c from svgalib + * Author: Matan Ziv-Av (matan@svgalib.org) + */ + +static int vga_test_vsync(struct video_card *card) +{ + return inb(card->iobase + 0x3C2) & 0x80; +} + +static void vga_clear_disable_vsync(struct video_card *card) +{ + u8 pb; + + outb(0x11, card->iobase + 0x3d4); + pb = inb(card->iobase + 0x3d5); + outb(0x11, card->iobase + 0x3d4); + outb(pb & 0xef, card->iobase + 0x3d5); +} + +static void vga_enable_vsync(struct video_card *card) +{ + u8 pb; + + /* + * Enable interrupt, clear pending + */ + outb(0x11, card->iobase + 0x3d4); + pb = inb(card->iobase + 0x3d5); + outb(0x11, card->iobase + 0x3d4); + outb((pb&0xcf) , card->iobase + 0x3d5); + + /* + * Allow interrupts + */ + outb(0x11, card->iobase + 0x3d4); + pb = inb(card->iobase + 0x3d5); + outb(0x11, card->iobase + 0x3d4); + outb(pb | 0x10 , card->iobase + 0x3d5); +} + +static struct vblank_ops vblank_io_ops = +{ + vga_test_vsync, + vga_enable_vsync, + vga_clear_disable_vsync, +}; + +static int vga_mm_test_vsync(struct video_card *card) +{ + return readb(card->iobase + 0x3C2) & 0x80; +} + +static void vga_mm_clear_disable_vsync(struct video_card *card) +{ + u8 pb; + + writeb(0x11, card->iobase + 0x3d4); + pb = readb(card->iobase + 0x3d5); + writeb(0x11, card->iobase + 0x3d4); + writeb(pb & 0xef, card->iobase + 0x3d5); +} + +static void vga_mm_enable_vsync(struct video_card *card) +{ + u8 pb; + + /* + * Enable interrupt, clear pending + */ + writeb(0x11, card->iobase + 0x3d4); + pb = readb(card->iobase + 0x3d5); + writeb(0x11, card->iobase + 0x3d4); + writeb((pb&0xcf) , card->iobase + 0x3d5); + + /* + * Allow interrupts + */ + writeb(0x11, card->iobase + 0x3d4); + pb = readb(card->iobase + 0x3d5); + writeb(0x11, card->iobase + 0x3d4); + writeb(pb | 0x10 , card->iobase + 0x3d5); +} + +static struct vblank_ops vga_mm_ops = +{ + vga_mm_test_vsync, + vga_mm_enable_vsync, + vga_mm_clear_disable_vsync, +}; + + +static int nv3_test_vsync(struct video_card *card) +{ + return readl(card->iobase+0x400100)&0x100; +} + +static void nv3_clear_and_disable_vsync(struct video_card *card) +{ + /* disable interrupt, clear pending */ + writel(0xffffffff, card->iobase + 0x000100); + writel(0x100, card->iobase + 0x400100); + writel(0, card->iobase + 0x000140); + writel(0, card->iobase + 0x400140); + writel(card->saved_pmc, card->iobase + 0x000200); +} + +static void nv3_enable_vsync(struct video_card *card) +{ + card->saved_pmc = inl(card->iobase + 0x200); + writel(card->saved_pmc|0x1000, card->iobase+0x200); + writel(0x1, card->iobase + 0x000140); + writel(0x100, card->iobase + 0x400140); + writel(0xffffffff, card->iobase + 0x000100); + writel(0xffffffff, card->iobase + 0x400100); +} + +static struct vblank_ops nv3_ops = { + nv3_test_vsync, + nv3_enable_vsync, + nv3_clear_and_disable_vsync, +}; + +static int nv4_test_vsync(struct video_card *card) +{ + return readl(card->iobase+0x600100)&0x1; +} + +static void nv4_clear_and_disable_vsync(struct video_card *card) +{ + /* disable interrupt, clear pending */ + writel(0xffffffff, card->iobase + 0x000100); + writel(0x1, card->iobase + 0x600100); + writel(0, card->iobase + 0x000140); + writel(0, card->iobase + 0x600140); + writel(card->saved_pmc, card->iobase + 0x000200); +} + +static void nv4_enable_vsync(struct video_card *card) +{ + card->saved_pmc = inl(card->iobase + 0x200); + writel(card->saved_pmc|(1<<24),card->iobase+0x200); + writel(0x1, card->iobase + 0x000140); + writel(0x1, card->iobase + 0x600140); + writel(0xffffffff, card->iobase + 0x000100); + writel(0xffffffff, card->iobase + 0x600100); +} + +static struct vblank_ops nv4_ops = { + nv4_test_vsync, + nv4_enable_vsync, + nv4_clear_and_disable_vsync, +}; + + +static int r128_test_vsync(struct video_card *card) +{ + return readl(card->iobase + 0x44) &1; +} + +static void r128_clear_and_disable_vsync(struct video_card *card) +{ + writel(1, card->iobase + 0x44); + writel(readl(card->iobase + 0x40) & 0xfffffffe, card->iobase + 0x40); +} + +static void r128_enable_vsync(struct video_card *card) +{ + writel(1, card->iobase + 0x44); + writel(readl(card->iobase + 0x40) | 1, card->iobase + 0x40); +} + +static struct vblank_ops r128_ops = { + r128_test_vsync, + r128_enable_vsync, + r128_clear_and_disable_vsync +}; + +static int rage_test_vsync(struct video_card *card) +{ + return inl(card->iobase + 0x18) &4; +} + +static void rage_clear_and_disable_vsync(struct video_card *card) +{ + outl((inl(card->iobase + 0x18) & 0xfffffff8) | 4, card->iobase + 0x18); +} + +static void rage_enable_vsync(struct video_card *card) +{ + outl((inl(card->iobase + 0x18) & 0xfffffff8) | 6, card->iobase + 0x18); +} + +static struct vblank_ops rage_ops = { + rage_test_vsync, + rage_enable_vsync, + rage_clear_and_disable_vsync +}; + +static int rendition_test_vsync(struct video_card *card) +{ + return inw(card->iobase + 0x44) & 1; +} + +static void rendition_clear_and_disable_vsync(struct video_card *card) +{ + outw(1, card->iobase + 0x44); + outw(0, card->iobase + 0x46); +} + +static void rendition_enable_vsync(struct video_card *card) +{ + outw(1, card->iobase + 0x44); + outw(1, card->iobase + 0x46); +} + +static struct vblank_ops rendition_ops = { + rendition_test_vsync, + rendition_enable_vsync, + rendition_clear_and_disable_vsync, +}; + +static int is_r128(struct pci_dev *pdev) +{ + switch(pdev->device) + { + case 0x4c45: + case 0x4c46: + case 0x4d46: + case 0x4d4c: + return 1; + case 0x4242: + case 0x4c57: + case 0x4c59: + case 0x4c5a: + return 1; + } + + switch(pdev->device >> 8) + { + case 0x50: + case 0x52: + case 0x53: + case 0x54: + return 1; + case 0x51: + return 1; + } + + return 0; + +} + +static int vga_init_vsync(struct video_card *card) +{ + struct pci_dev *pdev = card->pci_dev; + int res; + + switch(pdev->vendor) + { + case PCI_VENDOR_ID_MATROX: + res = 0; + if(pci_resource_len(pdev, 0) >= 1048576) + res = 1; + card->mmio = (unsigned long)ioremap(pci_resource_start(pdev, res), 0x2000); + card->mmio_len = 0x2000; + if(card->mmio == 0) + goto fail; + card->iobase = card->mmio + 0x1C00; + card->vops = &vga_mm_ops; + break; + case PCI_VENDOR_ID_SI: + card->iobase = pci_resource_start(pdev, 2) - 0x380; + card->vops = &vblank_io_ops; + break; + case PCI_VENDOR_ID_NVIDIA_SGS: + card->mmio = (unsigned long)ioremap(pci_resource_start(pdev, 0), 0x800000); + card->mmio_len = 0x800000; + if(card->mmio == 0) + goto fail; + card->iobase = card->mmio; + if(pdev->device < 0x20) + card->vops = &nv3_ops; + else + card->vops = &nv4_ops; + break; + case PCI_VENDOR_ID_NVIDIA: + card->mmio = (unsigned long)ioremap(pci_resource_start(pdev, 0), 0x800000); + card->mmio_len = 0x800000; + if(card->mmio == 0) + goto fail; + card->iobase = card->mmio; + card->vops= &nv4_ops; + break; + case PCI_VENDOR_ID_ATI: + /* FIXME: Add Radeon */ + if(is_r128(pdev)) + { + card->mmio = (unsigned long)ioremap(pci_resource_start(pdev, 2), 16384); + card->mmio_len = 16384; + if(card->mmio == 0) + goto fail; + card->iobase = card->mmio; + card->vops = &r128_ops; + } + else + { + card->iobase = pci_resource_start(pdev, 1); + card->vops = &rage_ops; + } + break; + case PCI_VENDOR_ID_RENDITION: + card->iobase = pci_resource_start(pdev, 1); + card->vops = &rendition_ops; + break; + default: + if(try_vga) + { + card->iobase = 0; + card->vops = &vblank_io_ops; + break; + } + printk(KERN_ERR "vblank: Unsupported video card %04X:%04X.\n", + pdev->vendor, pdev->device); + return -EOPNOTSUPP; + + } + return 0; +fail: + printk(KERN_ERR "vblank: Unable to map card.\n"); + return -ENOMEM; +} + +static void vblankdev_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct video_card *card = dev_id; + + spin_lock(&card->lock); + if(card->vops->test(card)) + { + card->vops->disable(card); + card->vops->enable(card); + card->count++; + wake_up_interruptible(&card->wait); + kill_fasync(&card->async_queue, SIGIO, POLL_IN); + } + spin_unlock(&card->lock); +} + +static int vblankdev_open(struct inode *inode, struct file *filp) +{ + struct video_card *card; + card = kmalloc(sizeof(struct video_card), GFP_KERNEL); + if(card == NULL) + return -ENOBUFS; + memset(card, 0, sizeof(struct video_card)); + init_waitqueue_head(&card->wait); + spin_lock_init(&card->lock); + filp->private_data = card; + return 0; +} + +static int vblankdev_fasync (int fd, struct file *filp, int mode) +{ + struct video_card *card = filp->private_data; + return fasync_helper(fd, filp, mode, &card->async_queue); +} + +static int vblankdev_release(struct inode *inode, struct file *filp) +{ + struct video_card *card = filp->private_data; + + if(card->running) + { + card->vops->disable(card); + free_irq(card->pci_dev->irq, card); + } + if(card->mmio) + iounmap((void *)card->mmio); + vblankdev_fasync(-1, filp, 0); + kfree(card); + return 0; +} + +static unsigned int vblankdev_poll(struct file *filp, poll_table *poll_table) +{ + struct video_card *card = filp->private_data; + + poll_wait(filp, &card->wait, poll_table); + if(card->count) + return POLLIN; + return 0; +} + +static ssize_t vblankdev_read(struct file *filp, char *buff, size_t count, loff_t *offp) +{ + struct video_card *card = filp->private_data; + unsigned long flags; + int err = -EWOULDBLOCK; + u32 num = 0; + size_t len; + DECLARE_WAITQUEUE(wait, current); + + /* Can't seek (pread) on this device */ + if (offp != &filp->f_pos) + return -ESPIPE; + + + add_wait_queue(&card->wait, &wait); + do + { + set_current_state(TASK_INTERRUPTIBLE); + spin_lock_irqsave(&card->lock, flags); + if(card->running) + { + num = card->count; + card->count = 0; + err = 0; + } + spin_unlock_irqrestore(&card->lock, flags); + if(num) + break; + schedule(); + if(signal_pending(current)) + { + err = -EINTR; + break; + } + } + while(!(filp->f_flags & O_NDELAY)); + + remove_wait_queue(&card->wait, &wait); + set_current_state(TASK_RUNNING); + + if(err) + return err; + + len = min(count, (size_t)4); + if(copy_to_user(buff, &num, 4)) + return -EFAULT; + return len; +} + +static int vblankdev_do_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) +{ + struct vblank_bind vbind; + struct pci_dev *pdev; + struct video_card *card = filp->private_data; + + switch(cmd) + { + case VBLIOC_BIND: + if(card->running) + return -EBUSY; + + if(copy_from_user(&vbind, (void *)arg, sizeof(struct vblank_bind))) + return -EFAULT; + + /* Domain isnt used yet */ + pdev = pci_find_slot(vbind.bus, vbind.devfn); + if(pdev == NULL) + return -ENODEV; + + if(pci_enable_device(pdev) < 0) + return -EIO; + + if(pdev->irq == 0) + return -EOPNOTSUPP; + + /* Ok try and bind it */ + card->pci_dev = pdev; + if(vga_init_vsync(card) < 0) + return -EOPNOTSUPP; + card->running = 1; + if(request_irq(pdev->irq, vblankdev_interrupt, SA_SHIRQ, "vblank", card) < 0) + { + card->running = 0; + return -EBUSY; + } + card->vops->enable(card); + return 0; + default: + return -ENOTTY; + } +} + +/* + * We need a lock here to avoid parallel binding of the same + * object. + */ + +static DECLARE_MUTEX(ioctl_sem); + +static int vblankdev_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) +{ + int ret; + + down(&ioctl_sem); + ret = vblankdev_do_ioctl(inode, filp, cmd, arg); + up(&ioctl_sem); + + return ret; +} + +static struct file_operations vblankdev_fops = { + owner: THIS_MODULE, + llseek: no_llseek, + read: vblankdev_read, + ioctl: vblankdev_ioctl, + open: vblankdev_open, + release: vblankdev_release, + fasync: vblankdev_fasync, + poll: vblankdev_poll +}; + +static struct miscdevice vblankdev = { + VBLANK_MINOR, + "vblank", + &vblankdev_fops +}; + +static int vblankdev_init(void) +{ + if(!pci_present()) + return -ENODEV; + if(misc_register(&vblankdev) < 0) + return -EINVAL; + + return 0; +} + +static void vblankdev_exit(void) +{ + misc_deregister(&vblankdev); +} + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Soeren Sandmann (sandmann@daimi.au.dk), very much based on work by Matan Ziv-Av (matan@svgalib.org), Alan Cox"); +MODULE_PARM(try_vga, "i"); + +module_init(vblankdev_init); +module_exit(vblankdev_exit); diff -urN linux-2.4.23-pre8/drivers/char/vt.c linux-2.4.23-pre8-pac1/drivers/char/vt.c --- linux-2.4.23-pre8/drivers/char/vt.c 2002-11-29 00:53:12.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/char/vt.c 2003-10-24 14:31:26.000000000 +0200 @@ -40,7 +40,8 @@ char vt_dont_switch; extern struct tty_driver console_driver; -#define VT_IS_IN_USE(i) (console_driver.table[i] && console_driver.table[i]->count) +#define VT_IS_IN_USE(i) (console_driver.table[i] && \ + atomic_read(&console_driver.table[i]->count)) #define VT_BUSY(i) (VT_IS_IN_USE(i) || i == fg_console || i == sel_cons) /* diff -urN linux-2.4.23-pre8/drivers/cpufreq/Makefile linux-2.4.23-pre8-pac1/drivers/cpufreq/Makefile --- linux-2.4.23-pre8/drivers/cpufreq/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/cpufreq/Makefile 2003-10-24 14:31:26.000000000 +0200 @@ -0,0 +1,12 @@ +O_TARGET := cpufreq.o + +# CPUfreq governors +obj-$(CONFIG_CPU_FREQ_GOV_USERSPACE) += userspace.o + +# CPUfreq cross-arch helpers +obj-$(CONFIG_CPU_FREQ_TABLE) += freq_table.o +obj-$(CONFIG_CPU_FREQ_PROC_INTF) += proc_intf.o + +export-objs := userspace.o freq_table.o + +include $(TOPDIR)/Rules.make diff -urN linux-2.4.23-pre8/drivers/cpufreq/freq_table.c linux-2.4.23-pre8-pac1/drivers/cpufreq/freq_table.c --- linux-2.4.23-pre8/drivers/cpufreq/freq_table.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/cpufreq/freq_table.c 2003-10-24 14:31:26.000000000 +0200 @@ -0,0 +1,153 @@ +/* + * linux/drivers/cpufreq/freq_table.c + * + * Copyright (C) 2002 - 2003 Dominik Brodowski + */ + +#include +#include +#include +#include +#include + +/********************************************************************* + * FREQUENCY TABLE HELPERS * + *********************************************************************/ + +int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy, + struct cpufreq_frequency_table *table) +{ + unsigned int min_freq = ~0; + unsigned int max_freq = 0; + unsigned int i = 0; + + for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) { + unsigned int freq = table[i].frequency; + if (freq == CPUFREQ_ENTRY_INVALID) + continue; + if (freq < min_freq) + min_freq = freq; + if (freq > max_freq) + max_freq = freq; + } + + policy->min = policy->cpuinfo.min_freq = min_freq; + policy->max = policy->cpuinfo.max_freq = max_freq; + + if (policy->min == ~0) + return -EINVAL; + else + return 0; +} +EXPORT_SYMBOL_GPL(cpufreq_frequency_table_cpuinfo); + + +int cpufreq_frequency_table_verify(struct cpufreq_policy *policy, + struct cpufreq_frequency_table *table) +{ + unsigned int next_larger = ~0; + unsigned int i = 0; + unsigned int count = 0; + + if (!cpu_online(policy->cpu)) + return -EINVAL; + + cpufreq_verify_within_limits(policy, + policy->cpuinfo.min_freq, + policy->cpuinfo.max_freq); + + for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) { + unsigned int freq = table[i].frequency; + if (freq == CPUFREQ_ENTRY_INVALID) + continue; + if ((freq >= policy->min) && (freq <= policy->max)) + count++; + else if ((next_larger > freq) && (freq > policy->max)) + next_larger = freq; + } + + if (!count) + policy->max = next_larger; + + cpufreq_verify_within_limits(policy, + policy->cpuinfo.min_freq, + policy->cpuinfo.max_freq); + + return 0; +} +EXPORT_SYMBOL_GPL(cpufreq_frequency_table_verify); + + +int cpufreq_frequency_table_target(struct cpufreq_policy *policy, + struct cpufreq_frequency_table *table, + unsigned int target_freq, + unsigned int relation, + unsigned int *index) +{ + struct cpufreq_frequency_table optimal = { .index = ~0, }; + struct cpufreq_frequency_table suboptimal = { .index = ~0, }; + unsigned int i; + + switch (relation) { + case CPUFREQ_RELATION_H: + optimal.frequency = 0; + suboptimal.frequency = ~0; + break; + case CPUFREQ_RELATION_L: + optimal.frequency = ~0; + suboptimal.frequency = 0; + break; + } + + if (!cpu_online(policy->cpu)) + return -EINVAL; + + for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) { + unsigned int freq = table[i].frequency; + if (freq == CPUFREQ_ENTRY_INVALID) + continue; + if ((freq < policy->min) || (freq > policy->max)) + continue; + switch(relation) { + case CPUFREQ_RELATION_H: + if (freq <= target_freq) { + if (freq >= optimal.frequency) { + optimal.frequency = freq; + optimal.index = i; + } + } else { + if (freq <= suboptimal.frequency) { + suboptimal.frequency = freq; + suboptimal.index = i; + } + } + break; + case CPUFREQ_RELATION_L: + if (freq >= target_freq) { + if (freq <= optimal.frequency) { + optimal.frequency = freq; + optimal.index = i; + } + } else { + if (freq >= suboptimal.frequency) { + suboptimal.frequency = freq; + suboptimal.index = i; + } + } + break; + } + } + if (optimal.index > i) { + if (suboptimal.index > i) + return -EINVAL; + *index = suboptimal.index; + } else + *index = optimal.index; + + return 0; +} +EXPORT_SYMBOL_GPL(cpufreq_frequency_table_target); + +MODULE_AUTHOR ("Dominik Brodowski "); +MODULE_DESCRIPTION ("CPUfreq frequency table helpers"); +MODULE_LICENSE ("GPL"); diff -urN linux-2.4.23-pre8/drivers/cpufreq/proc_intf.c linux-2.4.23-pre8-pac1/drivers/cpufreq/proc_intf.c --- linux-2.4.23-pre8/drivers/cpufreq/proc_intf.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/cpufreq/proc_intf.c 2003-10-24 14:31:26.000000000 +0200 @@ -0,0 +1,246 @@ +/* + * linux/drivers/cpufreq/proc_intf.c + * + * Copyright (C) 2002 - 2003 Dominik Brodowski + */ + +#include +#include +#include +#include +#include +#include +#include + + +#define CPUFREQ_ALL_CPUS ((NR_CPUS)) + +/** + * cpufreq_parse_policy - parse a policy string + * @input_string: the string to parse. + * @policy: the policy written inside input_string + * + * This function parses a "policy string" - something the user echo'es into + * /proc/cpufreq or gives as boot parameter - into a struct cpufreq_policy. + * If there are invalid/missing entries, they are replaced with current + * cpufreq policy. + */ +static int cpufreq_parse_policy(char input_string[42], struct cpufreq_policy *policy) +{ + unsigned int min = 0; + unsigned int max = 0; + unsigned int cpu = 0; + char str_governor[16]; + struct cpufreq_policy current_policy; + unsigned int result = -EFAULT; + + if (!policy) + return -EINVAL; + + policy->min = 0; + policy->max = 0; + policy->policy = 0; + policy->cpu = CPUFREQ_ALL_CPUS; + + if (sscanf(input_string, "%d:%d:%d:%15s", &cpu, &min, &max, str_governor) == 4) + { + policy->min = min; + policy->max = max; + policy->cpu = cpu; + result = 0; + goto scan_policy; + } + if (sscanf(input_string, "%d%%%d%%%d%%%15s", &cpu, &min, &max, str_governor) == 4) + { + if (!cpufreq_get_policy(¤t_policy, cpu)) { + policy->min = (min * current_policy.cpuinfo.max_freq) / 100; + policy->max = (max * current_policy.cpuinfo.max_freq) / 100; + policy->cpu = cpu; + result = 0; + goto scan_policy; + } + } + + if (sscanf(input_string, "%d:%d:%15s", &min, &max, str_governor) == 3) + { + policy->min = min; + policy->max = max; + result = 0; + goto scan_policy; + } + + if (sscanf(input_string, "%d%%%d%%%15s", &min, &max, str_governor) == 3) + { + if (!cpufreq_get_policy(¤t_policy, cpu)) { + policy->min = (min * current_policy.cpuinfo.max_freq) / 100; + policy->max = (max * current_policy.cpuinfo.max_freq) / 100; + result = 0; + goto scan_policy; + } + } + + return -EINVAL; + +scan_policy: + result = cpufreq_parse_governor(str_governor, &policy->policy, &policy->governor); + + return result; +} + +/** + * cpufreq_proc_read - read /proc/cpufreq + * + * This function prints out the current cpufreq policy. + */ +static int cpufreq_proc_read ( + char *page, + char **start, + off_t off, + int count, + int *eof, + void *data) +{ + char *p = page; + int len = 0; + struct cpufreq_policy policy; + unsigned int min_pctg = 0; + unsigned int max_pctg = 0; + unsigned int i = 0; + + if (off != 0) + goto end; + + p += sprintf(p, " minimum CPU frequency - maximum CPU frequency - policy\n"); + for (i=0;iname); + break; + default: + p += sprintf(p, "INVALID\n"); + break; + } + } +end: + len = (p - page); + if (len <= off+count) + *eof = 1; + *start = page + off; + len -= off; + if (len>count) + len = count; + if (len<0) + len = 0; + + return len; +} + + +/** + * cpufreq_proc_write - handles writing into /proc/cpufreq + * + * This function calls the parsing script and then sets the policy + * accordingly. + */ +static int cpufreq_proc_write ( + struct file *file, + const char *buffer, + unsigned long count, + void *data) +{ + int result = 0; + char proc_string[42] = {'\0'}; + struct cpufreq_policy policy; + unsigned int i = 0; + + + if ((count > sizeof(proc_string) - 1)) + return -EINVAL; + + if (copy_from_user(proc_string, buffer, count)) + return -EFAULT; + + proc_string[count] = '\0'; + + result = cpufreq_parse_policy(proc_string, &policy); + if (result) + return -EFAULT; + + if (policy.cpu == CPUFREQ_ALL_CPUS) + { + for (i=0; iread_proc = cpufreq_proc_read; + entry->write_proc = cpufreq_proc_write; + } + + return 0; +} + + +/** + * cpufreq_proc_exit - removes "cpufreq" from the /proc root directory. + * + * This function removes "cpufreq" from the /proc root directory. + */ +static void __exit cpufreq_proc_exit (void) +{ + remove_proc_entry("cpufreq", &proc_root); + return; +} + +MODULE_AUTHOR ("Dominik Brodowski "); +MODULE_DESCRIPTION ("CPUfreq /proc/cpufreq interface"); +MODULE_LICENSE ("GPL"); + +module_init(cpufreq_proc_init); +module_exit(cpufreq_proc_exit); diff -urN linux-2.4.23-pre8/drivers/cpufreq/userspace.c linux-2.4.23-pre8-pac1/drivers/cpufreq/userspace.c --- linux-2.4.23-pre8/drivers/cpufreq/userspace.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/cpufreq/userspace.c 2003-10-24 14:31:26.000000000 +0200 @@ -0,0 +1,559 @@ +/* + * drivers/cpufreq/userspace.c + * + * Copyright (C) 2001 Russell King + * (C) 2002 - 2003 Dominik Brodowski + * + * $Id:$ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define CTL_CPU_VARS_SPEED_MAX(cpunr) { \ + .ctl_name = CPU_NR_FREQ_MAX, \ + .data = &cpu_max_freq[cpunr], \ + .procname = "speed-max", \ + .maxlen = sizeof(cpu_max_freq[cpunr]),\ + .mode = 0444, \ + .proc_handler = proc_dointvec, } + +#define CTL_CPU_VARS_SPEED_MIN(cpunr) { \ + .ctl_name = CPU_NR_FREQ_MIN, \ + .data = &cpu_min_freq[cpunr], \ + .procname = "speed-min", \ + .maxlen = sizeof(cpu_min_freq[cpunr]),\ + .mode = 0444, \ + .proc_handler = proc_dointvec, } + +#define CTL_CPU_VARS_SPEED(cpunr) { \ + .ctl_name = CPU_NR_FREQ, \ + .procname = "speed", \ + .mode = 0644, \ + .proc_handler = cpufreq_procctl, \ + .strategy = cpufreq_sysctl, \ + .extra1 = (void*) (cpunr), } + +#define CTL_TABLE_CPU_VARS(cpunr) static ctl_table ctl_cpu_vars_##cpunr[] = {\ + CTL_CPU_VARS_SPEED_MAX(cpunr), \ + CTL_CPU_VARS_SPEED_MIN(cpunr), \ + CTL_CPU_VARS_SPEED(cpunr), \ + { .ctl_name = 0, }, } + +/* the ctl_table entry for each CPU */ +#define CPU_ENUM(s) { \ + .ctl_name = (CPU_NR + s), \ + .procname = #s, \ + .mode = 0555, \ + .child = ctl_cpu_vars_##s } + +/** + * A few values needed by the userspace governor + */ +static unsigned int cpu_max_freq[NR_CPUS]; +static unsigned int cpu_min_freq[NR_CPUS]; +static unsigned int cpu_cur_freq[NR_CPUS]; +static unsigned int cpu_is_managed[NR_CPUS]; +static struct cpufreq_policy current_policy[NR_CPUS]; + +static DECLARE_MUTEX (userspace_sem); + + +/* keep track of frequency transitions */ +static int +userspace_cpufreq_notifier(struct notifier_block *nb, unsigned long val, + void *data) +{ + struct cpufreq_freqs *freq = data; + + cpu_cur_freq[freq->cpu] = freq->new; + + return 0; +} + +static struct notifier_block userspace_cpufreq_notifier_block = { + .notifier_call = userspace_cpufreq_notifier +}; + + +/** + * cpufreq_set - set the CPU frequency + * @freq: target frequency in kHz + * @cpu: CPU for which the frequency is to be set + * + * Sets the CPU frequency to freq. + */ +int cpufreq_set(unsigned int freq, unsigned int cpu) +{ + int ret = -EINVAL; + + down(&userspace_sem); + if (!cpu_is_managed[cpu]) + goto err; + + if (freq < cpu_min_freq[cpu]) + freq = cpu_min_freq[cpu]; + if (freq > cpu_max_freq[cpu]) + freq = cpu_max_freq[cpu]; + + ret = cpufreq_driver_target(¤t_policy[cpu], freq, + CPUFREQ_RELATION_L); + + err: + up(&userspace_sem); + return ret; +} +EXPORT_SYMBOL_GPL(cpufreq_set); + + +/** + * cpufreq_setmax - set the CPU to the maximum frequency + * @cpu - affected cpu; + * + * Sets the CPU frequency to the maximum frequency supported by + * this CPU. + */ +int cpufreq_setmax(unsigned int cpu) +{ + if (!cpu_is_managed[cpu] || !cpu_online(cpu)) + return -EINVAL; + return cpufreq_set(cpu_max_freq[cpu], cpu); +} +EXPORT_SYMBOL_GPL(cpufreq_setmax); + + +/** + * cpufreq_get - get the current CPU frequency (in kHz) + * @cpu: CPU number + * + * Get the CPU current (static) CPU frequency + */ +unsigned int cpufreq_get(unsigned int cpu) +{ + return cpu_cur_freq[cpu]; +} +EXPORT_SYMBOL(cpufreq_get); + + +#ifdef CONFIG_CPU_FREQ_24_API + + +/*********************** cpufreq_sysctl interface ********************/ +static int +cpufreq_procctl(ctl_table *ctl, int write, struct file *filp, + void *buffer, size_t *lenp) +{ + char buf[16], *p; + int cpu = (int) ctl->extra1; + int len, left = *lenp; + + if (!left || (filp->f_pos && !write) || !cpu_online(cpu)) { + *lenp = 0; + return 0; + } + + if (write) { + unsigned int freq; + + len = left; + if (left > sizeof(buf)) + left = sizeof(buf); + if (copy_from_user(buf, buffer, left)) + return -EFAULT; + buf[sizeof(buf) - 1] = '\0'; + + freq = simple_strtoul(buf, &p, 0); + cpufreq_set(freq, cpu); + } else { + len = sprintf(buf, "%d\n", cpufreq_get(cpu)); + if (len > left) + len = left; + if (copy_to_user(buffer, buf, len)) + return -EFAULT; + } + + *lenp = len; + filp->f_pos += len; + return 0; +} + +static int +cpufreq_sysctl(ctl_table *table, int *name, int nlen, + void *oldval, size_t *oldlenp, + void *newval, size_t newlen, void **context) +{ + int cpu = (int) table->extra1; + + if (!cpu_online(cpu)) + return -EINVAL; + + if (oldval && oldlenp) { + size_t oldlen; + + if (get_user(oldlen, oldlenp)) + return -EFAULT; + + if (oldlen != sizeof(unsigned int)) + return -EINVAL; + + if (put_user(cpufreq_get(cpu), (unsigned int *)oldval) || + put_user(sizeof(unsigned int), oldlenp)) + return -EFAULT; + } + if (newval && newlen) { + unsigned int freq; + + if (newlen != sizeof(unsigned int)) + return -EINVAL; + + if (get_user(freq, (unsigned int *)newval)) + return -EFAULT; + + cpufreq_set(freq, cpu); + } + return 1; +} + +/* ctl_table ctl_cpu_vars_{0,1,...,(NR_CPUS-1)} */ +/* due to NR_CPUS tweaking, a lot of if/endifs are required, sorry */ + CTL_TABLE_CPU_VARS(0); +#if NR_CPUS > 1 + CTL_TABLE_CPU_VARS(1); +#endif +#if NR_CPUS > 2 + CTL_TABLE_CPU_VARS(2); +#endif +#if NR_CPUS > 3 + CTL_TABLE_CPU_VARS(3); +#endif +#if NR_CPUS > 4 + CTL_TABLE_CPU_VARS(4); +#endif +#if NR_CPUS > 5 + CTL_TABLE_CPU_VARS(5); +#endif +#if NR_CPUS > 6 + CTL_TABLE_CPU_VARS(6); +#endif +#if NR_CPUS > 7 + CTL_TABLE_CPU_VARS(7); +#endif +#if NR_CPUS > 8 + CTL_TABLE_CPU_VARS(8); +#endif +#if NR_CPUS > 9 + CTL_TABLE_CPU_VARS(9); +#endif +#if NR_CPUS > 10 + CTL_TABLE_CPU_VARS(10); +#endif +#if NR_CPUS > 11 + CTL_TABLE_CPU_VARS(11); +#endif +#if NR_CPUS > 12 + CTL_TABLE_CPU_VARS(12); +#endif +#if NR_CPUS > 13 + CTL_TABLE_CPU_VARS(13); +#endif +#if NR_CPUS > 14 + CTL_TABLE_CPU_VARS(14); +#endif +#if NR_CPUS > 15 + CTL_TABLE_CPU_VARS(15); +#endif +#if NR_CPUS > 16 + CTL_TABLE_CPU_VARS(16); +#endif +#if NR_CPUS > 17 + CTL_TABLE_CPU_VARS(17); +#endif +#if NR_CPUS > 18 + CTL_TABLE_CPU_VARS(18); +#endif +#if NR_CPUS > 19 + CTL_TABLE_CPU_VARS(19); +#endif +#if NR_CPUS > 20 + CTL_TABLE_CPU_VARS(20); +#endif +#if NR_CPUS > 21 + CTL_TABLE_CPU_VARS(21); +#endif +#if NR_CPUS > 22 + CTL_TABLE_CPU_VARS(22); +#endif +#if NR_CPUS > 23 + CTL_TABLE_CPU_VARS(23); +#endif +#if NR_CPUS > 24 + CTL_TABLE_CPU_VARS(24); +#endif +#if NR_CPUS > 25 + CTL_TABLE_CPU_VARS(25); +#endif +#if NR_CPUS > 26 + CTL_TABLE_CPU_VARS(26); +#endif +#if NR_CPUS > 27 + CTL_TABLE_CPU_VARS(27); +#endif +#if NR_CPUS > 28 + CTL_TABLE_CPU_VARS(28); +#endif +#if NR_CPUS > 29 + CTL_TABLE_CPU_VARS(29); +#endif +#if NR_CPUS > 30 + CTL_TABLE_CPU_VARS(30); +#endif +#if NR_CPUS > 31 + CTL_TABLE_CPU_VARS(31); +#endif +#if NR_CPUS > 32 +#error please extend CPU enumeration +#endif + +/* due to NR_CPUS tweaking, a lot of if/endifs are required, sorry */ +static ctl_table ctl_cpu_table[NR_CPUS + 1] = { + CPU_ENUM(0), +#if NR_CPUS > 1 + CPU_ENUM(1), +#endif +#if NR_CPUS > 2 + CPU_ENUM(2), +#endif +#if NR_CPUS > 3 + CPU_ENUM(3), +#endif +#if NR_CPUS > 4 + CPU_ENUM(4), +#endif +#if NR_CPUS > 5 + CPU_ENUM(5), +#endif +#if NR_CPUS > 6 + CPU_ENUM(6), +#endif +#if NR_CPUS > 7 + CPU_ENUM(7), +#endif +#if NR_CPUS > 8 + CPU_ENUM(8), +#endif +#if NR_CPUS > 9 + CPU_ENUM(9), +#endif +#if NR_CPUS > 10 + CPU_ENUM(10), +#endif +#if NR_CPUS > 11 + CPU_ENUM(11), +#endif +#if NR_CPUS > 12 + CPU_ENUM(12), +#endif +#if NR_CPUS > 13 + CPU_ENUM(13), +#endif +#if NR_CPUS > 14 + CPU_ENUM(14), +#endif +#if NR_CPUS > 15 + CPU_ENUM(15), +#endif +#if NR_CPUS > 16 + CPU_ENUM(16), +#endif +#if NR_CPUS > 17 + CPU_ENUM(17), +#endif +#if NR_CPUS > 18 + CPU_ENUM(18), +#endif +#if NR_CPUS > 19 + CPU_ENUM(19), +#endif +#if NR_CPUS > 20 + CPU_ENUM(20), +#endif +#if NR_CPUS > 21 + CPU_ENUM(21), +#endif +#if NR_CPUS > 22 + CPU_ENUM(22), +#endif +#if NR_CPUS > 23 + CPU_ENUM(23), +#endif +#if NR_CPUS > 24 + CPU_ENUM(24), +#endif +#if NR_CPUS > 25 + CPU_ENUM(25), +#endif +#if NR_CPUS > 26 + CPU_ENUM(26), +#endif +#if NR_CPUS > 27 + CPU_ENUM(27), +#endif +#if NR_CPUS > 28 + CPU_ENUM(28), +#endif +#if NR_CPUS > 29 + CPU_ENUM(29), +#endif +#if NR_CPUS > 30 + CPU_ENUM(30), +#endif +#if NR_CPUS > 31 + CPU_ENUM(31), +#endif +#if NR_CPUS > 32 +#error please extend CPU enumeration +#endif + { + .ctl_name = 0, + } +}; + +static ctl_table ctl_cpu[2] = { + { + .ctl_name = CTL_CPU, + .procname = "cpu", + .mode = 0555, + .child = ctl_cpu_table, + }, + { + .ctl_name = 0, + } +}; + +struct ctl_table_header *cpufreq_sysctl_table; + +static inline void cpufreq_sysctl_init(void) +{ + cpufreq_sysctl_table = register_sysctl_table(ctl_cpu, 0); +} + +static inline void cpufreq_sysctl_exit(void) +{ + unregister_sysctl_table(cpufreq_sysctl_table); +} + +#else +#define cpufreq_sysctl_init() do {} while(0) +#define cpufreq_sysctl_exit() do {} while(0) +#endif /* CONFIG_CPU_FREQ_24API */ + + +static int cpufreq_governor_userspace(struct cpufreq_policy *policy, + unsigned int event) +{ + unsigned int cpu = policy->cpu; + switch (event) { + case CPUFREQ_GOV_START: + if ((!cpu_online(cpu)) || + !policy->cur) + return -EINVAL; + down(&userspace_sem); + cpu_is_managed[cpu] = 1; + cpu_min_freq[cpu] = policy->min; + cpu_max_freq[cpu] = policy->max; + cpu_cur_freq[cpu] = policy->cur; + memcpy (¤t_policy[cpu], policy, sizeof(struct cpufreq_policy)); + up(&userspace_sem); + break; + case CPUFREQ_GOV_STOP: + down(&userspace_sem); + cpu_is_managed[cpu] = 0; + cpu_min_freq[cpu] = 0; + cpu_max_freq[cpu] = 0; + up(&userspace_sem); + break; + case CPUFREQ_GOV_LIMITS: + down(&userspace_sem); + cpu_min_freq[cpu] = policy->min; + cpu_max_freq[cpu] = policy->max; + if (policy->max < cpu_cur_freq[cpu]) + __cpufreq_driver_target(¤t_policy[cpu], policy->max, + CPUFREQ_RELATION_H); + else if (policy->min > cpu_cur_freq[cpu]) + __cpufreq_driver_target(¤t_policy[cpu], policy->min, + CPUFREQ_RELATION_L); + memcpy (¤t_policy[cpu], policy, sizeof(struct cpufreq_policy)); + up(&userspace_sem); + break; + } + return 0; +} + +/* on ARM SA1100 we need to rely on the values of cpufreq_get() - because + * of this, cpu_cur_freq[] needs to be set early. + */ +#if defined(CONFIG_ARM) && defined(CONFIG_ARCH_SA1100) +extern unsigned int sa11x0_getspeed(void); + +static void cpufreq_sa11x0_compat(void) +{ + cpu_cur_freq[0] = sa11x0_getspeed(); +} +#else +#define cpufreq_sa11x0_compat() do {} while(0) +#endif + + +static struct cpufreq_governor cpufreq_gov_userspace = { + .name = "userspace", + .governor = cpufreq_governor_userspace, +}; +EXPORT_SYMBOL(cpufreq_gov_userspace); + +static int already_init = 0; + +int cpufreq_gov_userspace_init(void) +{ + if (!already_init) { + down(&userspace_sem); + cpufreq_sa11x0_compat(); + cpufreq_sysctl_init(); + cpufreq_register_notifier(&userspace_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); + already_init = 1; + up(&userspace_sem); + } + return cpufreq_register_governor(&cpufreq_gov_userspace); +} +EXPORT_SYMBOL(cpufreq_gov_userspace_init); + + +static void __exit cpufreq_gov_userspace_exit(void) +{ + cpufreq_unregister_governor(&cpufreq_gov_userspace); + cpufreq_unregister_notifier(&userspace_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); + cpufreq_sysctl_exit(); +} + + +MODULE_AUTHOR ("Dominik Brodowski , Russell King "); +MODULE_DESCRIPTION ("CPUfreq policy governor 'userspace'"); +MODULE_LICENSE ("GPL"); + +module_init(cpufreq_gov_userspace_init); +module_exit(cpufreq_gov_userspace_exit); diff -urN linux-2.4.23-pre8/drivers/hotplug/Config.in linux-2.4.23-pre8-pac1/drivers/hotplug/Config.in --- linux-2.4.23-pre8/drivers/hotplug/Config.in 2003-08-25 13:44:41.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/hotplug/Config.in 2003-10-24 14:31:26.000000000 +0200 @@ -6,12 +6,13 @@ dep_tristate 'Support for PCI Hotplug (EXPERIMENTAL)' CONFIG_HOTPLUG_PCI $CONFIG_EXPERIMENTAL $CONFIG_PCI +if [ "$CONFIG_ACPI_INTERPRETER" ]; then + dep_tristate ' ACPI PCI Hotplug driver' CONFIG_HOTPLUG_PCI_ACPI $CONFIG_HOTPLUG_PCI +fi dep_tristate ' Compaq PCI Hotplug driver' CONFIG_HOTPLUG_PCI_COMPAQ $CONFIG_HOTPLUG_PCI $CONFIG_X86 dep_mbool ' Save configuration into NVRAM on Compaq servers' CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM $CONFIG_HOTPLUG_PCI_COMPAQ if [ "$CONFIG_X86_IO_APIC" = "y" ]; then dep_tristate ' IBM PCI Hotplug driver' CONFIG_HOTPLUG_PCI_IBM $CONFIG_HOTPLUG_PCI $CONFIG_X86_IO_APIC $CONFIG_X86 fi -if [ "$CONFIG_ACPI_INTERPRETER" ]; then - dep_tristate ' ACPI PCI Hotplug driver' CONFIG_HOTPLUG_PCI_ACPI $CONFIG_HOTPLUG_PCI -fi +dep_tristate ' IBM Thinkpad (20H2999) Docking driver (VERY EXPERIMENTAL) ' CONFIG_HOTPLUG_PCI_H2999 $CONFIG_HOTPLUG_PCI $CONFIG_X86 endmenu diff -urN linux-2.4.23-pre8/drivers/hotplug/Makefile linux-2.4.23-pre8-pac1/drivers/hotplug/Makefile --- linux-2.4.23-pre8/drivers/hotplug/Makefile 2003-08-25 13:44:41.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/hotplug/Makefile 2003-10-24 14:31:26.000000000 +0200 @@ -12,6 +12,7 @@ obj-$(CONFIG_HOTPLUG_PCI_COMPAQ) += cpqphp.o obj-$(CONFIG_HOTPLUG_PCI_IBM) += ibmphp.o obj-$(CONFIG_HOTPLUG_PCI_ACPI) += acpiphp.o +obj-$(CONFIG_HOTPLUG_PCI_H2999) += tp600.o pci_hotplug-objs := pci_hotplug_core.o \ pci_hotplug_util.o diff -urN linux-2.4.23-pre8/drivers/hotplug/tp600.c linux-2.4.23-pre8-pac1/drivers/hotplug/tp600.c --- linux-2.4.23-pre8/drivers/hotplug/tp600.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/hotplug/tp600.c 2003-10-24 14:31:26.000000000 +0200 @@ -0,0 +1,500 @@ +/* + * Drivers for the IBM 20H2999 found in the IBM thinkpad series + * machines. + * + * This driver was done without documentation from IBM + * + * _ + * { } + * | | All reverse engineering done + * | | in accordance with 92/250/EEC + * .-.! !.-. and Copyright (Computer Programs) + * .-! ! ! !.-. Regulations 1992 (S.I. 1992 No. 3233) + * ! ! ! ; + * \ ; + * \ ; + * ! : + * ! | + * | | + * + * + * Various other IBM's tried to obtain docs but failed. For that + * reason we only support warm not hot undocking at the moment. + * + * Known bugs: + * Sometimes we hang with an IRQ storm. I don't know what + * deals with the IRQ disables yet. (Hot dock) + * Sometimes busmastering (and maybe IRQs) don't come back + * (Seems to be a buffering issue for hot dock) + * + * Yet to do: + * ISA is not yet handled (oh god help us) + * Instead of saving/restoring pci devices we should + * re-enumerate that subtree so you can change devices + * (That also deals with stale save problems) + * We need to do a proper warm save/restore interface + * Bridged cards don't yet work + * + * Usage: + * Load module + * Pray + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "pci_hotplug.h" +#include "tp600.h" + +static struct h2999_dev *testdev; + +/** + * pci_save_slot - save slot PCI data + * @slot: slot to save + * + * Save the slot data from a PCI device + */ + +static void pci_save_slot(struct h2999_slot *s) +{ + int i, n; + + for(i=0;i<8;i++) + { + struct pci_dev *p = pci_find_slot(s->dev->hotplug_bus, PCI_DEVFN(s->slotid, i)); + s->pci[i] = p; + if(p) + { + for(n = 0; n < 64; n++) + pci_read_config_dword(p, n * 4, &s->save[i][n]); +// printk("Saved %02X:%02X.%X\n", +// s->dev->hotplug_bus, s->slotid, i); + } + } +} + +static void pci_restore_slot(struct h2999_slot *s) +{ + int i,n; + + for(i = 0 ; i < 8; i++) + { + if(s->pci[i]) + { + pci_set_power_state(s->pci[i], 0); + + for(n = 0; n < 54; n++) + if(n!=1) + pci_write_config_dword(s->pci[i], n * 4, s->save[i][n]); + pci_write_config_dword(s->pci[i], 4, s->save[i][1]); +// printk("Restored %02X:%02X.%X\n", +// s->dev->hotplug_bus, s->slotid, i); + } + } +} + +/** + * slot_enable - enable H2999 slot + * @slot: slot to enable + * + * Enable a slot. Its not actually clear what this means with + * a hot dock. We can certainly 'discover' the PCI device in the + * slot when asked. + */ + +static int slot_enable(struct hotplug_slot *slot) +{ + struct h2999_slot *s = slot->private; + int i; + pci_restore_slot(s); + for(i=0; i < 8; i++) + { + if(s->pci[i] && (s->drivermap&(1<pci[i]); + } + return 0; +} + +/** + * slot_disable - disable H2999 slot + * @slot: slot to disable + * + * Disable a slot. Its not actually clear what to do here. We could + * report the device as having been removed when we are told to do + * this. + */ + +static int slot_disable(struct hotplug_slot *slot) +{ + struct h2999_slot *s = slot->private; + struct pci_dev *pdev; + int i; + + for(i = 0; i < 8; i++) + { + pdev = s->pci[i]; + /* Hack for now */ + if (pdev && pdev->driver) { + if (!pdev->driver->remove) + return -EBUSY; + } + } + + s->drivermap = 0; + + for(i = 0; i < 8; i++) + { + pdev = s->pci[i]; + if(pdev) + { + if(pdev->driver) + { + s->drivermap|=(1<driver->remove(pdev); + pdev->driver = NULL; + } + } + } + return 0; +} + +/** + * set_attention_status - set attention callback + * @slot: slot to set + * @value: on/off + * + * Called when the hotplug layer wants to set the attention status of + * the hotplug slot. The H2999 doesn't have an attention control (at + * least not that we know of). So we ignore this. + */ + +static int set_attention_status(struct hotplug_slot *slot, u8 value) +{ + return 0; +} + +/** + * hardware_test - test hardware callback + * @slot: slot to test + * value: test to run + * + * The H2999 does not support any hardware tests that we know of. + */ + +static int hardware_test(struct hotplug_slot *slot, u32 value) +{ + return 0; +} + +/** + * get_power_status - power query callback + * @slot; slot to query + * @value: returned state + * + * Called when the hotplug layer wants to ask us if the slot is + * powered. We work on the basis that all slots are powered when + * the unit is docked. This seems to be correct but I've not actually + * rammed a voltmeter into the slots to see if they are cleverer than + * that. + */ + +static int get_power_status(struct hotplug_slot *slot, u8 *value) +{ + struct h2999_slot *s = slot->private; + + /* Slots are all powered when docked */ + if(s->dev->docked > 0) + *value = 1; + else + *value = 0; + return 0; +} + +/** + * get_adapter_status - card presence query + * @slot: slot to query + * @value: returned state + * + * If we are not docked, we know the "slot" is empty. If we are + * docked its a bit more complicated. + */ + +static int get_adapter_status(struct hotplug_slot *slot, u8 *value) +{ + struct h2999_slot *s = slot->private; + + *value = 0; + + if(s->dev->docked) + *value = 1; + return 0; +} + +static struct hotplug_slot_ops h2999_ops = { + THIS_MODULE, + slot_enable, + slot_disable, + set_attention_status, + hardware_test, + get_power_status, + NULL, + NULL, + get_adapter_status +}; + +/** + * h2999_is_docked - check if docked + * @dev: h2999 device + * + * Check if we are currently docked. The method we use at the moment + * relies on poking around behind the bridge. There is no doubt a + * correct way to do this. Maybe one day IBM will be decide to + * actually provide documentation + */ + +static int h2999_is_docked(struct h2999_dev *dev) +{ + struct pci_dev *pdev = pci_find_slot(dev->hotplug_bus, PCI_DEVFN(0,0)); + u32 status; + + if(pdev == NULL) + return 0; /* Shouldnt happen - must be undocked */ + + if(pci_read_config_dword(pdev, PCI_VENDOR_ID, &status)) + return 0; /* Config read failed - its missing */ + + if(status == 0xFFFFFFFFUL) /* Failed */ + return 0; + + /* Must be docked */ + return 1; +} +/** + * h2999_reconfigure_dock - redock event handler + * @dev: h2999 device + * + * A redocking event has occurred. There may also have been an undock + * before hand. If so then the unconfigure routine is called first. + */ + +static void h2999_reconfigure_dock(struct h2999_dev *dev) +{ + int docked, i; + + docked = h2999_is_docked(dev); + + if(docked ^ dev->docked) + { + printk("h2999: Now %sdocked.\n", + docked?"":"un"); + if(docked) + { + /* We should do the re-enumeration of the bus here + The current save/restore is a test hack */ + for(i=0; i < H2999_SLOTS; i++) + { + if(dev->slots[i].hotplug_slot.private != &dev->slots[i]) + BUG(); + slot_enable(&dev->slots[i].hotplug_slot); + } + } + else + { + for(i=0; i < H2999_SLOTS; i++) + { + if(slot_disable(&dev->slots[i].hotplug_slot)) + printk(KERN_ERR "h2999: someone undocked while devices were in use, how rude!\n"); + } + } + dev->docked = docked; + } + /* Clear bits */ + pci_write_config_byte(dev->pdev, 0x1f, 0xf0); +} + +/* + * h2999_attach - attach an H2999 bridge + * @pdev: PCI device + * @unused: unused + * + * Called when the PCI layer discovers an H2999 docking bridge is + * present in the system. We scan the bridge to obtain its current + * status and register it with the hot plug layer + */ + +static int __devinit h2999_attach(struct pci_dev *pdev, const struct pci_device_id *unused) +{ + /* PCI core found a new H2999 */ + struct h2999_dev *dev; + u8 bus; + int i; + + dev = kmalloc(sizeof(*dev), GFP_KERNEL); + if(dev == NULL) + goto nomem; + + memset(dev, 0, sizeof(*dev)); + + dev->pdev = pdev; + + pci_read_config_byte(pdev, PCI_SECONDARY_BUS, &bus); + dev->hotplug_bus = bus; + + /* Requires hotplug_bus and pdev are set */ + + dev->docked = h2999_is_docked(dev); + + printk(KERN_INFO "Found IBM 20H2999. Status is %sdocked, docking bus is %d.\n", + dev->docked?"":"un", dev->hotplug_bus); + + /* + * Allow for 8 devices. On the TP600 at least we have + * 0-3 as the onboard devices, and 4-7 as the slots. + * To add more fun there is an ISA bridge which we + * don't really handle yet. + */ + + for(i = 0; i < H2999_SLOTS; i++) + { + struct h2999_slot *s = &dev->slots[i]; + int ret; + + s->hotplug_slot.info = &s->hotplug_info; + s->hotplug_slot.private = s; + s->slotid = i; + s->dev = dev; + s->live = 1; + s->hotplug_slot.ops = &h2999_ops; + s->hotplug_slot.name = s->name; + s->hotplug_info.power_status = dev->docked; + /* FIXME - should probe here + In truth the hp_register ought to call thse as needed! */ + s->hotplug_info.adapter_status = 0; + s->pdev = pci_find_slot(dev->hotplug_bus, PCI_DEVFN(i, 0)); + snprintf(s->name, SLOT_NAME_SIZE, "Dock%d.%d", dev->hotplug_bus, i); + pci_save_slot(s); + ret = pci_hp_register(&s->hotplug_slot); + if(ret) + { + printk(KERN_ERR "pci_hp_register failed for slot %d with error %d\n", i, ret); + s->live = 0; + } + } + pci_set_drvdata(pdev, dev); + + testdev = dev; + return 0; +nomem: + printk(KERN_ERR "h2999_attach: out of memory.\n"); + return -ENOMEM; +} + +/** + * h2999_cleanup - free H2999 memory resources + * @dev: h2999 device + * + * Unregister and free up all of our slots + */ + +static void __devinit h2999_cleanup(struct h2999_dev *dev) +{ + struct h2999_slot *s; + int slot; + + for(slot = 0; slot < H2999_SLOTS; slot++) + { + s = &dev->slots[slot]; + if(s->live) + pci_hp_deregister(&s->hotplug_slot); + } + kfree(dev); +} + +/** + * h2999_detach - an H2999 controller vanished + * @dev: device that vanished + * + * Called when the PCI layer sees the bridge unplugged. At the moment + * this doesn't happen and since its currently unclear what to do + * in the hot plug layer if it does this may be a good thing 8) + */ + +static void __devinit h2999_detach(struct pci_dev *pdev) +{ + struct h2999_dev *dev = pci_get_drvdata(pdev); + h2999_cleanup(dev); +} + + +static struct pci_device_id h2999_id_tbl[] __devinitdata = { + { PCI_VENDOR_ID_IBM, 0x0095, PCI_ANY_ID, PCI_ANY_ID, }, + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, h2999_id_tbl); + +static struct pci_driver h2999_driver = { + name: "h2999", + id_table: h2999_id_tbl, + probe: h2999_attach, + remove: __devexit_p(h2999_detach) + /* FIXME - PM functions */ +}; + +/* + * Test harness + */ + +static struct completion thread_done; + +static int h2999_thread(void *unused) +{ + lock_kernel(); + while(testdev != NULL) + { + set_current_state(TASK_INTERRUPTIBLE); + if(signal_pending(current)) + break; + schedule_timeout(HZ); + h2999_reconfigure_dock(testdev); + } + unlock_kernel(); + complete_and_exit(&thread_done, 0); +} + +static int __init h2999_init_module(void) +{ + int rc; + printk(KERN_INFO "IBM 20H2999 PCI docking bridge driver v0.01\n"); + + init_completion(&thread_done); + + rc = pci_module_init(&h2999_driver); + if (rc == 0) + { + if( kernel_thread(h2999_thread, NULL, CLONE_SIGHAND) >= 0) + return 0; + } + complete(&thread_done); + return rc; +} + +static void __exit h2999_cleanup_module(void) +{ + pci_unregister_driver(&h2999_driver); + wait_for_completion(&thread_done); +} + +module_init(h2999_init_module); +module_exit(h2999_cleanup_module); + +MODULE_AUTHOR("Alan Cox"); +MODULE_DESCRIPTION("IBM 20H2999 Docking Bridge Driver"); +MODULE_LICENSE("GPL"); + diff -urN linux-2.4.23-pre8/drivers/hotplug/tp600.h linux-2.4.23-pre8-pac1/drivers/hotplug/tp600.h --- linux-2.4.23-pre8/drivers/hotplug/tp600.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/hotplug/tp600.h 2003-10-24 14:31:26.000000000 +0200 @@ -0,0 +1,29 @@ +#define SLOT_NAME_SIZE 12 + +struct h2999_slot +{ + int slotid; + + struct hotplug_slot hotplug_slot; + struct hotplug_slot_info hotplug_info; + char name[SLOT_NAME_SIZE]; + + struct h2999_dev *dev; + struct pci_dev *pdev; + int live; + + struct pci_dev *pci[8]; + u32 save[8][64]; + u8 drivermap; +}; + +#define H2999_SLOTS 8 + +struct h2999_dev +{ + int docked; + int hotplug_bus; + struct pci_dev *pdev; + + struct h2999_slot slots[H2999_SLOTS]; +}; diff -urN linux-2.4.23-pre8/drivers/ide/ide-dma.c linux-2.4.23-pre8-pac1/drivers/ide/ide-dma.c --- linux-2.4.23-pre8/drivers/ide/ide-dma.c 2003-08-25 13:44:41.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/ide/ide-dma.c 2003-10-24 14:31:26.000000000 +0200 @@ -1,5 +1,5 @@ /* - * linux/drivers/ide/ide-dma.c Version 4.13 May 21, 2003 + * linux/drivers/ide/ide-dma.c Version 4.15 Sep 14, 2003 * * Copyright (c) 1999-2000 Andre Hedrick * May be copied or modified under the terms of the GNU General Public License @@ -660,11 +660,15 @@ * __ide_dma_check - check DMA setup * @drive: drive to check * - * Don't use - due for extermination + * Default check for IDE DMA being allowed. We block DMA + * if we can't configure it or if the interface lacks DMA + * for lba48 devices. */ int __ide_dma_check (ide_drive_t *drive) { + if(drive->capacity48 > (1ULL)<<28 && HWIF(drive)->lba48_pio) + return 1; return config_drive_for_dma(drive); } diff -urN linux-2.4.23-pre8/drivers/ide/ide.c linux-2.4.23-pre8-pac1/drivers/ide/ide.c --- linux-2.4.23-pre8/drivers/ide/ide.c 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/ide/ide.c 2003-10-24 14:31:26.000000000 +0200 @@ -1,5 +1,5 @@ /* - * linux/drivers/ide/ide.c Version 7.00beta3 Apr 22 2003 + * linux/drivers/ide/ide.c Version 7.00beta4 Sep 14 2003 * * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) */ @@ -121,8 +121,8 @@ * */ -#define REVISION "Revision: 7.00beta4-2.4" -#define VERSION "Id: ide.c 7.00b4 20030520" +#define REVISION "Revision: 7.00beta5-2.4" +#define VERSION "Id: ide.c 7.00b4 20030914" #undef REALLY_SLOW_IO /* most systems can safely undef this */ @@ -249,6 +249,7 @@ hwif->mwdma_mask = 0x80; /* disable all mwdma */ hwif->swdma_mask = 0x80; /* disable all swdma */ hwif->sata = 0; /* assume PATA */ + hwif->lba48_pio = 0; /* Default to old behaviour */ default_hwif_iops(hwif); default_hwif_transport(hwif); @@ -740,6 +741,8 @@ } if (!drive->present) continue; + if(idedefault_attach(drive)) + printk(KERN_ERR "%s: failed to reassigned to default driver.\n", drive->name); if (drive->id != NULL) { kfree(drive->id); drive->id = NULL; diff -urN linux-2.4.23-pre8/drivers/ide/legacy/qd65xx.c linux-2.4.23-pre8-pac1/drivers/ide/legacy/qd65xx.c --- linux-2.4.23-pre8/drivers/ide/legacy/qd65xx.c 2003-06-13 16:51:33.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/ide/legacy/qd65xx.c 2003-10-24 14:31:26.000000000 +0200 @@ -269,7 +269,7 @@ int recovery_time = 415; /* worst case values from the dos driver */ if (drive->id && !qd_find_disk_type(drive, &active_time, &recovery_time)) { - pio = ide_get_best_pio_mode(drive, pio, 255, &d); + pio = ide_get_best_pio_mode(drive, 255, pio, &d); pio = IDE_MIN(pio,4); switch (pio) { diff -urN linux-2.4.23-pre8/drivers/ide/pci/adma100.c linux-2.4.23-pre8-pac1/drivers/ide/pci/adma100.c --- linux-2.4.23-pre8/drivers/ide/pci/adma100.c 2003-06-13 16:51:33.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/ide/pci/adma100.c 2003-10-24 14:31:26.000000000 +0200 @@ -76,5 +76,7 @@ MODULE_DESCRIPTION("Basic PIO support for ADMA100 IDE"); MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, adma100_pci_tbl); + EXPORT_NO_SYMBOLS; diff -urN linux-2.4.23-pre8/drivers/ide/pci/aec62xx.c linux-2.4.23-pre8-pac1/drivers/ide/pci/aec62xx.c --- linux-2.4.23-pre8/drivers/ide/pci/aec62xx.c 2003-06-13 16:51:33.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/ide/pci/aec62xx.c 2003-10-24 14:31:26.000000000 +0200 @@ -565,4 +565,6 @@ MODULE_DESCRIPTION("PCI driver module for ARTOP AEC62xx IDE"); MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, aec62xx_pci_tbl); + EXPORT_NO_SYMBOLS; diff -urN linux-2.4.23-pre8/drivers/ide/pci/alim15x3.c linux-2.4.23-pre8-pac1/drivers/ide/pci/alim15x3.c --- linux-2.4.23-pre8/drivers/ide/pci/alim15x3.c 2003-08-25 13:44:41.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/ide/pci/alim15x3.c 2003-10-24 14:31:26.000000000 +0200 @@ -579,6 +579,22 @@ } /** + * ali15x3_dma_check - check if DMA can be used + * @drive: drive to enable DMA on + * + * Check if we can move this device into DMA. config_drive_for_dma + * does most of the work, we must check the lba48_pio flag however + * + */ + +static int ali15x3_dma_check(ide_drive_t *drive) +{ + if(drive->capacity48 > (1ULL)<<28 && HWIF(drive)->lba48_pio) + return 1; + return ali15x3_config_drive_for_dma(drive); +} + +/** * init_chipset_ali15x3 - Initialise an ALi IDE controller * @dev: PCI device * @name: Name of the controller @@ -759,8 +775,11 @@ hwif->tuneproc = &ali15x3_tune_drive; hwif->speedproc = &ali15x3_tune_chipset; - /* Don't use LBA48 on ALi devices before rev 0xC5 */ - hwif->addressing = (m5229_revision <= 0xC4) ? 1 : 0; + /* Don't use LBA48 DMA on ALi devices before rev 0xC5. + PIO is fine */ + + hwif->addressing = 0; + hwif->lba48_pio = (m5229_revision <= 0xC4) ? 1 : 0; if (!hwif->dma_base) { hwif->drives[0].autotune = 1; @@ -779,7 +798,7 @@ /* * M1543C or newer for DMAing */ - hwif->ide_dma_check = &ali15x3_config_drive_for_dma; + hwif->ide_dma_check = &ali15x3_dma_check; hwif->ide_dma_write = &ali15x3_dma_write; if (!noautodma) hwif->autodma = 1; @@ -915,4 +934,6 @@ MODULE_DESCRIPTION("PCI driver module for ALi 15x3 IDE"); MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, alim15x3_pci_tbl); + EXPORT_NO_SYMBOLS; diff -urN linux-2.4.23-pre8/drivers/ide/pci/amd74xx.c linux-2.4.23-pre8-pac1/drivers/ide/pci/amd74xx.c --- linux-2.4.23-pre8/drivers/ide/pci/amd74xx.c 2003-06-13 16:51:33.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/ide/pci/amd74xx.c 2003-10-24 14:31:26.000000000 +0200 @@ -318,7 +318,7 @@ amd_80w = ((t & 0x3) ? 1 : 0) | ((t & 0xc) ? 2 : 0); for (i = 24; i >= 0; i -= 8) if (((u >> i) & 4) && !(amd_80w & (1 << (1 - (i >> 4))))) { - printk(KERN_WARNING "AMD_IDE: Bios didn't set cable bits corectly. Enabling workaround.\n"); + printk(KERN_WARNING "AMD_IDE: Bios didn't set cable bits correctly. Enabling workaround.\n"); amd_80w |= (1 << (1 - (i >> 4))); } break; @@ -480,4 +480,6 @@ MODULE_DESCRIPTION("AMD PCI IDE driver"); MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, amd74xx_pci_tbl); + EXPORT_NO_SYMBOLS; diff -urN linux-2.4.23-pre8/drivers/ide/pci/cmd64x.c linux-2.4.23-pre8-pac1/drivers/ide/pci/cmd64x.c --- linux-2.4.23-pre8/drivers/ide/pci/cmd64x.c 2003-06-13 16:51:33.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/ide/pci/cmd64x.c 2003-10-24 14:31:26.000000000 +0200 @@ -794,5 +794,7 @@ MODULE_DESCRIPTION("PCI driver module for CMD64x IDE"); MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, cmd64x_pci_tbl); + EXPORT_NO_SYMBOLS; diff -urN linux-2.4.23-pre8/drivers/ide/pci/cs5530.c linux-2.4.23-pre8-pac1/drivers/ide/pci/cs5530.c --- linux-2.4.23-pre8/drivers/ide/pci/cs5530.c 2003-06-13 16:51:33.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/ide/pci/cs5530.c 2003-10-24 14:31:26.000000000 +0200 @@ -460,4 +460,6 @@ MODULE_DESCRIPTION("PCI driver module for Cyrix/NS 5530 IDE"); MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, cs5530_pci_tbl); + EXPORT_NO_SYMBOLS; diff -urN linux-2.4.23-pre8/drivers/ide/pci/cy82c693.c linux-2.4.23-pre8-pac1/drivers/ide/pci/cy82c693.c --- linux-2.4.23-pre8/drivers/ide/pci/cy82c693.c 2003-06-13 16:51:33.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/ide/pci/cy82c693.c 2003-10-24 14:31:26.000000000 +0200 @@ -465,4 +465,6 @@ MODULE_DESCRIPTION("PCI driver module for the Cypress CY82C693 IDE"); MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, cy82c693_pci_tbl); + EXPORT_NO_SYMBOLS; diff -urN linux-2.4.23-pre8/drivers/ide/pci/generic.c linux-2.4.23-pre8-pac1/drivers/ide/pci/generic.c --- linux-2.4.23-pre8/drivers/ide/pci/generic.c 2003-08-25 13:44:41.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/ide/pci/generic.c 2003-10-24 14:31:26.000000000 +0200 @@ -167,4 +167,6 @@ MODULE_DESCRIPTION("PCI driver module for generic PCI IDE"); MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, generic_pci_tbl); + EXPORT_NO_SYMBOLS; diff -urN linux-2.4.23-pre8/drivers/ide/pci/hpt34x.c linux-2.4.23-pre8-pac1/drivers/ide/pci/hpt34x.c --- linux-2.4.23-pre8/drivers/ide/pci/hpt34x.c 2003-06-13 16:51:33.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/ide/pci/hpt34x.c 2003-10-24 14:31:26.000000000 +0200 @@ -367,4 +367,6 @@ MODULE_DESCRIPTION("PCI driver module for Highpoint 34x IDE"); MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, hpt34x_pci_tbl); + EXPORT_NO_SYMBOLS; diff -urN linux-2.4.23-pre8/drivers/ide/pci/hpt366.c linux-2.4.23-pre8-pac1/drivers/ide/pci/hpt366.c --- linux-2.4.23-pre8/drivers/ide/pci/hpt366.c 2003-08-25 13:44:41.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/ide/pci/hpt366.c 2003-10-24 14:31:26.000000000 +0200 @@ -465,7 +465,7 @@ static void hpt3xx_tune_drive (ide_drive_t *drive, u8 pio) { - pio = ide_get_best_pio_mode(drive, pio, 5, NULL); + pio = ide_get_best_pio_mode(drive, 255, pio, NULL); (void) hpt3xx_tune_chipset(drive, (XFER_PIO_0 + pio)); } @@ -713,7 +713,7 @@ /* Reconnect channels to bus */ outb(0x00, hwif->dma_base+0x73); - outb(0x00, hwif->dma_base+0x79); + outb(0x00, hwif->dma_base+0x77); } /** @@ -1343,7 +1343,7 @@ u8 pin1 = 0, pin2 = 0; unsigned int class_rev; static char *chipset_names[] = {"HPT366", "HPT366", "HPT368", - "HPT370", "HPT370A", "HPT372"}; + "HPT370", "HPT370A", "HPT372", "HPT372N"}; if (PCI_FUNC(dev->devfn) & 1) return; @@ -1351,16 +1351,11 @@ pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); class_rev &= 0xff; - /* New ident 372N reports revision 1. We could do the - io port based type identification instead perhaps (DID, RID) */ - - if(d->device == PCI_DEVICE_ID_TTI_HPT372N) - class_rev = 5; - - if(class_rev < 6) + if(class_rev <= 6) d->name = chipset_names[class_rev]; switch(class_rev) { + case 6: case 5: case 4: case 3: ide_setup_pci_device(dev, d); @@ -1444,4 +1439,6 @@ MODULE_DESCRIPTION("PCI driver module for Highpoint HPT366 IDE"); MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, hpt366_pci_tbl); + EXPORT_NO_SYMBOLS; diff -urN linux-2.4.23-pre8/drivers/ide/pci/it8172.c linux-2.4.23-pre8-pac1/drivers/ide/pci/it8172.c --- linux-2.4.23-pre8/drivers/ide/pci/it8172.c 2003-06-13 16:51:33.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/ide/pci/it8172.c 2003-10-24 14:31:26.000000000 +0200 @@ -331,4 +331,6 @@ MODULE_DESCRIPTION("PCI driver module for ITE 8172 IDE"); MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, it8172_pci_tbl); + EXPORT_NO_SYMBOLS; diff -urN linux-2.4.23-pre8/drivers/ide/pci/ns87415.c linux-2.4.23-pre8-pac1/drivers/ide/pci/ns87415.c --- linux-2.4.23-pre8/drivers/ide/pci/ns87415.c 2003-06-13 16:51:33.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/ide/pci/ns87415.c 2003-10-24 14:31:26.000000000 +0200 @@ -264,4 +264,6 @@ MODULE_DESCRIPTION("PCI driver module for NS87415 IDE"); MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, ns87415_pci_tbl); + EXPORT_NO_SYMBOLS; diff -urN linux-2.4.23-pre8/drivers/ide/pci/opti621.c linux-2.4.23-pre8-pac1/drivers/ide/pci/opti621.c --- linux-2.4.23-pre8/drivers/ide/pci/opti621.c 2003-06-13 16:51:33.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/ide/pci/opti621.c 2003-10-24 14:31:26.000000000 +0200 @@ -400,4 +400,6 @@ MODULE_DESCRIPTION("PCI driver module for Opti621 IDE"); MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, opti621_pci_tbl); + EXPORT_NO_SYMBOLS; diff -urN linux-2.4.23-pre8/drivers/ide/pci/pdc202xx_new.c linux-2.4.23-pre8-pac1/drivers/ide/pci/pdc202xx_new.c --- linux-2.4.23-pre8/drivers/ide/pci/pdc202xx_new.c 2003-06-13 16:51:33.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/ide/pci/pdc202xx_new.c 2003-10-24 14:31:26.000000000 +0200 @@ -677,4 +677,6 @@ MODULE_DESCRIPTION("PCI driver module for Promise PDC20268 and higher"); MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, pdc202new_pci_tbl); + EXPORT_NO_SYMBOLS; diff -urN linux-2.4.23-pre8/drivers/ide/pci/pdc202xx_old.c linux-2.4.23-pre8-pac1/drivers/ide/pci/pdc202xx_old.c --- linux-2.4.23-pre8/drivers/ide/pci/pdc202xx_old.c 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/ide/pci/pdc202xx_old.c 2003-10-24 14:31:26.000000000 +0200 @@ -877,4 +877,6 @@ MODULE_DESCRIPTION("PCI driver module for older Promise IDE"); MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, pdc202xx_pci_tbl); + EXPORT_NO_SYMBOLS; diff -urN linux-2.4.23-pre8/drivers/ide/pci/piix.c linux-2.4.23-pre8-pac1/drivers/ide/pci/piix.c --- linux-2.4.23-pre8/drivers/ide/pci/piix.c 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/ide/pci/piix.c 2003-10-24 14:31:26.000000000 +0200 @@ -153,6 +153,7 @@ case PCI_DEVICE_ID_INTEL_82801DB_11: case PCI_DEVICE_ID_INTEL_82801EB_11: case PCI_DEVICE_ID_INTEL_82801E_11: + case PCI_DEVICE_ID_INTEL_ESB_2: p += sprintf(p, "PIIX4 Ultra 100 "); break; case PCI_DEVICE_ID_INTEL_82372FB_1: @@ -290,6 +291,7 @@ case PCI_DEVICE_ID_INTEL_82801DB_10: case PCI_DEVICE_ID_INTEL_82801DB_11: case PCI_DEVICE_ID_INTEL_82801EB_11: + case PCI_DEVICE_ID_INTEL_ESB_2: mode = 3; break; /* UDMA 66 capable */ @@ -680,6 +682,7 @@ case PCI_DEVICE_ID_INTEL_82801DB_11: case PCI_DEVICE_ID_INTEL_82801EB_11: case PCI_DEVICE_ID_INTEL_82801E_11: + case PCI_DEVICE_ID_INTEL_ESB_2: { unsigned int extra = 0; pci_read_config_dword(dev, 0x54, &extra); @@ -874,7 +877,10 @@ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_11,PCI_ANY_ID, PCI_ANY_ID, 0, 0, 15}, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_11, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 16}, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_10,PCI_ANY_ID, PCI_ANY_ID, 0, 0, 17}, +#if 0 /* SATA is covered by ata_piix scsi driver */ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 18}, +#endif + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 19}, { 0, }, }; @@ -902,4 +908,6 @@ MODULE_DESCRIPTION("PCI driver module for Intel PIIX IDE"); MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, piix_pci_tbl); + EXPORT_NO_SYMBOLS; diff -urN linux-2.4.23-pre8/drivers/ide/pci/piix.h linux-2.4.23-pre8-pac1/drivers/ide/pci/piix.h --- linux-2.4.23-pre8/drivers/ide/pci/piix.h 2003-06-13 16:51:33.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/ide/pci/piix.h 2003-10-24 14:31:26.000000000 +0200 @@ -305,6 +305,20 @@ .enablebits = {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, .bootable = ON_BOARD, .extra = 0, + },{ /* 19 */ + .vendor = PCI_VENDOR_ID_INTEL, + .device = PCI_DEVICE_ID_INTEL_ESB_2, + .name = "ESB", + .init_setup = init_setup_piix, + .init_chipset = init_chipset_piix, + .init_iops = NULL, + .init_hwif = init_hwif_piix, + .init_dma = init_dma_piix, + .channels = 2, + .autodma = AUTODMA, + .enablebits = {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, + .bootable = ON_BOARD, + .extra = 0, },{ .vendor = 0, .device = 0, diff -urN linux-2.4.23-pre8/drivers/ide/pci/rz1000.c linux-2.4.23-pre8-pac1/drivers/ide/pci/rz1000.c --- linux-2.4.23-pre8/drivers/ide/pci/rz1000.c 2003-06-13 16:51:33.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/ide/pci/rz1000.c 2003-10-24 14:31:26.000000000 +0200 @@ -95,5 +95,7 @@ MODULE_DESCRIPTION("PCI driver module for RZ1000 IDE"); MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, rz1000_pci_tbl); + EXPORT_NO_SYMBOLS; diff -urN linux-2.4.23-pre8/drivers/ide/pci/sc1200.c linux-2.4.23-pre8-pac1/drivers/ide/pci/sc1200.c --- linux-2.4.23-pre8/drivers/ide/pci/sc1200.c 2003-06-13 16:51:33.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/ide/pci/sc1200.c 2003-10-24 14:31:26.000000000 +0200 @@ -595,4 +595,6 @@ MODULE_DESCRIPTION("PCI driver module for NS SC1200 IDE"); MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, sc1200_pci_tbl); + EXPORT_NO_SYMBOLS; diff -urN linux-2.4.23-pre8/drivers/ide/pci/serverworks.c linux-2.4.23-pre8-pac1/drivers/ide/pci/serverworks.c --- linux-2.4.23-pre8/drivers/ide/pci/serverworks.c 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/ide/pci/serverworks.c 2003-10-24 14:31:26.000000000 +0200 @@ -839,4 +839,6 @@ MODULE_DESCRIPTION("PCI driver module for Serverworks OSB4/CSB5/CSB6 IDE"); MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, svwks_pci_tbl); + EXPORT_NO_SYMBOLS; diff -urN linux-2.4.23-pre8/drivers/ide/pci/sgiioc4.c linux-2.4.23-pre8-pac1/drivers/ide/pci/sgiioc4.c --- linux-2.4.23-pre8/drivers/ide/pci/sgiioc4.c 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/ide/pci/sgiioc4.c 2003-10-24 14:31:26.000000000 +0200 @@ -888,4 +888,6 @@ MODULE_DESCRIPTION("PCI driver module for SGI IOC4 Base-IO Card"); MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, sgiioc4_pci_tbl); + EXPORT_NO_SYMBOLS; diff -urN linux-2.4.23-pre8/drivers/ide/pci/siimage.c linux-2.4.23-pre8-pac1/drivers/ide/pci/siimage.c --- linux-2.4.23-pre8/drivers/ide/pci/siimage.c 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/ide/pci/siimage.c 2003-10-24 14:31:26.000000000 +0200 @@ -1219,4 +1219,6 @@ MODULE_DESCRIPTION("PCI driver module for SiI IDE"); MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, siimage_pci_tbl); + EXPORT_NO_SYMBOLS; diff -urN linux-2.4.23-pre8/drivers/ide/pci/sis5513.c linux-2.4.23-pre8-pac1/drivers/ide/pci/sis5513.c --- linux-2.4.23-pre8/drivers/ide/pci/sis5513.c 2003-08-25 13:44:41.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/ide/pci/sis5513.c 2003-10-24 14:31:26.000000000 +0200 @@ -989,6 +989,8 @@ MODULE_DESCRIPTION("PCI driver module for SIS IDE"); MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, sis5513_pci_tbl); + EXPORT_NO_SYMBOLS; /* diff -urN linux-2.4.23-pre8/drivers/ide/pci/sl82c105.c linux-2.4.23-pre8-pac1/drivers/ide/pci/sl82c105.c --- linux-2.4.23-pre8/drivers/ide/pci/sl82c105.c 2003-06-13 16:51:33.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/ide/pci/sl82c105.c 2003-10-24 14:31:26.000000000 +0200 @@ -536,4 +536,6 @@ MODULE_DESCRIPTION("PCI driver module for W82C105 IDE"); MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, sl82c105_pci_tbl); + EXPORT_NO_SYMBOLS; diff -urN linux-2.4.23-pre8/drivers/ide/pci/slc90e66.c linux-2.4.23-pre8-pac1/drivers/ide/pci/slc90e66.c --- linux-2.4.23-pre8/drivers/ide/pci/slc90e66.c 2003-06-13 16:51:33.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/ide/pci/slc90e66.c 2003-10-24 14:31:26.000000000 +0200 @@ -409,4 +409,6 @@ MODULE_DESCRIPTION("PCI driver module for SLC90E66 IDE"); MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, slc90e66_pci_tbl); + EXPORT_NO_SYMBOLS; diff -urN linux-2.4.23-pre8/drivers/ide/pci/triflex.c linux-2.4.23-pre8-pac1/drivers/ide/pci/triflex.c --- linux-2.4.23-pre8/drivers/ide/pci/triflex.c 2003-06-13 16:51:33.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/ide/pci/triflex.c 2003-10-24 14:31:26.000000000 +0200 @@ -253,4 +253,6 @@ MODULE_DESCRIPTION("PCI driver module for Compaq Triflex IDE"); MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, triflex_pci_tbl); +EXPORT_NO_SYMBOLS; diff -urN linux-2.4.23-pre8/drivers/ide/pci/trm290.c linux-2.4.23-pre8-pac1/drivers/ide/pci/trm290.c --- linux-2.4.23-pre8/drivers/ide/pci/trm290.c 2003-06-13 16:51:33.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/ide/pci/trm290.c 2003-10-24 14:31:26.000000000 +0200 @@ -309,7 +309,10 @@ u8 reg = 0; struct pci_dev *dev = hwif->pci_dev; - hwif->addressing = 1; + /* LBA48 is only supported for PIO */ + hwif->addressing = 0; + hwif->lba48_pio = 1; + hwif->chipset = ide_trm290; cfgbase = pci_resource_start(dev, 4); if ((dev->class & 5) && cfgbase) { @@ -449,4 +452,6 @@ MODULE_DESCRIPTION("PCI driver module for Tekram TRM290 IDE"); MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, trm290_pci_tbl); + EXPORT_NO_SYMBOLS; diff -urN linux-2.4.23-pre8/drivers/ide/pci/via82cxxx.c linux-2.4.23-pre8-pac1/drivers/ide/pci/via82cxxx.c --- linux-2.4.23-pre8/drivers/ide/pci/via82cxxx.c 2003-08-25 13:44:41.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/ide/pci/via82cxxx.c 2003-10-24 14:31:26.000000000 +0200 @@ -667,4 +667,6 @@ MODULE_DESCRIPTION("PCI driver module for VIA IDE"); MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, via_pci_tbl); + EXPORT_NO_SYMBOLS; diff -urN linux-2.4.23-pre8/drivers/ide/raid/hptraid.c linux-2.4.23-pre8-pac1/drivers/ide/raid/hptraid.c --- linux-2.4.23-pre8/drivers/ide/raid/hptraid.c 2003-10-24 14:27:22.000000000 +0200 +++ linux-2.4.23-pre8-pac1/drivers/ide/raid/hptraid.c 2003-10-24 14:31:26.000000000 +0200 @@ -18,7 +18,11 @@ Based on work done by Søren Schmidt for FreeBSD Changelog: - 15.06.2003 wweissmann@gmx.at + 19.08.2003 v0.03 wweissmann@gmx.at + * register the raid volume only if all disks are available + * print a warning that raid-(0+)1 failover is not supported + + 15.06.2003 v0.02 wweissmann@gmx.at * correct values of raid-1 superbock * re-add check for availability of all disks * fix offset bug in raid-1 (introduced in raid 0+1 implementation) @@ -814,10 +818,6 @@ break; } - /* Initialize the gendisk structure */ - - ataraid_register_disk(device,raid[device].sectors); - /* Verify that we have all disks */ count=count_disks(raid+device); @@ -844,7 +844,17 @@ return -ENODEV; } } + printk(KERN_WARNING "ataraid%i: raid-0+1 disk failover is not implemented!\n", + device); } + else if (type == HPT_T_RAID_1) { + printk(KERN_WARNING "ataraid%i: raid-1 disk failover is not implemented!\n", + device); + } + /* Initialize the gendisk structure */ + + ataraid_register_disk(device,raid[device].sectors); + return 0; } @@ -856,7 +866,7 @@ int retval=-ENODEV; int device,i,count=0; - printk(KERN_INFO "Highpoint HPT370 Softwareraid driver for linux version 0.02\n"); + printk(KERN_INFO "Highpoint HPT370 Softwareraid driver for linux version 0.03\n"); for(i=0; oplist[i].op; i++) { do diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/README.txt linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/README.txt --- linux-2.4.23-pre8/drivers/ieee1394/.svn/README.txt 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/README.txt 2003-07-21 13:09:27.000000000 +0200 @@ -0,0 +1,2 @@ +This is a Subversion working copy administrative directory. +Visit http://subversion.tigris.org/ for more information. diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/dir-prop-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/dir-prop-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/dir-prop-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/dir-prop-base 2003-07-21 13:09:47.000000000 +0200 @@ -0,0 +1,8 @@ +K 10 +svn:ignore +V 25 +.*.o.flags +.depend +oui.c + +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/dir-props linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/dir-props --- linux-2.4.23-pre8/drivers/ieee1394/.svn/dir-props 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/dir-props 2003-07-21 13:09:47.000000000 +0200 @@ -0,0 +1,8 @@ +K 10 +svn:ignore +V 25 +.*.o.flags +.depend +oui.c + +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/entries linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/entries --- linux-2.4.23-pre8/drivers/ieee1394/.svn/entries 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/entries 2003-10-24 14:24:06.000000000 +0200 @@ -0,0 +1,410 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/format linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/format --- linux-2.4.23-pre8/drivers/ieee1394/.svn/format 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/format 2003-07-21 13:09:27.000000000 +0200 @@ -0,0 +1 @@ +2 diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/Config.in.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/Config.in.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/Config.in.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/Config.in.svn-base 2003-07-21 13:09:44.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/Makefile.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/Makefile.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/Makefile.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/Makefile.svn-base 2003-07-21 13:09:38.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/amdtp.c.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/amdtp.c.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/amdtp.c.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/amdtp.c.svn-base 2003-07-21 13:09:34.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/amdtp.h.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/amdtp.h.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/amdtp.h.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/amdtp.h.svn-base 2003-07-21 13:09:35.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/cmp.c.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/cmp.c.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/cmp.c.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/cmp.c.svn-base 2003-07-27 22:04:44.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/cmp.h.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/cmp.h.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/cmp.h.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/cmp.h.svn-base 2003-07-21 13:09:42.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/csr.c.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/csr.c.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/csr.c.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/csr.c.svn-base 2003-09-08 03:33:08.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/csr.h.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/csr.h.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/csr.h.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/csr.h.svn-base 2003-07-27 22:04:45.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/dma.c.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/dma.c.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/dma.c.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/dma.c.svn-base 2003-07-21 13:09:38.000000000 +0200 @@ -0,0 +1 @@ +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/dma.h.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/dma.h.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/dma.h.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/dma.h.svn-base 2003-07-21 13:09:40.000000000 +0200 @@ -0,0 +1 @@ +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/dv1394-private.h.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/dv1394-private.h.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/dv1394-private.h.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/dv1394-private.h.svn-base 2003-07-21 13:09:35.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/dv1394.c.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/dv1394.c.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/dv1394.c.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/dv1394.c.svn-base 2003-07-21 13:09:45.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/dv1394.h.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/dv1394.h.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/dv1394.h.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/dv1394.h.svn-base 2003-07-21 13:09:32.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/eth1394.c.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/eth1394.c.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/eth1394.c.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/eth1394.c.svn-base 2003-09-08 03:33:07.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/eth1394.h.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/eth1394.h.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/eth1394.h.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/eth1394.h.svn-base 2003-08-02 02:45:12.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/highlevel.c.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/highlevel.c.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/highlevel.c.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/highlevel.c.svn-base 2003-07-27 22:04:43.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/highlevel.h.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/highlevel.h.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/highlevel.h.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/highlevel.h.svn-base 2003-07-27 22:04:44.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/hosts.c.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/hosts.c.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/hosts.c.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/hosts.c.svn-base 2003-07-27 22:04:42.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/hosts.h.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/hosts.h.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/hosts.h.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/hosts.h.svn-base 2003-07-27 22:04:42.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/ieee1394-ioctl.h.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/ieee1394-ioctl.h.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/ieee1394-ioctl.h.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/ieee1394-ioctl.h.svn-base 2003-09-10 20:28:20.000000000 +0200 @@ -0,0 +1 @@ +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/ieee1394.h.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/ieee1394.h.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/ieee1394.h.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/ieee1394.h.svn-base 2003-07-21 13:09:46.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/ieee1394_core.c.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/ieee1394_core.c.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/ieee1394_core.c.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/ieee1394_core.c.svn-base 2003-10-12 01:06:14.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/ieee1394_core.h.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/ieee1394_core.h.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/ieee1394_core.h.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/ieee1394_core.h.svn-base 2003-07-27 22:04:40.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/ieee1394_hotplug.h.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/ieee1394_hotplug.h.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/ieee1394_hotplug.h.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/ieee1394_hotplug.h.svn-base 2003-07-21 13:09:32.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/ieee1394_transactions.c.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/ieee1394_transactions.c.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/ieee1394_transactions.c.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/ieee1394_transactions.c.svn-base 2003-09-08 03:33:05.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/ieee1394_transactions.h.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/ieee1394_transactions.h.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/ieee1394_transactions.h.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/ieee1394_transactions.h.svn-base 2003-09-08 03:33:06.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/ieee1394_types.h.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/ieee1394_types.h.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/ieee1394_types.h.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/ieee1394_types.h.svn-base 2003-07-27 22:04:44.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/iso.c.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/iso.c.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/iso.c.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/iso.c.svn-base 2003-07-21 13:09:45.000000000 +0200 @@ -0,0 +1 @@ +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/iso.h.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/iso.h.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/iso.h.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/iso.h.svn-base 2003-07-21 13:09:32.000000000 +0200 @@ -0,0 +1 @@ +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/nodemgr.c.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/nodemgr.c.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/nodemgr.c.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/nodemgr.c.svn-base 2003-10-12 01:06:14.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/nodemgr.h.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/nodemgr.h.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/nodemgr.h.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/nodemgr.h.svn-base 2003-07-21 13:09:38.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/ohci1394.c.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/ohci1394.c.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/ohci1394.c.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/ohci1394.c.svn-base 2003-09-08 03:33:03.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/ohci1394.h.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/ohci1394.h.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/ohci1394.h.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/ohci1394.h.svn-base 2003-07-21 13:09:35.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/oui.db.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/oui.db.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/oui.db.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/oui.db.svn-base 2003-07-21 13:09:31.000000000 +0200 @@ -0,0 +1 @@ +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/oui2c.sh.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/oui2c.sh.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/oui2c.sh.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/oui2c.sh.svn-base 2003-07-21 13:09:41.000000000 +0200 @@ -0,0 +1 @@ +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/pcilynx.c.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/pcilynx.c.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/pcilynx.c.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/pcilynx.c.svn-base 2003-09-08 03:33:08.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/pcilynx.h.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/pcilynx.h.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/pcilynx.h.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/pcilynx.h.svn-base 2003-07-21 13:09:46.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/raw1394-private.h.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/raw1394-private.h.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/raw1394-private.h.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/raw1394-private.h.svn-base 2003-07-21 13:09:37.000000000 +0200 @@ -0,0 +1 @@ +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/raw1394.c.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/raw1394.c.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/raw1394.c.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/raw1394.c.svn-base 2003-09-15 14:11:38.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/raw1394.h.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/raw1394.h.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/raw1394.h.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/raw1394.h.svn-base 2003-09-08 03:33:05.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/sbp2.c.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/sbp2.c.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/sbp2.c.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/sbp2.c.svn-base 2003-10-24 14:24:06.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/sbp2.h.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/sbp2.h.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/sbp2.h.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/sbp2.h.svn-base 2003-07-29 23:44:18.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/video1394.c.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/video1394.c.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/video1394.c.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/video1394.c.svn-base 2003-07-21 13:09:44.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/video1394.h.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/video1394.h.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/prop-base/video1394.h.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/prop-base/video1394.h.svn-base 2003-07-21 13:09:46.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/props/Config.in.svn-work linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/Config.in.svn-work --- linux-2.4.23-pre8/drivers/ieee1394/.svn/props/Config.in.svn-work 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/Config.in.svn-work 2003-07-21 13:09:44.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/props/Makefile.svn-work linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/Makefile.svn-work --- linux-2.4.23-pre8/drivers/ieee1394/.svn/props/Makefile.svn-work 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/Makefile.svn-work 2003-07-21 13:09:38.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/props/amdtp.c.svn-work linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/amdtp.c.svn-work --- linux-2.4.23-pre8/drivers/ieee1394/.svn/props/amdtp.c.svn-work 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/amdtp.c.svn-work 2003-07-21 13:09:34.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/props/amdtp.h.svn-work linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/amdtp.h.svn-work --- linux-2.4.23-pre8/drivers/ieee1394/.svn/props/amdtp.h.svn-work 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/amdtp.h.svn-work 2003-07-21 13:09:35.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/props/cmp.c.svn-work linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/cmp.c.svn-work --- linux-2.4.23-pre8/drivers/ieee1394/.svn/props/cmp.c.svn-work 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/cmp.c.svn-work 2003-07-27 22:04:44.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/props/cmp.h.svn-work linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/cmp.h.svn-work --- linux-2.4.23-pre8/drivers/ieee1394/.svn/props/cmp.h.svn-work 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/cmp.h.svn-work 2003-07-21 13:09:42.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/props/csr.c.svn-work linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/csr.c.svn-work --- linux-2.4.23-pre8/drivers/ieee1394/.svn/props/csr.c.svn-work 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/csr.c.svn-work 2003-09-08 03:33:08.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/props/csr.h.svn-work linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/csr.h.svn-work --- linux-2.4.23-pre8/drivers/ieee1394/.svn/props/csr.h.svn-work 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/csr.h.svn-work 2003-07-27 22:04:45.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/props/dma.c.svn-work linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/dma.c.svn-work --- linux-2.4.23-pre8/drivers/ieee1394/.svn/props/dma.c.svn-work 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/dma.c.svn-work 2003-07-21 13:09:38.000000000 +0200 @@ -0,0 +1 @@ +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/props/dma.h.svn-work linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/dma.h.svn-work --- linux-2.4.23-pre8/drivers/ieee1394/.svn/props/dma.h.svn-work 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/dma.h.svn-work 2003-07-21 13:09:40.000000000 +0200 @@ -0,0 +1 @@ +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/props/dv1394-private.h.svn-work linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/dv1394-private.h.svn-work --- linux-2.4.23-pre8/drivers/ieee1394/.svn/props/dv1394-private.h.svn-work 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/dv1394-private.h.svn-work 2003-07-21 13:09:35.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/props/dv1394.c.svn-work linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/dv1394.c.svn-work --- linux-2.4.23-pre8/drivers/ieee1394/.svn/props/dv1394.c.svn-work 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/dv1394.c.svn-work 2003-07-21 13:09:45.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/props/dv1394.h.svn-work linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/dv1394.h.svn-work --- linux-2.4.23-pre8/drivers/ieee1394/.svn/props/dv1394.h.svn-work 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/dv1394.h.svn-work 2003-07-21 13:09:32.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/props/eth1394.c.svn-work linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/eth1394.c.svn-work --- linux-2.4.23-pre8/drivers/ieee1394/.svn/props/eth1394.c.svn-work 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/eth1394.c.svn-work 2003-09-08 03:33:07.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/props/eth1394.h.svn-work linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/eth1394.h.svn-work --- linux-2.4.23-pre8/drivers/ieee1394/.svn/props/eth1394.h.svn-work 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/eth1394.h.svn-work 2003-08-02 02:45:12.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/props/highlevel.c.svn-work linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/highlevel.c.svn-work --- linux-2.4.23-pre8/drivers/ieee1394/.svn/props/highlevel.c.svn-work 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/highlevel.c.svn-work 2003-07-27 22:04:43.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/props/highlevel.h.svn-work linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/highlevel.h.svn-work --- linux-2.4.23-pre8/drivers/ieee1394/.svn/props/highlevel.h.svn-work 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/highlevel.h.svn-work 2003-07-27 22:04:44.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/props/hosts.c.svn-work linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/hosts.c.svn-work --- linux-2.4.23-pre8/drivers/ieee1394/.svn/props/hosts.c.svn-work 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/hosts.c.svn-work 2003-07-27 22:04:42.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/props/hosts.h.svn-work linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/hosts.h.svn-work --- linux-2.4.23-pre8/drivers/ieee1394/.svn/props/hosts.h.svn-work 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/hosts.h.svn-work 2003-07-27 22:04:42.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/props/ieee1394-ioctl.h.svn-work linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/ieee1394-ioctl.h.svn-work --- linux-2.4.23-pre8/drivers/ieee1394/.svn/props/ieee1394-ioctl.h.svn-work 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/ieee1394-ioctl.h.svn-work 2003-09-10 20:28:20.000000000 +0200 @@ -0,0 +1 @@ +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/props/ieee1394.h.svn-work linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/ieee1394.h.svn-work --- linux-2.4.23-pre8/drivers/ieee1394/.svn/props/ieee1394.h.svn-work 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/ieee1394.h.svn-work 2003-07-21 13:09:46.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/props/ieee1394_core.c.svn-work linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/ieee1394_core.c.svn-work --- linux-2.4.23-pre8/drivers/ieee1394/.svn/props/ieee1394_core.c.svn-work 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/ieee1394_core.c.svn-work 2003-10-12 01:06:14.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/props/ieee1394_core.h.svn-work linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/ieee1394_core.h.svn-work --- linux-2.4.23-pre8/drivers/ieee1394/.svn/props/ieee1394_core.h.svn-work 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/ieee1394_core.h.svn-work 2003-07-27 22:04:40.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/props/ieee1394_hotplug.h.svn-work linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/ieee1394_hotplug.h.svn-work --- linux-2.4.23-pre8/drivers/ieee1394/.svn/props/ieee1394_hotplug.h.svn-work 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/ieee1394_hotplug.h.svn-work 2003-07-21 13:09:32.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/props/ieee1394_transactions.c.svn-work linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/ieee1394_transactions.c.svn-work --- linux-2.4.23-pre8/drivers/ieee1394/.svn/props/ieee1394_transactions.c.svn-work 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/ieee1394_transactions.c.svn-work 2003-09-08 03:33:05.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/props/ieee1394_transactions.h.svn-work linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/ieee1394_transactions.h.svn-work --- linux-2.4.23-pre8/drivers/ieee1394/.svn/props/ieee1394_transactions.h.svn-work 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/ieee1394_transactions.h.svn-work 2003-09-08 03:33:06.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/props/ieee1394_types.h.svn-work linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/ieee1394_types.h.svn-work --- linux-2.4.23-pre8/drivers/ieee1394/.svn/props/ieee1394_types.h.svn-work 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/ieee1394_types.h.svn-work 2003-07-27 22:04:44.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/props/iso.c.svn-work linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/iso.c.svn-work --- linux-2.4.23-pre8/drivers/ieee1394/.svn/props/iso.c.svn-work 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/iso.c.svn-work 2003-07-21 13:09:45.000000000 +0200 @@ -0,0 +1 @@ +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/props/iso.h.svn-work linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/iso.h.svn-work --- linux-2.4.23-pre8/drivers/ieee1394/.svn/props/iso.h.svn-work 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/iso.h.svn-work 2003-07-21 13:09:32.000000000 +0200 @@ -0,0 +1 @@ +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/props/nodemgr.c.svn-work linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/nodemgr.c.svn-work --- linux-2.4.23-pre8/drivers/ieee1394/.svn/props/nodemgr.c.svn-work 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/nodemgr.c.svn-work 2003-10-12 01:06:14.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/props/nodemgr.h.svn-work linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/nodemgr.h.svn-work --- linux-2.4.23-pre8/drivers/ieee1394/.svn/props/nodemgr.h.svn-work 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/nodemgr.h.svn-work 2003-07-21 13:09:38.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/props/ohci1394.c.svn-work linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/ohci1394.c.svn-work --- linux-2.4.23-pre8/drivers/ieee1394/.svn/props/ohci1394.c.svn-work 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/ohci1394.c.svn-work 2003-09-08 03:33:03.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/props/ohci1394.h.svn-work linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/ohci1394.h.svn-work --- linux-2.4.23-pre8/drivers/ieee1394/.svn/props/ohci1394.h.svn-work 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/ohci1394.h.svn-work 2003-07-21 13:09:35.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/props/oui.db.svn-work linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/oui.db.svn-work --- linux-2.4.23-pre8/drivers/ieee1394/.svn/props/oui.db.svn-work 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/oui.db.svn-work 2003-07-21 13:09:31.000000000 +0200 @@ -0,0 +1 @@ +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/props/oui2c.sh.svn-work linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/oui2c.sh.svn-work --- linux-2.4.23-pre8/drivers/ieee1394/.svn/props/oui2c.sh.svn-work 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/oui2c.sh.svn-work 2003-07-21 13:09:41.000000000 +0200 @@ -0,0 +1 @@ +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/props/pcilynx.c.svn-work linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/pcilynx.c.svn-work --- linux-2.4.23-pre8/drivers/ieee1394/.svn/props/pcilynx.c.svn-work 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/pcilynx.c.svn-work 2003-09-08 03:33:08.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/props/pcilynx.h.svn-work linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/pcilynx.h.svn-work --- linux-2.4.23-pre8/drivers/ieee1394/.svn/props/pcilynx.h.svn-work 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/pcilynx.h.svn-work 2003-07-21 13:09:46.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/props/raw1394-private.h.svn-work linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/raw1394-private.h.svn-work --- linux-2.4.23-pre8/drivers/ieee1394/.svn/props/raw1394-private.h.svn-work 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/raw1394-private.h.svn-work 2003-07-21 13:09:37.000000000 +0200 @@ -0,0 +1 @@ +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/props/raw1394.c.svn-work linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/raw1394.c.svn-work --- linux-2.4.23-pre8/drivers/ieee1394/.svn/props/raw1394.c.svn-work 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/raw1394.c.svn-work 2003-09-15 14:11:38.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/props/raw1394.h.svn-work linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/raw1394.h.svn-work --- linux-2.4.23-pre8/drivers/ieee1394/.svn/props/raw1394.h.svn-work 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/raw1394.h.svn-work 2003-09-08 03:33:05.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/props/sbp2.c.svn-work linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/sbp2.c.svn-work --- linux-2.4.23-pre8/drivers/ieee1394/.svn/props/sbp2.c.svn-work 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/sbp2.c.svn-work 2003-10-24 14:24:06.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/props/sbp2.h.svn-work linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/sbp2.h.svn-work --- linux-2.4.23-pre8/drivers/ieee1394/.svn/props/sbp2.h.svn-work 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/sbp2.h.svn-work 2003-07-29 23:44:18.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/props/video1394.c.svn-work linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/video1394.c.svn-work --- linux-2.4.23-pre8/drivers/ieee1394/.svn/props/video1394.c.svn-work 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/video1394.c.svn-work 2003-07-21 13:09:44.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/props/video1394.h.svn-work linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/video1394.h.svn-work --- linux-2.4.23-pre8/drivers/ieee1394/.svn/props/video1394.h.svn-work 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/props/video1394.h.svn-work 2003-07-21 13:09:46.000000000 +0200 @@ -0,0 +1,5 @@ +K 12 +svn:keywords +V 3 +Rev +END diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/Config.in.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/Config.in.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/Config.in.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/Config.in.svn-base 2003-07-21 13:09:44.000000000 +0200 @@ -0,0 +1,46 @@ +# -*- shell-script -*- + +if [ "$CONFIG_PCI" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then + mainmenu_option next_comment + comment 'IEEE 1394 (FireWire) support (EXPERIMENTAL)' + + dep_tristate 'IEEE 1394 (FireWire) support (EXPERIMENTAL)' CONFIG_IEEE1394 $CONFIG_PCI + + if [ "$CONFIG_IEEE1394" != "n" ]; then + + comment "Device Drivers" + + if [ "$CONFIG_I2C" = "n" -o "$CONFIG_I2C_ALGOBIT" = "n" ]; then + comment ' Texas Instruments PCILynx requires I2C bit-banging' + else + dep_tristate ' Texas Instruments PCILynx support' CONFIG_IEEE1394_PCILYNX $CONFIG_IEEE1394 $CONFIG_I2C $CONFIG_I2C_ALGOBIT + fi + + # Non-maintained pcilynx options + # if [ "$CONFIG_IEEE1394_PCILYNX" != "n" ]; then + # bool ' Use PCILynx local RAM' CONFIG_IEEE1394_PCILYNX_LOCALRAM + # bool ' Support for non-IEEE1394 local ports' CONFIG_IEEE1394_PCILYNX_PORTS + # fi + + dep_tristate ' OHCI-1394 support' CONFIG_IEEE1394_OHCI1394 $CONFIG_IEEE1394 + + comment "Protocol Drivers" + dep_tristate ' OHCI-1394 Video support' CONFIG_IEEE1394_VIDEO1394 $CONFIG_IEEE1394_OHCI1394 + dep_tristate ' SBP-2 support (Harddisks etc.)' CONFIG_IEEE1394_SBP2 $CONFIG_SCSI $CONFIG_IEEE1394 + if [ "$CONFIG_IEEE1394_SBP2" != "n" ]; then + bool ' Enable Phys DMA support for SBP2 (Debug)' CONFIG_IEEE1394_SBP2_PHYS_DMA + fi + dep_tristate ' Ethernet over 1394' CONFIG_IEEE1394_ETH1394 $CONFIG_IEEE1394 + dep_tristate ' OHCI-DV I/O support' CONFIG_IEEE1394_DV1394 $CONFIG_IEEE1394_OHCI1394 + dep_tristate ' Raw IEEE1394 I/O support' CONFIG_IEEE1394_RAWIO $CONFIG_IEEE1394 + dep_tristate ' IEC61883-1 Plug support' CONFIG_IEEE1394_CMP $CONFIG_IEEE1394 + + if [ "$CONFIG_IEEE1394_CMP" != "n" ]; then + dep_tristate ' IEC61883-6 (Audio transmission) support' CONFIG_IEEE1394_AMDTP $CONFIG_IEEE1394_OHCI1394 $CONFIG_IEEE1394_CMP + fi + + bool 'Excessive debugging output' CONFIG_IEEE1394_VERBOSEDEBUG + bool "OUI Database built-in" CONFIG_IEEE1394_OUI_DB + fi + endmenu +fi diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/Makefile.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/Makefile.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/Makefile.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/Makefile.svn-base 2003-07-21 13:09:38.000000000 +0200 @@ -0,0 +1,31 @@ +# +# Makefile for the Linux IEEE 1394 implementation +# + +O_TARGET := ieee1394drv.o + +export-objs := ieee1394_core.o ohci1394.o cmp.o iso.o + +list-multi := ieee1394.o +ieee1394-objs := ieee1394_core.o ieee1394_transactions.o hosts.o \ + highlevel.o csr.o nodemgr.o oui.o dma.o iso.o + +obj-$(CONFIG_IEEE1394) += ieee1394.o +obj-$(CONFIG_IEEE1394_PCILYNX) += pcilynx.o +obj-$(CONFIG_IEEE1394_OHCI1394) += ohci1394.o +obj-$(CONFIG_IEEE1394_VIDEO1394) += video1394.o +obj-$(CONFIG_IEEE1394_RAWIO) += raw1394.o +obj-$(CONFIG_IEEE1394_SBP2) += sbp2.o +obj-$(CONFIG_IEEE1394_DV1394) += dv1394.o +obj-$(CONFIG_IEEE1394_ETH1394) += eth1394.o +obj-$(CONFIG_IEEE1394_AMDTP) += amdtp.o +obj-$(CONFIG_IEEE1394_CMP) += cmp.o + +include $(TOPDIR)/Rules.make + +ieee1394.o: $(ieee1394-objs) + $(LD) $(LDFLAGS) -r -o $@ $(ieee1394-objs) + +oui.o: oui.c +oui.c: oui.db oui2c.sh + $(CONFIG_SHELL) oui2c.sh < oui.db > $@ diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/amdtp.c.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/amdtp.c.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/amdtp.c.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/amdtp.c.svn-base 2003-07-21 13:09:34.000000000 +0200 @@ -0,0 +1,1296 @@ +/* -*- c-basic-offset: 8 -*- + * + * amdtp.c - Audio and Music Data Transmission Protocol Driver + * Copyright (C) 2001 Kristian Høgsberg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* OVERVIEW + * -------- + * + * The AMDTP driver is designed to expose the IEEE1394 bus as a + * regular OSS soundcard, i.e. you can link /dev/dsp to /dev/amdtp and + * then your favourite MP3 player, game or whatever sound program will + * output to an IEEE1394 isochronous channel. The signal destination + * could be a set of IEEE1394 loudspeakers (if and when such things + * become available) or an amplifier with IEEE1394 input (like the + * Sony STR-LSA1). The driver only handles the actual streaming, some + * connection management is also required for this to actually work. + * That is outside the scope of this driver, and furthermore it is not + * really standardized yet. + * + * The Audio and Music Data Tranmission Protocol is available at + * + * http://www.1394ta.org/Download/Technology/Specifications/2001/AM20Final-jf2.pdf + * + * + * TODO + * ---- + * + * - We should be able to change input sample format between LE/BE, as + * we already shift the bytes around when we construct the iso + * packets. + * + * - Fix DMA stop after bus reset! + * + * - Clean up iso context handling in ohci1394. + * + * + * MAYBE TODO + * ---------- + * + * - Receive data for local playback or recording. Playback requires + * soft syncing with the sound card. + * + * - Signal processing, i.e. receive packets, do some processing, and + * transmit them again using the same packet structure and timestamps + * offset by processing time. + * + * - Maybe make an ALSA interface, that is, create a file_ops + * implementation that recognizes ALSA ioctls and uses defaults for + * things that can't be controlled through ALSA (iso channel). + * + * Changes: + * + * - Audit copy_from_user in amdtp_write. + * Daniele Bellucci + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hosts.h" +#include "highlevel.h" +#include "ieee1394.h" +#include "ieee1394_core.h" +#include "ohci1394.h" + +#include "amdtp.h" +#include "cmp.h" + +#define FMT_AMDTP 0x10 +#define FDF_AM824 0x00 +#define FDF_SFC_32KHZ 0x00 +#define FDF_SFC_44K1HZ 0x01 +#define FDF_SFC_48KHZ 0x02 +#define FDF_SFC_88K2HZ 0x03 +#define FDF_SFC_96KHZ 0x04 +#define FDF_SFC_176K4HZ 0x05 +#define FDF_SFC_192KHZ 0x06 + +struct descriptor_block { + struct output_more_immediate { + u32 control; + u32 pad0; + u32 skip; + u32 pad1; + u32 header[4]; + } header_desc; + + struct output_last { + u32 control; + u32 data_address; + u32 branch; + u32 status; + } payload_desc; +}; + +struct packet { + struct descriptor_block *db; + dma_addr_t db_bus; + struct iso_packet *payload; + dma_addr_t payload_bus; +}; + +#include + +#if defined __BIG_ENDIAN_BITFIELD + +struct iso_packet { + /* First quadlet */ + unsigned int dbs : 8; + unsigned int eoh0 : 2; + unsigned int sid : 6; + + unsigned int dbc : 8; + unsigned int fn : 2; + unsigned int qpc : 3; + unsigned int sph : 1; + unsigned int reserved : 2; + + /* Second quadlet */ + unsigned int fdf : 8; + unsigned int eoh1 : 2; + unsigned int fmt : 6; + + unsigned int syt : 16; + + quadlet_t data[0]; +}; + +#elif defined __LITTLE_ENDIAN_BITFIELD + +struct iso_packet { + /* First quadlet */ + unsigned int sid : 6; + unsigned int eoh0 : 2; + unsigned int dbs : 8; + + unsigned int reserved : 2; + unsigned int sph : 1; + unsigned int qpc : 3; + unsigned int fn : 2; + unsigned int dbc : 8; + + /* Second quadlet */ + unsigned int fmt : 6; + unsigned int eoh1 : 2; + unsigned int fdf : 8; + + unsigned int syt : 16; + + quadlet_t data[0]; +}; + +#else + +#error Unknown bitfield type + +#endif + +struct fraction { + int integer; + int numerator; + int denominator; +}; + +#define PACKET_LIST_SIZE 256 +#define MAX_PACKET_LISTS 4 + +struct packet_list { + struct list_head link; + int last_cycle_count; + struct packet packets[PACKET_LIST_SIZE]; +}; + +#define BUFFER_SIZE 128 + +/* This implements a circular buffer for incoming samples. */ + +struct buffer { + size_t head, tail, length, size; + unsigned char data[0]; +}; + +struct stream { + int iso_channel; + int format; + int rate; + int dimension; + int fdf; + int mode; + int sample_format; + struct cmp_pcr *opcr; + + /* Input samples are copied here. */ + struct buffer *input; + + /* ISO Packer state */ + unsigned char dbc; + struct packet_list *current_packet_list; + int current_packet; + struct fraction ready_samples, samples_per_cycle; + + /* We use these to generate control bits when we are packing + * iec958 data. + */ + int iec958_frame_count; + int iec958_rate_code; + + /* The cycle_count and cycle_offset fields are used for the + * synchronization timestamps (syt) in the cip header. They + * are incremented by at least a cycle every time we put a + * time stamp in a packet. As we don't time stamp all + * packages, cycle_count isn't updated in every cycle, and + * sometimes it's incremented by 2. Thus, we have + * cycle_count2, which is simply incremented by one with each + * packet, so we can compare it to the transmission time + * written back in the dma programs. + */ + atomic_t cycle_count, cycle_count2; + struct fraction cycle_offset, ticks_per_syt_offset; + int syt_interval; + int stale_count; + + /* Theses fields control the sample output to the DMA engine. + * The dma_packet_lists list holds packet lists currently + * queued for dma; the head of the list is currently being + * processed. The last program in a packet list generates an + * interrupt, which removes the head from dma_packet_lists and + * puts it back on the free list. + */ + struct list_head dma_packet_lists; + struct list_head free_packet_lists; + wait_queue_head_t packet_list_wait; + spinlock_t packet_list_lock; + struct ohci1394_iso_tasklet iso_tasklet; + struct pci_pool *descriptor_pool, *packet_pool; + + /* Streams at a host controller are chained through this field. */ + struct list_head link; + struct amdtp_host *host; +}; + +struct amdtp_host { + struct hpsb_host *host; + struct ti_ohci *ohci; + struct list_head stream_list; + devfs_handle_t devfs; + spinlock_t stream_list_lock; +}; + +static devfs_handle_t devfs_handle; + +static struct hpsb_highlevel amdtp_highlevel; + +/* FIXME: This doesn't belong here... */ + +#define OHCI1394_CONTEXT_CYCLE_MATCH 0x80000000 +#define OHCI1394_CONTEXT_RUN 0x00008000 +#define OHCI1394_CONTEXT_WAKE 0x00001000 +#define OHCI1394_CONTEXT_DEAD 0x00000800 +#define OHCI1394_CONTEXT_ACTIVE 0x00000400 + +void ohci1394_start_it_ctx(struct ti_ohci *ohci, int ctx, + dma_addr_t first_cmd, int z, int cycle_match) +{ + reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, 1 << ctx); + reg_write(ohci, OHCI1394_IsoXmitCommandPtr + ctx * 16, first_cmd | z); + reg_write(ohci, OHCI1394_IsoXmitContextControlClear + ctx * 16, ~0); + wmb(); + reg_write(ohci, OHCI1394_IsoXmitContextControlSet + ctx * 16, + OHCI1394_CONTEXT_CYCLE_MATCH | (cycle_match << 16) | + OHCI1394_CONTEXT_RUN); +} + +void ohci1394_wake_it_ctx(struct ti_ohci *ohci, int ctx) +{ + reg_write(ohci, OHCI1394_IsoXmitContextControlSet + ctx * 16, + OHCI1394_CONTEXT_WAKE); +} + +void ohci1394_stop_it_ctx(struct ti_ohci *ohci, int ctx, int synchronous) +{ + u32 control; + int wait; + + reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 1 << ctx); + reg_write(ohci, OHCI1394_IsoXmitContextControlClear + ctx * 16, + OHCI1394_CONTEXT_RUN); + wmb(); + + if (synchronous) { + for (wait = 0; wait < 5; wait++) { + control = reg_read(ohci, OHCI1394_IsoXmitContextControlSet + ctx * 16); + if ((control & OHCI1394_CONTEXT_ACTIVE) == 0) + break; + + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(1); + } + } +} + +/* Note: we can test if free_packet_lists is empty without aquiring + * the packet_list_lock. The interrupt handler only adds to the free + * list, there is no race condition between testing the list non-empty + * and acquiring the lock. + */ + +static struct packet_list *stream_get_free_packet_list(struct stream *s) +{ + struct packet_list *pl; + unsigned long flags; + + if (list_empty(&s->free_packet_lists)) + return NULL; + + spin_lock_irqsave(&s->packet_list_lock, flags); + pl = list_entry(s->free_packet_lists.next, struct packet_list, link); + list_del(&pl->link); + spin_unlock_irqrestore(&s->packet_list_lock, flags); + + return pl; +} + +static void stream_start_dma(struct stream *s, struct packet_list *pl) +{ + u32 syt_cycle, cycle_count, start_cycle; + + cycle_count = reg_read(s->host->ohci, + OHCI1394_IsochronousCycleTimer) >> 12; + syt_cycle = (pl->last_cycle_count - PACKET_LIST_SIZE + 1) & 0x0f; + + /* We program the DMA controller to start transmission at + * least 17 cycles from now - this happens when the lower four + * bits of cycle_count is 0x0f and syt_cycle is 0, in this + * case the start cycle is cycle_count - 15 + 32. */ + start_cycle = (cycle_count & ~0x0f) + 32 + syt_cycle; + if ((start_cycle & 0x1fff) >= 8000) + start_cycle = start_cycle - 8000 + 0x2000; + + ohci1394_start_it_ctx(s->host->ohci, s->iso_tasklet.context, + pl->packets[0].db_bus, 3, + start_cycle & 0x7fff); +} + +static void stream_put_dma_packet_list(struct stream *s, + struct packet_list *pl) +{ + unsigned long flags; + struct packet_list *prev; + + /* Remember the cycle_count used for timestamping the last packet. */ + pl->last_cycle_count = atomic_read(&s->cycle_count2) - 1; + pl->packets[PACKET_LIST_SIZE - 1].db->payload_desc.branch = 0; + + spin_lock_irqsave(&s->packet_list_lock, flags); + list_add_tail(&pl->link, &s->dma_packet_lists); + spin_unlock_irqrestore(&s->packet_list_lock, flags); + + prev = list_entry(pl->link.prev, struct packet_list, link); + if (pl->link.prev != &s->dma_packet_lists) { + struct packet *last = &prev->packets[PACKET_LIST_SIZE - 1]; + last->db->payload_desc.branch = pl->packets[0].db_bus | 3; + last->db->header_desc.skip = pl->packets[0].db_bus | 3; + ohci1394_wake_it_ctx(s->host->ohci, s->iso_tasklet.context); + } + else + stream_start_dma(s, pl); +} + +static void stream_shift_packet_lists(unsigned long l) +{ + struct stream *s = (struct stream *) l; + struct packet_list *pl; + struct packet *last; + int diff; + + if (list_empty(&s->dma_packet_lists)) { + HPSB_ERR("empty dma_packet_lists in %s", __FUNCTION__); + return; + } + + /* Now that we know the list is non-empty, we can get the head + * of the list without locking, because the process context + * only adds to the tail. + */ + pl = list_entry(s->dma_packet_lists.next, struct packet_list, link); + last = &pl->packets[PACKET_LIST_SIZE - 1]; + + /* This is weird... if we stop dma processing in the middle of + * a packet list, the dma context immediately generates an + * interrupt if we enable it again later. This only happens + * when amdtp_release is interrupted while waiting for dma to + * complete, though. Anyway, we detect this by seeing that + * the status of the dma descriptor that we expected an + * interrupt from is still 0. + */ + if (last->db->payload_desc.status == 0) { + HPSB_INFO("weird interrupt..."); + return; + } + + /* If the last descriptor block does not specify a branch + * address, we have a sample underflow. + */ + if (last->db->payload_desc.branch == 0) + HPSB_INFO("FIXME: sample underflow..."); + + /* Here we check when (which cycle) the last packet was sent + * and compare it to what the iso packer was using at the + * time. If there is a mismatch, we adjust the cycle count in + * the iso packer. However, there are still up to + * MAX_PACKET_LISTS packet lists queued with bad time stamps, + * so we disable time stamp monitoring for the next + * MAX_PACKET_LISTS packet lists. + */ + diff = (last->db->payload_desc.status - pl->last_cycle_count) & 0xf; + if (diff > 0 && s->stale_count == 0) { + atomic_add(diff, &s->cycle_count); + atomic_add(diff, &s->cycle_count2); + s->stale_count = MAX_PACKET_LISTS; + } + + if (s->stale_count > 0) + s->stale_count--; + + /* Finally, we move the packet list that was just processed + * back to the free list, and notify any waiters. + */ + spin_lock(&s->packet_list_lock); + list_del(&pl->link); + list_add_tail(&pl->link, &s->free_packet_lists); + spin_unlock(&s->packet_list_lock); + + wake_up_interruptible(&s->packet_list_wait); +} + +static struct packet *stream_current_packet(struct stream *s) +{ + if (s->current_packet_list == NULL && + (s->current_packet_list = stream_get_free_packet_list(s)) == NULL) + return NULL; + + return &s->current_packet_list->packets[s->current_packet]; +} + +static void stream_queue_packet(struct stream *s) +{ + s->current_packet++; + if (s->current_packet == PACKET_LIST_SIZE) { + stream_put_dma_packet_list(s, s->current_packet_list); + s->current_packet_list = NULL; + s->current_packet = 0; + } +} + +/* Integer fractional math. When we transmit a 44k1Hz signal we must + * send 5 41/80 samples per isochronous cycle, as these occur 8000 + * times a second. Of course, we must send an integral number of + * samples in a packet, so we use the integer math to alternate + * between sending 5 and 6 samples per packet. + */ + +static void fraction_init(struct fraction *f, int numerator, int denominator) +{ + f->integer = numerator / denominator; + f->numerator = numerator % denominator; + f->denominator = denominator; +} + +static __inline__ void fraction_add(struct fraction *dst, + struct fraction *src1, + struct fraction *src2) +{ + /* assert: src1->denominator == src2->denominator */ + + int sum, denom; + + /* We use these two local variables to allow gcc to optimize + * the division and the modulo into only one division. */ + + sum = src1->numerator + src2->numerator; + denom = src1->denominator; + dst->integer = src1->integer + src2->integer + sum / denom; + dst->numerator = sum % denom; + dst->denominator = denom; +} + +static __inline__ void fraction_sub_int(struct fraction *dst, + struct fraction *src, int integer) +{ + dst->integer = src->integer - integer; + dst->numerator = src->numerator; + dst->denominator = src->denominator; +} + +static __inline__ int fraction_floor(struct fraction *frac) +{ + return frac->integer; +} + +static __inline__ int fraction_ceil(struct fraction *frac) +{ + return frac->integer + (frac->numerator > 0 ? 1 : 0); +} + +void packet_initialize(struct packet *p, struct packet *next) +{ + /* Here we initialize the dma descriptor block for + * transferring one iso packet. We use two descriptors per + * packet: an OUTPUT_MORE_IMMMEDIATE descriptor for the + * IEEE1394 iso packet header and an OUTPUT_LAST descriptor + * for the payload. + */ + + p->db->header_desc.control = + DMA_CTL_OUTPUT_MORE | DMA_CTL_IMMEDIATE | 8; + + if (next) { + p->db->payload_desc.control = + DMA_CTL_OUTPUT_LAST | DMA_CTL_BRANCH; + p->db->payload_desc.branch = next->db_bus | 3; + p->db->header_desc.skip = next->db_bus | 3; + } + else { + p->db->payload_desc.control = + DMA_CTL_OUTPUT_LAST | DMA_CTL_BRANCH | + DMA_CTL_UPDATE | DMA_CTL_IRQ; + p->db->payload_desc.branch = 0; + p->db->header_desc.skip = 0; + } + p->db->payload_desc.data_address = p->payload_bus; + p->db->payload_desc.status = 0; +} + +struct packet_list *packet_list_alloc(struct stream *s) +{ + int i; + struct packet_list *pl; + struct packet *next; + + pl = kmalloc(sizeof *pl, SLAB_KERNEL); + if (pl == NULL) + return NULL; + + for (i = 0; i < PACKET_LIST_SIZE; i++) { + struct packet *p = &pl->packets[i]; + p->db = pci_pool_alloc(s->descriptor_pool, SLAB_KERNEL, + &p->db_bus); + p->payload = pci_pool_alloc(s->packet_pool, SLAB_KERNEL, + &p->payload_bus); + } + + for (i = 0; i < PACKET_LIST_SIZE; i++) { + if (i < PACKET_LIST_SIZE - 1) + next = &pl->packets[i + 1]; + else + next = NULL; + packet_initialize(&pl->packets[i], next); + } + + return pl; +} + +void packet_list_free(struct packet_list *pl, struct stream *s) +{ + int i; + + for (i = 0; i < PACKET_LIST_SIZE; i++) { + struct packet *p = &pl->packets[i]; + pci_pool_free(s->descriptor_pool, p->db, p->db_bus); + pci_pool_free(s->packet_pool, p->payload, p->payload_bus); + } + kfree(pl); +} + +static struct buffer *buffer_alloc(int size) +{ + struct buffer *b; + + b = kmalloc(sizeof *b + size, SLAB_KERNEL); + if (b == NULL) + return NULL; + b->head = 0; + b->tail = 0; + b->length = 0; + b->size = size; + + return b; +} + +static unsigned char *buffer_get_bytes(struct buffer *buffer, int size) +{ + unsigned char *p; + + if (buffer->head + size > buffer->size) + BUG(); + + p = &buffer->data[buffer->head]; + buffer->head += size; + if (buffer->head == buffer->size) + buffer->head = 0; + buffer->length -= size; + + return p; +} + +static unsigned char *buffer_put_bytes(struct buffer *buffer, + size_t max, size_t *actual) +{ + size_t length; + unsigned char *p; + + p = &buffer->data[buffer->tail]; + length = min(buffer->size - buffer->length, max); + if (buffer->tail + length < buffer->size) { + *actual = length; + buffer->tail += length; + } + else { + *actual = buffer->size - buffer->tail; + buffer->tail = 0; + } + + buffer->length += *actual; + return p; +} + +static u32 get_iec958_header_bits(struct stream *s, int sub_frame, u32 sample) +{ + int csi, parity, shift; + int block_start; + u32 bits; + + switch (s->iec958_frame_count) { + case 1: + csi = s->format == AMDTP_FORMAT_IEC958_AC3; + break; + case 2: + case 9: + csi = 1; + break; + case 24 ... 27: + csi = (s->iec958_rate_code >> (27 - s->iec958_frame_count)) & 0x01; + break; + default: + csi = 0; + break; + } + + block_start = (s->iec958_frame_count == 0 && sub_frame == 0); + + /* The parity bit is the xor of the sample bits and the + * channel status info bit. */ + for (shift = 16, parity = sample ^ csi; shift > 0; shift >>= 1) + parity ^= (parity >> shift); + + bits = (block_start << 5) | /* Block start bit */ + ((sub_frame == 0) << 4) | /* Subframe bit */ + ((parity & 1) << 3) | /* Parity bit */ + (csi << 2); /* Channel status info bit */ + + return bits; +} + +static u32 get_header_bits(struct stream *s, int sub_frame, u32 sample) +{ + switch (s->format) { + case AMDTP_FORMAT_IEC958_PCM: + case AMDTP_FORMAT_IEC958_AC3: + return get_iec958_header_bits(s, sub_frame, sample); + + case AMDTP_FORMAT_RAW: + return 0x40; + + default: + return 0; + } +} + +static void fill_payload_le16(struct stream *s, quadlet_t *data, int nevents) +{ + quadlet_t *event, sample, bits; + unsigned char *p; + int i, j; + + for (i = 0, event = data; i < nevents; i++) { + + for (j = 0; j < s->dimension; j++) { + p = buffer_get_bytes(s->input, 2); + sample = (p[1] << 16) | (p[0] << 8); + bits = get_header_bits(s, j, sample); + event[j] = cpu_to_be32((bits << 24) | sample); + } + + event += s->dimension; + if (++s->iec958_frame_count == 192) + s->iec958_frame_count = 0; + } +} + +static void fill_packet(struct stream *s, struct packet *packet, int nevents) +{ + int syt_index, syt, size; + u32 control; + + size = (nevents * s->dimension + 2) * sizeof(quadlet_t); + + /* Update DMA descriptors */ + packet->db->payload_desc.status = 0; + control = packet->db->payload_desc.control & 0xffff0000; + packet->db->payload_desc.control = control | size; + + /* Fill IEEE1394 headers */ + packet->db->header_desc.header[0] = + (IEEE1394_SPEED_100 << 16) | (0x01 << 14) | + (s->iso_channel << 8) | (TCODE_ISO_DATA << 4); + packet->db->header_desc.header[1] = size << 16; + + /* Calculate synchronization timestamp (syt). First we + * determine syt_index, that is, the index in the packet of + * the sample for which the timestamp is valid. */ + syt_index = (s->syt_interval - s->dbc) & (s->syt_interval - 1); + if (syt_index < nevents) { + syt = ((atomic_read(&s->cycle_count) << 12) | + s->cycle_offset.integer) & 0xffff; + fraction_add(&s->cycle_offset, + &s->cycle_offset, &s->ticks_per_syt_offset); + + /* This next addition should be modulo 8000 (0x1f40), + * but we only use the lower 4 bits of cycle_count, so + * we don't need the modulo. */ + atomic_add(s->cycle_offset.integer / 3072, &s->cycle_count); + s->cycle_offset.integer %= 3072; + } + else + syt = 0xffff; + + atomic_inc(&s->cycle_count2); + + /* Fill cip header */ + packet->payload->eoh0 = 0; + packet->payload->sid = s->host->host->node_id & 0x3f; + packet->payload->dbs = s->dimension; + packet->payload->fn = 0; + packet->payload->qpc = 0; + packet->payload->sph = 0; + packet->payload->reserved = 0; + packet->payload->dbc = s->dbc; + packet->payload->eoh1 = 2; + packet->payload->fmt = FMT_AMDTP; + packet->payload->fdf = s->fdf; + packet->payload->syt = cpu_to_be16(syt); + + switch (s->sample_format) { + case AMDTP_INPUT_LE16: + fill_payload_le16(s, packet->payload->data, nevents); + break; + } + + s->dbc += nevents; +} + +static void stream_flush(struct stream *s) +{ + struct packet *p; + int nevents; + struct fraction next; + + /* The AMDTP specifies two transmission modes: blocking and + * non-blocking. In blocking mode you always transfer + * syt_interval or zero samples, whereas in non-blocking mode + * you send as many samples as you have available at transfer + * time. + * + * The fraction samples_per_cycle specifies the number of + * samples that become available per cycle. We add this to + * the fraction ready_samples, which specifies the number of + * leftover samples from the previous transmission. The sum, + * stored in the fraction next, specifies the number of + * samples available for transmission, and from this we + * determine the number of samples to actually transmit. + */ + + while (1) { + fraction_add(&next, &s->ready_samples, &s->samples_per_cycle); + if (s->mode == AMDTP_MODE_BLOCKING) { + if (fraction_floor(&next) >= s->syt_interval) + nevents = s->syt_interval; + else + nevents = 0; + } + else + nevents = fraction_floor(&next); + + p = stream_current_packet(s); + if (s->input->length < nevents * s->dimension * 2 || p == NULL) + break; + + fill_packet(s, p, nevents); + stream_queue_packet(s); + + /* Now that we have successfully queued the packet for + * transmission, we update the fraction ready_samples. */ + fraction_sub_int(&s->ready_samples, &next, nevents); + } +} + +static int stream_alloc_packet_lists(struct stream *s) +{ + int max_nevents, max_packet_size, i; + + if (s->mode == AMDTP_MODE_BLOCKING) + max_nevents = s->syt_interval; + else + max_nevents = fraction_ceil(&s->samples_per_cycle); + + max_packet_size = max_nevents * s->dimension * 4 + 8; + s->packet_pool = pci_pool_create("packet pool", s->host->ohci->dev, + max_packet_size, 0, 0 ,SLAB_KERNEL); + + if (s->packet_pool == NULL) + return -1; + + INIT_LIST_HEAD(&s->free_packet_lists); + INIT_LIST_HEAD(&s->dma_packet_lists); + for (i = 0; i < MAX_PACKET_LISTS; i++) { + struct packet_list *pl = packet_list_alloc(s); + if (pl == NULL) + break; + list_add_tail(&pl->link, &s->free_packet_lists); + } + + return i < MAX_PACKET_LISTS ? -1 : 0; +} + +static void stream_free_packet_lists(struct stream *s) +{ + struct list_head *lh, *next; + + if (s->current_packet_list != NULL) + packet_list_free(s->current_packet_list, s); + list_for_each_safe(lh, next, &s->dma_packet_lists) + packet_list_free(list_entry(lh, struct packet_list, link), s); + list_for_each_safe(lh, next, &s->free_packet_lists) + packet_list_free(list_entry(lh, struct packet_list, link), s); + if (s->packet_pool != NULL) + pci_pool_destroy(s->packet_pool); + + s->current_packet_list = NULL; + INIT_LIST_HEAD(&s->free_packet_lists); + INIT_LIST_HEAD(&s->dma_packet_lists); + s->packet_pool = NULL; +} + +static void plug_update(struct cmp_pcr *plug, void *data) +{ + struct stream *s = data; + + HPSB_INFO("plug update: p2p_count=%d, channel=%d", + plug->p2p_count, plug->channel); + s->iso_channel = plug->channel; + if (plug->p2p_count > 0) { + struct packet_list *pl; + + pl = list_entry(s->dma_packet_lists.next, struct packet_list, link); + stream_start_dma(s, pl); + } + else { + ohci1394_stop_it_ctx(s->host->ohci, s->iso_tasklet.context, 0); + } +} + +static int stream_configure(struct stream *s, int cmd, struct amdtp_ioctl *cfg) +{ + const int transfer_delay = 9000; + + if (cfg->format <= AMDTP_FORMAT_IEC958_AC3) + s->format = cfg->format; + else + return -EINVAL; + + switch (cfg->rate) { + case 32000: + s->syt_interval = 8; + s->fdf = FDF_SFC_32KHZ; + s->iec958_rate_code = 0x0c; + break; + case 44100: + s->syt_interval = 8; + s->fdf = FDF_SFC_44K1HZ; + s->iec958_rate_code = 0x00; + break; + case 48000: + s->syt_interval = 8; + s->fdf = FDF_SFC_48KHZ; + s->iec958_rate_code = 0x04; + break; + case 88200: + s->syt_interval = 16; + s->fdf = FDF_SFC_88K2HZ; + s->iec958_rate_code = 0x00; + break; + case 96000: + s->syt_interval = 16; + s->fdf = FDF_SFC_96KHZ; + s->iec958_rate_code = 0x00; + break; + case 176400: + s->syt_interval = 32; + s->fdf = FDF_SFC_176K4HZ; + s->iec958_rate_code = 0x00; + break; + case 192000: + s->syt_interval = 32; + s->fdf = FDF_SFC_192KHZ; + s->iec958_rate_code = 0x00; + break; + + default: + return -EINVAL; + } + + s->rate = cfg->rate; + fraction_init(&s->samples_per_cycle, s->rate, 8000); + fraction_init(&s->ready_samples, 0, 8000); + + /* The ticks_per_syt_offset is initialized to the number of + * ticks between syt_interval events. The number of ticks per + * second is 24.576e6, so the number of ticks between + * syt_interval events is 24.576e6 * syt_interval / rate. + */ + fraction_init(&s->ticks_per_syt_offset, + 24576000 * s->syt_interval, s->rate); + fraction_init(&s->cycle_offset, (transfer_delay % 3072) * s->rate, s->rate); + atomic_set(&s->cycle_count, transfer_delay / 3072); + atomic_set(&s->cycle_count2, 0); + + s->mode = cfg->mode; + s->sample_format = AMDTP_INPUT_LE16; + + /* When using the AM824 raw subformat we can stream signals of + * any dimension. The IEC958 subformat, however, only + * supports 2 channels. + */ + if (s->format == AMDTP_FORMAT_RAW || cfg->dimension == 2) + s->dimension = cfg->dimension; + else + return -EINVAL; + + if (s->opcr != NULL) { + cmp_unregister_opcr(s->host->host, s->opcr); + s->opcr = NULL; + } + + switch(cmd) { + case AMDTP_IOC_PLUG: + s->opcr = cmp_register_opcr(s->host->host, cfg->u.plug, + /*payload*/ 12, plug_update, s); + if (s->opcr == NULL) + return -EINVAL; + s->iso_channel = s->opcr->channel; + break; + + case AMDTP_IOC_CHANNEL: + if (cfg->u.channel >= 0 && cfg->u.channel < 64) + s->iso_channel = cfg->u.channel; + else + return -EINVAL; + break; + } + + /* The ioctl settings were all valid, so we realloc the packet + * lists to make sure the packet size is big enough. + */ + if (s->packet_pool != NULL) + stream_free_packet_lists(s); + + if (stream_alloc_packet_lists(s) < 0) { + stream_free_packet_lists(s); + return -ENOMEM; + } + + return 0; +} + +struct stream *stream_alloc(struct amdtp_host *host) +{ + struct stream *s; + unsigned long flags; + + s = kmalloc(sizeof(struct stream), SLAB_KERNEL); + if (s == NULL) + return NULL; + + memset(s, 0, sizeof(struct stream)); + s->host = host; + + s->input = buffer_alloc(BUFFER_SIZE); + if (s->input == NULL) { + kfree(s); + return NULL; + } + + s->descriptor_pool = pci_pool_create("descriptor pool", host->ohci->dev, + sizeof(struct descriptor_block), + 16, 0, SLAB_KERNEL); + + if (s->descriptor_pool == NULL) { + kfree(s->input); + kfree(s); + return NULL; + } + + INIT_LIST_HEAD(&s->free_packet_lists); + INIT_LIST_HEAD(&s->dma_packet_lists); + + init_waitqueue_head(&s->packet_list_wait); + spin_lock_init(&s->packet_list_lock); + + ohci1394_init_iso_tasklet(&s->iso_tasklet, OHCI_ISO_TRANSMIT, + stream_shift_packet_lists, + (unsigned long) s); + + if (ohci1394_register_iso_tasklet(host->ohci, &s->iso_tasklet) < 0) { + pci_pool_destroy(s->descriptor_pool); + kfree(s->input); + kfree(s); + return NULL; + } + + spin_lock_irqsave(&host->stream_list_lock, flags); + list_add_tail(&s->link, &host->stream_list); + spin_unlock_irqrestore(&host->stream_list_lock, flags); + + return s; +} + +void stream_free(struct stream *s) +{ + unsigned long flags; + + /* Stop the DMA. We wait for the dma packet list to become + * empty and let the dma controller run out of programs. This + * seems to be more reliable than stopping it directly, since + * that sometimes generates an it transmit interrupt if we + * later re-enable the context. + */ + wait_event_interruptible(s->packet_list_wait, + list_empty(&s->dma_packet_lists)); + + ohci1394_stop_it_ctx(s->host->ohci, s->iso_tasklet.context, 1); + ohci1394_unregister_iso_tasklet(s->host->ohci, &s->iso_tasklet); + + if (s->opcr != NULL) + cmp_unregister_opcr(s->host->host, s->opcr); + + spin_lock_irqsave(&s->host->stream_list_lock, flags); + list_del(&s->link); + spin_unlock_irqrestore(&s->host->stream_list_lock, flags); + + kfree(s->input); + + stream_free_packet_lists(s); + pci_pool_destroy(s->descriptor_pool); + + kfree(s); +} + +/* File operations */ + +static ssize_t amdtp_write(struct file *file, const char *buffer, size_t count, + loff_t *offset_is_ignored) +{ + struct stream *s = file->private_data; + unsigned char *p; + int i; + size_t length; + + if (s->packet_pool == NULL) + return -EBADFD; + + /* Fill the circular buffer from the input buffer and call the + * iso packer when the buffer is full. The iso packer may + * leave bytes in the buffer for two reasons: either the + * remaining bytes wasn't enough to build a new packet, or + * there were no free packet lists. In the first case we + * re-fill the buffer and call the iso packer again or return + * if we used all the data from userspace. In the second + * case, the wait_event_interruptible will block until the irq + * handler frees a packet list. + */ + + for (i = 0; i < count; i += length) { + p = buffer_put_bytes(s->input, count - i, &length); + if (copy_from_user(p, buffer + i, length)) + return -EFAULT; + if (s->input->length < s->input->size) + continue; + + stream_flush(s); + + if (s->current_packet_list != NULL) + continue; + + if (file->f_flags & O_NONBLOCK) + return i + length > 0 ? i + length : -EAGAIN; + + if (wait_event_interruptible(s->packet_list_wait, + !list_empty(&s->free_packet_lists))) + return -EINTR; + } + + return count; +} + +static int amdtp_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct stream *s = file->private_data; + struct amdtp_ioctl cfg; + + switch(cmd) + { + case AMDTP_IOC_PLUG: + case AMDTP_IOC_CHANNEL: + if (copy_from_user(&cfg, (struct amdtp_ioctl *) arg, sizeof cfg)) + return -EFAULT; + else + return stream_configure(s, cmd, &cfg); + + default: + return -EINVAL; + } +} + +static unsigned int amdtp_poll(struct file *file, poll_table *pt) +{ + struct stream *s = file->private_data; + + poll_wait(file, &s->packet_list_wait, pt); + + if (!list_empty(&s->free_packet_lists)) + return POLLOUT | POLLWRNORM; + else + return 0; +} + +static int amdtp_open(struct inode *inode, struct file *file) +{ + struct amdtp_host *host; + int i = ieee1394_file_to_instance(file); + + host = hpsb_get_hostinfo_bykey(&amdtp_highlevel, i); + if (host == NULL) + return -ENODEV; + + file->private_data = stream_alloc(host); + if (file->private_data == NULL) + return -ENOMEM; + + return 0; +} + +static int amdtp_release(struct inode *inode, struct file *file) +{ + struct stream *s = file->private_data; + + stream_free(s); + + return 0; +} + +static struct file_operations amdtp_fops = +{ + .owner = THIS_MODULE, + .write = amdtp_write, + .poll = amdtp_poll, + .ioctl = amdtp_ioctl, + .open = amdtp_open, + .release = amdtp_release +}; + +/* IEEE1394 Subsystem functions */ + +static void amdtp_add_host(struct hpsb_host *host) +{ + struct amdtp_host *ah; + int minor; + char name[16]; + + if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME) != 0) + return; + + ah = hpsb_create_hostinfo(&amdtp_highlevel, host, sizeof(*ah)); + if (!ah) { + HPSB_ERR("amdtp: Unable able to alloc hostinfo"); + return; + } + + ah->host = host; + ah->ohci = host->hostdata; + + hpsb_set_hostinfo_key(&amdtp_highlevel, host, ah->ohci->id); + + minor = IEEE1394_MINOR_BLOCK_AMDTP * 16 + ah->ohci->id; + + sprintf(name, "%d", ah->ohci->id); + + INIT_LIST_HEAD(&ah->stream_list); + spin_lock_init(&ah->stream_list_lock); + + ah->devfs = devfs_register(devfs_handle, name, + DEVFS_FL_AUTO_OWNER, + IEEE1394_MAJOR, minor, + S_IFCHR | S_IRUSR | S_IWUSR, + &amdtp_fops, NULL); +} + +static void amdtp_remove_host(struct hpsb_host *host) +{ + struct amdtp_host *ah = hpsb_get_hostinfo(&amdtp_highlevel, host); + + if (ah) + devfs_unregister(ah->devfs); + + return; +} + +static struct hpsb_highlevel amdtp_highlevel = { + .name = "amdtp", + .add_host = amdtp_add_host, + .remove_host = amdtp_remove_host, +}; + +/* Module interface */ + +MODULE_AUTHOR("Kristian Hogsberg "); +MODULE_DESCRIPTION("Driver for Audio & Music Data Transmission Protocol " + "on OHCI boards."); +MODULE_SUPPORTED_DEVICE("amdtp"); +MODULE_LICENSE("GPL"); + +static int __init amdtp_init_module (void) +{ + if (ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_AMDTP, + THIS_MODULE, &amdtp_fops)) { + HPSB_ERR("amdtp: unable to get minor device block"); + return -EIO; + } + + devfs_handle = devfs_mk_dir(NULL, "amdtp", NULL); + + hpsb_register_highlevel(&amdtp_highlevel); + + HPSB_INFO("Loaded AMDTP driver"); + + return 0; +} + +static void __exit amdtp_exit_module (void) +{ + hpsb_unregister_highlevel(&amdtp_highlevel); + devfs_unregister(devfs_handle); + ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_AMDTP); + + HPSB_INFO("Unloaded AMDTP driver"); +} + +module_init(amdtp_init_module); +module_exit(amdtp_exit_module); diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/amdtp.h.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/amdtp.h.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/amdtp.h.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/amdtp.h.svn-base 2003-07-21 13:09:35.000000000 +0200 @@ -0,0 +1,84 @@ +/* -*- c-basic-offset: 8 -*- */ + +#ifndef __AMDTP_H +#define __AMDTP_H + +#include +#include "ieee1394-ioctl.h" + +/* The userspace interface for the Audio & Music Data Transmission + * Protocol driver is really simple. First, open /dev/amdtp, use the + * ioctl to configure format, rate, dimension and either plug or + * channel, then start writing samples. + * + * The formats supported by the driver are listed below. + * AMDTP_FORMAT_RAW corresponds to the AM824 raw format, which can + * carry any number of channels, so use this if you're streaming + * multichannel audio. The AMDTP_FORMAT_IEC958_PCM corresponds to the + * AM824 IEC958 encapsulation without the IEC958 data bit set, using + * AMDTP_FORMAT_IEC958_AC3 will transmit the samples with the data bit + * set, suitable for transmitting compressed AC-3 audio. + * + * The rate field specifies the transmission rate; supported values + * are 32000, 44100, 48000, 88200, 96000, 176400 and 192000. + * + * The dimension field specifies the dimension of the signal, that is, + * the number of audio channels. Only AMDTP_FORMAT_RAW supports + * settings greater than 2. + * + * The mode field specifies which transmission mode to use. The AMDTP + * specifies two different transmission modes: blocking and + * non-blocking. The blocking transmission mode always send a fixed + * number of samples, typically 8, 16 or 32. To exactly match the + * transmission rate, the driver alternates between sending empty and + * non-empty packets. In non-blocking mode, the driver transmits as + * small packets as possible. For example, for a transmission rate of + * 44100Hz, the driver should send 5 41/80 samples in every cycle, but + * this is not possible so instead the driver alternates between + * sending 5 and 6 samples. + * + * The last thing to specify is either the isochronous channel to use + * or the output plug to connect to. If you know what channel the + * destination device will listen on, you can specify the channel + * directly and use the AMDTP_IOC_CHANNEL ioctl. However, if the + * destination device chooses the channel and uses the IEC61883-1 plug + * mechanism, you can specify an output plug to connect to. The + * driver will pick up the channel number from the plug once the + * destination device locks the output plug control register. In this + * case set the plug field and use the AMDTP_IOC_PLUG ioctl. + * + * Having configured the interface, the driver now accepts writes of + * regular 16 bit signed little endian samples, with the channels + * interleaved. For example, 4 channels would look like: + * + * | sample 0 | sample 1 ... + * | ch. 0 | ch. 1 | ch. 2 | ch. 3 | ch. 0 | ... + * | lsb | msb | lsb | msb | lsb | msb | lsb | msb | lsb | msb | ... + * + */ + +enum { + AMDTP_FORMAT_RAW, + AMDTP_FORMAT_IEC958_PCM, + AMDTP_FORMAT_IEC958_AC3 +}; + +enum { + AMDTP_MODE_BLOCKING, + AMDTP_MODE_NON_BLOCKING, +}; + +enum { + AMDTP_INPUT_LE16, + AMDTP_INPUT_BE16, +}; + +struct amdtp_ioctl { + __u32 format; + __u32 rate; + __u32 dimension; + __u32 mode; + union { __u32 channel; __u32 plug; } u; +}; + +#endif /* __AMDTP_H */ diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/cmp.c.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/cmp.c.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/cmp.c.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/cmp.c.svn-base 2003-07-27 22:04:44.000000000 +0200 @@ -0,0 +1,302 @@ +/* -*- c-basic-offset: 8 -*- + * + * cmp.c - Connection Management Procedures + * Copyright (C) 2001 Kristian Høgsberg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* TODO + * ---- + * + * - Implement IEC61883-1 output plugs and connection management. + * This should probably be part of the general subsystem, as it could + * be shared with dv1394. + * + * - Add IEC61883 unit directory when loading this module. This + * requires a run-time changeable config rom. + */ + +#include +#include +#include +#include +#include + +#include "hosts.h" +#include "highlevel.h" +#include "ieee1394.h" +#include "ieee1394_core.h" +#include "cmp.h" + +struct plug { + union { + struct cmp_pcr pcr; + quadlet_t quadlet; + } u; + void (*update)(struct cmp_pcr *plug, void *data); + void *data; +}; + +struct cmp_host { + struct hpsb_host *host; + + union { + struct cmp_mpr ompr; + quadlet_t ompr_quadlet; + } u; + struct plug opcr[2]; + + union { + struct cmp_mpr impr; + quadlet_t impr_quadlet; + } v; + struct plug ipcr[2]; +}; + +enum { + CMP_P2P_CONNECTION, + CMP_BC_CONNECTION +}; + +#define CSR_PCR_MAP 0x900 +#define CSR_PCR_MAP_END 0x9fc + +static struct hpsb_highlevel cmp_highlevel; + +struct cmp_pcr * +cmp_register_opcr(struct hpsb_host *host, int opcr_number, int payload, + void (*update)(struct cmp_pcr *pcr, void *data), + void *data) +{ + struct cmp_host *ch; + struct plug *plug; + + ch = hpsb_get_hostinfo(&cmp_highlevel, host); + + if (opcr_number >= ch->u.ompr.nplugs || + ch->opcr[opcr_number].update != NULL) + return NULL; + + plug = &ch->opcr[opcr_number]; + plug->u.pcr.online = 1; + plug->u.pcr.bcast_count = 0; + plug->u.pcr.p2p_count = 0; + plug->u.pcr.overhead = 0; + plug->u.pcr.payload = payload; + plug->update = update; + plug->data = data; + + return &plug->u.pcr; +} + +void cmp_unregister_opcr(struct hpsb_host *host, struct cmp_pcr *opcr) +{ + struct cmp_host *ch; + struct plug *plug; + + ch = hpsb_get_hostinfo(&cmp_highlevel, host); + plug = (struct plug *)opcr; + if (plug - ch->opcr >= ch->u.ompr.nplugs) BUG(); + + plug->u.pcr.online = 0; + plug->update = NULL; +} + +static void reset_plugs(struct cmp_host *ch) +{ + int i; + + ch->u.ompr.non_persistent_ext = 0xff; + for (i = 0; i < ch->u.ompr.nplugs; i++) { + ch->opcr[i].u.pcr.bcast_count = 0; + ch->opcr[i].u.pcr.p2p_count = 0; + ch->opcr[i].u.pcr.overhead = 0; + } +} + +static void cmp_add_host(struct hpsb_host *host) +{ + struct cmp_host *ch = hpsb_create_hostinfo(&cmp_highlevel, host, sizeof (*ch)); + + if (ch == NULL) { + HPSB_ERR("Failed to allocate cmp_host"); + return; + } + + ch->host = host; + ch->u.ompr.rate = IEEE1394_SPEED_100; + ch->u.ompr.bcast_channel_base = 63; + ch->u.ompr.nplugs = 2; + + reset_plugs(ch); +} + +static void cmp_host_reset(struct hpsb_host *host) +{ + struct cmp_host *ch; + + ch = hpsb_get_hostinfo(&cmp_highlevel, host); + if (ch == NULL) { + HPSB_ERR("cmp: Tried to reset unknown host"); + return; + } + + reset_plugs(ch); +} + +static int pcr_read(struct hpsb_host *host, int nodeid, quadlet_t *buf, + u64 addr, size_t length, u16 flags) +{ + int csraddr = addr - CSR_REGISTER_BASE; + int plug; + struct cmp_host *ch; + + if (length != 4) + return RCODE_TYPE_ERROR; + + ch = hpsb_get_hostinfo(&cmp_highlevel, host); + if (csraddr == 0x900) { + *buf = cpu_to_be32(ch->u.ompr_quadlet); + return RCODE_COMPLETE; + } + else if (csraddr < 0x904 + ch->u.ompr.nplugs * 4) { + plug = (csraddr - 0x904) / 4; + *buf = cpu_to_be32(ch->opcr[plug].u.quadlet); + return RCODE_COMPLETE; + } + else if (csraddr < 0x980) { + return RCODE_ADDRESS_ERROR; + } + else if (csraddr == 0x980) { + *buf = cpu_to_be32(ch->v.impr_quadlet); + return RCODE_COMPLETE; + } + else if (csraddr < 0x984 + ch->v.impr.nplugs * 4) { + plug = (csraddr - 0x984) / 4; + *buf = cpu_to_be32(ch->ipcr[plug].u.quadlet); + return RCODE_COMPLETE; + } + else + return RCODE_ADDRESS_ERROR; +} + +static int pcr_lock(struct hpsb_host *host, int nodeid, quadlet_t *store, + u64 addr, quadlet_t data, quadlet_t arg, int extcode, u16 flags) +{ + int csraddr = addr - CSR_REGISTER_BASE; + int plug; + struct cmp_host *ch; + + ch = hpsb_get_hostinfo(&cmp_highlevel, host); + + if (extcode != EXTCODE_COMPARE_SWAP) + return RCODE_TYPE_ERROR; + + if (csraddr == 0x900) { + /* FIXME: Ignore writes to bits 30-31 and 0-7 */ + *store = cpu_to_be32(ch->u.ompr_quadlet); + if (arg == cpu_to_be32(ch->u.ompr_quadlet)) + ch->u.ompr_quadlet = be32_to_cpu(data); + + return RCODE_COMPLETE; + } + if (csraddr < 0x904 + ch->u.ompr.nplugs * 4) { + plug = (csraddr - 0x904) / 4; + *store = cpu_to_be32(ch->opcr[plug].u.quadlet); + + if (arg == *store) + ch->opcr[plug].u.quadlet = be32_to_cpu(data); + + if (be32_to_cpu(*store) != ch->opcr[plug].u.quadlet && + ch->opcr[plug].update != NULL) + ch->opcr[plug].update(&ch->opcr[plug].u.pcr, + ch->opcr[plug].data); + + return RCODE_COMPLETE; + } + else if (csraddr < 0x980) { + return RCODE_ADDRESS_ERROR; + } + else if (csraddr == 0x980) { + /* FIXME: Ignore writes to bits 24-31 and 0-7 */ + *store = cpu_to_be32(ch->u.ompr_quadlet); + if (arg == cpu_to_be32(ch->u.ompr_quadlet)) + ch->u.ompr_quadlet = be32_to_cpu(data); + + return RCODE_COMPLETE; + } + else if (csraddr < 0x984 + ch->v.impr.nplugs * 4) { + plug = (csraddr - 0x984) / 4; + *store = cpu_to_be32(ch->ipcr[plug].u.quadlet); + + if (arg == *store) + ch->ipcr[plug].u.quadlet = be32_to_cpu(data); + + if (be32_to_cpu(*store) != ch->ipcr[plug].u.quadlet && + ch->ipcr[plug].update != NULL) + ch->ipcr[plug].update(&ch->ipcr[plug].u.pcr, + ch->ipcr[plug].data); + + return RCODE_COMPLETE; + } + else + return RCODE_ADDRESS_ERROR; +} + + +static struct hpsb_highlevel cmp_highlevel = { + .name = "cmp", + .add_host = cmp_add_host, + .host_reset = cmp_host_reset, +}; + +static struct hpsb_address_ops pcr_ops = { + .read = pcr_read, + .lock = pcr_lock, +}; + +/* Module interface */ + +MODULE_AUTHOR("Kristian Hogsberg "); +MODULE_DESCRIPTION("Connection Management Procedures (CMP)"); +MODULE_SUPPORTED_DEVICE("cmp"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(cmp_register_opcr); +EXPORT_SYMBOL(cmp_unregister_opcr); + +static int __init cmp_init_module (void) +{ + hpsb_register_highlevel (&cmp_highlevel); + + hpsb_register_addrspace(&cmp_highlevel, &pcr_ops, + CSR_REGISTER_BASE + CSR_PCR_MAP, + CSR_REGISTER_BASE + CSR_PCR_MAP_END); + + HPSB_INFO("Loaded CMP driver"); + + return 0; +} + +static void __exit cmp_exit_module (void) +{ + hpsb_unregister_highlevel(&cmp_highlevel); + + HPSB_INFO("Unloaded CMP driver"); +} + +module_init(cmp_init_module); +module_exit(cmp_exit_module); diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/cmp.h.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/cmp.h.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/cmp.h.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/cmp.h.svn-base 2003-07-21 13:09:42.000000000 +0200 @@ -0,0 +1,31 @@ +#ifndef __CMP_H +#define __CMP_H + +struct cmp_mpr { + u32 nplugs:5; + u32 reserved:3; + u32 persistent_ext:8; + u32 non_persistent_ext:8; + u32 bcast_channel_base:6; + u32 rate:2; +} __attribute__((packed)); + +struct cmp_pcr { + u32 payload:10; + u32 overhead:4; + u32 speed:2; + u32 channel:6; + u32 reserved:2; + u32 p2p_count:6; + u32 bcast_count:1; + u32 online:1; +} __attribute__((packed)); + +struct cmp_pcr *cmp_register_opcr(struct hpsb_host *host, int plug, + int payload, + void (*update)(struct cmp_pcr *plug, + void *data), + void *data); +void cmp_unregister_opcr(struct hpsb_host *host, struct cmp_pcr *plug); + +#endif /* __CMP_H */ diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/csr.c.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/csr.c.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/csr.c.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/csr.c.svn-base 2003-09-08 03:33:08.000000000 +0200 @@ -0,0 +1,732 @@ +/* + * IEEE 1394 for Linux + * + * CSR implementation, iso/bus manager implementation. + * + * Copyright (C) 1999 Andreas E. Bombe + * 2002 Manfred Weihs + * + * This code is licensed under the GPL. See the file COPYING in the root + * directory of the kernel sources for details. + * + * + * Contributions: + * + * Manfred Weihs + * configuration ROM manipulation + * + */ + +#include +#include /* needed for MODULE_PARM */ +#include +#include + +#include "ieee1394_types.h" +#include "hosts.h" +#include "ieee1394.h" +#include "highlevel.h" + +/* Module Parameters */ +/* this module parameter can be used to disable mapping of the FCP registers */ +MODULE_PARM(fcp,"i"); +MODULE_PARM_DESC(fcp, "FCP-registers"); +static int fcp = 1; + +static u16 csr_crc16(unsigned *data, int length) +{ + int check=0, i; + int shift, sum, next=0; + + for (i = length; i; i--) { + for (next = check, shift = 28; shift >= 0; shift -= 4 ) { + sum = ((next >> 12) ^ (be32_to_cpu(*data) >> shift)) & 0xf; + next = (next << 4) ^ (sum << 12) ^ (sum << 5) ^ (sum); + } + check = next & 0xffff; + data++; + } + + return check; +} + +static void host_reset(struct hpsb_host *host) +{ + host->csr.state &= 0x300; + + host->csr.bus_manager_id = 0x3f; + host->csr.bandwidth_available = 4915; + host->csr.channels_available_hi = 0xfffffffe; /* pre-alloc ch 31 per 1394a-2000 */ + host->csr.channels_available_lo = ~0; + host->csr.broadcast_channel = 0x80000000 | 31; + + if (host->is_irm) { + if (host->driver->hw_csr_reg) { + host->driver->hw_csr_reg(host, 2, 0xfffffffe, ~0); + } + } + + host->csr.node_ids = host->node_id << 16; + + if (!host->is_root) { + /* clear cmstr bit */ + host->csr.state &= ~0x100; + } + + host->csr.topology_map[1] = + cpu_to_be32(be32_to_cpu(host->csr.topology_map[1]) + 1); + host->csr.topology_map[2] = cpu_to_be32(host->node_count << 16 + | host->selfid_count); + host->csr.topology_map[0] = + cpu_to_be32((host->selfid_count + 2) << 16 + | csr_crc16(host->csr.topology_map + 1, + host->selfid_count + 2)); + + host->csr.speed_map[1] = + cpu_to_be32(be32_to_cpu(host->csr.speed_map[1]) + 1); + host->csr.speed_map[0] = cpu_to_be32(0x3f1 << 16 + | csr_crc16(host->csr.speed_map+1, + 0x3f1)); +} + +/* + * HI == seconds (bits 0:2) + * LO == fraction units of 1/8000 of a second, as per 1394 (bits 19:31) + * + * Convert to units and then to HZ, for comparison to jiffies. + * + * By default this will end up being 800 units, or 100ms (125usec per + * unit). + * + * NOTE: The spec says 1/8000, but also says we can compute based on 1/8192 + * like CSR specifies. Should make our math less complex. + */ +static inline void calculate_expire(struct csr_control *csr) +{ + unsigned long units; + + /* Take the seconds, and convert to units */ + units = (unsigned long)(csr->split_timeout_hi & 0x07) << 13; + + /* Add in the fractional units */ + units += (unsigned long)(csr->split_timeout_lo >> 19); + + /* Convert to jiffies */ + csr->expire = (unsigned long)(units * HZ) >> 13UL; + + /* Just to keep from rounding low */ + csr->expire++; + + HPSB_VERBOSE("CSR: setting expire to %lu, HZ=%lu", csr->expire, HZ); +} + + +static void add_host(struct hpsb_host *host) +{ + host->csr.lock = SPIN_LOCK_UNLOCKED; + + host->csr.rom_size = host->driver->get_rom(host, &host->csr.rom); + host->csr.rom_version = 0; + host->csr.state = 0; + host->csr.node_ids = 0; + host->csr.split_timeout_hi = 0; + host->csr.split_timeout_lo = 800 << 19; + calculate_expire(&host->csr); + host->csr.cycle_time = 0; + host->csr.bus_time = 0; + host->csr.bus_manager_id = 0x3f; + host->csr.bandwidth_available = 4915; + host->csr.channels_available_hi = 0xfffffffe; /* pre-alloc ch 31 per 1394a-2000 */ + host->csr.channels_available_lo = ~0; + host->csr.broadcast_channel = 0x80000000 | 31; + + if (host->is_irm) { + if (host->driver->hw_csr_reg) { + host->driver->hw_csr_reg(host, 2, 0xfffffffe, ~0); + } + } +} + +int hpsb_update_config_rom(struct hpsb_host *host, const quadlet_t *new_rom, + size_t size, unsigned char rom_version) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&host->csr.lock, flags); + if (rom_version != host->csr.rom_version) + ret = -1; + else if (size > (CSR_CONFIG_ROM_SIZE << 2)) + ret = -2; + else { + memcpy(host->csr.rom,new_rom,size); + host->csr.rom_size=size; + host->csr.rom_version++; + ret=0; + } + spin_unlock_irqrestore(&host->csr.lock, flags); + return ret; +} + +int hpsb_get_config_rom(struct hpsb_host *host, quadlet_t *buffer, + size_t buffersize, size_t *rom_size, unsigned char *rom_version) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&host->csr.lock, flags); + *rom_version=host->csr.rom_version; + *rom_size=host->csr.rom_size; + if (buffersize < host->csr.rom_size) + ret = -1; + else { + memcpy(buffer,host->csr.rom,host->csr.rom_size); + ret=0; + } + spin_unlock_irqrestore(&host->csr.lock, flags); + return ret; +} + + +/* Read topology / speed maps and configuration ROM */ +static int read_maps(struct hpsb_host *host, int nodeid, quadlet_t *buffer, + u64 addr, size_t length, u16 fl) +{ + unsigned long flags; + int csraddr = addr - CSR_REGISTER_BASE; + const char *src; + + spin_lock_irqsave(&host->csr.lock, flags); + + if (csraddr < CSR_TOPOLOGY_MAP) { + if (csraddr + length > CSR_CONFIG_ROM + host->csr.rom_size) { + spin_unlock_irqrestore(&host->csr.lock, flags); + return RCODE_ADDRESS_ERROR; + } + src = ((char *)host->csr.rom) + csraddr - CSR_CONFIG_ROM; + } else if (csraddr < CSR_SPEED_MAP) { + src = ((char *)host->csr.topology_map) + csraddr + - CSR_TOPOLOGY_MAP; + } else { + src = ((char *)host->csr.speed_map) + csraddr - CSR_SPEED_MAP; + } + + memcpy(buffer, src, length); + spin_unlock_irqrestore(&host->csr.lock, flags); + return RCODE_COMPLETE; +} + + +#define out if (--length == 0) break + +static int read_regs(struct hpsb_host *host, int nodeid, quadlet_t *buf, + u64 addr, size_t length, u16 flags) +{ + int csraddr = addr - CSR_REGISTER_BASE; + int oldcycle; + quadlet_t ret; + + if ((csraddr | length) & 0x3) + return RCODE_TYPE_ERROR; + + length /= 4; + + switch (csraddr) { + case CSR_STATE_CLEAR: + *(buf++) = cpu_to_be32(host->csr.state); + out; + case CSR_STATE_SET: + *(buf++) = cpu_to_be32(host->csr.state); + out; + case CSR_NODE_IDS: + *(buf++) = cpu_to_be32(host->csr.node_ids); + out; + + case CSR_RESET_START: + return RCODE_TYPE_ERROR; + + /* address gap - handled by default below */ + + case CSR_SPLIT_TIMEOUT_HI: + *(buf++) = cpu_to_be32(host->csr.split_timeout_hi); + out; + case CSR_SPLIT_TIMEOUT_LO: + *(buf++) = cpu_to_be32(host->csr.split_timeout_lo); + out; + + /* address gap */ + return RCODE_ADDRESS_ERROR; + + case CSR_CYCLE_TIME: + oldcycle = host->csr.cycle_time; + host->csr.cycle_time = + host->driver->devctl(host, GET_CYCLE_COUNTER, 0); + + if (oldcycle > host->csr.cycle_time) { + /* cycle time wrapped around */ + host->csr.bus_time += 1 << 7; + } + *(buf++) = cpu_to_be32(host->csr.cycle_time); + out; + case CSR_BUS_TIME: + oldcycle = host->csr.cycle_time; + host->csr.cycle_time = + host->driver->devctl(host, GET_CYCLE_COUNTER, 0); + + if (oldcycle > host->csr.cycle_time) { + /* cycle time wrapped around */ + host->csr.bus_time += (1 << 7); + } + *(buf++) = cpu_to_be32(host->csr.bus_time + | (host->csr.cycle_time >> 25)); + out; + + /* address gap */ + return RCODE_ADDRESS_ERROR; + + case CSR_BUSY_TIMEOUT: + /* not yet implemented */ + return RCODE_ADDRESS_ERROR; + + case CSR_BUS_MANAGER_ID: + if (host->driver->hw_csr_reg) + ret = host->driver->hw_csr_reg(host, 0, 0, 0); + else + ret = host->csr.bus_manager_id; + + *(buf++) = cpu_to_be32(ret); + out; + case CSR_BANDWIDTH_AVAILABLE: + if (host->driver->hw_csr_reg) + ret = host->driver->hw_csr_reg(host, 1, 0, 0); + else + ret = host->csr.bandwidth_available; + + *(buf++) = cpu_to_be32(ret); + out; + case CSR_CHANNELS_AVAILABLE_HI: + if (host->driver->hw_csr_reg) + ret = host->driver->hw_csr_reg(host, 2, 0, 0); + else + ret = host->csr.channels_available_hi; + + *(buf++) = cpu_to_be32(ret); + out; + case CSR_CHANNELS_AVAILABLE_LO: + if (host->driver->hw_csr_reg) + ret = host->driver->hw_csr_reg(host, 3, 0, 0); + else + ret = host->csr.channels_available_lo; + + *(buf++) = cpu_to_be32(ret); + out; + + case CSR_BROADCAST_CHANNEL: + *(buf++) = cpu_to_be32(host->csr.broadcast_channel); + out; + + /* address gap to end - fall through to default */ + default: + return RCODE_ADDRESS_ERROR; + } + + return RCODE_COMPLETE; +} + +static int write_regs(struct hpsb_host *host, int nodeid, int destid, + quadlet_t *data, u64 addr, size_t length, u16 flags) +{ + int csraddr = addr - CSR_REGISTER_BASE; + + if ((csraddr | length) & 0x3) + return RCODE_TYPE_ERROR; + + length /= 4; + + switch (csraddr) { + case CSR_STATE_CLEAR: + /* FIXME FIXME FIXME */ + printk("doh, someone wants to mess with state clear\n"); + out; + case CSR_STATE_SET: + printk("doh, someone wants to mess with state set\n"); + out; + + case CSR_NODE_IDS: + host->csr.node_ids &= NODE_MASK << 16; + host->csr.node_ids |= be32_to_cpu(*(data++)) & (BUS_MASK << 16); + host->node_id = host->csr.node_ids >> 16; + host->driver->devctl(host, SET_BUS_ID, host->node_id >> 6); + out; + + case CSR_RESET_START: + /* FIXME - perform command reset */ + out; + + /* address gap */ + return RCODE_ADDRESS_ERROR; + + case CSR_SPLIT_TIMEOUT_HI: + host->csr.split_timeout_hi = + be32_to_cpu(*(data++)) & 0x00000007; + calculate_expire(&host->csr); + out; + case CSR_SPLIT_TIMEOUT_LO: + host->csr.split_timeout_lo = + be32_to_cpu(*(data++)) & 0xfff80000; + calculate_expire(&host->csr); + out; + + /* address gap */ + return RCODE_ADDRESS_ERROR; + + case CSR_CYCLE_TIME: + /* should only be set by cycle start packet, automatically */ + host->csr.cycle_time = be32_to_cpu(*data); + host->driver->devctl(host, SET_CYCLE_COUNTER, + be32_to_cpu(*(data++))); + out; + case CSR_BUS_TIME: + host->csr.bus_time = be32_to_cpu(*(data++)) & 0xffffff80; + out; + + /* address gap */ + return RCODE_ADDRESS_ERROR; + + case CSR_BUSY_TIMEOUT: + /* not yet implemented */ + return RCODE_ADDRESS_ERROR; + + case CSR_BUS_MANAGER_ID: + case CSR_BANDWIDTH_AVAILABLE: + case CSR_CHANNELS_AVAILABLE_HI: + case CSR_CHANNELS_AVAILABLE_LO: + /* these are not writable, only lockable */ + return RCODE_TYPE_ERROR; + + case CSR_BROADCAST_CHANNEL: + /* only the valid bit can be written */ + host->csr.broadcast_channel = (host->csr.broadcast_channel & ~0x40000000) + | (be32_to_cpu(*data) & 0x40000000); + out; + + /* address gap to end - fall through */ + default: + return RCODE_ADDRESS_ERROR; + } + + return RCODE_COMPLETE; +} + +#undef out + + +static int lock_regs(struct hpsb_host *host, int nodeid, quadlet_t *store, + u64 addr, quadlet_t data, quadlet_t arg, int extcode, u16 fl) +{ + int csraddr = addr - CSR_REGISTER_BASE; + unsigned long flags; + quadlet_t *regptr = NULL; + + if (csraddr & 0x3) + return RCODE_TYPE_ERROR; + + if (csraddr < CSR_BUS_MANAGER_ID || csraddr > CSR_CHANNELS_AVAILABLE_LO + || extcode != EXTCODE_COMPARE_SWAP) + goto unsupported_lockreq; + + data = be32_to_cpu(data); + arg = be32_to_cpu(arg); + + /* Is somebody releasing the broadcast_channel on us? */ + if (csraddr == CSR_CHANNELS_AVAILABLE_HI && (data & 0x1)) { + /* Note: this is may not be the right way to handle + * the problem, so we should look into the proper way + * eventually. */ + HPSB_WARN("Node [" NODE_BUS_FMT "] wants to release " + "broadcast channel 31. Ignoring.", + NODE_BUS_ARGS(host, nodeid)); + + data &= ~0x1; /* keep broadcast channel allocated */ + } + + if (host->driver->hw_csr_reg) { + quadlet_t old; + + old = host->driver-> + hw_csr_reg(host, (csraddr - CSR_BUS_MANAGER_ID) >> 2, + data, arg); + + *store = cpu_to_be32(old); + return RCODE_COMPLETE; + } + + spin_lock_irqsave(&host->csr.lock, flags); + + switch (csraddr) { + case CSR_BUS_MANAGER_ID: + regptr = &host->csr.bus_manager_id; + *store = cpu_to_be32(*regptr); + if (*regptr == arg) + *regptr = data; + break; + + case CSR_BANDWIDTH_AVAILABLE: + { + quadlet_t bandwidth; + quadlet_t old; + quadlet_t new; + + regptr = &host->csr.bandwidth_available; + old = *regptr; + + /* bandwidth available algorithm adapted from IEEE 1394a-2000 spec */ + if (arg > 0x1fff) { + *store = cpu_to_be32(old); /* change nothing */ + break; + } + data &= 0x1fff; + if (arg >= data) { + /* allocate bandwidth */ + bandwidth = arg - data; + if (old >= bandwidth) { + new = old - bandwidth; + *store = cpu_to_be32(arg); + *regptr = new; + } else { + *store = cpu_to_be32(old); + } + } else { + /* deallocate bandwidth */ + bandwidth = data - arg; + if (old + bandwidth < 0x2000) { + new = old + bandwidth; + *store = cpu_to_be32(arg); + *regptr = new; + } else { + *store = cpu_to_be32(old); + } + } + break; + } + + case CSR_CHANNELS_AVAILABLE_HI: + { + /* Lock algorithm for CHANNELS_AVAILABLE as recommended by 1394a-2000 */ + quadlet_t affected_channels = arg ^ data; + + regptr = &host->csr.channels_available_hi; + + if ((arg & affected_channels) == (*regptr & affected_channels)) { + *regptr ^= affected_channels; + *store = cpu_to_be32(arg); + } else { + *store = cpu_to_be32(*regptr); + } + + break; + } + + case CSR_CHANNELS_AVAILABLE_LO: + { + /* Lock algorithm for CHANNELS_AVAILABLE as recommended by 1394a-2000 */ + quadlet_t affected_channels = arg ^ data; + + regptr = &host->csr.channels_available_lo; + + if ((arg & affected_channels) == (*regptr & affected_channels)) { + *regptr ^= affected_channels; + *store = cpu_to_be32(arg); + } else { + *store = cpu_to_be32(*regptr); + } + break; + } + } + + spin_unlock_irqrestore(&host->csr.lock, flags); + + return RCODE_COMPLETE; + + unsupported_lockreq: + switch (csraddr) { + case CSR_STATE_CLEAR: + case CSR_STATE_SET: + case CSR_RESET_START: + case CSR_NODE_IDS: + case CSR_SPLIT_TIMEOUT_HI: + case CSR_SPLIT_TIMEOUT_LO: + case CSR_CYCLE_TIME: + case CSR_BUS_TIME: + case CSR_BROADCAST_CHANNEL: + return RCODE_TYPE_ERROR; + + case CSR_BUSY_TIMEOUT: + /* not yet implemented - fall through */ + default: + return RCODE_ADDRESS_ERROR; + } +} + +static int lock64_regs(struct hpsb_host *host, int nodeid, octlet_t * store, + u64 addr, octlet_t data, octlet_t arg, int extcode, u16 fl) +{ + int csraddr = addr - CSR_REGISTER_BASE; + unsigned long flags; + + data = be64_to_cpu(data); + arg = be64_to_cpu(arg); + + if (csraddr & 0x3) + return RCODE_TYPE_ERROR; + + if (csraddr != CSR_CHANNELS_AVAILABLE + || extcode != EXTCODE_COMPARE_SWAP) + goto unsupported_lock64req; + + /* Is somebody releasing the broadcast_channel on us? */ + if (csraddr == CSR_CHANNELS_AVAILABLE_HI && (data & 0x100000000ULL)) { + /* Note: this is may not be the right way to handle + * the problem, so we should look into the proper way + * eventually. */ + HPSB_WARN("Node [" NODE_BUS_FMT "] wants to release " + "broadcast channel 31. Ignoring.", + NODE_BUS_ARGS(host, nodeid)); + + data &= ~0x100000000ULL; /* keep broadcast channel allocated */ + } + + if (host->driver->hw_csr_reg) { + quadlet_t data_hi, data_lo; + quadlet_t arg_hi, arg_lo; + quadlet_t old_hi, old_lo; + + data_hi = data >> 32; + data_lo = data & 0xFFFFFFFF; + arg_hi = arg >> 32; + arg_lo = arg & 0xFFFFFFFF; + + old_hi = host->driver->hw_csr_reg(host, (csraddr - CSR_BUS_MANAGER_ID) >> 2, + data_hi, arg_hi); + + old_lo = host->driver->hw_csr_reg(host, ((csraddr + 4) - CSR_BUS_MANAGER_ID) >> 2, + data_lo, arg_lo); + + *store = cpu_to_be64(((octlet_t)old_hi << 32) | old_lo); + } else { + octlet_t old; + octlet_t affected_channels = arg ^ data; + + spin_lock_irqsave(&host->csr.lock, flags); + + old = ((octlet_t)host->csr.channels_available_hi << 32) | host->csr.channels_available_lo; + + if ((arg & affected_channels) == (old & affected_channels)) { + host->csr.channels_available_hi ^= (affected_channels >> 32); + host->csr.channels_available_lo ^= (affected_channels & 0xffffffff); + *store = cpu_to_be64(arg); + } else { + *store = cpu_to_be64(old); + } + + spin_unlock_irqrestore(&host->csr.lock, flags); + } + + /* Is somebody erroneously releasing the broadcast_channel on us? */ + if (host->csr.channels_available_hi & 0x1) + host->csr.channels_available_hi &= ~0x1; + + return RCODE_COMPLETE; + + unsupported_lock64req: + switch (csraddr) { + case CSR_STATE_CLEAR: + case CSR_STATE_SET: + case CSR_RESET_START: + case CSR_NODE_IDS: + case CSR_SPLIT_TIMEOUT_HI: + case CSR_SPLIT_TIMEOUT_LO: + case CSR_CYCLE_TIME: + case CSR_BUS_TIME: + case CSR_BUS_MANAGER_ID: + case CSR_BROADCAST_CHANNEL: + case CSR_BUSY_TIMEOUT: + case CSR_BANDWIDTH_AVAILABLE: + return RCODE_TYPE_ERROR; + + default: + return RCODE_ADDRESS_ERROR; + } +} + +static int write_fcp(struct hpsb_host *host, int nodeid, int dest, + quadlet_t *data, u64 addr, size_t length, u16 flags) +{ + int csraddr = addr - CSR_REGISTER_BASE; + + if (length > 512) + return RCODE_TYPE_ERROR; + + switch (csraddr) { + case CSR_FCP_COMMAND: + highlevel_fcp_request(host, nodeid, 0, (u8 *)data, length); + break; + case CSR_FCP_RESPONSE: + highlevel_fcp_request(host, nodeid, 1, (u8 *)data, length); + break; + default: + return RCODE_TYPE_ERROR; + } + + return RCODE_COMPLETE; +} + + +static struct hpsb_highlevel csr_highlevel = { + .name = "standard registers", + .add_host = add_host, + .host_reset = host_reset, +}; + + +static struct hpsb_address_ops map_ops = { + .read = read_maps, +}; + +static struct hpsb_address_ops fcp_ops = { + .write = write_fcp, +}; + +static struct hpsb_address_ops reg_ops = { + .read = read_regs, + .write = write_regs, + .lock = lock_regs, + .lock64 = lock64_regs, +}; + +void init_csr(void) +{ + hpsb_register_highlevel(&csr_highlevel); + + hpsb_register_addrspace(&csr_highlevel, ®_ops, CSR_REGISTER_BASE, + CSR_REGISTER_BASE + CSR_CONFIG_ROM); + hpsb_register_addrspace(&csr_highlevel, &map_ops, + CSR_REGISTER_BASE + CSR_CONFIG_ROM, + CSR_REGISTER_BASE + CSR_CONFIG_ROM_END); + if (fcp) { + hpsb_register_addrspace(&csr_highlevel, &fcp_ops, + CSR_REGISTER_BASE + CSR_FCP_COMMAND, + CSR_REGISTER_BASE + CSR_FCP_END); + } + hpsb_register_addrspace(&csr_highlevel, &map_ops, + CSR_REGISTER_BASE + CSR_TOPOLOGY_MAP, + CSR_REGISTER_BASE + CSR_TOPOLOGY_MAP_END); + hpsb_register_addrspace(&csr_highlevel, &map_ops, + CSR_REGISTER_BASE + CSR_SPEED_MAP, + CSR_REGISTER_BASE + CSR_SPEED_MAP_END); +} + +void cleanup_csr(void) +{ + hpsb_unregister_highlevel(&csr_highlevel); +} diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/csr.h.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/csr.h.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/csr.h.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/csr.h.svn-base 2003-07-27 22:04:45.000000000 +0200 @@ -0,0 +1,65 @@ + +#ifndef _IEEE1394_CSR_H +#define _IEEE1394_CSR_H + +#ifdef CONFIG_PREEMPT +#include +#endif + +#define CSR_REGISTER_BASE 0xfffff0000000ULL + +/* register offsets relative to CSR_REGISTER_BASE */ +#define CSR_STATE_CLEAR 0x0 +#define CSR_STATE_SET 0x4 +#define CSR_NODE_IDS 0x8 +#define CSR_RESET_START 0xc +#define CSR_SPLIT_TIMEOUT_HI 0x18 +#define CSR_SPLIT_TIMEOUT_LO 0x1c +#define CSR_CYCLE_TIME 0x200 +#define CSR_BUS_TIME 0x204 +#define CSR_BUSY_TIMEOUT 0x210 +#define CSR_BUS_MANAGER_ID 0x21c +#define CSR_BANDWIDTH_AVAILABLE 0x220 +#define CSR_CHANNELS_AVAILABLE 0x224 +#define CSR_CHANNELS_AVAILABLE_HI 0x224 +#define CSR_CHANNELS_AVAILABLE_LO 0x228 +#define CSR_BROADCAST_CHANNEL 0x234 +#define CSR_CONFIG_ROM 0x400 +#define CSR_CONFIG_ROM_END 0x800 +#define CSR_FCP_COMMAND 0xB00 +#define CSR_FCP_RESPONSE 0xD00 +#define CSR_FCP_END 0xF00 +#define CSR_TOPOLOGY_MAP 0x1000 +#define CSR_TOPOLOGY_MAP_END 0x1400 +#define CSR_SPEED_MAP 0x2000 +#define CSR_SPEED_MAP_END 0x3000 + + +struct csr_control { + spinlock_t lock; + + quadlet_t state; + quadlet_t node_ids; + quadlet_t split_timeout_hi, split_timeout_lo; + unsigned long expire; // Calculated from split_timeout + quadlet_t cycle_time; + quadlet_t bus_time; + quadlet_t bus_manager_id; + quadlet_t bandwidth_available; + quadlet_t channels_available_hi, channels_available_lo; + quadlet_t broadcast_channel; + + quadlet_t *rom; + size_t rom_size; + unsigned char rom_version; + + + quadlet_t topology_map[256]; + quadlet_t speed_map[1024]; +}; + + +void init_csr(void); +void cleanup_csr(void); + +#endif /* _IEEE1394_CSR_H */ diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/dma.c.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/dma.c.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/dma.c.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/dma.c.svn-base 2003-07-21 13:09:38.000000000 +0200 @@ -0,0 +1,239 @@ +/* + * DMA region bookkeeping routines + * + * Copyright (C) 2002 Maas Digital LLC + * + * This code is licensed under the GPL. See the file COPYING in the root + * directory of the kernel sources for details. + */ + +#include +#include +#include +#include +#include "dma.h" + +/* dma_prog_region */ + +void dma_prog_region_init(struct dma_prog_region *prog) +{ + prog->kvirt = NULL; + prog->dev = NULL; + prog->n_pages = 0; + prog->bus_addr = 0; +} + +int dma_prog_region_alloc(struct dma_prog_region *prog, unsigned long n_bytes, struct pci_dev *dev) +{ + /* round up to page size */ + n_bytes = round_up_to_page(n_bytes); + + prog->n_pages = n_bytes / PAGE_SIZE; + + prog->kvirt = pci_alloc_consistent(dev, prog->n_pages * PAGE_SIZE, &prog->bus_addr); + if (!prog->kvirt) { + printk(KERN_ERR "dma_prog_region_alloc: pci_alloc_consistent() failed\n"); + dma_prog_region_free(prog); + return -ENOMEM; + } + + prog->dev = dev; + + return 0; +} + +void dma_prog_region_free(struct dma_prog_region *prog) +{ + if (prog->kvirt) { + pci_free_consistent(prog->dev, prog->n_pages * PAGE_SIZE, prog->kvirt, prog->bus_addr); + } + + prog->kvirt = NULL; + prog->dev = NULL; + prog->n_pages = 0; + prog->bus_addr = 0; +} + +/* dma_region */ + +void dma_region_init(struct dma_region *dma) +{ + dma->kvirt = NULL; + dma->dev = NULL; + dma->n_pages = 0; + dma->n_dma_pages = 0; + dma->sglist = NULL; +} + +int dma_region_alloc(struct dma_region *dma, unsigned long n_bytes, struct pci_dev *dev, int direction) +{ + unsigned int i, n_pages; + + /* round up to page size */ + n_bytes = round_up_to_page(n_bytes); + + n_pages = n_bytes / PAGE_SIZE; + + dma->kvirt = vmalloc_32(n_pages * PAGE_SIZE); + if (!dma->kvirt) { + printk(KERN_ERR "dma_region_alloc: vmalloc_32() failed\n"); + goto err; + } + + dma->n_pages = n_pages; + + /* Clear the ram out, no junk to the user */ + memset(dma->kvirt, 0, n_pages * PAGE_SIZE); + + /* allocate scatter/gather list */ + dma->sglist = kmalloc(dma->n_pages * sizeof(struct scatterlist), GFP_KERNEL); + if (!dma->sglist) { + printk(KERN_ERR "dma_region_alloc: kmalloc(sglist) failed\n"); + goto err; + } + + /* just to be safe - this will become unnecessary once sglist->address goes away */ + memset(dma->sglist, 0, dma->n_pages * sizeof(struct scatterlist)); + + /* fill scatter/gather list with pages */ + for (i = 0; i < dma->n_pages; i++) { + unsigned long va = (unsigned long) dma->kvirt + i * PAGE_SIZE; + + dma->sglist[i].page = vmalloc_to_page((void *)va); + dma->sglist[i].length = PAGE_SIZE; + } + + /* map sglist to the IOMMU */ + dma->n_dma_pages = pci_map_sg(dev, &dma->sglist[0], dma->n_pages, direction); + + if (dma->n_dma_pages == 0) { + printk(KERN_ERR "dma_region_alloc: pci_map_sg() failed\n"); + goto err; + } + + dma->dev = dev; + dma->direction = direction; + + return 0; + +err: + dma_region_free(dma); + return -ENOMEM; +} + +void dma_region_free(struct dma_region *dma) +{ + if (dma->n_dma_pages) { + pci_unmap_sg(dma->dev, dma->sglist, dma->n_pages, dma->direction); + dma->n_dma_pages = 0; + dma->dev = NULL; + } + + if (dma->sglist) { + kfree(dma->sglist); + dma->sglist = NULL; + } + + if (dma->kvirt) { + vfree(dma->kvirt); + dma->kvirt = NULL; + dma->n_pages = 0; + } +} + +/* find the scatterlist index and remaining offset corresponding to a + given offset from the beginning of the buffer */ +static inline int dma_region_find(struct dma_region *dma, unsigned long offset, unsigned long *rem) +{ + int i; + unsigned long off = offset; + + for (i = 0; i < dma->n_dma_pages; i++) { + if (off < sg_dma_len(&dma->sglist[i])) { + *rem = off; + break; + } + + off -= sg_dma_len(&dma->sglist[i]); + } + + BUG_ON(i >= dma->n_dma_pages); + + return i; +} + +dma_addr_t dma_region_offset_to_bus(struct dma_region *dma, unsigned long offset) +{ + unsigned long rem; + + struct scatterlist *sg = &dma->sglist[dma_region_find(dma, offset, &rem)]; + return sg_dma_address(sg) + rem; +} + +void dma_region_sync(struct dma_region *dma, unsigned long offset, unsigned long len) +{ + int first, last; + unsigned long rem; + + if (!len) + len = 1; + + first = dma_region_find(dma, offset, &rem); + last = dma_region_find(dma, offset + len - 1, &rem); + + pci_dma_sync_sg(dma->dev, &dma->sglist[first], last - first + 1, dma->direction); +} + +/* nopage() handler for mmap access */ + +static struct page* +dma_region_pagefault(struct vm_area_struct *area, unsigned long address, int write_access) +{ + unsigned long offset; + unsigned long kernel_virt_addr; + struct page *ret = NOPAGE_SIGBUS; + + struct dma_region *dma = (struct dma_region*) area->vm_private_data; + + if (!dma->kvirt) + goto out; + + if ( (address < (unsigned long) area->vm_start) || + (address > (unsigned long) area->vm_start + (PAGE_SIZE * dma->n_pages)) ) + goto out; + + offset = address - area->vm_start; + kernel_virt_addr = (unsigned long) dma->kvirt + offset; + ret = vmalloc_to_page((void*) kernel_virt_addr); + get_page(ret); +out: + return ret; +} + +static struct vm_operations_struct dma_region_vm_ops = { + .nopage = dma_region_pagefault, +}; + +int dma_region_mmap(struct dma_region *dma, struct file *file, struct vm_area_struct *vma) +{ + unsigned long size; + + if (!dma->kvirt) + return -EINVAL; + + /* must be page-aligned */ + if (vma->vm_pgoff != 0) + return -EINVAL; + + /* check the length */ + size = vma->vm_end - vma->vm_start; + if (size > (PAGE_SIZE * dma->n_pages)) + return -EINVAL; + + vma->vm_ops = &dma_region_vm_ops; + vma->vm_private_data = dma; + vma->vm_file = file; + vma->vm_flags |= VM_RESERVED; + + return 0; +} diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/dma.h.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/dma.h.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/dma.h.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/dma.h.svn-base 2003-07-21 13:09:40.000000000 +0200 @@ -0,0 +1,84 @@ +/* + * DMA region bookkeeping routines + * + * Copyright (C) 2002 Maas Digital LLC + * + * This code is licensed under the GPL. See the file COPYING in the root + * directory of the kernel sources for details. + */ + +#ifndef IEEE1394_DMA_H +#define IEEE1394_DMA_H + +#include +#include + +/* struct dma_prog_region + + a small, physically-contiguous DMA buffer with random-access, + synchronous usage characteristics +*/ + +struct dma_prog_region { + unsigned char *kvirt; /* kernel virtual address */ + struct pci_dev *dev; /* PCI device */ + unsigned int n_pages; /* # of kernel pages */ + dma_addr_t bus_addr; /* base bus address */ +}; + +/* clear out all fields but do not allocate any memory */ +void dma_prog_region_init(struct dma_prog_region *prog); +int dma_prog_region_alloc(struct dma_prog_region *prog, unsigned long n_bytes, struct pci_dev *dev); +void dma_prog_region_free(struct dma_prog_region *prog); + +static inline dma_addr_t dma_prog_region_offset_to_bus(struct dma_prog_region *prog, unsigned long offset) +{ + return prog->bus_addr + offset; +} + +/* struct dma_region + + a large, non-physically-contiguous DMA buffer with streaming, + asynchronous usage characteristics +*/ + +struct dma_region { + unsigned char *kvirt; /* kernel virtual address */ + struct pci_dev *dev; /* PCI device */ + unsigned int n_pages; /* # of kernel pages */ + unsigned int n_dma_pages; /* # of IOMMU pages */ + struct scatterlist *sglist; /* IOMMU mapping */ + int direction; /* PCI_DMA_TODEVICE, etc */ +}; + +/* clear out all fields but do not allocate anything */ +void dma_region_init(struct dma_region *dma); + +/* allocate the buffer and map it to the IOMMU */ +int dma_region_alloc(struct dma_region *dma, unsigned long n_bytes, struct pci_dev *dev, int direction); + +/* unmap and free the buffer */ +void dma_region_free(struct dma_region *dma); + +/* sync the IO bus' view of the buffer with the CPU's view */ +void dma_region_sync(struct dma_region *dma, unsigned long offset, unsigned long len); + +/* map the buffer into a user space process */ +int dma_region_mmap(struct dma_region *dma, struct file *file, struct vm_area_struct *vma); + +/* macro to index into a DMA region (or dma_prog_region) */ +#define dma_region_i(_dma, _type, _index) ( ((_type*) ((_dma)->kvirt)) + (_index) ) + +/* return the DMA bus address of the byte with the given offset + relative to the beginning of the dma_region */ +dma_addr_t dma_region_offset_to_bus(struct dma_region *dma, unsigned long offset); + +/* round up a number of bytes to be a multiple of the PAGE_SIZE */ +static inline unsigned long round_up_to_page(unsigned long len) +{ + if (len % PAGE_SIZE) + len += PAGE_SIZE - (len % PAGE_SIZE); + return len; +} + +#endif /* IEEE1394_DMA_H */ diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/dv1394-private.h.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/dv1394-private.h.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/dv1394-private.h.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/dv1394-private.h.svn-base 2003-07-21 13:09:35.000000000 +0200 @@ -0,0 +1,591 @@ +/* + * dv1394-private.h - DV input/output over IEEE 1394 on OHCI chips + * Copyright (C)2001 Daniel Maas + * receive, proc_fs by Dan Dennedy + * + * based on: + * video1394.h - driver for OHCI 1394 boards + * Copyright (C)1999,2000 Sebastien Rougeaux + * Peter Schlaile + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _DV_1394_PRIVATE_H +#define _DV_1394_PRIVATE_H + +#include "ieee1394.h" +#include "ohci1394.h" +#include "dma.h" + +/* data structures private to the dv1394 driver */ +/* none of this is exposed to user-space */ + + +/* + the 8-byte CIP (Common Isochronous Packet) header that precedes + each packet of DV data. + + See the IEC 61883 standard. +*/ + +struct CIP_header { unsigned char b[8]; }; + +static inline void fill_cip_header(struct CIP_header *cip, + unsigned char source_node_id, + unsigned long counter, + enum pal_or_ntsc format, + unsigned long timestamp) +{ + cip->b[0] = source_node_id; + cip->b[1] = 0x78; /* packet size in quadlets (480/4) - even for empty packets! */ + cip->b[2] = 0x00; + cip->b[3] = counter; + + cip->b[4] = 0x80; /* const */ + + switch(format) { + case DV1394_PAL: + cip->b[5] = 0x80; + break; + case DV1394_NTSC: + cip->b[5] = 0x00; + break; + } + + cip->b[6] = timestamp >> 8; + cip->b[7] = timestamp & 0xFF; +} + + + +/* + DMA commands used to program the OHCI's DMA engine + + See the Texas Instruments OHCI 1394 chipset documentation. +*/ + +struct output_more_immediate { u32 q[8]; }; +struct output_more { u32 q[4]; }; +struct output_last { u32 q[4]; }; +struct input_more { u32 q[4]; }; +struct input_last { u32 q[4]; }; + +/* outputs */ + +static inline void fill_output_more_immediate(struct output_more_immediate *omi, + unsigned char tag, + unsigned char channel, + unsigned char sync_tag, + unsigned int payload_size) +{ + omi->q[0] = cpu_to_le32(0x02000000 | 8); /* OUTPUT_MORE_IMMEDIATE; 8 is the size of the IT header */ + omi->q[1] = 0; + omi->q[2] = 0; + omi->q[3] = 0; + + /* IT packet header */ + omi->q[4] = cpu_to_le32( (0x0 << 16) /* IEEE1394_SPEED_100 */ + | (tag << 14) + | (channel << 8) + | (TCODE_ISO_DATA << 4) + | (sync_tag) ); + + /* reserved field; mimic behavior of my Sony DSR-40 */ + omi->q[5] = cpu_to_le32((payload_size << 16) | (0x7F << 8) | 0xA0); + + omi->q[6] = 0; + omi->q[7] = 0; +} + +static inline void fill_output_more(struct output_more *om, + unsigned int data_size, + unsigned long data_phys_addr) +{ + om->q[0] = cpu_to_le32(data_size); + om->q[1] = cpu_to_le32(data_phys_addr); + om->q[2] = 0; + om->q[3] = 0; +} + +static inline void fill_output_last(struct output_last *ol, + int want_timestamp, + int want_interrupt, + unsigned int data_size, + unsigned long data_phys_addr) +{ + u32 temp = 0; + temp |= 1 << 28; /* OUTPUT_LAST */ + + if (want_timestamp) /* controller will update timestamp at DMA time */ + temp |= 1 << 27; + + if (want_interrupt) + temp |= 3 << 20; + + temp |= 3 << 18; /* must take branch */ + temp |= data_size; + + ol->q[0] = cpu_to_le32(temp); + ol->q[1] = cpu_to_le32(data_phys_addr); + ol->q[2] = 0; + ol->q[3] = 0; +} + +/* inputs */ + +static inline void fill_input_more(struct input_more *im, + int want_interrupt, + unsigned int data_size, + unsigned long data_phys_addr) +{ + u32 temp = 2 << 28; /* INPUT_MORE */ + temp |= 8 << 24; /* s = 1, update xferStatus and resCount */ + if (want_interrupt) + temp |= 0 << 20; /* interrupts, i=0 in packet-per-buffer mode */ + temp |= 0x0 << 16; /* disable branch to address for packet-per-buffer mode */ + /* disable wait on sync field, not used in DV :-( */ + temp |= data_size; + + im->q[0] = cpu_to_le32(temp); + im->q[1] = cpu_to_le32(data_phys_addr); + im->q[2] = 0; /* branchAddress and Z not use in packet-per-buffer mode */ + im->q[3] = 0; /* xferStatus & resCount, resCount must be initialize to data_size */ +} + +static inline void fill_input_last(struct input_last *il, + int want_interrupt, + unsigned int data_size, + unsigned long data_phys_addr) +{ + u32 temp = 3 << 28; /* INPUT_LAST */ + temp |= 8 << 24; /* s = 1, update xferStatus and resCount */ + if (want_interrupt) + temp |= 3 << 20; /* enable interrupts */ + temp |= 0xC << 16; /* enable branch to address */ + /* disable wait on sync field, not used in DV :-( */ + temp |= data_size; + + il->q[0] = cpu_to_le32(temp); + il->q[1] = cpu_to_le32(data_phys_addr); + il->q[2] = cpu_to_le32(1); /* branchAddress (filled in later) and Z = 1 descriptor in next block */ + il->q[3] = cpu_to_le32(data_size); /* xferStatus & resCount, resCount must be initialize to data_size */ +} + + + +/* + A "DMA descriptor block" consists of several contiguous DMA commands. + struct DMA_descriptor_block encapsulates all of the commands necessary + to send one packet of DV data. + + There are three different types of these blocks: + + 1) command to send an empty packet (CIP header only, no DV data): + + OUTPUT_MORE-Immediate <-- contains the iso header in-line + OUTPUT_LAST <-- points to the CIP header + + 2) command to send a full packet when the DV data payload does NOT + cross a page boundary: + + OUTPUT_MORE-Immediate <-- contains the iso header in-line + OUTPUT_MORE <-- points to the CIP header + OUTPUT_LAST <-- points to entire DV data payload + + 3) command to send a full packet when the DV payload DOES cross + a page boundary: + + OUTPUT_MORE-Immediate <-- contains the iso header in-line + OUTPUT_MORE <-- points to the CIP header + OUTPUT_MORE <-- points to first part of DV data payload + OUTPUT_LAST <-- points to second part of DV data payload + + This struct describes all three block types using unions. + + !!! It is vital that an even number of these descriptor blocks fit on one + page of memory, since a block cannot cross a page boundary !!! + + */ + +struct DMA_descriptor_block { + + union { + struct { + /* iso header, common to all output block types */ + struct output_more_immediate omi; + + union { + /* empty packet */ + struct { + struct output_last ol; /* CIP header */ + } empty; + + /* full packet */ + struct { + struct output_more om; /* CIP header */ + + union { + /* payload does not cross page boundary */ + struct { + struct output_last ol; /* data payload */ + } nocross; + + /* payload crosses page boundary */ + struct { + struct output_more om; /* data payload */ + struct output_last ol; /* data payload */ + } cross; + } u; + + } full; + } u; + } out; + + struct { + struct input_last il; + } in; + + } u; + + /* ensure that PAGE_SIZE % sizeof(struct DMA_descriptor_block) == 0 + by padding out to 128 bytes */ + u32 __pad__[12]; +}; + + +/* struct frame contains all data associated with one frame in the + ringbuffer these are allocated when the DMA context is initialized + do_dv1394_init(). They are re-used after the card finishes + transmitting the frame. */ + +struct video_card; /* forward declaration */ + +struct frame { + + /* points to the struct video_card that owns this frame */ + struct video_card *video; + + /* index of this frame in video_card->frames[] */ + unsigned int frame_num; + + /* FRAME_CLEAR - DMA program not set up, waiting for data + FRAME_READY - DMA program written, ready to transmit + + Changes to these should be locked against the interrupt + */ + enum { + FRAME_CLEAR = 0, + FRAME_READY + } state; + + /* whether this frame has been DMA'ed already; used only from + the IRQ handler to determine whether the frame can be reset */ + int done; + + + /* kernel virtual pointer to the start of this frame's data in + the user ringbuffer. Use only for CPU access; to get the DMA + bus address you must go through the video->user_dma mapping */ + unsigned long data; + + /* Max # of packets per frame */ +#define MAX_PACKETS 500 + + + /* a PAGE_SIZE memory pool for allocating CIP headers + !header_pool must be aligned to PAGE_SIZE! */ + struct CIP_header *header_pool; + dma_addr_t header_pool_dma; + + + /* a physically contiguous memory pool for allocating DMA + descriptor blocks; usually around 64KB in size + !descriptor_pool must be aligned to PAGE_SIZE! */ + struct DMA_descriptor_block *descriptor_pool; + dma_addr_t descriptor_pool_dma; + unsigned long descriptor_pool_size; + + + /* # of packets allocated for this frame */ + unsigned int n_packets; + + + /* below are several pointers (kernel virtual addresses, not + DMA bus addresses) to parts of the DMA program. These are + set each time the DMA program is written in + frame_prepare(). They are used later on, e.g. from the + interrupt handler, to check the status of the frame */ + + /* points to status/timestamp field of first DMA packet */ + /* (we'll check it later to monitor timestamp accuracy) */ + u32 *frame_begin_timestamp; + + /* the timestamp we assigned to the first packet in the frame */ + u32 assigned_timestamp; + + /* pointer to the first packet's CIP header (where the timestamp goes) */ + struct CIP_header *cip_syt1; + + /* pointer to the second packet's CIP header + (only set if the first packet was empty) */ + struct CIP_header *cip_syt2; + + /* in order to figure out what caused an interrupt, + store pointers to the status fields of the two packets + that can cause interrupts. We'll check these from the + interrupt handler. + */ + u32 *mid_frame_timestamp; + u32 *frame_end_timestamp; + + /* branch address field of final packet. This is effectively + the "tail" in the chain of DMA descriptor blocks. + We will fill it with the address of the first DMA descriptor + block in the subsequent frame, once it is ready. + */ + u32 *frame_end_branch; + + /* the number of descriptors in the first descriptor block + of the frame. Needed to start DMA */ + int first_n_descriptors; +}; + + +struct packet { + u16 timestamp; + u16 invalid; + u16 iso_header; + u16 data_length; + u32 cip_h1; + u32 cip_h2; + unsigned char data[480]; + unsigned char padding[16]; /* force struct size =512 for page alignment */ +}; + + +/* allocate/free a frame */ +static struct frame* frame_new(unsigned int frame_num, struct video_card *video); +static void frame_delete(struct frame *f); + +/* reset f so that it can be used again */ +static void frame_reset(struct frame *f); + +/* struct video_card contains all data associated with one instance + of the dv1394 driver +*/ +enum modes { + MODE_RECEIVE, + MODE_TRANSMIT +}; + +struct video_card { + + /* ohci card to which this instance corresponds */ + struct ti_ohci *ohci; + + /* OHCI card id; the link between the VFS inode and a specific video_card + (essentially the device minor number) */ + int id; + + /* entry in dv1394_cards */ + struct list_head list; + + /* handle to /dev/ieee1394/dv/N, NULL if devfs not in use */ + devfs_handle_t devfs_handle; + + /* OHCI card IT DMA context number, -1 if not in use */ + int ohci_it_ctx; + struct ohci1394_iso_tasklet it_tasklet; + + /* register offsets for current IT DMA context, 0 if not in use */ + u32 ohci_IsoXmitContextControlSet; + u32 ohci_IsoXmitContextControlClear; + u32 ohci_IsoXmitCommandPtr; + + /* OHCI card IR DMA context number, -1 if not in use */ + struct ohci1394_iso_tasklet ir_tasklet; + int ohci_ir_ctx; + + /* register offsets for current IR DMA context, 0 if not in use */ + u32 ohci_IsoRcvContextControlSet; + u32 ohci_IsoRcvContextControlClear; + u32 ohci_IsoRcvCommandPtr; + u32 ohci_IsoRcvContextMatch; + + + /* CONCURRENCY CONTROL */ + + /* there are THREE levels of locking associated with video_card. */ + + /* + 1) the 'open' flag - this prevents more than one process from + opening the device. (the driver currently assumes only one opener). + This is a regular int, but use test_and_set_bit() (on bit zero) + for atomicity. + */ + unsigned long open; + + /* + 2) the spinlock - this provides mutual exclusion between the interrupt + handler and process-context operations. Generally you must take the + spinlock under the following conditions: + 1) DMA (and hence the interrupt handler) may be running + AND + 2) you need to operate on the video_card, especially active_frame + + It is OK to play with video_card without taking the spinlock if + you are certain that DMA is not running. Even if DMA is running, + it is OK to *read* active_frame with the lock, then drop it + immediately. This is safe because the interrupt handler will never + advance active_frame onto a frame that is not READY (and the spinlock + must be held while marking a frame READY). + + spinlock is also used to protect ohci_it_ctx and ohci_ir_ctx, + which can be accessed from both process and interrupt context + */ + spinlock_t spinlock; + + /* flag to prevent spurious interrupts (which OHCI seems to + generate a lot :) from accessing the struct */ + int dma_running; + + /* + 3) the sleeping semaphore 'sem' - this is used from process context only, + to serialize various operations on the video_card. Even though only one + open() is allowed, we still need to prevent multiple threads of execution + from entering calls like read, write, ioctl, etc. + + I honestly can't think of a good reason to use dv1394 from several threads + at once, but we need to serialize anyway to prevent oopses =). + + NOTE: if you need both spinlock and sem, take sem first to avoid deadlock! + */ + struct semaphore sem; + + /* people waiting for buffer space, please form a line here... */ + wait_queue_head_t waitq; + + /* support asynchronous I/O signals (SIGIO) */ + struct fasync_struct *fasync; + + /* the large, non-contiguous (rvmalloc()) ringbuffer for DV + data, exposed to user-space via mmap() */ + unsigned long dv_buf_size; + struct dma_region dv_buf; + + /* next byte in the ringbuffer that a write() call will fill */ + size_t write_off; + + struct frame *frames[DV1394_MAX_FRAMES]; + + /* n_frames also serves as an indicator that this struct video_card is + initialized and ready to run DMA buffers */ + + int n_frames; + + /* this is the frame that is currently "owned" by the OHCI DMA controller + (set to -1 iff DMA is not running) + + ! must lock against the interrupt handler when accessing it ! + + RULES: + + Only the interrupt handler may change active_frame if DMA + is running; if not, process may change it + + If the next frame is READY, the interrupt handler will advance + active_frame when the current frame is finished. + + If the next frame is CLEAR, the interrupt handler will re-transmit + the current frame, and the dropped_frames counter will be incremented. + + The interrupt handler will NEVER advance active_frame to a + frame that is not READY. + + */ + int active_frame; + int first_run; + + /* the same locking rules apply to these three fields also: */ + + /* altered ONLY from process context. Must check first_clear_frame->state; + if it's READY, that means the ringbuffer is full with READY frames; + if it's CLEAR, that means one or more ringbuffer frames are CLEAR */ + unsigned int first_clear_frame; + + /* altered both by process and interrupt */ + unsigned int n_clear_frames; + + /* only altered by the interrupt */ + unsigned int dropped_frames; + + + + /* the CIP accumulator and continuity counter are properties + of the DMA stream as a whole (not a single frame), so they + are stored here in the video_card */ + + unsigned long cip_accum; + unsigned long cip_n, cip_d; + unsigned int syt_offset; + unsigned int continuity_counter; + + enum pal_or_ntsc pal_or_ntsc; + + /* redundant, but simplifies the code somewhat */ + unsigned int frame_size; /* in bytes */ + + /* the isochronous channel to use, -1 if video card is inactive */ + int channel; + + + /* physically contiguous packet ringbuffer for receive */ + struct dma_region packet_buf; + unsigned long packet_buf_size; + + unsigned int current_packet; + int first_frame; /* received first start frame marker? */ + enum modes mode; +}; + +/* + if the video_card is not initialized, then the ONLY fields that are valid are: + ohci + open + n_frames +*/ + +static inline int video_card_initialized(struct video_card *v) +{ + return v->n_frames > 0; +} + +static int do_dv1394_init(struct video_card *video, struct dv1394_init *init); +static int do_dv1394_init_default(struct video_card *video); +static void do_dv1394_shutdown(struct video_card *video, int free_user_buf); + + +/* NTSC empty packet rate accurate to within 0.01%, + calibrated against a Sony DSR-40 DVCAM deck */ + +#define CIP_N_NTSC 68000000 +#define CIP_D_NTSC 1068000000 + +#define CIP_N_PAL 1 +#define CIP_D_PAL 16 + +#endif /* _DV_1394_PRIVATE_H */ + diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/dv1394.c.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/dv1394.c.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/dv1394.c.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/dv1394.c.svn-base 2003-07-21 13:09:45.000000000 +0200 @@ -0,0 +1,2970 @@ +/* + * dv1394.c - DV input/output over IEEE 1394 on OHCI chips + * Copyright (C)2001 Daniel Maas + * receive, proc_fs by Dan Dennedy + * + * based on: + * video1394.c - video driver for OHCI 1394 boards + * Copyright (C)1999,2000 Sebastien Rougeaux + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + OVERVIEW + + I designed dv1394 as a "pipe" that you can use to shoot DV onto a + FireWire bus. In transmission mode, dv1394 does the following: + + 1. accepts contiguous frames of DV data from user-space, via write() + or mmap() (see dv1394.h for the complete API) + 2. wraps IEC 61883 packets around the DV data, inserting + empty synchronization packets as necessary + 3. assigns accurate SYT timestamps to the outgoing packets + 4. shoots them out using the OHCI card's IT DMA engine + + Thanks to Dan Dennedy, we now have a receive mode that does the following: + + 1. accepts raw IEC 61883 packets from the OHCI card + 2. re-assembles the DV data payloads into contiguous frames, + discarding empty packets + 3. sends the DV data to user-space via read() or mmap() +*/ + +/* + TODO: + + - tunable frame-drop behavior: either loop last frame, or halt transmission + + - use a scatter/gather buffer for DMA programs (f->descriptor_pool) + so that we don't rely on allocating 64KB of contiguous kernel memory + via pci_alloc_consistent() + + DONE: + - during reception, better handling of dropped frames and continuity errors + - during reception, prevent DMA from bypassing the irq tasklets + - reduce irq rate during reception (1/250 packets). + - add many more internal buffers during reception with scatter/gather dma. + - add dbc (continuity) checking on receive, increment status.dropped_frames + if not continuous. + - restart IT DMA after a bus reset + - safely obtain and release ISO Tx channels in cooperation with OHCI driver + - map received DIF blocks to their proper location in DV frame (ensure + recovery if dropped packet) + - handle bus resets gracefully (OHCI card seems to take care of this itself(!)) + - do not allow resizing the user_buf once allocated; eliminate nuke_buffer_mappings + - eliminated #ifdef DV1394_DEBUG_LEVEL by inventing macros debug_printk and irq_printk + - added wmb() and mb() to places where PCI read/write ordering needs to be enforced + - set video->id correctly + - store video_cards in an array indexed by OHCI card ID, rather than a list + - implement DMA context allocation to cooperate with other users of the OHCI + - fix all XXX showstoppers + - disable IR/IT DMA interrupts on shutdown + - flush pci writes to the card by issuing a read + - devfs and character device dispatching (* needs testing with Linux 2.2.x) + - switch over to the new kernel DMA API (pci_map_*()) (* needs testing on platforms with IOMMU!) + - keep all video_cards in a list (for open() via chardev), set file->private_data = video + - dv1394_poll should indicate POLLIN when receiving buffers are available + - add proc fs interface to set cip_n, cip_d, syt_offset, and video signal + - expose xmit and recv as separate devices (not exclusive) + - expose NTSC and PAL as separate devices (can be overridden) + - read/edit channel in procfs + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ieee1394.h" +#include "ieee1394_types.h" +#include "nodemgr.h" +#include "hosts.h" +#include "ieee1394_core.h" +#include "highlevel.h" +#include "dv1394.h" +#include "dv1394-private.h" + +#include "ohci1394.h" + +#ifndef virt_to_page +#define virt_to_page(x) MAP_NR(x) +#endif + +#ifndef vmalloc_32 +#define vmalloc_32(x) vmalloc(x) +#endif + + +/* DEBUG LEVELS: + 0 - no debugging messages + 1 - some debugging messages, but none during DMA frame transmission + 2 - lots of messages, including during DMA frame transmission + (will cause undeflows if your machine is too slow!) +*/ + +#define DV1394_DEBUG_LEVEL 0 + +/* for debugging use ONLY: allow more than one open() of the device */ +/* #define DV1394_ALLOW_MORE_THAN_ONE_OPEN 1 */ + +#if DV1394_DEBUG_LEVEL >= 2 +#define irq_printk( args... ) printk( args ) +#else +#define irq_printk( args... ) +#endif + +#if DV1394_DEBUG_LEVEL >= 1 +#define debug_printk( args... ) printk( args) +#else +#define debug_printk( args... ) +#endif + +/* issue a dummy PCI read to force the preceding write + to be posted to the PCI bus immediately */ + +static inline void flush_pci_write(struct ti_ohci *ohci) +{ + mb(); + reg_read(ohci, OHCI1394_IsochronousCycleTimer); +} + +static void it_tasklet_func(unsigned long data); +static void ir_tasklet_func(unsigned long data); + +/* GLOBAL DATA */ + +/* list of all video_cards */ +static LIST_HEAD(dv1394_cards); +static spinlock_t dv1394_cards_lock = SPIN_LOCK_UNLOCKED; + +static LIST_HEAD(dv1394_devfs); +struct dv1394_devfs_entry { + struct list_head list; + devfs_handle_t devfs; + char name[32]; + struct dv1394_devfs_entry *parent; +}; +static spinlock_t dv1394_devfs_lock = SPIN_LOCK_UNLOCKED; + +/* translate from a struct file* to the corresponding struct video_card* */ + +static inline struct video_card* file_to_video_card(struct file *file) +{ + return (struct video_card*) file->private_data; +} + +/*** FRAME METHODS *********************************************************/ + +static void frame_reset(struct frame *f) +{ + f->state = FRAME_CLEAR; + f->done = 0; + f->n_packets = 0; + f->frame_begin_timestamp = NULL; + f->assigned_timestamp = 0; + f->cip_syt1 = NULL; + f->cip_syt2 = NULL; + f->mid_frame_timestamp = NULL; + f->frame_end_timestamp = NULL; + f->frame_end_branch = NULL; +} + +static struct frame* frame_new(unsigned int frame_num, struct video_card *video) +{ + struct frame *f = kmalloc(sizeof(*f), GFP_KERNEL); + if (!f) + return NULL; + + f->video = video; + f->frame_num = frame_num; + + f->header_pool = pci_alloc_consistent(f->video->ohci->dev, PAGE_SIZE, &f->header_pool_dma); + if (!f->header_pool) { + printk(KERN_ERR "dv1394: failed to allocate CIP header pool\n"); + kfree(f); + return NULL; + } + + debug_printk("dv1394: frame_new: allocated CIP header pool at virt 0x%08lx (contig) dma 0x%08lx size %ld\n", + (unsigned long) f->header_pool, (unsigned long) f->header_pool_dma, PAGE_SIZE); + + f->descriptor_pool_size = MAX_PACKETS * sizeof(struct DMA_descriptor_block); + /* make it an even # of pages */ + f->descriptor_pool_size += PAGE_SIZE - (f->descriptor_pool_size%PAGE_SIZE); + + f->descriptor_pool = pci_alloc_consistent(f->video->ohci->dev, + f->descriptor_pool_size, + &f->descriptor_pool_dma); + if (!f->descriptor_pool) { + pci_free_consistent(f->video->ohci->dev, PAGE_SIZE, f->header_pool, f->header_pool_dma); + kfree(f); + return NULL; + } + + debug_printk("dv1394: frame_new: allocated DMA program memory at virt 0x%08lx (contig) dma 0x%08lx size %ld\n", + (unsigned long) f->descriptor_pool, (unsigned long) f->descriptor_pool_dma, f->descriptor_pool_size); + + f->data = 0; + frame_reset(f); + + return f; +} + +static void frame_delete(struct frame *f) +{ + pci_free_consistent(f->video->ohci->dev, PAGE_SIZE, f->header_pool, f->header_pool_dma); + pci_free_consistent(f->video->ohci->dev, f->descriptor_pool_size, f->descriptor_pool, f->descriptor_pool_dma); + kfree(f); +} + + + + +/* + frame_prepare() - build the DMA program for transmitting + + Frame_prepare() must be called OUTSIDE the video->spinlock. + However, frame_prepare() must still be serialized, so + it should be called WITH the video->sem taken. + */ + +static void frame_prepare(struct video_card *video, unsigned int this_frame) +{ + struct frame *f = video->frames[this_frame]; + int last_frame; + + struct DMA_descriptor_block *block; + dma_addr_t block_dma; + struct CIP_header *cip; + dma_addr_t cip_dma; + + unsigned int n_descriptors, full_packets, packets_per_frame, payload_size; + + /* these flags denote packets that need special attention */ + int empty_packet, first_packet, last_packet, mid_packet; + + u32 *branch_address, *last_branch_address = NULL; + unsigned long data_p; + int first_packet_empty = 0; + u32 cycleTimer, ct_sec, ct_cyc, ct_off; + unsigned long irq_flags; + + irq_printk("frame_prepare( %d ) ---------------------\n", this_frame); + + full_packets = 0; + + + + if (video->pal_or_ntsc == DV1394_PAL) + packets_per_frame = DV1394_PAL_PACKETS_PER_FRAME; + else + packets_per_frame = DV1394_NTSC_PACKETS_PER_FRAME; + + while ( full_packets < packets_per_frame ) { + empty_packet = first_packet = last_packet = mid_packet = 0; + + data_p = f->data + full_packets * 480; + + /************************************************/ + /* allocate a descriptor block and a CIP header */ + /************************************************/ + + /* note: these should NOT cross a page boundary (DMA restriction) */ + + if (f->n_packets >= MAX_PACKETS) { + printk(KERN_ERR "dv1394: FATAL ERROR: max packet count exceeded\n"); + return; + } + + /* the block surely won't cross a page boundary, + since an even number of descriptor_blocks fit on a page */ + block = &(f->descriptor_pool[f->n_packets]); + + /* DMA address of the block = offset of block relative + to the kernel base address of the descriptor pool + + DMA base address of the descriptor pool */ + block_dma = ((unsigned long) block - (unsigned long) f->descriptor_pool) + f->descriptor_pool_dma; + + + /* the whole CIP pool fits on one page, so no worries about boundaries */ + if ( ((unsigned long) &(f->header_pool[f->n_packets]) - (unsigned long) f->header_pool) + > PAGE_SIZE) { + printk(KERN_ERR "dv1394: FATAL ERROR: no room to allocate CIP header\n"); + return; + } + + cip = &(f->header_pool[f->n_packets]); + + /* DMA address of the CIP header = offset of cip + relative to kernel base address of the header pool + + DMA base address of the header pool */ + cip_dma = (unsigned long) cip % PAGE_SIZE + f->header_pool_dma; + + /* is this an empty packet? */ + + if (video->cip_accum > (video->cip_d - video->cip_n)) { + empty_packet = 1; + payload_size = 8; + video->cip_accum -= (video->cip_d - video->cip_n); + } else { + payload_size = 488; + video->cip_accum += video->cip_n; + } + + /* there are three important packets each frame: + + the first packet in the frame - we ask the card to record the timestamp when + this packet is actually sent, so we can monitor + how accurate our timestamps are. Also, the first + packet serves as a semaphore to let us know that + it's OK to free the *previous* frame's DMA buffer + + the last packet in the frame - this packet is used to detect buffer underflows. + if this is the last ready frame, the last DMA block + will have a branch back to the beginning of the frame + (so that the card will re-send the frame on underflow). + if this branch gets taken, we know that at least one + frame has been dropped. When the next frame is ready, + the branch is pointed to its first packet, and the + semaphore is disabled. + + a "mid" packet slightly before the end of the frame - this packet should trigger + an interrupt so we can go and assign a timestamp to the first packet + in the next frame. We don't use the very last packet in the frame + for this purpose, because that would leave very little time to set + the timestamp before DMA starts on the next frame. + */ + + if (f->n_packets == 0) { + first_packet = 1; + } else if ( full_packets == (packets_per_frame-1) ) { + last_packet = 1; + } else if (f->n_packets == packets_per_frame) { + mid_packet = 1; + } + + + /********************/ + /* setup CIP header */ + /********************/ + + /* the timestamp will be written later from the + mid-frame interrupt handler. For now we just + store the address of the CIP header(s) that + need a timestamp. */ + + /* first packet in the frame needs a timestamp */ + if (first_packet) { + f->cip_syt1 = cip; + if (empty_packet) + first_packet_empty = 1; + + } else if (first_packet_empty && (f->n_packets == 1) ) { + /* if the first packet was empty, the second + packet's CIP header also needs a timestamp */ + f->cip_syt2 = cip; + } + + fill_cip_header(cip, + /* the node ID number of the OHCI card */ + reg_read(video->ohci, OHCI1394_NodeID) & 0x3F, + video->continuity_counter, + video->pal_or_ntsc, + 0xFFFF /* the timestamp is filled in later */); + + /* advance counter, only for full packets */ + if ( ! empty_packet ) + video->continuity_counter++; + + /******************************/ + /* setup DMA descriptor block */ + /******************************/ + + /* first descriptor - OUTPUT_MORE_IMMEDIATE, for the controller's IT header */ + fill_output_more_immediate( &(block->u.out.omi), 1, video->channel, 0, payload_size); + + if (empty_packet) { + /* second descriptor - OUTPUT_LAST for CIP header */ + fill_output_last( &(block->u.out.u.empty.ol), + + /* want completion status on all interesting packets */ + (first_packet || mid_packet || last_packet) ? 1 : 0, + + /* want interrupts on all interesting packets */ + (first_packet || mid_packet || last_packet) ? 1 : 0, + + sizeof(struct CIP_header), /* data size */ + cip_dma); + + if (first_packet) + f->frame_begin_timestamp = &(block->u.out.u.empty.ol.q[3]); + else if (mid_packet) + f->mid_frame_timestamp = &(block->u.out.u.empty.ol.q[3]); + else if (last_packet) { + f->frame_end_timestamp = &(block->u.out.u.empty.ol.q[3]); + f->frame_end_branch = &(block->u.out.u.empty.ol.q[2]); + } + + branch_address = &(block->u.out.u.empty.ol.q[2]); + n_descriptors = 3; + if (first_packet) + f->first_n_descriptors = n_descriptors; + + } else { /* full packet */ + + /* second descriptor - OUTPUT_MORE for CIP header */ + fill_output_more( &(block->u.out.u.full.om), + sizeof(struct CIP_header), /* data size */ + cip_dma); + + + /* third (and possibly fourth) descriptor - for DV data */ + /* the 480-byte payload can cross a page boundary; if so, + we need to split it into two DMA descriptors */ + + /* does the 480-byte data payload cross a page boundary? */ + if ( (PAGE_SIZE- ((unsigned long)data_p % PAGE_SIZE) ) < 480 ) { + + /* page boundary crossed */ + + fill_output_more( &(block->u.out.u.full.u.cross.om), + /* data size - how much of data_p fits on the first page */ + PAGE_SIZE - (data_p % PAGE_SIZE), + + /* DMA address of data_p */ + dma_region_offset_to_bus(&video->dv_buf, + data_p - (unsigned long) video->dv_buf.kvirt)); + + fill_output_last( &(block->u.out.u.full.u.cross.ol), + + /* want completion status on all interesting packets */ + (first_packet || mid_packet || last_packet) ? 1 : 0, + + /* want interrupt on all interesting packets */ + (first_packet || mid_packet || last_packet) ? 1 : 0, + + /* data size - remaining portion of data_p */ + 480 - (PAGE_SIZE - (data_p % PAGE_SIZE)), + + /* DMA address of data_p + PAGE_SIZE - (data_p % PAGE_SIZE) */ + dma_region_offset_to_bus(&video->dv_buf, + data_p + PAGE_SIZE - (data_p % PAGE_SIZE) - (unsigned long) video->dv_buf.kvirt)); + + if (first_packet) + f->frame_begin_timestamp = &(block->u.out.u.full.u.cross.ol.q[3]); + else if (mid_packet) + f->mid_frame_timestamp = &(block->u.out.u.full.u.cross.ol.q[3]); + else if (last_packet) { + f->frame_end_timestamp = &(block->u.out.u.full.u.cross.ol.q[3]); + f->frame_end_branch = &(block->u.out.u.full.u.cross.ol.q[2]); + } + + branch_address = &(block->u.out.u.full.u.cross.ol.q[2]); + + n_descriptors = 5; + if (first_packet) + f->first_n_descriptors = n_descriptors; + + full_packets++; + + } else { + /* fits on one page */ + + fill_output_last( &(block->u.out.u.full.u.nocross.ol), + + /* want completion status on all interesting packets */ + (first_packet || mid_packet || last_packet) ? 1 : 0, + + /* want interrupt on all interesting packets */ + (first_packet || mid_packet || last_packet) ? 1 : 0, + + 480, /* data size (480 bytes of DV data) */ + + + /* DMA address of data_p */ + dma_region_offset_to_bus(&video->dv_buf, + data_p - (unsigned long) video->dv_buf.kvirt)); + + if (first_packet) + f->frame_begin_timestamp = &(block->u.out.u.full.u.nocross.ol.q[3]); + else if (mid_packet) + f->mid_frame_timestamp = &(block->u.out.u.full.u.nocross.ol.q[3]); + else if (last_packet) { + f->frame_end_timestamp = &(block->u.out.u.full.u.nocross.ol.q[3]); + f->frame_end_branch = &(block->u.out.u.full.u.nocross.ol.q[2]); + } + + branch_address = &(block->u.out.u.full.u.nocross.ol.q[2]); + + n_descriptors = 4; + if (first_packet) + f->first_n_descriptors = n_descriptors; + + full_packets++; + } + } + + /* link this descriptor block into the DMA program by filling in + the branch address of the previous block */ + + /* note: we are not linked into the active DMA chain yet */ + + if (last_branch_address) { + *(last_branch_address) = cpu_to_le32(block_dma | n_descriptors); + } + + last_branch_address = branch_address; + + + f->n_packets++; + + } + + /* when we first assemble a new frame, set the final branch + to loop back up to the top */ + *(f->frame_end_branch) = cpu_to_le32(f->descriptor_pool_dma | f->first_n_descriptors); + + /* make the latest version of this frame visible to the PCI card */ + dma_region_sync(&video->dv_buf, f->data - (unsigned long) video->dv_buf.kvirt, video->frame_size); + + /* lock against DMA interrupt */ + spin_lock_irqsave(&video->spinlock, irq_flags); + + f->state = FRAME_READY; + + video->n_clear_frames--; + + last_frame = video->first_clear_frame - 1; + if (last_frame == -1) + last_frame = video->n_frames-1; + + video->first_clear_frame = (video->first_clear_frame + 1) % video->n_frames; + + irq_printk(" frame %d prepared, active_frame = %d, n_clear_frames = %d, first_clear_frame = %d\n last=%d\n", + this_frame, video->active_frame, video->n_clear_frames, video->first_clear_frame, last_frame); + + irq_printk(" begin_ts %08lx mid_ts %08lx end_ts %08lx end_br %08lx\n", + (unsigned long) f->frame_begin_timestamp, + (unsigned long) f->mid_frame_timestamp, + (unsigned long) f->frame_end_timestamp, + (unsigned long) f->frame_end_branch); + + if (video->active_frame != -1) { + + /* if DMA is already active, we are almost done */ + /* just link us onto the active DMA chain */ + if (video->frames[last_frame]->frame_end_branch) { + u32 temp; + + /* point the previous frame's tail to this frame's head */ + *(video->frames[last_frame]->frame_end_branch) = cpu_to_le32(f->descriptor_pool_dma | f->first_n_descriptors); + + /* this write MUST precede the next one, or we could silently drop frames */ + wmb(); + + /* disable the want_status semaphore on the last packet */ + temp = le32_to_cpu(*(video->frames[last_frame]->frame_end_branch - 2)); + temp &= 0xF7CFFFFF; + *(video->frames[last_frame]->frame_end_branch - 2) = cpu_to_le32(temp); + + /* flush these writes to memory ASAP */ + flush_pci_write(video->ohci); + + /* NOTE: + ideally the writes should be "atomic": if + the OHCI card reads the want_status flag in + between them, we'll falsely report a + dropped frame. Hopefully this window is too + small to really matter, and the consequence + is rather harmless. */ + + + irq_printk(" new frame %d linked onto DMA chain\n", this_frame); + + } else { + printk(KERN_ERR "dv1394: last frame not ready???\n"); + } + + } else { + + u32 transmit_sec, transmit_cyc; + u32 ts_cyc, ts_off; + + /* DMA is stopped, so this is the very first frame */ + video->active_frame = this_frame; + + /* set CommandPtr to address and size of first descriptor block */ + reg_write(video->ohci, video->ohci_IsoXmitCommandPtr, + video->frames[video->active_frame]->descriptor_pool_dma | + f->first_n_descriptors); + + /* assign a timestamp based on the current cycle time... + We'll tell the card to begin DMA 100 cycles from now, + and assign a timestamp 103 cycles from now */ + + cycleTimer = reg_read(video->ohci, OHCI1394_IsochronousCycleTimer); + + ct_sec = cycleTimer >> 25; + ct_cyc = (cycleTimer >> 12) & 0x1FFF; + ct_off = cycleTimer & 0xFFF; + + transmit_sec = ct_sec; + transmit_cyc = ct_cyc + 100; + + transmit_sec += transmit_cyc/8000; + transmit_cyc %= 8000; + + ts_off = ct_off; + ts_cyc = transmit_cyc + 3; + ts_cyc %= 8000; + + f->assigned_timestamp = (ts_cyc&0xF) << 12; + + /* now actually write the timestamp into the appropriate CIP headers */ + if (f->cip_syt1) { + f->cip_syt1->b[6] = f->assigned_timestamp >> 8; + f->cip_syt1->b[7] = f->assigned_timestamp & 0xFF; + } + if (f->cip_syt2) { + f->cip_syt2->b[6] = f->assigned_timestamp >> 8; + f->cip_syt2->b[7] = f->assigned_timestamp & 0xFF; + } + + /* --- start DMA --- */ + + /* clear all bits in ContextControl register */ + + reg_write(video->ohci, video->ohci_IsoXmitContextControlClear, 0xFFFFFFFF); + wmb(); + + /* the OHCI card has the ability to start ISO transmission on a + particular cycle (start-on-cycle). This way we can ensure that + the first DV frame will have an accurate timestamp. + + However, start-on-cycle only appears to work if the OHCI card + is cycle master! Since the consequences of messing up the first + timestamp are minimal*, just disable start-on-cycle for now. + + * my DV deck drops the first few frames before it "locks in;" + so the first frame having an incorrect timestamp is inconsequential. + */ + +#if 0 + reg_write(video->ohci, video->ohci_IsoXmitContextControlSet, + (1 << 31) /* enable start-on-cycle */ + | ( (transmit_sec & 0x3) << 29) + | (transmit_cyc << 16)); + wmb(); +#endif + + video->dma_running = 1; + + /* set the 'run' bit */ + reg_write(video->ohci, video->ohci_IsoXmitContextControlSet, 0x8000); + flush_pci_write(video->ohci); + + /* --- DMA should be running now --- */ + + debug_printk(" Cycle = %4u ContextControl = %08x CmdPtr = %08x\n", + (reg_read(video->ohci, OHCI1394_IsochronousCycleTimer) >> 12) & 0x1FFF, + reg_read(video->ohci, video->ohci_IsoXmitContextControlSet), + reg_read(video->ohci, video->ohci_IsoXmitCommandPtr)); + + debug_printk(" DMA start - current cycle %4u, transmit cycle %4u (%2u), assigning ts cycle %2u\n", + ct_cyc, transmit_cyc, transmit_cyc & 0xF, ts_cyc & 0xF); + +#if DV1394_DEBUG_LEVEL >= 2 + { + /* check if DMA is really running */ + int i = 0; + while (i < 20) { + mb(); + mdelay(1); + if (reg_read(video->ohci, video->ohci_IsoXmitContextControlSet) & (1 << 10)) { + printk("DMA ACTIVE after %d msec\n", i); + break; + } + i++; + } + + printk("set = %08x, cmdPtr = %08x\n", + reg_read(video->ohci, video->ohci_IsoXmitContextControlSet), + reg_read(video->ohci, video->ohci_IsoXmitCommandPtr) + ); + + if ( ! (reg_read(video->ohci, video->ohci_IsoXmitContextControlSet) & (1 << 10)) ) { + printk("DMA did NOT go active after 20ms, event = %x\n", + reg_read(video->ohci, video->ohci_IsoXmitContextControlSet) & 0x1F); + } else + printk("DMA is RUNNING!\n"); + } +#endif + + } + + + spin_unlock_irqrestore(&video->spinlock, irq_flags); +} + + + +/*** RECEIVE FUNCTIONS *****************************************************/ + +/* + frame method put_packet + + map and copy the packet data to its location in the frame + based upon DIF section and sequence +*/ + +static void inline +frame_put_packet (struct frame *f, struct packet *p) +{ + int section_type = p->data[0] >> 5; /* section type is in bits 5 - 7 */ + int dif_sequence = p->data[1] >> 4; /* dif sequence number is in bits 4 - 7 */ + int dif_block = p->data[2]; + + /* sanity check */ + if (dif_sequence > 11 || dif_block > 149) return; + + switch (section_type) { + case 0: /* 1 Header block */ + memcpy( (void *) f->data + dif_sequence * 150 * 80, p->data, 480); + break; + + case 1: /* 2 Subcode blocks */ + memcpy( (void *) f->data + dif_sequence * 150 * 80 + (1 + dif_block) * 80, p->data, 480); + break; + + case 2: /* 3 VAUX blocks */ + memcpy( (void *) f->data + dif_sequence * 150 * 80 + (3 + dif_block) * 80, p->data, 480); + break; + + case 3: /* 9 Audio blocks interleaved with video */ + memcpy( (void *) f->data + dif_sequence * 150 * 80 + (6 + dif_block * 16) * 80, p->data, 480); + break; + + case 4: /* 135 Video blocks interleaved with audio */ + memcpy( (void *) f->data + dif_sequence * 150 * 80 + (7 + (dif_block / 15) + dif_block) * 80, p->data, 480); + break; + + default: /* we can not handle any other data */ + break; + } +} + + +static void start_dma_receive(struct video_card *video) +{ + if (video->first_run == 1) { + video->first_run = 0; + + /* start DMA once all of the frames are READY */ + video->n_clear_frames = 0; + video->first_clear_frame = -1; + video->current_packet = 0; + video->active_frame = 0; + + /* reset iso recv control register */ + reg_write(video->ohci, video->ohci_IsoRcvContextControlClear, 0xFFFFFFFF); + wmb(); + + /* clear bufferFill, set isochHeader and speed (0=100) */ + reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, 0x40000000); + + /* match on all tags, listen on channel */ + reg_write(video->ohci, video->ohci_IsoRcvContextMatch, 0xf0000000 | video->channel); + + /* address and first descriptor block + Z=1 */ + reg_write(video->ohci, video->ohci_IsoRcvCommandPtr, + video->frames[0]->descriptor_pool_dma | 1); /* Z=1 */ + wmb(); + + video->dma_running = 1; + + /* run */ + reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, 0x8000); + flush_pci_write(video->ohci); + + debug_printk("dv1394: DMA started\n"); + +#if DV1394_DEBUG_LEVEL >= 2 + { + int i; + + for (i = 0; i < 1000; ++i) { + mdelay(1); + if (reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) { + printk("DMA ACTIVE after %d msec\n", i); + break; + } + } + if ( reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 11) ) { + printk("DEAD, event = %x\n", + reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & 0x1F); + } else + printk("RUNNING!\n"); + } +#endif + } + else if ( reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 11) ) { + debug_printk("DEAD, event = %x\n", + reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & 0x1F); + + /* wake */ + reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, (1 << 12)); + } +} + + +/* + receive_packets() - build the DMA program for receiving +*/ + +static void receive_packets(struct video_card *video) +{ + struct DMA_descriptor_block *block = NULL; + dma_addr_t block_dma = 0; + struct packet *data = NULL; + dma_addr_t data_dma = 0; + u32 *last_branch_address = NULL; + unsigned long irq_flags; + int want_interrupt = 0; + struct frame *f = NULL; + int i, j; + + spin_lock_irqsave(&video->spinlock, irq_flags); + + for (j = 0; j < video->n_frames; j++) { + + /* connect frames */ + if (j > 0 && f != NULL && f->frame_end_branch != NULL) + *(f->frame_end_branch) = cpu_to_le32(video->frames[j]->descriptor_pool_dma | 1); /* set Z=1 */ + + f = video->frames[j]; + + for (i = 0; i < MAX_PACKETS; i++) { + /* locate a descriptor block and packet from the buffer */ + block = &(f->descriptor_pool[i]); + block_dma = ((unsigned long) block - (unsigned long) f->descriptor_pool) + f->descriptor_pool_dma; + + data = ((struct packet*)video->packet_buf.kvirt) + f->frame_num * MAX_PACKETS + i; + data_dma = dma_region_offset_to_bus( &video->packet_buf, + ((unsigned long) data - (unsigned long) video->packet_buf.kvirt) ); + + /* setup DMA descriptor block */ + want_interrupt = ((i % (MAX_PACKETS/2)) == 0 || i == (MAX_PACKETS-1)); + fill_input_last( &(block->u.in.il), want_interrupt, 512, data_dma); + + /* link descriptors */ + last_branch_address = f->frame_end_branch; + + if (last_branch_address != NULL) + *(last_branch_address) = cpu_to_le32(block_dma | 1); /* set Z=1 */ + + f->frame_end_branch = &(block->u.in.il.q[2]); + } + + } /* next j */ + + spin_unlock_irqrestore(&video->spinlock, irq_flags); + +} + + + +/*** MANAGEMENT FUNCTIONS **************************************************/ + +static int do_dv1394_init(struct video_card *video, struct dv1394_init *init) +{ + unsigned long flags, new_buf_size; + int i; + u64 chan_mask; + int retval = -EINVAL; + + debug_printk("dv1394: initialising %d\n", video->id); + if (init->api_version != DV1394_API_VERSION) + return -EINVAL; + + /* first sanitize all the parameters */ + if ( (init->n_frames < 2) || (init->n_frames > DV1394_MAX_FRAMES) ) + return -EINVAL; + + if ( (init->format != DV1394_NTSC) && (init->format != DV1394_PAL) ) + return -EINVAL; + + if ( (init->syt_offset == 0) || (init->syt_offset > 50) ) + /* default SYT offset is 3 cycles */ + init->syt_offset = 3; + + if ( (init->channel > 63) || (init->channel < 0) ) + init->channel = 63; + + chan_mask = (u64)1 << init->channel; + + /* calculate what size DMA buffer is needed */ + if (init->format == DV1394_NTSC) + new_buf_size = DV1394_NTSC_FRAME_SIZE * init->n_frames; + else + new_buf_size = DV1394_PAL_FRAME_SIZE * init->n_frames; + + /* round up to PAGE_SIZE */ + if (new_buf_size % PAGE_SIZE) new_buf_size += PAGE_SIZE - (new_buf_size % PAGE_SIZE); + + /* don't allow the user to allocate the DMA buffer more than once */ + if (video->dv_buf.kvirt && video->dv_buf_size != new_buf_size) { + printk("dv1394: re-sizing the DMA buffer is not allowed\n"); + return -EINVAL; + } + + /* shutdown the card if it's currently active */ + /* (the card should not be reset if the parameters are screwy) */ + + do_dv1394_shutdown(video, 0); + + /* try to claim the ISO channel */ + spin_lock_irqsave(&video->ohci->IR_channel_lock, flags); + if (video->ohci->ISO_channel_usage & chan_mask) { + spin_unlock_irqrestore(&video->ohci->IR_channel_lock, flags); + retval = -EBUSY; + goto err; + } + video->ohci->ISO_channel_usage |= chan_mask; + spin_unlock_irqrestore(&video->ohci->IR_channel_lock, flags); + + video->channel = init->channel; + + /* initialize misc. fields of video */ + video->n_frames = init->n_frames; + video->pal_or_ntsc = init->format; + + video->cip_accum = 0; + video->continuity_counter = 0; + + video->active_frame = -1; + video->first_clear_frame = 0; + video->n_clear_frames = video->n_frames; + video->dropped_frames = 0; + + video->write_off = 0; + + video->first_run = 1; + video->current_packet = -1; + video->first_frame = 0; + + if (video->pal_or_ntsc == DV1394_NTSC) { + video->cip_n = init->cip_n != 0 ? init->cip_n : CIP_N_NTSC; + video->cip_d = init->cip_d != 0 ? init->cip_d : CIP_D_NTSC; + video->frame_size = DV1394_NTSC_FRAME_SIZE; + } else { + video->cip_n = init->cip_n != 0 ? init->cip_n : CIP_N_PAL; + video->cip_d = init->cip_d != 0 ? init->cip_d : CIP_D_PAL; + video->frame_size = DV1394_PAL_FRAME_SIZE; + } + + video->syt_offset = init->syt_offset; + + /* find and claim DMA contexts on the OHCI card */ + + if (video->ohci_it_ctx == -1) { + ohci1394_init_iso_tasklet(&video->it_tasklet, OHCI_ISO_TRANSMIT, + it_tasklet_func, (unsigned long) video); + + if (ohci1394_register_iso_tasklet(video->ohci, &video->it_tasklet) < 0) { + printk(KERN_ERR "dv1394: could not find an available IT DMA context\n"); + retval = -EBUSY; + goto err; + } + + video->ohci_it_ctx = video->it_tasklet.context; + debug_printk("dv1394: claimed IT DMA context %d\n", video->ohci_it_ctx); + } + + if (video->ohci_ir_ctx == -1) { + ohci1394_init_iso_tasklet(&video->ir_tasklet, OHCI_ISO_RECEIVE, + ir_tasklet_func, (unsigned long) video); + + if (ohci1394_register_iso_tasklet(video->ohci, &video->ir_tasklet) < 0) { + printk(KERN_ERR "dv1394: could not find an available IR DMA context\n"); + retval = -EBUSY; + goto err; + } + video->ohci_ir_ctx = video->ir_tasklet.context; + debug_printk("dv1394: claimed IR DMA context %d\n", video->ohci_ir_ctx); + } + + /* allocate struct frames */ + for (i = 0; i < init->n_frames; i++) { + video->frames[i] = frame_new(i, video); + + if (!video->frames[i]) { + printk(KERN_ERR "dv1394: Cannot allocate frame structs\n"); + retval = -ENOMEM; + goto err; + } + } + + if (!video->dv_buf.kvirt) { + /* allocate the ringbuffer */ + retval = dma_region_alloc(&video->dv_buf, new_buf_size, video->ohci->dev, PCI_DMA_TODEVICE); + if (retval) + goto err; + + video->dv_buf_size = new_buf_size; + + debug_printk("dv1394: Allocated %d frame buffers, total %u pages (%u DMA pages), %lu bytes\n", + video->n_frames, video->dv_buf.n_pages, + video->dv_buf.n_dma_pages, video->dv_buf_size); + } + + /* set up the frame->data pointers */ + for (i = 0; i < video->n_frames; i++) + video->frames[i]->data = (unsigned long) video->dv_buf.kvirt + i * video->frame_size; + + if (!video->packet_buf.kvirt) { + /* allocate packet buffer */ + video->packet_buf_size = sizeof(struct packet) * video->n_frames * MAX_PACKETS; + if (video->packet_buf_size % PAGE_SIZE) + video->packet_buf_size += PAGE_SIZE - (video->packet_buf_size % PAGE_SIZE); + + retval = dma_region_alloc(&video->packet_buf, video->packet_buf_size, + video->ohci->dev, PCI_DMA_FROMDEVICE); + if (retval) + goto err; + + debug_printk("dv1394: Allocated %d packets in buffer, total %u pages (%u DMA pages), %lu bytes\n", + video->n_frames*MAX_PACKETS, video->packet_buf.n_pages, + video->packet_buf.n_dma_pages, video->packet_buf_size); + } + + /* set up register offsets for IT context */ + /* IT DMA context registers are spaced 16 bytes apart */ + video->ohci_IsoXmitContextControlSet = OHCI1394_IsoXmitContextControlSet+16*video->ohci_it_ctx; + video->ohci_IsoXmitContextControlClear = OHCI1394_IsoXmitContextControlClear+16*video->ohci_it_ctx; + video->ohci_IsoXmitCommandPtr = OHCI1394_IsoXmitCommandPtr+16*video->ohci_it_ctx; + + /* enable interrupts for IT context */ + reg_write(video->ohci, OHCI1394_IsoXmitIntMaskSet, (1 << video->ohci_it_ctx)); + debug_printk("dv1394: interrupts enabled for IT context %d\n", video->ohci_it_ctx); + + /* set up register offsets for IR context */ + /* IR DMA context registers are spaced 32 bytes apart */ + video->ohci_IsoRcvContextControlSet = OHCI1394_IsoRcvContextControlSet+32*video->ohci_ir_ctx; + video->ohci_IsoRcvContextControlClear = OHCI1394_IsoRcvContextControlClear+32*video->ohci_ir_ctx; + video->ohci_IsoRcvCommandPtr = OHCI1394_IsoRcvCommandPtr+32*video->ohci_ir_ctx; + video->ohci_IsoRcvContextMatch = OHCI1394_IsoRcvContextMatch+32*video->ohci_ir_ctx; + + /* enable interrupts for IR context */ + reg_write(video->ohci, OHCI1394_IsoRecvIntMaskSet, (1 << video->ohci_ir_ctx) ); + debug_printk("dv1394: interrupts enabled for IR context %d\n", video->ohci_ir_ctx); + + return 0; + +err: + do_dv1394_shutdown(video, 1); + return retval; +} + +/* if the user doesn't bother to call ioctl(INIT) before starting + mmap() or read()/write(), just give him some default values */ + +static int do_dv1394_init_default(struct video_card *video) +{ + struct dv1394_init init; + + init.api_version = DV1394_API_VERSION; + init.n_frames = DV1394_MAX_FRAMES / 4; + /* the following are now set via proc_fs or devfs */ + init.channel = video->channel; + init.format = video->pal_or_ntsc; + init.cip_n = video->cip_n; + init.cip_d = video->cip_d; + init.syt_offset = video->syt_offset; + + return do_dv1394_init(video, &init); +} + +/* do NOT call from interrupt context */ +static void stop_dma(struct video_card *video) +{ + unsigned long flags; + int i; + + /* no interrupts */ + spin_lock_irqsave(&video->spinlock, flags); + + video->dma_running = 0; + + if ( (video->ohci_it_ctx == -1) && (video->ohci_ir_ctx == -1) ) + goto out; + + /* stop DMA if in progress */ + if ( (video->active_frame != -1) || + (reg_read(video->ohci, video->ohci_IsoXmitContextControlClear) & (1 << 10)) || + (reg_read(video->ohci, video->ohci_IsoRcvContextControlClear) & (1 << 10)) ) { + + /* clear the .run bits */ + reg_write(video->ohci, video->ohci_IsoXmitContextControlClear, (1 << 15)); + reg_write(video->ohci, video->ohci_IsoRcvContextControlClear, (1 << 15)); + flush_pci_write(video->ohci); + + video->active_frame = -1; + video->first_run = 1; + + /* wait until DMA really stops */ + i = 0; + while (i < 1000) { + + /* wait 0.1 millisecond */ + udelay(100); + + if ( (reg_read(video->ohci, video->ohci_IsoXmitContextControlClear) & (1 << 10)) || + (reg_read(video->ohci, video->ohci_IsoRcvContextControlClear) & (1 << 10)) ) { + /* still active */ + debug_printk("dv1394: stop_dma: DMA not stopped yet\n" ); + mb(); + } else { + debug_printk("dv1394: stop_dma: DMA stopped safely after %d ms\n", i/10); + break; + } + + i++; + } + + if (i == 1000) { + printk(KERN_ERR "dv1394: stop_dma: DMA still going after %d ms!\n", i/10); + } + } + else + debug_printk("dv1394: stop_dma: already stopped.\n"); + +out: + spin_unlock_irqrestore(&video->spinlock, flags); +} + + + +static void do_dv1394_shutdown(struct video_card *video, int free_dv_buf) +{ + int i; + + debug_printk("dv1394: shutdown...\n"); + + /* stop DMA if in progress */ + stop_dma(video); + + /* release the DMA contexts */ + if (video->ohci_it_ctx != -1) { + video->ohci_IsoXmitContextControlSet = 0; + video->ohci_IsoXmitContextControlClear = 0; + video->ohci_IsoXmitCommandPtr = 0; + + /* disable interrupts for IT context */ + reg_write(video->ohci, OHCI1394_IsoXmitIntMaskClear, (1 << video->ohci_it_ctx)); + + /* remove tasklet */ + ohci1394_unregister_iso_tasklet(video->ohci, &video->it_tasklet); + debug_printk("dv1394: IT context %d released\n", video->ohci_it_ctx); + video->ohci_it_ctx = -1; + } + + if (video->ohci_ir_ctx != -1) { + video->ohci_IsoRcvContextControlSet = 0; + video->ohci_IsoRcvContextControlClear = 0; + video->ohci_IsoRcvCommandPtr = 0; + video->ohci_IsoRcvContextMatch = 0; + + /* disable interrupts for IR context */ + reg_write(video->ohci, OHCI1394_IsoRecvIntMaskClear, (1 << video->ohci_ir_ctx)); + + /* remove tasklet */ + ohci1394_unregister_iso_tasklet(video->ohci, &video->ir_tasklet); + debug_printk("dv1394: IR context %d released\n", video->ohci_ir_ctx); + video->ohci_ir_ctx = -1; + } + + /* release the ISO channel */ + if (video->channel != -1) { + u64 chan_mask; + unsigned long flags; + + chan_mask = (u64)1 << video->channel; + + spin_lock_irqsave(&video->ohci->IR_channel_lock, flags); + video->ohci->ISO_channel_usage &= ~(chan_mask); + spin_unlock_irqrestore(&video->ohci->IR_channel_lock, flags); + + video->channel = -1; + } + + /* free the frame structs */ + for (i = 0; i < DV1394_MAX_FRAMES; i++) { + if (video->frames[i]) + frame_delete(video->frames[i]); + video->frames[i] = NULL; + } + + video->n_frames = 0; + + /* we can't free the DMA buffer unless it is guaranteed that + no more user-space mappings exist */ + + if (free_dv_buf) { + dma_region_free(&video->dv_buf); + video->dv_buf_size = 0; + } + + /* free packet buffer */ + dma_region_free(&video->packet_buf); + video->packet_buf_size = 0; + + debug_printk("dv1394: shutdown OK\n"); +} + +/* + ********************************** + *** MMAP() THEORY OF OPERATION *** + ********************************** + + The ringbuffer cannot be re-allocated or freed while + a user program maintains a mapping of it. (note that a mapping + can persist even after the device fd is closed!) + + So, only let the user process allocate the DMA buffer once. + To resize or deallocate it, you must close the device file + and open it again. + + Previously Dan M. hacked out a scheme that allowed the DMA + buffer to change by forcefully unmapping it from the user's + address space. It was prone to error because it's very hard to + track all the places the buffer could have been mapped (we + would have had to walk the vma list of every process in the + system to be sure we found all the mappings!). Instead, we + force the user to choose one buffer size and stick with + it. This small sacrifice is worth the huge reduction in + error-prone code in dv1394. +*/ + +int dv1394_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct video_card *video = file_to_video_card(file); + int retval = -EINVAL; + + /* serialize mmap */ + down(&video->sem); + + if ( ! video_card_initialized(video) ) { + retval = do_dv1394_init_default(video); + if (retval) + goto out; + } + + retval = dma_region_mmap(&video->dv_buf, file, vma); +out: + up(&video->sem); + return retval; +} + +/*** DEVICE FILE INTERFACE *************************************************/ + +/* no need to serialize, multiple threads OK */ +static unsigned int dv1394_poll(struct file *file, struct poll_table_struct *wait) +{ + struct video_card *video = file_to_video_card(file); + unsigned int mask = 0; + unsigned long flags; + + poll_wait(file, &video->waitq, wait); + + spin_lock_irqsave(&video->spinlock, flags); + if ( video->n_frames == 0 ) { + + } else if ( video->active_frame == -1 ) { + /* nothing going on */ + mask |= POLLOUT; + } else { + /* any clear/ready buffers? */ + if (video->n_clear_frames >0) + mask |= POLLOUT | POLLIN; + } + spin_unlock_irqrestore(&video->spinlock, flags); + + return mask; +} + +static int dv1394_fasync(int fd, struct file *file, int on) +{ + /* I just copied this code verbatim from Alan Cox's mouse driver example + (linux/Documentation/DocBook/) */ + + struct video_card *video = file_to_video_card(file); + + int retval = fasync_helper(fd, file, on, &video->fasync); + + if (retval < 0) + return retval; + return 0; +} + +static ssize_t dv1394_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) +{ + struct video_card *video = file_to_video_card(file); + DECLARE_WAITQUEUE(wait, current); + ssize_t ret; + size_t cnt; + unsigned long flags; + int target_frame; + + /* serialize this to prevent multi-threaded mayhem */ + if (file->f_flags & O_NONBLOCK) { + if (down_trylock(&video->sem)) + return -EAGAIN; + } else { + if (down_interruptible(&video->sem)) + return -ERESTARTSYS; + } + + if ( !video_card_initialized(video) ) { + ret = do_dv1394_init_default(video); + if (ret) { + up(&video->sem); + return ret; + } + } + + ret = 0; + add_wait_queue(&video->waitq, &wait); + + while (count > 0) { + + /* must set TASK_INTERRUPTIBLE *before* checking for free + buffers; otherwise we could miss a wakeup if the interrupt + fires between the check and the schedule() */ + + set_current_state(TASK_INTERRUPTIBLE); + + spin_lock_irqsave(&video->spinlock, flags); + + target_frame = video->first_clear_frame; + + spin_unlock_irqrestore(&video->spinlock, flags); + + if (video->frames[target_frame]->state == FRAME_CLEAR) { + + /* how much room is left in the target frame buffer */ + cnt = video->frame_size - (video->write_off - target_frame * video->frame_size); + + } else { + /* buffer is already used */ + cnt = 0; + } + + if (cnt > count) + cnt = count; + + if (cnt <= 0) { + /* no room left, gotta wait */ + if (file->f_flags & O_NONBLOCK) { + if (!ret) + ret = -EAGAIN; + break; + } + if (signal_pending(current)) { + if (!ret) + ret = -ERESTARTSYS; + break; + } + + schedule(); + + continue; /* start over from 'while(count > 0)...' */ + } + + if (copy_from_user(video->dv_buf.kvirt + video->write_off, buffer, cnt)) { + if (!ret) + ret = -EFAULT; + break; + } + + video->write_off = (video->write_off + cnt) % (video->n_frames * video->frame_size); + + count -= cnt; + buffer += cnt; + ret += cnt; + + if (video->write_off == video->frame_size * ((target_frame + 1) % video->n_frames)) + frame_prepare(video, target_frame); + } + + remove_wait_queue(&video->waitq, &wait); + set_current_state(TASK_RUNNING); + up(&video->sem); + return ret; +} + + +static ssize_t dv1394_read(struct file *file, char *buffer, size_t count, loff_t *ppos) +{ + struct video_card *video = file_to_video_card(file); + DECLARE_WAITQUEUE(wait, current); + ssize_t ret; + size_t cnt; + unsigned long flags; + int target_frame; + + /* serialize this to prevent multi-threaded mayhem */ + if (file->f_flags & O_NONBLOCK) { + if (down_trylock(&video->sem)) + return -EAGAIN; + } else { + if (down_interruptible(&video->sem)) + return -ERESTARTSYS; + } + + if ( !video_card_initialized(video) ) { + ret = do_dv1394_init_default(video); + if (ret) { + up(&video->sem); + return ret; + } + video->continuity_counter = -1; + + receive_packets(video); + + start_dma_receive(video); + } + + ret = 0; + add_wait_queue(&video->waitq, &wait); + + while (count > 0) { + + /* must set TASK_INTERRUPTIBLE *before* checking for free + buffers; otherwise we could miss a wakeup if the interrupt + fires between the check and the schedule() */ + + set_current_state(TASK_INTERRUPTIBLE); + + spin_lock_irqsave(&video->spinlock, flags); + + target_frame = video->first_clear_frame; + + spin_unlock_irqrestore(&video->spinlock, flags); + + if (target_frame >= 0 && + video->n_clear_frames > 0 && + video->frames[target_frame]->state == FRAME_CLEAR) { + + /* how much room is left in the target frame buffer */ + cnt = video->frame_size - (video->write_off - target_frame * video->frame_size); + + } else { + /* buffer is already used */ + cnt = 0; + } + + if (cnt > count) + cnt = count; + + if (cnt <= 0) { + /* no room left, gotta wait */ + if (file->f_flags & O_NONBLOCK) { + if (!ret) + ret = -EAGAIN; + break; + } + if (signal_pending(current)) { + if (!ret) + ret = -ERESTARTSYS; + break; + } + + schedule(); + + continue; /* start over from 'while(count > 0)...' */ + } + + if (copy_to_user(buffer, video->dv_buf.kvirt + video->write_off, cnt)) { + if (!ret) + ret = -EFAULT; + break; + } + + video->write_off = (video->write_off + cnt) % (video->n_frames * video->frame_size); + + count -= cnt; + buffer += cnt; + ret += cnt; + + if (video->write_off == video->frame_size * ((target_frame + 1) % video->n_frames)) { + spin_lock_irqsave(&video->spinlock, flags); + video->n_clear_frames--; + video->first_clear_frame = (video->first_clear_frame + 1) % video->n_frames; + spin_unlock_irqrestore(&video->spinlock, flags); + } + } + + remove_wait_queue(&video->waitq, &wait); + set_current_state(TASK_RUNNING); + up(&video->sem); + return ret; +} + + +/*** DEVICE IOCTL INTERFACE ************************************************/ + +/* I *think* the VFS serializes ioctl() for us, so we don't have to worry + about situations like having two threads in here at once... */ + +static int dv1394_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct video_card *video = file_to_video_card(file); + unsigned long flags; + int ret = -EINVAL; + + DECLARE_WAITQUEUE(wait, current); + + /* serialize this to prevent multi-threaded mayhem */ + if (file->f_flags & O_NONBLOCK) { + if (down_trylock(&video->sem)) + return -EAGAIN; + } else { + if (down_interruptible(&video->sem)) + return -ERESTARTSYS; + } + + switch(cmd) + { + case DV1394_SUBMIT_FRAMES: + case DV1394_IOC_SUBMIT_FRAMES: { + unsigned int n_submit; + + if ( !video_card_initialized(video) ) { + ret = do_dv1394_init_default(video); + if (ret) + goto out; + } + + n_submit = (unsigned int) arg; + + if (n_submit > video->n_frames) { + ret = -EINVAL; + goto out; + } + + while (n_submit > 0) { + + add_wait_queue(&video->waitq, &wait); + set_current_state(TASK_INTERRUPTIBLE); + + spin_lock_irqsave(&video->spinlock, flags); + + /* wait until video->first_clear_frame is really CLEAR */ + while (video->frames[video->first_clear_frame]->state != FRAME_CLEAR) { + + spin_unlock_irqrestore(&video->spinlock, flags); + + if (signal_pending(current)) { + remove_wait_queue(&video->waitq, &wait); + set_current_state(TASK_RUNNING); + ret = -EINTR; + goto out; + } + + schedule(); + set_current_state(TASK_INTERRUPTIBLE); + + spin_lock_irqsave(&video->spinlock, flags); + } + spin_unlock_irqrestore(&video->spinlock, flags); + + remove_wait_queue(&video->waitq, &wait); + set_current_state(TASK_RUNNING); + + frame_prepare(video, video->first_clear_frame); + + n_submit--; + } + + ret = 0; + break; + } + case DV1394_WAIT_FRAMES: + case DV1394_IOC_WAIT_FRAMES: { + unsigned int n_wait; + + if ( !video_card_initialized(video) ) { + ret = -EINVAL; + goto out; + } + + n_wait = (unsigned int) arg; + + /* since we re-run the last frame on underflow, we will + never actually have n_frames clear frames; at most only + n_frames - 1 */ + + if (n_wait > (video->n_frames-1) ) { + ret = -EINVAL; + goto out; + } + + add_wait_queue(&video->waitq, &wait); + set_current_state(TASK_INTERRUPTIBLE); + + spin_lock_irqsave(&video->spinlock, flags); + + while (video->n_clear_frames < n_wait) { + + spin_unlock_irqrestore(&video->spinlock, flags); + + if (signal_pending(current)) { + remove_wait_queue(&video->waitq, &wait); + set_current_state(TASK_RUNNING); + ret = -EINTR; + goto out; + } + + schedule(); + set_current_state(TASK_INTERRUPTIBLE); + + spin_lock_irqsave(&video->spinlock, flags); + } + + spin_unlock_irqrestore(&video->spinlock, flags); + + remove_wait_queue(&video->waitq, &wait); + set_current_state(TASK_RUNNING); + ret = 0; + break; + } + case DV1394_RECEIVE_FRAMES: + case DV1394_IOC_RECEIVE_FRAMES: { + unsigned int n_recv; + + if ( !video_card_initialized(video) ) { + ret = -EINVAL; + goto out; + } + + n_recv = (unsigned int) arg; + + /* at least one frame must be active */ + if (n_recv > (video->n_frames-1) ) { + ret = -EINVAL; + goto out; + } + + spin_lock_irqsave(&video->spinlock, flags); + + /* release the clear frames */ + video->n_clear_frames -= n_recv; + + /* advance the clear frame cursor */ + video->first_clear_frame = (video->first_clear_frame + n_recv) % video->n_frames; + + /* reset dropped_frames */ + video->dropped_frames = 0; + + spin_unlock_irqrestore(&video->spinlock, flags); + + ret = 0; + break; + } + case DV1394_START_RECEIVE: + case DV1394_IOC_START_RECEIVE: { + if ( !video_card_initialized(video) ) { + ret = do_dv1394_init_default(video); + if (ret) + goto out; + } + + video->continuity_counter = -1; + + receive_packets(video); + + start_dma_receive(video); + + ret = 0; + break; + } + case DV1394_INIT: + case DV1394_IOC_INIT: { + struct dv1394_init init; + if (arg == (unsigned long) NULL) { + ret = do_dv1394_init_default(video); + } else { + if (copy_from_user(&init, (void*)arg, sizeof(init))) { + ret = -EFAULT; + goto out; + } + ret = do_dv1394_init(video, &init); + } + break; + } + case DV1394_SHUTDOWN: + case DV1394_IOC_SHUTDOWN: + do_dv1394_shutdown(video, 0); + ret = 0; + break; + + case DV1394_GET_STATUS: + case DV1394_IOC_GET_STATUS: { + struct dv1394_status status; + + if ( !video_card_initialized(video) ) { + ret = -EINVAL; + goto out; + } + + status.init.api_version = DV1394_API_VERSION; + status.init.channel = video->channel; + status.init.n_frames = video->n_frames; + status.init.format = video->pal_or_ntsc; + status.init.cip_n = video->cip_n; + status.init.cip_d = video->cip_d; + status.init.syt_offset = video->syt_offset; + + status.first_clear_frame = video->first_clear_frame; + + /* the rest of the fields need to be locked against the interrupt */ + spin_lock_irqsave(&video->spinlock, flags); + + status.active_frame = video->active_frame; + status.n_clear_frames = video->n_clear_frames; + + status.dropped_frames = video->dropped_frames; + + /* reset dropped_frames */ + video->dropped_frames = 0; + + spin_unlock_irqrestore(&video->spinlock, flags); + + if (copy_to_user((void*)arg, &status, sizeof(status))) { + ret = -EFAULT; + goto out; + } + + ret = 0; + break; + } + + default: + break; + } + + out: + up(&video->sem); + return ret; +} + + + +/*** DEVICE FILE INTERFACE CONTINUED ***************************************/ + +static int dv1394_open(struct inode *inode, struct file *file) +{ + struct video_card *video = NULL; + + /* if the device was opened through devfs, then file->private_data + has already been set to video by devfs */ + if (file->private_data) { + video = (struct video_card*) file->private_data; + + } else { + /* look up the card by ID */ + + struct list_head *lh; + unsigned long flags; + + spin_lock_irqsave(&dv1394_cards_lock, flags); + if (!list_empty(&dv1394_cards)) { + struct video_card *p; + list_for_each(lh, &dv1394_cards) { + p = list_entry(lh, struct video_card, list); + if ((p->id) == ieee1394_file_to_instance(file)) { + video = p; + break; + } + } + } + spin_unlock_irqrestore(&dv1394_cards_lock, flags); + + if (!video) { + debug_printk("dv1394: OHCI card %d not found", ieee1394_file_to_instance(file)); + return -ENODEV; + } + + file->private_data = (void*) video; + } + +#ifndef DV1394_ALLOW_MORE_THAN_ONE_OPEN + + if ( test_and_set_bit(0, &video->open) ) { + /* video is already open by someone else */ + return -EBUSY; + } + +#endif + + return 0; +} + + +static int dv1394_release(struct inode *inode, struct file *file) +{ + struct video_card *video = file_to_video_card(file); + + /* OK to free the DMA buffer, no more mappings can exist */ + do_dv1394_shutdown(video, 1); + + /* clean up async I/O users */ + dv1394_fasync(-1, file, 0); + + /* give someone else a turn */ + clear_bit(0, &video->open); + + return 0; +} + + +/*** PROC_FS INTERFACE ******************************************************/ +#ifdef CONFIG_PROC_FS +static LIST_HEAD(dv1394_procfs); +struct dv1394_procfs_entry { + struct list_head list; + struct proc_dir_entry *procfs; + char name[32]; + struct dv1394_procfs_entry *parent; +}; +static spinlock_t dv1394_procfs_lock = SPIN_LOCK_UNLOCKED; + +static int dv1394_procfs_read( char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct video_card *video = (struct video_card*) data; + + snprintf( page, count, + "\ +format=%s\n\ +channel=%d\n\ +cip_n=%lu\n\ +cip_d=%lu\n\ +syt_offset=%u\n", + (video->pal_or_ntsc == DV1394_NTSC ? "NTSC" : "PAL"), + video->channel, + video->cip_n, video->cip_d, video->syt_offset ); + return strlen(page); +} + +/* lifted from the stallion.c driver */ +#undef TOLOWER +#define TOLOWER(x) ((((x) >= 'A') && ((x) <= 'Z')) ? ((x) + 0x20) : (x)) +static unsigned long atol(char *str) +{ + unsigned long val; + int base, c; + char *sp; + + val = 0; + sp = str; + if ((*sp == '0') && (*(sp+1) == 'x')) { + base = 16; + sp += 2; + } else if (*sp == '0') { + base = 8; + sp++; + } else { + base = 10; + } + + for (; (*sp != 0); sp++) { + c = (*sp > '9') ? (TOLOWER(*sp) - 'a' + 10) : (*sp - '0'); + if ((c < 0) || (c >= base)) { + printk(KERN_ERR "dv1394: atol() invalid argument %s\n", str); + val = 0; + break; + } + val = (val * base) + c; + } + return(val); +} + +static int dv1394_procfs_write( struct file *file, + const char *buffer, unsigned long count, void *data) +{ + int len = 0; + char new_value[65]; + char *pos; + struct video_card *video = (struct video_card*) data; + + if (count > 64) + len = 64; + else + len = count; + + if (copy_from_user( new_value, buffer, len)) + return -EFAULT; + + new_value[len] = 0; + pos = strchr(new_value, '='); + if (pos != NULL) { + int val_len = len - (pos-new_value) - 1; + char buf[65]; + memset(buf, 0, 65); + strncpy(buf, pos+1, val_len); + if (buf[val_len-1] == '\n') buf[val_len-1] = 0; + + if (strnicmp( new_value, "format", (pos-new_value)) == 0) { + if (strnicmp( buf, "NTSC", val_len) == 0) + video->pal_or_ntsc = DV1394_NTSC; + else if (strnicmp( buf, "PAL", val_len) == 0) + video->pal_or_ntsc = DV1394_PAL; + + } else if (strnicmp( new_value, "cip_n", (pos-new_value)) == 0) { + video->cip_n = atol(buf); + } else if (strnicmp( new_value, "cip_d", (pos-new_value)) == 0) { + video->cip_d = atol(buf); + } else if (strnicmp( new_value, "syt_offset", (pos-new_value)) == 0) { + video->syt_offset = atol(buf); + } else if (strnicmp( new_value, "channel", (pos-new_value)) == 0) { + video->channel = atol(buf); + } + } + + return len; +} + +struct dv1394_procfs_entry * +dv1394_procfs_find( char *name) +{ + struct list_head *lh; + struct dv1394_procfs_entry *p; + + spin_lock( &dv1394_procfs_lock); + if (!list_empty(&dv1394_procfs)) { + list_for_each(lh, &dv1394_procfs) { + p = list_entry(lh, struct dv1394_procfs_entry, list); + if (!strncmp(p->name, name, sizeof(p->name))) { + spin_unlock( &dv1394_procfs_lock); + return p; + } + } + } + spin_unlock( &dv1394_procfs_lock); + return NULL; +} + +static int dv1394_procfs_add_entry(struct video_card *video) +{ + char buf[32]; + struct dv1394_procfs_entry *p; + struct dv1394_procfs_entry *parent; + + p = kmalloc(sizeof(struct dv1394_procfs_entry), GFP_KERNEL); + if (!p) { + printk(KERN_ERR "dv1394: cannot allocate dv1394_procfs_entry\n"); + goto err; + } + memset(p, 0, sizeof(struct dv1394_procfs_entry)); + + snprintf(buf, sizeof(buf), "dv/host%d/%s", (video->id>>2), + (video->pal_or_ntsc == DV1394_NTSC ? "NTSC" : "PAL")); + + parent = dv1394_procfs_find(buf); + if (parent == NULL) { + printk(KERN_ERR "dv1394: unable to locate parent procfs of %s\n", buf); + goto err_free; + } + + p->procfs = create_proc_entry( + (video->mode == MODE_RECEIVE ? "in" : "out"), + 0666, parent->procfs); + + if (p->procfs == NULL) { + printk(KERN_ERR "dv1394: unable to create /proc/bus/ieee1394/%s/%s\n", + parent->name, + (video->mode == MODE_RECEIVE ? "in" : "out")); + goto err_free; + } + + p->procfs->owner = THIS_MODULE; + p->procfs->data = video; + p->procfs->read_proc = dv1394_procfs_read; + p->procfs->write_proc = dv1394_procfs_write; + + spin_lock( &dv1394_procfs_lock); + INIT_LIST_HEAD(&p->list); + list_add_tail(&p->list, &dv1394_procfs); + spin_unlock( &dv1394_procfs_lock); + + return 0; + + err_free: + kfree(p); + err: + return -ENOMEM; +} + +static int +dv1394_procfs_add_dir( char *name, + struct dv1394_procfs_entry *parent, + struct dv1394_procfs_entry **out) +{ + struct dv1394_procfs_entry *p; + + p = kmalloc(sizeof(struct dv1394_procfs_entry), GFP_KERNEL); + if (!p) { + printk(KERN_ERR "dv1394: cannot allocate dv1394_procfs_entry\n"); + goto err; + } + memset(p, 0, sizeof(struct dv1394_procfs_entry)); + + if (parent == NULL) { + snprintf(p->name, sizeof(p->name), "%s", name); + p->procfs = proc_mkdir( name, ieee1394_procfs_entry); + } else { + snprintf(p->name, sizeof(p->name), "%s/%s", parent->name, name); + p->procfs = proc_mkdir( name, parent->procfs); + } + if (p->procfs == NULL) { + printk(KERN_ERR "dv1394: unable to create /proc/bus/ieee1394/%s\n", p->name); + goto err_free; + } + + p->procfs->owner = THIS_MODULE; + p->parent = parent; + if (out != NULL) *out = p; + + spin_lock( &dv1394_procfs_lock); + INIT_LIST_HEAD(&p->list); + list_add_tail(&p->list, &dv1394_procfs); + spin_unlock( &dv1394_procfs_lock); + + return 0; + + err_free: + kfree(p); + err: + return -ENOMEM; +} + +void dv1394_procfs_del( char *name) +{ + struct dv1394_procfs_entry *p = dv1394_procfs_find(name); + if (p != NULL) { + if (p->parent == NULL) + remove_proc_entry(p->name, ieee1394_procfs_entry); + else + remove_proc_entry(p->name, p->parent->procfs); + + spin_lock( &dv1394_procfs_lock); + list_del(&p->list); + spin_unlock( &dv1394_procfs_lock); + kfree(p); + } +} +#endif /* CONFIG_PROC_FS */ + +/*** DEVICE DRIVER HANDLERS ************************************************/ + +static void it_tasklet_func(unsigned long data) +{ + int wake = 0; + struct video_card *video = (struct video_card*) data; + + spin_lock(&video->spinlock); + + if (!video->dma_running) + goto out; + + irq_printk("ContextControl = %08x, CommandPtr = %08x\n", + reg_read(video->ohci, video->ohci_IsoXmitContextControlSet), + reg_read(video->ohci, video->ohci_IsoXmitCommandPtr) + ); + + + if ( (video->ohci_it_ctx != -1) && + (reg_read(video->ohci, video->ohci_IsoXmitContextControlSet) & (1 << 10)) ) { + + struct frame *f; + unsigned int frame, i; + + + if (video->active_frame == -1) + frame = 0; + else + frame = video->active_frame; + + /* check all the DMA-able frames */ + for (i = 0; i < video->n_frames; i++, frame = (frame+1) % video->n_frames) { + + irq_printk("IRQ checking frame %d...", frame); + f = video->frames[frame]; + if (f->state != FRAME_READY) { + irq_printk("clear, skipping\n"); + /* we don't own this frame */ + continue; + } + + irq_printk("DMA\n"); + + /* check the frame begin semaphore to see if we can free the previous frame */ + if ( *(f->frame_begin_timestamp) ) { + int prev_frame; + struct frame *prev_f; + + + + /* don't reset, need this later *(f->frame_begin_timestamp) = 0; */ + irq_printk(" BEGIN\n"); + + prev_frame = frame - 1; + if (prev_frame == -1) + prev_frame += video->n_frames; + prev_f = video->frames[prev_frame]; + + /* make sure we can actually garbage collect + this frame */ + if ( (prev_f->state == FRAME_READY) && + prev_f->done && (!f->done) ) + { + frame_reset(prev_f); + video->n_clear_frames++; + wake = 1; + video->active_frame = frame; + + irq_printk(" BEGIN - freeing previous frame %d, new active frame is %d\n", prev_frame, frame); + } else { + irq_printk(" BEGIN - can't free yet\n"); + } + + f->done = 1; + } + + + /* see if we need to set the timestamp for the next frame */ + if ( *(f->mid_frame_timestamp) ) { + struct frame *next_frame; + u32 begin_ts, ts_cyc, ts_off; + + *(f->mid_frame_timestamp) = 0; + + begin_ts = le32_to_cpu(*(f->frame_begin_timestamp)); + + irq_printk(" MIDDLE - first packet was sent at cycle %4u (%2u), assigned timestamp was (%2u) %4u\n", + begin_ts & 0x1FFF, begin_ts & 0xF, + f->assigned_timestamp >> 12, f->assigned_timestamp & 0xFFF); + + /* prepare next frame and assign timestamp */ + next_frame = video->frames[ (frame+1) % video->n_frames ]; + + if (next_frame->state == FRAME_READY) { + irq_printk(" MIDDLE - next frame is ready, good\n"); + } else { + debug_printk("dv1394: Underflow! At least one frame has been dropped.\n"); + next_frame = f; + } + + /* set the timestamp to the timestamp of the last frame sent, + plus the length of the last frame sent, plus the syt latency */ + ts_cyc = begin_ts & 0xF; + /* advance one frame, plus syt latency (typically 2-3) */ + ts_cyc += f->n_packets + video->syt_offset ; + + ts_off = 0; + + ts_cyc += ts_off/3072; + ts_off %= 3072; + + next_frame->assigned_timestamp = ((ts_cyc&0xF) << 12) + ts_off; + if (next_frame->cip_syt1) { + next_frame->cip_syt1->b[6] = next_frame->assigned_timestamp >> 8; + next_frame->cip_syt1->b[7] = next_frame->assigned_timestamp & 0xFF; + } + if (next_frame->cip_syt2) { + next_frame->cip_syt2->b[6] = next_frame->assigned_timestamp >> 8; + next_frame->cip_syt2->b[7] = next_frame->assigned_timestamp & 0xFF; + } + + } + + /* see if the frame looped */ + if ( *(f->frame_end_timestamp) ) { + + *(f->frame_end_timestamp) = 0; + + debug_printk(" END - the frame looped at least once\n"); + + video->dropped_frames++; + } + + + + } /* for (each frame) */ + } + + if (wake) { + kill_fasync(&video->fasync, SIGIO, POLL_OUT); + + /* wake readers/writers/ioctl'ers */ + wake_up_interruptible(&video->waitq); + } + +out: + spin_unlock(&video->spinlock); +} + +static void ir_tasklet_func(unsigned long data) +{ + int wake = 0; + struct video_card *video = (struct video_card*) data; + + spin_lock(&video->spinlock); + + if (!video->dma_running) + goto out; + + if ( (video->ohci_ir_ctx != -1) && + (reg_read(video->ohci, video->ohci_IsoRcvContextControlSet) & (1 << 10)) ) + { + + int sof=0; /* start-of-frame flag */ + struct frame *f; + u16 packet_length, packet_time; + int i, dbc=0; + struct DMA_descriptor_block *block = NULL; + u16 xferstatus; + + int next_i, prev_i; + struct DMA_descriptor_block *next = NULL; + dma_addr_t next_dma = 0; + struct DMA_descriptor_block *prev = NULL; + + /* loop over all descriptors in all frames */ + for (i = 0; i < video->n_frames*MAX_PACKETS; i++) { + struct packet *p = dma_region_i(&video->packet_buf, struct packet, video->current_packet); + + /* make sure we are seeing the latest changes to p */ + dma_region_sync(&video->packet_buf, + (unsigned long) p - (unsigned long) video->packet_buf.kvirt, + sizeof(struct packet)); + + packet_length = le16_to_cpu(p->data_length); + packet_time = le16_to_cpu(p->timestamp); + + irq_printk("received packet %02d, timestamp=%04x, length=%04x, sof=%02x%02x\n", video->current_packet, + packet_time, packet_length, + p->data[0], p->data[1]); + + /* get the descriptor based on packet_buffer cursor */ + f = video->frames[video->current_packet / MAX_PACKETS]; + block = &(f->descriptor_pool[video->current_packet % MAX_PACKETS]); + xferstatus = le32_to_cpu(block->u.in.il.q[3]) >> 16; + xferstatus &= 0x1F; + irq_printk("ir_tasklet_func: xferStatus/resCount [%d] = 0x%08x\n", i, le32_to_cpu(block->u.in.il.q[3]) ); + + /* get the current frame */ + f = video->frames[video->active_frame]; + + /* exclude empty packet */ + if (packet_length > 8 && xferstatus == 0x11) { + /* check for start of frame */ + /* DRD> Changed to check section type ([0]>>5==0) + and dif sequence ([1]>>4==0) */ + sof = ( (p->data[0] >> 5) == 0 && (p->data[1] >> 4) == 0); + + dbc = (int) (p->cip_h1 >> 24); + if ( video->continuity_counter != -1 && dbc > ((video->continuity_counter + 1) % 256) ) + { + printk(KERN_WARNING "dv1394: discontinuity detected, dropping all frames\n" ); + video->dropped_frames += video->n_clear_frames + 1; + video->first_frame = 0; + video->n_clear_frames = 0; + video->first_clear_frame = -1; + } + video->continuity_counter = dbc; + + if (!video->first_frame) { + if (sof) { + video->first_frame = 1; + } + + } else if (sof) { + /* close current frame */ + frame_reset(f); /* f->state = STATE_CLEAR */ + video->n_clear_frames++; + if (video->n_clear_frames > video->n_frames) { + video->dropped_frames++; + printk(KERN_WARNING "dv1394: dropped a frame during reception\n" ); + video->n_clear_frames = video->n_frames-1; + video->first_clear_frame = (video->first_clear_frame + 1) % video->n_frames; + } + if (video->first_clear_frame == -1) + video->first_clear_frame = video->active_frame; + + /* get the next frame */ + video->active_frame = (video->active_frame + 1) % video->n_frames; + f = video->frames[video->active_frame]; + irq_printk(" frame received, active_frame = %d, n_clear_frames = %d, first_clear_frame = %d\n", + video->active_frame, video->n_clear_frames, video->first_clear_frame); + } + if (video->first_frame) { + if (sof) { + /* open next frame */ + f->state = FRAME_READY; + } + + /* copy to buffer */ + if (f->n_packets > (video->frame_size / 480)) { + printk(KERN_ERR "frame buffer overflow during receive\n"); + } + + frame_put_packet(f, p); + + } /* first_frame */ + } + + /* stop, end of ready packets */ + else if (xferstatus == 0) { + break; + } + + /* reset xferStatus & resCount */ + block->u.in.il.q[3] = cpu_to_le32(512); + + /* terminate dma chain at this (next) packet */ + next_i = video->current_packet; + f = video->frames[next_i / MAX_PACKETS]; + next = &(f->descriptor_pool[next_i % MAX_PACKETS]); + next_dma = ((unsigned long) block - (unsigned long) f->descriptor_pool) + f->descriptor_pool_dma; + next->u.in.il.q[0] |= 3 << 20; /* enable interrupt */ + next->u.in.il.q[2] = 0; /* disable branch */ + + /* link previous to next */ + prev_i = (next_i == 0) ? (MAX_PACKETS * video->n_frames - 1) : (next_i - 1); + f = video->frames[prev_i / MAX_PACKETS]; + prev = &(f->descriptor_pool[prev_i % MAX_PACKETS]); + if (prev_i % (MAX_PACKETS/2)) { + prev->u.in.il.q[0] &= ~(3 << 20); /* no interrupt */ + } else { + prev->u.in.il.q[0] |= 3 << 20; /* enable interrupt */ + } + prev->u.in.il.q[2] = cpu_to_le32(next_dma | 1); /* set Z=1 */ + wmb(); + + /* wake up DMA in case it fell asleep */ + reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, (1 << 12)); + + /* advance packet_buffer cursor */ + video->current_packet = (video->current_packet + 1) % (MAX_PACKETS * video->n_frames); + + } /* for all packets */ + + wake = 1; /* why the hell not? */ + + } /* receive interrupt */ + + if (wake) { + kill_fasync(&video->fasync, SIGIO, POLL_IN); + + /* wake readers/writers/ioctl'ers */ + wake_up_interruptible(&video->waitq); + } + +out: + spin_unlock(&video->spinlock); +} + +static struct file_operations dv1394_fops= +{ + .owner = THIS_MODULE, + .poll = dv1394_poll, + .ioctl = dv1394_ioctl, + .mmap = dv1394_mmap, + .open = dv1394_open, + .write = dv1394_write, + .read = dv1394_read, + .release = dv1394_release, + .fasync = dv1394_fasync, +}; + + +/*** DEVFS HELPERS *********************************************************/ + +struct dv1394_devfs_entry * +dv1394_devfs_find( char *name) +{ + struct list_head *lh; + struct dv1394_devfs_entry *p; + + spin_lock( &dv1394_devfs_lock); + if (!list_empty(&dv1394_devfs)) { + list_for_each(lh, &dv1394_devfs) { + p = list_entry(lh, struct dv1394_devfs_entry, list); + if (!strncmp(p->name, name, sizeof(p->name))) { + goto found; + } + } + } + p = NULL; + +found: + spin_unlock( &dv1394_devfs_lock); + return p; +} + +#ifdef CONFIG_DEVFS_FS +static int dv1394_devfs_add_entry(struct video_card *video) +{ + char buf[32]; + struct dv1394_devfs_entry *p; + struct dv1394_devfs_entry *parent; + + p = kmalloc(sizeof(struct dv1394_devfs_entry), GFP_KERNEL); + if (!p) { + printk(KERN_ERR "dv1394: cannot allocate dv1394_devfs_entry\n"); + goto err; + } + memset(p, 0, sizeof(struct dv1394_devfs_entry)); + + snprintf(buf, sizeof(buf), "dv/host%d/%s", (video->id>>2), + (video->pal_or_ntsc == DV1394_NTSC ? "NTSC" : "PAL")); + + parent = dv1394_devfs_find(buf); + if (parent == NULL) { + printk(KERN_ERR "dv1394: unable to locate parent devfs of %s\n", buf); + goto err_free; + } + + video->devfs_handle = devfs_register( + parent->devfs, + (video->mode == MODE_RECEIVE ? "in" : "out"), + DEVFS_FL_NONE, + IEEE1394_MAJOR, + IEEE1394_MINOR_BLOCK_DV1394*16 + video->id, + S_IFCHR | S_IRUGO | S_IWUGO, + &dv1394_fops, + (void*) video); + p->devfs = video->devfs_handle; + + if (p->devfs == NULL) { + printk(KERN_ERR "dv1394: unable to create /dev/ieee1394/%s/%s\n", + parent->name, + (video->mode == MODE_RECEIVE ? "in" : "out")); + goto err_free; + } + + spin_lock( &dv1394_devfs_lock); + INIT_LIST_HEAD(&p->list); + list_add_tail(&p->list, &dv1394_devfs); + spin_unlock( &dv1394_devfs_lock); + + return 0; + + err_free: + kfree(p); + err: + return -ENOMEM; +} + +static int +dv1394_devfs_add_dir( char *name, + struct dv1394_devfs_entry *parent, + struct dv1394_devfs_entry **out) +{ + struct dv1394_devfs_entry *p; + + p = kmalloc(sizeof(struct dv1394_devfs_entry), GFP_KERNEL); + if (!p) { + printk(KERN_ERR "dv1394: cannot allocate dv1394_devfs_entry\n"); + goto err; + } + memset(p, 0, sizeof(struct dv1394_devfs_entry)); + + if (parent == NULL) { + snprintf(p->name, sizeof(p->name), "%s", name); + p->devfs = devfs_mk_dir(ieee1394_devfs_handle, name, NULL); + } else { + snprintf(p->name, sizeof(p->name), "%s/%s", parent->name, name); + p->devfs = devfs_mk_dir(parent->devfs, name, NULL); + } + if (p->devfs == NULL) { + printk(KERN_ERR "dv1394: unable to create /dev/ieee1394/%s\n", p->name); + goto err_free; + } + + p->parent = parent; + if (out != NULL) *out = p; + + spin_lock( &dv1394_devfs_lock); + INIT_LIST_HEAD(&p->list); + list_add_tail(&p->list, &dv1394_devfs); + spin_unlock( &dv1394_devfs_lock); + + return 0; + + err_free: + kfree(p); + err: + return -ENOMEM; +} + +void dv1394_devfs_del( char *name) +{ + struct dv1394_devfs_entry *p = dv1394_devfs_find(name); + if (p != NULL) { + devfs_unregister(p->devfs); + + spin_lock( &dv1394_devfs_lock); + list_del(&p->list); + spin_unlock( &dv1394_devfs_lock); + kfree(p); + } +} +#endif /* CONFIG_DEVFS_FS */ + + +/*** HOTPLUG STUFF **********************************************************/ +/* + * Export information about protocols/devices supported by this driver. + */ +static struct ieee1394_device_id dv1394_id_table[] = { + { + .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION, + .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff, + .version = AVC_SW_VERSION_ENTRY & 0xffffff + }, + { } +}; + +static struct hpsb_protocol_driver dv1394_driver = { + .name = "DV/1394 Driver", + .id_table = dv1394_id_table, +}; + +MODULE_DEVICE_TABLE(ieee1394, dv1394_id_table); + + +/*** IEEE1394 HPSB CALLBACKS ***********************************************/ + +static int dv1394_init(struct ti_ohci *ohci, enum pal_or_ntsc format, enum modes mode) +{ + struct video_card *video; + unsigned long flags; + int i; + + video = kmalloc(sizeof(struct video_card), GFP_KERNEL); + if (!video) { + printk(KERN_ERR "dv1394: cannot allocate video_card\n"); + goto err; + } + + memset(video, 0, sizeof(struct video_card)); + + video->ohci = ohci; + /* lower 2 bits of id indicate which of four "plugs" + per host */ + video->id = ohci->id << 2; + if (format == DV1394_NTSC) + video->id |= mode; + else + video->id |= 2 + mode; + + video->ohci_it_ctx = -1; + video->ohci_ir_ctx = -1; + + video->ohci_IsoXmitContextControlSet = 0; + video->ohci_IsoXmitContextControlClear = 0; + video->ohci_IsoXmitCommandPtr = 0; + + video->ohci_IsoRcvContextControlSet = 0; + video->ohci_IsoRcvContextControlClear = 0; + video->ohci_IsoRcvCommandPtr = 0; + video->ohci_IsoRcvContextMatch = 0; + + video->n_frames = 0; /* flag that video is not initialized */ + video->channel = 63; /* default to broadcast channel */ + video->active_frame = -1; + + /* initialize the following for proc_fs */ + video->pal_or_ntsc = format; + video->cip_n = 0; /* 0 = use builtin default */ + video->cip_d = 0; + video->syt_offset = 0; + video->mode = mode; + +#ifdef CONFIG_PROC_FS + if ( dv1394_procfs_add_entry(video) < 0 ) + goto err_free; +#endif + + for (i = 0; i < DV1394_MAX_FRAMES; i++) + video->frames[i] = NULL; + + dma_region_init(&video->dv_buf); + video->dv_buf_size = 0; + dma_region_init(&video->packet_buf); + video->packet_buf_size = 0; + + clear_bit(0, &video->open); + spin_lock_init(&video->spinlock); + video->dma_running = 0; + init_MUTEX(&video->sem); + init_waitqueue_head(&video->waitq); + video->fasync = NULL; + + spin_lock_irqsave(&dv1394_cards_lock, flags); + INIT_LIST_HEAD(&video->list); + list_add_tail(&video->list, &dv1394_cards); + spin_unlock_irqrestore(&dv1394_cards_lock, flags); + +#ifdef CONFIG_DEVFS_FS + if (dv1394_devfs_add_entry(video) < 0) + goto err_free; +#endif + + debug_printk("dv1394: dv1394_init() OK on ID %d\n", video->id); + + return 0; + + err_free: + kfree(video); + err: + return -1; +} + +static void dv1394_un_init(struct video_card *video) +{ + char buf[32]; + + /* obviously nobody has the driver open at this point */ + do_dv1394_shutdown(video, 1); + snprintf(buf, sizeof(buf), "dv/host%d/%s/%s", (video->id >> 2), + (video->pal_or_ntsc == DV1394_NTSC ? "NTSC" : "PAL"), + (video->mode == MODE_RECEIVE ? "in" : "out") + ); +#ifdef CONFIG_DEVFS_FS + dv1394_devfs_del(buf); +#endif +#ifdef CONFIG_PROC_FS + dv1394_procfs_del(buf); +#endif + list_del(&video->list); + kfree(video); +} + + +static void dv1394_remove_host (struct hpsb_host *host) +{ + struct ti_ohci *ohci; + struct video_card *video = NULL; + unsigned long flags; + struct list_head *lh, *templh; + char buf[32]; + int n; + + /* We only work with the OHCI-1394 driver */ + if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME)) + return; + + ohci = (struct ti_ohci *)host->hostdata; + + + /* find the corresponding video_cards */ + spin_lock_irqsave(&dv1394_cards_lock, flags); + if (!list_empty(&dv1394_cards)) { + list_for_each_safe(lh, templh, &dv1394_cards) { + video = list_entry(lh, struct video_card, list); + if ((video->id >> 2) == ohci->id) + dv1394_un_init(video); + } + } + spin_unlock_irqrestore(&dv1394_cards_lock, flags); + + n = (video->id >> 2); +#ifdef CONFIG_DEVFS_FS + snprintf(buf, sizeof(buf), "dv/host%d/NTSC", n); + dv1394_devfs_del(buf); + snprintf(buf, sizeof(buf), "dv/host%d/PAL", n); + dv1394_devfs_del(buf); + snprintf(buf, sizeof(buf), "dv/host%d", n); + dv1394_devfs_del(buf); +#endif + +#ifdef CONFIG_PROC_FS + snprintf(buf, sizeof(buf), "dv/host%d/NTSC", n); + dv1394_procfs_del(buf); + snprintf(buf, sizeof(buf), "dv/host%d/PAL", n); + dv1394_procfs_del(buf); + snprintf(buf, sizeof(buf), "dv/host%d", n); + dv1394_procfs_del(buf); +#endif +} + +static void dv1394_add_host (struct hpsb_host *host) +{ + struct ti_ohci *ohci; + char buf[16]; + + /* We only work with the OHCI-1394 driver */ + if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME)) + return; + + ohci = (struct ti_ohci *)host->hostdata; + +#ifdef CONFIG_PROC_FS +{ + struct dv1394_procfs_entry *p; + p = dv1394_procfs_find("dv"); + if (p != NULL) { + snprintf(buf, sizeof(buf), "host%d", ohci->id); + dv1394_procfs_add_dir(buf, p, &p); + dv1394_procfs_add_dir("NTSC", p, NULL); + dv1394_procfs_add_dir("PAL", p, NULL); + } +} +#endif + +#ifdef CONFIG_DEVFS_FS +{ + struct dv1394_devfs_entry *devfs_entry = dv1394_devfs_find("dv"); + if (devfs_entry != NULL) { + snprintf(buf, sizeof(buf), "host%d", ohci->id); + dv1394_devfs_add_dir(buf, devfs_entry, &devfs_entry); + dv1394_devfs_add_dir("NTSC", devfs_entry, NULL); + dv1394_devfs_add_dir("PAL", devfs_entry, NULL); + } +} +#endif + + dv1394_init(ohci, DV1394_NTSC, MODE_RECEIVE); + dv1394_init(ohci, DV1394_NTSC, MODE_TRANSMIT); + dv1394_init(ohci, DV1394_PAL, MODE_RECEIVE); + dv1394_init(ohci, DV1394_PAL, MODE_TRANSMIT); +} + + +/* Bus reset handler. In the event of a bus reset, we may need to + re-start the DMA contexts - otherwise the user program would + end up waiting forever. +*/ + +static void dv1394_host_reset(struct hpsb_host *host) +{ + struct ti_ohci *ohci; + struct video_card *video = NULL; + unsigned long flags; + struct list_head *lh; + + /* We only work with the OHCI-1394 driver */ + if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME)) + return; + + ohci = (struct ti_ohci *)host->hostdata; + + + /* find the corresponding video_cards */ + spin_lock_irqsave(&dv1394_cards_lock, flags); + if (!list_empty(&dv1394_cards)) { + list_for_each(lh, &dv1394_cards) { + video = list_entry(lh, struct video_card, list); + if ((video->id >> 2) == ohci->id) + break; + } + } + spin_unlock_irqrestore(&dv1394_cards_lock, flags); + + if (!video) + return; + + + spin_lock_irqsave(&video->spinlock, flags); + + if (!video->dma_running) + goto out; + + /* check IT context */ + if (video->ohci_it_ctx != -1) { + u32 ctx; + + ctx = reg_read(video->ohci, video->ohci_IsoXmitContextControlSet); + + /* if (RUN but not ACTIVE) */ + if ( (ctx & (1<<15)) && + !(ctx & (1<<10)) ) { + + debug_printk("dv1394: IT context stopped due to bus reset; waking it up\n"); + + /* to be safe, assume a frame has been dropped. User-space programs + should handle this condition like an underflow. */ + video->dropped_frames++; + + /* for some reason you must clear, then re-set the RUN bit to restart DMA */ + + /* clear RUN */ + reg_write(video->ohci, video->ohci_IsoXmitContextControlClear, (1 << 15)); + flush_pci_write(video->ohci); + + /* set RUN */ + reg_write(video->ohci, video->ohci_IsoXmitContextControlSet, (1 << 15)); + flush_pci_write(video->ohci); + + /* set the WAKE bit (just in case; this isn't strictly necessary) */ + reg_write(video->ohci, video->ohci_IsoXmitContextControlSet, (1 << 12)); + flush_pci_write(video->ohci); + + irq_printk("dv1394: AFTER IT restart ctx 0x%08x ptr 0x%08x\n", + reg_read(video->ohci, video->ohci_IsoXmitContextControlSet), + reg_read(video->ohci, video->ohci_IsoXmitCommandPtr)); + } + } + + /* check IR context */ + if (video->ohci_ir_ctx != -1) { + u32 ctx; + + ctx = reg_read(video->ohci, video->ohci_IsoRcvContextControlSet); + + /* if (RUN but not ACTIVE) */ + if ( (ctx & (1<<15)) && + !(ctx & (1<<10)) ) { + + debug_printk("dv1394: IR context stopped due to bus reset; waking it up\n"); + + /* to be safe, assume a frame has been dropped. User-space programs + should handle this condition like an overflow. */ + video->dropped_frames++; + + /* for some reason you must clear, then re-set the RUN bit to restart DMA */ + /* XXX this doesn't work for me, I can't get IR DMA to restart :[ */ + + /* clear RUN */ + reg_write(video->ohci, video->ohci_IsoRcvContextControlClear, (1 << 15)); + flush_pci_write(video->ohci); + + /* set RUN */ + reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, (1 << 15)); + flush_pci_write(video->ohci); + + /* set the WAKE bit (just in case; this isn't strictly necessary) */ + reg_write(video->ohci, video->ohci_IsoRcvContextControlSet, (1 << 12)); + flush_pci_write(video->ohci); + + irq_printk("dv1394: AFTER IR restart ctx 0x%08x ptr 0x%08x\n", + reg_read(video->ohci, video->ohci_IsoRcvContextControlSet), + reg_read(video->ohci, video->ohci_IsoRcvCommandPtr)); + } + } + +out: + spin_unlock_irqrestore(&video->spinlock, flags); + + /* wake readers/writers/ioctl'ers */ + wake_up_interruptible(&video->waitq); +} + +static struct hpsb_highlevel dv1394_highlevel = { + .name = "dv1394", + .add_host = dv1394_add_host, + .remove_host = dv1394_remove_host, + .host_reset = dv1394_host_reset, +}; + + +/*** KERNEL MODULE HANDLERS ************************************************/ + +MODULE_AUTHOR("Dan Maas , Dan Dennedy "); +MODULE_DESCRIPTION("driver for DV input/output on OHCI board"); +MODULE_SUPPORTED_DEVICE("dv1394"); +MODULE_LICENSE("GPL"); + +static void __exit dv1394_exit_module(void) +{ + hpsb_unregister_protocol(&dv1394_driver); + + hpsb_unregister_highlevel(&dv1394_highlevel); + ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_DV1394); + +#ifdef CONFIG_DEVFS_FS + dv1394_devfs_del("dv"); +#endif +#ifdef CONFIG_PROC_FS + dv1394_procfs_del("dv"); +#endif +} + +static int __init dv1394_init_module(void) +{ + if (ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_DV1394, + THIS_MODULE, &dv1394_fops)) { + printk(KERN_ERR "dv1394: unable to register character device\n"); + return -EIO; + } + +#ifdef CONFIG_DEVFS_FS + if (dv1394_devfs_add_dir("dv", NULL, NULL) < 0) { + printk(KERN_ERR "dv1394: unable to create /dev/ieee1394/dv\n"); + ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_DV1394); + return -ENOMEM; + } +#endif + +#ifdef CONFIG_PROC_FS + if (dv1394_procfs_add_dir("dv",NULL,NULL) < 0) { + printk(KERN_ERR "dv1394: unable to create /proc/bus/ieee1394/dv\n"); + ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_DV1394); +#ifdef CONFIG_DEVFS_FS + dv1394_devfs_del("dv"); +#endif + return -ENOMEM; + } +#endif + + hpsb_register_highlevel (&dv1394_highlevel); + + hpsb_register_protocol(&dv1394_driver); + + return 0; +} + +module_init(dv1394_init_module); +module_exit(dv1394_exit_module); diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/dv1394.h.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/dv1394.h.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/dv1394.h.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/dv1394.h.svn-base 2003-07-21 13:09:32.000000000 +0200 @@ -0,0 +1,347 @@ +/* + * dv1394.h - DV input/output over IEEE 1394 on OHCI chips + * Copyright (C)2001 Daniel Maas + * receive, proc_fs by Dan Dennedy + * + * based on: + * video1394.h - driver for OHCI 1394 boards + * Copyright (C)1999,2000 Sebastien Rougeaux + * Peter Schlaile + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _DV_1394_H +#define _DV_1394_H + +/* This is the public user-space interface. Try not to break it. */ + +#define DV1394_API_VERSION 0x20011127 + +/* ******************** + ** ** + ** DV1394 API ** + ** ** + ******************** + + There are two methods of operating the DV1394 DV output device. + + 1) + + The simplest is an interface based on write(): simply write + full DV frames of data to the device, and they will be transmitted + as quickly as possible. The FD may be set for non-blocking I/O, + in which case you can use select() or poll() to wait for output + buffer space. + + To set the DV output parameters (e.g. whether you want NTSC or PAL + video), use the DV1394_INIT ioctl, passing in the parameters you + want in a struct dv1394_init. + + Example 1: + To play a raw .DV file: cat foo.DV > /dev/dv1394 + (cat will use write() internally) + + Example 2: + static struct dv1394_init init = { + 0x63, (broadcast channel) + 4, (four-frame ringbuffer) + DV1394_NTSC, (send NTSC video) + 0, 0 (default empty packet rate) + } + + ioctl(fd, DV1394_INIT, &init); + + while (1) { + read( , buf, DV1394_NTSC_FRAME_SIZE ); + write( , buf, DV1394_NTSC_FRAME_SIZE ); + } + + 2) + + For more control over buffering, and to avoid unnecessary copies + of the DV data, you can use the more sophisticated the mmap() interface. + First, call the DV1394_INIT ioctl to specify your parameters, + including the number of frames in the ringbuffer. Then, calling mmap() + on the dv1394 device will give you direct access to the ringbuffer + from which the DV card reads your frame data. + + The ringbuffer is simply one large, contiguous region of memory + containing two or more frames of packed DV data. Each frame of DV data + is 120000 bytes (NTSC) or 144000 bytes (PAL). + + Fill one or more frames in the ringbuffer, then use the DV1394_SUBMIT_FRAMES + ioctl to begin I/O. You can use either the DV1394_WAIT_FRAMES ioctl + or select()/poll() to wait until the frames are transmitted. Next, you'll + need to call the DV1394_GET_STATUS ioctl to determine which ringbuffer + frames are clear (ready to be filled with new DV data). Finally, use + DV1394_SUBMIT_FRAMES again to send the new data to the DV output. + + + Example: here is what a four-frame ringbuffer might look like + during DV transmission: + + + frame 0 frame 1 frame 2 frame 3 + + *--------------------------------------* + | CLEAR | DV data | DV data | CLEAR | + *--------------------------------------* + + + transmission goes in this direction --->>> + + + The DV hardware is currently transmitting the data in frame 1. + Once frame 1 is finished, it will automatically transmit frame 2. + (if frame 2 finishes before frame 3 is submitted, the device + will continue to transmit frame 2, and will increase the dropped_frames + counter each time it repeats the transmission). + + + If you called DV1394_GET_STATUS at this instant, you would + receive the following values: + + n_frames = 4 + active_frame = 1 + first_clear_frame = 3 + n_clear_frames = 2 + + At this point, you should write new DV data into frame 3 and optionally + frame 0. Then call DV1394_SUBMIT_FRAMES to inform the device that + it may transmit the new frames. + + ERROR HANDLING + + An error (buffer underflow/overflow or a break in the DV stream due + to a 1394 bus reset) can be detected by checking the dropped_frames + field of struct dv1394_status (obtained through the + DV1394_GET_STATUS ioctl). + + The best way to recover from such an error is to re-initialize + dv1394, either by using the DV1394_INIT ioctl call, or closing the + file descriptor and opening it again. (note that you must unmap all + ringbuffer mappings when closing the file descriptor, or else + dv1394 will still be considered 'in use'). + + MAIN LOOP + + For maximum efficiency and robustness against bus errors, you are + advised to model the main loop of your application after the + following pseudo-code example: + + (checks of system call return values omitted for brevity; always + check return values in your code!) + + while ( frames left ) { + + struct pollfd *pfd = ...; + + pfd->fd = dv1394_fd; + pfd->revents = 0; + pfd->events = POLLOUT | POLLIN; (OUT for transmit, IN for receive) + + (add other sources of I/O here) + + poll(pfd, 1, -1); (or select(); add a timeout if you want) + + if (pfd->revents) { + struct dv1394_status status; + + ioctl(dv1394_fd, DV1394_GET_STATUS, &status); + + if (status.dropped_frames > 0) { + reset_dv1394(); + } else { + for (int i = 0; i < status.n_clear_frames; i++) { + copy_DV_frame(); + } + } + } + } + + where copy_DV_frame() reads or writes on the dv1394 file descriptor + (read/write mode) or copies data to/from the mmap ringbuffer and + then calls ioctl(DV1394_SUBMIT_FRAMES) to notify dv1394 that new + frames are availble (mmap mode). + + reset_dv1394() is called in the event of a buffer + underflow/overflow or a halt in the DV stream (e.g. due to a 1394 + bus reset). To guarantee recovery from the error, this function + should close the dv1394 file descriptor (and munmap() all + ringbuffer mappings, if you are using them), then re-open the + dv1394 device (and re-map the ringbuffer). + +*/ + + +/* maximum number of frames in the ringbuffer */ +#define DV1394_MAX_FRAMES 32 + +/* number of *full* isochronous packets per DV frame */ +#define DV1394_NTSC_PACKETS_PER_FRAME 250 +#define DV1394_PAL_PACKETS_PER_FRAME 300 + +/* size of one frame's worth of DV data, in bytes */ +#define DV1394_NTSC_FRAME_SIZE (480 * DV1394_NTSC_PACKETS_PER_FRAME) +#define DV1394_PAL_FRAME_SIZE (480 * DV1394_PAL_PACKETS_PER_FRAME) + + +/* ioctl() commands */ + +enum { + /* I don't like using 0 as a valid ioctl() */ + DV1394_INVALID = 0, + + + /* get the driver ready to transmit video. + pass a struct dv1394_init* as the parameter (see below), + or NULL to get default parameters */ + DV1394_INIT, + + + /* stop transmitting video and free the ringbuffer */ + DV1394_SHUTDOWN, + + + /* submit N new frames to be transmitted, where + the index of the first new frame is first_clear_buffer, + and the index of the last new frame is + (first_clear_buffer + N) % n_frames */ + DV1394_SUBMIT_FRAMES, + + + /* block until N buffers are clear (pass N as the parameter) + Because we re-transmit the last frame on underrun, there + will at most be n_frames - 1 clear frames at any time */ + DV1394_WAIT_FRAMES, + + /* capture new frames that have been received, where + the index of the first new frame is first_clear_buffer, + and the index of the last new frame is + (first_clear_buffer + N) % n_frames */ + DV1394_RECEIVE_FRAMES, + + + DV1394_START_RECEIVE, + + + /* pass a struct dv1394_status* as the parameter (see below) */ + DV1394_GET_STATUS, +}; + +#include "ieee1394-ioctl.h" + + +enum pal_or_ntsc { + DV1394_NTSC = 0, + DV1394_PAL +}; + + + + +/* this is the argument to DV1394_INIT */ +struct dv1394_init { + /* DV1394_API_VERSION */ + unsigned int api_version; + + /* isochronous transmission channel to use */ + unsigned int channel; + + /* number of frames in the ringbuffer. Must be at least 2 + and at most DV1394_MAX_FRAMES. */ + unsigned int n_frames; + + /* send/receive PAL or NTSC video format */ + enum pal_or_ntsc format; + + /* the following are used only for transmission */ + + /* set these to zero unless you want a + non-default empty packet rate (see below) */ + unsigned long cip_n; + unsigned long cip_d; + + /* set this to zero unless you want a + non-default SYT cycle offset (default = 3 cycles) */ + unsigned int syt_offset; +}; + +/* NOTE: you may only allocate the DV frame ringbuffer once each time + you open the dv1394 device. DV1394_INIT will fail if you call it a + second time with different 'n_frames' or 'format' arguments (which + would imply a different size for the ringbuffer). If you need a + different buffer size, simply close and re-open the device, then + initialize it with your new settings. */ + +/* Q: What are cip_n and cip_d? */ + +/* + A: DV video streams do not utilize 100% of the potential bandwidth offered + by IEEE 1394 (FireWire). To achieve the correct rate of data transmission, + DV devices must periodically insert empty packets into the 1394 data stream. + Typically there is one empty packet per 14-16 data-carrying packets. + + Some DV devices will accept a wide range of empty packet rates, while others + require a precise rate. If the dv1394 driver produces empty packets at + a rate that your device does not accept, you may see ugly patterns on the + DV output, or even no output at all. + + The default empty packet insertion rate seems to work for many people; if + your DV output is stable, you can simply ignore this discussion. However, + we have exposed the empty packet rate as a parameter to support devices that + do not work with the default rate. + + The decision to insert an empty packet is made with a numerator/denominator + algorithm. Empty packets are produced at an average rate of CIP_N / CIP_D. + You can alter the empty packet rate by passing non-zero values for cip_n + and cip_d to the INIT ioctl. + + */ + + + +struct dv1394_status { + /* this embedded init struct returns the current dv1394 + parameters in use */ + struct dv1394_init init; + + /* the ringbuffer frame that is currently being + displayed. (-1 if the device is not transmitting anything) */ + int active_frame; + + /* index of the first buffer (ahead of active_frame) that + is ready to be filled with data */ + unsigned int first_clear_frame; + + /* how many buffers, including first_clear_buffer, are + ready to be filled with data */ + unsigned int n_clear_frames; + + /* how many times the DV stream has underflowed, overflowed, + or otherwise encountered an error, since the previous call + to DV1394_GET_STATUS */ + unsigned int dropped_frames; + + /* N.B. The dropped_frames counter is only a lower bound on the actual + number of dropped frames, with the special case that if dropped_frames + is zero, then it is guaranteed that NO frames have been dropped + since the last call to DV1394_GET_STATUS. + */ +}; + + +#endif /* _DV_1394_H */ diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/eth1394.c.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/eth1394.c.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/eth1394.c.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/eth1394.c.svn-base 2003-09-08 03:33:07.000000000 +0200 @@ -0,0 +1,1656 @@ +/* + * eth1394.c -- Ethernet driver for Linux IEEE-1394 Subsystem + * + * Copyright (C) 2001-2003 Ben Collins + * 2000 Bonin Franck + * 2003 Steve Kinneberg + * + * Mainly based on work by Emanuel Pirker and Andreas E. Bombe + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* This driver intends to support RFC 2734, which describes a method for + * transporting IPv4 datagrams over IEEE-1394 serial busses. This driver + * will ultimately support that method, but currently falls short in + * several areas. + * + * TODO: + * RFC 2734 related: + * - Add Config ROM entry + * - Add MCAP. Limited Multicast exists only to 224.0.0.1 and 224.0.0.2. + * + * Non-RFC 2734 related: + * - Handle fragmented skb's coming from the networking layer. + * - Move generic GASP reception to core 1394 code + * - Convert kmalloc/kfree for link fragments to use kmem_cache_* instead + * - Stability improvements + * - Performance enhancements + * - Change hardcoded 1394 bus address region to a dynamic memory space allocation + * - Consider garbage collecting old partial datagrams after X amount of time + */ + + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ieee1394_types.h" +#include "ieee1394_core.h" +#include "ieee1394_transactions.h" +#include "ieee1394.h" +#include "highlevel.h" +#include "iso.h" +#include "nodemgr.h" +#include "eth1394.h" + +#define ETH1394_PRINT_G(level, fmt, args...) \ + printk(level "%s: " fmt, driver_name, ## args) + +#define ETH1394_PRINT(level, dev_name, fmt, args...) \ + printk(level "%s: %s: " fmt, driver_name, dev_name, ## args) + +#define DEBUG(fmt, args...) \ + printk(KERN_ERR "%s:%s[%d]: " fmt "\n", driver_name, __FUNCTION__, __LINE__, ## args) +#define TRACE() printk(KERN_ERR "%s:%s[%d] ---- TRACE\n", driver_name, __FUNCTION__, __LINE__) + +static char version[] __devinitdata = + "$Rev$ Ben Collins "; + +struct fragment_info { + struct list_head list; + int offset; + int len; +}; + +struct partial_datagram { + struct list_head list; + u16 dgl; + u16 dg_size; + u16 ether_type; + struct sk_buff *skb; + char *pbuf; + struct list_head frag_info; +}; + +/* Our ieee1394 highlevel driver */ +static const char driver_name[] = "eth1394"; + +static kmem_cache_t *packet_task_cache; + +static struct hpsb_highlevel eth1394_highlevel; + +/* Use common.lf to determine header len */ +static const int hdr_type_len[] = { + sizeof (struct eth1394_uf_hdr), + sizeof (struct eth1394_ff_hdr), + sizeof (struct eth1394_sf_hdr), + sizeof (struct eth1394_sf_hdr) +}; + +/* Change this to IEEE1394_SPEED_S100 to make testing easier */ +#define ETH1394_SPEED_DEF IEEE1394_SPEED_MAX + +/* For now, this needs to be 1500, so that XP works with us */ +#define ETH1394_DATA_LEN ETH_DATA_LEN + +static const u16 eth1394_speedto_maxpayload[] = { +/* S100, S200, S400, S800, S1600, S3200 */ + 512, 1024, 2048, 4096, 4096, 4096 +}; + +MODULE_AUTHOR("Ben Collins (bcollins@debian.org)"); +MODULE_DESCRIPTION("IEEE 1394 IPv4 Driver (IPv4-over-1394 as per RFC 2734)"); +MODULE_LICENSE("GPL"); + +/* The max_partial_datagrams parameter is the maximum number of fragmented + * datagrams per node that eth1394 will keep in memory. Providing an upper + * bound allows us to limit the amount of memory that partial datagrams + * consume in the event that some partial datagrams are never completed. This + * should probably change to a sysctl item or the like if possible. + */ +MODULE_PARM(max_partial_datagrams, "i"); +MODULE_PARM_DESC(max_partial_datagrams, + "Maximum number of partially received fragmented datagrams " + "(default = 25)."); +static int max_partial_datagrams = 25; + + +static int ether1394_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, void *daddr, void *saddr, + unsigned len); +static int ether1394_rebuild_header(struct sk_buff *skb); +static int ether1394_header_parse(struct sk_buff *skb, unsigned char *haddr); +static int ether1394_header_cache(struct neighbour *neigh, struct hh_cache *hh); +static void ether1394_header_cache_update(struct hh_cache *hh, + struct net_device *dev, + unsigned char * haddr); +static int ether1394_mac_addr(struct net_device *dev, void *p); + +static inline void purge_partial_datagram(struct list_head *old); +static int ether1394_tx(struct sk_buff *skb, struct net_device *dev); +static void ether1394_iso(struct hpsb_iso *iso); + +static int ether1394_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); +static int ether1394_ethtool_ioctl(struct net_device *dev, void *useraddr); + +static void eth1394_iso_shutdown(struct eth1394_priv *priv) +{ + priv->bc_state = ETHER1394_BC_CLOSED; + + if (priv->iso != NULL) { + if (!in_interrupt()) + hpsb_iso_shutdown(priv->iso); + priv->iso = NULL; + } +} + +static int ether1394_init_bc(struct net_device *dev) +{ + struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv; + + /* First time sending? Need a broadcast channel for ARP and for + * listening on */ + if (priv->bc_state == ETHER1394_BC_CHECK) { + quadlet_t bc; + + /* Get the local copy of the broadcast channel and check its + * validity (the IRM should validate it for us) */ + + bc = priv->host->csr.broadcast_channel; + + if ((bc & 0xc0000000) != 0xc0000000) { + /* broadcast channel not validated yet */ + ETH1394_PRINT(KERN_WARNING, dev->name, + "Error BROADCAST_CHANNEL register valid " + "bit not set, can't send IP traffic\n"); + + eth1394_iso_shutdown(priv); + + return -EAGAIN; + } + if (priv->broadcast_channel != (bc & 0x3f)) { + /* This really shouldn't be possible, but just in case + * the IEEE 1394 spec changes regarding broadcast + * channels in the future. */ + + eth1394_iso_shutdown(priv); + + if (in_interrupt()) + return -EAGAIN; + + priv->broadcast_channel = bc & 0x3f; + ETH1394_PRINT(KERN_INFO, dev->name, + "Changing to broadcast channel %d...\n", + priv->broadcast_channel); + + priv->iso = hpsb_iso_recv_init(priv->host, 16 * 4096, + 16, priv->broadcast_channel, + 1, ether1394_iso); + if (priv->iso == NULL) { + ETH1394_PRINT(KERN_ERR, dev->name, + "failed to change broadcast " + "channel\n"); + return -EAGAIN; + } + } + if (hpsb_iso_recv_start(priv->iso, -1, (1 << 3), -1) < 0) { + ETH1394_PRINT(KERN_ERR, dev->name, + "Could not start data stream reception\n"); + + eth1394_iso_shutdown(priv); + + return -EAGAIN; + } + priv->bc_state = ETHER1394_BC_OPENED; + } + + return 0; +} + +/* This is called after an "ifup" */ +static int ether1394_open (struct net_device *dev) +{ + struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv; + unsigned long flags; + int ret; + + /* Something bad happened, don't even try */ + if (priv->bc_state == ETHER1394_BC_CLOSED) + return -EAGAIN; + + spin_lock_irqsave(&priv->lock, flags); + ret = ether1394_init_bc(dev); + spin_unlock_irqrestore(&priv->lock, flags); + + if (ret) + return ret; + + netif_start_queue (dev); + return 0; +} + +/* This is called after an "ifdown" */ +static int ether1394_stop (struct net_device *dev) +{ + netif_stop_queue (dev); + return 0; +} + +/* Return statistics to the caller */ +static struct net_device_stats *ether1394_stats (struct net_device *dev) +{ + return &(((struct eth1394_priv *)dev->priv)->stats); +} + +/* What to do if we timeout. I think a host reset is probably in order, so + * that's what we do. Should we increment the stat counters too? */ +static void ether1394_tx_timeout (struct net_device *dev) +{ + ETH1394_PRINT (KERN_ERR, dev->name, "Timeout, resetting host %s\n", + ((struct eth1394_priv *)(dev->priv))->host->driver->name); + + highlevel_host_reset (((struct eth1394_priv *)(dev->priv))->host); + + netif_wake_queue (dev); +} + +static int ether1394_change_mtu(struct net_device *dev, int new_mtu) +{ + struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv; + int phy_id = NODEID_TO_NODE(priv->host->node_id); + + if ((new_mtu < 68) || (new_mtu > min(ETH1394_DATA_LEN, (int)(priv->maxpayload[phy_id] - + (sizeof(union eth1394_hdr) + ETHER1394_GASP_OVERHEAD))))) + return -EINVAL; + dev->mtu = new_mtu; + return 0; +} + +static inline void ether1394_register_limits(int nodeid, u16 maxpayload, + unsigned char sspd, u64 eui, u64 fifo, + struct eth1394_priv *priv) +{ + if (nodeid < 0 || nodeid >= ALL_NODES) { + ETH1394_PRINT_G (KERN_ERR, "Cannot register invalid nodeid %d\n", nodeid); + return; + } + + priv->maxpayload[nodeid] = maxpayload; + priv->sspd[nodeid] = sspd; + priv->fifo[nodeid] = fifo; + priv->eui[nodeid] = eui; + + priv->maxpayload[ALL_NODES] = min(priv->maxpayload[ALL_NODES], maxpayload); + priv->sspd[ALL_NODES] = min(priv->sspd[ALL_NODES], sspd); + + return; +} + +static void ether1394_reset_priv (struct net_device *dev, int set_mtu) +{ + unsigned long flags; + int i; + struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv; + struct hpsb_host *host = priv->host; + int phy_id = NODEID_TO_NODE(host->node_id); + u64 guid = *((u64*)&(host->csr.rom[3])); + u16 maxpayload = 1 << (((be32_to_cpu(host->csr.rom[2]) >> 12) & 0xf) + 1); + + spin_lock_irqsave (&priv->lock, flags); + + /* Clear the speed/payload/offset tables */ + memset (priv->maxpayload, 0, sizeof (priv->maxpayload)); + memset (priv->sspd, 0, sizeof (priv->sspd)); + memset (priv->fifo, 0, sizeof (priv->fifo)); + + priv->sspd[ALL_NODES] = ETH1394_SPEED_DEF; + priv->maxpayload[ALL_NODES] = eth1394_speedto_maxpayload[priv->sspd[ALL_NODES]]; + + priv->bc_state = ETHER1394_BC_CHECK; + + /* Register our limits now */ + ether1394_register_limits(phy_id, maxpayload, + host->speed_map[(phy_id << 6) + phy_id], + guid, ETHER1394_REGION_ADDR, priv); + + /* We'll use our maxpayload as the default mtu */ + if (set_mtu) { + dev->mtu = min(ETH1394_DATA_LEN, (int)(priv->maxpayload[phy_id] - + (sizeof(union eth1394_hdr) + ETHER1394_GASP_OVERHEAD))); + + /* Set our hardware address while we're at it */ + *(u64*)dev->dev_addr = guid; + *(u64*)dev->broadcast = ~0x0ULL; + } + + spin_unlock_irqrestore (&priv->lock, flags); + + for (i = 0; i < ALL_NODES; i++) { + struct list_head *lh, *n; + + spin_lock_irqsave(&priv->pdg[i].lock, flags); + if (!set_mtu) { + list_for_each_safe(lh, n, &priv->pdg[i].list) { + purge_partial_datagram(lh); + } + } + INIT_LIST_HEAD(&(priv->pdg[i].list)); + priv->pdg[i].sz = 0; + spin_unlock_irqrestore(&priv->pdg[i].lock, flags); + } +} + +/* This function is called by register_netdev */ +static int ether1394_init_dev (struct net_device *dev) +{ + /* Our functions */ + dev->open = ether1394_open; + dev->stop = ether1394_stop; + dev->hard_start_xmit = ether1394_tx; + dev->get_stats = ether1394_stats; + dev->tx_timeout = ether1394_tx_timeout; + dev->change_mtu = ether1394_change_mtu; + + dev->hard_header = ether1394_header; + dev->rebuild_header = ether1394_rebuild_header; + dev->hard_header_cache = ether1394_header_cache; + dev->header_cache_update= ether1394_header_cache_update; + dev->hard_header_parse = ether1394_header_parse; + dev->set_mac_address = ether1394_mac_addr; + dev->do_ioctl = ether1394_do_ioctl; + + /* Some constants */ + dev->watchdog_timeo = ETHER1394_TIMEOUT; + dev->flags = IFF_BROADCAST | IFF_MULTICAST; + dev->features = NETIF_F_HIGHDMA; + dev->addr_len = ETH1394_ALEN; + dev->hard_header_len = ETH1394_HLEN; + dev->type = ARPHRD_IEEE1394; + + ether1394_reset_priv (dev, 1); + + return 0; +} + +/* + * This function is called every time a card is found. It is generally called + * when the module is installed. This is where we add all of our ethernet + * devices. One for each host. + */ +static void ether1394_add_host (struct hpsb_host *host) +{ + int i; + struct host_info *hi = NULL; + struct net_device *dev = NULL; + struct eth1394_priv *priv; + static int version_printed = 0; + + if (version_printed++ == 0) + ETH1394_PRINT_G (KERN_INFO, "%s\n", version); + + /* We should really have our own alloc_hpsbdev() function in + * net_init.c instead of calling the one for ethernet then hijacking + * it for ourselves. That way we'd be a real networking device. */ + dev = alloc_etherdev(sizeof (struct eth1394_priv)); + + if (dev == NULL) { + ETH1394_PRINT_G (KERN_ERR, "Out of memory trying to allocate " + "etherdevice for IEEE 1394 device %s-%d\n", + host->driver->name, host->id); + goto out; + } + + SET_MODULE_OWNER(dev); + + dev->init = ether1394_init_dev; + + priv = (struct eth1394_priv *)dev->priv; + + spin_lock_init(&priv->lock); + priv->host = host; + + for (i = 0; i < ALL_NODES; i++) { + spin_lock_init(&priv->pdg[i].lock); + INIT_LIST_HEAD(&priv->pdg[i].list); + priv->pdg[i].sz = 0; + } + + hi = hpsb_create_hostinfo(ð1394_highlevel, host, sizeof(*hi)); + + if (hi == NULL) { + ETH1394_PRINT_G (KERN_ERR, "Out of memory trying to create " + "hostinfo for IEEE 1394 device %s-%d\n", + host->driver->name, host->id); + goto out; + } + + if (register_netdev (dev)) { + ETH1394_PRINT (KERN_ERR, dev->name, "Error registering network driver\n"); + goto out; + } + + ETH1394_PRINT (KERN_ERR, dev->name, "IEEE-1394 IPv4 over 1394 Ethernet (%s)\n", + host->driver->name); + + hi->host = host; + hi->dev = dev; + + /* Ignore validity in hopes that it will be set in the future. It'll + * be checked when the eth device is opened. */ + priv->broadcast_channel = host->csr.broadcast_channel & 0x3f; + + priv->iso = hpsb_iso_recv_init(host, 16 * 4096, 16, priv->broadcast_channel, + 1, ether1394_iso); + if (priv->iso == NULL) { + priv->bc_state = ETHER1394_BC_CLOSED; + } + return; + +out: + if (dev != NULL) + kfree(dev); + if (hi) + hpsb_destroy_hostinfo(ð1394_highlevel, host); + + return; +} + +/* Remove a card from our list */ +static void ether1394_remove_host (struct hpsb_host *host) +{ + struct host_info *hi = hpsb_get_hostinfo(ð1394_highlevel, host); + + if (hi != NULL) { + struct eth1394_priv *priv = (struct eth1394_priv *)hi->dev->priv; + + eth1394_iso_shutdown(priv); + + if (hi->dev) { + unregister_netdev (hi->dev); + kfree(hi->dev); + } + } + + return; +} + +/* A reset has just arisen */ +static void ether1394_host_reset (struct hpsb_host *host) +{ + struct host_info *hi = hpsb_get_hostinfo(ð1394_highlevel, host); + struct net_device *dev; + + /* This can happen for hosts that we don't use */ + if (hi == NULL) + return; + + dev = hi->dev; + + /* Reset our private host data, but not our mtu */ + netif_stop_queue (dev); + ether1394_reset_priv (dev, 0); + netif_wake_queue (dev); +} + +/****************************************** + * HW Header net device functions + ******************************************/ +/* These functions have been adapted from net/ethernet/eth.c */ + + +/* Create a fake MAC header for an arbitrary protocol layer. + * saddr=NULL means use device source address + * daddr=NULL means leave destination address (eg unresolved arp). */ +static int ether1394_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, void *daddr, void *saddr, + unsigned len) +{ + struct eth1394hdr *eth = (struct eth1394hdr *)skb_push(skb, ETH1394_HLEN); + + eth->h_proto = htons(type); + + if (dev->flags & (IFF_LOOPBACK|IFF_NOARP)) + { + memset(eth->h_dest, 0, dev->addr_len); + return(dev->hard_header_len); + } + + if (daddr) + { + memcpy(eth->h_dest,daddr,dev->addr_len); + return dev->hard_header_len; + } + + return -dev->hard_header_len; + +} + + +/* Rebuild the faked MAC header. This is called after an ARP + * (or in future other address resolution) has completed on this + * sk_buff. We now let ARP fill in the other fields. + * + * This routine CANNOT use cached dst->neigh! + * Really, it is used only when dst->neigh is wrong. + */ +static int ether1394_rebuild_header(struct sk_buff *skb) +{ + struct eth1394hdr *eth = (struct eth1394hdr *)skb->data; + struct net_device *dev = skb->dev; + + switch (eth->h_proto) + { +#ifdef CONFIG_INET + case __constant_htons(ETH_P_IP): + return arp_find((unsigned char*)ð->h_dest, skb); +#endif + default: + printk(KERN_DEBUG + "%s: unable to resolve type %X addresses.\n", + dev->name, (int)eth->h_proto); + break; + } + + return 0; +} + +static int ether1394_header_parse(struct sk_buff *skb, unsigned char *haddr) +{ + struct net_device *dev = skb->dev; + memcpy(haddr, dev->dev_addr, ETH1394_ALEN); + return ETH1394_ALEN; +} + + +static int ether1394_header_cache(struct neighbour *neigh, struct hh_cache *hh) +{ + unsigned short type = hh->hh_type; + struct eth1394hdr *eth = (struct eth1394hdr*)(((u8*)hh->hh_data) + 6); + struct net_device *dev = neigh->dev; + + if (type == __constant_htons(ETH_P_802_3)) { + return -1; + } + + eth->h_proto = type; + memcpy(eth->h_dest, neigh->ha, dev->addr_len); + + hh->hh_len = ETH1394_HLEN; + return 0; +} + +/* Called by Address Resolution module to notify changes in address. */ +static void ether1394_header_cache_update(struct hh_cache *hh, + struct net_device *dev, + unsigned char * haddr) +{ + memcpy(((u8*)hh->hh_data) + 6, haddr, dev->addr_len); +} + +static int ether1394_mac_addr(struct net_device *dev, void *p) +{ + if (netif_running(dev)) + return -EBUSY; + + /* Not going to allow setting the MAC address, we really need to use + * the real one suppliled by the hardware */ + return -EINVAL; + } + + + +/****************************************** + * Datagram reception code + ******************************************/ + +/* Copied from net/ethernet/eth.c */ +static inline u16 ether1394_type_trans(struct sk_buff *skb, + struct net_device *dev) +{ + struct eth1394hdr *eth; + unsigned char *rawp; + + skb->mac.raw = skb->data; + skb_pull (skb, ETH1394_HLEN); + eth = (struct eth1394hdr*)skb->mac.raw; + + if (*eth->h_dest & 1) { + if (memcmp(eth->h_dest, dev->broadcast, dev->addr_len)==0) + skb->pkt_type = PACKET_BROADCAST; +#if 0 + else + skb->pkt_type = PACKET_MULTICAST; +#endif + } else { + if (memcmp(eth->h_dest, dev->dev_addr, dev->addr_len)) + skb->pkt_type = PACKET_OTHERHOST; + } + + if (ntohs (eth->h_proto) >= 1536) + return eth->h_proto; + + rawp = skb->data; + + if (*(unsigned short *)rawp == 0xFFFF) + return htons (ETH_P_802_3); + + return htons (ETH_P_802_2); +} + +/* Parse an encapsulated IP1394 header into an ethernet frame packet. + * We also perform ARP translation here, if need be. */ +static inline u16 ether1394_parse_encap(struct sk_buff *skb, + struct net_device *dev, + nodeid_t srcid, nodeid_t destid, + u16 ether_type) +{ + struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv; + u64 dest_hw; + unsigned short ret = 0; + + /* Setup our hw addresses. We use these to build the + * ethernet header. */ + if (destid == (LOCAL_BUS | ALL_NODES)) + dest_hw = ~0ULL; /* broadcast */ + else + dest_hw = priv->eui[NODEID_TO_NODE(destid)]; + + /* If this is an ARP packet, convert it. First, we want to make + * use of some of the fields, since they tell us a little bit + * about the sending machine. */ + if (ether_type == __constant_htons (ETH_P_ARP)) { + unsigned long flags; + struct eth1394_arp *arp1394 = (struct eth1394_arp*)skb->data; + struct arphdr *arp = (struct arphdr *)skb->data; + unsigned char *arp_ptr = (unsigned char *)(arp + 1); + u64 fifo_addr = (u64)ntohs(arp1394->fifo_hi) << 32 | + ntohl(arp1394->fifo_lo); + u8 host_max_rec = (be32_to_cpu(priv->host->csr.rom[2]) >> + 12) & 0xf; + u8 max_rec = min(host_max_rec, (u8)(arp1394->max_rec)); + u16 maxpayload = min(eth1394_speedto_maxpayload[arp1394->sspd], + (u16)(1 << (max_rec + 1))); + + + /* Update our speed/payload/fifo_offset table */ + spin_lock_irqsave (&priv->lock, flags); + ether1394_register_limits(NODEID_TO_NODE(srcid), maxpayload, + arp1394->sspd, arp1394->s_uniq_id, + fifo_addr, priv); + spin_unlock_irqrestore (&priv->lock, flags); + + /* Now that we're done with the 1394 specific stuff, we'll + * need to alter some of the data. Believe it or not, all + * that needs to be done is sender_IP_address needs to be + * moved, the destination hardware address get stuffed + * in and the hardware address length set to 8. + * + * IMPORTANT: The code below overwrites 1394 specific data + * needed above data so keep the call to + * ether1394_register_limits() before munging the data for the + * higher level IP stack. */ + + arp->ar_hln = 8; + arp_ptr += arp->ar_hln; /* skip over sender unique id */ + *(u32*)arp_ptr = arp1394->sip; /* move sender IP addr */ + arp_ptr += arp->ar_pln; /* skip over sender IP addr */ + + if (arp->ar_op == 1) + /* just set ARP req target unique ID to 0 */ + memset(arp_ptr, 0, ETH1394_ALEN); + else + memcpy(arp_ptr, dev->dev_addr, ETH1394_ALEN); + } + + /* Now add the ethernet header. */ + if (dev->hard_header (skb, dev, __constant_ntohs (ether_type), + &dest_hw, NULL, skb->len) >= 0) + ret = ether1394_type_trans(skb, dev); + + return ret; +} + +static inline int fragment_overlap(struct list_head *frag_list, int offset, int len) +{ + struct list_head *lh; + struct fragment_info *fi; + + list_for_each(lh, frag_list) { + fi = list_entry(lh, struct fragment_info, list); + + if ( ! ((offset > (fi->offset + fi->len - 1)) || + ((offset + len - 1) < fi->offset))) + return 1; + } + return 0; +} + +static inline struct list_head *find_partial_datagram(struct list_head *pdgl, int dgl) +{ + struct list_head *lh; + struct partial_datagram *pd; + + list_for_each(lh, pdgl) { + pd = list_entry(lh, struct partial_datagram, list); + if (pd->dgl == dgl) + return lh; + } + return NULL; +} + +/* Assumes that new fragment does not overlap any existing fragments */ +static inline int new_fragment(struct list_head *frag_info, int offset, int len) +{ + struct list_head *lh; + struct fragment_info *fi, *fi2, *new; + + list_for_each(lh, frag_info) { + fi = list_entry(lh, struct fragment_info, list); + if ((fi->offset + fi->len) == offset) { + /* The new fragment can be tacked on to the end */ + fi->len += len; + /* Did the new fragment plug a hole? */ + fi2 = list_entry(lh->next, struct fragment_info, list); + if ((fi->offset + fi->len) == fi2->offset) { + /* glue fragments together */ + fi->len += fi2->len; + list_del(lh->next); + kfree(fi2); + } + return 0; + } else if ((offset + len) == fi->offset) { + /* The new fragment can be tacked on to the beginning */ + fi->offset = offset; + fi->len += len; + /* Did the new fragment plug a hole? */ + fi2 = list_entry(lh->prev, struct fragment_info, list); + if ((fi2->offset + fi2->len) == fi->offset) { + /* glue fragments together */ + fi2->len += fi->len; + list_del(lh); + kfree(fi); + } + return 0; + } else if (offset > (fi->offset + fi->len)) { + break; + } else if ((offset + len) < fi->offset) { + lh = lh->prev; + break; + } + } + + new = kmalloc(sizeof(struct fragment_info), GFP_ATOMIC); + if (!new) + return -ENOMEM; + + new->offset = offset; + new->len = len; + + list_add(&new->list, lh); + + return 0; +} + +static inline int new_partial_datagram(struct net_device *dev, + struct list_head *pdgl, int dgl, + int dg_size, char *frag_buf, + int frag_off, int frag_len) +{ + struct partial_datagram *new; + + new = kmalloc(sizeof(struct partial_datagram), GFP_ATOMIC); + if (!new) + return -ENOMEM; + + INIT_LIST_HEAD(&new->frag_info); + + if (new_fragment(&new->frag_info, frag_off, frag_len) < 0) { + kfree(new); + return -ENOMEM; + } + + new->dgl = dgl; + new->dg_size = dg_size; + + new->skb = dev_alloc_skb(dg_size + dev->hard_header_len + 15); + if (!new->skb) { + struct fragment_info *fi = list_entry(new->frag_info.next, + struct fragment_info, + list); + kfree(fi); + kfree(new); + return -ENOMEM; + } + + skb_reserve(new->skb, (dev->hard_header_len + 15) & ~15); + new->pbuf = skb_put(new->skb, dg_size); + memcpy(new->pbuf + frag_off, frag_buf, frag_len); + + list_add(&new->list, pdgl); + + return 0; +} + +static inline int update_partial_datagram(struct list_head *pdgl, struct list_head *lh, + char *frag_buf, int frag_off, int frag_len) +{ + struct partial_datagram *pd = list_entry(lh, struct partial_datagram, list); + + if (new_fragment(&pd->frag_info, frag_off, frag_len) < 0) { + return -ENOMEM; + } + + memcpy(pd->pbuf + frag_off, frag_buf, frag_len); + + /* Move list entry to beginnig of list so that oldest partial + * datagrams percolate to the end of the list */ + list_del(lh); + list_add(lh, pdgl); + + return 0; +} + +static inline void purge_partial_datagram(struct list_head *old) +{ + struct partial_datagram *pd = list_entry(old, struct partial_datagram, list); + struct list_head *lh, *n; + + list_for_each_safe(lh, n, &pd->frag_info) { + struct fragment_info *fi = list_entry(lh, struct fragment_info, list); + list_del(lh); + kfree(fi); + } + list_del(old); + kfree_skb(pd->skb); + kfree(pd); +} + +static inline int is_datagram_complete(struct list_head *lh, int dg_size) +{ + struct partial_datagram *pd = list_entry(lh, struct partial_datagram, list); + struct fragment_info *fi = list_entry(pd->frag_info.next, + struct fragment_info, list); + + return (fi->len == dg_size); +} + +/* Packet reception. We convert the IP1394 encapsulation header to an + * ethernet header, and fill it with some of our other fields. This is + * an incoming packet from the 1394 bus. */ +static int ether1394_data_handler(struct net_device *dev, int srcid, int destid, + char *buf, int len) +{ + struct sk_buff *skb; + unsigned long flags; + struct eth1394_priv *priv; + union eth1394_hdr *hdr = (union eth1394_hdr *)buf; + u16 ether_type = 0; /* initialized to clear warning */ + int hdr_len; + + priv = (struct eth1394_priv *)dev->priv; + + /* First, did we receive a fragmented or unfragmented datagram? */ + hdr->words.word1 = ntohs(hdr->words.word1); + + hdr_len = hdr_type_len[hdr->common.lf]; + + if (hdr->common.lf == ETH1394_HDR_LF_UF) { + /* An unfragmented datagram has been received by the ieee1394 + * bus. Build an skbuff around it so we can pass it to the + * high level network layer. */ + + skb = dev_alloc_skb(len + dev->hard_header_len + 15); + if (!skb) { + HPSB_PRINT (KERN_ERR, "ether1394 rx: low on mem\n"); + priv->stats.rx_dropped++; + return -1; + } + skb_reserve(skb, (dev->hard_header_len + 15) & ~15); + memcpy(skb_put(skb, len - hdr_len), buf + hdr_len, len - hdr_len); + ether_type = hdr->uf.ether_type; + } else { + /* A datagram fragment has been received, now the fun begins. */ + + struct list_head *pdgl, *lh; + struct partial_datagram *pd; + int fg_off; + int fg_len = len - hdr_len; + int dg_size; + int dgl; + int retval; + int sid = NODEID_TO_NODE(srcid); + struct pdg_list *pdg = &(priv->pdg[sid]); + + hdr->words.word3 = ntohs(hdr->words.word3); + /* The 4th header word is reserved so no need to do ntohs() */ + + if (hdr->common.lf == ETH1394_HDR_LF_FF) { + ether_type = hdr->ff.ether_type; + dgl = hdr->ff.dgl; + dg_size = hdr->ff.dg_size + 1; + fg_off = 0; + } else { + hdr->words.word2 = ntohs(hdr->words.word2); + dgl = hdr->sf.dgl; + dg_size = hdr->sf.dg_size + 1; + fg_off = hdr->sf.fg_off; + } + spin_lock_irqsave(&pdg->lock, flags); + + pdgl = &(pdg->list); + lh = find_partial_datagram(pdgl, dgl); + + if (lh == NULL) { + if (pdg->sz == max_partial_datagrams) { + /* remove the oldest */ + purge_partial_datagram(pdgl->prev); + pdg->sz--; + } + + retval = new_partial_datagram(dev, pdgl, dgl, dg_size, + buf + hdr_len, fg_off, + fg_len); + if (retval < 0) { + spin_unlock_irqrestore(&pdg->lock, flags); + goto bad_proto; + } + pdg->sz++; + lh = find_partial_datagram(pdgl, dgl); + } else { + struct partial_datagram *pd; + + pd = list_entry(lh, struct partial_datagram, list); + + if (fragment_overlap(&pd->frag_info, fg_off, fg_len)) { + /* Overlapping fragments, obliterate old + * datagram and start new one. */ + purge_partial_datagram(lh); + retval = new_partial_datagram(dev, pdgl, dgl, + dg_size, + buf + hdr_len, + fg_off, fg_len); + if (retval < 0) { + pdg->sz--; + spin_unlock_irqrestore(&pdg->lock, flags); + goto bad_proto; + } + } else { + retval = update_partial_datagram(pdgl, lh, + buf + hdr_len, + fg_off, fg_len); + if (retval < 0) { + /* Couldn't save off fragment anyway + * so might as well obliterate the + * datagram now. */ + purge_partial_datagram(lh); + pdg->sz--; + spin_unlock_irqrestore(&pdg->lock, flags); + goto bad_proto; + } + } /* fragment overlap */ + } /* new datagram or add to existing one */ + + pd = list_entry(lh, struct partial_datagram, list); + + if (hdr->common.lf == ETH1394_HDR_LF_FF) { + pd->ether_type = ether_type; + } + + if (is_datagram_complete(lh, dg_size)) { + ether_type = pd->ether_type; + pdg->sz--; + skb = skb_get(pd->skb); + purge_partial_datagram(lh); + spin_unlock_irqrestore(&pdg->lock, flags); + } else { + /* Datagram is not complete, we're done for the + * moment. */ + spin_unlock_irqrestore(&pdg->lock, flags); + return 0; + } + } /* unframgented datagram or fragmented one */ + + /* Write metadata, and then pass to the receive level */ + skb->dev = dev; + skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */ + + /* Parse the encapsulation header. This actually does the job of + * converting to an ethernet frame header, aswell as arp + * conversion if needed. ARP conversion is easier in this + * direction, since we are using ethernet as our backend. */ + skb->protocol = ether1394_parse_encap(skb, dev, srcid, destid, + ether_type); + + + spin_lock_irqsave(&priv->lock, flags); + if (!skb->protocol) { + priv->stats.rx_errors++; + priv->stats.rx_dropped++; + dev_kfree_skb_any(skb); + goto bad_proto; + } + + if (netif_rx(skb) == NET_RX_DROP) { + priv->stats.rx_errors++; + priv->stats.rx_dropped++; + goto bad_proto; + } + + /* Statistics */ + priv->stats.rx_packets++; + priv->stats.rx_bytes += skb->len; + +bad_proto: + if (netif_queue_stopped(dev)) + netif_wake_queue(dev); + spin_unlock_irqrestore(&priv->lock, flags); + + dev->last_rx = jiffies; + + return 0; +} + +static int ether1394_write(struct hpsb_host *host, int srcid, int destid, + quadlet_t *data, u64 addr, size_t len, u16 flags) +{ + struct host_info *hi = hpsb_get_hostinfo(ð1394_highlevel, host); + + if (hi == NULL) { + ETH1394_PRINT_G(KERN_ERR, "Could not find net device for host %s\n", + host->driver->name); + return RCODE_ADDRESS_ERROR; + } + + if (ether1394_data_handler(hi->dev, srcid, destid, (char*)data, len)) + return RCODE_ADDRESS_ERROR; + else + return RCODE_COMPLETE; +} + +static void ether1394_iso(struct hpsb_iso *iso) +{ + quadlet_t *data; + char *buf; + struct host_info *hi = hpsb_get_hostinfo(ð1394_highlevel, iso->host); + struct net_device *dev; + struct eth1394_priv *priv; + unsigned int len; + u32 specifier_id; + u16 source_id; + int i; + int nready; + + if (hi == NULL) { + ETH1394_PRINT_G(KERN_ERR, "Could not find net device for host %s\n", + iso->host->driver->name); + return; + } + + dev = hi->dev; + + nready = hpsb_iso_n_ready(iso); + for (i = 0; i < nready; i++) { + struct hpsb_iso_packet_info *info = &iso->infos[iso->first_packet + i]; + data = (quadlet_t*) (iso->data_buf.kvirt + info->offset); + + /* skip over GASP header */ + buf = (char *)data + 8; + len = info->len - 8; + + specifier_id = (((be32_to_cpu(data[0]) & 0xffff) << 8) | + ((be32_to_cpu(data[1]) & 0xff000000) >> 24)); + source_id = be32_to_cpu(data[0]) >> 16; + + priv = (struct eth1394_priv *)dev->priv; + + if (info->channel != (iso->host->csr.broadcast_channel & 0x3f) || + specifier_id != ETHER1394_GASP_SPECIFIER_ID) { + /* This packet is not for us */ + continue; + } + ether1394_data_handler(dev, source_id, LOCAL_BUS | ALL_NODES, + buf, len); + } + + hpsb_iso_recv_release_packets(iso, i); + + dev->last_rx = jiffies; +} + +/****************************************** + * Datagram transmission code + ******************************************/ + +/* Convert a standard ARP packet to 1394 ARP. The first 8 bytes (the entire + * arphdr) is the same format as the ip1394 header, so they overlap. The rest + * needs to be munged a bit. The remainder of the arphdr is formatted based + * on hwaddr len and ipaddr len. We know what they'll be, so it's easy to + * judge. + * + * Now that the EUI is used for the hardware address all we need to do to make + * this work for 1394 is to insert 2 quadlets that contain max_rec size, + * speed, and unicast FIFO address information between the sender_unique_id + * and the IP addresses. + */ +static inline void ether1394_arp_to_1394arp(struct sk_buff *skb, + struct net_device *dev) +{ + struct eth1394_priv *priv = (struct eth1394_priv *)(dev->priv); + u16 phy_id = NODEID_TO_NODE(priv->host->node_id); + + struct arphdr *arp = (struct arphdr *)skb->data; + unsigned char *arp_ptr = (unsigned char *)(arp + 1); + struct eth1394_arp *arp1394 = (struct eth1394_arp *)skb->data; + + /* Believe it or not, all that need to happen is sender IP get moved + * and set hw_addr_len, max_rec, sspd, fifo_hi and fifo_lo. */ + arp1394->hw_addr_len = 16; + arp1394->sip = *(u32*)(arp_ptr + ETH1394_ALEN); + arp1394->max_rec = (be32_to_cpu(priv->host->csr.rom[2]) >> 12) & 0xf; + arp1394->sspd = priv->sspd[phy_id]; + arp1394->fifo_hi = htons (priv->fifo[phy_id] >> 32); + arp1394->fifo_lo = htonl (priv->fifo[phy_id] & ~0x0); + + return; +} + +/* We need to encapsulate the standard header with our own. We use the + * ethernet header's proto for our own. */ +static inline unsigned int ether1394_encapsulate_prep(unsigned int max_payload, + int proto, + union eth1394_hdr *hdr, + u16 dg_size, u16 dgl) +{ + unsigned int adj_max_payload = max_payload - hdr_type_len[ETH1394_HDR_LF_UF]; + + /* Does it all fit in one packet? */ + if (dg_size <= adj_max_payload) { + hdr->uf.lf = ETH1394_HDR_LF_UF; + hdr->uf.ether_type = proto; + } else { + hdr->ff.lf = ETH1394_HDR_LF_FF; + hdr->ff.ether_type = proto; + hdr->ff.dg_size = dg_size - 1; + hdr->ff.dgl = dgl; + adj_max_payload = max_payload - hdr_type_len[ETH1394_HDR_LF_FF]; + } + return((dg_size + (adj_max_payload - 1)) / adj_max_payload); +} + +static inline unsigned int ether1394_encapsulate(struct sk_buff *skb, + unsigned int max_payload, + union eth1394_hdr *hdr) +{ + union eth1394_hdr *bufhdr; + int ftype = hdr->common.lf; + int hdrsz = hdr_type_len[ftype]; + unsigned int adj_max_payload = max_payload - hdrsz; + + switch(ftype) { + case ETH1394_HDR_LF_UF: + bufhdr = (union eth1394_hdr *)skb_push(skb, hdrsz); + bufhdr->words.word1 = htons(hdr->words.word1); + bufhdr->words.word2 = hdr->words.word2; + break; + + case ETH1394_HDR_LF_FF: + bufhdr = (union eth1394_hdr *)skb_push(skb, hdrsz); + bufhdr->words.word1 = htons(hdr->words.word1); + bufhdr->words.word2 = hdr->words.word2; + bufhdr->words.word3 = htons(hdr->words.word3); + bufhdr->words.word4 = 0; + + /* Set frag type here for future interior fragments */ + hdr->common.lf = ETH1394_HDR_LF_IF; + hdr->sf.fg_off = 0; + break; + + default: + hdr->sf.fg_off += adj_max_payload; + bufhdr = (union eth1394_hdr *)skb_pull(skb, adj_max_payload); + if (max_payload >= skb->len) + hdr->common.lf = ETH1394_HDR_LF_LF; + bufhdr->words.word1 = htons(hdr->words.word1); + bufhdr->words.word2 = htons(hdr->words.word2); + bufhdr->words.word3 = htons(hdr->words.word3); + bufhdr->words.word4 = 0; + } + + return min(max_payload, skb->len); +} + +static inline struct hpsb_packet *ether1394_alloc_common_packet(struct hpsb_host *host) +{ + struct hpsb_packet *p; + + p = alloc_hpsb_packet(0); + if (p) { + p->host = host; + p->data = NULL; + p->generation = get_hpsb_generation(host); + p->type = hpsb_async; + } + return p; +} + +static inline int ether1394_prep_write_packet(struct hpsb_packet *p, + struct hpsb_host *host, + nodeid_t node, u64 addr, + void * data, int tx_len) +{ + p->node_id = node; + p->data = NULL; + + p->tcode = TCODE_WRITEB; + p->header[1] = (host->node_id << 16) | (addr >> 32); + p->header[2] = addr & 0xffffffff; + + p->header_size = 16; + p->expect_response = 1; + + if (hpsb_get_tlabel(p)) { + ETH1394_PRINT_G(KERN_ERR, "No more tlabels left while sending " + "to node " NODE_BUS_FMT "\n", NODE_BUS_ARGS(host, node)); + return -1; + } + p->header[0] = (p->node_id << 16) | (p->tlabel << 10) + | (1 << 8) | (TCODE_WRITEB << 4); + + p->header[3] = tx_len << 16; + p->data_size = tx_len + (tx_len % 4 ? 4 - (tx_len % 4) : 0); + p->data = (quadlet_t*)data; + + return 0; +} + +static inline void ether1394_prep_gasp_packet(struct hpsb_packet *p, + struct eth1394_priv *priv, + struct sk_buff *skb, int length) +{ + p->header_size = 4; + p->tcode = TCODE_STREAM_DATA; + + p->header[0] = (length << 16) | (3 << 14) + | ((priv->broadcast_channel) << 8) + | (TCODE_STREAM_DATA << 4); + p->data_size = length; + p->data = ((quadlet_t*)skb->data) - 2; + p->data[0] = cpu_to_be32((priv->host->node_id << 16) | + ETHER1394_GASP_SPECIFIER_ID_HI); + p->data[1] = cpu_to_be32((ETHER1394_GASP_SPECIFIER_ID_LO << 24) | + ETHER1394_GASP_VERSION); + + /* Setting the node id to ALL_NODES (not LOCAL_BUS | ALL_NODES) + * prevents hpsb_send_packet() from setting the speed to an arbitrary + * value based on packet->node_id if packet->node_id is not set. */ + p->node_id = ALL_NODES; + p->speed_code = priv->sspd[ALL_NODES]; +} + +static inline void ether1394_free_packet(struct hpsb_packet *packet) +{ + if (packet->tcode != TCODE_STREAM_DATA) + hpsb_free_tlabel(packet); + packet->data = NULL; + free_hpsb_packet(packet); +} + +static void ether1394_complete_cb(void *__ptask); + +static int ether1394_send_packet(struct packet_task *ptask, unsigned int tx_len) +{ + struct eth1394_priv *priv = ptask->priv; + struct hpsb_packet *packet = NULL; + + packet = ether1394_alloc_common_packet(priv->host); + if (!packet) + return -1; + + if (ptask->tx_type == ETH1394_GASP) { + int length = tx_len + (2 * sizeof(quadlet_t)); + + ether1394_prep_gasp_packet(packet, priv, ptask->skb, length); + } else if (ether1394_prep_write_packet(packet, priv->host, + ptask->dest_node, + ptask->addr, ptask->skb->data, + tx_len)) { + free_hpsb_packet(packet); + return -1; + } + + ptask->packet = packet; + hpsb_set_packet_complete_task(ptask->packet, ether1394_complete_cb, + ptask); + + if (!hpsb_send_packet(packet)) { + ether1394_free_packet(packet); + return -1; + } + + return 0; +} + + +/* Task function to be run when a datagram transmission is completed */ +static inline void ether1394_dg_complete(struct packet_task *ptask, int fail) +{ + struct sk_buff *skb = ptask->skb; + struct net_device *dev = skb->dev; + struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv; + unsigned long flags; + + /* Statistics */ + spin_lock_irqsave(&priv->lock, flags); + if (fail) { + priv->stats.tx_dropped++; + priv->stats.tx_errors++; + } else { + priv->stats.tx_bytes += skb->len; + priv->stats.tx_packets++; + } + spin_unlock_irqrestore(&priv->lock, flags); + + dev_kfree_skb_any(skb); + kmem_cache_free(packet_task_cache, ptask); +} + + +/* Callback for when a packet has been sent and the status of that packet is + * known */ +static void ether1394_complete_cb(void *__ptask) +{ + struct packet_task *ptask = (struct packet_task *)__ptask; + struct hpsb_packet *packet = ptask->packet; + int fail = 0; + + if (packet->tcode != TCODE_STREAM_DATA) + fail = hpsb_packet_success(packet); + + ether1394_free_packet(packet); + + ptask->outstanding_pkts--; + if (ptask->outstanding_pkts > 0 && !fail) + { + int tx_len; + + /* Add the encapsulation header to the fragment */ + tx_len = ether1394_encapsulate(ptask->skb, ptask->max_payload, + &ptask->hdr); + if (ether1394_send_packet(ptask, tx_len)) + ether1394_dg_complete(ptask, 1); + } else { + ether1394_dg_complete(ptask, fail); + } +} + + + +/* Transmit a packet (called by kernel) */ +static int ether1394_tx (struct sk_buff *skb, struct net_device *dev) +{ + int kmflags = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL; + struct eth1394hdr *eth; + struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv; + int proto; + unsigned long flags; + nodeid_t dest_node; + eth1394_tx_type tx_type; + int ret = 0; + unsigned int tx_len; + unsigned int max_payload; + u16 dg_size; + u16 dgl; + struct packet_task *ptask; + struct node_entry *ne; + + ptask = kmem_cache_alloc(packet_task_cache, kmflags); + if (ptask == NULL) { + ret = -ENOMEM; + goto fail; + } + + spin_lock_irqsave (&priv->lock, flags); + if (priv->bc_state == ETHER1394_BC_CLOSED) { + ETH1394_PRINT(KERN_ERR, dev->name, + "Cannot send packet, no broadcast channel available.\n"); + ret = -EAGAIN; + spin_unlock_irqrestore (&priv->lock, flags); + goto fail; + } + + if ((ret = ether1394_init_bc(dev))) { + spin_unlock_irqrestore (&priv->lock, flags); + goto fail; + } + + spin_unlock_irqrestore (&priv->lock, flags); + + if ((skb = skb_share_check (skb, kmflags)) == NULL) { + ret = -ENOMEM; + goto fail; + } + + /* Get rid of the fake eth1394 header, but save a pointer */ + eth = (struct eth1394hdr*)skb->data; + skb_pull(skb, ETH1394_HLEN); + + ne = hpsb_guid_get_entry(be64_to_cpu(*(u64*)eth->h_dest)); + if (!ne) + dest_node = LOCAL_BUS | ALL_NODES; + else + dest_node = ne->nodeid; + + proto = eth->h_proto; + + /* If this is an ARP packet, convert it */ + if (proto == __constant_htons (ETH_P_ARP)) + ether1394_arp_to_1394arp (skb, dev); + + max_payload = priv->maxpayload[NODEID_TO_NODE(dest_node)]; + + /* This check should be unnecessary, but we'll keep it for safety for + * a while longer. */ + if (max_payload < 512) { + ETH1394_PRINT(KERN_WARNING, dev->name, + "max_payload too small: %d (setting to 512)\n", + max_payload); + max_payload = 512; + } + + /* Set the transmission type for the packet. ARP packets and IP + * broadcast packets are sent via GASP. */ + if (memcmp(eth->h_dest, dev->broadcast, ETH1394_ALEN) == 0 || + proto == __constant_htons(ETH_P_ARP) || + (proto == __constant_htons(ETH_P_IP) && + IN_MULTICAST(__constant_ntohl(skb->nh.iph->daddr)))) { + tx_type = ETH1394_GASP; + max_payload -= ETHER1394_GASP_OVERHEAD; + } else { + tx_type = ETH1394_WRREQ; + } + + dg_size = skb->len; + + spin_lock_irqsave (&priv->lock, flags); + dgl = priv->dgl[NODEID_TO_NODE(dest_node)]; + if (max_payload < dg_size + hdr_type_len[ETH1394_HDR_LF_UF]) + priv->dgl[NODEID_TO_NODE(dest_node)]++; + spin_unlock_irqrestore (&priv->lock, flags); + + ptask->hdr.words.word1 = 0; + ptask->hdr.words.word2 = 0; + ptask->hdr.words.word3 = 0; + ptask->hdr.words.word4 = 0; + ptask->skb = skb; + ptask->priv = priv; + ptask->tx_type = tx_type; + + if (tx_type != ETH1394_GASP) { + u64 addr; + + /* This test is just temporary until ConfigROM support has + * been added to eth1394. Until then, we need an ARP packet + * after a bus reset from the current destination node so that + * we can get FIFO information. */ + if (priv->fifo[NODEID_TO_NODE(dest_node)] == 0ULL) { + ret = -EAGAIN; + goto fail; + } + + spin_lock_irqsave(&priv->lock, flags); + addr = priv->fifo[NODEID_TO_NODE(dest_node)]; + spin_unlock_irqrestore(&priv->lock, flags); + + ptask->addr = addr; + ptask->dest_node = dest_node; + } + + ptask->tx_type = tx_type; + ptask->max_payload = max_payload; + ptask->outstanding_pkts = ether1394_encapsulate_prep(max_payload, proto, + &ptask->hdr, dg_size, + dgl); + + /* Add the encapsulation header to the fragment */ + tx_len = ether1394_encapsulate(skb, max_payload, &ptask->hdr); + dev->trans_start = jiffies; + if (ether1394_send_packet(ptask, tx_len)) + goto fail; + + netif_wake_queue(dev); + return 0; +fail: + if (ptask) + kmem_cache_free(packet_task_cache, ptask); + + if (skb != NULL) + dev_kfree_skb(skb); + + spin_lock_irqsave (&priv->lock, flags); + priv->stats.tx_dropped++; + priv->stats.tx_errors++; + spin_unlock_irqrestore (&priv->lock, flags); + + if (netif_queue_stopped(dev)) + netif_wake_queue(dev); + + return 0; /* returning non-zero causes serious problems */ +} + +static int ether1394_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + switch(cmd) { + case SIOCETHTOOL: + return ether1394_ethtool_ioctl(dev, (void *) ifr->ifr_data); + + case SIOCGMIIPHY: /* Get address of MII PHY in use. */ + case SIOCGMIIREG: /* Read MII PHY register. */ + case SIOCSMIIREG: /* Write MII PHY register. */ + default: + return -EOPNOTSUPP; + } + + return 0; +} + +static int ether1394_ethtool_ioctl(struct net_device *dev, void *useraddr) +{ + u32 ethcmd; + + if (get_user(ethcmd, (u32 *)useraddr)) + return -EFAULT; + + switch (ethcmd) { + case ETHTOOL_GDRVINFO: { + struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; + strcpy (info.driver, driver_name); + strcpy (info.version, "$Rev$"); + /* FIXME XXX provide sane businfo */ + strcpy (info.bus_info, "ieee1394"); + if (copy_to_user (useraddr, &info, sizeof (info))) + return -EFAULT; + break; + } + case ETHTOOL_GSET: + case ETHTOOL_SSET: + case ETHTOOL_NWAY_RST: + case ETHTOOL_GLINK: + case ETHTOOL_GMSGLVL: + case ETHTOOL_SMSGLVL: + default: + return -EOPNOTSUPP; + } + + return 0; +} + +/* Function for incoming 1394 packets */ +static struct hpsb_address_ops addr_ops = { + .write = ether1394_write, +}; + +/* Ieee1394 highlevel driver functions */ +static struct hpsb_highlevel eth1394_highlevel = { + .name = driver_name, + .add_host = ether1394_add_host, + .remove_host = ether1394_remove_host, + .host_reset = ether1394_host_reset, +}; + +static int __init ether1394_init_module (void) +{ + packet_task_cache = kmem_cache_create("packet_task", sizeof(struct packet_task), + 0, 0, NULL, NULL); + + /* Register ourselves as a highlevel driver */ + hpsb_register_highlevel(ð1394_highlevel); + + hpsb_register_addrspace(ð1394_highlevel, &addr_ops, ETHER1394_REGION_ADDR, + ETHER1394_REGION_ADDR_END); + + return 0; +} + +static void __exit ether1394_exit_module (void) +{ + hpsb_unregister_highlevel(ð1394_highlevel); + kmem_cache_destroy(packet_task_cache); +} + +module_init(ether1394_init_module); +module_exit(ether1394_exit_module); diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/eth1394.h.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/eth1394.h.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/eth1394.h.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/eth1394.h.svn-base 2003-08-02 02:45:12.000000000 +0200 @@ -0,0 +1,234 @@ +/* + * eth1394.h -- Ethernet driver for Linux IEEE-1394 Subsystem + * + * Copyright (C) 2000 Bonin Franck + * (C) 2001 Ben Collins + * + * Mainly based on work by Emanuel Pirker and Andreas E. Bombe + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __ETH1394_H +#define __ETH1394_H + +#include "ieee1394.h" + +/* Register for incoming packets. This is 4096 bytes, which supports up to + * S3200 (per Table 16-3 of IEEE 1394b-2002). */ +#define ETHER1394_REGION_ADDR_LEN 4096 +#define ETHER1394_REGION_ADDR 0xfffff0200000ULL +#define ETHER1394_REGION_ADDR_END (ETHER1394_REGION_ADDR + ETHER1394_REGION_ADDR_LEN) + +/* GASP identifier numbers for IPv4 over IEEE 1394 */ +#define ETHER1394_GASP_SPECIFIER_ID 0x00005E +#define ETHER1394_GASP_SPECIFIER_ID_HI ((ETHER1394_GASP_SPECIFIER_ID >> 8) & 0xffff) +#define ETHER1394_GASP_SPECIFIER_ID_LO (ETHER1394_GASP_SPECIFIER_ID & 0xff) +#define ETHER1394_GASP_VERSION 1 + +#define ETHER1394_GASP_OVERHEAD (2 * sizeof(quadlet_t)) /* GASP header overhead */ + +/* Node set == 64 */ +#define NODE_SET (ALL_NODES + 1) + +enum eth1394_bc_states { ETHER1394_BC_CLOSED, ETHER1394_BC_OPENED, + ETHER1394_BC_CHECK }; + +struct pdg_list { + struct list_head list; /* partial datagram list per node */ + unsigned int sz; /* partial datagram list size per node */ + spinlock_t lock; /* partial datagram lock */ +}; + +/* Private structure for our ethernet driver */ +struct eth1394_priv { + struct net_device_stats stats; /* Device stats */ + struct hpsb_host *host; /* The card for this dev */ + u16 maxpayload[NODE_SET]; /* Max payload per node */ + unsigned char sspd[NODE_SET]; /* Max speed per node */ + u64 fifo[ALL_NODES]; /* FIFO offset per node */ + u64 eui[ALL_NODES]; /* EUI-64 per node */ + spinlock_t lock; /* Private lock */ + int broadcast_channel; /* Async stream Broadcast Channel */ + enum eth1394_bc_states bc_state; /* broadcast channel state */ + struct hpsb_iso *iso; /* Async stream recv handle */ + struct pdg_list pdg[ALL_NODES]; /* partial RX datagram lists */ + int dgl[NODE_SET]; /* Outgoing datagram label per node */ +}; + +struct host_info { + struct hpsb_host *host; + struct net_device *dev; +}; + + +/* Define a fake hardware header format for the networking core. Note that + * header size cannot exceed 16 bytes as that is the size of the header cache. + * Also, we do not need the source address in the header so we omit it and + * keep the header to under 16 bytes */ +#define ETH1394_ALEN (8) +#define ETH1394_HLEN (10) + +struct eth1394hdr { + unsigned char h_dest[ETH1394_ALEN]; /* destination eth1394 addr */ + unsigned short h_proto; /* packet type ID field */ +} __attribute__((packed)); + + + +typedef enum {ETH1394_GASP, ETH1394_WRREQ} eth1394_tx_type; + +/* IP1394 headers */ +#include + +/* Unfragmented */ +#if defined __BIG_ENDIAN_BITFIELD +struct eth1394_uf_hdr { + u16 lf:2; + u16 res:14; + u16 ether_type; /* Ethernet packet type */ +} __attribute__((packed)); +#elif defined __LITTLE_ENDIAN_BITFIELD +struct eth1394_uf_hdr { + u16 res:14; + u16 lf:2; + u16 ether_type; +} __attribute__((packed)); +#else +#error Unknown bit field type +#endif + +/* First fragment */ +#if defined __BIG_ENDIAN_BITFIELD +struct eth1394_ff_hdr { + u16 lf:2; + u16 res1:2; + u16 dg_size:12; /* Datagram size */ + u16 ether_type; /* Ethernet packet type */ + u16 dgl; /* Datagram label */ + u16 res2; +} __attribute__((packed)); +#elif defined __LITTLE_ENDIAN_BITFIELD +struct eth1394_ff_hdr { + u16 dg_size:12; + u16 res1:2; + u16 lf:2; + u16 ether_type; + u16 dgl; + u16 res2; +} __attribute__((packed)); +#else +#error Unknown bit field type +#endif + +/* XXX: Subsequent fragments, including last */ +#if defined __BIG_ENDIAN_BITFIELD +struct eth1394_sf_hdr { + u16 lf:2; + u16 res1:2; + u16 dg_size:12; /* Datagram size */ + u16 res2:4; + u16 fg_off:12; /* Fragment offset */ + u16 dgl; /* Datagram label */ + u16 res3; +} __attribute__((packed)); +#elif defined __LITTLE_ENDIAN_BITFIELD +struct eth1394_sf_hdr { + u16 dg_size:12; + u16 res1:2; + u16 lf:2; + u16 fg_off:12; + u16 res2:4; + u16 dgl; + u16 res3; +} __attribute__((packed)); +#else +#error Unknown bit field type +#endif + +#if defined __BIG_ENDIAN_BITFIELD +struct eth1394_common_hdr { + u16 lf:2; + u16 pad1:14; +} __attribute__((packed)); +#elif defined __LITTLE_ENDIAN_BITFIELD +struct eth1394_common_hdr { + u16 pad1:14; + u16 lf:2; +} __attribute__((packed)); +#else +#error Unknown bit field type +#endif + +struct eth1394_hdr_words { + u16 word1; + u16 word2; + u16 word3; + u16 word4; +}; + +union eth1394_hdr { + struct eth1394_common_hdr common; + struct eth1394_uf_hdr uf; + struct eth1394_ff_hdr ff; + struct eth1394_sf_hdr sf; + struct eth1394_hdr_words words; +}; + +/* End of IP1394 headers */ + +/* Fragment types */ +#define ETH1394_HDR_LF_UF 0 /* unfragmented */ +#define ETH1394_HDR_LF_FF 1 /* first fragment */ +#define ETH1394_HDR_LF_LF 2 /* last fragment */ +#define ETH1394_HDR_LF_IF 3 /* interior fragment */ + +#define IP1394_HW_ADDR_LEN 16 /* As per RFC */ + +/* Our arp packet (ARPHRD_IEEE1394) */ +struct eth1394_arp { + u16 hw_type; /* 0x0018 */ + u16 proto_type; /* 0x0806 */ + u8 hw_addr_len; /* 16 */ + u8 ip_addr_len; /* 4 */ + u16 opcode; /* ARP Opcode */ + /* Above is exactly the same format as struct arphdr */ + + u64 s_uniq_id; /* Sender's 64bit EUI */ + u8 max_rec; /* Sender's max packet size */ + u8 sspd; /* Sender's max speed */ + u16 fifo_hi; /* hi 16bits of sender's FIFO addr */ + u32 fifo_lo; /* lo 32bits of sender's FIFO addr */ + u32 sip; /* Sender's IP Address */ + u32 tip; /* IP Address of requested hw addr */ +}; + +/* Network timeout */ +#define ETHER1394_TIMEOUT 100000 + +/* This is our task struct. It's used for the packet complete callback. */ +struct packet_task { + struct sk_buff *skb; + int outstanding_pkts; + eth1394_tx_type tx_type; + int max_payload; + struct hpsb_packet *packet; + struct eth1394_priv *priv; + union eth1394_hdr hdr; + u64 addr; + u16 dest_node; +}; + +#endif /* __ETH1394_H */ diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/highlevel.c.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/highlevel.c.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/highlevel.c.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/highlevel.c.svn-base 2003-07-27 22:04:43.000000000 +0200 @@ -0,0 +1,653 @@ +/* + * IEEE 1394 for Linux + * + * Copyright (C) 1999 Andreas E. Bombe + * + * This code is licensed under the GPL. See the file COPYING in the root + * directory of the kernel sources for details. + * + * + * Contributions: + * + * Christian Toegel + * unregister address space + * + * Manfred Weihs + * unregister address space + * + */ + +#include +#include +#include + +#include "ieee1394.h" +#include "ieee1394_types.h" +#include "hosts.h" +#include "ieee1394_core.h" +#include "highlevel.h" + + +struct hl_host_info { + struct list_head list; + struct hpsb_host *host; + size_t size; + unsigned long key; + void *data; +}; + + +static LIST_HEAD(hl_drivers); +static rwlock_t hl_drivers_lock = RW_LOCK_UNLOCKED; + +static LIST_HEAD(addr_space); +static rwlock_t addr_space_lock = RW_LOCK_UNLOCKED; + +/* addr_space list will have zero and max already included as bounds */ +static struct hpsb_address_ops dummy_ops = { NULL, NULL, NULL, NULL }; +static struct hpsb_address_serve dummy_zero_addr, dummy_max_addr; + + +static struct hl_host_info *hl_get_hostinfo(struct hpsb_highlevel *hl, + struct hpsb_host *host) +{ + struct hl_host_info *hi = NULL; + struct list_head *lh; + + if (!hl || !host) + return NULL; + + read_lock(&hl->host_info_lock); + list_for_each (lh, &hl->host_info_list) { + hi = list_entry(lh, struct hl_host_info, list); + if (hi->host == host) + break; + hi = NULL; + } + read_unlock(&hl->host_info_lock); + + return hi; +} + + +/* Returns a per host/driver data structure that was previously stored by + * hpsb_create_hostinfo. */ +void *hpsb_get_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host) +{ + struct hl_host_info *hi = hl_get_hostinfo(hl, host); + + if (hi) + return hi->data; + + return NULL; +} + + +/* If size is zero, then the return here is only valid for error checking */ +void *hpsb_create_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host, + size_t data_size) +{ + struct hl_host_info *hi; + void *data; + unsigned long flags; + + hi = hl_get_hostinfo(hl, host); + if (hi) { + HPSB_ERR("%s called hpsb_create_hostinfo when hostinfo already exists", + hl->name); + return NULL; + } + + hi = kmalloc(sizeof(*hi) + data_size, GFP_KERNEL); + if (!hi) + return NULL; + + memset(hi, 0, sizeof(*hi) + data_size); + + if (data_size) { + data = hi->data = hi + 1; + hi->size = data_size; + } else + data = hi; + + hi->host = host; + + write_lock_irqsave(&hl->host_info_lock, flags); + list_add_tail(&hi->list, &hl->host_info_list); + write_unlock_irqrestore(&hl->host_info_lock, flags); + + return data; +} + + +int hpsb_set_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host, + void *data) +{ + struct hl_host_info *hi; + + hi = hl_get_hostinfo(hl, host); + if (hi) { + if (!hi->size && !hi->data) { + hi->data = data; + return 0; + } else + HPSB_ERR("%s called hpsb_set_hostinfo when hostinfo already has data", + hl->name); + } else + HPSB_ERR("%s called hpsb_set_hostinfo when no hostinfo exists", + hl->name); + + return -EINVAL; +} + + +void hpsb_destroy_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host) +{ + struct hl_host_info *hi; + + hi = hl_get_hostinfo(hl, host); + if (hi) { + unsigned long flags; + write_lock_irqsave(&hl->host_info_lock, flags); + list_del(&hi->list); + write_unlock_irqrestore(&hl->host_info_lock, flags); + kfree(hi); + } + + return; +} + + +void hpsb_set_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host, unsigned long key) +{ + struct hl_host_info *hi; + + hi = hl_get_hostinfo(hl, host); + if (hi) + hi->key = key; + + return; +} + + +unsigned long hpsb_get_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host) +{ + struct hl_host_info *hi; + + hi = hl_get_hostinfo(hl, host); + if (hi) + return hi->key; + + return 0; +} + + +void *hpsb_get_hostinfo_bykey(struct hpsb_highlevel *hl, unsigned long key) +{ + struct list_head *lh; + struct hl_host_info *hi; + void *data = NULL; + + if (!hl) + return NULL; + + read_lock(&hl->host_info_lock); + list_for_each (lh, &hl->host_info_list) { + hi = list_entry(lh, struct hl_host_info, list); + if (hi->key == key) { + data = hi->data; + break; + } + } + read_unlock(&hl->host_info_lock); + + return data; +} + + +struct hpsb_host *hpsb_get_host_bykey(struct hpsb_highlevel *hl, unsigned long key) +{ + struct list_head *lh; + struct hl_host_info *hi; + struct hpsb_host *host = NULL; + + if (!hl) + return NULL; + + read_lock(&hl->host_info_lock); + list_for_each (lh, &hl->host_info_list) { + hi = list_entry(lh, struct hl_host_info, list); + if (hi->key == key) { + host = hi->host; + break; + } + } + read_unlock(&hl->host_info_lock); + + return host; +} + + +void hpsb_register_highlevel(struct hpsb_highlevel *hl) +{ + struct list_head *lh; + unsigned long flags; + + INIT_LIST_HEAD(&hl->addr_list); + INIT_LIST_HEAD(&hl->host_info_list); + + rwlock_init(&hl->host_info_lock); + + write_lock_irqsave(&hl_drivers_lock, flags); + list_add_tail(&hl->hl_list, &hl_drivers); + write_unlock_irqrestore(&hl_drivers_lock, flags); + + if (hl->add_host) { + down(&hpsb_hosts_lock); + list_for_each (lh, &hpsb_hosts) { + struct hpsb_host *host = list_entry(lh, struct hpsb_host, host_list); + hl->add_host(host); + } + up(&hpsb_hosts_lock); + } + + return; +} + +void hpsb_unregister_highlevel(struct hpsb_highlevel *hl) +{ + struct list_head *lh, *next; + struct hpsb_address_serve *as; + unsigned long flags; + + write_lock_irqsave(&addr_space_lock, flags); + list_for_each_safe (lh, next, &hl->addr_list) { + as = list_entry(lh, struct hpsb_address_serve, addr_list); + list_del(&as->as_list); + kfree(as); + } + write_unlock_irqrestore(&addr_space_lock, flags); + + write_lock_irqsave(&hl_drivers_lock, flags); + list_del(&hl->hl_list); + write_unlock_irqrestore(&hl_drivers_lock, flags); + + if (hl->remove_host) { + down(&hpsb_hosts_lock); + list_for_each(lh, &hpsb_hosts) { + struct hpsb_host *host = list_entry(lh, struct hpsb_host, host_list); + + hl->remove_host(host); + hpsb_destroy_hostinfo(hl, host); + } + up(&hpsb_hosts_lock); + } +} + +int hpsb_register_addrspace(struct hpsb_highlevel *hl, + struct hpsb_address_ops *ops, u64 start, u64 end) +{ + struct hpsb_address_serve *as; + struct list_head *entry; + int retval = 0; + unsigned long flags; + + if (((start|end) & 3) || (start >= end) || (end > 0x1000000000000ULL)) { + HPSB_ERR("%s called with invalid addresses", __FUNCTION__); + return 0; + } + + as = (struct hpsb_address_serve *) + kmalloc(sizeof(struct hpsb_address_serve), GFP_KERNEL); + if (as == NULL) { + return 0; + } + + INIT_LIST_HEAD(&as->as_list); + INIT_LIST_HEAD(&as->addr_list); + as->op = ops; + as->start = start; + as->end = end; + + write_lock_irqsave(&addr_space_lock, flags); + entry = addr_space.next; + + while (list_entry(entry, struct hpsb_address_serve, as_list)->end + <= start) { + if (list_entry(entry->next, struct hpsb_address_serve, as_list) + ->start >= end) { + list_add(&as->as_list, entry); + list_add_tail(&as->addr_list, &hl->addr_list); + retval = 1; + break; + } + entry = entry->next; + } + write_unlock_irqrestore(&addr_space_lock, flags); + + if (retval == 0) { + kfree(as); + } + + return retval; +} + +int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, u64 start) +{ + int retval = 0; + struct hpsb_address_serve *as; + struct list_head *entry; + unsigned long flags; + + write_lock_irqsave(&addr_space_lock, flags); + + entry = hl->addr_list.next; + + while (entry != &hl->addr_list) { + as = list_entry(entry, struct hpsb_address_serve, addr_list); + entry = entry->next; + if (as->start == start) { + list_del(&as->as_list); + list_del(&as->addr_list); + kfree(as); + retval = 1; + break; + } + } + + write_unlock_irqrestore(&addr_space_lock, flags); + + return retval; +} + +int hpsb_listen_channel(struct hpsb_highlevel *hl, struct hpsb_host *host, + unsigned int channel) +{ + if (channel > 63) { + HPSB_ERR("%s called with invalid channel", __FUNCTION__); + return -EINVAL; + } + + if (host->iso_listen_count[channel]++ == 0) { + return host->driver->devctl(host, ISO_LISTEN_CHANNEL, channel); + } + + return 0; +} + +void hpsb_unlisten_channel(struct hpsb_highlevel *hl, struct hpsb_host *host, + unsigned int channel) +{ + if (channel > 63) { + HPSB_ERR("%s called with invalid channel", __FUNCTION__); + return; + } + + if (--host->iso_listen_count[channel] == 0) { + host->driver->devctl(host, ISO_UNLISTEN_CHANNEL, channel); + } +} + + +void highlevel_add_host(struct hpsb_host *host) +{ + struct list_head *entry; + struct hpsb_highlevel *hl; + + read_lock(&hl_drivers_lock); + list_for_each(entry, &hl_drivers) { + hl = list_entry(entry, struct hpsb_highlevel, hl_list); + if (hl->add_host) + hl->add_host(host); + } + read_unlock(&hl_drivers_lock); +} + +void highlevel_remove_host(struct hpsb_host *host) +{ + struct list_head *entry; + struct hpsb_highlevel *hl; + + read_lock(&hl_drivers_lock); + list_for_each(entry, &hl_drivers) { + hl = list_entry(entry, struct hpsb_highlevel, hl_list); + + if (hl->remove_host) { + hl->remove_host(host); + hpsb_destroy_hostinfo(hl, host); + } + } + read_unlock(&hl_drivers_lock); +} + +void highlevel_host_reset(struct hpsb_host *host) +{ + struct list_head *entry; + struct hpsb_highlevel *hl; + + read_lock(&hl_drivers_lock); + list_for_each(entry, &hl_drivers) { + hl = list_entry(entry, struct hpsb_highlevel, hl_list); + + if (hl->host_reset) + hl->host_reset(host); + } + read_unlock(&hl_drivers_lock); +} + +void highlevel_iso_receive(struct hpsb_host *host, void *data, + size_t length) +{ + struct list_head *entry; + struct hpsb_highlevel *hl; + int channel = (((quadlet_t *)data)[0] >> 8) & 0x3f; + + read_lock(&hl_drivers_lock); + entry = hl_drivers.next; + + while (entry != &hl_drivers) { + hl = list_entry(entry, struct hpsb_highlevel, hl_list); + if (hl->iso_receive) { + hl->iso_receive(host, channel, data, length); + } + entry = entry->next; + } + read_unlock(&hl_drivers_lock); +} + +void highlevel_fcp_request(struct hpsb_host *host, int nodeid, int direction, + void *data, size_t length) +{ + struct list_head *entry; + struct hpsb_highlevel *hl; + int cts = ((quadlet_t *)data)[0] >> 4; + + read_lock(&hl_drivers_lock); + entry = hl_drivers.next; + + while (entry != &hl_drivers) { + hl = list_entry(entry, struct hpsb_highlevel, hl_list); + if (hl->fcp_request) { + hl->fcp_request(host, nodeid, direction, cts, data, + length); + } + entry = entry->next; + } + read_unlock(&hl_drivers_lock); +} + +int highlevel_read(struct hpsb_host *host, int nodeid, void *data, + u64 addr, unsigned int length, u16 flags) +{ + struct hpsb_address_serve *as; + struct list_head *entry; + unsigned int partlength; + int rcode = RCODE_ADDRESS_ERROR; + + read_lock(&addr_space_lock); + + entry = addr_space.next; + as = list_entry(entry, struct hpsb_address_serve, as_list); + + while (as->start <= addr) { + if (as->end > addr) { + partlength = min(as->end - addr, (u64) length); + + if (as->op->read) { + rcode = as->op->read(host, nodeid, data, + addr, partlength, flags); + } else { + rcode = RCODE_TYPE_ERROR; + } + + (u8 *)data += partlength; + length -= partlength; + addr += partlength; + + if ((rcode != RCODE_COMPLETE) || !length) { + break; + } + } + + entry = entry->next; + as = list_entry(entry, struct hpsb_address_serve, as_list); + } + + read_unlock(&addr_space_lock); + + if (length && (rcode == RCODE_COMPLETE)) { + rcode = RCODE_ADDRESS_ERROR; + } + + return rcode; +} + +int highlevel_write(struct hpsb_host *host, int nodeid, int destid, + void *data, u64 addr, unsigned int length, u16 flags) +{ + struct hpsb_address_serve *as; + struct list_head *entry; + unsigned int partlength; + int rcode = RCODE_ADDRESS_ERROR; + + read_lock(&addr_space_lock); + + entry = addr_space.next; + as = list_entry(entry, struct hpsb_address_serve, as_list); + + while (as->start <= addr) { + if (as->end > addr) { + partlength = min(as->end - addr, (u64) length); + + if (as->op->write) { + rcode = as->op->write(host, nodeid, destid, + data, addr, partlength, flags); + } else { + rcode = RCODE_TYPE_ERROR; + } + + (u8 *)data += partlength; + length -= partlength; + addr += partlength; + + if ((rcode != RCODE_COMPLETE) || !length) { + break; + } + } + + entry = entry->next; + as = list_entry(entry, struct hpsb_address_serve, as_list); + } + + read_unlock(&addr_space_lock); + + if (length && (rcode == RCODE_COMPLETE)) { + rcode = RCODE_ADDRESS_ERROR; + } + + return rcode; +} + + +int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store, + u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode, u16 flags) +{ + struct hpsb_address_serve *as; + struct list_head *entry; + int rcode = RCODE_ADDRESS_ERROR; + + read_lock(&addr_space_lock); + + entry = addr_space.next; + as = list_entry(entry, struct hpsb_address_serve, as_list); + + while (as->start <= addr) { + if (as->end > addr) { + if (as->op->lock) { + rcode = as->op->lock(host, nodeid, store, addr, + data, arg, ext_tcode, flags); + } else { + rcode = RCODE_TYPE_ERROR; + } + + break; + } + + entry = entry->next; + as = list_entry(entry, struct hpsb_address_serve, as_list); + } + + read_unlock(&addr_space_lock); + + return rcode; +} + +int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store, + u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags) +{ + struct hpsb_address_serve *as; + struct list_head *entry; + int rcode = RCODE_ADDRESS_ERROR; + + read_lock(&addr_space_lock); + + entry = addr_space.next; + as = list_entry(entry, struct hpsb_address_serve, as_list); + + while (as->start <= addr) { + if (as->end > addr) { + if (as->op->lock64) { + rcode = as->op->lock64(host, nodeid, store, + addr, data, arg, + ext_tcode, flags); + } else { + rcode = RCODE_TYPE_ERROR; + } + + break; + } + + entry = entry->next; + as = list_entry(entry, struct hpsb_address_serve, as_list); + } + + read_unlock(&addr_space_lock); + + return rcode; +} + +void init_hpsb_highlevel(void) +{ + INIT_LIST_HEAD(&dummy_zero_addr.as_list); + INIT_LIST_HEAD(&dummy_zero_addr.addr_list); + INIT_LIST_HEAD(&dummy_max_addr.as_list); + INIT_LIST_HEAD(&dummy_max_addr.addr_list); + + dummy_zero_addr.op = dummy_max_addr.op = &dummy_ops; + + dummy_zero_addr.start = dummy_zero_addr.end = 0; + dummy_max_addr.start = dummy_max_addr.end = ((u64) 1) << 48; + + list_add_tail(&dummy_zero_addr.as_list, &addr_space); + list_add_tail(&dummy_max_addr.as_list, &addr_space); +} diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/highlevel.h.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/highlevel.h.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/highlevel.h.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/highlevel.h.svn-base 2003-07-27 22:04:44.000000000 +0200 @@ -0,0 +1,182 @@ + +#ifndef IEEE1394_HIGHLEVEL_H +#define IEEE1394_HIGHLEVEL_H + + +struct hpsb_address_serve { + struct list_head as_list; /* global list */ + + struct list_head addr_list; /* hpsb_highlevel list */ + + struct hpsb_address_ops *op; + + /* first address handled and first address behind, quadlet aligned */ + u64 start, end; +}; + + +/* + * The above structs are internal to highlevel driver handling. Only the + * following structures are of interest to actual highlevel drivers. + */ + +struct hpsb_highlevel { + const char *name; + + /* Any of the following pointers can legally be NULL, except for + * iso_receive which can only be NULL when you don't request + * channels. */ + + /* New host initialized. Will also be called during + * hpsb_register_highlevel for all hosts already installed. */ + void (*add_host) (struct hpsb_host *host); + + /* Host about to be removed. Will also be called during + * hpsb_unregister_highlevel once for each host. */ + void (*remove_host) (struct hpsb_host *host); + + /* Host experienced bus reset with possible configuration changes. Note + * that this one may occur during interrupt/bottom half handling. You + * can not expect to be able to do stock hpsb_reads. */ + void (*host_reset) (struct hpsb_host *host); + + /* An isochronous packet was received. Channel contains the channel + * number for your convenience, it is also contained in the included + * packet header (first quadlet, CRCs are missing). You may get called + * for channel/host combinations you did not request. */ + void (*iso_receive) (struct hpsb_host *host, int channel, + quadlet_t *data, size_t length); + + /* A write request was received on either the FCP_COMMAND (direction = + * 0) or the FCP_RESPONSE (direction = 1) register. The cts arg + * contains the cts field (first byte of data). + */ + void (*fcp_request) (struct hpsb_host *host, int nodeid, int direction, + int cts, u8 *data, size_t length); + + + struct list_head hl_list; + struct list_head addr_list; + + struct list_head host_info_list; + rwlock_t host_info_lock; +}; + +struct hpsb_address_ops { + /* + * Null function pointers will make the respective operation complete + * with RCODE_TYPE_ERROR. Makes for easy to implement read-only + * registers (just leave everything but read NULL). + * + * All functions shall return appropriate IEEE 1394 rcodes. + */ + + /* These functions have to implement block reads for themselves. */ + /* These functions either return a response code + or a negative number. In the first case a response will be generated; in the + later case, no response will be sent and the driver, that handled the request + will send the response itself + */ + int (*read) (struct hpsb_host *host, int nodeid, quadlet_t *buffer, + u64 addr, size_t length, u16 flags); + int (*write) (struct hpsb_host *host, int nodeid, int destid, + quadlet_t *data, u64 addr, size_t length, u16 flags); + + /* Lock transactions: write results of ext_tcode operation into + * *store. */ + int (*lock) (struct hpsb_host *host, int nodeid, quadlet_t *store, + u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode, u16 flags); + int (*lock64) (struct hpsb_host *host, int nodeid, octlet_t *store, + u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags); +}; + + +void init_hpsb_highlevel(void); + +void highlevel_add_host(struct hpsb_host *host); +void highlevel_remove_host(struct hpsb_host *host); +void highlevel_host_reset(struct hpsb_host *host); + + +/* these functions are called to handle transactions. They are called, when + a packet arrives. The flags argument contains the second word of the first header + quadlet of the incoming packet (containing transaction label, retry code, + transaction code and priority). These functions either return a response code + or a negative number. In the first case a response will be generated; in the + later case, no response will be sent and the driver, that handled the request + will send the response itself. +*/ +int highlevel_read(struct hpsb_host *host, int nodeid, void *data, + u64 addr, unsigned int length, u16 flags); +int highlevel_write(struct hpsb_host *host, int nodeid, int destid, + void *data, u64 addr, unsigned int length, u16 flags); +int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store, + u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode, u16 flags); +int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store, + u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags); + +void highlevel_iso_receive(struct hpsb_host *host, void *data, + size_t length); +void highlevel_fcp_request(struct hpsb_host *host, int nodeid, int direction, + void *data, size_t length); + + +/* + * Register highlevel driver. The name pointer has to stay valid at all times + * because the string is not copied. + */ +void hpsb_register_highlevel(struct hpsb_highlevel *hl); +void hpsb_unregister_highlevel(struct hpsb_highlevel *hl); + +/* + * Register handlers for host address spaces. Start and end are 48 bit pointers + * and have to be quadlet aligned (end points to the first address behind the + * handled addresses. This function can be called multiple times for a single + * hpsb_highlevel to implement sparse register sets. The requested region must + * not overlap any previously allocated region, otherwise registering will fail. + * + * It returns true for successful allocation. There is no unregister function, + * all address spaces are deallocated together with the hpsb_highlevel. + */ +int hpsb_register_addrspace(struct hpsb_highlevel *hl, + struct hpsb_address_ops *ops, u64 start, u64 end); + +int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, u64 start); + +/* + * Enable or disable receving a certain isochronous channel through the + * iso_receive op. + */ +int hpsb_listen_channel(struct hpsb_highlevel *hl, struct hpsb_host *host, + unsigned int channel); +void hpsb_unlisten_channel(struct hpsb_highlevel *hl, struct hpsb_host *host, + unsigned int channel); + + +/* Retrieve a hostinfo pointer bound to this driver/host */ +void *hpsb_get_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host); + +/* Allocate a hostinfo pointer of data_size bound to this driver/host */ +void *hpsb_create_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host, + size_t data_size); + +/* Free and remove the hostinfo pointer bound to this driver/host */ +void hpsb_destroy_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host); + +/* Set an alternate lookup key for the hostinfo bound to this driver/host */ +void hpsb_set_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host, unsigned long key); + +/* Retrieve the alternate lookup key for the hostinfo bound to this driver/host */ +unsigned long hpsb_get_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host); + +/* Retrieve a hostinfo pointer bound to this driver using its alternate key */ +void *hpsb_get_hostinfo_bykey(struct hpsb_highlevel *hl, unsigned long key); + +/* Set the hostinfo pointer to something useful. Usually follows a call to + * hpsb_create_hostinfo, where the size is 0. */ +int hpsb_set_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host, void *data); + +/* Retrieve hpsb_host using a highlevel handle and a key */ +struct hpsb_host *hpsb_get_host_bykey(struct hpsb_highlevel *hl, unsigned long key); + +#endif /* IEEE1394_HIGHLEVEL_H */ diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/hosts.c.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/hosts.c.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/hosts.c.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/hosts.c.svn-base 2003-07-27 22:04:42.000000000 +0200 @@ -0,0 +1,198 @@ +/* + * IEEE 1394 for Linux + * + * Low level (host adapter) management. + * + * Copyright (C) 1999 Andreas E. Bombe + * Copyright (C) 1999 Emanuel Pirker + * + * This code is licensed under the GPL. See the file COPYING in the root + * directory of the kernel sources for details. + */ + +#include +#include +#include +#include +#include + +#include "ieee1394_types.h" +#include "hosts.h" +#include "ieee1394_core.h" +#include "highlevel.h" + +LIST_HEAD(hpsb_hosts); +DECLARE_MUTEX(hpsb_hosts_lock); + +static int dummy_transmit_packet(struct hpsb_host *h, struct hpsb_packet *p) +{ + return 0; +} + +static int dummy_devctl(struct hpsb_host *h, enum devctl_cmd c, int arg) +{ + return -1; +} + +static int dummy_isoctl(struct hpsb_iso *iso, enum isoctl_cmd command, unsigned long arg) +{ + return -1; +} + +static struct hpsb_host_driver dummy_driver = { + .transmit_packet = dummy_transmit_packet, + .devctl = dummy_devctl, + .isoctl = dummy_isoctl +}; + +/** + * hpsb_ref_host - increase reference count for host controller. + * @host: the host controller + * + * Increase the reference count for the specified host controller. + * When holding a reference to a host, the memory allocated for the + * host struct will not be freed and the host is guaranteed to be in a + * consistent state. The driver may be unloaded or the controller may + * be removed (PCMCIA), but the host struct will remain valid. + */ + +int hpsb_ref_host(struct hpsb_host *host) +{ + struct list_head *lh; + int retval = 0; + + down(&hpsb_hosts_lock); + list_for_each(lh, &hpsb_hosts) { + if (host == list_entry(lh, struct hpsb_host, host_list)) { + host->driver->devctl(host, MODIFY_USAGE, 1); + host->refcount++; + retval = 1; + break; + } + } + up(&hpsb_hosts_lock); + + return retval; +} + +/** + * hpsb_unref_host - decrease reference count for host controller. + * @host: the host controller + * + * Decrease the reference count for the specified host controller. + * When the reference count reaches zero, the memory allocated for the + * &hpsb_host will be freed. + */ + +void hpsb_unref_host(struct hpsb_host *host) +{ + host->driver->devctl(host, MODIFY_USAGE, 0); + + down(&hpsb_hosts_lock); + host->refcount--; + + if (!host->refcount && host->is_shutdown) + kfree(host); + up(&hpsb_hosts_lock); +} + +/** + * hpsb_alloc_host - allocate a new host controller. + * @drv: the driver that will manage the host controller + * @extra: number of extra bytes to allocate for the driver + * + * Allocate a &hpsb_host and initialize the general subsystem specific + * fields. If the driver needs to store per host data, as drivers + * usually do, the amount of memory required can be specified by the + * @extra parameter. Once allocated, the driver should initialize the + * driver specific parts, enable the controller and make it available + * to the general subsystem using hpsb_add_host(). + * + * The &hpsb_host is allocated with an single initial reference + * belonging to the driver. Once the driver is done with the struct, + * for example, when the driver is unloaded, it should release this + * reference using hpsb_unref_host(). + * + * Return Value: a pointer to the &hpsb_host if succesful, %NULL if + * no memory was available. + */ + +struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra) +{ + struct hpsb_host *h; + int i; + + h = kmalloc(sizeof(struct hpsb_host) + extra, SLAB_KERNEL); + if (!h) return NULL; + memset(h, 0, sizeof(struct hpsb_host) + extra); + + h->hostdata = h + 1; + h->driver = drv; + h->refcount = 1; + + INIT_LIST_HEAD(&h->pending_packets); + spin_lock_init(&h->pending_pkt_lock); + + for (i = 0; i < ARRAY_SIZE(h->tpool); i++) + HPSB_TPOOL_INIT(&h->tpool[i]); + + atomic_set(&h->generation, 0); + + init_timer(&h->timeout); + h->timeout.data = (unsigned long) h; + h->timeout.function = abort_timedouts; + h->timeout_interval = HZ / 20; // 50ms by default + + h->topology_map = h->csr.topology_map + 3; + h->speed_map = (u8 *)(h->csr.speed_map + 2); + + return h; +} + +static int alloc_hostnum(void) +{ + int hostnum = 0; + + while (1) { + struct list_head *lh; + int found = 0; + + list_for_each(lh, &hpsb_hosts) { + struct hpsb_host *host = list_entry(lh, struct hpsb_host, host_list); + + if (host->id == hostnum) { + found = 1; + break; + } + } + + if (!found) + return hostnum; + + hostnum++; + } + + return 0; +} + +void hpsb_add_host(struct hpsb_host *host) +{ + down(&hpsb_hosts_lock); + host->id = alloc_hostnum(); + list_add_tail(&host->host_list, &hpsb_hosts); + up(&hpsb_hosts_lock); + + highlevel_add_host(host); + host->driver->devctl(host, RESET_BUS, LONG_RESET); +} + +void hpsb_remove_host(struct hpsb_host *host) +{ + down(&hpsb_hosts_lock); + host->is_shutdown = 1; + host->driver = &dummy_driver; + list_del(&host->host_list); + up(&hpsb_hosts_lock); + + highlevel_remove_host(host); +} diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/hosts.h.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/hosts.h.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/hosts.h.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/hosts.h.svn-base 2003-07-27 22:04:42.000000000 +0200 @@ -0,0 +1,239 @@ +#ifndef _IEEE1394_HOSTS_H +#define _IEEE1394_HOSTS_H + +#include +#include +#include +#include + +#include "ieee1394_types.h" +#include "csr.h" + +/* size of the array used to store config rom (in quadlets) + maximum is 0x100. About 0x40 is needed for the default + entries. So 0x80 should provide enough space for additional + directories etc. + Note: All lowlevel drivers are required to allocate at least + this amount of memory for the configuration rom! +*/ +#define CSR_CONFIG_ROM_SIZE 0x100 + +struct hpsb_packet; +struct hpsb_iso; + +struct hpsb_host { + struct list_head host_list; + + void *hostdata; + + atomic_t generation; + + int refcount; + + struct list_head pending_packets; + spinlock_t pending_pkt_lock; + struct timer_list timeout; + unsigned long timeout_interval; + + unsigned char iso_listen_count[64]; + + int node_count; /* number of identified nodes on this bus */ + int selfid_count; /* total number of SelfIDs received */ + int nodes_active; /* number of nodes that are actually active */ + + nodeid_t node_id; /* node ID of this host */ + nodeid_t irm_id; /* ID of this bus' isochronous resource manager */ + nodeid_t busmgr_id; /* ID of this bus' bus manager */ + + /* this nodes state */ + unsigned in_bus_reset:1; + unsigned is_shutdown:1; + + /* this nodes' duties on the bus */ + unsigned is_root:1; + unsigned is_cycmst:1; + unsigned is_irm:1; + unsigned is_busmgr:1; + + int reset_retries; + quadlet_t *topology_map; + u8 *speed_map; + struct csr_control csr; + + /* Per node tlabel pool allocation */ + struct hpsb_tlabel_pool tpool[64]; + + struct hpsb_host_driver *driver; + + struct pci_dev *pdev; + + int id; +}; + + + +enum devctl_cmd { + /* Host is requested to reset its bus and cancel all outstanding async + * requests. If arg == 1, it shall also attempt to become root on the + * bus. Return void. */ + RESET_BUS, + + /* Arg is void, return value is the hardware cycle counter value. */ + GET_CYCLE_COUNTER, + + /* Set the hardware cycle counter to the value in arg, return void. + * FIXME - setting is probably not required. */ + SET_CYCLE_COUNTER, + + /* Configure hardware for new bus ID in arg, return void. */ + SET_BUS_ID, + + /* If arg true, start sending cycle start packets, stop if arg == 0. + * Return void. */ + ACT_CYCLE_MASTER, + + /* Cancel all outstanding async requests without resetting the bus. + * Return void. */ + CANCEL_REQUESTS, + + /* Decrease host usage count if arg == 0, increase otherwise. Return + * 1 for success, 0 for failure. Increase usage may fail if the driver + * is in the process of shutting itself down. Decrease usage can not + * fail. */ + MODIFY_USAGE, + + /* Start or stop receiving isochronous channel in arg. Return void. + * This acts as an optimization hint, hosts are not required not to + * listen on unrequested channels. */ + ISO_LISTEN_CHANNEL, + ISO_UNLISTEN_CHANNEL +}; + +enum isoctl_cmd { + /* rawiso API - see iso.h for the meanings of these commands + (they correspond exactly to the hpsb_iso_* API functions) + * INIT = allocate resources + * START = begin transmission/reception + * STOP = halt transmission/reception + * QUEUE/RELEASE = produce/consume packets + * SHUTDOWN = deallocate resources + */ + + XMIT_INIT, + XMIT_START, + XMIT_STOP, + XMIT_QUEUE, + XMIT_SHUTDOWN, + + RECV_INIT, + RECV_LISTEN_CHANNEL, /* multi-channel only */ + RECV_UNLISTEN_CHANNEL, /* multi-channel only */ + RECV_SET_CHANNEL_MASK, /* multi-channel only; arg is a *u64 */ + RECV_START, + RECV_STOP, + RECV_RELEASE, + RECV_SHUTDOWN, + RECV_FLUSH +}; + +enum reset_types { + /* 166 microsecond reset -- only type of reset available on + non-1394a capable IEEE 1394 controllers */ + LONG_RESET, + + /* Short (arbitrated) reset -- only available on 1394a capable + IEEE 1394 capable controllers */ + SHORT_RESET, + + /* Variants, that set force_root before issueing the bus reset */ + LONG_RESET_FORCE_ROOT, SHORT_RESET_FORCE_ROOT, + + /* Variants, that clear force_root before issueing the bus reset */ + LONG_RESET_NO_FORCE_ROOT, SHORT_RESET_NO_FORCE_ROOT +}; + +struct hpsb_host_driver { + const char *name; + + /* This function must store a pointer to the configuration ROM into the + * location referenced to by pointer and return the size of the ROM. It + * may not fail. If any allocation is required, it must be done + * earlier. + */ + size_t (*get_rom) (struct hpsb_host *host, quadlet_t **pointer); + + /* This function shall implement packet transmission based on + * packet->type. It shall CRC both parts of the packet (unless + * packet->type == raw) and do byte-swapping as necessary or instruct + * the hardware to do so. It can return immediately after the packet + * was queued for sending. After sending, hpsb_sent_packet() has to be + * called. Return 0 for failure. + * NOTE: The function must be callable in interrupt context. + */ + int (*transmit_packet) (struct hpsb_host *host, + struct hpsb_packet *packet); + + /* This function requests miscellanous services from the driver, see + * above for command codes and expected actions. Return -1 for unknown + * command, though that should never happen. + */ + int (*devctl) (struct hpsb_host *host, enum devctl_cmd command, int arg); + + /* ISO transmission/reception functions. Return 0 on success, -1 + * (or -EXXX errno code) on failure. If the low-level driver does not + * support the new ISO API, set isoctl to NULL. + */ + int (*isoctl) (struct hpsb_iso *iso, enum isoctl_cmd command, unsigned long arg); + + /* This function is mainly to redirect local CSR reads/locks to the iso + * management registers (bus manager id, bandwidth available, channels + * available) to the hardware registers in OHCI. reg is 0,1,2,3 for bus + * mgr, bwdth avail, ch avail hi, ch avail lo respectively (the same ids + * as OHCI uses). data and compare are the new data and expected data + * respectively, return value is the old value. + */ + quadlet_t (*hw_csr_reg) (struct hpsb_host *host, int reg, + quadlet_t data, quadlet_t compare); +}; + + +extern struct list_head hpsb_hosts; +extern struct semaphore hpsb_hosts_lock; + + +/* + * In order to prevent hosts from unloading, use hpsb_ref_host(). This prevents + * the host from going away (e.g. makes module unloading of the driver + * impossible), but still can not guarantee it (e.g. PC-Card being pulled by the + * user). hpsb_ref_host() returns false if host could not be locked. If it is + * successful, host is valid as a pointer until hpsb_unref_host() (not just + * until after remove_host). + */ +int hpsb_ref_host(struct hpsb_host *host); +void hpsb_unref_host(struct hpsb_host *host); + +struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra); +void hpsb_add_host(struct hpsb_host *host); +void hpsb_remove_host(struct hpsb_host *h); + +/* updates the configuration rom of a host. + * rom_version must be the current version, + * otherwise it will fail with return value -1. + * Return value -2 indicates that the new + * rom version is too big. + * Return value 0 indicates success + */ +int hpsb_update_config_rom(struct hpsb_host *host, + const quadlet_t *new_rom, size_t size, unsigned char rom_version); + +/* reads the current version of the configuration rom of a host. + * buffersize is the size of the buffer, rom_size + * returns the size of the current rom image. + * rom_version is the version number of the fetched rom. + * return value -1 indicates, that the buffer was + * too small, 0 indicates success. + */ +int hpsb_get_config_rom(struct hpsb_host *host, quadlet_t *buffer, + size_t buffersize, size_t *rom_size, unsigned char *rom_version); + +#endif /* _IEEE1394_HOSTS_H */ diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/ieee1394-ioctl.h.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/ieee1394-ioctl.h.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/ieee1394-ioctl.h.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/ieee1394-ioctl.h.svn-base 2003-09-10 20:28:20.000000000 +0200 @@ -0,0 +1,111 @@ +/* Base file for all ieee1394 ioctl's. Linux-1394 has allocated base '#' + * with a range of 0x00-0x3f. */ + +#ifndef __IEEE1394_IOCTL_H +#define __IEEE1394_IOCTL_H + +#include +#include + + +/* AMDTP Gets 6 */ +#define AMDTP_IOC_CHANNEL _IOW('#', 0x00, struct amdtp_ioctl) +#define AMDTP_IOC_PLUG _IOW('#', 0x01, struct amdtp_ioctl) +#define AMDTP_IOC_PING _IOW('#', 0x02, struct amdtp_ioctl) +#define AMDTP_IOC_ZAP _IO ('#', 0x03) + + +/* DV1394 Gets 10 */ + +/* Get the driver ready to transmit video. pass a struct dv1394_init* as + * the parameter (see below), or NULL to get default parameters */ +#define DV1394_IOC_INIT _IOW('#', 0x06, struct dv1394_init) + +/* Stop transmitting video and free the ringbuffer */ +#define DV1394_IOC_SHUTDOWN _IO ('#', 0x07) + +/* Submit N new frames to be transmitted, where the index of the first new + * frame is first_clear_buffer, and the index of the last new frame is + * (first_clear_buffer + N) % n_frames */ +#define DV1394_IOC_SUBMIT_FRAMES _IO ('#', 0x08) + +/* Block until N buffers are clear (pass N as the parameter) Because we + * re-transmit the last frame on underrun, there will at most be n_frames + * - 1 clear frames at any time */ +#define DV1394_IOC_WAIT_FRAMES _IO ('#', 0x09) + +/* Capture new frames that have been received, where the index of the + * first new frame is first_clear_buffer, and the index of the last new + * frame is (first_clear_buffer + N) % n_frames */ +#define DV1394_IOC_RECEIVE_FRAMES _IO ('#', 0x0a) + +/* Tell card to start receiving DMA */ +#define DV1394_IOC_START_RECEIVE _IO ('#', 0x0b) + +/* Pass a struct dv1394_status* as the parameter */ +#define DV1394_IOC_GET_STATUS _IOR('#', 0x0c, struct dv1394_status) + + +/* Video1394 Gets 10 */ + +#define VIDEO1394_IOC_LISTEN_CHANNEL \ + _IOWR('#', 0x10, struct video1394_mmap) +#define VIDEO1394_IOC_UNLISTEN_CHANNEL \ + _IOW ('#', 0x11, int) +#define VIDEO1394_IOC_LISTEN_QUEUE_BUFFER \ + _IOW ('#', 0x12, struct video1394_wait) +#define VIDEO1394_IOC_LISTEN_WAIT_BUFFER \ + _IOWR('#', 0x13, struct video1394_wait) +#define VIDEO1394_IOC_TALK_CHANNEL \ + _IOWR('#', 0x14, struct video1394_mmap) +#define VIDEO1394_IOC_UNTALK_CHANNEL \ + _IOW ('#', 0x15, int) +/* + * This one is broken: it really wanted + * "sizeof (struct video1394_wait) + sizeof (struct video1394_queue_variable)" + * but got just a "size_t" + */ +#define VIDEO1394_IOC_TALK_QUEUE_BUFFER \ + _IOW ('#', 0x16, size_t) +#define VIDEO1394_IOC_TALK_WAIT_BUFFER \ + _IOW ('#', 0x17, struct video1394_wait) +#define VIDEO1394_IOC_LISTEN_POLL_BUFFER \ + _IOWR('#', 0x18, struct video1394_wait) + + +/* Raw1394's ISO interface */ +#define RAW1394_IOC_ISO_XMIT_INIT \ + _IOW ('#', 0x1a, struct raw1394_iso_status) +#define RAW1394_IOC_ISO_RECV_INIT \ + _IOWR('#', 0x1b, struct raw1394_iso_status) +#define RAW1394_IOC_ISO_RECV_START \ + _IOC (_IOC_WRITE, '#', 0x1c, sizeof(int) * 3) +#define RAW1394_IOC_ISO_XMIT_START \ + _IOC (_IOC_WRITE, '#', 0x1d, sizeof(int) * 2) +#define RAW1394_IOC_ISO_XMIT_RECV_STOP \ + _IO ('#', 0x1e) +#define RAW1394_IOC_ISO_GET_STATUS \ + _IOR ('#', 0x1f, struct raw1394_iso_status) +#define RAW1394_IOC_ISO_SHUTDOWN \ + _IO ('#', 0x20) +#define RAW1394_IOC_ISO_QUEUE_ACTIVITY \ + _IO ('#', 0x21) +#define RAW1394_IOC_ISO_RECV_LISTEN_CHANNEL \ + _IOW ('#', 0x22, unsigned char) +#define RAW1394_IOC_ISO_RECV_UNLISTEN_CHANNEL \ + _IOW ('#', 0x23, unsigned char) +#define RAW1394_IOC_ISO_RECV_SET_CHANNEL_MASK \ + _IOW ('#', 0x24, __u64) +#define RAW1394_IOC_ISO_RECV_PACKETS \ + _IOW ('#', 0x25, struct raw1394_iso_packets) +#define RAW1394_IOC_ISO_RECV_RELEASE_PACKETS \ + _IOW ('#', 0x26, unsigned int) +#define RAW1394_IOC_ISO_XMIT_PACKETS \ + _IOW ('#', 0x27, struct raw1394_iso_packets) +#define RAW1394_IOC_ISO_XMIT_SYNC \ + _IO ('#', 0x28) +#define RAW1394_IOC_ISO_RECV_FLUSH \ + _IO ('#', 0x29) + + +#endif /* __IEEE1394_IOCTL_H */ diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/ieee1394.h.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/ieee1394.h.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/ieee1394.h.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/ieee1394.h.svn-base 2003-07-21 13:09:46.000000000 +0200 @@ -0,0 +1,175 @@ +/* + * Generic IEEE 1394 definitions + */ + +#ifndef _IEEE1394_IEEE1394_H +#define _IEEE1394_IEEE1394_H + +#define TCODE_WRITEQ 0x0 +#define TCODE_WRITEB 0x1 +#define TCODE_WRITE_RESPONSE 0x2 +#define TCODE_READQ 0x4 +#define TCODE_READB 0x5 +#define TCODE_READQ_RESPONSE 0x6 +#define TCODE_READB_RESPONSE 0x7 +#define TCODE_CYCLE_START 0x8 +#define TCODE_LOCK_REQUEST 0x9 +#define TCODE_ISO_DATA 0xa +#define TCODE_STREAM_DATA 0xa +#define TCODE_LOCK_RESPONSE 0xb + +#define RCODE_COMPLETE 0x0 +#define RCODE_CONFLICT_ERROR 0x4 +#define RCODE_DATA_ERROR 0x5 +#define RCODE_TYPE_ERROR 0x6 +#define RCODE_ADDRESS_ERROR 0x7 + +#define EXTCODE_MASK_SWAP 0x1 +#define EXTCODE_COMPARE_SWAP 0x2 +#define EXTCODE_FETCH_ADD 0x3 +#define EXTCODE_LITTLE_ADD 0x4 +#define EXTCODE_BOUNDED_ADD 0x5 +#define EXTCODE_WRAP_ADD 0x6 + +#define ACK_COMPLETE 0x1 +#define ACK_PENDING 0x2 +#define ACK_BUSY_X 0x4 +#define ACK_BUSY_A 0x5 +#define ACK_BUSY_B 0x6 +#define ACK_DATA_ERROR 0xd +#define ACK_TYPE_ERROR 0xe + +/* Non-standard "ACK codes" for internal use */ +#define ACKX_NONE (-1) +#define ACKX_SEND_ERROR (-2) +#define ACKX_ABORTED (-3) +#define ACKX_TIMEOUT (-4) + + +#define IEEE1394_SPEED_100 0x00 +#define IEEE1394_SPEED_200 0x01 +#define IEEE1394_SPEED_400 0x02 +#define IEEE1394_SPEED_800 0x03 +#define IEEE1394_SPEED_1600 0x04 +#define IEEE1394_SPEED_3200 0x05 +/* The current highest tested speed supported by the subsystem */ +#define IEEE1394_SPEED_MAX IEEE1394_SPEED_800 + +/* Maps speed values above to a string representation */ +extern const char *hpsb_speedto_str[]; + + +#define SELFID_PWRCL_NO_POWER 0x0 +#define SELFID_PWRCL_PROVIDE_15W 0x1 +#define SELFID_PWRCL_PROVIDE_30W 0x2 +#define SELFID_PWRCL_PROVIDE_45W 0x3 +#define SELFID_PWRCL_USE_1W 0x4 +#define SELFID_PWRCL_USE_3W 0x5 +#define SELFID_PWRCL_USE_6W 0x6 +#define SELFID_PWRCL_USE_10W 0x7 + +#define SELFID_PORT_CHILD 0x3 +#define SELFID_PORT_PARENT 0x2 +#define SELFID_PORT_NCONN 0x1 +#define SELFID_PORT_NONE 0x0 + + +#include + +#ifdef __BIG_ENDIAN_BITFIELD + +struct selfid { + u32 packet_identifier:2; /* always binary 10 */ + u32 phy_id:6; + /* byte */ + u32 extended:1; /* if true is struct ext_selfid */ + u32 link_active:1; + u32 gap_count:6; + /* byte */ + u32 speed:2; + u32 phy_delay:2; + u32 contender:1; + u32 power_class:3; + /* byte */ + u32 port0:2; + u32 port1:2; + u32 port2:2; + u32 initiated_reset:1; + u32 more_packets:1; +} __attribute__((packed)); + +struct ext_selfid { + u32 packet_identifier:2; /* always binary 10 */ + u32 phy_id:6; + /* byte */ + u32 extended:1; /* if false is struct selfid */ + u32 seq_nr:3; + u32 reserved:2; + u32 porta:2; + /* byte */ + u32 portb:2; + u32 portc:2; + u32 portd:2; + u32 porte:2; + /* byte */ + u32 portf:2; + u32 portg:2; + u32 porth:2; + u32 reserved2:1; + u32 more_packets:1; +} __attribute__((packed)); + +#elif defined __LITTLE_ENDIAN_BITFIELD /* __BIG_ENDIAN_BITFIELD */ + +/* + * Note: these mean to be bit fields of a big endian SelfID as seen on a little + * endian machine. Without swapping. + */ + +struct selfid { + u32 phy_id:6; + u32 packet_identifier:2; /* always binary 10 */ + /* byte */ + u32 gap_count:6; + u32 link_active:1; + u32 extended:1; /* if true is struct ext_selfid */ + /* byte */ + u32 power_class:3; + u32 contender:1; + u32 phy_delay:2; + u32 speed:2; + /* byte */ + u32 more_packets:1; + u32 initiated_reset:1; + u32 port2:2; + u32 port1:2; + u32 port0:2; +} __attribute__((packed)); + +struct ext_selfid { + u32 phy_id:6; + u32 packet_identifier:2; /* always binary 10 */ + /* byte */ + u32 porta:2; + u32 reserved:2; + u32 seq_nr:3; + u32 extended:1; /* if false is struct selfid */ + /* byte */ + u32 porte:2; + u32 portd:2; + u32 portc:2; + u32 portb:2; + /* byte */ + u32 more_packets:1; + u32 reserved2:1; + u32 porth:2; + u32 portg:2; + u32 portf:2; +} __attribute__((packed)); + +#else +#error What? PDP endian? +#endif /* __BIG_ENDIAN_BITFIELD */ + + +#endif /* _IEEE1394_IEEE1394_H */ diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/ieee1394_core.c.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/ieee1394_core.c.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/ieee1394_core.c.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/ieee1394_core.c.svn-base 2003-10-12 01:06:13.000000000 +0200 @@ -0,0 +1,1354 @@ +/* + * IEEE 1394 for Linux + * + * Core support: hpsb_packet management, packet handling and forwarding to + * highlevel or lowlevel code + * + * Copyright (C) 1999, 2000 Andreas E. Bombe + * 2002 Manfred Weihs + * + * This code is licensed under the GPL. See the file COPYING in the root + * directory of the kernel sources for details. + * + * + * Contributions: + * + * Manfred Weihs + * loopback functionality in hpsb_send_packet + * allow highlevel drivers to disable automatic response generation + * and to generate responses themselves (deferred) + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ieee1394_types.h" +#include "ieee1394.h" +#include "hosts.h" +#include "ieee1394_core.h" +#include "highlevel.h" +#include "ieee1394_transactions.h" +#include "csr.h" +#include "nodemgr.h" +#include "dma.h" +#include "iso.h" + +/* + * Disable the nodemgr detection and config rom reading functionality. + */ +MODULE_PARM(disable_nodemgr, "i"); +MODULE_PARM_DESC(disable_nodemgr, "Disable nodemgr functionality."); +static int disable_nodemgr = 0; + +/* We are GPL, so treat us special */ +MODULE_LICENSE("GPL"); + +static kmem_cache_t *hpsb_packet_cache; + +/* Some globals used */ +const char *hpsb_speedto_str[] = { "S100", "S200", "S400", "S800", "S1600", "S3200" }; + +#ifdef CONFIG_IEEE1394_VERBOSEDEBUG +static void dump_packet(const char *text, quadlet_t *data, int size) +{ + int i; + + size /= 4; + size = (size > 4 ? 4 : size); + + printk(KERN_DEBUG "ieee1394: %s", text); + for (i = 0; i < size; i++) + printk(" %08x", data[i]); + printk("\n"); +} +#else +#define dump_packet(x,y,z) +#endif + +static void run_packet_complete(struct hpsb_packet *packet) +{ + if (packet->complete_routine != NULL) { + void (*complete_routine)(void*) = packet->complete_routine; + void *complete_data = packet->complete_data; + + packet->complete_routine = NULL; + packet->complete_data = NULL; + complete_routine(complete_data); + } + return; +} + +/** + * hpsb_set_packet_complete_task - set the task that runs when a packet + * completes. You cannot call this more than once on a single packet + * before it is sent. + * + * @packet: the packet whose completion we want the task added to + * @routine: function to call + * @data: data (if any) to pass to the above function + */ +void hpsb_set_packet_complete_task(struct hpsb_packet *packet, + void (*routine)(void *), void *data) +{ + BUG_ON(packet->complete_routine != NULL); + packet->complete_routine = routine; + packet->complete_data = data; + return; +} + +/** + * alloc_hpsb_packet - allocate new packet structure + * @data_size: size of the data block to be allocated + * + * This function allocates, initializes and returns a new &struct hpsb_packet. + * It can be used in interrupt context. A header block is always included, its + * size is big enough to contain all possible 1394 headers. The data block is + * only allocated when @data_size is not zero. + * + * For packets for which responses will be received the @data_size has to be big + * enough to contain the response's data block since no further allocation + * occurs at response matching time. + * + * The packet's generation value will be set to the current generation number + * for ease of use. Remember to overwrite it with your own recorded generation + * number if you can not be sure that your code will not race with a bus reset. + * + * Return value: A pointer to a &struct hpsb_packet or NULL on allocation + * failure. + */ +struct hpsb_packet *alloc_hpsb_packet(size_t data_size) +{ + struct hpsb_packet *packet = NULL; + void *data = NULL; + + packet = kmem_cache_alloc(hpsb_packet_cache, GFP_ATOMIC); + if (packet == NULL) + return NULL; + + memset(packet, 0, sizeof(struct hpsb_packet)); + packet->header = packet->embedded_header; + + if (data_size) { + data = kmalloc(data_size + 8, GFP_ATOMIC); + if (data == NULL) { + kmem_cache_free(hpsb_packet_cache, packet); + return NULL; + } + + packet->data = data; + packet->data_size = data_size; + } + + INIT_LIST_HEAD(&packet->list); + sema_init(&packet->state_change, 0); + packet->complete_routine = NULL; + packet->complete_data = NULL; + packet->state = hpsb_unused; + packet->generation = -1; + packet->data_be = 1; + + return packet; +} + + +/** + * free_hpsb_packet - free packet and data associated with it + * @packet: packet to free (is NULL safe) + * + * This function will free packet->data, packet->header and finally the packet + * itself. + */ +void free_hpsb_packet(struct hpsb_packet *packet) +{ + if (!packet) return; + + kfree(packet->data); + kmem_cache_free(hpsb_packet_cache, packet); +} + + +int hpsb_reset_bus(struct hpsb_host *host, int type) +{ + if (!host->in_bus_reset) { + host->driver->devctl(host, RESET_BUS, type); + return 0; + } else { + return 1; + } +} + + +int hpsb_bus_reset(struct hpsb_host *host) +{ + if (host->in_bus_reset) { + HPSB_NOTICE("%s called while bus reset already in progress", + __FUNCTION__); + return 1; + } + + abort_requests(host); + host->in_bus_reset = 1; + host->irm_id = -1; + host->is_irm = 0; + host->busmgr_id = -1; + host->is_busmgr = 0; + host->is_cycmst = 0; + host->node_count = 0; + host->selfid_count = 0; + + return 0; +} + + +/* + * Verify num_of_selfids SelfIDs and return number of nodes. Return zero in + * case verification failed. + */ +static int check_selfids(struct hpsb_host *host) +{ + int nodeid = -1; + int rest_of_selfids = host->selfid_count; + struct selfid *sid = (struct selfid *)host->topology_map; + struct ext_selfid *esid; + int esid_seq = 23; + + host->nodes_active = 0; + + while (rest_of_selfids--) { + if (!sid->extended) { + nodeid++; + esid_seq = 0; + + if (sid->phy_id != nodeid) { + HPSB_INFO("SelfIDs failed monotony check with " + "%d", sid->phy_id); + return 0; + } + + if (sid->link_active) { + host->nodes_active++; + if (sid->contender) + host->irm_id = LOCAL_BUS | sid->phy_id; + } + } else { + esid = (struct ext_selfid *)sid; + + if ((esid->phy_id != nodeid) + || (esid->seq_nr != esid_seq)) { + HPSB_INFO("SelfIDs failed monotony check with " + "%d/%d", esid->phy_id, esid->seq_nr); + return 0; + } + esid_seq++; + } + sid++; + } + + esid = (struct ext_selfid *)(sid - 1); + while (esid->extended) { + if ((esid->porta == 0x2) || (esid->portb == 0x2) + || (esid->portc == 0x2) || (esid->portd == 0x2) + || (esid->porte == 0x2) || (esid->portf == 0x2) + || (esid->portg == 0x2) || (esid->porth == 0x2)) { + HPSB_INFO("SelfIDs failed root check on " + "extended SelfID"); + return 0; + } + esid--; + } + + sid = (struct selfid *)esid; + if ((sid->port0 == 0x2) || (sid->port1 == 0x2) || (sid->port2 == 0x2)) { + HPSB_INFO("SelfIDs failed root check"); + return 0; + } + + host->node_count = nodeid + 1; + return 1; +} + +static void build_speed_map(struct hpsb_host *host, int nodecount) +{ + u8 speedcap[nodecount]; + u8 cldcnt[nodecount]; + u8 *map = host->speed_map; + struct selfid *sid; + struct ext_selfid *esid; + int i, j, n; + + for (i = 0; i < (nodecount * 64); i += 64) { + for (j = 0; j < nodecount; j++) { + map[i+j] = IEEE1394_SPEED_MAX; + } + } + + for (i = 0; i < nodecount; i++) { + cldcnt[i] = 0; + } + + /* find direct children count and speed */ + for (sid = (struct selfid *)&host->topology_map[host->selfid_count-1], + n = nodecount - 1; + (void *)sid >= (void *)host->topology_map; sid--) { + if (sid->extended) { + esid = (struct ext_selfid *)sid; + + if (esid->porta == 0x3) cldcnt[n]++; + if (esid->portb == 0x3) cldcnt[n]++; + if (esid->portc == 0x3) cldcnt[n]++; + if (esid->portd == 0x3) cldcnt[n]++; + if (esid->porte == 0x3) cldcnt[n]++; + if (esid->portf == 0x3) cldcnt[n]++; + if (esid->portg == 0x3) cldcnt[n]++; + if (esid->porth == 0x3) cldcnt[n]++; + } else { + if (sid->port0 == 0x3) cldcnt[n]++; + if (sid->port1 == 0x3) cldcnt[n]++; + if (sid->port2 == 0x3) cldcnt[n]++; + + speedcap[n] = sid->speed; + n--; + } + } + + /* set self mapping */ + for (i = 0; i < nodecount; i++) { + map[64*i + i] = speedcap[i]; + } + + /* fix up direct children count to total children count; + * also fix up speedcaps for sibling and parent communication */ + for (i = 1; i < nodecount; i++) { + for (j = cldcnt[i], n = i - 1; j > 0; j--) { + cldcnt[i] += cldcnt[n]; + speedcap[n] = min(speedcap[n], speedcap[i]); + n -= cldcnt[n] + 1; + } + } + + for (n = 0; n < nodecount; n++) { + for (i = n - cldcnt[n]; i <= n; i++) { + for (j = 0; j < (n - cldcnt[n]); j++) { + map[j*64 + i] = map[i*64 + j] = + min(map[i*64 + j], speedcap[n]); + } + for (j = n + 1; j < nodecount; j++) { + map[j*64 + i] = map[i*64 + j] = + min(map[i*64 + j], speedcap[n]); + } + } + } +} + + +void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid) +{ + if (host->in_bus_reset) { + HPSB_VERBOSE("Including SelfID 0x%x", sid); + host->topology_map[host->selfid_count++] = sid; + } else { + HPSB_NOTICE("Spurious SelfID packet (0x%08x) received from bus %d", + sid, NODEID_TO_BUS(host->node_id)); + } +} + +void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot) +{ + if (!host->in_bus_reset) + HPSB_NOTICE("SelfID completion called outside of bus reset!"); + + host->node_id = LOCAL_BUS | phyid; + host->is_root = isroot; + + if (!check_selfids(host)) { + if (host->reset_retries++ < 20) { + /* selfid stage did not complete without error */ + HPSB_NOTICE("Error in SelfID stage, resetting"); + host->in_bus_reset = 0; + /* this should work from ohci1394 now... */ + hpsb_reset_bus(host, LONG_RESET); + return; + } else { + HPSB_NOTICE("Stopping out-of-control reset loop"); + HPSB_NOTICE("Warning - topology map and speed map will not be valid"); + host->reset_retries = 0; + } + } else { + host->reset_retries = 0; + build_speed_map(host, host->node_count); + } + + HPSB_VERBOSE("selfid_complete called with successful SelfID stage " + "... irm_id: 0x%X node_id: 0x%X",host->irm_id,host->node_id); + + /* irm_id is kept up to date by check_selfids() */ + if (host->irm_id == host->node_id) { + host->is_irm = 1; + } else { + host->is_busmgr = 0; + host->is_irm = 0; + } + + if (isroot) { + host->driver->devctl(host, ACT_CYCLE_MASTER, 1); + host->is_cycmst = 1; + } + atomic_inc(&host->generation); + host->in_bus_reset = 0; + highlevel_host_reset(host); +} + + +void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet, + int ackcode) +{ + unsigned long flags; + + packet->ack_code = ackcode; + + if (packet->no_waiter) { + /* must not have a tlabel allocated */ + free_hpsb_packet(packet); + return; + } + + if (ackcode != ACK_PENDING || !packet->expect_response) { + packet->state = hpsb_complete; + up(&packet->state_change); + up(&packet->state_change); + run_packet_complete(packet); + return; + } + + packet->state = hpsb_pending; + packet->sendtime = jiffies; + + spin_lock_irqsave(&host->pending_pkt_lock, flags); + list_add_tail(&packet->list, &host->pending_packets); + spin_unlock_irqrestore(&host->pending_pkt_lock, flags); + + up(&packet->state_change); + mod_timer(&host->timeout, jiffies + host->timeout_interval); +} + +/** + * hpsb_send_phy_config - transmit a PHY configuration packet on the bus + * @host: host that PHY config packet gets sent through + * @rootid: root whose force_root bit should get set (-1 = don't set force_root) + * @gapcnt: gap count value to set (-1 = don't set gap count) + * + * This function sends a PHY config packet on the bus through the specified host. + * + * Return value: 0 for success or error number otherwise. + */ +int hpsb_send_phy_config(struct hpsb_host *host, int rootid, int gapcnt) +{ + struct hpsb_packet *packet; + int retval = 0; + + if (rootid >= ALL_NODES || rootid < -1 || gapcnt > 0x3f || gapcnt < -1 || + (rootid == -1 && gapcnt == -1)) { + HPSB_DEBUG("Invalid Parameter: rootid = %d gapcnt = %d", + rootid, gapcnt); + return -EINVAL; + } + + packet = alloc_hpsb_packet(0); + if (!packet) + return -ENOMEM; + + packet->host = host; + packet->header_size = 8; + packet->data_size = 0; + packet->expect_response = 0; + packet->no_waiter = 0; + packet->type = hpsb_raw; + packet->header[0] = 0; + if (rootid != -1) + packet->header[0] |= rootid << 24 | 1 << 23; + if (gapcnt != -1) + packet->header[0] |= gapcnt << 16 | 1 << 22; + + packet->header[1] = ~packet->header[0]; + + packet->generation = get_hpsb_generation(host); + + if (!hpsb_send_packet(packet)) { + retval = -EINVAL; + goto fail; + } + + down(&packet->state_change); + down(&packet->state_change); + +fail: + free_hpsb_packet(packet); + + return retval; +} + +/** + * hpsb_send_packet - transmit a packet on the bus + * @packet: packet to send + * + * 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 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 + * number or the host reports a transmit error. + * + * Return value: False (0) on failure, true (1) otherwise. + */ +int hpsb_send_packet(struct hpsb_packet *packet) +{ + struct hpsb_host *host = packet->host; + + if (host->is_shutdown || host->in_bus_reset + || (packet->generation != get_hpsb_generation(host))) { + return 0; + } + + packet->state = hpsb_queued; + + if (packet->node_id == host->node_id) + { /* it is a local request, so handle it locally */ + quadlet_t *data; + size_t size=packet->data_size+packet->header_size; + + data = kmalloc(packet->header_size + packet->data_size, GFP_ATOMIC); + if (!data) { + HPSB_ERR("unable to allocate memory for concatenating header and data"); + return 0; + } + + memcpy(data, packet->header, packet->header_size); + + if (packet->data_size) + { + if (packet->data_be) { + memcpy(((u8*)data)+packet->header_size, packet->data, packet->data_size); + } else { + int i; + quadlet_t *my_data=(quadlet_t*) ((u8*) data + packet->data_size); + for (i=0; i < packet->data_size/4; i++) { + my_data[i] = cpu_to_be32(packet->data[i]); + } + } + } + + dump_packet("send packet local:", packet->header, + packet->header_size); + + hpsb_packet_sent(host, packet, packet->expect_response?ACK_PENDING:ACK_COMPLETE); + hpsb_packet_received(host, data, size, 0); + + kfree(data); + + return 1; + } + + if (packet->type == hpsb_async && packet->node_id != ALL_NODES) { + packet->speed_code = + host->speed_map[NODEID_TO_NODE(host->node_id) * 64 + + NODEID_TO_NODE(packet->node_id)]; + } + + switch (packet->speed_code) { + case 2: + dump_packet("send packet 400:", packet->header, + packet->header_size); + break; + case 1: + dump_packet("send packet 200:", packet->header, + packet->header_size); + break; + default: + dump_packet("send packet 100:", packet->header, + packet->header_size); + } + + return host->driver->transmit_packet(host, packet); +} + +static void send_packet_nocare(struct hpsb_packet *packet) +{ + if (!hpsb_send_packet(packet)) { + free_hpsb_packet(packet); + } +} + + +void handle_packet_response(struct hpsb_host *host, int tcode, quadlet_t *data, + size_t size) +{ + struct hpsb_packet *packet = NULL; + struct list_head *lh; + int tcode_match = 0; + int tlabel; + unsigned long flags; + + tlabel = (data[0] >> 10) & 0x3f; + + spin_lock_irqsave(&host->pending_pkt_lock, flags); + + list_for_each(lh, &host->pending_packets) { + packet = list_entry(lh, struct hpsb_packet, list); + if ((packet->tlabel == tlabel) + && (packet->node_id == (data[1] >> 16))){ + break; + } + } + + if (lh == &host->pending_packets) { + HPSB_DEBUG("unsolicited response packet received - no tlabel match"); + dump_packet("contents:", data, 16); + spin_unlock_irqrestore(&host->pending_pkt_lock, flags); + return; + } + + switch (packet->tcode) { + case TCODE_WRITEQ: + case TCODE_WRITEB: + if (tcode == TCODE_WRITE_RESPONSE) tcode_match = 1; + break; + case TCODE_READQ: + if (tcode == TCODE_READQ_RESPONSE) tcode_match = 1; + break; + case TCODE_READB: + if (tcode == TCODE_READB_RESPONSE) tcode_match = 1; + break; + case TCODE_LOCK_REQUEST: + if (tcode == TCODE_LOCK_RESPONSE) tcode_match = 1; + break; + } + + if (!tcode_match || (packet->tlabel != tlabel) + || (packet->node_id != (data[1] >> 16))) { + HPSB_INFO("unsolicited response packet received - tcode mismatch"); + dump_packet("contents:", data, 16); + + spin_unlock_irqrestore(&host->pending_pkt_lock, flags); + return; + } + + list_del(&packet->list); + + spin_unlock_irqrestore(&host->pending_pkt_lock, flags); + + /* FIXME - update size fields? */ + switch (tcode) { + case TCODE_WRITE_RESPONSE: + memcpy(packet->header, data, 12); + break; + case TCODE_READQ_RESPONSE: + memcpy(packet->header, data, 16); + break; + case TCODE_READB_RESPONSE: + memcpy(packet->header, data, 16); + memcpy(packet->data, data + 4, size - 16); + break; + case TCODE_LOCK_RESPONSE: + memcpy(packet->header, data, 16); + memcpy(packet->data, data + 4, (size - 16) > 8 ? 8 : size - 16); + break; + } + + packet->state = hpsb_complete; + up(&packet->state_change); + run_packet_complete(packet); +} + + +static struct hpsb_packet *create_reply_packet(struct hpsb_host *host, + quadlet_t *data, size_t dsize) +{ + struct hpsb_packet *p; + + dsize += (dsize % 4 ? 4 - (dsize % 4) : 0); + + p = alloc_hpsb_packet(dsize); + if (p == NULL) { + /* FIXME - send data_error response */ + return NULL; + } + + p->type = hpsb_async; + p->state = hpsb_unused; + p->host = host; + p->node_id = data[1] >> 16; + p->tlabel = (data[0] >> 10) & 0x3f; + p->no_waiter = 1; + + p->generation = get_hpsb_generation(host); + + if (dsize % 4) { + p->data[dsize / 4] = 0; + } + + return p; +} + +#define PREP_ASYNC_HEAD_RCODE(tc) \ + packet->tcode = tc; \ + packet->header[0] = (packet->node_id << 16) | (packet->tlabel << 10) \ + | (1 << 8) | (tc << 4); \ + packet->header[1] = (packet->host->node_id << 16) | (rcode << 12); \ + packet->header[2] = 0 + +static void fill_async_readquad_resp(struct hpsb_packet *packet, int rcode, + quadlet_t data) +{ + PREP_ASYNC_HEAD_RCODE(TCODE_READQ_RESPONSE); + packet->header[3] = data; + packet->header_size = 16; + packet->data_size = 0; +} + +static void fill_async_readblock_resp(struct hpsb_packet *packet, int rcode, + int length) +{ + if (rcode != RCODE_COMPLETE) + length = 0; + + PREP_ASYNC_HEAD_RCODE(TCODE_READB_RESPONSE); + packet->header[3] = length << 16; + packet->header_size = 16; + packet->data_size = length + (length % 4 ? 4 - (length % 4) : 0); +} + +static void fill_async_write_resp(struct hpsb_packet *packet, int rcode) +{ + PREP_ASYNC_HEAD_RCODE(TCODE_WRITE_RESPONSE); + packet->header[2] = 0; + packet->header_size = 12; + packet->data_size = 0; +} + +static void fill_async_lock_resp(struct hpsb_packet *packet, int rcode, int extcode, + int length) +{ + if (rcode != RCODE_COMPLETE) + length = 0; + + PREP_ASYNC_HEAD_RCODE(TCODE_LOCK_RESPONSE); + packet->header[3] = (length << 16) | extcode; + packet->header_size = 16; + packet->data_size = length; +} + +#define PREP_REPLY_PACKET(length) \ + packet = create_reply_packet(host, data, length); \ + if (packet == NULL) break + +static void handle_incoming_packet(struct hpsb_host *host, int tcode, + quadlet_t *data, size_t size, int write_acked) +{ + struct hpsb_packet *packet; + int length, rcode, extcode; + quadlet_t buffer; + nodeid_t source = data[1] >> 16; + nodeid_t dest = data[0] >> 16; + u16 flags = (u16) data[0]; + u64 addr; + + /* big FIXME - no error checking is done for an out of bounds length */ + + switch (tcode) { + case TCODE_WRITEQ: + addr = (((u64)(data[1] & 0xffff)) << 32) | data[2]; + rcode = highlevel_write(host, source, dest, data+3, + addr, 4, flags); + + if (!write_acked + && (NODEID_TO_NODE(data[0] >> 16) != NODE_MASK) + && (rcode >= 0)) { + /* not a broadcast write, reply */ + PREP_REPLY_PACKET(0); + fill_async_write_resp(packet, rcode); + send_packet_nocare(packet); + } + break; + + case TCODE_WRITEB: + addr = (((u64)(data[1] & 0xffff)) << 32) | data[2]; + rcode = highlevel_write(host, source, dest, data+4, + addr, data[3]>>16, flags); + + if (!write_acked + && (NODEID_TO_NODE(data[0] >> 16) != NODE_MASK) + && (rcode >= 0)) { + /* not a broadcast write, reply */ + PREP_REPLY_PACKET(0); + fill_async_write_resp(packet, rcode); + send_packet_nocare(packet); + } + break; + + case TCODE_READQ: + addr = (((u64)(data[1] & 0xffff)) << 32) | data[2]; + rcode = highlevel_read(host, source, &buffer, addr, 4, flags); + + if (rcode >= 0) { + PREP_REPLY_PACKET(0); + fill_async_readquad_resp(packet, rcode, buffer); + send_packet_nocare(packet); + } + break; + + case TCODE_READB: + length = data[3] >> 16; + PREP_REPLY_PACKET(length); + + addr = (((u64)(data[1] & 0xffff)) << 32) | data[2]; + rcode = highlevel_read(host, source, packet->data, addr, + length, flags); + + if (rcode >= 0) { + fill_async_readblock_resp(packet, rcode, length); + send_packet_nocare(packet); + } else { + free_hpsb_packet(packet); + } + break; + + case TCODE_LOCK_REQUEST: + length = data[3] >> 16; + extcode = data[3] & 0xffff; + addr = (((u64)(data[1] & 0xffff)) << 32) | data[2]; + + PREP_REPLY_PACKET(8); + + if ((extcode == 0) || (extcode >= 7)) { + /* let switch default handle error */ + length = 0; + } + + switch (length) { + case 4: + rcode = highlevel_lock(host, source, packet->data, addr, + data[4], 0, extcode,flags); + fill_async_lock_resp(packet, rcode, extcode, 4); + break; + case 8: + if ((extcode != EXTCODE_FETCH_ADD) + && (extcode != EXTCODE_LITTLE_ADD)) { + rcode = highlevel_lock(host, source, + packet->data, addr, + data[5], data[4], + extcode, flags); + fill_async_lock_resp(packet, rcode, extcode, 4); + } else { + rcode = highlevel_lock64(host, source, + (octlet_t *)packet->data, addr, + *(octlet_t *)(data + 4), 0ULL, + extcode, flags); + fill_async_lock_resp(packet, rcode, extcode, 8); + } + break; + case 16: + rcode = highlevel_lock64(host, source, + (octlet_t *)packet->data, addr, + *(octlet_t *)(data + 6), + *(octlet_t *)(data + 4), + extcode, flags); + fill_async_lock_resp(packet, rcode, extcode, 8); + break; + default: + rcode = RCODE_TYPE_ERROR; + fill_async_lock_resp(packet, rcode, + extcode, 0); + } + + if (rcode >= 0) { + send_packet_nocare(packet); + } else { + free_hpsb_packet(packet); + } + break; + } + +} +#undef PREP_REPLY_PACKET + + +void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size, + int write_acked) +{ + int tcode; + + if (host->in_bus_reset) { + HPSB_INFO("received packet during reset; ignoring"); + return; + } + + dump_packet("received packet:", data, size); + + tcode = (data[0] >> 4) & 0xf; + + switch (tcode) { + case TCODE_WRITE_RESPONSE: + case TCODE_READQ_RESPONSE: + case TCODE_READB_RESPONSE: + case TCODE_LOCK_RESPONSE: + handle_packet_response(host, tcode, data, size); + break; + + case TCODE_WRITEQ: + case TCODE_WRITEB: + case TCODE_READQ: + case TCODE_READB: + case TCODE_LOCK_REQUEST: + handle_incoming_packet(host, tcode, data, size, write_acked); + break; + + + case TCODE_ISO_DATA: + highlevel_iso_receive(host, data, size); + break; + + case TCODE_CYCLE_START: + /* simply ignore this packet if it is passed on */ + break; + + default: + HPSB_NOTICE("received packet with bogus transaction code %d", + tcode); + break; + } +} + + +void abort_requests(struct hpsb_host *host) +{ + unsigned long flags; + struct hpsb_packet *packet; + struct list_head *lh, *tlh; + LIST_HEAD(llist); + + host->driver->devctl(host, CANCEL_REQUESTS, 0); + + spin_lock_irqsave(&host->pending_pkt_lock, flags); + list_splice(&host->pending_packets, &llist); + INIT_LIST_HEAD(&host->pending_packets); + spin_unlock_irqrestore(&host->pending_pkt_lock, flags); + + list_for_each_safe(lh, tlh, &llist) { + packet = list_entry(lh, struct hpsb_packet, list); + list_del(&packet->list); + packet->state = hpsb_complete; + packet->ack_code = ACKX_ABORTED; + up(&packet->state_change); + run_packet_complete(packet); + } +} + +void abort_timedouts(unsigned long __opaque) +{ + struct hpsb_host *host = (struct hpsb_host *)__opaque; + unsigned long flags; + struct hpsb_packet *packet; + unsigned long expire; + struct list_head *lh, *tlh; + LIST_HEAD(expiredlist); + + spin_lock_irqsave(&host->csr.lock, flags); + expire = host->csr.expire; + spin_unlock_irqrestore(&host->csr.lock, flags); + + spin_lock_irqsave(&host->pending_pkt_lock, flags); + + list_for_each_safe(lh, tlh, &host->pending_packets) { + packet = list_entry(lh, struct hpsb_packet, list); + if (time_before(packet->sendtime + expire, jiffies)) { + list_del(&packet->list); + list_add(&packet->list, &expiredlist); + } + } + + if (!list_empty(&host->pending_packets)) + mod_timer(&host->timeout, jiffies + host->timeout_interval); + + spin_unlock_irqrestore(&host->pending_pkt_lock, flags); + + list_for_each_safe(lh, tlh, &expiredlist) { + packet = list_entry(lh, struct hpsb_packet, list); + list_del(&packet->list); + packet->state = hpsb_complete; + packet->ack_code = ACKX_TIMEOUT; + up(&packet->state_change); + run_packet_complete(packet); + } +} + + +/* + * character device dispatching (see ieee1394_core.h) + * Dan Maas + */ + +static struct { + struct file_operations *file_ops; + struct module *module; +} ieee1394_chardevs[16]; + +static rwlock_t ieee1394_chardevs_lock = RW_LOCK_UNLOCKED; + +static int ieee1394_dispatch_open(struct inode *inode, struct file *file); + +static struct file_operations ieee1394_chardev_ops = { + .owner =THIS_MODULE, + .open = ieee1394_dispatch_open, +}; + +devfs_handle_t ieee1394_devfs_handle; + + +/* claim a block of minor numbers */ +int ieee1394_register_chardev(int blocknum, + struct module *module, + struct file_operations *file_ops) +{ + int retval; + + if ( (blocknum < 0) || (blocknum > 15) ) + return -EINVAL; + + write_lock(&ieee1394_chardevs_lock); + + if (ieee1394_chardevs[blocknum].file_ops == NULL) { + /* grab the minor block */ + ieee1394_chardevs[blocknum].file_ops = file_ops; + ieee1394_chardevs[blocknum].module = module; + + retval = 0; + } else { + /* block already taken */ + retval = -EBUSY; + } + + write_unlock(&ieee1394_chardevs_lock); + + return retval; +} + +/* release a block of minor numbers */ +void ieee1394_unregister_chardev(int blocknum) +{ + if ( (blocknum < 0) || (blocknum > 15) ) + return; + + write_lock(&ieee1394_chardevs_lock); + + if (ieee1394_chardevs[blocknum].file_ops) { + ieee1394_chardevs[blocknum].file_ops = NULL; + ieee1394_chardevs[blocknum].module = NULL; + } + + write_unlock(&ieee1394_chardevs_lock); +} + +/* + ieee1394_get_chardev() - look up and acquire a character device + driver that has previously registered using ieee1394_register_chardev() + + On success, returns 1 and sets module and file_ops to the driver. + The module will have an incremented reference count. + + On failure, returns 0. + The module will NOT have an incremented reference count. +*/ + +static int ieee1394_get_chardev(int blocknum, + struct module **module, + struct file_operations **file_ops) +{ + int ret = 0; + + if ((blocknum < 0) || (blocknum > 15)) + return ret; + + read_lock(&ieee1394_chardevs_lock); + + *module = ieee1394_chardevs[blocknum].module; + *file_ops = ieee1394_chardevs[blocknum].file_ops; + + if (*file_ops == NULL) + goto out; + + /* don't need try_inc_mod_count if the driver is non-modular */ + if (*module && (try_inc_mod_count(*module) == 0)) + goto out; + + /* success! */ + ret = 1; + +out: + read_unlock(&ieee1394_chardevs_lock); + return ret; +} + +/* the point of entry for open() on any ieee1394 character device */ +static int ieee1394_dispatch_open(struct inode *inode, struct file *file) +{ + struct file_operations *file_ops; + struct module *module; + int blocknum; + int retval; + + /* + Maintaining correct module reference counts is tricky here! + + The key thing to remember is that the VFS increments the + reference count of ieee1394 before it calls + ieee1394_dispatch_open(). + + If the open() succeeds, then we need to transfer this extra + reference to the task-specific driver module (e.g. raw1394). + The VFS will deref the driver module automatically when the + file is later released. + + If the open() fails, then the VFS will drop the + reference count of whatever module file->f_op->owner points + to, immediately after this function returns. + */ + + /* shift away lower four bits of the minor + to get the index of the ieee1394_driver + we want */ + + blocknum = (MINOR(inode->i_rdev) >> 4) & 0xF; + + /* look up the driver */ + + if (ieee1394_get_chardev(blocknum, &module, &file_ops) == 0) + return -ENODEV; + + /* redirect all subsequent requests to the driver's + own file_operations */ + file->f_op = file_ops; + + /* at this point BOTH ieee1394 and the task-specific driver have + an extra reference */ + + /* follow through with the open() */ + retval = file_ops->open(inode, file); + + if (retval == 0) { + + /* If the open() succeeded, then ieee1394 will be left + with an extra module reference, so we discard it here. + + The task-specific driver still has the extra + reference given to it by ieee1394_get_chardev(). + This extra reference prevents the module from + unloading while the file is open, and will be + dropped by the VFS when the file is released. + */ + + if (THIS_MODULE) + __MOD_DEC_USE_COUNT((struct module*) THIS_MODULE); + + /* note that if ieee1394 is compiled into the kernel, + THIS_MODULE will be (void*) NULL, hence the if and + the cast are necessary */ + + } else { + + /* if the open() failed, then we need to drop the + extra reference we gave to the task-specific + driver */ + + if (module) + __MOD_DEC_USE_COUNT(module); + + /* point the file's f_ops back to ieee1394. The VFS will then + decrement ieee1394's reference count immediately after this + function returns. */ + + file->f_op = &ieee1394_chardev_ops; + } + + return retval; +} + +struct proc_dir_entry *ieee1394_procfs_entry; + +static int __init ieee1394_init(void) +{ + hpsb_packet_cache = kmem_cache_create("hpsb_packet", sizeof(struct hpsb_packet), + 0, 0, NULL, NULL); + + ieee1394_devfs_handle = devfs_mk_dir(NULL, "ieee1394", NULL); + + if (register_chrdev(IEEE1394_MAJOR, "ieee1394", &ieee1394_chardev_ops)) { + HPSB_ERR("unable to register character device major %d!\n", IEEE1394_MAJOR); + devfs_unregister(ieee1394_devfs_handle); + return -ENODEV; + } + +#ifdef CONFIG_PROC_FS + /* Must be done before we start everything else, since the drivers + * may use it. */ + ieee1394_procfs_entry = proc_mkdir("ieee1394", proc_bus); + if (ieee1394_procfs_entry == NULL) { + HPSB_ERR("unable to create /proc/bus/ieee1394\n"); + unregister_chrdev(IEEE1394_MAJOR, "ieee1394"); + devfs_unregister(ieee1394_devfs_handle); + return -ENOMEM; + } + ieee1394_procfs_entry->owner = THIS_MODULE; +#endif + + init_hpsb_highlevel(); + init_csr(); + if (!disable_nodemgr) + init_ieee1394_nodemgr(); + else + HPSB_INFO("nodemgr functionality disabled"); + + return 0; +} + +static void __exit ieee1394_cleanup(void) +{ + if (!disable_nodemgr) + cleanup_ieee1394_nodemgr(); + + cleanup_csr(); + kmem_cache_destroy(hpsb_packet_cache); + + unregister_chrdev(IEEE1394_MAJOR, "ieee1394"); + + /* it's ok to pass a NULL devfs_handle to devfs_unregister */ + devfs_unregister(ieee1394_devfs_handle); + + remove_proc_entry("ieee1394", proc_bus); +} + +module_init(ieee1394_init); +module_exit(ieee1394_cleanup); + +/* Exported symbols */ + +/** hosts.c **/ +EXPORT_SYMBOL(hpsb_alloc_host); +EXPORT_SYMBOL(hpsb_add_host); +EXPORT_SYMBOL(hpsb_remove_host); +EXPORT_SYMBOL(hpsb_ref_host); +EXPORT_SYMBOL(hpsb_unref_host); + +/** ieee1394_core.c **/ +EXPORT_SYMBOL(hpsb_speedto_str); +EXPORT_SYMBOL(hpsb_set_packet_complete_task); +EXPORT_SYMBOL(alloc_hpsb_packet); +EXPORT_SYMBOL(free_hpsb_packet); +EXPORT_SYMBOL(hpsb_send_phy_config); +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); +EXPORT_SYMBOL(hpsb_packet_sent); +EXPORT_SYMBOL(hpsb_packet_received); +EXPORT_SYMBOL(ieee1394_register_chardev); +EXPORT_SYMBOL(ieee1394_unregister_chardev); +EXPORT_SYMBOL(ieee1394_devfs_handle); +EXPORT_SYMBOL(ieee1394_procfs_entry); + +/** ieee1394_transactions.c **/ +EXPORT_SYMBOL(hpsb_get_tlabel); +EXPORT_SYMBOL(hpsb_free_tlabel); +EXPORT_SYMBOL(hpsb_make_readpacket); +EXPORT_SYMBOL(hpsb_make_writepacket); +EXPORT_SYMBOL(hpsb_make_streampacket); +EXPORT_SYMBOL(hpsb_make_lockpacket); +EXPORT_SYMBOL(hpsb_make_lock64packet); +EXPORT_SYMBOL(hpsb_make_phypacket); +EXPORT_SYMBOL(hpsb_make_isopacket); +EXPORT_SYMBOL(hpsb_read); +EXPORT_SYMBOL(hpsb_write); +EXPORT_SYMBOL(hpsb_lock); +EXPORT_SYMBOL(hpsb_lock64); +EXPORT_SYMBOL(hpsb_send_gasp); +EXPORT_SYMBOL(hpsb_packet_success); + +/** highlevel.c **/ +EXPORT_SYMBOL(hpsb_register_highlevel); +EXPORT_SYMBOL(hpsb_unregister_highlevel); +EXPORT_SYMBOL(hpsb_register_addrspace); +EXPORT_SYMBOL(hpsb_unregister_addrspace); +EXPORT_SYMBOL(hpsb_listen_channel); +EXPORT_SYMBOL(hpsb_unlisten_channel); +EXPORT_SYMBOL(hpsb_get_hostinfo); +EXPORT_SYMBOL(hpsb_get_host_bykey); +EXPORT_SYMBOL(hpsb_create_hostinfo); +EXPORT_SYMBOL(hpsb_destroy_hostinfo); +EXPORT_SYMBOL(hpsb_set_hostinfo_key); +EXPORT_SYMBOL(hpsb_get_hostinfo_key); +EXPORT_SYMBOL(hpsb_get_hostinfo_bykey); +EXPORT_SYMBOL(hpsb_set_hostinfo); +EXPORT_SYMBOL(highlevel_read); +EXPORT_SYMBOL(highlevel_write); +EXPORT_SYMBOL(highlevel_lock); +EXPORT_SYMBOL(highlevel_lock64); +EXPORT_SYMBOL(highlevel_add_host); +EXPORT_SYMBOL(highlevel_remove_host); +EXPORT_SYMBOL(highlevel_host_reset); + +/** nodemgr.c **/ +EXPORT_SYMBOL(hpsb_guid_get_entry); +EXPORT_SYMBOL(hpsb_nodeid_get_entry); +EXPORT_SYMBOL(hpsb_node_fill_packet); +EXPORT_SYMBOL(hpsb_node_read); +EXPORT_SYMBOL(hpsb_node_write); +EXPORT_SYMBOL(hpsb_node_lock); +EXPORT_SYMBOL(hpsb_register_protocol); +EXPORT_SYMBOL(hpsb_unregister_protocol); +EXPORT_SYMBOL(hpsb_release_unit_directory); + +/** csr.c **/ +EXPORT_SYMBOL(hpsb_update_config_rom); +EXPORT_SYMBOL(hpsb_get_config_rom); + +/** dma.c **/ +EXPORT_SYMBOL(dma_prog_region_init); +EXPORT_SYMBOL(dma_prog_region_alloc); +EXPORT_SYMBOL(dma_prog_region_free); +EXPORT_SYMBOL(dma_region_init); +EXPORT_SYMBOL(dma_region_alloc); +EXPORT_SYMBOL(dma_region_free); +EXPORT_SYMBOL(dma_region_sync); +EXPORT_SYMBOL(dma_region_mmap); +EXPORT_SYMBOL(dma_region_offset_to_bus); + +/** iso.c **/ +EXPORT_SYMBOL(hpsb_iso_xmit_init); +EXPORT_SYMBOL(hpsb_iso_recv_init); +EXPORT_SYMBOL(hpsb_iso_xmit_start); +EXPORT_SYMBOL(hpsb_iso_recv_start); +EXPORT_SYMBOL(hpsb_iso_recv_listen_channel); +EXPORT_SYMBOL(hpsb_iso_recv_unlisten_channel); +EXPORT_SYMBOL(hpsb_iso_recv_set_channel_mask); +EXPORT_SYMBOL(hpsb_iso_stop); +EXPORT_SYMBOL(hpsb_iso_shutdown); +EXPORT_SYMBOL(hpsb_iso_xmit_queue_packet); +EXPORT_SYMBOL(hpsb_iso_xmit_sync); +EXPORT_SYMBOL(hpsb_iso_recv_release_packets); +EXPORT_SYMBOL(hpsb_iso_n_ready); +EXPORT_SYMBOL(hpsb_iso_packet_sent); +EXPORT_SYMBOL(hpsb_iso_packet_received); +EXPORT_SYMBOL(hpsb_iso_wake); +EXPORT_SYMBOL(hpsb_iso_recv_flush); diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/ieee1394_core.h.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/ieee1394_core.h.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/ieee1394_core.h.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/ieee1394_core.h.svn-base 2003-07-27 22:04:40.000000000 +0200 @@ -0,0 +1,233 @@ + +#ifndef _IEEE1394_CORE_H +#define _IEEE1394_CORE_H + +#include +#include +#include +#include +#include "hosts.h" + + +struct hpsb_packet { + /* This struct is basically read-only for hosts with the exception of + * the data buffer contents and xnext - see below. */ + struct list_head list; + + /* This can be used for host driver internal linking. */ + struct list_head driver_list; + + nodeid_t node_id; + + /* Async and Iso types should be clear, raw means send-as-is, do not + * CRC! Byte swapping shall still be done in this case. */ + enum { hpsb_async, hpsb_iso, hpsb_raw } __attribute__((packed)) type; + + /* Okay, this is core internal and a no care for hosts. + * queued = queued for sending + * pending = sent, waiting for response + * complete = processing completed, successful or not + * incoming = incoming packet + */ + enum { + hpsb_unused, hpsb_queued, hpsb_pending, hpsb_complete, hpsb_incoming + } __attribute__((packed)) state; + + /* These are core internal. */ + signed char tlabel; + char ack_code; + char tcode; + + unsigned expect_response:1; + unsigned no_waiter:1; + + /* Data big endianness flag - may vary from request to request. The + * header is always in machine byte order. + * Not really used currently. */ + unsigned data_be:1; + + /* Speed to transmit with: 0 = 100Mbps, 1 = 200Mbps, 2 = 400Mbps */ + unsigned speed_code:2; + + /* + * *header and *data are guaranteed to be 32-bit DMAable and may be + * overwritten to allow in-place byte swapping. Neither of these is + * CRCed (the sizes also don't include CRC), but contain space for at + * least one additional quadlet to allow in-place CRCing. The memory is + * also guaranteed to be DMA mappable. + */ + quadlet_t *header; + quadlet_t *data; + size_t header_size; + size_t data_size; + + + struct hpsb_host *host; + unsigned int generation; + + /* Very core internal, don't care. */ + struct semaphore state_change; + + /* Function (and possible data to pass to it) to call when this + * packet is completed. */ + void (*complete_routine)(void *); + void *complete_data; + + /* Store jiffies for implementing bus timeouts. */ + unsigned long sendtime; + + quadlet_t embedded_header[5]; +}; + +/* Set a task for when a packet completes */ +void hpsb_set_packet_complete_task(struct hpsb_packet *packet, + void (*routine)(void *), void *data); + +static inline struct hpsb_packet *driver_packet(struct list_head *l) +{ + return list_entry(l, struct hpsb_packet, driver_list); +} + +void abort_timedouts(unsigned long __opaque); +void abort_requests(struct hpsb_host *host); + +struct hpsb_packet *alloc_hpsb_packet(size_t data_size); +void free_hpsb_packet(struct hpsb_packet *packet); + + +/* + * Generation counter for the complete 1394 subsystem. Generation gets + * incremented on every change in the subsystem (e.g. bus reset). + * + * Use the functions, not the variable. + */ +#include + +static inline unsigned int get_hpsb_generation(struct hpsb_host *host) +{ + return atomic_read(&host->generation); +} + +/* + * Send a PHY configuration packet. + */ +int hpsb_send_phy_config(struct hpsb_host *host, int rootid, int gapcnt); + +/* + * Queue packet for transmitting, return 0 for failure. + */ +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, int type); + +/* + * The following functions are exported for host driver module usage. All of + * them are safe to use in interrupt contexts, although some are quite + * complicated so you may want to run them in bottom halves instead of calling + * them directly. + */ + +/* 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 + * quadlet is complement of first) is expected to be done and succesful. + */ +void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid); + +/* + * Notify completion of SelfID stage to the core and report new physical ID + * and whether host is root now. + */ +void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot); + +/* + * Notify core of sending a packet. Ackcode is the ack code returned for async + * transmits or ACKX_SEND_ERROR if the transmission failed completely; ACKX_NONE + * for other cases (internal errors that don't justify a panic). Safe to call + * from within a transmit packet routine. + */ +void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet, + int ackcode); + +/* + * Hand over received packet to the core. The contents of data are expected to + * be the full packet but with the CRCs left out (data block follows header + * immediately), with the header (i.e. the first four quadlets) in machine byte + * order and the data block in big endian. *data can be safely overwritten + * after this call. + * + * If the packet is a write request, write_acked is to be set to true if it was + * ack_complete'd already, false otherwise. This arg is ignored for any other + * packet type. + */ +void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size, + int write_acked); + + +/* + * CHARACTER DEVICE DISPATCHING + * + * All ieee1394 character device drivers share the same major number + * (major 171). The 256 minor numbers are allocated to the various + * task-specific interfaces (raw1394, video1394, dv1394, etc) in + * blocks of 16. + * + * The core ieee1394.o modules handles the initial open() for all + * character devices on major 171; it then dispatches to the + * appropriate task-specific driver. + * + * Minor device number block allocations: + * + * Block 0 ( 0- 15) raw1394 + * Block 1 ( 16- 31) video1394 + * Block 2 ( 32- 47) dv1394 + * + * Blocks 3-14 free for future allocation + * + * Block 15 (240-255) reserved for drivers under development, etc. + */ + +#define IEEE1394_MAJOR 171 + +#define IEEE1394_MINOR_BLOCK_RAW1394 0 +#define IEEE1394_MINOR_BLOCK_VIDEO1394 1 +#define IEEE1394_MINOR_BLOCK_DV1394 2 +#define IEEE1394_MINOR_BLOCK_AMDTP 3 +#define IEEE1394_MINOR_BLOCK_EXPERIMENTAL 15 + +/* return the index (within a minor number block) of a file */ +static inline unsigned char ieee1394_file_to_instance(struct file *file) +{ + unsigned char minor = MINOR(file->f_dentry->d_inode->i_rdev); + + /* return lower 4 bits */ + return minor & 0xF; +} + +/* + * Task-specific drivers should call ieee1394_register_chardev() to + * request a block of 16 minor numbers. + * + * Returns 0 if the request was successful, -EBUSY if the block was + * already taken. + */ + +int ieee1394_register_chardev(int blocknum, /* 0-15 */ + struct module *module, /* THIS_MODULE */ + struct file_operations *file_ops); + +/* release a block of minor numbers */ +void ieee1394_unregister_chardev(int blocknum); + +/* the devfs handle for /dev/ieee1394; NULL if devfs is not in use */ +extern devfs_handle_t ieee1394_devfs_handle; + +/* the proc_fs entry for /proc/ieee1394 */ +extern struct proc_dir_entry *ieee1394_procfs_entry; + +#endif /* _IEEE1394_CORE_H */ diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/ieee1394_hotplug.h.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/ieee1394_hotplug.h.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/ieee1394_hotplug.h.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/ieee1394_hotplug.h.svn-base 2003-07-21 13:09:32.000000000 +0200 @@ -0,0 +1,28 @@ +#ifndef _IEEE1394_HOTPLUG_H +#define _IEEE1394_HOTPLUG_H + +#include + +#define IEEE1394_MATCH_VENDOR_ID 0x0001 +#define IEEE1394_MATCH_MODEL_ID 0x0002 +#define IEEE1394_MATCH_SPECIFIER_ID 0x0004 +#define IEEE1394_MATCH_VERSION 0x0008 + +/* + * Unit spec id and sw version entry for some protocols + */ +#define AVC_UNIT_SPEC_ID_ENTRY 0x0000A02D +#define AVC_SW_VERSION_ENTRY 0x00010001 +#define CAMERA_UNIT_SPEC_ID_ENTRY 0x0000A02D +#define CAMERA_SW_VERSION_ENTRY 0x00000100 + +struct ieee1394_device_id { + u32 match_flags; + u32 vendor_id; + u32 model_id; + u32 specifier_id; + u32 version; + void *driver_data; +}; + +#endif /* _IEEE1394_HOTPLUG_H */ diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/ieee1394_transactions.c.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/ieee1394_transactions.c.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/ieee1394_transactions.c.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/ieee1394_transactions.c.svn-base 2003-09-08 03:33:05.000000000 +0200 @@ -0,0 +1,633 @@ +/* + * IEEE 1394 for Linux + * + * Transaction support. + * + * Copyright (C) 1999 Andreas E. Bombe + * + * This code is licensed under the GPL. See the file COPYING in the root + * directory of the kernel sources for details. + */ + +#include +#include +#include +#include + +#include "ieee1394.h" +#include "ieee1394_types.h" +#include "hosts.h" +#include "ieee1394_core.h" +#include "highlevel.h" +#include "nodemgr.h" + + +#define PREP_ASYNC_HEAD_ADDRESS(tc) \ + packet->tcode = tc; \ + packet->header[0] = (packet->node_id << 16) | (packet->tlabel << 10) \ + | (1 << 8) | (tc << 4); \ + packet->header[1] = (packet->host->node_id << 16) | (addr >> 32); \ + packet->header[2] = addr & 0xffffffff + + +static void fill_async_readquad(struct hpsb_packet *packet, u64 addr) +{ + PREP_ASYNC_HEAD_ADDRESS(TCODE_READQ); + packet->header_size = 12; + packet->data_size = 0; + packet->expect_response = 1; +} + +static void fill_async_readblock(struct hpsb_packet *packet, u64 addr, int length) +{ + PREP_ASYNC_HEAD_ADDRESS(TCODE_READB); + packet->header[3] = length << 16; + packet->header_size = 16; + packet->data_size = 0; + packet->expect_response = 1; +} + +static void fill_async_writequad(struct hpsb_packet *packet, u64 addr, quadlet_t data) +{ + PREP_ASYNC_HEAD_ADDRESS(TCODE_WRITEQ); + packet->header[3] = data; + packet->header_size = 16; + packet->data_size = 0; + packet->expect_response = 1; +} + +static void fill_async_writeblock(struct hpsb_packet *packet, u64 addr, int length) +{ + PREP_ASYNC_HEAD_ADDRESS(TCODE_WRITEB); + packet->header[3] = length << 16; + packet->header_size = 16; + packet->expect_response = 1; + packet->data_size = length + (length % 4 ? 4 - (length % 4) : 0); +} + +static void fill_async_lock(struct hpsb_packet *packet, u64 addr, int extcode, + int length) +{ + PREP_ASYNC_HEAD_ADDRESS(TCODE_LOCK_REQUEST); + packet->header[3] = (length << 16) | extcode; + packet->header_size = 16; + packet->data_size = length; + packet->expect_response = 1; +} + +static void fill_iso_packet(struct hpsb_packet *packet, int length, int channel, + int tag, int sync) +{ + packet->header[0] = (length << 16) | (tag << 14) | (channel << 8) + | (TCODE_ISO_DATA << 4) | sync; + + packet->header_size = 4; + packet->data_size = length; + packet->type = hpsb_iso; + packet->tcode = TCODE_ISO_DATA; +} + +static void fill_phy_packet(struct hpsb_packet *packet, quadlet_t data) +{ + packet->header[0] = data; + packet->header[1] = ~data; + packet->header_size = 8; + packet->data_size = 0; + packet->expect_response = 0; + packet->type = hpsb_raw; /* No CRC added */ + packet->speed_code = IEEE1394_SPEED_100; /* Force speed to be 100Mbps */ +} + +static void fill_async_stream_packet(struct hpsb_packet *packet, int length, + int channel, int tag, int sync) +{ + packet->header[0] = (length << 16) | (tag << 14) | (channel << 8) + | (TCODE_STREAM_DATA << 4) | sync; + + packet->header_size = 4; + packet->data_size = length; + packet->type = hpsb_async; + packet->tcode = TCODE_ISO_DATA; +} + +/** + * hpsb_get_tlabel - allocate a transaction label + * @packet: the packet who's tlabel/tpool we set + * + * Every asynchronous transaction on the 1394 bus needs a transaction + * label to match the response to the request. This label has to be + * different from any other transaction label in an outstanding request to + * the same node to make matching possible without ambiguity. + * + * There are 64 different tlabels, so an allocated tlabel has to be freed + * with hpsb_free_tlabel() after the transaction is complete (unless it's + * reused again for the same target node). + * + * Return value: Zero on success, otherwise non-zero. A non-zero return + * generally means there are no available tlabels. If this is called out + * of interrupt or atomic context, then it will sleep until can return a + * tlabel. + */ +int hpsb_get_tlabel(struct hpsb_packet *packet) +{ + unsigned long flags; + struct hpsb_tlabel_pool *tp; + + tp = &packet->host->tpool[packet->node_id & NODE_MASK]; + + if (in_interrupt()) { + if (down_trylock(&tp->count)) + return 1; + } else { + down(&tp->count); + } + + spin_lock_irqsave(&tp->lock, flags); + + packet->tlabel = find_next_zero_bit(tp->pool, 64, tp->next); + if (packet->tlabel > 63) + packet->tlabel = find_first_zero_bit(tp->pool, 64); + tp->next = (packet->tlabel + 1) % 64; + /* Should _never_ happen */ + BUG_ON(test_and_set_bit(packet->tlabel, tp->pool)); + tp->allocations++; + spin_unlock_irqrestore(&tp->lock, flags); + + return 0; +} + +/** + * hpsb_free_tlabel - free an allocated transaction label + * @packet: packet whos tlabel/tpool needs to be cleared + * + * Frees the transaction label allocated with hpsb_get_tlabel(). The + * tlabel has to be freed after the transaction is complete (i.e. response + * was received for a split transaction or packet was sent for a unified + * transaction). + * + * A tlabel must not be freed twice. + */ +void hpsb_free_tlabel(struct hpsb_packet *packet) +{ + unsigned long flags; + struct hpsb_tlabel_pool *tp; + + tp = &packet->host->tpool[packet->node_id & NODE_MASK]; + + BUG_ON(packet->tlabel > 63 || packet->tlabel < 0); + + spin_lock_irqsave(&tp->lock, flags); + BUG_ON(!test_and_clear_bit(packet->tlabel, tp->pool)); + spin_unlock_irqrestore(&tp->lock, flags); + + up(&tp->count); +} + + + +int hpsb_packet_success(struct hpsb_packet *packet) +{ + switch (packet->ack_code) { + case ACK_PENDING: + switch ((packet->header[1] >> 12) & 0xf) { + case RCODE_COMPLETE: + return 0; + case RCODE_CONFLICT_ERROR: + return -EAGAIN; + case RCODE_DATA_ERROR: + return -EREMOTEIO; + case RCODE_TYPE_ERROR: + return -EACCES; + case RCODE_ADDRESS_ERROR: + return -EINVAL; + default: + HPSB_ERR("received reserved rcode %d from node %d", + (packet->header[1] >> 12) & 0xf, + packet->node_id); + return -EAGAIN; + } + HPSB_PANIC("reached unreachable code 1 in %s", __FUNCTION__); + + case ACK_BUSY_X: + case ACK_BUSY_A: + case ACK_BUSY_B: + return -EBUSY; + + case ACK_TYPE_ERROR: + return -EACCES; + + case ACK_COMPLETE: + if (packet->tcode == TCODE_WRITEQ + || packet->tcode == TCODE_WRITEB) { + return 0; + } else { + HPSB_ERR("impossible ack_complete from node %d " + "(tcode %d)", packet->node_id, packet->tcode); + return -EAGAIN; + } + + + case ACK_DATA_ERROR: + if (packet->tcode == TCODE_WRITEB + || packet->tcode == TCODE_LOCK_REQUEST) { + return -EAGAIN; + } else { + HPSB_ERR("impossible ack_data_error from node %d " + "(tcode %d)", packet->node_id, packet->tcode); + return -EAGAIN; + } + + case ACKX_NONE: + case ACKX_SEND_ERROR: + case ACKX_ABORTED: + case ACKX_TIMEOUT: + /* error while sending */ + return -EAGAIN; + + default: + HPSB_ERR("got invalid ack %d from node %d (tcode %d)", + packet->ack_code, packet->node_id, packet->tcode); + return -EAGAIN; + } + + HPSB_PANIC("reached unreachable code 2 in %s", __FUNCTION__); +} + +struct hpsb_packet *hpsb_make_readpacket(struct hpsb_host *host, nodeid_t node, + u64 addr, size_t length) +{ + struct hpsb_packet *packet; + + if (length == 0) + return NULL; + + packet = alloc_hpsb_packet(length + (length % 4 ? 4 - (length % 4) : 0)); + if (!packet) + return NULL; + + packet->host = host; + packet->node_id = node; + + if (hpsb_get_tlabel(packet)) { + free_hpsb_packet(packet); + return NULL; + } + + if (length == 4) + fill_async_readquad(packet, addr); + else + fill_async_readblock(packet, addr, length); + + return packet; +} + +struct hpsb_packet *hpsb_make_writepacket (struct hpsb_host *host, nodeid_t node, + u64 addr, quadlet_t *buffer, size_t length) +{ + struct hpsb_packet *packet; + + if (length == 0) + return NULL; + + packet = alloc_hpsb_packet(length + (length % 4 ? 4 - (length % 4) : 0)); + if (!packet) + return NULL; + + if (length % 4) { /* zero padding bytes */ + packet->data[length >> 2] = 0; + } + packet->host = host; + packet->node_id = node; + + if (hpsb_get_tlabel(packet)) { + free_hpsb_packet(packet); + return NULL; + } + + if (length == 4) { + fill_async_writequad(packet, addr, buffer ? *buffer : 0); + } else { + fill_async_writeblock(packet, addr, length); + if (buffer) + memcpy(packet->data, buffer, length); + } + + return packet; +} + +struct hpsb_packet *hpsb_make_streampacket(struct hpsb_host *host, u8 *buffer, int length, + int channel, int tag, int sync) +{ + struct hpsb_packet *packet; + + if (length == 0) + return NULL; + + packet = alloc_hpsb_packet(length + (length % 4 ? 4 - (length % 4) : 0)); + if (!packet) + return NULL; + + if (length % 4) { /* zero padding bytes */ + packet->data[length >> 2] = 0; + } + packet->host = host; + + if (hpsb_get_tlabel(packet)) { + free_hpsb_packet(packet); + return NULL; + } + + fill_async_stream_packet(packet, length, channel, tag, sync); + if (buffer) + memcpy(packet->data, buffer, length); + + return packet; +} + +struct hpsb_packet *hpsb_make_lockpacket(struct hpsb_host *host, nodeid_t node, + u64 addr, int extcode, quadlet_t *data, + quadlet_t arg) +{ + struct hpsb_packet *p; + u32 length; + + p = alloc_hpsb_packet(8); + if (!p) return NULL; + + p->host = host; + p->node_id = node; + if (hpsb_get_tlabel(p)) { + free_hpsb_packet(p); + return NULL; + } + + switch (extcode) { + case EXTCODE_FETCH_ADD: + case EXTCODE_LITTLE_ADD: + length = 4; + if (data) + p->data[0] = *data; + break; + default: + length = 8; + if (data) { + p->data[0] = arg; + p->data[1] = *data; + } + break; + } + fill_async_lock(p, addr, extcode, length); + + return p; +} + +struct hpsb_packet *hpsb_make_lock64packet(struct hpsb_host *host, nodeid_t node, + u64 addr, int extcode, octlet_t *data, + octlet_t arg) +{ + struct hpsb_packet *p; + u32 length; + + p = alloc_hpsb_packet(16); + if (!p) return NULL; + + p->host = host; + p->node_id = node; + if (hpsb_get_tlabel(p)) { + free_hpsb_packet(p); + return NULL; + } + + switch (extcode) { + case EXTCODE_FETCH_ADD: + case EXTCODE_LITTLE_ADD: + length = 8; + if (data) { + p->data[0] = *data >> 32; + p->data[1] = *data & 0xffffffff; + } + break; + default: + length = 16; + if (data) { + p->data[0] = arg >> 32; + p->data[1] = arg & 0xffffffff; + p->data[2] = *data >> 32; + p->data[3] = *data & 0xffffffff; + } + break; + } + fill_async_lock(p, addr, extcode, length); + + return p; +} + +struct hpsb_packet *hpsb_make_phypacket(struct hpsb_host *host, + quadlet_t data) +{ + struct hpsb_packet *p; + + p = alloc_hpsb_packet(0); + if (!p) return NULL; + + p->host = host; + fill_phy_packet(p, data); + + return p; +} + +struct hpsb_packet *hpsb_make_isopacket(struct hpsb_host *host, + int length, int channel, + int tag, int sync) +{ + struct hpsb_packet *p; + + p = alloc_hpsb_packet(length); + if (!p) return NULL; + + p->host = host; + fill_iso_packet(p, length, channel, tag, sync); + + p->generation = get_hpsb_generation(host); + + return p; +} + +/* + * FIXME - these functions should probably read from / write to user space to + * avoid in kernel buffers for user space callers + */ + +int hpsb_read(struct hpsb_host *host, nodeid_t node, unsigned int generation, + u64 addr, quadlet_t *buffer, size_t length) +{ + struct hpsb_packet *packet; + int retval = 0; + + if (length == 0) + return -EINVAL; + + BUG_ON(in_interrupt()); // We can't be called in an interrupt, yet + + packet = hpsb_make_readpacket(host, node, addr, length); + + if (!packet) { + return -ENOMEM; + } + + packet->generation = generation; + if (!hpsb_send_packet(packet)) { + retval = -EINVAL; + goto hpsb_read_fail; + } + + down(&packet->state_change); + down(&packet->state_change); + retval = hpsb_packet_success(packet); + + if (retval == 0) { + if (length == 4) { + *buffer = packet->header[3]; + } else { + memcpy(buffer, packet->data, length); + } + } + +hpsb_read_fail: + hpsb_free_tlabel(packet); + free_hpsb_packet(packet); + + return retval; +} + + +int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation, + u64 addr, quadlet_t *buffer, size_t length) +{ + struct hpsb_packet *packet; + int retval; + + if (length == 0) + return -EINVAL; + + BUG_ON(in_interrupt()); // We can't be called in an interrupt, yet + + packet = hpsb_make_writepacket (host, node, addr, buffer, length); + + if (!packet) + return -ENOMEM; + + packet->generation = generation; + if (!hpsb_send_packet(packet)) { + retval = -EINVAL; + goto hpsb_write_fail; + } + + down(&packet->state_change); + down(&packet->state_change); + retval = hpsb_packet_success(packet); + +hpsb_write_fail: + hpsb_free_tlabel(packet); + free_hpsb_packet(packet); + + return retval; +} + + +int hpsb_lock(struct hpsb_host *host, nodeid_t node, unsigned int generation, + u64 addr, int extcode, quadlet_t *data, quadlet_t arg) +{ + struct hpsb_packet *packet; + int retval = 0; + + BUG_ON(in_interrupt()); // We can't be called in an interrupt, yet + + packet = hpsb_make_lockpacket(host, node, addr, extcode, data, arg); + if (!packet) + return -ENOMEM; + + packet->generation = generation; + if (!hpsb_send_packet(packet)) { + retval = -EINVAL; + goto hpsb_lock_fail; + } + down(&packet->state_change); + down(&packet->state_change); + retval = hpsb_packet_success(packet); + + if (retval == 0) { + *data = packet->data[0]; + } + +hpsb_lock_fail: + hpsb_free_tlabel(packet); + free_hpsb_packet(packet); + + return retval; +} + +int hpsb_lock64(struct hpsb_host *host, nodeid_t node, unsigned int generation, + u64 addr, int extcode, octlet_t *data, octlet_t arg) +{ + struct hpsb_packet *packet; + int retval = 0; + + BUG_ON(in_interrupt()); // We can't be called in an interrupt, yet + + packet = hpsb_make_lock64packet(host, node, addr, extcode, data, arg); + if (!packet) + return -ENOMEM; + + packet->generation = generation; + if (!hpsb_send_packet(packet)) { + retval = -EINVAL; + goto hpsb_lock64_fail; + } + down(&packet->state_change); + down(&packet->state_change); + retval = hpsb_packet_success(packet); + + if (retval == 0) + *data = (u64)packet->data[1] << 32 | packet->data[0]; + +hpsb_lock64_fail: + hpsb_free_tlabel(packet); + free_hpsb_packet(packet); + + return retval; +} + +int hpsb_send_gasp(struct hpsb_host *host, int channel, unsigned int generation, + quadlet_t *buffer, size_t length, u32 specifier_id, + unsigned int version) +{ + struct hpsb_packet *packet; + int retval = 0; + u16 specifier_id_hi = (specifier_id & 0x00ffff00) >> 8; + u8 specifier_id_lo = specifier_id & 0xff; + + HPSB_VERBOSE("Send GASP: channel = %d, length = %Zd", channel, length); + + length += 8; + + packet = hpsb_make_streampacket(host, NULL, length, channel, 3, 0); + if (!packet) + return -ENOMEM; + + packet->data[0] = cpu_to_be32((host->node_id << 16) | specifier_id_hi); + packet->data[1] = cpu_to_be32((specifier_id_lo << 24) | (version & 0x00ffffff)); + + memcpy(&(packet->data[2]), buffer, length - 8); + + packet->generation = generation; + + packet->no_waiter = 1; + + if (!hpsb_send_packet(packet)) { + free_hpsb_packet(packet); + retval = -EINVAL; + } + + return retval; +} diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/ieee1394_transactions.h.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/ieee1394_transactions.h.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/ieee1394_transactions.h.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/ieee1394_transactions.h.svn-base 2003-09-08 03:33:06.000000000 +0200 @@ -0,0 +1,64 @@ +#ifndef _IEEE1394_TRANSACTIONS_H +#define _IEEE1394_TRANSACTIONS_H + +#include "ieee1394_core.h" + + +/* + * Get and free transaction labels. + */ +int hpsb_get_tlabel(struct hpsb_packet *packet); +void hpsb_free_tlabel(struct hpsb_packet *packet); + +struct hpsb_packet *hpsb_make_readpacket(struct hpsb_host *host, nodeid_t node, + u64 addr, size_t length); +struct hpsb_packet *hpsb_make_lockpacket(struct hpsb_host *host, nodeid_t node, + u64 addr, int extcode, quadlet_t *data, + quadlet_t arg); +struct hpsb_packet *hpsb_make_lock64packet(struct hpsb_host *host, nodeid_t node, + u64 addr, int extcode, octlet_t *data, + octlet_t arg); +struct hpsb_packet *hpsb_make_phypacket(struct hpsb_host *host, + quadlet_t data) ; +struct hpsb_packet *hpsb_make_isopacket(struct hpsb_host *host, + int length, int channel, + int tag, int sync); +struct hpsb_packet *hpsb_make_writepacket (struct hpsb_host *host, nodeid_t node, + u64 addr, quadlet_t *buffer, size_t length); +struct hpsb_packet *hpsb_make_streampacket(struct hpsb_host *host, u8 *buffer, + int length, int channel, int tag, int sync); + +/* + * hpsb_packet_success - Make sense of the ack and reply codes and + * return more convenient error codes: + * 0 success + * -EBUSY node is busy, try again + * -EAGAIN error which can probably resolved by retry + * -EREMOTEIO node suffers from an internal error + * -EACCES this transaction is not allowed on requested address + * -EINVAL invalid address at node + */ +int hpsb_packet_success(struct hpsb_packet *packet); + + +/* + * The generic read, write and lock functions. All recognize the local node ID + * and act accordingly. Read and write automatically use quadlet commands if + * length == 4 and and block commands otherwise (however, they do not yet + * support lengths that are not a multiple of 4). You must explicitly specifiy + * the generation for which the node ID is valid, to avoid sending packets to + * the wrong nodes when we race with a bus reset. + */ +int hpsb_read(struct hpsb_host *host, nodeid_t node, unsigned int generation, + u64 addr, quadlet_t *buffer, size_t length); +int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation, + u64 addr, quadlet_t *buffer, size_t length); +int hpsb_lock(struct hpsb_host *host, nodeid_t node, unsigned int generation, + u64 addr, int extcode, quadlet_t *data, quadlet_t arg); +int hpsb_lock64(struct hpsb_host *host, nodeid_t node, unsigned int generation, + u64 addr, int extcode, octlet_t *data, octlet_t arg); +int hpsb_send_gasp(struct hpsb_host *host, int channel, unsigned int generation, + quadlet_t *buffer, size_t length, u32 specifier_id, + unsigned int version); + +#endif /* _IEEE1394_TRANSACTIONS_H */ diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/ieee1394_types.h.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/ieee1394_types.h.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/ieee1394_types.h.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/ieee1394_types.h.svn-base 2003-07-27 22:04:44.000000000 +0200 @@ -0,0 +1,110 @@ + +#ifndef _IEEE1394_TYPES_H +#define _IEEE1394_TYPES_H + +#include +#include +#include +#include +#include +#include +#include +#include + + +#ifndef BITS_TO_LONGS /* < 2.4.21-pre6 */ +#define BITS_TO_LONGS(bits) \ + (((bits)+BITS_PER_LONG-1)/BITS_PER_LONG) +#define DECLARE_BITMAP(name,bits) \ + unsigned long name[BITS_TO_LONGS(bits)] +#define CLEAR_BITMAP(name,bits) \ + memset(name, 0, BITS_TO_LONGS(bits)*sizeof(unsigned long)) +#endif + + +/* Transaction Label handling */ +struct hpsb_tlabel_pool { + DECLARE_BITMAP(pool, 64); + spinlock_t lock; + u8 next; + u32 allocations; + struct semaphore count; +}; + +#define HPSB_TPOOL_INIT(_tp) \ +do { \ + CLEAR_BITMAP((_tp)->pool, 64); \ + spin_lock_init(&(_tp)->lock); \ + (_tp)->next = 0; \ + (_tp)->allocations = 0; \ + sema_init(&(_tp)->count, 63); \ +} while (0) + + +typedef u32 quadlet_t; +typedef u64 octlet_t; +typedef u16 nodeid_t; + +typedef u8 byte_t; +typedef u64 nodeaddr_t; +typedef u16 arm_length_t; + +#define BUS_MASK 0xffc0 +#define BUS_SHIFT 6 +#define NODE_MASK 0x003f +#define LOCAL_BUS 0xffc0 +#define ALL_NODES 0x003f + +#define NODEID_TO_BUS(nodeid) ((nodeid & BUS_MASK) >> BUS_SHIFT) +#define NODEID_TO_NODE(nodeid) (nodeid & NODE_MASK) + +/* Can be used to consistently print a node/bus ID. */ +#define NODE_BUS_FMT "%d-%02d:%04d" +#define NODE_BUS_ARGS(__host, __nodeid) \ + __host->id, NODEID_TO_NODE(__nodeid), NODEID_TO_BUS(__nodeid) + +#define HPSB_PRINT(level, fmt, args...) printk(level "ieee1394: " fmt "\n" , ## args) + +#define HPSB_DEBUG(fmt, args...) HPSB_PRINT(KERN_DEBUG, fmt , ## args) +#define HPSB_INFO(fmt, args...) HPSB_PRINT(KERN_INFO, fmt , ## args) +#define HPSB_NOTICE(fmt, args...) HPSB_PRINT(KERN_NOTICE, fmt , ## args) +#define HPSB_WARN(fmt, args...) HPSB_PRINT(KERN_WARNING, fmt , ## args) +#define HPSB_ERR(fmt, args...) HPSB_PRINT(KERN_ERR, fmt , ## args) + +#ifdef CONFIG_IEEE1394_VERBOSEDEBUG +#define HPSB_VERBOSE(fmt, args...) HPSB_PRINT(KERN_DEBUG, fmt , ## args) +#else +#define HPSB_VERBOSE(fmt, args...) +#endif + +#define HPSB_PANIC(fmt, args...) panic("ieee1394: " fmt "\n" , ## args) + +#define HPSB_TRACE() HPSB_PRINT(KERN_INFO, "TRACE - %s, %s(), line %d", __FILE__, __FUNCTION__, __LINE__) + + +#ifdef __BIG_ENDIAN + +static __inline__ void *memcpy_le32(u32 *dest, const u32 *__src, size_t count) +{ + void *tmp = dest; + u32 *src = (u32 *)__src; + + count /= 4; + + while (count--) { + *dest++ = swab32p(src++); + } + + return tmp; +} + +#else + +static __inline__ void *memcpy_le32(u32 *dest, const u32 *src, size_t count) +{ + return memcpy(dest, src, count); +} + +#endif /* __BIG_ENDIAN */ + +#endif /* _IEEE1394_TYPES_H */ diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/iso.c.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/iso.c.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/iso.c.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/iso.c.svn-base 2003-07-21 13:09:45.000000000 +0200 @@ -0,0 +1,443 @@ +/* + * IEEE 1394 for Linux + * + * kernel ISO transmission/reception + * + * Copyright (C) 2002 Maas Digital LLC + * + * This code is licensed under the GPL. See the file COPYING in the root + * directory of the kernel sources for details. + */ + +#include +#include +#include "iso.h" + +void hpsb_iso_stop(struct hpsb_iso *iso) +{ + if (!(iso->flags & HPSB_ISO_DRIVER_STARTED)) + return; + + iso->host->driver->isoctl(iso, iso->type == HPSB_ISO_XMIT ? + XMIT_STOP : RECV_STOP, 0); + iso->flags &= ~HPSB_ISO_DRIVER_STARTED; +} + +void hpsb_iso_shutdown(struct hpsb_iso *iso) +{ + if (iso->flags & HPSB_ISO_DRIVER_INIT) { + hpsb_iso_stop(iso); + iso->host->driver->isoctl(iso, iso->type == HPSB_ISO_XMIT ? + XMIT_SHUTDOWN : RECV_SHUTDOWN, 0); + iso->flags &= ~HPSB_ISO_DRIVER_INIT; + } + + dma_region_free(&iso->data_buf); + kfree(iso); +} + +static struct hpsb_iso* hpsb_iso_common_init(struct hpsb_host *host, enum hpsb_iso_type type, + unsigned int data_buf_size, + unsigned int buf_packets, + int channel, + int irq_interval, + void (*callback)(struct hpsb_iso*)) +{ + struct hpsb_iso *iso; + int dma_direction; + + /* make sure driver supports the ISO API */ + if (!host->driver->isoctl) { + printk(KERN_INFO "ieee1394: host driver '%s' does not support the rawiso API\n", + host->driver->name); + return NULL; + } + + /* sanitize parameters */ + + if (buf_packets < 2) + buf_packets = 2; + + if (irq_interval < 1 || irq_interval > buf_packets / 2) + irq_interval = buf_packets / 2; + + if (channel < -1 || channel >= 64) + return NULL; + + /* channel = -1 is OK for multi-channel recv but not for xmit */ + if (type == HPSB_ISO_XMIT && channel < 0) + return NULL; + + /* allocate and write the struct hpsb_iso */ + + iso = kmalloc(sizeof(*iso) + buf_packets * sizeof(struct hpsb_iso_packet_info), GFP_KERNEL); + if (!iso) + return NULL; + + iso->infos = (struct hpsb_iso_packet_info *)(iso + 1); + + iso->type = type; + iso->host = host; + iso->hostdata = NULL; + iso->callback = callback; + init_waitqueue_head(&iso->waitq); + iso->channel = channel; + iso->irq_interval = irq_interval; + dma_region_init(&iso->data_buf); + iso->buf_size = round_up_to_page(data_buf_size); + iso->buf_packets = buf_packets; + iso->pkt_dma = 0; + iso->first_packet = 0; + spin_lock_init(&iso->lock); + + if (iso->type == HPSB_ISO_XMIT) { + iso->n_ready_packets = iso->buf_packets; + dma_direction = PCI_DMA_TODEVICE; + } else { + iso->n_ready_packets = 0; + dma_direction = PCI_DMA_FROMDEVICE; + } + + atomic_set(&iso->overflows, 0); + iso->flags = 0; + iso->prebuffer = 0; + + /* allocate the packet buffer */ + if (dma_region_alloc(&iso->data_buf, iso->buf_size, host->pdev, dma_direction)) + goto err; + + return iso; + +err: + hpsb_iso_shutdown(iso); + return NULL; +} + +int hpsb_iso_n_ready(struct hpsb_iso* iso) +{ + unsigned long flags; + int val; + + spin_lock_irqsave(&iso->lock, flags); + val = iso->n_ready_packets; + spin_unlock_irqrestore(&iso->lock, flags); + + return val; +} + + +struct hpsb_iso* hpsb_iso_xmit_init(struct hpsb_host *host, + unsigned int data_buf_size, + unsigned int buf_packets, + int channel, + int speed, + int irq_interval, + void (*callback)(struct hpsb_iso*)) +{ + struct hpsb_iso *iso = hpsb_iso_common_init(host, HPSB_ISO_XMIT, + data_buf_size, buf_packets, + channel, irq_interval, callback); + if (!iso) + return NULL; + + iso->speed = speed; + + /* tell the driver to start working */ + if (host->driver->isoctl(iso, XMIT_INIT, 0)) + goto err; + + iso->flags |= HPSB_ISO_DRIVER_INIT; + return iso; + +err: + hpsb_iso_shutdown(iso); + return NULL; +} + +struct hpsb_iso* hpsb_iso_recv_init(struct hpsb_host *host, + unsigned int data_buf_size, + unsigned int buf_packets, + int channel, + int irq_interval, + void (*callback)(struct hpsb_iso*)) +{ + struct hpsb_iso *iso = hpsb_iso_common_init(host, HPSB_ISO_RECV, + data_buf_size, buf_packets, + channel, irq_interval, callback); + if (!iso) + return NULL; + + /* tell the driver to start working */ + if (host->driver->isoctl(iso, RECV_INIT, 0)) + goto err; + + iso->flags |= HPSB_ISO_DRIVER_INIT; + return iso; + +err: + hpsb_iso_shutdown(iso); + return NULL; +} + +int hpsb_iso_recv_listen_channel(struct hpsb_iso *iso, unsigned char channel) +{ + if (iso->type != HPSB_ISO_RECV || iso->channel != -1 || channel >= 64) + return -EINVAL; + return iso->host->driver->isoctl(iso, RECV_LISTEN_CHANNEL, channel); +} + +int hpsb_iso_recv_unlisten_channel(struct hpsb_iso *iso, unsigned char channel) +{ + if (iso->type != HPSB_ISO_RECV || iso->channel != -1 || channel >= 64) + return -EINVAL; + return iso->host->driver->isoctl(iso, RECV_UNLISTEN_CHANNEL, channel); +} + +int hpsb_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask) +{ + if (iso->type != HPSB_ISO_RECV || iso->channel != -1) + return -EINVAL; + return iso->host->driver->isoctl(iso, RECV_SET_CHANNEL_MASK, (unsigned long) &mask); +} + +int hpsb_iso_recv_flush(struct hpsb_iso *iso) +{ + if (iso->type != HPSB_ISO_RECV) + return -EINVAL; + return iso->host->driver->isoctl(iso, RECV_FLUSH, 0); +} + +static int do_iso_xmit_start(struct hpsb_iso *iso, int cycle) +{ + int retval = iso->host->driver->isoctl(iso, XMIT_START, cycle); + if (retval) + return retval; + + iso->flags |= HPSB_ISO_DRIVER_STARTED; + return retval; +} + +int hpsb_iso_xmit_start(struct hpsb_iso *iso, int cycle, int prebuffer) +{ + if (iso->type != HPSB_ISO_XMIT) + return -1; + + if (iso->flags & HPSB_ISO_DRIVER_STARTED) + return 0; + + if (cycle < -1) + cycle = -1; + else if (cycle >= 8000) + cycle %= 8000; + + iso->xmit_cycle = cycle; + + if (prebuffer < 0) + prebuffer = iso->buf_packets; + else if (prebuffer == 0) + prebuffer = 1; + + if (prebuffer > iso->buf_packets) + prebuffer = iso->buf_packets; + + iso->prebuffer = prebuffer; + + /* remember the starting cycle; DMA will commence from xmit_queue_packets() + once enough packets have been buffered */ + iso->start_cycle = cycle; + + return 0; +} + +int hpsb_iso_recv_start(struct hpsb_iso *iso, int cycle, int tag_mask, int sync) +{ + int retval = 0; + int isoctl_args[3]; + + if (iso->type != HPSB_ISO_RECV) + return -1; + + if (iso->flags & HPSB_ISO_DRIVER_STARTED) + return 0; + + if (cycle < -1) + cycle = -1; + else if (cycle >= 8000) + cycle %= 8000; + + isoctl_args[0] = cycle; + + if (tag_mask < 0) + /* match all tags */ + tag_mask = 0xF; + isoctl_args[1] = tag_mask; + + isoctl_args[2] = sync; + + retval = iso->host->driver->isoctl(iso, RECV_START, (unsigned long) &isoctl_args[0]); + if (retval) + return retval; + + iso->flags |= HPSB_ISO_DRIVER_STARTED; + return retval; +} + +/* check to make sure the user has not supplied bogus values of offset/len + that would cause the kernel to access memory outside the buffer */ + +static int hpsb_iso_check_offset_len(struct hpsb_iso *iso, + unsigned int offset, unsigned short len, + unsigned int *out_offset, unsigned short *out_len) +{ + if (offset >= iso->buf_size) + return -EFAULT; + + /* make sure the packet does not go beyond the end of the buffer */ + if (offset + len > iso->buf_size) + return -EFAULT; + + /* check for wrap-around */ + if (offset + len < offset) + return -EFAULT; + + /* now we can trust 'offset' and 'length' */ + *out_offset = offset; + *out_len = len; + + return 0; +} + + +int hpsb_iso_xmit_queue_packet(struct hpsb_iso *iso, u32 offset, u16 len, u8 tag, u8 sy) +{ + struct hpsb_iso_packet_info *info; + unsigned long flags; + int rv; + + if (iso->type != HPSB_ISO_XMIT) + return -EINVAL; + + /* is there space in the buffer? */ + if (iso->n_ready_packets <= 0) { + return -EBUSY; + } + + info = &iso->infos[iso->first_packet]; + + /* check for bogus offset/length */ + if (hpsb_iso_check_offset_len(iso, offset, len, &info->offset, &info->len)) + return -EFAULT; + + info->tag = tag; + info->sy = sy; + + spin_lock_irqsave(&iso->lock, flags); + + rv = iso->host->driver->isoctl(iso, XMIT_QUEUE, (unsigned long) info); + if (rv) + goto out; + + /* increment cursors */ + iso->first_packet = (iso->first_packet+1) % iso->buf_packets; + iso->xmit_cycle = (iso->xmit_cycle+1) % 8000; + iso->n_ready_packets--; + + if (iso->prebuffer != 0) { + iso->prebuffer--; + if (iso->prebuffer <= 0) { + iso->prebuffer = 0; + rv = do_iso_xmit_start(iso, iso->start_cycle); + } + } + +out: + spin_unlock_irqrestore(&iso->lock, flags); + return rv; +} + +int hpsb_iso_xmit_sync(struct hpsb_iso *iso) +{ + if (iso->type != HPSB_ISO_XMIT) + return -EINVAL; + + return wait_event_interruptible(iso->waitq, hpsb_iso_n_ready(iso) == iso->buf_packets); +} + +void hpsb_iso_packet_sent(struct hpsb_iso *iso, int cycle, int error) +{ + unsigned long flags; + spin_lock_irqsave(&iso->lock, flags); + + /* predict the cycle of the next packet to be queued */ + + /* jump ahead by the number of packets that are already buffered */ + cycle += iso->buf_packets - iso->n_ready_packets; + cycle %= 8000; + + iso->xmit_cycle = cycle; + iso->n_ready_packets++; + iso->pkt_dma = (iso->pkt_dma + 1) % iso->buf_packets; + + if (iso->n_ready_packets == iso->buf_packets || error != 0) { + /* the buffer has run empty! */ + atomic_inc(&iso->overflows); + } + + spin_unlock_irqrestore(&iso->lock, flags); +} + +void hpsb_iso_packet_received(struct hpsb_iso *iso, u32 offset, u16 len, + u16 cycle, u8 channel, u8 tag, u8 sy) +{ + unsigned long flags; + spin_lock_irqsave(&iso->lock, flags); + + if (iso->n_ready_packets == iso->buf_packets) { + /* overflow! */ + atomic_inc(&iso->overflows); + } else { + struct hpsb_iso_packet_info *info = &iso->infos[iso->pkt_dma]; + info->offset = offset; + info->len = len; + info->cycle = cycle; + info->channel = channel; + info->tag = tag; + info->sy = sy; + + iso->pkt_dma = (iso->pkt_dma+1) % iso->buf_packets; + iso->n_ready_packets++; + } + + spin_unlock_irqrestore(&iso->lock, flags); +} + +int hpsb_iso_recv_release_packets(struct hpsb_iso *iso, unsigned int n_packets) +{ + unsigned long flags; + unsigned int i; + int rv = 0; + + if (iso->type != HPSB_ISO_RECV) + return -1; + + spin_lock_irqsave(&iso->lock, flags); + for (i = 0; i < n_packets; i++) { + rv = iso->host->driver->isoctl(iso, RECV_RELEASE, + (unsigned long) &iso->infos[iso->first_packet]); + if (rv) + break; + + iso->first_packet = (iso->first_packet+1) % iso->buf_packets; + iso->n_ready_packets--; + } + spin_unlock_irqrestore(&iso->lock, flags); + return rv; +} + +void hpsb_iso_wake(struct hpsb_iso *iso) +{ + wake_up_interruptible(&iso->waitq); + + if (iso->callback) + iso->callback(iso); +} diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/iso.h.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/iso.h.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/iso.h.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/iso.h.svn-base 2003-07-21 13:09:32.000000000 +0200 @@ -0,0 +1,190 @@ +/* + * IEEE 1394 for Linux + * + * kernel ISO transmission/reception + * + * Copyright (C) 2002 Maas Digital LLC + * + * This code is licensed under the GPL. See the file COPYING in the root + * directory of the kernel sources for details. + */ + +#ifndef IEEE1394_ISO_H +#define IEEE1394_ISO_H + +#include "hosts.h" +#include "dma.h" + +/* high-level ISO interface */ + +/* This API sends and receives isochronous packets on a large, + virtually-contiguous kernel memory buffer. The buffer may be mapped + into a user-space process for zero-copy transmission and reception. + + There are no explicit boundaries between packets in the buffer. A + packet may be transmitted or received at any location. However, + low-level drivers may impose certain restrictions on alignment or + size of packets. (e.g. in OHCI no packet may cross a page boundary, + and packets should be quadlet-aligned) +*/ + +/* Packet descriptor - the API maintains a ring buffer of these packet + descriptors in kernel memory (hpsb_iso.infos[]). */ + +struct hpsb_iso_packet_info { + /* offset of data payload relative to the first byte of the buffer */ + __u32 offset; + + /* length of the data payload, in bytes (not including the isochronous header) */ + __u16 len; + + /* (recv only) the cycle number (mod 8000) on which the packet was received */ + __u16 cycle; + + /* (recv only) channel on which the packet was received */ + __u8 channel; + + /* 2-bit 'tag' and 4-bit 'sy' fields of the isochronous header */ + __u8 tag; + __u8 sy; +}; + +enum hpsb_iso_type { HPSB_ISO_RECV = 0, HPSB_ISO_XMIT = 1 }; + +struct hpsb_iso { + enum hpsb_iso_type type; + + /* pointer to low-level driver and its private data */ + struct hpsb_host *host; + void *hostdata; + + /* a function to be called (from interrupt context) after + outgoing packets have been sent, or incoming packets have + arrived */ + void (*callback)(struct hpsb_iso*); + + /* wait for buffer space */ + wait_queue_head_t waitq; + + int speed; /* IEEE1394_SPEED_100, 200, or 400 */ + int channel; /* -1 if multichannel */ + + /* greatest # of packets between interrupts - controls + the maximum latency of the buffer */ + int irq_interval; + + /* the buffer for packet data payloads */ + struct dma_region data_buf; + + /* size of data_buf, in bytes (always a multiple of PAGE_SIZE) */ + unsigned int buf_size; + + /* # of packets in the ringbuffer */ + unsigned int buf_packets; + + /* protects packet cursors */ + spinlock_t lock; + + /* the index of the next packet that will be produced + or consumed by the user */ + int first_packet; + + /* the index of the next packet that will be transmitted + or received by the 1394 hardware */ + int pkt_dma; + + /* how many packets, starting at first_packet: + (transmit) are ready to be filled with data + (receive) contain received data */ + int n_ready_packets; + + /* how many times the buffer has overflowed or underflowed */ + atomic_t overflows; + + /* private flags to track initialization progress */ +#define HPSB_ISO_DRIVER_INIT (1<<0) +#define HPSB_ISO_DRIVER_STARTED (1<<1) + unsigned int flags; + + /* # of packets left to prebuffer (xmit only) */ + int prebuffer; + + /* starting cycle for DMA (xmit only) */ + int start_cycle; + + /* cycle at which next packet will be transmitted, + -1 if not known */ + int xmit_cycle; + + /* ringbuffer of packet descriptors in regular kernel memory + * XXX Keep this last, since we use over-allocated memory from + * this entry to fill this field. */ + struct hpsb_iso_packet_info *infos; +}; + +/* functions available to high-level drivers (e.g. raw1394) */ + +/* allocate the buffer and DMA context */ + +struct hpsb_iso* hpsb_iso_xmit_init(struct hpsb_host *host, + unsigned int data_buf_size, + unsigned int buf_packets, + int channel, + int speed, + int irq_interval, + void (*callback)(struct hpsb_iso*)); + +/* note: if channel = -1, multi-channel receive is enabled */ +struct hpsb_iso* hpsb_iso_recv_init(struct hpsb_host *host, + unsigned int data_buf_size, + unsigned int buf_packets, + int channel, + int irq_interval, + void (*callback)(struct hpsb_iso*)); + +/* multi-channel only */ +int hpsb_iso_recv_listen_channel(struct hpsb_iso *iso, unsigned char channel); +int hpsb_iso_recv_unlisten_channel(struct hpsb_iso *iso, unsigned char channel); +int hpsb_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask); + +/* start/stop DMA */ +int hpsb_iso_xmit_start(struct hpsb_iso *iso, int start_on_cycle, int prebuffer); +int hpsb_iso_recv_start(struct hpsb_iso *iso, int start_on_cycle, int tag_mask, int sync); +void hpsb_iso_stop(struct hpsb_iso *iso); + +/* deallocate buffer and DMA context */ +void hpsb_iso_shutdown(struct hpsb_iso *iso); + +/* queue a packet for transmission. 'offset' is relative to the beginning of the + DMA buffer, where the packet's data payload should already have been placed */ +int hpsb_iso_xmit_queue_packet(struct hpsb_iso *iso, u32 offset, u16 len, u8 tag, u8 sy); + +/* wait until all queued packets have been transmitted to the bus */ +int hpsb_iso_xmit_sync(struct hpsb_iso *iso); + +/* N packets have been read out of the buffer, re-use the buffer space */ +int hpsb_iso_recv_release_packets(struct hpsb_iso *recv, unsigned int n_packets); + +/* check for arrival of new packets immediately (even if irq_interval + has not yet been reached) */ +int hpsb_iso_recv_flush(struct hpsb_iso *iso); + +/* returns # of packets ready to send or receive */ +int hpsb_iso_n_ready(struct hpsb_iso *iso); + +/* the following are callbacks available to low-level drivers */ + +/* call after a packet has been transmitted to the bus (interrupt context is OK) + 'cycle' is the _exact_ cycle the packet was sent on + 'error' should be non-zero if some sort of error occurred when sending the packet +*/ +void hpsb_iso_packet_sent(struct hpsb_iso *iso, int cycle, int error); + +/* call after a packet has been received (interrupt context OK) */ +void hpsb_iso_packet_received(struct hpsb_iso *iso, u32 offset, u16 len, + u16 cycle, u8 channel, u8 tag, u8 sy); + +/* call to wake waiting processes after buffer space has opened up. */ +void hpsb_iso_wake(struct hpsb_iso *iso); + +#endif /* IEEE1394_ISO_H */ diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/nodemgr.c.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/nodemgr.c.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/nodemgr.c.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/nodemgr.c.svn-base 2003-10-12 01:06:14.000000000 +0200 @@ -0,0 +1,1525 @@ +/* + * Node information (ConfigROM) collection and management. + * + * Copyright (C) 2000 Andreas E. Bombe + * 2001-2003 Ben Collins + * + * This code is licensed under the GPL. See the file COPYING in the root + * directory of the kernel sources for details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_PROC_FS +#include +#endif + +#include "ieee1394_types.h" +#include "ieee1394.h" +#include "nodemgr.h" +#include "hosts.h" +#include "ieee1394_transactions.h" +#include "highlevel.h" +#include "csr.h" +#include "nodemgr.h" + + + +static char *nodemgr_find_oui_name(int oui) +{ +#ifdef CONFIG_IEEE1394_OUI_DB + extern struct oui_list_struct { + int oui; + char *name; + } oui_list[]; + int i; + + for (i = 0; oui_list[i].name; i++) + if (oui_list[i].oui == oui) + return oui_list[i].name; +#endif + return NULL; +} + + +/* + * Basically what we do here is start off retrieving the bus_info block. + * From there will fill in some info about the node, verify it is of IEEE + * 1394 type, and that the crc checks out ok. After that we start off with + * the root directory, and subdirectories. To do this, we retrieve the + * quadlet header for a directory, find out the length, and retrieve the + * complete directory entry (be it a leaf or a directory). We then process + * it and add the info to our structure for that particular node. + * + * We verify CRC's along the way for each directory/block/leaf. The entire + * node structure is generic, and simply stores the information in a way + * that's easy to parse by the protocol interface. + */ + +/* The nodemgr maintains a number of data structures: the node list, + * the driver list, unit directory list and the host info list. The + * first three lists are accessed from process context only: /proc + * readers, insmod and rmmod, and the nodemgr thread. Access to these + * lists are serialized by means of the nodemgr_serialize mutex, which + * must be taken before accessing the structures and released + * afterwards. The host info list is only accessed during insmod, + * rmmod and from interrupt and allways only for a short period of + * time, so a spinlock is used to protect this list. + */ + +static DECLARE_MUTEX(nodemgr_serialize); +static LIST_HEAD(node_list); +static LIST_HEAD(driver_list); +static LIST_HEAD(unit_directory_list); + + +struct host_info { + struct hpsb_host *host; + struct completion exited; + struct semaphore reset_sem; + int pid; + char daemon_name[15]; +}; + +static struct hpsb_highlevel nodemgr_highlevel; + +#ifdef CONFIG_PROC_FS + +#define PUTF(fmt, args...) \ +do { \ + len += sprintf(page + len, fmt, ## args); \ + pos = begin + len; \ + if (pos < off) { \ + len = 0; \ + begin = pos; \ + } \ + if (pos > off + count) \ + goto done_proc; \ +} while (0) + + +static int raw1394_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct list_head *lh; + struct node_entry *ne; + off_t begin = 0, pos = 0; + int len = 0; + + if (down_interruptible(&nodemgr_serialize)) + return -EINTR; + + list_for_each(lh, &node_list) { + struct list_head *l; + int ud_count = 0, lud_count = 0; + + ne = list_entry(lh, struct node_entry, list); + if (!ne) + continue; + + PUTF("Node[" NODE_BUS_FMT "] GUID[%016Lx]:\n", + NODE_BUS_ARGS(ne->host, ne->nodeid), (unsigned long long)ne->guid); + + /* Generic Node information */ + PUTF(" Vendor ID: `%s' [0x%06x]\n", + ne->vendor_name ?: "Unknown", ne->vendor_id); + PUTF(" Capabilities: 0x%06x\n", ne->capabilities); + PUTF(" Bus Options:\n"); + PUTF(" IRMC(%d) CMC(%d) ISC(%d) BMC(%d) PMC(%d) GEN(%d)\n" + " LSPD(%d) MAX_REC(%d) CYC_CLK_ACC(%d)\n", + ne->busopt.irmc, ne->busopt.cmc, ne->busopt.isc, ne->busopt.bmc, + ne->busopt.pmc, ne->busopt.generation, ne->busopt.lnkspd, + ne->busopt.max_rec, ne->busopt.cyc_clk_acc); + + /* If this is the host entry, output some info about it aswell */ + if (ne->host != NULL && ne->host->node_id == ne->nodeid) { + PUTF(" Host Node Status:\n"); + PUTF(" Host Driver : %s\n", ne->host->driver->name); + PUTF(" Nodes connected : %d\n", ne->host->node_count); + PUTF(" Nodes active : %d\n", ne->host->nodes_active); + PUTF(" SelfIDs received: %d\n", ne->host->selfid_count); + PUTF(" Irm ID : [" NODE_BUS_FMT "]\n", + NODE_BUS_ARGS(ne->host, ne->host->irm_id)); + PUTF(" BusMgr ID : [" NODE_BUS_FMT "]\n", + NODE_BUS_ARGS(ne->host, ne->host->busmgr_id)); + PUTF(" In Bus Reset : %s\n", ne->host->in_bus_reset ? "yes" : "no"); + PUTF(" Root : %s\n", ne->host->is_root ? "yes" : "no"); + PUTF(" Cycle Master : %s\n", ne->host->is_cycmst ? "yes" : "no"); + PUTF(" IRM : %s\n", ne->host->is_irm ? "yes" : "no"); + PUTF(" Bus Manager : %s\n", ne->host->is_busmgr ? "yes" : "no"); + } + + /* Now the unit directories */ + list_for_each (l, &ne->unit_directories) { + struct unit_directory *ud = list_entry (l, struct unit_directory, node_list); + int printed = 0; // small hack + + if (ud->parent == NULL) + PUTF(" Unit Directory %d:\n", lud_count++); + else + PUTF(" Logical Unit Directory %d:\n", ud_count++); + if (ud->flags & UNIT_DIRECTORY_VENDOR_ID) { + PUTF(" Vendor/Model ID: %s [%06x]", + ud->vendor_name ?: "Unknown", ud->vendor_id); + printed = 1; + } + if (ud->flags & UNIT_DIRECTORY_MODEL_ID) { + if (!printed) + PUTF(" Vendor/Model ID: %s [%06x]", + ne->vendor_name ?: "Unknown", ne->vendor_id); + PUTF(" / %s [%06x]", ud->model_name ?: "Unknown", ud->model_id); + printed = 1; + } + if (printed) + PUTF("\n"); + + if (ud->flags & UNIT_DIRECTORY_SPECIFIER_ID) + PUTF(" Software Specifier ID: %06x\n", ud->specifier_id); + if (ud->flags & UNIT_DIRECTORY_VERSION) + PUTF(" Software Version: %06x\n", ud->version); + if (ud->driver) + PUTF(" Driver: %s\n", ud->driver->name); + PUTF(" Length (in quads): %d\n", ud->length); + } + + } + +done_proc: + up(&nodemgr_serialize); + + *start = page + (off - begin); + len -= (off - begin); + if (len > count) + len = count; + else { + *eof = 1; + if (len <= 0) + return 0; + } + + return len; +} + +#undef PUTF +#endif /* CONFIG_PROC_FS */ + +static void nodemgr_process_config_rom(struct node_entry *ne, + quadlet_t busoptions); + +static int nodemgr_read_quadlet(struct hpsb_host *host, + nodeid_t nodeid, unsigned int generation, + octlet_t address, quadlet_t *quad) +{ + int i; + int ret = 0; + + for (i = 0; i < 3; i++) { + ret = hpsb_read(host, nodeid, generation, address, quad, 4); + if (!ret) + break; + + set_current_state(TASK_INTERRUPTIBLE); + if (schedule_timeout (HZ/3)) + return -1; + } + *quad = be32_to_cpu(*quad); + + return ret; +} + +static int nodemgr_size_text_leaf(struct hpsb_host *host, + nodeid_t nodeid, unsigned int generation, + octlet_t address) +{ + quadlet_t quad; + int size = 0; + + if (nodemgr_read_quadlet(host, nodeid, generation, address, &quad)) + return -1; + + if (CONFIG_ROM_KEY(quad) == CONFIG_ROM_DESCRIPTOR_LEAF) { + /* This is the offset. */ + address += 4 * CONFIG_ROM_VALUE(quad); + if (nodemgr_read_quadlet(host, nodeid, generation, address, &quad)) + return -1; + /* Now we got the size of the text descriptor leaf. */ + size = CONFIG_ROM_LEAF_LENGTH(quad); + } + + return size; +} + +static int nodemgr_read_text_leaf(struct node_entry *ne, + octlet_t address, + quadlet_t *quadp) +{ + quadlet_t quad; + int i, size, ret; + + if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation, address, &quad) + || CONFIG_ROM_KEY(quad) != CONFIG_ROM_DESCRIPTOR_LEAF) + return -1; + + /* This is the offset. */ + address += 4 * CONFIG_ROM_VALUE(quad); + if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation, address, &quad)) + return -1; + + /* Now we got the size of the text descriptor leaf. */ + size = CONFIG_ROM_LEAF_LENGTH(quad) - 2; + if (size <= 0) + return -1; + + address += 4; + for (i = 0; i < 2; i++, address += 4, quadp++) { + if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation, address, quadp)) + return -1; + } + + /* Now read the text string. */ + ret = -ENXIO; + for (; size > 0; size--, address += 4, quadp++) { + for (i = 0; i < 3; i++) { + ret = hpsb_node_read(ne, address, quadp, 4); + if (ret != -EAGAIN) + break; + } + if (ret) + break; + } + + return ret; +} + +static struct node_entry *nodemgr_scan_root_directory + (struct hpsb_host *host, nodeid_t nodeid, unsigned int generation) +{ + octlet_t address; + quadlet_t quad; + int length; + int code, size, total_size; + struct node_entry *ne; + + address = CSR_REGISTER_BASE + CSR_CONFIG_ROM; + + if (nodemgr_read_quadlet(host, nodeid, generation, address, &quad)) + return NULL; + + if (CONFIG_ROM_BUS_INFO_LENGTH(quad) == 1) /* minimal config rom */ + return NULL; + + address += 4 + CONFIG_ROM_BUS_INFO_LENGTH(quad) * 4; + + if (nodemgr_read_quadlet(host, nodeid, generation, address, &quad)) + return NULL; + length = CONFIG_ROM_ROOT_LENGTH(quad); + address += 4; + + size = 0; + total_size = sizeof(struct node_entry); + for (; length > 0; length--, address += 4) { + if (nodemgr_read_quadlet(host, nodeid, generation, address, &quad)) + return NULL; + code = CONFIG_ROM_KEY(quad); + + if (code == CONFIG_ROM_VENDOR_ID && length > 0) { + /* Check if there is a text descriptor leaf + immediately after this. */ + size = nodemgr_size_text_leaf(host, nodeid, generation, + address + 4); + if (size > 0) { + address += 4; + length--; + total_size += (size + 1) * sizeof (quadlet_t); + } else if (size < 0) + return NULL; + } + } + ne = kmalloc(total_size, GFP_KERNEL); + + if (!ne) + return NULL; + + memset(ne, 0, total_size); + + if (size != 0) { + ne->vendor_name = (const char *) &(ne->quadlets[2]); + ne->quadlets[size] = 0; + } else { + ne->vendor_name = NULL; + } + + return ne; +} + +static struct node_entry *nodemgr_create_node(octlet_t guid, quadlet_t busoptions, + struct host_info *hi, + nodeid_t nodeid, unsigned int generation) +{ + struct hpsb_host *host = hi->host; + struct node_entry *ne; + + ne = nodemgr_scan_root_directory (host, nodeid, generation); + if (!ne) return NULL; + + INIT_LIST_HEAD(&ne->list); + INIT_LIST_HEAD(&ne->unit_directories); + ne->host = host; + ne->nodeid = nodeid; + ne->generation = generation; + ne->guid = guid; + ne->guid_vendor_id = (guid >> 40) & 0xffffff; + ne->guid_vendor_oui = nodemgr_find_oui_name(ne->guid_vendor_id); + + list_add_tail(&ne->list, &node_list); + + nodemgr_process_config_rom (ne, busoptions); + + HPSB_DEBUG("%s added: ID:BUS[" NODE_BUS_FMT "] GUID[%016Lx]", + (host->node_id == nodeid) ? "Host" : "Node", + NODE_BUS_ARGS(host, nodeid), (unsigned long long)guid); + + return ne; +} + +static struct node_entry *find_entry_by_guid(u64 guid) +{ + struct list_head *lh; + struct node_entry *ne; + + list_for_each(lh, &node_list) { + ne = list_entry(lh, struct node_entry, list); + if (ne->guid == guid) return ne; + } + + return NULL; +} + +static struct node_entry *find_entry_by_nodeid(struct hpsb_host *host, nodeid_t nodeid) +{ + struct list_head *lh; + struct node_entry *ne; + + list_for_each(lh, &node_list) { + ne = list_entry(lh, struct node_entry, list); + if (ne->nodeid == nodeid && ne->host == host) + return ne; + } + + return NULL; +} + +static struct unit_directory *nodemgr_scan_unit_directory + (struct node_entry *ne, octlet_t address) +{ + struct unit_directory *ud; + quadlet_t quad; + u8 flags, todo; + int length, size, total_size, count; + int vendor_name_size, model_name_size; + + if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation, address, &quad)) + return NULL; + length = CONFIG_ROM_DIRECTORY_LENGTH(quad) ; + address += 4; + + size = 0; + total_size = sizeof (struct unit_directory); + flags = 0; + count = 0; + vendor_name_size = 0; + model_name_size = 0; + for (; length > 0; length--, address += 4) { + int code; + quadlet_t value; + + if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation, + address, &quad)) + return NULL; + code = CONFIG_ROM_KEY(quad); + value = CONFIG_ROM_VALUE(quad); + + todo = 0; + switch (code) { + case CONFIG_ROM_VENDOR_ID: + todo = UNIT_DIRECTORY_VENDOR_TEXT; + break; + + case CONFIG_ROM_MODEL_ID: + todo = UNIT_DIRECTORY_MODEL_TEXT; + break; + + case CONFIG_ROM_SPECIFIER_ID: + case CONFIG_ROM_UNIT_SW_VERSION: + break; + + case CONFIG_ROM_DESCRIPTOR_LEAF: + case CONFIG_ROM_DESCRIPTOR_DIRECTORY: + /* TODO: read strings... icons? */ + break; + + default: + /* Which types of quadlets do we want to + store? Only count immediate values and + CSR offsets for now. */ + code &= CONFIG_ROM_KEY_TYPE_MASK; + if ((code & CONFIG_ROM_KEY_TYPE_LEAF) == 0) + count++; + break; + } + + if (todo && length > 0) { + /* Check if there is a text descriptor leaf + immediately after this. */ + size = nodemgr_size_text_leaf(ne->host, + ne->nodeid, + ne->generation, + address + 4); + + if (todo == UNIT_DIRECTORY_VENDOR_TEXT) + vendor_name_size = size; + else + model_name_size = size; + + if (size > 0) { + address += 4; + length--; + flags |= todo; + total_size += (size + 1) * sizeof (quadlet_t); + } + else if (size < 0) + return NULL; + } + } + + total_size += count * sizeof (quadlet_t); + ud = kmalloc (total_size, GFP_KERNEL); + + if (ud != NULL) { + memset (ud, 0, total_size); + ud->flags = flags; + ud->length = count; + ud->vendor_name_size = vendor_name_size; + ud->model_name_size = model_name_size; + } + + return ud; +} + + +/* This implementation currently only scans the config rom and its + * immediate unit directories looking for software_id and + * software_version entries, in order to get driver autoloading working. */ +static struct unit_directory * nodemgr_process_unit_directory + (struct node_entry *ne, octlet_t address, struct unit_directory *parent) +{ + struct unit_directory *ud; + quadlet_t quad; + quadlet_t *infop; + int length; + struct unit_directory *ud_temp = NULL; + + if (!(ud = nodemgr_scan_unit_directory(ne, address))) + goto unit_directory_error; + + ud->ne = ne; + ud->address = address; + + if (parent) { + ud->flags |= UNIT_DIRECTORY_LUN_DIRECTORY; + ud->parent = parent; + } + + if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation, + address, &quad)) + goto unit_directory_error; + length = CONFIG_ROM_DIRECTORY_LENGTH(quad) ; + address += 4; + + infop = (quadlet_t *) ud->quadlets; + for (; length > 0; length--, address += 4) { + int code; + quadlet_t value; + quadlet_t *quadp; + + if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation, + address, &quad)) + goto unit_directory_error; + code = CONFIG_ROM_KEY(quad) ; + value = CONFIG_ROM_VALUE(quad); + + switch (code) { + case CONFIG_ROM_VENDOR_ID: + ud->vendor_id = value; + ud->flags |= UNIT_DIRECTORY_VENDOR_ID; + + if (ud->vendor_id) + ud->vendor_oui = nodemgr_find_oui_name(ud->vendor_id); + + if ((ud->flags & UNIT_DIRECTORY_VENDOR_TEXT) != 0) { + length--; + address += 4; + quadp = &(ud->quadlets[ud->length]); + if (nodemgr_read_text_leaf(ne, address, quadp) == 0 + && quadp[0] == 0 && quadp[1] == 0) { + /* We only support minimal + ASCII and English. */ + quadp[ud->vendor_name_size] = 0; + ud->vendor_name + = (const char *) &(quadp[2]); + } + } + break; + + case CONFIG_ROM_MODEL_ID: + ud->model_id = value; + ud->flags |= UNIT_DIRECTORY_MODEL_ID; + if ((ud->flags & UNIT_DIRECTORY_MODEL_TEXT) != 0) { + length--; + address += 4; + quadp = &(ud->quadlets[ud->length + ud->vendor_name_size + 1]); + if (nodemgr_read_text_leaf(ne, address, quadp) == 0 + && quadp[0] == 0 && quadp[1] == 0) { + /* We only support minimal + ASCII and English. */ + quadp[ud->model_name_size] = 0; + ud->model_name + = (const char *) &(quadp[2]); + } + } + break; + + case CONFIG_ROM_SPECIFIER_ID: + ud->specifier_id = value; + ud->flags |= UNIT_DIRECTORY_SPECIFIER_ID; + break; + + case CONFIG_ROM_UNIT_SW_VERSION: + ud->version = value; + ud->flags |= UNIT_DIRECTORY_VERSION; + break; + + case CONFIG_ROM_DESCRIPTOR_LEAF: + case CONFIG_ROM_DESCRIPTOR_DIRECTORY: + /* TODO: read strings... icons? */ + break; + + case CONFIG_ROM_LOGICAL_UNIT_DIRECTORY: + ud->flags |= UNIT_DIRECTORY_HAS_LUN_DIRECTORY; + ud_temp = nodemgr_process_unit_directory(ne, address + value * 4, ud); + + if (ud_temp == NULL) + break; + + /* inherit unspecified values */ + if ((ud->flags & UNIT_DIRECTORY_VENDOR_ID) && + !(ud_temp->flags & UNIT_DIRECTORY_VENDOR_ID)) + { + ud_temp->flags |= UNIT_DIRECTORY_VENDOR_ID; + ud_temp->vendor_id = ud->vendor_id; + } + if ((ud->flags & UNIT_DIRECTORY_MODEL_ID) && + !(ud_temp->flags & UNIT_DIRECTORY_MODEL_ID)) + { + ud_temp->flags |= UNIT_DIRECTORY_MODEL_ID; + ud_temp->model_id = ud->model_id; + } + if ((ud->flags & UNIT_DIRECTORY_SPECIFIER_ID) && + !(ud_temp->flags & UNIT_DIRECTORY_SPECIFIER_ID)) + { + ud_temp->flags |= UNIT_DIRECTORY_SPECIFIER_ID; + ud_temp->specifier_id = ud->specifier_id; + } + if ((ud->flags & UNIT_DIRECTORY_VERSION) && + !(ud_temp->flags & UNIT_DIRECTORY_VERSION)) + { + ud_temp->flags |= UNIT_DIRECTORY_VERSION; + ud_temp->version = ud->version; + } + + break; + + default: + /* Which types of quadlets do we want to + store? Only count immediate values and + CSR offsets for now. */ + code &= CONFIG_ROM_KEY_TYPE_MASK; + if ((code & CONFIG_ROM_KEY_TYPE_LEAF) == 0) + *infop++ = quad; + break; + } + } + + list_add_tail(&ud->node_list, &ne->unit_directories); + list_add_tail(&ud->driver_list, &unit_directory_list); + + return ud; + +unit_directory_error: + if (ud != NULL) + kfree(ud); + return NULL; +} + + +static void nodemgr_process_root_directory(struct node_entry *ne) +{ + octlet_t address; + quadlet_t quad; + int length; + + address = CSR_REGISTER_BASE + CSR_CONFIG_ROM; + + if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation, + address, &quad)) + return; + address += 4 + CONFIG_ROM_BUS_INFO_LENGTH(quad) * 4; + + if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation, + address, &quad)) + return; + length = CONFIG_ROM_ROOT_LENGTH(quad); + address += 4; + + for (; length > 0; length--, address += 4) { + int code, value; + + if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation, + address, &quad)) + return; + code = CONFIG_ROM_KEY(quad); + value = CONFIG_ROM_VALUE(quad); + + switch (code) { + case CONFIG_ROM_VENDOR_ID: + ne->vendor_id = value; + + if (ne->vendor_id) + ne->vendor_oui = nodemgr_find_oui_name(ne->vendor_id); + + /* Now check if there is a vendor name text + string. */ + if (ne->vendor_name != NULL) { + length--; + address += 4; + if (nodemgr_read_text_leaf(ne, address, ne->quadlets) != 0 + || ne->quadlets[0] != 0 || ne->quadlets[1] != 0) + /* We only support minimal + ASCII and English. */ + ne->vendor_name = NULL; + } + break; + + case CONFIG_ROM_NODE_CAPABILITES: + ne->capabilities = value; + break; + + case CONFIG_ROM_UNIT_DIRECTORY: + nodemgr_process_unit_directory(ne, address + value * 4, NULL); + break; + + case CONFIG_ROM_DESCRIPTOR_LEAF: + case CONFIG_ROM_DESCRIPTOR_DIRECTORY: + /* TODO: read strings... icons? */ + break; + } + } +} + +#ifdef CONFIG_HOTPLUG + +static void nodemgr_call_policy(char *verb, struct unit_directory *ud) +{ + char *argv [3], **envp, *buf, *scratch; + int i = 0, value; + + if (!hotplug_path [0]) + return; + if (!current->fs->root) + return; + if (!(envp = (char **) kmalloc(20 * sizeof (char *), GFP_KERNEL))) { + HPSB_DEBUG ("ENOMEM"); + return; + } + if (!(buf = kmalloc(256, GFP_KERNEL))) { + kfree(envp); + HPSB_DEBUG("ENOMEM2"); + return; + } + + /* only one standardized param to hotplug command: type */ + argv[0] = hotplug_path; + argv[1] = "ieee1394"; + argv[2] = 0; + + /* minimal command environment */ + envp[i++] = "HOME=/"; + envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; + +#ifdef CONFIG_IEEE1394_VERBOSEDEBUG + /* hint that policy agent should enter no-stdout debug mode */ + envp[i++] = "DEBUG=kernel"; +#endif + /* extensible set of named bus-specific parameters, + * supporting multiple driver selection algorithms. + */ + scratch = buf; + + envp[i++] = scratch; + scratch += sprintf(scratch, "ACTION=%s", verb) + 1; + envp[i++] = scratch; + scratch += sprintf(scratch, "VENDOR_ID=%06x", ud->vendor_id) + 1; + envp[i++] = scratch; + scratch += sprintf(scratch, "GUID=%016Lx", (long long unsigned)ud->ne->guid) + 1; + envp[i++] = scratch; + scratch += sprintf(scratch, "SPECIFIER_ID=%06x", ud->specifier_id) + 1; + envp[i++] = scratch; + scratch += sprintf(scratch, "VERSION=%06x", ud->version) + 1; + envp[i++] = 0; + + /* NOTE: user mode daemons can call the agents too */ + HPSB_VERBOSE("NodeMgr: %s %s %016Lx", argv[0], verb, (long long unsigned)ud->ne->guid); + + value = call_usermodehelper(argv[0], argv, envp); + kfree(buf); + kfree(envp); + if (value != 0) + HPSB_DEBUG("NodeMgr: hotplug policy returned %d", value); +} + +#else + +static inline void +nodemgr_call_policy(char *verb, struct unit_directory *ud) +{ + HPSB_VERBOSE("NodeMgr: nodemgr_call_policy(): hotplug not enabled"); + return; +} + +#endif /* CONFIG_HOTPLUG */ + +static void nodemgr_claim_unit_directory(struct unit_directory *ud, + struct hpsb_protocol_driver *driver) +{ + ud->driver = driver; + list_move_tail(&ud->driver_list, &driver->unit_directories); +} + +static void nodemgr_release_unit_directory(struct unit_directory *ud) +{ + ud->driver = NULL; + list_move_tail(&ud->driver_list, &unit_directory_list); +} + +void hpsb_release_unit_directory(struct unit_directory *ud) +{ + down(&nodemgr_serialize); + nodemgr_release_unit_directory(ud); + up(&nodemgr_serialize); +} + +static void nodemgr_free_unit_directories(struct node_entry *ne) +{ + struct list_head *lh, *next; + struct unit_directory *ud; + + list_for_each_safe(lh, next, &ne->unit_directories) { + ud = list_entry(lh, struct unit_directory, node_list); + + if (ud->driver && ud->driver->disconnect) + ud->driver->disconnect(ud); + + nodemgr_release_unit_directory(ud); + nodemgr_call_policy("remove", ud); + + list_del(&ud->driver_list); + list_del(&ud->node_list); + + kfree(ud); + } +} + +static struct ieee1394_device_id * +nodemgr_match_driver(struct hpsb_protocol_driver *driver, + struct unit_directory *ud) +{ + struct ieee1394_device_id *id; + + for (id = driver->id_table; id->match_flags != 0; id++) { + if ((id->match_flags & IEEE1394_MATCH_VENDOR_ID) && + id->vendor_id != ud->vendor_id) + continue; + + if ((id->match_flags & IEEE1394_MATCH_MODEL_ID) && + id->model_id != ud->model_id) + continue; + + if ((id->match_flags & IEEE1394_MATCH_SPECIFIER_ID) && + id->specifier_id != ud->specifier_id) + continue; + + /* software version does a bitwise comparison instead of equality */ + if ((id->match_flags & IEEE1394_MATCH_VERSION) && + !(id->version & ud->version)) + continue; + + return id; + } + + return NULL; +} + +static struct hpsb_protocol_driver * +nodemgr_find_driver(struct unit_directory *ud) +{ + struct list_head *l; + struct hpsb_protocol_driver *match, *driver; + struct ieee1394_device_id *device_id; + + match = NULL; + list_for_each(l, &driver_list) { + driver = list_entry(l, struct hpsb_protocol_driver, list); + device_id = nodemgr_match_driver(driver, ud); + + if (device_id != NULL) { + match = driver; + break; + } + } + + return match; +} + +static void nodemgr_bind_drivers (struct node_entry *ne) +{ + struct list_head *lh; + struct hpsb_protocol_driver *driver; + struct unit_directory *ud; + + list_for_each(lh, &ne->unit_directories) { + ud = list_entry(lh, struct unit_directory, node_list); + driver = nodemgr_find_driver(ud); + if (driver && (!driver->probe || driver->probe(ud) == 0)) + nodemgr_claim_unit_directory(ud, driver); + nodemgr_call_policy("add", ud); + } +} + + +int hpsb_register_protocol(struct hpsb_protocol_driver *driver) +{ + struct unit_directory *ud; + struct list_head *lh, *next; + + if (down_interruptible(&nodemgr_serialize)) + return -EINTR; + + list_add_tail(&driver->list, &driver_list); + + INIT_LIST_HEAD(&driver->unit_directories); + + list_for_each_safe (lh, next, &unit_directory_list) { + ud = list_entry(lh, struct unit_directory, driver_list); + + if (nodemgr_match_driver(driver, ud) && + (!driver->probe || driver->probe(ud) == 0)) + nodemgr_claim_unit_directory(ud, driver); + } + + up(&nodemgr_serialize); + + /* + * Right now registration always succeeds, but maybe we should + * detect clashes in protocols handled by other drivers. + * DRD> No because multiple drivers are needed to handle certain devices. + * For example, a DV camera is an IEC 61883 device (dv1394) and AV/C (raw1394). + * This will become less an issue with libiec61883 using raw1394. + * + * BenC: But can we handle this with an ALLOW_SHARED flag for a + * protocol? When we get an SBP-3 driver, it will be nice if they were + * mutually exclusive, since SBP-3 can handle SBP-2 protocol. + * + * Not to mention that we currently do not seem to support multiple + * drivers claiming the same unitdirectory. If we implement both of + * those, then we'll need to keep probing when a driver claims a + * unitdirectory, but is sharable. + */ + + return 0; +} + +void hpsb_unregister_protocol(struct hpsb_protocol_driver *driver) +{ + struct list_head *lh, *next; + struct unit_directory *ud; + + down(&nodemgr_serialize); + + list_del(&driver->list); + + list_for_each_safe (lh, next, &driver->unit_directories) { + ud = list_entry(lh, struct unit_directory, driver_list); + + if (ud->driver && ud->driver->disconnect) + ud->driver->disconnect(ud); + + nodemgr_release_unit_directory(ud); + } + + up(&nodemgr_serialize); +} + +static void nodemgr_process_config_rom(struct node_entry *ne, + quadlet_t busoptions) +{ + ne->busopt.irmc = (busoptions >> 31) & 1; + ne->busopt.cmc = (busoptions >> 30) & 1; + ne->busopt.isc = (busoptions >> 29) & 1; + ne->busopt.bmc = (busoptions >> 28) & 1; + ne->busopt.pmc = (busoptions >> 27) & 1; + ne->busopt.cyc_clk_acc = (busoptions >> 16) & 0xff; + ne->busopt.max_rec = 1 << (((busoptions >> 12) & 0xf) + 1); + ne->busopt.generation = (busoptions >> 4) & 0xf; + ne->busopt.lnkspd = busoptions & 0x7; + + HPSB_VERBOSE("NodeMgr: raw=0x%08x irmc=%d cmc=%d isc=%d bmc=%d pmc=%d " + "cyc_clk_acc=%d max_rec=%d gen=%d lspd=%d", + busoptions, ne->busopt.irmc, ne->busopt.cmc, + ne->busopt.isc, ne->busopt.bmc, ne->busopt.pmc, + ne->busopt.cyc_clk_acc, ne->busopt.max_rec, + ne->busopt.generation, ne->busopt.lnkspd); + + /* + * When the config rom changes we disconnect all drivers and + * free the cached unit directories and reread the whole + * thing. If this was a new device, the call to + * nodemgr_disconnect_drivers is a no-op and all is well. + */ + nodemgr_free_unit_directories(ne); + nodemgr_process_root_directory(ne); + nodemgr_bind_drivers(ne); +} + +/* + * This function updates nodes that were present on the bus before the + * reset and still are after the reset. The nodeid and the config rom + * may have changed, and the drivers managing this device must be + * informed that this device just went through a bus reset, to allow + * the to take whatever actions required. + */ +static void nodemgr_update_node(struct node_entry *ne, quadlet_t busoptions, + struct host_info *hi, nodeid_t nodeid, + unsigned int generation) +{ + struct list_head *lh; + struct unit_directory *ud; + + if (ne->nodeid != nodeid) { + HPSB_DEBUG("Node changed: " NODE_BUS_FMT " -> " NODE_BUS_FMT, + NODE_BUS_ARGS(ne->host, ne->nodeid), + NODE_BUS_ARGS(ne->host, nodeid)); + ne->nodeid = nodeid; + } + + if (ne->busopt.generation != ((busoptions >> 4) & 0xf)) + nodemgr_process_config_rom (ne, busoptions); + + /* Since that's done, we can declare this record current */ + ne->generation = generation; + + list_for_each (lh, &ne->unit_directories) { + ud = list_entry (lh, struct unit_directory, node_list); + if (ud->driver && ud->driver->update != NULL) + ud->driver->update(ud); + } +} + +static int read_businfo_block(struct hpsb_host *host, nodeid_t nodeid, unsigned int generation, + quadlet_t *buffer, int buffer_length) +{ + octlet_t addr = CSR_REGISTER_BASE + CSR_CONFIG_ROM; + unsigned header_size; + int i; + + /* IEEE P1212 says that devices should support 64byte block + * reads, aligned on 64byte boundaries. That doesn't seem to + * work though, and we are forced to doing quadlet sized + * reads. */ + + HPSB_VERBOSE("Initiating ConfigROM request for node " NODE_BUS_FMT, + NODE_BUS_ARGS(host, nodeid)); + + /* + * Must retry a few times if config rom read returns zero (how long?). Will + * not normally occur, but we should do the right thing. For example, with + * some sbp2 devices, the bridge chipset cannot return valid config rom reads + * immediately after power-on, since they need to detect the type of + * device attached (disk or CD-ROM). + */ + for (i = 0; i < 4; i++) { + if (nodemgr_read_quadlet(host, nodeid, generation, + addr, &buffer[0]) < 0) { + HPSB_ERR("ConfigROM quadlet transaction error for node " + NODE_BUS_FMT, NODE_BUS_ARGS(host, nodeid)); + return -1; + } + if (buffer[0]) + break; + + set_current_state(TASK_INTERRUPTIBLE); + if (schedule_timeout (HZ/4)) + return -1; + } + + header_size = buffer[0] >> 24; + addr += 4; + + if (header_size == 1) { + HPSB_INFO("Node " NODE_BUS_FMT " has a minimal ROM. " + "Vendor is %08x", + NODE_BUS_ARGS(host, nodeid), buffer[0] & 0x00ffffff); + return -1; + } + + if (header_size < 4) { + HPSB_INFO("Node " NODE_BUS_FMT " has non-standard ROM " + "format (%d quads), cannot parse", + NODE_BUS_ARGS(host, nodeid), header_size); + return -1; + } + + for (i = 1; i < buffer_length; i++, addr += 4) { + if (nodemgr_read_quadlet(host, nodeid, generation, + addr, &buffer[i]) < 0) { + HPSB_ERR("ConfigROM quadlet transaction " + "error for node " NODE_BUS_FMT, + NODE_BUS_ARGS(host, nodeid)); + return -1; + } + } + + return 0; +} + +static void nodemgr_remove_node(struct node_entry *ne) +{ + HPSB_DEBUG("Node removed: ID:BUS[" NODE_BUS_FMT "] GUID[%016Lx]", + NODE_BUS_ARGS(ne->host, ne->nodeid), (unsigned long long)ne->guid); + + nodemgr_free_unit_directories(ne); + list_del(&ne->list); + kfree(ne); + + return; +} + +/* This is where we probe the nodes for their information and provided + * features. */ +static void nodemgr_node_probe_one(struct host_info *hi, + nodeid_t nodeid, int generation) +{ + struct hpsb_host *host = hi->host; + struct node_entry *ne; + quadlet_t buffer[5]; + octlet_t guid; + + /* We need to detect when the ConfigROM's generation has changed, + * so we only update the node's info when it needs to be. */ + + if (read_businfo_block (host, nodeid, generation, + buffer, sizeof(buffer) >> 2)) + return; + + if (buffer[1] != IEEE1394_BUSID_MAGIC) { + /* This isn't a 1394 device, but we let it slide. There + * was a report of a device with broken firmware which + * reported '2394' instead of '1394', which is obviously a + * mistake. One would hope that a non-1394 device never + * gets connected to Firewire bus. If someone does, we + * shouldn't be held responsible, so we'll allow it with a + * warning. */ + HPSB_WARN("Node " NODE_BUS_FMT " has invalid busID magic [0x%08x]", + NODE_BUS_ARGS(host, nodeid), buffer[1]); + } + + guid = ((u64)buffer[3] << 32) | buffer[4]; + ne = find_entry_by_guid(guid); + + if (!ne) + nodemgr_create_node(guid, buffer[2], hi, nodeid, generation); + else + nodemgr_update_node(ne, buffer[2], hi, nodeid, generation); + + return; +} + +static void nodemgr_node_probe_cleanup(struct hpsb_host *host, unsigned int generation) +{ + struct list_head *lh, *next; + struct node_entry *ne; + + /* Now check to see if we have any nodes that aren't referenced + * any longer. */ + list_for_each_safe(lh, next, &node_list) { + ne = list_entry(lh, struct node_entry, list); + + /* Only checking this host */ + if (ne->host != host) + continue; + + /* If the generation didn't get updated, then either the + * node was removed, or it failed the above probe. Either + * way, we remove references to it, since they are + * invalid. */ + if (ne->generation != generation) + nodemgr_remove_node(ne); + } + + return; +} + +static void nodemgr_node_probe(struct host_info *hi, int generation) +{ + int count; + struct hpsb_host *host = hi->host; + struct selfid *sid = (struct selfid *)host->topology_map; + nodeid_t nodeid = LOCAL_BUS; + + /* Scan each node on the bus */ + for (count = host->selfid_count; count; count--, sid++) { + if (sid->extended) + continue; + + if (!sid->link_active) { + nodeid++; + continue; + } + nodemgr_node_probe_one(hi, nodeid++, generation); + } + + /* If we had a bus reset while we were scanning the bus, it is + * possible that we did not probe all nodes. In that case, we + * skip the clean up for now, since we could remove nodes that + * were still on the bus. The bus reset increased hi->reset_sem, + * so there's a bus scan pending which will do the clean up + * eventually. */ + if (generation == get_hpsb_generation(host)) + nodemgr_node_probe_cleanup(host, generation); + + return; +} + +/* Because we are a 1394a-2000 compliant IRM, we need to inform all the other + * nodes of the broadcast channel. (Really we're only setting the validity + * bit). Other IRM responsibilities go in here as well. */ +static void nodemgr_do_irm_duties(struct hpsb_host *host) +{ + quadlet_t bc; + + if (!host->is_irm) + return; + + host->csr.broadcast_channel |= 0x40000000; /* set validity bit */ + + bc = cpu_to_be32(host->csr.broadcast_channel); + + hpsb_write(host, LOCAL_BUS | ALL_NODES, get_hpsb_generation(host), + (CSR_REGISTER_BASE | CSR_BROADCAST_CHANNEL), + &bc, sizeof(quadlet_t)); + + /* If there is no bus manager then we should set the root node's + * force_root bit to promote bus stability per the 1394 + * spec. (8.4.2.6) */ + if (host->busmgr_id == 0xffff && host->node_count > 1) + { + u16 root_node = host->node_count - 1; + struct node_entry *ne = find_entry_by_nodeid(host, root_node | LOCAL_BUS); + + if (ne && ne->busopt.cmc) + hpsb_send_phy_config(host, root_node, -1); + else { + HPSB_DEBUG("The root node is not cycle master capable; " + "selecting a new root node and resetting..."); + hpsb_send_phy_config(host, NODEID_TO_NODE(host->node_id), -1); + hpsb_reset_bus(host, LONG_RESET_FORCE_ROOT); + } + } +} + +/* We need to ensure that if we are not the IRM, that the IRM node is capable of + * everything we can do, otherwise issue a bus reset and try to become the IRM + * ourselves. */ +static int nodemgr_check_irm_capability(struct hpsb_host *host, int cycles) +{ + quadlet_t bc; + int status; + + if (host->is_irm) + return 1; + + status = hpsb_read(host, LOCAL_BUS | (host->irm_id), + get_hpsb_generation(host), + (CSR_REGISTER_BASE | CSR_BROADCAST_CHANNEL), + &bc, sizeof(quadlet_t)); + + if (status < 0 || !(be32_to_cpu(bc) & 0x80000000)) { + /* The current irm node does not have a valid BROADCAST_CHANNEL + * register and we do, so reset the bus with force_root set */ + HPSB_DEBUG("Current remote IRM is not 1394a-2000 compliant, resetting..."); + + if (cycles >= 5) { + /* Oh screw it! Just leave the bus as it is */ + HPSB_DEBUG("Stopping reset loop for IRM sanity"); + return 1; + } + + hpsb_send_phy_config(host, NODEID_TO_NODE(host->node_id), -1); + hpsb_reset_bus(host, LONG_RESET_FORCE_ROOT); + + return 0; + } + + return 1; +} + +static int nodemgr_host_thread(void *__hi) +{ + struct host_info *hi = (struct host_info *)__hi; + struct hpsb_host *host = hi->host; + int reset_cycles = 0; + + /* No userlevel access needed */ + daemonize(); + + strcpy(current->comm, hi->daemon_name); + + /* Sit and wait for a signal to probe the nodes on the bus. This + * happens when we get a bus reset. */ + while (!down_interruptible(&hi->reset_sem) && + !down_interruptible(&nodemgr_serialize)) { + unsigned int generation = 0; + int i; + + /* Pause for 1/4 second in 1/16 second intervals, + * to make sure things settle down. */ + for (i = 0; i < 4 ; i++) { + set_current_state(TASK_INTERRUPTIBLE); + if (schedule_timeout(HZ/16)) { + up(&nodemgr_serialize); + goto caught_signal; + } + + /* Now get the generation in which the node ID's we collect + * are valid. During the bus scan we will use this generation + * for the read transactions, so that if another reset occurs + * during the scan the transactions will fail instead of + * returning bogus data. */ + generation = get_hpsb_generation(host); + + /* If we get a reset before we are done waiting, then + * start the the waiting over again */ + while (!down_trylock(&hi->reset_sem)) + i = 0; + } + + if (!nodemgr_check_irm_capability(host, reset_cycles++)) { + /* Do nothing, we are resetting */ + up(&nodemgr_serialize); + continue; + } + + reset_cycles = 0; + + nodemgr_node_probe(hi, generation); + nodemgr_do_irm_duties(host); + + up(&nodemgr_serialize); + } + +caught_signal: + HPSB_VERBOSE("NodeMgr: Exiting thread"); + + complete_and_exit(&hi->exited, 0); +} + +struct node_entry *hpsb_guid_get_entry(u64 guid) +{ + struct node_entry *ne; + + down(&nodemgr_serialize); + ne = find_entry_by_guid(guid); + up(&nodemgr_serialize); + + return ne; +} + +struct node_entry *hpsb_nodeid_get_entry(struct hpsb_host *host, nodeid_t nodeid) +{ + struct node_entry *ne; + + down(&nodemgr_serialize); + ne = find_entry_by_nodeid(host, nodeid); + up(&nodemgr_serialize); + + return ne; +} + +/* The following four convenience functions use a struct node_entry + * for addressing a node on the bus. They are intended for use by any + * process context, not just the nodemgr thread, so we need to be a + * little careful when reading out the node ID and generation. The + * thing that can go wrong is that we get the node ID, then a bus + * reset occurs, and then we read the generation. The node ID is + * possibly invalid, but the generation is current, and we end up + * sending a packet to a the wrong node. + * + * The solution is to make sure we read the generation first, so that + * if a reset occurs in the process, we end up with a stale generation + * and the transactions will fail instead of silently using wrong node + * ID's. + */ + +void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *pkt) +{ + pkt->host = ne->host; + pkt->generation = ne->generation; + barrier(); + pkt->node_id = ne->nodeid; +} + +int hpsb_node_read(struct node_entry *ne, u64 addr, + quadlet_t *buffer, size_t length) +{ + unsigned int generation = ne->generation; + + barrier(); + return hpsb_read(ne->host, ne->nodeid, generation, + addr, buffer, length); +} + +int hpsb_node_write(struct node_entry *ne, u64 addr, + quadlet_t *buffer, size_t length) +{ + unsigned int generation = ne->generation; + + barrier(); + return hpsb_write(ne->host, ne->nodeid, generation, + addr, buffer, length); +} + +int hpsb_node_lock(struct node_entry *ne, u64 addr, + int extcode, quadlet_t *data, quadlet_t arg) +{ + unsigned int generation = ne->generation; + + barrier(); + return hpsb_lock(ne->host, ne->nodeid, generation, + addr, extcode, data, arg); +} + +static void nodemgr_add_host(struct hpsb_host *host) +{ + struct host_info *hi; + + hi = hpsb_create_hostinfo(&nodemgr_highlevel, host, sizeof(*hi)); + + if (!hi) { + HPSB_ERR ("NodeMgr: out of memory in add host"); + return; + } + + hi->host = host; + init_completion(&hi->exited); + sema_init(&hi->reset_sem, 0); + + sprintf(hi->daemon_name, "knodemgrd_%d", host->id); + + hi->pid = kernel_thread(nodemgr_host_thread, hi, + CLONE_FS | CLONE_FILES | CLONE_SIGHAND); + + if (hi->pid < 0) { + HPSB_ERR ("NodeMgr: failed to start %s thread for %s", + hi->daemon_name, host->driver->name); + hpsb_destroy_hostinfo(&nodemgr_highlevel, host); + return; + } + + return; +} + +static void nodemgr_host_reset(struct hpsb_host *host) +{ + struct host_info *hi = hpsb_get_hostinfo(&nodemgr_highlevel, host); + + if (hi != NULL) { + HPSB_VERBOSE("NodeMgr: Processing host reset for %s", hi->daemon_name); + up(&hi->reset_sem); + } else + HPSB_ERR ("NodeMgr: could not process reset of unused host"); + + return; +} + +static void nodemgr_remove_host(struct hpsb_host *host) +{ + struct list_head *lh, *next; + struct node_entry *ne; + struct host_info *hi = hpsb_get_hostinfo(&nodemgr_highlevel, host); + + if (hi) { + if (hi->pid >= 0) { + kill_proc(hi->pid, SIGTERM, 1); + wait_for_completion(&hi->exited); + } + } else + HPSB_ERR("NodeMgr: host %s does not exist, cannot remove", + host->driver->name); + + down(&nodemgr_serialize); + + /* Even if we fail the host_info part, remove all the node + * entries. */ + list_for_each_safe(lh, next, &node_list) { + ne = list_entry(lh, struct node_entry, list); + + if (ne->host == host) + nodemgr_remove_node(ne); + } + + up(&nodemgr_serialize); + + return; +} + +static struct hpsb_highlevel nodemgr_highlevel = { + .name = "Node manager", + .add_host = nodemgr_add_host, + .host_reset = nodemgr_host_reset, + .remove_host = nodemgr_remove_host, +}; + +#define PROC_ENTRY "devices" + +void init_ieee1394_nodemgr(void) +{ +#ifdef CONFIG_PROC_FS + if (!create_proc_read_entry(PROC_ENTRY, 0444, ieee1394_procfs_entry, raw1394_read_proc, NULL)) + HPSB_ERR("Can't create devices procfs entry"); +#endif + hpsb_register_highlevel(&nodemgr_highlevel); +} + +void cleanup_ieee1394_nodemgr(void) +{ + hpsb_unregister_highlevel(&nodemgr_highlevel); +#ifdef CONFIG_PROC_FS + remove_proc_entry(PROC_ENTRY, ieee1394_procfs_entry); +#endif +} diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/nodemgr.h.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/nodemgr.h.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/nodemgr.h.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/nodemgr.h.svn-base 2003-07-21 13:09:38.000000000 +0200 @@ -0,0 +1,259 @@ +/* + * Copyright (C) 2000 Andreas E. Bombe + * 2001 Ben Collins + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the 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 _IEEE1394_NODEMGR_H +#define _IEEE1394_NODEMGR_H + +#include "ieee1394_core.h" +#include "ieee1394_hotplug.h" + +#define CONFIG_ROM_BUS_INFO_LENGTH(q) ((q) >> 24) +#define CONFIG_ROM_BUS_CRC_LENGTH(q) (((q) >> 16) & 0xff) +#define CONFIG_ROM_BUS_CRC(q) ((q) & 0xffff) + +#define CONFIG_ROM_ROOT_LENGTH(q) ((q) >> 16) +#define CONFIG_ROM_ROOT_CRC(q) ((q) & 0xffff) + +#define CONFIG_ROM_DIRECTORY_LENGTH(q) ((q) >> 16) +#define CONFIG_ROM_DIRECTORY_CRC(q) ((q) & 0xffff) + +#define CONFIG_ROM_LEAF_LENGTH(q) ((q) >> 16) +#define CONFIG_ROM_LEAF_CRC(q) ((q) & 0xffff) + +#define CONFIG_ROM_DESCRIPTOR_TYPE(q) ((q) >> 24) +#define CONFIG_ROM_DESCRIPTOR_SPECIFIER_ID(q) ((q) & 0xffffff) +#define CONFIG_ROM_DESCRIPTOR_WIDTH(q) ((q) >> 28) +#define CONFIG_ROM_DESCRIPTOR_CHAR_SET(q) (((q) >> 16) & 0xfff) +#define CONFIG_ROM_DESCRIPTOR_LANG(q) ((q) & 0xffff) + +#define CONFIG_ROM_KEY_ID_MASK 0x3f +#define CONFIG_ROM_KEY_TYPE_MASK 0xc0 +#define CONFIG_ROM_KEY_TYPE_IMMEDIATE 0x00 +#define CONFIG_ROM_KEY_TYPE_OFFSET 0x40 +#define CONFIG_ROM_KEY_TYPE_LEAF 0x80 +#define CONFIG_ROM_KEY_TYPE_DIRECTORY 0xc0 + +#define CONFIG_ROM_KEY(q) ((q) >> 24) +#define CONFIG_ROM_VALUE(q) ((q) & 0xffffff) + +#define CONFIG_ROM_VENDOR_ID 0x03 +#define CONFIG_ROM_MODEL_ID 0x17 +#define CONFIG_ROM_NODE_CAPABILITES 0x0C +#define CONFIG_ROM_UNIT_DIRECTORY 0xd1 +#define CONFIG_ROM_LOGICAL_UNIT_DIRECTORY 0xd4 +#define CONFIG_ROM_SPECIFIER_ID 0x12 +#define CONFIG_ROM_UNIT_SW_VERSION 0x13 +#define CONFIG_ROM_DESCRIPTOR_LEAF 0x81 +#define CONFIG_ROM_DESCRIPTOR_DIRECTORY 0xc1 + +/* '1' '3' '9' '4' in ASCII */ +#define IEEE1394_BUSID_MAGIC 0x31333934 + +/* This is the start of a Node entry structure. It should be a stable API + * for which to gather info from the Node Manager about devices attached + * to the bus. */ +struct bus_options { + u8 irmc; /* Iso Resource Manager Capable */ + u8 cmc; /* Cycle Master Capable */ + u8 isc; /* Iso Capable */ + u8 bmc; /* Bus Master Capable */ + u8 pmc; /* Power Manager Capable (PNP spec) */ + u8 cyc_clk_acc; /* Cycle clock accuracy */ + u8 generation; /* Incremented when configrom changes */ + u8 lnkspd; /* Link speed */ + u16 max_rec; /* Maximum packet size node can receive */ +}; + +#define UNIT_DIRECTORY_VENDOR_ID 0x01 +#define UNIT_DIRECTORY_MODEL_ID 0x02 +#define UNIT_DIRECTORY_SPECIFIER_ID 0x04 +#define UNIT_DIRECTORY_VERSION 0x08 +#define UNIT_DIRECTORY_VENDOR_TEXT 0x10 +#define UNIT_DIRECTORY_MODEL_TEXT 0x20 +#define UNIT_DIRECTORY_HAS_LUN_DIRECTORY 0x40 +#define UNIT_DIRECTORY_LUN_DIRECTORY 0x80 + +/* + * A unit directory corresponds to a protocol supported by the + * node. If a node supports eg. IP/1394 and AV/C, its config rom has a + * unit directory for each of these protocols. + * + * Unit directories appear on two types of lists: for each node we + * maintain a list of the unit directories found in its config rom and + * for each driver we maintain a list of the unit directories + * (ie. devices) the driver manages. + */ +struct unit_directory { + struct node_entry *ne; /* The node which this directory belongs to */ + octlet_t address; /* Address of the unit directory on the node */ + u8 flags; /* Indicates which entries were read */ + + quadlet_t vendor_id; + const char *vendor_name; + const char *vendor_oui; + + int vendor_name_size; + quadlet_t model_id; + const char *model_name; + int model_name_size; + quadlet_t specifier_id; + quadlet_t version; + + struct hpsb_protocol_driver *driver; + void *driver_data; + + /* For linking the nodes managed by the driver, or unmanaged nodes */ + struct list_head driver_list; + + /* For linking directories belonging to a node */ + struct list_head node_list; + + /* for tracking unit versus logical unit */ + struct unit_directory *parent; + + int length; /* Number of quadlets */ + + /* XXX Must be last in the struct! */ + quadlet_t quadlets[0]; +}; + +struct node_entry { + struct list_head list; + u64 guid; /* GUID of this node */ + u32 guid_vendor_id; /* Top 24bits of guid */ + const char *guid_vendor_oui; /* OUI name of guid vendor id */ + + struct hpsb_host *host; /* Host this node is attached to */ + nodeid_t nodeid; /* NodeID */ + struct bus_options busopt; /* Bus Options */ + unsigned int generation; /* Synced with hpsb generation */ + + /* The following is read from the config rom */ + u32 vendor_id; + const char *vendor_name; + const char *vendor_oui; + + u32 capabilities; + struct hpsb_tlabel_pool *tpool; + struct list_head unit_directories; + + /* XXX Must be last in the struct! */ + quadlet_t quadlets[0]; +}; + +struct hpsb_protocol_driver { + /* The name of the driver, e.g. SBP2 or IP1394 */ + const char *name; + + /* + * The device id table describing the protocols and/or devices + * supported by this driver. This is used by the nodemgr to + * decide if a driver could support a given node, but the + * probe function below can implement further protocol + * dependent or vendor dependent checking. + */ + struct ieee1394_device_id *id_table; + + /* + * The probe function is called when a device is added to the + * bus and the nodemgr finds a matching entry in the drivers + * device id table or when registering this driver and a + * previously unhandled device can be handled. The driver may + * decline to handle the device based on further investigation + * of the device (or whatever reason) in which case a negative + * error code should be returned, otherwise 0 should be + * returned. The driver may use the driver_data field in the + * unit directory to store per device driver specific data. + */ + int (*probe)(struct unit_directory *ud); + + /* + * The disconnect function is called when a device is removed + * from the bus or if it wasn't possible to read the guid + * after the last bus reset. + */ + void (*disconnect)(struct unit_directory *ud); + + /* + * The update function is called when the node has just + * survived a bus reset, i.e. it is still present on the bus. + * However, it may be necessary to reestablish the connection + * or login into the node again, depending on the protocol. + */ + void (*update)(struct unit_directory *ud); + + /* Driver in list of all registered drivers */ + struct list_head list; + + /* The list of unit directories managed by this driver */ + struct list_head unit_directories; +}; + +int hpsb_register_protocol(struct hpsb_protocol_driver *driver); +void hpsb_unregister_protocol(struct hpsb_protocol_driver *driver); +void hpsb_release_unit_directory(struct unit_directory *ud); + +static inline int hpsb_node_entry_valid(struct node_entry *ne) +{ + return ne->generation == get_hpsb_generation(ne->host); +} + +/* + * Returns a node entry (which has its reference count incremented) or NULL if + * the GUID in question is not known. Getting a valid entry does not mean that + * the node with this GUID is currently accessible (might be powered down). + */ +struct node_entry *hpsb_guid_get_entry(u64 guid); + +/* Same as above, but use the nodeid to get an node entry. This is not + * fool-proof by itself, since the nodeid can change. */ +struct node_entry *hpsb_nodeid_get_entry(struct hpsb_host *host, nodeid_t nodeid); + +/* + * If the entry refers to a local host, this function will return the pointer + * to the hpsb_host structure. It will return NULL otherwise. Once you have + * established it is a local host, you can use that knowledge from then on (the + * GUID won't wander to an external node). */ +struct hpsb_host *hpsb_get_host_by_ne(struct node_entry *ne); + +/* + * This will fill in the given, pre-initialised hpsb_packet with the current + * information from the node entry (host, node ID, generation number). It will + * return false if the node owning the GUID is not accessible (and not modify the + * hpsb_packet) and return true otherwise. + * + * Note that packet sending may still fail in hpsb_send_packet if a bus reset + * happens while you are trying to set up the packet (due to obsolete generation + * number). It will at least reliably fail so that you don't accidentally and + * unknowingly send your packet to the wrong node. + */ +void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *pkt); + +int hpsb_node_read(struct node_entry *ne, u64 addr, + quadlet_t *buffer, size_t length); +int hpsb_node_write(struct node_entry *ne, u64 addr, + quadlet_t *buffer, size_t length); +int hpsb_node_lock(struct node_entry *ne, u64 addr, + int extcode, quadlet_t *data, quadlet_t arg); + + +void init_ieee1394_nodemgr(void); +void cleanup_ieee1394_nodemgr(void); + +#endif /* _IEEE1394_NODEMGR_H */ diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/ohci1394.c.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/ohci1394.c.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/ohci1394.c.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/ohci1394.c.svn-base 2003-09-08 03:33:03.000000000 +0200 @@ -0,0 +1,3742 @@ +/* + * ohci1394.c - driver for OHCI 1394 boards + * Copyright (C)1999,2000 Sebastien Rougeaux + * Gord Peters + * 2001 Ben Collins + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the 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. + */ + +/* + * Things known to be working: + * . Async Request Transmit + * . Async Response Receive + * . Async Request Receive + * . Async Response Transmit + * . Iso Receive + * . DMA mmap for iso receive + * . Config ROM generation + * + * Things implemented, but still in test phase: + * . Iso Transmit + * . Async Stream Packets Transmit (Receive done via Iso interface) + * + * Things not implemented: + * . DMA error recovery + * + * Known bugs: + * . devctl BUS_RESET arg confusion (reset type or root holdoff?) + * added LONG_RESET_ROOT and SHORT_RESET_ROOT for root holdoff --kk + */ + +/* + * Acknowledgments: + * + * Adam J Richter + * . Use of pci_class to find device + * + * Andreas Tobler + * . Updated proc_fs calls + * + * Emilie Chung + * . Tip on Async Request Filter + * + * Pascal Drolet + * . Various tips for optimization and functionnalities + * + * Robert Ficklin + * . Loop in irq_handler + * + * James Goodwin + * . Various tips on initialization, self-id reception, etc. + * + * Albrecht Dress + * . Apple PowerBook detection + * + * Daniel Kobras + * . Reset the board properly before leaving + misc cleanups + * + * Leon van Stuivenberg + * . Bug fixes + * + * Ben Collins + * . Working big-endian support + * . Updated to 2.4.x module scheme (PCI aswell) + * . Removed procfs support since it trashes random mem + * . Config ROM generation + * + * Manfred Weihs + * . Reworked code for initiating bus resets + * (long, short, with or without hold-off) + * + * Nandu Santhi + * . Added support for nVidia nForce2 onboard Firewire chipset + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_ALL_PPC +#include +#include +#include +#include +#endif + +#include "ieee1394.h" +#include "ieee1394_types.h" +#include "hosts.h" +#include "dma.h" +#include "iso.h" +#include "ieee1394_core.h" +#include "highlevel.h" +#include "ohci1394.h" + +#ifdef CONFIG_IEEE1394_VERBOSEDEBUG +#define OHCI1394_DEBUG +#endif + +#ifdef DBGMSG +#undef DBGMSG +#endif + +#ifdef OHCI1394_DEBUG +#define DBGMSG(card, fmt, args...) \ +printk(KERN_INFO "%s_%d: " fmt "\n" , OHCI1394_DRIVER_NAME, card , ## args) +#else +#define DBGMSG(card, fmt, args...) +#endif + +#ifdef CONFIG_IEEE1394_OHCI_DMA_DEBUG +#define OHCI_DMA_ALLOC(fmt, args...) \ + HPSB_ERR("%s(%s)alloc(%d): "fmt, OHCI1394_DRIVER_NAME, __FUNCTION__, \ + ++global_outstanding_dmas, ## args) +#define OHCI_DMA_FREE(fmt, args...) \ + HPSB_ERR("%s(%s)free(%d): "fmt, OHCI1394_DRIVER_NAME, __FUNCTION__, \ + --global_outstanding_dmas, ## args) +static int global_outstanding_dmas = 0; +#else +#define OHCI_DMA_ALLOC(fmt, args...) +#define OHCI_DMA_FREE(fmt, args...) +#endif + +/* print general (card independent) information */ +#define PRINT_G(level, fmt, args...) \ +printk(level "%s: " fmt "\n" , OHCI1394_DRIVER_NAME , ## args) + +/* print card specific information */ +#define PRINT(level, card, fmt, args...) \ +printk(level "%s_%d: " fmt "\n" , OHCI1394_DRIVER_NAME, card , ## args) + +static char version[] __devinitdata = + "$Rev$ Ben Collins "; + +/* Module Parameters */ +MODULE_PARM(phys_dma,"i"); +MODULE_PARM_DESC(phys_dma, "Enable physical dma (default = 1)."); +static int phys_dma = 1; + +static void dma_trm_tasklet(unsigned long data); +static void dma_trm_reset(struct dma_trm_ctx *d); + +static int alloc_dma_rcv_ctx(struct ti_ohci *ohci, struct dma_rcv_ctx *d, + enum context_type type, int ctx, int num_desc, + int buf_size, int split_buf_size, int context_base); +static void free_dma_rcv_ctx(struct dma_rcv_ctx *d); + +static int alloc_dma_trm_ctx(struct ti_ohci *ohci, struct dma_trm_ctx *d, + enum context_type type, int ctx, int num_desc, + int context_base); + +static void ohci1394_pci_remove(struct pci_dev *pdev); + +#ifndef __LITTLE_ENDIAN +static unsigned hdr_sizes[] = +{ + 3, /* TCODE_WRITEQ */ + 4, /* TCODE_WRITEB */ + 3, /* TCODE_WRITE_RESPONSE */ + 0, /* ??? */ + 3, /* TCODE_READQ */ + 4, /* TCODE_READB */ + 3, /* TCODE_READQ_RESPONSE */ + 4, /* TCODE_READB_RESPONSE */ + 1, /* TCODE_CYCLE_START (???) */ + 4, /* TCODE_LOCK_REQUEST */ + 2, /* TCODE_ISO_DATA */ + 4, /* TCODE_LOCK_RESPONSE */ +}; + +/* Swap headers */ +static inline void packet_swab(quadlet_t *data, int tcode) +{ + size_t size = hdr_sizes[tcode]; + + if (tcode > TCODE_LOCK_RESPONSE || hdr_sizes[tcode] == 0) + return; + + while (size--) + data[size] = swab32(data[size]); +} +#else +/* Don't waste cycles on same sex byte swaps */ +#define packet_swab(w,x) +#endif /* !LITTLE_ENDIAN */ + +/*********************************** + * IEEE-1394 functionality section * + ***********************************/ + +static u8 get_phy_reg(struct ti_ohci *ohci, u8 addr) +{ + int i; + unsigned long flags; + quadlet_t r; + + spin_lock_irqsave (&ohci->phy_reg_lock, flags); + + reg_write(ohci, OHCI1394_PhyControl, (addr << 8) | 0x00008000); + + for (i = 0; i < OHCI_LOOP_COUNT; i++) { + if (reg_read(ohci, OHCI1394_PhyControl) & 0x80000000) + break; + + mdelay(1); + } + + r = reg_read(ohci, OHCI1394_PhyControl); + + if (i >= OHCI_LOOP_COUNT) + PRINT (KERN_ERR, ohci->id, "Get PHY Reg timeout [0x%08x/0x%08x/%d]", + r, r & 0x80000000, i); + + spin_unlock_irqrestore (&ohci->phy_reg_lock, flags); + + return (r & 0x00ff0000) >> 16; +} + +static void set_phy_reg(struct ti_ohci *ohci, u8 addr, u8 data) +{ + int i; + unsigned long flags; + u32 r = 0; + + spin_lock_irqsave (&ohci->phy_reg_lock, flags); + + reg_write(ohci, OHCI1394_PhyControl, (addr << 8) | data | 0x00004000); + + for (i = 0; i < OHCI_LOOP_COUNT; i++) { + r = reg_read(ohci, OHCI1394_PhyControl); + if (!(r & 0x00004000)) + break; + + mdelay(1); + } + + if (i == OHCI_LOOP_COUNT) + PRINT (KERN_ERR, ohci->id, "Set PHY Reg timeout [0x%08x/0x%08x/%d]", + r, r & 0x00004000, i); + + spin_unlock_irqrestore (&ohci->phy_reg_lock, flags); + + return; +} + +/* Or's our value into the current value */ +static void set_phy_reg_mask(struct ti_ohci *ohci, u8 addr, u8 data) +{ + u8 old; + + old = get_phy_reg (ohci, addr); + old |= data; + set_phy_reg (ohci, addr, old); + + return; +} + +static void handle_selfid(struct ti_ohci *ohci, struct hpsb_host *host, + int phyid, int isroot) +{ + quadlet_t *q = ohci->selfid_buf_cpu; + quadlet_t self_id_count=reg_read(ohci, OHCI1394_SelfIDCount); + size_t size; + quadlet_t q0, q1; + + /* Check status of self-id reception */ + + if (ohci->selfid_swap) + q0 = le32_to_cpu(q[0]); + else + q0 = q[0]; + + if ((self_id_count & 0x80000000) || + ((self_id_count & 0x00FF0000) != (q0 & 0x00FF0000))) { + PRINT(KERN_ERR, ohci->id, + "Error in reception of SelfID packets [0x%08x/0x%08x] (count: %d)", + self_id_count, q0, ohci->self_id_errors); + + /* Tip by James Goodwin : + * We had an error, generate another bus reset in response. */ + if (ohci->self_id_errorsself_id_errors++; + } else { + PRINT(KERN_ERR, ohci->id, + "Too many errors on SelfID error reception, giving up!"); + } + return; + } + + /* SelfID Ok, reset error counter. */ + ohci->self_id_errors = 0; + + size = ((self_id_count & 0x00001FFC) >> 2) - 1; + q++; + + while (size > 0) { + if (ohci->selfid_swap) { + q0 = le32_to_cpu(q[0]); + q1 = le32_to_cpu(q[1]); + } else { + q0 = q[0]; + q1 = q[1]; + } + + if (q0 == ~q1) { + DBGMSG (ohci->id, "SelfID packet 0x%x received", q0); + hpsb_selfid_received(host, cpu_to_be32(q0)); + if (((q0 & 0x3f000000) >> 24) == phyid) + DBGMSG (ohci->id, "SelfID for this node is 0x%08x", q0); + } else { + PRINT(KERN_ERR, ohci->id, + "SelfID is inconsistent [0x%08x/0x%08x]", q0, q1); + } + q += 2; + size -= 2; + } + + DBGMSG(ohci->id, "SelfID complete"); + + return; +} + +static void ohci_soft_reset(struct ti_ohci *ohci) { + int i; + + reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_softReset); + + for (i = 0; i < OHCI_LOOP_COUNT; i++) { + if (!reg_read(ohci, OHCI1394_HCControlSet) & OHCI1394_HCControl_softReset) + break; + mdelay(1); + } + DBGMSG (ohci->id, "Soft reset finished"); +} + +static int run_context(struct ti_ohci *ohci, int reg, char *msg) +{ + u32 nodeId; + + /* check that the node id is valid */ + nodeId = reg_read(ohci, OHCI1394_NodeID); + if (!(nodeId&0x80000000)) { + PRINT(KERN_ERR, ohci->id, + "Running dma failed because Node ID is not valid"); + return -1; + } + + /* check that the node number != 63 */ + if ((nodeId&0x3f)==63) { + PRINT(KERN_ERR, ohci->id, + "Running dma failed because Node ID == 63"); + return -1; + } + + /* Run the dma context */ + reg_write(ohci, reg, 0x8000); + + if (msg) PRINT(KERN_DEBUG, ohci->id, "%s", msg); + + return 0; +} + +/* Generate the dma receive prgs and start the context */ +static void initialize_dma_rcv_ctx(struct dma_rcv_ctx *d, int generate_irq) +{ + struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci); + int i; + + ohci1394_stop_context(ohci, d->ctrlClear, NULL); + + for (i=0; inum_desc; i++) { + u32 c; + + c = DMA_CTL_INPUT_MORE | DMA_CTL_UPDATE | DMA_CTL_BRANCH; + if (generate_irq) + c |= DMA_CTL_IRQ; + + d->prg_cpu[i]->control = cpu_to_le32(c | d->buf_size); + + /* End of descriptor list? */ + if (i + 1 < d->num_desc) { + d->prg_cpu[i]->branchAddress = + cpu_to_le32((d->prg_bus[i+1] & 0xfffffff0) | 0x1); + } else { + d->prg_cpu[i]->branchAddress = + cpu_to_le32((d->prg_bus[0] & 0xfffffff0)); + } + + d->prg_cpu[i]->address = cpu_to_le32(d->buf_bus[i]); + d->prg_cpu[i]->status = cpu_to_le32(d->buf_size); + } + + d->buf_ind = 0; + d->buf_offset = 0; + + if (d->type == DMA_CTX_ISO) { + /* Clear contextControl */ + reg_write(ohci, d->ctrlClear, 0xffffffff); + + /* Set bufferFill, isochHeader, multichannel for IR context */ + reg_write(ohci, d->ctrlSet, 0xd0000000); + + /* Set the context match register to match on all tags */ + reg_write(ohci, d->ctxtMatch, 0xf0000000); + + /* Clear the multi channel mask high and low registers */ + reg_write(ohci, OHCI1394_IRMultiChanMaskHiClear, 0xffffffff); + reg_write(ohci, OHCI1394_IRMultiChanMaskLoClear, 0xffffffff); + + /* Set up isoRecvIntMask to generate interrupts */ + reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 1 << d->ctx); + } + + /* Tell the controller where the first AR program is */ + reg_write(ohci, d->cmdPtr, d->prg_bus[0] | 0x1); + + /* Run context */ + reg_write(ohci, d->ctrlSet, 0x00008000); + + DBGMSG(ohci->id, "Receive DMA ctx=%d initialized", d->ctx); +} + +/* Initialize the dma transmit context */ +static void initialize_dma_trm_ctx(struct dma_trm_ctx *d) +{ + struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci); + + /* Stop the context */ + ohci1394_stop_context(ohci, d->ctrlClear, NULL); + + d->prg_ind = 0; + d->sent_ind = 0; + d->free_prgs = d->num_desc; + d->branchAddrPtr = NULL; + INIT_LIST_HEAD(&d->fifo_list); + INIT_LIST_HEAD(&d->pending_list); + + if (d->type == DMA_CTX_ISO) { + /* enable interrupts */ + reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, 1 << d->ctx); + } + + DBGMSG(ohci->id, "Transmit DMA ctx=%d initialized", d->ctx); +} + +/* Count the number of available iso contexts */ +static int get_nb_iso_ctx(struct ti_ohci *ohci, int reg) +{ + int i,ctx=0; + u32 tmp; + + reg_write(ohci, reg, 0xffffffff); + tmp = reg_read(ohci, reg); + + DBGMSG(ohci->id,"Iso contexts reg: %08x implemented: %08x", reg, tmp); + + /* Count the number of contexts */ + for (i=0; i<32; i++) { + if (tmp & 1) ctx++; + tmp >>= 1; + } + return ctx; +} + +static void ohci_init_config_rom(struct ti_ohci *ohci); + +/* Global initialization */ +static void ohci_initialize(struct ti_ohci *ohci) +{ + char irq_buf[16]; + quadlet_t buf; + + spin_lock_init(&ohci->phy_reg_lock); + spin_lock_init(&ohci->event_lock); + + /* Put some defaults to these undefined bus options */ + buf = reg_read(ohci, OHCI1394_BusOptions); + buf |= 0xE0000000; /* Enable IRMC, CMC and ISC */ + buf &= ~0x00ff0000; /* XXX: Set cyc_clk_acc to zero for now */ + buf &= ~0x18000000; /* Disable PMC and BMC */ + reg_write(ohci, OHCI1394_BusOptions, buf); + + /* Set the bus number */ + reg_write(ohci, OHCI1394_NodeID, 0x0000ffc0); + + /* Enable posted writes */ + reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_postedWriteEnable); + + /* Clear link control register */ + reg_write(ohci, OHCI1394_LinkControlClear, 0xffffffff); + + /* Enable cycle timer and cycle master and set the IRM + * contender bit in our self ID packets. */ + reg_write(ohci, OHCI1394_LinkControlSet, 0x00300000); + set_phy_reg_mask(ohci, 4, 0xc0); + + /* Clear interrupt registers */ + reg_write(ohci, OHCI1394_IntMaskClear, 0xffffffff); + reg_write(ohci, OHCI1394_IntEventClear, 0xffffffff); + + /* Set up self-id dma buffer */ + reg_write(ohci, OHCI1394_SelfIDBuffer, ohci->selfid_buf_bus); + + /* enable self-id dma */ + reg_write(ohci, OHCI1394_LinkControlSet, 0x00000200); + + /* Set the Config ROM mapping register */ + reg_write(ohci, OHCI1394_ConfigROMmap, ohci->csr_config_rom_bus); + + /* Initialize the Config ROM */ + ohci_init_config_rom(ohci); + + /* Now get our max packet size */ + ohci->max_packet_size = + 1<<(((reg_read(ohci, OHCI1394_BusOptions)>>12)&0xf)+1); + + /* Don't accept phy packets into AR request context */ + reg_write(ohci, OHCI1394_LinkControlClear, 0x00000400); + + /* Clear the interrupt mask */ + reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff); + reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff); + + /* Clear the interrupt mask */ + reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 0xffffffff); + reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 0xffffffff); + + /* Initialize AR dma */ + initialize_dma_rcv_ctx(&ohci->ar_req_context, 0); + initialize_dma_rcv_ctx(&ohci->ar_resp_context, 0); + + /* Initialize AT dma */ + initialize_dma_trm_ctx(&ohci->at_req_context); + initialize_dma_trm_ctx(&ohci->at_resp_context); + + /* + * Accept AT requests from all nodes. This probably + * will have to be controlled from the subsystem + * on a per node basis. + */ + reg_write(ohci,OHCI1394_AsReqFilterHiSet, 0x80000000); + + /* Specify AT retries */ + reg_write(ohci, OHCI1394_ATRetries, + OHCI1394_MAX_AT_REQ_RETRIES | + (OHCI1394_MAX_AT_RESP_RETRIES<<4) | + (OHCI1394_MAX_PHYS_RESP_RETRIES<<8)); + + /* We don't want hardware swapping */ + reg_write(ohci, OHCI1394_HCControlClear, OHCI1394_HCControl_noByteSwap); + + /* Enable interrupts */ + reg_write(ohci, OHCI1394_IntMaskSet, + OHCI1394_unrecoverableError | + OHCI1394_masterIntEnable | + OHCI1394_busReset | + OHCI1394_selfIDComplete | + OHCI1394_RSPkt | + OHCI1394_RQPkt | + OHCI1394_respTxComplete | + OHCI1394_reqTxComplete | + OHCI1394_isochRx | + OHCI1394_isochTx | + OHCI1394_cycleInconsistent); + + /* Enable link */ + reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_linkEnable); + + buf = reg_read(ohci, OHCI1394_Version); +#ifndef __sparc__ + sprintf (irq_buf, "%d", ohci->dev->irq); +#else + sprintf (irq_buf, "%s", __irq_itoa(ohci->dev->irq)); +#endif + PRINT(KERN_INFO, ohci->id, "OHCI-1394 %d.%d (PCI): IRQ=[%s] " + "MMIO=[%lx-%lx] Max Packet=[%d]", + ((((buf) >> 16) & 0xf) + (((buf) >> 20) & 0xf) * 10), + ((((buf) >> 4) & 0xf) + ((buf) & 0xf) * 10), irq_buf, + pci_resource_start(ohci->dev, 0), + pci_resource_start(ohci->dev, 0) + OHCI1394_REGISTER_SIZE - 1, + ohci->max_packet_size); +} + +/* + * Insert a packet in the DMA fifo and generate the DMA prg + * FIXME: rewrite the program in order to accept packets crossing + * page boundaries. + * check also that a single dma descriptor doesn't cross a + * page boundary. + */ +static void insert_packet(struct ti_ohci *ohci, + struct dma_trm_ctx *d, struct hpsb_packet *packet) +{ + u32 cycleTimer; + int idx = d->prg_ind; + + DBGMSG(ohci->id, "Inserting packet for node " NODE_BUS_FMT + ", tlabel=%d, tcode=0x%x, speed=%d", + NODE_BUS_ARGS(ohci->host, packet->node_id), packet->tlabel, + packet->tcode, packet->speed_code); + + d->prg_cpu[idx]->begin.address = 0; + d->prg_cpu[idx]->begin.branchAddress = 0; + + if (d->type == DMA_CTX_ASYNC_RESP) { + /* + * For response packets, we need to put a timeout value in + * the 16 lower bits of the status... let's try 1 sec timeout + */ + cycleTimer = reg_read(ohci, OHCI1394_IsochronousCycleTimer); + d->prg_cpu[idx]->begin.status = cpu_to_le32( + (((((cycleTimer>>25)&0x7)+1)&0x7)<<13) | + ((cycleTimer&0x01fff000)>>12)); + + DBGMSG(ohci->id, "cycleTimer: %08x timeStamp: %08x", + cycleTimer, d->prg_cpu[idx]->begin.status); + } else + d->prg_cpu[idx]->begin.status = 0; + + if ( (packet->type == hpsb_async) || (packet->type == hpsb_raw) ) { + + if (packet->type == hpsb_raw) { + d->prg_cpu[idx]->data[0] = cpu_to_le32(OHCI1394_TCODE_PHY<<4); + d->prg_cpu[idx]->data[1] = cpu_to_le32(packet->header[0]); + d->prg_cpu[idx]->data[2] = cpu_to_le32(packet->header[1]); + } else { + d->prg_cpu[idx]->data[0] = packet->speed_code<<16 | + (packet->header[0] & 0xFFFF); + + if (packet->tcode == TCODE_ISO_DATA) { + /* Sending an async stream packet */ + d->prg_cpu[idx]->data[1] = packet->header[0] & 0xFFFF0000; + } else { + /* Sending a normal async request or response */ + d->prg_cpu[idx]->data[1] = + (packet->header[1] & 0xFFFF) | + (packet->header[0] & 0xFFFF0000); + d->prg_cpu[idx]->data[2] = packet->header[2]; + d->prg_cpu[idx]->data[3] = packet->header[3]; + } + packet_swab(d->prg_cpu[idx]->data, packet->tcode); + } + + if (packet->data_size) { /* block transmit */ + if (packet->tcode == TCODE_STREAM_DATA){ + d->prg_cpu[idx]->begin.control = + cpu_to_le32(DMA_CTL_OUTPUT_MORE | + DMA_CTL_IMMEDIATE | 0x8); + } else { + d->prg_cpu[idx]->begin.control = + cpu_to_le32(DMA_CTL_OUTPUT_MORE | + DMA_CTL_IMMEDIATE | 0x10); + } + d->prg_cpu[idx]->end.control = + cpu_to_le32(DMA_CTL_OUTPUT_LAST | + DMA_CTL_IRQ | + DMA_CTL_BRANCH | + packet->data_size); + /* + * Check that the packet data buffer + * does 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, + "%s: packet data addr: %p size %Zd bytes " + "cross page boundary", __FUNCTION__, + packet->data, packet->data_size); + } + + d->prg_cpu[idx]->end.address = cpu_to_le32( + pci_map_single(ohci->dev, packet->data, + packet->data_size, + PCI_DMA_TODEVICE)); + OHCI_DMA_ALLOC("single, block transmit packet"); + + d->prg_cpu[idx]->end.branchAddress = 0; + d->prg_cpu[idx]->end.status = 0; + if (d->branchAddrPtr) + *(d->branchAddrPtr) = + cpu_to_le32(d->prg_bus[idx] | 0x3); + d->branchAddrPtr = + &(d->prg_cpu[idx]->end.branchAddress); + } else { /* quadlet transmit */ + if (packet->type == hpsb_raw) + d->prg_cpu[idx]->begin.control = + cpu_to_le32(DMA_CTL_OUTPUT_LAST | + DMA_CTL_IMMEDIATE | + DMA_CTL_IRQ | + DMA_CTL_BRANCH | + (packet->header_size + 4)); + else + d->prg_cpu[idx]->begin.control = + cpu_to_le32(DMA_CTL_OUTPUT_LAST | + DMA_CTL_IMMEDIATE | + DMA_CTL_IRQ | + DMA_CTL_BRANCH | + packet->header_size); + + if (d->branchAddrPtr) + *(d->branchAddrPtr) = + cpu_to_le32(d->prg_bus[idx] | 0x2); + d->branchAddrPtr = + &(d->prg_cpu[idx]->begin.branchAddress); + } + + } else { /* iso packet */ + d->prg_cpu[idx]->data[0] = packet->speed_code<<16 | + (packet->header[0] & 0xFFFF); + d->prg_cpu[idx]->data[1] = packet->header[0] & 0xFFFF0000; + packet_swab(d->prg_cpu[idx]->data, packet->tcode); + + d->prg_cpu[idx]->begin.control = + cpu_to_le32(DMA_CTL_OUTPUT_MORE | + DMA_CTL_IMMEDIATE | 0x8); + d->prg_cpu[idx]->end.control = + cpu_to_le32(DMA_CTL_OUTPUT_LAST | + DMA_CTL_UPDATE | + DMA_CTL_IRQ | + DMA_CTL_BRANCH | + packet->data_size); + d->prg_cpu[idx]->end.address = cpu_to_le32( + pci_map_single(ohci->dev, packet->data, + packet->data_size, PCI_DMA_TODEVICE)); + OHCI_DMA_ALLOC("single, iso transmit packet"); + + d->prg_cpu[idx]->end.branchAddress = 0; + d->prg_cpu[idx]->end.status = 0; + DBGMSG(ohci->id, "Iso xmit context info: header[%08x %08x]\n" + " begin=%08x %08x %08x %08x\n" + " %08x %08x %08x %08x\n" + " end =%08x %08x %08x %08x", + d->prg_cpu[idx]->data[0], d->prg_cpu[idx]->data[1], + d->prg_cpu[idx]->begin.control, + d->prg_cpu[idx]->begin.address, + d->prg_cpu[idx]->begin.branchAddress, + d->prg_cpu[idx]->begin.status, + d->prg_cpu[idx]->data[0], + d->prg_cpu[idx]->data[1], + d->prg_cpu[idx]->data[2], + d->prg_cpu[idx]->data[3], + d->prg_cpu[idx]->end.control, + d->prg_cpu[idx]->end.address, + d->prg_cpu[idx]->end.branchAddress, + d->prg_cpu[idx]->end.status); + if (d->branchAddrPtr) + *(d->branchAddrPtr) = cpu_to_le32(d->prg_bus[idx] | 0x3); + d->branchAddrPtr = &(d->prg_cpu[idx]->end.branchAddress); + } + d->free_prgs--; + + /* queue the packet in the appropriate context queue */ + list_add_tail(&packet->driver_list, &d->fifo_list); + d->prg_ind = (d->prg_ind+1)%d->num_desc; +} + +/* + * This function fills the FIFO with the (eventual) pending packets + * and runs or wakes up the DMA prg if necessary. + * + * The function MUST be called with the d->lock held. + */ +static int dma_trm_flush(struct ti_ohci *ohci, struct dma_trm_ctx *d) +{ + struct hpsb_packet *p; + int idx,z; + + if (list_empty(&d->pending_list) || d->free_prgs == 0) + return 0; + + p = driver_packet(d->pending_list.next); + idx = d->prg_ind; + z = (p->data_size) ? 3 : 2; + + /* insert the packets into the dma fifo */ + while (d->free_prgs > 0 && !list_empty(&d->pending_list)) { + struct hpsb_packet *p = driver_packet(d->pending_list.next); + list_del(&p->driver_list); + insert_packet(ohci, d, p); + } + + if (d->free_prgs == 0) + DBGMSG(ohci->id, "Transmit DMA FIFO ctx=%d is full... waiting", d->ctx); + + /* Is the context running ? (should be unless it is + the first packet to be sent in this context) */ + if (!(reg_read(ohci, d->ctrlSet) & 0x8000)) { + DBGMSG(ohci->id,"Starting transmit DMA ctx=%d",d->ctx); + reg_write(ohci, d->cmdPtr, d->prg_bus[idx]|z); + run_context(ohci, d->ctrlSet, NULL); + } + else { + /* Wake up the dma context if necessary */ + if (!(reg_read(ohci, d->ctrlSet) & 0x400)) { + DBGMSG(ohci->id,"Waking transmit DMA ctx=%d",d->ctx); + } + + /* do this always, to avoid race condition */ + reg_write(ohci, d->ctrlSet, 0x1000); + } + return 1; +} + +/* Transmission of an async or iso packet */ +static int ohci_transmit(struct hpsb_host *host, struct hpsb_packet *packet) +{ + struct ti_ohci *ohci = host->hostdata; + struct dma_trm_ctx *d; + unsigned long flags; + + if (packet->data_size > ohci->max_packet_size) { + PRINT(KERN_ERR, ohci->id, + "Transmit packet size %Zd is too big", + packet->data_size); + return 0; + } + + /* Decide whether we have an iso, a request, or a response packet */ + if (packet->type == hpsb_raw) + d = &ohci->at_req_context; + else if ((packet->tcode == TCODE_ISO_DATA) && (packet->type == hpsb_iso)) { + /* The legacy IT DMA context is initialized on first + * use. However, the alloc cannot be run from + * interrupt context, so we bail out if that is the + * case. I don't see anyone sending ISO packets from + * interrupt context anyway... */ + + if (ohci->it_legacy_context.ohci == NULL) { + if (in_interrupt()) { + PRINT(KERN_ERR, ohci->id, + "legacy IT context cannot be initialized during interrupt"); + return 0; + } + + if (alloc_dma_trm_ctx(ohci, &ohci->it_legacy_context, + DMA_CTX_ISO, 0, IT_NUM_DESC, + OHCI1394_IsoXmitContextBase) < 0) { + PRINT(KERN_ERR, ohci->id, + "error initializing legacy IT context"); + return 0; + } + + initialize_dma_trm_ctx(&ohci->it_legacy_context); + } + + d = &ohci->it_legacy_context; + } else if ((packet->tcode & 0x02) && (packet->tcode != TCODE_ISO_DATA)) + d = &ohci->at_resp_context; + else + d = &ohci->at_req_context; + + spin_lock_irqsave(&d->lock,flags); + + list_add_tail(&packet->driver_list, &d->pending_list); + + dma_trm_flush(ohci, d); + + spin_unlock_irqrestore(&d->lock,flags); + + return 1; +} + +static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg) +{ + struct ti_ohci *ohci = host->hostdata; + int retval = 0; + unsigned long flags; + int phy_reg; + + switch (cmd) { + case RESET_BUS: + switch (arg) { + case SHORT_RESET: + phy_reg = get_phy_reg(ohci, 5); + phy_reg |= 0x40; + set_phy_reg(ohci, 5, phy_reg); /* set ISBR */ + break; + case LONG_RESET: + phy_reg = get_phy_reg(ohci, 1); + phy_reg |= 0x40; + set_phy_reg(ohci, 1, phy_reg); /* set IBR */ + break; + case SHORT_RESET_NO_FORCE_ROOT: + phy_reg = get_phy_reg(ohci, 1); + if (phy_reg & 0x80) { + phy_reg &= ~0x80; + set_phy_reg(ohci, 1, phy_reg); /* clear RHB */ + } + + phy_reg = get_phy_reg(ohci, 5); + phy_reg |= 0x40; + set_phy_reg(ohci, 5, phy_reg); /* set ISBR */ + break; + case LONG_RESET_NO_FORCE_ROOT: + phy_reg = get_phy_reg(ohci, 1); + phy_reg &= ~0x80; + phy_reg |= 0x40; + set_phy_reg(ohci, 1, phy_reg); /* clear RHB, set IBR */ + break; + case SHORT_RESET_FORCE_ROOT: + phy_reg = get_phy_reg(ohci, 1); + if (!(phy_reg & 0x80)) { + phy_reg |= 0x80; + set_phy_reg(ohci, 1, phy_reg); /* set RHB */ + } + + phy_reg = get_phy_reg(ohci, 5); + phy_reg |= 0x40; + set_phy_reg(ohci, 5, phy_reg); /* set ISBR */ + break; + case LONG_RESET_FORCE_ROOT: + phy_reg = get_phy_reg(ohci, 1); + phy_reg |= 0xc0; + set_phy_reg(ohci, 1, phy_reg); /* set RHB and IBR */ + break; + default: + retval = -1; + } + break; + + case GET_CYCLE_COUNTER: + retval = reg_read(ohci, OHCI1394_IsochronousCycleTimer); + break; + + case SET_CYCLE_COUNTER: + reg_write(ohci, OHCI1394_IsochronousCycleTimer, arg); + break; + + case SET_BUS_ID: + PRINT(KERN_ERR, ohci->id, "devctl command SET_BUS_ID err"); + break; + + case ACT_CYCLE_MASTER: + if (arg) { + /* check if we are root and other nodes are present */ + u32 nodeId = reg_read(ohci, OHCI1394_NodeID); + if ((nodeId & (1<<30)) && (nodeId & 0x3f)) { + /* + * enable cycleTimer, cycleMaster + */ + DBGMSG(ohci->id, "Cycle master enabled"); + reg_write(ohci, OHCI1394_LinkControlSet, + 0x00300000); + } + } else { + /* disable cycleTimer, cycleMaster, cycleSource */ + reg_write(ohci, OHCI1394_LinkControlClear, 0x00700000); + } + break; + + case CANCEL_REQUESTS: + DBGMSG(ohci->id, "Cancel request received"); + dma_trm_reset(&ohci->at_req_context); + dma_trm_reset(&ohci->at_resp_context); + break; + + case MODIFY_USAGE: + if (arg) { + MOD_INC_USE_COUNT; + } else { + MOD_DEC_USE_COUNT; + } + retval = 1; + break; + + case ISO_LISTEN_CHANNEL: + { + u64 mask; + + if (arg<0 || arg>63) { + PRINT(KERN_ERR, ohci->id, + "%s: IS0 listen channel %d is out of range", + __FUNCTION__, arg); + return -EFAULT; + } + + /* activate the legacy IR context */ + if (ohci->ir_legacy_context.ohci == NULL) { + if (alloc_dma_rcv_ctx(ohci, &ohci->ir_legacy_context, + DMA_CTX_ISO, 0, IR_NUM_DESC, + IR_BUF_SIZE, IR_SPLIT_BUF_SIZE, + OHCI1394_IsoRcvContextBase) < 0) { + PRINT(KERN_ERR, ohci->id, "%s: failed to allocate an IR context", + __FUNCTION__); + return -ENOMEM; + } + ohci->ir_legacy_channels = 0; + initialize_dma_rcv_ctx(&ohci->ir_legacy_context, 1); + + DBGMSG(ohci->id, "ISO receive legacy context activated"); + } + + mask = (u64)0x1<IR_channel_lock, flags); + + if (ohci->ISO_channel_usage & mask) { + PRINT(KERN_ERR, ohci->id, + "%s: IS0 listen channel %d is already used", + __FUNCTION__, arg); + spin_unlock_irqrestore(&ohci->IR_channel_lock, flags); + return -EFAULT; + } + + ohci->ISO_channel_usage |= mask; + ohci->ir_legacy_channels |= mask; + + if (arg>31) + reg_write(ohci, OHCI1394_IRMultiChanMaskHiSet, + 1<<(arg-32)); + else + reg_write(ohci, OHCI1394_IRMultiChanMaskLoSet, + 1<IR_channel_lock, flags); + DBGMSG(ohci->id, "Listening enabled on channel %d", arg); + break; + } + case ISO_UNLISTEN_CHANNEL: + { + u64 mask; + + if (arg<0 || arg>63) { + PRINT(KERN_ERR, ohci->id, + "%s: IS0 unlisten channel %d is out of range", + __FUNCTION__, arg); + return -EFAULT; + } + + mask = (u64)0x1<IR_channel_lock, flags); + + if (!(ohci->ISO_channel_usage & mask)) { + PRINT(KERN_ERR, ohci->id, + "%s: IS0 unlisten channel %d is not used", + __FUNCTION__, arg); + spin_unlock_irqrestore(&ohci->IR_channel_lock, flags); + return -EFAULT; + } + + ohci->ISO_channel_usage &= ~mask; + ohci->ir_legacy_channels &= ~mask; + + if (arg>31) + reg_write(ohci, OHCI1394_IRMultiChanMaskHiClear, + 1<<(arg-32)); + else + reg_write(ohci, OHCI1394_IRMultiChanMaskLoClear, + 1<IR_channel_lock, flags); + DBGMSG(ohci->id, "Listening disabled on channel %d", arg); + + if (ohci->ir_legacy_channels == 0) { + free_dma_rcv_ctx(&ohci->ir_legacy_context); + DBGMSG(ohci->id, "ISO receive legacy context deactivated"); + } + break; + } + default: + PRINT_G(KERN_ERR, "ohci_devctl cmd %d not implemented yet", + cmd); + break; + } + return retval; +} + +/*********************************** + * rawiso ISO reception * + ***********************************/ + +/* + We use either buffer-fill or packet-per-buffer DMA mode. The DMA + buffer is split into "blocks" (regions described by one DMA + descriptor). Each block must be one page or less in size, and + must not cross a page boundary. + + There is one little wrinkle with buffer-fill mode: a packet that + starts in the final block may wrap around into the first block. But + the user API expects all packets to be contiguous. Our solution is + to keep the very last page of the DMA buffer in reserve - if a + packet spans the gap, we copy its tail into this page. +*/ + +struct ohci_iso_recv { + struct ti_ohci *ohci; + + struct ohci1394_iso_tasklet task; + int task_active; + + enum { BUFFER_FILL_MODE, + PACKET_PER_BUFFER_MODE } dma_mode; + + /* memory and PCI mapping for the DMA descriptors */ + struct dma_prog_region prog; + struct dma_cmd *block; /* = (struct dma_cmd*) prog.virt */ + + /* how many DMA blocks fit in the buffer */ + unsigned int nblocks; + + /* stride of DMA blocks */ + unsigned int buf_stride; + + /* number of blocks to batch between interrupts */ + int block_irq_interval; + + /* block that DMA will finish next */ + int block_dma; + + /* (buffer-fill only) block that the reader will release next */ + int block_reader; + + /* (buffer-fill only) bytes of buffer the reader has released, + less than one block */ + int released_bytes; + + /* (buffer-fill only) buffer offset at which the next packet will appear */ + int dma_offset; + + /* OHCI DMA context control registers */ + u32 ContextControlSet; + u32 ContextControlClear; + u32 CommandPtr; + u32 ContextMatch; +}; + +static void ohci_iso_recv_task(unsigned long data); +static void ohci_iso_recv_stop(struct hpsb_iso *iso); +static void ohci_iso_recv_shutdown(struct hpsb_iso *iso); +static int ohci_iso_recv_start(struct hpsb_iso *iso, int cycle, int tag_mask, int sync); +static void ohci_iso_recv_program(struct hpsb_iso *iso); + +static int ohci_iso_recv_init(struct hpsb_iso *iso) +{ + struct ti_ohci *ohci = iso->host->hostdata; + struct ohci_iso_recv *recv; + int ctx; + int ret = -ENOMEM; + + recv = kmalloc(sizeof(*recv), SLAB_KERNEL); + if (!recv) + return -ENOMEM; + + iso->hostdata = recv; + recv->ohci = ohci; + recv->task_active = 0; + dma_prog_region_init(&recv->prog); + recv->block = NULL; + + /* use buffer-fill mode, unless irq_interval is 1 + (note: multichannel requires buffer-fill) */ + + if (iso->irq_interval == 1 && iso->channel != -1) { + recv->dma_mode = PACKET_PER_BUFFER_MODE; + } else { + recv->dma_mode = BUFFER_FILL_MODE; + } + + /* set nblocks, buf_stride, block_irq_interval */ + + if (recv->dma_mode == BUFFER_FILL_MODE) { + recv->buf_stride = PAGE_SIZE; + + /* one block per page of data in the DMA buffer, minus the final guard page */ + recv->nblocks = iso->buf_size/PAGE_SIZE - 1; + if (recv->nblocks < 3) { + DBGMSG(ohci->id, "ohci_iso_recv_init: DMA buffer too small"); + goto err; + } + + /* iso->irq_interval is in packets - translate that to blocks */ + /* (err, sort of... 1 is always the safest value) */ + recv->block_irq_interval = iso->irq_interval / recv->nblocks; + if (recv->block_irq_interval*4 > recv->nblocks) + recv->block_irq_interval = recv->nblocks/4; + if (recv->block_irq_interval < 1) + recv->block_irq_interval = 1; + + } else { + int max_packet_size; + + recv->nblocks = iso->buf_packets; + recv->block_irq_interval = 1; + + /* choose a buffer stride */ + /* must be a power of 2, and <= PAGE_SIZE */ + + max_packet_size = iso->buf_size / iso->buf_packets; + + for (recv->buf_stride = 8; recv->buf_stride < max_packet_size; + recv->buf_stride *= 2); + + if (recv->buf_stride*iso->buf_packets > iso->buf_size || + recv->buf_stride > PAGE_SIZE) { + /* this shouldn't happen, but anyway... */ + DBGMSG(ohci->id, "ohci_iso_recv_init: problem choosing a buffer stride"); + goto err; + } + } + + recv->block_reader = 0; + recv->released_bytes = 0; + recv->block_dma = 0; + recv->dma_offset = 0; + + /* size of DMA program = one descriptor per block */ + if (dma_prog_region_alloc(&recv->prog, + sizeof(struct dma_cmd) * recv->nblocks, + recv->ohci->dev)) + goto err; + + recv->block = (struct dma_cmd*) recv->prog.kvirt; + + ohci1394_init_iso_tasklet(&recv->task, + iso->channel == -1 ? OHCI_ISO_MULTICHANNEL_RECEIVE : + OHCI_ISO_RECEIVE, + ohci_iso_recv_task, (unsigned long) iso); + + if (ohci1394_register_iso_tasklet(recv->ohci, &recv->task) < 0) + goto err; + + recv->task_active = 1; + + /* recv context registers are spaced 32 bytes apart */ + ctx = recv->task.context; + recv->ContextControlSet = OHCI1394_IsoRcvContextControlSet + 32 * ctx; + recv->ContextControlClear = OHCI1394_IsoRcvContextControlClear + 32 * ctx; + recv->CommandPtr = OHCI1394_IsoRcvCommandPtr + 32 * ctx; + recv->ContextMatch = OHCI1394_IsoRcvContextMatch + 32 * ctx; + + if (iso->channel == -1) { + /* clear multi-channel selection mask */ + reg_write(recv->ohci, OHCI1394_IRMultiChanMaskHiClear, 0xFFFFFFFF); + reg_write(recv->ohci, OHCI1394_IRMultiChanMaskLoClear, 0xFFFFFFFF); + } + + /* write the DMA program */ + ohci_iso_recv_program(iso); + + DBGMSG(ohci->id, "ohci_iso_recv_init: %s mode, DMA buffer is %lu pages" + " (%u bytes), using %u blocks, buf_stride %u, block_irq_interval %d", + recv->dma_mode == BUFFER_FILL_MODE ? + "buffer-fill" : "packet-per-buffer", + iso->buf_size/PAGE_SIZE, iso->buf_size, + recv->nblocks, recv->buf_stride, recv->block_irq_interval); + + return 0; + +err: + ohci_iso_recv_shutdown(iso); + return ret; +} + +static void ohci_iso_recv_stop(struct hpsb_iso *iso) +{ + struct ohci_iso_recv *recv = iso->hostdata; + + /* disable interrupts */ + reg_write(recv->ohci, OHCI1394_IsoRecvIntMaskClear, 1 << recv->task.context); + + /* halt DMA */ + ohci1394_stop_context(recv->ohci, recv->ContextControlClear, NULL); +} + +static void ohci_iso_recv_shutdown(struct hpsb_iso *iso) +{ + struct ohci_iso_recv *recv = iso->hostdata; + + if (recv->task_active) { + ohci_iso_recv_stop(iso); + ohci1394_unregister_iso_tasklet(recv->ohci, &recv->task); + recv->task_active = 0; + } + + dma_prog_region_free(&recv->prog); + kfree(recv); + iso->hostdata = NULL; +} + +/* set up a "gapped" ring buffer DMA program */ +static void ohci_iso_recv_program(struct hpsb_iso *iso) +{ + struct ohci_iso_recv *recv = iso->hostdata; + int blk; + + /* address of 'branch' field in previous DMA descriptor */ + u32 *prev_branch = NULL; + + for (blk = 0; blk < recv->nblocks; blk++) { + u32 control; + + /* the DMA descriptor */ + struct dma_cmd *cmd = &recv->block[blk]; + + /* offset of the DMA descriptor relative to the DMA prog buffer */ + unsigned long prog_offset = blk * sizeof(struct dma_cmd); + + /* offset of this packet's data within the DMA buffer */ + unsigned long buf_offset = blk * recv->buf_stride; + + if (recv->dma_mode == BUFFER_FILL_MODE) { + control = 2 << 28; /* INPUT_MORE */ + } else { + control = 3 << 28; /* INPUT_LAST */ + } + + control |= 8 << 24; /* s = 1, update xferStatus and resCount */ + + /* interrupt on last block, and at intervals */ + if (blk == recv->nblocks-1 || (blk % recv->block_irq_interval) == 0) { + control |= 3 << 20; /* want interrupt */ + } + + control |= 3 << 18; /* enable branch to address */ + control |= recv->buf_stride; + + cmd->control = cpu_to_le32(control); + cmd->address = cpu_to_le32(dma_region_offset_to_bus(&iso->data_buf, buf_offset)); + cmd->branchAddress = 0; /* filled in on next loop */ + cmd->status = cpu_to_le32(recv->buf_stride); + + /* link the previous descriptor to this one */ + if (prev_branch) { + *prev_branch = cpu_to_le32(dma_prog_region_offset_to_bus(&recv->prog, prog_offset) | 1); + } + + prev_branch = &cmd->branchAddress; + } + + /* the final descriptor's branch address and Z should be left at 0 */ +} + +/* listen or unlisten to a specific channel (multi-channel mode only) */ +static void ohci_iso_recv_change_channel(struct hpsb_iso *iso, unsigned char channel, int listen) +{ + struct ohci_iso_recv *recv = iso->hostdata; + int reg, i; + + if (channel < 32) { + reg = listen ? OHCI1394_IRMultiChanMaskLoSet : OHCI1394_IRMultiChanMaskLoClear; + i = channel; + } else { + reg = listen ? OHCI1394_IRMultiChanMaskHiSet : OHCI1394_IRMultiChanMaskHiClear; + i = channel - 32; + } + + reg_write(recv->ohci, reg, (1 << i)); + + /* issue a dummy read to force all PCI writes to be posted immediately */ + mb(); + reg_read(recv->ohci, OHCI1394_IsochronousCycleTimer); +} + +static void ohci_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask) +{ + struct ohci_iso_recv *recv = iso->hostdata; + int i; + + for (i = 0; i < 64; i++) { + if (mask & (1ULL << i)) { + if (i < 32) + reg_write(recv->ohci, OHCI1394_IRMultiChanMaskLoSet, (1 << i)); + else + reg_write(recv->ohci, OHCI1394_IRMultiChanMaskHiSet, (1 << (i-32))); + } else { + if (i < 32) + reg_write(recv->ohci, OHCI1394_IRMultiChanMaskLoClear, (1 << i)); + else + reg_write(recv->ohci, OHCI1394_IRMultiChanMaskHiClear, (1 << (i-32))); + } + } + + /* issue a dummy read to force all PCI writes to be posted immediately */ + mb(); + reg_read(recv->ohci, OHCI1394_IsochronousCycleTimer); +} + +static int ohci_iso_recv_start(struct hpsb_iso *iso, int cycle, int tag_mask, int sync) +{ + struct ohci_iso_recv *recv = iso->hostdata; + u32 command, contextMatch; + + reg_write(recv->ohci, recv->ContextControlClear, 0xFFFFFFFF); + wmb(); + + /* always keep ISO headers */ + command = (1 << 30); + + if (recv->dma_mode == BUFFER_FILL_MODE) + command |= (1 << 31); + + reg_write(recv->ohci, recv->ContextControlSet, command); + + /* match on specified tags */ + contextMatch = tag_mask << 28; + + if (iso->channel == -1) { + /* enable multichannel reception */ + reg_write(recv->ohci, recv->ContextControlSet, (1 << 28)); + } else { + /* listen on channel */ + contextMatch |= iso->channel; + } + + if (cycle != -1) { + u32 seconds; + + /* enable cycleMatch */ + reg_write(recv->ohci, recv->ContextControlSet, (1 << 29)); + + /* set starting cycle */ + cycle &= 0x1FFF; + + /* 'cycle' is only mod 8000, but we also need two 'seconds' bits - + just snarf them from the current time */ + seconds = reg_read(recv->ohci, OHCI1394_IsochronousCycleTimer) >> 25; + + /* advance one second to give some extra time for DMA to start */ + seconds += 1; + + cycle |= (seconds & 3) << 13; + + contextMatch |= cycle << 12; + } + + if (sync != -1) { + /* set sync flag on first DMA descriptor */ + struct dma_cmd *cmd = &recv->block[recv->block_dma]; + cmd->control |= cpu_to_le32(DMA_CTL_WAIT); + + /* match sync field */ + contextMatch |= (sync&0xf)<<8; + } + + reg_write(recv->ohci, recv->ContextMatch, contextMatch); + + /* address of first descriptor block */ + command = dma_prog_region_offset_to_bus(&recv->prog, + recv->block_dma * sizeof(struct dma_cmd)); + command |= 1; /* Z=1 */ + + reg_write(recv->ohci, recv->CommandPtr, command); + + /* enable interrupts */ + reg_write(recv->ohci, OHCI1394_IsoRecvIntMaskSet, 1 << recv->task.context); + + wmb(); + + /* run */ + reg_write(recv->ohci, recv->ContextControlSet, 0x8000); + + /* issue a dummy read of the cycle timer register to force + all PCI writes to be posted immediately */ + mb(); + reg_read(recv->ohci, OHCI1394_IsochronousCycleTimer); + + /* check RUN */ + if (!(reg_read(recv->ohci, recv->ContextControlSet) & 0x8000)) { + PRINT(KERN_ERR, recv->ohci->id, + "Error starting IR DMA (ContextControl 0x%08x)\n", + reg_read(recv->ohci, recv->ContextControlSet)); + return -1; + } + + return 0; +} + +static void ohci_iso_recv_release_block(struct ohci_iso_recv *recv, int block) +{ + /* re-use the DMA descriptor for the block */ + /* by linking the previous descriptor to it */ + + int next_i = block; + int prev_i = (next_i == 0) ? (recv->nblocks - 1) : (next_i - 1); + + struct dma_cmd *next = &recv->block[next_i]; + struct dma_cmd *prev = &recv->block[prev_i]; + + /* 'next' becomes the new end of the DMA chain, + so disable branch and enable interrupt */ + next->branchAddress = 0; + next->control |= cpu_to_le32(3 << 20); + next->status = cpu_to_le32(recv->buf_stride); + + /* link prev to next */ + prev->branchAddress = cpu_to_le32(dma_prog_region_offset_to_bus(&recv->prog, + sizeof(struct dma_cmd) * next_i) + | 1); /* Z=1 */ + + /* disable interrupt on previous DMA descriptor, except at intervals */ + if ((prev_i % recv->block_irq_interval) == 0) { + prev->control |= cpu_to_le32(3 << 20); /* enable interrupt */ + } else { + prev->control &= cpu_to_le32(~(3<<20)); /* disable interrupt */ + } + wmb(); + + /* wake up DMA in case it fell asleep */ + reg_write(recv->ohci, recv->ContextControlSet, (1 << 12)); +} + +static void ohci_iso_recv_bufferfill_release(struct ohci_iso_recv *recv, + struct hpsb_iso_packet_info *info) +{ + int len; + + /* release the memory where the packet was */ + len = info->len; + + /* add the wasted space for padding to 4 bytes */ + if (len % 4) + len += 4 - (len % 4); + + /* add 8 bytes for the OHCI DMA data format overhead */ + len += 8; + + recv->released_bytes += len; + + /* have we released enough memory for one block? */ + while (recv->released_bytes > recv->buf_stride) { + ohci_iso_recv_release_block(recv, recv->block_reader); + recv->block_reader = (recv->block_reader + 1) % recv->nblocks; + recv->released_bytes -= recv->buf_stride; + } +} + +static inline void ohci_iso_recv_release(struct hpsb_iso *iso, struct hpsb_iso_packet_info *info) +{ + struct ohci_iso_recv *recv = iso->hostdata; + if (recv->dma_mode == BUFFER_FILL_MODE) { + ohci_iso_recv_bufferfill_release(recv, info); + } else { + ohci_iso_recv_release_block(recv, info - iso->infos); + } +} + +/* parse all packets from blocks that have been fully received */ +static void ohci_iso_recv_bufferfill_parse(struct hpsb_iso *iso, struct ohci_iso_recv *recv) +{ + int wake = 0; + int runaway = 0; + + while (1) { + /* we expect the next parsable packet to begin at recv->dma_offset */ + /* note: packet layout is as shown in section 10.6.1.1 of the OHCI spec */ + + unsigned int offset; + unsigned short len, cycle; + unsigned char channel, tag, sy; + + unsigned char *p = iso->data_buf.kvirt; + + unsigned int this_block = recv->dma_offset/recv->buf_stride; + + /* don't loop indefinitely */ + if (runaway++ > 100000) { + atomic_inc(&iso->overflows); + PRINT(KERN_ERR, recv->ohci->id, + "IR DMA error - Runaway during buffer parsing!\n"); + break; + } + + /* stop parsing once we arrive at block_dma (i.e. don't get ahead of DMA) */ + if (this_block == recv->block_dma) + break; + + wake = 1; + + /* parse data length, tag, channel, and sy */ + + /* note: we keep our own local copies of 'len' and 'offset' + so the user can't mess with them by poking in the mmap area */ + + len = p[recv->dma_offset+2] | (p[recv->dma_offset+3] << 8); + + if (len > 4096) { + PRINT(KERN_ERR, recv->ohci->id, + "IR DMA error - bogus 'len' value %u\n", len); + } + + channel = p[recv->dma_offset+1] & 0x3F; + tag = p[recv->dma_offset+1] >> 6; + sy = p[recv->dma_offset+0] & 0xF; + + /* advance to data payload */ + recv->dma_offset += 4; + + /* check for wrap-around */ + if (recv->dma_offset >= recv->buf_stride*recv->nblocks) { + recv->dma_offset -= recv->buf_stride*recv->nblocks; + } + + /* dma_offset now points to the first byte of the data payload */ + offset = recv->dma_offset; + + /* advance to xferStatus/timeStamp */ + recv->dma_offset += len; + + /* payload is padded to 4 bytes */ + if (len % 4) { + recv->dma_offset += 4 - (len%4); + } + + /* check for wrap-around */ + if (recv->dma_offset >= recv->buf_stride*recv->nblocks) { + /* uh oh, the packet data wraps from the last + to the first DMA block - make the packet + contiguous by copying its "tail" into the + guard page */ + + int guard_off = recv->buf_stride*recv->nblocks; + int tail_len = len - (guard_off - offset); + + if (tail_len > 0 && tail_len < recv->buf_stride) { + memcpy(iso->data_buf.kvirt + guard_off, + iso->data_buf.kvirt, + tail_len); + } + + recv->dma_offset -= recv->buf_stride*recv->nblocks; + } + + /* parse timestamp */ + cycle = p[recv->dma_offset+0] | (p[recv->dma_offset+1]<<8); + cycle &= 0x1FFF; + + /* advance to next packet */ + recv->dma_offset += 4; + + /* check for wrap-around */ + if (recv->dma_offset >= recv->buf_stride*recv->nblocks) { + recv->dma_offset -= recv->buf_stride*recv->nblocks; + } + + hpsb_iso_packet_received(iso, offset, len, cycle, channel, tag, sy); + } + + if (wake) + hpsb_iso_wake(iso); +} + +static void ohci_iso_recv_bufferfill_task(struct hpsb_iso *iso, struct ohci_iso_recv *recv) +{ + int loop; + + /* loop over all blocks */ + for (loop = 0; loop < recv->nblocks; loop++) { + + /* check block_dma to see if it's done */ + struct dma_cmd *im = &recv->block[recv->block_dma]; + + /* check the DMA descriptor for new writes to xferStatus */ + u16 xferstatus = le32_to_cpu(im->status) >> 16; + + /* rescount is the number of bytes *remaining to be written* in the block */ + u16 rescount = le32_to_cpu(im->status) & 0xFFFF; + + unsigned char event = xferstatus & 0x1F; + + if (!event) { + /* nothing has happened to this block yet */ + break; + } + + if (event != 0x11) { + atomic_inc(&iso->overflows); + PRINT(KERN_ERR, recv->ohci->id, + "IR DMA error - OHCI error code 0x%02x\n", event); + } + + if (rescount != 0) { + /* the card is still writing to this block; + we can't touch it until it's done */ + break; + } + + /* OK, the block is finished... */ + + /* sync our view of the block */ + dma_region_sync(&iso->data_buf, recv->block_dma*recv->buf_stride, recv->buf_stride); + + /* reset the DMA descriptor */ + im->status = recv->buf_stride; + + /* advance block_dma */ + recv->block_dma = (recv->block_dma + 1) % recv->nblocks; + + if ((recv->block_dma+1) % recv->nblocks == recv->block_reader) { + atomic_inc(&iso->overflows); + DBGMSG(recv->ohci->id, "ISO reception overflow - " + "ran out of DMA blocks"); + } + } + + /* parse any packets that have arrived */ + ohci_iso_recv_bufferfill_parse(iso, recv); +} + +static void ohci_iso_recv_packetperbuf_task(struct hpsb_iso *iso, struct ohci_iso_recv *recv) +{ + int count; + int wake = 0; + + /* loop over the entire buffer */ + for (count = 0; count < recv->nblocks; count++) { + u32 packet_len = 0; + + /* pointer to the DMA descriptor */ + struct dma_cmd *il = ((struct dma_cmd*) recv->prog.kvirt) + iso->pkt_dma; + + /* check the DMA descriptor for new writes to xferStatus */ + u16 xferstatus = le32_to_cpu(il->status) >> 16; + u16 rescount = le32_to_cpu(il->status) & 0xFFFF; + + unsigned char event = xferstatus & 0x1F; + + if (!event) { + /* this packet hasn't come in yet; we are done for now */ + goto out; + } + + if (event == 0x11) { + /* packet received successfully! */ + + /* rescount is the number of bytes *remaining* in the packet buffer, + after the packet was written */ + packet_len = recv->buf_stride - rescount; + + } else if (event == 0x02) { + PRINT(KERN_ERR, recv->ohci->id, "IR DMA error - packet too long for buffer\n"); + } else if (event) { + PRINT(KERN_ERR, recv->ohci->id, "IR DMA error - OHCI error code 0x%02x\n", event); + } + + /* sync our view of the buffer */ + dma_region_sync(&iso->data_buf, iso->pkt_dma * recv->buf_stride, recv->buf_stride); + + /* record the per-packet info */ + { + /* iso header is 8 bytes ahead of the data payload */ + unsigned char *hdr; + + unsigned int offset; + unsigned short cycle; + unsigned char channel, tag, sy; + + offset = iso->pkt_dma * recv->buf_stride; + hdr = iso->data_buf.kvirt + offset; + + /* skip iso header */ + offset += 8; + packet_len -= 8; + + cycle = (hdr[0] | (hdr[1] << 8)) & 0x1FFF; + channel = hdr[5] & 0x3F; + tag = hdr[5] >> 6; + sy = hdr[4] & 0xF; + + hpsb_iso_packet_received(iso, offset, packet_len, cycle, channel, tag, sy); + } + + /* reset the DMA descriptor */ + il->status = recv->buf_stride; + + wake = 1; + recv->block_dma = iso->pkt_dma; + } + +out: + if (wake) + hpsb_iso_wake(iso); +} + +static void ohci_iso_recv_task(unsigned long data) +{ + struct hpsb_iso *iso = (struct hpsb_iso*) data; + struct ohci_iso_recv *recv = iso->hostdata; + + if (recv->dma_mode == BUFFER_FILL_MODE) + ohci_iso_recv_bufferfill_task(iso, recv); + else + ohci_iso_recv_packetperbuf_task(iso, recv); +} + +/*********************************** + * rawiso ISO transmission * + ***********************************/ + +struct ohci_iso_xmit { + struct ti_ohci *ohci; + struct dma_prog_region prog; + struct ohci1394_iso_tasklet task; + int task_active; + + u32 ContextControlSet; + u32 ContextControlClear; + u32 CommandPtr; +}; + +/* transmission DMA program: + one OUTPUT_MORE_IMMEDIATE for the IT header + one OUTPUT_LAST for the buffer data */ + +struct iso_xmit_cmd { + struct dma_cmd output_more_immediate; + u8 iso_hdr[8]; + u32 unused[2]; + struct dma_cmd output_last; +}; + +static int ohci_iso_xmit_init(struct hpsb_iso *iso); +static int ohci_iso_xmit_start(struct hpsb_iso *iso, int cycle); +static void ohci_iso_xmit_shutdown(struct hpsb_iso *iso); +static void ohci_iso_xmit_task(unsigned long data); + +static int ohci_iso_xmit_init(struct hpsb_iso *iso) +{ + struct ohci_iso_xmit *xmit; + unsigned int prog_size; + int ctx; + int ret = -ENOMEM; + + xmit = kmalloc(sizeof(*xmit), SLAB_KERNEL); + if (!xmit) + return -ENOMEM; + + iso->hostdata = xmit; + xmit->ohci = iso->host->hostdata; + xmit->task_active = 0; + + dma_prog_region_init(&xmit->prog); + + prog_size = sizeof(struct iso_xmit_cmd) * iso->buf_packets; + + if (dma_prog_region_alloc(&xmit->prog, prog_size, xmit->ohci->dev)) + goto err; + + ohci1394_init_iso_tasklet(&xmit->task, OHCI_ISO_TRANSMIT, + ohci_iso_xmit_task, (unsigned long) iso); + + if (ohci1394_register_iso_tasklet(xmit->ohci, &xmit->task) < 0) + goto err; + + xmit->task_active = 1; + + /* xmit context registers are spaced 16 bytes apart */ + ctx = xmit->task.context; + xmit->ContextControlSet = OHCI1394_IsoXmitContextControlSet + 16 * ctx; + xmit->ContextControlClear = OHCI1394_IsoXmitContextControlClear + 16 * ctx; + xmit->CommandPtr = OHCI1394_IsoXmitCommandPtr + 16 * ctx; + + return 0; + +err: + ohci_iso_xmit_shutdown(iso); + return ret; +} + +static void ohci_iso_xmit_stop(struct hpsb_iso *iso) +{ + struct ohci_iso_xmit *xmit = iso->hostdata; + + /* disable interrupts */ + reg_write(xmit->ohci, OHCI1394_IsoXmitIntMaskClear, 1 << xmit->task.context); + + /* halt DMA */ + if (ohci1394_stop_context(xmit->ohci, xmit->ContextControlClear, NULL)) { + /* XXX the DMA context will lock up if you try to send too much data! */ + PRINT(KERN_ERR, xmit->ohci->id, + "you probably exceeded the OHCI card's bandwidth limit - " + "reload the module and reduce xmit bandwidth"); + } +} + +static void ohci_iso_xmit_shutdown(struct hpsb_iso *iso) +{ + struct ohci_iso_xmit *xmit = iso->hostdata; + + if (xmit->task_active) { + ohci_iso_xmit_stop(iso); + ohci1394_unregister_iso_tasklet(xmit->ohci, &xmit->task); + xmit->task_active = 0; + } + + dma_prog_region_free(&xmit->prog); + kfree(xmit); + iso->hostdata = NULL; +} + +static void ohci_iso_xmit_task(unsigned long data) +{ + struct hpsb_iso *iso = (struct hpsb_iso*) data; + struct ohci_iso_xmit *xmit = iso->hostdata; + int wake = 0; + int count; + + /* check the whole buffer if necessary, starting at pkt_dma */ + for (count = 0; count < iso->buf_packets; count++) { + int cycle; + + /* DMA descriptor */ + struct iso_xmit_cmd *cmd = dma_region_i(&xmit->prog, struct iso_xmit_cmd, iso->pkt_dma); + + /* check for new writes to xferStatus */ + u16 xferstatus = le32_to_cpu(cmd->output_last.status) >> 16; + u8 event = xferstatus & 0x1F; + + if (!event) { + /* packet hasn't been sent yet; we are done for now */ + break; + } + + if (event != 0x11) + PRINT(KERN_ERR, xmit->ohci->id, + "IT DMA error - OHCI error code 0x%02x\n", event); + + /* at least one packet went out, so wake up the writer */ + wake = 1; + + /* parse cycle */ + cycle = le32_to_cpu(cmd->output_last.status) & 0x1FFF; + + /* tell the subsystem the packet has gone out */ + hpsb_iso_packet_sent(iso, cycle, event != 0x11); + + /* reset the DMA descriptor for next time */ + cmd->output_last.status = 0; + } + + if (wake) + hpsb_iso_wake(iso); +} + +static int ohci_iso_xmit_queue(struct hpsb_iso *iso, struct hpsb_iso_packet_info *info) +{ + struct ohci_iso_xmit *xmit = iso->hostdata; + + int next_i, prev_i; + struct iso_xmit_cmd *next, *prev; + + unsigned int offset; + unsigned short len; + unsigned char tag, sy; + + /* check that the packet doesn't cross a page boundary + (we could allow this if we added OUTPUT_MORE descriptor support) */ + if (cross_bound(info->offset, info->len)) { + PRINT(KERN_ERR, xmit->ohci->id, + "rawiso xmit: packet %u crosses a page boundary", + iso->first_packet); + return -EINVAL; + } + + offset = info->offset; + len = info->len; + tag = info->tag; + sy = info->sy; + + /* sync up the card's view of the buffer */ + dma_region_sync(&iso->data_buf, offset, len); + + /* append first_packet to the DMA chain */ + /* by linking the previous descriptor to it */ + /* (next will become the new end of the DMA chain) */ + + next_i = iso->first_packet; + prev_i = (next_i == 0) ? (iso->buf_packets - 1) : (next_i - 1); + + next = dma_region_i(&xmit->prog, struct iso_xmit_cmd, next_i); + prev = dma_region_i(&xmit->prog, struct iso_xmit_cmd, prev_i); + + /* set up the OUTPUT_MORE_IMMEDIATE descriptor */ + memset(next, 0, sizeof(struct iso_xmit_cmd)); + next->output_more_immediate.control = cpu_to_le32(0x02000008); + + /* ISO packet header is embedded in the OUTPUT_MORE_IMMEDIATE */ + + /* tcode = 0xA, and sy */ + next->iso_hdr[0] = 0xA0 | (sy & 0xF); + + /* tag and channel number */ + next->iso_hdr[1] = (tag << 6) | (iso->channel & 0x3F); + + /* transmission speed */ + next->iso_hdr[2] = iso->speed & 0x7; + + /* payload size */ + next->iso_hdr[6] = len & 0xFF; + next->iso_hdr[7] = len >> 8; + + /* set up the OUTPUT_LAST */ + next->output_last.control = cpu_to_le32(1 << 28); + next->output_last.control |= cpu_to_le32(1 << 27); /* update timeStamp */ + next->output_last.control |= cpu_to_le32(3 << 20); /* want interrupt */ + next->output_last.control |= cpu_to_le32(3 << 18); /* enable branch */ + next->output_last.control |= cpu_to_le32(len); + + /* payload bus address */ + next->output_last.address = cpu_to_le32(dma_region_offset_to_bus(&iso->data_buf, offset)); + + /* leave branchAddress at zero for now */ + + /* re-write the previous DMA descriptor to chain to this one */ + + /* set prev branch address to point to next (Z=3) */ + prev->output_last.branchAddress = cpu_to_le32( + dma_prog_region_offset_to_bus(&xmit->prog, sizeof(struct iso_xmit_cmd) * next_i) | 3); + + /* disable interrupt, unless required by the IRQ interval */ + if (prev_i % iso->irq_interval) { + prev->output_last.control &= cpu_to_le32(~(3 << 20)); /* no interrupt */ + } else { + prev->output_last.control |= cpu_to_le32(3 << 20); /* enable interrupt */ + } + + wmb(); + + /* wake DMA in case it is sleeping */ + reg_write(xmit->ohci, xmit->ContextControlSet, 1 << 12); + + /* issue a dummy read of the cycle timer to force all PCI + writes to be posted immediately */ + mb(); + reg_read(xmit->ohci, OHCI1394_IsochronousCycleTimer); + + return 0; +} + +static int ohci_iso_xmit_start(struct hpsb_iso *iso, int cycle) +{ + struct ohci_iso_xmit *xmit = iso->hostdata; + + /* clear out the control register */ + reg_write(xmit->ohci, xmit->ContextControlClear, 0xFFFFFFFF); + wmb(); + + /* address and length of first descriptor block (Z=3) */ + reg_write(xmit->ohci, xmit->CommandPtr, + dma_prog_region_offset_to_bus(&xmit->prog, iso->pkt_dma * sizeof(struct iso_xmit_cmd)) | 3); + + /* cycle match */ + if (cycle != -1) { + u32 start = cycle & 0x1FFF; + + /* 'cycle' is only mod 8000, but we also need two 'seconds' bits - + just snarf them from the current time */ + u32 seconds = reg_read(xmit->ohci, OHCI1394_IsochronousCycleTimer) >> 25; + + /* advance one second to give some extra time for DMA to start */ + seconds += 1; + + start |= (seconds & 3) << 13; + + reg_write(xmit->ohci, xmit->ContextControlSet, 0x80000000 | (start << 16)); + } + + /* enable interrupts */ + reg_write(xmit->ohci, OHCI1394_IsoXmitIntMaskSet, 1 << xmit->task.context); + + /* run */ + reg_write(xmit->ohci, xmit->ContextControlSet, 0x8000); + mb(); + + /* wait 100 usec to give the card time to go active */ + udelay(100); + + /* check the RUN bit */ + if (!(reg_read(xmit->ohci, xmit->ContextControlSet) & 0x8000)) { + PRINT(KERN_ERR, xmit->ohci->id, "Error starting IT DMA (ContextControl 0x%08x)\n", + reg_read(xmit->ohci, xmit->ContextControlSet)); + return -1; + } + + return 0; +} + +static int ohci_isoctl(struct hpsb_iso *iso, enum isoctl_cmd cmd, unsigned long arg) +{ + + switch(cmd) { + case XMIT_INIT: + return ohci_iso_xmit_init(iso); + case XMIT_START: + return ohci_iso_xmit_start(iso, arg); + case XMIT_STOP: + ohci_iso_xmit_stop(iso); + return 0; + case XMIT_QUEUE: + return ohci_iso_xmit_queue(iso, (struct hpsb_iso_packet_info*) arg); + case XMIT_SHUTDOWN: + ohci_iso_xmit_shutdown(iso); + return 0; + + case RECV_INIT: + return ohci_iso_recv_init(iso); + case RECV_START: { + int *args = (int*) arg; + return ohci_iso_recv_start(iso, args[0], args[1], args[2]); + } + case RECV_STOP: + ohci_iso_recv_stop(iso); + return 0; + case RECV_RELEASE: + ohci_iso_recv_release(iso, (struct hpsb_iso_packet_info*) arg); + return 0; + case RECV_FLUSH: + ohci_iso_recv_task((unsigned long) iso); + return 0; + case RECV_SHUTDOWN: + ohci_iso_recv_shutdown(iso); + return 0; + case RECV_LISTEN_CHANNEL: + ohci_iso_recv_change_channel(iso, arg, 1); + return 0; + case RECV_UNLISTEN_CHANNEL: + ohci_iso_recv_change_channel(iso, arg, 0); + return 0; + case RECV_SET_CHANNEL_MASK: + ohci_iso_recv_set_channel_mask(iso, *((u64*) arg)); + return 0; + + default: + PRINT_G(KERN_ERR, "ohci_isoctl cmd %d not implemented yet", + cmd); + break; + } + return -EINVAL; +} + +/*************************************** + * IEEE-1394 functionality section END * + ***************************************/ + + +/******************************************************** + * Global stuff (interrupt handler, init/shutdown code) * + ********************************************************/ + +static void dma_trm_reset(struct dma_trm_ctx *d) +{ + unsigned long flags; + LIST_HEAD(packet_list); + + ohci1394_stop_context(d->ohci, d->ctrlClear, NULL); + + /* Lock the context, reset it and release it. Move the packets + * that were pending in the context to packet_list and free + * them after releasing the lock. */ + + spin_lock_irqsave(&d->lock, flags); + + list_splice(&d->fifo_list, &packet_list); + list_splice(&d->pending_list, &packet_list); + INIT_LIST_HEAD(&d->fifo_list); + INIT_LIST_HEAD(&d->pending_list); + + d->branchAddrPtr = NULL; + d->sent_ind = d->prg_ind; + d->free_prgs = d->num_desc; + + spin_unlock_irqrestore(&d->lock, flags); + + /* Now process subsystem callbacks for the packets from the + * context. */ + + while (!list_empty(&packet_list)) { + struct hpsb_packet *p = driver_packet(packet_list.next); + PRINT(KERN_INFO, d->ohci->id, + "AT dma reset ctx=%d, aborting transmission", d->ctx); + list_del(&p->driver_list); + hpsb_packet_sent(d->ohci->host, p, ACKX_ABORTED); + } +} + +static void ohci_schedule_iso_tasklets(struct ti_ohci *ohci, + quadlet_t rx_event, + quadlet_t tx_event) +{ + struct list_head *lh; + struct ohci1394_iso_tasklet *t; + unsigned long mask; + + spin_lock(&ohci->iso_tasklet_list_lock); + + list_for_each(lh, &ohci->iso_tasklet_list) { + t = list_entry(lh, struct ohci1394_iso_tasklet, link); + mask = 1 << t->context; + + if (t->type == OHCI_ISO_TRANSMIT && tx_event & mask) + tasklet_schedule(&t->tasklet); + else if (rx_event & mask) + tasklet_schedule(&t->tasklet); + } + + spin_unlock(&ohci->iso_tasklet_list_lock); + +} + +static void ohci_irq_handler(int irq, void *dev_id, + struct pt_regs *regs_are_unused) +{ + quadlet_t event, node_id; + struct ti_ohci *ohci = (struct ti_ohci *)dev_id; + struct hpsb_host *host = ohci->host; + int phyid = -1, isroot = 0; + unsigned long flags; + + /* Read and clear the interrupt event register. Don't clear + * the busReset event, though. This is done when we get the + * selfIDComplete interrupt. */ + spin_lock_irqsave(&ohci->event_lock, flags); + event = reg_read(ohci, OHCI1394_IntEventClear); + reg_write(ohci, OHCI1394_IntEventClear, event & ~OHCI1394_busReset); + spin_unlock_irqrestore(&ohci->event_lock, flags); + + if (!event) return; + + DBGMSG(ohci->id, "IntEvent: %08x", event); + + if (event & OHCI1394_unrecoverableError) { + int ctx; + PRINT(KERN_ERR, ohci->id, "Unrecoverable error!"); + + if (reg_read(ohci, OHCI1394_AsReqTrContextControlSet) & 0x800) + PRINT(KERN_ERR, ohci->id, "Async Req Tx Context died: " + "ctrl[%08x] cmdptr[%08x]", + reg_read(ohci, OHCI1394_AsReqTrContextControlSet), + reg_read(ohci, OHCI1394_AsReqTrCommandPtr)); + + if (reg_read(ohci, OHCI1394_AsRspTrContextControlSet) & 0x800) + PRINT(KERN_ERR, ohci->id, "Async Rsp Tx Context died: " + "ctrl[%08x] cmdptr[%08x]", + reg_read(ohci, OHCI1394_AsRspTrContextControlSet), + reg_read(ohci, OHCI1394_AsRspTrCommandPtr)); + + if (reg_read(ohci, OHCI1394_AsReqRcvContextControlSet) & 0x800) + PRINT(KERN_ERR, ohci->id, "Async Req Rcv Context died: " + "ctrl[%08x] cmdptr[%08x]", + reg_read(ohci, OHCI1394_AsReqRcvContextControlSet), + reg_read(ohci, OHCI1394_AsReqRcvCommandPtr)); + + if (reg_read(ohci, OHCI1394_AsRspRcvContextControlSet) & 0x800) + PRINT(KERN_ERR, ohci->id, "Async Rsp Rcv Context died: " + "ctrl[%08x] cmdptr[%08x]", + reg_read(ohci, OHCI1394_AsRspRcvContextControlSet), + reg_read(ohci, OHCI1394_AsRspRcvCommandPtr)); + + for (ctx = 0; ctx < ohci->nb_iso_xmit_ctx; ctx++) { + if (reg_read(ohci, OHCI1394_IsoXmitContextControlSet + (16 * ctx)) & 0x800) + PRINT(KERN_ERR, ohci->id, "Iso Xmit %d Context died: " + "ctrl[%08x] cmdptr[%08x]", ctx, + reg_read(ohci, OHCI1394_IsoXmitContextControlSet + (16 * ctx)), + reg_read(ohci, OHCI1394_IsoXmitCommandPtr + (16 * ctx))); + } + + for (ctx = 0; ctx < ohci->nb_iso_rcv_ctx; ctx++) { + if (reg_read(ohci, OHCI1394_IsoRcvContextControlSet + (32 * ctx)) & 0x800) + PRINT(KERN_ERR, ohci->id, "Iso Recv %d Context died: " + "ctrl[%08x] cmdptr[%08x] match[%08x]", ctx, + reg_read(ohci, OHCI1394_IsoRcvContextControlSet + (32 * ctx)), + reg_read(ohci, OHCI1394_IsoRcvCommandPtr + (32 * ctx)), + reg_read(ohci, OHCI1394_IsoRcvContextMatch + (32 * ctx))); + } + + event &= ~OHCI1394_unrecoverableError; + } + + if (event & OHCI1394_cycleInconsistent) { + /* We subscribe to the cycleInconsistent event only to + * clear the corresponding event bit... otherwise, + * isochronous cycleMatch DMA won't work. */ + DBGMSG(ohci->id, "OHCI1394_cycleInconsistent"); + event &= ~OHCI1394_cycleInconsistent; + } + + if (event & OHCI1394_busReset) { + /* The busReset event bit can't be cleared during the + * selfID phase, so we disable busReset interrupts, to + * avoid burying the cpu in interrupt requests. */ + spin_lock_irqsave(&ohci->event_lock, flags); + reg_write(ohci, OHCI1394_IntMaskClear, OHCI1394_busReset); + + if (ohci->check_busreset) { + int loop_count = 0; + + udelay(10); + + while (reg_read(ohci, OHCI1394_IntEventSet) & OHCI1394_busReset) { + reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset); + + spin_unlock_irqrestore(&ohci->event_lock, flags); + udelay(10); + spin_lock_irqsave(&ohci->event_lock, flags); + + /* The loop counter check is to prevent the driver + * from remaining in this state forever. For the + * initial bus reset, the loop continues for ever + * and the system hangs, until some device is plugged-in + * or out manually into a port! The forced reset seems + * to solve this problem. This mainly effects nForce2. */ + if (loop_count > 10000) { + ohci_devctl(host, RESET_BUS, LONG_RESET); + DBGMSG(ohci->id, "Detected bus-reset loop. Forced a bus reset!"); + loop_count = 0; + } + + loop_count++; + } + } + spin_unlock_irqrestore(&ohci->event_lock, flags); + if (!host->in_bus_reset) { + DBGMSG(ohci->id, "irq_handler: Bus reset requested"); + + /* Subsystem call */ + hpsb_bus_reset(ohci->host); + } + event &= ~OHCI1394_busReset; + } + + /* XXX: We need a way to also queue the OHCI1394_reqTxComplete, + * but for right now we simply run it upon reception, to make sure + * we get sent acks before response packets. This sucks mainly + * because it halts the interrupt handler. */ + if (event & OHCI1394_reqTxComplete) { + struct dma_trm_ctx *d = &ohci->at_req_context; + DBGMSG(ohci->id, "Got reqTxComplete interrupt " + "status=0x%08X", reg_read(ohci, d->ctrlSet)); + if (reg_read(ohci, d->ctrlSet) & 0x800) + ohci1394_stop_context(ohci, d->ctrlClear, + "reqTxComplete"); + else + dma_trm_tasklet ((unsigned long)d); + event &= ~OHCI1394_reqTxComplete; + } + if (event & OHCI1394_respTxComplete) { + struct dma_trm_ctx *d = &ohci->at_resp_context; + DBGMSG(ohci->id, "Got respTxComplete interrupt " + "status=0x%08X", reg_read(ohci, d->ctrlSet)); + if (reg_read(ohci, d->ctrlSet) & 0x800) + ohci1394_stop_context(ohci, d->ctrlClear, + "respTxComplete"); + else + tasklet_schedule(&d->task); + event &= ~OHCI1394_respTxComplete; + } + if (event & OHCI1394_RQPkt) { + struct dma_rcv_ctx *d = &ohci->ar_req_context; + DBGMSG(ohci->id, "Got RQPkt interrupt status=0x%08X", + reg_read(ohci, d->ctrlSet)); + if (reg_read(ohci, d->ctrlSet) & 0x800) + ohci1394_stop_context(ohci, d->ctrlClear, "RQPkt"); + else + tasklet_schedule(&d->task); + event &= ~OHCI1394_RQPkt; + } + if (event & OHCI1394_RSPkt) { + struct dma_rcv_ctx *d = &ohci->ar_resp_context; + DBGMSG(ohci->id, "Got RSPkt interrupt status=0x%08X", + reg_read(ohci, d->ctrlSet)); + if (reg_read(ohci, d->ctrlSet) & 0x800) + ohci1394_stop_context(ohci, d->ctrlClear, "RSPkt"); + else + tasklet_schedule(&d->task); + event &= ~OHCI1394_RSPkt; + } + if (event & OHCI1394_isochRx) { + quadlet_t rx_event; + + rx_event = reg_read(ohci, OHCI1394_IsoRecvIntEventSet); + reg_write(ohci, OHCI1394_IsoRecvIntEventClear, rx_event); + ohci_schedule_iso_tasklets(ohci, rx_event, 0); + event &= ~OHCI1394_isochRx; + } + if (event & OHCI1394_isochTx) { + quadlet_t tx_event; + + tx_event = reg_read(ohci, OHCI1394_IsoXmitIntEventSet); + reg_write(ohci, OHCI1394_IsoXmitIntEventClear, tx_event); + ohci_schedule_iso_tasklets(ohci, 0, tx_event); + event &= ~OHCI1394_isochTx; + } + if (event & OHCI1394_selfIDComplete) { + if (host->in_bus_reset) { + node_id = reg_read(ohci, OHCI1394_NodeID); + + if (!(node_id & 0x80000000)) { + PRINT(KERN_ERR, ohci->id, + "SelfID received, but NodeID invalid " + "(probably new bus reset occurred): %08X", + node_id); + goto selfid_not_valid; + } + + phyid = node_id & 0x0000003f; + isroot = (node_id & 0x40000000) != 0; + + DBGMSG(ohci->id, + "SelfID interrupt received " + "(phyid %d, %s)", phyid, + (isroot ? "root" : "not root")); + + handle_selfid(ohci, host, phyid, isroot); + + /* Clear the bus reset event and re-enable the + * busReset interrupt. */ + spin_lock_irqsave(&ohci->event_lock, flags); + reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset); + reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_busReset); + spin_unlock_irqrestore(&ohci->event_lock, flags); + + /* Accept Physical requests from all nodes. */ + reg_write(ohci,OHCI1394_AsReqFilterHiSet, 0xffffffff); + reg_write(ohci,OHCI1394_AsReqFilterLoSet, 0xffffffff); + + /* Turn on phys dma reception. + * + * TODO: Enable some sort of filtering management. + */ + if (phys_dma) { + reg_write(ohci,OHCI1394_PhyReqFilterHiSet, 0xffffffff); + reg_write(ohci,OHCI1394_PhyReqFilterLoSet, 0xffffffff); + reg_write(ohci,OHCI1394_PhyUpperBound, 0xffff0000); + } else { + reg_write(ohci,OHCI1394_PhyReqFilterHiSet, 0x00000000); + reg_write(ohci,OHCI1394_PhyReqFilterLoSet, 0x00000000); + } + + DBGMSG(ohci->id, "PhyReqFilter=%08x%08x", + reg_read(ohci,OHCI1394_PhyReqFilterHiSet), + reg_read(ohci,OHCI1394_PhyReqFilterLoSet)); + + hpsb_selfid_complete(host, phyid, isroot); + } else + PRINT(KERN_ERR, ohci->id, + "SelfID received outside of bus reset sequence"); + +selfid_not_valid: + event &= ~OHCI1394_selfIDComplete; + } + + /* Make sure we handle everything, just in case we accidentally + * enabled an interrupt that we didn't write a handler for. */ + if (event) + PRINT(KERN_ERR, ohci->id, "Unhandled interrupt(s) 0x%08x", + event); + + return; +} + +/* Put the buffer back into the dma context */ +static void insert_dma_buffer(struct dma_rcv_ctx *d, int idx) +{ + struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci); + DBGMSG(ohci->id, "Inserting dma buf ctx=%d idx=%d", d->ctx, idx); + + d->prg_cpu[idx]->status = cpu_to_le32(d->buf_size); + d->prg_cpu[idx]->branchAddress &= le32_to_cpu(0xfffffff0); + idx = (idx + d->num_desc - 1 ) % d->num_desc; + d->prg_cpu[idx]->branchAddress |= le32_to_cpu(0x00000001); + + /* wake up the dma context if necessary */ + if (!(reg_read(ohci, d->ctrlSet) & 0x400)) { + PRINT(KERN_INFO, ohci->id, + "Waking dma ctx=%d ... processing is probably too slow", + d->ctx); + } + + /* do this always, to avoid race condition */ + reg_write(ohci, d->ctrlSet, 0x1000); +} + +#define cond_le32_to_cpu(data, noswap) \ + (noswap ? data : le32_to_cpu(data)) + +static const int TCODE_SIZE[16] = {20, 0, 16, -1, 16, 20, 20, 0, + -1, 0, -1, 0, -1, -1, 16, -1}; + +/* + * Determine the length of a packet in the buffer + * Optimization suggested by Pascal Drolet + */ +static __inline__ int packet_length(struct dma_rcv_ctx *d, int idx, quadlet_t *buf_ptr, + int offset, unsigned char tcode, int noswap) +{ + int length = -1; + + if (d->type == DMA_CTX_ASYNC_REQ || d->type == DMA_CTX_ASYNC_RESP) { + length = TCODE_SIZE[tcode]; + if (length == 0) { + if (offset + 12 >= d->buf_size) { + length = (cond_le32_to_cpu(d->buf_cpu[(idx + 1) % d->num_desc] + [3 - ((d->buf_size - offset) >> 2)], noswap) >> 16); + } else { + length = (cond_le32_to_cpu(buf_ptr[3], noswap) >> 16); + } + length += 20; + } + } else if (d->type == DMA_CTX_ISO) { + /* Assumption: buffer fill mode with header/trailer */ + length = (cond_le32_to_cpu(buf_ptr[0], noswap) >> 16) + 8; + } + + if (length > 0 && length % 4) + length += 4 - (length % 4); + + return length; +} + +/* Tasklet that processes dma receive buffers */ +static void dma_rcv_tasklet (unsigned long data) +{ + struct dma_rcv_ctx *d = (struct dma_rcv_ctx*)data; + struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci); + unsigned int split_left, idx, offset, rescount; + unsigned char tcode; + int length, bytes_left, ack; + unsigned long flags; + quadlet_t *buf_ptr; + char *split_ptr; + char msg[256]; + + spin_lock_irqsave(&d->lock, flags); + + idx = d->buf_ind; + offset = d->buf_offset; + buf_ptr = d->buf_cpu[idx] + offset/4; + + rescount = le32_to_cpu(d->prg_cpu[idx]->status) & 0xffff; + bytes_left = d->buf_size - rescount - offset; + + while (bytes_left > 0) { + tcode = (cond_le32_to_cpu(buf_ptr[0], ohci->no_swap_incoming) >> 4) & 0xf; + + /* packet_length() will return < 4 for an error */ + length = packet_length(d, idx, buf_ptr, offset, tcode, ohci->no_swap_incoming); + + if (length < 4) { /* something is wrong */ + sprintf(msg,"Unexpected tcode 0x%x(0x%08x) in AR ctx=%d, length=%d", + tcode, cond_le32_to_cpu(buf_ptr[0], ohci->no_swap_incoming), + d->ctx, length); + ohci1394_stop_context(ohci, d->ctrlClear, msg); + spin_unlock_irqrestore(&d->lock, flags); + return; + } + + /* The first case is where we have a packet that crosses + * over more than one descriptor. The next case is where + * it's all in the first descriptor. */ + if ((offset + length) > d->buf_size) { + DBGMSG(ohci->id,"Split packet rcv'd"); + if (length > d->split_buf_size) { + ohci1394_stop_context(ohci, d->ctrlClear, + "Split packet size exceeded"); + d->buf_ind = idx; + d->buf_offset = offset; + spin_unlock_irqrestore(&d->lock, flags); + return; + } + + if (le32_to_cpu(d->prg_cpu[(idx+1)%d->num_desc]->status) + == d->buf_size) { + /* Other part of packet not written yet. + * this should never happen I think + * anyway we'll get it on the next call. */ + PRINT(KERN_INFO, ohci->id, + "Got only half a packet!"); + d->buf_ind = idx; + d->buf_offset = offset; + spin_unlock_irqrestore(&d->lock, flags); + return; + } + + split_left = length; + split_ptr = (char *)d->spb; + memcpy(split_ptr,buf_ptr,d->buf_size-offset); + split_left -= d->buf_size-offset; + split_ptr += d->buf_size-offset; + insert_dma_buffer(d, idx); + idx = (idx+1) % d->num_desc; + buf_ptr = d->buf_cpu[idx]; + offset=0; + + while (split_left >= d->buf_size) { + memcpy(split_ptr,buf_ptr,d->buf_size); + split_ptr += d->buf_size; + split_left -= d->buf_size; + insert_dma_buffer(d, idx); + idx = (idx+1) % d->num_desc; + buf_ptr = d->buf_cpu[idx]; + } + + if (split_left > 0) { + memcpy(split_ptr, buf_ptr, split_left); + offset = split_left; + buf_ptr += offset/4; + } + } else { + DBGMSG(ohci->id,"Single packet rcv'd"); + memcpy(d->spb, buf_ptr, length); + offset += length; + buf_ptr += length/4; + if (offset==d->buf_size) { + insert_dma_buffer(d, idx); + idx = (idx+1) % d->num_desc; + buf_ptr = d->buf_cpu[idx]; + offset=0; + } + } + + /* We get one phy packet to the async descriptor for each + * bus reset. We always ignore it. */ + if (tcode != OHCI1394_TCODE_PHY) { + if (!ohci->no_swap_incoming) + packet_swab(d->spb, tcode); + DBGMSG(ohci->id, "Packet received from node" + " %d ack=0x%02X spd=%d tcode=0x%X" + " length=%d ctx=%d tlabel=%d", + (d->spb[1]>>16)&0x3f, + (cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>16)&0x1f, + (cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>21)&0x3, + tcode, length, d->ctx, + (cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>10)&0x3f); + + ack = (((cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>16)&0x1f) + == 0x11) ? 1 : 0; + + hpsb_packet_received(ohci->host, d->spb, + length-4, ack); + } +#ifdef OHCI1394_DEBUG + else + PRINT (KERN_DEBUG, ohci->id, "Got phy packet ctx=%d ... discarded", + d->ctx); +#endif + + rescount = le32_to_cpu(d->prg_cpu[idx]->status) & 0xffff; + + bytes_left = d->buf_size - rescount - offset; + + } + + d->buf_ind = idx; + d->buf_offset = offset; + + spin_unlock_irqrestore(&d->lock, flags); +} + +/* Bottom half that processes sent packets */ +static void dma_trm_tasklet (unsigned long data) +{ + struct dma_trm_ctx *d = (struct dma_trm_ctx*)data; + struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci); + struct hpsb_packet *packet; + unsigned long flags; + u32 status, ack; + size_t datasize; + + spin_lock_irqsave(&d->lock, flags); + + while (!list_empty(&d->fifo_list)) { + packet = driver_packet(d->fifo_list.next); + datasize = packet->data_size; + if (datasize && packet->type != hpsb_raw) + status = le32_to_cpu( + d->prg_cpu[d->sent_ind]->end.status) >> 16; + else + status = le32_to_cpu( + d->prg_cpu[d->sent_ind]->begin.status) >> 16; + + if (status == 0) + /* this packet hasn't been sent yet*/ + break; + +#ifdef OHCI1394_DEBUG + if (datasize) + if (((le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])>>4)&0xf) == 0xa) + DBGMSG(ohci->id, + "Stream packet sent to channel %d tcode=0x%X " + "ack=0x%X spd=%d dataLength=%d ctx=%d", + (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])>>8)&0x3f, + (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0])>>4)&0xf, + status&0x1f, (status>>5)&0x3, + le32_to_cpu(d->prg_cpu[d->sent_ind]->data[1])>>16, + d->ctx); + else + DBGMSG(ohci->id, + "Packet sent to node %d tcode=0x%X tLabel=" + "%d ack=0x%X spd=%d dataLength=%d ctx=%d", + (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[1]) + >>16)&0x3f, + (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0]) + >>4)&0xf, + (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0]) + >>10)&0x3f, + status&0x1f, (status>>5)&0x3, + le32_to_cpu(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", + (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[1]) + >>16)&0x3f, + (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0]) + >>4)&0xf, + (le32_to_cpu(d->prg_cpu[d->sent_ind]->data[0]) + >>10)&0x3f, + status&0x1f, (status>>5)&0x3, + le32_to_cpu(d->prg_cpu[d->sent_ind]->data[3]), + d->ctx); +#endif + + if (status & 0x10) { + ack = status & 0xf; + } else { + switch (status & 0x1f) { + case EVT_NO_STATUS: /* that should never happen */ + case EVT_RESERVED_A: /* that should never happen */ + case EVT_LONG_PACKET: /* that should never happen */ + PRINT(KERN_WARNING, ohci->id, "Received OHCI evt_* error 0x%x", status & 0x1f); + ack = ACKX_SEND_ERROR; + break; + case EVT_MISSING_ACK: + ack = ACKX_TIMEOUT; + break; + case EVT_UNDERRUN: + ack = ACKX_SEND_ERROR; + break; + case EVT_OVERRUN: /* that should never happen */ + PRINT(KERN_WARNING, ohci->id, "Received OHCI evt_* error 0x%x", status & 0x1f); + ack = ACKX_SEND_ERROR; + break; + case EVT_DESCRIPTOR_READ: + case EVT_DATA_READ: + case EVT_DATA_WRITE: + ack = ACKX_SEND_ERROR; + break; + case EVT_BUS_RESET: /* that should never happen */ + PRINT(KERN_WARNING, ohci->id, "Received OHCI evt_* error 0x%x", status & 0x1f); + ack = ACKX_SEND_ERROR; + break; + case EVT_TIMEOUT: + ack = ACKX_TIMEOUT; + break; + case EVT_TCODE_ERR: + ack = ACKX_SEND_ERROR; + break; + case EVT_RESERVED_B: /* that should never happen */ + case EVT_RESERVED_C: /* that should never happen */ + PRINT(KERN_WARNING, ohci->id, "Received OHCI evt_* error 0x%x", status & 0x1f); + ack = ACKX_SEND_ERROR; + break; + case EVT_UNKNOWN: + case EVT_FLUSHED: + ack = ACKX_SEND_ERROR; + break; + default: + PRINT(KERN_ERR, ohci->id, "Unhandled OHCI evt_* error 0x%x", status & 0x1f); + ack = ACKX_SEND_ERROR; + BUG(); + } + } + + list_del(&packet->driver_list); + hpsb_packet_sent(ohci->host, packet, ack); + + if (datasize) { + pci_unmap_single(ohci->dev, + cpu_to_le32(d->prg_cpu[d->sent_ind]->end.address), + datasize, PCI_DMA_TODEVICE); + OHCI_DMA_FREE("single Xmit data packet"); + } + + d->sent_ind = (d->sent_ind+1)%d->num_desc; + d->free_prgs++; + } + + dma_trm_flush(ohci, d); + + spin_unlock_irqrestore(&d->lock, flags); +} + +static void free_dma_rcv_ctx(struct dma_rcv_ctx *d) +{ + int i; + + if (d->ohci == NULL) + return; + + DBGMSG(d->ohci->id, "Freeing dma_rcv_ctx %d", d->ctx); + + if (d->ctrlClear) { + ohci1394_stop_context(d->ohci, d->ctrlClear, NULL); + + if (d->type == DMA_CTX_ISO) { + /* disable interrupts */ + reg_write(d->ohci, OHCI1394_IsoRecvIntMaskClear, 1 << d->ctx); + ohci1394_unregister_iso_tasklet(d->ohci, &d->ohci->ir_legacy_tasklet); + } else { + tasklet_kill(&d->task); + } + } + + if (d->buf_cpu) { + for (i=0; inum_desc; i++) + if (d->buf_cpu[i] && d->buf_bus[i]) { + pci_free_consistent( + d->ohci->dev, d->buf_size, + d->buf_cpu[i], d->buf_bus[i]); + OHCI_DMA_FREE("consistent dma_rcv buf[%d]", i); + } + kfree(d->buf_cpu); + kfree(d->buf_bus); + } + if (d->prg_cpu) { + for (i=0; inum_desc; i++) + if (d->prg_cpu[i] && d->prg_bus[i]) { + pci_pool_free(d->prg_pool, d->prg_cpu[i], d->prg_bus[i]); + OHCI_DMA_FREE("consistent dma_rcv prg[%d]", i); + } + pci_pool_destroy(d->prg_pool); + OHCI_DMA_FREE("dma_rcv prg pool"); + kfree(d->prg_cpu); + kfree(d->prg_bus); + } + if (d->spb) kfree(d->spb); + + /* Mark this context as freed. */ + d->ohci = NULL; +} + +static int +alloc_dma_rcv_ctx(struct ti_ohci *ohci, struct dma_rcv_ctx *d, + enum context_type type, int ctx, int num_desc, + int buf_size, int split_buf_size, int context_base) +{ + int i; + + d->ohci = ohci; + d->type = type; + d->ctx = ctx; + + d->num_desc = num_desc; + d->buf_size = buf_size; + d->split_buf_size = split_buf_size; + + d->ctrlSet = 0; + d->ctrlClear = 0; + d->cmdPtr = 0; + + d->buf_cpu = kmalloc(d->num_desc * sizeof(quadlet_t*), GFP_KERNEL); + d->buf_bus = kmalloc(d->num_desc * sizeof(dma_addr_t), GFP_KERNEL); + + if (d->buf_cpu == NULL || d->buf_bus == NULL) { + PRINT(KERN_ERR, ohci->id, "Failed to allocate dma buffer"); + free_dma_rcv_ctx(d); + return -ENOMEM; + } + memset(d->buf_cpu, 0, d->num_desc * sizeof(quadlet_t*)); + memset(d->buf_bus, 0, d->num_desc * sizeof(dma_addr_t)); + + d->prg_cpu = kmalloc(d->num_desc * sizeof(struct dma_cmd*), + GFP_KERNEL); + d->prg_bus = kmalloc(d->num_desc * sizeof(dma_addr_t), GFP_KERNEL); + + if (d->prg_cpu == NULL || d->prg_bus == NULL) { + PRINT(KERN_ERR, ohci->id, "Failed to allocate dma prg"); + free_dma_rcv_ctx(d); + return -ENOMEM; + } + memset(d->prg_cpu, 0, d->num_desc * sizeof(struct dma_cmd*)); + memset(d->prg_bus, 0, d->num_desc * sizeof(dma_addr_t)); + + d->spb = kmalloc(d->split_buf_size, GFP_KERNEL); + + if (d->spb == NULL) { + PRINT(KERN_ERR, ohci->id, "Failed to allocate split buffer"); + free_dma_rcv_ctx(d); + return -ENOMEM; + } + + d->prg_pool = pci_pool_create("ohci1394 rcv prg", ohci->dev, + sizeof(struct dma_cmd), 4, 0, SLAB_KERNEL); + OHCI_DMA_ALLOC("dma_rcv prg pool"); + + for (i=0; inum_desc; i++) { + d->buf_cpu[i] = pci_alloc_consistent(ohci->dev, + d->buf_size, + d->buf_bus+i); + OHCI_DMA_ALLOC("consistent dma_rcv buf[%d]", i); + + if (d->buf_cpu[i] != NULL) { + memset(d->buf_cpu[i], 0, d->buf_size); + } else { + PRINT(KERN_ERR, ohci->id, + "Failed to allocate dma buffer"); + free_dma_rcv_ctx(d); + return -ENOMEM; + } + + d->prg_cpu[i] = pci_pool_alloc(d->prg_pool, SLAB_KERNEL, d->prg_bus+i); + OHCI_DMA_ALLOC("pool dma_rcv prg[%d]", i); + + if (d->prg_cpu[i] != NULL) { + memset(d->prg_cpu[i], 0, sizeof(struct dma_cmd)); + } else { + PRINT(KERN_ERR, ohci->id, + "Failed to allocate dma prg"); + free_dma_rcv_ctx(d); + return -ENOMEM; + } + } + + spin_lock_init(&d->lock); + + if (type == DMA_CTX_ISO) { + ohci1394_init_iso_tasklet(&ohci->ir_legacy_tasklet, + OHCI_ISO_MULTICHANNEL_RECEIVE, + dma_rcv_tasklet, (unsigned long) d); + if (ohci1394_register_iso_tasklet(ohci, + &ohci->ir_legacy_tasklet) < 0) { + PRINT(KERN_ERR, ohci->id, "No IR DMA context available"); + free_dma_rcv_ctx(d); + return -EBUSY; + } + + /* the IR context can be assigned to any DMA context + * by ohci1394_register_iso_tasklet */ + d->ctx = ohci->ir_legacy_tasklet.context; + d->ctrlSet = OHCI1394_IsoRcvContextControlSet + 32*d->ctx; + d->ctrlClear = OHCI1394_IsoRcvContextControlClear + 32*d->ctx; + d->cmdPtr = OHCI1394_IsoRcvCommandPtr + 32*d->ctx; + d->ctxtMatch = OHCI1394_IsoRcvContextMatch + 32*d->ctx; + } else { + d->ctrlSet = context_base + OHCI1394_ContextControlSet; + d->ctrlClear = context_base + OHCI1394_ContextControlClear; + d->cmdPtr = context_base + OHCI1394_ContextCommandPtr; + + tasklet_init (&d->task, dma_rcv_tasklet, (unsigned long) d); + } + + return 0; +} + +static void free_dma_trm_ctx(struct dma_trm_ctx *d) +{ + int i; + + if (d->ohci == NULL) + return; + + DBGMSG(d->ohci->id, "Freeing dma_trm_ctx %d", d->ctx); + + if (d->ctrlClear) { + ohci1394_stop_context(d->ohci, d->ctrlClear, NULL); + + if (d->type == DMA_CTX_ISO) { + /* disable interrupts */ + reg_write(d->ohci, OHCI1394_IsoXmitIntMaskClear, 1 << d->ctx); + ohci1394_unregister_iso_tasklet(d->ohci, + &d->ohci->it_legacy_tasklet); + } else { + tasklet_kill(&d->task); + } + } + + if (d->prg_cpu) { + for (i=0; inum_desc; i++) + if (d->prg_cpu[i] && d->prg_bus[i]) { + pci_pool_free(d->prg_pool, d->prg_cpu[i], d->prg_bus[i]); + OHCI_DMA_FREE("pool dma_trm prg[%d]", i); + } + pci_pool_destroy(d->prg_pool); + OHCI_DMA_FREE("dma_trm prg pool"); + kfree(d->prg_cpu); + kfree(d->prg_bus); + } + + /* Mark this context as freed. */ + d->ohci = NULL; +} + +static int +alloc_dma_trm_ctx(struct ti_ohci *ohci, struct dma_trm_ctx *d, + enum context_type type, int ctx, int num_desc, + int context_base) +{ + int i; + + d->ohci = ohci; + d->type = type; + d->ctx = ctx; + d->num_desc = num_desc; + d->ctrlSet = 0; + d->ctrlClear = 0; + d->cmdPtr = 0; + + d->prg_cpu = kmalloc(d->num_desc * sizeof(struct at_dma_prg*), + GFP_KERNEL); + d->prg_bus = kmalloc(d->num_desc * sizeof(dma_addr_t), GFP_KERNEL); + + if (d->prg_cpu == NULL || d->prg_bus == NULL) { + PRINT(KERN_ERR, ohci->id, "Failed to allocate at dma prg"); + free_dma_trm_ctx(d); + return -ENOMEM; + } + memset(d->prg_cpu, 0, d->num_desc * sizeof(struct at_dma_prg*)); + memset(d->prg_bus, 0, d->num_desc * sizeof(dma_addr_t)); + + d->prg_pool = pci_pool_create("ohci1394 trm prg", ohci->dev, + sizeof(struct at_dma_prg), 4, 0, SLAB_KERNEL); + OHCI_DMA_ALLOC("dma_rcv prg pool"); + + for (i = 0; i < d->num_desc; i++) { + d->prg_cpu[i] = pci_pool_alloc(d->prg_pool, SLAB_KERNEL, d->prg_bus+i); + OHCI_DMA_ALLOC("pool dma_trm prg[%d]", i); + + if (d->prg_cpu[i] != NULL) { + memset(d->prg_cpu[i], 0, sizeof(struct at_dma_prg)); + } else { + PRINT(KERN_ERR, ohci->id, + "Failed to allocate at dma prg"); + free_dma_trm_ctx(d); + return -ENOMEM; + } + } + + spin_lock_init(&d->lock); + + /* initialize tasklet */ + if (type == DMA_CTX_ISO) { + ohci1394_init_iso_tasklet(&ohci->it_legacy_tasklet, OHCI_ISO_TRANSMIT, + dma_trm_tasklet, (unsigned long) d); + if (ohci1394_register_iso_tasklet(ohci, + &ohci->it_legacy_tasklet) < 0) { + PRINT(KERN_ERR, ohci->id, "No IT DMA context available"); + free_dma_trm_ctx(d); + return -EBUSY; + } + + /* IT can be assigned to any context by register_iso_tasklet */ + d->ctx = ohci->it_legacy_tasklet.context; + d->ctrlSet = OHCI1394_IsoXmitContextControlSet + 16 * d->ctx; + d->ctrlClear = OHCI1394_IsoXmitContextControlClear + 16 * d->ctx; + d->cmdPtr = OHCI1394_IsoXmitCommandPtr + 16 * d->ctx; + } else { + d->ctrlSet = context_base + OHCI1394_ContextControlSet; + d->ctrlClear = context_base + OHCI1394_ContextControlClear; + d->cmdPtr = context_base + OHCI1394_ContextCommandPtr; + tasklet_init (&d->task, dma_trm_tasklet, (unsigned long)d); + } + + return 0; +} + +static u16 ohci_crc16 (u32 *ptr, int length) +{ + int shift; + u32 crc, sum, data; + + crc = 0; + for (; length > 0; length--) { + data = be32_to_cpu(*ptr++); + for (shift = 28; shift >= 0; shift -= 4) { + sum = ((crc >> 12) ^ (data >> shift)) & 0x000f; + crc = (crc << 4) ^ (sum << 12) ^ (sum << 5) ^ sum; + } + crc &= 0xffff; + } + return crc; +} + +/* Config ROM macro implementation influenced by NetBSD OHCI driver */ + +struct config_rom_unit { + u32 *start; + u32 *refer; + int length; + int refunit; +}; + +struct config_rom_ptr { + u32 *data; + int unitnum; + struct config_rom_unit unitdir[10]; +}; + +#define cf_put_1quad(cr, q) (((cr)->data++)[0] = cpu_to_be32(q)) + +#define cf_put_4bytes(cr, b1, b2, b3, b4) \ + (((cr)->data++)[0] = cpu_to_be32(((b1) << 24) | ((b2) << 16) | ((b3) << 8) | (b4))) + +#define cf_put_keyval(cr, key, val) (((cr)->data++)[0] = cpu_to_be32(((key) << 24) | (val))) + +static inline void cf_put_str(struct config_rom_ptr *cr, const char *str) +{ + int t; + char fourb[4]; + + while (str[0]) { + memset(fourb, 0, 4); + for (t = 0; t < 4 && str[t]; t++) + fourb[t] = str[t]; + cf_put_4bytes(cr, fourb[0], fourb[1], fourb[2], fourb[3]); + str += strlen(str) < 4 ? strlen(str) : 4; + } + return; +} + +static inline void cf_put_crc16(struct config_rom_ptr *cr, int unit) +{ + *cr->unitdir[unit].start = + cpu_to_be32((cr->unitdir[unit].length << 16) | + ohci_crc16(cr->unitdir[unit].start + 1, + cr->unitdir[unit].length)); +} + +static inline void cf_unit_begin(struct config_rom_ptr *cr, int unit) +{ + if (cr->unitdir[unit].refer != NULL) { + *cr->unitdir[unit].refer |= + cpu_to_be32 (cr->data - cr->unitdir[unit].refer); + cf_put_crc16(cr, cr->unitdir[unit].refunit); + } + cr->unitnum = unit; + cr->unitdir[unit].start = cr->data++; +} + +static inline void cf_put_refer(struct config_rom_ptr *cr, char key, int unit) +{ + cr->unitdir[unit].refer = cr->data; + cr->unitdir[unit].refunit = cr->unitnum; + (cr->data++)[0] = cpu_to_be32(key << 24); +} + +static inline void cf_unit_end(struct config_rom_ptr *cr) +{ + cr->unitdir[cr->unitnum].length = cr->data - + (cr->unitdir[cr->unitnum].start + 1); + cf_put_crc16(cr, cr->unitnum); +} + +/* End of NetBSD derived code. */ + +static void ohci_init_config_rom(struct ti_ohci *ohci) +{ + struct config_rom_ptr cr; + + memset(&cr, 0, sizeof(cr)); + memset(ohci->csr_config_rom_cpu, 0, OHCI_CONFIG_ROM_LEN); + + cr.data = ohci->csr_config_rom_cpu; + + /* Bus info block */ + cf_unit_begin(&cr, 0); + cf_put_1quad(&cr, reg_read(ohci, OHCI1394_BusID)); + cf_put_1quad(&cr, reg_read(ohci, OHCI1394_BusOptions)); + cf_put_1quad(&cr, reg_read(ohci, OHCI1394_GUIDHi)); + cf_put_1quad(&cr, reg_read(ohci, OHCI1394_GUIDLo)); + cf_unit_end(&cr); + + DBGMSG(ohci->id, "GUID: %08x:%08x", reg_read(ohci, OHCI1394_GUIDHi), + reg_read(ohci, OHCI1394_GUIDLo)); + + /* IEEE P1212 suggests the initial ROM header CRC should only + * cover the header itself (and not the entire ROM). Since we do + * this, then we can make our bus_info_len the same as the CRC + * length. */ + ohci->csr_config_rom_cpu[0] |= cpu_to_be32( + (be32_to_cpu(ohci->csr_config_rom_cpu[0]) & 0x00ff0000) << 8); + reg_write(ohci, OHCI1394_ConfigROMhdr, + be32_to_cpu(ohci->csr_config_rom_cpu[0])); + + /* Root directory */ + cf_unit_begin(&cr, 1); + /* Vendor ID */ + cf_put_keyval(&cr, 0x03, reg_read(ohci,OHCI1394_VendorID) & 0xFFFFFF); + cf_put_refer(&cr, 0x81, 2); /* Textual description unit */ + cf_put_keyval(&cr, 0x0c, 0x0083c0); /* Node capabilities */ + /* NOTE: Add other unit referers here, and append at bottom */ + cf_unit_end(&cr); + + /* Textual description - "Linux 1394" */ + cf_unit_begin(&cr, 2); + cf_put_keyval(&cr, 0, 0); + cf_put_1quad(&cr, 0); + cf_put_str(&cr, "Linux OHCI-1394"); + cf_unit_end(&cr); + + ohci->csr_config_rom_length = cr.data - ohci->csr_config_rom_cpu; +} + +static size_t ohci_get_rom(struct hpsb_host *host, quadlet_t **ptr) +{ + struct ti_ohci *ohci=host->hostdata; + + DBGMSG(ohci->id, "request csr_rom address: %p", + ohci->csr_config_rom_cpu); + + *ptr = ohci->csr_config_rom_cpu; + + return ohci->csr_config_rom_length * 4; +} + +static quadlet_t ohci_hw_csr_reg(struct hpsb_host *host, int reg, + quadlet_t data, quadlet_t compare) +{ + struct ti_ohci *ohci = host->hostdata; + int i; + + reg_write(ohci, OHCI1394_CSRData, data); + reg_write(ohci, OHCI1394_CSRCompareData, compare); + reg_write(ohci, OHCI1394_CSRControl, reg & 0x3); + + for (i = 0; i < OHCI_LOOP_COUNT; i++) { + if (reg_read(ohci, OHCI1394_CSRControl) & 0x80000000) + break; + + mdelay(1); + } + + return reg_read(ohci, OHCI1394_CSRData); +} + +static struct hpsb_host_driver ohci1394_driver = { + .name = OHCI1394_DRIVER_NAME, + .get_rom = ohci_get_rom, + .transmit_packet = ohci_transmit, + .devctl = ohci_devctl, + .isoctl = ohci_isoctl, + .hw_csr_reg = ohci_hw_csr_reg, +}; + + + +/*********************************** + * PCI Driver Interface functions * + ***********************************/ + +#define FAIL(err, fmt, args...) \ +do { \ + PRINT_G(KERN_ERR, fmt , ## args); \ + ohci1394_pci_remove(dev); \ + return err; \ +} while (0) + +static int __devinit ohci1394_pci_probe(struct pci_dev *dev, + const struct pci_device_id *ent) +{ + static unsigned int card_id_counter = 0; + static int version_printed = 0; + + struct hpsb_host *host; + struct ti_ohci *ohci; /* shortcut to currently handled device */ + unsigned long ohci_base; + + if (version_printed++ == 0) + PRINT_G(KERN_INFO, "%s", version); + + if (pci_enable_device(dev)) + FAIL(-ENXIO, "Failed to enable OHCI hardware %d", + card_id_counter++); + pci_set_master(dev); + + host = hpsb_alloc_host(&ohci1394_driver, sizeof(struct ti_ohci)); + if (!host) FAIL(-ENOMEM, "Failed to allocate host structure"); + + ohci = host->hostdata; + ohci->id = card_id_counter++; + ohci->dev = dev; + ohci->host = host; + ohci->init_state = OHCI_INIT_ALLOC_HOST; + host->pdev = dev; + pci_set_drvdata(dev, ohci); + + /* We don't want hardware swapping */ + pci_write_config_dword(dev, OHCI1394_PCI_HCI_Control, 0); + + /* Some oddball Apple controllers do not order the selfid + * properly, so we make up for it here. */ +#ifndef __LITTLE_ENDIAN + /* XXX: Need a better way to check this. I'm wondering if we can + * read the values of the OHCI1394_PCI_HCI_Control and the + * noByteSwapData registers to see if they were not cleared to + * zero. Should this work? Obviously it's not defined what these + * registers will read when they aren't supported. Bleh! */ + if (dev->vendor == PCI_VENDOR_ID_APPLE && + dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW) { + ohci->no_swap_incoming = 1; + ohci->selfid_swap = 0; + } else + ohci->selfid_swap = 1; +#endif + +#ifndef PCI_DEVICE_ID_NVIDIA_NFORCE2_FW +#define PCI_DEVICE_ID_NVIDIA_NFORCE2_FW 0x006e +#endif + + /* These chipsets require a bit of extra care when checking after + * a busreset. */ + if ((dev->vendor == PCI_VENDOR_ID_APPLE && + dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW) || + (dev->vendor == PCI_VENDOR_ID_NVIDIA && + dev->device == PCI_DEVICE_ID_NVIDIA_NFORCE2_FW)) + ohci->check_busreset = 1; + + /* We hardwire the MMIO length, since some CardBus adaptors + * fail to report the right length. Anyway, the ohci spec + * clearly says it's 2kb, so this shouldn't be a problem. */ + ohci_base = pci_resource_start(dev, 0); + if (pci_resource_len(dev, 0) != OHCI1394_REGISTER_SIZE) + PRINT(KERN_WARNING, ohci->id, "Unexpected PCI resource length of %lx!", + pci_resource_len(dev, 0)); + + /* Seems PCMCIA handles this internally. Not sure why. Seems + * pretty bogus to force a driver to special case this. */ +#ifndef PCMCIA + if (!request_mem_region (ohci_base, OHCI1394_REGISTER_SIZE, OHCI1394_DRIVER_NAME)) + FAIL(-ENOMEM, "MMIO resource (0x%lx - 0x%lx) unavailable", + ohci_base, ohci_base + OHCI1394_REGISTER_SIZE); +#endif + ohci->init_state = OHCI_INIT_HAVE_MEM_REGION; + + ohci->registers = ioremap(ohci_base, OHCI1394_REGISTER_SIZE); + if (ohci->registers == NULL) + FAIL(-ENXIO, "Failed to remap registers - card not accessible"); + ohci->init_state = OHCI_INIT_HAVE_IOMAPPING; + DBGMSG(ohci->id, "Remapped memory spaces reg 0x%p", ohci->registers); + + /* csr_config rom allocation */ + ohci->csr_config_rom_cpu = + pci_alloc_consistent(ohci->dev, OHCI_CONFIG_ROM_LEN, + &ohci->csr_config_rom_bus); + OHCI_DMA_ALLOC("consistent csr_config_rom"); + if (ohci->csr_config_rom_cpu == NULL) + FAIL(-ENOMEM, "Failed to allocate buffer config rom"); + ohci->init_state = OHCI_INIT_HAVE_CONFIG_ROM_BUFFER; + + /* self-id dma buffer allocation */ + ohci->selfid_buf_cpu = + pci_alloc_consistent(ohci->dev, OHCI1394_SI_DMA_BUF_SIZE, + &ohci->selfid_buf_bus); + OHCI_DMA_ALLOC("consistent selfid_buf"); + + if (ohci->selfid_buf_cpu == NULL) + FAIL(-ENOMEM, "Failed to allocate DMA buffer for self-id packets"); + ohci->init_state = OHCI_INIT_HAVE_SELFID_BUFFER; + + if ((unsigned long)ohci->selfid_buf_cpu & 0x1fff) + PRINT(KERN_INFO, ohci->id, "SelfID buffer %p is not aligned on " + "8Kb boundary... may cause problems on some CXD3222 chip", + ohci->selfid_buf_cpu); + + /* No self-id errors at startup */ + ohci->self_id_errors = 0; + + ohci->init_state = OHCI_INIT_HAVE_TXRX_BUFFERS__MAYBE; + /* AR DMA request context allocation */ + if (alloc_dma_rcv_ctx(ohci, &ohci->ar_req_context, + DMA_CTX_ASYNC_REQ, 0, AR_REQ_NUM_DESC, + AR_REQ_BUF_SIZE, AR_REQ_SPLIT_BUF_SIZE, + OHCI1394_AsReqRcvContextBase) < 0) + FAIL(-ENOMEM, "Failed to allocate AR Req context"); + + /* AR DMA response context allocation */ + if (alloc_dma_rcv_ctx(ohci, &ohci->ar_resp_context, + DMA_CTX_ASYNC_RESP, 0, AR_RESP_NUM_DESC, + AR_RESP_BUF_SIZE, AR_RESP_SPLIT_BUF_SIZE, + OHCI1394_AsRspRcvContextBase) < 0) + FAIL(-ENOMEM, "Failed to allocate AR Resp context"); + + /* AT DMA request context */ + if (alloc_dma_trm_ctx(ohci, &ohci->at_req_context, + DMA_CTX_ASYNC_REQ, 0, AT_REQ_NUM_DESC, + OHCI1394_AsReqTrContextBase) < 0) + FAIL(-ENOMEM, "Failed to allocate AT Req context"); + + /* AT DMA response context */ + if (alloc_dma_trm_ctx(ohci, &ohci->at_resp_context, + DMA_CTX_ASYNC_RESP, 1, AT_RESP_NUM_DESC, + OHCI1394_AsRspTrContextBase) < 0) + FAIL(-ENOMEM, "Failed to allocate AT Resp context"); + + /* Start off with a soft reset, to clear everything to a sane + * state. */ + ohci_soft_reset(ohci); + + /* Now enable LPS, which we need in order to start accessing + * most of the registers. In fact, on some cards (ALI M5251), + * accessing registers in the SClk domain without LPS enabled + * will lock up the machine. Wait 50msec to make sure we have + * full link enabled. */ + reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_LPS); + mdelay(50); + + /* Determine the number of available IR and IT contexts. */ + ohci->nb_iso_rcv_ctx = + get_nb_iso_ctx(ohci, OHCI1394_IsoRecvIntMaskSet); + DBGMSG(ohci->id, "%d iso receive contexts available", + ohci->nb_iso_rcv_ctx); + + ohci->nb_iso_xmit_ctx = + get_nb_iso_ctx(ohci, OHCI1394_IsoXmitIntMaskSet); + DBGMSG(ohci->id, "%d iso transmit contexts available", + ohci->nb_iso_xmit_ctx); + + /* Set the usage bits for non-existent contexts so they can't + * be allocated */ + ohci->ir_ctx_usage = ~0 << ohci->nb_iso_rcv_ctx; + ohci->it_ctx_usage = ~0 << ohci->nb_iso_xmit_ctx; + + INIT_LIST_HEAD(&ohci->iso_tasklet_list); + spin_lock_init(&ohci->iso_tasklet_list_lock); + ohci->ISO_channel_usage = 0; + spin_lock_init(&ohci->IR_channel_lock); + + /* the IR DMA context is allocated on-demand; mark it inactive */ + ohci->ir_legacy_context.ohci = NULL; + + /* same for the IT DMA context */ + ohci->it_legacy_context.ohci = NULL; + + if (request_irq(dev->irq, ohci_irq_handler, SA_SHIRQ, + OHCI1394_DRIVER_NAME, ohci)) + FAIL(-ENOMEM, "Failed to allocate shared interrupt %d", dev->irq); + + ohci->init_state = OHCI_INIT_HAVE_IRQ; + ohci_initialize(ohci); + + /* Tell the highlevel this host is ready */ + hpsb_add_host(host); + ohci->init_state = OHCI_INIT_DONE; + + return 0; +#undef FAIL +} + +static void ohci1394_pci_remove(struct pci_dev *pdev) +{ + struct ti_ohci *ohci; + + ohci = pci_get_drvdata(pdev); + if (!ohci) + return; + + switch (ohci->init_state) { + case OHCI_INIT_DONE: + hpsb_remove_host(ohci->host); + + /* Clear out BUS Options */ + reg_write(ohci, OHCI1394_ConfigROMhdr, 0); + reg_write(ohci, OHCI1394_BusOptions, + (reg_read(ohci, OHCI1394_BusOptions) & 0x0000f007) | + 0x00ff0000); + memset(ohci->csr_config_rom_cpu, 0, OHCI_CONFIG_ROM_LEN); + + case OHCI_INIT_HAVE_IRQ: + /* Clear interrupt registers */ + reg_write(ohci, OHCI1394_IntMaskClear, 0xffffffff); + reg_write(ohci, OHCI1394_IntEventClear, 0xffffffff); + reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 0xffffffff); + reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 0xffffffff); + reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff); + reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff); + + /* Disable IRM Contender */ + set_phy_reg(ohci, 4, ~0xc0 & get_phy_reg(ohci, 4)); + + /* Clear link control register */ + reg_write(ohci, OHCI1394_LinkControlClear, 0xffffffff); + + /* Let all other nodes know to ignore us */ + ohci_devctl(ohci->host, RESET_BUS, LONG_RESET_NO_FORCE_ROOT); + + /* Soft reset before we start - this disables + * interrupts and clears linkEnable and LPS. */ + ohci_soft_reset(ohci); + free_irq(ohci->dev->irq, ohci); + + case OHCI_INIT_HAVE_TXRX_BUFFERS__MAYBE: + /* Free AR dma */ + free_dma_rcv_ctx(&ohci->ar_req_context); + free_dma_rcv_ctx(&ohci->ar_resp_context); + + /* Free AT dma */ + free_dma_trm_ctx(&ohci->at_req_context); + free_dma_trm_ctx(&ohci->at_resp_context); + + /* Free IR dma */ + free_dma_rcv_ctx(&ohci->ir_legacy_context); + + /* Free IT dma */ + free_dma_trm_ctx(&ohci->it_legacy_context); + + case OHCI_INIT_HAVE_SELFID_BUFFER: + pci_free_consistent(ohci->dev, OHCI1394_SI_DMA_BUF_SIZE, + ohci->selfid_buf_cpu, + ohci->selfid_buf_bus); + OHCI_DMA_FREE("consistent selfid_buf"); + + case OHCI_INIT_HAVE_CONFIG_ROM_BUFFER: + pci_free_consistent(ohci->dev, OHCI_CONFIG_ROM_LEN, + ohci->csr_config_rom_cpu, + ohci->csr_config_rom_bus); + OHCI_DMA_FREE("consistent csr_config_rom"); + + case OHCI_INIT_HAVE_IOMAPPING: + iounmap(ohci->registers); + + case OHCI_INIT_HAVE_MEM_REGION: +#ifndef PCMCIA + release_mem_region(pci_resource_start(ohci->dev, 0), + OHCI1394_REGISTER_SIZE); +#endif + +#ifdef CONFIG_ALL_PPC + /* On UniNorth, power down the cable and turn off the chip + * clock when the module is removed to save power on + * laptops. Turning it back ON is done by the arch code when + * pci_enable_device() is called */ + { + struct device_node* of_node; + + of_node = pci_device_to_OF_node(ohci->dev); + if (of_node) { + pmac_call_feature(PMAC_FTR_1394_ENABLE, of_node, 0, 0); + pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, of_node, 0, 0); + } + } +#endif /* CONFIG_ALL_PPC */ + + case OHCI_INIT_ALLOC_HOST: + pci_set_drvdata(ohci->dev, NULL); + hpsb_unref_host(ohci->host); + } +} + + +#ifdef CONFIG_PM +static int ohci1394_pci_resume (struct pci_dev *dev) +{ + pci_enable_device(dev); + return 0; +} +#endif + + +#define PCI_CLASS_FIREWIRE_OHCI ((PCI_CLASS_SERIAL_FIREWIRE << 8) | 0x10) + +static struct pci_device_id ohci1394_pci_tbl[] __devinitdata = { + { + .class = PCI_CLASS_FIREWIRE_OHCI, + .class_mask = PCI_ANY_ID, + .vendor = PCI_ANY_ID, + .device = PCI_ANY_ID, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { 0, }, +}; + +MODULE_DEVICE_TABLE(pci, ohci1394_pci_tbl); + +static struct pci_driver ohci1394_pci_driver = { + .name = OHCI1394_DRIVER_NAME, + .id_table = ohci1394_pci_tbl, + .probe = ohci1394_pci_probe, + .remove = ohci1394_pci_remove, + +#ifdef CONFIG_PM + .resume = ohci1394_pci_resume, +#endif /* PM */ +}; + + + +/*********************************** + * OHCI1394 Video Interface * + ***********************************/ + +/* essentially the only purpose of this code is to allow another + module to hook into ohci's interrupt handler */ + +int ohci1394_stop_context(struct ti_ohci *ohci, int reg, char *msg) +{ + int i=0; + + /* stop the channel program if it's still running */ + reg_write(ohci, reg, 0x8000); + + /* Wait until it effectively stops */ + while (reg_read(ohci, reg) & 0x400) { + i++; + if (i>5000) { + PRINT(KERN_ERR, ohci->id, + "Runaway loop while stopping context: %s...", msg ? msg : ""); + return 1; + } + + mb(); + udelay(10); + } + if (msg) PRINT(KERN_ERR, ohci->id, "%s: dma prg stopped", msg); + return 0; +} + +void ohci1394_init_iso_tasklet(struct ohci1394_iso_tasklet *tasklet, int type, + void (*func)(unsigned long), unsigned long data) +{ + tasklet_init(&tasklet->tasklet, func, data); + tasklet->type = type; + /* We init the tasklet->link field, so we can list_del() it + * without worrying whether it was added to the list or not. */ + INIT_LIST_HEAD(&tasklet->link); +} + +int ohci1394_register_iso_tasklet(struct ti_ohci *ohci, + struct ohci1394_iso_tasklet *tasklet) +{ + unsigned long flags, *usage; + int n, i, r = -EBUSY; + + if (tasklet->type == OHCI_ISO_TRANSMIT) { + n = ohci->nb_iso_xmit_ctx; + usage = &ohci->it_ctx_usage; + } + else { + n = ohci->nb_iso_rcv_ctx; + usage = &ohci->ir_ctx_usage; + + /* only one receive context can be multichannel (OHCI sec 10.4.1) */ + if (tasklet->type == OHCI_ISO_MULTICHANNEL_RECEIVE) { + if (test_and_set_bit(0, &ohci->ir_multichannel_used)) { + return r; + } + } + } + + spin_lock_irqsave(&ohci->iso_tasklet_list_lock, flags); + + for (i = 0; i < n; i++) + if (!test_and_set_bit(i, usage)) { + tasklet->context = i; + list_add_tail(&tasklet->link, &ohci->iso_tasklet_list); + r = 0; + break; + } + + spin_unlock_irqrestore(&ohci->iso_tasklet_list_lock, flags); + + return r; +} + +void ohci1394_unregister_iso_tasklet(struct ti_ohci *ohci, + struct ohci1394_iso_tasklet *tasklet) +{ + unsigned long flags; + + tasklet_kill(&tasklet->tasklet); + + spin_lock_irqsave(&ohci->iso_tasklet_list_lock, flags); + + if (tasklet->type == OHCI_ISO_TRANSMIT) + clear_bit(tasklet->context, &ohci->it_ctx_usage); + else { + clear_bit(tasklet->context, &ohci->ir_ctx_usage); + + if (tasklet->type == OHCI_ISO_MULTICHANNEL_RECEIVE) { + clear_bit(0, &ohci->ir_multichannel_used); + } + } + + list_del(&tasklet->link); + + spin_unlock_irqrestore(&ohci->iso_tasklet_list_lock, flags); +} + +EXPORT_SYMBOL(ohci1394_stop_context); +EXPORT_SYMBOL(ohci1394_init_iso_tasklet); +EXPORT_SYMBOL(ohci1394_register_iso_tasklet); +EXPORT_SYMBOL(ohci1394_unregister_iso_tasklet); + + +/*********************************** + * General module initialization * + ***********************************/ + +MODULE_AUTHOR("Sebastien Rougeaux "); +MODULE_DESCRIPTION("Driver for PCI OHCI IEEE-1394 controllers"); +MODULE_LICENSE("GPL"); + +static void __exit ohci1394_cleanup (void) +{ + pci_unregister_driver(&ohci1394_pci_driver); +} + +static int __init ohci1394_init(void) +{ + return pci_module_init(&ohci1394_pci_driver); +} + +module_init(ohci1394_init); +module_exit(ohci1394_cleanup); diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/ohci1394.h.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/ohci1394.h.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/ohci1394.h.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/ohci1394.h.svn-base 2003-07-21 13:09:35.000000000 +0200 @@ -0,0 +1,456 @@ +/* + * ohci1394.h - driver for OHCI 1394 boards + * Copyright (C)1999,2000 Sebastien Rougeaux + * Gord Peters + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the 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 _OHCI1394_H +#define _OHCI1394_H + +#include + +#include "ieee1394_types.h" +#include + +#define OHCI1394_DRIVER_NAME "ohci1394" + +#define OHCI1394_MAX_AT_REQ_RETRIES 0x2 +#define OHCI1394_MAX_AT_RESP_RETRIES 0x2 +#define OHCI1394_MAX_PHYS_RESP_RETRIES 0x8 +#define OHCI1394_MAX_SELF_ID_ERRORS 16 + +#define AR_REQ_NUM_DESC 4 /* number of AR req descriptors */ +#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 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 PAGE_SIZE /* 4096 bytes/buffer */ +#define IR_SPLIT_BUF_SIZE PAGE_SIZE /* split packet buffer */ + +#define IT_NUM_DESC 16 /* number of IT descriptors */ + +#define AT_REQ_NUM_DESC 32 /* number of AT req descriptors */ +#define AT_RESP_NUM_DESC 32 /* number of AT resp descriptors */ + +#define OHCI_LOOP_COUNT 100 /* Number of loops for reg read waits */ + +#define OHCI_CONFIG_ROM_LEN 1024 /* Length of the mapped configrom space */ + +#define OHCI1394_SI_DMA_BUF_SIZE 8192 /* length of the selfid buffer */ + +/* PCI configuration space addresses */ +#define OHCI1394_PCI_HCI_Control 0x40 + +struct dma_cmd { + u32 control; + u32 address; + u32 branchAddress; + 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 */ +}; + +/* identify whether a DMA context is asynchronous or isochronous */ +enum context_type { DMA_CTX_ASYNC_REQ, DMA_CTX_ASYNC_RESP, DMA_CTX_ISO }; + +/* DMA receive context */ +struct dma_rcv_ctx { + struct ti_ohci *ohci; + enum context_type type; + int ctx; + unsigned int num_desc; + + unsigned int buf_size; + unsigned int split_buf_size; + + /* dma block descriptors */ + struct dma_cmd **prg_cpu; + dma_addr_t *prg_bus; + struct pci_pool *prg_pool; + + /* dma buffers */ + quadlet_t **buf_cpu; + dma_addr_t *buf_bus; + + unsigned int buf_ind; + unsigned int buf_offset; + quadlet_t *spb; + spinlock_t lock; + struct tasklet_struct task; + int ctrlClear; + int ctrlSet; + int cmdPtr; + int ctxtMatch; +}; + +/* DMA transmit context */ +struct dma_trm_ctx { + struct ti_ohci *ohci; + enum context_type type; + int ctx; + unsigned int num_desc; + + /* dma block descriptors */ + struct at_dma_prg **prg_cpu; + dma_addr_t *prg_bus; + struct pci_pool *prg_pool; + + unsigned int prg_ind; + unsigned int sent_ind; + int free_prgs; + quadlet_t *branchAddrPtr; + + /* list of packets inserted in the AT FIFO */ + struct list_head fifo_list; + + /* list of pending packets to be inserted in the AT FIFO */ + struct list_head pending_list; + + spinlock_t lock; + struct tasklet_struct task; + int ctrlClear; + int ctrlSet; + int cmdPtr; +}; + +struct ohci1394_iso_tasklet { + struct tasklet_struct tasklet; + struct list_head link; + int context; + enum { OHCI_ISO_TRANSMIT, OHCI_ISO_RECEIVE, + OHCI_ISO_MULTICHANNEL_RECEIVE } type; +}; + +struct ti_ohci { + int id; /* sequential card number */ + + struct pci_dev *dev; + + enum { + OHCI_INIT_ALLOC_HOST, + OHCI_INIT_HAVE_MEM_REGION, + OHCI_INIT_HAVE_IOMAPPING, + OHCI_INIT_HAVE_CONFIG_ROM_BUFFER, + OHCI_INIT_HAVE_SELFID_BUFFER, + OHCI_INIT_HAVE_TXRX_BUFFERS__MAYBE, + OHCI_INIT_HAVE_IRQ, + OHCI_INIT_DONE, + } init_state; + + /* remapped memory spaces */ + void *registers; + + /* dma buffer for self-id packets */ + quadlet_t *selfid_buf_cpu; + dma_addr_t selfid_buf_bus; + + /* buffer for csr config rom */ + quadlet_t *csr_config_rom_cpu; + dma_addr_t csr_config_rom_bus; + int csr_config_rom_length; + + unsigned int max_packet_size; + + /* async receive */ + struct dma_rcv_ctx ar_resp_context; + struct dma_rcv_ctx ar_req_context; + + /* async transmit */ + struct dma_trm_ctx at_resp_context; + struct dma_trm_ctx at_req_context; + + /* iso receive */ + int nb_iso_rcv_ctx; + unsigned long ir_ctx_usage; /* use test_and_set_bit() for atomicity */ + unsigned long ir_multichannel_used; /* ditto */ + spinlock_t IR_channel_lock; + + /* iso receive (legacy API) */ + u64 ir_legacy_channels; /* note: this differs from ISO_channel_usage; + it only accounts for channels listened to + by the legacy API, so that we can know when + it is safe to free the legacy API context */ + + struct dma_rcv_ctx ir_legacy_context; + struct ohci1394_iso_tasklet ir_legacy_tasklet; + + /* iso transmit */ + int nb_iso_xmit_ctx; + unsigned long it_ctx_usage; /* use test_and_set_bit() for atomicity */ + + /* iso transmit (legacy API) */ + struct dma_trm_ctx it_legacy_context; + struct ohci1394_iso_tasklet it_legacy_tasklet; + + u64 ISO_channel_usage; + + /* IEEE-1394 part follows */ + struct hpsb_host *host; + + int phyid, isroot; + + spinlock_t phy_reg_lock; + spinlock_t event_lock; + + int self_id_errors; + + /* Tasklets for iso receive and transmit, used by video1394, + * amdtp and dv1394 */ + + struct list_head iso_tasklet_list; + spinlock_t iso_tasklet_list_lock; + + /* Swap the selfid buffer? */ + unsigned int selfid_swap:1; + /* Some Apple chipset seem to swap incoming headers for us */ + unsigned int no_swap_incoming:1; + + /* Force extra paranoia checking on bus-reset handling */ + unsigned int check_busreset:1; +}; + +static inline int cross_bound(unsigned long addr, unsigned int size) +{ + int cross=0; + if (size>PAGE_SIZE) { + cross = size/PAGE_SIZE; + size -= cross*PAGE_SIZE; + } + if ((PAGE_SIZE-addr%PAGE_SIZE)registers + offset); +} + +static inline u32 reg_read(const struct ti_ohci *ohci, int offset) +{ + return readl(ohci->registers + offset); +} + + +/* 2 KiloBytes of register space */ +#define OHCI1394_REGISTER_SIZE 0x800 + +/* Offsets relative to context bases defined below */ + +#define OHCI1394_ContextControlSet 0x000 +#define OHCI1394_ContextControlClear 0x004 +#define OHCI1394_ContextCommandPtr 0x00C + +/* register map */ +#define OHCI1394_Version 0x000 +#define OHCI1394_GUID_ROM 0x004 +#define OHCI1394_ATRetries 0x008 +#define OHCI1394_CSRData 0x00C +#define OHCI1394_CSRCompareData 0x010 +#define OHCI1394_CSRControl 0x014 +#define OHCI1394_ConfigROMhdr 0x018 +#define OHCI1394_BusID 0x01C +#define OHCI1394_BusOptions 0x020 +#define OHCI1394_GUIDHi 0x024 +#define OHCI1394_GUIDLo 0x028 +#define OHCI1394_ConfigROMmap 0x034 +#define OHCI1394_PostedWriteAddressLo 0x038 +#define OHCI1394_PostedWriteAddressHi 0x03C +#define OHCI1394_VendorID 0x040 +#define OHCI1394_HCControlSet 0x050 +#define OHCI1394_HCControlClear 0x054 +#define OHCI1394_HCControl_noByteSwap 0x40000000 +#define OHCI1394_HCControl_programPhyEnable 0x00800000 +#define OHCI1394_HCControl_aPhyEnhanceEnable 0x00400000 +#define OHCI1394_HCControl_LPS 0x00080000 +#define OHCI1394_HCControl_postedWriteEnable 0x00040000 +#define OHCI1394_HCControl_linkEnable 0x00020000 +#define OHCI1394_HCControl_softReset 0x00010000 +#define OHCI1394_SelfIDBuffer 0x064 +#define OHCI1394_SelfIDCount 0x068 +#define OHCI1394_IRMultiChanMaskHiSet 0x070 +#define OHCI1394_IRMultiChanMaskHiClear 0x074 +#define OHCI1394_IRMultiChanMaskLoSet 0x078 +#define OHCI1394_IRMultiChanMaskLoClear 0x07C +#define OHCI1394_IntEventSet 0x080 +#define OHCI1394_IntEventClear 0x084 +#define OHCI1394_IntMaskSet 0x088 +#define OHCI1394_IntMaskClear 0x08C +#define OHCI1394_IsoXmitIntEventSet 0x090 +#define OHCI1394_IsoXmitIntEventClear 0x094 +#define OHCI1394_IsoXmitIntMaskSet 0x098 +#define OHCI1394_IsoXmitIntMaskClear 0x09C +#define OHCI1394_IsoRecvIntEventSet 0x0A0 +#define OHCI1394_IsoRecvIntEventClear 0x0A4 +#define OHCI1394_IsoRecvIntMaskSet 0x0A8 +#define OHCI1394_IsoRecvIntMaskClear 0x0AC +#define OHCI1394_InitialBandwidthAvailable 0x0B0 +#define OHCI1394_InitialChannelsAvailableHi 0x0B4 +#define OHCI1394_InitialChannelsAvailableLo 0x0B8 +#define OHCI1394_FairnessControl 0x0DC +#define OHCI1394_LinkControlSet 0x0E0 +#define OHCI1394_LinkControlClear 0x0E4 +#define OHCI1394_NodeID 0x0E8 +#define OHCI1394_PhyControl 0x0EC +#define OHCI1394_IsochronousCycleTimer 0x0F0 +#define OHCI1394_AsReqFilterHiSet 0x100 +#define OHCI1394_AsReqFilterHiClear 0x104 +#define OHCI1394_AsReqFilterLoSet 0x108 +#define OHCI1394_AsReqFilterLoClear 0x10C +#define OHCI1394_PhyReqFilterHiSet 0x110 +#define OHCI1394_PhyReqFilterHiClear 0x114 +#define OHCI1394_PhyReqFilterLoSet 0x118 +#define OHCI1394_PhyReqFilterLoClear 0x11C +#define OHCI1394_PhyUpperBound 0x120 + +#define OHCI1394_AsReqTrContextBase 0x180 +#define OHCI1394_AsReqTrContextControlSet 0x180 +#define OHCI1394_AsReqTrContextControlClear 0x184 +#define OHCI1394_AsReqTrCommandPtr 0x18C + +#define OHCI1394_AsRspTrContextBase 0x1A0 +#define OHCI1394_AsRspTrContextControlSet 0x1A0 +#define OHCI1394_AsRspTrContextControlClear 0x1A4 +#define OHCI1394_AsRspTrCommandPtr 0x1AC + +#define OHCI1394_AsReqRcvContextBase 0x1C0 +#define OHCI1394_AsReqRcvContextControlSet 0x1C0 +#define OHCI1394_AsReqRcvContextControlClear 0x1C4 +#define OHCI1394_AsReqRcvCommandPtr 0x1CC + +#define OHCI1394_AsRspRcvContextBase 0x1E0 +#define OHCI1394_AsRspRcvContextControlSet 0x1E0 +#define OHCI1394_AsRspRcvContextControlClear 0x1E4 +#define OHCI1394_AsRspRcvCommandPtr 0x1EC + +/* Isochronous transmit registers */ +/* Add (16 * n) for context n */ +#define OHCI1394_IsoXmitContextBase 0x200 +#define OHCI1394_IsoXmitContextControlSet 0x200 +#define OHCI1394_IsoXmitContextControlClear 0x204 +#define OHCI1394_IsoXmitCommandPtr 0x20C + +/* Isochronous receive registers */ +/* Add (32 * n) for context n */ +#define OHCI1394_IsoRcvContextBase 0x400 +#define OHCI1394_IsoRcvContextControlSet 0x400 +#define OHCI1394_IsoRcvContextControlClear 0x404 +#define OHCI1394_IsoRcvCommandPtr 0x40C +#define OHCI1394_IsoRcvContextMatch 0x410 + +/* Interrupts Mask/Events */ + +#define OHCI1394_reqTxComplete 0x00000001 +#define OHCI1394_respTxComplete 0x00000002 +#define OHCI1394_ARRQ 0x00000004 +#define OHCI1394_ARRS 0x00000008 +#define OHCI1394_RQPkt 0x00000010 +#define OHCI1394_RSPkt 0x00000020 +#define OHCI1394_isochTx 0x00000040 +#define OHCI1394_isochRx 0x00000080 +#define OHCI1394_postedWriteErr 0x00000100 +#define OHCI1394_lockRespErr 0x00000200 +#define OHCI1394_selfIDComplete 0x00010000 +#define OHCI1394_busReset 0x00020000 +#define OHCI1394_phy 0x00080000 +#define OHCI1394_cycleSynch 0x00100000 +#define OHCI1394_cycle64Seconds 0x00200000 +#define OHCI1394_cycleLost 0x00400000 +#define OHCI1394_cycleInconsistent 0x00800000 +#define OHCI1394_unrecoverableError 0x01000000 +#define OHCI1394_cycleTooLong 0x02000000 +#define OHCI1394_phyRegRcvd 0x04000000 +#define OHCI1394_masterIntEnable 0x80000000 + +/* DMA Control flags */ +#define DMA_CTL_OUTPUT_MORE 0x00000000 +#define DMA_CTL_OUTPUT_LAST 0x10000000 +#define DMA_CTL_INPUT_MORE 0x20000000 +#define DMA_CTL_INPUT_LAST 0x30000000 +#define DMA_CTL_UPDATE 0x08000000 +#define DMA_CTL_IMMEDIATE 0x02000000 +#define DMA_CTL_IRQ 0x00300000 +#define DMA_CTL_BRANCH 0x000c0000 +#define DMA_CTL_WAIT 0x00030000 + +/* OHCI evt_* error types, table 3-2 of the OHCI 1.1 spec. */ +#define EVT_NO_STATUS 0x0 /* No event status */ +#define EVT_RESERVED_A 0x1 /* Reserved, not used !!! */ +#define EVT_LONG_PACKET 0x2 /* The revc data was longer than the buf */ +#define EVT_MISSING_ACK 0x3 /* A subaction gap was detected before an ack + arrived, or recv'd ack had a parity error */ +#define EVT_UNDERRUN 0x4 /* Underrun on corresponding FIFO, packet + truncated */ +#define EVT_OVERRUN 0x5 /* A recv FIFO overflowed on reception of ISO + packet */ +#define EVT_DESCRIPTOR_READ 0x6 /* An unrecoverable error occurred while host was + reading a descriptor block */ +#define EVT_DATA_READ 0x7 /* An error occurred while host controller was + attempting to read from host memory in the data + stage of descriptor processing */ +#define EVT_DATA_WRITE 0x8 /* An error occurred while host controller was + attempting to write either during the data stage + of descriptor processing, or when processing a single + 16-bit host memory write */ +#define EVT_BUS_RESET 0x9 /* Identifies a PHY packet in the recv buffer as + being a synthesized bus reset packet */ +#define EVT_TIMEOUT 0xa /* Indicates that the asynchronous transmit response + packet expired and was not transmitted, or that an + IT DMA context experienced a skip processing overflow */ +#define EVT_TCODE_ERR 0xb /* A bad tCode is associated with this packet. + The packet was flushed */ +#define EVT_RESERVED_B 0xc /* Reserved, not used !!! */ +#define EVT_RESERVED_C 0xd /* Reserved, not used !!! */ +#define EVT_UNKNOWN 0xe /* An error condition has occurred that cannot be + represented by any other event codes defined herein. */ +#define EVT_FLUSHED 0xf /* Send by the link side of output FIFO when asynchronous + packets are being flushed due to a bus reset. */ + +#define OHCI1394_TCODE_PHY 0xE + +void ohci1394_init_iso_tasklet(struct ohci1394_iso_tasklet *tasklet, + int type, + void (*func)(unsigned long), + unsigned long data); +int ohci1394_register_iso_tasklet(struct ti_ohci *ohci, + struct ohci1394_iso_tasklet *tasklet); +void ohci1394_unregister_iso_tasklet(struct ti_ohci *ohci, + struct ohci1394_iso_tasklet *tasklet); + +/* returns zero if successful, one if DMA context is locked up */ +int ohci1394_stop_context (struct ti_ohci *ohci, int reg, char *msg); +struct ti_ohci *ohci1394_get_struct(int card_num); + +#endif diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/oui.db.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/oui.db.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/oui.db.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/oui.db.svn-base 2003-07-21 13:09:31.000000000 +0200 @@ -0,0 +1,4931 @@ +000000 XEROX CORPORATION +000001 XEROX CORPORATION +000002 XEROX CORPORATION +000003 XEROX CORPORATION +000004 XEROX CORPORATION +000005 XEROX CORPORATION +000006 XEROX CORPORATION +000007 XEROX CORPORATION +000008 XEROX CORPORATION +000009 XEROX CORPORATION +00000A OMRON TATEISI ELECTRONICS CO. +00000B MATRIX CORPORATION +00000C CISCO SYSTEMS, INC. +00000D FIBRONICS LTD. +00000E FUJITSU LIMITED +00000F NEXT, INC. +000010 SYTEK INC. +000011 NORMEREL SYSTEMES +000012 INFORMATION TECHNOLOGY LIMITED +000013 CAMEX +000014 NETRONIX +000015 DATAPOINT CORPORATION +000016 DU PONT PIXEL SYSTEMS . +000017 TEKELEC +000018 WEBSTER COMPUTER CORPORATION +000019 APPLIED DYNAMICS INTERNATIONAL +00001A ADVANCED MICRO DEVICES +00001B NOVELL INC. +00001C BELL TECHNOLOGIES +00001D CABLETRON SYSTEMS, INC. +00001E TELSIST INDUSTRIA ELECTRONICA +00001F Telco Systems, Inc. +000020 DATAINDUSTRIER DIAB AB +000021 SUREMAN COMP. & COMMUN. CORP. +000022 VISUAL TECHNOLOGY INC. +000023 ABB INDUSTRIAL SYSTEMS AB +000024 CONNECT AS +000025 RAMTEK CORP. +000026 SHA-KEN CO., LTD. +000027 JAPAN RADIO COMPANY +000028 PRODIGY SYSTEMS CORPORATION +000029 IMC NETWORKS CORP. +00002A TRW - SEDD/INP +00002B CRISP AUTOMATION, INC +00002C AUTOTOTE LIMITED +00002D CHROMATICS INC +00002E SOCIETE EVIRA +00002F TIMEPLEX INC. +000030 VG LABORATORY SYSTEMS LTD +000031 QPSX COMMUNICATIONS PTY LTD +000032 Marconi plc +000033 EGAN MACHINERY COMPANY +000034 NETWORK RESOURCES CORPORATION +000035 SPECTRAGRAPHICS CORPORATION +000036 ATARI CORPORATION +000037 OXFORD METRICS LIMITED +000038 CSS LABS +000039 TOSHIBA CORPORATION +00003A CHYRON CORPORATION +00003B i Controls, Inc. +00003C AUSPEX SYSTEMS INC. +00003D UNISYS +00003E SIMPACT +00003F SYNTREX, INC. +000040 APPLICON, INC. +000041 ICE CORPORATION +000042 METIER MANAGEMENT SYSTEMS LTD. +000043 MICRO TECHNOLOGY +000044 CASTELLE CORPORATION +000045 FORD AEROSPACE & COMM. CORP. +000046 OLIVETTI NORTH AMERICA +000047 NICOLET INSTRUMENTS CORP. +000048 SEIKO EPSON CORPORATION +000049 APRICOT COMPUTERS, LTD +00004A ADC CODENOLL TECHNOLOGY CORP. +00004B ICL DATA OY +00004C NEC CORPORATION +00004D DCI CORPORATION +00004E AMPEX CORPORATION +00004F LOGICRAFT, INC. +000050 RADISYS CORPORATION +000051 HOB ELECTRONIC GMBH & CO. KG +000052 Intrusion.com, Inc. +000053 COMPUCORP +000054 MODICON, INC. +000055 COMMISSARIAT A L`ENERGIE ATOM. +000056 DR. B. STRUCK +000057 SCITEX CORPORATION LTD. +000058 RACORE COMPUTER PRODUCTS INC. +000059 HELLIGE GMBH +00005A SysKonnect GmbH +00005B ELTEC ELEKTRONIK AG +00005C TELEMATICS INTERNATIONAL INC. +00005D CS TELECOM +00005E USC INFORMATION SCIENCES INST +00005F SUMITOMO ELECTRIC IND., LTD. +000060 KONTRON ELEKTRONIK GMBH +000061 GATEWAY COMMUNICATIONS +000062 BULL HN INFORMATION SYSTEMS +000063 DR.ING.SEUFERT GMBH +000064 YOKOGAWA DIGITAL COMPUTER CORP +000065 NETWORK ASSOCIATES, INC. +000066 TALARIS SYSTEMS, INC. +000067 SOFT * RITE, INC. +000068 ROSEMOUNT CONTROLS +000069 CONCORD COMMUNICATIONS INC +00006A COMPUTER CONSOLES INC. +00006B SILICON GRAPHICS INC./MIPS +00006D CRAY COMMUNICATIONS, LTD. +00006E ARTISOFT, INC. +00006F MADGE NETWORKS LTD. +000070 HCL LIMITED +000071 ADRA SYSTEMS INC. +000072 MINIWARE TECHNOLOGY +000073 SIECOR CORPORATION +000074 RICOH COMPANY LTD. +000075 Nortel Networks +000076 ABEKAS VIDEO SYSTEM +000077 INTERPHASE CORPORATION +000078 LABTAM LIMITED +000079 NETWORTH INCORPORATED +00007A DANA COMPUTER INC. +00007B RESEARCH MACHINES +00007C AMPERE INCORPORATED +00007D SUN MICROSYSTEMS, INC. +00007E CLUSTRIX CORPORATION +00007F LINOTYPE-HELL AG +000080 CRAY COMMUNICATIONS A/S +000081 BAY NETWORKS +000082 LECTRA SYSTEMES SA +000083 TADPOLE TECHNOLOGY PLC +000084 SUPERNET +000085 CANON INC. +000086 MEGAHERTZ CORPORATION +000087 HITACHI, LTD. +000088 COMPUTER NETWORK TECH. CORP. +000089 CAYMAN SYSTEMS INC. +00008A DATAHOUSE INFORMATION SYSTEMS +00008B INFOTRON +00008C ALLOY COMPUTER PRODUCTS, INC. +00008D VERDIX CORPORATION +00008E SOLBOURNE COMPUTER, INC. +00008F RAYTHEON COMPANY +000090 MICROCOM +000091 ANRITSU CORPORATION +000092 COGENT DATA TECHNOLOGIES +000093 PROTEON INC. +000094 ASANTE TECHNOLOGIES +000095 SONY TEKTRONIX CORP. +000096 MARCONI ELECTRONICS LTD. +000097 EPOCH SYSTEMS +000098 CROSSCOMM CORPORATION +000099 MTX, INC. +00009A RC COMPUTER A/S +00009B INFORMATION INTERNATIONAL, INC +00009C ROLM MIL-SPEC COMPUTERS +00009D LOCUS COMPUTING CORPORATION +00009E MARLI S.A. +00009F AMERISTAR TECHNOLOGIES INC. +0000A0 TOKYO SANYO ELECTRIC CO. LTD. +0000A1 MARQUETTE ELECTRIC CO. +0000A2 BAY NETWORKS +0000A3 NETWORK APPLICATION TECHNOLOGY +0000A4 ACORN COMPUTERS LIMITED +0000A5 COMPATIBLE SYSTEMS CORP. +0000A6 NETWORK GENERAL CORPORATION +0000A7 NETWORK COMPUTING DEVICES INC. +0000A8 STRATUS COMPUTER INC. +0000A9 NETWORK SYSTEMS CORP. +0000AA XEROX CORPORATION +0000AB LOGIC MODELING CORPORATION +0000AC CONWARE COMPUTER CONSULTING +0000AD BRUKER INSTRUMENTS INC. +0000AE DASSAULT ELECTRONIQUE +0000AF NUCLEAR DATA INSTRUMENTATION +0000B0 RND-RAD NETWORK DEVICES +0000B1 ALPHA MICROSYSTEMS INC. +0000B2 TELEVIDEO SYSTEMS, INC. +0000B3 CIMLINC INCORPORATED +0000B4 EDIMAX COMPUTER COMPANY +0000B5 DATABILITY SOFTWARE SYS. INC. +0000B6 MICRO-MATIC RESEARCH +0000B7 DOVE COMPUTER CORPORATION +0000B8 SEIKOSHA CO., LTD. +0000B9 MCDONNELL DOUGLAS COMPUTER SYS +0000BA SIIG, INC. +0000BB TRI-DATA +0000BC ALLEN-BRADLEY CO. INC. +0000BD MITSUBISHI CABLE COMPANY +0000BE THE NTI GROUP +0000BF SYMMETRIC COMPUTER SYSTEMS +0000C0 WESTERN DIGITAL CORPORATION +0000C1 Madge Networks Ltd. +0000C2 INFORMATION PRESENTATION TECH. +0000C3 HARRIS CORP COMPUTER SYS DIV +0000C4 WATERS DIV. OF MILLIPORE +0000C5 FARALLON COMPUTING/NETOPIA +0000C6 EON SYSTEMS +0000C7 ARIX CORPORATION +0000C8 ALTOS COMPUTER SYSTEMS +0000C9 EMULEX CORPORATION +0000CA APPLITEK +0000CB COMPU-SHACK ELECTRONIC GMBH +0000CC DENSAN CO., LTD. +0000CD Centrecom Systems, Ltd. +0000CE MEGADATA CORP. +0000CF HAYES MICROCOMPUTER PRODUCTS +0000D0 DEVELCON ELECTRONICS LTD. +0000D1 ADAPTEC INCORPORATED +0000D2 SBE, INC. +0000D3 WANG LABORATORIES INC. +0000D4 PURE DATA LTD. +0000D5 MICROGNOSIS INTERNATIONAL +0000D6 PUNCH LINE HOLDING +0000D7 DARTMOUTH COLLEGE +0000D8 NOVELL, INC. +0000D9 NIPPON TELEGRAPH & TELEPHONE +0000DA ATEX +0000DB BRITISH TELECOMMUNICATIONS PLC +0000DC HAYES MICROCOMPUTER PRODUCTS +0000DD TCL INCORPORATED +0000DE CETIA +0000DF BELL & HOWELL PUB SYS DIV +0000E0 QUADRAM CORP. +0000E1 GRID SYSTEMS +0000E2 ACER TECHNOLOGIES CORP. +0000E3 INTEGRATED MICRO PRODUCTS LTD +0000E4 IN2 GROUPE INTERTECHNIQUE +0000E5 SIGMEX LTD. +0000E6 APTOR PRODUITS DE COMM INDUST +0000E7 STAR GATE TECHNOLOGIES +0000E8 ACCTON TECHNOLOGY CORP. +0000E9 ISICAD, INC. +0000EA UPNOD AB +0000EB MATSUSHITA COMM. IND. CO. LTD. +0000EC MICROPROCESS +0000ED APRIL +0000EE NETWORK DESIGNERS, LTD. +0000EF KTI +0000F0 SAMSUNG ELECTRONICS CO., LTD. +0000F1 MAGNA COMPUTER CORPORATION +0000F2 SPIDER COMMUNICATIONS +0000F3 GANDALF DATA LIMITED +0000F4 ALLIED TELESYN INTERNATIONAL +0000F5 DIAMOND SALES LIMITED +0000F6 APPLIED MICROSYSTEMS CORP. +0000F7 YOUTH KEEP ENTERPRISE CO LTD +0000F8 DIGITAL EQUIPMENT CORPORATION +0000F9 QUOTRON SYSTEMS INC. +0000FA MICROSAGE COMPUTER SYSTEMS INC +0000FB RECHNER ZUR KOMMUNIKATION +0000FC MEIKO +0000FD HIGH LEVEL HARDWARE +0000FE ANNAPOLIS MICRO SYSTEMS +0000FF CAMTEC ELECTRONICS LTD. +000100 EQUIP'TRANS +000102 3COM CORPORATION +000103 3COM CORPORATION +000104 DVICO Co., Ltd. +000105 BECKHOFF GmbH +000106 Tews Datentechnik GmbH +000107 Leiser GmbH +000108 AVLAB Technology, Inc. +000109 Nagano Japan Radio Co., Ltd. +00010A CIS TECHNOLOGY INC. +00010B Space CyberLink, Inc. +00010C System Talks Inc. +00010D CORECO, INC. +00010E Bri-Link Technologies Co., Ltd +00010F Nishan Systems, Inc. +000110 Gotham Networks +000111 iDigm Inc. +000112 Shark Multimedia Inc. +000113 OLYMPUS OPTICAL CO., LTD. +000114 KANDA TSUSHIN KOGYO CO., LTD. +000115 EXTRATECH CORPORATION +000116 Netspect Technologies, Inc. +000117 CANAL + +000118 EZ Digital Co., Ltd. +000119 Action Controls Pty. Ltd. +00011A EEH DataLink GmbH +00011B Unizone Technologies, Inc. +00011C Universal Talkware Corporation +00011D Centillium Communications +00011E Precidia Technologies, Inc. +00011F RC Networks, Inc. +000120 OSCILLOQUARTZ S.A. +000121 RapidStream Inc. +000122 Trend Communications, Ltd. +000123 DIGITAL ELECTRONICS CORP. +000124 Acer Incorporated +000125 YAESU MUSEN CO., LTD. +000126 PAC Labs +000127 The OPEN Group Limited +000128 EnjoyWeb, Inc. +000129 DFI Inc. +00012A Telematica Sistems Inteligente +00012B TELENET Co., Ltd. +00012C Aravox Technologies, Inc. +00012D Komodo Technology +00012E PC Partner Ltd. +00012F Twinhead International Corp +000130 Extreme Networks +000131 Detection Systems, Inc. +000132 Dranetz - BMI +000133 KYOWA Electronic Instruments C +000134 SIG Positec Systems AG +000135 KDC Corp. +000136 CyberTAN Technology, Inc. +000137 IT Farm Corporation +000138 XAVi Technologies Corp. +000139 Point Multimedia Systems +00013A SHELCAD COMMUNICATIONS, LTD. +00013B BNA SYSTEMS +00013C TIW SYSTEMS +00013D RiscStation Ltd. +00013E Ascom Tateco AB +00013F Neighbor World Co., Ltd. +000140 Sendtek Corporation +000141 CABLE PRINT +000142 Cisco Systems, Inc. +000143 Cisco Systems, Inc. +000144 Cereva Networks, Inc. +000145 WINSYSTEMS, INC. +000146 Tesco Controls, Inc. +000147 Zhone Technologies +000148 X-traWeb Inc. +000149 T.D.T. Transfer Data Test GmbH +00014A SONY COMPUTER SCIENCE LABS., I +00014B Ennovate Networks, Inc. +00014C Berkeley Process Control +00014D Shin Kin Enterprises Co., Ltd +00014E WIN Enterprises, Inc. +00014F LUMINOUS Networks, Inc. +000150 GILAT COMMUNICATIONS, LTD. +000151 Ensemble Communications +000152 CHROMATEK INC. +000153 ARCHTEK TELECOM CORPORATION +000154 G3M Corporation +000155 Promise Technology, Inc. +000156 FIREWIREDIRECT.COM, INC. +000157 SYSWAVE CO., LTD +000158 Electro Industries/Gauge Tech +000159 S1 Corporation +00015A Digital Video Broadcasting +00015B ITALTEL S.p.A/RF-UP-I +00015C CADANT INC. +00015D Pirus Networks +00015E BEST TECHNOLOGY CO., LTD. +00015F DIGITAL DESIGN GmbH +000160 ELMEX Co., LTD. +000161 Meta Machine Technology +000162 Cygnet Technologies, Inc. +000163 Cisco Systems, Inc. +000164 Cisco Systems, Inc. +000165 AirSwitch Corporation +000166 TC GROUP A/S +000167 HIOKI E.E. CORPORATION +000168 VITANA CORPORATION +000169 Celestix Networks Pte Ltd. +00016A ALITEC +00016B LightChip, Inc. +00016C FOXCONN +00016D Triton Network Systems +00016E Conklin Corporation +00016F HAITAI ELECTRONICS CO., LTD. +000170 ESE Embedded System Engineer'g +000171 Allied Data Technologies +000172 TechnoLand Co., LTD. +000173 JNI Corporation +000174 CyberOptics Corporation +000175 Radiant Communications Corp. +000176 Orient Silver Enterprises +000177 EDSL +000178 MARGI Systems, Inc. +000179 WIRELESS TECHNOLOGY, INC. +00017A Chengdu Maipu Electric Industrial Co., Ltd. +00017B Heidelberger Druckmaschinen AG +00017C AG-E GmbH +00017D ThermoQuest +00017E ADTEK System Science Co., Ltd. +00017F Experience Music Project +000180 AOpen, Inc. +000181 Nortel Networks +000182 DICA TECHNOLOGIES AG +000183 ANITE TELECOMS +000184 SIEB & MEYER AG +000185 Aloka Co., Ltd. +000186 DISCH GmbH +000187 i2SE GmbH +000188 LXCO Technologies ag +000189 Refraction Technology, Inc. +00018A ROI COMPUTER AG +00018B NetLinks Co., Ltd. +00018C Mega Vision +00018D AudeSi Technologies +00018E Logitec Corporation +00018F Kenetec, Inc. +000190 SMK-M +000191 SYRED Data Systems +000192 Texas Digital Systems +000193 Hanbyul Telecom Co., Ltd. +000194 Capital Equipment Corporation +000195 Sena Technologies, Inc. +000196 Cisco Systems, Inc. +000197 Cisco Systems, Inc. +000198 Darim Vision +000199 HeiSei Electronics +00019A LEUNIG GmbH +00019B Kyoto Microcomputer Co., Ltd. +00019C JDS Uniphase Inc. +00019D E-Control Systems, Inc. +00019E ESS Technology, Inc. +00019F Phonex Broadband +0001A0 Infinilink Corporation +0001A1 Mag-Tek, Inc. +0001A2 Logical Co., Ltd. +0001A3 GENESYS LOGIC, INC. +0001A4 Microlink Corporation +0001A5 Nextcomm, Inc. +0001A6 Scientific-Atlanta Arcodan A/S +0001A7 UNEX TECHNOLOGY CORPORATION +0001A8 Welltech Computer Co., Ltd. +0001A9 BMW AG +0001AA Airspan Communications, Ltd. +0001AB Main Street Networks +0001AC Sitara Networks, Inc. +0001AD Coach Master International d.b.a. CMI Worldwide, Inc. +0001AE Trex Enterprises +0001AF Motorola Computer Group +0001B0 Fulltek Technology Co., Ltd. +0001B1 General Bandwidth +0001B2 Digital Processing Systems, Inc. +0001B3 Precision Electronic Manufacturing +0001B4 Wayport, Inc. +0001B5 Turin Networks, Inc. +0001B6 SAEJIN T&M Co., Ltd. +0001B7 Centos, Inc. +0001B8 Netsensity, Inc. +0001B9 SKF Condition Monitoring +0001BA IC-Net, Inc. +0001BB Frequentis +0001BC Brains Corporation +0001BD Peterson Electro-Musical Products, Inc. +0001BE Gigalink Co., Ltd. +0001BF Teleforce Co., Ltd. +0001C0 CompuLab, Ltd. +0001C1 Exbit Technology +0001C2 ARK Research Corp. +0001C3 Acromag, Inc. +0001C4 NeoWave, Inc. +0001C5 Simpler Networks +0001C6 Quarry Technologies +0001C7 Cisco Systems, Inc. +0001C8 THOMAS CONRAD CORP. +0001C8 CONRAD CORP. +0001C9 Cisco Systems, Inc. +0001CA Geocast Network Systems, Inc. +0001CB NetGame, Ltd. +0001CC Japan Total Design Communication Co., Ltd. +0001CD ARtem +0001CE Custom Micro Products, Ltd. +0001CF Alpha Data Parallel Systems, Ltd. +0001D0 VitalPoint, Inc. +0001D1 CoNet Communications, Inc. +0001D2 MacPower Peripherals, Ltd. +0001D3 PAXCOMM, Inc. +0001D4 Leisure Time, Inc. +0001D5 HAEDONG INFO & COMM CO., LTD +0001D6 MAN Roland Druckmaschinen AG +0001D7 F5 Networks, Inc. +0001D8 Teltronics, Inc. +0001D9 Sigma, Inc. +0001DA WINCOMM Corporation +0001DB Freecom Technologies GmbH +0001DC Activetelco +0001DD Avail Networks +0001DE Trango Systems, Inc. +0001DF ISDN Communications, Ltd. +0001E0 Fast Systems, Inc. +0001E1 Kinpo Electronics, Inc. +0001E2 Ando Electric Corporation +0001E3 Siemens AG +0001E4 Sitera, Inc. +0001E5 Supernet, Inc. +0001E6 Hewlett-Packard Company +0001E7 Hewlett-Packard Company +0001E8 Force10 Networks, Inc. +0001E9 Litton Marine Systems B.V. +0001EA Cirilium Corp. +0001EB C-COM Corporation +0001EC Ericsson Group +0001ED SETA Corp. +0001EE Comtrol Europe, Ltd. +0001EF Camtel Technology Corp. +0001F0 Tridium, Inc. +0001F1 Innovative Concepts, Inc. +0001F3 QPS, Inc. +0001F4 Enterasys Networks +0001F5 ERIM S.A. +0001F6 Association of Musical Electronics Industry +0001F7 Image Display Systems, Inc. +0001F8 Adherent Systems, Ltd. +0001F9 TeraGlobal Communications Corp. +0001FA HOROSCAS +0001FB DoTop Technology, Inc. +0001FC Keyence Corporation +0001FD Digital Voice Systems, Inc. +0001FE DIGITAL EQUIPMENT CORPORATION +0001FF Data Direct Networks, Inc. +000200 Net & Sys Co., Ltd. +000201 IFM Electronic gmbh +000202 Amino Communications, Ltd. +000203 Woonsang Telecom, Inc. +000204 Bodmann Industries Elektronik GmbH +000205 Hitachi Denshi, Ltd. +000206 Telital R&D Denmark A/S +000208 Unify Networks, Inc. +000209 Shenzhen SED Information Technology Co., Ltd. +00020A Gefran Spa +00020B Native Networks, Inc. +00020C Metro-Optix +00020D Micronpc.com +00020E Laurel Networks, Inc. +00020F AATR +000210 Fenecom +000211 Nature Worldwide Technology Corp. +000212 SierraCom +000213 S.D.E.L. +000214 DTVRO +000215 Cotas Computer Technology A/B +000216 Cisco Systems, Inc. +000217 Cisco Systems, Inc. +000218 Advanced Scientific Corp +000219 Paralon Technologies +00021A Zuma Networks +00021B Kollmorgen-Servotronix +00021C Network Elements, Inc. +00021D Data General Communication Ltd. +00021E SIMTEL S.R.L. +00021F Aculab PLC +000220 Canon Aptex, Inc. +000221 DSP Application, Ltd. +000222 Chromisys, Inc. +000223 ClickTV +000224 Lantern Communications, Inc. +000225 Certus Technology, Inc. +000226 XESystems, Inc. +000227 ESD GmbH +000228 Necsom, Ltd. +000229 Adtec Corporation +00022A Asound Electronic +00022B Tamura Electric Works, Ltd. +00022C ABB Bomem, Inc. +00022D Agere Systems +00022E TEAC Corp. R& D +00022F P-Cube, Ltd. +000230 Intersoft Electronics +000231 Ingersoll-Rand +000232 Avision, Inc. +000233 Mantra Communications, Inc. +000234 Imperial Technology, Inc. +000235 Paragon Networks International +000236 INIT GmbH +000237 Cosmo Research Corp. +000238 Serome Technology, Inc. +000239 Visicom +00023A ZSK Stickmaschinen GmbH +00023B Redback Networks +00023C Creative Technology, Ltd. +00023D NuSpeed, Inc. +00023E Selta Telematica S.p.a +00023F Compal Electronics, Inc. +000240 Seedek Co., Ltd. +000241 Amer.com +000242 Videoframe Systems +000243 Raysis Co., Ltd. +000244 SURECOM Technology Co. +000245 Lampus Co, Ltd. +000246 All-Win Tech Co., Ltd. +000247 Great Dragon Information Technology (Group) Co., Ltd. +000248 Pila GmbH & Co. +000249 Aviv Infocom Co, Ltd. +00024A Cisco Systems, Inc. +00024B Cisco Systems, Inc. +00024C SiByte, Inc. +00024D Mannesman Dematic Colby Pty. Ltd. +00024E Datacard Group +00024F IPM Datacom S.R.L. +000250 Geyser Networks, Inc. +000251 Soma Networks +000252 Carrier Corporation +000253 Televideo, Inc. +000254 WorldGate +000255 IBM Corporation +000256 Alpha Processor, Inc. +000257 Microcom Corp. +000258 Flying Packets Communications +000259 Tsann Kuen China (Shanghai)Enterprise Co., Ltd. IT Group +00025A Catena Networks +00025B Cambridge Silicon Radio +00025C SCI Systems (Kunshan) Co., Ltd. +00025E High Technology Ltd +00025F Nortel Networks +000260 Accordion Networks, Inc. +000261 i3 Micro Technology AB +000262 Soyo Group Soyo Com Tech Co., Ltd +000263 UPS Manufacturing SRL +000264 AudioRamp.com +000265 Virditech Co. Ltd. +000266 Thermalogic Corporation +000267 NODE RUNNER, INC. +000268 Harris Government Communications +000269 Nadatel Co., Ltd +00026A Cocess Telecom Co., Ltd. +00026B BCM Computers Co., Ltd. +00026C Philips CFT +00026D Adept Telecom +00026E NeGeN Access, Inc. +00026F Senao International Co., Ltd. +000270 Crewave Co., Ltd. +000271 Vpacket Communications +000272 CC&C Technologies, Inc. +000273 Coriolis Networks +000274 Tommy Technologies Corp. +000275 SMART Technologies, Inc. +000276 Primax Electronics Ltd. +000277 Cash Systemes Industrie +000278 Samsung Electro-Mechanics Co., Ltd. +000279 Control Applications, Ltd. +00027A IOI Technology Corporation +00027B Amplify Net, Inc. +00027C Trilithic, Inc. +00027D Cisco Systems, Inc. +00027E Cisco Systems, Inc. +00027F ask-technologies.com +000280 Mu Net, Inc. +000281 Red-M (Communications) Ltd. +000282 ViaClix, Inc. +000283 Spectrum Controls, Inc. +000284 Alstom T&D P&C +000285 Riverstone Networks +000286 Occam Networks +000287 Adapcom +000288 GLOBAL VILLAGE COMMUNICATION +000289 DNE Technologies +00028A Ambit Microsystems Corporation +00028B VDSL Systems OY +00028C Micrel-Synergy Semiconductor +00028D Movita Technologies, Inc. +00028E Rapid 5 Networks, Inc. +00028F Globetek, Inc. +000290 Woorigisool, Inc. +000291 Open Network Co., Ltd. +000292 Logic Innovations, Inc. +000293 Solid Data Systems +000294 Tokyo Sokushin Co., Ltd. +000295 IP.Access Limited +000296 Lectron Co,. Ltd. +000297 C-COR.net +000298 Broadframe Corporation +000299 Apex, Inc. +00029A Storage Apps +00029B Kreatel Communications AB +00029D Merix Corp. +00029E Information Equipment Co., Ltd. +00029F L-3 Communication Aviation Recorders +0002A0 Flatstack Ltd. +0002A1 World Wide Packets +0002A2 Hilscher GmbH +0002A3 ABB Power Automation +0002A4 AddPac Technology Co., Ltd. +0002A5 Compaq Computer Corporation +0002A6 Effinet Systems Co., Ltd. +0002A7 Vivace Networks +0002A8 Air Link Technology +0002A9 RACOM, s.r.o. +0002AA PLcom Co., Ltd. +0002AB CTC Union Technologies Co., Ltd. +0002AC 3PAR data +0002AD Asahi Optical Co., Ltd. +0002AE Scannex Electronics Ltd. +0002AF TeleCruz Technology, Inc. +0002B0 Hokubu Communication & Industrial Co., Ltd. +0002B1 Anritsu, Ltd. +0002B2 Cablevision +0002B3 Intel Corporation +0002B4 DAPHNE +0002B5 Avnet, Inc. +0002B6 Acrosser Technology Co., Ltd. +0002B7 Watanabe Electric Industry Co., Ltd. +0002B8 WHI KONSULT AB +0002B9 Cisco Systems, Inc. +0002BA Cisco Systems, Inc. +0002BB Continuous Computing +0002BC LVL 7 Systems, Inc. +0002BD Bionet Co., Ltd. +0002BE Totsu Engineering, Inc. +0002BF dotRocket, Inc. +0002C0 Bencent Tzeng Industry Co., Ltd. +0002C1 Innovative Electronic Designs, Inc. +0002C2 Net Vision Telecom +0002C3 Arelnet Ltd. +0002C4 Vector International BUBA +0002C5 Evertz Microsystems Ltd. +0002C6 Data Track Technology PLC +0002C7 ALPS ELECTRIC Co., Ltd. +0002C8 Technocom Communications Technology (pte) Ltd +0002C9 Mellanox Technologies +0002CA EndPoints, Inc. +0002CB TriState Ltd. +0002CC M.C.C.I +0002CD TeleDream, Inc. +0002CE FoxJet, Inc. +0002CF ZyGate Communications, Inc. +0002D0 Comdial Corporation +0002D1 Vivotek, Inc. +0002D2 Workstation AG +0002D3 NetBotz, Inc. +0002D4 PDA Peripherals, Inc. +0002D5 ACR +0002D6 NICE Systems +0002D7 EMPEG Ltd +0002D8 BRECIS Communications Corporation +0002D9 Reliable Controls +0002DA ExiO Communications, Inc. +0002DB NETSEC +0002DC Fujitsu General Limited +0002DD Bromax Communications, Ltd. +0002DE Astrodesign, Inc. +0002DF Net Com Systems, Inc. +0002E0 ETAS GmbH +0002E1 Integrated Network Corporation +0002E2 NDC Infared Engineering +0002E3 LITE-ON Communications, Inc. +0002E4 JC HYUN Systems, Inc. +0002E5 Timeware Ltd. +0002E6 Gould Instrument Systems, Inc. +0002E7 CAB GmbH & Co KG +0002E8 E.D.&A. +0002E9 CS Systemes De Securite - C3S +0002EA Videonics, Inc. +0002EB Easent Communications +0002EC Maschoff Design Engineering +0002ED DXO Telecom Co., Ltd. +0002EE Nokia Danmark A/S +0002EF CCC Network Systems Group Ltd. +0002F0 AME Optimedia Technology Co., Ltd. +0002F1 Pinetron Co., Ltd. +0002F2 eDevice, Inc. +0002F3 Media Serve Co., Ltd. +0002F4 PCTEL, Inc. +0002F5 VIVE Synergies, Inc. +0002F6 Equipe Communications +0002F7 ARM +0002F8 SEAKR Engineering, Inc. +0002F9 Mimos Semiconductor SDN BHD +0002FA DX Antenna Co., Ltd. +0002FB Baumuller Aulugen-Systemtechnik GmbH +0002FC Cisco Systems, Inc. +0002FD Cisco Systems, Inc. +0002FE Viditec, Inc. +0002FF Handan Broad InfoCom +000300 NetContinuum, Inc. +000301 Avantas Networks Corporation +000302 Oasys Telecom, Inc. +000303 JAMA Electronics Co., Ltd. +000304 Pacific Broadband Communications +000305 Smart Network Devices GmbH +000306 Fusion In Tech Co., Ltd. +000307 Secure Works, Inc. +000308 AM Communications, Inc. +000309 Texcel Technology PLC +00030A Argus Technologies +00030B Hunter Technology, Inc. +00030C Telesoft Technologies Ltd. +00030D Uniwill Computer Corp. +00030E Core Communications Co., Ltd. +00030F Legend Digital China Ltd. +000310 Link Evolution Corp. +000311 Micro Technology Co., Ltd. +000312 TR-Systemtechnik GmbH +000313 Access Media SPA +000314 Teleware Network Systems +000315 Cidco Incorporated +000316 Nobell Communications, Inc. +000317 Merlin Systems, Inc. +000318 Cyras Systems, Inc. +000319 Infineon AG +00031A Beijing Broad Telecom Ltd., China +00031B Cellvision Systems, Inc. +00031C Svenska Hardvarufabriken AB +00031D Taiwan Commate Computer, Inc. +00031E Optranet, Inc. +00031F Condev Ltd. +000320 Xpeed, Inc. +000321 Reco Research Co., Ltd. +000322 IDIS Co., Ltd. +000323 Cornet Technology, Inc. +000324 Tottori SANYO Electric Co., Ltd. +000325 Arima Computer Corp. +000326 Iwasaki Information Systems Co., Ltd. +000327 ACT'L +000328 Mace Group, Inc. +000329 F3, Inc. +00032A UniData Communication Systems, Inc. +00032B GAI Datenfunksysteme GmbH +00032C ABB Industrie AG +00032D IBASE Technology, Inc. +00032E Scope Information Management, Ltd. +00032F Global Sun Technology, Inc. +000330 Imagenics, Co., Ltd. +000331 Cisco Systems, Inc. +000332 Cisco Systems, Inc. +000333 Digitel Co., Ltd. +000334 Newport Electronics +000335 Mirae Technology +000336 Zetes Technologies +000337 Vaone, Inc. +000338 Oak Technology +000339 Eurologic Systems, Ltd. +00033A Silicon Wave, Inc. +00033B TAMI Tech Co., Ltd. +00033C Daiden Co., Ltd. +00033D ILSHin Lab +00033E Tateyama System Laboratory Co., Ltd. +00033F BigBand Networks, Ltd. +000340 Floware Wireless Systems, Ltd. +000341 Axon Digital Design +000342 Nortel Networks +000343 Martin Professional A/S +000344 Tietech.Co., Ltd. +000345 Routrek Networks Corporation +000346 Hitachi Kokusai Electric, Inc. +000347 Intel Corporation +000348 Norscan Instruments, Ltd. +000349 Vidicode Datacommunicatie B.V. +00034A RIAS Corporation +00034B Nortel Networks +00034C Shanghai DigiVision Technology Co., Ltd. +00034D Chiaro Networks, Ltd. +00034E Pos Data Company, Ltd. +00034F Sur-Gard Security +000350 BTICINO SPA +000351 Diebold, Inc. +000352 Colubris Networks +000353 Mitac, Inc. +000354 Fiber Logic Communications +000355 TeraBeam Internet Systems +000356 Wincor Nixdorf GmbH & Co KG +000357 Intervoice-Brite, Inc. +000358 iCable System Co., Ltd. +000359 DigitalSis +00035A Phototron Limited +00035B BridgeWave Communications +00035C Saint Song Corp. +00035D Bosung Hi-Net Co., Ltd. +00035E Metropolitan Area Networks, Inc. +00035F Schuehle Mess - und. Kontrollsysteme +000360 PAC Interactive Technology, Inc. +000361 Widcomm, Inc. +000362 Vodtel Communications, Inc. +000363 Miraesys Co., Ltd. +000364 Scenix Semiconductor, Inc. +000365 Kira Information & Communications, Ltd. +000366 ASM Pacific Technology +000367 Jasmine Networks, Inc. +000368 Embedone Co., Ltd. +000369 Nippon Antenna Co., Ltd. +00036A Mainnet, Ltd. +00036B Cisco Systems, Inc. +00036C Cisco Systems, Inc. +00036D Runtop, Inc. +00036E Nicon Systems (Pty) Limited +00036F Telsey SPA +000370 NXTV, Inc. +000371 Acomz Networks Corp. +000372 ULAN +000373 Aselsan A.S +000374 Hunter Watertech +000375 NetMedia, Inc. +000376 Graphtec Technology, Inc. +000377 Gigabit Wireless +000378 HUMAX Co., Ltd. +000379 Proscend Communications, Inc. +00037A Taiyo Yuden Co., Ltd. +00037B IDEC IZUMI Corporation +00037C Coax Media +00037D Stellcom +00037E PORTech Communications, Inc. +00037F Atheros Communications, Inc. +000381 Ingenico International +000382 A-One Co., Ltd. +000383 Metera Networks, Inc. +000384 AETA +000385 Actelis Networks, Inc. +000386 Ho Net, Inc. +000387 Blaze Network Products +000388 Fastfame Technology Co., Ltd. +000389 Plantronics +00038A America Online, Inc. +00038B PLUS-ONE I&T, Inc. +00038C Total Impact +00038D PCS Revenue Control Systems, Inc. +00038E Atoga Systems, Inc. +00038F Weinschel Corporation +000390 Digital Video Communications, Inc. +000392 Hyundai Teletek Co., Ltd. +000393 Apple Computer, Inc. +000394 Connect One +000395 California Amplifier +000396 EZ Cast Co., Ltd. +000397 Watchfront Electronics +000398 WISI +000399 Dongju Informations & Communications Co., Ltd. +00039A nSine, Ltd. +00039B NetChip Technology, Inc. +00039C OptiMight Communications, Inc. +00039D Acer Communications & Multimedia, Inc. +00039E Tera System Co., Ltd. +00039F Cisco Systems, Inc. +0003A0 Cisco Systems, Inc. +0003A1 HIPER Information & Communication, Inc. +0003A2 Catapult Communications +0003A3 MAVIX, Ltd. +0003A4 Data Storage and Information Management +0003A5 Medea Corporation +0003A7 Unixtar Technology, Inc. +0003A8 IDOT Computers, Inc. +0003A9 AXCENT Media AG +0003AA Watlow +0003AB Bridge Information Systems +0003AC Fronius Schweissmaschinen +0003AD Emerson Energy Systems AB +0003AE Allied Advanced Manufacturing Pte, Ltd. +0003AF Paragea Communications +0003B0 Xsense Technology Corp. +0003B1 Abbott Laboratories HPD +0003B2 Radware +0003B3 IA Link Systems Co., Ltd. +0003B4 Macrotek International Corp. +0003B5 Entra Technology Co. +0003B6 QSI Corporation +0003B7 ZACCESS Systems +0003B8 NetKit Solutions, LLC +0003B9 Hualong Telecom Co., Ltd. +0003BA Sun Microsystems +0003BB Signal Communications Limited +0003BC COT GmbH +0003BD OmniCluster Technologies, Inc. +0003BE Netility +0003BF Centerpoint Broadband Technologies, Inc. +0003C0 RFTNC Co., Ltd. +0003C1 Packet Dynamics Ltd +0003C2 Solphone K.K. +0003C3 Micronik Multimedia +0003C4 Tomra Systems ASA +0003C5 Mobotix AG +0003C6 ICUE Systems, Inc. +0003C7 hopf Elektronik GmbH +0003C8 CML Emergency Services +0003C9 TECOM Co., Ltd. +0003CA MTS Systems Corp. +0003CB Nippon Systems Development Co., Ltd. +0003CC Momentum Computer, Inc. +0003CD Clovertech, Inc. +0003CE ETEN Technologies, Inc. +0003CF Muxcom, Inc. +0003D0 KOANKEISO Co., Ltd. +0003D1 Takaya Corporation +0003D2 Crossbeam Systems, Inc. +0003D3 Internet Energy Systems, Inc. +0003D4 Alloptic, Inc. +0003D5 Advanced Communications Co., Ltd. +0003D6 RADVision, Ltd. +0003D7 NextNet Wireless, Inc. +0003D8 iMPath Networks, Inc. +0003D9 Secheron SA +0003DA Takamisawa Cybernetics Co., Ltd. +0003DB Apogee Electronics Corp. +0003DC Lexar Media, Inc. +0003DD Comark Corp. +0003DE OTC Wireless +0003DF Desana Systems +0003E0 RadioFrame Networks, Inc. +0003E1 Winmate Communication, Inc. +0003E2 Comspace Corporation +0003E3 Cisco Systems, Inc. +0003E4 Cisco Systems, Inc. +0003E5 Hermstedt SG +0003E6 Entone Technologies, Inc. +0003E7 Logostek Co. Ltd. +0003E8 Wavelength Digital Limited +0003E9 Akara Canada, Inc. +0003EA Mega System Technologies, Inc. +0003EB Atrica +0003EC ICG Research, Inc. +0003ED Shinkawa Electric Co., Ltd. +0003EE MKNet Corporation +0003EF Oneline AG +0003F0 Redfern Broadband Networks +0003F1 Cicada Semiconductor, Inc. +0003F2 Seneca Networks +0003F3 Dazzle Multimedia, Inc. +0003F4 NetBurner +0003F5 Chip2Chip +0003F6 Allegro Networks, Inc. +0003F7 Plast-Control GmbH +0003F8 SanCastle Technologies, Inc. +0003F9 Pleiades Communications, Inc. +0003FA TiMetra Networks +0003FB Toko Seiki Company, Ltd. +0003FC Intertex Data AB +0003FD Cisco Systems, Inc. +0003FE Cisco Systems, Inc. +0003FF Connectix +000400 LEXMARK INTERNATIONAL, INC. +000401 Osaki Electric Co., Ltd. +000402 Nexsan Technologies, Ltd. +000403 Nexsi Corporation +000404 Makino Milling Machine Co., Ltd. +000405 ACN Technologies +000406 Fa. Metabox AG +000407 Topcon Positioning Systems, Inc. +000408 Sanko Electronics Co., Ltd. +000409 Cratos Networks +00040A Sage Systems +00040B 3com Europe Ltd. +00040C KANNO Work's Ltd. +00040D Avaya, Inc. +00040E AVM GmbH +00040F Asus Network Technologies, Inc. +000410 Spinnaker Networks, Inc. +000411 Inkra Networks, Inc. +000412 WaveSmith Networks, Inc. +000413 SNOM Technology AG +000414 Umezawa Musen Denki Co., Ltd. +000415 Rasteme Systems Co., Ltd. +000416 Parks S/A Comunicacoes Digitais +000417 ELAU AG +000418 Teltronic S.A.U. +000419 Fibercycle Networks, Inc. +00041A ines GmbH +00041B Digital Interfaces Ltd. +00041C ipDialog, Inc. +00041D Corega of America +00041E Shikoku Instrumentation Co., Ltd. +00041F Sony Computer Entertainment, Inc. +000420 Slim Devices, Inc. +000421 Ocular Networks +000422 Gordon Kapes, Inc. +000423 Intel Corporation +000424 TMC s.r.l. +000425 Atmel Corporation +000426 Autosys +000427 Cisco Systems, Inc. +000428 Cisco Systems, Inc. +000429 Pixord Corporation +00042A Wireless Networks, Inc. +00042B IT Access Co., Ltd. +00042C Minet, Inc. +00042D Sarian Systems, Ltd. +00042E Netous Technologies, Ltd. +00042F International Communications Products, Inc. +000430 Netgem +000431 Play Industries +000432 Voyetra Turtle Beach, Inc. +000433 Cyberboard A/S +000434 Accelent Systems, Inc. +000435 Comptek International, Inc. +000436 ELANsat Technologies, Inc. +000437 Powin Information Technology, Inc. +000438 Nortel Networks +000439 Rosco Entertainment Technology, Inc. +00043A Intelligent Telecommunications, Inc. +00043B Lava Computer Mfg., Inc. +00043C SONOS Co., Ltd. +00043D INDEL AG +00043E Telencomm +00043F Electronic Systems Technology, Inc. +000440 cyberPIXIE, Inc. +000441 Half Dome Systems, Inc. +000442 NACT +000443 Agilent Technologies, Inc. +000444 Wireless Home +000445 LMS Skalar Instruments GmbH +000446 CYZENTECH Co., Ltd. +000447 Acrowave Systems Co., Ltd. +000448 Polaroid Professional Imaging +000449 Mapletree Networks +00044A iPolicy Networks, Inc. +00044B NVIDIA +00044C JENOPTIK +00044D Cisco Systems, Inc. +00044E Cisco Systems, Inc. +00044F Leukhardt Systemelektronik GmbH +000450 DMD Computers SRL +000451 Medrad, Inc. +000452 RocketLogix, Inc. +000453 Yotta Yotta, Inc. +000454 Quadriga UK +000455 ANTARA.net +000456 PipingHot Networks +000457 Universal Access Technology, Inc. +000458 Fusion X Co., Ltd. +000459 Veristar Corporation +00045A The Linksys Group, Inc. +00045B Techsan Electronics Co., Ltd. +00045C Mobiwave Pte Ltd +00045D BEKA Elektronik +00045E Poly Trax Information Technology AG +00045F Evalue Technology, Inc. +000460 Knilink Technology, Inc. +000461 EPOX Computer Co., Ltd. +000462 DAKOS Data & Communication Co., Ltd. +000463 Philips Communication Security & Imaging +000464 Fantasma Networks, Inc. +000465 ist isdn support tecknik GmbH +000466 ARMITEL Co. +000467 Wuhan Research Institute +000468 Vivity, Inc. +000469 Innocom, Inc. +00046A Navini Networks +00046B Palm Wireless, Inc. +00046C Cyber Technology Co., Ltd. +00046D Cisco Systems, Inc. +00046E Cisco Systems, Inc. +00046F Digitel S/A Industria Eletronica +000470 ipUnplugged AB +000471 IPrad +000472 Telelynx, Inc. +000473 Photonex Corporation +000474 LEGRAND +000475 3 Com Corporation +000476 3 Com Corporation +000477 e-Appliance Corp. +000478 G. Star Technology Corporation +000479 Radius Co., Ltd. +00047A AXXESSIT ASA +00047B Schlumberger +00047C Skidata AG +00047D Pelco +00047E NKF Electronics +00047F Chr. Mayr GmbH & Co. KG +000480 Foundry Networks, Inc. +000481 Econolite Control Products, Inc. +000482 MediaLogic Corp. +000483 Deltron Technology, Inc. +000484 Amann GmbH +000485 PicoLight +000486 ITTC, University of Kansas +000487 Cogency Semiconductor, Inc. +000488 Eurotherm Action Incorporated. +000489 YAFO Networks, Inc. +00048A Temia Vertriebs GmbH +00048B Poscon Corporation +00048C Nayna Networks, Inc. +00048D Tone Commander Systems, Inc. +00048E Ohm Tech Labs, Inc. +00048F TD Systems Corp. +000490 Optical Access +000491 Technovision, Inc. +000492 Hive Internet, Ltd. +000493 Tsinghua Unisplendour Co., Ltd. +000494 Breezecom, Ltd. +000495 Tejas Networks +000496 Extreme Networks +000497 MacroSystem Digital Video AG +000499 Chino Corporation +00049A Cisco Systems, Inc. +00049B Cisco Systems, Inc. +00049C Surgient Networks, Inc. +00049D Ipanema Technologies +00049E Wirelink Co., Ltd. +00049F Metrowerks +0004A0 Verity Instruments, Inc. +0004A1 Pathway Connectivity +0004A2 L.S.I. Japan Co., Ltd. +0004A3 Microchip Technology, Inc. +0004A4 NetEnabled, Inc. +0004A5 Barco Projection Systems NV +0004A6 SAF Tehnika Ltd. +0004A7 FabiaTech Corporation +0004A8 Broadmax Technologies, Inc. +0004A9 SandStream Technologies, Inc. +0004AA Jetstream Communications +0004AB Comverse Network Systems, Inc. +0004AC IBM CORP. +0004AD Malibu Networks +0004AE Liquid Metronics +0004AF Digital Fountain, Inc. +0004B0 ELESIGN Co., Ltd. +0004B1 Signal Technology, Inc. +0004B2 ESSEGI SRL +0004B3 Videotek, Inc. +0004B4 CIAC +0004B5 Equitrac Corporation +0004B6 Tellumat (Pty) Ltd. +0004B7 AMB i.t. Holding +0004B8 Kumahira Co., Ltd. +0004B9 S.I. Soubou, Inc. +0004BA KDD Media Will Corporation +0004BB Bardac Corporation +0004BC Giantec, Inc. +0004BD Motorola BCS +0004BE OptXCon, Inc. +0004BF Versa Logic Corp. +0004C0 Cisco Systems, Inc. +0004C1 Cisco Systems, Inc. +0004C2 Magnipix, Inc. +0004C3 CASTOR Informatique +0004C4 Allen & Health +0004C5 ASE Technologies, USA +0004C6 Yamaha Motor Co., Ltd. +0004C7 NetMount +0004C8 LIBA Maschinefabrik GmbH +0004C9 Micro Electron Co., Ltd. +0004CA FreeMs Corp. +0004CB Tdsoft Communication, Ltd. +0004CC Peek Traffic BV. +0004CD Informedia Research Group +0004CE Patria Ailon +0004CF Seagate Technology +0004D0 Softlink s.r.o. +0004D1 Drew Technologies, Inc. +0004D2 Adcon Telemetry AG +0004D3 Toyokeiki Co., Ltd. +0004D4 Proview Electronics Co., Ltd. +0004D5 Hitachi Communication Systems, Inc. +0004D6 Takagi Industrial Co., Ltd. +0004D7 Omitec Instrumentation Ltd. +0004D8 IPWireless, Inc. +0004D9 Titan Electronics, Inc. +0004DA Relax Technology, Inc. +0004DB Tellus Group Corp. +0004DC Nortel Networks +0004DD Cisco Systems, Inc. +0004DE Cisco Systems, Inc. +0004DF Teracom Telematica Ltda. +0004E0 Procket Networks +0004E1 Infinior Microsystems +0004E2 SMC Networks, Inc. +0004E3 Accton Technology Corp. +0004E4 Daeryung Ind., Inc. +0004E5 Glonet Systems, Inc. +0004E6 Banyan Network Private Limited +0004E7 Lightpointe Communications, Inc +0004E8 IER, Inc. +0004E9 Infiniswitch Corporation +0004EA Hewlett-Packard Company +0004EB Paxonet Communications, Inc. +0004EC Memobox SA +0004ED Billion Electric Co., Ltd. +0004EE Lincoln Electric Company +0004EF Polestar Corp. +0004F0 International Computers, Ltd +0004F1 WhereNet +0004F2 Circa Communications, Ltd. +0004F3 FS FORTH-SYSTEME GmbH +0004F4 Infinite Electronics Inc. +0004F5 SnowShore Networks, Inc. +0004F6 Amphus +0004F7 Omega Band, Inc. +0004F8 QUALICABLE TV Industria E Com., Ltda +0004F9 Xtera Communications, Inc. +0004FA MIST Inc. +0004FB Commtech, Inc. +0004FC Stratus Computer (DE), Inc. +0004FD Japan Control Engineering Co., Ltd. +0004FE Pelago Networks +0004FF Acronet Co., Ltd. +000500 Cisco Systems, Inc. +000501 Cisco Systems, Inc. +000502 APPLE COMPUTER +000503 ICONAG +000504 Naray Information & Communication Enterprise +000505 Systems Integration Solutions, Inc. +000506 Reddo Networks AB +000507 Fine Appliance Corp. +000508 Inetcam, Inc. +000509 AVOC Nishimura Ltd. +00050A ICS Spa +00050B SICOM Systems, Inc. +00050C Network Photonics, Inc. +00050D Midstream Technologies, Inc. +00050E 3ware, Inc. +00050F Tanaka S/S Ltd. +000510 Infinite Shanghai Communication Terminals Ltd. +000511 Complementaty Technologies Ltd +000512 MeshNetworks, Inc. +000513 VTLinx Multimedia Systems, Inc. +000514 KDT Systems Co., Ltd. +000515 Nuark Co., Ltd. +000516 SMART Modular Technologies +000517 Shellcomm, Inc. +000518 Jupiters Technology +000519 Siemens Building Technologies AG, +00051A 3Com Europe Ltd. +00051B Magic Control Technology Corporation +00051C Xnet Technology Corp. +00051D Airocon, Inc. +00051E Rhapsody Networks +00051F Taijin Media Co., Ltd. +000520 Smartronix, Inc. +000521 Control Microsystems +000522 LEA*D Corporation, Inc. +000523 AVL List GmbH +000524 BTL System (HK) Limited +000525 Puretek Industrial Co., Ltd. +000526 IPAS GmbH +000527 SJ Tek Co. Ltd +000528 New Focus, Inc. +000529 Shanghai Broadan Communication Technology Co., Ltd +00052A Ikegami Tsushinki Co., Ltd. +00052B HORIBA, Ltd. +00052C Supreme Magic Corporation +00052D Zoltrix International Limited +00052E Cinta Networks +00052F Leviton Voice and Data +000530 Andiamo Systems, Inc. +000531 Cisco Systems, Inc. +000532 Cisco Systems, Inc. +000533 Sanera Systems, Inc. +000534 Northstar Engineering Ltd. +000535 Chip PC Ltd. +000536 Danam Communications, Inc. +000537 Nets Technology Co., Ltd. +000538 Merilus, Inc. +000539 A Brand New World in Sweden AB +00053A Willowglen Services Pte Ltd +00053B Harbour Networks Ltd., Co. Beijing +00053C Xircom +00053D Agere Systems +00053E KID Systeme GmbH +00053F VisionTek, Inc. +000540 FAST Corporation +000541 Advanced Systems Co., Ltd. +000542 Otari, Inc. +000543 IQ Wireless GmbH +000544 Valley Technologies, Inc. +000545 Internet Photonics +000546 KDD Network Systems Co., Ltd. +000547 Starent Networks +000548 Disco Corporation +000549 Salira Optical Network Systems +00054A Ario Data Networks, Inc. +00054B Micro Innovation AG +00054C RF Innovations Pty Ltd +00054D Brans Technologies, Inc. +00054E Philips Components +000550 Digi-Tech Communications Limited +000551 F & S Elektronik Systeme GmbH +000552 Xycotec Computer GmbH +000553 DVC Company, Inc. +000554 Rangestar Wireless +000555 Japan Cash Machine Co., Ltd. +000556 360 Systems +000557 Agile TV Corporation +000558 Synchronous, Inc. +000559 Intracom S.A. +00055A Power Dsine Ltd. +00055B Charles Industries, Ltd. +00055C Kowa Company, Ltd. +00055D D-Link Systems, Inc. +00055E Cisco Systems, Inc. +00055F Cisco Systems, Inc. +000560 LEADER COMM.CO., LTD +000561 nac Image Technology, Inc. +000562 Digital View Limited +000563 J-Works, Inc. +000564 Tsinghua Bitway Co., Ltd. +000565 Tailyn Communication Company Ltd. +000566 Secui.com Corporation +000567 Etymonic Design, Inc. +000568 Piltofish Networks AB +000569 VMWARE, Inc. +00056B C.P. Technology Co., Ltd. +00056C Hung Chang Co., Ltd. +00056D Pacific Corporation +00056E National Enhance Technology, Inc. +00056F Innomedia Technologies Pvt. Ltd. +000570 Baydel Ltd. +000571 Seiwa Electronics Co. +000572 Deonet Co., Ltd. +000573 Cisco Systems, Inc. +000574 Cisco Systems, Inc. +000575 CDS-Electronics BV +000576 NSM Technology Ltd. +000577 SM Information & Communication +000579 Universal Control Solution Corp. +00057A Hatteras Networks +00057B Chung Nam Electronic Co., Ltd. +00057C RCO Security AB +00057D Sun Communications, Inc. +00057E Eckelmann Steuerungstechnik GmbH +00057F Acqis Technology +000580 Fibrolan Ltd. +000581 Snell & Wilcox Ltd. +000582 ClearCube Technology +000583 ImageCom Limited +000584 AbsoluteValue Systems, Inc. +000585 Juniper Networks, Inc. +000586 Lucent Technologies +000587 Locus, Incorporated +000588 Sensoria Corp. +000589 National Datacomputer +00058A Netcom Co., Ltd. +00058B IPmental, Inc. +00058C Opentech Inc. +00058D Lynx Photonic Networks, Inc. +00058E Ahead Communications System GmbH +00058F CLCsoft co. +000590 Ascom Business Systems +000591 Active Silicon Ltd. +000592 Pultex Corp. +000593 Grammar Engine Inc. +000594 IXXAT Automation GmbH +000595 Alesis Corporation +000596 Genotech Co., Ltd. +000597 Eagle Traffic Control Systems +000598 CRONOS S.r.l. +000599 PEI Electronics, Inc. +00059A Cisco Systems, Inc. +00059B Cisco Systems, Inc. +00059C Kleinknecht GmbH, Ing. Buero +00059D Daniel Computing Systems, Inc. +00059E Zinwell Corporation +00059F Yotta Networks, Inc. +0005A0 MOBILINE Kft. +0005A1 Zenocom +0005A2 CELOX Networks +0005A3 QEI, Inc. +0005A4 Lucid Voice Ltd. +0005A5 KOTT +0005A6 Extron Electronics +0005A7 Hyperchip, Inc. +0005A8 WYLE ELECTRONICS +0005A9 Princeton Networks, Inc. +0005AA Moore Industries Int. +0005AB Cyber Fone, Inc. +0005AC Northern Digital, Inc. +0005AD Topspin Communications, Inc. +0005AE Mediaport USA +0005AF InnoScan Computing A/S +0005B0 Korea Computer Technology Co., Ltd. +0005B1 ASB Technology BV +0005B2 Medison Co., Ltd. +0005B3 Asahi-Engineering Co., Ltd. +0005B4 Aceex Corporation +0005B5 Broadcom Technologies +0005B6 INSYS Microelectronics GmbH +0005B7 Arbor Technology Corp. +0005B8 Electronic Design Associates, Inc. +0005B9 Airvana, Inc. +0005BA Area Netwoeks, Inc. +0005BC Resorsys Ltd. +0005BD ROAX BV +0005BE Kongsberg Seatex AS +0005BF JustEzy Technology, Inc. +0005C0 Digital Network Alacarte Co., Ltd. +0005C1 A-Kyung Motion, Inc. +0005C2 Digital Archway, Inc. +0005C3 Pacific Instruments, Inc. +0005C4 Telect, Inc. +0005C5 Flaga HF +0005C6 Triz Communications +0005C7 I/F-COM A/S +0005C8 VERYTECH +0005C9 LG Innotek +0005CA Hitron Technology, Inc. +0005CB ROIS Technologies, Inc. +0005CC Sumtel Communications, Inc. +0005CD Nippon Columbia +0005CE Prolink Microsystems Corporation +0005CF Thunder River Technologies, Inc. +0005D0 Solinet Systems +0005D1 Metavector Technologies +0005D2 DAP Technologies +0005D3 CAC, Inc. +0005D4 FutureSmart Networks, Inc. +0005D5 Speedcom Wireless +0005D6 Titan Wireless +0005D7 Vista Imaging, Inc. +0005D8 Arescom, Inc. +0005D9 Techno Valley, Inc. +0005DA Apex Automationstechnik +0005DB Nentec GmbH +0005DC Cisco Systems, Inc. +0005DD Cisco Systems, Inc. +0005DE Gi Fone Korea, Inc. +0005DF Electronic Innovation, Inc. +0005E0 Empirix Corp. +0005E1 Trellis Photonics, Ltd. +0005E2 Creativ Network Technologies +0005E3 LightSand Communications, Inc. +0005E4 Red Lion Controls L.P. +0005E5 Renishaw PLC +0005E6 Egenera, Inc. +0005E7 Netrake +0005E8 TurboWave, Inc. +0005E9 Unicess Networks, Inc. +0005EA Viewcast Corporation +0005EB Blue Ridge Networks, Inc. +0005EC Mosaic Systems Inc. +0005ED Technikum Joanneaum GmbH +0005EE BEWATOR Group +0005EF ADOIR Digital Technology +0005F0 SATEC +0005F1 VRcom, Inc. +0005F2 Power R, Inc. +0005F3 Weboyn +0005F4 SystemBase Co., Ltd. +0005F5 OYO Geospace Corp. +0005F6 Young Chang Co. Ltd. +0005F7 Analog Devices, Inc. +0005F8 Real Time Access, Inc. +0005F9 Diva Systems +0005FA IPOptical, Inc. +0005FB Sharegate +0005FC Schenck Pegasus Corp. +0005FD PacketLight Networks Ltd. +0005FE Traficon N.V. +0005FF SNS Solutions, Inc. +000600 Tokyo Electronic Industry Co., Ltd. +000601 Otanikeiki Co., Ltd. +000602 Cirkitech Electronics Co. +000603 Baker Hughes +000604 @Track Communications, Inc. +000605 Inncom International, Inc. +000606 RapidWan, Inc. +000607 Omni-Directional Control Technology Inc. +000608 At-Sky SAS +000609 Crossport Systems +00060A Blue2space.com +00060B Paceline Systems Corporation +00060C Melco Industries, Inc. +00060D Wave7 Optics +00060E IGSYS Systems, Inc. +00060F Narad Networks Inc +000610 Abeona Networks Inc +000611 Zeus Wireless, Inc. +000612 Accusys, Inc. +000613 Kawasaki Steel Corporation +000614 Prism Holdings +000615 Kimoto Electric Co., Ltd. +000616 Tel Net Co., Ltd. +000617 Redswitch Inc. +000618 DigiPower Manufacturing Inc. +000619 Connection Technology Systems +00061A Zetari Inc. +00061B Portable Systems, IBM Japan Co, Ltd +00061C Hoshino Metal Industries, Ltd. +00061D MIP Telecom, Inc. +00061E Maxan Systems +00061F Vision Components GmbH +000620 Serial System Ltd. +000621 Hinox, Co., Ltd. +000622 Chung Fu Chen Yeh Enterprise Corp. +000623 MGE UPS Systems France +000624 Gentner Communications +000625 The Linksys Group, Inc. +000626 MWE GmbH +000627 Uniwide Technologies, Inc. +000628 Cisco Systems, Inc. +000629 IBM CORPORATION +00062A Cisco Systems, Inc. +00062B INTRASERVER TECHNOLOGY +00062C Network Robots, Inc. +00062D TouchStar Technologies, L.L.C. +00062E Aristos Logic Corp. +00062F Pivotech Systems Inc. +000630 Adtranz Sweden +000631 Optical Solutions, Inc. +000632 Mesco Engineering GmbH +000633 Heimann Biometric Systems GmbH +000634 GTE Airfone Inc. +000635 PacketAir Networks, Inc. +000636 Jedai Broadband Networks +000637 Toptrend-Meta Information (ShenZhen) Inc. +000638 Sungjin C&C Co., Ltd. +000639 Newtec +00063A Dura Micro, Inc. +00063B Lineo Canada Corp. +00063C NMI Electronics Ltd +00063D Microwave Data Systems Inc. +00063E Opthos Inc. +00063F Everex Communications Inc. +000640 White Rock Networks +000641 ITCN +000642 Genetel Systems Inc. +000643 SONO Computer Co., Ltd. +000644 NEIX Inc. +000645 Meisei Electric Co. Ltd. +000646 ShenZhen XunBao Network Technology Co Ltd +000647 Etrali S.A. +000648 Seedsware, Inc. +000649 Quante +00064A Honeywell Co., Ltd. (KOREA) +00064B Alexon Co., Ltd. +00064C Invicta Networks, Inc. +00064D Sencore +00064E Broad Net Technology Inc. +00064F PRO-NETS Technology Corporation +000650 Tiburon Networks, Inc. +000651 Aspen Networks Inc. +000652 Cisco Systems, Inc. +000653 Cisco Systems, Inc. +000654 Maxxio Technologies +000655 Yipee, Inc. +000656 Tactel AB +000657 Market Central, Inc. +000658 Helmut Fischer GmbH & Co. KG +000659 EAL (Apeldoorn) B.V. +00065A Strix Systems +00065B Dell Computer Corp. +00065C Malachite Technologies, Inc. +00065D Heidelberg Web Systems +00065E Photuris, Inc. +00065F ECI Telecom - NGTS Ltd. +000660 NADEX Co., Ltd. +000661 NIA Home Technologies Corp. +000662 MBM Technology Ltd. +000663 Human Technology Co., Ltd. +000664 Fostex Corporation +000665 Summy Gikem, Inc. +000666 Roving Networks +000667 Tripp Lite +000668 Vicon Industries Inc. +000669 Datasound Laboratories Ltd +00066A InfiniCon Systems, Inc. +00066B Sysmex Corporation +00066C Robinson Corporation +00066D Compuprint S.P.A. +00066E Delta Electronics, Inc. +00066F Korea Data Systems +000670 Upponetti Oy +000671 Softing AG +000672 Netezza +000673 Optelecom, Inc. +000674 Spectrum Control, Inc. +000675 Banderacom, Inc. +000676 Novra Technologies, Inc. +000677 SICK AG +000678 Marantz Japan, Inc. +000679 Konami Corporation +00067A JMP Systems +00067B Toplink C&C Corporation +00067C CISCO SYSTEMS, INC. +00067D Takasago Ltd. +0006C1 CISCO SYSTEMS, INC. +000701 RACAL-DATACOM +000800 MULTITECH SYSTEMS, INC. +0008C7 COMPAQ COMPUTER CORPORATION +000A27 Apple Computer, Inc. +001000 CABLE TELEVISION +001001 MCK COMMUNICATIONS +001002 ACTIA +001003 IMATRON, INC. +001004 THE BRANTLEY COILE COMPANY,INC +001005 UEC COMMERCIAL +001006 RACAL RECORDERS LTD. +001007 CISCO SYSTEMS, INC. +001008 VIENNA SYSTEMS CORPORATION +001009 HORO QUARTZ +00100A WILLIAMS COMMUNICATIONS GROUP +00100B CISCO SYSTEMS, INC. +00100C ITO CO., LTD. +00100D CISCO SYSTEMS, INC. +00100E MICRO LINEAR COPORATION +00100F INDUSTRIAL CPU SYSTEMS +001010 INITIO CORPORATION +001011 CISCO SYSTEMS, INC. +001012 PROCESSOR SYSTEMS (I) PVT LTD +001013 INDUSTRIAL COMPUTER SOURCE +001014 CISCO SYSTEMS, INC. +001015 OOMON INC. +001016 T.SQWARE +001017 MICOS GMBH +001018 BROADCOM CORPORATION +001019 SIRONA DENTAL SYSTEMS +00101A PICTURETEL CORP. +00101B CORNET TECHNOLOGY, INC. +00101C OHM TECHNOLOGIES INTL, LLC +00101D WINBOND ELECTRONICS CORP. +00101E MATSUSHITA ELECTRONIC +00101F CISCO SYSTEMS, INC. +001020 WELCH ALLYN, DATA COLLECTION +001021 ENCANTO NETWORKS, INC. +001022 SATCOM MEDIA CORPORATION +001023 FLOWWISE NETWORKS, INC. +001024 NAGOYA ELECTRIC WORKS CO., LTD +001025 GRAYHILL INC. +001026 ACCELERATED NETWORKS, INC. +001027 L-3 COMMUNICATIONS EAST +001028 COMPUTER TECHNICA, INC. +001029 CISCO SYSTEMS, INC. +00102A ZF MICROSYSTEMS, INC. +00102B UMAX DATA SYSTEMS, INC. +00102C Lasat Networks A/S +00102D HITACHI SOFTWARE ENGINEERING +00102E NETWORK SYSTEMS & TECHNOLOGIES +00102F CISCO SYSTEMS, INC. +001030 WI-LAN, INC. +001031 OBJECTIVE COMMUNICATIONS, INC. +001032 ALTA TECHNOLOGY +001033 ACCESSLAN COMMUNICATIONS, INC. +001034 GNP COMPUTERS +001035 ELITEGROUP COMPUTER +001036 INTER-TEL INTEGRATED SYSTEMS +001037 CYQ'VE TECHNOLOGY CO., LTD. +001038 MICRO RESEARCH INSTITUTE, INC. +001039 VECTRON SYSTEMS GMBH +00103A DIAMOND NETWORK TECH +00103B HIPPI NETWORKING FORUM +00103C IC ENSEMBLE, INC. +00103D PHASECOM, LTD. +00103E NETSCHOOLS CORPORATION +00103F TOLLGRADE COMMUNICATIONS, INC. +001040 INTERMEC CORPORATION +001041 BRISTOL BABCOCK, INC. +001042 ALACRITECH +001043 A2 CORPORATION +001044 INNOLABS CORPORATION +001045 Nortel Networks +001046 ALCORN MCBRIDE INC. +001047 ECHO ELETRIC CO. LTD. +001048 HTRC AUTOMATION, INC. +001049 SHORELINE TELEWORKS, INC. +00104A THE PARVUC CORPORATION +00104B 3COM CORPORATION +00104C COMPUTER ACCESS TECHNOLOGY +00104D SURTEC INDUSTRIES, INC. +00104E CEOLOGIC +00104F STORAGE TECHNOLOGY CORPORATION +001050 RION CO., LTD. +001051 CMICRO CORPORATION +001052 METTLER-TOLEDO (ALBSTADT) GMBH +001053 COMPUTER TECHNOLOGY CORP. +001054 CISCO SYSTEMS, INC. +001055 FUJITSU MICROELECTRONICS, INC. +001056 SODICK CO., LTD. +001057 Rebel.com, Inc. +001058 ARROWPOINT COMMUNICATIONS,INC. +001059 DIABLO RESEARCH CO. LLC +00105A 3COM CORPORATION +00105B NET INSIGHT AB +00105C QUANTUM DESIGNS (H.K.) LTD. +00105D DRAGER, BUSINESS UNIT +00105E HEKIMIAN LABORATORIES, INC. +00105F IN-SNEC +001060 BILLIONTON SYSTEMS, INC. +001061 HOSTLINK CORP. +001062 NX SERVER, ILNC. +001063 STARGUIDE DIGITAL NETWORKS +001064 DIGITAL EQUIPMENT CORP. +001065 RADYNE CORPORATION +001066 ADVANCED CONTROL SYSTEMS, INC. +001067 REDBACK NETWORKS, INC. +001068 COMOS TELECOM +001069 HELIOSS COMMUNICATIONS, INC. +00106A DIGITAL MICROWAVE CORPORATION +00106B SONUS NETWORKS, INC. +00106C INFRATEC PLUS GMBH +00106D INTEGRITY COMMUNICATIONS, INC. +00106E TADIRAN COM. LTD. +00106F TRENTON TECHNOLOGY INC. +001070 CARADON TREND LTD. +001071 ADVANET INC. +001072 GVN TECHNOLOGIES, INC. +001073 TECHNOBOX, INC. +001074 ATEN INTERNATIONAL CO., LTD. +001075 Maxtor Corporation +001076 EUREM GMBH +001077 SAF DRIVE SYSTEMS, LTD. +001078 NUERA COMMUNICATIONS, INC. +001079 CISCO SYSTEMS, INC. +00107A AMBICOM, INC. +00107B CISCO SYSTEMS, INC. +00107C P-COM, INC. +00107D AURORA COMMUNICATIONS, LTD. +00107E BACHMANN ELECTRONIC GMBH +00107F CRESTRON ELECTRONICS, INC. +001080 METAWAVE COMMUNICATIONS +001081 DPS, INC. +001082 JNA TELECOMMUNICATIONS LIMITED +001083 HEWLETT-PACKARD COMPANY +001084 K-BOT COMMUNICATIONS +001085 POLARIS COMMUNICATIONS, INC. +001086 ATTO TECHNOLOGY, INC. +001087 Xstreamis PLC +001088 AMERICAN NETWORKS INC. +001089 WEBSONIC +00108A TERALOGIC, INC. +00108B LASERANIMATION SOLLINGER GMBH +00108C FUJITSU TELECOMMUNICATIONS +00108D JOHNSON CONTROLS, INC. +00108E HUGH SYMONS CONCEPT +00108F RAPTOR SYSTEMS +001090 CIMETRICS, INC. +001091 NO WIRES NEEDED BV +001092 NETCORE INC. +001093 CMS COMPUTERS, LTD. +001094 ADTECH, INC. +001095 THOMSON CONSUMER ELECTRONICS +001096 TRACEWELL SYSTEMS, INC. +001097 WINNET METROPOLITAN +001098 STARNET TECHNOLOGIES, INC. +001099 INNOMEDIA, INC. +00109A NETLINE +00109B VIXEL CORPORATION +00109C M-SYSTEM CO., LTD. +00109D CLARINET SYSTEMS, INC. +00109E AWARE, INC. +00109F PAVO, INC. +0010A0 INNOVEX TECHNOLOGIES, INC. +0010A1 KENDIN SEMICONDUCTOR, INC. +0010A2 TNS +0010A3 OMNITRONIX, INC. +0010A4 XIRCOM +0010A5 OXFORD INSTRUMENTS +0010A6 CISCO SYSTEMS, INC. +0010A7 UNEX TECHNOLOGY CORPORATION +0010A8 RELIANCE COMPUTER CORP. +0010A9 ADHOC TECHNOLOGIES +0010AA MEDIA4, INC. +0010AB KOITO INDUSTRIES, LTD. +0010AC IMCI TECHNOLOGIES +0010AD SOFTRONICS USB, INC. +0010AE SHINKO ELECTRIC INDUSTRIES CO. +0010AF TAC SYSTEMS, INC. +0010B0 MERIDIAN TECHNOLOGY CORP. +0010B1 FOR-A CO., LTD. +0010B2 COACTIVE AESTHETICS +0010B3 NOKIA MULTIMEDIA TERMINALS +0010B4 ATMOSPHERE NETWORKS +0010B5 ACCTON TECHNOLOGY CORPORATION +0010B6 ENTRATA COMMUNICATIONS CORP. +0010B7 COYOTE TECHNOLOGIES, LLC +0010B8 ISHIGAKI COMPUTER SYSTEM CO. +0010B9 MAXTOR CORP. +0010BA MARTINHO-DAVIS SYSTEMS, INC. +0010BB DATA & INFORMATION TECHNOLOGY +0010BC Nortel Networks +0010BD THE TELECOMMUNICATION +0010BE TELEXIS CORP. +0010BF INTER AIR WIRELESS +0010C0 ARMA, INC. +0010C1 OI ELECTRIC CO., LTD. +0010C2 WILLNET, INC. +0010C3 CSI-CONTROL SYSTEMS +0010C4 MEDIA LINKS CO., LTD. +0010C5 PROTOCOL TECHNOLOGIES, INC. +0010C6 USI +0010C7 DATA TRANSMISSION NETWORK +0010C8 COMMUNICATIONS ELECTRONICS +0010C9 MITSUBISHI ELECTRONICS +0010CA INTEGRAL ACCESS +0010CB FACIT K.K. +0010CC CLP COMPUTER LOGISTIK +0010CD INTERFACE CONCEPT +0010CE VOLAMP, LTD. +0010CF FIBERLANE COMMUNICATIONS +0010D0 WITCOM, LTD. +0010D1 Top Layer Networks, Inc. +0010D2 NITTO TSUSHINKI CO., LTD +0010D3 GRIPS ELECTRONIC GMBH +0010D4 STORAGE COMPUTER CORPORATION +0010D5 IMASDE CANARIAS, S.A. +0010D6 ITT A/CD +0010D7 ARGOSY RESEARCH INC. +0010D8 CALISTA +0010D9 IBM JAPAN, FUJISAWA MT+D +0010DA MOTION ENGINEERING, INC. +0010DB NETSCREEN TECHNOLOGIES, INC. +0010DC MICRO-STAR INTERNATIONAL +0010DD ENABLE SEMICONDUCTOR, INC. +0010DE INTERNATIONAL DATACASTING +0010DF RISE COMPUTER INC. +0010E0 COBALT MICROSERVER, INC. +0010E1 S.I. TECH, INC. +0010E2 ARRAYCOMM, INC. +0010E3 COMPAQ COMPUTER CORPORATION +0010E4 NSI CORPORATION +0010E5 SOLECTRON TEXAS +0010E6 APPLIED INTELLIGENT +0010E7 BREEZECOM +0010E8 TELOCITY, INCORPORATED +0010E9 RAIDTEC LTD. +0010EA ADEPT TECHNOLOGY +0010EB SELSIUS SYSTEMS, ILNC. +0010EC RPCG, LLC +0010ED SUNDANCE TECHNOLOGY, INC. +0010EE CTI PRODUCTS, INC. +0010EF DB NETWORKS, INC. +0010F0 RITTAL-WERK RUDOLF LOH +0010F1 I-O CORPORATION +0010F2 ANTEC +0010F3 NEXCOM INTERNATIONAL CO., LTD. +0010F4 VERTICAL NETWORKS, INC. +0010F5 AMHERST SYSTEMS, INC. +0010F6 CISCO SYSTEMS, INC. +0010F7 IRIICHI TECHNOLOGIES +0010F8 KENWOOD TMI CORPORATION +0010F9 UNIQUE SYSTEMS, INC. +0010FA ZAYANTE, INC. +0010FB ZIDA TECHNOLOGIES LIMITED +0010FC BROADBAND NETWORKS, INC. +0010FD COCOM A/S +0010FE DIGITAL EQUIPMENT CORPORATION +0010FF CISCO SYSTEMS, INC. +001C7C PERQ SYSTEMS CORPORATION +002000 LEXMARK INTERNATIONAL, INC. +002001 DSP SOLUTIONS, INC. +002002 SERITECH ENTERPRISE CO., LTD. +002003 PIXEL POWER LTD. +002004 YAMATAKE-HONEYWELL CO., LTD. +002005 SIMPLE TECHNOLOGY +002006 GARRETT COMMUNICATIONS, INC. +002007 SFA, INC. +002008 CABLE & COMPUTER TECHNOLOGY +002009 PACKARD BELL ELEC., INC. +00200A SOURCE-COMM CORP. +00200B OCTAGON SYSTEMS CORP. +00200C ADASTRA SYSTEMS CORP. +00200D CARL ZEISS +00200E SATELLITE TECHNOLOGY MGMT, INC +00200F TANBAC CO., LTD. +002010 JEOL SYSTEM TECHNOLOGY CO. LTD +002011 CANOPUS CO., LTD. +002012 CAMTRONICS MEDICAL SYSTEMS +002013 DIVERSIFIED TECHNOLOGY, INC. +002014 GLOBAL VIEW CO., LTD. +002015 ACTIS COMPUTER SA +002016 SHOWA ELECTRIC WIRE & CABLE CO +002017 ORBOTECH +002018 CIS TECHNOLOGY INC. +002019 OHLER GMBH +00201A N-BASE SWITCH COMMUNICATIONS +00201B NORTHERN TELECOM/NETWORK +00201C EXCEL, INC. +00201D KATANA PRODUCTS +00201E NETQUEST CORPORATION +00201F BEST POWER TECHNOLOGY, INC. +002020 MEGATRON COMPUTER INDUSTRIES +002021 ALGORITHMS SOFTWARE PVT. LTD. +002022 TEKNIQUE, INC. +002023 T.C. TECHNOLOGIES PTY. LTD +002024 PACIFIC COMMUNICATION SCIENCES +002025 CONTROL TECHNOLOGY, INC. +002026 AMKLY SYSTEMS, INC. +002027 MING FORTUNE INDUSTRY CO., LTD +002028 WEST EGG SYSTEMS, INC. +002029 TELEPROCESSING PRODUCTS, INC. +00202A N.V. DZINE +00202B ADVANCED TELECOMMUNICATIONS +00202C WELLTRONIX CO., LTD. +00202D TAIYO CORPORATION +00202E DAYSTAR DIGITAL +00202F ZETA COMMUNICATIONS, LTD. +002030 ANALOG & DIGITAL SYSTEMS +002031 ERTEC GMBH +002032 ALCATEL TAISEL +002033 SYNAPSE TECHNOLOGIES, INC. +002034 ROTEC INDUSTRIEAUTOMATION GMBH +002035 IBM CORPORATION +002036 BMC SOFTWARE +002037 SEAGATE TECHNOLOGY +002038 VME MICROSYSTEMS INTERNATIONAL +002039 SCINETS +00203A DIGITAL BI0METRICS INC. +00203B WISDM LTD. +00203C EUROTIME AB +00203D NOVAR ELECTRONICS CORPORATION +00203E LOGICAN TECHNOLOGIES, INC. +00203F JUKI CORPORATION +002040 Motorola Broadband Communications Sector +002041 DATA NET +002042 DATAMETRICS CORP. +002043 NEURON COMPANY LIMITED +002044 GENITECH PTY LTD +002045 ION Networks, Inc. +002046 CIPRICO, INC. +002047 STEINBRECHER CORP. +002048 Marconi Communications +002049 COMTRON, INC. +00204A PRONET GMBH +00204B AUTOCOMPUTER CO., LTD. +00204C MITRON COMPUTER PTE LTD. +00204D INOVIS GMBH +00204E NETWORK SECURITY SYSTEMS, INC. +00204F DEUTSCHE AEROSPACE AG +002050 KOREA COMPUTER INC. +002051 PHOENIX DATA COMMUNUNICATIONS +002052 RAGULA SYSTEMS +002053 HUNTSVILLE MICROSYSTEMS, INC. +002054 EASTERN RESEARCH, INC. +002055 ALTECH CO., LTD. +002056 NEOPRODUCTS +002057 TITZE DATENTECHNIK GMBH +002058 ALLIED SIGNAL INC. +002059 MIRO COMPUTER PRODUCTS AG +00205A COMPUTER IDENTICS +00205B SKYLINE TECHNOLOGY +00205C INTERNET SYSTEMS/ FLORIDA INC. +00205D NANOMATIC OY +00205E CASTLE ROCK, INC. +00205F GAMMADATA COMPUTER GMBH +002060 ALCATEL ITALIA S.P.A. +002061 DYNATECH COMMUNICATIONS, INC. +002062 SCORPION LOGIC, LTD. +002063 WIPRO INFOTECH LTD. +002064 PROTEC MICROSYSTEMS, INC. +002065 SUPERNET NETWORKING INC. +002066 GENERAL MAGIC, INC. +002068 ISDYNE +002069 ISDN SYSTEMS CORPORATION +00206A OSAKA COMPUTER CORP. +00206B MINOLTA CO., LTD. +00206C EVERGREEN TECHNOLOGY CORP. +00206D DATA RACE, INC. +00206E XACT, INC. +00206F FLOWPOINT CORPORATION +002070 HYNET, LTD. +002071 IBR GMBH +002072 WORKLINK INNOVATIONS +002073 FUSION SYSTEMS CORPORATION +002074 SUNGWOON SYSTEMS +002075 MOTOROLA COMMUNICATION ISRAEL +002076 REUDO CORPORATION +002077 KARDIOS SYSTEMS CORP. +002078 RUNTOP, INC. +002079 MIKRON GMBH +00207A WISE COMMUNICATIONS, INC. +00207B LEVEL ONE COMMUNICATIONS +00207C AUTEC GMBH +00207D ADVANCED COMPUTER APPLICATIONS +00207E FINECOM CO., LTD. +00207F KYOEI SANGYO CO., LTD. +002080 SYNERGY (UK) LTD. +002081 TITAN ELECTRONICS +002082 ONEAC CORPORATION +002083 PRESTICOM INCORPORATED +002084 OCE PRINTING SYSTEMS, GMBH +002085 EXIDE ELECTRONICS +002086 MICROTECH ELECTRONICS LIMITED +002087 MEMOTEC COMMUNICATIONS CORP. +002088 GLOBAL VILLAGE COMMUNICATION +002089 T3PLUS NETWORKING, INC. +00208A SONIX COMMUNICATIONS, LTD. +00208B LAPIS TECHNOLOGIES, INC. +00208C GALAXY NETWORKS, INC. +00208D CMD TECHNOLOGY +00208E CHEVIN SOFTWARE ENG. LTD. +00208F ECI TELECOM LTD. +002090 ADVANCED COMPRESSION +002091 J125, NATIONAL SECURITY AGENCY +002092 CHESS ENGINEERING B.V. +002093 LANDINGS TECHNOLOGY CORP. +002094 CUBIX CORPORATION +002095 RIVA ELECTRONICS +002096 SIEBE ENVIRONMENTAL CONTROLS +002097 APPLIED SIGNAL TECHNOLOGY +002098 HECTRONIC AB +002099 BON ELECTRIC CO., LTD. +00209A THE 3DO COMPANY +00209B ERSAT ELECTRONIC GMBH +00209C PRIMARY ACCESS CORP. +00209D LIPPERT AUTOMATIONSTECHNIK +00209E BROWN'S OPERATING SYSTEM +00209F MERCURY COMPUTER SYSTEMS, INC. +0020A0 OA LABORATORY CO., LTD. +0020A1 DOVATRON +0020A2 GALCOM NETWORKING LTD. +0020A3 DIVICOM INC. +0020A4 MULTIPOINT NETWORKS +0020A5 API ENGINEERING +0020A6 PROXIM, INC. +0020A7 PAIRGAIN TECHNOLOGIES, INC. +0020A8 SAST TECHNOLOGY CORP. +0020A9 WHITE HORSE INDUSTRIAL +0020AA DIGIMEDIA VISION LTD. +0020AB MICRO INDUSTRIES CORP. +0020AC INTERFLEX DATENSYSTEME GMBH +0020AD LINQ SYSTEMS +0020AE ORNET DATA COMMUNICATION TECH. +0020AF 3COM CORPORATION +0020B0 GATEWAY DEVICES, INC. +0020B1 COMTECH RESEARCH INC. +0020B2 GKD GESELLSCHAFT FUR +0020B3 SCLTEC COMMUNICATIONS SYSTEMS +0020B4 TERMA ELEKTRONIK AS +0020B5 YASKAWA ELECTRIC CORPORATION +0020B6 AGILE NETWORKS, INC. +0020B7 NAMAQUA COMPUTERWARE +0020B8 PRIME OPTION, INC. +0020B9 METRICOM, INC. +0020BA CENTER FOR HIGH PERFORMANCE +0020BB ZAX CORPORATION +0020BC JTEC PTY LTD. +0020BD NIOBRARA R & D CORPORATION +0020BE LAN ACCESS CORP. +0020BF AEHR TEST SYSTEMS +0020C0 PULSE ELECTRONICS, INC. +0020C1 TAIKO ELECTRIC WORKS, LTD. +0020C2 TEXAS MEMORY SYSTEMS, INC. +0020C3 COUNTER SOLUTIONS LTD. +0020C4 INET,INC. +0020C5 EAGLE TECHNOLOGY +0020C6 NECTEC +0020C7 AKAI Professional M.I. Corp. +0020C8 LARSCOM INCORPORATED +0020C9 VICTRON BV +0020CA DIGITAL OCEAN +0020CB PRETEC ELECTRONICS CORP. +0020CC DIGITAL SERVICES, LTD. +0020CD HYBRID NETWORKS, INC. +0020CE LOGICAL DESIGN GROUP, INC. +0020CF TEST & MEASUREMENT SYSTEMS INC +0020D0 VERSALYNX CORPORATION +0020D1 MICROCOMPUTER SYSTEMS (M) SDN. +0020D2 RAD DATA COMMUNICATIONS, LTD. +0020D3 OST (OUEST STANDARD TELEMATIQU +0020D4 CABLETRON - ZEITTNET INC. +0020D5 VIPA GMBH +0020D6 BREEZECOM +0020D7 JAPAN MINICOMPUTER SYSTEMS CO. +0020D8 NETWAVE TECHNOLOGIES, INC. +0020D9 PANASONIC TECHNOLOGIES, INC./ +0020DA XYLAN CORPORATION +0020DB XNET TECHNOLOGY, INC. +0020DC DENSITRON TAIWAN LTD. +0020DD AWA LTD. +0020DE JAPAN DIGITAL LABORAT'Y CO.LTD +0020DF KYOSAN ELECTRIC MFG. CO., LTD. +0020E0 PREMAX ELECTRONICS, INC. +0020E1 ALAMAR ELECTRONICS +0020E2 INFORMATION RESOURCE +0020E3 MCD KENCOM CORPORATION +0020E4 HSING TECH ENTERPRISE CO., LTD +0020E5 APEX DATA, INC. +0020E6 LIDKOPING MACHINE TOOLS AB +0020E7 B&W NUCLEAR SERVICE COMPANY +0020E8 DATATREK CORPORATION +0020E9 DANTEL +0020EA EFFICIENT NETWORKS, INC. +0020EB CINCINNATI MICROWAVE, INC. +0020EC TECHWARE SYSTEMS CORP. +0020ED GIGA-BYTE TECHNOLOGY CO., LTD. +0020EE GTECH CORPORATION +0020EF USC CORPORATION +0020F0 UNIVERSAL MICROELECTRONICS CO. +0020F1 ALTOS INDIA LIMITED +0020F2 SUN MICROSYSTEMS, INC. +0020F3 RAYNET CORPORATION +0020F4 SPECTRIX CORPORATION +0020F5 PANDATEL AG +0020F6 NET TEK AND KARLNET, INC. +0020F7 CYBERDATA +0020F8 CARRERA COMPUTERS, INC. +0020F9 PARALINK NETWORKS, INC. +0020FA GDE SYSTEMS, INC. +0020FB OCTEL COMMUNICATIONS CORP. +0020FC MATROX +0020FD ITV TECHNOLOGIES, INC. +0020FE TOPWARE INC. / GRAND COMPUTER +0020FF SYMMETRICAL TECHNOLOGIES +003000 ALLWELL TECHNOLOGY CORP. +003001 SMP +003002 Expand Networks +003003 Phasys Ltd. +003004 LEADTEK RESEARCH INC. +003005 Fujitsu Siemens Computers +003006 SUPERPOWER COMPUTER +003007 OPTI, INC. +003008 AVIO DIGITAL, INC. +003009 Tachion Networks, Inc. +00300A AZTECH SYSTEMS LTD. +00300B mPHASE Technologies, Inc. +00300C CONGRUENCY, LTD. +00300D MMC Technology, Inc. +00300E Klotz Digital AG +00300F IMT - Information Management T +003010 VISIONETICS INTERNATIONAL +003011 HMS FIELDBUS SYSTEMS AB +003012 DIGITAL ENGINEERING LTD. +003013 NEC Corporation +003014 DIVIO, INC. +003015 CP CLARE CORP. +003016 ISHIDA CO., LTD. +003017 TERASTACK LTD. +003018 Jetway Information Co., Ltd. +003019 CISCO SYSTEMS, INC. +00301A SMARTBRIDGES PTE. LTD. +00301B SHUTTLE, INC. +00301C ALTVATER AIRDATA SYSTEMS +00301D SKYSTREAM, INC. +00301E 3COM Europe Ltd. +00301F OPTICAL NETWORKS, INC. +003020 TSI, Inc.. +003021 HSING TECH. ENTERPRISE CO.,LTD +003022 Fong Kai Industrial Co., Ltd. +003023 COGENT COMPUTER SYSTEMS, INC. +003024 CISCO SYSTEMS, INC. +003025 CHECKOUT COMPUTER SYSTEMS, LTD +003026 HEITEL +003027 KERBANGO, INC. +003028 FASE Saldatura srl +003029 OPICOM +00302A SOUTHERN INFORMATION +00302B INALP NETWORKS, INC. +00302C SYLANTRO SYSTEMS CORPORATION +00302D QUANTUM BRIDGE COMMUNICATIONS +00302E Hoft & Wessel AG +00302F Smiths Industries +003030 HARMONIX CORPORATION +003031 LIGHTWAVE COMMUNICATIONS, INC. +003032 MAGICRAM, INC. +003033 ORIENT TELECOM CO., LTD. +003036 RMP ELEKTRONIKSYSTEME GMBH +003037 Packard Bell Nec Services +003038 XCP, INC. +003039 SOFTBOOK PRESS +00303A MAATEL +00303B PowerCom Technology +00303C ONNTO CORP. +00303D IVA CORPORATION +00303E Radcom Ltd. +00303F TurboComm Tech Inc. +003040 CISCO SYSTEMS, INC. +003041 SAEJIN T & M CO., LTD. +003042 DeTeWe-Deutsche Telephonwerke +003043 IDREAM TECHNOLOGIES, PTE. LTD. +003044 Portsmith LLC +003045 Village Networks, Inc. (VNI) +003046 Controlled Electronic Manageme +003047 NISSEI ELECTRIC CO., LTD. +003048 Supermicro Computer, Inc. +003049 BRYANT TECHNOLOGY, LTD. +00304A FRAUNHOFER INSTITUTE IMS +00304B ORBACOM SYSTEMS, INC. +00304C APPIAN COMMUNICATIONS, INC. +00304D ESI +00304E BUSTEC PRODUCTION LTD. +00304F PLANET Technology Corporation +003050 Versa Technology +003051 ORBIT AVIONIC & COMMUNICATION +003052 ELASTIC NETWORKS +003053 Basler AG +003054 CASTLENET TECHNOLOGY, INC. +003055 Hitachi Semiconductor America, +003056 Beck IPC GmbH +003057 E-Tel Corporation +003058 API MOTION +003059 DIGITAL-LOGIC AG +00305A TELGEN CORPORATION +00305B MODULE DEPARTMENT +00305C SMAR Laboratories Corp. +00305D DIGITRA SYSTEMS, INC. +00305E Abelko Innovation +00305F IMACON APS +003060 STARMATIX, INC. +003061 MobyTEL +003062 PATH 1 NETWORK TECHNOL'S INC. +003063 SANTERA SYSTEMS, INC. +003064 ADLINK TECHNOLOGY, INC. +003065 APPLE COMPUTER, INC. +003066 DIGITAL WIRELESS CORPORATION +003067 BIOSTAR MICROTECH INT'L CORP. +003068 CYBERNETICS TECH. CO., LTD. +003069 IMPACCT TECHNOLOGY CORP. +00306A PENTA MEDIA CO., LTD. +00306B CMOS SYSTEMS, INC. +00306C Hitex Holding GmbH +00306D LUCENT TECHNOLOGIES +00306E HEWLETT PACKARD +00306F SEYEON TECH. CO., LTD. +003070 1Net Corporation +003071 Cisco Systems, Inc. +003072 INTELLIBYTE INC. +003073 International Microsystems, In +003074 EQUIINET LTD. +003075 ADTECH +003076 Akamba Corporation +003077 ONPREM NETWORKS +003078 Cisco Systems, Inc. +003079 CQOS, INC. +00307A Advanced Technology & Systems +00307B Cisco Systems, Inc. +00307C ADID SA +00307D GRE AMERICA, INC. +00307E Redflex Communication Systems +00307F IRLAN LTD. +003080 CISCO SYSTEMS, INC. +003081 ALTOS C&C +003082 TAIHAN ELECTRIC WIRE CO., LTD. +003083 Ivron Systems +003084 ALLIED TELESYN INTERNAIONAL +003085 CISCO SYSTEMS, INC. +003086 Transistor Devices, Inc. +003087 VEGA GRIESHABER KG +003088 Siara Systems, Inc. +003089 Spectrapoint Wireless, LLC +00308A NICOTRA SISTEMI S.P.A +00308B Brix Networks +00308C ADVANCED DIGITAL INFORMATION +00308D PINNACLE SYSTEMS, INC. +00308E CROSS MATCH TECHNOLOGIES, INC. +00308F MICRILOR, Inc. +003090 CYRA TECHNOLOGIES, INC. +003091 TAIWAN FIRST LINE ELEC. CORP. +003092 ModuNORM GmbH +003093 SONNET TECHNOLOGIES, INC. +003094 Cisco Systems, Inc. +003095 Procomp Informatics, Ltd. +003096 CISCO SYSTEMS, INC. +003097 EXOMATIC AB +003098 Global Converging Technologies +003099 BOENIG UND KALLENBACH OHG +00309A ASTRO TERRA CORP. +00309B Smartware +00309C Timing Applications, Inc. +00309D Nimble Microsystems, Inc. +00309E WORKBIT CORPORATION. +00309F AMBER NETWORKS +0030A0 TYCO SUBMARINE SYSTEMS, LTD. +0030A1 OPTI TECH CO., LTD. +0030A2 Lightner Engineering +0030A3 CISCO SYSTEMS, INC. +0030A4 Woodwind Communications System +0030A5 ACTIVE POWER +0030A6 VIANET TECHNOLOGIES, LTD. +0030A7 SCHWEITZER ENGINEERING +0030A8 OL'E COMMUNICATIONS, INC. +0030A9 Netiverse, Inc. +0030AA AXUS MICROSYSTEMS, INC. +0030AB DELTA NETWORKS, INC. +0030AC Systeme Lauer GmbH & Co., Ltd. +0030AD SHANGHAI COMMUNICATION +0030AE Times N System, Inc. +0030AF Honeywell Reqelsysteme GmbH +0030B0 Convergenet Technologies +0030B1 GOC GESELLSCHAFT FUR OPTISCHE +0030B2 WESCAM - HEALDSBURG +0030B3 San Valley Systems, Inc. +0030B4 INTERSIL CORP. +0030B5 Tadiran Microwave Networks +0030B6 CISCO SYSTEMS, INC. +0030B7 Teletrol Systems, Inc. +0030B8 RiverDelta Networks +0030B9 ECTEL +0030BA AC&T SYSTEM CO., LTD. +0030BB CacheFlow, Inc. +0030BC Optronic AG +0030BD BELKIN COMPONENTS +0030BE City-Net Technology, Inc. +0030BF MULTIDATA GMBH +0030C0 Lara Technology, Inc. +0030C1 HEWLETT-PACKARD +0030C2 COMONE +0030C3 FLUECKIGER ELEKTRONIK AG +0030C4 Niigata Canotec Co., Inc. +0030C5 CADENCE DESIGN SYSTEMS +0030C6 CONTROL SOLUTIONS, INC. +0030C7 MACROMATE CORP. +0030C8 GAD LINE, LTD. +0030C9 LuxN, N +0030CA Discovery Com +0030CB OMNI FLOW COMPUTERS, INC. +0030CC Tenor Networks, Inc. +0030CD CONEXANT SYSTEMS, INC. +0030CE Zaffire +0030CF TWO TECHNOLOGIES, INC. +0030D1 INOVA CORPORATION +0030D2 WIN TECHNOLOGIES, CO., LTD. +0030D3 Agilent Technologies +0030D4 COMTIER +0030D5 DResearch GmbH +0030D6 MSC VERTRIEBS GMBH +0030D7 Innovative Systems, L.L.C. +0030D8 SITEK +0030D9 DATACORE SOFTWARE CORP. +0030DA COMTREND CO. +0030DB Mindready Solutions, Inc. +0030DC RIGHTECH CORPORATION +0030DD INDIGITA CORPORATION +0030DE WAGO Kontakttechnik GmbH +0030DF KB/TEL TELECOMUNICACIONES +0030E0 OXFORD SEMICONDUCTOR LTD. +0030E1 ACROTRON SYSTEMS, INC. +0030E2 GARNET SYSTEMS CO., LTD. +0030E3 SEDONA NETWORKS CORP. +0030E4 CHIYODA SYSTEM RIKEN +0030E5 Amper Datos S.A. +0030E6 SIEMENS MEDICAL SYSTEMS +0030E7 CNF MOBILE SOLUTIONS, INC. +0030E8 ENSIM CORP. +0030E9 GMA COMMUNICATION MANUFACT'G +0030EA TeraForce Technology Corporation +0030EB TURBONET COMMUNICATIONS, INC. +0030EC BORGARDT +0030ED Expert Magnetics Corp. +0030EE DSG Technology, Inc. +0030EF NEON TECHNOLOGY, INC. +0030F0 Uniform Industrial Corp. +0030F1 Accton Technology Corp. +0030F2 CISCO SYSTEMS, INC. +0030F3 At Work Computers +0030F4 STARDOT TECHNOLOGIES +0030F5 Wild Lab. Ltd. +0030F6 SECURELOGIX CORPORATION +0030F7 RAMIX INC. +0030F8 Dynapro Systems, Inc. +0030F9 Sollae Systems Co., Ltd. +0030FA TELICA, INC. +0030FB AZS Technology AG +0030FC Terawave Communications, Inc. +0030FD INTEGRATED SYSTEMS DESIGN +0030FE DSA GmbH +0030FF DATAFAB SYSTEMS, INC. +004000 PCI COMPONENTES DA AMZONIA LTD +004001 ZYXEL COMMUNICATIONS, INC. +004002 PERLE SYSTEMS LIMITED +004003 WESTINGHOUSE PROCESS CONTROL +004004 ICM CO. LTD. +004005 ANI COMMUNICATIONS INC. +004006 SAMPO TECHNOLOGY CORPORATION +004007 TELMAT INFORMATIQUE +004008 A PLUS INFO CORPORATION +004009 TACHIBANA TECTRON CO., LTD. +00400A PIVOTAL TECHNOLOGIES, INC. +00400B CISCO SYSTEMS, INC. +00400C GENERAL MICRO SYSTEMS, INC. +00400D LANNET DATA COMMUNICATIONS,LTD +00400E MEMOTEC COMMUNICATIONS, INC. +00400F DATACOM TECHNOLOGIES +004010 SONIC SYSTEMS, INC. +004011 ANDOVER CONTROLS CORPORATION +004012 WINDATA, INC. +004013 NTT DATA COMM. SYSTEMS CORP. +004014 COMSOFT GMBH +004015 ASCOM INFRASYS AG +004016 HADAX ELECTRONICS, INC. +004017 XCD INC. +004018 ADOBE SYSTEMS, INC. +004019 AEON SYSTEMS, INC. +00401A FUJI ELECTRIC CO., LTD. +00401B PRINTER SYSTEMS CORP. +00401C AST RESEARCH, INC. +00401D INVISIBLE SOFTWARE, INC. +00401E ICC +00401F COLORGRAPH LTD +004020 PINACL COMMUNICATION +004021 RASTER GRAPHICS +004022 KLEVER COMPUTERS, INC. +004023 LOGIC CORPORATION +004024 COMPAC INC. +004025 MOLECULAR DYNAMICS +004026 MELCO, INC. +004027 SMC MASSACHUSETTS, INC. +004028 NETCOMM LIMITED +004029 COMPEX +00402A CANOGA-PERKINS +00402B TRIGEM COMPUTER, INC. +00402C ISIS DISTRIBUTED SYSTEMS, INC. +00402D HARRIS ADACOM CORPORATION +00402E PRECISION SOFTWARE, INC. +00402F XLNT DESIGNS INC. +004030 GK COMPUTER +004031 KOKUSAI ELECTRIC CO., LTD +004032 DIGITAL COMMUNICATIONS +004033 ADDTRON TECHNOLOGY CO., LTD. +004034 BUSTEK CORPORATION +004035 OPCOM +004036 TRIBE COMPUTER WORKS, INC. +004037 SEA-ILAN, INC. +004038 TALENT ELECTRIC INCORPORATED +004039 OPTEC DAIICHI DENKO CO., LTD. +00403A IMPACT TECHNOLOGIES +00403B SYNERJET INTERNATIONAL CORP. +00403C FORKS, INC. +00403D TERADATA +00403E RASTER OPS CORPORATION +00403F SSANGYONG COMPUTER SYSTEMS +004040 RING ACCESS, INC. +004041 FUJIKURA LTD. +004042 N.A.T. GMBH +004043 NOKIA TELECOMMUNICATIONS +004044 QNIX COMPUTER CO., LTD. +004045 TWINHEAD CORPORATION +004046 UDC RESEARCH LIMITED +004047 WIND RIVER SYSTEMS +004048 SMD INFORMATICA S.A. +004049 TEGIMENTA AG +00404A WEST AUSTRALIAN DEPARTMENT +00404B MAPLE COMPUTER SYSTEMS +00404C HYPERTEC PTY LTD. +00404D TELECOMMUNICATIONS TECHNIQUES +00404E FLUENT, INC. +00404F SPACE & NAVAL WARFARE SYSTEMS +004050 IRONICS, INCORPORATED +004051 GRACILIS, INC. +004052 STAR TECHNOLOGIES, INC. +004053 AMPRO COMPUTERS +004054 CONNECTION MACHINES SERVICES +004055 METRONIX GMBH +004056 MCM JAPAN LTD. +004057 LOCKHEED - SANDERS +004058 KRONOS, INC. +004059 YOSHIDA KOGYO K. K. +00405A GOLDSTAR INFORMATION & COMM. +00405B FUNASSET LIMITED +00405C FUTURE SYSTEMS, INC. +00405D STAR-TEK, INC. +00405E NORTH HILLS ISRAEL +00405F AFE COMPUTERS LTD. +004060 COMENDEC LTD +004061 DATATECH ENTERPRISES CO., LTD. +004062 E-SYSTEMS, INC./GARLAND DIV. +004063 VIA TECHNOLOGIES, INC. +004064 KLA INSTRUMENTS CORPORATION +004065 GTE SPACENET +004066 HITACHI CABLE, LTD. +004067 OMNIBYTE CORPORATION +004068 EXTENDED SYSTEMS +004069 LEMCOM SYSTEMS, INC. +00406A KENTEK INFORMATION SYSTEMS,INC +00406B SYSGEN +00406C COPERNIQUE +00406D LANCO, INC. +00406E COROLLARY, INC. +00406F SYNC RESEARCH INC. +004070 INTERWARE CO., LTD. +004071 ATM COMPUTER GMBH +004072 APPLIED INNOVATION, INC. +004073 BASS ASSOCIATES +004074 CABLE AND WIRELESS +004075 M-TRADE (UK) LTD +004076 Sun Conversion Technologies +004077 MAXTON TECHNOLOGY CORPORATION +004078 WEARNES AUTOMATION PTE LTD +004079 JUKO MANUFACTURE COMPANY, LTD. +00407A SOCIETE D'EXPLOITATION DU CNIT +00407B SCIENTIFIC ATLANTA +00407C QUME CORPORATION +00407D EXTENSION TECHNOLOGY CORP. +00407E EVERGREEN SYSTEMS, INC. +00407F AGEMA INFRARED SYSTEMS AB +004080 ATHENIX CORPORATION +004081 MANNESMANN SCANGRAPHIC GMBH +004082 LABORATORY EQUIPMENT CORP. +004083 TDA INDUSTRIA DE PRODUTOS +004084 HONEYWELL INC. +004085 SAAB INSTRUMENTS AB +004086 MICHELS & KLEBERHOFF COMPUTER +004087 UBITREX CORPORATION +004088 MOBIUS TECHNOLOGIES, INC. +004089 MEIDENSHA CORPORATION +00408A TPS TELEPROCESSING SYS. GMBH +00408B RAYLAN CORPORATION +00408C AXIS COMMUNICATIONS AB +00408D THE GOODYEAR TIRE & RUBBER CO. +00408E DIGILOG, INC. +00408F WM-DATA MINFO AB +004090 ANSEL COMMUNICATIONS +004091 PROCOMP INDUSTRIA ELETRONICA +004092 ASP COMPUTER PRODUCTS, INC. +004093 PAXDATA NETWORKS LTD. +004094 SHOGRAPHICS, INC. +004095 R.P.T. INTERGROUPS INT'L LTD. +004096 Aironet Wireless Communication +004097 DATEX DIVISION OF +004098 DRESSLER GMBH & CO. +004099 NEWGEN SYSTEMS CORP. +00409A NETWORK EXPRESS, INC. +00409B HAL COMPUTER SYSTEMS INC. +00409C TRANSWARE +00409D DIGIBOARD, INC. +00409E CONCURRENT TECHNOLOGIES LTD. +00409F LANCAST/CASAT TECHNOLOGY, INC. +0040A0 GOLDSTAR CO., LTD. +0040A1 ERGO COMPUTING +0040A2 KINGSTAR TECHNOLOGY INC. +0040A3 MICROUNITY SYSTEMS ENGINEERING +0040A4 ROSE ELECTRONICS +0040A5 CLINICOMP INTL. +0040A6 Cray, Inc. +0040A7 ITAUTEC PHILCO S.A. +0040A8 IMF INTERNATIONAL LTD. +0040A9 DATACOM INC. +0040AA VALMET AUTOMATION INC. +0040AB ROLAND DG CORPORATION +0040AC SUPER WORKSTATION, INC. +0040AD SMA REGELSYSTEME GMBH +0040AE DELTA CONTROLS, INC. +0040AF DIGITAL PRODUCTS, INC. +0040B0 BYTEX CORPORATION, ENGINEERING +0040B1 CODONICS INC. +0040B2 SYSTEMFORSCHUNG +0040B3 PAR MICROSYSTEMS CORPORATION +0040B4 NEXTCOM K.K. +0040B5 VIDEO TECHNOLOGY COMPUTERS LTD +0040B6 COMPUTERM CORPORATION +0040B7 STEALTH COMPUTER SYSTEMS +0040B8 IDEA ASSOCIATES +0040B9 MACQ ELECTRONIQUE SA +0040BA ALLIANT COMPUTER SYSTEMS CORP. +0040BB GOLDSTAR CABLE CO., LTD. +0040BC ALGORITHMICS LTD. +0040BD STARLIGHT NETWORKS, INC. +0040BE BOEING DEFENSE & SPACE +0040BF CHANNEL SYSTEMS INTERN'L INC. +0040C0 VISTA CONTROLS CORPORATION +0040C1 BIZERBA-WERKE WILHEIM KRAUT +0040C2 APPLIED COMPUTING DEVICES +0040C3 FISCHER AND PORTER CO. +0040C4 KINKEI SYSTEM CORPORATION +0040C5 MICOM COMMUNICATIONS INC. +0040C6 FIBERNET RESEARCH, INC. +0040C7 RUBY TECH CORPORATION +0040C8 MILAN TECHNOLOGY CORPORATION +0040C9 NCUBE +0040CA FIRST INTERNAT'L COMPUTER, INC +0040CB LANWAN TECHNOLOGIES +0040CC SILCOM MANUF'G TECHNOLOGY INC. +0040CD TERA MICROSYSTEMS, INC. +0040CE NET-SOURCE, INC. +0040CF STRAWBERRY TREE, INC. +0040D0 MITAC INTERNATIONAL CORP. +0040D1 FUKUDA DENSHI CO., LTD. +0040D2 PAGINE CORPORATION +0040D3 KIMPSION INTERNATIONAL CORP. +0040D4 GAGE TALKER CORP. +0040D5 SARTORIUS AG +0040D6 LOCAMATION B.V. +0040D7 STUDIO GEN INC. +0040D8 OCEAN OFFICE AUTOMATION LTD. +0040D9 AMERICAN MEGATRENDS INC. +0040DA TELSPEC LTD +0040DB ADVANCED TECHNICAL SOLUTIONS +0040DC TRITEC ELECTRONIC GMBH +0040DD HONG TECHNOLOGIES +0040DE ELETTRONICA SAN GIORGIO +0040DF DIGALOG SYSTEMS, INC. +0040E0 ATOMWIDE LTD. +0040E1 MARNER INTERNATIONAL, INC. +0040E2 MESA RIDGE TECHNOLOGIES, INC. +0040E3 QUIN SYSTEMS LTD +0040E4 E-M TECHNOLOGY, INC. +0040E5 SYBUS CORPORATION +0040E6 C.A.E.N. +0040E7 ARNOS INSTRUMENTS & COMPUTER +0040E8 CHARLES RIVER DATA SYSTEMS,INC +0040E9 ACCORD SYSTEMS, INC. +0040EA PLAIN TREE SYSTEMS INC +0040EB MARTIN MARIETTA CORPORATION +0040EC MIKASA SYSTEM ENGINEERING +0040ED NETWORK CONTROLS INT'NATL INC. +0040EE OPTIMEM +0040EF HYPERCOM, INC. +0040F0 MICRO SYSTEMS, INC. +0040F1 CHUO ELECTRONICS CO., LTD. +0040F2 JANICH & KLASS COMPUTERTECHNIK +0040F3 NETCOR +0040F4 CAMEO COMMUNICATIONS, INC. +0040F5 OEM ENGINES +0040F6 KATRON COMPUTERS INC. +0040F7 POLAROID MEDICAL IMAGING SYS. +0040F8 SYSTEMHAUS DISCOM +0040F9 COMBINET +0040FA MICROBOARDS, INC. +0040FB CASCADE COMMUNICATIONS CORP. +0040FC IBR COMPUTER TECHNIK GMBH +0040FD LXE +0040FE SYMPLEX COMMUNICATIONS +0040FF TELEBIT CORPORATION +005000 NEXO COMMUNICATIONS, INC. +005001 YAMASHITA SYSTEMS CORP. +005002 OMNISEC AG +005003 GRETAG MACBETH AG +005004 3COM CORPORATION +005006 TAC AB +005007 SIEMENS TELECOMMUNICATION +005008 TIVA MICROCOMPUTER CORP. (TMC) +005009 PHILIPS BROADBAND NETWORKS +00500A IRIS TECHNOLOGIES, INC. +00500B CISCO SYSTEMS, INC. +00500C ETEK LABS, INC. +00500D SATORI ELECTORIC CO., LTD. +00500E CHROMATIS NETWORKS,INC. +00500F CISCO SYSTEMS, INC. +005010 NOVANET LEARNING, INC. +005012 CBL - GMBH +005013 Chaparral Technologies, Inc. +005014 CISCO SYSTEMS, INC. +005015 BRIGHT STAR ENGINEERING +005016 SST/WOODHEAD INDUSTRIES +005017 RSR S.R.L. +005018 ADVANCED MULTIMEDIA INTERNET +005019 SPRING TIDE NETWORKS, INC. +00501A UISIQN +00501B ABL CANADA, INC. +00501C JATOM SYSTEMS, INC. +00501E MIRANDA TECHNOLOGIES, INC. +00501F MRG SYSTEMS, LTD. +005020 MEDIASTAR CO., LTD. +005021 EIS INTERNATIONAL, INC. +005022 ZONET TECHNOLOGY, INC. +005023 PG DESIGN ELECTRONICS, INC. +005024 NAVIC SYSTEMS, INC. +005026 COSYSTEMS, INC. +005027 GENICOM CORPORATION +005028 AVAL COMMUNICATIONS +005029 1394 PRINTER WORKING GROUP +00502A CISCO SYSTEMS, INC. +00502B GENRAD LTD. +00502C SOYO COMPUTER, INC. +00502D ACCEL, INC. +00502E CAMBEX CORPORATION +00502F TOLLBRIDGE TECHNOLOGIES, INC. +005030 FUTURE PLUS SYSTEMS +005031 AEROFLEX LABORATORIES, INC. +005032 PICAZO COMMUNICATIONS, INC. +005033 MAYAN NETWORKS +005036 NETCAM, LTD. +005037 KOGA ELECTRONICS CO. +005038 DAIN TELECOM CO., LTD. +005039 MARINER NETWORKS +00503A DATONG ELECTRONICS LTD. +00503B MEDIAFIRE CORPORATION +00503C TSINGHUA NOVEL ELECTRONICS +00503E CISCO SYSTEMS, INC. +00503F ANCHOR GAMES +005040 EMWARE, INC. +005041 CTX OPTO ELECTRONIC CORP. +005042 SCI MANUFACTURING +005043 MARVELL SEMICONDUCTOR, INC. +005044 ASACA CORPORATION +005045 RIOWORKS SOLUTIONS, INC. +005046 MENICX INTERNATIONAL CO., LTD. +005048 INFOLIBRIA +005049 ELLACOYA NETWORKS, INC. +00504A ELTECO A.S. +00504B BARCONET N.V. +00504C GALIL MOTION CONTROL, INC. +00504D TOKYO ELECTRON DEVICE LTD. +00504E SIERRA MONITOR CORP. +00504F OLENCOM ELECTRONICS +005050 CISCO SYSTEMS, INC. +005051 IWATSU ELECTRIC CO., LTD. +005052 TIARA NETWORKS, INC. +005053 CISCO SYSTEMS, INC. +005054 CISCO SYSTEMS, INC. +005055 DOMS A/S +005056 VMWARE, INC. +005057 BROADBAND ACCESS SYSTEMS +005058 VEGASTREAM LIMITED +005059 SUITE TECHNOLOGY SYSTEMS +00505A NETWORK ALCHEMY, INC. +00505B KAWASAKI LSI U.S.A., INC. +00505C TUNDO CORPORATION +00505E DIGITEK MICROLOGIC S.A. +00505F BRAND INNOVATORS +005060 TANDBERG TELECOM AS +005062 KOUWELL ELECTRONICS CORP. ** +005063 OY COMSEL SYSTEM AB +005064 CAE ELECTRONICS +005065 DENSEI-LAMBAD Co., Ltd. +005066 ATECOM GMBH ADVANCED +005067 AEROCOMM, INC. +005068 ELECTRONIC INDUSTRIES +005069 PIXSTREAM INCORPORATED +00506A EDEVA, INC. +00506B SPX-ATEG +00506C G & L BEIJER ELECTRONICS AB +00506D VIDEOJET SYSTEMS +00506E CORDER ENGINEERING CORPORATION +00506F G-CONNECT +005070 CHAINTECH COMPUTER CO., LTD. +005071 AIWA CO., LTD. +005072 CORVIS CORPORATION +005073 CISCO SYSTEMS, INC. +005074 ADVANCED HI-TECH CORP. +005075 KESTREL SOLUTIONS +005076 IBM +005077 PROLIFIC TECHNOLOGY, INC. +005078 MEGATON HOUSE, LTD. +00507A XPEED, INC. +00507B MERLOT COMMUNICATIONS +00507C VIDEOCON AG +00507D IFP +00507E NEWER TECHNOLOGY +00507F DRAYTEK CORP. +005080 CISCO SYSTEMS, INC. +005081 MURATA MACHINERY, LTD. +005082 FORESSON CORPORATION +005083 GILBARCO, INC. +005084 ATL PRODUCTS +005086 TELKOM SA, LTD. +005087 TERASAKI ELECTRIC CO., LTD. +005088 AMANO CORPORATION +005089 SAFETY MANAGEMENT SYSTEMS +00508B COMPAQ COMPUTER CORPORATION +00508C RSI SYSTEMS +00508D ABIT COMPUTER CORPORATION +00508E OPTIMATION, INC. +00508F ASITA TECHNOLOGIES INT'L LTD. +005090 DCTRI +005091 NETACCESS, INC. +005092 RIGAKU INDUSTRIAL CORPORATION +005093 BOEING +005094 PACE MICRO TECHNOLOGY PLC +005095 PERACOM NETWORKS +005096 SALIX TECHNOLOGIES, INC. +005097 MMC-EMBEDDED +005098 GLOBALOOP, LTD. +005099 3COM EUROPE, LTD. +00509A TAG ELECTRONIC SYSTEMS +00509B SWITCHCORE AB +00509C BETA RESEARCH +00509D THE INDUSTREE B.V. +00509E LES TECHNOLOGIES +00509F HORIZON COMPUTER +0050A0 DELTA COMPUTER SYSTEMS, INC. +0050A1 CARLO GAVAZZI, INC. +0050A2 CISCO SYSTEMS, INC. +0050A3 TRANSMEDIA COMMUNICATIONS, INC +0050A4 IO TECH, INC. +0050A5 CAPITOL BUSINESS SYSTEMS, LTD. +0050A6 OPTRONICS +0050A7 CISCO SYSTEMS, INC. +0050A8 OPENCON SYSTEMS, INC. +0050A9 MOLDAT WIRELESS TECHNOLGIES +0050AA KONICA CORPORATION +0050AB NALTEC, INC. +0050AC MAPLE COMPUTER CORPORATION +0050AD COMMUNIQUE WIRELESS CORP. +0050AE IWAKI ELECTRONICS CO., LTD. +0050AF INTERGON, INC. +0050B0 TECHNOLOGY ATLANTA CORPORATION +0050B1 GIDDINGS & LEWIS +0050B2 BRODEL AUTOMATION +0050B3 VOICEBOARD CORPORATION +0050B4 SATCHWELL CONTROL SYSTEMS, LTD +0050B5 FICHET-BAUCHE +0050B6 GOOD WAY IND. CO., LTD. +0050B7 BOSER TECHNOLOGY CO., LTD. +0050B8 INOVA COMPUTERS GMBH & CO. KG +0050B9 XITRON TECHNOLOGIES, INC. +0050BA D-LINK +0050BB CMS TECHNOLOGIES +0050BC HAMMER STORAGE SOLUTIONS +0050BD CISCO SYSTEMS, INC. +0050BE FAST MULTIMEDIA AG +0050BF MOTOTECH INC. +0050C0 GATAN, INC. +0050C1 GEMFLEX NETWORKS, LTD. +0050C2 IEEE REGISTRATION AUTHORITY +0050C4 IMD +0050C5 ADS TECHNOLOGIES, INC. +0050C6 LOOP TELECOMMUNICATION +0050C8 ADDONICS COMMUNICATIONS, INC. +0050C9 MASPRO DENKOH CORP. +0050CA NET TO NET TECHNOLOGIES +0050CB JETTER +0050CC XYRATEX +0050CD DIGIANSWER A/S +0050CE LG INTERNATIONAL CORP. +0050CF VANLINK COMMUNICATION +0050D0 MINERVA SYSTEMS +0050D1 CISCO SYSTEMS, INC. +0050D2 BAE Systems Canada, Inc. +0050D3 DIGITAL AUDIO +0050D4 JOOHONG INFORMATION & +0050D5 AD SYSTEMS CORP. +0050D6 ATLAS COPCO TOOLS AB +0050D7 TELSTRAT +0050D8 UNICORN COMPUTER CORP. +0050D9 ENGETRON-ENGENHARIA ELETRONICA +0050DA 3COM CORPORATION +0050DB CONTEMPORARY CONTROL +0050DC TAS TELEFONBAU A. SCHWABE +0050DD SERRA SOLDADURA, S.A. +0050DE SIGNUM SYSTEMS CORP. +0050DF AIRFIBER, INC. +0050E1 NS TECH ELECTRONICS SDN BHD +0050E2 CISCO SYSTEMS, INC. +0050E3 TELEGATE +0050E4 APPLE COMPUTER, INC. +0050E6 HAKUSAN CORPORATION +0050E7 PARADISE INNOVATIONS (ASIA) +0050E8 NOMADIX INC. +0050EA XEL COMMUNICTIONS, INC. +0050EB ALPHA-TOP CORPORATION +0050EC OLICOM A/S +0050ED ANDA NETWORKS +0050EE TEK DIGITEL CORPORATION +0050EF SPE SYSTEMHAUS GMBH +0050F0 CISCO SYSTEMS, INC. +0050F1 LIBIT SIGNAL PROCESSING, LTD. +0050F2 MICROSOFT CORP. +0050F3 GLOBAL NET INFORMATION CO.,LTD +0050F4 SIGMATEK GMBH & CO. KG +0050F6 PAN-INTERNATIONAL +0050F7 VENTURE MANUFACTURING +0050F8 ENTREGA TECHNOLOGIES, INC. +0050FA OXTEL, LTD. +0050FB VSK ELECTRONICS +0050FC EDIMAX TECHNOLOGY CO., LTD. +0050FD ISIONCOMM CO., LTD. +0050FE PCTVNET ASA +0050FF HAKKO ELECTRONICS CO., LTD. +006000 XYCOM INC. +006001 INNOSYS, INC. +006002 SCREEN SUBTITLING SYSTEMS, LTD +006003 TERAOKA WEIGH SYSTEM PTE, LTD. +006004 COMPUTADORES MODULARES SA +006005 FEEDBACK DATA LTD. +006006 SOTEC CO., LTD +006007 ACRES GAMING, INC. +006008 3COM CORPORATION +006009 CISCO SYSTEMS, INC. +00600A SORD COMPUTER CORPORATION +00600B LOGWARE GMBH +00600C APPLIED DATA SYSTEMS, INC. +00600D MICRODESIGN GMBH +00600E WAVENET INTERNATIONAL, INC. +00600F WESTELL, INC. +006010 NETWORK MACHINES, INC. +006011 CRYSTAL SEMICONDUCTOR CORP. +006012 POWER COMPUTING CORPORATION +006013 NETSTAL MASCHINEN AG +006014 EDEC CO., LTD. +006015 NET2NET CORPORATION +006016 CLARIION +006017 TOKIMEC INC. +006018 STELLAR ONE CORPORATION +006019 BOEHRINGER MANNHEIM CORP. +00601A KEITHLEY INSTRUMENTS +00601B MESA ELECTRONICS +00601C TELXON CORPORATION +00601D LUCENT TECHNOLOGIES +00601E SOFTLAB, INC. +00601F STALLION TECHNOLOGIES +006020 PIVOTAL NETWORKING, INC. +006021 DSC CORPORATION +006022 VICOM SYSTEMS, INC. +006023 PERICOM SEMICONDUCTOR CORP. +006024 GRADIENT TECHNOLOGIES, INC. +006025 ACTIVE IMAGING PLC +006026 VIKING COMPONENTS, INC. +006027 Superior Modular Products +006028 MACROVISION CORPORATION +006029 CARY PERIPHERALS INC. +00602A SYMICRON COMPUTER +00602B PEAK AUDIO +00602C LINX DATA TERMINALS, INC. +00602D ALERTON TECHNOLOGIES, INC. +00602E CYCLADES CORPORATION +00602F CISCO SYSTEMS, INC. +006030 VILLAGE TRONIC +006031 HRK SYSTEMS +006032 I-CUBE, INC. +006033 ACUITY IMAGING, INC. +006034 ROBERT BOSCH GMBH +006035 DALLAS SEMICONDUCTOR, INC. +006036 AUSTRIAN RESEARCH CENTER +006037 PHILIPS SEMICONDUCTORS +006038 Nortel Networks +006039 SANCOM TECHNOLOGY, INC. +00603A QUICK CONTROLS LTD. +00603B AMTEC SPA +00603C HAGIWARA SYS-COM CO., LTD. +00603D 3CX +00603E CISCO SYSTEMS, INC. +00603F PATAPSCO DESIGNS +006040 NETRO CORP. +006041 Yokogawa Electric Corporation +006042 TKS (USA), INC. +006043 COMSOFT SYSTEMS, INC. +006044 LITTON/POLY-SCIENTIFIC +006045 PATHLIGHT TECHNOLOGIES +006046 VMETRO, INC. +006047 CISCO SYSTEMS, INC. +006048 EMC CORPORATION +006049 VINA TECHNOLOGIES +00604A SAIC IDEAS GROUP +00604B BIODATA GMBH +00604C SAT +00604D MMC NETWORKS, INC. +00604E CYCLE COMPUTER CORPORATION, INC. +00604F SUZUKI MFG. CO., LTD. +006050 INTERNIX INC. +006051 QUALITY SEMICONDUCTOR +006052 PERIPHERALS ENTERPRISE CO., L. +006053 TOYODA MACHINE WORKS, LTD. +006054 CONTROLWARE GMBH +006055 CORNELL UNIVERSITY +006056 NETWORK TOOLS, INC. +006057 MURATA MANUFACTURING CO., LTD. +006058 COPPER MOUNTAIN +006059 TECHNICAL COMMUNICATIONS CORP. +00605A CELCORE, INC. +00605B INTRASERVER TECHNOLOGY INC. +00605C CISCO SYSTEMS, INC. +00605D SCANIVALVE CORP. +00605E LIBERTY TECHNOLOGY NETWORKING +00605F NIPPON UNISOFT CORPORATION +006060 DAWNING TECHNOLOGIES, INC. +006061 WHISTLE COMMUNICATIONS CORP. +006062 TELESYNC, INC. +006063 PSION DACOM PLC. +006064 NETCOMM LIMITED +006065 BERNECKER & RAINER +006066 LACROIX TECHNOLGIE +006067 ACER NETXUS INC. +006068 EICON TECHNOLOGY CORPORATION +006069 BROCADE COMMUNICATIONS SYSTEMS +00606A MITSUBISHI WIRELESS COMM. INC. +00606B AICHI ELECTRONICS CO.,LTD. +00606C ARESCOM +00606D DIGITAL EQUIPMENT CORP. +00606E DAVICOM SEMICONDUCTOR, INC. +00606F CLARION CORPORATION OF AMERICA +006070 CISCO SYSTEMS, INC. +006071 MIDAS LAB, INC. +006072 VXL INSTRUMENTS, LIMITED +006073 REDCREEK COMMUNICATIONS, INC. +006074 QSC AUDIO PRODUCTS +006075 PENTEK, INC. +006076 SCHLUMBERGER TECHNOLOGIES +006077 PRISA NETWORKS +006078 POWER MEASUREMENT LTD. +006079 WAVEPHORE NETWORKS, INC. +00607A DVS GMBH +00607B FORE SYSTEMS, INC. +00607C WAVEACCESS, LTD. +00607D SENTIENT NETWORKS INC. +00607E GIGALABS, INC. +00607F AURORA TECHNOLOGIES, INC. +006080 MICROTRONIX DATACOM LTD. +006081 TV/COM INTERNATIONAL +006082 NOVALINK TECHNOLOGIES, INC. +006083 CISCO SYSTEMS, INC. +006084 DIGITAL VIDEO +006085 STORAGE CONCEPTS +006086 LOGIC REPLACEMENT TECH. LTD. +006087 KANSAI ELECTRIC CO., LTD. +006088 WHITE MOUNTAIN DSP, INC. +006089 XATA +00608A CITADEL COMPUTER +00608B CONFERTECH INTERNATIONAL +00608C 3COM CORPORATION +00608D UNIPULSE CORP. +00608E HE ELECTRONICS, TECHNOLOGIE & +00608F TEKRAM TECHNOLOGY CO., LTD. +006090 ABLE COMMUNICATIONS, INC. +006091 FIRST PACIFIC NETWORKS, INC. +006092 MICRO/SYS, INC. +006093 VARIAN +006094 IBM CORP. +006095 ACCU-TIME SYSTEMS, INC. +006096 T.S. MICROTECH INC. +006097 3COM CORPORATION +006098 HT COMMUNICATIONS +006099 LAN MEDIA CORPORATION +00609A NJK TECHNO CO. +00609B ASTRO-MED, INC. +00609C PERKIN-ELMER CORPORATION +00609D PMI FOOD EQUIPMENT GROUP +00609E X3 - INFORMATION TECHNOLOGY +00609F PHAST CORPORATION +0060A0 SWITCHED NETWORK +0060A1 VPNET +0060A2 NIHON UNISYS LIMITED CO. +0060A3 CONTINUUM TECHNOLOGY CORP. +0060A4 GRINAKER SYSTEM TECHNOLOGIES +0060A5 PERFORMANCE TELECOM CORP. +0060A6 PARTICLE MEASURING SYSTEMS +0060A7 MICROSENS GMBH & CO. KG +0060A8 TIDOMAT AB +0060A9 GESYTEC MBH +0060AA INTELLIGENT DEVICES INC. (IDI) +0060AB LARSCOM INCORPORATED +0060AC RESILIENCE CORPORATION +0060AD MEGACHIPS CORPORATION +0060AE TRIO INFORMATION SYSTEMS AB +0060AF PACIFIC MICRO DATA, INC. +0060B0 HEWLETT-PACKARD CO. +0060B1 INPUT/OUTPUT, INC. +0060B2 PROCESS CONTROL CORP. +0060B3 Z-COM, INC. +0060B4 GLENAYRE R&D INC. +0060B5 KEBA GMBH +0060B6 LAND COMPUTER CO., LTD. +0060B7 CHANNELMATIC, INC. +0060B8 CORELIS INC. +0060B9 NITSUKO CORPORATION +0060BA SAHARA NETWORKS, INC. +0060BB CABLETRON - NETLINK, INC. +0060BC KEUNYOUNG ELECTRONICS & +0060BD HUBBELL-PULSECOM +0060BE WEBTRONICS +0060BF MACRAIGOR SYSTEMS, INC. +0060C0 NERA AS +0060C1 WAVESPAN CORPORATION +0060C2 MPL AG +0060C3 NETVISION CORPORATION +0060C4 SOLITON SYSTEMS K.K. +0060C5 ANCOT CORP. +0060C6 DCS AG +0060C7 AMATI COMMUNICATIONS CORP. +0060C8 KUKA WELDING SYSTEMS & ROBOTS +0060C9 CONTROLNET, INC. +0060CA HARMONIC SYSTEMS INCORPORATED +0060CB HITACHI ZOSEN CORPORATION +0060CC EMTRAK, INCORPORATED +0060CD VIDEOSERVER, INC. +0060CE ACCLAIM COMMUNICATIONS +0060CF ALTEON NETWORKS, INC. +0060D0 SNMP RESEARCH INCORPORATED +0060D1 CASCADE COMMUNICATIONS +0060D2 LUCENT TECHNOLOGIES TAIWAN +0060D3 AT&T +0060D4 ELDAT COMMUNICATION LTD. +0060D5 MIYACHI TECHNOS CORP. +0060D6 NOVATEL WIRELESS TECHNOLOGIES +0060D7 ECOLE POLYTECHNIQUE FEDERALE +0060D8 ELMIC SYSTEMS, INC. +0060D9 TRANSYS NETWORKS INC. +0060DA JBM ELECTRONICS CO. +0060DB NTP ELEKTRONIK A/S +0060DC TOYO COMMUNICATION EQUIPMENT +0060DD MYRICOM, INC. +0060DE KAYSER-THREDE GMBH +0060DF INRANGE TECHNOLOGIES CORP. +0060E0 AXIOM TECHNOLOGY CO., LTD. +0060E1 ORCKIT COMMUNICATIONS LTD. +0060E2 QUEST ENGINEERING & DEV. +0060E3 ARBIN INSTRUMENTS +0060E4 COMPUSERVE, INC. +0060E5 FUJI AUTOMATION CO., LTD. +0060E6 SHOMITI SYSTEMS INCORPORATED +0060E7 RANDATA +0060E8 HITACHI COMPUTER PRODUCTS +0060E9 ATOP TECHNOLOGIES, INC. +0060EA STREAMLOGIC +0060EB FOURTHTRACK SYSTEMS +0060EC HERMARY OPTO ELECTRONICS INC. +0060ED RICARDO TEST AUTOMATION LTD. +0060EE APOLLO +0060EF FLYTECH TECHNOLOGY CO., LTD. +0060F0 JOHNSON & JOHNSON MEDICAL, INC +0060F1 EXP COMPUTER, INC. +0060F2 LASERGRAPHICS, INC. +0060F3 NETCOM SYSTEMS, INC. +0060F4 ADVANCED COMPUTER SOLUTIONS, +0060F5 ICON WEST, INC. +0060F6 NEXTEST COMMUNICATION +0060F7 DATAFUSION SYSTEMS +0060F8 LORAN INTERNATIONAL TECHN. INC +0060F9 DIAMOND LANE COMMUNICATIONS +0060FA EDUCATIONAL TECHNOLOGY +0060FB PACKETEER, INC. +0060FC CONSERVATION THROUGH +0060FD NETICS, INC. +0060FE LYNX SYSTEM DEVELOPERS, INC. +0060FF QUVIS, INC. +0070B0 M/A-COM INC. COMPANIES +0070B3 DATA RECALL LTD. +008000 MULTITECH SYSTEMS, INC. +008001 PERIPHONICS CORPORATION +008002 SATELCOM (UK) LTD +008003 HYTEC ELECTRONICS LTD. +008004 ANTLOW COMMUNICATIONS, LTD. +008005 CACTUS COMPUTER INC. +008006 COMPUADD CORPORATION +008007 DLOG NC-SYSTEME +008008 DYNATECH COMPUTER SYSTEMS +008009 JUPITER SYSTEMS, INC. +00800A JAPAN COMPUTER CORP. +00800B CSK CORPORATION +00800C VIDECOM LIMITED +00800D VOSSWINKEL F.U. +00800E ATLANTIX CORPORATION +00800F STANDARD MICROSYSTEMS +008010 COMMODORE INTERNATIONAL +008011 DIGITAL SYSTEMS INT'L. INC. +008012 INTEGRATED MEASUREMENT SYSTEMS +008013 THOMAS-CONRAD CORPORATION +008014 ESPRIT SYSTEMS +008015 SEIKO SYSTEMS, INC. +008016 WANDEL AND GOLTERMANN +008017 PFU LIMITED +008018 KOBE STEEL, LTD. +008019 DAYNA COMMUNICATIONS, INC. +00801A BELL ATLANTIC +00801B KODIAK TECHNOLOGY +00801C NEWPORT SYSTEMS SOLUTIONS +00801D INTEGRATED INFERENCE MACHINES +00801E XINETRON, INC. +00801F KRUPP ATLAS ELECTRONIK GMBH +008020 NETWORK PRODUCTS +008021 NEWBRIDGE RESEARCH CORP. +008022 SCAN-OPTICS +008023 INTEGRATED BUSINESS NETWORKS +008024 KALPANA, INC. +008025 STOLLMANN GMBH +008026 NETWORK PRODUCTS CORPORATION +008027 ADAPTIVE SYSTEMS, INC. +008028 TRADPOST (HK) LTD +008029 EAGLE TECHNOLOGY, INC. +00802A TEST SYSTEMS & SIMULATIONS INC +00802B INTEGRATED MARKETING CO +00802C THE SAGE GROUP PLC +00802D XYLOGICS INC +00802E CASTLE ROCK COMPUTING +00802F NATIONAL INSTRUMENTS CORP. +008030 NEXUS ELECTRONICS +008031 BASYS, CORP. +008032 ACCESS CO., LTD. +008033 FORMATION, INC. +008034 SMT GOUPIL +008035 TECHNOLOGY WORKS, INC. +008036 REFLEX MANUFACTURING SYSTEMS +008037 Ericsson Group +008038 DATA RESEARCH & APPLICATIONS +008039 ALCATEL STC AUSTRALIA +00803A VARITYPER, INC. +00803B APT COMMUNICATIONS, INC. +00803C TVS ELECTRONICS LTD +00803D SURIGIKEN CO., LTD. +00803E SYNERNETICS +00803F TATUNG COMPANY +008040 JOHN FLUKE MANUFACTURING CO. +008041 VEB KOMBINAT ROBOTRON +008042 FORCE COMPUTERS +008043 NETWORLD, INC. +008044 SYSTECH COMPUTER CORP. +008045 MATSUSHITA ELECTRIC IND. CO +008046 UNIVERSITY OF TORONTO +008047 IN-NET CORP. +008048 COMPEX INCORPORATED +008049 NISSIN ELECTRIC CO., LTD. +00804A PRO-LOG +00804B EAGLE TECHNOLOGIES PTY.LTD. +00804C CONTEC CO., LTD. +00804D CYCLONE MICROSYSTEMS, INC. +00804E APEX COMPUTER COMPANY +00804F DAIKIN INDUSTRIES, LTD. +008050 ZIATECH CORPORATION +008051 FIBERMUX +008052 TECHNICALLY ELITE CONCEPTS +008053 INTELLICOM, INC. +008054 FRONTIER TECHNOLOGIES CORP. +008055 FERMILAB +008056 SPHINX ELEKTRONIK GMBH +008057 ADSOFT, LTD. +008058 PRINTER SYSTEMS CORPORATION +008059 STANLEY ELECTRIC CO., LTD +00805A TULIP COMPUTERS INTERNAT'L B.V +00805B CONDOR SYSTEMS, INC. +00805C AGILIS CORPORATION +00805D CANSTAR +00805E LSI LOGIC CORPORATION +00805F COMPAQ COMPUTER CORPORATION +008060 NETWORK INTERFACE CORPORATION +008061 LITTON SYSTEMS, INC. +008062 INTERFACE CO. +008063 RICHARD HIRSCHMANN GMBH & CO. +008064 WYSE TECHNOLOGY +008065 CYBERGRAPHIC SYSTEMS PTY LTD. +008066 ARCOM CONTROL SYSTEMS, LTD. +008067 SQUARE D COMPANY +008068 YAMATECH SCIENTIFIC LTD. +008069 COMPUTONE SYSTEMS +00806A ERI (EMPAC RESEARCH INC.) +00806B SCHMID TELECOMMUNICATION +00806C CEGELEC PROJECTS LTD +00806D CENTURY SYSTEMS CORP. +00806E NIPPON STEEL CORPORATION +00806F ONELAN LTD. +008070 COMPUTADORAS MICRON +008071 SAI TECHNOLOGY +008072 MICROPLEX SYSTEMS LTD. +008073 DWB ASSOCIATES +008074 FISHER CONTROLS +008075 PARSYTEC GMBH +008076 MCNC +008077 BROTHER INDUSTRIES, LTD. +008078 PRACTICAL PERIPHERALS, INC. +008079 MICROBUS DESIGNS LTD. +00807A AITECH SYSTEMS LTD. +00807B ARTEL COMMUNICATIONS CORP. +00807C FIBERCOM, INC. +00807D EQUINOX SYSTEMS INC. +00807E SOUTHERN PACIFIC LTD. +00807F DY-4 INCORPORATED +008080 DATAMEDIA CORPORATION +008081 KENDALL SQUARE RESEARCH CORP. +008082 PEP MODULAR COMPUTERS GMBH +008083 AMDAHL +008084 THE CLOUD INC. +008085 H-THREE SYSTEMS CORPORATION +008086 COMPUTER GENERATION INC. +008087 OKI ELECTRIC INDUSTRY CO., LTD +008088 VICTOR COMPANY OF JAPAN, LTD. +008089 TECNETICS (PTY) LTD. +00808A SUMMIT MICROSYSTEMS CORP. +00808B DACOLL LIMITED +00808C NetScout Systems, Inc. +00808D WESTCOAST TECHNOLOGY B.V. +00808E RADSTONE TECHNOLOGY +00808F C. ITOH ELECTRONICS, INC. +008090 MICROTEK INTERNATIONAL, INC. +008091 TOKYO ELECTRIC CO.,LTD +008092 JAPAN COMPUTER INDUSTRY, INC. +008093 XYRON CORPORATION +008094 ALFA LAVAL AUTOMATION AB +008095 BASIC MERTON HANDELSGES.M.B.H. +008096 HUMAN DESIGNED SYSTEMS, INC. +008097 CENTRALP AUTOMATISMES +008098 TDK CORPORATION +008099 KLOCKNER MOELLER IPC +00809A NOVUS NETWORKS LTD +00809B JUSTSYSTEM CORPORATION +00809C LUXCOM, INC. +00809D Commscraft Ltd. +00809E DATUS GMBH +00809F ALCATEL BUSINESS SYSTEMS +0080A0 EDISA HEWLETT PACKARD S/A +0080A1 MICROTEST, INC. +0080A2 CREATIVE ELECTRONIC SYSTEMS +0080A3 LANTRONIX +0080A4 LIBERTY ELECTRONICS +0080A5 SPEED INTERNATIONAL +0080A6 REPUBLIC TECHNOLOGY, INC. +0080A7 MEASUREX CORP. +0080A8 VITACOM CORPORATION +0080A9 CLEARPOINT RESEARCH +0080AA MAXPEED +0080AB DUKANE NETWORK INTEGRATION +0080AC IMLOGIX, DIVISION OF GENESYS +0080AD CNET TECHNOLOGY, INC. +0080AE HUGHES NETWORK SYSTEMS +0080AF ALLUMER CO., LTD. +0080B0 ADVANCED INFORMATION +0080B1 SOFTCOM A/S +0080B2 NETWORK EQUIPMENT TECHNOLOGIES +0080B3 AVAL DATA CORPORATION +0080B4 SOPHIA SYSTEMS +0080B5 UNITED NETWORKS INC. +0080B6 THEMIS COMPUTER +0080B7 STELLAR COMPUTER +0080B8 BUG, INCORPORATED +0080B9 ARCHE TECHNOLIGIES INC. +0080BA SPECIALIX (ASIA) PTE, LTD +0080BB HUGHES LAN SYSTEMS +0080BC HITACHI ENGINEERING CO., LTD +0080BD THE FURUKAWA ELECTRIC CO., LTD +0080BE ARIES RESEARCH +0080BF TAKAOKA ELECTRIC MFG. CO. LTD. +0080C0 PENRIL DATACOMM +0080C1 LANEX CORPORATION +0080C2 IEEE 802 COMMITTEE +0080C3 BICC INFORMATION SYSTEMS & SVC +0080C4 DOCUMENT TECHNOLOGIES, INC. +0080C5 NOVELLCO DE MEXICO +0080C6 NATIONAL DATACOMM CORPORATION +0080C7 XIRCOM +0080C8 D-LINK SYSTEMS, INC. +0080C9 ALBERTA MICROELECTRONIC CENTRE +0080CA NETCOM RESEARCH INCORPORATED +0080CB FALCO DATA PRODUCTS +0080CC MICROWAVE BYPASS SYSTEMS +0080CD MICRONICS COMPUTER, INC. +0080CE BROADCAST TELEVISION SYSTEMS +0080CF EMBEDDED PERFORMANCE INC. +0080D0 COMPUTER PERIPHERALS, INC. +0080D1 KIMTRON CORPORATION +0080D2 SHINNIHONDENKO CO., LTD. +0080D3 SHIVA CORP. +0080D4 CHASE RESEARCH LTD. +0080D5 CADRE TECHNOLOGIES +0080D6 NUVOTECH, INC. +0080D7 FANTUM ENGINEERING, INC. +0080D8 NETWORK PERIPHERALS INC. +0080D9 EMK ELEKTRONIK +0080DA BRUEL & KJAER +0080DB GRAPHON CORPORATION +0080DC PICKER INTERNATIONAL +0080DD GMX INC/GIMIX +0080DE GIPSI S.A. +0080DF ADC CODENOLL TECHNOLOGY CORP. +0080E0 XTP SYSTEMS, INC. +0080E1 STMICROELECTRONICS +0080E2 T.D.I. CO., LTD. +0080E3 CORAL NETWORK CORPORATION +0080E4 NORTHWEST DIGITAL SYSTEMS, INC +0080E5 MYLEX CORPORATION +0080E6 PEER NETWORKS, INC. +0080E7 LYNWOOD SCIENTIFIC DEV. LTD. +0080E8 CUMULUS CORPORATIION +0080E9 MADGE NETWORKS +0080EA ADVA Optical Networking Ltd. +0080EB COMPCONTROL B.V. +0080EC SUPERCOMPUTING SOLUTIONS, INC. +0080ED IQ TECHNOLOGIES, INC. +0080EE THOMSON CSF +0080EF RATIONAL +0080F0 KYUSHU MATSUSHITA ELECTRIC CO. +0080F1 OPUS SYSTEMS +0080F2 RAYCOM SYSTEMS INC +0080F3 SUN ELECTRONICS CORP. +0080F4 TELEMECANIQUE ELECTRIQUE +0080F5 QUANTEL LTD +0080F6 SYNERGY MICROSYSTEMS +0080F7 ZENITH ELECTRONICS +0080F8 MIZAR, INC. +0080F9 HEURIKON CORPORATION +0080FA RWT GMBH +0080FB BVM LIMITED +0080FC AVATAR CORPORATION +0080FD EXSCEED CORPRATION +0080FE AZURE TECHNOLOGIES, INC. +0080FF SOC. DE TELEINFORMATIQUE RTC +009000 DIAMOND MULTIMEDIA +009001 NISHIMU ELCTRONICS INDUSTRIES +009002 ALLGON AB +009003 APLIO +009004 3COM EUROPE LTD. +009005 PROTECH SYSTEMS CO., LTD. +009006 HAMAMATSU PHOTONICS K.K. +009007 DOMEX TECHNOLOGY CORP. +009008 HAN A SYSTEMS, INC. +009009 i Controls, Inc. +00900A PROTON ELECTRONIC INDUSTRIAL +00900B LANNER ELECTRONICS, INC. +00900C CISCO SYSTEMS, INC. +00900D OVERLAND DATA INC. +00900E HANDLINK TECHNOLOGIES, INC. +00900F KAWASAKI HEAVY INDUSTRIES, LTD +009010 SIMULATION LABORATORIES, INC. +009011 WAVTRACE, INC. +009012 GLOBESPAN SEMICONDUCTOR, INC. +009013 SAMSAN CORP. +009014 ROTORK INSTRUMENTS, LTD. +009015 CENTIGRAM COMMUNICATIONS CORP. +009016 ZAC +009017 ZYPCOM, INC. +009018 ITO ELECTRIC INDUSTRY CO, LTD. +009019 HERMES ELECTRONICS CO., LTD. +00901A UNISPHERE SOLUTIONS +00901B DIGITAL CONTROLS +00901C MPS SOFTWARE GMBH +00901D PEC (NZ) LTD. +00901E SELESTA INGEGNE RIA S.P.A. +00901F ADTEC PRODUCTIONS, INC. +009020 PHILIPS ANALYTICAL X-RAY B.V. +009021 CISCO SYSTEMS, INC. +009022 IVEX +009023 ZILOG INC. +009024 PIPELINKS, INC. +009025 VISION SYSTEMS LTD. PTY +009026 ADVANCED SWITCHING +009027 INTEL CORPORATION +009028 NIPPON SIGNAL CO., LTD. +009029 CRYPTO AG +00902A COMMUNICATION DEVICES, INC. +00902B CISCO SYSTEMS, INC. +00902C DATA & CONTROL EQUIPMENT LTD. +00902D DATA ELECTRONICS +00902E NAMCO LIMITED +00902F NETCORE SYSTEMS, INC. +009030 HONEYWELL-DATING +009031 MYSTICOM, LTD. +009032 PELCOMBE GROUP LTD. +009033 INNOVAPHONE GMBH +009034 IMAGIC, INC. +009035 ALPHA TELECOM, INC. +009036 ENS, INC. +009037 ACUCOMM, INC. +009038 FOUNTAIN TECHNOLOGIES, INC. +009039 SHASTA NETWORKS +00903A NIHON MEDIA TOOL INC. +00903B TRIEMS RESEARCH LAB, INC. +00903C ATLANTIC NETWORK SYSTEMS +00903D BIOPAC SYSTEMS, INC. +00903E N.V. PHILIPS INDUSTRIAL +00903F AZTEC RADIOMEDIA +009040 CASTLE NETWORKS, INC. +009041 APPLIED DIGITAL ACCESS +009042 ECCS +009043 NICHIBEI DENSHI CO., LTD. +009044 ASSURED DIGITAL, INC. +009045 MARIPOSA TECHNOLOGY +009046 DEXDYNE, LTD. +009047 GIGA FAST E. LTD. +009048 ZEAL CORPORATION +009049 ENTRIDIA CORPORATION +00904A CONCUR SYSTEM TECHNOLOGIES +00904B GEMTEK TECHNOLOGY CO., LTD. +00904C EPIGRAM, INC. +00904D SPEC S.A. +00904E DELEM BV +00904F ABB POWER T&D COMPANY, INC. +009050 TELESTE OY +009051 ULTIMATE TECHNOLOGY CORP. +009052 SELCOM ELETTRONICA S.R.L. +009053 DAEWOO ELECTRONICS CO., LTD. +009054 INNOVATIVE SEMICONDUCTORS, INC +009055 PARKER HANNIFIN CORPORATION +009056 TELESTREAM, INC. +009057 AANETCOM, INC. +009058 ULTRA ELECTRONICS LTD. +009059 TELECOM DEVICE K.K. +00905A DEARBORN GROUP, INC. +00905B RAYMOND AND LAE ENGINEERING +00905C EDMI +00905D NETCOM SICHERHEITSTECHNIK GMBH +00905E RAULAND-BORG CORPORATION +00905F CISCO SYSTEMS, INC. +009060 SYSTEM CREATE CORP. +009061 PACIFIC RESEARCH & ENGINEERING +009062 ICP VORTEX COMPUTERSYSTEME +009063 COHERENT COMMUNICATIONS +009064 THOMSON BROADCAST SYSTEMS +009065 FINISAR CORPORATION +009066 Troika Networks, Inc. +009067 WALKABOUT COMPUTERS, INC. +009068 DVT CORP. +009069 JUNIPER NETWORKS, INC. +00906A TURNSTONE SYSTEMS, INC. +00906B APPLIED RESOURCES, INC. +00906C GWT GLOBAL WEIGHING +00906D CISCO SYSTEMS, INC. +00906E PRAXON, INC. +00906F CISCO SYSTEMS, INC. +009070 NEO NETWORKS, INC. +009071 BADGER TECHNOLOGY, INC. +009072 SIMRAD AS +009073 GAIO TECHNOLOGY +009074 ARGON NETWORKS, INC. +009075 NEC DO BRASIL S.A. +009076 FMT AIRCRAFT GATE SUPPORT +009077 ADVANCED FIBRE COMMUNICATIONS +009078 MER TELEMANAGEMENT +009079 CLEARONE INC. +00907A SPECTRALINK CORP. +00907B E-TECH, INC. +00907C DIGITALCAST, INC. +00907D HOME WIRELESS NETWORKS +00907E VETRONIX CORP. +00907F WATCHGUARD TECHNOLOGIES, INC. +009080 NOT LIMITED, INC. +009081 ALOHA NETWORKS, INC. +009082 FORCE INSTITUTE +009083 TURBO COMMUNICATION, INC. +009084 ATECH SYSTEM +009085 GOLDEN ENTERPRISES, INC. +009086 CISCO SYSTEMS, INC. +009087 ITIS +009088 BAXALL SECURITY LTD. +009089 SOFTCOM MICROSYSTEMS, INC. +00908A BAYLY COMMUNICATIONS, INC. +00908B CELL COMPUTING, INC. +00908C ETREND ELECTRONICS, INC. +00908D VICKERS ELECTRONICS SYSTEMS +00908E Nortel Networks Broadband Access +00908F AUDIOCODES LTD. +009090 I-BUS +009091 DIGITALSCAPE, INC. +009092 CISCO SYSTEMS, INC. +009093 NANAO CORPORATION +009094 OSPREY TECHNOLOGIES, INC. +009095 UNIVERSAL AVIONICS +009096 ASKEY COMPUTER CORP. +009097 SYCAMORE NETWORKS +009098 SBC DESIGNS, INC. +009099 ALLIED TELESIS,K.K. +00909A ONE WORLD SYSTEMS, INC. +00909B MARKPOINT AB +00909C COMBOX, LTD. +00909D GSE SYSTEMS, INC. +00909E DELPHI ENGINEERING GROUP +00909F DIGI-DATA CORPORATION +0090A0 8X8 INC. +0090A1 FLYING PIG SYSTEMS, LTD. +0090A2 CYBERTAN TECHNOLOGY, INC. +0090A3 MEDIALINCS CO., LTD. +0090A4 ALTIGA NETWORKS +0090A5 SPECTRA LOGIC +0090A6 CISCO SYSTEMS, INC. +0090A7 CLIENTEC CORPORATION +0090A8 NINETILES NETWORKS LTD. +0090A9 WESTERN DIGITAL +0090AA INDIGO ACTIVE VISION +0090AB CISCO SYSTEMS, INC. +0090AC OPTIVISION, INC. +0090AD ASPECT ELECTRONICS, INC. +0090AE ITALTEL SPA +0090AF J. MORITA MFG. CORP. +0090B0 VADEM +0090B1 CISCO SYSTEMS, INC. +0090B2 AVICI SYSTEMS INC. +0090B3 AGRANAT SYSTEMS +0090B4 WILLOWBROOK TECHNOLOGIES +0090B5 NIKON CORPORATION +0090B6 FIBEX SYSTEMS +0090B7 DIGITAL LIGHTWAVE, INC. +0090B8 ROHDE & SCHWARZ GMBH & CO. KG +0090B9 BERAN INSTRUMENTS LTD. +0090BA VALID NETWORKS, INC. +0090BB TAINET COMMUNICATION SYSTEM +0090BC TELEMANN CO., LTD. +0090BD OMNIA COMMUNICATIONS, INC. +0090BE IBC/INTEGRATED BUSINESS +0090BF CISCO SYSTEMS, INC. +0090C0 K.J. LAW ENGINEERS, INC. +0090C1 EDA INDUSTRIES +0090C2 JK MICROSYSTEMS, INC. +0090C3 TOPIC SEMICONDUCTOR CORP. +0090C4 JAVELIN SYSTEMS, INC. +0090C5 INTERNET MAGIC, INC. +0090C6 OPTIM SYSTEMS, INC. +0090C7 ICOM INC. +0090C8 WAVERIDER COMMUNICATIONS +0090C9 PRODUCTIVITY ENHANCEMENT +0090CA ACCORD VIDEO +0090CB WIRELESS ONLINE, INC. +0090CC PLANEX COMMUNICATIONS, INC. +0090CD ENT-EMPRESA NACIONAL +0090CE TETRA GMBH +0090CF NORTEL +0090D0 ALCATEL BELL +0090D1 LEICHU ENTERPRISE CO., LTD. +0090D2 ARTEL VIDEO SYSTEMS +0090D3 GIESECKE & DEVRIENT GMBH +0090D4 BINDVIEW DEVELOPMENT CORP. +0090D5 EUPHONIX, INC. +0090D6 CRYSTAL GROUP +0090D7 NETBOOST CORP. +0090D8 WHITECROSS SYSTEMS +0090D9 CISCO SYSTEMS, INC. +0090DA DYNARC, INC. +0090DB NEXT LEVEL COMMUNICATIONS +0090DC TECO INFORMATION SYSTEMS +0090DD THE MIHARU COMMUNICATIONS +0090DE CARDKEY SYSTEMS, INC. +0090DF MITSUBISHI CHEMICAL +0090E0 SYSTRAN CORP. +0090E1 TELENA S.P.A. +0090E2 DISTRIBUTED PROCESSING +0090E3 AVEX ELECTRONICS INC. +0090E4 NEC AMERICA, INC. +0090E5 TEKNEMA, INC. +0090E6 ACER LABORATORIES, INC. +0090E7 HORSCH ELEKTRONIK AG +0090E8 MOXA TECHNOLOGIES CORP., LTD. +0090E9 JANZ COMPUTER AG +0090EA ALPHA TECHNOLOGIES, INC. +0090EB SENTRY TELECOM SYSTEMS +0090EC PYRESCOM +0090ED CENTRAL SYSTEM RESEARCH +0090EE PERSONAL COMMUNICATIONS +0090EF INTEGRIX, INC. +0090F0 HARMONIC LIGHTWAVES, LTD. +0090F1 DOT HILL SYSTEMS CORPORATION +0090F2 CISCO SYSTEMS, INC. +0090F3 ASPECT COMMUNICATIONS +0090F4 LIGHTNING INSTRUMENTATION +0090F5 CLEVO CO. +0090F6 ESCALATE NETWORKS, INC. +0090F7 NBASE COMMUNICATIONS LTD. +0090F8 MEDIATRIX TELECOM +0090F9 LEITCH +0090FA GIGANET, INC. +0090FB PORTWELL, INC. +0090FC NETWORK COMPUTING DEVICES +0090FD COPPERCOM, INC. +0090FE ELECOM CO., LTD. (LANEED DIV. +0090FF TELLUS TECHNOLOGY INC. +009D8E CARDIAC RECORDERS, INC. +00A000 CENTILLION NETWORKS, INC. +00A001 WATKINS-JOHNSON COMPANY +00A002 LEEDS & NORTHRUP AUSTRALIA +00A003 STAEFA CONTROL SYSTEM +00A004 NETPOWER, INC. +00A005 DANIEL INSTRUMENTS, LTD. +00A006 IMAGE DATA PROCESSING +00A007 APEXX TECHNOLOGY, INC. +00A008 NETCORP +00A009 WHITETREE NETWORK +00A00A R.D.C. COMMUNICATION +00A00B COMPUTEX CO., LTD. +00A00C KINGMAX TECHNOLOGY, INC. +00A00D THE PANDA PROJECT +00A00E VISUAL NETWORKS, INC. +00A00F Broadband Technologies +00A010 SYSLOGIC DATENTECHNIK AG +00A011 MUTOH INDUSTRIES LTD. +00A012 B.A.T.M. ADVANCED TECHNOLOGIES +00A013 TELTREND LTD. +00A014 CSIR +00A015 WYLE +00A016 MICROPOLIS CORP. +00A017 J B M CORPORATION +00A018 CREATIVE CONTROLLERS, INC. +00A019 NEBULA CONSULTANTS, INC. +00A01A BINAR ELEKTRONIK AB +00A01B PREMISYS COMMUNICATIONS, INC. +00A01C NASCENT NETWORKS CORPORATION +00A01D SIXNET +00A01E EST CORPORATION +00A01F TRICORD SYSTEMS, INC. +00A020 CITICORP/TTI +00A021 GENERAL DYNAMICS- +00A022 CENTRE FOR DEVELOPMENT OF +00A023 APPLIED CREATIVE TECHNOLOGY, +00A024 3COM CORPORATION +00A025 REDCOM LABS INC. +00A026 TELDAT, S.A. +00A027 FIREPOWER SYSTEMS, INC. +00A028 CONNER PERIPHERALS +00A029 COULTER CORPORATION +00A02A TRANCELL SYSTEMS +00A02B TRANSITIONS RESEARCH CORP. +00A02C INTERWAVE COMMUNICATIONS +00A02D 1394 Trade Association +00A02E BRAND COMMUNICATIONS, LTD. +00A02F PIRELLI CAVI +00A030 CAPTOR NV/SA +00A031 HAZELTINE CORPORATION, MS 1-17 +00A032 GES SINGAPORE PTE. LTD. +00A033 IMC MESS-SYSTEME GMBH +00A034 AXEL +00A035 CYLINK CORPORATION +00A036 APPLIED NETWORK TECHNOLOGY +00A037 DATASCOPE CORPORATION +00A038 EMAIL ELECTRONICS +00A039 ROSS TECHNOLOGY, INC. +00A03A KUBOTEK CORPORATION +00A03B TOSHIN ELECTRIC CO., LTD. +00A03C EG&G NUCLEAR INSTRUMENTS +00A03D OPTO - 22 +00A03E ATM FORUM +00A03F COMPUTER SOCIETY MICROPROCES'R +00A040 APPLE COMPUTER +00A041 LEYBOLD-INFICON +00A042 SPUR PRODUCTS CORP. +00A043 AMERICAN TECHNOLOGY LABS, INC. +00A044 NTT INTELLIGENT TECHNOLOGY +00A045 PHOENIX CONTACT GMBH & CO. +00A046 SCITEX CORP. LTD. +00A047 INTEGRATED FITNESS CORP. +00A048 QUESTECH, LTD. +00A049 DIGITECH INDUSTRIES, INC. +00A04A NISSHIN ELECTRIC CO., LTD. +00A04B TFL LAN INC. +00A04C INNOVATIVE SYSTEMS & TECH. INC +00A04D EDA INSTRUMENTS, INC. +00A04E VOELKER TECHNOLOGIES, INC. +00A04F AMERITEC CORP. +00A050 CYPRESS SEMICONDUCTOR +00A051 ANGIA COMMUNICATIONS. INC. +00A052 STANILITE ELECTRONICS PTY. LTD +00A053 COMPACT DEVICES, INC. +00A055 LINKTECH, INC. +00A056 MICROPROSS +00A057 ELSA AG +00A058 GLORY, LTD. +00A059 HAMILTON HALLMARK +00A05A KOFAX IMAGE PRODUCTS +00A05B MARQUIP, INC. +00A05C INVENTORY CONVERSION, INC./ +00A05D CS COMPUTER SYSTEME GMBH +00A05E MYRIAD LOGIC INC. +00A05F BTG ENGINEERING BV +00A060 ACER PERIPHERALS, INC. +00A061 PURITAN BENNETT +00A062 AES PRODATA +00A063 JRL SYSTEMS, INC. +00A064 KVB/ANALECT +00A065 NEXLAND, INC. +00A066 ISA CO., LTD. +00A067 NETWORK SERVICES GROUP +00A068 BHP LIMITED +00A069 TrueTime +00A06A VERILINK CORP. +00A06B DMS DORSCH MIKROSYSTEM GMBH +00A06C SHINDENGEN ELECTRIC MFG. +00A06D MANNESMANN TALLY CORPORATION +00A06E AUSTRON, INC. +00A06F THE APPCON GROUP, INC. +00A070 COASTCOM +00A071 VIDEO LOTTERY TECHNOLOGIES,INC +00A072 OVATION SYSTEMS LTD. +00A073 COM21, INC. +00A074 PERCEPTION TECHNOLOGY +00A075 MICRON TECHNOLOGY, INC. +00A076 CARDWARE LAB, INC. +00A077 FUJITSU NEXION, INC. +00A078 Marconi Communications +00A079 ALPS ELECTRIC (USA), INC. +00A07A ADVANCED PERIPHERALS +00A07B DAWN COMPUTER INCORPORATION +00A07C TONYANG NYLON CO., LTD. +00A07D SEEQ TECHNOLOGY, INC. +00A07E AVID TECHNOLOGY, INC. +00A07F GSM-SYNTEL, LTD. +00A080 ANTARES MICROSYSTEMS +00A081 ALCATEL DATA NETWORKS +00A082 NKT ELEKTRONIK A/S +00A083 ASIMMPHONY TURKEY +00A084 DATAPLEX PTY. LTD. +00A086 AMBER WAVE SYSTEMS, INC. +00A087 MITEL SEMICONDUCTOR, LTD. +00A088 ESSENTIAL COMMUNICATIONS +00A089 XPOINT TECHNOLOGIES, INC. +00A08A BROOKTROUT TECHNOLOGY, INC. +00A08B ASTON ELECTRONIC DESIGNS LTD. +00A08C MULTIMEDIA LANS, INC. +00A08D JACOMO CORPORATION +00A08E Nokia Internet Communications +00A08F DESKNET SYSTEMS, INC. +00A090 TIMESTEP CORPORATION +00A091 APPLICOM INTERNATIONAL +00A092 H. BOLLMANN MANUFACTURERS, LTD +00A093 B/E AEROSPACE +00A094 COMSAT CORPORATION +00A095 ACACIA NETWORKS, INC. +00A096 MITSUMI ELECTRIC CO., LTD. +00A097 JC INFORMATION SYSTEMS +00A098 NETWORK APPLIANCE CORP. +00A099 K-NET LTD. +00A09A NIHON KOHDEN AMERICA +00A09B QPSX COMMUNICATIONS, LTD. +00A09C XYPLEX, INC. +00A09D JOHNATHON FREEMAN TECHNOLOGIES +00A09E ICTV +00A09F COMMVISION CORP. +00A0A0 COMPACT DATA, LTD. +00A0A1 EPIC DATA INC. +00A0A2 DIGICOM S.P.A. +00A0A3 RELIABLE POWER METERS +00A0A4 MICROS SYSTEMS, INC. +00A0A5 TEKNOR MICROSYSTEME, INC. +00A0A6 M.I. SYSTEMS, K.K. +00A0A7 VORAX CORPORATION +00A0A8 RENEX CORPORATION +00A0A9 GN NETTEST (CANADA) INC. +00A0AA SPACELABS MEDICAL +00A0AB NETCS INFORMATIONSTECHNIK GMBH +00A0AC GILAT SATELLITE NETWORKS, LTD. +00A0AD MARCONI SPA +00A0AE NUCOM SYSTEMS, INC. +00A0AF WMS INDUSTRIES +00A0B0 I-O DATA DEVICE, INC. +00A0B1 FIRST VIRTUAL CORPORATION +00A0B2 SHIMA SEIKI +00A0B3 ZYKRONIX +00A0B4 TEXAS MICROSYSTEMS, INC. +00A0B5 3H TECHNOLOGY +00A0B6 SANRITZ AUTOMATION CO., LTD. +00A0B7 CORDANT, INC. +00A0B8 SYMBIOS LOGIC INC. +00A0B9 EAGLE TECHNOLOGY, INC. +00A0BA PATTON ELECTRONICS CO. +00A0BB HILAN GMBH +00A0BC VIASAT, INCORPORATED +00A0BD I-TECH CORP. +00A0BE INTEGRATED CIRCUIT SYSTEMS,INC +00A0BF WIRELESS DATA GROUP MOTOROLA +00A0C0 DIGITAL LINK CORP. +00A0C1 ORTIVUS MEDICAL AB +00A0C2 R.A. SYSTEMS CO., LTD. +00A0C3 UNICOMPUTER GMBH +00A0C4 CRISTIE ELECTRONICS LTD. +00A0C5 ZYXEL COMMUNICATION +00A0C6 QUALCOMM INCORPORATED +00A0C7 TADIRAN TELECOMMUNICATIONS +00A0C8 ADTRAN INC. +00A0C9 INTEL CORPORATION - HF1-06 +00A0CA FUJITSU DENSO LTD. +00A0CB ARK TELECOMMUNICATIONS, INC. +00A0CC LITE-ON COMMUNICATIONS, INC. +00A0CD DR. JOHANNES HEIDENHAIN GMBH +00A0CE ASTROCOM CORPORATION +00A0CF SOTAS, INC. +00A0D0 TEN X TECHNOLOGY, INC. +00A0D1 INVENTEC CORPORATION +00A0D2 ALLIED TELESIS INTERNATIONAL +00A0D3 INSTEM COMPUTER SYSTEMS, LTD. +00A0D4 RADIOLAN, INC. +00A0D5 SIERRA WIRELESS INC. +00A0D6 SBE, INC. +00A0D7 KASTEN CHASE APPLIED RESEARCH +00A0D8 SPECTRA - TEK +00A0D9 CONVEX COMPUTER CORPORATION +00A0DA INTEGRATED SYSTEMS +00A0DB FISHER & PAYKEL PRODUCTION +00A0DC O.N. ELECTRONIC CO., LTD. +00A0DD AZONIX CORPORATION +00A0DE YAMAHA CORPORATION +00A0DF STS TECHNOLOGIES, INC. +00A0E0 TENNYSON TECHNOLOGIES PTY LTD +00A0E1 WESTPORT RESEARCH +00A0E2 KEISOKU GIKEN CORP. +00A0E3 XKL SYSTEMS CORP. +00A0E4 OPTIQUEST +00A0E5 NHC COMMUNICATIONS +00A0E6 DIALOGIC CORPORATION +00A0E7 CENTRAL DATA CORPORATION +00A0E8 REUTERS HOLDINGS PLC +00A0E9 ELECTRONIC RETAILING SYSTEMS +00A0EA ETHERCOM CORP. +00A0EB FASTCOMM COMMUNICATIONS CORP. +00A0EC TRANSMITTON LTD. +00A0ED PRI AUTOMATION +00A0EE NASHOBA NETWORKS +00A0EF LUCIDATA LTD. +00A0F0 TORONTO MICROELECTRONICS INC. +00A0F1 MTI +00A0F2 INFOTEK COMMUNICATIONS, INC. +00A0F3 STAUBLI +00A0F4 GE +00A0F5 RADGUARD LTD. +00A0F6 AUTOGAS SYSTEMS, INC. +00A0F7 V.I COMPUTER CORP. +00A0F8 SYMBOL TECHNOLOGIES, INC. +00A0F9 BINTEC COMMUNICATIONS GMBH +00A0FA Marconi Communication GmbH +00A0FB TORAY ENGINEERING CO., LTD. +00A0FC IMAGE SCIENCES, INC. +00A0FD SCITEX DIGITAL PRINTING, INC. +00A0FE BOSTON TECHNOLOGY, INC. +00A0FF TELLABS OPERATIONS, INC. +00AA00 INTEL CORPORATION +00AA01 INTEL CORPORATION +00AA02 INTEL CORPORATION +00AA3C OLIVETTI TELECOM SPA (OLTECO) +00B009 Grass Valley Group +00B017 InfoGear Technology Corp. +00B019 Casi-Rusco +00B01C Westport Technologies +00B01E Rantic Labs, Inc. +00B02A ORSYS GmbH +00B02D ViaGate Technologies, Inc. +00B03B HiQ Networks +00B048 Marconi Communications Inc. +00B04A Cisco Systems, Inc. +00B052 Intellon Corporation +00B064 Cisco Systems, Inc. +00B069 Honewell Oy +00B06D Jones Futurex Inc. +00B080 Mannesmann Ipulsys B.V. +00B086 LocSoft Limited +00B08E Cisco Systems, Inc. +00B091 Transmeta Corp. +00B094 Alaris, Inc. +00B09A Morrow Technologies Corp. +00B09D Point Grey Research Inc. +00B0AC SIAE-Microelettronica S.p.A. +00B0AE Symmetricom +00B0B3 Xstreamis PLC +00B0C2 Cisco Systems, Inc. +00B0C7 Tellabs Operations, Inc. +00B0CE TECHNOLOGY RESCUE +00B0D0 Dell Computer Corp. +00B0DB Nextcell, Inc. +00B0DF Reliable Data Technology, Inc. +00B0E7 British Federal Ltd. +00B0EC EACEM +00B0EE Ajile Systems, Inc. +00B0F0 CALY NETWORKS +00B0F5 NetWorth Technologies, Inc. +00BB01 OCTOTHORPE CORP. +00BBF0 UNGERMANN-BASS INC. +00C000 LANOPTICS, LTD. +00C001 DIATEK PATIENT MANAGMENT +00C002 SERCOMM CORPORATION +00C003 GLOBALNET COMMUNICATIONS +00C004 JAPAN BUSINESS COMPUTER CO.LTD +00C005 LIVINGSTON ENTERPRISES, INC. +00C006 NIPPON AVIONICS CO., LTD. +00C007 PINNACLE DATA SYSTEMS, INC. +00C008 SECO SRL +00C009 KT TECHNOLOGY (S) PTE LTD +00C00A MICRO CRAFT +00C00B NORCONTROL A.S. +00C00C RELIA TECHNOLGIES +00C00D ADVANCED LOGIC RESEARCH, INC. +00C00E PSITECH, INC. +00C00F QUANTUM SOFTWARE SYSTEMS LTD. +00C010 HIRAKAWA HEWTECH CORP. +00C011 INTERACTIVE COMPUTING DEVICES +00C012 NETSPAN CORPORATION +00C013 NETRIX +00C014 TELEMATICS CALABASAS INT'L,INC +00C015 NEW MEDIA CORPORATION +00C016 ELECTRONIC THEATRE CONTROLS +00C017 FORTE NETWORKS +00C018 LANART CORPORATION +00C019 LEAP TECHNOLOGY, INC. +00C01A COROMETRICS MEDICAL SYSTEMS +00C01B SOCKET COMMUNICATIONS, INC. +00C01C INTERLINK COMMUNICATIONS LTD. +00C01D GRAND JUNCTION NETWORKS, INC. +00C01E LA FRANCAISE DES JEUX +00C01F S.E.R.C.E.L. +00C020 ARCO ELECTRONIC, CONTROL LTD. +00C021 NETEXPRESS +00C022 LASERMASTER TECHNOLOGIES, INC. +00C023 TUTANKHAMON ELECTRONICS +00C024 EDEN SISTEMAS DE COMPUTACAO SA +00C025 DATAPRODUCTS CORPORATION +00C026 LANS TECHNOLOGY CO., LTD. +00C027 CIPHER SYSTEMS, INC. +00C028 JASCO CORPORATION +00C029 KABEL RHEYDT AG +00C02A OHKURA ELECTRIC CO., LTD. +00C02B GERLOFF GESELLSCHAFT FUR +00C02C CENTRUM COMMUNICATIONS, INC. +00C02D FUJI PHOTO FILM CO., LTD. +00C02E NETWIZ +00C02F OKUMA CORPORATION +00C030 INTEGRATED ENGINEERING B. V. +00C031 DESIGN RESEARCH SYSTEMS, INC. +00C032 I-CUBED LIMITED +00C033 TELEBIT COMMUNICATIONS APS +00C034 TRANSACTION NETWORK +00C035 QUINTAR COMPANY +00C036 RAYTECH ELECTRONIC CORP. +00C037 DYNATEM +00C038 RASTER IMAGE PROCESSING SYSTEM +00C039 TDK SEMICONDUCTOR CORPORATION +00C03A MEN-MIKRO ELEKTRONIK GMBH +00C03B MULTIACCESS COMPUTING CORP. +00C03C TOWER TECH S.R.L. +00C03D WIESEMANN & THEIS GMBH +00C03E FA. GEBR. HELLER GMBH +00C03F STORES AUTOMATED SYSTEMS, INC. +00C040 ECCI +00C041 DIGITAL TRANSMISSION SYSTEMS +00C042 DATALUX CORP. +00C043 STRATACOM +00C044 EMCOM CORPORATION +00C045 ISOLATION SYSTEMS, LTD. +00C046 KEMITRON LTD. +00C047 UNIMICRO SYSTEMS, INC. +00C048 BAY TECHNICAL ASSOCIATES +00C049 U.S. ROBOTICS, INC. +00C04A GROUP 2000 AG +00C04B CREATIVE MICROSYSTEMS +00C04C DEPARTMENT OF FOREIGN AFFAIRS +00C04D MITEC, INC. +00C04E COMTROL CORPORATION +00C04F DELL COMPUTER CORPORATION +00C050 TOYO DENKI SEIZO K.K. +00C051 ADVANCED INTEGRATION RESEARCH +00C052 BURR-BROWN +00C053 DAVOX CORPORATION +00C054 NETWORK PERIPHERALS, LTD. +00C055 MODULAR COMPUTING TECHNOLOGIES +00C056 SOMELEC +00C057 MYCO ELECTRONICS +00C058 DATAEXPERT CORP. +00C059 NIPPON DENSO CO., LTD. +00C05A SEMAPHORE COMMUNICATIONS CORP. +00C05B NETWORKS NORTHWEST, INC. +00C05C ELONEX PLC +00C05D L&N TECHNOLOGIES +00C05E VARI-LITE, INC. +00C05F FINE-PAL COMPANY LIMITED +00C060 ID SCANDINAVIA AS +00C061 SOLECTEK CORPORATION +00C062 IMPULSE TECHNOLOGY +00C063 MORNING STAR TECHNOLOGIES, INC +00C064 GENERAL DATACOMM IND. INC. +00C065 SCOPE COMMUNICATIONS, INC. +00C066 DOCUPOINT, INC. +00C067 UNITED BARCODE INDUSTRIES +00C068 PHILIP DRAKE ELECTRONICS LTD. +00C069 ADAPTIVE BROADBAND CORPORATION +00C06A ZAHNER-ELEKTRIK GMBH & CO. KG +00C06B OSI PLUS CORPORATION +00C06C SVEC COMPUTER CORP. +00C06D BOCA RESEARCH, INC. +00C06E HAFT TECHNOLOGY, INC. +00C06F KOMATSU LTD. +00C070 SECTRA SECURE-TRANSMISSION AB +00C071 AREANEX COMMUNICATIONS, INC. +00C072 KNX LTD. +00C073 XEDIA CORPORATION +00C074 TOYODA AUTOMATIC LOOM +00C075 XANTE CORPORATION +00C076 I-DATA INTERNATIONAL A-S +00C077 DAEWOO TELECOM LTD. +00C078 COMPUTER SYSTEMS ENGINEERING +00C079 FONSYS CO.,LTD. +00C07A PRIVA B.V. +00C07B ASCEND COMMUNICATIONS, INC. +00C07C HIGHTECH INFORMATION +00C07D RISC DEVELOPMENTS LTD. +00C07E KUBOTA CORPORATION ELECTRONIC +00C07F NUPON COMPUTING CORP. +00C080 NETSTAR, INC. +00C081 METRODATA LTD. +00C082 MOORE PRODUCTS CO. +00C083 TRACE MOUNTAIN PRODUCTS, INC. +00C084 DATA LINK CORP. LTD. +00C085 ELECTRONICS FOR IMAGING, INC. +00C086 THE LYNK CORPORATION +00C087 UUNET TECHNOLOGIES, INC. +00C088 EKF ELEKTRONIK GMBH +00C089 TELINDUS DISTRIBUTION +00C08A LAUTERBACH DATENTECHNIK GMBH +00C08B RISQ MODULAR SYSTEMS, INC. +00C08C PERFORMANCE TECHNOLOGIES, INC. +00C08D TRONIX PRODUCT DEVELOPMENT +00C08E NETWORK INFORMATION TECHNOLOGY +00C08F MATSUSHITA ELECTRIC WORKS, LTD +00C090 PRAIM S.R.L. +00C091 JABIL CIRCUIT, INC. +00C092 MENNEN MEDICAL INC. +00C093 ALTA RESEARCH CORP. +00C094 VMX INC. +00C095 ZNYX +00C096 TAMURA CORPORATION +00C097 ARCHIPEL SA +00C098 CHUNTEX ELECTRONIC CO., LTD. +00C099 YOSHIKI INDUSTRIAL CO.,LTD. +00C09A PHOTONICS CORPORATION +00C09B RELIANCE COMM/TEC, R-TEC +00C09C TOA ELECTRONIC LTD. +00C09D DISTRIBUTED SYSTEMS INT'L, INC +00C09E CACHE COMPUTERS, INC. +00C09F QUANTA COMPUTER, INC. +00C0A0 ADVANCE MICRO RESEARCH, INC. +00C0A1 TOKYO DENSHI SEKEI CO. +00C0A2 INTERMEDIUM A/S +00C0A3 DUAL ENTERPRISES CORPORATION +00C0A4 UNIGRAF OY +00C0A5 DICKENS DATA SYSTEMS +00C0A6 EXICOM AUSTRALIA PTY. LTD +00C0A7 SEEL LTD. +00C0A8 GVC CORPORATION +00C0A9 BARRON MCCANN LTD. +00C0AA SILICON VALLEY COMPUTER +00C0AB Telco Systems, Inc. +00C0AC GAMBIT COMPUTER COMMUNICATIONS +00C0AD MARBEN COMMUNICATION SYSTEMS +00C0AE TOWERCOM CO. INC. DBA PC HOUSE +00C0AF TEKLOGIX INC. +00C0B0 GCC TECHNOLOGIES,INC. +00C0B1 GENIUS NET CO. +00C0B2 NORAND CORPORATION +00C0B3 COMSTAT DATACOMM CORPORATION +00C0B4 MYSON TECHNOLOGY, INC. +00C0B5 CORPORATE NETWORK SYSTEMS,INC. +00C0B6 MERIDIAN DATA, INC. +00C0B7 AMERICAN POWER CONVERSION CORP +00C0B8 FRASER'S HILL LTD. +00C0B9 FUNK SOFTWARE, INC. +00C0BA NETVANTAGE +00C0BB FORVAL CREATIVE, INC. +00C0BC TELECOM AUSTRALIA/CSSC +00C0BD INEX TECHNOLOGIES, INC. +00C0BE ALCATEL - SEL +00C0BF TECHNOLOGY CONCEPTS, LTD. +00C0C0 SHORE MICROSYSTEMS, INC. +00C0C1 QUAD/GRAPHICS, INC. +00C0C2 INFINITE NETWORKS LTD. +00C0C3 ACUSON COMPUTED SONOGRAPHY +00C0C4 COMPUTER OPERATIONAL +00C0C5 SID INFORMATICA +00C0C6 PERSONAL MEDIA CORP. +00C0C7 SPARKTRUM MICROSYSTEMS, INC. +00C0C8 MICRO BYTE PTY. LTD. +00C0C9 ELSAG BAILEY PROCESS +00C0CA ALFA, INC. +00C0CB CONTROL TECHNOLOGY CORPORATION +00C0CC TELESCIENCES CO SYSTEMS, INC. +00C0CD COMELTA, S.A. +00C0CE CEI SYSTEMS & ENGINEERING PTE +00C0CF IMATRAN VOIMA OY +00C0D0 RATOC SYSTEM INC. +00C0D1 COMTREE TECHNOLOGY CORPORATION +00C0D2 SYNTELLECT, INC. +00C0D3 OLYMPUS IMAGE SYSTEMS, INC. +00C0D4 AXON NETWORKS, INC. +00C0D5 QUANCOM ELECTRONIC GMBH +00C0D6 J1 SYSTEMS, INC. +00C0D7 TAIWAN TRADING CENTER DBA +00C0D8 UNIVERSAL DATA SYSTEMS +00C0D9 QUINTE NETWORK CONFIDENTIALITY +00C0DA NICE SYSTEMS LTD. +00C0DB IPC CORPORATION (PTE) LTD. +00C0DC EOS TECHNOLOGIES, INC. +00C0DD QLogic Corporation +00C0DE ZCOMM, INC. +00C0DF KYE SYSTEMS CORP. +00C0E0 DSC COMMUNICATION CORP. +00C0E1 SONIC SOLUTIONS +00C0E2 CALCOMP, INC. +00C0E3 OSITECH COMMUNICATIONS, INC. +00C0E4 SIEMENS BUILDING +00C0E5 GESPAC, S.A. +00C0E6 Verilink Corporation +00C0E7 FIBERDATA AB +00C0E8 PLEXCOM, INC. +00C0E9 OAK SOLUTIONS, LTD. +00C0EA ARRAY TECHNOLOGY LTD. +00C0EB SEH COMPUTERTECHNIK GMBH +00C0EC DAUPHIN TECHNOLOGY +00C0ED US ARMY ELECTRONIC +00C0EE KYOCERA CORPORATION +00C0EF ABIT CORPORATION +00C0F0 KINGSTON TECHNOLOGY CORP. +00C0F1 SHINKO ELECTRIC CO., LTD. +00C0F2 TRANSITION NETWORKS +00C0F3 NETWORK COMMUNICATIONS CORP. +00C0F4 INTERLINK SYSTEM CO., LTD. +00C0F5 METACOMP, INC. +00C0F6 CELAN TECHNOLOGY INC. +00C0F7 ENGAGE COMMUNICATION, INC. +00C0F8 ABOUT COMPUTING INC. +00C0F9 HARRIS AND JEFFRIES, INC. +00C0FA CANARY COMMUNICATIONS, INC. +00C0FB ADVANCED TECHNOLOGY LABS +00C0FC ELASTIC REALITY, INC. +00C0FD PROSUM +00C0FE APTEC COMPUTER SYSTEMS, INC. +00C0FF DOT HILL SYSTEMS CORPORATION +00CBBD Cambridge Broadband Ltd. +00CF1C COMMUNICATION MACHINERY CORP. +00D000 FERRAN SCIENTIFIC, INC. +00D001 VST TECHNOLOGIES, INC. +00D002 DITECH CORPORATION +00D003 COMDA ENTERPRISES CORP. +00D004 PENTACOM LTD. +00D005 ZHS ZEITMANAGEMENTSYSTEME +00D006 CISCO SYSTEMS, INC. +00D007 MIC ASSOCIATES, INC. +00D008 MACTELL CORPORATION +00D009 HSING TECH. ENTERPRISE CO. LTD +00D00A LANACCESS TELECOM S.A. +00D00B RHK TECHNOLOGY, INC. +00D00C SNIJDER MICRO SYSTEMS +00D00D MICROMERITICS INSTRUMENT +00D00E PLURIS, INC. +00D00F SPEECH DESIGN GMBH +00D010 CONVERGENT NETWORKS, INC. +00D011 PRISM VIDEO, INC. +00D012 GATEWORKS CORP. +00D013 PRIMEX AEROSPACE COMPANY +00D014 ROOT, INC. +00D015 UNIVEX MICROTECHNOLOGY CORP. +00D016 SCM MICROSYSTEMS, INC. +00D017 SYNTECH INFORMATION CO., LTD. +00D018 QWES. COM, INC. +00D019 DAINIPPON SCREEN CORPORATE +00D01A URMET SUD S.P.A. +00D01B MIMAKI ENGINEERING CO., LTD. +00D01C SBS TECHNOLOGIES, +00D01D FURUNO ELECTRIC CO., LTD. +00D01E PINGTEL CORP. +00D01F CTAM PTY. LTD. +00D020 AIM SYSTEM, INC. +00D021 REGENT ELECTRONICS CORP. +00D022 INCREDIBLE TECHNOLOGIES, INC. +00D023 INFORTREND TECHNOLOGY, INC. +00D024 Cognex Corporation +00D025 XROSSTECH, INC. +00D026 HIRSCHMANN AUSTRIA GMBH +00D027 APPLIED AUTOMATION, INC. +00D028 OMNEON VIDEO NETWORKS +00D029 WAKEFERN FOOD CORPORATION +00D02A FLEXION SYSTEMS +00D02B JETCELL, INC. +00D02C CAMPBELL SCIENTIFIC, INC. +00D02D ADEMCO +00D02E COMMUNICATION AUTOMATION CORP. +00D02F VLSI TECHNOLOGY INC. +00D030 SAFETRAN SYSTEMS CORP. +00D031 INDUSTRIAL LOGIC CORPORATION +00D032 YANO ELECTRIC CO., LTD. +00D033 DALIAN DAXIAN NETWORK +00D034 ORMEC SYSTEMS CORP. +00D035 BEHAVIOR TECH. COMPUTER CORP. +00D036 TECHNOLOGY ATLANTA CORP. +00D037 PHILIPS-DVS-LO BDR +00D038 FIVEMERE, LTD. +00D039 UTILICOM, INC. +00D03A ZONEWORX, INC. +00D03B VISION PRODUCTS PTY. LTD. +00D03C Vieo, Inc. +00D03E ROCKETCHIPS, INC. +00D03F AMERICAN COMMUNICATION +00D040 SYSMATE CO., LTD. +00D041 AMIGO TECHNOLOGY CO., LTD. +00D042 MAHLO GMBH & CO. UG +00D043 ZONAL RETAIL DATA SYSTEMS +00D044 ALIDIAN NETWORKS, INC. +00D045 KVASER AB +00D046 DOLBY LABORATORIES, INC. +00D047 XN TECHNOLOGIES +00D048 ECTON, INC. +00D049 IMPRESSTEK CO., LTD. +00D04A PRESENCE TECHNOLOGY GMBH +00D04B LA CIE GROUP S.A. +00D04C EUROTEL TELECOM LTD. +00D04D DIV OF RESEARCH & STATISTICS +00D04E LOGIBAG +00D04F BITRONICS, INC. +00D050 ISKRATEL +00D051 O2 MICRO, INC. +00D052 ASCEND COMMUNICATIONS, INC. +00D053 CONNECTED SYSTEMS +00D054 SAS INSTITUTE INC. +00D055 KATHREIN-WERKE KG +00D056 SOMAT CORPORATION +00D057 ULTRAK, INC. +00D058 CISCO SYSTEMS, INC. +00D059 AMBIT MICROSYSTEMS CORP. +00D05A SYMBIONICS, LTD. +00D05B ACROLOOP MOTION CONTROL +00D05C TECHNOTREND SYSTEMTECHNIK GMBH +00D05D INTELLIWORXX, INC. +00D05E STRATABEAM TECHNOLOGY, INC. +00D05F VALCOM, INC. +00D060 PANASONIC EUROPEAN +00D061 TREMON ENTERPRISES CO., LTD. +00D062 DIGIGRAM +00D063 CISCO SYSTEMS, INC. +00D064 MULTITEL +00D065 TOKO ELECTRIC +00D066 WINTRISS ENGINEERING CORP. +00D067 CAMPIO COMMUNICATIONS +00D068 IWILL CORPORATION +00D069 TECHNOLOGIC SYSTEMS +00D06A LINKUP SYSTEMS CORPORATION +00D06B SR TELECOM INC. +00D06C SHAREWAVE, INC. +00D06D ACRISON, INC. +00D06E TRENDVIEW RECORDERS LTD. +00D06F KMC CONTROLS +00D070 LONG WELL ELECTRONICS CORP. +00D071 ECHELON CORP. +00D072 BROADLOGIC +00D073 ACN ADVANCED COMMUNICATIONS +00D074 TAQUA SYSTEMS, INC. +00D075 ALARIS MEDICAL SYSTEMS, INC. +00D076 MERRILL LYNCH & CO., INC. +00D077 LUCENT TECHNOLOGIES +00D078 ELTEX OF SWEDEN AB +00D079 CISCO SYSTEMS, INC. +00D07A AMAQUEST COMPUTER CORP. +00D07B COMCAM INTERNATIONAL LTD. +00D07C KOYO ELECTRONICS INC. CO.,LTD. +00D07D COSINE COMMUNICATIONS +00D07E KEYCORP LTD. +00D07F STRATEGY & TECHNOLOGY, LIMITED +00D080 EXABYTE CORPORATION +00D081 REAL TIME DEVICES USA, INC. +00D082 IOWAVE INC. +00D083 INVERTEX, INC. +00D084 NEXCOMM SYSTEMS, INC. +00D085 OTIS ELEVATOR COMPANY +00D086 FOVEON, INC. +00D087 MICROFIRST INC. +00D088 MAINSAIL NETWORKS, INC. +00D089 DYNACOLOR, INC. +00D08A PHOTRON USA +00D08B ADVA Limited +00D08C GENOA TECHNOLOGY, INC. +00D08D PHOENIX GROUP, INC. +00D08E NVISION INC. +00D08F ARDENT TECHNOLOGIES, INC. +00D090 CISCO SYSTEMS, INC. +00D091 SMARTSAN SYSTEMS, INC. +00D092 GLENAYRE WESTERN MULTIPLEX +00D093 TQ - COMPONENTS GMBH +00D094 TIMELINE VISTA, INC. +00D095 XYLAN CORPORATION +00D096 3COM EUROPE LTD. +00D097 CISCO SYSTEMS, INC. +00D098 IPS AUTOMATION +00D099 ELCARD OY +00D09A FILANET CORPORATION +00D09B SPECTEL LTD. +00D09C KAPADIA COMMUNICATIONS +00D09D VERIS INDUSTRIES +00D09E 2WIRE, INC. +00D09F NOVTEK TEST SYSTEMS +00D0A0 MIPS DENMARK +00D0A1 OSKAR VIERLING GMBH + CO. KG +00D0A2 INTEGRATED DEVICE +00D0A3 VOCAL DATA, INC. +00D0A4 ALANTRO COMMUNICATIONS +00D0A5 AMERICAN ARIUM +00D0A6 LANBIRD TECHNOLOGY CO., LTD. +00D0A7 TOKYO SOKKI KENKYUJO CO., LTD. +00D0A8 NETWORK ENGINES, INC. +00D0A9 SHINANO KENSHI CO., LTD. +00D0AA CHASE COMMUNICATIONS +00D0AB DELTAKABEL TELECOM CV +00D0AC GRAYSON WIRELESS +00D0AD TL INDUSTRIES +00D0AE ORESIS COMMUNICATIONS, INC. +00D0AF CUTLER-HAMMER, INC. +00D0B0 BITSWITCH LTD. +00D0B1 OMEGA ELECTRONICS SA +00D0B2 XIOTECH CORPORATION +00D0B3 DRS FLIGHT SAFETY AND +00D0B4 KATSUJIMA CO., LTD. +00D0B5 DOTCOM +00D0B6 CRESCENT NETWORKS, INC. +00D0B7 INTEL CORPOTATION +00D0B8 IOMEGA CORP. +00D0B9 MICROTEK INTERNATIONAL, INC. +00D0BA CISCO SYSTEMS, INC. +00D0BB CISCO SYSTEMS, INC. +00D0BC CISCO SYSTEMS, INC. +00D0BD SICAN GMBH +00D0BE EMUTEC INC. +00D0BF PIVOTAL TECHNOLOGIES +00D0C0 CISCO SYSTEMS, INC. +00D0C1 HARMONIC DATA SYSTEMS, LTD. +00D0C2 BALTHAZAR TECHNOLOGY AB +00D0C3 VIVID TECHNOLOGY PTE, LTD. +00D0C4 TERATECH CORPORATION +00D0C5 COMPUTATIONAL SYSTEMS, INC. +00D0C6 THOMAS & BETTS CORP. +00D0C7 PATHWAY, INC. +00D0C8 I/O CONSULTING A/S +00D0C9 ADVANTECH CO., LTD. +00D0CA INTRINSYC SOFTWARE INC. +00D0CB DASAN CO., LTD. +00D0CC TECHNOLOGIES LYRE INC. +00D0CD ATAN TECHNOLOGY INC. +00D0CE ASYST ELECTRONIC +00D0CF MORETON BAY +00D0D0 ZHONGXING TELECOM LTD. +00D0D1 SIROCCO SYSTEMS, INC. +00D0D2 EPILOG CORPORATION +00D0D3 CISCO SYSTEMS, INC. +00D0D4 V-BITS, INC. +00D0D5 GRUNDIG AG +00D0D6 AETHRA TELECOMUNICAZIONI +00D0D7 B2C2, INC. +00D0D8 3Com Corporation +00D0D9 DEDICATED MICROCOMPUTERS +00D0DA TAICOM DATA SYSTEMS CO., LTD. +00D0DB MCQUAY INTERNATIONAL +00D0DC MODULAR MINING SYSTEMS, INC. +00D0DD SUNRISE TELECOM, INC. +00D0DE PHILIPS MULTIMEDIA NETWORK +00D0DF KUZUMI ELECTRONICS, INC. +00D0E0 DOOIN ELECTRONICS CO. +00D0E1 AVIONITEK ISRAEL INC. +00D0E2 MRT MICRO, INC. +00D0E3 ELE-CHEM ENGINEERING CO., LTD. +00D0E4 CISCO SYSTEMS, INC. +00D0E5 SOLIDUM SYSTEMS CORP. +00D0E6 IBOND INC. +00D0E7 VCON TELECOMMUNICATION LTD. +00D0E8 MAC SYSTEM CO., LTD. +00D0E9 ADVANTAGE CENTURY +00D0EA NEXTONE COMMUNICATIONS, INC. +00D0EB LIGHTERA NETWORKS, INC. +00D0EC NAKAYO TELECOMMUNICATIONS, INC +00D0ED XIOX +00D0EE DICTAPHONE CORPORATION +00D0EF IGT +00D0F0 CONVISION TECHNOLOGY GMBH +00D0F1 SEGA ENTERPRISES, LTD. +00D0F2 MONTEREY NETWORKS +00D0F3 SOLARI DI UDINE SPA +00D0F4 CARINTHIAN TECH INSTITUTE +00D0F5 ORANGE MICRO, INC. +00D0F6 NORTHCHURCH COMMUNICATIONS INC +00D0F7 NEXT NETS CORPORATION +00D0F8 FUJIAN STAR TERMINAL +00D0F9 ACUTE COMMUNICATIONS CORP. +00D0FA RACAL GUARDATA +00D0FB TEK MICROSYSTEMS, INCORPORATED +00D0FC GRANITE MICROSYSTEMS +00D0FD OPTIMA TELE.COM, INC. +00D0FE ASTRAL POINT +00D0FF CISCO SYSTEMS, INC. +00DD00 UNGERMANN-BASS INC. +00DD01 UNGERMANN-BASS INC. +00DD02 UNGERMANN-BASS INC. +00DD03 UNGERMANN-BASS INC. +00DD04 UNGERMANN-BASS INC. +00DD05 UNGERMANN-BASS INC. +00DD06 UNGERMANN-BASS INC. +00DD07 UNGERMANN-BASS INC. +00DD08 UNGERMANN-BASS INC. +00DD09 UNGERMANN-BASS INC. +00DD0A UNGERMANN-BASS INC. +00DD0B UNGERMANN-BASS INC. +00DD0C UNGERMANN-BASS INC. +00DD0D UNGERMANN-BASS INC. +00DD0E UNGERMANN-BASS INC. +00DD0F UNGERMANN-BASS INC. +00E000 FUJITSU, LTD +00E001 STRAND LIGHTING LIMITED +00E002 CROSSROADS SYSTEMS, INC. +00E003 NOKIA WIRELESS BUSINESS COMMUN +00E004 PMC-SIERRA, INC. +00E005 TECHNICAL CORP. +00E006 SILICON INTEGRATED SYS. CORP. +00E007 NETWORK ALCHEMY LTD. +00E008 AMAZING CONTROLS! INC. +00E009 MARATHON TECHNOLOGIES CORP. +00E00A DIBA, INC. +00E00B ROOFTOP COMMUNICATIONS CORP. +00E00C MOTOROLA +00E00D RADIANT SYSTEMS +00E00E AVALON IMAGING SYSTEMS, INC. +00E00F SHANGHAI BAUD DATA +00E010 HESS SB-AUTOMATENBAU GMBH +00E011 UNIDEN SAN DIEGO +00E012 PLUTO TECHNOLOGIES +00E013 EASTERN ELECTRONIC CO., LTD. +00E014 CISCO SYSTEMS, INC. +00E015 HEIWA CORPORATION +00E016 RAPID CITY COMMUNICATIONS +00E017 EXXACT GMBH +00E018 ASUSTEK COMPUTER INC. +00E019 ING. GIORDANO ELETTRONICA +00E01A COMTEC SYSTEMS. CO., LTD. +00E01B SPHERE COMMUNICATIONS, INC. +00E01C MOBILITY ELECTRONICSY +00E01D WEBTV NETWORKS, INC. +00E01E CISCO SYSTEMS, INC. +00E01F AVIDIA SYSTEMS, INC. +00E020 TECNOMEN OY +00E021 FREEGATE CORP. +00E022 MEDIALIGHT INC. +00E023 TELRAD +00E024 GADZOOX NETWORKS +00E025 DIT CO., LTD. +00E026 EASTMAN KODAK CO. +00E027 DUX, INC. +00E028 APTIX CORPORATION +00E029 STANDARD MICROSYSTEMS CORP. +00E02A TANDBERG TELEVISION AS +00E02B EXTREME NETWORKS +00E02C AST COMPUTER +00E02D INNOMEDIALOGIC, INC. +00E02E SPC ELECTRONICS CORPORATION +00E02F MCNS HOLDINGS, L.P. +00E030 MELITA INTERNATIONAL CORP. +00E031 HAGIWARA ELECTRIC CO., LTD. +00E032 MISYS FINANCIAL SYSTEMS, LTD. +00E033 E.E.P.D. GMBH +00E034 CISCO SYSTEMS, INC. +00E035 LOUGHBOROUGH SOUND IMAGES, PLC +00E036 PIONEER CORPORATION +00E037 CENTURY CORPORATION +00E038 PROXIMA CORPORATION +00E039 PARADYNE CORP. +00E03A CABLETRON SYSTEMS, INC. +00E03B PROMINET CORPORATION +00E03C ADVANSYS +00E03D FOCON ELECTRONIC SYSTEMS A/S +00E03E ALFATECH, INC. +00E03F JATON CORPORATION +00E040 DESKSTATION TECHNOLOGY, INC. +00E041 CSPI +00E042 PACOM DATA LTD. +00E043 VITALCOM +00E044 LSICS CORPORATION +00E045 TOUCHWAVE, INC. +00E046 BENTLY NEVADA CORP. +00E047 INFOCUS SYSTEMS +00E048 SDL COMMUNICATIONS, INC. +00E049 MICROWI ELECTRONIC GMBH +00E04A ENHANCED MESSAGING SYSTEMS,INC +00E04B JUMP INDUSTRIELLE +00E04C REALTEK SEMICONDUCTOR CORP. +00E04D INTERNET INITIATIVE JAPAN, INC +00E04E SANYO DENKI CO., LTD. +00E04F CISCO SYSTEMS, INC. +00E050 EXECUTONE INFORMATION +00E051 TALX CORPORATION +00E052 FOUNDRY NETWORKS, INC. +00E053 CELLPORT LABS, INC. +00E054 KODAI HITEC CO., LTD. +00E055 INGENIERIA ELECTRONICA +00E056 HOLONTECH CORPORATION +00E057 HAN MICROTELECOM. CO., LTD. +00E058 PHASE ONE DENMARK A/S +00E059 CONTROLLED ENVIRONMENTS, LTD. +00E05A GALEA NETWORK SECURITY +00E05B WEST END SYSTEMS CORP. +00E05C MATSUSHITA KOTOBUKI +00E05D UNITEC CO., LTD. +00E05E JAPAN AVIATION ELECTRONICS +00E05F E-NET, INC. +00E060 SHERWOOD +00E061 EDGEPOINT NETWORKS, INC. +00E062 HOST ENGINEERING +00E063 CABLETRON - YAGO SYSTEMS, INC. +00E064 SAMSUNG ELECTRONICS +00E065 OPTICAL ACCESS INTERNATIONAL +00E066 PROMAX SYSTEMS, INC. +00E067 EAC AUTOMATION-CONSULTING GMBH +00E068 MERRIMAC SYSTEMS INC. +00E069 JAYCOR NETWORKS, INC. +00E06A KAPSCH AG +00E06B W&G SPECIAL PRODUCTS +00E06C BALTIMORE TECHNOLOGIES, LTD. +00E06D COMPUWARE CORPORATION +00E06E FAR SYSTEMS SPA +00E06F TERAYON CORP. +00E070 DH TECHNOLOGY +00E071 EPIS MICROCOMPUTER +00E072 LYNK +00E073 NATIONAL AMUSEMENT +00E074 TIERNAN COMMUNICATIONS, INC. +00E075 ATLAS COMPUTER EQUIPMENT, INC. +00E076 DEVELOPMENT CONCEPTS, INC. +00E077 WEBGEAR, INC. +00E078 BERKELEY NETWORKS +00E079 A.T.N.R. +00E07A MIKRODIDAKT AB +00E07B BAY NETWORKS +00E07C METTLER-TOLEDO, INC. +00E07D NETRONIX, INC. +00E07E WALT DISNEY IMAGINEERING +00E07F LOGISTISTEM SRL +00E080 CONTROL RESOURCES CORPORATION +00E081 TYAN COMPUTER CORP. +00E082 ANERMA +00E083 JATO TECHNOLOGIES, INC. +00E084 COMPULITE R&D +00E085 GLOBAL MAINTECH, INC. +00E086 CYBEX COMPUTER PRODUCTS +00E087 LECROY +00E088 LTX CORPORATION +00E089 ION Networks, Inc. +00E08A GEC AVERY, LTD. +00E08B QLOGIC CORP. +00E08C NEOPARADIGM LABS, INC. +00E08D PRESSURE SYSTEMS, INC. +00E08E UTSTARCOM +00E08F CISCO SYSTEMS, INC. +00E090 BECKMAN LAB. AUTOMATION DIV. +00E091 LG ELECTRONICS, INC. +00E092 ADMTEK INCORPORATED +00E093 ACKFIN NETWORKS +00E094 OSAI SRL +00E095 ADVANCED-VISION TECHNOLGIES +00E096 SHIMADZU CORPORATION +00E097 CARRIER ACCESS CORPORATION +00E098 ABOCOM SYSTEMS, INC. +00E099 SAMSON AG +00E09A POSITRON INDUSTRIES, INC. +00E09B ENGAGE NETWORKS, INC. +00E09C MII +00E09D SARNOFF CORPORATION +00E09E QUANTUM CORPORATION +00E09F PIXEL VISION +00E0A0 WILTRON CO. +00E0A1 HIMA PAUL HILDEBRANDT +00E0A2 MICROSLATE INC. +00E0A3 CISCO SYSTEMS, INC. +00E0A4 ESAOTE S.P.A. +00E0A5 COMCORE SEMICONDUCTOR, INC. +00E0A6 TELOGY NETWORKS, INC. +00E0A7 IPC INFORMATION SYSTEMS, INC. +00E0A8 SAT GMBH&CO +00E0A9 FUNAI ELECTRIC CO., LTD. +00E0AA ELECTROSONIC LTD. +00E0AB DIMAT S.A. +00E0AC MIDSCO, INC. +00E0AD EES TECHNOLOGY, LTD. +00E0AE XAQTI CORPORATION +00E0AF GENERAL DYNAMICS INFORMATION +00E0B0 CISCO SYSTEMS, INC. +00E0B1 PACKET ENGINES, INC. +00E0B2 TELMAX COMMUNICATIONS CORP. +00E0B3 ETHERWAN SYSTEMS, INC. +00E0B4 TECHNO SCOPE CO., LTD. +00E0B5 ARDENT COMMUNICATIONS CORP. +00E0B6 Entrada Networks +00E0B7 PI GROUP, LTD. +00E0B8 GATEWAY 2000 +00E0B9 BYAS SYSTEMS +00E0BA BERGHOF AUTOMATIONSTECHNIK +00E0BB NBX CORPORATION +00E0BC SYMON COMMUNICATIONS, INC. +00E0BD INTERFACE SYSTEMS, INC. +00E0BE GENROCO INTERNATIONAL, INC. +00E0BF TORRENT NETWORKING +00E0C0 SEIWA ERECTRIC MFG. CO., LTD. +00E0C1 MEMOREX TELEX JAPAN, LTD. +00E0C2 NECSY SPA +00E0C3 SAKAI SYSTEM DEVELOPMENT CORP. +00E0C4 HORNER ELECTRIC, INC. +00E0C5 BCOM ELECTRONICS INC. +00E0C6 LINK2IT, L.L.C. +00E0C7 EUROTECH SRL +00E0C8 VIRTUAL ACCESS, LTD. +00E0C9 AUTOMATEDLOGIC CORPORATION +00E0CA BEST DATA PRODUCTS +00E0CB RESON, INC. +00E0CC HERO SYSTEMS, LTD. +00E0CD SENSIS CORPORATION +00E0CE ARN +00E0CF INTEGRATED DEVICE +00E0D0 NETSPEED, INC. +00E0D1 TELSIS LIMITED +00E0D2 VERSANET COMMUNICATIONS, INC. +00E0D3 DATENTECHNIK GMBH +00E0D4 EXCELLENT COMPUTER +00E0D5 ARCXEL TECHNOLOGIES, INC. +00E0D6 COMPUTER & COMMUNICATION +00E0D7 SUNSHINE ELECTRONICS, INC. +00E0D8 LANBIT COMPUTER, INC. +00E0D9 TAZMO CO., LTD. +00E0DA ASSURED ACCESS +00E0DB VIAVIDEO COMMUNICATIONS +00E0DC NEXWARE CORP. +00E0DD ZENITH ELECTRONICS CORPORATION +00E0DE DATAX NV +00E0DF KE KOMMUNIKATIONS-ELECTRONIK +00E0E0 SI ELECTRONICS, LTD. +00E0E1 G2 NETWORKS, ILNC. +00E0E2 INNOVA CORP. +00E0E3 SK-ELEKTRONIK GMBH +00E0E4 FANUC ROBOTICS NORTH AMERICA, +00E0E5 CINCO NETWORKS, INC. +00E0E6 INCAA DATACOM B.V. +00E0E7 RAYTHEON E-SYSTEMS, INC. +00E0E8 GRETACODER DATA SYSTEMS AG +00E0E9 DATA LABS, INC. +00E0EA INNOVAT COMMUNICATIONS, INC. +00E0EB DIGICOM SYSTEMS, INCORPORATED +00E0EC CELESTICA INC. +00E0ED SILICOM, LTD. +00E0EE MAREL HF +00E0EF DIONEX +00E0F0 ABLER TECHNOLOGY, INC. +00E0F1 THAT CORPORATION +00E0F2 ARLOTTO COMNET, INC. +00E0F3 WEBSPRINT COMMUNICATIONS, INC. +00E0F4 INSIDE TECHNOLOGY A/S +00E0F5 TELES AG +00E0F6 DECISION EUROPE +00E0F7 CISCO SYSTEMS, INC. +00E0F8 DIANA CONTROL AB +00E0F9 CISCO SYSTEMS, INC. +00E0FA TRL TECHNOLOGY, LTD. +00E0FB LEIGHTRONIX, INC. +00E0FC HUAWEI TECHNOLOGIES CO., LTD. +00E0FD A-TREND TECHNOLOGY CO., LTD. +00E0FE CISCO SYSTEMS, INC. +00E0FF SECURITY DYNAMICS TECHNOLOGIES +00E6D3 NIXDORF COMPUTER CORP. +020701 RACAL-DATACOM +021C7C PERQ SYSTEMS CORPORATION +026086 LOGIC REPLACEMENT TECH. LTD. +02608C 3COM CORPORATION +027001 RACAL-DATACOM +0270B0 M/A-COM INC. COMPANIES +0270B3 DATA RECALL LTD +029D8E CARDIAC RECORDERS INC. +02AA3C OLIVETTI TELECOMM SPA (OLTECO) +02BB01 OCTOTHORPE CORP. +02C08C 3COM CORPORATION +02CF1C COMMUNICATION MACHINERY CORP. +02E6D3 NIXDORF COMPUTER CORPORATION +040AE0 XMIT AG COMPUTER NETWORKS +04E0C4 TRIUMPH-ADLER AG +080001 COMPUTERVISION CORPORATION +080002 BRIDGE COMMUNICATIONS INC. +080003 ADVANCED COMPUTER COMM. +080004 CROMEMCO INCORPORATED +080005 SYMBOLICS INC. +080006 SIEMENS AG +080007 APPLE COMPUTER INC. +080008 BOLT BERANEK AND NEWMAN INC. +080009 HEWLETT PACKARD +08000A NESTAR SYSTEMS INCORPORATED +08000B UNISYS CORPORATION +08000C MIKLYN DEVELOPMENT CO. +08000D INTERNATIONAL COMPUTERS LTD. +08000E NCR CORPORATION +08000F MITEL CORPORATION +080011 TEKTRONIX INC. +080012 BELL ATLANTIC INTEGRATED SYST. +080013 EXXON +080014 EXCELAN +080015 STC BUSINESS SYSTEMS +080016 BARRISTER INFO SYS CORP +080017 NATIONAL SEMICONDUCTOR +080018 PIRELLI FOCOM NETWORKS +080019 GENERAL ELECTRIC CORPORATION +08001A TIARA/ 10NET +08001B DATA GENERAL +08001C KDD-KOKUSAI DEBNSIN DENWA CO. +08001D ABLE COMMUNICATIONS INC. +08001E APOLLO COMPUTER INC. +08001F SHARP CORPORATION +080020 SUN MICROSYSTEMS INC. +080021 3M COMPANY +080022 NBI INC. +080023 MATSUHITA GRAPHIC COMM SYS INC +080024 10NET COMMUNICATIONS/DCA +080025 CONTROL DATA +080026 NORSK DATA A.S. +080027 CADMUS COMPUTER SYSTEMS +080028 TEXAS INSTRUMENTS +080029 MEGATEK CORPORATION +08002A MOSAIC TECHNOLOGIES INC. +08002B DIGITAL EQUIPMENT CORPORATION +08002C BRITTON LEE INC. +08002D LAN-TEC INC. +08002E METAPHOR COMPUTER SYSTEMS +08002F PRIME COMPUTER INC. +080030 NETWORK RESEARCH CORPORATION +080030 CERN +080030 ROYAL MELBOURNE INST OF TECH +080031 LITTLE MACHINES INC. +080032 TIGAN INCORPORATED +080033 BAUSCH & LOMB +080034 FILENET CORPORATION +080035 MICROFIVE CORPORATION +080036 INTERGRAPH CORPORATION +080037 FUJI-XEROX CO. LTD. +080038 CII HONEYWELL BULL +080039 SPIDER SYSTEMS LIMITED +08003A ORCATECH INC. +08003B TORUS SYSTEMS LIMITED +08003C SCHLUMBERGER WELL SERVICES +08003D CADNETIX CORPORATIONS +08003E CODEX CORPORATION +08003F FRED KOSCHARA ENTERPRISES +080040 FERRANTI COMPUTER SYS. LIMITED +080041 RACAL-MILGO INFORMATION SYS.. +080042 JAPAN MACNICS CORP. +080043 PIXEL COMPUTER INC. +080044 DAVID SYSTEMS INC. +080045 CONCURRENT COMPUTER CORP. +080046 SONY CORPORATION LTD. +080047 SEQUENT COMPUTER SYSTEMS INC. +080048 EUROTHERM GAUGING SYSTEMS +080049 UNIVATION +08004A BANYAN SYSTEMS INC. +08004B PLANNING RESEARCH CORP. +08004C HYDRA COMPUTER SYSTEMS INC. +08004D CORVUS SYSTEMS INC. +08004E 3COM EUROPE LTD. +08004F CYGNET SYSTEMS +080050 DAISY SYSTEMS CORP. +080051 EXPERDATA +080052 INSYSTEC +080053 MIDDLE EAST TECH. UNIVERSITY +080055 STANFORD TELECOMM. INC. +080056 STANFORD LINEAR ACCEL. CENTER +080057 EVANS & SUTHERLAND +080058 SYSTEMS CONCEPTS +080059 A/S MYCRON +08005A IBM CORPORATION +08005B VTA TECHNOLOGIES INC. +08005C FOUR PHASE SYSTEMS +08005D GOULD INC. +08005E COUNTERPOINT COMPUTER INC. +08005F SABER TECHNOLOGY CORP. +080060 INDUSTRIAL NETWORKING INC. +080061 JAROGATE LTD. +080062 GENERAL DYNAMICS +080063 PLESSEY +080064 AUTOPHON AG +080065 GENRAD INC. +080066 AGFA CORPORATION +080067 COMDESIGN +080068 RIDGE COMPUTERS +080069 SILICON GRAPHICS INC. +08006A ATT BELL LABORATORIES +08006B ACCEL TECHNOLOGIES INC. +08006C SUNTEK TECHNOLOGY INT'L +08006D WHITECHAPEL COMPUTER WORKS +08006E MASSCOMP +08006F PHILIPS APELDOORN B.V. +080070 MITSUBISHI ELECTRIC CORP. +080071 MATRA (DSIE) +080072 XEROX CORP UNIV GRANT PROGRAM +080073 TECMAR INC. +080074 CASIO COMPUTER CO. LTD. +080075 DANSK DATA ELECTRONIK +080076 PC LAN TECHNOLOGIES +080077 TSL COMMUNICATIONS LTD. +080078 ACCELL CORPORATION +080079 THE DROID WORKS +08007A INDATA +08007B SANYO ELECTRIC CO. LTD. +08007C VITALINK COMMUNICATIONS CORP. +08007E AMALGAMATED WIRELESS(AUS) LTD +08007F CARNEGIE-MELLON UNIVERSITY +080080 AES DATA INC. +080081 ,ASTECH INC. +080082 VERITAS SOFTWARE +080083 SEIKO INSTRUM. AND ELECTRONICS +080084 TOMEN ELECTRONICS CORP. +080085 ELXSI +080086 IMAGEN CORPORATION +080087 XYPLEX +080088 MCDATA CORPORATION +080089 KINETICS +08008A PERFORMANCE TECHNOLOGY +08008B PYRAMID TECHNOLOGY CORP. +08008C NETWORK RESEARCH CORPORATION +08008D XYVISION INC. +08008E TANDEM COMPUTERS +08008F CHIPCOM CORPORATION +080090 SONOMA SYSTEMS +08BBCC AK-NORD EDV VERTRIEBSGES. MBH +10005A IBM CORPORATION +1000E8 NATIONAL SEMICONDUCTOR +800010 ATT BELL LABORATORIES +A06A00 Verilink Corporation +AA0000 DIGITAL EQUIPMENT CORPORATION +AA0001 DIGITAL EQUIPMENT CORPORATION +AA0002 DIGITAL EQUIPMENT CORPORATION +AA0003 DIGITAL EQUIPMENT CORPORATION +AA0004 DIGITAL EQUIPMENT CORPORATION diff -urN linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/oui2c.sh.svn-base linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/oui2c.sh.svn-base --- linux-2.4.23-pre8/drivers/ieee1394/.svn/text-base/oui2c.sh.svn-base 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.23-pre8-pac1/drivers/ieee1394/.svn/text-base/oui2c.sh.svn-base 2003-07-21 13:09:41.000000000 +0200 @@ -0,0 +1,23 @@ +#!/bin/sh + +cat < + +#ifdef CONFIG_IEEE1394_OUI_DB +struct oui_list_struct { + int oui; + char *name; +} oui_list[] = { +EOF + +while read oui name; do + echo " { 0x$oui, \"$name\" }," +done + +cat <, + * Stephan Linz + * Manfred Weihs + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the 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. + */ + +/* + * Contributions: + * + * Manfred Weihs + * reading bus info block (containing GUID) from serial + * eeprom via i2c and storing it in config ROM + * Reworked code for initiating bus resets + * (long, short, with or without hold-off) + * Enhancements in async and iso send code + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ieee1394.h" +#include "ieee1394_types.h" +#include "hosts.h" +#include "ieee1394_core.h" +#include "highlevel.h" +#include "pcilynx.h" + +#include +#include + +/* print general (card independent) information */ +#define PRINT_G(level, fmt, args...) printk(level "pcilynx: " fmt "\n" , ## args) +/* print card specific information */ +#define PRINT(level, card, fmt, args...) printk(level "pcilynx%d: " fmt "\n" , card , ## args) + +#ifdef CONFIG_IEEE1394_VERBOSEDEBUG +#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...) do {} while (0) +#define PRINTD(level, card, fmt, args...) do {} while (0) +#endif + + +/* Module Parameters */ +MODULE_PARM(skip_eeprom,"i"); +MODULE_PARM_DESC(skip_eeprom, "Do not try to read bus info block from serial eeprom, but user generic one (default = 0)."); +static int skip_eeprom = 0; + + +static struct hpsb_host_driver lynx_driver; +static unsigned int card_id; + + + +/* + * I2C stuff + */ + +/* the i2c stuff was inspired by i2c-philips-par.c */ + +static void bit_setscl(void *data, int state) +{ + if (state) { + ((struct ti_lynx *) data)->i2c_driven_state |= 0x00000040; + } else { + ((struct ti_lynx *) data)->i2c_driven_state &= ~0x00000040; + } + reg_write((struct ti_lynx *) data, SERIAL_EEPROM_CONTROL, ((struct ti_lynx *) data)->i2c_driven_state); +} + +static void bit_setsda(void *data, int state) +{ + if (state) { + ((struct ti_lynx *) data)->i2c_driven_state |= 0x00000010; + } else { + ((struct ti_lynx *) data)->i2c_driven_state &= ~0x00000010; + } + reg_write((struct ti_lynx *) data, SERIAL_EEPROM_CONTROL, ((struct ti_lynx *) data)->i2c_driven_state); +} + +static int bit_getscl(void *data) +{ + return reg_read((struct ti_lynx *) data, SERIAL_EEPROM_CONTROL) & 0x00000040; +} + +static int bit_getsda(void *data) +{ + return reg_read((struct ti_lynx *) data, SERIAL_EEPROM_CONTROL) & 0x00000010; +} + +static int bit_reg(struct i2c_client *client) +{ + return 0; +} + +static int bit_unreg(struct i2c_client *client) +{ + return 0; +} + +static struct i2c_algo_bit_data bit_data = { + .setsda = bit_setsda, + .setscl = bit_setscl, + .getsda = bit_getsda, + .getscl = bit_getscl, + .udelay = 5, + .mdelay = 5, + .timeout = 100, +}; + +static struct i2c_adapter bit_ops = { + .id = 0xAA, //FIXME: probably we should get an id in i2c-id.h + .client_register = bit_reg, + .client_unregister = bit_unreg, + .nam